CMenu.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  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. Class : CMenu
  12. Description :
  13. -----------------------------------------------------------------------------------------------------*/
  14. //this compensates for a difference in calculation of the page width by 18 pixels
  15. //in mozilla and netscape versus IE
  16. var MOZILLA_PAGE_WIDTH_COMPENSATION = 18;
  17. function CMenu(id,style) {
  18. this.m_htmlContainer = document.body;
  19. this.m_bVisible = false;
  20. this.m_id = id;
  21. this.m_htmlDivElement = null;
  22. this.m_parent = null;
  23. this.m_menuItems = new Array();
  24. this.m_style = style;
  25. this.m_callback = null;
  26. this.m_observers = new CObserver(this);
  27. this.m_offsetXCoords = 0;
  28. this.m_offsetYCoords = 0;
  29. this.m_bContainsCascadedChildren = false;
  30. }
  31. function CMenu_setHTMLContainer(container) {
  32. this.m_htmlContainer = container;
  33. }
  34. function CMenu_getHTMLContainer() {
  35. return this.m_htmlContainer;
  36. }
  37. function CMenu_setParent(parent) {
  38. this.m_parent = parent;
  39. }
  40. function CMenu_getParent() {
  41. return this.m_parent;
  42. }
  43. function CMenu_getId() {
  44. return this.m_id;
  45. }
  46. function CMenu_getHTMLDiv() {
  47. return this.m_htmlDivElement;
  48. }
  49. function CMenu_create() {
  50. newElement = (document.all && typeof this.m_htmlContainer.document != "undefined") ? this.m_htmlContainer.document.createElement("div") : this.m_htmlContainer.ownerDocument.createElement("div");
  51. if(typeof this.getStyle() == "object")
  52. newElement.className = this.getStyle().getNormalState();
  53. newElement.style.display = "none";
  54. newElement.style.position = "absolute";
  55. newElement.id = this.m_id;
  56. //append the new menu
  57. this.m_htmlContainer.appendChild(newElement);
  58. //create a reference to it
  59. this.m_htmlDivElement = newElement;
  60. }
  61. function CMenu_draw() {
  62. if(this.m_htmlContainer == null)
  63. return;
  64. if(this.m_htmlDivElement == null)
  65. this.create();
  66. var html='';
  67. if(this.m_menuItems.length == 0) {
  68. if(this.m_callback != null) {
  69. menu = this;
  70. setTimeout("menu.executeCallback()", 1000);
  71. // build a html div with a wait cursor
  72. html='<table class="menuItem_normal" CELLPADDING="0" CELLSPACING="0">';
  73. html += '<tr>';
  74. html += '<td>';
  75. html += '<img width="16" height="16" src="../common/images/tv_loading.gif"/>';
  76. html += '</td>';
  77. html += '<td nowrap="nowrap" align="left">';
  78. if(typeof gUIFrameWorkMenuLoadingMessage != 'undefined') {
  79. html += gUIFrameWorkMenuLoadingMessage;
  80. } else {
  81. html += '...';
  82. }
  83. html += '</td>';
  84. html += '</tr>';
  85. html += '</table>';
  86. }
  87. } else {
  88. //add the items
  89. var i=0;
  90. var html='<table CELLPADDING="0" CELLSPACING="0" role="menu" aria-label="Menu Popup">';
  91. for (i=0; i < this.m_menuItems.length; i++) {
  92. if(this.m_menuItems[i].isVisible()) {
  93. html += '<tr><td>';
  94. html += this.m_menuItems[i].draw();
  95. html += '</td></tr>';
  96. }
  97. }
  98. html += '</table>';
  99. }
  100. try
  101. {
  102. this.m_htmlDivElement.innerHTML = html;
  103. // attach the event handlers
  104. this.attachEvents();
  105. }
  106. catch (e)
  107. {
  108. }
  109. }
  110. function CMenu_updateCoords() {
  111. //set the z-index first, we still need to set it even if the menu doesn't have a parent
  112. //and the coordinates are not set, This is to ensure that the hidden 'shim' is displayed
  113. //underneath the menu
  114. this.setZIndex(500);
  115. myParent = this.getParent();
  116. if(this.getHTMLDiv() == null || myParent == null || ( !(myParent instanceof CToolbarButton) && !(myParent instanceof CMenuItem) ) ) {
  117. return;
  118. }
  119. // make sure the parent has implemented the method "getMenuType"
  120. if(typeof myParent.getMenuType != 'function') {
  121. return;
  122. }
  123. var x=0; var y=0;
  124. myParentHTMLElement = document.getElementById(this.getParent().getId());
  125. if(myParentHTMLElement == null)
  126. return;
  127. var current = myParentHTMLElement;
  128. // calculate the page width
  129. var pageWidth = 0;
  130. if(typeof window.innerWidth != "undefined")
  131. pageWidth = window.innerWidth - MOZILLA_PAGE_WIDTH_COMPENSATION;
  132. else
  133. pageWidth = document.body.clientWidth;
  134. // calculate the page height
  135. var pageHeight = 0;
  136. if(typeof window.innerHeight != "undefined")
  137. pageHeight = window.innerHeight;
  138. else
  139. pageHeight = document.body.clientHeight;
  140. // handle drop down menus
  141. if(myParent.getMenuType() == 'dropDown') {
  142. x = document.body.scrollLeft; y = myParentHTMLElement.offsetHeight + document.body.scrollTop;
  143. while(current != null) {
  144. x += current.offsetLeft; y += current.offsetTop;
  145. current = current.offsetParent;
  146. }
  147. // if the right side of the drop down menu extends beyond browser window viewing area, adjust accordingly
  148. if((x + this.getHTMLDiv().offsetWidth) > pageWidth) {
  149. x = pageWidth - this.getHTMLDiv().offsetWidth;
  150. }
  151. // if the bottom of the drop down menu extends below the browser viewing area and there is enough room to draw at the top, then draw to the top
  152. if(((y + this.getHTMLDiv().offsetHeight) > pageHeight) && (y - (this.getHTMLDiv().offsetHeight + myParentHTMLElement.clientHeight) >= 0)) {
  153. y -= (this.getHTMLDiv().offsetHeight + myParentHTMLElement.clientHeight);
  154. }
  155. } else if(myParent.getMenuType() == 'cascaded') {
  156. x = myParentHTMLElement.offsetWidth + document.body.scrollLeft; y = document.body.scrollTop;
  157. while(current != null) {
  158. x += current.offsetLeft; y += current.offsetTop;
  159. current = current.offsetParent;
  160. }
  161. // if the right side of the cascaded menu extends beyond the viewing area of the browser window right side, render to the left insted of the right
  162. if((x + this.getHTMLDiv().offsetWidth) > pageWidth) {
  163. x -= myParentHTMLElement.offsetWidth + this.getHTMLDiv().offsetWidth;
  164. }
  165. // if the bottom of the cascaded menu extends beyond the bottom of the browser viewing area, draw to the top
  166. if((y + this.getHTMLDiv().offsetHeight) > pageHeight) {
  167. y -= (this.getHTMLDiv().offsetHeight-myParentHTMLElement.clientHeight);
  168. }
  169. }
  170. this.setXCoord(x);
  171. this.setYCoord(y);
  172. }
  173. function CMenu_add(menuItem) {
  174. if(typeof menuItem.getObservers == "function" && typeof menuItem.getObservers() == "object") {
  175. menuItem.getObservers().attach(this, this.closeSubMenus, menuItem.onmouseover);
  176. menuItem.getObservers().attach(this, this.closeAllMenus, menuItem.onmouseup);
  177. menuItem.getObservers().attach(this, this.closeSubMenus, menuItem.onfocus);
  178. menuItem.getObservers().attach(this, this.closeAllMenus, menuItem.onkeypress);
  179. }
  180. this.m_menuItems[this.m_menuItems.length] = menuItem;
  181. }
  182. function CMenu_get(index) {
  183. if(index >= 0 && index < this.getNumItems()) {
  184. return this.m_menuItems[index];
  185. }
  186. return null;
  187. }
  188. function CMenu_getNumItems() {
  189. return this.m_menuItems.length;
  190. }
  191. function CMenu_hide() {
  192. if(this.m_htmlDivElement != null) {
  193. this.m_htmlDivElement.style.display = "none";
  194. this.hideHiddenIframe();
  195. }
  196. this.m_bVisible = false;
  197. // get the actual element that spawned the menu
  198. var theControl = this.getParent();
  199. if (theControl != null && typeof theControl.setFocus == "function")
  200. theControl.setFocus();
  201. }
  202. function CMenu_show() {
  203. if(this.m_htmlDivElement != null) {
  204. var htmlElementId = this.m_htmlDivElement.id;
  205. this.m_htmlDivElement.style.display = "block";
  206. this.m_bVisible = true;
  207. // update the x and y coords
  208. this.updateCoords();
  209. var isNS7 = ((!document.all) && (document.getElementById)) ? true : false;
  210. var iFrameId = "uiFrameworkHiddenIframe"+this.m_id;
  211. var hiddenIframeElement = document.getElementById(iFrameId);
  212. //create the shim and set its size and coords based on the parent menu
  213. if (hiddenIframeElement == null) {
  214. hiddenIframeElement = this.createHiddenIFrame(iFrameId);
  215. }
  216. //show the shim
  217. if(hiddenIframeElement) {
  218. hiddenIframeElement.style.display = "block";
  219. updateIframeCoords(iFrameId, htmlElementId, isNS7);
  220. setTimeout('updateIframeCoords("'+iFrameId+'", "'+htmlElementId+'", '+isNS7+')',50);
  221. }
  222. if (!isNS7)
  223. {
  224. try
  225. {
  226. this.m_htmlDivElement.focus();
  227. }
  228. catch (e)
  229. {
  230. }
  231. }
  232. }
  233. }
  234. function CMenu_createHiddenIFrame(iFrameId)
  235. {
  236. var container = this.getHTMLContainer();
  237. var iframeElem = (document.all && typeof container.document != "undefined") ? container.document.createElement("iframe") : container.ownerDocument.createElement("iframe");
  238. iframeElem.setAttribute("id",iFrameId);
  239. iframeElem.setAttribute("src",'../common/images/spacer.gif');
  240. iframeElem.setAttribute("scrolling",'no');
  241. iframeElem.setAttribute("frameborder",'0');
  242. iframeElem.style.position='absolute';
  243. iframeElem.style.minWidth='0px';
  244. iframeElem.style.minHeight='0px';
  245. iframeElem.style.left='0px';
  246. iframeElem.style.top='0px';
  247. iframeElem.style.zIndex=-499;
  248. iframeElem.style.display='none';
  249. container.appendChild(iframeElem);
  250. return iframeElem;
  251. }
  252. function CMenu_isVisible() {
  253. return this.m_bVisible;
  254. }
  255. function CMenu_remove(childClicked) {
  256. for(var i = 0; i < this.getNumItems(); ++i) {
  257. var currentItem = this.get(i);
  258. if(typeof currentItem.getMenu == "function" && currentItem.getMenu() != null)
  259. currentItem.getMenu().remove();
  260. }
  261. //Only enable when not clicking this items parent.
  262. if (this.getParent && this.getParent() instanceof CMenuItem && !childClicked) {
  263. this.getParent().enable();
  264. }
  265. if(this.m_htmlContainer != null && this.m_htmlDivElement != null) {
  266. this.m_htmlContainer.removeChild(this.m_htmlDivElement);
  267. }
  268. this.m_bVisible = false;
  269. this.m_htmlDivElement = null;
  270. this.hideHiddenIframe();
  271. }
  272. function CMenu_hideHiddenIframe(forceHide) {
  273. var hiddenIframeElement = document.getElementById("uiFrameworkHiddenIframe"+this.m_id);
  274. if(hiddenIframeElement) {
  275. hiddenIframeElement.style.display = "none";
  276. }
  277. }
  278. function CMenu_enable() {
  279. }
  280. function CMenu_disable() {
  281. }
  282. function CMenu_getState() {
  283. }
  284. function CMenu_clear() {
  285. if(this.m_htmlDivElement != null)
  286. this.m_htmlDivElement.innerHTML='';
  287. this.m_menuItems.splice(0, this.m_menuItems.length)
  288. }
  289. function CMenu_attachEvents() {
  290. for(var i = 0; i < this.m_menuItems.length; i++) {
  291. if(typeof this.m_menuItems[i].attachEvents == "function")
  292. this.m_menuItems[i].attachEvents();
  293. }
  294. }
  295. function CMenu_closeSubMenus(state) {
  296. // Called during a notification...
  297. // make sure we hide any submenus which have been opened.
  298. for(var i = 0; i < this.m_menuItems.length; i++) {
  299. menuItem = this.m_menuItems[i];
  300. subject = state.getSubject();
  301. if(menuItem != subject && typeof menuItem.getMenu == "function" && menuItem.getMenu() != null && menuItem.getMenu().isVisible()) {
  302. menuItem.getMenu().remove();
  303. }
  304. }
  305. }
  306. function CMenu_closeAllMenus(state) {
  307. // Called during a notification...
  308. current = this;
  309. var highestMenu = null;
  310. while(current) {
  311. if(current instanceof CMenu) {
  312. highestMenu = current;
  313. }
  314. //not always guaranteed to have a parent, for example drop down combo boxes
  315. if (current.getParent) {
  316. current = current.getParent();
  317. }
  318. else {
  319. current=null;
  320. }
  321. }
  322. if(highestMenu != null)
  323. highestMenu.remove();
  324. }
  325. function CMenu_setStyle(style) {
  326. this.m_style = style;
  327. }
  328. function CMenu_getStyle() {
  329. return this.m_style;
  330. }
  331. function CMenu_setOffsetXCoords(x) {
  332. if (x && x != 'undefined')
  333. this.m_offsetXCoords = x;
  334. }
  335. function CMenu_setOffsetYCoords(y) {
  336. if (y && y != 'undefined')
  337. this.m_offsetYCoords = y;
  338. }
  339. function CMenu_setContainsCascadedChildren(flag) {
  340. this.m_bContainsCascadedChildren = flag;
  341. }
  342. function CMenu_hasCascadedChildren() {
  343. return this.m_bContainsCascadedChildren;
  344. }
  345. function CMenu_setXCoord(x) {
  346. htmlDiv = this.getHTMLDiv();
  347. if(htmlDiv != null)
  348. htmlDiv.style.left = x + this.m_offsetXCoords + "px";
  349. }
  350. function CMenu_setYCoord(y) {
  351. htmlDiv = this.getHTMLDiv();
  352. if(htmlDiv != null)
  353. htmlDiv.style.top = y + this.m_offsetYCoords + "px";
  354. }
  355. function CMenu_setZIndex(zIndex) {
  356. htmlDiv = this.getHTMLDiv();
  357. if(htmlDiv != null)
  358. htmlDiv.style.zIndex = zIndex;
  359. }
  360. // set a callback routine to populate the menu
  361. function CMenu_registerCallback(callback) {
  362. this.m_callback = callback;
  363. }
  364. function CMenu_executeCallback() {
  365. if(this.m_callback == null)
  366. return;
  367. this.m_callback();
  368. }
  369. function CMenu_getObservers() {
  370. return this.m_observers;
  371. }
  372. function CMenu_onmouseover(evt) {
  373. //get the event in a cross-browser fashion
  374. evt = (evt) ? evt : ((event) ? event : null);
  375. // notify our parent (if one exists) of this event
  376. if(this.getParent() != null && typeof this.getParent().onmouseover == 'function')
  377. this.getParent().onmouseover(evt);
  378. // notify observers of this event
  379. this.getObservers().notify(CMenu_onmouseover);
  380. }
  381. function CMenu_onmouseout(evt) {
  382. //get the event in a cross-browser fashion
  383. evt = (evt) ? evt : ((event) ? event : null);
  384. // notify our parent (if one exists) of this event
  385. if(this.getParent() != null && typeof this.getParent().onmouseout == 'function')
  386. this.getParent().onmouseout(evt);
  387. // notify observers of this event
  388. this.getObservers().notify(CMenu_onmouseout);
  389. }
  390. function CMenu_onmouseup(evt) {
  391. //get the event in a cross-browser fashion
  392. evt = (evt) ? evt : ((event) ? event : null);
  393. // notify our parent (if one exists) of this event
  394. if(this.getParent() != null && typeof this.getParent().onmouseup == 'function')
  395. this.getParent().onmouseup(evt);
  396. // notify observers of this event
  397. this.getObservers().notify(CMenu_onmouseup);
  398. }
  399. function CMenu_onkeypress(evt) {
  400. //get the event in a cross-browser fashion
  401. evt = (evt) ? evt : ((event) ? event : null);
  402. // notify our parent (if one exists) of this event
  403. if(this.getParent() != null && typeof this.getParent().onkeypress == 'function')
  404. this.getParent().onkeypress(evt);
  405. // notify observers of this event
  406. this.getObservers().notify(CMenu_onkeypress);
  407. }
  408. CMenu.prototype.draw = CMenu_draw;
  409. CMenu.prototype.updateCoords = CMenu_updateCoords;
  410. CMenu.prototype.add = CMenu_add;
  411. CMenu.prototype.get = CMenu_get;
  412. CMenu.prototype.getNumItems = CMenu_getNumItems;
  413. CMenu.prototype.hide = CMenu_hide;
  414. CMenu.prototype.hideHiddenIframe = CMenu_hideHiddenIframe;
  415. CMenu.prototype.show = CMenu_show;
  416. CMenu.prototype.enable = CMenu_enable;
  417. CMenu.prototype.disable = CMenu_disable;
  418. CMenu.prototype.getState = CMenu_getState;
  419. CMenu.prototype.clear = CMenu_clear;
  420. CMenu.prototype.attachEvents = CMenu_attachEvents;
  421. CMenu.prototype.setParent = CMenu_setParent;
  422. CMenu.prototype.getParent = CMenu_getParent;
  423. CMenu.prototype.getHTMLContainer = CMenu_getHTMLContainer;
  424. CMenu.prototype.setHTMLContainer = CMenu_setHTMLContainer;
  425. CMenu.prototype.getHTMLDiv = CMenu_getHTMLDiv;
  426. CMenu.prototype.create = CMenu_create;
  427. CMenu.prototype.remove = CMenu_remove;
  428. CMenu.prototype.getId = CMenu_getId;
  429. CMenu.prototype.isVisible = CMenu_isVisible;
  430. CMenu.prototype.setStyle = CMenu_setStyle;
  431. CMenu.prototype.getStyle = CMenu_getStyle;
  432. CMenu.prototype.closeSubMenus = CMenu_closeSubMenus;
  433. CMenu.prototype.closeAllMenus = CMenu_closeAllMenus
  434. CMenu.prototype.setOffsetXCoords = CMenu_setOffsetXCoords;
  435. CMenu.prototype.setOffsetYCoords = CMenu_setOffsetYCoords;
  436. CMenu.prototype.setContainsCascadedChildren = CMenu_setContainsCascadedChildren;
  437. CMenu.prototype.hasCascadedChildren = CMenu_hasCascadedChildren;
  438. CMenu.prototype.setXCoord = CMenu_setXCoord;
  439. CMenu.prototype.setYCoord = CMenu_setYCoord;
  440. CMenu.prototype.setZIndex = CMenu_setZIndex;
  441. CMenu.prototype.update = new Function("return true");
  442. CMenu.prototype.registerCallback = CMenu_registerCallback;
  443. CMenu.prototype.executeCallback = CMenu_executeCallback;
  444. CMenu.prototype.getObservers = CMenu_getObservers;
  445. CMenu.prototype.onmouseover = CMenu_onmouseover;
  446. CMenu.prototype.onmouseout = CMenu_onmouseout;
  447. CMenu.prototype.onmouseup = CMenu_onmouseup;
  448. CMenu.prototype.onkeypress = CMenu_onkeypress;
  449. CMenu.prototype.createHiddenIFrame = CMenu_createHiddenIFrame;
  450. function updateIframeCoords(id, containerId, isNS7)
  451. {
  452. var container = document.getElementById(containerId);
  453. var hiddenIframeElement = document.getElementById(id);
  454. if (hiddenIframeElement && container) {
  455. if(isNS7 == true) {
  456. hiddenIframeElement.style.left = container.offsetLeft;
  457. hiddenIframeElement.style.top = container.offsetTop;
  458. hiddenIframeElement.style.width = container.offsetWidth;
  459. hiddenIframeElement.style.height = container.offsetHeight;
  460. } else {
  461. hiddenIframeElement.style.pixelLeft = container.offsetLeft;
  462. hiddenIframeElement.style.pixelTop = container.offsetTop;
  463. hiddenIframeElement.style.pixelWidth = container.offsetWidth;
  464. hiddenIframeElement.style.pixelHeight = container.offsetHeight;
  465. }
  466. }
  467. }