/** @namespace Bus @desc Centralized inter-starlet messaging. Main methods are ask/tell, others are curried aliases for specific actions. */ var Bus = typeof Bus !== 'undefined' ? Bus : { /* properties */ /** @member {Boolean} Bus.registered @readonly @desc Whether Starlet has registered itself with Connection. */ 'registered': false, 'requests' : {}, /* methods */ // i/o /** @method Bus.ask @readonly @desc Request data with criteria, or send a data-related instruction expecting a result. Data on demand (action), future updates (subscribe), or both can be acquired via this single method. @arg {String} packet - Name of {@link OrionObjects.DataPacket} being requested. @arg {Object} meta - Criteria and information about the request. Besides the properties defined below, each packet type expects varying additional criteria. @arg {String} [meta.action] - Action to be performed immediately (e.g. 'list', 'get', etc.). @arg {Boolean} [meta.subscribe] - Whether to receive future updates. @arg {Function} [meta.callback] - Function to respond to incoming data. May also be associated via the promise's then method, though it will only resolve once. Remember to specify the context of the callback or include a closure so it can access its controller. @returns {Object} promise @see {@link Bus.tell} @see {@link Widget.ControllerClass#ask} @see {@link Widget.ControllerClass#tell} @see {@link http://api.jquery.com/category/deferred-object/} @example Bus.ask('users', { 'action' : 'list', 'subscribe': true, 'callback' : controller.onUserData.bind(controller) }); @example Bus.ask('users', {'action': 'list'}).then(controller.onUserData.bind(controller)); */ 'ask': function (packet, meta) { packet === 'logs' && meta.subscribe === true && (log.verbosity = {'min': L_OFF, 'max': L_OFF}); log(L_DEBUG, 'Bus.ask', arguments); // init meta = meta || {}; meta.starlet = meta.starlet || Starlet.name; meta.packet = meta.packet || packet; meta.ask = new Date().getTime(); meta.tell = false; var persist = ~$.inArray(meta.type, ['update', 'both']) || meta.update || meta.subscribe, deferred = $.Deferred(); // prepare callback if (typeof meta.callback === 'function') { meta.callback = linkCallback(meta.callback, window, persist, deferred); meta.namespace = 'window'; } else { meta.callback = meta.callback || linkCallback(false, window, persist, deferred); meta.namespace = meta.namespace || 'window'; } // send OrionCommunication.messageConnection('Distributor', 'onRequest', [meta]); //Bus.requests[new Date().getTime()] = meta; return deferred.promise(); }, /** @method Bus.tell @readonly @desc Send a data-related instruction, expecting no result. @arg {String} packet - Name of {@link OrionObjects.DataPacket} being requested. @arg {Object} meta - Criteria and information about the request. Besides action, each packet type expects varying additional criteria. @arg {String} [meta.action] - Action to be performed (e.g. 'list', 'get', etc.). @returns {Boolean} true @see {@link Bus.ask} @see {@link Widget.ControllerClass#ask} @see {@link Widget.ControllerClass#tell} @example Bus.tell('usergroups', { 'action': 'create', 'name' : 'Foo', 'users' : [1, 2, 3] }); */ 'tell': function (packet, meta) { log(L_DEBUG, 'Bus.tell', arguments); // init meta = meta || {}; meta.starlet = meta.starlet || Starlet.name; meta.packet = meta.packet || packet; meta.ask = false; meta.tell = new Date().getTime(); // send OrionCommunication.messageConnection('Distributor', 'onRequest', [meta]); //Bus.requests[new Date().getTime()] = meta; return true; }, // in development 'askLocal': function (packet, callback, data) { log(L_DEBUG, 'Bus.askLocal', arguments); var deferred = $.Deferred(), instances = Widget.instances(); $.each(instances, function () { this.$element.triggerHandler(packet, [data, callback, deferred]); }); return deferred.promise(); }, // in development 'tellLocal': function (packet, data) { log(L_DEBUG, 'Bus.tellLocal', arguments); var instances = Widget.instances(); $.each(instances, function () { this.$element.triggerHandler(packet, [data]); }); }, // curried aliases /** @method Bus.console @readonly @desc Open developer console for a Starlet. @arg {String} [starlet=Starlet.name - Framework name of Starlet to open developer console for. @returns {Boolean} true */ 'console': function (starlet) { starlet = starlet || Starlet.name; this.tell('starlets', {'action': 'inspect', 'name': starlet}); }, /** @method Bus.register @readonly @desc Registers Starlet with Connection. @returns {Boolean} true */ 'register': function () { if (!Bus.registered) { log(L_DEBUG, 'Bus.register', arguments); Bus.registered = true; return this.tell('starlets', { 'action' : 'register', 'identifier' : Starlet.identifier, 'title' : Starlet.title, 'url' : window.location.href, 'tearoff' : Starlet.states.tearoff, 'minitearoff': Starlet.states.minitearoff, 'overlay' : Starlet.states.overlay }); }}, /** @method Bus.unregister @readonly @desc Unregisters Starlet with Connection. @returns {Boolean} true */ 'unregister': function (name) { if (Bus.registered) { log(L_DEBUG, 'Bus.unregister', arguments); Bus.registered = false; return this.tell('starlets', {'action': 'unregister'}); }}, /** @method Bus.reload @readonly @desc Reloads Starlet's WebView. @arg {Boolean} [nocache=true] - Whether Starlet's WebView should be reloaded from server. @returns {Boolean} true */ 'reload': function (nocache) { log(L_DEBUG, 'Bus.reload', arguments); nocache = typeof nocache === 'undefined' ? true : !!nocache; return this.tell('starlets', {'action': 'reload', 'nocache': nocache}); }, // in development 'options': function (key, a, b) { log(L_DEBUG, 'Bus.options', arguments); var caller = arguments.callee.caller, widgetId = caller.controller ? caller.controller.uniqueId : 0; switch (arguments.length) { case 1: return this.ask ('options', {'key': key, 'type': 'init'}); // (key) get only via promise case 2: return typeof a == 'function' ? this.ask ('options', {'key': key, 'type': 'update', 'callback': a}) // (key, callback) get only via promise/callback : this.tell('options', {'key': key, 'value': a}) // (key, value) set only case 3: return this.ask ('options', {'key': key, 'type': 'both', 'value': a, 'callback': b}) // (key, value, callback) set/get via promise/callback default: log(L_ERROR, 'Bus.options', 'invalid arguments'); { return false; } } }, // in development 'subscribe': function (type, packet, callback, args) { log(L_DEBUG, 'Bus.subscribe', arguments); var newargs = { 'type' : type, 'packet' : packet, 'callback' : callback }; $.extend(newargs, args); return type == 'init' || type == 'both' ? this.ask ('subscribe_packet', newargs) : this.tell('subscribe_packet', newargs); }, // in development 'subscribeFilter': function (packet, callback, args) { log(L_DEBUG, 'Bus.subscribe', arguments); var newargs = { 'packet' : packet, 'callback' : callback }; $.extend(newargs, args); return this.ask('subscribe_filter_packet', newargs); }, /** @method Bus.nav @readonly @desc Navigate framework to a specific Starlet. @arg {String} starlet - Framework name of Starlet to navigate to. */ 'nav': function (starlet) { log(L_DEBUG, 'Bus.nav', arguments); OrionCommunication.messageConnection('Distributor', 'onNavigate', [starlet]); }, /** @method Bus.relay @readonly @desc Sends a command to another Starlet, which must have the corresponding case defined. @arg {String} starlet - Framework name of Starlet to send command. @arg {String} command - Name of command being sent. @arg {Object} options - Index of additional values to send. */ 'relay': function (starlet, command, options) { log(L_DEBUG, 'Bus.relay', arguments); OrionCommunication.messageConnection('Distributor', 'onRelay', [starlet, command, options]); }, /** @method Bus.navRelay @readonly @desc Navigates to another Starlet while sending it a command. Target Starlet must have the corresponding case defined. @arg {String} starlet - Framework name of Starlet to navigate to and send command. @arg {String} command - Name of command being sent. @arg {Object} options - Index of additional values to send. */ 'navRelay': function (starlet, command, options) { log(L_DEBUG, 'Bus.navRelay', arguments); Bus.nav(starlet); Bus.relay(starlet, command, options); }, /** @method Bus.crypto @readonly @desc Encrypts or decrypts data passed into it. @arg {Boolean} encrypt - true - encrypt; false - decrypt @arg {String} data - if encrypting, the string to encrypt; if decrypting, the base64 string to decrypt @arg {String} salt - encryption salt */ 'crypto': function (encrypt, data, salt) { OrionCommunication.messageConnection('Distributor', 'onCrypto', { starlet: Starlet.name, encrypt: encrypt, data: data, salt: salt, callback: linkCallback(meta.callback, window, false, deferred) }); } };