You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by ji...@apache.org on 2017/02/20 06:41:05 UTC
[16/50] [abbrv] incubator-weex git commit: V0.10.0 stable gitlab
(#178)
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/callback-manager.js
----------------------------------------------------------------------
diff --git a/html5/runtime/callback-manager.js b/html5/runtime/callback-manager.js
new file mode 100644
index 0000000..3dad20d
--- /dev/null
+++ b/html5/runtime/callback-manager.js
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ */
+export default class CallbackManager {
+ constructor (instanceId) {
+ this.instanceId = instanceId
+ this.lastCallbackId = 0
+ this.callbacks = []
+ }
+ add (callback) {
+ this.lastCallbackId++
+ this.callbacks[this.lastCallbackId] = callback
+ return this.lastCallbackId
+ }
+ remove (callbackId) {
+ const callback = this.callbacks[callbackId]
+ this.callbacks[callbackId] = undefined
+ return callback
+ }
+ consume (callbackId, data, ifKeepAlive) {
+ const callback = this.callbacks[callbackId]
+ if (typeof ifKeepAlive === 'undefined' || ifKeepAlive === false) {
+ this.callbacks[callbackId] = undefined
+ }
+ if (typeof callback === 'function') {
+ return callback(data)
+ }
+ return new Error(`invalid callback id "${callbackId}"`)
+ }
+ close () {
+ this.callbacks = this.callbacks.map(cb => undefined)
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/config.js
----------------------------------------------------------------------
diff --git a/html5/runtime/config.js b/html5/runtime/config.js
new file mode 100644
index 0000000..d69d44e
--- /dev/null
+++ b/html5/runtime/config.js
@@ -0,0 +1,15 @@
+import { Document, Element, Comment } from './vdom'
+import Listener from './listener'
+import { TaskCenter } from './task-center'
+
+const config = {
+ Document, Element, Comment, Listener,
+ TaskCenter,
+ sendTasks (...args) {
+ return global.callNative(...args)
+ }
+}
+
+Document.handler = config.sendTasks
+
+export default config
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/handler.js
----------------------------------------------------------------------
diff --git a/html5/runtime/handler.js b/html5/runtime/handler.js
index c285d65..21a68bd 100644
--- a/html5/runtime/handler.js
+++ b/html5/runtime/handler.js
@@ -21,7 +21,7 @@ const handlerMap = {
* @return {function} taskHandler
*/
export function createHandler (id, handler) {
- const defaultHandler = handler || callNative
+ const defaultHandler = handler || global.callNative
/* istanbul ignore if */
if (typeof defaultHandler !== 'function') {
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/index.js
----------------------------------------------------------------------
diff --git a/html5/runtime/index.js b/html5/runtime/index.js
index 88c6381..aaa3423 100644
--- a/html5/runtime/index.js
+++ b/html5/runtime/index.js
@@ -6,30 +6,27 @@
*/
import * as shared from '../shared'
-import { Document, Element, Comment } from './vdom'
-import Listener from './listener'
-import init from './init'
-const config = {
- Document, Element, Comment, Listener,
- sendTasks (...args) {
- return global.callNative(...args)
- }
-}
+import init from './init'
+import config from './config'
-Document.handler = config.sendTasks
+import {
+ register,
+ unregister,
+ has
+} from './service'
/* istanbul ignore next */
function freezePrototype () {
shared.freezePrototype()
- Object.freeze(Element)
- Object.freeze(Comment)
- Object.freeze(Listener)
- Object.freeze(Document.prototype)
- Object.freeze(Element.prototype)
- Object.freeze(Comment.prototype)
- Object.freeze(Listener.prototype)
+ Object.freeze(config.Element)
+ Object.freeze(config.Comment)
+ Object.freeze(config.Listener)
+ Object.freeze(config.Document.prototype)
+ Object.freeze(config.Element.prototype)
+ Object.freeze(config.Comment.prototype)
+ Object.freeze(config.Listener.prototype)
}
export default {
@@ -37,6 +34,7 @@ export default {
resetNativeConsole: shared.resetNativeConsole,
setNativeTimer: shared.setNativeTimer,
resetNativeTimer: shared.resetNativeTimer,
+ service: { register, unregister, has },
freezePrototype,
init,
config
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/init.js
----------------------------------------------------------------------
diff --git a/html5/runtime/init.js b/html5/runtime/init.js
index 1cba7ca..ad44460 100644
--- a/html5/runtime/init.js
+++ b/html5/runtime/init.js
@@ -1,4 +1,9 @@
+import { init as initTaskHandler } from './task-center'
+import { registerElement } from './vdom/element-types'
+import { services, register, unregister } from './service'
+
let frameworks
+let runtimeConfig
const versionRegExp = /^\s*\/\/ *(\{[^}]*\}) *\r?\n/
@@ -21,6 +26,26 @@ function checkVersion (code) {
return info
}
+function createServices (id, env, config) {
+ // Init JavaScript services for this instance.
+ const serviceMap = Object.create(null)
+ serviceMap.service = Object.create(null)
+ services.forEach(({ name, options }) => {
+ if (process.env.NODE_ENV === 'development') {
+ console.debug(`[JS Runtime] create service ${name}.`)
+ }
+ const create = options.create
+ if (create) {
+ const result = create(id, env, config)
+ Object.assign(serviceMap.service, result)
+ Object.assign(serviceMap, result.instance)
+ }
+ })
+ delete serviceMap.service.instance
+ Object.freeze(serviceMap.service)
+ return serviceMap
+}
+
const instanceMap = {}
/**
@@ -33,24 +58,38 @@ const instanceMap = {}
*/
function createInstance (id, code, config, data) {
let info = instanceMap[id]
+
if (!info) {
+ // Init instance info.
info = checkVersion(code) || {}
if (!frameworks[info.framework]) {
info.framework = 'Weex'
}
- info.created = Date.now()
- instanceMap[id] = info
+
+ // Init instance config.
config = JSON.parse(JSON.stringify(config || {}))
config.bundleVersion = info.version
config.env = JSON.parse(JSON.stringify(global.WXEnvironment || {}))
console.debug(`[JS Framework] create an ${info.framework}@${config.bundleVersion} instance from ${config.bundleVersion}`)
- return frameworks[info.framework].createInstance(id, code, config, data)
+
+ const env = {
+ info,
+ config,
+ created: Date.now(),
+ framework: info.framework
+ }
+ env.services = createServices(id, env, runtimeConfig)
+ instanceMap[id] = env
+
+ return frameworks[info.framework].createInstance(id, code, config, data, env)
}
return new Error(`invalid instance id "${id}"`)
}
const methods = {
- createInstance
+ createInstance,
+ registerService: register,
+ unregisterService: unregister
}
/**
@@ -59,6 +98,9 @@ const methods = {
*/
function genInit (methodName) {
methods[methodName] = function (...args) {
+ if (methodName === 'registerComponents') {
+ checkComponentMethods(args[0])
+ }
for (const name in frameworks) {
const framework = frameworks[name]
if (framework && framework[methodName]) {
@@ -68,6 +110,16 @@ function genInit (methodName) {
}
}
+function checkComponentMethods (components) {
+ if (Array.isArray(components)) {
+ components.forEach((name) => {
+ if (name && name.type && name.methods) {
+ registerElement(name.type, name.methods)
+ }
+ })
+ }
+}
+
/**
* Register methods which will be called for each instance.
* @param {string} methodName
@@ -78,9 +130,26 @@ function genInstance (methodName) {
const info = instanceMap[id]
if (info && frameworks[info.framework]) {
const result = frameworks[info.framework][methodName](...args)
- if (methodName === 'destroyInstance') {
+
+ // Lifecycle methods
+ if (methodName === 'refreshInstance') {
+ services.forEach(service => {
+ const refresh = service.options.refresh
+ if (refresh) {
+ refresh(id, { info, runtime: runtimeConfig })
+ }
+ })
+ }
+ else if (methodName === 'destroyInstance') {
+ services.forEach(service => {
+ const destroy = service.options.destroy
+ if (destroy) {
+ destroy(id, { info, runtime: runtimeConfig })
+ }
+ })
delete instanceMap[id]
}
+
return result
}
return new Error(`invalid instance id "${id}"`)
@@ -105,7 +174,9 @@ function adaptInstance (methodName, nativeMethodName) {
}
export default function init (config) {
- frameworks = config.frameworks || {}
+ runtimeConfig = config || {}
+ frameworks = runtimeConfig.frameworks || {}
+ initTaskHandler()
// Init each framework by `init` method and `config` which contains three
// virtual-DOM Class: `Document`, `Element` & `Comment`, and a JS bridge method:
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/service.js
----------------------------------------------------------------------
diff --git a/html5/runtime/service.js b/html5/runtime/service.js
new file mode 100644
index 0000000..0773ed6
--- /dev/null
+++ b/html5/runtime/service.js
@@ -0,0 +1,58 @@
+// JS Services
+
+export const 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.
+ */
+export function register (name, options) {
+ if (has(name)) {
+ console.warn(`Service "${name}" has been registered already!`)
+ }
+ else {
+ options = Object.assign({}, options)
+ services.push({ name, options })
+ }
+}
+
+/**
+ * Unregister a JavaScript service by name
+ * @param {string} name
+ */
+export function unregister (name) {
+ services.some((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}
+ */
+export 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(service => service.name).indexOf(name)
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/task-center.js
----------------------------------------------------------------------
diff --git a/html5/runtime/task-center.js b/html5/runtime/task-center.js
new file mode 100644
index 0000000..c39192a
--- /dev/null
+++ b/html5/runtime/task-center.js
@@ -0,0 +1,129 @@
+import CallbackManager from './callback-manager'
+import Element from './vdom/element'
+
+let fallback = function () {}
+
+// The API of TaskCenter would be re-design.
+export class TaskCenter {
+ constructor (id, sendTasks) {
+ Object.defineProperty(this, 'instanceId', {
+ enumerable: true,
+ value: id
+ })
+ Object.defineProperty(this, 'callbackManager', {
+ enumerable: true,
+ value: new CallbackManager()
+ })
+ fallback = sendTasks || function () {}
+ }
+
+ callback (callbackId, data, ifKeepAlive) {
+ return this.callbackManager.consume(callbackId, data, ifKeepAlive)
+ }
+
+ destroyCallback () {
+ return this.callbackManager.close()
+ }
+
+ typof (v) {
+ const s = Object.prototype.toString.call(v)
+ return s.substring(8, s.length - 1).toLowerCase()
+ }
+
+ /**
+ * 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
+ * @param {object} app
+ * @return {primitive}
+ */
+ normalize (v) {
+ const type = this.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':
+ if (v instanceof Element) {
+ return v.ref
+ }
+ return v
+ case 'function':
+ return this.callbackManager.add(v).toString()
+ /* istanbul ignore next */
+ default:
+ return JSON.stringify(v)
+ }
+ }
+
+ send (type, options, args) {
+ const { action, component, ref, module, method } = options
+
+ args = args.map(arg => this.normalize(arg))
+
+ switch (type) {
+ case 'dom':
+ return this[action](this.instanceId, args)
+ case 'component':
+ return this.componentHandler(this.instanceId, ref, method, args, { component })
+ default:
+ return this.moduleHandler(this.instanceId, module, method, args, {})
+ }
+ }
+
+ callDOM (action, args) {
+ return this[action](this.instanceId, args)
+ }
+
+ callComponent (ref, method, args) {
+ return this.componentHandler(this.instanceId, ref, method, args, {})
+ }
+
+ callModule (module, method, args) {
+ return this.moduleHandler(this.instanceId, module, method, args, {})
+ }
+}
+
+export function init () {
+ const DOM_METHODS = {
+ createFinish: global.callCreateFinish,
+ updateFinish: global.callUpdateFinish,
+ refreshFinish: global.callRefreshFinish,
+
+ createBody: global.callCreateBody,
+
+ addElement: global.callAddElement,
+ removeElement: global.callRemoveElement,
+ moveElement: global.callMoveElement,
+ updateAttrs: global.callUpdateAttrs,
+ updateStyle: global.callUpdateStyle,
+
+ addEvent: global.callAddEvent,
+ removeEvent: global.callRemoveEvent
+ }
+ const proto = TaskCenter.prototype
+
+ for (const name in DOM_METHODS) {
+ const method = DOM_METHODS[name]
+ proto[name] = method ?
+ (id, args) => method(id, ...args) :
+ (id, args) => fallback(id, [{ module: 'dom', method: name, args }], '-1')
+ }
+
+ proto.componentHandler = global.callNativeComponent ||
+ ((id, ref, method, args, options) =>
+ fallback(id, [{ component: options.component, ref, method, args }]))
+
+ proto.moduleHandler = global.callNativeModule ||
+ ((id, module, method, args) =>
+ fallback(id, [{ module, method, args }]))
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/vdom/document.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/document.js b/html5/runtime/vdom/document.js
index cf6b097..34e8936 100644
--- a/html5/runtime/vdom/document.js
+++ b/html5/runtime/vdom/document.js
@@ -7,6 +7,7 @@ import '../../shared/objectAssign'
import Comment from './comment'
import Element from './element'
import Listener from '../listener'
+import { TaskCenter } from '../task-center'
import { createHandler } from '../handler'
import { addDoc, removeDoc, appendBody, setBody } from './operation'
@@ -18,7 +19,8 @@ export default function Document (id, url, handler) {
addDoc(id, this)
this.nodeMap = {}
const L = Document.Listener || Listener
- this.listener = new L(id, handler || createHandler(id, Document.handler))
+ this.listener = new L(id, handler || createHandler(id, Document.handler)) // deprecated
+ this.taskCenter = new TaskCenter(id, handler ? (id, ...args) => handler(...args) : Document.handler)
this.createDocumentElement()
}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/vdom/element-types.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/element-types.js b/html5/runtime/vdom/element-types.js
new file mode 100644
index 0000000..a4a24cc
--- /dev/null
+++ b/html5/runtime/vdom/element-types.js
@@ -0,0 +1,65 @@
+import { getTaskCenter } from './operation'
+
+let Element
+
+export function setElement (El) {
+ Element = El
+}
+
+/**
+ * A map which stores all type of elements.
+ * @type {Object}
+ */
+export const elementTypes = {}
+
+/**
+ * Register an extended element type with component methods.
+ * @param {string} type component type
+ * @param {array} methods a list of method names
+ */
+export function registerElement (type, methods) {
+ // Skip when no special component methods.
+ if (!methods || !methods.length) {
+ return
+ }
+
+ // Init constructor.
+ const XElement = function (props) {
+ Element.call(this, type, props, true)
+ }
+
+ // Init prototype.
+ XElement.prototype = Object.create(Element.prototype)
+ Object.defineProperty(XElement.prototype, 'constructor', {
+ configurable: false,
+ enumerable: false,
+ writable: false,
+ value: Element
+ })
+
+ // Add methods to prototype.
+ methods.forEach(methodName => {
+ XElement.prototype[methodName] = function (...args) {
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter) {
+ return taskCenter.send('component', {
+ ref: this.ref,
+ component: type,
+ method: methodName
+ }, args)
+ }
+ }
+ })
+
+ // Add to element type map.
+ elementTypes[type] = XElement
+}
+
+/**
+ * Clear all element types. Only for testing.
+ */
+export function clearElementTypes () {
+ for (const type in elementTypes) {
+ delete elementTypes[type]
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/vdom/element.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/element.js b/html5/runtime/vdom/element.js
index 2af5054..e7a7526 100644
--- a/html5/runtime/vdom/element.js
+++ b/html5/runtime/vdom/element.js
@@ -7,7 +7,7 @@ import '../../shared/objectAssign'
import Node from './node'
import {
getDoc,
- getListener,
+ getTaskCenter,
uniqueId,
linkParent,
nextElement,
@@ -16,10 +16,18 @@ import {
moveIndex,
removeIndex
} from './operation'
+import {
+ elementTypes,
+ setElement
+} from './element-types'
const DEFAULT_TAG_NAME = 'div'
-export default function Element (type = DEFAULT_TAG_NAME, props) {
+export default function Element (type = DEFAULT_TAG_NAME, props, isExtended) {
+ const XElement = elementTypes[type]
+ if (XElement && !isExtended) {
+ return new XElement(props)
+ }
props = props || {}
this.nodeType = 1
this.nodeId = uniqueId()
@@ -41,6 +49,8 @@ function registerNode (docId, node) {
doc.nodeMap[node.nodeId] = node
}
+setElement(Element)
+
Object.assign(Element.prototype, {
/**
* Append a child node.
@@ -60,9 +70,13 @@ Object.assign(Element.prototype, {
}
if (node.nodeType === 1) {
insertIndex(node, this.pureChildren, this.pureChildren.length)
- const listener = getListener(this.docId)
- if (listener) {
- return listener.addElement(node, this.ref, -1)
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter) {
+ return taskCenter.send(
+ 'dom',
+ { action: 'addElement' },
+ [this.ref, node.toJSON(), -1]
+ )
}
}
}
@@ -70,9 +84,13 @@ Object.assign(Element.prototype, {
moveIndex(node, this.children, this.children.length, true)
if (node.nodeType === 1) {
const index = moveIndex(node, this.pureChildren, this.pureChildren.length)
- const listener = getListener(this.docId)
- if (listener && index >= 0) {
- return listener.moveElement(node.ref, this.ref, index)
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter && index >= 0) {
+ return taskCenter.send(
+ 'dom',
+ { action: 'moveElement' },
+ [node.ref, this.ref, index]
+ )
}
}
}
@@ -106,9 +124,13 @@ Object.assign(Element.prototype, {
? this.pureChildren.indexOf(pureBefore)
: this.pureChildren.length
)
- const listener = getListener(this.docId)
- if (listener) {
- return listener.addElement(node, this.ref, index)
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter) {
+ return taskCenter.send(
+ 'dom',
+ { action: 'addElement' },
+ [this.ref, node.toJSON(), index]
+ )
}
}
}
@@ -116,6 +138,7 @@ Object.assign(Element.prototype, {
moveIndex(node, this.children, this.children.indexOf(before), true)
if (node.nodeType === 1) {
const pureBefore = nextElement(before)
+ /* istanbul ignore next */
const index = moveIndex(
node,
this.pureChildren,
@@ -123,9 +146,13 @@ Object.assign(Element.prototype, {
? this.pureChildren.indexOf(pureBefore)
: this.pureChildren.length
)
- const listener = getListener(this.docId)
- if (listener && index >= 0) {
- return listener.moveElement(node.ref, this.ref, index)
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter && index >= 0) {
+ return taskCenter.send(
+ 'dom',
+ { action: 'moveElement' },
+ [node.ref, this.ref, index]
+ )
}
}
}
@@ -157,10 +184,14 @@ Object.assign(Element.prototype, {
this.pureChildren,
this.pureChildren.indexOf(previousElement(after)) + 1
)
- const listener = getListener(this.docId)
+ const taskCenter = getTaskCenter(this.docId)
/* istanbul ignore else */
- if (listener) {
- return listener.addElement(node, this.ref, index)
+ if (taskCenter) {
+ return taskCenter.send(
+ 'dom',
+ { action: 'addElement' },
+ [this.ref, node.toJSON(), index]
+ )
}
}
}
@@ -172,9 +203,13 @@ Object.assign(Element.prototype, {
this.pureChildren,
this.pureChildren.indexOf(previousElement(after)) + 1
)
- const listener = getListener(this.docId)
- if (listener && index >= 0) {
- return listener.moveElement(node.ref, this.ref, index)
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter && index >= 0) {
+ return taskCenter.send(
+ 'dom',
+ { action: 'moveElement' },
+ [node.ref, this.ref, index]
+ )
}
}
}
@@ -190,9 +225,13 @@ Object.assign(Element.prototype, {
removeIndex(node, this.children, true)
if (node.nodeType === 1) {
removeIndex(node, this.pureChildren)
- const listener = getListener(this.docId)
- if (listener) {
- listener.removeElement(node.ref)
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter) {
+ taskCenter.send(
+ 'dom',
+ { action: 'removeElement' },
+ [node.ref]
+ )
}
}
}
@@ -205,11 +244,15 @@ Object.assign(Element.prototype, {
* Clear all child nodes.
*/
clear () {
- const listener = getListener(this.docId)
+ const taskCenter = getTaskCenter(this.docId)
/* istanbul ignore else */
- if (listener) {
+ if (taskCenter) {
this.pureChildren.forEach(node => {
- listener.removeElement(node.ref)
+ taskCenter.send(
+ 'dom',
+ { action: 'removeElement' },
+ [node.ref]
+ )
})
}
this.children.forEach(node => {
@@ -230,9 +273,15 @@ Object.assign(Element.prototype, {
return
}
this.attr[key] = value
- const listener = getListener(this.docId)
- if (!silent && listener) {
- listener.setAttr(this.ref, key, value)
+ const taskCenter = getTaskCenter(this.docId)
+ if (!silent && taskCenter) {
+ const result = {}
+ result[key] = value
+ taskCenter.send(
+ 'dom',
+ { action: 'updateAttrs' },
+ [this.ref, result]
+ )
}
},
@@ -247,9 +296,15 @@ Object.assign(Element.prototype, {
return
}
this.style[key] = value
- const listener = getListener(this.docId)
- if (!silent && listener) {
- listener.setStyle(this.ref, key, value)
+ const taskCenter = getTaskCenter(this.docId)
+ if (!silent && taskCenter) {
+ const result = {}
+ result[key] = value
+ taskCenter.send(
+ 'dom',
+ { action: 'updateStyle' },
+ [this.ref, result]
+ )
}
},
@@ -264,9 +319,13 @@ Object.assign(Element.prototype, {
}
Object.assign(this.classStyle, classStyle)
- const listener = getListener(this.docId)
- if (listener) {
- listener.setStyles(this.ref, this.toStyle())
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter) {
+ taskCenter.send(
+ 'dom',
+ { action: 'updateStyle' },
+ [this.ref, this.toStyle()]
+ )
}
},
@@ -278,9 +337,13 @@ Object.assign(Element.prototype, {
addEvent (type, handler) {
if (!this.event[type]) {
this.event[type] = handler
- const listener = getListener(this.docId)
- if (listener) {
- listener.addEvent(this.ref, type)
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter) {
+ taskCenter.send(
+ 'dom',
+ { action: 'addEvent' },
+ [this.ref, type]
+ )
}
}
},
@@ -292,9 +355,13 @@ Object.assign(Element.prototype, {
removeEvent (type) {
if (this.event[type]) {
delete this.event[type]
- const listener = getListener(this.docId)
- if (listener) {
- listener.removeEvent(this.ref, type)
+ const taskCenter = getTaskCenter(this.docId)
+ if (taskCenter) {
+ taskCenter.send(
+ 'dom',
+ { action: 'removeEvent' },
+ [this.ref, type]
+ )
}
}
},
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/vdom/index.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/index.js b/html5/runtime/vdom/index.js
index 67a85b4..e2f0ad7 100644
--- a/html5/runtime/vdom/index.js
+++ b/html5/runtime/vdom/index.js
@@ -1,9 +1,15 @@
import Node from './node'
-import Comment from './comment'
import Element from './element'
+import Comment from './comment'
import Document from './document'
export {
+ elementTypes,
+ registerElement,
+ clearElementTypes
+} from './element-types'
+
+export {
Document,
Node,
Element,
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/runtime/vdom/operation.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/operation.js b/html5/runtime/vdom/operation.js
index e9bdd99..7f8c65f 100644
--- a/html5/runtime/vdom/operation.js
+++ b/html5/runtime/vdom/operation.js
@@ -29,6 +29,7 @@ export function removeDoc (id) {
}
/**
+ * @deprecated
* Get listener by document id.
* @param {string} id
* @return {object} listener
@@ -42,6 +43,19 @@ export function getListener (id) {
}
/**
+ * Get TaskCenter instance by id.
+ * @param {string} id
+ * @return {object} TaskCenter
+ */
+export function getTaskCenter (id) {
+ const doc = docMap[id]
+ if (doc && doc.taskCenter) {
+ return doc.taskCenter
+ }
+ return null
+}
+
+/**
* Get a unique id.
*/
let nextNodeRef = 1
@@ -88,7 +102,7 @@ export function appendBody (doc, node, before) {
delete doc.nodeMap[node.nodeId]
}
documentElement.pureChildren.push(node)
- doc.listener.createBody(node)
+ sendBody(doc, node)
}
else {
node.parentNode = documentElement
@@ -96,6 +110,19 @@ export function appendBody (doc, node, before) {
}
}
+function sendBody (doc, node) {
+ const body = node.toJSON()
+ const children = body.children
+ delete body.children
+ let result = doc.taskCenter.send('dom', { action: 'createBody' }, [body])
+ if (children) {
+ children.forEach(child => {
+ result = doc.taskCenter.send('dom', { action: 'addElement' }, [body.ref, child, -1])
+ })
+ }
+ return result
+}
+
/**
* Set up body node.
* @param {object} document
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/services/amd/index.js
----------------------------------------------------------------------
diff --git a/html5/services/amd/index.js b/html5/services/amd/index.js
new file mode 100644
index 0000000..dd5a0eb
--- /dev/null
+++ b/html5/services/amd/index.js
@@ -0,0 +1,86 @@
+/**
+ * @fileOverview
+ * A simple implementation of AMD for weex.
+ */
+
+/**
+ * amd modules (<id, module> pair)
+ * - id : instance id.
+ * - module: {
+ * name: module name
+ * , factory: module's factory function
+ * , cached: cached module,
+ * , deps: module's dependencies, always be [] under most circumstances.
+ * }
+ */
+const modules = {}
+
+const amdService = {
+
+ // create a amd service.
+ create: (id, env, config) => {
+ if (!env.framework.match(/Vue/i)) {
+ return
+ }
+
+ const mod = {}
+ modules[id] = mod
+ const amdObject = {
+
+ /**
+ * define a module.
+ * @param {String} name: module name.
+ * @param {Array} deps: dependencies. Always be empty array.
+ * @param {function} factory: factory function.
+ */
+ define (name, deps, factory) {
+ if (mod[name]) {
+ console.warn(`[amdService] already defined module: '${name}'`)
+ }
+ if (typeof deps === 'function') {
+ factory = deps
+ deps = []
+ }
+ mod[name] = { name, factory, cached: false, deps }
+ },
+
+ /**
+ * require a module.
+ * @param {string} name - module name.
+ */
+ require (name) {
+ const servMod = mod[name]
+ if (!servMod) {
+ return console.warn(`[amdService] module '${name}' is not defined.`)
+ }
+ if (servMod.cached) {
+ return servMod.cached
+ }
+ const exports = {}
+ const module = { exports }
+ const { deps } = servMod
+ let ret
+ if (deps && deps.length >= 1) {
+ /**
+ * to support:
+ * define(name, ['foo', 'bar'], function (foo, bar) { ... })
+ */
+ const args = deps.map(depName => require(depName))
+ ret = servMod.factory(...args)
+ }
+ else {
+ ret = servMod.factory(amdObject.require, exports, module)
+ }
+ servMod.cached = ret || module.exports
+ return servMod.cached
+ }
+ }
+ return { instance: amdObject }
+ },
+
+ destroy: (id, env) => {
+ delete modules[id]
+ }
+}
+
+export default amdService
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/services/broadcast-channel/index.js
----------------------------------------------------------------------
diff --git a/html5/services/broadcast-channel/index.js b/html5/services/broadcast-channel/index.js
new file mode 100644
index 0000000..2e04e30
--- /dev/null
+++ b/html5/services/broadcast-channel/index.js
@@ -0,0 +1,106 @@
+/**
+ * @fileOverview
+ * The polyfill of BroadcastChannel API.
+ * This api can be used to achieve inter-instance communications.
+ *
+ * https://html.spec.whatwg.org/multipage/comms.html#broadcasting-to-other-browsing-contexts
+ */
+
+import { MessageEvent } from './message-event'
+
+const channels = {}
+const instances = {}
+
+/**
+ * An empty constructor for BroadcastChannel polyfill.
+ * The real constructor will be defined when a Weex instance created because
+ * we need to track the channel by Weex instance id.
+ */
+function BroadcastChannel () {}
+
+/**
+ * Sends the given message to other BroadcastChannel objects set up for this channel.
+ * @param {any} message
+ */
+BroadcastChannel.prototype.postMessage = function (message) {
+ if (this._closed) {
+ throw new Error(`BroadcastChannel "${this.name}" is closed.`)
+ }
+
+ const subscribers = channels[this.name]
+ if (subscribers && subscribers.length) {
+ for (let i = 0; i < subscribers.length; ++i) {
+ const member = subscribers[i]
+
+ if (member._closed || member === this) continue
+
+ if (typeof member.onmessage === 'function') {
+ member.onmessage(new MessageEvent('message', { data: message }))
+ }
+ }
+ }
+}
+
+/**
+ * Closes the BroadcastChannel object, opening it up to garbage collection.
+ */
+BroadcastChannel.prototype.close = function () {
+ if (this._closed) {
+ return
+ }
+
+ this._closed = true
+
+ // remove itself from channels.
+ if (channels[this.name]) {
+ const subscribers = channels[this.name].filter(x => x !== this)
+ if (subscribers.length) {
+ channels[this.name] = subscribers
+ }
+ else {
+ delete channels[this.name]
+ }
+ }
+}
+
+export default {
+ create: (id, env, config) => {
+ instances[id] = []
+ if (typeof global.BroadcastChannel === 'function') {
+ return {}
+ }
+ const serviceObject = {
+ /**
+ * Returns a new BroadcastChannel object via which messages for the given
+ * channel name can be sent and received.
+ * @param {string} name
+ */
+ BroadcastChannel: function (name) {
+ // the name property is readonly
+ Object.defineProperty(this, 'name', {
+ configurable: false,
+ enumerable: true,
+ writable: false,
+ value: String(name)
+ })
+
+ this._closed = false
+ this.onmessage = null
+
+ if (!channels[this.name]) {
+ channels[this.name] = []
+ }
+ channels[this.name].push(this)
+ instances[id].push(this)
+ }
+ }
+ serviceObject.BroadcastChannel.prototype = BroadcastChannel.prototype
+ return {
+ instance: serviceObject
+ }
+ },
+ destroy: (id, env) => {
+ instances[id].forEach(channel => channel.close())
+ delete instances[id]
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/services/broadcast-channel/message-event.js
----------------------------------------------------------------------
diff --git a/html5/services/broadcast-channel/message-event.js b/html5/services/broadcast-channel/message-event.js
new file mode 100644
index 0000000..437728e
--- /dev/null
+++ b/html5/services/broadcast-channel/message-event.js
@@ -0,0 +1,21 @@
+/**
+ * Mock MessageEvent type
+ * @param {string} type
+ * @param {object} dict { data, origin, source, ports }
+ *
+ * This type has been simplified.
+ * https://html.spec.whatwg.org/multipage/comms.html#messageevent
+ * https://dom.spec.whatwg.org/#interface-event
+ */
+export function MessageEvent (type, dict = {}) {
+ this.type = type || 'message'
+
+ this.data = dict.data || null
+ this.origin = dict.origin || ''
+ this.source = dict.source || null
+ this.ports = dict.ports || []
+
+ // inherit properties
+ this.target = null
+ this.timeStamp = Date.now()
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/services/index.js
----------------------------------------------------------------------
diff --git a/html5/services/index.js b/html5/services/index.js
new file mode 100644
index 0000000..266a4d3
--- /dev/null
+++ b/html5/services/index.js
@@ -0,0 +1,5 @@
+import BroadcastChannel from './broadcast-channel/index'
+
+export default {
+ BroadcastChannel
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/shared/setTimeout.js
----------------------------------------------------------------------
diff --git a/html5/shared/setTimeout.js b/html5/shared/setTimeout.js
index cc3790f..c0fd472 100644
--- a/html5/shared/setTimeout.js
+++ b/html5/shared/setTimeout.js
@@ -40,3 +40,5 @@ export function resetNativeTimer () {
global.setTimeout = originalSetTimeout
global.setTimeoutCallback = null
}
+
+setNativeTimer()
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/case/basic/dynamic-id.output.js
----------------------------------------------------------------------
diff --git a/html5/test/case/basic/dynamic-id.output.js b/html5/test/case/basic/dynamic-id.output.js
new file mode 100644
index 0000000..5029a30
--- /dev/null
+++ b/html5/test/case/basic/dynamic-id.output.js
@@ -0,0 +1,44 @@
+{
+ type: 'div',
+ children: [
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello',
+ a: 1
+ }
+ },
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello',
+ a: 1,
+ b: 1
+ }
+ },
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello'
+ }
+ },
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello'
+ }
+ },
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello'
+ }
+ },
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello'
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/case/basic/dynamic-id.source.js
----------------------------------------------------------------------
diff --git a/html5/test/case/basic/dynamic-id.source.js b/html5/test/case/basic/dynamic-id.source.js
new file mode 100644
index 0000000..d9abf61
--- /dev/null
+++ b/html5/test/case/basic/dynamic-id.source.js
@@ -0,0 +1,76 @@
+define('@weex-component/id', function (require, exports, module) {
+
+;
+ module.exports = {
+ ready: function () {
+ if (this.$el('x')) {
+ this.$el('x').setAttr('a', 1)
+ }
+ if (this.$el('y')) {
+ this.$el('y').setAttr('a', 1)
+ }
+ if (this.$el('')) {
+ this.$el('').setAttr('a', 1)
+ }
+ if (this.$el('0')) {
+ this.$el('0').setAttr('a', 1)
+ }
+ if (this.$el(0)) {
+ this.$el(0).setAttr('b', 1)
+ }
+ }
+ }
+
+;module.exports.template = {
+ "type": "div",
+ "children": [
+ {
+ "type": "text",
+ "id": function () { return "x" },
+ "attr": {
+ "value": "Hello"
+ }
+ },
+ {
+ "type": "text",
+ "id": function () { return 0 },
+ "attr": {
+ "value": "Hello"
+ }
+ },
+ {
+ "type": "text",
+ "id": function () { return '' },
+ "attr": {
+ "value": "Hello"
+ }
+ },
+ {
+ "type": "text",
+ "id": function () { return null },
+ "attr": {
+ "value": "Hello"
+ }
+ },
+ {
+ "type": "text",
+ "id": function () { return NaN },
+ "attr": {
+ "value": "Hello"
+ }
+ },
+ {
+ "type": "text",
+ "id": function () { return },
+ "attr": {
+ "value": "Hello"
+ }
+ }
+ ]
+}
+
+;})
+
+// require module
+
+bootstrap('@weex-component/id')
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/case/basic/global-weex-object.output.js
----------------------------------------------------------------------
diff --git a/html5/test/case/basic/global-weex-object.output.js b/html5/test/case/basic/global-weex-object.output.js
new file mode 100644
index 0000000..3e1fa19
--- /dev/null
+++ b/html5/test/case/basic/global-weex-object.output.js
@@ -0,0 +1,6 @@
+{
+ type: 'div',
+ attr: {
+ a: 'WeexDemo'
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/case/basic/global-weex-object.source.js
----------------------------------------------------------------------
diff --git a/html5/test/case/basic/global-weex-object.source.js b/html5/test/case/basic/global-weex-object.source.js
new file mode 100644
index 0000000..3a8e99f
--- /dev/null
+++ b/html5/test/case/basic/global-weex-object.source.js
@@ -0,0 +1,19 @@
+weex.define('@weex-component/foo', function (require, exports, module) {
+ module.exports = {
+ data: function () {
+ return {
+ x: weex.config.env.appName
+ }
+ },
+ template: {
+ "type": "div",
+ "attr": {
+ "a": function () {
+ return this.x
+ }
+ }
+ }
+ }
+})
+
+weex.bootstrap('@weex-component/foo')
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/case/basic/id.output.js
----------------------------------------------------------------------
diff --git a/html5/test/case/basic/id.output.js b/html5/test/case/basic/id.output.js
new file mode 100644
index 0000000..7ce073c
--- /dev/null
+++ b/html5/test/case/basic/id.output.js
@@ -0,0 +1,32 @@
+{
+ type: 'div',
+ children: [
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello',
+ a: 1
+ }
+ },
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello',
+ a: 1,
+ b: 1
+ }
+ },
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello'
+ }
+ },
+ {
+ type: 'text',
+ attr: {
+ value: 'Hello'
+ }
+ }
+ ]
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/case/basic/id.source.js
----------------------------------------------------------------------
diff --git a/html5/test/case/basic/id.source.js b/html5/test/case/basic/id.source.js
new file mode 100644
index 0000000..4a5fb65
--- /dev/null
+++ b/html5/test/case/basic/id.source.js
@@ -0,0 +1,62 @@
+define('@weex-component/id', function (require, exports, module) {
+
+;
+ module.exports = {
+ ready: function () {
+ if (this.$el('x')) {
+ this.$el('x').setAttr('a', 1)
+ }
+ if (this.$el('y')) {
+ this.$el('y').setAttr('a', 1)
+ }
+ if (this.$el('')) {
+ this.$el('').setAttr('a', 1)
+ }
+ if (this.$el('0')) {
+ this.$el('0').setAttr('a', 1)
+ }
+ if (this.$el(0)) {
+ this.$el(0).setAttr('b', 1)
+ }
+ }
+ }
+
+;module.exports.template = {
+ "type": "div",
+ "children": [
+ {
+ "type": "text",
+ "id": "x",
+ "attr": {
+ "value": "Hello"
+ }
+ },
+ {
+ "type": "text",
+ "id": "0",
+ "attr": {
+ "value": "Hello"
+ }
+ },
+ {
+ "type": "text",
+ "id": '',
+ "attr": {
+ "value": "Hello"
+ }
+ },
+ {
+ "type": "text",
+ "id": null,
+ "attr": {
+ "value": "Hello"
+ }
+ }
+ ]
+}
+
+;})
+
+// require module
+
+bootstrap('@weex-component/id')
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/case/prepare.js
----------------------------------------------------------------------
diff --git a/html5/test/case/prepare.js b/html5/test/case/prepare.js
index fd92918..9629dbb 100644
--- a/html5/test/case/prepare.js
+++ b/html5/test/case/prepare.js
@@ -11,6 +11,7 @@ import {
import shared from '../../shared'
import { Document, Element, Comment } from '../../runtime/vdom'
import Listener from '../../runtime/listener'
+import { TaskCenter, init } from '../../runtime/task-center'
// load framework
import * as defaultFramework from '../../frameworks/legacy'
@@ -27,10 +28,13 @@ global.callAddElement = function (id, ref, json, index) {
return callNativeHandler(id, [{ module: 'dom', method: 'addElement', args: [ref, json, index] }])
}
+init()
+
// create test driver runtime
export function createRuntime () {
const config = {
Document, Element, Comment, Listener,
+ TaskCenter,
sendTasks (...args) {
return callNativeHandler(...args)
}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/case/tester.js
----------------------------------------------------------------------
diff --git a/html5/test/case/tester.js b/html5/test/case/tester.js
index 490a3a4..9c2b299 100644
--- a/html5/test/case/tester.js
+++ b/html5/test/case/tester.js
@@ -46,6 +46,8 @@ describe('test input and output', function () {
app.$destroy()
}
+ it('global Weex object', () => checkOutput(app, 'global-weex-object'))
+
it('single case', () => checkOutput(app, 'foo'))
it('foo2 case', () => checkOutput(app, 'foo2'))
it('foo3 case', () => checkOutput(app, 'foo3'))
@@ -78,6 +80,9 @@ describe('test input and output', function () {
it('repeat with array non-obj case', () => checkOutput(app, 'repeat-array-non-obj'))
it('repeat watch case', () => checkOutput(app, 'repeat-watch'))
+ it('id case', () => checkOutput(app, 'id'))
+ it('dynamic id case', () => checkOutput(app, 'dynamic-id'))
+
it('reset style case', () => checkOutput(app, 'reset-style'))
it('dynamic type case', () => checkOutput(app, 'dynamic-type'))
it('dynamic property case', () => checkOutput(app, 'dynamic-property'))
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/api/methods.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/api/methods.js b/html5/test/unit/default/api/methods.js
index 56f4ce0..6a7d26a 100644
--- a/html5/test/unit/default/api/methods.js
+++ b/html5/test/unit/default/api/methods.js
@@ -35,17 +35,17 @@ describe('built-in methods', () => {
differ: new Differ(),
requireModule: (name) => {
requireSpy(name)
-
const module = requireModule(this, name)
+ const mockModule = {}
for (const moduleName in module) {
- module[moduleName] = function (...args) {
+ mockModule[moduleName] = function (...args) {
moduleSpy(...args)
if (typeof args[args.length - 1] === 'function') {
args[args.length - 1]()
}
}
}
- return module
+ return mockModule
}
},
_setStyle: function () {},
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/app/bundle.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/app/bundle.js b/html5/test/unit/default/app/bundle.js
index 195b457..183ba49 100644
--- a/html5/test/unit/default/app/bundle.js
+++ b/html5/test/unit/default/app/bundle.js
@@ -4,9 +4,6 @@ import sinonChai from 'sinon-chai'
const { expect } = chai
chai.use(sinonChai)
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import * as bundle from '../../../../frameworks/legacy/app/bundle'
import * as register from '../../../../frameworks/legacy/app/register'
import { removeWeexPrefix } from '../../../../frameworks/legacy/util'
@@ -46,19 +43,16 @@ describe('parsing a bundle file', () => {
const id = Date.now()
callTasksSpy = sinon.spy()
- const doc = new Document(id, '', (tasks, callback) => {
- app.callTasks(tasks, callback)
- }, Listener)
+ const doc = new Document(id, '', (tasks) => {
+ app.callTasks(tasks)
+ })
app = {
id, doc,
customComponentMap: {},
commonModules: {},
callbacks: {},
- callTasks: (tasks, callback) => {
- callTasksSpy(tasks)
- callback && callback()
- },
+ callTasks: callTasksSpy,
requireModule: function (name) {
return register.requireModule(this, name)
}
@@ -213,7 +207,6 @@ describe('parsing a bundle file', () => {
expect(callTasksSpy.calledTwice).to.be.true
expect(ready.calledOnce).to.be.true
-
const task1 = callTasksSpy.firstCall.args[0][0]
expect(task1.module).to.be.equal('dom')
expect(task1.method).to.be.equal('createBody')
@@ -256,6 +249,21 @@ describe('parsing a bundle file', () => {
)
expect(result).instanceof(Error)
})
+
+ it('with viewport config', () => {
+ bundle.bootstrap(
+ app,
+ '@weex-component/undefined',
+ {
+ viewport: { width: 640 }
+ }
+ )
+ expect(callTasksSpy.callCount).to.be.equal(1)
+ const tasks = callTasksSpy.lastCall.args[0]
+ expect(tasks[0].module).to.be.equal('meta')
+ expect(tasks[0].method).to.be.equal('setViewport')
+ expect(tasks[0].args).to.deep.equal([{ width: 640 }])
+ })
})
})
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/app/ctrl.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/app/ctrl.js b/html5/test/unit/default/app/ctrl.js
index 9f69431..f7d91f2 100644
--- a/html5/test/unit/default/app/ctrl.js
+++ b/html5/test/unit/default/app/ctrl.js
@@ -4,13 +4,9 @@ import sinonChai from 'sinon-chai'
const { expect } = chai
chai.use(sinonChai)
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import * as ctrl from '../../../../frameworks/legacy/app/ctrl'
import Differ from '../../../../frameworks/legacy/app/differ'
import { Document } from '../../../../runtime/vdom'
-import Listener from '../../../../runtime/listener'
describe('the api of app', () => {
let app
@@ -26,15 +22,14 @@ describe('the api of app', () => {
registerComponent: function () {},
// define: sinon.spy(),
// bootstrap: sinon.stub(),
- callbacks: {
- 1: spy2
- },
vm: {},
differ: new Differ(id)
}
- app.doc = new Document(id, '', spy1, Listener)
+ app.doc = new Document(id, '', spy1)
app.doc.createBody('div')
+
+ app.doc.taskCenter.callbackManager.add(spy2)
// app.bootstrap.returns()
return app
@@ -129,8 +124,6 @@ describe('the api of app', () => {
const data = { a: 'b' }
ctrl.callback(app, '1', data, true)
expect(spy2.calledOnce).to.be.true
- expect(spy2.args[0][0]).to.deep.equal(data)
- expect(app.callbacks[1]).to.be.a('function')
const task = spy1.firstCall.args[0][0]
expect(task.module).to.be.equal('dom')
@@ -142,13 +135,9 @@ describe('the api of app', () => {
const data = { a: 'b' }
ctrl.callback(app, '1', data, true)
expect(spy2.calledTwice).to.be.true
- expect(spy2.args[0][0]).to.deep.equal(data)
- expect(app.callbacks[1]).to.be.a('function')
ctrl.callback(app, '1', data, false)
expect(spy2.calledThrice).to.be.true
- expect(spy2.args[0][0]).to.deep.equal(data)
- expect(app.callbacks[1]).to.be.undefined
})
it('error', () => {
@@ -158,31 +147,6 @@ describe('the api of app', () => {
})
})
- describe('updateActions', () => {
- let originalCallNative
-
- before(() => {
- originalCallNative = global.callNative
- global.callNative = function () {}
- })
-
- after(() => {
- global.callNative = originalCallNative
- })
-
- it('update actions in listener', () => {
- app.doc.listener.updates = [
- {
- method () {},
- args: [undefined, null, /\.x/i, new Date(), 2, '3', true, ['']]
- }
- ]
- ctrl.updateActions(app)
-
- expect(app.doc.listener.updates).to.deep.equal([])
- })
- })
-
describe('refreshData', () => {
it('a simple data', () => {
const data = { b: 'c' }
@@ -219,7 +183,6 @@ describe('the api of app', () => {
expect(app.vm).to.be.null
expect(app.doc).to.be.null
expect(app.customComponentMap).to.be.null
- expect(app.callbacks).to.be.null
})
it('the incomplete data', () => {
const appx = createApp()
@@ -230,7 +193,6 @@ describe('the api of app', () => {
expect(appx.vm).to.be.null
expect(appx.doc).to.be.null
expect(appx.customComponentMap).to.be.null
- expect(appx.callbacks).to.be.null
})
it('clear vms', () => {
const appy = createApp()
@@ -245,7 +207,6 @@ describe('the api of app', () => {
expect(appy.vm).to.be.null
expect(appy.doc).to.be.null
expect(appy.customComponentMap).to.be.null
- expect(appy.callbacks).to.be.null
})
})
})
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/app/index.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/app/index.js b/html5/test/unit/default/app/index.js
index c8c57c0..53a6938 100644
--- a/html5/test/unit/default/app/index.js
+++ b/html5/test/unit/default/app/index.js
@@ -4,43 +4,22 @@ import sinonChai from 'sinon-chai'
const { expect } = chai
chai.use(sinonChai)
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import App from '../../../../frameworks/legacy/app'
-import { Element } from '../../../../runtime/vdom'
+import { Element, Document } from '../../../../runtime/vdom'
describe('App Instance', () => {
- const oriCallNative = global.callNative
- const oriCallAddElement = global.callAddElement
- const callNativeSpy = sinon.spy()
- const callAddElementSpy = sinon.spy()
+ const oriDocumentHandler = Document.handler
+ const sendTasksSpy = sinon.spy()
let app
- before(() => {
- global.callNative = (id, tasks, callbackId) => {
- callNativeSpy(id, tasks, callbackId)
- /* istanbul ignore if */
- if (callbackId !== '-1') {
- app.callbacks[callbackId] && app.callbacks[callbackId]()
- }
- }
- global.callAddElement = (name, ref, json, index, callbackId) => {
- callAddElementSpy(name, ref, json, index, callbackId)
- /* istanbul ignore if */
- if (callbackId !== '-1') {
- app.callbacks[callbackId] && app.callbacks[callbackId]()
- }
- }
- })
-
beforeEach(() => {
- app = new App(Date.now() + '')
+ Document.handler = sendTasksSpy
+ const id = Date.now() + ''
+ app = new App(id, {})
})
- after(() => {
- global.callNative = oriCallNative
- global.callAddElement = oriCallAddElement
+ afterEach(() => {
+ Document.handler = oriDocumentHandler
})
describe('normal check', () => {
@@ -75,7 +54,7 @@ describe('App Instance', () => {
}]
app.callTasks(tasks)
- expect(callNativeSpy.lastCall.args[1]).to.deep.equal(tasks)
+ expect(sendTasksSpy.lastCall.args[1]).to.deep.equal(tasks)
})
it('with callback', (done) => {
@@ -86,11 +65,13 @@ describe('App Instance', () => {
}]
app.callTasks(tasks)
- expect(callNativeSpy.lastCall.args[1]).to.deep.equal(tasks)
+ expect(sendTasksSpy.lastCall.args[1]).to.deep.equal(tasks)
done()
})
it('with function arg', (done) => {
+ const callbackId = '1'
+
const tasks = [{
module: 'dom',
method: 'createBody',
@@ -98,8 +79,11 @@ describe('App Instance', () => {
}]
app.callTasks(tasks)
- expect(callNativeSpy.lastCall.args[1]).to.deep.equal(tasks)
- expect(callNativeSpy.lastCall.args[1][0].args[0]).to.be.a('string')
+ expect(sendTasksSpy.lastCall.args[1]).to.deep.equal([{
+ module: 'dom',
+ method: 'createBody',
+ args: [callbackId]
+ }])
done()
})
@@ -114,12 +98,17 @@ describe('App Instance', () => {
}]
app.callTasks(tasks)
- expect(callNativeSpy.lastCall.args[1]).to.deep.equal(tasks)
- expect(callNativeSpy.lastCall.args[1][0].args[0]).to.be.equal('1')
+ expect(sendTasksSpy.lastCall.args[1]).to.deep.equal([{
+ module: 'dom',
+ method: 'createBody',
+ args: [node.ref]
+ }])
done()
})
it('with callback after close', (done) => {
+ const callbackId = '1'
+
const tasks = [{
module: 'dom',
method: 'createBody',
@@ -129,8 +118,11 @@ describe('App Instance', () => {
app.doc.close()
app.callTasks(tasks)
- expect(callNativeSpy.lastCall.args[1]).to.deep.equal(tasks)
- expect(callNativeSpy.lastCall.args[1][0].args[0]).to.be.a('string')
+ expect(sendTasksSpy.lastCall.args[1]).to.deep.equal([{
+ module: 'dom',
+ method: 'createBody',
+ args: [callbackId]
+ }])
done()
})
})
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/app/viewport.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/app/viewport.js b/html5/test/unit/default/app/viewport.js
new file mode 100644
index 0000000..ea914a3
--- /dev/null
+++ b/html5/test/unit/default/app/viewport.js
@@ -0,0 +1,61 @@
+import chai from 'chai'
+import sinon from 'sinon'
+import sinonChai from 'sinon-chai'
+const { expect } = chai
+chai.use(sinonChai)
+
+import * as viewport from '../../../../frameworks/legacy/app/viewport'
+
+describe('viewport', function () {
+ const originalCallNative = global.callNative
+ const { setViewport, validateViewport } = viewport
+ const mockApp = {
+ id: 'mock',
+ callTasks (...args) {
+ global.callNative(...args)
+ }
+ }
+
+ before(() => {
+ sinon.stub(console, 'warn')
+ })
+
+ beforeEach(() => {
+ global.callNative = sinon.spy()
+ })
+ afterEach(() => {
+ global.callNative = originalCallNative
+ console.warn.reset()
+ })
+
+ it('invalid setViewport', () => {
+ setViewport()
+ expect(global.callNative.callCount).to.be.equal(0)
+ setViewport({})
+ expect(global.callNative.callCount).to.be.equal(0)
+ })
+
+ it('setViewport', () => {
+ setViewport(mockApp, {})
+ expect(global.callNative.callCount).to.be.equal(1)
+ setViewport(mockApp, { width: 640 })
+ expect(global.callNative.callCount).to.be.equal(2)
+ setViewport(mockApp, { width: 'device-width' })
+ expect(global.callNative.callCount).to.be.equal(3)
+ })
+
+ it('validateViewport', () => {
+ expect(validateViewport()).to.be.false
+ expect(console.warn.callCount).to.be.equal(1)
+ expect(validateViewport({})).to.be.false
+ expect(console.warn.callCount).to.be.equal(2)
+
+ expect(validateViewport({ width: 200 })).to.be.true
+ expect(console.warn.callCount).to.be.equal(2)
+ expect(validateViewport({ width: 'device-width' })).to.be.true
+ expect(console.warn.callCount).to.be.equal(2)
+
+ expect(validateViewport({ width: 'initial-width' })).to.be.false
+ expect(console.warn.callCount).to.be.equal(3)
+ })
+})
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/runtime.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/runtime.js b/html5/test/unit/default/runtime.js
index 67a59ab..57a36b2 100644
--- a/html5/test/unit/default/runtime.js
+++ b/html5/test/unit/default/runtime.js
@@ -9,6 +9,7 @@ chai.use(sinonChai)
import runtime from '../../../runtime'
import frameworks from '../../../frameworks'
import defaultConfig from '../../../frameworks/legacy/config'
+import { init as resetTaskHandler } from '../../../runtime/task-center'
const { init, config } = runtime
config.frameworks = frameworks
@@ -29,8 +30,10 @@ function clearRefs (json) {
describe('framework entry', () => {
const oriCallNative = global.callNative
const oriCallAddElement = global.callAddElement
+ const oriDocumentHandler = config.Document.handler
const callNativeSpy = sinon.spy()
const callAddElementSpy = sinon.spy()
+ const documentHandlerSpy = sinon.spy()
const instanceId = Date.now() + ''
before(() => {
@@ -44,7 +47,6 @@ describe('framework entry', () => {
}])
}
}
- config.Document.handler = global.callNative
global.callAddElement = (name, id, ref, json, index, callbackId) => {
callAddElementSpy(name, ref, json, index, callbackId)
/* istanbul ignore if */
@@ -55,15 +57,18 @@ describe('framework entry', () => {
}])
}
}
+ config.Document.handler = oriDocumentHandler
+ resetTaskHandler()
})
afterEach(() => {
callNativeSpy.reset()
callAddElementSpy.reset()
+ documentHandlerSpy.reset()
})
after(() => {
- config.Document.handler = function () {}
+ config.Document.handler = oriDocumentHandler
global.callNative = oriCallNative
global.callAddElement = oriCallAddElement
})
@@ -104,7 +109,6 @@ describe('framework entry', () => {
bootstrap('@weex-component/main')
`
framework.createInstance(instanceId, code)
-
expect(callNativeSpy.callCount).to.be.equal(2)
expect(callAddElementSpy.callCount).to.be.equal(1)
@@ -168,7 +172,7 @@ describe('framework entry', () => {
expect(frameworks.xxx.createInstance.callCount).equal(1)
expect(frameworks.yyy.createInstance.callCount).equal(0)
expect(frameworks.Weex.createInstance.callCount).equal(0)
- expect(frameworks.xxx.createInstance.firstCall.args).eql([
+ expect(frameworks.xxx.createInstance.firstCall.args.slice(0, 4)).eql([
instanceId + '~',
code,
{ bundleVersion: '0.3.1', env: {}},
@@ -191,7 +195,7 @@ describe('framework entry', () => {
expect(frameworks.xxx.createInstance.callCount).equal(2)
expect(frameworks.yyy.createInstance.callCount).equal(0)
expect(frameworks.Weex.createInstance.callCount).equal(1)
- expect(frameworks.Weex.createInstance.firstCall.args).eql([
+ expect(frameworks.Weex.createInstance.firstCall.args.slice(0, 4)).eql([
instanceId + '~~~',
code,
{ bundleVersion: undefined, env: {}},
@@ -212,7 +216,7 @@ describe('framework entry', () => {
expect(frameworks.xxx.createInstance.callCount).equal(2)
expect(frameworks.yyy.createInstance.callCount).equal(1)
expect(frameworks.Weex.createInstance.callCount).equal(1)
- expect(frameworks.yyy.createInstance.firstCall.args).eql([
+ expect(frameworks.yyy.createInstance.firstCall.args.slice(0, 4)).eql([
instanceId + '~~~~',
code,
{ bundleVersion: undefined, env: {}},
@@ -225,7 +229,7 @@ describe('framework entry', () => {
expect(frameworks.xxx.createInstance.callCount).equal(2)
expect(frameworks.yyy.createInstance.callCount).equal(1)
expect(frameworks.Weex.createInstance.callCount).equal(2)
- expect(frameworks.Weex.createInstance.secondCall.args).eql([
+ expect(frameworks.Weex.createInstance.secondCall.args.slice(0, 4)).eql([
instanceId + '~~~~~',
code,
{ bundleVersion: undefined, env: {}},
@@ -238,7 +242,7 @@ describe('framework entry', () => {
expect(frameworks.xxx.createInstance.callCount).equal(2)
expect(frameworks.yyy.createInstance.callCount).equal(1)
expect(frameworks.Weex.createInstance.callCount).equal(3)
- expect(frameworks.Weex.createInstance.thirdCall.args).eql([
+ expect(frameworks.Weex.createInstance.thirdCall.args.slice(0, 4)).eql([
instanceId + '~~~~~~',
code,
{ bundleVersion: undefined, env: {}},
@@ -320,14 +324,13 @@ describe('framework entry', () => {
const textRef = json.children[0].ref
framework.refreshInstance(instanceId, { showText: false })
expect(callNativeSpy.callCount).to.be.equal(2)
-
expect(callNativeSpy.firstCall.args[0]).to.be.equal(instanceId)
expect(callNativeSpy.firstCall.args[1]).to.deep.equal([{
module: 'dom',
method: 'removeElement',
args: [textRef]
}])
- expect(callNativeSpy.firstCall.args[2]).to.be.equal('-1')
+ // expect(callNativeSpy.firstCall.args[2]).to.be.equal('-1')
expect(callNativeSpy.secondCall.args[0]).to.be.equal(instanceId)
expect(callNativeSpy.secondCall.args[1]).to.deep.equal([{
@@ -335,7 +338,7 @@ describe('framework entry', () => {
method: 'refreshFinish',
args: []
}])
- expect(callNativeSpy.secondCall.args[2]).to.be.equal('-1')
+ // expect(callNativeSpy.secondCall.args[2]).to.be.equal('-1')
})
it('with a non-exist instanceId', () => {
@@ -384,6 +387,21 @@ describe('framework entry', () => {
})
expect(defaultConfig.nativeComponentMap).not.contain.keys('e')
})
+
+ it('with methods', () => {
+ const components = [{
+ type: 'x',
+ methods: ['foo', 'bar']
+ }, {
+ type: 'y',
+ methods: []
+ }, {
+ type: 'z',
+ methods: null
+ }]
+ framework.registerComponents(components)
+ expect(defaultConfig.nativeComponentMap).to.contain.keys('x', 'y', 'z')
+ })
})
describe('register modules', () => {
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/vm/dom-helper.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/vm/dom-helper.js b/html5/test/unit/default/vm/dom-helper.js
index 1f4c9c8..fbcd8d2 100644
--- a/html5/test/unit/default/vm/dom-helper.js
+++ b/html5/test/unit/default/vm/dom-helper.js
@@ -1,9 +1,6 @@
import chai from 'chai'
const { expect } = chai
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import {
createElement,
createBlock,
@@ -104,10 +101,13 @@ describe('help attach target', () => {
})
it('attach body to documentElement', () => {
+ const oriCallnative = global.callNative
+ global.callNative = function () {}
const target = createBody(vm, 'bar')
const dest = vm._app.doc.documentElement
attachTarget(vm, target, dest)
expect(dest.children).eql([target])
+ global.callNative = oriCallnative
})
it('attach element to body', () => {
@@ -329,12 +329,15 @@ describe('help remove target', () => {
})
it('remove body', () => {
+ const oriCallnative = global.callNative
+ global.callNative = function () {}
const parent = vm._app.doc.documentElement
const element = createBody(vm, 'baz')
parent.appendChild(element)
expect(parent.children).eql([element])
removeTarget(vm, element)
expect(parent.children).eql([])
+ global.callNative = oriCallnative
})
it('remove element', () => {
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/vm/events.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/vm/events.js b/html5/test/unit/default/vm/events.js
index 28e9a59..e065e7f 100644
--- a/html5/test/unit/default/vm/events.js
+++ b/html5/test/unit/default/vm/events.js
@@ -4,12 +4,8 @@ import sinonChai from 'sinon-chai'
const { expect } = chai
chai.use(sinonChai)
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import Vm from '../../../../frameworks/legacy/vm'
import { Document } from '../../../../runtime/vdom'
-import Listener from '../../../../runtime/listener'
describe('bind and fire events', () => {
let doc, customComponentMap, spy
@@ -26,9 +22,7 @@ describe('bind and fire events', () => {
beforeEach(() => {
spy = sinon.spy()
- doc = new Document('test', '', (actions) => {
- spy(actions)
- }, Listener)
+ doc = new Document('test', '', spy)
customComponentMap = {}
})
@@ -59,7 +53,6 @@ describe('bind and fire events', () => {
const vm = new Vm('foo', customComponentMap.foo, { _app: app })
checkReady(vm, function () {
- doc.close()
expect(doc.body.event.click).a('function')
const el = doc.body
@@ -68,10 +61,9 @@ describe('bind and fire events', () => {
expect(doc.listener.updates.length).eql(0)
el.event.click({ xxx: 1 })
-
expect(el.attr.a).eql(2)
- expect(spy.args.length).eql(1)
- expect(doc.listener.updates).eql([
+ expect(spy.args.length).eql(2)
+ expect(spy.args[1][0]).eql([
{ module: 'dom', method: 'updateAttrs', args: [el.ref, { a: 2 }] }
])
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/default/vm/vm.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/default/vm/vm.js b/html5/test/unit/default/vm/vm.js
index e12b068..ffd9eb7 100644
--- a/html5/test/unit/default/vm/vm.js
+++ b/html5/test/unit/default/vm/vm.js
@@ -4,14 +4,13 @@ import sinonChai from 'sinon-chai'
const { expect } = chai
chai.use(sinonChai)
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import Vm from '../../../../frameworks/legacy/vm'
import { Document } from '../../../../runtime/vdom'
-import Listener from '../../../../runtime/listener'
+import { init as resetTaskHandler } from '../../../../runtime/task-center'
import Differ from '../../../../frameworks/legacy/app/differ'
+const oriCallNative = global.callNative
+
describe('generate virtual dom for a single vm', () => {
const spy = sinon.spy()
const spy1 = sinon.spy()
@@ -25,7 +24,7 @@ describe('generate virtual dom for a single vm', () => {
actions.forEach((action) => {
spy.apply(null, ['test', action.method].concat(action.args))
})
- }, Listener)
+ })
customComponentMap = {}
})
@@ -942,13 +941,16 @@ describe('generate virtual dom for sub vm', () => {
let differ
beforeEach(() => {
- doc = new Document('test', null, null, Listener)
+ global.callNative = function () {}
+ resetTaskHandler()
+ doc = new Document('test', null, null)
customComponentMap = {}
differ = new Differ('test')
})
afterEach(() => {
doc.destroy()
+ global.callNative = oriCallNative
})
it('generate sub elements', () => {
@@ -1588,7 +1590,7 @@ describe('generate dom actions', () => {
actions.forEach((action) => {
spy.apply(null, ['bar', action.method].concat(action.args))
})
- }, Listener)
+ })
differ = new Differ('foo')
customComponentMap = {}
app = { doc, customComponentMap, differ }
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/shared/BroadcastChannel.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/shared/BroadcastChannel.js b/html5/test/unit/shared/BroadcastChannel.js
new file mode 100644
index 0000000..3fda443
--- /dev/null
+++ b/html5/test/unit/shared/BroadcastChannel.js
@@ -0,0 +1,220 @@
+import { expect } from 'chai'
+import sinon from 'sinon'
+
+import service from '../../../services/broadcast-channel/index'
+import { MessageEvent } from '../../../services/broadcast-channel/message-event'
+const { BroadcastChannel } = service.create('foo').instance
+
+describe('BroadcastChannel', () => {
+ it('is a function', () => {
+ expect(BroadcastChannel).is.an('function')
+ })
+
+ it('has standard APIs', () => {
+ const JamesBond = new BroadcastChannel('007')
+ expect(JamesBond.name).is.an('string')
+ expect(JamesBond.onmessage).is.an('null')
+ expect(JamesBond.postMessage).is.an('function')
+ expect(JamesBond.close).is.an('function')
+
+ expect(JamesBond).to.have.ownProperty('name')
+ expect(JamesBond).to.have.ownProperty('onmessage')
+ expect(JamesBond).not.to.have.ownProperty('postMessage')
+ expect(JamesBond).not.to.have.ownProperty('close')
+ JamesBond.close()
+ })
+
+ it.skip('inherit APIs', () => {
+ const ProfessorX = new BroadcastChannel('Charles')
+ expect(ProfessorX.addEventListener).is.an('function')
+ expect(ProfessorX.removeEventListener).is.an('function')
+ expect(ProfessorX.dispatchEvent).is.an('function')
+ })
+
+ it('name attribute is readonly', () => {
+ const Wolverine = new BroadcastChannel('Logan')
+ expect(Wolverine.name).to.equal('Logan')
+ Wolverine.name = 'Wolverine'
+ expect(Wolverine.name).to.equal('Logan')
+ Wolverine.close()
+ })
+
+ describe('basci usage', () => {
+ const Hulk = new BroadcastChannel('Avengers')
+ const Stack = new BroadcastChannel('Avengers')
+ const Steven = new BroadcastChannel('Avengers')
+ const Logan = new BroadcastChannel('Mutants')
+ const Erik = new BroadcastChannel('Mutants')
+
+ beforeEach(() => {
+ Hulk.onmessage = sinon.spy()
+ Stack.onmessage = sinon.spy()
+ Steven.onmessage = sinon.spy()
+ Logan.onmessage = sinon.spy()
+ })
+
+ afterEach(() => {
+ Hulk.onmessage = null
+ Stack.onmessage = null
+ Steven.onmessage = null
+ Logan.onmessage = null
+ Erik.onmessage = null
+ })
+
+ it('trigger onmessage', () => {
+ Hulk.postMessage('Hulk Smash !!!')
+ expect(Hulk.onmessage.callCount).to.be.equal(0)
+ expect(Logan.onmessage.callCount).to.be.equal(0)
+ expect(Stack.onmessage.callCount).to.be.equal(1)
+ expect(Steven.onmessage.callCount).to.be.equal(1)
+ })
+
+ it('don\'t trigger onmessage itself', () => {
+ Logan.postMessage('Any one here ?')
+ expect(Hulk.onmessage.callCount).to.be.equal(0)
+ expect(Logan.onmessage.callCount).to.be.equal(0)
+ expect(Stack.onmessage.callCount).to.be.equal(0)
+ expect(Steven.onmessage.callCount).to.be.equal(0)
+ })
+
+ it('send multi messages', () => {
+ Hulk.postMessage('Hulk Smash !!!')
+ Logan.postMessage('I will fight you !')
+ Stack.postMessage('whatever')
+ Hulk.postMessage('whatever')
+ Stack.postMessage('whatever')
+ Steven.postMessage('whatever')
+ Stack.postMessage('whatever')
+
+ expect(Hulk.onmessage.callCount).to.be.equal(4)
+ expect(Logan.onmessage.callCount).to.be.equal(0)
+ expect(Stack.onmessage.callCount).to.be.equal(3)
+ expect(Steven.onmessage.callCount).to.be.equal(5)
+ })
+
+ it('send string message', () => {
+ Stack.postMessage('I am Iron-Man.')
+
+ expect(Hulk.onmessage.callCount).to.be.equal(1)
+ expect(Steven.onmessage.callCount).to.be.equal(1)
+
+ const event = Hulk.onmessage.firstCall.args[0]
+ expect(event).is.an('object')
+ expect(event.data).is.a('string')
+ expect(event.data).to.be.equal('I am Iron-Man.')
+ })
+
+ it('send object message', () => {
+ const message = {
+ type: 'SOKOVIA ACCORDS',
+ approvedCountry: 117,
+ content: 'The Avengers shall no longer be a private organization.'
+ }
+
+ Stack.postMessage(message)
+
+ const event = Steven.onmessage.firstCall.args[0]
+ expect(event).is.an('object')
+ expect(event.data).is.a('object')
+ expect(event.data).to.deep.equal(message)
+ })
+
+ it('close channel', () => {
+ Hulk.close()
+
+ Steven.postMessage('come to fight !')
+ expect(Hulk.onmessage.callCount).to.be.equal(0)
+ expect(Stack.onmessage.callCount).to.be.equal(1)
+ expect(Steven.onmessage.callCount).to.be.equal(0)
+ })
+
+ it('send message after close', () => {
+ Hulk.close()
+
+ expect(() => { Hulk.postMessage('I am leaving.') }).to.throw(Error)
+
+ expect(Hulk.onmessage.callCount).to.be.equal(0)
+ expect(Logan.onmessage.callCount).to.be.equal(0)
+ expect(Stack.onmessage.callCount).to.be.equal(0)
+ expect(Steven.onmessage.callCount).to.be.equal(0)
+ })
+
+ it('MessageEvent dafault parameters', () => {
+ const event = new MessageEvent()
+
+ expect(event).is.an('object')
+ expect(event.data).to.be.null
+ expect(event.type).to.be.equal('message')
+ expect(event.origin).to.be.equal('')
+ expect(event.target).to.be.null
+ expect(event.source).to.be.null
+ expect(event.timeStamp).to.be.a('number')
+ expect(event.ports).to.be.an('array')
+ })
+
+ it('MessageEvent constructor', () => {
+ const source = { type: 'empty' }
+ const event = new MessageEvent('custom', {
+ source,
+ data: 'Nothing',
+ origin: 'http://127.0.0.1',
+ ports: ['8080']
+ })
+
+ expect(event).is.an('object')
+ expect(event.data).to.be.equal('Nothing')
+ expect(event.type).to.be.equal('custom')
+ expect(event.origin).to.be.equal('http://127.0.0.1')
+ expect(event.target).to.be.null
+ expect(event.source).to.deep.equal(source)
+ expect(event.timeStamp).to.be.a('number')
+ expect(event.ports).to.deep.equal(['8080'])
+ })
+
+ it('use MessageEvent', () => {
+ Steven.postMessage('Be Together.')
+
+ const event = Stack.onmessage.firstCall.args[0]
+ expect(event).is.an('object')
+ expect(event.data).to.be.equal('Be Together.')
+ expect(event.type).to.be.equal('message')
+ expect(event.origin).to.be.equal('')
+ expect(event.target).to.be.null
+ expect(event.timeStamp).to.be.a('number')
+ })
+
+ it('invalid usage', () => {
+ const stranger = {
+ name: 'stranger',
+ close: Erik.close,
+ postMessage: Erik.postMessage
+ }
+
+ stranger.postMessage('hello world.')
+
+ expect(Hulk.onmessage.callCount).to.be.equal(0)
+ expect(Logan.onmessage.callCount).to.be.equal(0)
+ expect(Stack.onmessage.callCount).to.be.equal(0)
+ expect(Steven.onmessage.callCount).to.be.equal(0)
+
+ stranger.close()
+ })
+
+ it('close all', () => {
+ Hulk.close()
+ Stack.close()
+ Steven.close()
+ Logan.close()
+ Erik.close()
+
+ // close again
+ expect(() => {
+ Hulk.close()
+ Stack.close()
+ Steven.close()
+ Logan.close()
+ Erik.close()
+ }).to.not.throw
+ })
+ })
+})
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/vanilla/index.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/vanilla/index.js b/html5/test/unit/vanilla/index.js
index 24584da..a0e84e8 100644
--- a/html5/test/unit/vanilla/index.js
+++ b/html5/test/unit/vanilla/index.js
@@ -1,8 +1,5 @@
import { expect } from 'chai'
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import vanilla from '../../../frameworks/vanilla'
import runtime from '../../../runtime'
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/vdom/index.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/vdom/index.js b/html5/test/unit/vdom/index.js
index 886d7e6..7c8d854 100644
--- a/html5/test/unit/vdom/index.js
+++ b/html5/test/unit/vdom/index.js
@@ -4,28 +4,15 @@ import sinonChai from 'sinon-chai'
const { expect } = chai
chai.use(sinonChai)
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import {
Document,
Element,
- Comment
+ Comment,
+ elementTypes,
+ registerElement,
+ clearElementTypes
} from '../../../runtime/vdom'
-global.callNative = function () {}
-global.callAddElement = function () {}
-
-const tempHandler = Document.handler
-
-before(() => {
- Document.handler = global.callNative
-})
-
-after(() => {
- Document.handler = tempHandler
-})
-
describe('document constructor', () => {
it('create & destroy document', () => {
const doc = new Document('foo', 'http://path/to/url')
@@ -38,6 +25,49 @@ describe('document constructor', () => {
})
})
+describe('component methods management', () => {
+ before(() => {
+ registerElement('x', ['foo', 'bar'])
+ registerElement('y', [])
+ registerElement('z')
+ })
+
+ after(() => {
+ clearElementTypes()
+ })
+
+ it('has registered element types', () => {
+ expect(Object.keys(elementTypes)).eql(['x'])
+ })
+
+ it('will call component method', () => {
+ const spy = sinon.spy()
+ const doc = new Document('test', '', spy)
+ const x = new Element('x')
+ const y = new Element('y')
+ const z = new Element('z')
+ const n = new Element('n')
+ expect(x.foo).is.function
+ expect(x.bar).is.function
+ expect(x.baz).is.undefined
+ expect(y.foo).is.undefined
+ expect(z.foo).is.undefined
+ expect(n.foo).is.undefined
+
+ doc.createBody('r')
+ doc.documentElement.appendChild(doc.body)
+ doc.body.appendChild(x)
+ doc.body.appendChild(y)
+ doc.body.appendChild(z)
+ doc.body.appendChild(n)
+ expect(spy.args.length).eql(5)
+
+ x.foo(1, 2, 3)
+ expect(spy.args.length).eql(6)
+ expect(spy.args[5]).eql([[{ component: 'x', method: 'foo', ref: x.ref, args: [1, 2, 3] }]])
+ })
+})
+
describe('document methods', () => {
let doc
@@ -435,12 +465,12 @@ describe('complicated situations', () => {
doc = new Document('foo', '', spy)
doc.createBody('r')
doc.documentElement.appendChild(doc.body)
- el = new Element('bar', null, doc)
- el2 = new Element('baz', null, doc)
- el3 = new Element('qux', null, doc)
- c = new Comment('aaa', doc)
- c2 = new Comment('bbb', doc)
- c3 = new Comment('ccc', doc)
+ el = new Element('bar')
+ el2 = new Element('baz')
+ el3 = new Element('qux')
+ c = new Comment('aaa')
+ c2 = new Comment('bbb')
+ c3 = new Comment('ccc')
})
afterEach(() => {
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/b5123119/html5/test/unit/vdom/listener.js
----------------------------------------------------------------------
diff --git a/html5/test/unit/vdom/listener.js b/html5/test/unit/vdom/listener.js
index 1f260b6..84de22b 100644
--- a/html5/test/unit/vdom/listener.js
+++ b/html5/test/unit/vdom/listener.js
@@ -4,15 +4,9 @@ import sinonChai from 'sinon-chai'
const { expect } = chai
chai.use(sinonChai)
-global.callNative = function () {}
-global.callAddElement = function () {}
-
import { Document } from '../../../runtime/vdom'
import Listener from '../../../runtime/listener'
-global.callNative = function () {}
-global.callAddElement = function () {}
-
describe('dom listener basic', () => {
it('works with no id', () => {
const doc = new Document(null, null, null)
@@ -20,6 +14,10 @@ describe('dom listener basic', () => {
})
it('works with no handler', () => {
+ const oriCallNative = global.callNative
+ const oriCallAddElement = global.callAddElement
+ const oriDocumentHandler = Document.handler
+
Document.handler = null
global.callNative = function () { return -1 }
global.callAddElement = function () { return -1 }
@@ -30,6 +28,10 @@ describe('dom listener basic', () => {
const el = doc.createElement('a')
doc.body.appendChild(el)
doc.destroy()
+
+ global.callNative = oriCallNative
+ global.callAddElement = oriCallAddElement
+ Document.handler = oriDocumentHandler
})
it('works with an handler', () => {
@@ -77,7 +79,7 @@ describe('dom listener details', () => {
expect(spy.args[0]).eql([[{
module: 'dom', method: 'createBody',
args: [{ type: 'r', ref: '_root', attr: { a: 1 }, style: { b: 2 }}]
- }]])
+ }], '-1'])
done()
})
@@ -108,7 +110,7 @@ describe('dom listener details', () => {
expect(spy.args[0]).eql([[{
module: 'dom', method: 'createBody',
args: [{ type: 'r', ref: '_root', attr: { a: 1 }, style: { b: 2 }}]
- }]])
+ }], '-1'])
done()
})
@@ -192,7 +194,7 @@ describe('dom listener details', () => {
expect(spy.args[0]).eql([[{
module: 'dom', method: 'createBody',
args: [body.toJSON()]
- }]])
+ }], '-1'])
const el = doc.createElement('a')
el.setAttr('x', 1)
@@ -202,7 +204,7 @@ describe('dom listener details', () => {
expect(spy.args[1]).eql([[{
module: 'dom', method: 'addElement',
args: ['_root', el.toJSON(), -1]
- }]])
+ }], '-1'])
const el2 = doc.createElement('b')
doc.body.insertBefore(el2, el) // [el2, el]
@@ -214,16 +216,16 @@ describe('dom listener details', () => {
expect(spy.args[2]).eql([[{
module: 'dom', method: 'addElement',
args: ['_root', el2.toJSON(), 0]
- }]])
+ }], '-1'])
expect(spy.args[3]).eql([[{
module: 'dom', method: 'addElement',
args: ['_root', el3.toJSON(), 2]
- }]])
+ }], '-1'])
done()
})
- it('batch when document closed', (done) => {
+ it.skip('batch when document closed', (done) => {
const body = doc.createBody('r')
doc.documentElement.appendChild(body)
@@ -348,16 +350,14 @@ describe('dom listener details', () => {
args: [el.ref, 'appear']
}])
- doc.close()
-
el.setAttr('a', 1)
el.setStyle('a', 2)
el.setClassStyle({ a: 3, b: 4 })
el.addEvent('click', () => {})
el.addEvent('appear', () => {})
el.removeEvent('appear')
- expect(spy.args.length).eql(10)
- expect(doc.listener.updates).eql([
+ expect(spy.args.length).eql(16)
+ expect(spy.args.slice(10).map(c => c[0][0])).eql([
{ module: 'dom', method: 'updateAttrs', args: [el.ref, { a: 1 }] },
{ module: 'dom', method: 'updateStyle', args: [el.ref, { a: 2 }] },
{ module: 'dom', method: 'updateStyle', args: [el.ref, { a: 2, b: 4 }] },