Changeset - 75dfd7eb1e77
[Not reviewed]
default
0 4 0
drewp@bigasterisk.com - 20 months ago 2023-05-27 09:05:27
drewp@bigasterisk.com
clean up. still seems to work
4 files changed with 34 insertions and 192 deletions:
0 comments (0 inline, 0 general)
light9/live/Effect.ts
Show inline comments
 
@@ -28,19 +28,17 @@ function valuePred(graph: SyncedGraph, a
 
  }
 
}
 

	
 
// effect settings data; r/w sync with the graph
 
export class Effect {
 
  private settings: Array<{ device: NamedNode; deviceAttr: NamedNode; setting: NamedNode; value: ControlValue }> = [];
 
  private ctxForEffect: NamedNode
 
  settingsChanged:SubEvent<void>=new SubEvent()
 
  private ctxForEffect: NamedNode;
 
  settingsChanged: SubEvent<void> = new SubEvent();
 
  constructor(
 
    public graph: SyncedGraph,
 
    public uri: NamedNode,
 
    // called if the graph changes our values and not when the caller uses edit()
 
    // private onValuesChanged: (values: void) => void
 
    public uri: NamedNode // called if the graph changes our values and not when the caller uses edit()
 
  ) {
 
    this.ctxForEffect = this.graph.Uri(this.uri.value.replace("light9.bigasterisk.com/effect", `light9.bigasterisk.com/show/${shortShow}/effect`));
 
    graph.runHandler(this.rebuildSettingsFromGraph.bind(this), `effect sync ${uri.value}`);
 
  }
 

	
 
  addNewEffectToGraph() {
 
@@ -62,21 +60,19 @@ export class Effect {
 
    const U = this.graph.U();
 
    if (patch && !patchContainsPreds(patch, [U(":setting"), U(":device"), U(":deviceAttr")])) {
 
      // that's an approx list of preds , but it just means we'll miss some pathological settings edits
 
      //   return;
 
    }
 

	
 
    log("syncFromGraph", this.uri);
 
    // log("syncFromGraph", this.uri);
 

	
 
    // this repeats work- it gathers all settings when really some values changed (and we might even know about them). maybe push the value-fetching into a secnod phase of the run, and have the 1st phase drop out early
 
    const newSettings = [];
 

	
 
    const seenDevAttrPairs: Set<string> = new Set();
 

	
 
    for (let setting of Array.from(this.graph.objects(this.uri, U(":setting")))) {
 
        log(`  setting ${setting.value}`);
 
      // log(`  setting ${setting.value}`);
 
      if (!isUri(setting)) throw new Error();
 
      let value: ControlValue;
 
      const device = this.graph.uriValue(setting, U(":device"));
 
      const deviceAttr = this.graph.uriValue(setting, U(":deviceAttr"));
 

	
 
      const pred = valuePred(this.graph, deviceAttr);
 
@@ -93,16 +89,15 @@ export class Effect {
 
        }
 
      }
 
      //   log(`change: graph contains ${deviceAttr.value} ${value}`);
 

	
 
      newSettings.push({ device, deviceAttr, setting, value });
 
    }
 
    log(newSettings)
 
    this.settings = newSettings;
 
    log(`rebuild to ${this.settings.length}`);
 
    this.settingsChanged.emit()
 
    this.settingsChanged.emit(); // maybe one emitter per dev+attr?
 
    // this.onValuesChanged();
 
  }
 

	
 
  currentValue(device: NamedNode, deviceAttr: NamedNode): ControlValue | null {
 
    for (let s of this.settings) {
 
      if (device.equals(s.device) && deviceAttr.equals(s.deviceAttr)) {
light9/live/Light9AttrControl.ts
Show inline comments
 
import debug from "debug";
 
import { css, html, LitElement, PropertyValues } from "lit";
 
import { customElement, property, state } from "lit/decorators.js";
 
import { Literal, NamedNode } from "n3";
 
import { SubEvent } from "sub-events";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
import { SyncedGraph } from "../web/SyncedGraph";
 
import { ControlValue, Effect } from "./Effect";
 
import { GraphToControls } from "./GraphToControls";
 
import { DeviceAttrRow } from "./Light9DeviceControl";
 
import { Choice } from "./Light9Listbox";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
export { Slider } from "@material/mwc-slider";
 
export { Light9ColorPicker } from "../web/light9-color-picker";
 

	
 
export { Light9Listbox } from "./Light9Listbox";
 
const log = debug("settings.dev.attr");
 

	
 
type DataTypeNames = "scalar" | "color" | "choice";
 
const makeType = (d: DataTypeNames) => new NamedNode(`http://light9.bigasterisk.com/${d}`);
 

	
 
// UI for one device attr (of any type).
 
@@ -29,86 +27,61 @@ export class Light9AttrControl extends L
 
        align-items: center;
 
      }
 
      #colorControls > * {
 
        margin: 0 3px;
 
      }
 
      :host {
 
        border: 2px solid white;
 
      }
 
      mwc-slider {
 
        width: 250px;
 
      }
 
    `,
 
  ];
 

	
 
  @property() deviceAttrRow: DeviceAttrRow | null = null;
 
  @state() dataType: DataTypeNames = "scalar";
 

	
 
  @property() effect: Effect | null = null;
 
  // we'll connect to this and receive graphValueChanged and send uiValueChanged
 
  // @property() graphToControls!: GraphToControls;
 

	
 
  @property() enableChange: boolean = false;
 
  @property() value: ControlValue | null = null; // e.g. color string
 

	
 
  // slider mode
 
  // @property() sliderValue: number = 0;
 

	
 
  // color mode
 

	
 
  // choice mode
 
  // @property() pickedChoice: Choice | null = null;
 
  // @property() choiceValue: Choice | null = null;
 

	
 
  valueChanged: SubEvent<Literal> = new SubEvent();
 

	
 
  constructor() {
 
    super();
 
    getTopGraph().then((g) => {
 
      this.graph = g;
 
      if (this.deviceAttrRow === null) throw new Error();
 
      // this.graph.runHandler(this.graphReads.bind(this), `${this.deviceAttrRow.device} ${this.deviceAttrRow.uri} reads`);
 
    });
 
  }
 

	
 
  connectedCallback(): void {
 
    super.connectedCallback();
 
    setTimeout(() => {
 
      // only needed once per page layout
 
      this.shadowRoot?.querySelector("mwc-slider")?.layout(/*skipUpdateUI=*/ false);
 
    }, 1);
 
  }
 

	
 
  render() {
 
    if (this.deviceAttrRow === null) throw new Error();
 
    const dbg = html` live-control ${this.dataType}  ]`;
 
    if (this.dataType == "scalar") {
 
      const v = this.value || 0;
 
      return html`${dbg} <mwc-slider .value=${v} step=${1 / 255} min="0" max="1" @input=${this.onSliderInput}></mwc-slider> `;
 
      return html`<mwc-slider .value=${v} step=${1 / 255} min="0" max="1" @input=${this.onValueInput}></mwc-slider> `;
 
    } else if ((this.dataType = "color")) {
 
      const v = this.value || '#000'
 
      const v = this.value || "#000";
 
      return html`
 
        ${dbg}
 
        <div id="colorControls">
 
          <button on-click="goBlack">0.0</button>
 
          <light9-color-picker .color=${v} @input=${this.onColorInput}></light9-color-picker>
 
          <button @click=${this.goBlack}>0.0</button>
 
          <light9-color-picker .color=${v} @input=${this.onValueInput}></light9-color-picker>
 
        </div>
 
      `;
 
    } else if (this.dataType == "choice") {
 
      return html`${dbg} <light9-listbox .choices=${this.deviceAttrRow.choices} .value=${this.choiceValue}> </light9-listbox> `;
 
      return html`<light9-listbox .choices=${this.deviceAttrRow.choices} .value=${this.value}> </light9-listbox> `;
 
    }
 
  }
 

	
 
  // graphReads() {
 
  //   if (this.deviceAttrRow === null) throw new Error();
 
  //   const U = this.graph.U();
 
  //   this.effect?.currentValue(this.deviceAttrRow.device, this.deviceAttrRow.uri);
 
  // }
 

	
 
  updated(changedProperties: PropertyValues<this>) {
 
    super.updated(changedProperties);
 
    // if (changedProperties.has("graphToControls")) {
 
    //   // this.graphToControls.register(this.device, this.deviceAttrRow.uri, this.onGraphValueChanged.bind(this));
 
    //   this.enableChange = true;
 
    // }
 

	
 
    if (changedProperties.has("deviceAttrRow")) {
 
      this.onDeviceAttrRowProperty();
 
    }
 
    if (changedProperties.has("effect")) {
 
      this.onEffectProperty();
 
@@ -119,14 +92,14 @@ export class Light9AttrControl extends L
 
  }
 

	
 
  private onValueProperty() {
 
    if (this.deviceAttrRow === null) throw new Error();
 
    if (this.effect !== null && this.graph !== undefined) {
 
      const p = this.effect.edit(this.deviceAttrRow.device, this.deviceAttrRow.uri, this.value);
 
      log("patch", p, "to", this.graph);
 
      if (p.adds.length || p.dels.length) {
 
        log("Effect told us to graph.patch", p, "to", this.graph);
 
        this.graph.applyAndSendPatch(p);
 
      }
 
    }
 
  }
 

	
 
  private onEffectProperty() {
 
@@ -136,17 +109,16 @@ export class Light9AttrControl extends L
 
      this.effectSettingsChanged();
 
    });
 
    this.effectSettingsChanged();
 
  }
 

	
 
  private effectSettingsChanged() {
 
    // anything in the settings graph is new
 
    log("i check the effect current value");
 
    // something in the settings graph is new
 
    if (this.deviceAttrRow === null) throw new Error();
 
    if (this.effect === null) throw new Error();
 
    log("graph->ui on ", this.deviceAttrRow.device, this.deviceAttrRow.uri);
 
    // log("graph->ui on ", this.deviceAttrRow.device, this.deviceAttrRow.uri);
 
    const v=this.effect.currentValue(this.deviceAttrRow.device, this.deviceAttrRow.uri);
 
    this.onGraphValueChanged(v);
 
  }
 

	
 
  private onDeviceAttrRowProperty() {
 
    if (this.deviceAttrRow === null) throw new Error();
 
@@ -157,104 +129,53 @@ export class Light9AttrControl extends L
 
      this.dataType = "color";
 
    } else if (d.equals(makeType("choice"))) {
 
      this.dataType = "choice";
 
    }
 
  }
 

	
 
  onSliderInput(ev: CustomEvent) {
 
  onValueInput(ev: CustomEvent) {
 
    if (ev.detail === undefined) {
 
      // not sure what this is, but it seems to be followed by good events
 
      return;
 
    }
 
    log(ev.type, ev.detail.value);
 
    this.value = ev.detail.value;
 
    // this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, ev.detail.value);
 
  }
 

	
 
onColorInput(ev: CustomEvent) {
 
  this.value = ev.detail.value;
 
}
 

	
 
  onGraphValueChanged(v: ControlValue | null) {
 
    if (this.deviceAttrRow === null) throw new Error();
 
    log("change: control must display", v, "for", this.deviceAttrRow.device.value, this.deviceAttrRow.uri.value);
 
    // log("change: control must display", v, "for", this.deviceAttrRow.device.value, this.deviceAttrRow.uri.value);
 
    // this.enableChange = false;
 
    if (this.dataType == "scalar") {
 
      if (v !== null) {
 
        setTimeout(() => {
 
          // only needed once per page layout
 
          this.shadowRoot?.querySelector("mwc-slider")?.layout(/*skipUpdateUI=*/ false);
 
        }, 1);
 
        this.value = v;
 
      } else {
 
         this.value = 0;
 
      }
 
    } else if (this.dataType == "color") {
 
      log('graph sets coolor', v)
 
      this.value=v;
 
    }
 
    // if (v === null) {
 
    //   this.clear();
 
    // } else {
 
    //   this.value = v;
 
    // }
 
    // if (this.deviceAttrRow.useChoice) {
 
    //   this.choiceValue = v === null ? v : v.value;
 
    // }
 
    // this.enableChange = true;
 
  }
 

	
 
  graphToColor(v: ControlValue | null) {
 
    this.value = v === null ? "#000" : v;
 
    return;
 
    // const cp = this.shadowRoot?.querySelector("light9-color-picker") as Light9ColorPicker | null;
 
    // if (cp) {
 
    //   if (typeof v != "string") throw new Error("type v is " + typeof v);
 
    //   if (v === null) {
 
    //     v = "#000";
 
    //   }
 
    //   cp.setColor(v as string);
 
    // }
 
  }
 

	
 
  goBlack() {
 
    this.value = "#000000";
 
  }
 

	
 
  onChoice(value: any) {
 
    // if (this.graphToControls == null || !this.enableChange) {
 
    //   return;
 
    // }
 
    // if (value != null) {
 
    //   value = this.graph.Uri(value);
 
    // } else {
 
    //   value = null;
 
    // }
 
    // this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, value);
 
  }
 

	
 
  onChange(value: any) {
 
    // if (this.graphToControls == null || !this.enableChange) {
 
    //   return;
 
    // }
 
    // if (typeof value === "number" && isNaN(value)) {
 
    //   return;
 
    // } // let onChoice do it
 
    // //log('change: control tells graph', @deviceAttrRow.uri.value, value)
 
    // if (value === undefined) {
 
    //   value = null;
 
    // }
 
    // this.graphToControls.controlChanged(this.device, this.deviceAttrRow.uri, value);
 
  }
 

	
 
  // clear() {
 
  //   this.pickedChoice = null;
 
  //   this.sliderWriteValue = 0;
 
  //   if (this.deviceAttrRow.useColor) {
 
  //     return (this.value = "#000000");
 
  //   } else if (this.deviceAttrRow.useChoice) {
 
  //     return (this.value = this.pickedChoice = null);
 
  //   } else {
 
  //     return (this.value = this.sliderValue = 0);
 
  //   }
 
  // }
 
}
light9/live/Light9DeviceControl.ts
Show inline comments
 
@@ -3,32 +3,27 @@ import { css, html, LitElement } from "l
 
import { customElement, property } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { unique } from "underscore";
 
import { Patch, patchContainsPreds } from "../web/patch";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
import { SyncedGraph } from "../web/SyncedGraph";
 
import { GraphToControls } from "./GraphToControls";
 
import { Choice } from "./Light9Listbox";
 
import { Light9AttrControl } from "./Light9AttrControl";
 
import { Effect } from "./Effect";
 
export { ResourceDisplay } from "../web/ResourceDisplay";
 
export { Light9AttrControl };
 
const log = debug("settings.dev");
 

	
 
export interface DeviceAttrRow {
 
  uri: NamedNode; //devattr
 
  device: NamedNode;
 
  attrClasses: string; // the css kind
 
  dataType: NamedNode;
 
  showColorPicker: boolean;
 
  useColor: boolean;
 
  useChoice: boolean;
 
  choices: Choice[];
 
  choiceSize: number;
 
  useSlider: boolean;
 
  max: number;
 
  // choiceSize: number;
 
  // max: number;
 
}
 

	
 
// Widgets for one device with multiple Light9LiveControl rows for the attr(s).
 
@customElement("light9-device-control")
 
export class Light9DeviceControl extends LitElement {
 
  graph!: SyncedGraph;
 
@@ -80,37 +75,35 @@ export class Light9DeviceControl extends
 
    `,
 
  ];
 

	
 
  render() {
 
    return html`
 
      <div class="device ${this.devClasses}">
 
        <h2 style="${this._bgStyle(this.deviceClass)}" xon-click="onClick">
 
        <h2 style="${this._bgStyle(this.deviceClass)}" @click=${this.onClick}>
 
          <resource-display id="mainLabel" .uri="${this.uri}"></resource-display>
 
          a <resource-display minor .uri="${this.deviceClass}"></resource-display>
 
        </h2>
 

	
 
        ${this.deviceAttrs.map(
 
          (dattr: DeviceAttrRow) => html`
 
            <div @click="onAttrClick" class="deviceAttr ${dattr.attrClasses}">
 
              <span>
 
                attr
 
                <resource-display minor .uri=${dattr.uri}></resource-display>
 
              </span>
 
              <light9-attr-control .deviceAttrRow=${dattr} .effect=${this.effect}>
 
                .graphToControls={this.graphToControls}
 
              </light9-attr-control>
 
            </div>
 
          `
 
        )}
 
      </div>
 
    `;
 
  }
 

	
 
  @property() uri!: NamedNode;
 
  @property() effect!: Effect;
 
  // @property() graphToControls!: GraphToControls;
 

	
 
  @property() devClasses: string = ""; // the css kind
 
  @property() deviceAttrs: DeviceAttrRow[] = [];
 
  @property() deviceClass: NamedNode | null = null;
 
  @property() selectedAttrs: Set<NamedNode> = new Set();
 

	
 
@@ -142,13 +135,12 @@ export class Light9DeviceControl extends
 
  setAttrSelected(devAttr: NamedNode, isSel: boolean) {
 
    if (isSel) {
 
      this.selectedAttrs.add(devAttr);
 
    } else {
 
      this.selectedAttrs.delete(devAttr);
 
    }
 
    // this.syncDeviceAttrsFromGraph();
 
  }
 

	
 
  syncDeviceAttrsFromGraph(patch?: Patch) {
 
    const U = this.graph.U();
 
    if (patch && !patchContainsPreds(patch, [U("rdf:type"), U(":deviceAttr"), U(":dataType"), U(":choice")])) {
 
      return;
 
@@ -171,36 +163,28 @@ export class Light9DeviceControl extends
 
    const U = (x: string) => this.graph.Uri(x);
 
    const dataType = this.graph.uriValue(devAttr, U(":dataType"));
 
    const daRow = {
 
      uri: devAttr,
 
      device: this.uri,
 
      dataType,
 
      showColorPicker: dataType.equals(U(":color")),
 
      attrClasses: this.selectedAttrs.has(devAttr) ? "selected" : "",
 
      useColor: false,
 
      useChoice: false,
 
      choices: [] as Choice[],
 
      choiceSize: 0,
 
      useSlider: false,
 
      max: 1,
 
    };
 
    if (dataType.equals(U(":color"))) {
 
      daRow.useColor = true;
 
    } else if (dataType.equals(U(":choice"))) {
 
      daRow.useChoice = true;
 
     if (dataType.equals(U(":choice"))) {
 
      const choiceUris = this.graph.sortedUris(this.graph.objects(devAttr, U(":choice")));
 
      daRow.choices = (() => {
 
        const result = [];
 
        for (x of Array.from(choiceUris)) {
 
          result.push({ uri: x.value, label: this.graph.labelOrTail(x) });
 
        }
 
        return result;
 
      })();
 
      daRow.choiceSize = Math.min(choiceUris.length + 1, 10);
 
    } else {
 
      daRow.useSlider = true;
 
      daRow.max = 1;
 
      if (dataType.equals(U(":angle"))) {
 
        // varies
 
        daRow.max = 1;
 
      }
 
    }
light9/live/Light9DeviceSettings.ts
Show inline comments
 
import debug from "debug";
 
import { css, html, LitElement, PropertyValues } from "lit";
 
import { customElement, property } from "lit/decorators.js";
 
import { NamedNode } from "n3";
 
import { sortBy, uniq } from "underscore";
 
import { Patch, patchContainsPreds } from "../web/patch";
 
import { Patch } from "../web/patch";
 
import { getTopGraph } from "../web/RdfdbSyncedGraph";
 
import { SyncedGraph } from "../web/SyncedGraph";
 
import { GraphToControls } from "./GraphToControls";
 
import { Effect } from "./Effect";
 
export { EditChoice } from "../web/EditChoice";
 
export { Light9DeviceControl as Light9LiveDeviceControl } from "./Light9DeviceControl";
 
const log = debug("settings");
 

	
 
@customElement("light9-device-settings")
 
@@ -29,16 +28,17 @@ export class Light9DeviceSettings extend
 
        flex-grow: 1;
 
        position: relative;
 
        width: 100%;
 
        overflow-y: auto;
 
      }
 

	
 
      light9-live-device-control > div {
 
      light9-device-control > div {
 
        break-inside: avoid-column;
 
      }
 
      light9-live-device-control {
 
      light9-device-control {
 
        vertical-align: top;
 
      }
 
    `,
 
  ];
 

	
 
  render() {
 
    return html`
 
@@ -62,72 +62,67 @@ export class Light9DeviceSettings extend
 
        )}
 
      </div>
 
    `;
 
  }
 

	
 
  devices: Array<NamedNode> = [];
 
  // uri of the effect being edited, or null. This is the
 
  // master value; GraphToControls follows.
 
  @property() currentEffect: Effect | null = null;
 
  // graphToControls!: GraphToControls;
 
  okToWriteUrl: boolean = false;
 

	
 
  constructor() {
 
    super();
 

	
 
    getTopGraph().then((g) => {
 
      this.graph = g;
 
      this.graph.runHandler(this.findDevices.bind(this), "findDevices");
 
      // this.graphToControls = new GraphToControls(this.graph);
 
      // this.graph.runHandler(this.update.bind(this), "Light9LiveControls update");
 
      this.setEffectFromUrl();
 
    });
 
  }
 

	
 
  onEffectChoice2(ev: CustomEvent) {
 
    const uri = ev.detail.newValue as NamedNode;
 
    if (uri === null) {
 
      this.currentEffect = null;
 
    } else {
 
      this.currentEffect = new Effect(this.graph, uri);
 
    }
 
  }
 

	
 
  updated(changedProperties: PropertyValues<this>) {
 
    log("ctls udpated", changedProperties);
 
    if (changedProperties.has("currentEffect")) {
 
      log(`effectChoice to ${this.currentEffect?.uri?.value}`);
 
      this.onEffectChoice();
 
      this.writeToUrl(this.currentEffect?.uri);
 
    }
 
    // this.graphToControls?.debugDump();
 
  }
 

	
 
  // Note that this doesn't fetch setting values, so it only should get rerun
 
  // upon (rarer) changes to the devices etc.
 
  // upon (rarer) changes to the devices etc. todo: make that be true
 
  findDevices(patch?: Patch) {
 
    const U = this.graph.U();
 
    // if (patch && !patchContainsPreds(patch, [U("rdf:type")])) {
 
    //   return;
 
    // }
 

	
 
    this.devices = [];
 
    let classes = this.graph.subjects(U("rdf:type"), U(":DeviceClass"));
 
    log(`found ${classes.length} device classes`);
 
    uniq(sortBy(classes, "value"), true).forEach((dc) => {
 
      sortBy(this.graph.subjects(U("rdf:type"), dc), "value").forEach((dev) => {
 
        log(`found dev ${dev.value}`);
 
        this.devices.push(dev as NamedNode);
 
      });
 
    });
 
    this.requestUpdate();
 
  }
 

	
 
  setEffectFromUrl() {
 
    // not a continuous bidi link between url and effect; it only reads
 
    // the url when the page loads.
 
    const effect = new URL(window.location.href).searchParams.get("effect");
 
    if (effect != null) {
 
      log(`found effect in url ${effect}`);
 
      this.currentEffect = new Effect(this.graph, this.graph.Uri(effect));
 
    }
 
    this.okToWriteUrl = true;
 
  }
 

	
 
  writeToUrl(effect: NamedNode | undefined) {
 
@@ -145,64 +140,11 @@ export class Light9DeviceSettings extend
 
  }
 

	
 
  newEffect() {
 
    // this.effectChoice = this.graphToControls.newEffect();
 
  }
 

	
 
  onEffectChoice() {
 
    const U = (x: any) => this.graph.Uri(x);
 
    // if (this.effectChoice == null) {
 
    //   // unlink
 
    //   log("onEffectChoice unlink");
 
    //   if (this.graphToControls != null) {
 
    //     this.graphToControls.setEffect(null);
 
    //   }
 
    // } else {
 
    //   if (this.graphToControls != null) {
 
    //     this.graphToControls.setEffect(this.effectChoice);
 
    //   } else {
 
    //     throw new Error("graphToControls not set");
 
    //   }
 
    // }
 
    this.writeToUrl(this.currentEffect?.uri);
 
  }
 

	
 
  clearAll() {
 
    // clears the effect!
 
    return; //this.graphToControls.emptyEffect();
 
  }
 

	
 
  // configureFromGraph() {
 
  //   const U = (x: string) => this.graph.Uri(x);
 

	
 
  //   const newDevs: NamedNode[] = [];
 
  //   for (let dc of Array.from(this.graph.sortedUris(this.graph.subjects(U("rdf:type"), U(":DeviceClass"))))) {
 
  //     for (let dev of Array.from(this.graph.sortedUris(this.graph.subjects(U("rdf:type"), dc)))) {
 
  //       if (this.graph.contains(dev, U(":hideInLiveUi"), null)) {
 
  //         continue;
 
  //       }
 
  //       if (newDevs.length == 0) newDevs.push(dev);
 
  //     }
 
  //   }
 
  //   log("is this called?");
 
  //   log(`controls update now has ${newDevs.length} devices`);
 
  //   this.devices = newDevs;
 
  //   this.requestUpdate();
 

	
 
  //   return;
 

	
 
  //   // Tried css columns- big slowdown from relayout as I'm scrolling.
 
  //   // Tried isotope- seems to only scroll to the right.
 
  //   // Tried columnize- fails in jquery maybe from weird elements.
 

	
 
  //   // not sure how to get this run after the children are created
 
  //   return setTimeout(
 
  //     () =>
 
  //       $("#deviceControls").isotope({
 
  //         // fitColumns would be nice, but it doesn't scroll vertically
 
  //         layoutMode: "masonry",
 
  //         containerStyle: null,
 
  //       }),
 
  //     2000
 
  //   );
 
  // }
 
}
0 comments (0 inline, 0 general)