1 /** 2 * @ignore 3 */ 4 var Ozone = Ozone ? Ozone : {}; 5 6 /** 7 * @ignore 8 * @namespace 9 */ 10 Ozone.eventing = Ozone.eventing ? Ozone.eventing : {}; 11 12 //----------------------------------------------------------------- 13 //Ozone Eventing Widget Object 14 //----------------------------------------------------------------- 15 /** 16 * @deprecated Since OWF 3.7.0 You should use <a href="#.getInstance">Ozone.eventing.Widget.getInstance</a> 17 * @constructor 18 * @param {String} widgetRelay The URL for the widget relay file. The relay file must be specified with full location details, but without a fully 19 * qualified path. In the case where the relay is residing @ http://server/path/relay.html, the path used must be from the context root of the local 20 * widget. In this case, it would be /path/relay.html. Do not include the protocol. 21 * @param {Function} afterInit - callback to be executed after the widget is finished initializing. 22 * @description The Ozone.eventing.Widget object manages the eventing for an individual widget (Deprecated). This constructor is deprecated. 23 * You should use <a href="#.getInstance">Ozone.eventing.Widget.getInstance</a> 24 * @example 25 * this.widgetEventingController = new Ozone.eventing.Widget( 26 * 'owf-sample-html/js/eventing/rpc_relay.uncompressed.html', function() { 27 * 28 * //put code here to execute after widget init - perhaps immediately publish to a channel 29 * 30 * }); 31 * @throws {Error} throws an error with a message if widget initialization fails 32 */ 33 Ozone.eventing.Widget = function(widgetRelay, afterInit) { 34 if (Ozone.eventing.Widget.instance == null) { 35 Ozone.eventing.Widget.instance = this; 36 this.isAfterInit = false; 37 //connect passed in function to the internal callback function 38 if (afterInit != null) { 39 owfdojo.connect( 40 this,'afterInitCallBack', 41 this,afterInit); 42 } 43 this.setWidgetRelay(widgetRelay); 44 try { 45 this.widgetInit(); 46 } catch (error) { 47 throw 'Widget relay init failed. Relaying will not work. Inner Exception: ' + error.name + ": " + error.message; 48 } 49 } 50 else { 51 if (afterInit != null) { 52 if (this.isAfterInit === false) { 53 //connect passed in function to the internal callback function 54 owfdojo.connect( 55 this,'afterInitCallBack', 56 this,afterInit); 57 } 58 else { 59 //already initialized just execute the supplied callback 60 setTimeout(afterInit,50); 61 } 62 } 63 } 64 return Ozone.eventing.Widget.instance; 65 }; 66 67 /** 68 * @description The location of the widget relay file. The relay file should be defined 69 * globally for the entire widget by setting Ozone.eventing.Widget.widgetRelayURL to the relay file url, immediately after 70 * including the widget bundle javascript. If the relay is not defined at all it is assumed to be at 71 * /[context]/js/eventing/rpc_relay.uncompressed.html. The relay file must be specified with full location details, but without a fully 72 * qualified path. In the case where the relay is residing @ http://server/path/relay.html, the path used must be from the context root of the local 73 * widget. In this case, it would be /path/relay.html. Do not include the protocol. 74 * @since OWF 3.7.0 75 * @example 76 * <script type="text/javascript" src="../../js-min/owf-widget-min.js"></script> 77 * <script> 78 * //The location is assumed to be at /[context]/js/eventing/rpc_relay.uncompressed.html if it is not 79 * //set the path correctly below 80 * Ozone.eventing.Widget.widgetRelayURL = '/owf/js/eventing/rpc_relay.uncompressed.html'; 81 * //... 82 * </script> 83 * 84 */ 85 Ozone.eventing.Widget.widgetRelayURL = Ozone.eventing.Widget.widgetRelayURL ? Ozone.eventing.Widget.widgetRelayURL : null; 86 87 Ozone.eventing.Widget.prototype = { 88 89 version: Ozone.version.owfversion + Ozone.version.eventing, 90 91 /** 92 * @ignore 93 * @returns The URL for the widgetRelay 94 * @description This should not be called from usercode. 95 */ 96 getWidgetRelay : function() { 97 return this.widgetRelay; 98 }, 99 /** 100 * @ignore 101 * @param The relaypath to set. 102 * @description This should not be called from usercode. 103 */ 104 setWidgetRelay : function(relaypath) { 105 //if null figure out path 106 if (relaypath == null) { 107 //check if global path variable was set 108 if (Ozone.eventing.Widget.widgetRelayURL != null) { 109 relaypath = Ozone.eventing.Widget.widgetRelayURL; 110 } 111 //else calculate a standard relative path 112 else { 113 //find root context - assume relay file is at /<context/js/eventing/rpc_relay.uncompressed.html 114 var baseContextPath = window.location.pathname; 115 var baseContextPathRegex = /^(\/[^\/]+\/).*$/i; 116 var matches = baseContextPath.match(baseContextPathRegex); 117 if (matches != null && matches[1] != null && matches[1].length > 0) { 118 baseContextPath = matches[1]; 119 //remove final / 120 baseContextPath = baseContextPath.substring(0,baseContextPath.length-1); 121 } 122 else { 123 baseContextPath = ''; 124 } 125 relaypath = baseContextPath + '/js/eventing/rpc_relay.uncompressed.html'; 126 } 127 } 128 this.widgetRelay = window.location.protocol + "//" + window.location.host + (relaypath.charAt(0) != '/'? ('/'+relaypath) : relaypath); 129 }, 130 /** 131 * @description Returns the Widget Id 132 * @returns {String} The widgetId is a complex JSON encoded string which identifies a widget for Eventing. 133 * Embedded in this string is the widget's uniqueId as the 'id' attribute. There is other data is in the string 134 * which is needed for Eventing and other APIs to function properly. This complex widgetId string may be used in 135 * the <a href="#publish">Ozone.eventing.Widget.publish</a> function to designate a specific recipient for a message. 136 * Additionally, once subscribed to a channel via <a href="#subscribe">Ozone.eventing.Widget.subscribe</a> during the 137 * receipt of a message, the sender's widgetId is made available as the first argument to the handler function. 138 * @example 139 * //decode and retrieve the widget's unique id 140 * var complexIdString = this.eventingController.getWidgetId(); 141 * var complexIdObj = owfdojo.toJson(complexIdString); 142 * 143 * //complexIdObj will look like 144 * // { 145 * // //widget's uniqueId 146 * // id:"49cd21f0-3110-8121-d905-18ffa81b442e" 147 * // } 148 * 149 * //get Widget's uniqueId 150 * alert('widget id = ' + complexIdObj.id); 151 */ 152 getWidgetId : function() { 153 return this.widgetId; 154 }, 155 /** 156 * @ignore 157 * @returns The containerRelay 158 * @description This should not be called from usercode. 159 */ 160 getContainerRelay : function() { 161 return this.containerRelay; 162 }, 163 /** 164 * @ignore 165 * @description This method is called by the Widget's constructor. It should never be called from user code. 166 */ 167 widgetInit : function() { 168 var queryHash = {}; 169 var jsonString = null; 170 171 //check for data in window.name 172 var configParams = Ozone.util.parseWindowNameData(); 173 if (configParams != null) { 174 175 //the id is the whole contents of the window.name 176 this.widgetId = '{\"id\":\"' + configParams.id + '\"}'; 177 this.locked = configParams.locked; 178 179 //embedded in the id is the relay 180 this.containerRelay = configParams.relayUrl; 181 } 182 else { 183 throw { 184 name :'WidgetInitException', 185 message :'The call to container_init failed. Inner Exception: ' 186 }; 187 } 188 189 gadgets.rpc.setRelayUrl("..", this.containerRelay, false, true); 190 191 192 var onClickHandler, 193 onKeyDownHandler; 194 195 function activateWidget() { 196 197 var config = { 198 fn: "activateWidget", 199 params: { 200 guid: configParams.id, 201 focusIframe: document.activeElement === document.body 202 } 203 }; 204 205 var stateChannel = '_WIDGET_STATE_CHANNEL_' + configParams.id; 206 if (!this.disableActivateWidget) { 207 gadgets.rpc.call('..', stateChannel, null, this.widgetId, config); 208 } 209 else { 210 this.disableActivateWidget = false; 211 } 212 } 213 214 //register for after_container_init 215 gadgets.rpc.register("after_container_init", owfdojo.hitch(this,function() { 216 217 gadgets.rpc.unregister("after_container_init"); 218 219 //attach mouse click and keydown listener to send activate calls for the widget 220 if(!onClickHandler) { 221 onClickHandler = owfdojo.connect(document, 'click', owfdojo.hitch(this, activateWidget)); 222 } 223 224 if(!onKeyDownHandler) { 225 onKeyDownHandler = owfdojo.connect(document, 'onkeyup', owfdojo.hitch(this, activateWidget)); 226 } 227 228 //execute callback 229 this.afterContainerInit(); 230 231 })); 232 233 gadgets.rpc.register("_widget_activated", owfdojo.hitch(this,function() { 234 //console.log("_widget_activated => " + configParams.id); 235 236 if(onClickHandler) { 237 owfdojo.disconnect(onClickHandler); 238 } 239 if(onClickHandler) { 240 owfdojo.disconnect(onKeyDownHandler); 241 } 242 243 onClickHandler = null; 244 onKeyDownHandler = null; 245 246 })); 247 248 gadgets.rpc.register("_widget_deactivated", owfdojo.hitch(this,function() { 249 //console.log("_widget_deactivated => " + configParams.id); 250 251 if(!onClickHandler) { 252 onClickHandler = owfdojo.connect(document, 'click', owfdojo.hitch(this, activateWidget)); 253 } 254 if(!onKeyDownHandler) { 255 onKeyDownHandler = owfdojo.connect(document, 'onkeyup', owfdojo.hitch(this, activateWidget)); 256 } 257 })); 258 259 //register with container 260 try { 261 var idString = '{\"id\":\"' + configParams.id + '\"}'; 262 var data = { 263 id: idString, 264 version: this.version, 265 useMultiPartMessagesForIFPC: true, 266 relayUrl: this.widgetRelay 267 }; 268 269 if (Ozone.util.pageLoad.loadTime != null && Ozone.util.pageLoad.autoSend) { 270 data.loadTime = Ozone.util.pageLoad.loadTime; 271 } 272 273 //jsonString = gadgets.json.stringify(data); 274 jsonString = Ozone.util.toString(data); 275 gadgets.rpc.call('..', 'container_init', null, idString, jsonString); 276 277 } catch (error) { 278 throw { 279 name :'WidgetInitException', 280 message :'The call to container_init failed. Inner Exception: ' + error 281 }; 282 } 283 }, 284 285 isInitialized: function() { 286 return this.isAfterInit; 287 }, 288 289 /** 290 * @ignore 291 * default noop callback 292 */ 293 afterInitCallBack: function(widgetEventingController) { 294 295 }, 296 297 /** 298 * @ignore 299 * @description This method is called by the Widget's constructor. It should never be called from user code. 300 */ 301 afterContainerInit: function() { 302 this.isAfterInit = true; 303 if (this.afterInitCallBack != null) { 304 this.afterInitCallBack(this); 305 } 306 }, 307 308 /** 309 * @ignore 310 */ 311 registerHandler : function(handlerName, handlerObject) { 312 //Simple wrapper for manager objects to register handler functions 313 gadgets.rpc.register(handlerName, handlerObject); 314 }, 315 316 /** 317 * @ignore 318 * Wraps gadgets.rpc.call. 319 */ 320 send:function () { 321 gadgets.rpc.call.apply(gadgets.rpc, arguments); 322 }, 323 324 /** 325 * @description Subscribe to a named channel for a given function. 326 * @param {String} channelName The channel to subscribe to. 327 * @param {Function} handler The function you wish to subscribe. This function will be called with three 328 * arguments: sender, msg, channel. 329 * @param {String} [handler.sender] The first argument passed to the handler function is the id of the sender 330 * of the message. See <a href="#getWidgetId">Ozone.eventing.Widget.getWidgetId</a> 331 * for a description of this id. 332 * @param {Object} [handler.msg] The second argument passed to the handler function is the message itself. 333 * @param {String} [handler.channel] The third argument passed to the handler function is the channel the message was 334 * published on. 335 * @example 336 * this.widgetEventingController = Ozone.eventing.Widget.getInstance(); 337 * this.widgetEventingController.subscribe("ClockChannel", this.update); 338 * 339 * var update = function(sender, msg, channel) { 340 * document.getElementById('currentTime').innerHTML = msg; 341 * } 342 * 343 */ 344 subscribe : function(channelName, handler) { 345 gadgets.pubsub.subscribe(channelName, handler); 346 return this; 347 }, 348 /** 349 * @description Unsubscribe to a named channel 350 * @param {String} channelName The channel to unsubscribe to. 351 * @example 352 * this.widgetEventingController.unsubscribe("ClockChannel"); 353 */ 354 unsubscribe : function(channelName) { 355 gadgets.pubsub.unsubscribe(channelName); 356 return this; 357 }, 358 /** 359 * @description Publish a message to a given channel 360 * @param {String} channelName The name of the channel to publish to 361 * @param {Object} message The message to publish to the channel. 362 * @param {String} [dest] The id of a particular destination. Defaults to null which sends to all 363 * subscribers on the channel. See <a href="#getWidgetId">Ozone.eventing.Widget.getWidgetId</a> 364 * for a description of the id. 365 * @example 366 * this.widgetEventingController = Ozone.eventing.Widget.getInstance(); 367 * this.widgetEventingController.publish("ClockChannel", currentTimeString); 368 */ 369 publish : function(channelName, message, dest) { 370 gadgets.pubsub.publish(channelName, message, dest); 371 return this; 372 } 373 }; 374 375 /** 376 * @description Retrieves Ozone.eventing.Widget Singleton instance 377 * @param {Function} [afterInit] callback function to be executed after the Ozone.eventing.Widget singleton is initialized 378 * @param {String} [widgetRelay] Optionally redefine the location of the relay file. The relay file should be defined 379 * globally for the entire widget by setting Ozone.eventing.Widget.widgetRelayURL to the relay file url, immediately after 380 * including the widget bundle javascript. If the relay is not defined at all it is assumed to be at 381 * /[context]/js/eventing/rpc_relay.uncompressed.html. The relay file must be specified with full location details, but without a fully 382 * qualified path. In the case where the relay is residing @ http://server/path/relay.html, the path used must be from the context root of the local 383 * widget. In this case, it would be /path/relay.html. Do not include the protocol. 384 * @since OWF 3.7.0 385 * @throws {Error} throws an error with a message if widget initialization fails 386 * @example 387 * <script type="text/javascript" src="../../js-min/owf-widget-min.js"></script> 388 * <script> 389 * //The location is assumed to be at /[context]/js/eventing/rpc_relay.uncompressed.html if it is not 390 * //set the path correctly below 391 * Ozone.eventing.Widget.widgetRelayURL = '/owf/js/eventing/rpc_relay.uncompressed.html'; 392 * 393 * owfdojo.addOnLoad(function() { 394 * //get widget instance 395 * var widgetEventingController = Ozone.eventing.Widget.getInstance(); 396 * //do something 397 * widgetEventingController.publish("FooChannel", 'message goes here'); 398 * }); 399 * </script> 400 */ 401 Ozone.eventing.Widget.getInstance = function(afterInit, widgetRelay) { 402 if (Ozone.eventing.Widget.instance == null) { 403 Ozone.eventing.Widget.instance = new Ozone.eventing.Widget(widgetRelay, afterInit); 404 } 405 else { 406 if (afterInit != null) { 407 if (!Ozone.eventing.Widget.instance.isAfterInit) { 408 //connect passed in function to the internal callback function 409 owfdojo.connect( 410 Ozone.eventing.Widget.instance,'afterInitCallBack', 411 Ozone.eventing.Widget.instance,afterInit); 412 } 413 else { 414 //already initialized just execute the supplied callback 415 setTimeout(function() { 416 afterInit(Ozone.eventing.Widget.instance) 417 },50); 418 } 419 } 420 } 421 return Ozone.eventing.Widget.instance; 422 }; 423