fragmentBridge.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. // Licensed Materials - Property of IBM
  2. //
  3. // IBM Cognos Products: cpscrn
  4. //
  5. // (C) Copyright IBM Corp. 2005, 2016
  6. //
  7. // US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  8. //
  9. //
  10. /* Copyright IBM Corp. 2009 2011Rights Reserved. */
  11. /**
  12. * @author rjd
  13. */
  14. dojo.declare("com.ibm.cognos.bux.fragmentBridge", null,
  15. {
  16. resources:
  17. [
  18. [ "SCRIPT", "$CGI$/dashboard/messages/messages/pfmessages?section=JS" ],
  19. [ "SCRIPT", "$WEB$/fragments/xdojo/core.js" ],
  20. [ "SCRIPT", "$WEB$/fragments/cps.core.js" ],
  21. [ "SCRIPT", "$WEB$/common/framework/validator/CValidator.js" ]
  22. ],
  23. onLoad: function()
  24. {
  25. this.domID = "_" + this.iContext.widgetId + "_";
  26. if (window._F_Config === undefined)
  27. {
  28. var config = this.iContext.bridgeConfig;
  29. var gateway = window.bux ? config.gateway : this.iContext.io.rewriteURI(config.gateway);
  30. var webcontent = window.bux ? config.webContent : this.iContext.io.rewriteURI(config.webContent);
  31. window._F_Config = new Object();
  32. _F_Config.init = function()
  33. {
  34. this.gateway = gateway;
  35. this.application = config.application;
  36. this.webContent = webcontent;
  37. this.appGateway = this.gateway + this.application;
  38. this.version = "1.1.0";
  39. // signed values for portlet bridge
  40. this.bridgeGateway = config.bridgeGateway;
  41. this.bridgeWebContent = config.bridgeWebContent;
  42. };
  43. _F_Config.init();
  44. }
  45. _IW_Resource.initialize();
  46. // detect and download fragment controller js
  47. var i, l = this.resources.length;
  48. for (i = 0; i < l; i++)
  49. {
  50. _IW_runQueue.add(_IW_Resource, _IW_Resource.loadResource, [ this.resources[i][0], this._expandMacros(this.resources[i][1]) ]);
  51. }
  52. // queue the creation and retrieval of fragment
  53. _IW_runQueue.add(this, this._loadFragment, []);
  54. _IW_runQueue.run();
  55. // Bux specific code
  56. this.setBuxMenu();
  57. },
  58. onUnload: function()
  59. {
  60. if (this.fragment)
  61. {
  62. this.fragment.destroy();
  63. }
  64. },
  65. onView: function()
  66. {
  67. if (this.fragment)
  68. {
  69. this.fragment.setMode("view");
  70. }
  71. },
  72. onEdit: function()
  73. {
  74. if (this.fragment)
  75. {
  76. this.fragment.setMode("edit");
  77. }
  78. },
  79. setBuxMenu: function() {
  80. // Add refresh to bux menu
  81. if (window.bux && BUXMSG !== undefined) {
  82. this.iContext.iEvents.fireEvent("com.ibm.bux.widgetchrome.toolbar.init", null, [ this.getMenuObject() ]);
  83. }
  84. },
  85. getMenuObject: function() {
  86. return {
  87. "_root": [{
  88. "name" : "refresh",
  89. "label" : BUXMSG.GEN.IDS_GEN_REFRESH,
  90. "iconClass" : "bux-refresh-button",
  91. "action" : "widget.refresh",
  92. "items" : null
  93. }]
  94. };
  95. },
  96. onToolbarAction: function(iEvent) {
  97. if (String(iEvent.payload) === "widget.refresh") {
  98. this.fragment.raiseEvent("fragment.refresh");
  99. }
  100. },
  101. onWidgetRefresh: function() {
  102. this.fragment.raiseEvent("fragment.refresh");
  103. },
  104. _expandMacros: function(text)
  105. {
  106. return text.replace(/\$CGI\$/g, _F_Config.gateway).replace(/\$WEB\$/g, _F_Config.webContent);
  107. },
  108. /*
  109. * This method hooks up event handlers that will remove the "onBeforeUnload" handler and
  110. * put it back accordingly when the user clicks somwhere inside the fragment content div.
  111. * IE will trigger this event when we have a href, form submit event if the location is a javascript function.
  112. * see defect: 257696
  113. */
  114. _attachHandlerForIEBeforeUnloadFix: function(div){
  115. if (dojo.isIE && div && !div.beforeUnloadFixAttached){
  116. xAddEventListener(div,"mouseup", _IW_mouseUpHandler);
  117. xAddEventListener(div,"keydown", _IW_keyDownHandler);
  118. xAddEventListener(div,"keyup", _IW_keyUpHandler);
  119. div.beforeUnloadFixAttached = true;
  120. }
  121. },
  122. _loadFragment: function()
  123. {
  124. var overrideFragmentController = function(){
  125. if (fragment && !fragment.prototype.widgetOverride){
  126. fragment.prototype.widgetOverride = true;
  127. /* Override BUX specific functionality */
  128. if (window.bux){
  129. /*Needed for Ajax response error handling.*/
  130. fragment.prototype._processFragmentXMLBase = fragment.prototype.processFragmentXML;
  131. fragment.prototype.processFragmentXML = function(){
  132. this._processFragmentXMLBase.apply(this, arguments);
  133. if (this._ajaxDeferredCall){
  134. this._ajaxDeferredCall = null;
  135. }
  136. }
  137. /*Error handling override*/
  138. fragment.prototype.processError = function(code, message, details){
  139. if (this._ajaxDeferredCall){
  140. /*use the deferred call if we have one (used in BUX)*/
  141. var e = new Error();
  142. if (code == "invalidCredentials"){
  143. e.code = "camAuthUserRecoverable";
  144. }else {
  145. e.code = code;
  146. }
  147. if (message){
  148. e.message = message;
  149. }else{
  150. e.message = dojo.string.substitute(BUXMSG.EDG.IDS_EDG_HTTP_ERROR, [code])
  151. }
  152. e.details = details;
  153. this._ajaxDeferredCall.reject(e);
  154. } else {
  155. _F_alert(code + ":\n" + message, this.title);
  156. }
  157. }
  158. /*Replace fragment alert with BUX message box*/
  159. window._F_alert = function(msg, title){
  160. bux.messageBox(bux.MB_ERROR, title, msg, null);
  161. }
  162. /*Replace fragment _F_Ajax with bux xhr to handle errors properly (e.g. timeout)*/
  163. var baseAjaxPrototype = _F_Ajax.Request;
  164. if (!baseAjaxPrototype.widgetOverride){
  165. _F_Ajax.Request.prototype.widgetOverride = true;
  166. _F_Ajax.Request = function(url, options, caller){
  167. // we don't care about the parsed dojo response, we simply set the 'handleAs' to 'text' in IE for performance reason (when the response is html). Firefox is faster when it's set to xml
  168. var requestObject = {handleAs: dojo.isIE ? "text" : "xml"};
  169. requestObject.sync= (options.asynchronous !== undefined) ? !options.asynchronous : false;
  170. requestObject.headers ={
  171. "X-Fragment-Version": _F_Config.version,
  172. "X-Controller-Agent": "fragment/" + _F_Config.version,
  173. "Accept": "text/javascript, text/html, application/xml, text/xml, */*"
  174. };
  175. if (typeof options.parameters == "object"){
  176. requestObject.content = options.parameters;
  177. }
  178. var method = (options.method || "post").toLowerCase();
  179. if (method == 'post'){
  180. var contentType = options.contentType || "application/x-www-form-urlencoded";
  181. var encoding = options.encoding;
  182. requestObject.headers['Content-Type'] = contentType + (encoding ? '; charset=' + encoding : '');
  183. }
  184. url = _F_Config.expandMacros(url);
  185. if ((method == "post" || method == "put")){
  186. if (options.postBody === undefined){
  187. var parts = url.split('?');
  188. url = parts[0];
  189. options.postBody = parts[1];
  190. }
  191. if (method == 'post'){
  192. requestObject.postData = options.postBody;
  193. } else if (method == 'put'){
  194. requestObject.putData = options.postBody;
  195. }
  196. }
  197. requestObject.url = url;
  198. var _self = this;
  199. requestObject.load = function(content, ioargs){
  200. _self.transport = ioargs.xhr;
  201. var fdc = null;
  202. if (caller){
  203. /* Give the caller a deferred call so it can control the error handling*/
  204. fdc = new dojo.Deferred();
  205. caller._ajaxDeferredCall = fdc;
  206. }
  207. /* start ajax processing.*/
  208. options.onSuccess.call(_self, _self.transport);
  209. if (caller){
  210. return fdc;
  211. }
  212. }
  213. var dfd;
  214. if (method == 'get'){
  215. dfd = bux.xhrGet(requestObject);
  216. }else if (method == 'put'){
  217. dfd = bux.xhrPut(requestObject);
  218. }else{
  219. dfd = bux.xhrPost(requestObject);
  220. }
  221. dfd.then(null, function(e){bux.errorBox(e.message, null, e);});
  222. }
  223. _F_Ajax.Request.prototype = baseAjaxPrototype.prototype;
  224. baseAjaxPrototype = null;
  225. }
  226. }
  227. }
  228. }
  229. overrideFragmentController();
  230. _F_init();
  231. // make sure there's a dummy root fragment for eventing
  232. if (fragment["FRAG_"] === undefined)
  233. new fragment("/ROOT", "FRAG_");
  234. // create destination div
  235. var id = "FRAG_" + this.iContext.widgetId + "_";
  236. var div = $(id + "content");
  237. this._attachHandlerForIEBeforeUnloadFix(div);
  238. div.setAttribute("fragmentid", id);
  239. var sPath = this.iContext.bridgeConfig.fragmentPath;
  240. sPath += (sPath.indexOf('?') == -1) ? '?' : '&';
  241. // Tell the fragment rewriter the values for the proxied gateway and webcontent
  242. sPath += "frag-gateway=" + _F_Strings.urlEncode(_F_Config.gateway) + "&frag-webcontent=" + _F_Strings.urlEncode(_F_Config.webContent);
  243. // create fragment object from path provided by iWidget content
  244. this.fragment = new fragment(sPath, id);
  245. // give fragment access to iwidget
  246. this.fragment.iContext = this.iContext;
  247. this.fragment.iWidget = this;
  248. this._attachFragmentEvents();
  249. // hook fragment transient property mechanism
  250. if (!window.bux){
  251. this.fragment.encodedTransients = this.fragmentEncodedTransients;
  252. }
  253. this.fragment.transientUpdate = this.fragmentTransientUpdate;
  254. this.fragment.transientUpdateList = this.fragmentTransientUpdateList;
  255. // copy itemset items to the fragment custom properties
  256. this.customInit();
  257. // Ajax
  258. this.fragment.retrieve();
  259. return false;
  260. },
  261. /**
  262. * customInit - copy attribute itemSet to fragment.customProperties
  263. * @returns boolean - true if there were items to copy
  264. */
  265. customInit: function() {
  266. this.customUpdated = false;
  267. // copy itemset attributes as custom properties
  268. var att = this.iContext.getItemSet("attributes");
  269. var names = att.getAllNames();
  270. if (names) {
  271. var params = {}, hasParams = false, i, l = names.length;
  272. for (i = 0; i < l; i++) {
  273. if (names[i] != "version" && names[i] != "path" && names[i] != "undefined") {
  274. params[names[i]] = att.getItemValue(names[i]);
  275. hasParams = true;
  276. }
  277. }
  278. if (hasParams) {
  279. this.fragment.customProperties = params;
  280. }
  281. }
  282. return hasParams;
  283. },
  284. /**
  285. * fragmentCustomUpdate - update attribute itemSet from fragment.customProperties
  286. */
  287. customUpdate: function() {
  288. if (this.customUpdated && this.fragment.customProperties) {
  289. var att = this.iContext.getiWidgetAttributes();
  290. for (var name in this.fragment.customProperties) {
  291. att.setItemValue(name, this.fragment.customProperties[name]);
  292. }
  293. att.save();
  294. this.customUpdated = false;
  295. }
  296. },
  297. /*
  298. * This methods hooks up all fragment event handler needed to by the iWidget bridge.
  299. * We currently hook up handler for:
  300. * - 'fragment.mode.change'
  301. * - 'fragment.retrieve.after'.
  302. */
  303. _attachFragmentEvents: function()
  304. {
  305. if (this.fragment)
  306. {
  307. this.fragment.addEventListener("fragment.mode.change", this._fragmentModeChangeHandler, false);
  308. this.fragment.addEventListener("fragment.retrieve.after", this._fragmentRetrieveAfterHandler, false);
  309. this.fragment.addEventListener("fragment.title.change", this._fragmentTitleChangeHandler, false);
  310. }
  311. },
  312. /*
  313. * Called when "fragment.title.change' occurs.
  314. * The proper widget event will be fired
  315. *
  316. */
  317. _fragmentTitleChangeHandler: function(ev){
  318. this.iWidget.iContext.iEvents.fireEvent( "com.ibm.bux.widget.action", null, {
  319. action: "chrome.property.set",
  320. name: "title",
  321. value: ev.payload.newTitle
  322. });
  323. },
  324. /*
  325. * Called when "fragment.retrieve.after' occurs.
  326. * If the fragment customs are different than the one saved by the widget,
  327. * we will update the iWidget and save the attributes.
  328. *
  329. * NOTE: Context of function is fragment, use this.iWidget to access this class
  330. */
  331. _fragmentRetrieveAfterHandler: function(ev)
  332. {
  333. // update windows state in case the widget was maximized before the fragment was loaded
  334. this.iWidget.updateWindowState();
  335. this.iWidget.customUpdate();
  336. },
  337. /*
  338. * Called when "fragment.mode.change' occurs.
  339. * In this method we will switch the fragment div to the edit div if we are goinf into edit mode.
  340. *
  341. * NOTE: Context of function is fragment, use this.iWidget to access this class
  342. */
  343. _fragmentModeChangeHandler: function(ev)
  344. {
  345. try
  346. {
  347. if (ev.payload.newMode == "edit")
  348. {
  349. this.viewDiv = this.div;
  350. this.div = this.id + "edit_content";
  351. var editDiv = $(this.div);
  352. this.iWidget._attachHandlerForIEBeforeUnloadFix(editDiv);
  353. $(this.viewDiv).innerHTML = "";
  354. }
  355. else if (ev.payload.newMode == "view" && ev.payload.currentMode == "edit")
  356. {
  357. this.div = this.viewDiv;
  358. $(this.div).innerHTML = $(this.id + "edit_content").innerHTML;
  359. $(this.id + "edit_content").innerHTML = "";
  360. this.iContext.iEvents.fireEvent("onModeChanged", null, { newMode: "view" });
  361. // at this point customs have not yet been updated, signal copy to be made in "after" handler
  362. this.iWidget.customUpdated = true;
  363. // special builder event to close lotus mashups dialog
  364. // event constant: com.ibm.mm.builder.Topics.Widget_ConfigurationFinished
  365. dojo.publish("/widget/action/finished", [this.iContext.widgetId]);
  366. }
  367. }
  368. catch (e)
  369. {
  370. _F_alert( e)
  371. }
  372. },
  373. /*
  374. * Hook for 'fragment.encodedTransients'
  375. *
  376. * Note: "this" is the fragment object
  377. *
  378. */
  379. fragmentEncodedTransients: function()
  380. {
  381. // assemble everything as url
  382. var s = "";
  383. for (var name in this.transientState)
  384. s += "&" + _F_Strings.urlEncode(name) + "=" + _F_Strings.urlEncode(this.transientState[name]);
  385. // Tell the fragment rewriter the values for the proxied gateway and webcontent
  386. s += "&frag-gateway=" + _F_Strings.urlEncode(_F_Config.gateway) + "&frag-webcontent=" + _F_Strings.urlEncode(_F_Config.webContent);
  387. s += "&bridge-gatewayURL=" + _F_Strings.urlEncode(_F_Config.bridgeGateway) + "&bridge-webContentURL=" + _F_Strings.urlEncode(_F_Config.bridgeWebContent);
  388. return s;
  389. },
  390. /*
  391. * Hook for 'fragment.transientUpdate'
  392. *
  393. * Note: "this" is the fragment object
  394. *
  395. */
  396. fragmentTransientUpdate: function(sName, sValue, sScope, sChannel)
  397. {
  398. this.iContext.iEvents.fireEvent("com.ibm.cognos.cps.transients", "string", sName);
  399. },
  400. fragmentTransientUpdateList: function(list)
  401. {
  402. this.iContext.iEvents.fireEvent("com.ibm.cognos.cps.transients", "string", list);
  403. },
  404. onCognosTransients: function(evt)
  405. {
  406. var list = evt.payload;
  407. if (list && list.length > 0) {
  408. var i, l = list.length;
  409. for (i = 0; i < l; i++) {
  410. this.fragment.transientUpdateCheck(list[i].name, list[i].value, list[i].channel, true);
  411. }
  412. }
  413. },
  414. onWidgetResize: function(evt){
  415. this.isMaximized = evt.payload.maximized;
  416. this.updateWindowState();
  417. },
  418. updateWindowState: function(){
  419. if (this.fragment && this.fragment.loaded){
  420. if (this.fragment.mode == "view"){
  421. if (this.isMaximized){
  422. this.fragment.setWindowState("maximized");
  423. }else{
  424. this.fragment.setWindowState("normal");
  425. }
  426. }
  427. }
  428. }
  429. });
  430. function _IW_removeBeforeUnload(){
  431. if (window.onbeforeunload){
  432. window._IW_onbeforeunloadBackup = window.onbeforeunload;
  433. window.onbeforeunload = null;
  434. setTimeout("window.onbeforeunload = window._IW_onbeforeunloadBackup;", 10);
  435. }
  436. };
  437. function _IW_mouseUpHandler(){
  438. _IW_removeBeforeUnload();
  439. };
  440. function _IW_keyDownHandler(){
  441. if (window.event.keyCode == 13){
  442. _IW_removeBeforeUnload();
  443. }
  444. };
  445. function _IW_keyUpHandler(){
  446. if (window.event.keyCode == 32){
  447. _IW_removeBeforeUnload();
  448. }
  449. };
  450. function arrayIndexOf(arr, value, begin, strict)
  451. {
  452. for (var i = +begin || 0, l = arr.length; i < l; i++)
  453. if (arr[i]===value || strict && arr[i]==value)
  454. return i;
  455. return -1;
  456. };
  457. if (window._IW_runQueue === undefined) {
  458. /**
  459. * _IW_Resource : Resource loading (LINK & SCRIPT)
  460. */
  461. var _IW_Resource =
  462. {
  463. initialized : false,
  464. loaded: new Array(),
  465. loadState: 0,
  466. initialize: function()
  467. {
  468. if (!this.initialized) {
  469. var nodes = document.getElementsByTagName("SCRIPT");
  470. var l = nodes.length;
  471. for (var i = 0; i < l; i++)
  472. {
  473. var attrs = nodes[i].attributes;
  474. for (var j = 0; j < attrs.length; j++)
  475. if (attrs[j].nodeName == "src")
  476. {
  477. this.loaded.push(attrs[j].nodeValue);
  478. break;
  479. }
  480. }
  481. var nodes = document.getElementsByTagName("LINK");
  482. var l = nodes.length;
  483. for (var i = 0; i < l; i++)
  484. {
  485. var attrs = nodes[i].attributes;
  486. for (var j = 0; j < attrs.length; j++)
  487. if (attrs[j].nodeName == "href")
  488. {
  489. this.loaded.push(attrs[j].nodeValue);
  490. break;
  491. }
  492. }
  493. this.initialized = true;
  494. }
  495. },
  496. loadResource: function(tagName, href, arg1)
  497. {
  498. if (arrayIndexOf(this.loaded, href) == -1)
  499. {
  500. var tagName = tagName.toUpperCase();
  501. var head = document.getElementsByTagName('HEAD').item(0);
  502. var node = document.createElement(tagName);
  503. var _self = this;
  504. switch (tagName)
  505. {
  506. case "SCRIPT":
  507. this.loadState++;
  508. node.onload = node.onreadystatechange = function()
  509. {
  510. if (this.readyState && !(this.readyState == 'loaded' || this.readyState == 'complete'))
  511. {
  512. return;
  513. }
  514. if (arrayIndexOf(_self.loaded, href) != -1)
  515. {
  516. return;
  517. }
  518. _self.loaded.push(href);
  519. _self.loadState--;
  520. if (_self.loadState == 0) {
  521. _IW_runQueue.resume();
  522. }
  523. };
  524. node.type = 'text/javascript';
  525. node.src = href;
  526. head.appendChild(node);
  527. break;
  528. case "LINK":
  529. node.type = 'text/css';
  530. node.rel = "stylesheet";
  531. if (arg1 != null && arg1 != "")
  532. node.media = arg1;
  533. node.href = href;
  534. head.appendChild(node);
  535. _self.loaded.push(href);
  536. _IW_runQueue.resume();
  537. break;
  538. default:
  539. _IW_log("unsupported tag named: " + tagName);
  540. break;
  541. }
  542. // indicate to stop the run of the queue
  543. return true;
  544. }
  545. return false;
  546. }
  547. };
  548. //------------------------------------------------------------------------------
  549. // execute a method on an object with arguments
  550. var _IW_Queue =
  551. {
  552. };
  553. _IW_Queue.Runnable = function(obj, func, args)
  554. {
  555. this.obj = obj;
  556. this.func = func;
  557. this.args = args;
  558. };
  559. _IW_Queue.Runnable.prototype =
  560. {
  561. run: function()
  562. {
  563. var stopRun = this.func.apply(this.obj, this.args);
  564. this.func = null;
  565. this.obj = null;
  566. this.args = null;
  567. return stopRun;
  568. }
  569. };
  570. _IW_Queue.Queue = function()
  571. {
  572. this.head = null;
  573. this.tail = null;
  574. };
  575. _IW_Queue.Queue.prototype =
  576. {
  577. add: function(obj)
  578. {
  579. var newEntry =
  580. {
  581. value: obj,
  582. next: null
  583. };
  584. if (this.tail)
  585. this.tail.next = newEntry;
  586. else
  587. this.head = newEntry;
  588. this.tail = newEntry;
  589. },
  590. hasNext: function()
  591. {
  592. return (this.head != null);
  593. },
  594. next: function()
  595. {
  596. var entry = this.head;
  597. var obj = entry.value;
  598. this.head = entry.next;
  599. if (entry.next == null)
  600. this.tail = null;
  601. entry.next = null;
  602. delete (entry);
  603. return obj;
  604. }
  605. };
  606. _IW_Queue.RunQueue = function()
  607. {
  608. this.queue = new _IW_Queue.Queue();
  609. this.isRunning = false;
  610. };
  611. _IW_Queue.RunQueue.prototype =
  612. {
  613. add: function(obj, func, args)
  614. {
  615. var canRun = !this.queue.hasNext();
  616. this.queue.add(new _IW_Queue.Runnable(obj, func, args));
  617. return canRun;
  618. },
  619. run: function()
  620. {
  621. if (!this.isRunning){
  622. this.isRunning = true;
  623. this.resume();
  624. }
  625. },
  626. resume: function()
  627. {
  628. while (this.queue.hasNext())
  629. if (this.queue.next().run()){
  630. break;
  631. }
  632. this.isRunning = this.queue.hasNext();
  633. }
  634. };
  635. window._IW_runQueue = new _IW_Queue.RunQueue();
  636. }