@riotjs/dom-bindings
Advanced tools
Comparing version 4.3.0 to 4.4.0
/** | ||
* Convert a string from camel case to dash-case | ||
* @param {string} string - probably a component tag name | ||
* @returns {string} component name normalized | ||
*/ | ||
/** | ||
* Convert a string containing dashes to camel case | ||
* @param {string} string - input string | ||
* @returns {string} my-string -> myString | ||
*/ | ||
function dashToCamelCase(string) { | ||
return string.replace(/-(\w)/g, (_, c) => c.toUpperCase()) | ||
} | ||
/** | ||
* Move all the child nodes from a source tag to another | ||
* @param {HTMLElement} source - source node | ||
* @param {HTMLElement} target - target node | ||
* @returns {undefined} it's a void method ¯\_(ツ)_/¯ | ||
*/ | ||
// Ignore this helper because it's needed only for svg tags | ||
function moveChildren(source, target) { | ||
if (source.firstChild) { | ||
target.appendChild(source.firstChild); | ||
moveChildren(source, target); | ||
} | ||
} | ||
/** | ||
* Remove the child nodes from any DOM node | ||
@@ -33,2 +63,14 @@ * @param {HTMLElement} node - target node | ||
const ATTRIBUTE = 0; | ||
const EVENT = 1; | ||
const TEXT = 2; | ||
const VALUE = 3; | ||
var expressionTypes = { | ||
ATTRIBUTE, | ||
EVENT, | ||
TEXT, | ||
VALUE | ||
}; | ||
/** | ||
@@ -130,10 +172,4 @@ * Create the template meta object in case of <template> fragments | ||
const remove = (get, parent, children, start, end) => { | ||
if ((end - start) < 2) | ||
parent.removeChild(get(children[start], -1)); | ||
else { | ||
const range = parent.ownerDocument.createRange(); | ||
range.setStartBefore(get(children[start], -1)); | ||
range.setEndAfter(get(children[end - 1], -1)); | ||
range.deleteContents(); | ||
} | ||
while (start < end) | ||
removeChild(get(children[start++], -1), parent); | ||
}; | ||
@@ -429,2 +465,19 @@ | ||
let removeChild = (child, parentNode) => { | ||
/* istanbul ignore if */ | ||
if ('remove' in child) { | ||
removeChild = child => { | ||
child.remove(); | ||
}; | ||
} | ||
else { | ||
removeChild = (child, parentNode) => { | ||
/* istanbul ignore else */ | ||
if (child.parentNode === parentNode) | ||
parentNode.removeChild(child); | ||
}; | ||
} | ||
removeChild(child, parentNode); | ||
}; | ||
/*! (c) 2018 Andrea Giammarchi (ISC) */ | ||
@@ -647,11 +700,23 @@ | ||
/** | ||
* Check if a value is null or undefined | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the 'undefined' and 'null' types | ||
* Quick type checking | ||
* @param {*} element - anything | ||
* @param {string} type - type definition | ||
* @returns {boolean} true if the type corresponds | ||
*/ | ||
function isNil(value) { | ||
return value === null || value === undefined | ||
function checkType(element, type) { | ||
return typeof element === type | ||
} | ||
/** | ||
* Check if an element is part of an svg | ||
* @param {HTMLElement} el - element to check | ||
* @returns {boolean} true if we are in an svg context | ||
*/ | ||
function isSvg(el) { | ||
const owner = el.ownerSVGElement; | ||
return !!owner || owner === null | ||
} | ||
/** | ||
* Check if an element is a template tag | ||
@@ -665,2 +730,29 @@ * @param {HTMLElement} el - element to check | ||
/** | ||
* Check if a value is a Boolean | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the value is a boolean | ||
*/ | ||
function isBoolean(value) { | ||
return checkType(value, 'boolean') | ||
} | ||
/** | ||
* Check if a value is an Object | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the value is an object | ||
*/ | ||
function isObject(value) { | ||
return !isNil(value) && checkType(value, 'object') | ||
} | ||
/** | ||
* Check if a value is null or undefined | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the 'undefined' and 'null' types | ||
*/ | ||
function isNil(value) { | ||
return value === null || value === undefined | ||
} | ||
const EachBinding = Object.seal({ | ||
@@ -942,32 +1034,2 @@ // dynamic binding properties | ||
const ATTRIBUTE = 0; | ||
const EVENT = 1; | ||
const TEXT = 2; | ||
const VALUE = 3; | ||
var expressionTypes = { | ||
ATTRIBUTE, | ||
EVENT, | ||
TEXT, | ||
VALUE | ||
}; | ||
/** | ||
* Check if a value is a Boolean | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the value is a boolean | ||
*/ | ||
function isBoolean(value) { | ||
return typeof value === 'boolean' | ||
} | ||
/** | ||
* Check if a value is an Object | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the value is an object | ||
*/ | ||
function isObject(value) { | ||
return typeof value === 'object' | ||
} | ||
const REMOVE_ATTRIBUTE = 'removeAttribute'; | ||
@@ -1223,2 +1285,45 @@ const SET_ATTIBUTE = 'setAttribute'; | ||
/** | ||
* Evaluate a list of attribute expressions | ||
* @param {Array} attributes - attribute expressions generated by the riot compiler | ||
* @returns {Object} key value pairs with the result of the computation | ||
*/ | ||
function evaluateAttributeExpressions(attributes) { | ||
return attributes.reduce((acc, attribute) => { | ||
const {value, type} = attribute; | ||
switch (true) { | ||
// spread attribute | ||
case !attribute.name && type === ATTRIBUTE: | ||
return { | ||
...acc, | ||
...value | ||
} | ||
// value attribute | ||
case type === VALUE: | ||
acc.value = attribute.value; | ||
break | ||
// normal attributes | ||
default: | ||
acc[dashToCamelCase(attribute.name)] = attribute.value; | ||
} | ||
return acc | ||
}, {}) | ||
} | ||
function extendParentScope(attributes, scope, parentScope) { | ||
if (!attributes || !attributes.length) return parentScope | ||
const expressions = attributes.map(attr => ({ | ||
...attr, | ||
value: attr.evaluate(scope) | ||
})); | ||
return Object.assign( | ||
Object.create(parentScope || null), | ||
evaluateAttributeExpressions(expressions) | ||
) | ||
} | ||
const SlotBinding = Object.seal({ | ||
@@ -1228,4 +1333,9 @@ // dynamic binding properties | ||
name: null, | ||
attributes: [], | ||
template: null, | ||
getTemplateScope(scope, parentScope) { | ||
return extendParentScope(this.attributes, scope, parentScope) | ||
}, | ||
// API methods | ||
@@ -1242,3 +1352,3 @@ mount(scope, parentScope) { | ||
if (this.template) { | ||
this.template.mount(this.node, parentScope); | ||
this.template.mount(this.node, this.getTemplateScope(scope, parentScope)); | ||
moveSlotInnerContent(this.node); | ||
@@ -1252,4 +1362,4 @@ } | ||
update(scope, parentScope) { | ||
if (this.template && parentScope) { | ||
this.template.update(parentScope); | ||
if (this.template) { | ||
this.template.update(this.getTemplateScope(scope, parentScope)); | ||
} | ||
@@ -1261,3 +1371,3 @@ | ||
if (this.template) { | ||
this.template.unmount(parentScope, null, mustRemoveRoot); | ||
this.template.unmount(this.getTemplateScope(scope, parentScope), null, mustRemoveRoot); | ||
} | ||
@@ -1287,5 +1397,6 @@ | ||
*/ | ||
function createSlot(node, { name }) { | ||
function createSlot(node, { name, attributes }) { | ||
return { | ||
...SlotBinding, | ||
attributes, | ||
node, | ||
@@ -1408,8 +1519,23 @@ name | ||
/** | ||
* Text expressions in a template tag will get childNodeIndex value normalized | ||
* depending on the position of the <template> tag offset | ||
* @param {Expression[]} expressions - riot expressions array | ||
* @param {number} textExpressionsOffset - offset of the <template> tag | ||
* @returns {Expression[]} expressions containing the text expressions normalized | ||
*/ | ||
function fixTextExpressionsOffset(expressions, textExpressionsOffset) { | ||
return expressions.map(e => e.type === TEXT ? { | ||
...e, | ||
childNodeIndex: e.childNodeIndex + textExpressionsOffset | ||
} : e) | ||
} | ||
/** | ||
* Bind a new expression object to a DOM node | ||
* @param {HTMLElement} root - DOM node where to bind the expression | ||
* @param {Object} binding - binding data | ||
* @param {number|null} templateTagOffset - if it's defined we need to fix the text expressions childNodeIndex offset | ||
* @returns {Expression} Expression object | ||
*/ | ||
function create$5(root, binding) { | ||
function create$5(root, binding, templateTagOffset) { | ||
const { selector, type, redundantAttribute, expressions } = binding; | ||
@@ -1420,3 +1546,3 @@ // find the node to apply the bindings | ||
if (redundantAttribute) node.removeAttribute(redundantAttribute); | ||
const bindingExpressions = expressions || []; | ||
// init the binding | ||
@@ -1427,3 +1553,5 @@ return (bindings[type] || bindings[SIMPLE])( | ||
...binding, | ||
expressions: expressions || [] | ||
expressions: templateTagOffset && !selector ? | ||
fixTextExpressionsOffset(bindingExpressions, templateTagOffset) : | ||
bindingExpressions | ||
} | ||
@@ -1433,13 +1561,2 @@ ) | ||
/** | ||
* Check if an element is part of an svg | ||
* @param {HTMLElement} el - element to check | ||
* @returns {boolean} true if we are in an svg context | ||
*/ | ||
function isSvg(el) { | ||
const owner = el.ownerSVGElement; | ||
return !!owner || owner === null | ||
} | ||
// in this case a simple innerHTML is enough | ||
@@ -1481,18 +1598,2 @@ function createHTMLTree(html, root) { | ||
/** | ||
* Move all the child nodes from a source tag to another | ||
* @param {HTMLElement} source - source node | ||
* @param {HTMLElement} target - target node | ||
* @returns {undefined} it's a void method ¯\_(ツ)_/¯ | ||
*/ | ||
// Ignore this helper because it's needed only for svg tags | ||
/* istanbul ignore next */ | ||
function moveChildren(source, target) { | ||
if (source.firstChild) { | ||
target.appendChild(source.firstChild); | ||
moveChildren(source, target); | ||
} | ||
} | ||
/** | ||
* Inject the DOM tree into a target node | ||
@@ -1575,5 +1676,9 @@ * @param {HTMLElement} el - target element | ||
const {parentNode} = children ? children[0] : el; | ||
const isTemplateTag = isTemplate(el); | ||
const templateTagOffset = isTemplateTag ? Math.max( | ||
Array.from(parentNode.children).indexOf(el), | ||
0 | ||
) : null; | ||
this.isTemplateTag = isTemplateTag; | ||
this.isTemplateTag = isTemplate(el); | ||
// create the DOM if it wasn't created before | ||
@@ -1597,3 +1702,7 @@ this.createDOM(el); | ||
// create the bindings | ||
this.bindings = this.bindingsData.map(binding => create$5(this.el, binding)); | ||
this.bindings = this.bindingsData.map(binding => create$5( | ||
this.el, | ||
binding, | ||
templateTagOffset | ||
)); | ||
this.bindings.forEach(b => b.mount(scope, parentScope)); | ||
@@ -1600,0 +1709,0 @@ |
@@ -8,2 +8,32 @@ (function (global, factory) { | ||
/** | ||
* Convert a string from camel case to dash-case | ||
* @param {string} string - probably a component tag name | ||
* @returns {string} component name normalized | ||
*/ | ||
/** | ||
* Convert a string containing dashes to camel case | ||
* @param {string} string - input string | ||
* @returns {string} my-string -> myString | ||
*/ | ||
function dashToCamelCase(string) { | ||
return string.replace(/-(\w)/g, (_, c) => c.toUpperCase()) | ||
} | ||
/** | ||
* Move all the child nodes from a source tag to another | ||
* @param {HTMLElement} source - source node | ||
* @param {HTMLElement} target - target node | ||
* @returns {undefined} it's a void method ¯\_(ツ)_/¯ | ||
*/ | ||
// Ignore this helper because it's needed only for svg tags | ||
function moveChildren(source, target) { | ||
if (source.firstChild) { | ||
target.appendChild(source.firstChild); | ||
moveChildren(source, target); | ||
} | ||
} | ||
/** | ||
* Remove the child nodes from any DOM node | ||
@@ -40,2 +70,14 @@ * @param {HTMLElement} node - target node | ||
const ATTRIBUTE = 0; | ||
const EVENT = 1; | ||
const TEXT = 2; | ||
const VALUE = 3; | ||
var expressionTypes = { | ||
ATTRIBUTE, | ||
EVENT, | ||
TEXT, | ||
VALUE | ||
}; | ||
/** | ||
@@ -137,10 +179,4 @@ * Create the template meta object in case of <template> fragments | ||
const remove = (get, parent, children, start, end) => { | ||
if ((end - start) < 2) | ||
parent.removeChild(get(children[start], -1)); | ||
else { | ||
const range = parent.ownerDocument.createRange(); | ||
range.setStartBefore(get(children[start], -1)); | ||
range.setEndAfter(get(children[end - 1], -1)); | ||
range.deleteContents(); | ||
} | ||
while (start < end) | ||
removeChild(get(children[start++], -1), parent); | ||
}; | ||
@@ -436,2 +472,19 @@ | ||
let removeChild = (child, parentNode) => { | ||
/* istanbul ignore if */ | ||
if ('remove' in child) { | ||
removeChild = child => { | ||
child.remove(); | ||
}; | ||
} | ||
else { | ||
removeChild = (child, parentNode) => { | ||
/* istanbul ignore else */ | ||
if (child.parentNode === parentNode) | ||
parentNode.removeChild(child); | ||
}; | ||
} | ||
removeChild(child, parentNode); | ||
}; | ||
/*! (c) 2018 Andrea Giammarchi (ISC) */ | ||
@@ -654,11 +707,23 @@ | ||
/** | ||
* Check if a value is null or undefined | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the 'undefined' and 'null' types | ||
* Quick type checking | ||
* @param {*} element - anything | ||
* @param {string} type - type definition | ||
* @returns {boolean} true if the type corresponds | ||
*/ | ||
function isNil(value) { | ||
return value === null || value === undefined | ||
function checkType(element, type) { | ||
return typeof element === type | ||
} | ||
/** | ||
* Check if an element is part of an svg | ||
* @param {HTMLElement} el - element to check | ||
* @returns {boolean} true if we are in an svg context | ||
*/ | ||
function isSvg(el) { | ||
const owner = el.ownerSVGElement; | ||
return !!owner || owner === null | ||
} | ||
/** | ||
* Check if an element is a template tag | ||
@@ -672,2 +737,29 @@ * @param {HTMLElement} el - element to check | ||
/** | ||
* Check if a value is a Boolean | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the value is a boolean | ||
*/ | ||
function isBoolean(value) { | ||
return checkType(value, 'boolean') | ||
} | ||
/** | ||
* Check if a value is an Object | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the value is an object | ||
*/ | ||
function isObject(value) { | ||
return !isNil(value) && checkType(value, 'object') | ||
} | ||
/** | ||
* Check if a value is null or undefined | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the 'undefined' and 'null' types | ||
*/ | ||
function isNil(value) { | ||
return value === null || value === undefined | ||
} | ||
const EachBinding = Object.seal({ | ||
@@ -949,32 +1041,2 @@ // dynamic binding properties | ||
const ATTRIBUTE = 0; | ||
const EVENT = 1; | ||
const TEXT = 2; | ||
const VALUE = 3; | ||
var expressionTypes = { | ||
ATTRIBUTE, | ||
EVENT, | ||
TEXT, | ||
VALUE | ||
}; | ||
/** | ||
* Check if a value is a Boolean | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the value is a boolean | ||
*/ | ||
function isBoolean(value) { | ||
return typeof value === 'boolean' | ||
} | ||
/** | ||
* Check if a value is an Object | ||
* @param {*} value - anything | ||
* @returns {boolean} true only for the value is an object | ||
*/ | ||
function isObject(value) { | ||
return typeof value === 'object' | ||
} | ||
const REMOVE_ATTRIBUTE = 'removeAttribute'; | ||
@@ -1230,2 +1292,45 @@ const SET_ATTIBUTE = 'setAttribute'; | ||
/** | ||
* Evaluate a list of attribute expressions | ||
* @param {Array} attributes - attribute expressions generated by the riot compiler | ||
* @returns {Object} key value pairs with the result of the computation | ||
*/ | ||
function evaluateAttributeExpressions(attributes) { | ||
return attributes.reduce((acc, attribute) => { | ||
const {value, type} = attribute; | ||
switch (true) { | ||
// spread attribute | ||
case !attribute.name && type === ATTRIBUTE: | ||
return { | ||
...acc, | ||
...value | ||
} | ||
// value attribute | ||
case type === VALUE: | ||
acc.value = attribute.value; | ||
break | ||
// normal attributes | ||
default: | ||
acc[dashToCamelCase(attribute.name)] = attribute.value; | ||
} | ||
return acc | ||
}, {}) | ||
} | ||
function extendParentScope(attributes, scope, parentScope) { | ||
if (!attributes || !attributes.length) return parentScope | ||
const expressions = attributes.map(attr => ({ | ||
...attr, | ||
value: attr.evaluate(scope) | ||
})); | ||
return Object.assign( | ||
Object.create(parentScope || null), | ||
evaluateAttributeExpressions(expressions) | ||
) | ||
} | ||
const SlotBinding = Object.seal({ | ||
@@ -1235,4 +1340,9 @@ // dynamic binding properties | ||
name: null, | ||
attributes: [], | ||
template: null, | ||
getTemplateScope(scope, parentScope) { | ||
return extendParentScope(this.attributes, scope, parentScope) | ||
}, | ||
// API methods | ||
@@ -1249,3 +1359,3 @@ mount(scope, parentScope) { | ||
if (this.template) { | ||
this.template.mount(this.node, parentScope); | ||
this.template.mount(this.node, this.getTemplateScope(scope, parentScope)); | ||
moveSlotInnerContent(this.node); | ||
@@ -1259,4 +1369,4 @@ } | ||
update(scope, parentScope) { | ||
if (this.template && parentScope) { | ||
this.template.update(parentScope); | ||
if (this.template) { | ||
this.template.update(this.getTemplateScope(scope, parentScope)); | ||
} | ||
@@ -1268,3 +1378,3 @@ | ||
if (this.template) { | ||
this.template.unmount(parentScope, null, mustRemoveRoot); | ||
this.template.unmount(this.getTemplateScope(scope, parentScope), null, mustRemoveRoot); | ||
} | ||
@@ -1294,5 +1404,6 @@ | ||
*/ | ||
function createSlot(node, { name }) { | ||
function createSlot(node, { name, attributes }) { | ||
return { | ||
...SlotBinding, | ||
attributes, | ||
node, | ||
@@ -1415,8 +1526,23 @@ name | ||
/** | ||
* Text expressions in a template tag will get childNodeIndex value normalized | ||
* depending on the position of the <template> tag offset | ||
* @param {Expression[]} expressions - riot expressions array | ||
* @param {number} textExpressionsOffset - offset of the <template> tag | ||
* @returns {Expression[]} expressions containing the text expressions normalized | ||
*/ | ||
function fixTextExpressionsOffset(expressions, textExpressionsOffset) { | ||
return expressions.map(e => e.type === TEXT ? { | ||
...e, | ||
childNodeIndex: e.childNodeIndex + textExpressionsOffset | ||
} : e) | ||
} | ||
/** | ||
* Bind a new expression object to a DOM node | ||
* @param {HTMLElement} root - DOM node where to bind the expression | ||
* @param {Object} binding - binding data | ||
* @param {number|null} templateTagOffset - if it's defined we need to fix the text expressions childNodeIndex offset | ||
* @returns {Expression} Expression object | ||
*/ | ||
function create$5(root, binding) { | ||
function create$5(root, binding, templateTagOffset) { | ||
const { selector, type, redundantAttribute, expressions } = binding; | ||
@@ -1427,3 +1553,3 @@ // find the node to apply the bindings | ||
if (redundantAttribute) node.removeAttribute(redundantAttribute); | ||
const bindingExpressions = expressions || []; | ||
// init the binding | ||
@@ -1434,3 +1560,5 @@ return (bindings[type] || bindings[SIMPLE])( | ||
...binding, | ||
expressions: expressions || [] | ||
expressions: templateTagOffset && !selector ? | ||
fixTextExpressionsOffset(bindingExpressions, templateTagOffset) : | ||
bindingExpressions | ||
} | ||
@@ -1440,13 +1568,2 @@ ) | ||
/** | ||
* Check if an element is part of an svg | ||
* @param {HTMLElement} el - element to check | ||
* @returns {boolean} true if we are in an svg context | ||
*/ | ||
function isSvg(el) { | ||
const owner = el.ownerSVGElement; | ||
return !!owner || owner === null | ||
} | ||
// in this case a simple innerHTML is enough | ||
@@ -1488,18 +1605,2 @@ function createHTMLTree(html, root) { | ||
/** | ||
* Move all the child nodes from a source tag to another | ||
* @param {HTMLElement} source - source node | ||
* @param {HTMLElement} target - target node | ||
* @returns {undefined} it's a void method ¯\_(ツ)_/¯ | ||
*/ | ||
// Ignore this helper because it's needed only for svg tags | ||
/* istanbul ignore next */ | ||
function moveChildren(source, target) { | ||
if (source.firstChild) { | ||
target.appendChild(source.firstChild); | ||
moveChildren(source, target); | ||
} | ||
} | ||
/** | ||
* Inject the DOM tree into a target node | ||
@@ -1582,5 +1683,9 @@ * @param {HTMLElement} el - target element | ||
const {parentNode} = children ? children[0] : el; | ||
const isTemplateTag = isTemplate(el); | ||
const templateTagOffset = isTemplateTag ? Math.max( | ||
Array.from(parentNode.children).indexOf(el), | ||
0 | ||
) : null; | ||
this.isTemplateTag = isTemplateTag; | ||
this.isTemplateTag = isTemplate(el); | ||
// create the DOM if it wasn't created before | ||
@@ -1604,3 +1709,7 @@ this.createDOM(el); | ||
// create the bindings | ||
this.bindings = this.bindingsData.map(binding => create$5(this.el, binding)); | ||
this.bindings = this.bindingsData.map(binding => create$5( | ||
this.el, | ||
binding, | ||
templateTagOffset | ||
)); | ||
this.bindings.forEach(b => b.mount(scope, parentScope)); | ||
@@ -1607,0 +1716,0 @@ |
{ | ||
"name": "@riotjs/dom-bindings", | ||
"version": "4.3.0", | ||
"version": "4.4.0", | ||
"description": "Riot.js DOM bindings", | ||
@@ -41,3 +41,3 @@ "main": "dist/umd.dom-bindings.js", | ||
"coveralls": "^3.0.6", | ||
"eslint": "^6.3.0", | ||
"eslint": "^6.4.0", | ||
"eslint-config-riot": "^3.0.0", | ||
@@ -49,11 +49,12 @@ "esm": "^3.2.25", | ||
"nyc": "^14.1.1", | ||
"rollup": "^1.20.3", | ||
"rollup": "^1.21.4", | ||
"rollup-plugin-alias": "^2.0.0", | ||
"rollup-plugin-node-resolve": "^5.2.0", | ||
"sinon": "^7.4.1", | ||
"sinon": "^7.4.2", | ||
"sinon-chai": "^3.3.0" | ||
}, | ||
"dependencies": { | ||
"domdiff": "^2.0.7" | ||
"@riotjs/util": "^1.1.0", | ||
"domdiff": "^2.1.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
110991
3171
2
+ Added@riotjs/util@^1.1.0
+ Added@riotjs/util@1.3.1(transitive)
Updateddomdiff@^2.1.0