miniapp-windmill-renderer
Version:
Windmill renderer-side proxy.
1,368 lines (1,304 loc) • 39.3 kB
JavaScript
/**
* windmill.renderer.js v0.5.1.
*/
;console.log('Start windmill renderer (0.5.1) framework. Build at 2019-02-21 10:54');
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global['windmill-renderer'] = factory());
}(this, (function () { 'use strict';
// polyfill for Object.assign
if (typeof Object.assign != 'function') {
Object.defineProperty(Object, 'assign', {
writable: true,
enumerable: false,
configurable: true,
value: function objectAssign(target, varArgs) {
var arguments$1 = arguments;
if (target == null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var next = arguments$1[index];
if (next != null) {
for (var key in next) {
if (Object.prototype.hasOwnProperty.call(next, key)) {
to[key] = next[key];
}
}
}
}
return to;
}
});
}
/**
* Generate uniqueId
*/
var uniqueId = (function () {
var start = 100000;
return function getUniqueId() {
var id = String(start);
start += 1;
return id;
};
})();
/**
* Get current runtime context object
*/
function getContextObject() {
return typeof global !== 'undefined'
? global
: typeof self !== 'undefined'
? self
: (new Function('return this'))(); // tslint:disable-line
}
/**
* Set a global API to current context
*/
function setGlobalAPI(name, value, readonly) {
if ( readonly === void 0 ) readonly = true;
var context = getContextObject();
try {
Object.defineProperty(context, name, {
value: value,
configurable: true,
enumerable: true,
writable: !readonly
});
}
catch (e) {
context[name] = value;
}
}
/**
* Pick specific methods from a target object
*/
function pickMethods(object, methods) {
var exportObject = {};
methods.forEach(function (method) {
if (typeof object[method] === 'function') {
exportObject[method] = function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return object[method].apply(object, args);
};
}
});
return exportObject;
}
function getType(param) {
return Object.prototype.toString.call(param).slice(8, -1);
}
function isPlainObject(param) {
return getType(param) === 'Object';
}
function deepClone(source) {
var result = {};
try {
result = JSON.parse(JSON.stringify(source));
}
catch (e) { }
return result;
}
function noop() {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
}
/**
* Logger and Debugger methods
*/
// real logger of current context, could be override by host context
var logger = function () { };
var debuggerEnv = {};
var LOG_LEVELS = ['debug', 'info', 'log', 'warn', 'error'];
// override default logger
function setLoggerEnv(env) {
if (!env || !env.platform) {
return console.error('set logger environment failed.');
}
Object.assign(debuggerEnv, env);
}
function isDebugMode() {
return debuggerEnv.debugMode === true
|| debuggerEnv.debugMode === 'true'; // compatible for android
}
function isForTest() {
return typeof process === 'object'
&& process
&& process.env
&& process.env.PURPOSE === 'test';
}
/**
* Decide wether to print logs for the specified level.
*/
function shouldPrint(level) {
// intercept logger function in test mode
if (isForTest()) {
if (typeof __test_logger__ === 'function') {
logger = __test_logger__;
return true;
}
return false;
}
// always print log in debugMode
if (isDebugMode()) {
return true;
}
// check the log level
var defaultLevel = debuggerEnv.logLevel
|| ('debug');
return LOG_LEVELS.indexOf(level) >= LOG_LEVELS.indexOf(defaultLevel);
}
var capitalize = function (str) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
/**
* Default logger function, be compatible with different platforms.
*/
function defaultLogger(level, log) {
var role = '[wml-r]';
var str = "[" + (capitalize(level)) + "]" + role + " " + log;
{
var WEEX_PLATFORMS = ['Android', 'iOS'];
if (debuggerEnv.isWeex && WEEX_PLATFORMS.indexOf(debuggerEnv.platform) > -1) {
return console.log(str);
}
else {
return console.error(str);
}
}
}
logger = defaultLogger;
function debug(output) {
if (shouldPrint('debug')) {
logger('debug', output);
}
}
function warn(output) {
if (shouldPrint('warn')) {
logger('warn', output);
}
}
function error(output) {
if (shouldPrint('error')) {
logger('error', output);
}
}
function throwError(errMsg) {
error(errMsg);
if ("development" !== 'production' && !isForTest()) {
throw new Error(errMsg);
}
}
/**
* Get the source code of a function.
* May not always work well, it should only be used in debug logs.
*/
function getCode(fn) {
if (typeof fn === 'function') {
return Function.prototype.toString.call(fn);
}
return '';
}
var network = [
"request",
"uploadFile",
"downloadFile"
];
var miniApp = [
"setAppShareInfo",
"hideLauncherLoading",
"setWebViewTop",
"setWebViewBackgroundImage",
"getConfig",
"reLaunch"
];
var mtop = [
"request"
];
var storage = [
"length",
"setItem",
"getItem",
"removeItem",
"clearStorage",
"getStorageInfo",
{
name: "getItemSync",
sync: true
},
{
name: "setItemSync",
sync: true
},
{
name: "removeItemSync",
sync: true
},
{
name: "clearStorageSync",
sync: true
},
{
name: "getStorageInfoSync",
sync: true
}
];
var memoryStorage = [
"setItem",
"getItem"
];
var tabBar = [
"show",
"hide",
"setTabBarItem",
"setTabBarStyle",
"setTabBarBadge",
"removeTabBarBadge",
"showTabBarRedDot",
"hideTabBarRedDot"
];
var navigator = [
"push",
"pop",
"openMessagePage",
"reloadPage",
"getBackStack",
"popToHome",
"navigateTo",
"redirectTo",
"switchTab",
"navigateBackMiniProgram",
"navigateToMiniProgram"
];
var user = [
"login",
"logout",
"info"
];
var modal = [
"alert",
"confirm",
"toast",
"hideToast",
"showLoading",
"hideLoading",
"prompt"
];
var navigatorBar = [
"show",
"hide",
"setTitle",
"setRightItem",
"setStyle",
"setDrawer",
"setActionSheet",
"hasIndexBadge",
"scaleIndexBadge",
"resetIndexBadge",
"getHeight",
"openDrawer",
"isDrawerOpened",
"closeDrawer",
"setLeftItem",
"showMenu",
"hideMenu",
"getStatusBarHeight",
"setNavigationBar",
"hideNavigationBarLoading",
"showNavigationBarLoading"
];
var clipboard = [
"writeText",
"readText"
];
var picker = [
"pick",
"pickDate",
"pickTime",
"chooseCity"
];
var webSocket = [
"webSocket",
"send",
"close",
"onOpen",
"onMessage",
"onClose",
"onError"
];
var calendar = [
"addEvent",
"checkEvent",
"removeEvent"
];
var connection = [
"getType",
"getDownlinkMax",
"onChange"
];
var screen = [
"setAlwaysOn",
"setBrightness",
"getScreenBrightness"
];
var broadcast = [
"createChannel",
"postMessage",
"onMessage",
"close"
];
var share = [
"doShare"
];
var cookie = [
"read",
"write",
"getAllObjects"
];
var audio = [
"load",
"play",
"pause",
"stop",
"setVolume",
"canPlayType"
];
var wopc = [
"getSessionKey",
"setSessionKey",
"authorize",
"getSetting",
"openSetting"
];
var WopcMtopPlugin = [
"request"
];
var device = [
"onShake",
"vibrate",
"vibrateShort",
"onUserCaptureScreen",
"offUserCaptureScreen",
"scan"
];
var keyboard = [
"hideKeyboard"
];
var contact = [
"choosePhoneContact"
];
var location = [
"getLocation"
];
var alipay = [
"tradePay"
];
var userTrack = [
"commit",
"commitut",
"commitEvent",
"customAdvance",
"pageAppear",
"pageDisappear",
"skipPage",
"updatePageUtparam",
"updateNextPageUtparam"
];
var aluWVJSBridge = [
"userIsLogin",
"refreshAlipayCookie"
];
var TBDeviceInfo = [
"getUtdid"
];
var actionSheet = [
"showActionSheet"
];
var image = [
"chooseImage",
"previewImage",
"compressImage",
"getImageInfo",
"saveImage"
];
var media = [
"startVoice",
"stopVoice"
];
var audioRecord = [
"startRecord",
"stopRecord",
"cancelRecord"
];
var audioPlayer = [
"playVoice",
"pauseVoice",
"stopVoice"
];
var file = [
"saveFile",
"getFileInfo",
"getFileList",
"removeFile"
];
var video = [
"chooseVideo",
"getVideoInfo",
"saveVideoToPhotosAlbum"
];
var phone = [
"makePhoneCall"
];
var compass = [
"startCompass",
"stopCompass",
"onCompassChange"
];
var tbsecurity = [
"secureToken"
];
var sendMtop = [
"request"
];
var ZCache = [
"prefetch",
"fetch"
];
var WVZCache = [
"prefetch",
"fetch"
];
var sku = [
"show",
"hide"
];
var chat = [
"open"
];
var ucc = [
"uccBind",
"uccTrustLogin",
"uccUnbind"
];
var address = [
"choose"
];
var taopai = [
"openTaopaiShoot",
"openTaopaiEdit"
];
var poi = [
"openPOI"
];
var availableModules$1 = {
network: network,
miniApp: miniApp,
mtop: mtop,
storage: storage,
memoryStorage: memoryStorage,
tabBar: tabBar,
navigator: navigator,
user: user,
modal: modal,
navigatorBar: navigatorBar,
clipboard: clipboard,
picker: picker,
webSocket: webSocket,
calendar: calendar,
connection: connection,
screen: screen,
broadcast: broadcast,
share: share,
cookie: cookie,
audio: audio,
wopc: wopc,
WopcMtopPlugin: WopcMtopPlugin,
device: device,
keyboard: keyboard,
contact: contact,
location: location,
alipay: alipay,
userTrack: userTrack,
"nuvajs-exec": [
"exec"
],
aluWVJSBridge: aluWVJSBridge,
TBDeviceInfo: TBDeviceInfo,
actionSheet: actionSheet,
image: image,
media: media,
audioRecord: audioRecord,
audioPlayer: audioPlayer,
file: file,
video: video,
phone: phone,
compass: compass,
tbsecurity: tbsecurity,
sendMtop: sendMtop,
ZCache: ZCache,
WVZCache: WVZCache,
sku: sku,
chat: chat,
ucc: ucc,
address: address,
"private": [
"addProperties"
],
taopai: taopai,
poi: poi
};
/**
* Available modules of windmill container.
*
* It can be used by DSL framework to decide what apis should
* a module expose and generate the module proxy object.
*/
// using the same source file with native SDK
/**
* Register modules to worker context.
*/
function registerModules(modules, noWarning) {
if ( noWarning === void 0 ) noWarning = false;
if (!isPlainObject(modules)) {
error('Invalid parameter type! '
+ 'The module definition is not a plain object.');
return;
}
var loop = function ( moduleName ) {
var registeredModule = modules[moduleName];
if (availableModules$1[moduleName]) {
noWarning || warn("The \"" + moduleName + "\" module has already been registered."
+ "It would be overridden.");
}
else {
availableModules$1[moduleName] = [];
}
var moduleDefine = availableModules$1[moduleName];
if (Array.isArray(registeredModule)) {
registeredModule.forEach(function (methodDefine) {
if (isPlainObject(methodDefine)) {
// TODO: omit duplicated when methodDefine is plain object
moduleDefine.push(methodDefine);
}
else if (typeof methodDefine === 'string') {
var methodName = methodDefine;
if (moduleDefine.indexOf(methodName) === -1) {
moduleDefine.push(methodName);
}
else if (!noWarning) {
warn("The \"" + methodName + "\" of the \"" + moduleName + "\" module "
+ "has already been registered.");
}
}
});
}
else {
error("Invalid parameter type! The method list of the "
+ "\"" + moduleName + "\" module should be an Array.");
}
};
for (var moduleName in modules) loop( moduleName );
}
/**
* Create a module getter which depends on the worker runtime api
*/
function createModuleGetter(getRuntime, moduleInterceptor // intercept a module call
) {
// cached module proxies
var moduleInvoker = moduleInterceptor || function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return (ref = getRuntime()).$call.apply(ref, args);
var ref;
};
// universal module invoker for sync module
var syncModuleInvoker = moduleInterceptor || function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return (ref = getRuntime()).$callSync.apply(ref, args);
var ref;
};
/**
* Require a specific module.
* If the module name is not given, it'll return a universal module api.
*/
return function requireModule(moduleName) {
// return a universal module call api
if (!moduleName) {
debug("Require a universal module proxy.");
return { call: moduleInvoker };
}
// warn about unknown module
var moduleDefine = availableModules$1[moduleName];
if (!Array.isArray(moduleDefine)) {
warn("Require unknown module \"" + moduleName + "\"."
+ "It may not exist or haven't been registered.");
return;
}
debug(("Require the \"" + moduleName + "\" module."));
// return cached module proxy
// if (moduleProxies[moduleName]) {
// return moduleProxies[moduleName]
// }
// create module proxy
var apis = {};
moduleDefine.forEach(function (methodDefine) {
if (typeof methodDefine === 'string') {
apis[methodDefine] = function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return moduleInvoker.apply(void 0, [ (moduleName + "." + methodDefine) ].concat( args ));
};
}
else if (isPlainObject(methodDefine) && methodDefine.name) {
var methodName = methodDefine.name;
if (methodDefine.sync) {
apis[methodName] = function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return syncModuleInvoker.apply(void 0, [ (moduleName + "." + methodName) ].concat( args ));
};
}
else {
apis[methodName] = function () {
var args = [], len = arguments.length;
while ( len-- ) args[ len ] = arguments[ len ];
return moduleInvoker.apply(void 0, [ (moduleName + "." + methodName) ].concat( args ));
};
}
}
});
return apis;
};
}
/**
* Handshake constant event names.
*
* Worker Renderer
* │ W_PAGE_READY │
* │ ---------------------------> │
* │ <--------------------------- │
* │ R_PAGE_READY │
* │ │
* │ │
* │ SEND_STATE │
* │ ---------------------------> │
* │ <--------------------------- │
* │ GOT_STATE │
* │ │
* │ │
* │ W_STATE_CHANGE │
* │ ---------------------------> │
* │ <--------------------------- │
* │ R_STATE_CHANGE │
* │ │
*/
/**
* Handshake between worker and renderer.
*/
var R_READY = '[[RendererRuntimeReady]]';
/**
* supported app lifecycles
* [key]: lifecycle event name
* [value]: lifecycle method name in options
*/
// supported page lifecycles
/**
* Global apis for communication between worker and native.
*/
/**
* Global apis for communication between renderer and native.
*/
var POST_MESSAGE = '__windmill_post_message__';
var ON_MESSAGE = '__windmill_on_message__';
/**
* The global api to create a standalone context for app.
*/
/**
* The global api of worker runtime apis.
*/
/**
* The global api to register dsl framework in worker context.
*/
/**
* The global api to create a standalone module getter.
*/
var MODULE_GETTER = '__WINDMILL_MODULE_GETTER__';
/**
* Event emitted when any page lifecycle emitted
*/
/**
* Abstract Windmill Runtime APIs
*/
var AppRuntime = function AppRuntime() { };
AppRuntime.prototype.$on = function $on (event, callback) {
if ( callback === void 0 ) callback = noop;
debug(("$on \"" + event + "\""));
!event && throwError(("invalid event name " + event + " for windmill.$on."));
callback === noop && throwError(("bind event " + event + " with no callback through windmill.$on."));
return this.bridge.onReceiveMessage({
data: { type: event },
origin: this.label,
type: "Event" /* Event */
}, callback);
};
AppRuntime.prototype.$once = function $once (event, callback) {
if ( callback === void 0 ) callback = noop;
debug(("$once \"" + event + "\""));
!event && throwError(("invalid event name " + event + " for windmill.$once."));
callback === noop && throwError(("bind event " + event + " with no callback through windmill.$once."));
return this.bridge.onReceiveMessage({
data: { type: event, once: true },
origin: this.label,
type: "Event" /* Event */
}, callback);
};
AppRuntime.prototype.$off = function $off (event, listener) {
debug(("$off \"" + event + "\""));
!event && throwError(("invalid event name " + event + " for windmill.$off."));
return this.bridge.unbindEventListener((("Event") + "." + event), listener);
};
/**
* binding lifecycle hooks.
* @param lifecycle for app: 'app:launch', etc... for page: 'page@someClientId:load', etc...
* @param hook callback function, taking a messageData.result.option as argument.
*/
AppRuntime.prototype.$cycle = function $cycle (lifecycle, hook) {
if ( hook === void 0 ) hook = noop;
debug(("$cycle \"" + lifecycle + "\""));
if (!lifecycle || !/^app:|^page(:|@)/.test(lifecycle)) {
throwError(("invalid lifecycle name " + lifecycle + " for windmill.$cycle."));
}
hook === noop && throwError(("hook lifecycle " + lifecycle + " with no callback function through windmill.$cycle."));
if (this.label !== 'AppWorker' && /^app:/.test(lifecycle)) {
throwError("Shouldn't bind lifecycle hook for app in a page client.");
}
return this.bridge.onReceiveMessage({
type: "Lifecycle" /* Lifecycle */,
origin: this.label,
data: { type: lifecycle }
}, hook);
};
AppRuntime.prototype.$decycle = function $decycle (lifecycle, hook) {
debug(("$decycle \"" + lifecycle + "\""));
if (!lifecycle || !/^app:|^page(:|@)/.test(lifecycle)) {
throwError(("invalid lifecycle name " + lifecycle + " for windmill.$decycle."));
}
return this.bridge.unbindEventListener((("Lifecycle") + "." + lifecycle), hook);
};
/**
* emit a message to local or remote.
* @param event for local: just the event name. for remote: use 'eventName@clientId'.
* @param data event data.
* @param clientId (optional) remote client id or 'AppWorker' for worker.
*/
AppRuntime.prototype.$emit = function $emit (event, data, clientId) {
if ( data === void 0 ) data = {};
debug(("$emit(\"" + event + "\")"));
!event && throwError(("invalid event name " + event + " for windmill.$emit."));
// for remote event. emit a event to remote client (or 'AppWorker').
if (clientId && clientId !== this.label) {
return this.bridge.postMessage({
data: { type: event, data: data },
origin: this.label,
target: clientId,
type: "Event" /* Event */
});
}
// for local event.
return this.bridge.emitEvent(("" + event), data);
};
AppRuntime.prototype.$callAsync = function $callAsync (method, params, context, modifier) {
var this$1 = this;
if ( params === void 0 ) params = {};
if ( context === void 0 ) context = {};
if ( modifier === void 0 ) modifier = {};
debug(("$callAsync \"" + method + "\""));
if (!method) {
throwError(("invalid method name " + method + " for windmill.$callAsync."));
}
return new Promise(function (resolve, reject) {
this$1.bridge.dispatchMessage({
type: "ModuleCall" /* ModuleCall */,
origin: modifier.origin || this$1.label,
target: modifier.target || 'AppWorker',
data: { method: method, params: params, context: context }
}, resolve, reject, false);
});
};
AppRuntime.prototype.$call = function $call (method, params, successCallback, failureCallback, context, modifier) {
if ( params === void 0 ) params = {};
if ( successCallback === void 0 ) successCallback = noop;
if ( failureCallback === void 0 ) failureCallback = noop;
if ( context === void 0 ) context = {};
if ( modifier === void 0 ) modifier = {};
debug(("$call \"" + method + "\", params: " + (JSON.stringify(params))));
if (!method) {
throwError(("invalid method name " + method + " for windmill.$call."));
}
return this.bridge.dispatchMessage({
type: "ModuleCall" /* ModuleCall */,
origin: modifier.origin || this.label,
target: modifier.target || 'AppWorker',
data: { method: method, params: params, context: context },
}, successCallback, failureCallback, true);
};
AppRuntime.prototype.$registerModules = function $registerModules (modules) {
registerModules(modules, true);
};
AppRuntime.prototype.$getAvailableModules = function $getAvailableModules () {
return deepClone(availableModules$1);
};
/**
* Event Emitter
* Partially implement the events module of Node.js.
* https://nodejs.org/api/events.html#events_class_eventemitter
*/
var eventMapKey = '[[EVENT_MAP]]';
function initListeners(emitter, eventName) {
var events = emitter[eventMapKey];
if (!Array.isArray(events[eventName])) {
events[eventName] = [];
}
return events[eventName];
}
var EventEmitter = function EventEmitter() {
debug("Create new EventEmitter.");
Object.defineProperty(this, eventMapKey, {
configurable: false,
enumerable: false,
writable: false,
value: {}
});
};
EventEmitter.prototype.on = function on (eventName, listener) {
debug(("EventEmitter: on(\"" + eventName + "\")"));
var listeners = initListeners(this, eventName);
listeners.push({ listener: listener, once: false, callCount: 0 });
return this;
};
EventEmitter.prototype.once = function once (eventName, listener) {
debug(("EventEmitter: once(\"" + eventName + "\")"));
var listeners = initListeners(this, eventName);
listeners.push({ listener: listener, once: true, callCount: 0 });
return this;
};
EventEmitter.prototype.off = function off (eventName, listener) {
debug(("EventEmitter: off(\"" + eventName + "\"" + (listener ? ', listener' : '') + ")"));
var events = this[eventMapKey];
if (listener) {
var listeners = events[eventName];
if (Array.isArray(listeners)) {
var index = listeners.findIndex(function (x) { return x.listener === listener; });
if (index !== -1) {
listeners.splice(index, 1);
}
}
}
else {
delete events[eventName];
}
return this;
};
EventEmitter.prototype.emit = function emit (eventName) {
var args = [], len = arguments.length - 1;
while ( len-- > 0 ) args[ len ] = arguments[ len + 1 ];
debug(("EventEmitter: emit(\"" + eventName + "\", " + (JSON.stringify(args)) + ")"));
var events = this[eventMapKey];
var listeners = events[eventName];
if (Array.isArray(listeners)) {
// invoke event listeners
events[eventName] = listeners.filter(function (desc) {
try {
desc.listener.apply(null, args);
desc.callCount += 1;
}
catch (err) {
error("Failed to emit the \"" + eventName + "\" event: " + (err.toString())
+ "\nSource code: " + (getCode(desc.listener)));
// throw the error anyway
throw err;
}
return !desc.once;
});
}
return this;
};
function getMsgModuleFromWeex(weex) {
return (weex.requireModule('@weex/windmill')
|| weex.requireModule('windmill'));
}
/**
* Using native bridge APIs if they are exist.
*
* It would be more efficient than using module APIs.
* https://yuque.antfin-inc.com/taobaoapp/design/app_render_interface
*/
var bridgeWarningCount = 3;
function getMsgModuleFromContext() {
var context = getContextObject();
if (typeof context[POST_MESSAGE] === 'function') {
var bridge = {};
bridge.postMessage = context[POST_MESSAGE];
bridge.onmessage = function (onMessage) {
debug(("Register the \"" + ON_MESSAGE + "\" API."));
setGlobalAPI(ON_MESSAGE, onMessage);
};
return bridge;
}
if (bridgeWarningCount > 0) {
bridgeWarningCount--;
error(("Can't find available \"" + POST_MESSAGE + "\" API in the context."));
}
return false;
}
// function callNativeBridge(msg: any) {
// windmill.postMessage(JSON.stringify(msg))
// }
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
function guid() {
return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4());
}
function callNativeBridge(msg, identify) {
windmill.runMessage({
cmd: 'postMessage',
identify: identify,
data: {
message: JSON.stringify(msg),
pageid: ("[Page ID : " + (guid()) + "]")
}
});
}
function onNotify(callback) {
onmessage = function (msg) {
callback(msg);
};
}
var _msgModuleForWebview;
var _onMessageCalledOnce = false;
function getMsgModuleFromWebview(identify) {
if (!_msgModuleForWebview) {
// const context: any = typeof window !== 'undefined' ? window : global
_msgModuleForWebview = {
postMessage: function postMessage(msg) {
// return callWindvane(context, 'Windmill', 'postMessage', msg, () => {}, handleError)
return callNativeBridge(msg, identify);
},
onmessage: function onmessage(callback) {
"development" !== 'production' && console.debug("Set onMessage for webview.");
if (_onMessageCalledOnce) {
return;
}
_onMessageCalledOnce = true;
// return callWindvane(context, 'Windmill', 'onMessage', {}, callback, handleError)
return onNotify(callback);
}
};
}
return _msgModuleForWebview;
}
/**
* in case the messageModule is not ready, we should use lazy module
* to cache all the messages assumed to post, and when the one is
* ready, then flush the messages.
*/
var LazyMessageModule = function LazyMessageModule() {
this._messages = [];
};
LazyMessageModule.prototype.postMessage = function postMessage (message) {
debug(("cache message in lazyMsgModule. " + (JSON.stringify(message))));
this._messages.push(message);
};
LazyMessageModule.prototype.replaceWith = function replaceWith (msgModule) {
isLazyModuleActive = false;
this._messageModule = msgModule;
this._flush();
};
LazyMessageModule.prototype._flush = function _flush () {
var this$1 = this;
this._messages.forEach(function (msg) { return this$1._messageModule.postMessage(msg); });
};
var lazyModule = new LazyMessageModule();
var isLazyModuleActive;
/**
* getMessageModule will return the current messageModule or a lazy module if current one
* is not ready yet. The lazy module will cache all the posted messages, and flush them when
* a real messageModule (like 'windmill' module for weex) is ready. In the mean time when the
* real messageModule is ready, we'll set the onMessage hook to it.
* @param weex Weex instance.
* @param onMessage set message module's onmessage method with this function.
*/
function getMessageModule(weex, onMessage, identify) {
var msgModule = (weex
? getMsgModuleFromWeex(weex)
: (getMsgModuleFromContext() || getMsgModuleFromWebview(identify)));
if (!msgModule) {
throwError(("can't find message module (" + (weex ? 'windmill module' : 'message module in webview') + ")."));
isLazyModuleActive = true;
return lazyModule;
}
// set onmessage method to the message module.
if (typeof onMessage === 'function') {
debug('Set the "onmessage" method to the bridge through callback.');
try {
msgModule.onmessage(onMessage);
}
catch (e) {
error('Failed to set the "onmessage" method to the bridge through callback.');
error(e.toString());
}
}
// replace lazy msg module.
if (isLazyModuleActive) {
lazyModule.replaceWith(msgModule);
}
return msgModule;
}
var isWeex;
// for 'evt@clientId', return 'evt'
// for 'evt', return 'evt' itself.
function getPureEventName(name) {
var match = name.match(/([^@]+)(@\S+)/);
return match && match[1] || name;
}
var RendererBridge = function RendererBridge(weex, option) {
var this$1 = this;
if ( option === void 0 ) option = {};
debug('Create a new RendererBridge.');
this.identify = option.identify;
debug(("[multi-app] The current worker identify is " + (this.identify)));
isWeex = option.isWeex;
this._emitter = new EventEmitter();
// register onmessage api
debug(("Register onmessage api for " + (isWeex ? 'Weex windmill module' : 'webview') + "."));
if (isWeex) {
this._weex = weex;
}
this._onMessage = function (message) {
debug(("Receive message from the worker. (message: " + (JSON.stringify(message)) + ")"));
if (!isPlainObject(message)) {
error("The parameter of onmessage should be a plain object! "
+ "Not " + (getType(message)));
if (typeof message === 'string') {
try {
message = JSON.parse(message);
}
catch (e) {
error(("Failed to parse the message string. " + (e.toString())));
return;
}
}
}
var type = message.type;
var msgData = message.data; if ( msgData === void 0 ) msgData = {};
var origin = message.origin;
var callbackId = message.callbackId;
switch (type) {
case "Callback" /* Callback */:
{
this$1._emitter.emit(("callback@AppWorker:" + callbackId), msgData);
}
break;
case "Event" /* Event */:
{
var eventType = getPureEventName(msgData.type);
this$1._emitter.emit((type + "." + eventType), Object.assign({ origin: origin }, msgData, { type: eventType }));
}
break;
case "Lifecycle" /* Lifecycle */:
{
this$1._emitter.emit((type + "." + (msgData.lifecycle)), msgData.options);
}
break;
case "SetData" /* SetData */:
{
this$1._emitter.emit((("Event") + ".setdata"), msgData);
}
break;
default: {
throwError(("Unknown message type received from worker: \"" + type + "\""));
}
}
};
getMessageModule(weex, this._onMessage, this.identify);
};
RendererBridge.prototype.dispatchMessage = function dispatchMessage (message, success, fail, keepAlive) {
debug(("Dispatch message to worker. (message: " + (JSON.stringify(message)) + ")"));
message.callbackId = this._genCallbackId(function (param) {
if (param.status && param.status === 'SUCCESS') {
return success(param);
}
// TODO: check return status
switch (param.status) {
case 'FAILED': break;
}
error("call API " + (message.data.method) + " "
+ "from renderer failed: " + (param.status) + ", " + (param.error));
return fail(param);
}, { keepAlive: keepAlive });
try {
message.keepAlive = true;
this.postMessage(message);
}
catch (err) {
fail(err);
}
};
/**
* post message to worker.
* @param message MessageObject.
*/
RendererBridge.prototype.postMessage = function postMessage (message) {
try {
debug(("Call postMessage to worker. (message: " + (JSON.stringify(message)) + ")"));
getMessageModule(this._weex, this._onMessage, this.identify).postMessage(message);
}
catch (err) {
throwError(err.message || err.toString() || 'postMessage failed.');
}
};
/**
* auto bind a callbackId to a callback listener.
* return a callbackId.
*/
RendererBridge.prototype._genCallbackId = function _genCallbackId (callback, ref) {
var keepAlive = ref.keepAlive;
var callbackId = ref.callbackId;
var id = callbackId ? callbackId : uniqueId();
this._emitter[keepAlive ? 'on' : 'once'](("callback@AppWorker:" + id), callback);
return id;
};
/**
* bind messages with user defined handlers.
* type:
* 1. event: Event, data.type: xxx
* 2. lifecycle: Lifecycle, data.type: 'app:launch' / 'page:show'
*/
RendererBridge.prototype.onReceiveMessage = function onReceiveMessage (message, callback) {
var type = message.type;
var data = message.data; if ( data === void 0 ) data = {}; // Event / Lifecycle
var name = data.type;
if (type === "Event" /* Event */) {
name = getPureEventName(name);
data.type = name;
}
var bind = data.once ? 'once' : 'on';
this._emitter[bind]((type + "." + name), callback);
};
RendererBridge.prototype.unbindEventListener = function unbindEventListener (event, listener) {
this._emitter.off(getPureEventName(event), listener);
};
RendererBridge.prototype.emitEvent = function emitEvent (event, data) {
if ( data === void 0 ) data = {};
var evtName = getPureEventName(event);
this._emitter.emit((("Event") + "." + evtName), { type: evtName, data: data });
};
var RendererRuntime = (function (AppRuntime$$1) {
function RendererRuntime(weex, options) {
if ( options === void 0 ) options = {};
AppRuntime$$1.call(this);
this._name = options.pageName || '';
this.label = options.clientId || '';
if (weex && isPlainObject(weex.config)) {
this._name = weex.config.pageName || '';
this.label = weex.config.clientId || '';
if (weex.config.availableModules) {
this.$registerModules(weex.config.availableModules);
this._gotAvailableModulesFromWeex = true;
}
else {
warn("No available modules in weex options.");
}
}
debug(("Create a new RendererRuntime. (" + (this.label) + ", " + (this._name) + ")"));
this.bridge = new RendererBridge(weex, options);
this._init();
}
if ( AppRuntime$$1 ) RendererRuntime.__proto__ = AppRuntime$$1;
RendererRuntime.prototype = Object.create( AppRuntime$$1 && AppRuntime$$1.prototype );
RendererRuntime.prototype.constructor = RendererRuntime;
RendererRuntime.prototype._init = function _init () {
var this$1 = this;
// listening on event from worker and register available modules
this.bridge.onReceiveMessage({
origin: 'AppWorker',
target: this.label,
type: "Event" /* Event */,
data: { type: 'registerModules' }
}, function (event /* EventData */) {
if (event && event.type === 'registerModules') {
debug(("Register available modules in renderer. (" + (Object.keys(event.data)) + ")"));
this$1.$registerModules(event.data);
}
});
};
// dispatch ready message
RendererRuntime.prototype.ready = function ready () {
this.bridge.dispatchMessage({
origin: this.label,
target: 'AppWorker',
type: "Event" /* Event */,
data: {
type: R_READY,
data: {
label: this.label,
handshake: !this._gotAvailableModulesFromWeex
}
}
}, noop, noop);
};
RendererRuntime.prototype.$getCurrentActivePageId = function $getCurrentActivePageId () {
return this.label;
};
return RendererRuntime;
}(AppRuntime));
var exposedAPIs = [
'$on',
'$once',
'$off',
'$emit',
'$cycle',
'$decycle',
'$call',
'$callAsync',
'$navTo',
'$getAvailableModules',
'$getCurrentActivePageId'
];
function index (weex, options) {
var isWeex = !!(weex && weex.requireModule);
setLoggerEnv({
platform: isWeex && weex.config.env.platform,
debugMode: isWeex && weex.config.env.debugMode,
isWeex: isWeex
});
debug("Setup Windmill renderer framework.");
// For weex renderer, use weex.requireModule. For webview
// renderer, ignore the weex parameter.
if (weex && !weex.requireModule) {
options = weex;
weex = undefined;
}
if (!options) {
options = {};
}
options = Object.assign({}, options); // incase option is frozen.
options.isWeex = isWeex;
debug(("Instantiate renderer in " + (isWeex ? 'Weex container' : 'WindVane container') + "."));
var renderer = new RendererRuntime(weex, options);
var runtime = pickMethods(renderer, exposedAPIs);
debug(("Prepare runtime APIs: " + (JSON.stringify(exposedAPIs))));
// whether to expose the module getter api to current context
if (options.exposeModuleGetter) {
setGlobalAPI(MODULE_GETTER, createModuleGetter(function () { return runtime; }));
}
renderer.ready();
return runtime;
}
return index;
})));