eventNotification.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /********************************************************************************************************************************
  2. * Licensed Materials - Property of IBM *
  3. * *
  4. * IBM Cognos Products: AGS *
  5. * *
  6. * (C) Copyright IBM Corp. 2005, 2008 *
  7. * *
  8. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. *
  9. *********************************************************************************************************************************/
  10. /*
  11. Wraps a CObserver to provide a general notification framework that includes support
  12. for frames. A primary goal of the framework is to enable components to 'listen' for
  13. events that are trapped and thus not propagated to the interested component, or events
  14. that would never reach the component because it is outside the context of the component
  15. and bubbles up (or bubbles down) another part of the component tree.
  16. The following comments outline the framework use.
  17. 1. The framework expects each window (main or frames) to have a CWndObserver, and
  18. support the getWndObserver() function, i.e. each window has the following script:
  19. oWndObserver = new CWndObserver(window.id);//global observer
  20. function getWndObserver() {
  21. return oWndObserver;
  22. }
  23. 2. A wndObserver can be hooked up to listen to events from Frames by adding the following
  24. script to the onload handler as follows (parent knows what it is interested in):
  25. getWndObserver().attachFrames("mouseup");
  26. 3. Part of the framework deal is that components that trap events should notify their
  27. wndObserver that such an event occurred. Example assumes a menu that has a CObserver:
  28. if (getWndObserver()) {
  29. //in this example, attach the wndObserver as a listener to the menu's CObserver
  30. menu.getObservers().attach(getWndObserver(), getWndObserver().mouseup, menu.onmouseup);
  31. }
  32. 4. Should a component wish to receive notification of events that are outside its scope (events
  33. it would never recieve in normal operation) then the component can listen as follows:
  34. getWndObserver().addListener(reportFrame.m_contextMenu, reportFrame.m_contextMenu.remove, "mouseup");
  35. 5. Generally, component handlers can be attached to the wndObserver as follows (if a handler is
  36. already connected to the component, it will still get called):
  37. getWndObserver().attachEvent(document.body, "mouseup");
  38. 6. To notify, use the following (its important to spicify the src obj if you don't want to be
  39. notified about events you have generated - meltdown):
  40. getWndObserver().notify(this, "mouseup");
  41. */
  42. //some constants
  43. sNotifyMouseUp = "mouseup";
  44. sNotifyMouseDown = "mousedown";
  45. //document.body.oWndObserver = new CWndObserver(window.id);//global observer
  46. //function getWndObserver() {
  47. // return oWndObserver;
  48. //}
  49. function CWndObserver(id) {
  50. this.m_cObserver = new CObserver(this);
  51. this.id = id;
  52. this.toRemoveLisenters = new Array();
  53. this.nesting=0;
  54. }
  55. //add an event listener. Listeners must 'implement' the Update function as per
  56. //CObserver requirements. A listener is an observer in CObserver parlance.
  57. function CWndObserver_addListener(listener, callback, evt) {
  58. this.m_cObserver.attach(listener, callback, evt);
  59. }
  60. //Remove an event listener.
  61. function CWndObserver_removeWhenDone(listener) {
  62. this.toRemoveLisenters.push(listener);
  63. }
  64. //Remove an event listener.
  65. function CWndObserver_removeListener(listener) {
  66. var observers = this.m_cObserver.m_observers;
  67. var length = observers.length;
  68. var tmpArray = new Array();
  69. for (var i=0;i < length;i++) {
  70. if (observers[i].getObserver() != listener) {
  71. tmpArray.push(observers[i]);
  72. }
  73. }
  74. this.m_cObserver.m_observers = tmpArray;
  75. }
  76. //Remove an event listener.
  77. function CWndObserver_removeListenerById(id) {
  78. var observers = this.m_cObserver.m_observers;
  79. var length = observers.length;
  80. var tmpArray = new Array();
  81. for (var i=0;i < length;i++) {
  82. if (observers[i].getObserver().id == id) {
  83. this.removeListener(observers[i].getObserver());
  84. }
  85. }
  86. }
  87. //a required method of CObserver listeners, and used from EventHandlerChain
  88. function CWndObserver_update(event) {
  89. this.notify(event, event.type);
  90. }
  91. //Note, when attaching events, the handlerStr should not be prefixed with 'on'.
  92. // ie. use 'mouseup' rather than 'onmouseup', as the 'on' prefix is 'handled'
  93. //in the eventHandlerChainUtil.
  94. function CWndObserver_attachEvent(obj, handlerStr) {
  95. //THIS DOESN'T WORK IN FIREFOX NETSCAPE BROWSERS!
  96. //TODO: try CWndObserver_privateCheckObjectForHandler
  97. var handler = obj["on" + handlerStr];
  98. if (handler) {
  99. //this should swap out the existing handler, but arrange that it is still called
  100. //pass in this, so ehc knows who to call - will callback to this.update(evt).
  101. eventHandlerChainUtil.doEventHandlerChain(obj, handlerStr, this);
  102. } else {
  103. obj["on" + handlerStr] = function() {
  104. document.body.getWndObserver().notify(this,handlerStr);
  105. }
  106. }
  107. }
  108. // ** POSSIBLE FUTURE SUPPORT FOR NETSCAPE/FIREFOX (EXPERIMENTAL) **
  109. function CWndObserver_privateCheckObjectForHandler(obj, handlerStr) {
  110. //THIS DOESN'T WORK IN FIREFOX NETSCAPE BROWSERS!
  111. handlerStr = "on" + handlerStr;
  112. //possible firefox/netscape way
  113. var attributes = obj.attributes;
  114. if (attributes) {
  115. var i = 0;
  116. for (i = 0; i < attributes.length && !handler; i++) {
  117. if (attributes[i].name == handlerStr) {
  118. return true;
  119. }
  120. }
  121. }
  122. }
  123. //Parameter is the event to listen for (a string e.g. "mouseup"). Chunder through the
  124. //frames adding ourself as a listener for the evt
  125. function CWndObserver_attachFrames(evt,frame) {
  126. var frame = frame?frame:window;
  127. var framesCount = frame.frames.length;
  128. for(var i = 0; i < framesCount; ++i) {
  129. //For some reason the body sometimes is not loaded correctly. So make
  130. //sure it is their before doing any work.
  131. //if (!frame.frames[i].getWndObserver && frame.frames[i].document.body) {
  132. if (frame.frames[i].document.body && !frame.frames[i].document.body.getWndObserver) {
  133. frame.frames[i].document.body.oWndObserver = new CWndObserver(frame.frames[i].name);
  134. frame.frames[i].document.body.getWndObserver = function() {
  135. return this.oWndObserver;
  136. }
  137. frame.frames[i].document.body.oWndObserver.attachEvent(frame.frames[i].document.body,evt);
  138. //frame.frames[i].document.body["on"+evt] = function() {
  139. // this.getWndObserver().notify(this, evt);
  140. //}
  141. }
  142. //For some reason sometimes we get here when body is not there yet.
  143. if (frame.frames[i].document.body && frame.frames[i].document.body.getWndObserver) {
  144. //Remove before adding just incase it was added before.
  145. frame.frames[i].document.body.getWndObserver().removeListener(this);
  146. //attach ourselves as a listener for stuff
  147. frame.frames[i].document.body.getWndObserver().addListener(this, this.notify, evt);
  148. }
  149. }
  150. }
  151. //Propagate an event. evt may be undefined.
  152. //object may be a string (mouseup - evt undefined)
  153. //or a CState, or a WndObserver (or what?)
  154. function CWndObserver_notify(obj, evt) {
  155. evt = (evt == null || evt == 'undefined')? obj.type : evt; //is an event?
  156. evt = (evt == null || evt == 'undefined')? obj.m_evt : evt;//is a CState?
  157. this.privateNotify(obj, evt);
  158. }
  159. //specific callback for an onmouseup - useful when attaching to an existing CObserver
  160. //and the Cobserver's evt is already set to a function (rather than the string "mouseup")
  161. //param should be a CState (from CObserver), or possibly an event.
  162. function CWndObserver_notifyMouseUp(obj) {
  163. this.privateNotify(obj, sNotifyMouseUp);
  164. }
  165. //mousedown specific callback - can add more functions if we need them (i.e. mousemove etc)
  166. function CWndObserver_notifyMouseDown(obj) {
  167. this.privateNotify(obj, "mousedown");
  168. }
  169. //Expect the obj to be a callback from an CObserver (in this case, obj will be a CState),
  170. //or obj will be an event (string). obj should not be null
  171. //obj is generally the src - a CState, or a WndObserver
  172. function CWndObserver_privateNotify(obj, evt) {
  173. // Prevent reentry into this method to avoid a stack exception.
  174. if (this.nesting!=0) return;
  175. var src = (obj.m_observer && obj.m_subject)? obj.m_subject : obj;
  176. evt = (evt == null || evt == 'undefined')? src.m_evt : evt;
  177. //we don't want to notify back to the observer that notified us!
  178. //naughty, but need to access the observers listeners directly (hidden here)
  179. //to omit callbacks to the source
  180. var cachedObservers = this.m_cObserver.m_observers;
  181. var tmpObservers = new Array();
  182. for (var i = 0; i < cachedObservers.length; i++) {
  183. if (src != cachedObservers[i].m_observer)
  184. tmpObservers.push(this.m_cObserver.m_observers[i]);
  185. }
  186. //notify
  187. this.m_cObserver.m_observers = tmpObservers;
  188. this.nesting++;
  189. this.m_cObserver.notify(evt);
  190. this.nesting--;
  191. this.m_cObserver.m_observers = cachedObservers;
  192. //Remove any tagged listeners. This is when some might have been tagged
  193. //during the notify call.
  194. for(var i=0; i<this.toRemoveLisenters.length;i++) {
  195. this.removeListener(this.toRemoveLisenters[i]);
  196. }
  197. //reset
  198. this.toRemoveLisenters = new Array();
  199. }
  200. //private - only used here to propagate notifications
  201. CWndObserver.prototype.privateNotify = CWndObserver_privateNotify;
  202. //public use
  203. CWndObserver.prototype.addListener = CWndObserver_addListener;
  204. CWndObserver.prototype.removeListener = CWndObserver_removeListener;
  205. CWndObserver.prototype.removeListenerById = CWndObserver_removeListenerById;
  206. CWndObserver.prototype.removeWhenDone = CWndObserver_removeWhenDone;
  207. CWndObserver.prototype.attachEvent = CWndObserver_attachEvent;
  208. CWndObserver.prototype.notify = CWndObserver_notify;
  209. CWndObserver.prototype.attachFrames = CWndObserver_attachFrames;
  210. CWndObserver.prototype.update = CWndObserver_update;
  211. CWndObserver.prototype.mouseup = CWndObserver_notifyMouseUp;
  212. CWndObserver.prototype.mousedown = CWndObserver_notifyMouseDown;