weex-js-runtime
Version:
Weex JS Runtime
1,732 lines (1,579 loc) • 80.2 kB
JavaScript
/* 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