diff --git a/light9/web/live/GraphToControls.ts b/light9/web/live/GraphToControls.ts
--- a/light9/web/live/GraphToControls.ts
+++ b/light9/web/live/GraphToControls.ts
@@ -67,12 +67,12 @@ export class GraphToControls {
return this.graph.Uri(effect.value.replace("light9.bigasterisk.com/effect", "light9.bigasterisk.com/show/dance2019/effect"));
}
- setEffect(effect: NamedNode) {
+ setEffect(effect: NamedNode | null) {
this.clearSettings();
this.effect = effect;
- this.ctx = this.ctxForEffect(effect);
+ this.ctx = !effect ? null : this.ctxForEffect(effect);
// are these going to pile up? consider @graph.triggerHandler('GTC sync')
- return this.graph.runHandler(this.syncFromGraph.bind(this), "GraphToControls sync");
+ this.graph.runHandler(this.syncFromGraph.bind(this), "GraphToControls sync");
}
newEffect() {
diff --git a/light9/web/live/Light9LiveDeviceControl.ts b/light9/web/live/Light9DeviceControl.ts
rename from light9/web/live/Light9LiveDeviceControl.ts
rename to light9/web/live/Light9DeviceControl.ts
--- a/light9/web/live/Light9LiveDeviceControl.ts
+++ b/light9/web/live/Light9DeviceControl.ts
@@ -1,10 +1,34 @@
import debug from "debug";
-const log = debug("devcontrol");
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
+import { NamedNode } from "n3";
+import { unique } from "underscore";
+import { Patch, patchContainsPreds } from "../patch";
+import { getTopGraph } from "../RdfdbSyncedGraph";
+import { SyncedGraph } from "../SyncedGraph";
+import { GraphToControls } from "./GraphToControls";
+import { Choice } from "./Light9Listbox";
+import { Light9LiveControl } from "./Light9LiveControl";
+export { ResourceDisplay } from "../ResourceDisplay";
+export { Light9LiveControl };
+const log = debug("devcontrol");
+
+interface DeviceAttrRow {
+ uri: NamedNode; //devattr
+ attrClasses: string; // the css kind
+ dataType: NamedNode;
+ showColorPicker: boolean;
+ useColor: boolean;
+ useChoice: boolean;
+ choices: Choice[];
+ choiceSize: number;
+ useSlider: boolean;
+ max: number;
+}
@customElement("light9-device-control")
export class Light9DeviceControl extends LitElement {
+ graph!: SyncedGraph;
static styles = [
css`
:host {
@@ -55,100 +79,86 @@ export class Light9DeviceControl extends
render() {
return html`
-
-
-
- a
+
+
+
+ a
-
-
- attr
-
-
-
+ ${this.deviceAttrs.map(
+ (dattr: DeviceAttrRow) => html`
+
+ attr
+
+
+ `
+ )}
`;
}
- static getter_properties: {
- graph: { type: any; notify: boolean; }; uri: { type: any; notify: boolean; }; effect: { type: any; }; deviceClass: { type: any; notify: boolean; }; // the uri str
- deviceAttrs: { type: any; notify: boolean; }; graphToControls: { ...; }; bgStyle: { ...; }; devClasses: { ...; }; // the css kind
- };
- selectedAttrs: any;
- graph: any;
- uri: any;
- devClasses: string;
- deviceClass: any;
- deviceAttrs: {};
- shadowRoot: any;
- static initClass() {
- this.getter_properties = {
- graph: { type: Object, notify: true },
- uri: { type: String, notify: true },
- effect: { type: String },
- deviceClass: { type: String, notify: true }, // the uri str
- deviceAttrs: { type: Array, notify: true },
- graphToControls: { type: Object },
- bgStyle: { type: String, computed: "_bgStyle(deviceClass)" },
- devClasses: { type: String, value: "" }, // the css kind
- };
- this.getter_observers = ["onGraph(graph)"];
- }
+ @property() uri!: NamedNode;
+ @property() effect!: NamedNode;
+ @property() graphToControls!: GraphToControls;
+
+ @property() devClasses: string = ""; // the css kind
+ @property() deviceAttrs: DeviceAttrRow[] = [];
+ @property() deviceClass: NamedNode | null = null;
+ @property() selectedAttrs: Set = new Set();
+
constructor() {
super();
+ getTopGraph().then((g) => {
+ this.graph = g;
+ this.graph.runHandler(this.configureFromGraphz.bind(this), `${this.uri.value} update`);
+ });
this.selectedAttrs = new Set(); // uri strings
}
- _bgStyle(deviceClass: { value: any; length: number; charCodeAt: (arg0: number) => number }) {
+
+ _bgStyle(deviceClass: NamedNode | null): string {
+ if (!deviceClass) return "";
let hash = 0;
- deviceClass = deviceClass.value;
- for (let start = deviceClass.length - 10, i = start, end = deviceClass.length, asc = start <= end; asc ? i < end : i > end; asc ? i++ : i--) {
- hash += deviceClass.charCodeAt(i);
+ const u = deviceClass.value;
+ for (let i = u.length - 10; i < u.length; i++) {
+ hash += u.charCodeAt(i);
}
const hue = (hash * 8) % 360;
const accent = `hsl(${hue}, 49%, 22%)`;
return `background: linear-gradient(to right, rgba(31,31,31,0) 50%, ${accent} 100%);`;
}
- onGraph() {
- return this.graph.runHandler(this.update.bind(this), `${this.uri.value} update`);
+ setDeviceSelected(isSel: any) {
+ this.devClasses = isSel ? "selected" : "";
}
- setDeviceSelected(isSel: any) {
- return (this.devClasses = isSel ? "selected" : "");
- }
-
- setAttrSelected(devAttr: { value: any }, isSel: any) {
+ setAttrSelected(devAttr: NamedNode, isSel: boolean) {
if (isSel) {
this.selectedAttrs.add(devAttr.value);
} else {
this.selectedAttrs.delete(devAttr.value);
}
- return this.update();
+ return this.configureFromGraphz();
}
- update(patch: null) {
- const U = (x: string) => this.graph.Uri(x);
- if (patch != null && !SyncedGraph.patchContainsPreds(patch, [U("rdf:type"), U(":deviceAttr"), U(":dataType"), U(":choice")])) {
+ configureFromGraphz(patch?: Patch) {
+ const U = this.graph.U();
+ if (patch != null && !patchContainsPreds(patch, [U("rdf:type"), U(":deviceAttr"), U(":dataType"), U(":choice")])) {
return;
}
this.deviceClass = this.graph.uriValue(this.uri, U("rdf:type"));
this.deviceAttrs = [];
- return Array.from(_.unique(this.graph.sortedUris(this.graph.objects(this.deviceClass, U(":deviceAttr"))))).map((da: any) =>
- this.push("deviceAttrs", this.attrRow(da))
+ Array.from(unique(this.graph.sortedUris(this.graph.objects(this.deviceClass, U(":deviceAttr"))))).map((da: NamedNode) =>
+ this.deviceAttrs.push(this.attrRow(da))
);
- }
- push(arg0: string, arg1: { uri: { value: any }; dataType: any; showColorPicker: any; attrClasses: string }) {
- throw new Error("Method not implemented.");
+ this.requestUpdate();
}
- attrRow(devAttr: { value: any }) {
- let x: { value: any };
+ attrRow(devAttr: NamedNode): DeviceAttrRow {
+ let x: NamedNode;
const U = (x: string) => this.graph.Uri(x);
const dataType = this.graph.uriValue(devAttr, U(":dataType"));
const daRow = {
@@ -156,6 +166,12 @@ export class Light9DeviceControl extends
dataType,
showColorPicker: dataType.equals(U(":color")),
attrClasses: this.selectedAttrs.has(devAttr.value) ? "selected" : "",
+ useColor: false,
+ useChoice: false,
+ choices: [] as Choice[],
+ choiceSize: 0,
+ useSlider: false,
+ max: 1,
};
if (dataType.equals(U(":color"))) {
daRow.useColor = true;
@@ -182,16 +198,16 @@ export class Light9DeviceControl extends
}
clear() {
- return Array.from(this.shadowRoot.querySelectorAll("light9-live-control")).map((lc: { clear: () => any }) => lc.clear());
+ Array.from(this.shadowRoot!.querySelectorAll("light9-live-control")).map((lc: Element) => (lc as Light9LiveControl).clear());
}
onClick(ev: any) {
- return log("click", this.uri);
+ log("click", this.uri);
+ // select, etc
}
- // select, etc
onAttrClick(ev: { model: { dattr: { uri: any } } }) {
- return log("attr click", this.uri, ev.model.dattr.uri);
+ log("attr click", this.uri, ev.model.dattr.uri);
+ // select
}
}
-// select
diff --git a/light9/web/live/Light9Listbox.ts b/light9/web/live/Light9Listbox.ts
--- a/light9/web/live/Light9Listbox.ts
+++ b/light9/web/live/Light9Listbox.ts
@@ -1,8 +1,8 @@
import debug from "debug";
const log = debug("listbox");
-import { css, html, LitElement } from "lit";
+import { css, html, LitElement, PropertyValues } from "lit";
import { customElement, property } from "lit/decorators.js";
-
+export type Choice = {uri:string,label:string}
@customElement("light9-listbox")
export class Light9Listbox extends LitElement {
static styles = [
@@ -40,11 +40,12 @@ export class Light9Listbox extends LitEl
`;
}
- properties: {
- choices: { type: Array };
- value: { type: String; notify: true };
- };
- observers: ["onValue(value)"];
+ @property() choices: Array = [];
+ @property() value: String | null = null;
+
+ constructor() {
+ super();
+ }
selectOnFocus(ev) {
if (ev.target.uri === undefined) {
// *don't* clear for this, or we can't cycle through all choices (including none) with up/down keys
@@ -53,19 +54,22 @@ export class Light9Listbox extends LitEl
}
this.value = ev.target.uri;
}
- onValue(value) {
+ updated(changedProperties: PropertyValues) {
+ if (changedProperties.has("value")) {
+ if (this.value === null) {
+ this.clear();
+ }
+ }
+ }
+ onValue(value: String | null) {
if (value === null) {
this.clear();
}
}
clear() {
- this.async(
- function () {
- this.querySelectorAll("paper-item").forEach(function (item) {
- item.blur();
- });
- this.value = undefined;
- }.bind(this)
- );
+ this.querySelectorAll("paper-item").forEach(function (item) {
+ item.blur();
+ });
+ this.value = null;
}
}
diff --git a/light9/web/live/Light9LiveControl.ts b/light9/web/live/Light9LiveControl.ts
--- a/light9/web/live/Light9LiveControl.ts
+++ b/light9/web/live/Light9LiveControl.ts
@@ -2,9 +2,12 @@ import debug from "debug";
const log = debug("control");
import { css, html, LitElement } from "lit";
import { customElement, property } from "lit/decorators.js";
+import { SyncedGraph } from "../SyncedGraph";
@customElement("light9-live-control")
export class Light9LiveControl extends LitElement {
+ graph!:SyncedGraph
+
static styles = [
css`
#colorControls {
@@ -61,41 +64,38 @@ export class Light9LiveControl extends L
`;
}
- graph: { type: any; notify: boolean; }
- device: { type: any; };
- deviceAttrRow: { type: any; }; // object returned from attrRow, below
- value: { type: any; notify: boolean; }; // null, Uri, float, str
- choiceValue: { type: any; };
- immediateSlider: { notify: boolean; observer: string; };
- sliderWriteValue: { ...; };
- pickedChoice: { ...; };
- graphToControls: { ...; };
+
+
- enableChange: boolean;
- value: any;
- immediateSlider: any;
- deviceAttrRow: any;
- sliderWriteValue: { value: any; };
- choiceValue: any;
- graphToControls: any;
- graph: any;
- pickedChoice: any;
- static initClass() {
- this.getter_properties = {
- graph: { type: Object, notify: true },
- device: { type: Object },
- deviceAttrRow: { type: Object }, // object returned from attrRow, below
- value: { type: Object, notify: true }, // null, Uri, float, str
- choiceValue: { type: Object },
-
- immediateSlider: { notify: true, observer: "onSlider" },
- sliderWriteValue: { type: Number },
-
- pickedChoice: { observer: "onChange" },
- graphToControls: { type: Object },
- };
- this.getter_observers = ["onChange(value)", "onGraphToControls(graphToControls)", "onChoice(choiceValue)"];
- }
+ // "onChange(value)",
+ // "onChoice(choiceValue)"];
+ // "onGraphToControls(graphToControls)",
+ // choiceValue: { type: any; };
+ // choiceValue: { type: Object },
+ // choiceValue: any;
+ // device: { type: any; };
+ // device: { type: Object },
+ // deviceAttrRow: { type: any; }; // object returned from attrRow, below
+ // deviceAttrRow: { type: Object }, // object returned from attrRow, below
+ // deviceAttrRow: any;
+ // enableChange: boolean;
+ // graph: { type: Object, notify: true },
+ // graphToControls: { ...; };
+ // graphToControls: { type: Object },
+ // graphToControls: any;
+ // immediateSlider: { notify: boolean; observer: string; };
+ // immediateSlider: { notify: true, observer: "onSlider" },
+ // immediateSlider: any;
+ // pickedChoice: { ...; };
+ // pickedChoice: { observer: "onChange" },
+ // pickedChoice: any;
+ // sliderWriteValue: { ...; };
+ // sliderWriteValue: { type: Number },
+ // sliderWriteValue: { value: any; };
+ // value: { type: any; notify: boolean; }; // null, Uri, float, str
+ // value: { type: Object, notify: true }, // null, Uri, float, str
+ // value: any;
+
constructor() {
super();
this.enableChange = false; // until 1st graph read
diff --git a/light9/web/live/Light9LiveControls.ts b/light9/web/live/Light9LiveControls.ts
--- a/light9/web/live/Light9LiveControls.ts
+++ b/light9/web/live/Light9LiveControls.ts
@@ -1,11 +1,20 @@
import debug from "debug";
-const log = debug("controls");
import { css, html, LitElement } from "lit";
-import { customElement, property } from "lit/decorators.js";
+import { customElement } from "lit/decorators.js";
+import { NamedNode } from "n3";
+import { sortBy, uniq } from "underscore";
+import { Patch } from "../patch";
+import { getTopGraph } from "../RdfdbSyncedGraph";
+import { SyncedGraph } from "../SyncedGraph";
import { GraphToControls } from "./GraphToControls";
+export { Light9DeviceControl as Light9LiveDeviceControl } from "./Light9DeviceControl";
+
+const log = debug("controls");
@customElement("light9-live-controls")
export class Light9LiveControls extends LitElement {
+ graph!: SyncedGraph;
+
static styles = [
css`
:host {
@@ -32,85 +41,67 @@ export class Light9LiveControls extends
render() {
return html`
-
+
device control
-
+
-
-
-
+ ${this.devices.map(
+ (device: NamedNode) => html`
+
+ `
+ )}
`;
}
- static getter_properties: {
- graph: { type: any; notify: boolean };
- devices: { type: any; notify: boolean; value: {} };
- // string uri of the effect being edited, or null. This is the
- // master value; GraphToControls follows.
- effectChoice: { type: any; notify: boolean; value: any };
- graphToControls: { type: any };
- };
- static getter_observers: {};
- graphToControls: any;
- okToWriteUrl: boolean;
- currentSettings: {};
- graph: any;
- effectChoice: any;
- static initClass() {
- this.getter_properties = {
- graph: { type: Object, notify: true },
- devices: { type: Array, notify: true, value: [] },
- // string uri of the effect being edited, or null. This is the
- // master value; GraphToControls follows.
- effectChoice: { type: String, notify: true, value: null },
- graphToControls: { type: Object },
- };
- this.getter_observers = ["onGraph(graph)", "onEffectChoice(effectChoice)"];
- }
+ devices: Array = [];
+ // uri of the effect being edited, or null. This is the
+ // master value; GraphToControls follows.
+ effectChoice: NamedNode | null = null;
+ graphToControls!: GraphToControls;
+ okToWriteUrl: boolean = false;
constructor() {
super();
- this.graphToControls = null;
- this.okToWriteUrl = false;
- }
-
- ready() {
- super.ready(...arguments).ready();
- return (this.currentSettings = {});
+ getTopGraph().then((g) => {
+ this.graph = g;
+ this.graph.runHandler(this.findDevices.bind(this), "findDevices");
+ this.graphToControls = new GraphToControls(this.graph);
+ // this.graph.runHandler(this.xupdate.bind(this), "Light9LiveControls update");
+ this.setEffectFromUrl.bind(this);
+ });
}
- onGraph() {
- this.graphToControls = new GraphToControls(this.graph);
- this.graph.runHandler(this.update.bind(this), "Light9LiveControls update");
+ findDevices(patch?: Patch) {
+ const U = this.graph.U();
- // need graph to be loaded, so we don't make double settings? not sure.
- return setTimeout(this.setFromUrl.bind(this), 1);
+ this.devices = [];
+ let classes = this.graph.subjects(U("rdf:type"), U(":DeviceClass"));
+ uniq(sortBy(classes, "value"), true).forEach((dc) => {
+ sortBy(this.graph.subjects(U("rdf:type"), dc), "value").forEach((dev) => {
+ this.devices.push(dev as NamedNode);
+ });
+ });
+ this.requestUpdate();
}
-
- setFromUrl() {
+ 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 url", effect);
- this.effectChoice = effect;
+ this.effectChoice = this.graph.Uri(effect);
}
- return (this.okToWriteUrl = true);
+ this.okToWriteUrl = true;
}
writeToUrl(effectStr: any) {
@@ -140,7 +131,7 @@ export class Light9LiveControls extends
} else {
log("load", this.effectChoice);
if (this.graphToControls != null) {
- this.graphToControls.setEffect(this.graph.Uri(this.effectChoice));
+ this.graphToControls.setEffect(this.effectChoice);
}
}
return this.writeToUrl(this.effectChoice);
@@ -151,7 +142,7 @@ export class Light9LiveControls extends
return this.graphToControls.emptyEffect();
}
- update() {
+ configureFromGraph() {
const U = (x: string) => this.graph.Uri(x);
const newDevs = [];
diff --git a/light9/web/live/index.html b/light9/web/live/index.html
--- a/light9/web/live/index.html
+++ b/light9/web/live/index.html
@@ -3,7 +3,8 @@
device control
-
+
+