diff --git a/apps/app.helloworld/app.css b/apps/app.helloworld/app.css index cb17ba0..cb1ab50 100644 --- a/apps/app.helloworld/app.css +++ b/apps/app.helloworld/app.css @@ -1,25 +1,25 @@ /** * Custom Applications SDK for Mazda Connect Infotainment System - * + * * A mini framework that allows to write custom applications for the Mazda Connect Infotainment System * that includes an easy to use abstraction layer to the JCI system. * * Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk) * Copyright (c) 2016. All rights reserved. - * + * * WARNING: The installation of this application requires modifications to your Mazda Connect system. * If you don't feel comfortable performing these changes, please do not attempt to install this. You might * be ending up with an unusuable system that requires reset by your Dealer. You were warned! * - * This program is free software: you can redistribute it and/or modify it under the terms of the + * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public * License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. + * + * You should have received a copy of the GNU General Public License along with this program. * If not, see http://www.gnu.org/licenses/ * */ @@ -28,7 +28,7 @@ * NOTICE: It's important that you target your application with the [app] attribute */ -[app="app.helloworld"] .smallerText { +[app="app.helloworld"] .smallerText { font-size:0.8em; color: #aaa; margin-bottom:20px; diff --git a/apps/app.helloworld/app.js b/apps/app.helloworld/app.js index e5c874d..d234047 100644 --- a/apps/app.helloworld/app.js +++ b/apps/app.helloworld/app.js @@ -52,12 +52,6 @@ CustomApplicationsHandler.register("app.helloworld", new CustomApplication({ js: [], - /** - * (css) defines css includes - */ - - css: ['app.css'], - /** * (images) defines images that are being preloaded * diff --git a/gulpfile.js b/gulpfile.js index 26db961..4f4bc79 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -170,7 +170,7 @@ gulp.task('appdrive-framework-js', function() { base: frameworkPathInput + "js" }) .pipe(concat('framework.js')) - .pipe(uglify()) + //.pipe(uglify()) .pipe(concatutil.header(fs.readFileSync(frameworkPathInput + "resources/header.txt", "utf8"), { pkg: package })) diff --git a/src/framework/js/CustomApplication.js b/src/framework/js/CustomApplication.js index 5f95849..098fd99 100644 --- a/src/framework/js/CustomApplication.js +++ b/src/framework/js/CustomApplication.js @@ -140,6 +140,15 @@ var CustomApplication = (function() { CCW: 'ccw', + /** + * Life Cycles + * @type enum + */ + lifecyles: { + CREATED: 'created', + }, + + /** * Creates the custom application's log object. This method is called during the initialization of the * custom application. @@ -164,17 +173,17 @@ var CustomApplication = (function() { }, debug: function() { - CustomApplicationLog.debug.apply(CustomApplicationLog, this.__toArray(arguments)); + Logger.debug.apply(this, this.__toArray(arguments)); }, // info info: function() { - CustomApplicationLog.info.apply(CustomApplicationLog, this.__toArray(arguments)); + Logger.info.apply(this, this.__toArray(arguments)); }, // error error: function() { - CustomApplicationLog.error.apply(CustomApplicationLog, this.__toArray(arguments)); + Logger.error.apply(this, this.__toArray(arguments)); }, }; @@ -203,8 +212,8 @@ var CustomApplication = (function() { this.__currentContextIndex = false; // global specific - this.is = CustomApplicationHelpers.is(); - this.sprintr = CustomApplicationHelpers.sprintr; + this.is = CMU.helpers.is; + this.sprintr = CMU.helpers.sprintr; // initialize log this.__log(); @@ -222,7 +231,7 @@ var CustomApplication = (function() { }.bind(this), this.CHANGED); - this.__region = CustomApplicationDataHandler.get(VehicleData.general.region, 'na').value; + this.__region = false; // CustomApplicationDataHandler.get(VehicleData.general.region, 'na').value; // set loader status this.__loaded = false; @@ -250,7 +259,7 @@ var CustomApplication = (function() { this.__created = true; // execute life cycle - this.__lifecycle("created"); + this.__lifecycle(this.lifecyles.CREATED); // all done this.__initialized = true; @@ -298,7 +307,7 @@ var CustomApplication = (function() { // load javascripts if (this.require.js && !this.is.empty(this.require.js)) { toload++; - CustomApplicationResourceLoader.loadJavascript(this.require.js, this.location, function() { + CMU.requestResource(CMU.resource.JAVASCRIPT, this.require.js, this.location, function() { loaded++; isFinished(); }); @@ -307,25 +316,12 @@ var CustomApplication = (function() { // load css if (this.require.css && !this.is.empty(this.require.css)) { toload++; - CustomApplicationResourceLoader.loadCSS(this.require.css, this.location, function() { + CMU.requestResource(CMU.resource.CSS, this.require.css, this.location, function() { loaded++; isFinished(); }); } - // load images - if (this.require.images && !this.is.empty(this.require.images)) { - toload++; - CustomApplicationResourceLoader.loadImages(this.require.images, this.location, function(loadedImages) { - - // assign images - this.images = loadedImages; - - loaded++; - isFinished(); - }.bind(this)); - } - return; } diff --git a/src/framework/js/CustomApplicationLog.js b/src/framework/js/CustomApplicationLog.js deleted file mode 100644 index e86808d..0000000 --- a/src/framework/js/CustomApplicationLog.js +++ /dev/null @@ -1,147 +0,0 @@ -/** - * Custom Applications SDK for Mazda Connect Infotainment System - * - * A mini framework that allows to write custom applications for the Mazda Connect Infotainment System - * that includes an easy to use abstraction layer to the JCI system. - * - * Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk) - * Copyright (c) 2016. All rights reserved. - * - * WARNING: The installation of this application requires modifications to your Mazda Connect system. - * If you don't feel comfortable performing these changes, please do not attempt to install this. You might - * be ending up with an unusuable system that requires reset by your Dealer. You were warned! - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - * License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see http://www.gnu.org/licenses/ - * - */ - - -/** - * (CustomApplicationLog) - * - * A logger - */ - -var CustomApplicationLog = { - - levels: { - debug: 'DEBUG', - info: 'INFO', - error: 'ERROR', - }, - - enabledLogger: false, - enabledConsole: false, - - /** - * (enable) enables the log - */ - - enableLogger: function(value) { - - this.enabledLogger = value; - }, - - /** - * (enable) enables the log - */ - - enableConsole: function(value) { - - this.enabledConsole = value; - }, - - /** - * (debug) debug message - */ - - debug: function() { - this.__message(this.levels.debug, "#006600", Array.apply(null, arguments)); - }, - - /** - * (error) error message - */ - - error: function() { - this.__message(this.levels.error, "#FF0000", Array.apply(null, arguments)); - }, - - /** - * (info) info message - */ - - info: function() { - this.__message(this.levels.info, "#0000FF", Array.apply(null, arguments)); - }, - - /** - * (message) - */ - - __message: function(level, color, values) { - - if(this.enabledLogger || this.enabledConsole || typeof(DevLogger) != "undefined") { - - var msg = []; - if(values.length > 1) { - values.forEach(function(value, index) { - - if(index > 0) { - - switch(true) { - - case CustomApplicationHelpers.is().iterable(value): - - CustomApplicationHelpers.iterate(value, function(key, value, obj) { - - msg.push(obj ? CustomApplicationHelpers.sprintr("[{0}={1}]", key, value) : CustomApplicationHelpers.sprintr("[{0}]", value)); - - }); - break; - - default: - msg.push(value); - break; - } - } - - }); - } - - try { - if(this.enabledLogger && typeof(Logger) != "undefined") { - Logger.log(level, values[0], msg.join(" "), color); - } - - if(typeof(DevLogger) != "undefined") { - DevLogger.log(level, values[0], msg.join(" "), color); - } - } catch(e) { - // do nothing - } - - try { - if(this,enabledConsole) { - console.log( - CustomApplicationHelpers.sprintr("%c[{0}] [{1}] ", (new Date()).toDateString(), values[0]) + - CustomApplicationHelpers.sprintr("%c{0}", msg.join(" ")), - "color:black", - CustomApplicationHelpers.sprintr("color:{0}", color) - ); - } - } catch(e) { - // do nothing - } - } - } -}; \ No newline at end of file diff --git a/src/framework/js/CustomApplicationOverride.js b/src/framework/js/CustomApplicationOverride.js deleted file mode 100644 index 934147e..0000000 --- a/src/framework/js/CustomApplicationOverride.js +++ /dev/null @@ -1,652 +0,0 @@ -/** - * Custom Applications SDK for Mazda Connect Infotainment System - * - * A mini framework that allows to write custom applications for the Mazda Connect Infotainment System - * that includes an easy to use abstraction layer to the JCI system. - * - * Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk) - * Copyright (c) 2016. All rights reserved. - * - * WARNING: The installation of this application requires modifications to your Mazda Connect system. - * If you don't feel comfortable performing these changes, please do not attempt to install this. You might - * be ending up with an unusuable system that requires reset by your Dealer. You were warned! - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - * License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see http://www.gnu.org/licenses/ - * - */ - -/** - * This is the main system file that manages everything between the CMU backend server and the frontend. - */ - -/** - * (Logger) - */ - -window.Logger = { - - levels: { - debug: 'DEBUG', - info: 'INFO', - error: 'ERROR', - }, - - /** - * Subscriptions - * @array - */ - subscriptions: [], - - /** - * (debug) debug message - */ - - debug: function() { - this.__message(this.levels.debug, "#006600", Array.apply(null, arguments)); - }, - - /** - * (error) error message - */ - - error: function() { - this.__message(this.levels.error, "#FF0000", Array.apply(null, arguments)); - }, - - /** - * (info) info message - */ - - info: function() { - this.__message(this.levels.info, "#0000FF", Array.apply(null, arguments)); - }, - - /** - * Subscribe - * @return {[type]} [description] - */ - subscribe: function(callback) { - - if(typeof(callback) == "function") { - this.subscriptions.push(callback); - } - }, - - /** - * [__message description] - * @param {[type]} level [description] - * @param {[type]} color [description] - * @param {[type]} values [description] - * @return {[type]} [description] - */ - __message: function(level, color, values) { - - var msg = []; - - if(values.length > 1) { - values.forEach(function(value, index) { - - if(index > 0) { - - if(typeof(value) == "object") { - - var keys = value, o = false; - - if(Object.prototype.toString.call(value) == "[object Object]") { - var keys = Object.keys(value), - o = true; - } - - if(keys.forEach) { - - keys.forEach(function(v, index) { - msg.push(o ? '[' + v + '=' + value[v]+ ']' : '[' + v + ']'); - }); - - } - - } else { - msg.push(value); - } - } - }); - } - - msg = msg.join(" "); - - this.subscriptions.forEach(function(subscription) { - - try { - subscription(level, values[0], msg, color); - } catch(e) { - - } - }); - } -}; - - -/** - * (CustomApplications) - * - * Registers itself between the JCI system and CustomApplication framework. - */ - -window.CustomApplications = { - - ID: 'system', - - /** - * (locals) - */ - debug: false, - bootstrapped: false, - - systemAppId: 'system', - systemAppCategory: 'Applications', - - /** - * Overwrites - */ - proxyAppName: 'vdt', - proxyAppContext: 'DriveChartDetails', - proxyMmuiEvent: 'SelectDriveRecord', - - targetAppName: 'custom', - targetAppContext: 'Surface', - - /** - * Configuration - */ - configuration: { - - networkHost: '127.0.0.1', - networkPort: 9700, - - }, - - /** - * Commands - */ - commands: { - - REQUEST_PING: 'ping', - REQUEST_APPDRIVE: 'appdrive', - }, - - /** - * Results - */ - results: { - - RESULT_OK: 200, - RESULT_PONG: 201, - RESULT_NOTFOUND: 404, - RESULT_ERROR: 500, - }, - - /** - * Initializes the proxy - * @return void - */ - initialize: function(callback) { - - if(!this.initialized) { - - this.initialized = true; - - this.requests = {}; - - this.obtainConnection(); - } - - return callback ? callback() : true; - }, - - - /** - * Establishes a connection between the front and backend - * @return void - */ - obtainConnection: function() { - - try { - - this.client = new WebSocket('ws://' + this.configuration.networkHost + ':' + this.configuration.networkPort); - - /** - * Ping - */ - this.client.ping = function() { - - this.request(this.commands.REQUEST_PING, { - inboundStamp: (new Date()).getTime() - }, function(error, result) { - - Logger.info(this.ID, "ping", { - lost: error, - time: !error ? result.outboundStamp - result.inboundStamp : 0, - }); - - }.bind(this)); - - }.bind(this); - - /** - * onOpen - * @event - */ - this.client.onopen = function() { - - Logger.info(this.ID, "connection open"); - - this.client.ping(); - - this.requestAppDrive(); - - }.bind(this); - - /** - * onMessage - * @event - */ - this.client.onmessage = function(message) { - - this.handleReturnRequest(message); - - }.bind(this); - - /** - * onError - * @event - */ - this.client.onerror = function(error) { - - Logger.error(CustomApplications.ID, 'ClientError', error); - - }.bind(this); - - /** - * onClose - * @event - */ - this.client.onclose = function(event) { - - this.client = null; - - if(event.code == 3110) { - - } else { - - setTimeout(function() { - - CustomApplications.obtainConnection(); - - }, 5000); // retry later - - } - - }.bind(this); - - } catch(e) { - - this.client = null; - } - }, - - /** - * [request description] - * @return {[type]} [description] - */ - request: function(request, payload, callback) { - - // check connection state - if(!this.client || this.client.readyState != 1) return callback(true, {}); - - // prepare id - var id = false; - while(!id || this.requests[id]) { - id = (new Date()).getTime(); - } - - // register request - this.requests[id] = callback; - - // sanity check - payload = payload || {}; - - // add request id - payload.requestId = id; - - payload.request = request; - - // execute - return this.client.send(JSON.stringify(payload)); - }, - - - /** - * Processes a request - * @param {[type]} data [description] - * @return {[type]} [description] - */ - handleReturnRequest: function(message) { - - try { - // parse message - var payload = JSON.parse(message.data); - - // check against active requests - if(payload.requestId && this.requests[payload.requestId]) { - - var callback = this.requests[payload.requestId]; - - if(typeof(callback) == "function") { - - callback(payload.result == this.results.RESULT_ERROR, payload); - } - - delete this.requests[payload.requestId]; - - return; // all done - } - - } catch(e) { - - Logger.error(CustomApplications.ID, 'handleReturnRequest', e); - } - }, - - - /** - * Trys to load the AppDrive - * @return void - */ - requestAppDrive: function() { - - if(typeof(CustomApplicationsHandler) != "undefined") return false; - - if(!this.request(this.commands.REQUEST_APPDRIVE, false, function(error, result) { - - if(error || !result.appdrive) { - return setTimeout(function() { - - this.requestAppDrive(); - - }.bind(this), 100); - } - - // load appdrive - this.loadAppDrive(result.appdrive, function() { - - // boot strap system - this.bootstrap(); - - // update applications - this.updateApplications(); - - }.bind(this)); - - }.bind(this))); - }, - - - /** - * Attempts to load the AppDrive - * @param object appdrive The AppDrive object - * @return void - */ - loadAppDrive: function(appdrive, callback) { - - this.appdrive = appdrive; - - if(this.appdrive) { - - // load css - this.loadCSS(this.appdrive.css); - - // load js - this.loadJS(this.appdrive.js, callback); - } - }, - - - /** - * (bootstrap) - * - * Bootstraps the JCI system - */ - - bootstrap: function() { - - // verify that core objects are available - if(typeof framework === 'object' && framework._currentAppUiaId === this.systemAppId && this.bootstrapped === false) { - - // retrieve system app - var systemApp = framework.getAppInstance(this.systemAppId); - - // verify bootstrapping - yeah long name - if(systemApp) { - - // set to strap - if everything fails - no harm is done :-) - this.bootstrapped = true; - - // let's boostrap - try { - - // overwrite list2 handler - systemApp._contextTable[this.systemAppCategory].controlProperties.List2Ctrl.selectCallback = this.menuItemSelectCallback.bind(systemApp); - - // for usb changes - we do this right now but might - if(typeof(systemApp.overwriteStatusMenuUSBAudioMsgHandler) == "undefined") { - systemApp.overwriteStatusMenuUSBAudioMsgHandler = systemApp._StatusMenuUSBAudioMsgHandler; - systemApp._StatusMenuUSBAudioMsgHandler = this.StatusMenuUSBAudioMsgHandler.bind(systemApp); - } - - // overwrite framework route handler - if(typeof(framework.overwriteRouteMmmuiMsg) == "undefined") { - framework.overwriteRouteMmmuiMsg = framework.routeMmuiMsg; - framework.routeMmuiMsg = this.routeMmuiMsg.bind(framework); - } - - // ovewrite framework MMUI sender - if(typeof(framework.overwriteSendEventToMmui) == "undefined") { - framework.overwriteSendEventToMmui = framework.sendEventToMmui; - framework.sendEventToMmui = this.sendEventToMmui.bind(framework); - } - - // assign template transition - framework.transitionsObj._genObj._TEMPLATE_CATEGORIES_TABLE.SurfaceTmplt = 'Detail with UMP'; - - } catch(e) { - // bootstrapping process failed - we just leave it here - } - } - } - }, - - - /** - * (Overwrite) menuItemSelectCallback - */ - - menuItemSelectCallback: function(listCtrlObj, appData, params) { - - try { - - if(appData.mmuiEvent == "SelectCustomApplication") { - - // exit if handler is not available - if(typeof(CustomApplicationsHandler) != "undefined") { - - // launch app - if(CustomApplicationsHandler.launch(appData)) { - - // clone app data - try { - appData = JSON.parse(JSON.stringify(appData)); - - // set app data - appData.appName = CustomApplicationsProxy.proxyAppName; - appData.mmuiEvent = CustomApplicationsProxy.proxyMmuiEvent; - } catch(e) { - // do nothing - } - } - } - } - - } catch(e) { - // do nothing - } - - // pass to original handler - this._menuItemSelectCallback(listCtrlObj, appData, params); - }, - - - /** - * (Overwrite) sendEventToMmui - */ - - sendEventToMmui: function(uiaId, eventId, params, fromVui) { - - var currentUiaId = this.getCurrentApp(), - currentContextId = this.getCurrCtxtId(); - - // proxy overwrites - if(typeof(CustomApplicationsHandler) === 'object' && currentUiaId == CustomApplicationsProxy.targetAppName) { - currentUiaId = CustomApplicationsProxy.proxyAppName; - currentContextId = CustomApplicationsProxy.proxyAppContext; - } - - // pass to original handler - framework.overwriteSendEventToMmui(uiaId, eventId, params, fromVui, currentUiaId, currentContextId); - }, - - - /** - * (Overwrite) routeMmuiMsg - */ - - routeMmuiMsg: function(jsObject) { - - if(typeof(CustomApplicationsHandler) === 'object') { - - try { - - var proxy = CustomApplications; - - // validate routing message - switch(jsObject.msgType) { - - // magic switch - case 'ctxtChg': - if(jsObject.uiaId == proxy.proxyAppName) { - jsObject.uiaId = proxy.targetAppName; - jsObject.ctxtId = proxy.targetAppContext; - } - break; - - // check if our proxy app is in the focus stack - case 'focusStack': - - if(jsObject.appIdList && jsObject.appIdList.length) { - for(var i = 0; i < jsObject.appIdList.length; i++) { - var appId = jsObject.appIdList[i]; - if(appId.id == proxy.proxyAppName) { - appId.id = proxy.targetAppName; - } - }; - } - - case 'msg': - case 'alert': - - if(jsObject.uiaId == proxy.proxyAppName) { - jsObject.uiaId = proxy.targetAppName; - } - - break; - default: - // do nothing - break; - } - - } catch(e) { - // do nothing - } - } - - // pass to framework - framework.overwriteRouteMmmuiMsg(jsObject); - }, - - - /** - * (Overwrite) StatusMenuUSBAudioMsgHandler - */ - - StatusMenuUSBAudioMsgHandler: function(msg) { - - // pass to original handler - this.overwriteStatusMenuUSBAudioMsgHandler(msg); - }, - - - /** - * (updateApplications) - */ - - updateApplications: function() { - // extend with custom applications - try { - if(typeof(CustomApplicationsHandler) != "undefined") { - - CustomApplicationsHandler.retrieve(function(items) { - - var systemApp = framework.getAppInstance(this.systemAppId); - - items.forEach(function(item) { - - systemApp._masterApplicationDataList.items.push(item); - - framework.localize._appDicts[this.systemAppId][item.appData.appName.replace(".", "_")] = item.title; - - framework.common._contextCategory._contextCategoryTable[item.appData.appName + '.*'] = 'Applications'; - - }.bind(this)); - - }.bind(this)); - } - } catch(e) { - // failed to register applications - } - } - -}; - - -/** - * Runtime Caller - */ - -if(window.opera) { - window.opera.addEventListener('AfterEvent.load', function (e) { - CustomApplications.initialize(function() { - CustomApplications.bootstrap(); - }); - }); -} - - -/** EOF **/ \ No newline at end of file diff --git a/src/framework/js/CustomApplicationResourceLoader.js b/src/framework/js/CustomApplicationResourceLoader.js deleted file mode 100644 index 11a5335..0000000 --- a/src/framework/js/CustomApplicationResourceLoader.js +++ /dev/null @@ -1,195 +0,0 @@ -/** - * Custom Applications SDK for Mazda Connect Infotainment System - * - * A mini framework that allows to write custom applications for the Mazda Connect Infotainment System - * that includes an easy to use abstraction layer to the JCI system. - * - * Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk) - * Copyright (c) 2016. All rights reserved. - * - * WARNING: The installation of this application requires modifications to your Mazda Connect system. - * If you don't feel comfortable performing these changes, please do not attempt to install this. You might - * be ending up with an unusuable system that requires reset by your Dealer. You were warned! - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - * License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see http://www.gnu.org/licenses/ - * - */ - -/** - * (CustomApplicationResourceLoader) - * - * The resource loader for applications - */ - -var CustomApplicationResourceLoader = { - - __name: 'ResourceLoader', - - /** - * (loadJavascript) - */ - - loadJavascript: function(scripts, path, callback, options, async) { - - this.__loadInvoker(scripts, path, function(filename, next) { - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = filename; - script.onload = next; - document.body.appendChild(script); - }, callback, options, async); - }, - - /** - * (loadCSS) - */ - - loadCSS: function(css, path, callback, options, async) { - - this.__loadInvoker(css, path, function(filename, next) { - var css = document.createElement('link'); - css.rel = "stylesheet"; - css.type = "text/css"; - css.href = filename - css.onload = async ? callback : next; - document.body.appendChild(css); - }, callback, options, async); - }, - - /** - * (loadImages) - */ - - loadImages: function(images, path, callback, options, async) { - - this.__loadInvoker(images, path, function(filename, next, id) { - var img = document.createElement('img'); - img.onload = function() { - - if(async) { - var result = false; - if(id) { - result = {}; - result[id] = this; - } - callback(id ? result : this); - } else { - next(this); - } - } - img.src = filename; - }, callback, options, async); - }, - - /** - * (fromFormatted) - */ - - fromFormatted: function(format, items) { - - items.forEach(function(value, index) { - items[index] = CustomApplicationHelpers.sprintr(format, value); - }); - - return items; - - }, - - - /** - * (__loadInvoker) - */ - - __loadInvoker: function(items, path, build, callback, options, async) { - - var ids = false, result = false, options = options ? options : {}, timeout = false; - - // assign default object - this.logger = CustomApplicationLog; - - // support for arrays and objects - if(CustomApplicationHelpers.is().object(items)) { - - var idsObject = items, ids = [], items = []; - - Object.keys(idsObject).map(function(key) { - ids.push(key); - items.push(idsObject[key]); - }); - - // return as object - result = {}; - - } else { - - if(!CustomApplicationHelpers.is().array(items)) items = [items]; - } - - // loaded handler - var loaded = 0, next = function(failure) { - loaded++; - if(loaded >= items.length) { - if(CustomApplicationHelpers.is().fn(callback)) { - callback(result); - } - } - }; - - // process items - items.forEach(function(filename, index) { - - try { - - filename = path + filename; - - this.logger.debug(this.__name, "Attempting to load resource from", filename); - - if(!async && options.timeout) { - - clearTimeout(timeout); - timeout = setTimeout(function() { - - this.logger.error(this.__name, "Timeout occured while loading resource", filename); - - // just do the next one - next(true); - - }.bind(this), options.timeout); - - } - - build(filename, function(resource) { - - this.logger.info(this.__name, "Successfully loaded resource", filename); - - if(resource && ids != false) { - this.logger.debug(this.__name, "Loaded resource assigned to id", {id: ids[index], filename: filename}); - - result[ids[index]] = resource; - } - - if(async) { - if(CustomApplicationHelpers.is().fn(callback)) callback(); - } else { - next(); - } - - }.bind(this), ids ? ids[index] : false); - - } catch(e) { - this.logger.error(this.__name, "Failed to load resource", {filename: filename, error: e.message}); - } - - }.bind(this)); - } - -} diff --git a/src/framework/js/CustomApplicationsHandler.js b/src/framework/js/CustomApplicationsHandler.js deleted file mode 100644 index 1c901af..0000000 --- a/src/framework/js/CustomApplicationsHandler.js +++ /dev/null @@ -1,283 +0,0 @@ - /** - * Custom Applications SDK for Mazda Connect Infotainment System - * - * A mini framework that allows to write custom applications for the Mazda Connect Infotainment System - * that includes an easy to use abstraction layer to the JCI system. - * - * Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk) - * Copyright (c) 2016. All rights reserved. - * - * WARNING: The installation of this application requires modifications to your Mazda Connect system. - * If you don't feel comfortable performing these changes, please do not attempt to install this. You might - * be ending up with an unusuable system that requires reset by your Dealer. You were warned! - * - * This program is free software: you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - * License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see http://www.gnu.org/licenses/ - * - */ - -/** - * (CustomApplicationsHandler) - * - * This is the custom handler that manages the application between the JCI system and the mini framework - */ - -var CustomApplicationsHandler = { - - __name: 'ApplicationsHandler', - - /** - * (Applications) storage for applications - */ - - applications: {}, - - /** - * (Paths) - */ - - paths: { - framework: 'apps/custom/runtime/', - applications: 'apps/custom/apps/', - vendor: 'apps/custom/runtime/vendor/', - surface: 'apps/custom/runtime/surface/', - }, - - /** - * (Mapping) - */ - - mapping: { - - - }, - - /** - * (initialize) Initializes some of the core objects - */ - - initialize: function() { - - this.initialized = true; - - this.loader = CustomApplicationResourceLoader; - - this.log = CustomApplicationLog; - - }, - - - /** - * (Retrieve) loads the current application list and returns the additional items - */ - - retrieve: function(callback) { - - try { - // initialize - if(!this.initialized) this.initialize(); - - // load libraries - this.loader.loadJavascript("jquery.js", this.paths.vendor, function() { - - this.loader.loadCSS("runtime.css", this.paths.framework, function() { - - this.loader.loadJavascript("apps.js", this.paths.applications, function() { - - // this has been completed - if(typeof(CustomApplications) != "undefined") { - - // load applications - this.loader.loadJavascript( - this.loader.fromFormatted("{0}/app.js", CustomApplications), - this.paths.applications, - function() { - // all applications are loaded, run data - CustomApplicationDataHandler.initialize(); - - // create menu items - callback(this.getMenuItems()); - }.bind(this) - ); - } - - }.bind(this)); // apps.js - - }.bind(this)); // bootstrap css - - }.bind(this)); // jquery library - - } catch(e) { - - // error message - this.log.error(this.__name, "Error while retrieving applications", e); - - // make sure that we notify otherwise we don't get any applications - callback(this.getMenuItems()); - } - }, - - /** - * (get) returns an application by id - */ - - get: function(id) { - - return this.applications[id] ? this.applications[id] : false; - }, - - - /** - * (Register) registers all the custom applications - */ - - register: function(id, application) { - - // unregister previous instance - if(this.applications[id]) { - this.applications[id].__terminate(); - this.applications[id] = false; - } - - // registering - this.log.info(this.__name, {id:id}, "Registering application"); - - application.id = id; - - application.location = this.paths.applications + id + "/"; - - application.__initialize(); - - this.applications[id] = application; - - return true; - }, - - /** - * (launch) launches an application - */ - - launch: function(id) { - - this.log.info(this.__name, {id: id}, "Launch request for application"); - - if(CustomApplicationHelpers.is().object(id)) { - - id = id.appId ? id.appId : false; - } - - if(this.applications[id]) { - - this.currentApplicationId = id; - - this.log.info(this.__name, {id: id}, "Launching application"); - - return true; - } - - this.log.error(this.__name, {id: id}, "Launch failed because application was not registered"); - - return false; - }, - - /** - * (sleep) sleeps an application - */ - - sleep: function(application) { - - if(application.id == this.currentApplicationId) { - // remember last state - this.lastApplicationId = this.currentApplicationId; - - // clear current - this.currentApplicationId = false; - } - - application.__sleep(); - }, - - - /** - * (getCurrentApplication) returns the current application - */ - - getCurrentApplication: function(allowLast) { - - var applicationId = this.currentApplicationId || (allowLast ? this.lastApplicationId : false); - - if(applicationId) { - - this.log.debug(this.__name, "Invoking current set application", {id: applicationId}); - - if(this.applications[applicationId]) { - - this.currentApplicationId = applicationId; - - return this.applications[applicationId]; - } - - this.log.error(this.__name, "Application was not registered", {id: applicationId}); - - return false; - } - - this.log.error(this.__name, "Missing currentApplicationId"); - - return false; - }, - - /** - * (notifyDataChange) notifies the active application about a data change - */ - - notifyDataChange: function(id, payload) { - - if(this.currentApplicationId && this.applications[this.currentApplicationId]) { - - this.applications[this.currentApplicationId].__notify(id, payload); - - } - - }, - - - /** - * (getMenuItems) returns the items for the main application menu - */ - - getMenuItems: function(callback) { - - return CustomApplicationHelpers.iterate(this.applications, function(id, application) { - - this.log.info(this.__name, {id:id}, "Adding application to menu", { - title: application.getTitle(), - }); - - // set localized language - for now it's just the title - return { - appData : { - appName : application.getId(), - appId: application.getId(), - isVisible : true, - mmuiEvent : 'SelectCustomApplication', - }, - title: application.getTitle(), - text1Id : application.getId().replace(".", "_"), - disabled : false, - itemStyle : 'style02', - hasCaret : application.getHasMenuCaret(), - }; - - }.bind(this)); - }, - -}; diff --git a/src/framework/js/CustomApplicationDataHandler.js b/src/framework/js/DataHandler.js similarity index 100% rename from src/framework/js/CustomApplicationDataHandler.js rename to src/framework/js/DataHandler.js diff --git a/src/framework/js/Handler.js b/src/framework/js/Handler.js new file mode 100644 index 0000000..caae286 --- /dev/null +++ b/src/framework/js/Handler.js @@ -0,0 +1,260 @@ + /** + * Custom Applications SDK for Mazda Connect Infotainment System + * + * A mini framework that allows to write custom applications for the Mazda Connect Infotainment System + * that includes an easy to use abstraction layer to the JCI system. + * + * Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk) + * Copyright (c) 2016. All rights reserved. + * + * WARNING: The installation of this application requires modifications to your Mazda Connect system. + * If you don't feel comfortable performing these changes, please do not attempt to install this. You might + * be ending up with an unusuable system that requires reset by your Dealer. You were warned! + * + * This program is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see http://www.gnu.org/licenses/ + * + */ + +/** + * (Handler) + * + * Responsibe to handle applications + */ + +CMU.attach("handler", function(cmu) { + + + function Handler() { + + + CMU.waitFor("proxy", function(proxy) { + + proxy.add({ + + // We use the old vdt-DriveChartDetails app as our proxy + proxyAppName: 'vdt', + proxyAppContext: 'DriveChartDetails', + proxyMmuiEvent: 'SelectDriveRecord', + + targetAppName: 'custom', + targetAppContext: 'Surface', + + mmuiEvent: 'SelectCustomApplication', + + callback: function(appData) { + + return this.launch(appData); + + }.bind(this), + + }); + + CMU.waitFor("helpers", function(helpers) { + + this.initialize(); + + }.bind(this)); + + }.bind(this)); + + }; + + Handler.prototype = { + + /** + * (initialize) + */ + + initialize: function() { + + this.applications = CMU.appdrive ? CMU.appdrive.applications : false; + + console.log(this.applications); + + if(this.applications) { + + CMU.requestApplications(); + } + }, + + + /** + * (get) returns an application by id + */ + + get: function(id) { + + return this.applications[id] ? this.applications[id] : false; + }, + + + /** + * (Register) registers all the custom applications + */ + + register: function(id, application) { + + if(!this.applications[id]) return false; + + console.log(this.applications[id]); + + // unregister previous instance + if(this.applications[id].instance) { + this.applications[id].instance.__terminate(); + this.applications[id].instance = false; + } + + // registering + Logger.info(this.__name, {id:id}, "Registering application"); + + this.applications[id].instance = application; + + this.applications[id].instance.id = id; + + this.applications[id].instance.location = this.applications[id].info.path; + + this.applications[id].instance.__initialize(); + + return true; + }, + + /** + * (launch) launches an application + */ + + launch: function(id) { + + this.log.info(this.__name, {id: id}, "Launch request for application"); + + if(CustomApplicationHelpers.is().object(id)) { + + id = id.appId ? id.appId : false; + } + + if(this.applications[id]) { + + this.currentApplicationId = id; + + this.log.info(this.__name, {id: id}, "Launching application"); + + return true; + } + + this.log.error(this.__name, {id: id}, "Launch failed because application was not registered"); + + return false; + }, + + /** + * (sleep) sleeps an application + */ + + sleep: function(application) { + + if(application.id == this.currentApplicationId) { + // remember last state + this.lastApplicationId = this.currentApplicationId; + + // clear current + this.currentApplicationId = false; + } + + application.__sleep(); + }, + + + /** + * (getCurrentApplication) returns the current application + */ + + getCurrentApplication: function(allowLast) { + + var applicationId = this.currentApplicationId || (allowLast ? this.lastApplicationId : false); + + if(applicationId) { + + this.log.debug(this.__name, "Invoking current set application", {id: applicationId}); + + if(this.applications[applicationId]) { + + this.currentApplicationId = applicationId; + + return this.applications[applicationId]; + } + + this.log.error(this.__name, "Application was not registered", {id: applicationId}); + + return false; + } + + this.log.error(this.__name, "Missing currentApplicationId"); + + return false; + }, + + /** + * (notifyDataChange) notifies the active application about a data change + */ + + notifyDataChange: function(id, payload) { + + if(this.currentApplicationId && this.applications[this.currentApplicationId]) { + + this.applications[this.currentApplicationId].__notify(id, payload); + + } + + }, + + + /** + * (getMenuItems) returns the items for the main application menu + */ + + getMenuItems: function(callback) { + + + return CustomApplicationHelpers.iterate(this.applications, function(id, application) { + + this.log.info(this.__name, {id:id}, "Adding application to menu", { + title: application.getTitle(), + }); + + // set localized language - for now it's just the title + return { + appData : { + appName : application.getId(), + appId: application.getId(), + isVisible : true, + mmuiEvent : 'SelectCustomApplication', + }, + title: application.getTitle(), + text1Id : application.getId().replace(".", "_"), + disabled : false, + itemStyle : 'style02', + hasCaret : application.getHasMenuCaret(), + }; + + }.bind(this)); + }, + + }; + + var handler = new Handler(); + + // global alias + window.CustomApplicationsHandler = handler; + + return handler; +}); + +/** eof */ \ No newline at end of file diff --git a/src/framework/js/CustomApplicationHelpers.js b/src/framework/js/Helpers.js similarity index 79% rename from src/framework/js/CustomApplicationHelpers.js rename to src/framework/js/Helpers.js index 61397b3..4dea7af 100644 --- a/src/framework/js/CustomApplicationHelpers.js +++ b/src/framework/js/Helpers.js @@ -25,21 +25,18 @@ */ /** - * (CustomApplicationHelpers) + * (Helpers) * * A abstract collection of helpers for the framework */ -var CustomApplicationHelpers = { - /** - * (is) a implemention of the flyandi:is library - */ +CMU.attach("helpers", function(cmu) { - is: function() { - - return { + return { + is: { + /** undefined */ undefined: 'undefined', __toString: function() { @@ -120,41 +117,41 @@ var CustomApplicationHelpers = { same: function(a, b) { return a == b; }, - }; - }, + }, - /** - * (iterate) a iterate that supports arrays and objects - */ + /** + * (iterate) a iterate that supports arrays and objects + */ - iterate: function(o, item) { + iterate: function(o, item) { - if(this.is().object(o)) { - return Object.keys(o).map(function(key) { - return item(key, o[key], true); - }); - } else if (this.is().array(o)) { - return o.map(function(value, key) { - return item(key, value); - }); - } - }, + if(this.is().object(o)) { + return Object.keys(o).map(function(key) { + return item(key, o[key], true); + }); + } else if (this.is().array(o)) { + return o.map(function(value, key) { + return item(key, value); + }); + } + }, - /** - * (sprintr) (https://gist.github.com/flyandi/395816232c70de327801) - */ + /** + * (sprintr) (https://gist.github.com/flyandi/395816232c70de327801) + */ - sprintr: function() { - var - args = Array.prototype.slice.call(arguments), - subject = arguments[0]; + sprintr: function() { + var + args = Array.prototype.slice.call(arguments), + subject = arguments[0]; - args.shift(); + args.shift(); - for(var i = 0; i < args.length; i++) - subject = subject.split("{" + i + "}").join(args[i]); + for(var i = 0; i < args.length; i++) + subject = subject.split("{" + i + "}").join(args[i]); - return subject; - }, - -}; \ No newline at end of file + return subject; + }, + } +}); +/** eof */ \ No newline at end of file diff --git a/src/framework/js/Logger.js b/src/framework/js/Logger.js new file mode 100644 index 0000000..942bd20 --- /dev/null +++ b/src/framework/js/Logger.js @@ -0,0 +1,139 @@ +/** + * Custom Applications SDK for Mazda Connect Infotainment System + * + * A mini framework that allows to write custom applications for the Mazda Connect Infotainment System + * that includes an easy to use abstraction layer to the JCI system. + * + * Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk) + * Copyright (c) 2016. All rights reserved. + * + * WARNING: The installation of this application requires modifications to your Mazda Connect system. + * If you don't feel comfortable performing these changes, please do not attempt to install this. You might + * be ending up with an unusuable system that requires reset by your Dealer. You were warned! + * + * This program is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see http://www.gnu.org/licenses/ + * + */ + + +/** + * (Logger) + * + * A logger + */ + +CMU.attach("logger", function(cmu) { + + return window.Logger = { + + levels: { + debug: 'DEBUG', + info: 'INFO', + error: 'ERROR', + }, + + /** + * Subscriptions + * @array + */ + subscriptions: [], + + /** + * (debug) debug message + */ + + debug: function() { + this.__message(this.levels.debug, "#006600", Array.apply(null, arguments)); + }, + + /** + * (error) error message + */ + + error: function() { + this.__message(this.levels.error, "#FF0000", Array.apply(null, arguments)); + }, + + /** + * (info) info message + */ + + info: function() { + this.__message(this.levels.info, "#0000FF", Array.apply(null, arguments)); + }, + + /** + * Subscribe + * @return {[type]} [description] + */ + subscribe: function(callback) { + + if(typeof(callback) == "function") { + this.subscriptions.push(callback); + } + }, + + /** + * [__message description] + * @param {[type]} level [description] + * @param {[type]} color [description] + * @param {[type]} values [description] + * @return {[type]} [description] + */ + __message: function(level, color, values) { + + var msg = []; + + if(values.length > 1) { + values.forEach(function(value, index) { + + if(index > 0) { + + if(typeof(value) == "object") { + + var keys = value, o = false; + + if(Object.prototype.toString.call(value) == "[object Object]") { + var keys = Object.keys(value), + o = true; + } + + if(keys.forEach) { + + keys.forEach(function(v, index) { + msg.push(o ? '[' + v + '=' + value[v]+ ']' : '[' + v + ']'); + }); + + } + + } else { + msg.push(value); + } + } + }); + } + + msg = msg.join(" "); + + this.subscriptions.forEach(function(subscription) { + + try { + subscription(level, values[0], msg, color); + } catch(e) { + + } + }); + } + }; +}); + +/** eof */ \ No newline at end of file diff --git a/src/framework/js/Proxy.js b/src/framework/js/Proxy.js new file mode 100644 index 0000000..d227cf2 --- /dev/null +++ b/src/framework/js/Proxy.js @@ -0,0 +1,307 @@ +/** + * Custom Applications SDK for Mazda Connect Infotainment System + * + * A mini framework that allows to write custom applications for the Mazda Connect Infotainment System + * that includes an easy to use abstraction layer to the JCI system. + * + * Written by Andreas Schwarz (http://github.com/flyandi/mazda-custom-applications-sdk) + * Copyright (c) 2016. All rights reserved. + * + * WARNING: The installation of this application requires modifications to your Mazda Connect system. + * If you don't feel comfortable performing these changes, please do not attempt to install this. You might + * be ending up with an unusuable system that requires reset by your Dealer. You were warned! + * + * This program is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see http://www.gnu.org/licenses/ + * + */ + + +/** + * (Proxy) + * + * Registers itself between the JCI system and CustomApplication framework. + */ + +CMU.attach("proxy", function(cmu) { + + function Proxy() { + + let that = this; + + // register bootstrap event + + if(window.opera) { + window.opera.addEventListener('AfterEvent.load', function (e) { + that.bootstrap(); + }); + } + + }; + + Proxy.prototype = { + + /** + * The SYSTEM_APP_ID constant + * @var string + */ + SYSTEM_APP_ID: 'system', + + /** + * The SYSTEM_APP_CATEGORY constant + * @var string + */ + SYSTEM_APP_CATEGORY: 'Applications', + + /** + * An array that stores the registered proxies + * @var array + */ + proxies: {}, + + /** + * An translation array that converts a uiaId to a proxy + * @type {Object} + */ + uiaIds: {}, + + + /** + * Adds a new proxy + * @param void + */ + add: function(proxy) { + + if(!proxy.mmuiEvent || this.has(proxy.mmuiEvent)) return false; + + this.proxies[proxy.mmuiEvent] = proxy; + + this.uiaIds[proxy.proxyAppName] = proxy.mmuiEvent; + + return true; + }, + + + /** + * Checks if a proxy exists + * @param {[type]} mmuiEvent [description] + * @return {Boolean} [description] + */ + has: function(mmuiEvent) { + return this.proxies[mmuiEvent] ? true : false; + }, + + /** + * Returns a proxy + * @param {[type]} mmuiEvent [description] + * @return {[type]} [description] + */ + get: function(mmuiEvent) { + return this.proxies[mmuiEvent]; + }, + + /** + * Converts a uiaId to a prixy + * @param {[type]} uiaId [description] + * @return {[type]} [description] + */ + fromUiaId: function(uiaId) { + + var entry = this.uiaIds[uiaId]; + + if(entry && this.has(entry)) { + return this.get(entry); + } + + return false; + }, + + + /** + * Bootstraps the JCI system + * @return {[type]} [description] + */ + bootstrap: function() { + + // verify that core objects are available + if(typeof framework === 'object' && framework._currentAppUiaId === this.SYSTEM_APP_ID && this.bootstrapped === false) { + + // retrieve system app + var systemApp = framework.getAppInstance(this.SYSTEM_APP_ID); + + // verify bootstrapping - yeah long name + if(systemApp) { + + // set to strap - if everything fails - no harm is done :-) + this.bootstrapped = true; + + // let's boostrap + try { + + // overwrite list2 handler + systemApp._contextTable[this.systemAppCategory].controlProperties.List2Ctrl.selectCallback = this.menuItemSelectCallback.bind(systemApp); + + // overwrite framework route handler + if(typeof(framework.overwriteRouteMmmuiMsg) == "undefined") { + framework.overwriteRouteMmmuiMsg = framework.routeMmuiMsg; + framework.routeMmuiMsg = this.routeMmuiMsg.bind(framework); + } + + // ovewrite framework MMUI sender + if(typeof(framework.overwriteSendEventToMmui) == "undefined") { + framework.overwriteSendEventToMmui = framework.sendEventToMmui; + framework.sendEventToMmui = this.sendEventToMmui.bind(framework); + } + + // assign template transition + framework.transitionsObj._genObj._TEMPLATE_CATEGORIES_TABLE.SurfaceTmplt = 'Detail with UMP'; + + } catch(e) { + // bootstrapping process failed - we just leave it here + } + } + } + }, + + /** + * (Overwrite) menuItemSelectCallback + */ + + menuItemSelectCallback: function(listCtrlObj, appData, params) { + + try { + + if(CMU.proxy.has(appData.mmuiEvent)) { + + var proxy = CMU.proxy.getProxyForEvent(appData.mmuiEvent); + + if(proxy && typeof(proxy.callback == "function") && proxy.callback(appData)) { + + try { + // clone app data + appData = JSON.parse(JSON.stringify(appData)); + + // overwrite proxy + appData.appName = proxy.proxyAppName; + appData.mmuiEvent = proxy.proxyMmuiEvent; + + } catch(e) { + // do nothing + } + } + } + + } catch(e) { + // do nothing + } + + // pass to original handler + this._menuItemSelectCallback(listCtrlObj, appData, params); + }, + + + /** + * (Overwrite) sendEventToMmui + */ + + sendEventToMmui: function(uiaId, eventId, params, fromVui) { + + var currentUiaId = this.getCurrentApp(), + currentContextId = this.getCurrCtxtId(), + proxy = CMU.proxy.fromUiaId(currentUiaId); + + // check proxy + if(proxy) { + currentUiaId = proxy.proxyAppName; + currentContextId = proxy.proxyAppContext; + } + + // pass to original handler + framework.overwriteSendEventToMmui(uiaId, eventId, params, fromVui, currentUiaId, currentContextId); + }, + + + /** + * (Overwrite) routeMmuiMsg + */ + + routeMmuiMsg: function(jsObject) { + + if(CMU.has("handler")) { + + try { + + // validate routing message + switch(jsObject.msgType) { + + // magic switch + case 'ctxtChg': + + var proxy = CMU.proxy.fromUiaId(jsObject.uiaId); + + if(proxy) { + jsObject.uiaId = proxy.targetAppName; + jsObject.ctxtId = proxy.targetAppContext; + } + break; + + // check if our proxy is in the focus stack + case 'focusStack': + + if(jsObject.appIdList && jsObject.appIdList.length) { + for(var i = 0; i < jsObject.appIdList.length; i++) { + + var appId = jsObject.appIdList[i], + proxy = CMU.proxy.fromUiaId(appId.id); + + if(proxy) { + appId.id = proxy.targetAppName; + } + }; + } + + case 'msg': + case 'alert': + + var proxy = CMU.proxy.fromUiaId(jsObject.uiaId); + + if(proxy) { + jsObject.uiaId = proxy.targetAppName; + } + + break; + + default: + // do nothing + break; + } + + } catch(e) { + // do nothing + } + } + + // pass to framework + framework.overwriteRouteMmmuiMsg(jsObject); + }, + + }; + + /** + * Initial Handler + */ + + return new Proxy(); + +}); + + +/** EOF **/ \ No newline at end of file diff --git a/src/node-cmu/cmu.js b/src/node-cmu/cmu.js index 312c86c..ed8e5c2 100644 --- a/src/node-cmu/cmu.js +++ b/src/node-cmu/cmu.js @@ -48,12 +48,17 @@ const fs = require("fs"); const REQUEST_VERSION = "version"; const REQUEST_PING = "ping"; const REQUEST_SETUP = "setup"; +const REQUEST_APPLICATIONS = "applications"; +const REQUEST_RESOURCES = "resource"; const RESULT_OK = 200; const RESULT_PONG = 201; const RESULT_NOTFOUND = 404; const RESULT_ERROR = 500; +const RESOURCE_TYPE_JAVASCRIPT = "js"; +const RESOURCE_TYPE_CSS = "css"; +const RESOURCE_TYPE_JSON = "json"; const MOUNTROOT_PATH = "/tmp/mnt/"; const APPDRIVE_PATH = "/appdrive/"; @@ -70,6 +75,7 @@ const SYSTEM_PATH = "system/"; const SYSTEM_FRAMEWORK_PATH = "framework/"; const SYSTEM_FRAMEWORK_JS = "framework.js"; const SYSTEM_FRAMEWORK_CSS = "framework.css"; +const SYSTEM_FRAMEWORK_VENDOR_PATH = "vendor/"; const SYSTEM_CUSTOM_PATH = "custom/"; const JCI_MOUNT_PATH = "/tmp/mnt/data_persist/appdrive/"; // we link our resources in here @@ -217,16 +223,82 @@ cmu.prototype = { if(this.appdrive && this.appdrive.enabled) { - // load javascripts - this.requestLoadJavascript(this.resources.js); + try { - // load css - this.requestLoadCSS(this.resources.css); + // send appdrive + this.sendFromPayload(client, payload, { + appdrive: this.appdrive + }); + // load javascripts + this.requestLoadJavascript(this.resources.js); + + // load css + this.requestLoadCSS(this.resources.css); + + } catch(e) { + + } } break; + /** + * Applications + * @type REQUEST_APPLICATIONS + */ + case REQUEST_APPLICATIONS: + + if(this.appdrive && this.appdrive.enabled) { + + Object.keys(this.appdrive.applications).forEach(function(key) { + + try{ + let application = this.appdrive.applications[key]; + + this.requestLoadJavascript(application.files[APPLICATION_JS]); + + this.requestLoadCSS(application.files[APPLICATION_CSS]); + + }catch(e) { + console.error(e); + } + + }.bind(this)); + } + + break; + + + /** + * Resource + * @type REQUEST_RESOURCES + */ + case REQUEST_RESOURCES: + + console.log(payload); + + /* switch(payload.type) { + + case RESOURCE_TYPE_JSON: + + break; + + case RESOURCE_TYPE_CSS: + + console.log(request); + + break; + + case RESOURCE_TYPE_JAVASCRIPT: + + + break; + + }*/ + + break; + /** * Default - Pass to application handler * @type default @@ -304,8 +376,11 @@ cmu.prototype = { */ invokeLoadCommand: function(command, files) { - let source = files instanceof Array ? files : ([].push(files)), - data = []; + let data = [], source = files; + + if(!Array.isArray(files)) { + (source = []).push(files); + } source.forEach(function(filename) { @@ -410,6 +485,19 @@ cmu.prototype = { // create symbolic link for this session fs.symlinkSync([systemPath, SYSTEM_CUSTOM_PATH].join(""), mountPath); + /** + * Find Vendor + */ + + let vendorPath = [systemPath, SYSTEM_FRAMEWORK_PATH, SYSTEM_FRAMEWORK_VENDOR_PATH].join(""), + vendorFiles = fs.readdirSync(vendorPath); + + if(vendorFiles.length) vendorFiles.forEach(function(fileName) { + + this.resources.js.push([vendorPath, fileName].join("")); + + }.bind(this)); + /** * Find Applications */ @@ -430,9 +518,11 @@ cmu.prototype = { if(this._isDir(applicationPath)) { let profile = { - id: appId, - path: applicationPath, files: {}, + info: { + id: appId, + path: applicationPath, + }, }, parts = [APPLICATION_JS, APPLICATION_JSON, APPLICATION_CSS, APPLICATION_WORKER], found = 0; diff --git a/src/system/cmu.js b/src/system/cmu.js index fb1ce7d..be2b9cc 100644 --- a/src/system/cmu.js +++ b/src/system/cmu.js @@ -47,6 +47,8 @@ window.CMU = { REQUEST_PING: 'ping', REQUEST_SETUP: 'setup', + REQUEST_APPLICATIONS: 'applications', + REQUEST_APPDRIVE: 'appdrive', }, /** @@ -70,6 +72,16 @@ window.CMU = { RESULT_ERROR: 500, }, + /** + * Resource + */ + + resource: { + JAVASCRIPT: 'js', + CSS: 'css', + JSON: 'json', + }, + /** * Initializes the proxy * @return void @@ -82,6 +94,8 @@ window.CMU = { this.requestBuffer = {}; + this.waitForQueue = {}; + this.obtainConnection(); } @@ -177,13 +191,48 @@ window.CMU = { } }, + /** - * [requestSetup description] + * Request initial setup * @return {[type]} [description] */ - requestSetup: function() { + requestSetup: function(callback) { - this.request(this.requests.REQUEST_SETUP); + this.request(this.requests.REQUEST_SETUP, false, function(error, result) { + + this.appdrive = result.appdrive; + + }.bind(this)); + }, + + /** + * Requests the applicationst to be loaded + * @return {[type]} [description] + */ + requestApplications: function() { + + this.request(this.requests.REQUEST_APPLICATIONS); + }, + + + /** + * [requestResource description] + * @return {[type]} [description] + */ + requestResource: function(type, files, location, callback) { + + if(typeof(location) == "function") callback = location; + + if(typeof(files) != "object") { + (files = []).push(files); + } + + console.log(files, location); + + if(typeof(location) == "string") { + + + } }, /** @@ -212,8 +261,6 @@ window.CMU = { payload.request = request; - console.log(payload); - // execute return this.client.send(JSON.stringify(payload)); }, @@ -294,6 +341,53 @@ window.CMU = { } }, + /** + * (attach) + */ + + attach: function(key, callback) { + + if(this.has(key) || typeof(callback) != "function") return false; + + this[key] = callback(this); + + if(this.waitForQueue[key]) { + + this.waitForQueue[key].forEach(function(callback) { + callback(this[key]); + }.bind(this)); + + this.waitForQueue[key] = false; + } + }, + + + /** + * (has) + */ + + has: function(key) { + + return this[key] ? true : false; + }, + + + /** + * (waitFor) + */ + + waitFor: function(key, callback) { + + if(typeof(callback) != 'function') return false; + + if(this.has(key)) return callback(this[key]); + + if(!this.waitForQueue[key]) this.waitForQueue[key] = []; + + this.waitForQueue[key].push(callback); + + }, + /** * (__loadInvoker) @@ -307,6 +401,8 @@ window.CMU = { if(item.location && item.contents) { + this.__unload(item.location); + var element = document.createElement(tag); element.setAttribute("data-script-url", item.location); element.appendChild(document.createTextNode(item.contents)); @@ -315,7 +411,21 @@ window.CMU = { document.head.appendChild(element); } - }); + }.bind(this)); + }, + + /** + * [__unload description] + * @return {[type]} [description] + */ + __unload: function(location) { + + var element = document.querySelector('[data-script-url="' + location + '"]'); + + if(element) { + document.head.removeChild(element); + } + }, /** @@ -353,7 +463,7 @@ window.CMU = { */ if(window.opera) { - window.opera.addEventListener('AfterEvent.load', function (e) { + window.opera.addEventListener('load', function (e) { CMU.initialize(); }); }