uiProperty
This commit is contained in:
parent
b92c439f07
commit
152a76af5e
116
js/src/ui.js
116
js/src/ui.js
|
@ -63,6 +63,9 @@ var uiFragmentExists = Struct.makeConstructor('ui-fragment-exists', ['fragmentId
|
||||||
// already present. (See the implementation for details.)
|
// already present. (See the implementation for details.)
|
||||||
var uiAttribute = Struct.makeConstructor('ui-attribute', ['selector', 'attribute', 'value']);
|
var uiAttribute = Struct.makeConstructor('ui-attribute', ['selector', 'attribute', 'value']);
|
||||||
|
|
||||||
|
// Assertion. Similar to uiAttribute, but for properties of DOM nodes.
|
||||||
|
var uiProperty = Struct.makeConstructor('ui-property', ['selector', 'property', 'value']);
|
||||||
|
|
||||||
// Messages.
|
// Messages.
|
||||||
// NOTE: These do not treat "class" specially!
|
// NOTE: These do not treat "class" specially!
|
||||||
var setAttribute = Struct.makeConstructor('set-ui-attribute', ['selector', 'attribute', 'value']);
|
var setAttribute = Struct.makeConstructor('set-ui-attribute', ['selector', 'attribute', 'value']);
|
||||||
|
@ -120,7 +123,16 @@ function spawnUIDriver(options) {
|
||||||
new DemandMatcher([uiAttribute(_$('selector'), _$('attribute'), _$('value'))],
|
new DemandMatcher([uiAttribute(_$('selector'), _$('attribute'), _$('value'))],
|
||||||
[Patch.advertise(uiAttribute(_$('selector'), _$('attribute'), _$('value')))],
|
[Patch.advertise(uiAttribute(_$('selector'), _$('attribute'), _$('value')))],
|
||||||
function (c) {
|
function (c) {
|
||||||
Dataspace.spawn(new UIAttribute(c.selector, c.attribute, c.value));
|
Dataspace.spawn(new UIAttribute(
|
||||||
|
c.selector, c.attribute, c.value, 'attribute'));
|
||||||
|
}));
|
||||||
|
|
||||||
|
Dataspace.spawn(
|
||||||
|
new DemandMatcher([uiProperty(_$('selector'), _$('property'), _$('value'))],
|
||||||
|
[Patch.advertise(uiProperty(_$('selector'), _$('property'), _$('value')))],
|
||||||
|
function (c) {
|
||||||
|
Dataspace.spawn(new UIAttribute(
|
||||||
|
c.selector, c.property, c.value, 'property'));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Dataspace.spawn(new AttributeUpdater());
|
Dataspace.spawn(new AttributeUpdater());
|
||||||
|
@ -430,24 +442,31 @@ UIFragment.prototype.handleDomEvent = function (c, e) {
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
function UIAttribute(selector, attribute, value) {
|
function UIAttribute(selector, key, value, kind) {
|
||||||
|
if (['attribute', 'property'].indexOf(kind) === -1) {
|
||||||
|
throw new Error("UIAttribute: kind must be 'attribute' or 'property'; got " + kind);
|
||||||
|
}
|
||||||
|
|
||||||
this.selector = selector;
|
this.selector = selector;
|
||||||
this.attribute = attribute;
|
this.key = key;
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
this.kind = kind;
|
||||||
|
|
||||||
this.savedValues = [];
|
this.savedValues = [];
|
||||||
// ^ Array of {node: DOMNode, value: (U Null String)}, when attribute !== 'class'.
|
// ^ Array of {node: DOMNode, value: (U Null String)},
|
||||||
// ^ Array of {node: DOMNode}, when attribute === 'class'.
|
// when attribute !== 'class' or kind !== 'attribute'.
|
||||||
|
// ^ Array of {node: DOMNode},
|
||||||
|
// when attribute === 'class' and kind === 'attribute'.
|
||||||
}
|
}
|
||||||
|
|
||||||
UIAttribute.prototype.boot = function () {
|
UIAttribute.prototype.boot = function () {
|
||||||
var a = uiAttribute(this.selector, this.attribute, this.value);
|
var a = ((this.kind === 'attribute') ? uiAttribute : uiProperty)(this.selector, this.key, this.value);
|
||||||
this.install();
|
this.install();
|
||||||
return Patch.sub(a).andThen(Patch.pub(a));
|
return Patch.sub(a).andThen(Patch.pub(a));
|
||||||
};
|
};
|
||||||
|
|
||||||
UIAttribute.prototype.trapexit = function () {
|
UIAttribute.prototype.trapexit = function () {
|
||||||
console.log('UIAttribute trapexit running', this.selector, this.attribute, this.value);
|
console.log('UIAttribute trapexit running', this.selector, this.key, this.value, this.kind);
|
||||||
this.restoreSavedValues();
|
this.restoreSavedValues();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -458,20 +477,27 @@ function splitClassValue(v) {
|
||||||
|
|
||||||
UIAttribute.prototype.install = function () {
|
UIAttribute.prototype.install = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
var nodes = Array.prototype.slice.call(document.querySelectorAll(self.selector));
|
selectorMatch(document, self.selector).forEach(function (node) {
|
||||||
|
switch (self.kind) {
|
||||||
nodes.forEach(function (node) {
|
case 'attribute':
|
||||||
if (self.attribute === 'class') {
|
if (self.key === 'class') {
|
||||||
// Deliberately maintains duplicates, so we don't interfere with
|
// Deliberately maintains duplicates, so we don't interfere
|
||||||
// potential other UIAttribute instances on the same objects for
|
// with potential other UIAttribute instances on the same
|
||||||
// the same attribute. See also restoreSavedValues.
|
// objects for the same attribute. See also
|
||||||
var existing = splitClassValue(node.getAttribute('class'));
|
// restoreSavedValues.
|
||||||
var toAdd = splitClassValue(self.value);
|
var existing = splitClassValue(node.getAttribute('class'));
|
||||||
self.savedValues.push({node: node});
|
var toAdd = splitClassValue(self.value);
|
||||||
node.setAttribute('class', existing.concat(toAdd).join(' '));
|
self.savedValues.push({node: node});
|
||||||
} else {
|
node.setAttribute('class', existing.concat(toAdd).join(' '));
|
||||||
self.savedValues.push({node: node, value: node.getAttribute(self.attribute)});
|
} else {
|
||||||
node.setAttribute(self.attribute, self.value);
|
self.savedValues.push({node: node, value: node.getAttribute(self.key)});
|
||||||
|
node.setAttribute(self.key, self.value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'property':
|
||||||
|
self.savedValues.push({node: node, value: node[self.key]});
|
||||||
|
node[self.key] = self.value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -479,24 +505,35 @@ UIAttribute.prototype.install = function () {
|
||||||
UIAttribute.prototype.restoreSavedValues = function () {
|
UIAttribute.prototype.restoreSavedValues = function () {
|
||||||
var self = this;
|
var self = this;
|
||||||
self.savedValues.forEach(function (entry) {
|
self.savedValues.forEach(function (entry) {
|
||||||
if (self.attribute === 'class') {
|
switch (self.kind) {
|
||||||
var existing = splitClassValue(entry.node.getAttribute('class'));
|
case 'attribute':
|
||||||
var toRemove = splitClassValue(self.value);
|
if (self.key === 'class') {
|
||||||
toRemove.forEach(function (v) {
|
var existing = splitClassValue(entry.node.getAttribute('class'));
|
||||||
var i = existing.indexOf(v);
|
var toRemove = splitClassValue(self.value);
|
||||||
if (i !== -1) { existing.splice(i, 1); }
|
toRemove.forEach(function (v) {
|
||||||
});
|
var i = existing.indexOf(v);
|
||||||
if (existing.length === 0) {
|
if (i !== -1) { existing.splice(i, 1); }
|
||||||
entry.node.removeAttribute('class');
|
});
|
||||||
} else {
|
if (existing.length === 0) {
|
||||||
entry.node.setAttribute('class', existing.join(' '));
|
entry.node.removeAttribute('class');
|
||||||
}
|
} else {
|
||||||
} else {
|
entry.node.setAttribute('class', existing.join(' '));
|
||||||
if (entry.value === null) {
|
}
|
||||||
entry.node.removeAttribute(self.attribute);
|
} else {
|
||||||
} else {
|
if (entry.value === null) {
|
||||||
entry.node.setAttribute(self.attribute, entry.value);
|
entry.node.removeAttribute(self.key);
|
||||||
}
|
} else {
|
||||||
|
entry.node.setAttribute(self.key, entry.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'property':
|
||||||
|
if (typeof entry.value === 'undefined') {
|
||||||
|
delete entry.node[self.key];
|
||||||
|
} else {
|
||||||
|
entry.node[self.key] = entry.value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
self.savedValues = [];
|
self.savedValues = [];
|
||||||
|
@ -683,6 +720,7 @@ module.exports.uiEvent = uiEvent;
|
||||||
module.exports.uiFragment = uiFragment;
|
module.exports.uiFragment = uiFragment;
|
||||||
module.exports.uiFragmentExists = uiFragmentExists;
|
module.exports.uiFragmentExists = uiFragmentExists;
|
||||||
module.exports.uiAttribute = uiAttribute;
|
module.exports.uiAttribute = uiAttribute;
|
||||||
|
module.exports.uiProperty = uiProperty;
|
||||||
module.exports.setAttribute = setAttribute;
|
module.exports.setAttribute = setAttribute;
|
||||||
module.exports.removeAttribute = removeAttribute;
|
module.exports.removeAttribute = removeAttribute;
|
||||||
module.exports.setProperty = setProperty;
|
module.exports.setProperty = setProperty;
|
||||||
|
|
Loading…
Reference in New Issue