You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by da...@apache.org on 2017/08/17 03:59:28 UTC
[11/43] incubator-weex git commit: * [jsfm] refactor the file
structure in runtime
* [jsfm] refactor the file structure in runtime
Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/0729ac59
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/0729ac59
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/0729ac59
Branch: refs/heads/0.16-dev
Commit: 0729ac590a7e69aa279de973273fa228507f77f1
Parents: 25b0101
Author: Hanks <zh...@gmail.com>
Authored: Mon Aug 7 15:49:36 2017 +0800
Committer: Hanks <zh...@gmail.com>
Committed: Mon Aug 7 15:49:36 2017 +0800
----------------------------------------------------------------------
html5/runtime/api/config.js | 36 +++++
html5/runtime/api/init.js | 215 ++++++++++++++++++++++++++
html5/runtime/api/service.js | 77 ++++++++++
html5/runtime/bridge/CallbackManager.js | 58 +++++++
html5/runtime/bridge/Handler.js | 91 +++++++++++
html5/runtime/bridge/Listener.js | 220 +++++++++++++++++++++++++++
html5/runtime/bridge/TaskCenter.js | 133 ++++++++++++++++
html5/runtime/bridge/normalize.js | 95 ++++++++++++
html5/runtime/callback-manager.js | 58 -------
html5/runtime/config.js | 36 -----
html5/runtime/handler.js | 91 -----------
html5/runtime/index.js | 11 +-
html5/runtime/init.js | 215 --------------------------
html5/runtime/listener.js | 220 ---------------------------
html5/runtime/normalize.js | 98 ------------
html5/runtime/service.js | 77 ----------
html5/runtime/task-center.js | 132 ----------------
html5/runtime/utils.js | 13 ++
html5/runtime/vdom/comment.js | 4 +-
html5/runtime/vdom/directive.js | 5 +-
html5/runtime/vdom/document.js | 10 +-
html5/runtime/vdom/element.js | 4 +-
html5/runtime/vdom/index.js | 8 +-
html5/runtime/vdom/node.js | 3 +-
html5/runtime/vdom/operation.js | 8 -
25 files changed, 957 insertions(+), 961 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/api/config.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/config.js b/html5/runtime/api/config.js
new file mode 100644
index 0000000..729ceaf
--- /dev/null
+++ b/html5/runtime/api/config.js
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+import { Document, Element, Comment } from '../vdom'
+import Listener from '../bridge/Listener'
+import { TaskCenter } from '../bridge/TaskCenter'
+
+const config = {
+ Document, Element, Comment, Listener,
+ TaskCenter,
+ sendTasks (...args) {
+ if (typeof callNative === 'function') {
+ return callNative(...args)
+ }
+ return (global.callNative || (() => {}))(...args)
+ }
+}
+
+Document.handler = config.sendTasks
+
+export default config
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/api/init.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/init.js b/html5/runtime/api/init.js
new file mode 100644
index 0000000..cc770af
--- /dev/null
+++ b/html5/runtime/api/init.js
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+import { init as initTaskHandler } from '../bridge/TaskCenter'
+import { registerElement } from '../vdom/element-types'
+import { services, register, unregister } from './service'
+
+let frameworks
+let runtimeConfig
+
+const versionRegExp = /^\s*\/\/ *(\{[^}]*\}) *\r?\n/
+
+/**
+ * Detect a JS Bundle code and make sure which framework it's based to. Each JS
+ * Bundle should make sure that it starts with a line of JSON comment and is
+ * more that one line.
+ * @param {string} code
+ * @return {object}
+ */
+function checkVersion (code) {
+ let info
+ const result = versionRegExp.exec(code)
+ if (result) {
+ try {
+ info = JSON.parse(result[1])
+ }
+ catch (e) {}
+ }
+ 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 = {}
+
+/**
+ * Check which framework a certain JS Bundle code based to. And create instance
+ * by this framework.
+ * @param {string} id
+ * @param {string} code
+ * @param {object} config
+ * @param {object} data
+ */
+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'
+ }
+
+ // 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}`)
+
+ 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,
+ registerService: register,
+ unregisterService: unregister
+}
+
+/**
+ * Register methods which init each frameworks.
+ * @param {string} methodName
+ */
+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]) {
+ framework[methodName](...args)
+ }
+ }
+ }
+}
+
+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
+ */
+function genInstance (methodName) {
+ methods[methodName] = function (...args) {
+ const id = args[0]
+ const info = instanceMap[id]
+ if (info && frameworks[info.framework]) {
+ const result = frameworks[info.framework][methodName](...args)
+
+ // 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}"`)
+ }
+}
+
+/**
+ * Adapt some legacy method(s) which will be called for each instance. These
+ * methods should be deprecated and removed later.
+ * @param {string} methodName
+ * @param {string} nativeMethodName
+ */
+function adaptInstance (methodName, nativeMethodName) {
+ methods[nativeMethodName] = function (...args) {
+ const id = args[0]
+ const info = instanceMap[id]
+ if (info && frameworks[info.framework]) {
+ return frameworks[info.framework][methodName](...args)
+ }
+ return new Error(`invalid instance id "${id}"`)
+ }
+}
+
+export default function init (config) {
+ 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:
+ // `sendTasks(...args)`.
+ for (const name in frameworks) {
+ const framework = frameworks[name]
+ framework.init(config)
+ }
+
+ // @todo: The method `registerMethods` will be re-designed or removed later.
+ ; ['registerComponents', 'registerModules', 'registerMethods'].forEach(genInit)
+
+ ; ['destroyInstance', 'refreshInstance', 'receiveTasks', 'getRoot'].forEach(genInstance)
+
+ adaptInstance('receiveTasks', 'callJS')
+
+ return methods
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/api/service.js
----------------------------------------------------------------------
diff --git a/html5/runtime/api/service.js b/html5/runtime/api/service.js
new file mode 100644
index 0000000..6f2e72e
--- /dev/null
+++ b/html5/runtime/api/service.js
@@ -0,0 +1,77 @@
+/*
+ * 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
+
+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/0729ac59/html5/runtime/bridge/CallbackManager.js
----------------------------------------------------------------------
diff --git a/html5/runtime/bridge/CallbackManager.js b/html5/runtime/bridge/CallbackManager.js
new file mode 100644
index 0000000..058fcc0
--- /dev/null
+++ b/html5/runtime/bridge/CallbackManager.js
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+import { decodePrimitive } from './normalize'
+
+/**
+ * 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]
+ delete this.callbacks[callbackId]
+ return callback
+ }
+ consume (callbackId, data, ifKeepAlive) {
+ const callback = this.callbacks[callbackId]
+ if (typeof ifKeepAlive === 'undefined' || ifKeepAlive === false) {
+ delete this.callbacks[callbackId]
+ }
+ if (typeof callback === 'function') {
+ return callback(decodePrimitive(data))
+ }
+ return new Error(`invalid callback id "${callbackId}"`)
+ }
+ close () {
+ this.callbacks = {}
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/bridge/Handler.js
----------------------------------------------------------------------
diff --git a/html5/runtime/bridge/Handler.js b/html5/runtime/bridge/Handler.js
new file mode 100644
index 0000000..71bf4c5
--- /dev/null
+++ b/html5/runtime/bridge/Handler.js
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+/**
+ * @fileOverview
+ * Task handler for communication between javascript and native.
+ */
+
+const handlerMap = {
+ createBody: 'callCreateBody',
+ addElement: 'callAddElement',
+ removeElement: 'callRemoveElement',
+ moveElement: 'callMoveElement',
+ updateAttrs: 'callUpdateAttrs',
+ updateStyle: 'callUpdateStyle',
+ addEvent: 'callAddEvent',
+ removeEvent: 'callRemoveEvent'
+}
+
+/**
+ * Create a task handler.
+ * @param {string} id
+ * @param {function} handler
+ * @return {function} taskHandler
+ */
+export function createHandler (id, handler) {
+ const defaultHandler = handler || global.callNative
+
+ /* istanbul ignore if */
+ if (typeof defaultHandler !== 'function') {
+ console.error('[JS Runtime] no default handler')
+ }
+
+ return function taskHandler (tasks) {
+ /* istanbul ignore if */
+ if (!Array.isArray(tasks)) {
+ tasks = [tasks]
+ }
+ for (let i = 0; i < tasks.length; i++) {
+ const returnValue = dispatchTask(id, tasks[i], defaultHandler)
+ if (returnValue === -1) {
+ return returnValue
+ }
+ }
+ }
+}
+
+/**
+ * Check if there is a corresponding available handler in the environment.
+ * @param {string} module
+ * @param {string} method
+ * @return {boolean}
+ */
+function hasAvailableHandler (module, method) {
+ return module === 'dom'
+ && handlerMap[method]
+ && typeof global[handlerMap[method]] === 'function'
+}
+
+/**
+ * Dispatch the task to the specified handler.
+ * @param {string} id
+ * @param {object} task
+ * @param {function} defaultHandler
+ * @return {number} signal returned from native
+ */
+function dispatchTask (id, task, defaultHandler) {
+ const { module, method, args } = task
+
+ if (hasAvailableHandler(module, method)) {
+ return global[handlerMap[method]](id, ...args, '-1')
+ }
+
+ return defaultHandler(id, [task], '-1')
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/bridge/Listener.js
----------------------------------------------------------------------
diff --git a/html5/runtime/bridge/Listener.js b/html5/runtime/bridge/Listener.js
new file mode 100644
index 0000000..2bf3893
--- /dev/null
+++ b/html5/runtime/bridge/Listener.js
@@ -0,0 +1,220 @@
+/*
+ * 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 = []) {
+ return { module: 'dom', method: name, args: args }
+}
+
+export default class Listener {
+ constructor (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 must be a function')
+ }
+ }
+
+ /**
+ * Send the "createFinish" signal.
+ * @param {function} callback
+ * @return {undefined | number} the signal sent by native
+ */
+ createFinish (callback) {
+ const handler = this.handler
+ return handler([createAction('createFinish')], callback)
+ }
+
+ /**
+ * Send the "updateFinish" signal.
+ * @param {function} callback
+ * @return {undefined | number} the signal sent by native
+ */
+ updateFinish (callback) {
+ const handler = this.handler
+ return handler([createAction('updateFinish')], callback)
+ }
+
+ /**
+ * Send the "refreshFinish" signal.
+ * @param {function} callback
+ * @return {undefined | number} the signal sent by native
+ */
+ refreshFinish (callback) {
+ const handler = this.handler
+ return handler([createAction('refreshFinish')], callback)
+ }
+
+ /**
+ * Send the "createBody" signal.
+ * @param {object} element
+ * @return {undefined | number} the signal sent by native
+ */
+ createBody (element) {
+ const body = element.toJSON()
+ const children = body.children
+ delete body.children
+ const actions = [createAction('createBody', [body])]
+ if (children) {
+ actions.push.apply(actions, children.map(child => {
+ return createAction('addElement', [body.ref, child, -1])
+ }))
+ }
+ return this.addActions(actions)
+ }
+
+ /**
+ * Send the "addElement" signal.
+ * @param {object} element
+ * @param {stirng} reference id
+ * @param {number} index
+ * @return {undefined | number} the signal sent by native
+ */
+ addElement (element, ref, index) {
+ if (!(index >= 0)) {
+ index = -1
+ }
+ return this.addActions(createAction('addElement', [ref, element.toJSON(), index]))
+ }
+
+ /**
+ * Send the "removeElement" signal.
+ * @param {stirng} reference id
+ * @return {undefined | number} the signal sent by native
+ */
+ removeElement (ref) {
+ if (Array.isArray(ref)) {
+ const actions = ref.map((r) => createAction('removeElement', [r]))
+ return this.addActions(actions)
+ }
+ return this.addActions(createAction('removeElement', [ref]))
+ }
+
+ /**
+ * Send the "moveElement" signal.
+ * @param {stirng} target reference id
+ * @param {stirng} parent reference id
+ * @param {number} index
+ * @return {undefined | number} the signal sent by native
+ */
+ moveElement (targetRef, parentRef, index) {
+ return this.addActions(createAction('moveElement', [targetRef, parentRef, index]))
+ }
+
+ /**
+ * Send the "updateAttrs" signal.
+ * @param {stirng} reference id
+ * @param {stirng} key
+ * @param {stirng} value
+ * @return {undefined | number} the signal sent by native
+ */
+ setAttr (ref, key, value) {
+ const result = {}
+ result[key] = value
+ return this.addActions(createAction('updateAttrs', [ref, result]))
+ }
+
+ /**
+ * Send the "updateStyle" signal, update a sole style.
+ * @param {stirng} reference id
+ * @param {stirng} key
+ * @param {stirng} value
+ * @return {undefined | number} the signal sent by native
+ */
+ setStyle (ref, key, value) {
+ const result = {}
+ result[key] = value
+ return this.addActions(createAction('updateStyle', [ref, result]))
+ }
+
+ /**
+ * Send the "updateStyle" signal.
+ * @param {stirng} reference id
+ * @param {object} style
+ * @return {undefined | number} the signal sent by native
+ */
+ setStyles (ref, style) {
+ return this.addActions(createAction('updateStyle', [ref, style]))
+ }
+
+ /**
+ * Send the "addEvent" signal.
+ * @param {stirng} reference id
+ * @param {string} event type
+ * @return {undefined | number} the signal sent by native
+ */
+ addEvent (ref, type) {
+ return this.addActions(createAction('addEvent', [ref, type]))
+ }
+
+ /**
+ * Send the "removeEvent" signal.
+ * @param {stirng} reference id
+ * @param {string} event type
+ * @return {undefined | number} the signal sent by native
+ */
+ removeEvent (ref, type) {
+ return this.addActions(createAction('removeEvent', [ref, type]))
+ }
+
+ /**
+ * Default handler.
+ * @param {object | array} actions
+ * @param {function} callback
+ * @return {} anything returned by callback function
+ */
+ handler (actions, cb) {
+ return cb && cb()
+ }
+
+ /**
+ * Add actions into updates.
+ * @param {object | array} actions
+ * @return {undefined | number} the signal sent by native
+ */
+ addActions (actions) {
+ const updates = this.updates
+ const handler = this.handler
+
+ if (!Array.isArray(actions)) {
+ actions = [actions]
+ }
+
+ if (this.batched) {
+ updates.push.apply(updates, actions)
+ }
+ else {
+ return handler(actions)
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/bridge/TaskCenter.js
----------------------------------------------------------------------
diff --git a/html5/runtime/bridge/TaskCenter.js b/html5/runtime/bridge/TaskCenter.js
new file mode 100644
index 0000000..fd4f5ee
--- /dev/null
+++ b/html5/runtime/bridge/TaskCenter.js
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+import CallbackManager from './CallbackManager'
+import Element from '../vdom/Element'
+import { typof } from '../utils'
+import { normalizePrimitive } from './normalize'
+
+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(id)
+ })
+ fallback = sendTasks || function () {}
+ }
+
+ callback (callbackId, data, ifKeepAlive) {
+ return this.callbackManager.consume(callbackId, data, ifKeepAlive)
+ }
+
+ 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}
+ */
+ normalize (v) {
+ const type = typof(v)
+
+ if (v instanceof Element) {
+ return v.ref
+ }
+
+ if (v._isVue && v.$el instanceof Element) {
+ return v.$el.ref
+ }
+
+ if (type === 'Function') {
+ return this.callbackManager.add(v).toString()
+ }
+
+ return normalizePrimitive(v)
+ }
+
+ send (type, params, args, options) {
+ const { action, component, ref, module, method } = params
+
+ 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, Object.assign({ component }, options))
+ default:
+ return this.moduleHandler(this.instanceId, module, method, args, options)
+ }
+ }
+
+ callDOM (action, args) {
+ return this[action](this.instanceId, args)
+ }
+
+ callComponent (ref, method, args, options) {
+ return this.componentHandler(this.instanceId, ref, method, args, options)
+ }
+
+ callModule (module, method, args, options) {
+ return this.moduleHandler(this.instanceId, module, method, args, options)
+ }
+}
+
+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/0729ac59/html5/runtime/bridge/normalize.js
----------------------------------------------------------------------
diff --git a/html5/runtime/bridge/normalize.js b/html5/runtime/bridge/normalize.js
new file mode 100644
index 0000000..486167d
--- /dev/null
+++ b/html5/runtime/bridge/normalize.js
@@ -0,0 +1,95 @@
+import { typof } from '../utils'
+
+export function bufferToBase64 (buffer) {
+ if (typeof btoa !== 'function') {
+ return ''
+ }
+ const string = Array.prototype.map.call(
+ new Uint8Array(buffer),
+ code => String.fromCharCode(code)
+ ).join('')
+ return btoa(string) // eslint-disable-line no-undef
+}
+
+export function base64ToBuffer (base64) {
+ if (typeof atob !== 'function') {
+ return new ArrayBuffer(0)
+ }
+ const string = atob(base64) // eslint-disable-line no-undef
+ const array = new Uint8Array(string.length)
+ Array.prototype.forEach.call(string, (ch, i) => {
+ array[i] = ch.charCodeAt(0)
+ })
+ return array.buffer
+}
+
+/**
+ * Normalize a primitive value.
+ * @param {any} v
+ * @return {primitive}
+ */
+export function normalizePrimitive (v) {
+ const 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)
+ }
+}
+
+export function decodePrimitive (data) {
+ if (typof(data) === 'Object') {
+ // decode base64 into binary
+ if (data['@type'] && data['@type'] === 'binary') {
+ return base64ToBuffer(data.base64 || '')
+ }
+
+ const realData = {}
+ for (const key in data) {
+ realData[key] = decodePrimitive(data[key])
+ }
+ return realData
+ }
+ if (typof(data) === 'Array') {
+ return data.map(decodePrimitive)
+ }
+ return data
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/callback-manager.js
----------------------------------------------------------------------
diff --git a/html5/runtime/callback-manager.js b/html5/runtime/callback-manager.js
deleted file mode 100644
index 058fcc0..0000000
--- a/html5/runtime/callback-manager.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * 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.
- */
-
-import { decodePrimitive } from './normalize'
-
-/**
- * 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]
- delete this.callbacks[callbackId]
- return callback
- }
- consume (callbackId, data, ifKeepAlive) {
- const callback = this.callbacks[callbackId]
- if (typeof ifKeepAlive === 'undefined' || ifKeepAlive === false) {
- delete this.callbacks[callbackId]
- }
- if (typeof callback === 'function') {
- return callback(decodePrimitive(data))
- }
- return new Error(`invalid callback id "${callbackId}"`)
- }
- close () {
- this.callbacks = {}
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/config.js
----------------------------------------------------------------------
diff --git a/html5/runtime/config.js b/html5/runtime/config.js
deleted file mode 100644
index 695aa66..0000000
--- a/html5/runtime/config.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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.
- */
-import { Document, Element, Comment } from './vdom'
-import Listener from './listener'
-import { TaskCenter } from './task-center'
-
-const config = {
- Document, Element, Comment, Listener,
- TaskCenter,
- sendTasks (...args) {
- if (typeof callNative === 'function') {
- return callNative(...args)
- }
- return (global.callNative || (() => {}))(...args)
- }
-}
-
-Document.handler = config.sendTasks
-
-export default config
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/handler.js
----------------------------------------------------------------------
diff --git a/html5/runtime/handler.js b/html5/runtime/handler.js
deleted file mode 100644
index 71bf4c5..0000000
--- a/html5/runtime/handler.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.
- */
-
-/**
- * @fileOverview
- * Task handler for communication between javascript and native.
- */
-
-const handlerMap = {
- createBody: 'callCreateBody',
- addElement: 'callAddElement',
- removeElement: 'callRemoveElement',
- moveElement: 'callMoveElement',
- updateAttrs: 'callUpdateAttrs',
- updateStyle: 'callUpdateStyle',
- addEvent: 'callAddEvent',
- removeEvent: 'callRemoveEvent'
-}
-
-/**
- * Create a task handler.
- * @param {string} id
- * @param {function} handler
- * @return {function} taskHandler
- */
-export function createHandler (id, handler) {
- const defaultHandler = handler || global.callNative
-
- /* istanbul ignore if */
- if (typeof defaultHandler !== 'function') {
- console.error('[JS Runtime] no default handler')
- }
-
- return function taskHandler (tasks) {
- /* istanbul ignore if */
- if (!Array.isArray(tasks)) {
- tasks = [tasks]
- }
- for (let i = 0; i < tasks.length; i++) {
- const returnValue = dispatchTask(id, tasks[i], defaultHandler)
- if (returnValue === -1) {
- return returnValue
- }
- }
- }
-}
-
-/**
- * Check if there is a corresponding available handler in the environment.
- * @param {string} module
- * @param {string} method
- * @return {boolean}
- */
-function hasAvailableHandler (module, method) {
- return module === 'dom'
- && handlerMap[method]
- && typeof global[handlerMap[method]] === 'function'
-}
-
-/**
- * Dispatch the task to the specified handler.
- * @param {string} id
- * @param {object} task
- * @param {function} defaultHandler
- * @return {number} signal returned from native
- */
-function dispatchTask (id, task, defaultHandler) {
- const { module, method, args } = task
-
- if (hasAvailableHandler(module, method)) {
- return global[handlerMap[method]](id, ...args, '-1')
- }
-
- return defaultHandler(id, [task], '-1')
-}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/index.js
----------------------------------------------------------------------
diff --git a/html5/runtime/index.js b/html5/runtime/index.js
index 25810ac..85b7525 100644
--- a/html5/runtime/index.js
+++ b/html5/runtime/index.js
@@ -26,14 +26,9 @@
import * as shared from '../shared'
-import init from './init'
-import config from './config'
-
-import {
- register,
- unregister,
- has
-} from './service'
+import init from './api/init'
+import config from './api/config'
+import { register, unregister, has } from './api/service'
/* istanbul ignore next */
function freezePrototype () {
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/init.js
----------------------------------------------------------------------
diff --git a/html5/runtime/init.js b/html5/runtime/init.js
deleted file mode 100644
index ad46a3e..0000000
--- a/html5/runtime/init.js
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * 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.
- */
-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/
-
-/**
- * Detect a JS Bundle code and make sure which framework it's based to. Each JS
- * Bundle should make sure that it starts with a line of JSON comment and is
- * more that one line.
- * @param {string} code
- * @return {object}
- */
-function checkVersion (code) {
- let info
- const result = versionRegExp.exec(code)
- if (result) {
- try {
- info = JSON.parse(result[1])
- }
- catch (e) {}
- }
- 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 = {}
-
-/**
- * Check which framework a certain JS Bundle code based to. And create instance
- * by this framework.
- * @param {string} id
- * @param {string} code
- * @param {object} config
- * @param {object} data
- */
-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'
- }
-
- // 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}`)
-
- 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,
- registerService: register,
- unregisterService: unregister
-}
-
-/**
- * Register methods which init each frameworks.
- * @param {string} methodName
- */
-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]) {
- framework[methodName](...args)
- }
- }
- }
-}
-
-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
- */
-function genInstance (methodName) {
- methods[methodName] = function (...args) {
- const id = args[0]
- const info = instanceMap[id]
- if (info && frameworks[info.framework]) {
- const result = frameworks[info.framework][methodName](...args)
-
- // 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}"`)
- }
-}
-
-/**
- * Adapt some legacy method(s) which will be called for each instance. These
- * methods should be deprecated and removed later.
- * @param {string} methodName
- * @param {string} nativeMethodName
- */
-function adaptInstance (methodName, nativeMethodName) {
- methods[nativeMethodName] = function (...args) {
- const id = args[0]
- const info = instanceMap[id]
- if (info && frameworks[info.framework]) {
- return frameworks[info.framework][methodName](...args)
- }
- return new Error(`invalid instance id "${id}"`)
- }
-}
-
-export default function init (config) {
- 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:
- // `sendTasks(...args)`.
- for (const name in frameworks) {
- const framework = frameworks[name]
- framework.init(config)
- }
-
- // @todo: The method `registerMethods` will be re-designed or removed later.
- ; ['registerComponents', 'registerModules', 'registerMethods'].forEach(genInit)
-
- ; ['destroyInstance', 'refreshInstance', 'receiveTasks', 'getRoot'].forEach(genInstance)
-
- adaptInstance('receiveTasks', 'callJS')
-
- return methods
-}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/listener.js
----------------------------------------------------------------------
diff --git a/html5/runtime/listener.js b/html5/runtime/listener.js
deleted file mode 100644
index 2bf3893..0000000
--- a/html5/runtime/listener.js
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * 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 = []) {
- return { module: 'dom', method: name, args: args }
-}
-
-export default class Listener {
- constructor (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 must be a function')
- }
- }
-
- /**
- * Send the "createFinish" signal.
- * @param {function} callback
- * @return {undefined | number} the signal sent by native
- */
- createFinish (callback) {
- const handler = this.handler
- return handler([createAction('createFinish')], callback)
- }
-
- /**
- * Send the "updateFinish" signal.
- * @param {function} callback
- * @return {undefined | number} the signal sent by native
- */
- updateFinish (callback) {
- const handler = this.handler
- return handler([createAction('updateFinish')], callback)
- }
-
- /**
- * Send the "refreshFinish" signal.
- * @param {function} callback
- * @return {undefined | number} the signal sent by native
- */
- refreshFinish (callback) {
- const handler = this.handler
- return handler([createAction('refreshFinish')], callback)
- }
-
- /**
- * Send the "createBody" signal.
- * @param {object} element
- * @return {undefined | number} the signal sent by native
- */
- createBody (element) {
- const body = element.toJSON()
- const children = body.children
- delete body.children
- const actions = [createAction('createBody', [body])]
- if (children) {
- actions.push.apply(actions, children.map(child => {
- return createAction('addElement', [body.ref, child, -1])
- }))
- }
- return this.addActions(actions)
- }
-
- /**
- * Send the "addElement" signal.
- * @param {object} element
- * @param {stirng} reference id
- * @param {number} index
- * @return {undefined | number} the signal sent by native
- */
- addElement (element, ref, index) {
- if (!(index >= 0)) {
- index = -1
- }
- return this.addActions(createAction('addElement', [ref, element.toJSON(), index]))
- }
-
- /**
- * Send the "removeElement" signal.
- * @param {stirng} reference id
- * @return {undefined | number} the signal sent by native
- */
- removeElement (ref) {
- if (Array.isArray(ref)) {
- const actions = ref.map((r) => createAction('removeElement', [r]))
- return this.addActions(actions)
- }
- return this.addActions(createAction('removeElement', [ref]))
- }
-
- /**
- * Send the "moveElement" signal.
- * @param {stirng} target reference id
- * @param {stirng} parent reference id
- * @param {number} index
- * @return {undefined | number} the signal sent by native
- */
- moveElement (targetRef, parentRef, index) {
- return this.addActions(createAction('moveElement', [targetRef, parentRef, index]))
- }
-
- /**
- * Send the "updateAttrs" signal.
- * @param {stirng} reference id
- * @param {stirng} key
- * @param {stirng} value
- * @return {undefined | number} the signal sent by native
- */
- setAttr (ref, key, value) {
- const result = {}
- result[key] = value
- return this.addActions(createAction('updateAttrs', [ref, result]))
- }
-
- /**
- * Send the "updateStyle" signal, update a sole style.
- * @param {stirng} reference id
- * @param {stirng} key
- * @param {stirng} value
- * @return {undefined | number} the signal sent by native
- */
- setStyle (ref, key, value) {
- const result = {}
- result[key] = value
- return this.addActions(createAction('updateStyle', [ref, result]))
- }
-
- /**
- * Send the "updateStyle" signal.
- * @param {stirng} reference id
- * @param {object} style
- * @return {undefined | number} the signal sent by native
- */
- setStyles (ref, style) {
- return this.addActions(createAction('updateStyle', [ref, style]))
- }
-
- /**
- * Send the "addEvent" signal.
- * @param {stirng} reference id
- * @param {string} event type
- * @return {undefined | number} the signal sent by native
- */
- addEvent (ref, type) {
- return this.addActions(createAction('addEvent', [ref, type]))
- }
-
- /**
- * Send the "removeEvent" signal.
- * @param {stirng} reference id
- * @param {string} event type
- * @return {undefined | number} the signal sent by native
- */
- removeEvent (ref, type) {
- return this.addActions(createAction('removeEvent', [ref, type]))
- }
-
- /**
- * Default handler.
- * @param {object | array} actions
- * @param {function} callback
- * @return {} anything returned by callback function
- */
- handler (actions, cb) {
- return cb && cb()
- }
-
- /**
- * Add actions into updates.
- * @param {object | array} actions
- * @return {undefined | number} the signal sent by native
- */
- addActions (actions) {
- const updates = this.updates
- const handler = this.handler
-
- if (!Array.isArray(actions)) {
- actions = [actions]
- }
-
- if (this.batched) {
- updates.push.apply(updates, actions)
- }
- else {
- return handler(actions)
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/normalize.js
----------------------------------------------------------------------
diff --git a/html5/runtime/normalize.js b/html5/runtime/normalize.js
deleted file mode 100644
index f1e93b8..0000000
--- a/html5/runtime/normalize.js
+++ /dev/null
@@ -1,98 +0,0 @@
-export function typof (v) {
- const s = Object.prototype.toString.call(v)
- return s.substring(8, s.length - 1)
-}
-
-export function bufferToBase64 (buffer) {
- if (typeof btoa !== 'function') {
- return ''
- }
- const string = Array.prototype.map.call(
- new Uint8Array(buffer),
- code => String.fromCharCode(code)
- ).join('')
- return btoa(string) // eslint-disable-line no-undef
-}
-
-export function base64ToBuffer (base64) {
- if (typeof atob !== 'function') {
- return new ArrayBuffer(0)
- }
- const string = atob(base64) // eslint-disable-line no-undef
- const array = new Uint8Array(string.length)
- Array.prototype.forEach.call(string, (ch, i) => {
- array[i] = ch.charCodeAt(0)
- })
- return array.buffer
-}
-
-/**
- * Normalize a primitive value.
- * @param {any} v
- * @return {primitive}
- */
-export function normalizePrimitive (v) {
- const 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)
- }
-}
-
-export function decodePrimitive (data) {
- if (typof(data) === 'Object') {
- // decode base64 into binary
- if (data['@type'] && data['@type'] === 'binary') {
- return base64ToBuffer(data.base64 || '')
- }
-
- const realData = {}
- for (const key in data) {
- realData[key] = decodePrimitive(data[key])
- }
- return realData
- }
- if (typof(data) === 'Array') {
- return data.map(decodePrimitive)
- }
- return data
-}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/service.js
----------------------------------------------------------------------
diff --git a/html5/runtime/service.js b/html5/runtime/service.js
deleted file mode 100644
index 6f2e72e..0000000
--- a/html5/runtime/service.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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
-
-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/0729ac59/html5/runtime/task-center.js
----------------------------------------------------------------------
diff --git a/html5/runtime/task-center.js b/html5/runtime/task-center.js
deleted file mode 100644
index b2f960f..0000000
--- a/html5/runtime/task-center.js
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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.
- */
-import CallbackManager from './callback-manager'
-import Element from './vdom/element'
-import { typof, normalizePrimitive } from './normalize'
-
-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(id)
- })
- fallback = sendTasks || function () {}
- }
-
- callback (callbackId, data, ifKeepAlive) {
- return this.callbackManager.consume(callbackId, data, ifKeepAlive)
- }
-
- 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}
- */
- normalize (v) {
- const type = typof(v)
-
- if (v instanceof Element) {
- return v.ref
- }
-
- if (v._isVue && v.$el instanceof Element) {
- return v.$el.ref
- }
-
- if (type === 'Function') {
- return this.callbackManager.add(v).toString()
- }
-
- return normalizePrimitive(v)
- }
-
- send (type, params, args, options) {
- const { action, component, ref, module, method } = params
-
- 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, Object.assign({ component }, options))
- default:
- return this.moduleHandler(this.instanceId, module, method, args, options)
- }
- }
-
- callDOM (action, args) {
- return this[action](this.instanceId, args)
- }
-
- callComponent (ref, method, args, options) {
- return this.componentHandler(this.instanceId, ref, method, args, options)
- }
-
- callModule (module, method, args, options) {
- return this.moduleHandler(this.instanceId, module, method, args, options)
- }
-}
-
-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/0729ac59/html5/runtime/utils.js
----------------------------------------------------------------------
diff --git a/html5/runtime/utils.js b/html5/runtime/utils.js
new file mode 100644
index 0000000..e91e354
--- /dev/null
+++ b/html5/runtime/utils.js
@@ -0,0 +1,13 @@
+
+/**
+ * Get a unique id.
+ */
+let nextNodeRef = 1
+export function uniqueId () {
+ return (nextNodeRef++).toString()
+}
+
+export function typof (v) {
+ const s = Object.prototype.toString.call(v)
+ return s.substring(8, s.length - 1)
+}
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/vdom/comment.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/comment.js b/html5/runtime/vdom/comment.js
index 24d3482..d7ab115 100644
--- a/html5/runtime/vdom/comment.js
+++ b/html5/runtime/vdom/comment.js
@@ -17,8 +17,8 @@
* under the License.
*/
-import Node from './node'
-import { uniqueId } from './operation'
+import Node from './Node'
+import { uniqueId } from '../utils'
export default class Comment extends Node {
constructor (value) {
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/vdom/directive.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/directive.js b/html5/runtime/vdom/directive.js
index 97371ca..66f33c7 100644
--- a/html5/runtime/vdom/directive.js
+++ b/html5/runtime/vdom/directive.js
@@ -1,7 +1,4 @@
-function typof (v) {
- const s = Object.prototype.toString.call(v)
- return s.substring(8, s.length - 1)
-}
+import { typof } from '../utils'
// match the binding delimiter
const delimiterRE = /\[\[((?:.|\n)+?)\]\]/g
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/vdom/document.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/document.js b/html5/runtime/vdom/document.js
index 64b6210..58efa5d 100644
--- a/html5/runtime/vdom/document.js
+++ b/html5/runtime/vdom/document.js
@@ -17,11 +17,11 @@
* under the License.
*/
-import Comment from './comment'
-import Element from './element'
-import Listener from '../listener'
-import { TaskCenter } from '../task-center'
-import { createHandler } from '../handler'
+import Comment from './Comment'
+import Element from './Element'
+import Listener from '../bridge/Listener'
+import { TaskCenter } from '../bridge/TaskCenter'
+import { createHandler } from '../bridge/Handler'
import { addDoc, removeDoc, appendBody, setBody } from './operation'
/**
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/vdom/element.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/element.js b/html5/runtime/vdom/element.js
index 5f5268c..d0115a5 100644
--- a/html5/runtime/vdom/element.js
+++ b/html5/runtime/vdom/element.js
@@ -17,11 +17,10 @@
* under the License.
*/
-import Node from './node'
+import Node from './Node'
import {
getDoc,
getTaskCenter,
- uniqueId,
linkParent,
nextElement,
previousElement,
@@ -29,6 +28,7 @@ import {
moveIndex,
removeIndex
} from './operation'
+import { uniqueId } from '../utils'
import { elementTypes, setElement } from './element-types'
import { filterDirective } from './directive'
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/vdom/index.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/index.js b/html5/runtime/vdom/index.js
index 119a761..2c979e8 100644
--- a/html5/runtime/vdom/index.js
+++ b/html5/runtime/vdom/index.js
@@ -16,10 +16,10 @@
* specific language governing permissions and limitations
* under the License.
*/
-import Node from './node'
-import Element from './element'
-import Comment from './comment'
-import Document from './document'
+import Node from './Node'
+import Element from './Element'
+import Comment from './Comment'
+import Document from './Document'
export {
elementTypes,
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/vdom/node.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/node.js b/html5/runtime/vdom/node.js
index f36d0a5..645f7df 100644
--- a/html5/runtime/vdom/node.js
+++ b/html5/runtime/vdom/node.js
@@ -17,7 +17,8 @@
* under the License.
*/
-import { getDoc, uniqueId } from './operation'
+import { uniqueId } from '../utils'
+import { getDoc } from './operation'
export default class Node {
constructor () {
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/0729ac59/html5/runtime/vdom/operation.js
----------------------------------------------------------------------
diff --git a/html5/runtime/vdom/operation.js b/html5/runtime/vdom/operation.js
index a29ac4c..460732a 100644
--- a/html5/runtime/vdom/operation.js
+++ b/html5/runtime/vdom/operation.js
@@ -74,14 +74,6 @@ export function getTaskCenter (id) {
}
/**
- * Get a unique id.
- */
-let nextNodeRef = 1
-export function uniqueId () {
- return (nextNodeRef++).toString()
-}
-
-/**
* Append body node to documentElement.
* @param {object} document
* @param {object} node