pagelayout.js 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516
  1. // Licensed Materials - Property of IBM
  2. //
  3. // IBM Cognos Products: cpscrn
  4. //
  5. // (C) Copyright IBM Corp. 2005, 2011
  6. //
  7. // US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  8. //
  9. //
  10. // Copyright (C) 2008 Cognos ULC, an IBM Company. All rights reserved.
  11. // Cognos (R) is a trademark of Cognos ULC, (formerly Cognos Incorporated).
  12. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  13. // PageLayout
  14. /*
  15. Classes defined in this files:
  16. CPage - application level API, owns everything
  17. CLayout - holds an object hierachy that represents a layout, serializable in multiple formats
  18. CRow - a simple holder of columns, serializable
  19. CColumn - contain rows or is a valid dropzone for portlets
  20. CZone - hold the portlets for a dropzone column and manages all interactions
  21. CPortlet - represents the portlet properties and proxies for a CPanel
  22. CPanel - handles all interactions with the moveable portlets
  23. */
  24. //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  25. // Utility
  26. function _F_getElementLeft(eElement)
  27. {
  28. var nLeftPos = eElement.offsetLeft; // initialize var to store calculations
  29. var eParElement = eElement.offsetParent; // identify first offset parent element
  30. while (eParElement != null)
  31. { // move up through element hierarchy
  32. nLeftPos += eParElement.offsetLeft - eParElement.scrollLeft; // appending left offset of each parent
  33. eParElement = eParElement.offsetParent; // until no more offset parents exist
  34. }
  35. return nLeftPos; // return the number calculated
  36. }
  37. function _F_getElementTop(eElement)
  38. {
  39. var nTopPos = eElement.offsetTop;
  40. var eParElement = eElement.offsetParent;
  41. while (eParElement != null)
  42. {
  43. nTopPos += eParElement.offsetTop - eParElement.scrollTop;
  44. eParElement = eParElement.offsetParent;
  45. }
  46. return nTopPos;
  47. }
  48. function _F_serializeObject(obj, sName)
  49. {
  50. var s = '';
  51. sName = sName != undefined ? sName : "";
  52. if (typeof(obj) == "object" && sName != "")
  53. {
  54. // create element
  55. s += '<' + sName;
  56. // output attributes
  57. for (var sProp in obj)
  58. if (typeof(obj[sProp]) != "object" && sProp != "_text_")
  59. s += _F_serializeObject(obj[sProp], sProp);
  60. if (typeof(obj[sProp]) == "object" || sProp == "_text_")
  61. {
  62. s += '>';
  63. // output contents
  64. for (var sProp in obj)
  65. if (typeof(obj[sProp]) == "object" || sProp == "_text_")
  66. s += _F_serializeObject(obj[sProp], sProp);
  67. s += '</' + sName + '>';
  68. }
  69. else
  70. s += '/>';
  71. }
  72. else if (typeof(obj) == "object")
  73. {
  74. // output contents
  75. for (var sProp in obj)
  76. s += _F_serializeObject(obj[sProp], sProp);
  77. }
  78. else if (sName == "_text_")
  79. {
  80. // create text node
  81. s += _F_Strings.xmlEncode(obj);
  82. }
  83. else if (sName != "")
  84. {
  85. // create attribute
  86. s += ' ' + sName + '="' + _F_Strings.xmlEncode(obj) + '"';
  87. }
  88. return s;
  89. }
  90. //-------------------------------------------------------------
  91. //-- class CColumn
  92. //- Class CColumn(int width, CRow[] rows)
  93. function CColumn(width, rows)
  94. {
  95. this.parent = null;
  96. this.width = width ? width : "100";
  97. this.rows = rows ? rows : [];
  98. var i, l = this.rows.length;
  99. for (i = 0; i < l; i++)
  100. this.rows[i].parent = this;
  101. this.id = CColumn.prototype.idCount++;
  102. }
  103. CColumn.prototype =
  104. {
  105. idCount: 0,
  106. //- string getBaseId()
  107. getBaseId: function()
  108. {
  109. if (this.parent)
  110. return this.parent.getBaseId();
  111. return "";
  112. },
  113. //- Boolean isLast()
  114. isLast: function()
  115. {
  116. if (!this.parent)
  117. return true;
  118. return this.parent.columns[this.parent.columns.length - 1] === this;
  119. },
  120. //- Object findColumnById(string id)
  121. findColumnById: function(id)
  122. {
  123. if (this.id == id)
  124. return this;
  125. var obj = null;
  126. if (this.rows.length)
  127. {
  128. var i, l = this.rows.length;
  129. for (i = 0; i < l; i++)
  130. {
  131. if (obj = this.rows[i].findColumnById(id))
  132. break;
  133. }
  134. }
  135. return obj;
  136. },
  137. //- void setWidth(int w)
  138. setWidth: function(w)
  139. {
  140. this.width = w;
  141. },
  142. //- void getColumns(CColumn[] columns)
  143. getColumns: function(columns)
  144. {
  145. if (this.rows.length)
  146. for (var i = 0; i < this.rows.length; i++)
  147. this.rows[i].getColumns(columns);
  148. else
  149. columns.push(this);
  150. },
  151. //- HTMLElementImage getSpacer()
  152. getSpacer: function()
  153. {
  154. return $(this.getBaseId() + "zone" + this.id);
  155. },
  156. //- HTMLElementDiv getResizeBar()
  157. getResizeBar: function()
  158. {
  159. return $(this.getBaseId() + "resizebar" + this.id);
  160. },
  161. //- void setSpacerHeight(int h)
  162. setSpacerHeight: function(h)
  163. {
  164. var img = this.getSpacer();
  165. if (img)
  166. img.height = h;
  167. var resizeBar = this.getResizeBar();
  168. if (resizeBar)
  169. xHeight(resizeBar, h);
  170. },
  171. //- HTMLElementDiv getDiv()
  172. getDiv: function()
  173. {
  174. return xParent(this.getSpacer(), true);
  175. },
  176. //- Object getRect()
  177. getRect: function()
  178. {
  179. var div = this.getDiv();
  180. return { left: xPageX(div), top: xPageY(div), width: xWidth(div), height: xHeight(div) };
  181. },
  182. //- Object getGlobalRect()
  183. getGlobalRect: function()
  184. {
  185. var div = this.getDiv();
  186. return { left: _F_getElementLeft(div), top: _F_getElementTop(div), width: xWidth(div), height: xHeight(div) };
  187. },
  188. //- HTMLElementImage getSpacer()
  189. addRow: function(row)
  190. {
  191. this.rows.push(row);
  192. },
  193. // - string render()
  194. render: function()
  195. {
  196. var s = '<td id="' + this.getBaseId() + 'column_' + this.id + '" width="' + this.width + '%" valign="top" align="center">';
  197. if (this.rows.length)
  198. {
  199. s += '<table border="0" cellspacing="0" cellpadding="0" width="100%">';
  200. for (var i = 0; i < this.rows.length; i++)
  201. s += this.rows[i].render();
  202. s += '</table>';
  203. }
  204. else
  205. {
  206. // border:1px solid gray;
  207. s += '<div style="width:100%; background-color: white; border:1px solid silver; background-image: url(' + RESOURCE_URI + '/pagelayout/images/arrow_template.gif); background-position: center center; background-repeat: no-repeat;">';
  208. s += '<img id="' + this.getBaseId() + 'zone' + this.id + '" src="' + RESOURCE_URI + '/pagelayout/images/space.gif" width="1" height="72px">';
  209. s += '</div>';
  210. }
  211. s += '</td>';
  212. if (!this.isLast())
  213. {
  214. s += '<td width="4px" valign="top" align="center"><div id="' + this.getBaseId() + 'resizebar' + this.id + '" baseId="' + this.getBaseId() + '" style="position:relative; width:4px; height:100%; cursor:w-resize;"' +
  215. ' onmousedown="CResizer.mouseDown(event)">';
  216. s += '</div></td>';
  217. }
  218. return s;
  219. },
  220. //- string serialize()
  221. serialize: function()
  222. {
  223. var s = '<column' + (this.width ? ' width="' + this.width + '"' : '') + '>';
  224. if (this.rows.length)
  225. {
  226. for (var i = 0; i < this.rows.length; i++)
  227. s += this.rows[i].serialize();
  228. }
  229. else
  230. s += this.zone.serialize();
  231. s += '</column>';
  232. return s;
  233. }
  234. }
  235. //------------------------------------------------------------
  236. //-- class CRow
  237. //- Class CRow(CColumn[] columns)
  238. function CRow(columns)
  239. {
  240. this.parent = null;
  241. // this.height = "100%";
  242. this.columns = columns ? columns : [];
  243. for (var i = 0; i < this.columns.length; i++)
  244. this.columns[i].parent = this;
  245. }
  246. CRow.prototype =
  247. {
  248. //- string getBaseId()
  249. getBaseId: function()
  250. {
  251. if (this.parent)
  252. return this.parent.getBaseId();
  253. return "";
  254. },
  255. //- Object findColumnById(string id)
  256. findColumnById: function(id)
  257. {
  258. var obj = null;
  259. var i, l = this.columns.length;
  260. for (i = 0; i < l; i++)
  261. {
  262. if (obj = this.columns[i].findColumnById(id))
  263. break;
  264. }
  265. return obj;
  266. },
  267. //- void getColumns(CColumn[] columns)
  268. getColumns: function(columns)
  269. {
  270. for (var i = 0; i < this.columns.length; i++)
  271. this.columns[i].getColumns(columns);
  272. },
  273. //- void addColumn(CColumn column)
  274. addColumn: function(column)
  275. {
  276. this.columns.push(column);
  277. column.parent = this;
  278. },
  279. //- string render()
  280. render: function()
  281. {
  282. var s = '<tr';
  283. if (this.height)
  284. s += ' height="' + this.height + '"';
  285. s += '>';
  286. if (this.columns.length > 1)
  287. {
  288. s += '<td valign="top">';
  289. s += '<table border="0" cellspacing="0" cellpadding="0" width="100%">';
  290. s += '<tr';
  291. if (this.height)
  292. s += ' height="' + this.height + '"';
  293. s += '>';
  294. }
  295. for (var i = 0; i < this.columns.length; i++)
  296. s += this.columns[i].render();
  297. if (this.columns.length > 1)
  298. {
  299. s += '</tr>';
  300. s += '</table>';
  301. s += '</td>';
  302. }
  303. s += '</tr>';
  304. return s;
  305. },
  306. //- string serialize()
  307. serialize: function()
  308. {
  309. var s = '<row' + (this.height ? ' height="' + this.height + '"' : '') + '>';
  310. var i, l = this.columns.length;
  311. for (i = 0; i < l; i++)
  312. s += this.columns[i].serialize();
  313. s += '</row>';
  314. return s;
  315. }
  316. }
  317. //-------------------------------------------------------------
  318. //-- class CLayout
  319. /*
  320. init()
  321. startSelection()
  322. moveSelection(x, y)
  323. endSelection(context)
  324. reflow
  325. hittest
  326. */
  327. //- Class CLayout(CRow[] rows, Object properties)
  328. function CLayout(rows, properties)
  329. {
  330. this.parent = null;
  331. this.properties = properties ? properties : null;
  332. this.rows = rows ? rows : [];
  333. var i, l = this.rows.length;
  334. for (i = 0; i < l; i++)
  335. this.rows[i].parent = this;
  336. }
  337. CLayout.prototype =
  338. {
  339. //- string getBaseId()
  340. getBaseId: function()
  341. {
  342. if (this.parent)
  343. return this.parent.getBaseId();
  344. return "";
  345. },
  346. //- void addRow(CRow row)
  347. addRow: function(row)
  348. {
  349. this.rows.push(row);
  350. row.parent = this;
  351. },
  352. //- string render()
  353. render: function()
  354. {
  355. var s = '<table border="0" cellspacing="0" cellpadding="0" width="100%">';
  356. for (var i = 0; i < this.rows.length; i++)
  357. s += this.rows[i].render();
  358. s += '</table>';
  359. return s;
  360. },
  361. //- void getColumns(CColumn[] columns)
  362. getColumns: function(columns)
  363. {
  364. for (var i = 0; i < this.rows.length; i++)
  365. this.rows[i].getColumns(columns);
  366. },
  367. //- Object findColumnById(string id)
  368. findColumnById: function(id)
  369. {
  370. var obj = null;
  371. var i, l = this.rows.length;
  372. for (i = 0; i < l; i++)
  373. {
  374. if (obj = this.rows[i].findColumnById(id))
  375. break;
  376. }
  377. return obj;
  378. },
  379. //- void setWidth(int w)
  380. setWidth: function(w)
  381. {
  382. },
  383. //- string serialize()
  384. serialize: function()
  385. {
  386. var s = "";
  387. s += '<layout xmlns="" version="1.1">';
  388. s += _F_serializeObject(this.properties);
  389. var i, l = this.rows.length;
  390. for (i = 0; i < l; i++)
  391. s += this.rows[i].serialize();
  392. s += '</layout>';
  393. return s;
  394. }
  395. }
  396. //-------------------------------------------------------------
  397. //-- class CPanel
  398. //- Class Cpanel(string sId)
  399. function CPanel(sId)
  400. {
  401. // Private Properties
  402. this.id = sId;
  403. this.parent = null;
  404. var self = this;
  405. var panel = $(sId + "panel");
  406. var caption = $(sId + "caption");
  407. var closebtn = $(sId + "caption_close");
  408. var editbtn = $(sId + "caption_edit");
  409. var x, y, w, h = false;
  410. //- CPage getPage()
  411. this.getPage = function()
  412. {
  413. return this.parent.getPage();
  414. }
  415. //- string getBaseId()
  416. this.getBaseId = function()
  417. {
  418. return this.getPage().getBaseId();
  419. }
  420. //- HTMLElementDiv getParentDiv()
  421. this.getParentDiv = function()
  422. {
  423. return this.getPage().getParentDiv();
  424. }
  425. // Public Methods
  426. //- void onunload()
  427. this.onunload = function()
  428. {
  429. if (xIE4Up) // clear cir refs
  430. {
  431. xDisableDrag(caption);
  432. }
  433. this.getParentDiv().removeChild(panel);
  434. if (closebtn != null)
  435. closebtn.onclick = null;
  436. self = panel = null;
  437. }
  438. //- void paint()
  439. this.paint = function()
  440. {
  441. if (fragments[sId] && fragments[sId].onresize)
  442. fragments[sId].onresize();
  443. }
  444. //- void position(int x, int y, int width)
  445. this.position = function(x, y, width)
  446. {
  447. var cx = xOffsetLeft(this.getParentDiv());
  448. var cy = xOffsetTop(this.getParentDiv());
  449. xMoveTo(panel, x - cx, y - cy);
  450. var content = $(this.id + "content");
  451. xWidth(content, width - 12);
  452. xWidth(panel, width - 8);
  453. }
  454. //- int getHeight()
  455. this.getHeight = function()
  456. {
  457. return xHeight(panel);
  458. }
  459. //- int getTop()
  460. this.getTop = function()
  461. {
  462. return xPageY(panel);
  463. }
  464. //- int getGlobalTop()
  465. this.getGlobalTop = function()
  466. {
  467. return _F_getElementTop(panel);
  468. }
  469. // Private Event Listeners
  470. var offset = { left: 0, top: 0 };
  471. function panelDragStart(e, x, y)
  472. {
  473. panel.style.backgroundColor="#eeeeee";
  474. panel.style.filter="alpha(opacity=50)";
  475. panel.style.opacity="0.3";
  476. offset.left = x - xLeft(panel);
  477. offset.top = y - xTop(panel);
  478. var div = $( self.getBaseId() + "shadow");
  479. xMoveTo(div, xLeft(panel), xTop(panel));
  480. xResizeTo(div, xWidth(panel), xHeight(panel));
  481. xShow(div);
  482. self.getPage().startSelection(x, y, self.parent);
  483. }
  484. function panelDragMove(e, dx, dy)
  485. {
  486. xMoveTo(panel, e.xDPX - offset.left, e.xDPY - offset.top);
  487. self.getPage().moveSelection(e.xDPX, e.xDPY);
  488. }
  489. function panelDragEnd(e, x, y)
  490. {
  491. panel.style.backgroundColor="";
  492. panel.style.filter="";
  493. panel.style.opacity="";
  494. var div = $(self.getBaseId() + "shadow");
  495. xHide(div);
  496. if (self.getPage().hasSelection())
  497. {
  498. self.getPage().movePortlet(self.parent);
  499. }
  500. else
  501. {
  502. xSlideTo(panel, xLeft(div), xTop(div), 500);
  503. }
  504. self.getPage().endSelection();
  505. }
  506. function panelMousedown()
  507. {
  508. xZIndex(panel, CPanel.z++);
  509. }
  510. // Constructor Code
  511. xZIndex(panel, CPanel.z++);
  512. this.paint();
  513. xEnableDrag(caption, panelDragStart, panelDragMove, panelDragEnd);
  514. panel.onmousedown = panelMousedown;
  515. if (closebtn != null)
  516. closebtn.onclick =
  517. function(evt)
  518. {
  519. if (self.parent)
  520. self.parent.notifyClose(self);
  521. };
  522. xShow(panel);
  523. }
  524. // end Panel object prototype
  525. CPanel.z = 0; // panel static property
  526. function panelMarkup(parentDiv, sId, sTitle, readOnly)
  527. {
  528. var panel = document.createElement("DIV");
  529. panel.className = "cogstyle-portlet-frame";
  530. panel.style.position = "absolute";
  531. panel.id = sId + "panel";
  532. parentDiv.appendChild(panel);
  533. var s =
  534. '<table border="0" cellpadding="0" cellspacing="0" width="100%">' +
  535. '<tr>' +
  536. '<td>' +
  537. '<div id="' + sId + 'caption_bar">' +
  538. '<table class="cogstyle-portlet-caption-bar" border="0" cellpadding="0" cellspacing="0" style="table-layout:fixed;" width="100%">' +
  539. '<tr>' +
  540. '<td id="' + sId + 'caption" class="cogstyle-portlet-caption" style="cursor: move;overflow: hidden;" width="*">' +
  541. '<div id="' + sId + 'F_caption">' +
  542. sTitle +
  543. '</div>' +
  544. '</td>' +
  545. '<td align="right" width="16px">';
  546. if (!readOnly){
  547. s+= '<table class="cogstyle-portlet-actions" border="0" cellpadding="0" cellspacing="0">' +
  548. '<tr>' +
  549. '<td id="' + sId + 'caption_close" align="center" valign="middle" class="cogstyle-portlet-action" onmouseover="caption.prototype.mouseOver(this)" onmouseout="caption.prototype.mouseOut(this)">' +
  550. '<img src="' + RESOURCE_URI + '/portlet/images/portlet_actions_close.gif" border="0" alt="Close" title="Close"/>' +
  551. '</td>' +
  552. '</tr>' +
  553. '</table>';
  554. }
  555. s+= '</td>' +
  556. '</tr>' +
  557. '</table>' +
  558. '</div>' +
  559. '</td>' +
  560. '</tr>' +
  561. '<tr>' +
  562. '<td class="cogstyle-portlet-scroll cogstyle-portlet-content cogstyle-portlet-borders">' +
  563. '<div id="' + sId + 'content" style="overflow:hidden">' +
  564. '<br><br><br>' +
  565. '<center>' +
  566. '<img src="' + RESOURCE_URI + '/pagelayout/images/indicator.gif" border="0" alt="Loading" title="Loading"/>' +
  567. '</center>' +
  568. '<br><br><br>' +
  569. '</div>' +
  570. '</td>' +
  571. '</tr>' +
  572. '</table>';
  573. panel.innerHTML = s;
  574. return panel;
  575. }
  576. //-------------------------------------------------------------
  577. //-- CPortlet Class
  578. /**
  579. retrieve()
  580. position(x, y, w)
  581. getHeight()
  582. getTop()
  583. getGlobalTop()
  584. render()
  585. notifyClose()
  586. destroy()
  587. */
  588. //- Class CPortlet(string sId, string sLayoutId, string sPortletId, string sTitle)
  589. //- Class CPortlet(Object sId)
  590. function CPortlet(sId, sLayoutId, sPortletId, sTitle)
  591. {
  592. this.parent = null;
  593. this.div = null;
  594. this.frag = null;
  595. if (typeof(sId) == 'object')
  596. {
  597. for (var sProp in sId)
  598. this[sProp] = sId[sProp];
  599. }
  600. else
  601. {
  602. this.id = sId;
  603. this.layoutId = sLayoutId ? sLayoutId : "";
  604. this.portletId = sPortletId ? sPortletId : "";
  605. this.title = sTitle ? sTitle : "";
  606. this.isNew = true;
  607. }
  608. }
  609. CPortlet.prototype =
  610. {
  611. //- CPage getPage()
  612. getPage: function()
  613. {
  614. return this.parent.getPage();
  615. },
  616. //- string getBaseId()
  617. getBaseId: function()
  618. {
  619. return this.getPage().getBaseId();
  620. },
  621. //- HTMLElementDiv getParentDiv()
  622. getParentDiv: function()
  623. {
  624. return this.getPage().getParentDiv();
  625. },
  626. //- void init(CZone zone)
  627. init: function(zone)
  628. {
  629. this.parent = zone;
  630. if (!this.div)
  631. {
  632. this.div = panelMarkup(this.getParentDiv(), this.id, this.title, this.getPage().isReadOnly);
  633. this.panel = new CPanel(this.id);
  634. this.panel.parent = this;
  635. }
  636. var page = this.getPage();
  637. if (page != null && page.storeId != null )
  638. if(this.isNew)
  639. this.path = "/cm/" + encodeURIComponent(page.storeId) +"?add=" + encodeURIComponent(this.portletId);
  640. else
  641. this.path = "/cm/" + encodeURIComponent(page.storeId) +"?query=" + encodeURIComponent(this.portletId);
  642. else
  643. this.path = "/cm/" + this.portletId;
  644. this.retrieve();
  645. },
  646. //- void retrieve()
  647. retrieve: function()
  648. {
  649. if (this.frag == null)
  650. {
  651. this.frag = new fragment(this.path, this.id);
  652. this.frag.mode = "preview";
  653. var _self = this;
  654. var _hook = this.frag.oncompleted;
  655. var _frag = this.frag
  656. this.frag.oncompleted = function(bComplete)
  657. {
  658. if (typeof(_hook) == "function")
  659. _hook.call(_frag, bComplete);
  660. _self.panel.paint();
  661. _self.parent.dirty = true;
  662. _self.parent.parent.reflow();
  663. };
  664. this.frag.retrieve();
  665. this.panel.paint();
  666. }
  667. },
  668. //- void position(int x, int y, int w)
  669. position: function(x, y, w)
  670. {
  671. this.panel.position(x, y, w);
  672. },
  673. //- int getHeight()
  674. getHeight: function()
  675. {
  676. return this.panel.getHeight();
  677. },
  678. //- int getTop()
  679. getTop: function()
  680. {
  681. return this.panel.getTop();
  682. },
  683. //- int getGlobalTop()
  684. getGlobalTop: function()
  685. {
  686. return this.panel.getGlobalTop();
  687. },
  688. //- string render()
  689. notifyClose: function(panel)
  690. {
  691. if (this.parent)
  692. this.parent.notifyClose(this);
  693. },
  694. //- string serialize()
  695. serialize: function()
  696. {
  697. var s =
  698. '<cps:portletInstance>' +
  699. '<cps:id>' + this.layoutId + '</cps:id>' +
  700. '<cps:portletId>' + this.portletId + '</cps:portletId>';
  701. if (this.context)
  702. {
  703. s +=
  704. '<wsrp:portletContext>' +
  705. '<wsrp:portletHandle>' + this.context.portletHandle + '</wsrp:portletHandle>' +
  706. '<wsrp:portletState>' + this.context.portletState + '</wsrp:portletState>';
  707. if (this.context.portletType)
  708. {
  709. s +=
  710. '<wsrp:extensions>' +
  711. '<cpsext:info xmlns:cpsext="http://developer.cognos.com/schemas/cps/wsrp/extensions/1/">' +
  712. '<cpsext:type>' + this.context.portletType + '</cpsext:type>' +
  713. '</cpsext:info>' +
  714. '</wsrp:extensions>';
  715. }
  716. s +=
  717. '</wsrp:portletContext>';
  718. }
  719. s +=
  720. '</cps:portletInstance>';
  721. return s;
  722. },
  723. //- void destroy()
  724. destroy: function()
  725. {
  726. this.panel.onunload();
  727. }
  728. }
  729. //-------------------------------------------------------------
  730. // column resize handler singleton
  731. var CResizer =
  732. {
  733. td1: null,
  734. td2: null,
  735. region: null,
  736. range: 0,
  737. min: 0,
  738. max: 0,
  739. baseId: "",
  740. columnId1: "",
  741. columnId2: "",
  742. mouseDown: function(evt)
  743. {
  744. xPreventDefault(evt);
  745. var e = new xEvent(evt);
  746. this.funcMove = function(e) { CResizer.mouseMove(e) };
  747. this.funcUp = function(e) { CResizer.mouseUp(e) };
  748. xAddEventListener(document, "mousemove", this.funcMove, true);
  749. xAddEventListener(document, "mouseup", this.funcUp, true);
  750. var div = e.target;
  751. this.baseId = div.getAttributeNode("baseId").nodeValue;
  752. var parentDiv = $(this.baseId + "content");
  753. var tdSizer = xParent(div, true);
  754. var tr = xParent(tdSizer, true);
  755. var tbody = xParent(tr, true);
  756. var table = xParent(tbody, true);
  757. var td1 = xPrevSib(tdSizer, "TD");
  758. var td2 = xNextSib(tdSizer, "TD");
  759. var sLabel = "column_";
  760. this.columnId1 = td1.id.substring(td1.id.indexOf(sLabel) + sLabel.length);
  761. this.columnId2 = td2.id.substring(td2.id.indexOf(sLabel) + sLabel.length);
  762. var cx = xOffsetLeft(parentDiv);
  763. var cy = xOffsetTop(parentDiv);
  764. var boxX = xPageX(table) - cx;
  765. var boxY = xPageY(table) - cy;
  766. var boxW = xWidth(table);
  767. var boxH = xHeight(table);
  768. var box = $(this.baseId + "resizeBox");
  769. var bar = $(this.baseId + "resizeBar");
  770. var info = $(this.baseId + "resizeInfo");
  771. var infoLeft = $(this.baseId + "resizeLeft");
  772. var infoRight = $(this.baseId + "resizeRight");
  773. xMoveTo(box, boxX, boxY);
  774. xResizeTo(box, boxW, boxH);
  775. var x = xPageX(div) - cx;
  776. var y = (xPageY(div) - cy) + 2;
  777. xMoveTo(bar, x, boxY);
  778. xResizeTo(bar, 4, boxH);
  779. xMoveTo(info, x - 30, Math.max(cy, boxY) + 20);
  780. infoLeft.innerHTML = td1.width;
  781. infoRight.innerHTML = td2.width;
  782. this.td1 = td1;
  783. this.td2 = td2;
  784. this.range = parseInt(td1.width) + parseInt(td2.width);
  785. this.region = { left: xPageX(td1) - cx, width: xWidth(td1) + xWidth(td2) };
  786. var pixelRange = this.region.width * 100 / this.range;
  787. this.min = this.region.left + (pixelRange / 10);
  788. this.max = this.region.left + this.region.width - (pixelRange / 10);
  789. xShow(box);
  790. xShow(bar);
  791. xShow(info);
  792. },
  793. mouseMove: function(evt)
  794. {
  795. xPreventDefault(evt);
  796. var e = new xEvent(evt);
  797. var div = e.target;
  798. var parentDiv = $(this.baseId + "content");
  799. var bar = $(this.baseId + "resizeBar");
  800. var info = $(this.baseId + "resizeInfo");
  801. var infoLeft = $(this.baseId + "resizeLeft");
  802. var infoRight = $(this.baseId + "resizeRight");
  803. var cx = xOffsetLeft(parentDiv) - xScrollLeft(parentDiv);
  804. var x = Math.min(Math.max(e.pageX - cx, this.min), this.max);
  805. var sizeLeft = x - this.region.left;
  806. var sizeRight = this.region.width - sizeLeft;
  807. xLeft(bar, x);
  808. xLeft(info, x - 30);
  809. infoLeft.innerHTML = Math.round(sizeLeft * this.range / this.region.width) + "%";
  810. infoRight.innerHTML = Math.round(sizeRight * this.range / this.region.width) + "%";
  811. },
  812. mouseUp: function(evt)
  813. {
  814. xPreventDefault(evt);
  815. var e = new xEvent(evt);
  816. var parentDiv = $(this.baseId + "content");
  817. xRemoveEventListener(document, "mousemove", this.funcMove, true);
  818. xRemoveEventListener(document, "mouseup", this.funcUp, true);
  819. var x = Math.min(Math.max(e.pageX - xOffsetLeft(parentDiv), this.min), this.max);
  820. var sizeLeft = x - this.region.left;
  821. var sizeRight = this.region.width - sizeLeft;
  822. var W1 = Math.round(sizeLeft * this.range / this.region.width);
  823. var W2 = Math.round(sizeRight * this.range / this.region.width);
  824. this.td1.width = W1 + "%";
  825. this.td2.width = W2 + "%";
  826. var box = $(this.baseId + "resizeBox");
  827. var bar = $(this.baseId + "resizeBar");
  828. var info = $(this.baseId + "resizeInfo");
  829. xHide(box);
  830. xHide(bar);
  831. xHide(info);
  832. this.td1 = null;
  833. this.td2 = null;
  834. var page = eval(this.baseId + "page");
  835. if (page)
  836. {
  837. page.setColumnWidths(this.columnId1, W1, this.columnId2, W2);
  838. page.reflow();
  839. }
  840. }
  841. }
  842. //-------------------------------------------------------------
  843. // CZone Class
  844. /**
  845. setColumn(column)
  846. destroy()
  847. getRect()
  848. hittest(x, y)
  849. insertHittest(x, y)
  850. appendPortlet(portlet)
  851. insertPortlet(index, portlet)
  852. reflow()
  853. notifyClose()
  854. */
  855. //- class CZone(CPortlet[] portlets)
  856. function CZone(portlets)
  857. {
  858. this.parent = null;
  859. this.column = null;
  860. this.portlets = portlets ? portlets : [];
  861. var i, l = this.portlets.length;
  862. for (i = 0; i < l; i++)
  863. this.portlets[i].parent = this;
  864. // reflow logic
  865. this.rows = [];
  866. this.lastRect = { };
  867. this.lastHeight = 0;
  868. this.dirty = true;
  869. }
  870. CZone.prototype =
  871. {
  872. //- void init()
  873. init: function()
  874. {
  875. var i, l = this.portlets.length;
  876. for (i = 0; i < l; i++)
  877. this.portlets[i].init(this);
  878. },
  879. //- void setDirty(Boolean bDirty)
  880. setDirty: function(bDirty)
  881. {
  882. this.dirty = bDirty == undefined ? true : bDirty;
  883. },
  884. // void appendPortlet(portlet)
  885. appendPortlet: function(portlet)
  886. {
  887. this.portlets.push(portlet);
  888. portlet.init(this);
  889. this.setDirty();
  890. this.reflow();
  891. },
  892. //- void insertPortlet(int index, CPortlet portlet)
  893. insertPortlet: function(index, portlet)
  894. {
  895. if (index > -1)
  896. _F_Array.insert(this.portlets, index, portlet);
  897. else
  898. this.portlets.push(portlet);
  899. portlet.init(this);
  900. this.setDirty();
  901. this.reflow();
  902. },
  903. //- void insertPortlet(int index, CPortlet portlet)
  904. removePortlet: function(portlet)
  905. {
  906. _F_Array.remove(this.portlets, portlet);
  907. this.setDirty();
  908. },
  909. //- CPage getPage()
  910. getPage: function()
  911. {
  912. return this.parent;
  913. },
  914. //- string getBaseId()
  915. getBaseId: function()
  916. {
  917. return this.getPage().getBaseId();
  918. },
  919. //- HTMLElementDiv getParentDiv()
  920. getParentDiv: function()
  921. {
  922. return this.getPage().getParentDiv();
  923. },
  924. //- void setBackground(string color)
  925. setBackground: function(color)
  926. {
  927. this.column.getDiv().style.backgroundColor = color;
  928. },
  929. //- void setColumn(CColumn column)
  930. setColumn: function(column)
  931. {
  932. this.column = column;
  933. column.zone = this;
  934. this.lastHeight = 0;
  935. this.setDirty();
  936. },
  937. //- void destroy()
  938. //-- destroy all of the portlets
  939. destroy: function()
  940. {
  941. for (var i = 0; i < this.portlets.length; i++)
  942. this.portlets[i].destroy();
  943. },
  944. //- rect getRect()
  945. getRect: function()
  946. {
  947. return this.column.getRect();
  948. },
  949. //- Boolean hittest(int x, int y)
  950. hittest: function(x, y)
  951. {
  952. var rc = this.column.getGlobalRect();
  953. return (x >= rc.left && x < rc.left + rc.width && y >= rc.top && y < rc.top + rc.height);
  954. },
  955. //- int insertHittest(int y)
  956. insertHittest: function(y)
  957. {
  958. var index = -1;
  959. var closest = 10000000;
  960. var rc = this.column.getGlobalRect();
  961. var top = rc.top;
  962. for (var i = 0; i < this.rows.length; i++)
  963. {
  964. var diff = Math.abs(y - (top + this.rows[i]));
  965. if (diff < closest)
  966. {
  967. closest = diff;
  968. index = i;
  969. }
  970. }
  971. return index;
  972. },
  973. //- void reflow()
  974. reflow: function()
  975. {
  976. var rc = this.column.getRect();
  977. // if dirty or we added portlets or the column rect has changed
  978. if (this.dirty ||
  979. (rc.left != this.lastRect.left || rc.top != this.lastRect.top || rc.width != this.lastRect.width || rc.height != this.lastRect.height))
  980. {
  981. this.lastRect = rc;
  982. if (this.portlets.length)
  983. {
  984. this.rows.length = this.portlets.length + 1;
  985. var i, totalHeight = 0, l = this.portlets.length;
  986. for (i = 0; i < l; i++)
  987. {
  988. this.portlets[i].position(rc.left + 2, rc.top + totalHeight, rc.width - 4);
  989. this.rows[i] = totalHeight;
  990. totalHeight += this.portlets[i].getHeight();
  991. }
  992. this.rows[i] = totalHeight;
  993. }
  994. else
  995. {
  996. this.rows.length = 0;
  997. totalHeight = 72;
  998. }
  999. if (this.lastHeight != totalHeight)
  1000. {
  1001. this.lastHeight = totalHeight;
  1002. this.column.setSpacerHeight(totalHeight);
  1003. this.setDirty();
  1004. }
  1005. else
  1006. this.setDirty(false);
  1007. }
  1008. return this.dirty;
  1009. },
  1010. //- void notifyClose(CPortlet portlet)
  1011. notifyClose: function(portlet)
  1012. {
  1013. // remove portlet
  1014. var oldportlet = this.portlets.remove(portlet);
  1015. portlet.destroy();
  1016. this.setDirty();
  1017. this.reflow();
  1018. // reflow parent
  1019. this.parent.reflow();
  1020. },
  1021. //- string serialize()
  1022. serialize: function()
  1023. {
  1024. var s = "";
  1025. var i, l = this.portlets.length;
  1026. for (i = 0; i < l; i++)
  1027. s += '<portlet id="' + this.portlets[i].layoutId + '"/>';
  1028. return s;
  1029. }
  1030. }
  1031. //-------------------------------------------------------------
  1032. // CPage Class
  1033. /*
  1034. render()
  1035. setLayout(layout)
  1036. getLayout()
  1037. hittest(x, y)
  1038. insertPortlet(portlet)
  1039. movePortlet(portlet)
  1040. selectZone(zone)
  1041. hasSelection()
  1042. startSelection()
  1043. moveSelection(x, y)
  1044. endSelection()
  1045. reflow
  1046. hittest
  1047. */
  1048. //- Class CPage(string baseId, string storeid, HTMLElementDiv parentDiv, CZone[] zones, Object properties)
  1049. function CPage(baseId, storeId, parentDiv, zones, properties)
  1050. {
  1051. this.isReadOnly = false;
  1052. this.baseId = baseId;
  1053. this.parentDiv = $(parentDiv);
  1054. this.layout = null;
  1055. this.storeId = storeId;
  1056. this.zones = zones ? zones : [];
  1057. var i, l = this.zones.length;
  1058. for (i = 0; i < l; i++)
  1059. this.zones[i].parent = this;
  1060. if (properties)
  1061. for (var sProp in properties)
  1062. this[sProp] = properties[sProp];
  1063. this.currentZone = -1;
  1064. this.currentInsert = -1;
  1065. //Reflow the page twice a second. This is allows the layout to deal with portlets whose size changes after the initial retrieve.
  1066. var _self = this;
  1067. this.funcForceReflow = function()
  1068. {
  1069. _self.reflow(true);
  1070. };
  1071. this.reflowTimer = setInterval(this.funcForceReflow, 500);
  1072. }
  1073. CPage.prototype =
  1074. {
  1075. //- string getBaseId()
  1076. getBaseId: function()
  1077. {
  1078. return this.baseId;
  1079. },
  1080. //- HTMLElementDiv getParentDiv()
  1081. getParentDiv: function()
  1082. {
  1083. return this.parentDiv;
  1084. },
  1085. //- void initZones(HTMLElementDiv div, CLayout layout)
  1086. initZones: function(div, layout)
  1087. {
  1088. this.layout = layout;
  1089. layout.parent = this;
  1090. $(div).innerHTML = layout.render();
  1091. columns = [];
  1092. layout.getColumns(columns);
  1093. // bind zone to column
  1094. var i, l = columns.length;
  1095. for (i = 0; i < l; i++)
  1096. this.zones[i].setColumn(columns[i]);
  1097. var i, l = this.zones.length;
  1098. for (i = 0; i < l; i++)
  1099. this.zones[i].init(this);
  1100. this.reflow();
  1101. },
  1102. //- void setLayout(HTMLElementDiv div, CLayout layout)
  1103. setLayout: function(div, layout)
  1104. {
  1105. this.layout = layout;
  1106. layout.parent = this;
  1107. $(div).innerHTML = layout.render();
  1108. columns = [];
  1109. layout.getColumns(columns);
  1110. // if there are more columns than zones, create extra zones
  1111. if (columns.length > this.zones.length)
  1112. {
  1113. for (var i = this.zones.length; i < columns.length; i++)
  1114. {
  1115. var zone = new CZone();
  1116. this.zones.push(zone);
  1117. zone.parent = this;
  1118. }
  1119. }
  1120. // if less, copy portlets to last zone and remove extra zones
  1121. else if (columns.length < this.zones.length)
  1122. {
  1123. var lastZone = this.zones[columns.length - 1];
  1124. var len = this.zones.length;
  1125. for (var i = columns.length; i < len; i++)
  1126. {
  1127. var zone = this.zones.pop();
  1128. for (var j = 0; j < zone.portlets.length; j++)
  1129. {
  1130. var portlet = zone.portlets[j];
  1131. lastZone.portlets.push(portlet);
  1132. portlet.parent = lastZone;
  1133. }
  1134. }
  1135. }
  1136. // bind zone to column
  1137. for (var i = 0; i < columns.length; i++)
  1138. this.zones[i].setColumn(columns[i]);
  1139. this.reflow();
  1140. },
  1141. //- CLayout getLayout()
  1142. getLayout: function()
  1143. {
  1144. return this.layout;
  1145. },
  1146. //- int hittest(int x, int y)
  1147. hittest: function(x, y)
  1148. {
  1149. var cx = xOffsetLeft(this.parentDiv);
  1150. var cy = xOffsetTop(this.parentDiv);
  1151. for (var i = 0; i < this.zones.length; i++)
  1152. if (this.zones[i].hittest(x, y))
  1153. return i;
  1154. return -1;
  1155. },
  1156. //- void insertPortlet(CPortlet portlet)
  1157. insertPortlet: function(portlet)
  1158. {
  1159. if (this.currentZone > -1)
  1160. this.zones[this.currentZone].insertPortlet( this.currentInsert, portlet);
  1161. this.reflow();
  1162. },
  1163. //- void movePortlet(CPortlet portlet)
  1164. movePortlet: function(portlet)
  1165. {
  1166. // requires selection point
  1167. if (this.currentZone == -1)
  1168. return;
  1169. var zoneTo = this.zones[this.currentZone];
  1170. // find portlet's zone and remove it
  1171. var zoneFrom = portlet.parent;
  1172. zoneFrom.removePortlet(portlet);
  1173. // insert portlet at insertion point
  1174. zoneTo.insertPortlet( this.currentInsert, portlet);
  1175. this.reflow();
  1176. },
  1177. //- void reflow(Boolean bForce)
  1178. reflow: function(bForce)
  1179. {
  1180. if (bForce)
  1181. for (var i = 0; i < this.zones.length; i++)
  1182. this.zones[i].setDirty();
  1183. var dirty = false;
  1184. do
  1185. {
  1186. dirty = false;
  1187. for (var i = 0; i < this.zones.length; i++)
  1188. {
  1189. if (dirty = this.zones[i].reflow())
  1190. break;
  1191. }
  1192. }
  1193. while (dirty);
  1194. },
  1195. //- void selectZone(CZone zone, int insert)
  1196. selectedZone: -1,
  1197. selectZone: function(zone, insert)
  1198. {
  1199. var div = $(this.getBaseId() + "selector");
  1200. if (zone > -1)
  1201. {
  1202. var rc = this.zones[zone].getRect();
  1203. var parentDiv = this.getParentDiv();
  1204. var cx = xOffsetLeft(parentDiv);
  1205. var cy = xOffsetTop(parentDiv);
  1206. var top = rc.top;
  1207. if (insert > -1)
  1208. top += this.zones[zone].rows[insert];
  1209. xMoveTo(div, (rc.left + 2) - cx, (top - 2) - cy);
  1210. xResizeTo(div, rc.width - 4, 6);
  1211. xShow(div);
  1212. }
  1213. else
  1214. {
  1215. xHide(div);
  1216. }
  1217. if (this.selectedZone != zone)
  1218. {
  1219. if (this.selectedZone > -1)
  1220. this.zones[this.selectedZone].setBackground("white");
  1221. if (zone > -1)
  1222. this.zones[zone].setBackground("#f0f0f0");
  1223. this.selectedZone = zone;
  1224. }
  1225. },
  1226. //- void startSelection(int x, int y, Cportlet portlet)
  1227. startSelection: function(x, y, portlet)
  1228. {
  1229. clearInterval(this.reflowTimer);
  1230. this.sourceZone = portlet ? _F_Array.indexOf(this.zones, portlet.parent) : -1;
  1231. this.sourceIndex = portlet ? _F_Array.indexOf(this.zones[this.sourceZone].portlets, portlet) : -1;
  1232. this.currentZone = -1;
  1233. },
  1234. //- void moveSelection(int x, int y)
  1235. moveSelection: function(x, y)
  1236. {
  1237. var zone = this.hittest(x, y);
  1238. var insert = -1;
  1239. if (zone > -1)
  1240. insert = this.zones[zone].insertHittest(y);
  1241. if (this.sourceZone != -1 &&
  1242. zone == this.sourceZone &&
  1243. (insert == this.sourceIndex || insert == this.sourceIndex + 1))
  1244. {
  1245. zone = -1;
  1246. }
  1247. if (!this.isReadOnly && (zone != this.currentZone || insert != this.currentInsert))
  1248. {
  1249. this.currentZone = zone;
  1250. this.currentInsert = insert;
  1251. this.selectZone(zone, insert);
  1252. }
  1253. },
  1254. //- void endSelection()
  1255. endSelection: function()
  1256. {
  1257. this.selectZone(-1);
  1258. this.reflowTimer = setInterval(this.funcForceReflow, 500);
  1259. },
  1260. //- void hasSelection()
  1261. hasSelection: function()
  1262. {
  1263. return this.currentZone > -1;
  1264. },
  1265. //- void setColumnWidths(string id1, int w1, string id2, int w2)
  1266. setColumnWidths: function( id1, w1, id2, w2)
  1267. {
  1268. var c1 = this.layout.findColumnById(id1);
  1269. var c2 = this.layout.findColumnById(id2);
  1270. if (c1 && c2)
  1271. {
  1272. c1.setWidth(w1);
  1273. c2.setWidth(w2);
  1274. }
  1275. },
  1276. //- string serialize()
  1277. serialize: function()
  1278. {
  1279. var s =
  1280. '<cps:pagelet xmlns:wsrp="urn:oasis:names:tc:wsrp:v1:types" xmlns:cps="http://developer.cognos.com/schemas/cps/asm/objects/1/">' +
  1281. '<cps:id>' + this.id + '</cps:id>' +
  1282. '<cps:name>' + this.name + '</cps:name>' +
  1283. '<cps:description>' + this.description + '</cps:description>' +
  1284. '<cps:screenTip>' + this.screenTip + '</cps:screenTip>' +
  1285. '<cps:layout>' + this.layout.serialize() + '</cps:layout>';
  1286. var i , l = this.zones.length;
  1287. for (i = 0; i < l; i++)
  1288. {
  1289. var j, lz = this.zones[i].portlets.length;
  1290. for (j = 0; j < lz; j++)
  1291. s += this.zones[i].portlets[j].serialize();
  1292. }
  1293. s += '</cps:pagelet>';
  1294. return s;
  1295. }
  1296. }