/******************************************************************************************************************************** * Licensed Materials - Property of IBM * * * * IBM Cognos Products: AGS * * * * (C) Copyright IBM Corp. 2005, 2008 * * * * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * *********************************************************************************************************************************/ /* Wraps a CObserver to provide a general notification framework that includes support for frames. A primary goal of the framework is to enable components to 'listen' for events that are trapped and thus not propagated to the interested component, or events that would never reach the component because it is outside the context of the component and bubbles up (or bubbles down) another part of the component tree. The following comments outline the framework use. 1. The framework expects each window (main or frames) to have a CWndObserver, and support the getWndObserver() function, i.e. each window has the following script: oWndObserver = new CWndObserver(window.id);//global observer function getWndObserver() { return oWndObserver; } 2. A wndObserver can be hooked up to listen to events from Frames by adding the following script to the onload handler as follows (parent knows what it is interested in): getWndObserver().attachFrames("mouseup"); 3. Part of the framework deal is that components that trap events should notify their wndObserver that such an event occurred. Example assumes a menu that has a CObserver: if (getWndObserver()) { //in this example, attach the wndObserver as a listener to the menu's CObserver menu.getObservers().attach(getWndObserver(), getWndObserver().mouseup, menu.onmouseup); } 4. Should a component wish to receive notification of events that are outside its scope (events it would never recieve in normal operation) then the component can listen as follows: getWndObserver().addListener(reportFrame.m_contextMenu, reportFrame.m_contextMenu.remove, "mouseup"); 5. Generally, component handlers can be attached to the wndObserver as follows (if a handler is already connected to the component, it will still get called): getWndObserver().attachEvent(document.body, "mouseup"); 6. To notify, use the following (its important to spicify the src obj if you don't want to be notified about events you have generated - meltdown): getWndObserver().notify(this, "mouseup"); */ //some constants sNotifyMouseUp = "mouseup"; sNotifyMouseDown = "mousedown"; //document.body.oWndObserver = new CWndObserver(window.id);//global observer //function getWndObserver() { // return oWndObserver; //} function CWndObserver(id) { this.m_cObserver = new CObserver(this); this.id = id; this.toRemoveLisenters = new Array(); this.nesting=0; } //add an event listener. Listeners must 'implement' the Update function as per //CObserver requirements. A listener is an observer in CObserver parlance. function CWndObserver_addListener(listener, callback, evt) { this.m_cObserver.attach(listener, callback, evt); } //Remove an event listener. function CWndObserver_removeWhenDone(listener) { this.toRemoveLisenters.push(listener); } //Remove an event listener. function CWndObserver_removeListener(listener) { var observers = this.m_cObserver.m_observers; var length = observers.length; var tmpArray = new Array(); for (var i=0;i < length;i++) { if (observers[i].getObserver() != listener) { tmpArray.push(observers[i]); } } this.m_cObserver.m_observers = tmpArray; } //Remove an event listener. function CWndObserver_removeListenerById(id) { var observers = this.m_cObserver.m_observers; var length = observers.length; var tmpArray = new Array(); for (var i=0;i < length;i++) { if (observers[i].getObserver().id == id) { this.removeListener(observers[i].getObserver()); } } } //a required method of CObserver listeners, and used from EventHandlerChain function CWndObserver_update(event) { this.notify(event, event.type); } //Note, when attaching events, the handlerStr should not be prefixed with 'on'. // ie. use 'mouseup' rather than 'onmouseup', as the 'on' prefix is 'handled' //in the eventHandlerChainUtil. function CWndObserver_attachEvent(obj, handlerStr) { //THIS DOESN'T WORK IN FIREFOX NETSCAPE BROWSERS! //TODO: try CWndObserver_privateCheckObjectForHandler var handler = obj["on" + handlerStr]; if (handler) { //this should swap out the existing handler, but arrange that it is still called //pass in this, so ehc knows who to call - will callback to this.update(evt). eventHandlerChainUtil.doEventHandlerChain(obj, handlerStr, this); } else { obj["on" + handlerStr] = function() { document.body.getWndObserver().notify(this,handlerStr); } } } // ** POSSIBLE FUTURE SUPPORT FOR NETSCAPE/FIREFOX (EXPERIMENTAL) ** function CWndObserver_privateCheckObjectForHandler(obj, handlerStr) { //THIS DOESN'T WORK IN FIREFOX NETSCAPE BROWSERS! handlerStr = "on" + handlerStr; //possible firefox/netscape way var attributes = obj.attributes; if (attributes) { var i = 0; for (i = 0; i < attributes.length && !handler; i++) { if (attributes[i].name == handlerStr) { return true; } } } } //Parameter is the event to listen for (a string e.g. "mouseup"). Chunder through the //frames adding ourself as a listener for the evt function CWndObserver_attachFrames(evt,frame) { var frame = frame?frame:window; var framesCount = frame.frames.length; for(var i = 0; i < framesCount; ++i) { //For some reason the body sometimes is not loaded correctly. So make //sure it is their before doing any work. //if (!frame.frames[i].getWndObserver && frame.frames[i].document.body) { if (frame.frames[i].document.body && !frame.frames[i].document.body.getWndObserver) { frame.frames[i].document.body.oWndObserver = new CWndObserver(frame.frames[i].name); frame.frames[i].document.body.getWndObserver = function() { return this.oWndObserver; } frame.frames[i].document.body.oWndObserver.attachEvent(frame.frames[i].document.body,evt); //frame.frames[i].document.body["on"+evt] = function() { // this.getWndObserver().notify(this, evt); //} } //For some reason sometimes we get here when body is not there yet. if (frame.frames[i].document.body && frame.frames[i].document.body.getWndObserver) { //Remove before adding just incase it was added before. frame.frames[i].document.body.getWndObserver().removeListener(this); //attach ourselves as a listener for stuff frame.frames[i].document.body.getWndObserver().addListener(this, this.notify, evt); } } } //Propagate an event. evt may be undefined. //object may be a string (mouseup - evt undefined) //or a CState, or a WndObserver (or what?) function CWndObserver_notify(obj, evt) { evt = (evt == null || evt == 'undefined')? obj.type : evt; //is an event? evt = (evt == null || evt == 'undefined')? obj.m_evt : evt;//is a CState? this.privateNotify(obj, evt); } //specific callback for an onmouseup - useful when attaching to an existing CObserver //and the Cobserver's evt is already set to a function (rather than the string "mouseup") //param should be a CState (from CObserver), or possibly an event. function CWndObserver_notifyMouseUp(obj) { this.privateNotify(obj, sNotifyMouseUp); } //mousedown specific callback - can add more functions if we need them (i.e. mousemove etc) function CWndObserver_notifyMouseDown(obj) { this.privateNotify(obj, "mousedown"); } //Expect the obj to be a callback from an CObserver (in this case, obj will be a CState), //or obj will be an event (string). obj should not be null //obj is generally the src - a CState, or a WndObserver function CWndObserver_privateNotify(obj, evt) { // Prevent reentry into this method to avoid a stack exception. if (this.nesting!=0) return; var src = (obj.m_observer && obj.m_subject)? obj.m_subject : obj; evt = (evt == null || evt == 'undefined')? src.m_evt : evt; //we don't want to notify back to the observer that notified us! //naughty, but need to access the observers listeners directly (hidden here) //to omit callbacks to the source var cachedObservers = this.m_cObserver.m_observers; var tmpObservers = new Array(); for (var i = 0; i < cachedObservers.length; i++) { if (src != cachedObservers[i].m_observer) tmpObservers.push(this.m_cObserver.m_observers[i]); } //notify this.m_cObserver.m_observers = tmpObservers; this.nesting++; this.m_cObserver.notify(evt); this.nesting--; this.m_cObserver.m_observers = cachedObservers; //Remove any tagged listeners. This is when some might have been tagged //during the notify call. for(var i=0; i