$
This commit is contained in:
214
node_modules/@riotjs/dom-bindings/src/bindings/each.js
generated
vendored
Normal file
214
node_modules/@riotjs/dom-bindings/src/bindings/each.js
generated
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
import {insertBefore, removeChild} from '@riotjs/util/dom'
|
||||
import createTemplateMeta from '../util/create-template-meta'
|
||||
import {defineProperty} from '@riotjs/util/objects'
|
||||
import {isTemplate} from '@riotjs/util/checks'
|
||||
import udomdiff from '../util/udomdiff'
|
||||
|
||||
const UNMOUNT_SCOPE = Symbol('unmount')
|
||||
|
||||
export const EachBinding = {
|
||||
// dynamic binding properties
|
||||
// childrenMap: null,
|
||||
// node: null,
|
||||
// root: null,
|
||||
// condition: null,
|
||||
// evaluate: null,
|
||||
// template: null,
|
||||
// isTemplateTag: false,
|
||||
nodes: [],
|
||||
// getKey: null,
|
||||
// indexName: null,
|
||||
// itemName: null,
|
||||
// afterPlaceholder: null,
|
||||
// placeholder: null,
|
||||
|
||||
// API methods
|
||||
mount(scope, parentScope) {
|
||||
return this.update(scope, parentScope)
|
||||
},
|
||||
update(scope, parentScope) {
|
||||
const {placeholder, nodes, childrenMap} = this
|
||||
const collection = scope === UNMOUNT_SCOPE ? null : this.evaluate(scope)
|
||||
const items = collection ? Array.from(collection) : []
|
||||
|
||||
// prepare the diffing
|
||||
const {
|
||||
newChildrenMap,
|
||||
batches,
|
||||
futureNodes
|
||||
} = createPatch(items, scope, parentScope, this)
|
||||
|
||||
// patch the DOM only if there are new nodes
|
||||
udomdiff(
|
||||
nodes,
|
||||
futureNodes,
|
||||
patch(
|
||||
Array.from(childrenMap.values()),
|
||||
parentScope
|
||||
),
|
||||
placeholder
|
||||
)
|
||||
|
||||
// trigger the mounts and the updates
|
||||
batches.forEach(fn => fn())
|
||||
|
||||
// update the children map
|
||||
this.childrenMap = newChildrenMap
|
||||
this.nodes = futureNodes
|
||||
|
||||
return this
|
||||
},
|
||||
unmount(scope, parentScope) {
|
||||
this.update(UNMOUNT_SCOPE, parentScope)
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch the DOM while diffing
|
||||
* @param {any[]} redundant - list of all the children (template, nodes, context) added via each
|
||||
* @param {*} parentScope - scope of the parent template
|
||||
* @returns {Function} patch function used by domdiff
|
||||
*/
|
||||
function patch(redundant, parentScope) {
|
||||
return (item, info) => {
|
||||
if (info < 0) {
|
||||
// get the last element added to the childrenMap saved previously
|
||||
const element = redundant[redundant.length - 1]
|
||||
|
||||
if (element) {
|
||||
// get the nodes and the template in stored in the last child of the childrenMap
|
||||
const {template, nodes, context} = element
|
||||
// remove the last node (notice <template> tags might have more children nodes)
|
||||
nodes.pop()
|
||||
|
||||
// notice that we pass null as last argument because
|
||||
// the root node and its children will be removed by domdiff
|
||||
if (!nodes.length) {
|
||||
// we have cleared all the children nodes and we can unmount this template
|
||||
redundant.pop()
|
||||
template.unmount(context, parentScope, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a template must be filtered from a loop
|
||||
* @param {Function} condition - filter function
|
||||
* @param {Object} context - argument passed to the filter function
|
||||
* @returns {boolean} true if this item should be skipped
|
||||
*/
|
||||
function mustFilterItem(condition, context) {
|
||||
return condition ? !condition(context) : false
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the scope of the looped template
|
||||
* @param {Object} scope - current template scope
|
||||
* @param {Object} options - options
|
||||
* @param {string} options.itemName - key to identify the looped item in the new context
|
||||
* @param {string} options.indexName - key to identify the index of the looped item
|
||||
* @param {number} options.index - current index
|
||||
* @param {*} options.item - collection item looped
|
||||
* @returns {Object} enhanced scope object
|
||||
*/
|
||||
function extendScope(scope, {itemName, indexName, index, item}) {
|
||||
defineProperty(scope, itemName, item)
|
||||
if (indexName) defineProperty(scope, indexName, index)
|
||||
|
||||
return scope
|
||||
}
|
||||
|
||||
/**
|
||||
* Loop the current template items
|
||||
* @param {Array} items - expression collection value
|
||||
* @param {*} scope - template scope
|
||||
* @param {*} parentScope - scope of the parent template
|
||||
* @param {EachBinding} binding - each binding object instance
|
||||
* @returns {Object} data
|
||||
* @returns {Map} data.newChildrenMap - a Map containing the new children template structure
|
||||
* @returns {Array} data.batches - array containing the template lifecycle functions to trigger
|
||||
* @returns {Array} data.futureNodes - array containing the nodes we need to diff
|
||||
*/
|
||||
function createPatch(items, scope, parentScope, binding) {
|
||||
const {condition, template, childrenMap, itemName, getKey, indexName, root, isTemplateTag} = binding
|
||||
const newChildrenMap = new Map()
|
||||
const batches = []
|
||||
const futureNodes = []
|
||||
|
||||
items.forEach((item, index) => {
|
||||
const context = extendScope(Object.create(scope), {itemName, indexName, index, item})
|
||||
const key = getKey ? getKey(context) : index
|
||||
const oldItem = childrenMap.get(key)
|
||||
const nodes = []
|
||||
|
||||
if (mustFilterItem(condition, context)) {
|
||||
return
|
||||
}
|
||||
|
||||
const mustMount = !oldItem
|
||||
const componentTemplate = oldItem ? oldItem.template : template.clone()
|
||||
const el = componentTemplate.el || root.cloneNode()
|
||||
const meta = isTemplateTag && mustMount ? createTemplateMeta(componentTemplate) : componentTemplate.meta
|
||||
|
||||
if (mustMount) {
|
||||
batches.push(() => componentTemplate.mount(el, context, parentScope, meta))
|
||||
} else {
|
||||
batches.push(() => componentTemplate.update(context, parentScope))
|
||||
}
|
||||
|
||||
// create the collection of nodes to update or to add
|
||||
// in case of template tags we need to add all its children nodes
|
||||
if (isTemplateTag) {
|
||||
nodes.push(...meta.children)
|
||||
} else {
|
||||
nodes.push(el)
|
||||
}
|
||||
|
||||
// delete the old item from the children map
|
||||
childrenMap.delete(key)
|
||||
futureNodes.push(...nodes)
|
||||
|
||||
// update the children map
|
||||
newChildrenMap.set(key, {
|
||||
nodes,
|
||||
template: componentTemplate,
|
||||
context,
|
||||
index
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
newChildrenMap,
|
||||
batches,
|
||||
futureNodes
|
||||
}
|
||||
}
|
||||
|
||||
export default function create(node, {evaluate, condition, itemName, indexName, getKey, template}) {
|
||||
const placeholder = document.createTextNode('')
|
||||
const root = node.cloneNode()
|
||||
|
||||
insertBefore(placeholder, node)
|
||||
removeChild(node)
|
||||
|
||||
return {
|
||||
...EachBinding,
|
||||
childrenMap: new Map(),
|
||||
node,
|
||||
root,
|
||||
condition,
|
||||
evaluate,
|
||||
isTemplateTag: isTemplate(root),
|
||||
template: template.createDOM(node),
|
||||
getKey,
|
||||
indexName,
|
||||
itemName,
|
||||
placeholder
|
||||
}
|
||||
}
|
65
node_modules/@riotjs/dom-bindings/src/bindings/if.js
generated
vendored
Normal file
65
node_modules/@riotjs/dom-bindings/src/bindings/if.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
import {insertBefore, removeChild} from '@riotjs/util/dom'
|
||||
|
||||
/**
|
||||
* Binding responsible for the `if` directive
|
||||
*/
|
||||
export const IfBinding = {
|
||||
// dynamic binding properties
|
||||
// node: null,
|
||||
// evaluate: null,
|
||||
// isTemplateTag: false,
|
||||
// placeholder: null,
|
||||
// template: null,
|
||||
|
||||
// API methods
|
||||
mount(scope, parentScope) {
|
||||
return this.update(scope, parentScope)
|
||||
},
|
||||
update(scope, parentScope) {
|
||||
const value = !!this.evaluate(scope)
|
||||
const mustMount = !this.value && value
|
||||
const mustUnmount = this.value && !value
|
||||
const mount = () => {
|
||||
const pristine = this.node.cloneNode()
|
||||
|
||||
insertBefore(pristine, this.placeholder)
|
||||
this.template = this.template.clone()
|
||||
this.template.mount(pristine, scope, parentScope)
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case mustMount:
|
||||
mount()
|
||||
break
|
||||
case mustUnmount:
|
||||
this.unmount(scope)
|
||||
break
|
||||
default:
|
||||
if (value) this.template.update(scope, parentScope)
|
||||
}
|
||||
|
||||
this.value = value
|
||||
|
||||
return this
|
||||
},
|
||||
unmount(scope, parentScope) {
|
||||
this.template.unmount(scope, parentScope, true)
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export default function create(node, { evaluate, template }) {
|
||||
const placeholder = document.createTextNode('')
|
||||
|
||||
insertBefore(placeholder, node)
|
||||
removeChild(node)
|
||||
|
||||
return {
|
||||
...IfBinding,
|
||||
node,
|
||||
evaluate,
|
||||
placeholder,
|
||||
template: template.createDOM(node)
|
||||
}
|
||||
}
|
14
node_modules/@riotjs/dom-bindings/src/bindings/index.js
generated
vendored
Normal file
14
node_modules/@riotjs/dom-bindings/src/bindings/index.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import {EACH, IF, SIMPLE, SLOT, TAG} from '@riotjs/util/binding-types'
|
||||
import EachBinding from './each'
|
||||
import IfBinding from './if'
|
||||
import SimpleBinding from './simple'
|
||||
import SlotBinding from './slot'
|
||||
import TagBinding from './tag'
|
||||
|
||||
export default {
|
||||
[IF]: IfBinding,
|
||||
[SIMPLE]: SimpleBinding,
|
||||
[EACH]: EachBinding,
|
||||
[TAG]: TagBinding,
|
||||
[SLOT]: SlotBinding
|
||||
}
|
11
node_modules/@riotjs/dom-bindings/src/bindings/simple.js
generated
vendored
Normal file
11
node_modules/@riotjs/dom-bindings/src/bindings/simple.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import createExpression from '../expression'
|
||||
import flattenCollectionMethods from '../util/flatten-collection-methods'
|
||||
|
||||
export default function create(node, { expressions }) {
|
||||
return {
|
||||
...flattenCollectionMethods(
|
||||
expressions.map(expression => createExpression(node, expression)),
|
||||
['mount', 'update', 'unmount']
|
||||
)
|
||||
}
|
||||
}
|
102
node_modules/@riotjs/dom-bindings/src/bindings/slot.js
generated
vendored
Normal file
102
node_modules/@riotjs/dom-bindings/src/bindings/slot.js
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
import {cleanNode, insertBefore, removeChild} from '@riotjs/util/dom'
|
||||
import {PARENT_KEY_SYMBOL} from '@riotjs/util/constants'
|
||||
import {evaluateAttributeExpressions} from '@riotjs/util/misc'
|
||||
import template from '../template'
|
||||
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
// this function is only meant to fix an edge case
|
||||
// https://github.com/riot/riot/issues/2842
|
||||
const getRealParent = (scope, parentScope) => scope[PARENT_KEY_SYMBOL] || parentScope
|
||||
|
||||
export const SlotBinding = {
|
||||
// dynamic binding properties
|
||||
// node: null,
|
||||
// name: null,
|
||||
attributes: [],
|
||||
// template: null,
|
||||
|
||||
getTemplateScope(scope, parentScope) {
|
||||
return extendParentScope(this.attributes, scope, parentScope)
|
||||
},
|
||||
|
||||
// API methods
|
||||
mount(scope, parentScope) {
|
||||
const templateData = scope.slots ? scope.slots.find(({id}) => id === this.name) : false
|
||||
const {parentNode} = this.node
|
||||
const realParent = getRealParent(scope, parentScope)
|
||||
|
||||
this.template = templateData && template(
|
||||
templateData.html,
|
||||
templateData.bindings
|
||||
).createDOM(parentNode)
|
||||
|
||||
if (this.template) {
|
||||
cleanNode(this.node)
|
||||
this.template.mount(this.node, this.getTemplateScope(scope, realParent), realParent)
|
||||
this.template.children = Array.from(this.node.childNodes)
|
||||
}
|
||||
|
||||
moveSlotInnerContent(this.node)
|
||||
removeChild(this.node)
|
||||
|
||||
return this
|
||||
},
|
||||
update(scope, parentScope) {
|
||||
if (this.template) {
|
||||
const realParent = getRealParent(scope, parentScope)
|
||||
this.template.update(this.getTemplateScope(scope, realParent), realParent)
|
||||
}
|
||||
|
||||
return this
|
||||
},
|
||||
unmount(scope, parentScope, mustRemoveRoot) {
|
||||
if (this.template) {
|
||||
this.template.unmount(this.getTemplateScope(scope, parentScope), null, mustRemoveRoot)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the inner content of the slots outside of them
|
||||
* @param {HTMLElement} slot - slot node
|
||||
* @returns {undefined} it's a void method ¯\_(ツ)_/¯
|
||||
*/
|
||||
function moveSlotInnerContent(slot) {
|
||||
const child = slot && slot.firstChild
|
||||
|
||||
if (!child) return
|
||||
|
||||
insertBefore(child, slot)
|
||||
moveSlotInnerContent(slot)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single slot binding
|
||||
* @param {HTMLElement} node - slot node
|
||||
* @param {string} name - slot id
|
||||
* @param {AttributeExpressionData[]} attributes - slot attributes
|
||||
* @returns {Object} Slot binding object
|
||||
*/
|
||||
export default function createSlot(node, { name, attributes }) {
|
||||
return {
|
||||
...SlotBinding,
|
||||
attributes,
|
||||
node,
|
||||
name
|
||||
}
|
||||
}
|
105
node_modules/@riotjs/dom-bindings/src/bindings/tag.js
generated
vendored
Normal file
105
node_modules/@riotjs/dom-bindings/src/bindings/tag.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
import {ATTRIBUTE} from '@riotjs/util/expression-types'
|
||||
import template from '../template'
|
||||
|
||||
/**
|
||||
* Create a new tag object if it was registered before, otherwise fallback to the simple
|
||||
* template chunk
|
||||
* @param {Function} component - component factory function
|
||||
* @param {Array<Object>} slots - array containing the slots markup
|
||||
* @param {Array} attributes - dynamic attributes that will be received by the tag element
|
||||
* @returns {TagImplementation|TemplateChunk} a tag implementation or a template chunk as fallback
|
||||
*/
|
||||
function getTag(component, slots = [], attributes = []) {
|
||||
// if this tag was registered before we will return its implementation
|
||||
if (component) {
|
||||
return component({slots, attributes})
|
||||
}
|
||||
|
||||
// otherwise we return a template chunk
|
||||
return template(slotsToMarkup(slots), [
|
||||
...slotBindings(slots), {
|
||||
// the attributes should be registered as binding
|
||||
// if we fallback to a normal template chunk
|
||||
expressions: attributes.map(attr => {
|
||||
return {
|
||||
type: ATTRIBUTE,
|
||||
...attr
|
||||
}
|
||||
})
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge all the slots bindings into a single array
|
||||
* @param {Array<Object>} slots - slots collection
|
||||
* @returns {Array<Bindings>} flatten bindings array
|
||||
*/
|
||||
function slotBindings(slots) {
|
||||
return slots.reduce((acc, {bindings}) => acc.concat(bindings), [])
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge all the slots together in a single markup string
|
||||
* @param {Array<Object>} slots - slots collection
|
||||
* @returns {string} markup of all the slots in a single string
|
||||
*/
|
||||
function slotsToMarkup(slots) {
|
||||
return slots.reduce((acc, slot) => {
|
||||
return acc + slot.html
|
||||
}, '')
|
||||
}
|
||||
|
||||
|
||||
export const TagBinding = {
|
||||
// dynamic binding properties
|
||||
// node: null,
|
||||
// evaluate: null,
|
||||
// name: null,
|
||||
// slots: null,
|
||||
// tag: null,
|
||||
// attributes: null,
|
||||
// getComponent: null,
|
||||
|
||||
mount(scope) {
|
||||
return this.update(scope)
|
||||
},
|
||||
update(scope, parentScope) {
|
||||
const name = this.evaluate(scope)
|
||||
|
||||
// simple update
|
||||
if (name && name === this.name) {
|
||||
this.tag.update(scope)
|
||||
} else {
|
||||
// unmount the old tag if it exists
|
||||
this.unmount(scope, parentScope, true)
|
||||
|
||||
// mount the new tag
|
||||
this.name = name
|
||||
this.tag = getTag(this.getComponent(name), this.slots, this.attributes)
|
||||
this.tag.mount(this.node, scope)
|
||||
}
|
||||
|
||||
return this
|
||||
},
|
||||
unmount(scope, parentScope, keepRootTag) {
|
||||
if (this.tag) {
|
||||
// keep the root tag
|
||||
this.tag.unmount(keepRootTag)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
export default function create(node, {evaluate, getComponent, slots, attributes}) {
|
||||
return {
|
||||
...TagBinding,
|
||||
node,
|
||||
evaluate,
|
||||
slots,
|
||||
attributes,
|
||||
getComponent
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user