Tutorial 3 - Completed

Behavior Graph Tutorial 3 Completed

by slevin11

HTML

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="styles.css" />
    <script type="module" src="app.js"></script>
    <title>Behavior Graph Tutorial 3</title>
  </head>

  <body>

    <div class="list-container">
      <div class="title">
        Todo List
      </div>

      <div class="list-header">
        <span id="action">Add</span> Item: <input id="new-item-text" type="text" />
        <button id="save">Save</button>
      </div>
      <ul id="list">
      </ul>
      <div class="list-footer">
        <div>Remaining items: <span id="remaining-count"></span></div>
      </div>
      <div id="templates" style="display:none;">
        <li class="list-item"><input class="completed-checkbox" type="checkbox" />
          <div class="item-text"></div><button class="item-delete">Delete</button>
        </li>
      </div>

    </div>

  </body>

</html>

CSS

.list-container {
  border: 2px solid #333;
  width: 400px;
  padding: 30px;
  font: 1em sans-serif;
}

.list-header {
  background-color: #eee;
  border: 1px solid #ccc;
  padding: 4px;
}

.list-footer {
  background-color: #eee;
  border: 1px solid #ccc;
  padding: 4px;
  margin-bottom: 10px;
}

.list-item {
  margin-bottom: 8px;
  padding: 4px;
}

.item-text {
  width: 200px;
  display: inline-block;
  margin-left: 4px;
}

.title {
  text-decoration: underline;
  margin-bottom: 10px;
}

.list-item.completed .item-text {
  text-decoration: line-through;
  color: gray;
}

.list-item.selected {
  background-color: lightgreen;
}

JavaScript

import * as bg from "https://cdn.skypack.dev/behavior-graph";

class ListExtent extends bg.Extent {
  constructor(graph) {
    super(graph);

    this.save = this.moment();
    document.querySelector('#save').addEventListener('click', () => {
      this.save.updateWithAction(document.querySelector('#new-item-text').value);
    });

    this.allItems = this.state([]);
    this.removeItem = this.moment();
		this.selectRequest = this.moment();
    this.selected = this.state(null);
    
    this.behavior()
      .supplies(this.allItems)
      .demands(this.save, this.removeItem)
      .runs(() => {
        if (this.save.justUpdated && this.selected.traceValue === null) {
          let item = new ItemExtent(this.graph, this.save.value, this);
          this.addChildLifetime(item);
          item.addToGraph();
          this.allItems.value.push(item);
          this.allItems.updateForce(this.allItems.value);
          this.sideEffect(() => {
            document.querySelector('#list').appendChild(item.itemElement);
            document.querySelector('#new-item-text').value = '';
          });
        } else if (this.removeItem.justUpdated) {
          let item = this.removeItem.value;
          item.removeFromGraph();
          this.allItems.update(this.allItems.value.filter(listItem => listItem !== item));
          this.sideEffect(() => {
            document.querySelector('#list').removeChild(item.itemElement);
          });
        }
      });
      
    this.behavior()
      .dynamicSupplies([this.allItems], () => {
        return this.allItems.value.map(item => item.itemText);
      })
      .demands(this.save)
      .runs(() => {
      	if (this.save.justUpdated && this.selected.traceValue !== null) {
        	this.selected.traceValue.itemText.update(this.save.value);
        }
      });
      
    this.behavior()
      .demands(this.allItems, this.addedToGraph)
      .dynamicDemands([this.allItems], () => {
        return this.allItems.value.map(item =>...