UNPKG

weex-js-runtime

Version:
1,732 lines (1,579 loc) 80.2 kB
/* Weex JS Runtime 0.23.7, Build 2018-02-01 20:34. */ (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.WeexJSRuntime = factory()); }(this, (function () { 'use strict'; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ function getHookKey (componentId, type, hookName) { return (type + "@" + hookName + "#" + componentId) } /** * For general callback management of a certain Weex instance. * Because function can not passed into native, so we create callback * callback id for each function and pass the callback id into native * in fact. And when a callback called from native, we can find the real * callback through the callback id we have passed before. */ var CallbackManager = function CallbackManager (instanceId) { this.instanceId = String(instanceId); this.lastCallbackId = 0; this.callbacks = {}; this.hooks = {}; }; CallbackManager.prototype.add = function add (callback) { this.lastCallbackId++; this.callbacks[this.lastCallbackId] = callback; return this.lastCallbackId }; CallbackManager.prototype.remove = function remove (callbackId) { var callback = this.callbacks[callbackId]; delete this.callbacks[callbackId]; return callback }; CallbackManager.prototype.registerHook = function registerHook (componentId, type, hookName, hookFunction) { // TODO: validate arguments var key = getHookKey(componentId, type, hookName); if (this.hooks[key]) { console.warn(("[JS Framework] Override an existing component hook \"" + key + "\".")); } this.hooks[key] = hookFunction; }; CallbackManager.prototype.triggerHook = function triggerHook (componentId, type, hookName, args) { // TODO: validate arguments var key = getHookKey(componentId, type, hookName); var hookFunction = this.hooks[key]; if (typeof hookFunction !== 'function') { console.error(("[JS Framework] Invalid hook function type (" + (typeof hookFunction) + ") on \"" + key + "\".")); return null } var result = null; try { result = hookFunction.apply(null, args || []); } catch (e) { console.error(("[JS Framework] Failed to execute the hook function on \"" + key + "\".")); } return result }; CallbackManager.prototype.consume = function consume (callbackId, data, ifKeepAlive) { var callback = this.callbacks[callbackId]; if (typeof ifKeepAlive === 'undefined' || ifKeepAlive === false) { delete this.callbacks[callbackId]; } if (typeof callback === 'function') { return callback(data) } return new Error(("invalid callback id \"" + callbackId + "\"")) }; CallbackManager.prototype.close = function close () { this.callbacks = {}; this.hooks = {}; }; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * Get a unique id. */ var nextNodeRef = 1; function uniqueId () { return (nextNodeRef++).toString() } function typof (v) { var s = Object.prototype.toString.call(v); return s.substring(8, s.length - 1) } function bufferToBase64 (buffer) { if (typeof btoa !== 'function') { return '' } var string = Array.prototype.map.call( new Uint8Array(buffer), function (code) { return String.fromCharCode(code); } ).join(''); return btoa(string) // eslint-disable-line no-undef } /** * Detect if the param is falsy or empty * @param {any} any */ function isEmpty (any) { if (!any || typeof any !== 'object') { return true } for (var key in any) { if (Object.prototype.hasOwnProperty.call(any, key)) { return false } } return true } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var docMap = {}; /** * Add a document object into docMap. * @param {string} id * @param {object} document */ function addDoc (id, doc) { if (id) { docMap[id] = doc; } } /** * Get the document object by id. * @param {string} id */ function getDoc (id) { return docMap[id] } /** * Remove the document from docMap by id. * @param {string} id */ function removeDoc (id) { delete docMap[id]; } /** * @deprecated * Get listener by document id. * @param {string} id * @return {object} listener */ /** * Get TaskCenter instance by id. * @param {string} id * @return {object} TaskCenter */ function getTaskCenter (id) { var doc = docMap[id]; if (doc && doc.taskCenter) { return doc.taskCenter } return null } /** * Append body node to documentElement. * @param {object} document * @param {object} node * @param {object} before */ function appendBody (doc, node, before) { var documentElement = doc.documentElement; if (documentElement.pureChildren.length > 0 || node.parentNode) { return } var children = documentElement.children; var beforeIndex = children.indexOf(before); if (beforeIndex < 0) { children.push(node); } else { children.splice(beforeIndex, 0, node); } if (node.nodeType === 1) { if (node.role === 'body') { node.docId = doc.id; node.ownerDocument = doc; node.parentNode = documentElement; linkParent(node, documentElement); } else { node.children.forEach(function (child) { child.parentNode = node; }); setBody(doc, node); node.docId = doc.id; node.ownerDocument = doc; linkParent(node, documentElement); delete doc.nodeMap[node.nodeId]; } documentElement.pureChildren.push(node); sendBody(doc, node); } else { node.parentNode = documentElement; doc.nodeMap[node.ref] = node; } } function sendBody (doc, node) { var body = node.toJSON(); if (doc && doc.taskCenter && typeof doc.taskCenter.send === 'function') { doc.taskCenter.send('dom', { action: 'createBody' }, [body]); } } /** * Set up body node. * @param {object} document * @param {object} element */ function setBody (doc, el) { el.role = 'body'; el.depth = 1; delete doc.nodeMap[el.nodeId]; el.ref = '_root'; doc.nodeMap._root = el; doc.body = el; } /** * Establish the connection between parent and child node. * @param {object} child node * @param {object} parent node */ function linkParent (node, parent) { node.parentNode = parent; if (parent.docId) { node.docId = parent.docId; node.ownerDocument = parent.ownerDocument; node.ownerDocument.nodeMap[node.nodeId] = node; node.depth = parent.depth + 1; } node.children.forEach(function (child) { linkParent(child, node); }); } /** * Get the next sibling element. * @param {object} node */ function nextElement (node) { while (node) { if (node.nodeType === 1) { return node } node = node.nextSibling; } } /** * Get the previous sibling element. * @param {object} node */ function previousElement (node) { while (node) { if (node.nodeType === 1) { return node } node = node.previousSibling; } } /** * Insert a node into list at the specified index. * @param {object} target node * @param {array} list * @param {number} newIndex * @param {boolean} changeSibling * @return {number} newIndex */ function insertIndex (target, list, newIndex, changeSibling) { /* istanbul ignore next */ if (newIndex < 0) { newIndex = 0; } var before = list[newIndex - 1]; var after = list[newIndex]; list.splice(newIndex, 0, target); if (changeSibling) { before && (before.nextSibling = target); target.previousSibling = before; target.nextSibling = after; after && (after.previousSibling = target); } return newIndex } /** * Move the node to a new index in list. * @param {object} target node * @param {array} list * @param {number} newIndex * @param {boolean} changeSibling * @return {number} newIndex */ function moveIndex (target, list, newIndex, changeSibling) { var index = list.indexOf(target); /* istanbul ignore next */ if (index < 0) { return -1 } if (changeSibling) { var before = list[index - 1]; var after = list[index + 1]; before && (before.nextSibling = after); after && (after.previousSibling = before); } list.splice(index, 1); var newIndexAfter = newIndex; if (index <= newIndex) { newIndexAfter = newIndex - 1; } var beforeNew = list[newIndexAfter - 1]; var afterNew = list[newIndexAfter]; list.splice(newIndexAfter, 0, target); if (changeSibling) { beforeNew && (beforeNew.nextSibling = target); target.previousSibling = beforeNew; target.nextSibling = afterNew; afterNew && (afterNew.previousSibling = target); } if (index === newIndexAfter) { return -1 } return newIndex } /** * Remove the node from list. * @param {object} target node * @param {array} list * @param {boolean} changeSibling */ function removeIndex (target, list, changeSibling) { var index = list.indexOf(target); /* istanbul ignore next */ if (index < 0) { return } if (changeSibling) { var before = list[index - 1]; var after = list[index + 1]; before && (before.nextSibling = after); after && (after.previousSibling = before); } list.splice(index, 1); } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var Node = function Node () { this.nodeId = uniqueId(); this.ref = this.nodeId; this.children = []; this.pureChildren = []; this.parentNode = null; this.nextSibling = null; this.previousSibling = null; }; /** * Destroy current node, and remove itself form nodeMap. */ Node.prototype.destroy = function destroy () { var doc = getDoc(this.docId); if (doc) { delete this.docId; delete doc.nodeMap[this.nodeId]; } this.children.forEach(function (child) { child.destroy(); }); }; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var Element$2; function setElement (El) { Element$2 = El; } /** * A map which stores all type of elements. * @type {Object} */ var registeredElements = {}; /** * Register an extended element type with component methods. * @param {string} type component type * @param {array} methods a list of method names */ function registerElement (type, methods) { // Skip when no special component methods. if (!methods || !methods.length) { return } // Init constructor. var WeexElement = (function (Element) { function WeexElement () { Element.apply(this, arguments); }if ( Element ) WeexElement.__proto__ = Element; WeexElement.prototype = Object.create( Element && Element.prototype ); WeexElement.prototype.constructor = WeexElement; return WeexElement; }(Element$2)); // Add methods to prototype. methods.forEach(function (methodName) { WeexElement.prototype[methodName] = function () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; var taskCenter = getTaskCenter(this.docId); if (taskCenter) { return taskCenter.send('component', { ref: this.ref, component: type, method: methodName }, args) } }; }); // Add to element type map. registeredElements[type] = WeexElement; } function getWeexElement (type) { return registeredElements[type] } /** * Clear all element types. Only for testing. */ /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var DEFAULT_TAG_NAME = 'div'; var BUBBLE_EVENTS = [ 'click', 'longpress', 'touchstart', 'touchmove', 'touchend', 'panstart', 'panmove', 'panend', 'horizontalpan', 'verticalpan', 'swipe' ]; function registerNode (docId, node) { var doc = getDoc(docId); doc.nodeMap[node.nodeId] = node; } var Element = (function (Node$$1) { function Element (type, props, isExtended) { if ( type === void 0 ) type = DEFAULT_TAG_NAME; Node$$1.call(this); var WeexElement = getWeexElement(type); if (WeexElement && !isExtended) { return new WeexElement(type, props, true) } props = props || {}; this.nodeType = 1; this.nodeId = uniqueId(); this.ref = this.nodeId; this.type = type; this.attr = props.attr || {}; this.style = props.style || {}; this.classStyle = props.classStyle || {}; this.classList = props.classList || []; this.event = {}; this.children = []; this.pureChildren = []; } if ( Node$$1 ) Element.__proto__ = Node$$1; Element.prototype = Object.create( Node$$1 && Node$$1.prototype ); Element.prototype.constructor = Element; /** * Append a child node. * @param {object} node * @return {undefined | number} the signal sent by native */ Element.prototype.appendChild = function appendChild (node) { if (node.parentNode && node.parentNode !== this) { return } /* istanbul ignore else */ if (!node.parentNode) { linkParent(node, this); insertIndex(node, this.children, this.children.length, true); if (this.docId) { registerNode(this.docId, node); } if (node.nodeType === 1) { insertIndex(node, this.pureChildren, this.pureChildren.length); var taskCenter = getTaskCenter(this.docId); if (taskCenter) { return taskCenter.send( 'dom', { action: 'addElement' }, [this.ref, node.toJSON(), -1] ) } } } else { moveIndex(node, this.children, this.children.length, true); if (node.nodeType === 1) { var index = moveIndex(node, this.pureChildren, this.pureChildren.length); var taskCenter$1 = getTaskCenter(this.docId); if (taskCenter$1 && index >= 0) { return taskCenter$1.send( 'dom', { action: 'moveElement' }, [node.ref, this.ref, index] ) } } } }; /** * Insert a node before specified node. * @param {object} node * @param {object} before * @return {undefined | number} the signal sent by native */ Element.prototype.insertBefore = function insertBefore (node, before) { if (node.parentNode && node.parentNode !== this) { return } if (node === before || (node.nextSibling && node.nextSibling === before)) { return } if (!node.parentNode) { linkParent(node, this); insertIndex(node, this.children, this.children.indexOf(before), true); if (this.docId) { registerNode(this.docId, node); } if (node.nodeType === 1) { var pureBefore = nextElement(before); var index = insertIndex( node, this.pureChildren, pureBefore ? this.pureChildren.indexOf(pureBefore) : this.pureChildren.length ); var taskCenter = getTaskCenter(this.docId); if (taskCenter) { return taskCenter.send( 'dom', { action: 'addElement' }, [this.ref, node.toJSON(), index] ) } } } else { moveIndex(node, this.children, this.children.indexOf(before), true); if (node.nodeType === 1) { var pureBefore$1 = nextElement(before); /* istanbul ignore next */ var index$1 = moveIndex( node, this.pureChildren, pureBefore$1 ? this.pureChildren.indexOf(pureBefore$1) : this.pureChildren.length ); var taskCenter$1 = getTaskCenter(this.docId); if (taskCenter$1 && index$1 >= 0) { return taskCenter$1.send( 'dom', { action: 'moveElement' }, [node.ref, this.ref, index$1] ) } } } }; /** * Insert a node after specified node. * @param {object} node * @param {object} after * @return {undefined | number} the signal sent by native */ Element.prototype.insertAfter = function insertAfter (node, after) { if (node.parentNode && node.parentNode !== this) { return } if (node === after || (node.previousSibling && node.previousSibling === after)) { return } if (!node.parentNode) { linkParent(node, this); insertIndex(node, this.children, this.children.indexOf(after) + 1, true); /* istanbul ignore else */ if (this.docId) { registerNode(this.docId, node); } if (node.nodeType === 1) { var index = insertIndex( node, this.pureChildren, this.pureChildren.indexOf(previousElement(after)) + 1 ); var taskCenter = getTaskCenter(this.docId); /* istanbul ignore else */ if (taskCenter) { return taskCenter.send( 'dom', { action: 'addElement' }, [this.ref, node.toJSON(), index] ) } } } else { moveIndex(node, this.children, this.children.indexOf(after) + 1, true); if (node.nodeType === 1) { var index$1 = moveIndex( node, this.pureChildren, this.pureChildren.indexOf(previousElement(after)) + 1 ); var taskCenter$1 = getTaskCenter(this.docId); if (taskCenter$1 && index$1 >= 0) { return taskCenter$1.send( 'dom', { action: 'moveElement' }, [node.ref, this.ref, index$1] ) } } } }; /** * Remove a child node, and decide whether it should be destroyed. * @param {object} node * @param {boolean} preserved */ Element.prototype.removeChild = function removeChild (node, preserved) { if (node.parentNode) { removeIndex(node, this.children, true); if (node.nodeType === 1) { removeIndex(node, this.pureChildren); var taskCenter = getTaskCenter(this.docId); if (taskCenter) { taskCenter.send( 'dom', { action: 'removeElement' }, [node.ref] ); } } } if (!preserved) { node.destroy(); } }; /** * Clear all child nodes. */ Element.prototype.clear = function clear () { var taskCenter = getTaskCenter(this.docId); /* istanbul ignore else */ if (taskCenter) { this.pureChildren.forEach(function (node) { taskCenter.send( 'dom', { action: 'removeElement' }, [node.ref] ); }); } this.children.forEach(function (node) { node.destroy(); }); this.children.length = 0; this.pureChildren.length = 0; }; /** * Set an attribute, and decide whether the task should be send to native. * @param {string} key * @param {string | number} value * @param {boolean} silent */ Element.prototype.setAttr = function setAttr (key, value, silent) { if (this.attr[key] === value && silent !== false) { return } this.attr[key] = value; var taskCenter = getTaskCenter(this.docId); if (!silent && taskCenter) { var result = {}; result[key] = value; taskCenter.send( 'dom', { action: 'updateAttrs' }, [this.ref, result] ); } }; /** * Set batched attributes. * @param {object} batchedAttrs * @param {boolean} silent */ Element.prototype.setAttrs = function setAttrs (batchedAttrs, silent) { var this$1 = this; if (isEmpty(batchedAttrs)) { return } var mutations = {}; for (var key in batchedAttrs) { if (this$1.attr[key] !== batchedAttrs[key]) { this$1.attr[key] = batchedAttrs[key]; mutations[key] = batchedAttrs[key]; } } if (!isEmpty(mutations)) { var taskCenter = getTaskCenter(this.docId); if (!silent && taskCenter) { taskCenter.send( 'dom', { action: 'updateAttrs' }, [this.ref, mutations] ); } } }; /** * Set a style property, and decide whether the task should be send to native. * @param {string} key * @param {string | number} value * @param {boolean} silent */ Element.prototype.setStyle = function setStyle (key, value, silent) { if (this.style[key] === value && silent !== false) { return } this.style[key] = value; var taskCenter = getTaskCenter(this.docId); if (!silent && taskCenter) { var result = {}; result[key] = value; taskCenter.send( 'dom', { action: 'updateStyle' }, [this.ref, result] ); } }; /** * Set batched style properties. * @param {object} batchedStyles * @param {boolean} silent */ Element.prototype.setStyles = function setStyles (batchedStyles, silent) { var this$1 = this; if (isEmpty(batchedStyles)) { return } var mutations = {}; for (var key in batchedStyles) { if (this$1.style[key] !== batchedStyles[key]) { this$1.style[key] = batchedStyles[key]; mutations[key] = batchedStyles[key]; } } if (!isEmpty(mutations)) { var taskCenter = getTaskCenter(this.docId); if (!silent && taskCenter) { taskCenter.send( 'dom', { action: 'updateStyle' }, [this.ref, mutations] ); } } }; /** * TODO: deprecated * Set style properties from class. * @param {object} classStyle */ Element.prototype.setClassStyle = function setClassStyle (classStyle) { var this$1 = this; // reset previous class style to empty string for (var key in this$1.classStyle) { this$1.classStyle[key] = ''; } Object.assign(this.classStyle, classStyle); var taskCenter = getTaskCenter(this.docId); if (taskCenter) { taskCenter.send( 'dom', { action: 'updateStyle' }, [this.ref, this.toStyle()] ); } }; /** * Set class list. * @param {array} classList */ Element.prototype.setClassList = function setClassList (classList) { var classes = typeof classList === 'string' ? classList.split(/\s+/) : Array.from(classList); if (Array.isArray(classes) && classes.length > 0) { this.classList = classes; var taskCenter = getTaskCenter(this.docId); if (taskCenter) { taskCenter.send( 'dom', { action: 'updateClassList' }, [this.ref, this.classList.slice()] ); } } }; /** * Add an event handler. * @param {string} event type * @param {function} event handler */ Element.prototype.addEvent = function addEvent (type, handler, params) { if (!this.event) { this.event = {}; } if (!this.event[type]) { this.event[type] = { handler: handler, params: params }; var taskCenter = getTaskCenter(this.docId); if (taskCenter) { taskCenter.send( 'dom', { action: 'addEvent' }, [this.ref, type] ); } } }; /** * Remove an event handler. * @param {string} event type */ Element.prototype.removeEvent = function removeEvent (type) { if (this.event && this.event[type]) { delete this.event[type]; var taskCenter = getTaskCenter(this.docId); if (taskCenter) { taskCenter.send( 'dom', { action: 'removeEvent' }, [this.ref, type] ); } } }; /** * Fire an event manually. * @param {string} type type * @param {function} event handler * @param {boolean} isBubble whether or not event bubble * @param {boolean} options * @return {} anything returned by handler function */ Element.prototype.fireEvent = function fireEvent (type, event, isBubble, options) { var result = null; var isStopPropagation = false; var eventDesc = this.event[type]; if (eventDesc && event) { var handler = eventDesc.handler; event.stopPropagation = function () { isStopPropagation = true; }; if (options && options.params) { result = handler.call.apply(handler, [ this ].concat( options.params, [event] )); } else { result = handler.call(this, event); } } if (!isStopPropagation && isBubble && (BUBBLE_EVENTS.indexOf(type) !== -1) && this.parentNode && this.parentNode.fireEvent) { event.currentTarget = this.parentNode; this.parentNode.fireEvent(type, event, isBubble); // no options } return result }; /** * Get all styles of current element. * @return {object} style */ Element.prototype.toStyle = function toStyle () { return Object.assign({}, this.classStyle, this.style) }; /** * Convert current element to JSON like object. * @return {object} element */ Element.prototype.toJSON = function toJSON () { var this$1 = this; var result = { ref: this.ref.toString(), type: this.type }; if (!isEmpty(this.attr)) { result.attr = this.attr; } if (this.classList.length > 0) { result.classList = this.classList.slice(); } var style = this.toStyle(); if (!isEmpty(style)) { result.style = style; } var event = []; for (var type in this$1.event) { var ref = this$1.event[type]; var params = ref.params; if (!params) { event.push(type); } else { event.push({ type: type, params: params }); } } if (event.length) { result.event = event; } if (this.pureChildren.length) { result.children = this.pureChildren.map(function (child) { return child.toJSON(); }); } return result }; /** * Convert to HTML element tag string. * @return {stirng} html */ Element.prototype.toString = function toString () { return '<' + this.type + ' attr=' + JSON.stringify(this.attr) + ' style=' + JSON.stringify(this.toStyle()) + '>' + this.pureChildren.map(function (child) { return child.toString(); }).join('') + '</' + this.type + '>' }; return Element; }(Node)); setElement(Element); /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * Normalize a primitive value. * @param {any} v * @return {primitive} */ function normalizePrimitive (v) { var type = typof(v); switch (type) { case 'Undefined': case 'Null': return '' case 'RegExp': return v.toString() case 'Date': return v.toISOString() case 'Number': case 'String': case 'Boolean': case 'Array': case 'Object': return v case 'ArrayBuffer': return { '@type': 'binary', dataType: type, base64: bufferToBase64(v) } case 'Int8Array': case 'Uint8Array': case 'Uint8ClampedArray': case 'Int16Array': case 'Uint16Array': case 'Int32Array': case 'Uint32Array': case 'Float32Array': case 'Float64Array': return { '@type': 'binary', dataType: type, base64: bufferToBase64(v.buffer) } default: return JSON.stringify(v) } } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var fallback = function () {}; // The API of TaskCenter would be re-design. var TaskCenter = function TaskCenter (id, sendTasks) { Object.defineProperty(this, 'instanceId', { enumerable: true, value: String(id) }); Object.defineProperty(this, 'callbackManager', { enumerable: true, value: new CallbackManager(id) }); fallback = sendTasks || function () {}; }; TaskCenter.prototype.callback = function callback (callbackId, data, ifKeepAlive) { return this.callbackManager.consume(callbackId, data, ifKeepAlive) }; TaskCenter.prototype.registerHook = function registerHook () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (ref = this.callbackManager).registerHook.apply(ref, args) var ref; }; TaskCenter.prototype.triggerHook = function triggerHook () { var args = [], len = arguments.length; while ( len-- ) args[ len ] = arguments[ len ]; return (ref = this.callbackManager).triggerHook.apply(ref, args) var ref; }; TaskCenter.prototype.updateData = function updateData (componentId, newData, callback) { this.send('module', { module: 'dom', method: 'updateComponentData' }, [componentId, newData, callback]); }; TaskCenter.prototype.destroyCallback = function destroyCallback () { return this.callbackManager.close() }; /** * Normalize a value. Specially, if the value is a function, then generate a function id * and save it to `CallbackManager`, at last return the function id. * @param{any} v * @return {primitive} */ TaskCenter.prototype.normalize = function normalize (v) { var type = typof(v); if (v && v instanceof Element) { return v.ref } if (v && v._isVue && v.$el instanceof Element) { return v.$el.ref } if (type === 'Function') { return this.callbackManager.add(v).toString() } return normalizePrimitive(v) }; TaskCenter.prototype.send = function send (type, params, args, options) { var this$1 = this; var action = params.action; var component = params.component; var ref = params.ref; var module = params.module; var method = params.method; args = args.map(function (arg) { return this$1.normalize(arg); }); switch (type) { case 'dom': return this[action](this.instanceId, args) case 'component': return this.componentHandler(this.instanceId, ref, method, args, Object.assign({ component: component }, options)) default: return this.moduleHandler(this.instanceId, module, method, args, options) } }; TaskCenter.prototype.callDOM = function callDOM (action, args) { return this[action](this.instanceId, args) }; TaskCenter.prototype.callComponent = function callComponent (ref, method, args, options) { return this.componentHandler(this.instanceId, ref, method, args, options) }; TaskCenter.prototype.callModule = function callModule (module, method, args, options) { return this.moduleHandler(this.instanceId, module, method, args, options) }; function init$1 () { var DOM_METHODS = { createFinish: global.callCreateFinish, updateFinish: global.callUpdateFinish, refreshFinish: global.callRefreshFinish, createBody: global.callCreateBody, registerStyleSheets: global.callRegisterStyleSheets, addElement: global.callAddElement, removeElement: global.callRemoveElement, moveElement: global.callMoveElement, updateAttrs: global.callUpdateAttrs, updateStyle: global.callUpdateStyle, updateClassList: global.callUpdateClassList, addEvent: global.callAddEvent, removeEvent: global.callRemoveEvent }; var proto = TaskCenter.prototype; var loop = function ( name ) { var method = DOM_METHODS[name]; proto[name] = method ? function (id, args) { return method.apply(void 0, [ id ].concat( args )); } : function (id, args) { return fallback(id, [{ module: 'dom', method: name, args: args }], '-1'); }; }; for (var name in DOM_METHODS) loop( name ); proto.componentHandler = global.callNativeComponent || (function (id, ref, method, args, options) { return fallback(id, [{ component: options.component, ref: ref, method: method, args: args }]); }); proto.moduleHandler = global.callNativeModule || (function (id, module, method, args) { return fallback(id, [{ module: module, method: method, args: args }]); }); } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ function fireEvent (document, nodeId, type, event, domChanges, params) { var el = document.getRef(nodeId); if (el) { return document.fireEvent(el, type, event, domChanges, params) } return new Error(("invalid element reference \"" + nodeId + "\"")) } function callback (document, callbackId, data, ifKeepAlive) { return document.taskCenter.callback(callbackId, data, ifKeepAlive) } function componentHook (document, componentId, type, hook, args) { if (!document || !document.taskCenter) { console.error("[JS Framework] Can't find \"document\" or \"taskCenter\"."); return null } var result = null; try { result = document.taskCenter.triggerHook(componentId, type, hook, args); } catch (e) { console.error(("[JS Framework] Failed to trigger the \"" + type + "@" + hook + "\" hook on " + componentId + ".")); } return result } /** * Accept calls from native (event or callback). * * @param {string} id * @param {array} tasks list with `method` and `args` */ function receiveTasks (id, tasks) { var document = getDoc(id); if (!document) { return new Error("[JS Framework] Failed to receiveTasks, " + "instance (" + id + ") is not available.") } if (Array.isArray(tasks)) { return tasks.map(function (task) { switch (task.method) { case 'callback': return callback.apply(void 0, [ document ].concat( task.args )) case 'fireEventSync': case 'fireEvent': return fireEvent.apply(void 0, [ document ].concat( task.args )) case 'componentHook': return componentHook.apply(void 0, [ document ].concat( task.args )) } }) } } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var weexModules = {}; /** * Register native modules information. * @param {object} newModules */ function registerModules (newModules) { var loop = function ( name ) { if (!weexModules[name]) { weexModules[name] = {}; } newModules[name].forEach(function (method) { if (typeof method === 'string') { weexModules[name][method] = true; } else { weexModules[name][method.name] = method.args; } }); }; for (var name in newModules) loop( name ); } /** * Check whether the module or the method has been registered. * @param {String} module name * @param {String} method name (optional) */ function isRegisteredModule (name, method) { if (typeof method === 'string') { return !!(weexModules[name] && weexModules[name][method]) } return !!weexModules[name] } function getModuleDescription (name) { return weexModules[name] } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var weexComponents = {}; /** * Register native components information. * @param {array} newComponents */ function registerComponents (newComponents) { if (Array.isArray(newComponents)) { newComponents.forEach(function (component) { if (!component) { return } if (typeof component === 'string') { weexComponents[component] = true; } else if (typeof component === 'object' && typeof component.type === 'string') { weexComponents[component.type] = component; registerElement(component.type, component.methods); } }); } } /** * Check whether the component has been registered. * @param {String} component name */ function isRegisteredComponent (name) { return !!weexComponents[name] } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ // JS Services var services = []; /** * Register a JavaScript service. * A JavaScript service options could have a set of lifecycle methods * for each Weex instance. For example: create, refresh, destroy. * For the JS framework maintainer if you want to supply some features * which need to work well in different Weex instances, even in different * frameworks separately. You can make a JavaScript service to init * its variables or classes for each Weex instance when it's created * and recycle them when it's destroyed. * @param {object} options Could have { create, refresh, destroy } * lifecycle methods. In create method it should * return an object of what variables or classes * would be injected into the Weex instance. */ function register (name, options) { if (has(name)) { console.warn(("Service \"" + name + "\" has been registered already!")); } else { options = Object.assign({}, options); services.push({ name: name, options: options }); } } /** * Unregister a JavaScript service by name * @param {string} name */ function unregister (name) { services.some(function (service, index) { if (service.name === name) { services.splice(index, 1); return true } }); } /** * Check if a JavaScript service with a certain name existed. * @param {string} name * @return {Boolean} */ function has (name) { return indexOf(name) >= 0 } /** * Find the index of a JavaScript service by name * @param {string} name * @return {number} */ function indexOf (name) { return services.map(function (service) { return service.name; }).indexOf(name) } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ function track (id, type, value) { var taskCenter = getTaskCenter(id); if (!taskCenter || typeof taskCenter.send !== 'function') { console.error("[JS Framework] Failed to create tracker!"); return } if (!type || !value) { console.warn(("[JS Framework] Invalid track type (" + type + ") or value (" + value + ")")); return } var label = "jsfm." + type + "." + value; try { if (isRegisteredModule('userTrack', 'addPerfPoint')) { var message = Object.create(null); message[label] = '4'; taskCenter.send('module', { module: 'userTrack', method: 'addPerfPoint' }, [message]); } } catch (err) { console.error(("[JS Framework] Failed to trace \"" + label + "\"!")); } } /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ var Comment = (function (Node$$1) { function Comment (value) { Node$$1.call(this); this.nodeType = 8; this.nodeId = uniqueId(); this.ref = this.nodeId; this.type = 'comment'; this.value = value; this.children = []; this.pureChildren = []; } if ( Node$$1 ) Comment.__proto__ = Node$$1; Comment.prototype = Object.create( Node$$1 && Node$$1.prototype ); Comment.prototype.constructor = Comment; /** * Convert to HTML comment string. * @return {stirng} html */ Comment.prototype.toString = function toString () { return '<!-- ' + this.value + ' -->' }; return Comment; }(Node)); /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /** * Create the action object. * @param {string} name * @param {array} arguments * @return {object} action */ function createAction (name, args) { if ( args === void 0 ) args = []; return { module: 'dom', method: name, args: args } } var Listener = function Listener (id, handler) { this.id = id; this.batched = false; this.updates = []; if (typeof handler === 'function') { Object.defineProperty(this, 'handler', { configurable: true, enumerable: true, writable: true, value: handler }); } else { console.error('[JS Runtime] invalid parameter, handler