common.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. /* Copyright (c) Business Objects 2006. All rights reserved. */
  2. if (typeof bobj == 'undefined') {
  3. bobj = {};
  4. }
  5. if (typeof bobj.constants == 'undefined') {
  6. bobj.constants = {
  7. modalLayerIndex:1000
  8. };
  9. }
  10. /**
  11. * @return [String] Returns a different id each time it's called
  12. */
  13. bobj.uniqueId = function() {
  14. return 'bobjid_' + (++bobj.uniqueId._count);
  15. };
  16. if (typeof bobj.uniqueId._count == 'undefined') {
  17. bobj.uniqueId._count = new Date().getTime();
  18. }
  19. /**
  20. * Like MochiKit.Base.update except that it checks each item in obj against
  21. * a test function before adding it to self.
  22. *
  23. * @param test [Function] function that returns a boolean when passed (self, obj, key)
  24. * @param self [Object|null] object to be updated
  25. * @param obj [Object] object to copy properties from
  26. */
  27. bobj.updateIf = function (test, self, obj/*, ... */) {
  28. if (self === null) {
  29. self = {};
  30. }
  31. for (var i = 1, len = arguments.length; i < len; i++) {
  32. var o = arguments[i];
  33. if (typeof(o) != 'undefined' && o !== null) {
  34. for (var k in o) {
  35. if (test(self, obj, k)) {
  36. self[k] = o[k];
  37. }
  38. }
  39. }
  40. }
  41. return self;
  42. };
  43. /**
  44. * Copy properties from obj to self if the properties are undefined in self
  45. */
  46. bobj.fillIn = MochiKit.Base.partial(bobj.updateIf, function(self, obj, k) {
  47. return (typeof(self[k]) == 'undefined');
  48. });
  49. bobj.isObject = function(obj) {
  50. return (obj && typeof obj == 'object');
  51. };
  52. bobj.isArray = function(obj) {
  53. return (bobj.isObject(obj) && obj.constructor == Array);
  54. };
  55. bobj.isString = function(obj) {
  56. return (typeof(obj) == 'string');
  57. };
  58. bobj.isNumber = function(obj) {
  59. return typeof(obj) == 'number' && isFinite(obj);
  60. };
  61. bobj.isBoolean = function(obj) {
  62. return typeof obj == 'boolean';
  63. };
  64. bobj.isFunction = function(obj) {
  65. return typeof(obj) == 'function';
  66. };
  67. /**
  68. * Checks for the border box model, where css width includes padding and borders.
  69. * IE uses this box model when a strict dtd is not specified.
  70. *
  71. * @return [boolean] Returns true if the border box model is being used
  72. */
  73. bobj.isBorderBoxModel = function() {
  74. if (typeof bobj.isBorderBoxModel._cachedValue == 'undefined') {
  75. /*
  76. * TODO: It is unnecessary to create DIV to check border box model. All we need to do is check _ie && quirksMode
  77. * I didn't remove it for sake of not breaking different scenarios (requires alot of testing)
  78. */
  79. if(document.body) {
  80. var box = document.createElement('div');
  81. box.style.width = '10px';
  82. box.style.padding = '1px';
  83. box.style.position = 'absolute';
  84. box.style.visibility = 'hidden';
  85. document.body.appendChild(box);
  86. bobj.isBorderBoxModel._cachedValue = (box.offsetWidth == 10);
  87. document.body.removeChild(box);
  88. }
  89. else {
  90. return _ie && bobj.isQuirksMode();
  91. }
  92. }
  93. return bobj.isBorderBoxModel._cachedValue;
  94. };
  95. /**
  96. * @return [boolean] True if the document is rendering in quirks mode
  97. */
  98. bobj.isQuirksMode = function() {
  99. return (document.compatMode != 'CSS1Compat');
  100. };
  101. /* Sets the visual style of the specified element
  102. *
  103. * @param element [DOM node]
  104. * @param visualStyle {} object containing visual styles
  105. */
  106. bobj.setVisualStyle =function(element,visualStyle) {
  107. if(element === null || visualStyle === null) {
  108. return;
  109. }
  110. var elemStyle = element.style;
  111. if(visualStyle.className) {
  112. element.className = visualStyle.className;
  113. }
  114. if(visualStyle.backgroundColor){
  115. elemStyle.backgroundColor = visualStyle.backgroundColor;
  116. }
  117. if(visualStyle.borderWidth){
  118. elemStyle.borderWidth = visualStyle.borderWidth;
  119. }
  120. if(visualStyle.borderStyle){
  121. elemStyle.borderStyle = visualStyle.borderStyle;
  122. }
  123. if(visualStyle.borderColor){
  124. elemStyle.borderColor = visualStyle.borderColor;
  125. }
  126. if(visualStyle.fontFamily) {
  127. elemStyle.fontFamily = visualStyle.fontFamily;
  128. }
  129. if(visualStyle.fontWeight) {
  130. elemStyle.fontWeight = visualStyle.fontWeight;
  131. }
  132. if(visualStyle.textDecoration) {
  133. elemStyle.textDecoration = visualStyle.textDecoration;
  134. }
  135. if(visualStyle.color) {
  136. elemStyle.color = visualStyle.color;
  137. }
  138. if(visualStyle.width) {
  139. elemStyle.width = visualStyle.width;
  140. }
  141. if(visualStyle.height) {
  142. elemStyle.height = visualStyle.height;
  143. }
  144. if(visualStyle.fontStyle) {
  145. elemStyle.fontStyle = visualStyle.fontStyle;
  146. }
  147. if(visualStyle.fontSize) {
  148. elemStyle.fontSize = visualStyle.fontSize;
  149. }
  150. if(visualStyle.left) {
  151. elemStyle.left = visualStyle.left;
  152. }
  153. if(visualStyle.top) {
  154. elemStyle.top = visualStyle.top;
  155. }
  156. };
  157. /**
  158. * Sets the outer size of an element, including padding, borders and margins.
  159. *
  160. * Note: Non-pixel units are ignored
  161. *
  162. * @param node [DOM node]
  163. * @param w [Int - optional] Width in pixels
  164. * @param h [Int - optional] Height in pixels
  165. * @param excludeMargins [bool - optional] When true, margins are not included
  166. * in the box size.
  167. */
  168. bobj.setOuterSize = function(node, w, h, excludeMargins) {
  169. var origStyle = null;
  170. var nodeStyle = node.style;
  171. if (nodeStyle.display == 'none') {
  172. // Nodes have to be displayed to get their calculated styles.
  173. // We display them but make them invisible and absolutely positioned
  174. // so they don't affect the layout.
  175. origStyle = {
  176. visibility: nodeStyle.visibility,
  177. position: nodeStyle.position,
  178. display: 'none'
  179. };
  180. nodeStyle.visibility = 'hidden';
  181. nodeStyle.position = 'absolute';
  182. nodeStyle.display = '';
  183. }
  184. function pixels (selector) {
  185. var value = MochiKit.DOM.getStyle(node, selector);
  186. if (bobj.isString(value) && value.substring(value.length - 2 == 'px')) {
  187. return (parseInt(value, 10) || 0);
  188. }
  189. return 0;
  190. }
  191. if (bobj.isNumber(w)) {
  192. if (!bobj.isBorderBoxModel()) {
  193. w -= pixels('border-left-width');
  194. w -= pixels('border-right-width');
  195. w -= pixels('padding-left');
  196. w -= pixels('padding-right');
  197. if(excludeMargins) {
  198. w -= pixels('margin-left');
  199. w -= pixels('margin-right');
  200. }
  201. }
  202. nodeStyle.width = Math.max(0, w) + 'px';
  203. }
  204. if (bobj.isNumber(h)) {
  205. if (!bobj.isBorderBoxModel()) {
  206. if(excludeMargins) {
  207. h -= pixels('margin-top');
  208. h -= pixels('margin-bottom');
  209. }
  210. h -= pixels('border-top-width');
  211. h -= pixels('border-bottom-width');
  212. h -= pixels('padding-top');
  213. h -= pixels('padding-bottom');
  214. }
  215. nodeStyle.height = Math.max(0, h) + 'px';
  216. }
  217. if (origStyle) {
  218. nodeStyle.display = origStyle.display;
  219. nodeStyle.position = origStyle.position;
  220. nodeStyle.visibility = origStyle.visibility;
  221. }
  222. };
  223. /**
  224. * Place an element with one of it's corners as near (x,y) as possible such that
  225. * the element is within the viewport
  226. *
  227. * @param elt [DOM Node] Element to place
  228. * @param x [int] Absolute horizontal position
  229. * @param y [int] Absolute vertical position
  230. * @param preferLeft [bool] Place left of x if there's enough space
  231. * @param preferTop [bool] Place above y if there's enough space
  232. */
  233. bobj.placeElement = function (elt, x, y, preferLeft, preferTop) {
  234. var eltStyle = elt.style;
  235. var oldVis = eltStyle.visibility || "visible";
  236. eltStyle.visibility = "hidden";
  237. eltStyle.position = "absolute";
  238. var oldDis = eltStyle.display;
  239. eltStyle.display = '';
  240. var eltX = x;
  241. var eltY = y;
  242. var eltW = elt.offsetWidth;
  243. var eltH = elt.offsetHeight;
  244. var wx1 = getScrollX();
  245. var wx2 = getScrollX() + winWidth();
  246. var wy1 = getScrollY();
  247. var wy2 = getScrollY() + winHeight();
  248. var isRightQ;
  249. if (preferLeft && ((x - wx1) > eltW)) { // place left
  250. isRightQ = false;
  251. }
  252. else if ((wx2 - x) > eltW) { // place right
  253. isRightQ = true;
  254. }
  255. else { // place wherever there's more space
  256. isRightQ = (wx2 - x) > (x - wx1);
  257. }
  258. var isBottomQ;
  259. if (preferTop && ((y - wy1) > eltH)) { // place top
  260. isBottomQ = false;
  261. }
  262. else if ((wy2 - y) > eltH) { // place bottom
  263. isBottomQ = true;
  264. }
  265. else { // place wherever there's more space
  266. isBottomQ = (wy2 - y) > (y - wy1);
  267. }
  268. if (!isRightQ) { eltX -= eltW; }
  269. if (!isBottomQ) { eltY -= eltH; }
  270. if ((eltX + eltW) > wx2) {
  271. eltX = wx2 - eltW;
  272. }
  273. if ((eltY + eltH) > wy2) {
  274. eltY = wy2 - eltH;
  275. }
  276. eltX = Math.max(wx1, eltX);
  277. eltY = Math.max(wy1, eltY);
  278. eltStyle.left = eltX + 'px';
  279. eltStyle.top = eltY + 'px';
  280. eltStyle.visibility = oldVis;
  281. eltStyle.display = oldDis;
  282. };
  283. /**
  284. * Get the node that contains a child widget.
  285. *
  286. * @param child [object] the widget whose parent node to be looked for
  287. */
  288. bobj.getContainer = function(child) {
  289. if (child && child.layer) {
  290. return child.layer.parentNode;
  291. }
  292. return null;
  293. };
  294. /**
  295. * Checks whether elem has a parent with the tag name equivalent to parentTagName
  296. *
  297. * @param elem [HTML node] the element whose parent is checked against parentTagName
  298. * @param parentTagName [String] Parent's tagName ie) TABLE
  299. *
  300. *
  301. * @return [boolean] True if elem has a parent with tagName equivalent to parentTagName
  302. */
  303. bobj.checkParent = function(elem,parentTagName) {
  304. var foundParent = false;
  305. if(elem && parentTagName) {
  306. parentTagName = parentTagName.toUpperCase();
  307. var parent = elem.parentNode;
  308. while(parent) {
  309. if(parent.tagName == parentTagName) {
  310. foundParent = true;
  311. break;
  312. }
  313. parent = parent.parentNode;
  314. }
  315. }
  316. return foundParent;
  317. };
  318. /**
  319. * Implements Array.slice for array-like objects. For example, the special
  320. * "arguments" variable within function calls is array-like but doesn't have
  321. * a slice method.
  322. *
  323. * @param arrayLike [Object] An array-like object as defined by MochiKit.Base.isArrayLike.
  324. * @param begin [Number] Zero-based index at which to begin extraction.
  325. * @param end [Number] Zero-based index at which to end extraction.
  326. * Extracts up to but not including end.
  327. *
  328. * @return [Array] A shallow copy of the portion of the array specified or null if invalid argument.
  329. */
  330. bobj.slice = function(arrayLike, begin, end) {
  331. if (bobj.isArray(arrayLike)) {
  332. return arrayLike.slice(begin, end);
  333. }
  334. else if (MochiKit.Base.isArrayLike(arrayLike)) {
  335. var retArray = [];
  336. var endIdx = arrayLike.length;
  337. if (bobj.isNumber(end) && end < endIdx) {
  338. endIdx = end;
  339. }
  340. begin = Math.max(begin, 0);
  341. for (var i = begin; i < endIdx; ++i) {
  342. retArray.push(arrayLike[i]);
  343. }
  344. return retArray;
  345. }
  346. return null;
  347. };
  348. /**
  349. * Extract a range of elements from a string or array-like list (non-destructive)
  350. *
  351. * @param list [String | Array-Like]
  352. * @param start [Int] Index of start, inclusive
  353. * @param end [Int] Index of end, exclusive
  354. *
  355. * @return Array of extracted elements or Null
  356. */
  357. bobj.extractRange = function(list, start, end) {
  358. if (list && bobj.isNumber(start)) {
  359. if (!bobj.isNumber(end) || end > list.length) {
  360. end = list.length;
  361. }
  362. start = Math.max(0, start);
  363. if (start < end) {
  364. var s1 = 0, e1 = start;
  365. var s2 = end, e2 = list.length;
  366. if (list.substring) {
  367. return (list.substring(s1, e1) + list.substring(s2, e2));
  368. }
  369. else {
  370. return bobj.slice(list, s1, e1).concat(bobj.slice(list, s2, e2));
  371. }
  372. }
  373. }
  374. return list;
  375. };
  376. /**
  377. * Returns a value with a unit appended
  378. *
  379. * @param val [int or string]
  380. * @param unit [sring - optional] Defaults to 'px'
  381. *
  382. * @return [string] Returns val as a string with unit appended if val is a
  383. * number. Returns val without modification if val is not a number.
  384. */
  385. bobj.unitValue = function(val, unit) {
  386. if (bobj.isNumber(val)) {
  387. return val + (unit || 'px');
  388. }
  389. return val;
  390. };
  391. /**
  392. * Evaluate an expression in the window (global) scope
  393. *
  394. * @param expression [String] Expression to evaluate
  395. *
  396. * @return Returns the result of the evaluation
  397. */
  398. bobj.evalInWindow = function(expression) {
  399. if (window.execScript) { // Internet Explorer
  400. return window.execScript(expression);
  401. }
  402. else {
  403. return MochiKit.Base.bind(eval, window, expression).call();
  404. }
  405. };
  406. /**
  407. * Remove whitespace from the left end of a string.
  408. *
  409. * @param str [String]
  410. *
  411. * @return [String] Returns a string with no leading whitespace
  412. */
  413. bobj.trimLeft = function(str) {
  414. str = str || '';
  415. return str.replace(/^\s+/g, '');
  416. };
  417. /**
  418. * Remove whitespace from the right end of a string.
  419. *
  420. * @param str [String]
  421. *
  422. * @return [String] Returns a string with no trailing whitespace
  423. */
  424. bobj.trimRight = function(str) {
  425. str = str || '';
  426. return str.replace(/\s+$/g, '');
  427. };
  428. /**
  429. * Remove whitespace from both ends of a string.
  430. *
  431. * @param str [String]
  432. *
  433. * @return [String] Returns a string with no leading or trailing whitespace
  434. */
  435. bobj.trim = function(str) {
  436. return bobj.trimLeft(bobj.trimRight(str));
  437. };
  438. /**
  439. * Check if the two inputs (and their contents) are equal.
  440. *
  441. * @param obj1 [Any]
  442. * @param obj2 [Any]
  443. *
  444. * @return [boolean] Returns true if the two inputs are equal.
  445. */
  446. bobj.equals = function (obj1, obj2) {
  447. if (typeof(obj1) != typeof(obj2)) {
  448. return false;
  449. }
  450. if (bobj.isObject(obj1)) {
  451. var same = true;
  452. for (var prop in obj1) {
  453. same = same && bobj.equals(obj1[prop], obj2[prop]);
  454. }
  455. return same;
  456. }
  457. else {
  458. return obj1 == obj2;
  459. }
  460. };
  461. /**
  462. * Creates a stylesheet link and adds it to document body
  463. * @param1 href [String] location of css file
  464. *
  465. */
  466. bobj.includeLink = function(href) {
  467. var head = document.getElementsByTagName("head")[0];
  468. var body = document.body;
  469. var link = document.createElement("link");
  470. link.setAttribute("rel","stylesheet");
  471. link.setAttribute("type","text/css");
  472. link.setAttribute("href",href);
  473. if(head) {
  474. head.appendChild(link);
  475. }
  476. else if(body) {
  477. body.appendChild(link);
  478. }
  479. };
  480. bobj.addStyleSheet = function(stylesheet,id) {
  481. var style = document.createElement('style');
  482. style.setAttribute("type", "text/css");
  483. if(id) {
  484. style.setAttribute("id", id);
  485. }
  486. if (style.styleSheet) {
  487. style.styleSheet.cssText = stylesheet;
  488. }
  489. else {
  490. style.appendChild(document.createTextNode(stylesheet));
  491. }
  492. var head = document.getElementsByTagName('head');
  493. var body = document.getElementsByTagName('body');
  494. if(head && head[0]) {
  495. head[0].appendChild(style);
  496. }
  497. else if(body && body[0]) {
  498. body[0].appendChild(style);
  499. }
  500. };
  501. bobj.removeAllChildElements = function(elem) {
  502. if(elem) {
  503. while(elem.firstChild) {
  504. bobj.removeAllChildElements(elem.firstChild);
  505. elem.removeChild(elem.firstChild);
  506. }
  507. }
  508. };
  509. bobj.getValueHashCode = function(valueType, value) {
  510. var Types = bobj.crv.params.DataTypes;
  511. switch(valueType) {
  512. case Types.BOOLEAN :
  513. case Types.CURRENCY:
  514. case Types.NUMBER:
  515. case Types.STRING:
  516. return '' + value;
  517. case Types.TIME:
  518. return '' + value.h + ',' + value.min + ',' + value.s + ',' + value.ms;
  519. case Types.DATE:
  520. return '' + value.y + ',' + value.m + ',' + value.d;
  521. case Types.DATE_TIME:
  522. return '' + value.y + ',' +value.m + ',' + value.d + ',' + value.h + ',' + value.min + ',' + value.s + ',' + value.ms;
  523. }
  524. };
  525. bobj.encodeUTF8 = function(string) {
  526. var arr = [];
  527. var strLen = string.length;
  528. for(var i = 0; i < strLen; i++) {
  529. var c = string.charCodeAt(i);
  530. if(c < 0x80) {
  531. arr.push(c);
  532. }
  533. else if(c < 0x0800) {
  534. arr.push((c >> 6) | 0xc0);
  535. arr.push(c & 0x3f | 0x80);
  536. }
  537. else if(c < 0xd800 || c >= 0xe000) {
  538. arr.push((c >> 12) | 0xe0);
  539. arr.push((c >> 6) & 0x3f | 0x80);
  540. arr.push(c & 0x3f | 0x80);
  541. }
  542. else if(c < 0xdc00) {
  543. var c2 = string.charCodeAt(i + 1);
  544. if(isNaN(c2) || c2 < 0xdc00 || c2 >= 0xe000) {
  545. arr.push(0xef, 0xbf, 0xbd);
  546. continue;
  547. }
  548. i++;
  549. val = ((c & 0x3ff) << 10) | (c2 & 0x3ff);
  550. val += 0x10000;
  551. arr.push((val >> 18) | 0xf0);
  552. arr.push((val >> 12) & 0x3f | 0x80);
  553. arr.push((val >> 6) & 0x3f | 0x80);
  554. arr.push(val & 0x3f | 0x80);
  555. }
  556. else {
  557. arr.push(0xef, 0xbf, 0xbd);
  558. }
  559. }
  560. return arr;
  561. };
  562. bobj.encodeBASE64 = function(byteArray) {
  563. var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  564. var arr = [];
  565. var c1, c2, c3, e1, e2, e3, e4;
  566. var i = 0, arrLen = byteArray.length;
  567. while(i < arrLen) {
  568. c1 = byteArray[i++];
  569. c2 = byteArray[i++];
  570. c3 = byteArray[i++];
  571. e1 = c1 >> 2;
  572. e2 = ((c1 & 3) << 4) | (c2 >> 4);
  573. e3 = ((c2 & 15) << 2) | (c3 >> 6);
  574. e4 = c3 & 63;
  575. if (isNaN(c2)) {
  576. e3 = e4 = 64;
  577. } else if(isNaN(c3)) {
  578. e4 = 64;
  579. }
  580. arr.push(keyStr.charAt(e1));
  581. arr.push(keyStr.charAt(e2));
  582. arr.push(keyStr.charAt(e3));
  583. arr.push(keyStr.charAt(e4));
  584. }
  585. return arr.join('');
  586. };
  587. /**
  588. * Checks if there's a DOM element whose ID attribute matches the given string. If not, continue to search for a DOM element
  589. * whose Name attribute matches the given string.
  590. *
  591. * @param idOrName [string] The ID or Name of the element to search for.
  592. * @return [DOM element] Returns a DOM element, or null.
  593. */
  594. bobj.getElementByIdOrName = function (idOrName) {
  595. if (!idOrName) {
  596. return null;
  597. }
  598. var elem = document.getElementById(idOrName);
  599. if (elem) {
  600. return elem;
  601. }
  602. var elems = document.getElementsByName(idOrName);
  603. if (elems && elems.length > 0) {
  604. return elems[0];
  605. }
  606. return null;
  607. };
  608. /*
  609. * Returns a rectangle that can be used for css clip property
  610. * @param top, right, bottom, left [Int]
  611. * @return [String] returns rect(top,right,bottom,left) in pixel unit
  612. */
  613. bobj.getRect = function(top, right, bottom, left) {
  614. return "rect(" + top + "px, "+ right + "px," + bottom + "px," + left + "px)";
  615. }
  616. bobj.getBodyScrollDimension = function() {
  617. var w = 0;
  618. var h = 0;
  619. var bodyTags = document.getElementsByTagName("Body");
  620. if(bodyTags && bodyTags[0]) {
  621. w = bodyTags[0].scrollWidth;
  622. h = bodyTags[0].scrollHeight;
  623. }
  624. return {w : w, h : h};
  625. }