UNPKG

cordova-plugin-ace

Version:

Enables you to mix native UI and native code with your JavaScript and HTML. http://microsoft.github.io/ace

252 lines (219 loc) 9.34 kB
//------------------------------------------------------------------------------------------------------- // Copyright (C) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. //------------------------------------------------------------------------------------------------------- // // The base class for all objects with a corresponding native instance. // All objects have a handle property. // function NativeObject(nativeTypeName /*, ...*/) { this._eventHandlers = {}; this._properties = {}; if (arguments.length > 1) { var constructorArgs = []; for (var i = 1; i < arguments.length; i++) { constructorArgs.push(arguments[i]); } // Call a parameterized constructor this.handle = ace.ToNative.queueCreateMessage(this, nativeTypeName, constructorArgs); } else { this.handle = ace.ToNative.queueCreateMessage(this, nativeTypeName); } }; function unwrapResult(result) { if (!result) return result; if (result.length !== undefined) { if (result.length == 1) { // This is a single primitive value from Android, which wraps it in a JSONArray // TODO: Fix this so we can distinguish between this and a one-element array return result[0]; } else if (typeof result === "string" || result instanceof String) { // Just a string, not really an array! return result; } else { alert("NYI: array: " + result.length + ", " + result); } } else if (result.value !== undefined) { var instance = ace.ToNative.instanceFromHandle(result); return instance; } else { // This is a single primitive value return result; } } function fieldHelper(instance, isPrivate, className, fieldName, onSuccess, onError) { if (!fieldName) { throw new Error("You must specify a field"); } if (!onSuccess) { throw new Error("You must specify a callback that receives the value"); } // The caller needs the value, so we can't queue this message in the same // batch as all the other messages. // First send out all pending messages ace.ToNative.sendPendingMessages(); // Now queue this single message if (instance) { if (isPrivate) { ace.ToNative.queuePrivateFieldGetMessage(instance, fieldName); } else { ace.ToNative.queueFieldGetMessage(instance, fieldName); } } else { ace.ToNative.queueStaticFieldGetMessage(className, fieldName); } // Send this out as a batch of one, with the passed-in callbacks ace.ToNative.sendPendingMessages(function (result) { onSuccess(unwrapResult(result)) }, onError); } function invokeHelper(instance, className, methodName, varargsStartIndex, varargs) { if (!methodName) { throw new Error("You must specify a method to invoke."); } var args = []; var onSuccess = null; var onError = null; // Process the arguments, skipping varargs[0] and perhaps varagrs[1], // which were either methodName or className+methodName for (var i = varargsStartIndex; i < varargs.length; i++) { if (typeof varargs[i] === "function") { if (!onSuccess) onSuccess = varargs[i]; else onError = varargs[i]; } else { args.push(varargs[i]); } } if (onSuccess) { // The caller wants a return value, so we can't queue this message in the same // batch as all the other messages. // First send out all pending messages ace.ToNative.sendPendingMessages(); // Now queue this single invocation message if (instance) ace.ToNative.queueInvokeMessage(instance, methodName, args); else ace.ToNative.queueStaticInvokeMessage(className, methodName, args); // Send this out as a batch of one, with the passed-in callbacks ace.ToNative.sendPendingMessages(function (result) { onSuccess(unwrapResult(result)) }, onError); } else { if (instance) ace.ToNative.queueInvokeMessage(instance, methodName, args); else ace.ToNative.queueStaticInvokeMessage(className, methodName, args); } } // Invoke an instance (or static) method // // Pass any arguments as additional parameters. // Valid arguments are primitive types. // If the last two parameters are functions, they will be used as // "onSuccess" and "onError" callback functions. // onSuccess is passed the return value from the method. // onError is passed the error. // If only the last parameter is a function, it will be used as an "onSuccess" // callback. NativeObject.prototype.invoke = function (methodName /*, ...*/) { invokeHelper(this, null, methodName, 1, arguments); }; // Invoke a static method // // Pass any arguments as additional parameters. // Valid arguments are primitive types. // If the last two parameters are functions, they will be used as // "onSuccess" and "onError" callback functions. // onSuccess is passed the return value from the method. // onError is passed the error. // If only the last parameter is a function, it will be used as an "onSuccess" // callback. NativeObject.invoke = function (className, methodName /*, ...*/) { invokeHelper(null, className, methodName, 2, arguments); }; // Get a property value // Properties are special because they are cached locally and therefore // can be retrieved synchronously. NativeObject.prototype.get = function (propertyName) { // Only ever retrieve a local value. // If something on the native side changes a property value, it will be reflected already. // // By design, the default value of all properties is undefined, which means "has never been set." // In practice, this could mean different native values on different platforms (like a different default font size). return this._properties[propertyName]; }; // Set a property value NativeObject.prototype.set = function (propertyName, propertyValue) { // Store locally this.invalidate(propertyName, propertyValue); // Send to the native side ace.ToNative.queueSetMessage(this, propertyName, propertyValue); }; // Set the property value without propagating the change to the native side. // This should ONLY be called in response to property invalidations that originate // from the native side. That way, both sides still stay in-sync. NativeObject.prototype.invalidate = function (propertyName, propertyValue) { // Store locally this._properties[propertyName] = propertyValue; }; // Get the value of an instance (or static) field NativeObject.prototype.getField = function (fieldName, onSuccess, onError) { fieldHelper(this, false, null, fieldName, onSuccess, onError); }; // Get the value of a static field NativeObject.getField = function (className, fieldName, onSuccess, onError) { fieldHelper(null, false, className, fieldName, onSuccess, onError); }; // Get the value of a private instance (or static) field NativeObject.prototype.getPrivateField = function (fieldName, onSuccess, onError) { fieldHelper(this, true, null, fieldName, onSuccess, onError); }; // Set the value of an instance (or static) field NativeObject.prototype.setField = function (fieldName, fieldValue) { ace.ToNative.queueFieldSetMessage(this, fieldName, fieldValue); }; NativeObject.prototype.addEventListener = function (eventName, func) { if (!this._eventHandlers[eventName]) { this._eventHandlers[eventName] = []; } this._eventHandlers[eventName].push(func); // The "loaded" event is special and handled purely on the managed side if (eventName != "loaded") { ace.ToNative.queueEventAddMessage(this, eventName); } }; NativeObject.prototype.removeEventListener = function (eventName, func) { if (this._eventHandlers[eventName]) { this._eventHandlers[eventName].remove(func); } ace.ToNative.queueEventRemoveMessage(this, eventName); }; NativeObject.prototype.removeAllEventListeners = function () { //TODO: Need to detach on native side, too! this._eventHandlers = {}; }; NativeObject.prototype.raiseEvent = function (eventName, eventData, eventData2) { // Call any handlers // Currently, derived collections do not have the _eventHandlers member if (this._eventHandlers) { if (this._eventHandlers[eventName]) { // Create a clone of the current event handlers list to ensure that we continue to notify // all handlers even if one calls back into removeEventListener var handlers = this._eventHandlers[eventName].slice(0); for (var i = 0; i < handlers.length; i++) { handlers[i](this, eventData, eventData2); } return true; } } return false; }; module.exports = NativeObject;