Skip to content

Commit

Permalink
element property definition is a function it is a read-only signal ge…
Browse files Browse the repository at this point in the history
…tter
  • Loading branch information
stephband committed Jul 26, 2024
1 parent 5e0e1e4 commit d8c6c41
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 38 deletions.
2 changes: 1 addition & 1 deletion element/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ definitions.
- `"boolean"` - defines a boolean attribute and a boolean property
- `"number"` - defines a string attribute and a number property
- `"string"` - defines a string attribute and string property
- `"tokens"` - defines a tokens attribute and a TokenList property
- `"tokens"` - defines a tokens attribute (think `class`) and a string setter / TokenList getter property
- `"src"` - defines a URL attribute that links to a data property (TODO)
- `"module"` - defines a URL attribute that ... (TODO)

Expand Down
17 changes: 14 additions & 3 deletions element/property.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const resolveAndAssign = function(signal, value) {
}
};

const symbols = {};

const types = {
attribute: (name, symbol) => ({
construct: function() { define(this, symbol, { value: Signal.of('') }); },
Expand Down Expand Up @@ -112,19 +114,28 @@ const types = {
};

export default overload((name, descriptor) => typeof descriptor, {
// Where descriptor is a function return a getter property that reads from
// a compute signal of fn, where fn is nonetheless called with context set
// to the object
function: (name, fn) => {
const camelcase = toCamelCase(name);
return fn(camelcase);
const symbol = symbols[camelcase] || (symbols[camelcase] = Symbol(camelcase));
return {
construct: function() { define(this, symbol, { value: Signal.from(fn, this) }); },
get: function() { return this[symbol].value; }
};
},

// Where descriptor is a descriptor object pass it straight back
// Where descriptor is a descriptor object pass it straight back. Whoever
// did this is expected to implement their own observers if needed.
object: arg(1),

// Where descriptor is a string return a descriptor object of that type
string: (name, descriptor) => {
const camelcase = toCamelCase(name);
const symbol = symbols[camelcase] || (symbols[camelcase] = Symbol(camelcase));
if (!types[descriptor]) throw new Error('element() property descriptor "' + descriptor + '" not supported');
return types[descriptor](camelcase, Symbol(camelcase));
return types[descriptor](camelcase, symbol);
}

// Where descriptor is undefined assume it is an attribute
Expand Down
12 changes: 7 additions & 5 deletions modules/compile/compile-attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ const assign = Object.assign;
compileAttributes(array, element, attribute, path, options[, debug])
**/

export default function compileAttribute(array, element, attribute, path, options, debug) {
export default function compileAttribute(array, element, attribute, path, options, template) {
const source = attribute.value;
if (!isLiteralString(source)) { return; }

const name = attribute.localName;
const tag = element.tagName.toLowerCase();
const name = attribute.localName;
const tag = element.tagName.toLowerCase();

// TODO: custom elements need to be flagged as potentially upgradeable, and
// we shall have to devise a way of upgrading their renderers. The problem
Expand All @@ -49,7 +49,7 @@ export default function compileAttribute(array, element, attribute, path, option
AttributeRenderer ;

const params = Renderer.parameterNames.join(', ');
const target = { source, path, name, upgradeable, Renderer };
const target = { template, path, name, source, upgradeable, Renderer };

if (window.DEBUG) {
const code = truncate(64, '<'
Expand All @@ -58,7 +58,9 @@ export default function compileAttribute(array, element, attribute, path, option
+ '">') ;

// Fill target object with debug info
assign(target, debug, { tag, code, property });
target.tag = tag;
target.code = code;
target.property = property;

// Attempt to compile, and in case of an error replace element with
// an error element
Expand Down
13 changes: 8 additions & 5 deletions modules/compile/compile-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,17 @@ const compileNode = overload((targets, node) => toType(node), {
return targets;
},

'text': (targets, node, path, options, debug) => {
'text': (targets, node, path, options, template) => {
const string = node.nodeValue;
if (!isLiteralString(string)) return targets;

const source = decode(string);
const target = {
source,
template,
path,
name: indexOf(node)
name: indexOf(node),
source,
Renderer: TextRenderer
};

if (window.DEBUG) {
Expand All @@ -149,8 +151,9 @@ const compileNode = overload((targets, node) => toType(node), {
source.trim()
);

// Fill target object with debug info
assign(target, debug, { tag, code });
// Add target object with debug info
target.tag = tag;
target.code = code;

// Attempt to compile, and in case of an error replace node with
// an error element
Expand Down
28 changes: 4 additions & 24 deletions modules/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,6 @@ function getElement(path, node) {
.reduce(getChild, node) ;
}

function compileFragment(id, fragment, options) {
//const content = template.content || create('fragment', template.childNodes, template) ;

let targets;
if (window.DEBUG) {
groupCollapsed('compile', '#' + id, 'yellow');
targets = compileNode(fragment, options, { template: '#' + id });
groupEnd();
}
else {
targets = compileNode(fragment, options);
}

return { id, fragment, targets };
}

function removeRange(first, last, fragment) {
if (window.DEBUG && first.parentNode !== last.parentNode) {
throw new Error('first and last not children of same parent')
Expand Down Expand Up @@ -266,12 +250,12 @@ export default class LiteralRenderer extends LiteralDOM {
return new LiteralRenderer(template);
}

static compile(fragment, options, debug) {
static compile(fragment, options, src) {
let targets;

if (window.DEBUG) {
groupCollapsed('compile', debug.template, 'yellow');
targets = compileNode(fragment, options, debug);
groupCollapsed('compile', src, 'yellow');
targets = compileNode(fragment, options, src);
groupEnd();
}
else {
Expand All @@ -287,12 +271,8 @@ export default class LiteralRenderer extends LiteralDOM {
nostrict: template.hasAttribute && template.hasAttribute('nostrict')
});

const debug = window.DEBUG && {
template: '#' + id
};

const compiled = cache[id]
|| (cache[id] = LiteralRenderer.compile(template.content, options, debug));
|| (cache[id] = LiteralRenderer.compile(template.content, options, '#' + id));

super(template.content.cloneNode(true), compiled, parent, parameters, data, options);
}
Expand Down

0 comments on commit d8c6c41

Please sign in to comment.