PageRenderTime 1873ms CodeModel.GetById 35ms RepoModel.GetById 6ms app.codeStats 1ms

/ShowMeTheBestReply/web-app/js/prototype/rico.js

http://showmethebestreply.googlecode.com/
JavaScript | 2126 lines | 1631 code | 407 blank | 88 comment | 409 complexity | e6adf449993b80da3b5ac357ec379c8e MD5 | raw file
  1. /**
  2. *
  3. * Copyright 2005 Sabre Airline Solutions
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
  6. * file except in compliance with the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software distributed under the
  11. * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  12. * either express or implied. See the License for the specific language governing permissions
  13. * and limitations under the License.
  14. **/
  15. //-------------------- rico.js
  16. var Rico = {
  17. Version: '1.1-beta2'
  18. }
  19. Rico.ArrayExtensions = new Array();
  20. if (Object.prototype.extend) {
  21. // in prototype.js...
  22. Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
  23. }
  24. if (Array.prototype.push) {
  25. // in prototype.js...
  26. Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
  27. }
  28. if (!Array.prototype.remove) {
  29. Array.prototype.remove = function(dx) {
  30. if( isNaN(dx) || dx > this.length )
  31. return false;
  32. for( var i=0,n=0; i<this.length; i++ )
  33. if( i != dx )
  34. this[n++]=this[i];
  35. this.length-=1;
  36. };
  37. Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
  38. }
  39. if (!Array.prototype.removeItem) {
  40. Array.prototype.removeItem = function(item) {
  41. for ( var i = 0 ; i < this.length ; i++ )
  42. if ( this[i] == item ) {
  43. this.remove(i);
  44. break;
  45. }
  46. };
  47. Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
  48. }
  49. if (!Array.prototype.indices) {
  50. Array.prototype.indices = function() {
  51. var indexArray = new Array();
  52. for ( index in this ) {
  53. var ignoreThis = false;
  54. for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
  55. if ( this[index] == Rico.ArrayExtensions[i] ) {
  56. ignoreThis = true;
  57. break;
  58. }
  59. }
  60. if ( !ignoreThis )
  61. indexArray[ indexArray.length ] = index;
  62. }
  63. return indexArray;
  64. }
  65. Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
  66. }
  67. // Create the loadXML method and xml getter for Mozilla
  68. if ( window.DOMParser &&
  69. window.XMLSerializer &&
  70. window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
  71. if (!Document.prototype.loadXML) {
  72. Document.prototype.loadXML = function (s) {
  73. var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
  74. while (this.hasChildNodes())
  75. this.removeChild(this.lastChild);
  76. for (var i = 0; i < doc2.childNodes.length; i++) {
  77. this.appendChild(this.importNode(doc2.childNodes[i], true));
  78. }
  79. };
  80. }
  81. Document.prototype.__defineGetter__( "xml",
  82. function () {
  83. return (new XMLSerializer()).serializeToString(this);
  84. }
  85. );
  86. }
  87. document.getElementsByTagAndClassName = function(tagName, className) {
  88. if ( tagName == null )
  89. tagName = '*';
  90. var children = document.getElementsByTagName(tagName) || document.all;
  91. var elements = new Array();
  92. if ( className == null )
  93. return children;
  94. for (var i = 0; i < children.length; i++) {
  95. var child = children[i];
  96. var classNames = child.className.split(' ');
  97. for (var j = 0; j < classNames.length; j++) {
  98. if (classNames[j] == className) {
  99. elements.push(child);
  100. break;
  101. }
  102. }
  103. }
  104. return elements;
  105. }
  106. //-------------------- ricoAccordion.js
  107. Rico.Accordion = Class.create();
  108. Rico.Accordion.prototype = {
  109. initialize: function(container, options) {
  110. this.container = $(container);
  111. this.lastExpandedTab = null;
  112. this.accordionTabs = new Array();
  113. this.setOptions(options);
  114. this._attachBehaviors();
  115. this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
  116. // set the initial visual state...
  117. for ( var i=1 ; i < this.accordionTabs.length ; i++ )
  118. {
  119. this.accordionTabs[i].collapse();
  120. this.accordionTabs[i].content.style.display = 'none';
  121. }
  122. this.lastExpandedTab = this.accordionTabs[0];
  123. this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
  124. this.lastExpandedTab.showExpanded();
  125. this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
  126. },
  127. setOptions: function(options) {
  128. this.options = {
  129. expandedBg : '#63699c',
  130. hoverBg : '#63699c',
  131. collapsedBg : '#6b79a5',
  132. expandedTextColor : '#ffffff',
  133. expandedFontWeight : 'bold',
  134. hoverTextColor : '#ffffff',
  135. collapsedTextColor : '#ced7ef',
  136. collapsedFontWeight : 'normal',
  137. hoverTextColor : '#ffffff',
  138. borderColor : '#1f669b',
  139. panelHeight : 200,
  140. onHideTab : null,
  141. onShowTab : null
  142. }.extend(options || {});
  143. },
  144. showTabByIndex: function( anIndex, animate ) {
  145. var doAnimate = arguments.length == 1 ? true : animate;
  146. this.showTab( this.accordionTabs[anIndex], doAnimate );
  147. },
  148. showTab: function( accordionTab, animate ) {
  149. var doAnimate = arguments.length == 1 ? true : animate;
  150. if ( this.options.onHideTab )
  151. this.options.onHideTab(this.lastExpandedTab);
  152. this.lastExpandedTab.showCollapsed();
  153. var accordion = this;
  154. var lastExpandedTab = this.lastExpandedTab;
  155. this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
  156. accordionTab.content.style.display = '';
  157. accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
  158. if ( doAnimate ) {
  159. new Effect.AccordionSize( this.lastExpandedTab.content,
  160. accordionTab.content,
  161. 1,
  162. this.options.panelHeight,
  163. 100, 10,
  164. { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
  165. this.lastExpandedTab = accordionTab;
  166. }
  167. else {
  168. this.lastExpandedTab.content.style.height = "1px";
  169. accordionTab.content.style.height = this.options.panelHeight + "px";
  170. this.lastExpandedTab = accordionTab;
  171. this.showTabDone(lastExpandedTab);
  172. }
  173. },
  174. showTabDone: function(collapsedTab) {
  175. collapsedTab.content.style.display = 'none';
  176. this.lastExpandedTab.showExpanded();
  177. if ( this.options.onShowTab )
  178. this.options.onShowTab(this.lastExpandedTab);
  179. },
  180. _attachBehaviors: function() {
  181. var panels = this._getDirectChildrenByTag(this.container, 'DIV');
  182. for ( var i = 0 ; i < panels.length ; i++ ) {
  183. var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
  184. if ( tabChildren.length != 2 )
  185. continue; // unexpected
  186. var tabTitleBar = tabChildren[0];
  187. var tabContentBox = tabChildren[1];
  188. this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
  189. }
  190. },
  191. _getDirectChildrenByTag: function(e, tagName) {
  192. var kids = new Array();
  193. var allKids = e.childNodes;
  194. for( var i = 0 ; i < allKids.length ; i++ )
  195. if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
  196. kids.push(allKids[i]);
  197. return kids;
  198. }
  199. };
  200. Rico.Accordion.Tab = Class.create();
  201. Rico.Accordion.Tab.prototype = {
  202. initialize: function(accordion, titleBar, content) {
  203. this.accordion = accordion;
  204. this.titleBar = titleBar;
  205. this.content = content;
  206. this._attachBehaviors();
  207. },
  208. collapse: function() {
  209. this.showCollapsed();
  210. this.content.style.height = "1px";
  211. },
  212. showCollapsed: function() {
  213. this.expanded = false;
  214. this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
  215. this.titleBar.style.color = this.accordion.options.collapsedTextColor;
  216. this.titleBar.style.fontWeight = this.accordion.options.collapsedFontWeight;
  217. this.content.style.overflow = "hidden";
  218. },
  219. showExpanded: function() {
  220. this.expanded = true;
  221. this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
  222. this.titleBar.style.color = this.accordion.options.expandedTextColor;
  223. this.content.style.overflow = "visible";
  224. },
  225. titleBarClicked: function(e) {
  226. if ( this.accordion.lastExpandedTab == this )
  227. return;
  228. this.accordion.showTab(this);
  229. },
  230. hover: function(e) {
  231. this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
  232. this.titleBar.style.color = this.accordion.options.hoverTextColor;
  233. },
  234. unhover: function(e) {
  235. if ( this.expanded ) {
  236. this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
  237. this.titleBar.style.color = this.accordion.options.expandedTextColor;
  238. }
  239. else {
  240. this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
  241. this.titleBar.style.color = this.accordion.options.collapsedTextColor;
  242. }
  243. },
  244. _attachBehaviors: function() {
  245. this.content.style.border = "1px solid " + this.accordion.options.borderColor;
  246. this.content.style.borderTopWidth = "0px";
  247. this.content.style.borderBottomWidth = "0px";
  248. this.content.style.margin = "0px";
  249. this.titleBar.onclick = this.titleBarClicked.bindAsEventListener(this);
  250. this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
  251. this.titleBar.onmouseout = this.unhover.bindAsEventListener(this);
  252. }
  253. };
  254. //-------------------- ricoAjaxEngine.js
  255. Rico.AjaxEngine = Class.create();
  256. Rico.AjaxEngine.prototype = {
  257. initialize: function() {
  258. this.ajaxElements = new Array();
  259. this.ajaxObjects = new Array();
  260. this.requestURLS = new Array();
  261. },
  262. registerAjaxElement: function( anId, anElement ) {
  263. if ( arguments.length == 1 )
  264. anElement = $(anId);
  265. this.ajaxElements[anId] = anElement;
  266. },
  267. registerAjaxObject: function( anId, anObject ) {
  268. this.ajaxObjects[anId] = anObject;
  269. },
  270. registerRequest: function (requestLogicalName, requestURL) {
  271. this.requestURLS[requestLogicalName] = requestURL;
  272. },
  273. sendRequest: function(requestName) {
  274. var requestURL = this.requestURLS[requestName];
  275. if ( requestURL == null )
  276. return;
  277. var queryString = "";
  278. if ( arguments.length > 1 ) {
  279. if(typeof(arguments[1]) == "object" && arguments[1].length != undefined) {
  280. queryString = this._createQueryString(arguments[1], 0);
  281. }
  282. else {
  283. queryString = this._createQueryString(arguments, 1);
  284. }
  285. }
  286. new Ajax.Request(requestURL, this._requestOptions(queryString));
  287. },
  288. sendRequestWithData: function(requestName, xmlDocument) {
  289. var requestURL = this.requestURLS[requestName];
  290. if ( requestURL == null )
  291. return;
  292. var queryString = "";
  293. if ( arguments.length > 2 ) {
  294. if(typeof(arguments[2]) == "object" && arguments[2].length != undefined) {
  295. queryString = this._createQueryString(arguments[2], 0);
  296. }
  297. else {
  298. queryString = this._createQueryString(arguments, 2);
  299. }
  300. }
  301. new Ajax.Request(requestURL + "?" + queryString, this._requestOptions(null,xmlDocument));
  302. },
  303. sendRequestAndUpdate: function(requestName,container,options) {
  304. var requestURL = this.requestURLS[requestName];
  305. if ( requestURL == null )
  306. return;
  307. var queryString = "";
  308. if ( arguments.length > 3 ) {
  309. if(typeof(arguments[3]) == "object" && arguments[3].length != undefined) {
  310. queryString = this._createQueryString(arguments[3], 0);
  311. }
  312. else {
  313. queryString = this._createQueryString(arguments, 3);
  314. }
  315. }
  316. var updaterOptions = this._requestOptions(queryString);
  317. updaterOptions.onComplete = null;
  318. updaterOptions.extend(options);
  319. new Ajax.Updater(container, requestURL, updaterOptions);
  320. },
  321. sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
  322. var requestURL = this.requestURLS[requestName];
  323. if ( requestURL == null )
  324. return;
  325. var queryString = "";
  326. if ( arguments.length > 4 ) {
  327. if(typeof(arguments[4]) == "object" && arguments[4].length != undefined) {
  328. queryString = this._createQueryString(arguments[4], 0);
  329. }
  330. else {
  331. queryString = this._createQueryString(arguments, 4);
  332. }
  333. }
  334. var updaterOptions = this._requestOptions(queryString,xmlDocument);
  335. updaterOptions.onComplete = null;
  336. updaterOptions.extend(options);
  337. new Ajax.Updater(container, requestURL + "?" + queryString, updaterOptions);
  338. },
  339. // Private -- not part of intended engine API --------------------------------------------------------------------
  340. _requestOptions: function(queryString,xmlDoc) {
  341. var self = this;
  342. var requestHeaders = ['X-Rico-Version', Rico.Version ];
  343. var sendMethod = "post"
  344. if ( arguments[1] )
  345. requestHeaders.push( 'Content-type', 'text/xml' );
  346. else
  347. sendMethod = "get";
  348. return { requestHeaders: requestHeaders,
  349. parameters: queryString,
  350. postBody: arguments[1] ? xmlDoc : null,
  351. method: sendMethod,
  352. onComplete: self._onRequestComplete.bind(self) };
  353. },
  354. _createQueryString: function( theArgs, offset ) {
  355. var self = this;
  356. var queryString = ""
  357. for ( var i = offset ; i < theArgs.length ; i++ ) {
  358. if ( i != offset )
  359. queryString += "&";
  360. var anArg = theArgs[i];
  361. if ( anArg.name != undefined && anArg.value != undefined ) {
  362. queryString += anArg.name + "=" + escape(anArg.value);
  363. }
  364. else {
  365. var ePos = anArg.indexOf('=');
  366. var argName = anArg.substring( 0, ePos );
  367. var argValue = anArg.substring( ePos + 1 );
  368. queryString += argName + "=" + escape(argValue);
  369. }
  370. }
  371. return queryString;
  372. },
  373. _onRequestComplete : function(request) {
  374. //!!TODO: error handling infrastructure??
  375. if (request.status != 200)
  376. return;
  377. var response = request.responseXML.getElementsByTagName("ajax-response");
  378. if (response == null || response.length != 1)
  379. return;
  380. this._processAjaxResponse( response[0].childNodes );
  381. },
  382. _processAjaxResponse: function( xmlResponseElements ) {
  383. for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
  384. var responseElement = xmlResponseElements[i];
  385. // only process nodes of type element.....
  386. if ( responseElement.nodeType != 1 )
  387. continue;
  388. var responseType = responseElement.getAttribute("type");
  389. var responseId = responseElement.getAttribute("id");
  390. if ( responseType == "object" )
  391. this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
  392. else if ( responseType == "element" )
  393. this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
  394. else
  395. alert('unrecognized AjaxResponse type : ' + responseType );
  396. }
  397. },
  398. _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
  399. ajaxObject.ajaxUpdate( responseElement );
  400. },
  401. _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
  402. ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
  403. }
  404. }
  405. var ajaxEngine = new Rico.AjaxEngine();
  406. //-------------------- ricoColor.js
  407. Rico.Color = Class.create();
  408. Rico.Color.prototype = {
  409. initialize: function(red, green, blue) {
  410. this.rgb = { r: red, g : green, b : blue };
  411. },
  412. setRed: function(r) {
  413. this.rgb.r = r;
  414. },
  415. setGreen: function(g) {
  416. this.rgb.g = g;
  417. },
  418. setBlue: function(b) {
  419. this.rgb.b = b;
  420. },
  421. setHue: function(h) {
  422. // get an HSB model, and set the new hue...
  423. var hsb = this.asHSB();
  424. hsb.h = h;
  425. // convert back to RGB...
  426. this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
  427. },
  428. setSaturation: function(s) {
  429. // get an HSB model, and set the new hue...
  430. var hsb = this.asHSB();
  431. hsb.s = s;
  432. // convert back to RGB and set values...
  433. this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
  434. },
  435. setBrightness: function(b) {
  436. // get an HSB model, and set the new hue...
  437. var hsb = this.asHSB();
  438. hsb.b = b;
  439. // convert back to RGB and set values...
  440. this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
  441. },
  442. darken: function(percent) {
  443. var hsb = this.asHSB();
  444. this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
  445. },
  446. brighten: function(percent) {
  447. var hsb = this.asHSB();
  448. this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
  449. },
  450. blend: function(other) {
  451. this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
  452. this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
  453. this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
  454. },
  455. isBright: function() {
  456. var hsb = this.asHSB();
  457. return this.asHSB().b > 0.5;
  458. },
  459. isDark: function() {
  460. return ! this.isBright();
  461. },
  462. asRGB: function() {
  463. return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
  464. },
  465. asHex: function() {
  466. return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
  467. },
  468. asHSB: function() {
  469. return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
  470. },
  471. toString: function() {
  472. return this.asHex();
  473. }
  474. };
  475. Rico.Color.createFromHex = function(hexCode) {
  476. if ( hexCode.indexOf('#') == 0 )
  477. hexCode = hexCode.substring(1);
  478. var red = hexCode.substring(0,2);
  479. var green = hexCode.substring(2,4);
  480. var blue = hexCode.substring(4,6);
  481. return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
  482. }
  483. /**
  484. * Factory method for creating a color from the background of
  485. * an HTML element.
  486. */
  487. Rico.Color.createColorFromBackground = function(elem) {
  488. var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");
  489. if ( actualColor == "transparent" && elem.parent )
  490. return Rico.Color.createColorFromBackground(elem.parent);
  491. if ( actualColor == null )
  492. return new Rico.Color(255,255,255);
  493. if ( actualColor.indexOf("rgb(") == 0 ) {
  494. var colors = actualColor.substring(4, actualColor.length - 1 );
  495. var colorArray = colors.split(",");
  496. return new Rico.Color( parseInt( colorArray[0] ),
  497. parseInt( colorArray[1] ),
  498. parseInt( colorArray[2] ) );
  499. }
  500. else if ( actualColor.indexOf("#") == 0 ) {
  501. var redPart = parseInt(actualColor.substring(1,3), 16);
  502. var greenPart = parseInt(actualColor.substring(3,5), 16);
  503. var bluePart = parseInt(actualColor.substring(5), 16);
  504. return new Rico.Color( redPart, greenPart, bluePart );
  505. }
  506. else
  507. return new Rico.Color(255,255,255);
  508. }
  509. Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
  510. var red = 0;
  511. var green = 0;
  512. var blue = 0;
  513. if (saturation == 0) {
  514. red = parseInt(brightness * 255.0 + 0.5);
  515. green = red;
  516. blue = red;
  517. }
  518. else {
  519. var h = (hue - Math.floor(hue)) * 6.0;
  520. var f = h - Math.floor(h);
  521. var p = brightness * (1.0 - saturation);
  522. var q = brightness * (1.0 - saturation * f);
  523. var t = brightness * (1.0 - (saturation * (1.0 - f)));
  524. switch (parseInt(h)) {
  525. case 0:
  526. red = (brightness * 255.0 + 0.5);
  527. green = (t * 255.0 + 0.5);
  528. blue = (p * 255.0 + 0.5);
  529. break;
  530. case 1:
  531. red = (q * 255.0 + 0.5);
  532. green = (brightness * 255.0 + 0.5);
  533. blue = (p * 255.0 + 0.5);
  534. break;
  535. case 2:
  536. red = (p * 255.0 + 0.5);
  537. green = (brightness * 255.0 + 0.5);
  538. blue = (t * 255.0 + 0.5);
  539. break;
  540. case 3:
  541. red = (p * 255.0 + 0.5);
  542. green = (q * 255.0 + 0.5);
  543. blue = (brightness * 255.0 + 0.5);
  544. break;
  545. case 4:
  546. red = (t * 255.0 + 0.5);
  547. green = (p * 255.0 + 0.5);
  548. blue = (brightness * 255.0 + 0.5);
  549. break;
  550. case 5:
  551. red = (brightness * 255.0 + 0.5);
  552. green = (p * 255.0 + 0.5);
  553. blue = (q * 255.0 + 0.5);
  554. break;
  555. }
  556. }
  557. return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
  558. }
  559. Rico.Color.RGBtoHSB = function(r, g, b) {
  560. var hue;
  561. var saturaton;
  562. var brightness;
  563. var cmax = (r > g) ? r : g;
  564. if (b > cmax)
  565. cmax = b;
  566. var cmin = (r < g) ? r : g;
  567. if (b < cmin)
  568. cmin = b;
  569. brightness = cmax / 255.0;
  570. if (cmax != 0)
  571. saturation = (cmax - cmin)/cmax;
  572. else
  573. saturation = 0;
  574. if (saturation == 0)
  575. hue = 0;
  576. else {
  577. var redc = (cmax - r)/(cmax - cmin);
  578. var greenc = (cmax - g)/(cmax - cmin);
  579. var bluec = (cmax - b)/(cmax - cmin);
  580. if (r == cmax)
  581. hue = bluec - greenc;
  582. else if (g == cmax)
  583. hue = 2.0 + redc - bluec;
  584. else
  585. hue = 4.0 + greenc - redc;
  586. hue = hue / 6.0;
  587. if (hue < 0)
  588. hue = hue + 1.0;
  589. }
  590. return { h : hue, s : saturation, b : brightness };
  591. }
  592. //-------------------- ricoCorner.js
  593. Rico.Corner = {
  594. round: function(e, options) {
  595. var e = $(e);
  596. this._setOptions(options);
  597. var color = this.options.color;
  598. if ( this.options.color == "fromElement" )
  599. color = this._background(e);
  600. var bgColor = this.options.bgColor;
  601. if ( this.options.bgColor == "fromParent" )
  602. bgColor = this._background(e.offsetParent);
  603. this._roundCornersImpl(e, color, bgColor);
  604. },
  605. _roundCornersImpl: function(e, color, bgColor) {
  606. if(this.options.border)
  607. this._renderBorder(e,bgColor);
  608. if(this._isTopRounded())
  609. this._roundTopCorners(e,color,bgColor);
  610. if(this._isBottomRounded())
  611. this._roundBottomCorners(e,color,bgColor);
  612. },
  613. _renderBorder: function(el,bgColor) {
  614. var borderValue = "1px solid " + this._borderColor(bgColor);
  615. var borderL = "border-left: " + borderValue;
  616. var borderR = "border-right: " + borderValue;
  617. var style = "style='" + borderL + ";" + borderR + "'";
  618. el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
  619. },
  620. _roundTopCorners: function(el, color, bgColor) {
  621. var corner = this._createCorner(bgColor);
  622. for(var i=0 ; i < this.options.numSlices ; i++ )
  623. corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
  624. el.style.paddingTop = 0;
  625. el.insertBefore(corner,el.firstChild);
  626. },
  627. _roundBottomCorners: function(el, color, bgColor) {
  628. var corner = this._createCorner(bgColor);
  629. for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
  630. corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
  631. el.style.paddingBottom = 0;
  632. el.appendChild(corner);
  633. },
  634. _createCorner: function(bgColor) {
  635. var corner = document.createElement("div");
  636. corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
  637. return corner;
  638. },
  639. _createCornerSlice: function(color,bgColor, n, position) {
  640. var slice = document.createElement("span");
  641. var inStyle = slice.style;
  642. inStyle.backgroundColor = color;
  643. inStyle.display = "block";
  644. inStyle.height = "1px";
  645. inStyle.overflow = "hidden";
  646. inStyle.fontSize = "1px";
  647. var borderColor = this._borderColor(color,bgColor);
  648. if ( this.options.border && n == 0 ) {
  649. inStyle.borderTopStyle = "solid";
  650. inStyle.borderTopWidth = "1px";
  651. inStyle.borderLeftWidth = "0px";
  652. inStyle.borderRightWidth = "0px";
  653. inStyle.borderBottomWidth = "0px";
  654. inStyle.height = "0px"; // assumes css compliant box model
  655. inStyle.borderColor = borderColor;
  656. }
  657. else if(borderColor) {
  658. inStyle.borderColor = borderColor;
  659. inStyle.borderStyle = "solid";
  660. inStyle.borderWidth = "0px 1px";
  661. }
  662. if ( !this.options.compact && (n == (this.options.numSlices-1)) )
  663. inStyle.height = "2px";
  664. this._setMargin(slice, n, position);
  665. this._setBorder(slice, n, position);
  666. return slice;
  667. },
  668. _setOptions: function(options) {
  669. this.options = {
  670. corners : "all",
  671. color : "fromElement",
  672. bgColor : "fromParent",
  673. blend : true,
  674. border : false,
  675. compact : false
  676. }.extend(options || {});
  677. this.options.numSlices = this.options.compact ? 2 : 4;
  678. if ( this._isTransparent() )
  679. this.options.blend = false;
  680. },
  681. _whichSideTop: function() {
  682. if ( this._hasString(this.options.corners, "all", "top") )
  683. return "";
  684. if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
  685. return "";
  686. if (this.options.corners.indexOf("tl") >= 0)
  687. return "left";
  688. else if (this.options.corners.indexOf("tr") >= 0)
  689. return "right";
  690. return "";
  691. },
  692. _whichSideBottom: function() {
  693. if ( this._hasString(this.options.corners, "all", "bottom") )
  694. return "";
  695. if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
  696. return "";
  697. if(this.options.corners.indexOf("bl") >=0)
  698. return "left";
  699. else if(this.options.corners.indexOf("br")>=0)
  700. return "right";
  701. return "";
  702. },
  703. _borderColor : function(color,bgColor) {
  704. if ( color == "transparent" )
  705. return bgColor;
  706. else if ( this.options.border )
  707. return this.options.border;
  708. else if ( this.options.blend )
  709. return this._blend( bgColor, color );
  710. else
  711. return "";
  712. },
  713. _setMargin: function(el, n, corners) {
  714. var marginSize = this._marginSize(n);
  715. var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
  716. if ( whichSide == "left" ) {
  717. el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
  718. }
  719. else if ( whichSide == "right" ) {
  720. el.style.marginRight = marginSize + "px"; el.style.marginLeft = "0px";
  721. }
  722. else {
  723. el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
  724. }
  725. },
  726. _setBorder: function(el,n,corners) {
  727. var borderSize = this._borderSize(n);
  728. var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
  729. if ( whichSide == "left" ) {
  730. el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
  731. }
  732. else if ( whichSide == "right" ) {
  733. el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth = "0px";
  734. }
  735. else {
  736. el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
  737. }
  738. },
  739. _marginSize: function(n) {
  740. if ( this._isTransparent() )
  741. return 0;
  742. var marginSizes = [ 5, 3, 2, 1 ];
  743. var blendedMarginSizes = [ 3, 2, 1, 0 ];
  744. var compactMarginSizes = [ 2, 1 ];
  745. var smBlendedMarginSizes = [ 1, 0 ];
  746. if ( this.options.compact && this.options.blend )
  747. return smBlendedMarginSizes[n];
  748. else if ( this.options.compact )
  749. return compactMarginSizes[n];
  750. else if ( this.options.blend )
  751. return blendedMarginSizes[n];
  752. else
  753. return marginSizes[n];
  754. },
  755. _borderSize: function(n) {
  756. var transparentBorderSizes = [ 5, 3, 2, 1 ];
  757. var blendedBorderSizes = [ 2, 1, 1, 1 ];
  758. var compactBorderSizes = [ 1, 0 ];
  759. var actualBorderSizes = [ 0, 2, 0, 0 ];
  760. if ( this.options.compact && (this.options.blend || this._isTransparent()) )
  761. return 1;
  762. else if ( this.options.compact )
  763. return compactBorderSizes[n];
  764. else if ( this.options.blend )
  765. return blendedBorderSizes[n];
  766. else if ( this.options.border )
  767. return actualBorderSizes[n];
  768. else if ( this._isTransparent() )
  769. return transparentBorderSizes[n];
  770. return 0;
  771. },
  772. _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
  773. _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
  774. _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
  775. _isTransparent: function() { return this.options.color == "transparent"; },
  776. _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
  777. _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
  778. _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
  779. }
  780. //-------------------- ricoDragAndDrop.js
  781. Rico.DragAndDrop = Class.create();
  782. Rico.DragAndDrop.prototype = {
  783. initialize: function() {
  784. this.dropZones = new Array();
  785. this.draggables = new Array();
  786. this.currentDragObjects = new Array();
  787. this.dragElement = null;
  788. this.lastSelectedDraggable = null;
  789. this.currentDragObjectVisible = false;
  790. this.interestedInMotionEvents = false;
  791. },
  792. registerDropZone: function(aDropZone) {
  793. this.dropZones[ this.dropZones.length ] = aDropZone;
  794. },
  795. deregisterDropZone: function(aDropZone) {
  796. var newDropZones = new Array();
  797. var j = 0;
  798. for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
  799. if ( this.dropZones[i] != aDropZone )
  800. newDropZones[j++] = this.dropZones[i];
  801. }
  802. this.dropZones = newDropZones;
  803. },
  804. clearDropZones: function() {
  805. this.dropZones = new Array();
  806. },
  807. registerDraggable: function( aDraggable ) {
  808. this.draggables[ this.draggables.length ] = aDraggable;
  809. this._addMouseDownHandler( aDraggable );
  810. },
  811. clearSelection: function() {
  812. for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
  813. this.currentDragObjects[i].deselect();
  814. this.currentDragObjects = new Array();
  815. this.lastSelectedDraggable = null;
  816. },
  817. hasSelection: function() {
  818. return this.currentDragObjects.length > 0;
  819. },
  820. setStartDragFromElement: function( e, mouseDownElement ) {
  821. this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
  822. this.startx = e.screenX - this.origPos.x
  823. this.starty = e.screenY - this.origPos.y
  824. //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
  825. //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
  826. //this.adjustedForDraggableSize = false;
  827. this.interestedInMotionEvents = this.hasSelection();
  828. this._terminateEvent(e);
  829. },
  830. updateSelection: function( draggable, extendSelection ) {
  831. if ( ! extendSelection )
  832. this.clearSelection();
  833. if ( draggable.isSelected() ) {
  834. this.currentDragObjects.removeItem(draggable);
  835. draggable.deselect();
  836. if ( draggable == this.lastSelectedDraggable )
  837. this.lastSelectedDraggable = null;
  838. }
  839. else {
  840. this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
  841. draggable.select();
  842. this.lastSelectedDraggable = draggable;
  843. }
  844. },
  845. _mouseDownHandler: function(e) {
  846. if ( arguments.length == 0 )
  847. e = event;
  848. // if not button 1 ignore it...
  849. var nsEvent = e.which != undefined;
  850. if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
  851. return;
  852. var eventTarget = e.target ? e.target : e.srcElement;
  853. var draggableObject = eventTarget.draggable;
  854. var candidate = eventTarget;
  855. while (draggableObject == null && candidate.parentNode) {
  856. candidate = candidate.parentNode;
  857. draggableObject = candidate.draggable;
  858. }
  859. if ( draggableObject == null )
  860. return;
  861. this.updateSelection( draggableObject, e.ctrlKey );
  862. // clear the drop zones postion cache...
  863. if ( this.hasSelection() )
  864. for ( var i = 0 ; i < this.dropZones.length ; i++ )
  865. this.dropZones[i].clearPositionCache();
  866. this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
  867. },
  868. _mouseMoveHandler: function(e) {
  869. var nsEvent = e.which != undefined;
  870. if ( !this.interestedInMotionEvents ) {
  871. this._terminateEvent(e);
  872. return;
  873. }
  874. if ( ! this.hasSelection() )
  875. return;
  876. if ( ! this.currentDragObjectVisible )
  877. this._startDrag(e);
  878. if ( !this.activatedDropZones )
  879. this._activateRegisteredDropZones();
  880. //if ( !this.adjustedForDraggableSize )
  881. // this._adjustForDraggableSize(e);
  882. this._updateDraggableLocation(e);
  883. this._updateDropZonesHover(e);
  884. this._terminateEvent(e);
  885. },
  886. _makeDraggableObjectVisible: function(e)
  887. {
  888. if ( !this.hasSelection() )
  889. return;
  890. var dragElement;
  891. if ( this.currentDragObjects.length > 1 )
  892. dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
  893. else
  894. dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
  895. // go ahead and absolute position it...
  896. if ( RicoUtil.getElementsComputedStyle(dragElement, "position") != "absolute" )
  897. dragElement.style.position = "absolute";
  898. // need to parent him into the document...
  899. if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
  900. document.body.appendChild(dragElement);
  901. this.dragElement = dragElement;
  902. this._updateDraggableLocation(e);
  903. this.currentDragObjectVisible = true;
  904. },
  905. /**
  906. _adjustForDraggableSize: function(e) {
  907. var dragElementWidth = this.dragElement.offsetWidth;
  908. var dragElementHeight = this.dragElement.offsetHeight;
  909. if ( this.startComponentX > dragElementWidth )
  910. this.startx -= this.startComponentX - dragElementWidth + 2;
  911. if ( e.offsetY ) {
  912. if ( this.startComponentY > dragElementHeight )
  913. this.starty -= this.startComponentY - dragElementHeight + 2;
  914. }
  915. this.adjustedForDraggableSize = true;
  916. },
  917. **/
  918. _updateDraggableLocation: function(e) {
  919. var dragObjectStyle = this.dragElement.style;
  920. dragObjectStyle.left = (e.screenX - this.startx) + "px"
  921. dragObjectStyle.top = (e.screenY - this.starty) + "px";
  922. },
  923. _updateDropZonesHover: function(e) {
  924. var n = this.dropZones.length;
  925. for ( var i = 0 ; i < n ; i++ ) {
  926. if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
  927. this.dropZones[i].hideHover();
  928. }
  929. for ( var i = 0 ; i < n ; i++ ) {
  930. if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
  931. if ( this.dropZones[i].canAccept(this.currentDragObjects) )
  932. this.dropZones[i].showHover();
  933. }
  934. }
  935. },
  936. _startDrag: function(e) {
  937. for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
  938. this.currentDragObjects[i].startDrag();
  939. this._makeDraggableObjectVisible(e);
  940. },
  941. _mouseUpHandler: function(e) {
  942. if ( ! this.hasSelection() )
  943. return;
  944. var nsEvent = e.which != undefined;
  945. if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
  946. return;
  947. this.interestedInMotionEvents = false;
  948. if ( this.dragElement == null ) {
  949. this._terminateEvent(e);
  950. return;
  951. }
  952. if ( this._placeDraggableInDropZone(e) )
  953. this._completeDropOperation(e);
  954. else {
  955. this._terminateEvent(e);
  956. new Effect.Position( this.dragElement,
  957. this.origPos.x,
  958. this.origPos.y,
  959. 200,
  960. 20,
  961. { complete : this._doCancelDragProcessing.bind(this) } );
  962. }
  963. },
  964. _completeDropOperation: function(e) {
  965. if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
  966. if ( this.dragElement.parentNode != null )
  967. this.dragElement.parentNode.removeChild(this.dragElement);
  968. }
  969. this._deactivateRegisteredDropZones();
  970. this._endDrag();
  971. this.clearSelection();
  972. this.dragElement = null;
  973. this.currentDragObjectVisible = false;
  974. this._terminateEvent(e);
  975. },
  976. _doCancelDragProcessing: function() {
  977. this._cancelDrag();
  978. if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
  979. if ( this.dragElement.parentNode != null ) {
  980. this.dragElement.parentNode.removeChild(this.dragElement);
  981. }
  982. }
  983. this._deactivateRegisteredDropZones();
  984. this.dragElement = null;
  985. this.currentDragObjectVisible = false;
  986. },
  987. _placeDraggableInDropZone: function(e) {
  988. var foundDropZone = false;
  989. var n = this.dropZones.length;
  990. for ( var i = 0 ; i < n ; i++ ) {
  991. if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
  992. if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
  993. this.dropZones[i].hideHover();
  994. this.dropZones[i].accept(this.currentDragObjects);
  995. foundDropZone = true;
  996. break;
  997. }
  998. }
  999. }
  1000. return foundDropZone;
  1001. },
  1002. _cancelDrag: function() {
  1003. for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
  1004. this.currentDragObjects[i].cancelDrag();
  1005. },
  1006. _endDrag: function() {
  1007. for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
  1008. this.currentDragObjects[i].endDrag();
  1009. },
  1010. _mousePointInDropZone: function( e, dropZone ) {
  1011. var absoluteRect = dropZone.getAbsoluteRect();
  1012. return e.clientX > absoluteRect.left &&
  1013. e.clientX < absoluteRect.right &&
  1014. e.clientY > absoluteRect.top &&
  1015. e.clientY < absoluteRect.bottom;
  1016. },
  1017. _addMouseDownHandler: function( aDraggable )
  1018. {
  1019. var htmlElement = aDraggable.getMouseDownHTMLElement();
  1020. if ( htmlElement != null ) {
  1021. htmlElement.draggable = aDraggable;
  1022. this._addMouseDownEvent( htmlElement );
  1023. }
  1024. },
  1025. _activateRegisteredDropZones: function() {
  1026. var n = this.dropZones.length;
  1027. for ( var i = 0 ; i < n ; i++ ) {
  1028. var dropZone = this.dropZones[i];
  1029. if ( dropZone.canAccept(this.currentDragObjects) )
  1030. dropZone.activate();
  1031. }
  1032. this.activatedDropZones = true;
  1033. },
  1034. _deactivateRegisteredDropZones: function() {
  1035. var n = this.dropZones.length;
  1036. for ( var i = 0 ; i < n ; i++ )
  1037. this.dropZones[i].deactivate();
  1038. this.activatedDropZones = false;
  1039. },
  1040. _addMouseDownEvent: function( htmlElement ) {
  1041. if ( typeof document.implementation != "undefined" &&
  1042. document.implementation.hasFeature("HTML", "1.0") &&
  1043. document.implementation.hasFeature("Events", "2.0") &&
  1044. document.implementation.hasFeature("CSS", "2.0") ) {
  1045. htmlElement.addEventListener("mousedown", this._mouseDownHandler.bindAsEventListener(this), false);
  1046. }
  1047. else {
  1048. htmlElement.attachEvent( "onmousedown", this._mouseDownHandler.bindAsEventListener(this) );
  1049. }
  1050. },
  1051. _terminateEvent: function(e) {
  1052. if ( e.stopPropagation != undefined )
  1053. e.stopPropagation();
  1054. else if ( e.cancelBubble != undefined )
  1055. e.cancelBubble = true;
  1056. if ( e.preventDefault != undefined )
  1057. e.preventDefault();
  1058. else
  1059. e.returnValue = false;
  1060. },
  1061. initializeEventHandlers: function() {
  1062. if ( typeof document.implementation != "undefined" &&
  1063. document.implementation.hasFeature("HTML", "1.0") &&
  1064. document.implementation.hasFeature("Events", "2.0") &&
  1065. document.implementation.hasFeature("CSS", "2.0") ) {
  1066. document.addEventListener("mouseup", this._mouseUpHandler.bindAsEventListener(this), false);
  1067. document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
  1068. }
  1069. else {
  1070. document.attachEvent( "onmouseup", this._mouseUpHandler.bindAsEventListener(this) );
  1071. document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
  1072. }
  1073. }
  1074. }
  1075. //var dndMgr = new Rico.DragAndDrop();
  1076. //dndMgr.initializeEventHandlers();
  1077. //-------------------- ricoDraggable.js
  1078. Rico.Draggable = Class.create();
  1079. Rico.Draggable.prototype = {
  1080. initialize: function( type, htmlElement ) {
  1081. this.type = type;
  1082. this.htmlElement = $(htmlElement);
  1083. this.selected = false;
  1084. },
  1085. /**
  1086. * Returns the HTML element that should have a mouse down event
  1087. * added to it in order to initiate a drag operation
  1088. *
  1089. **/
  1090. getMouseDownHTMLElement: function() {
  1091. return this.htmlElement;
  1092. },
  1093. select: function() {
  1094. this.selected = true;
  1095. if ( this.showingSelected )
  1096. return;
  1097. var htmlElement = this.getMouseDownHTMLElement();
  1098. var color = Rico.Color.createColorFromBackground(htmlElement);
  1099. color.isBright() ? color.darken(0.033) : color.brighten(0.033);
  1100. this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
  1101. htmlElement.style.backgroundColor = color.asHex();
  1102. this.showingSelected = true;
  1103. },
  1104. deselect: function() {
  1105. this.selected = false;
  1106. if ( !this.showingSelected )
  1107. return;
  1108. var htmlElement = this.getMouseDownHTMLElement();
  1109. htmlElement.style.backgroundColor = this.saveBackground;
  1110. this.showingSelected = false;
  1111. },
  1112. isSelected: function() {
  1113. return this.selected;
  1114. },
  1115. startDrag: function() {
  1116. },
  1117. cancelDrag: function() {
  1118. },
  1119. endDrag: function() {
  1120. },
  1121. getSingleObjectDragGUI: function() {
  1122. return this.htmlElement;
  1123. },
  1124. getMultiObjectDragGUI: function( draggables ) {
  1125. return this.htmlElement;
  1126. },
  1127. getDroppedGUI: function() {
  1128. return this.htmlElement;
  1129. },
  1130. toString: function() {
  1131. return this.type + ":" + this.htmlElement + ":";
  1132. }
  1133. }
  1134. //-------------------- ricoDropzone.js
  1135. Rico.Dropzone = Class.create();
  1136. Rico.Dropzone.prototype = {
  1137. initialize: function( htmlElement ) {
  1138. this.htmlElement = $(htmlElement);
  1139. this.absoluteRect = null;
  1140. },
  1141. getHTMLElement: function() {
  1142. return this.htmlElement;
  1143. },
  1144. clearPositionCache: function() {
  1145. this.absoluteRect = null;
  1146. },
  1147. getAbsoluteRect: function() {
  1148. if ( this.absoluteRect == null ) {
  1149. var htmlElement = this.getHTMLElement();
  1150. var pos = RicoUtil.toViewportPosition(htmlElement);
  1151. this.absoluteRect = {
  1152. top: pos.y,
  1153. left: pos.x,
  1154. bottom: pos.y + htmlElement.offsetHeight,
  1155. right: pos.x + htmlElement.offsetWidth
  1156. };
  1157. }
  1158. return this.absoluteRect;
  1159. },
  1160. activate: function() {
  1161. var htmlElement = this.getHTMLElement();
  1162. if (htmlElement == null || this.showingActive)
  1163. return;
  1164. this.showingActive = true;
  1165. this.saveBackgroundColor = htmlElement.style.backgroundColor;
  1166. var fallbackColor = "#ffea84";
  1167. var currentColor = Rico.Color.createColorFromBackground(htmlElement);
  1168. if ( currentColor == null )
  1169. htmlElement.style.backgroundColor = fallbackColor;
  1170. else {
  1171. currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
  1172. htmlElement.style.backgroundColor = currentColor.asHex();
  1173. }
  1174. },
  1175. deactivate: function() {
  1176. var htmlElement = this.getHTMLElement();
  1177. if (htmlElement == null || !this.showingActive)
  1178. return;
  1179. htmlElement.style.backgroundColor = this.saveBackgroundColor;
  1180. this.showingActive = false;
  1181. this.saveBackgroundColor = null;
  1182. },
  1183. showHover: function() {
  1184. var htmlElement = this.getHTMLElement();
  1185. if ( htmlElement == null || this.showingHover )
  1186. return;
  1187. this.saveBorderWidth = htmlElement.style.borderWidth;
  1188. this.saveBorderStyle = htmlElement.style.borderStyle;
  1189. this.saveBorderColor = htmlElement.style.borderColor;
  1190. this.showingHover = true;
  1191. htmlElement.style.borderWidth = "1px";
  1192. htmlElement.style.borderStyle = "solid";
  1193. //htmlElement.style.borderColor = "#ff9900";
  1194. htmlElement.style.borderColor = "#ffff00";
  1195. },
  1196. hideHover: function() {
  1197. var htmlElement = this.getHTMLElement();
  1198. if ( htmlElement == null || !this.showingHover )
  1199. return;
  1200. htmlElement.style.borderWidth = this.saveBorderWidth;
  1201. htmlElement.style.borderStyle = this.saveBorderStyle;
  1202. htmlElement.style.borderColor = this.saveBorderColor;
  1203. this.showingHover = false;
  1204. },
  1205. canAccept: function(draggableObjects) {
  1206. return true;
  1207. },
  1208. accept: function(draggableObjects) {
  1209. var htmlElement = this.getHTMLElement();
  1210. if ( htmlElement == null )
  1211. return;
  1212. n = draggableObjects.length;
  1213. for ( var i = 0 ; i < n ; i++ )
  1214. {
  1215. var theGUI = draggableObjects[i].getDroppedGUI();
  1216. if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
  1217. {
  1218. theGUI.style.position = "static";
  1219. theGUI.style.top = "";
  1220. theGUI.style.top = "";
  1221. }
  1222. htmlElement.appendChild(theGUI);
  1223. }
  1224. }
  1225. }
  1226. //-------------------- ricoEffects.js
  1227. /**
  1228. * Use the Effect namespace for effects. If using scriptaculous effects
  1229. * this will already be defined, otherwise we'll just create an empty
  1230. * object for it...
  1231. **/
  1232. if ( window.Effect == undefined )
  1233. Effect = {};
  1234. Effect.SizeAndPosition = Class.create();
  1235. Effect.SizeAndPosition.prototype = {
  1236. initialize: function(element, x, y, w, h, duration, steps, options) {
  1237. this.element = $(element);
  1238. this.x = x;
  1239. this.y = y;
  1240. this.w = w;
  1241. this.h = h;
  1242. this.duration = duration;
  1243. this.steps = steps;
  1244. this.options = arguments[7] || {};
  1245. this.sizeAndPosition();
  1246. },
  1247. sizeAndPosition: function() {
  1248. if (this.isFinished()) {
  1249. if(this.options.complete) this.options.complete(this);
  1250. return;
  1251. }
  1252. if (this.timer)
  1253. clearTimeout(this.timer);
  1254. var stepDuration = Math.round(this.duration/this.steps) ;
  1255. // Get original values: x,y = top left corner; w,h = width height
  1256. var currentX = this.element.offsetLeft;
  1257. var currentY = this.element.offsetTop;
  1258. var currentW = this.element.offsetWidth;
  1259. var currentH = this.element.offsetHeight;
  1260. // If values not set, or zero, we do not modify them, and take original as final as well
  1261. this.x = (this.x) ? this.x : currentX;
  1262. this.y = (this.y) ? this.y : currentY;
  1263. this.w = (this.w) ? this.w : currentW;
  1264. this.h = (this.h) ? this.h : currentH;
  1265. // how much do we need to modify our values for each step?
  1266. var difX = this.steps > 0 ? (this.x - currentX)/this.steps : 0;
  1267. var difY = this.steps > 0 ? (this.y - currentY)/this.steps : 0;
  1268. var difW = this.steps > 0 ? (this.w - currentW)/this.steps : 0;
  1269. var difH = this.steps > 0 ? (this.h - currentH)/this.steps : 0;
  1270. this.moveBy(difX, difY);
  1271. this.resizeBy(difW, difH);
  1272. this.duration -= stepDuration;
  1273. this.steps--;
  1274. this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
  1275. },
  1276. isFinished: function() {
  1277. return this.steps <= 0;
  1278. },
  1279. moveBy: function( difX, difY ) {
  1280. var currentLeft = this.element.offsetLeft;
  1281. var currentTop = this.element.offsetTop;
  1282. var intDifX = parseInt(difX);
  1283. var intDifY = parseInt(difY);
  1284. var style = this.element.style;
  1285. if ( intDifX != 0 )
  1286. style.left = (currentLeft + intDifX) + "px";
  1287. if ( intDifY != 0 )
  1288. style.top = (currentTop + intDifY) + "px";
  1289. },
  1290. resizeBy: function( difW, difH ) {
  1291. var currentWidth = this.element.offsetWidth;
  1292. var currentHeight = this.element.offsetHeight;
  1293. var intDifW = parseInt(difW);
  1294. var intDifH = parseInt(difH);
  1295. var style = this.element.style;
  1296. if ( intDifW != 0 )
  1297. style.width = (currentWidth + intDifW) + "px";
  1298. if ( intDifH != 0 )
  1299. style.height = (currentHeight + intDifH) + "px";
  1300. }
  1301. }
  1302. Effect.Size = Class.create();
  1303. Effect.Size.prototype = {
  1304. initialize: function(element, w, h, duration, steps, options) {
  1305. new Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
  1306. }
  1307. }
  1308. Effect.Position = Class.create();
  1309. Effect.Position.prototype = {
  1310. initialize: function(element, x, y, duration, steps, options) {
  1311. new Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
  1312. }
  1313. }
  1314. Effect.Round = Class.create();
  1315. Effect.Round.prototype = {
  1316. initialize: function(tagName, className, options) {
  1317. var elements = document.getElementsByTagAndClassName(tagName,className);
  1318. for ( var i = 0 ; i < elements.length ; i++ )
  1319. Rico.Corner.round( elements[i], options );
  1320. }
  1321. };
  1322. Effect.FadeTo = Class.create();
  1323. Effect.FadeTo.prototype = {
  1324. initialize: function( element, opacity, duration, steps, options) {
  1325. this.element = $(element);
  1326. this.opacity = opacity;
  1327. this.duration = duration;
  1328. this.steps = steps;
  1329. this.options = arguments[4] || {};
  1330. this.fadeTo();
  1331. },
  1332. fadeTo: function() {
  1333. if (this.isFinished()) {
  1334. if(this.options.complete) this.options.complete(this);
  1335. return;
  1336. }
  1337. if (this.timer)
  1338. clearTimeout(this.timer);
  1339. var stepDuration = Math.round(this.duration/this.steps) ;
  1340. var currentOpacity = this.getElementOpacity();
  1341. var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
  1342. this.changeOpacityBy(delta);
  1343. this.duration -= stepDuration;
  1344. this.steps--;
  1345. this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
  1346. },
  1347. changeOpacityBy: function(v) {
  1348. var currentOpacity = this.getElementOpacity();
  1349. var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
  1350. this.element.ricoOpacity = newOpacity;
  1351. this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
  1352. this.element.style.opacity = newOpacity; /*//*/;
  1353. },
  1354. isFinished: function() {
  1355. return this.steps <= 0;
  1356. },
  1357. getElementOpacity: function() {
  1358. if ( this.element.ricoOpacity == undefined ) {
  1359. var opacity;
  1360. if ( this.element.currentStyle ) {
  1361. opacity = this.element.currentStyle.opacity;
  1362. }
  1363. else if ( document.defaultView.getComputedStyle != undefined ) {
  1364. var computedStyle = document.defaultView.getComputedStyle;
  1365. opacity = computedStyle(this.element, null).getPropertyValue('opacity');
  1366. }
  1367. this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
  1368. }
  1369. return parseFloat(this.element.ricoOpacity);
  1370. }
  1371. }
  1372. Effect.AccordionSize = Class.create();
  1373. Effect.AccordionSize.prototype = {
  1374. initialize: function(e1, e2, start, end, duration, steps, options) {
  1375. this.e1 = $(e1);
  1376. this.e2 = $(e2);
  1377. this.start = start;
  1378. this.end = end;
  1379. this.duration = duration;
  1380. this.steps = steps;
  1381. this.options = arguments[6] || {};
  1382. this.accordionSize();
  1383. },
  1384. accordionSize: function() {
  1385. if (this.isFinished()) {
  1386. // just in case there are round errors or such...
  1387. this.e1.style.height = this.start + "px";
  1388. this.e2.style.height = this.end + "px";
  1389. if(this.options.complete)
  1390. this.options.complete(this);
  1391. return;
  1392. }
  1393. if (this.timer)
  1394. clearTimeout(this.timer);
  1395. var stepDuration = Math.round(this.duration/this.steps) ;
  1396. var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
  1397. this.resizeBy(diff);
  1398. this.duration -= stepDuration;
  1399. this.steps--;
  1400. this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
  1401. },
  1402. isFinished: function() {
  1403. return this.steps <= 0;
  1404. },
  1405. resizeBy: function(diff) {
  1406. var h1Height = this.e1.offsetHeight;
  1407. var h2Height = this.e2.offsetHeight;
  1408. var intDiff = parseInt(diff);
  1409. if ( diff != 0 ) {
  1410. this.e1.style.height = (h1Height - intDiff) + "px";
  1411. this.e2.style.height = (h2Height + intDiff) + "px";
  1412. }
  1413. }
  1414. };
  1415. //-------------------- ricoLiveGrid.js
  1416. // Rico.LiveGridMetaData -----------------------------------------------------
  1417. Rico.LiveGridMetaData = Class.create();
  1418. Rico.LiveGridMetaData.prototype = {
  1419. initialize: function( pageSize, totalRows, columnCount, options ) {
  1420. this.pageSize = pageSize;
  1421. this.totalRows = totalRows;
  1422. this.setOptions(options);
  1423. this.scrollArrowHeight = 16;
  1424. this.columnCount = columnCount;
  1425. },
  1426. setOptions: function(options) {
  1427. this.options = {
  1428. largeBufferSize : 7.0, // 7 pages
  1429. nearLimitFactor : 0.2 // 20% of buffer
  1430. }.extend(options || {});
  1431. },
  1432. getPageSize: function() {
  1433. return this.pageSize;
  1434. },
  1435. getTotalRows: function() {
  1436. return this.totalRows;
  1437. },
  1438. setTotalRows: function(n) {
  1439. this.totalRows = n;
  1440. },
  1441. getLargeBufferSize: function() {
  1442. return parseInt(this.options.largeBufferSize * this.pageSize);
  1443. },
  1444. getLimitTolerance: function() {
  1445. return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
  1446. }
  1447. };
  1448. // Rico.LiveGridScroller -----------------------------------------------------
  1449. Rico.LiveGridScroller = Class.create();
  1450. Rico.LiveGridScroller.prototype = {
  1451. initialize: function(liveGrid, viewPort) {
  1452. this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
  1453. this.liveGrid = liveGrid;
  1454. this.metaData = liveGrid.metaData;
  1455. this.createScrollBar();
  1456. this.scrollTimeout = null;
  1457. this.lastScrollPos = 0;
  1458. this.viewPort = viewPort;
  1459. this.rows = new Array();
  1460. },
  1461. isUnPlugged: function() {
  1462. return this.scrollerDiv.onscroll == null;
  1463. },
  1464. plugin: function() {
  1465. this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
  1466. },
  1467. unplug: function() {
  1468. this.scrollerDiv.onscroll = null;
  1469. },
  1470. sizeIEHeaderHack: function() {
  1471. if ( !this.isIE ) return;
  1472. var headerTable = $(this.liveGrid.tableId + "_header");
  1473. if ( headerTable )
  1474. headerTable.rows[0].cells[0].style.width =
  1475. (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
  1476. },
  1477. createScrollBar: function() {
  1478. var visibleHeight = this.liveGrid.viewPort.visibleHeight();
  1479. // create the outer div...
  1480. this.scrollerDiv = document.createElement("div");
  1481. var scrollerStyle = this.scrollerDiv.style;
  1482. scrollerStyle.borderRight = "1px solid #ababab"; // hard coded color!!!
  1483. scrollerStyle.position = "relative";
  1484. scrollerStyle.left = this.isIE ? "-6px" : "-3px";
  1485. scrollerStyle.width = "19px";
  1486. scrollerStyle.height = visibleHeight + "px";
  1487. scrollerStyle.overflow = "auto";
  1488. // create the inner div...
  1489. this.heightDiv = document.createElement("div");
  1490. this.heightDiv.style.width = "1px";
  1491. this.heightDiv.style.height = parseInt(visibleHeight *
  1492. this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
  1493. this.scrollerDiv.appendChild(this.heightDiv);
  1494. this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
  1495. var table = this.liveGrid.table;
  1496. table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
  1497. },
  1498. updateSize: function() {
  1499. var table = this.liveGrid.table;
  1500. var visibleHeight = this.viewPort.visibleHeight();
  1501. this.heightDiv.style.height = parseInt(visibleHeight *
  1502. this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
  1503. },
  1504. rowToPixel: function(rowOffset) {
  1505. return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
  1506. },
  1507. moveScroll: function(rowOffset) {
  1508. this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
  1509. if ( this.metaData.options.onscroll )
  1510. this.metaData.options.onscroll( this.liveGrid, rowOffset );
  1511. },
  1512. handleScroll: function() {
  1513. if ( this.scrollTimeout )
  1514. clearTimeout( this.scrollTimeout );
  1515. var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
  1516. this.liveGrid.requestContentRefresh(contentOffset);
  1517. this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
  1518. if ( this.metaData.options.onscroll )
  1519. this.metaData.options.onscroll( this.liveGrid, contentOffset );
  1520. this.scrollTimeout = setTimeout( this.scrollIdle.bind(this), 1200 );
  1521. },
  1522. scrollIdle: function() {
  1523. if ( this.metaData.options.onscrollidle )
  1524. this.metaData.options.onscrollidle();
  1525. }
  1526. };
  1527. // Rico.LiveGridBuffer -----------------------------------------------------
  1528. Rico.LiveGridBuffer = Class.create();
  1529. Rico.LiveGridBuffer.prototype = {
  1530. initialize: function(metaData, viewPort) {
  1531. this.startPos = 0;
  1532. this.size = 0;
  1533. this.metaData = metaData;
  1534. this.rows = new Array();
  1535. this.updateInProgress = false;
  1536. this.viewPort = viewPort;
  1537. this.maxBufferSize = metaData.getLargeBufferSize() * 2;
  1538. this.maxFetchSize = metaData.getLargeBufferSize();
  1539. this.lastOffset = 0;
  1540. },
  1541. getBlankRow: function() {
  1542. if (!this.blankRow ) {
  1543. this.blankRow = new Array();
  1544. for ( var i=0; i < this.metaData.columnCount ; i++ )
  1545. this.blankRow[i] = "&nbsp;";
  1546. }
  1547. return this.blankRow;
  1548. },
  1549. loadRows: function(ajaxResponse) {
  1550. var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
  1551. this.updateUI = rowsElement.getAttribute("update_ui") == "true"
  1552. var newRows = new Array()
  1553. var trs = rowsElement.getElementsByTagName("tr");
  1554. for ( var i=0 ; i < trs.length; i++ ) {
  1555. var row = newRows[i] = new Array();
  1556. var cells = trs[i].getElementsByTagName("td");
  1557. for ( var j=0; j < cells.length ; j++ ) {
  1558. var cell = cells[j];
  1559. var convertSpaces = cell.getAttribute("convert_spaces") == "true";
  1560. var cellContent = RicoUtil.getContentAsString(cell);
  1561. row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
  1562. if (!row[j])
  1563. row[j] = '&nbsp;';
  1564. }
  1565. }
  1566. return newRows;
  1567. },
  1568. update: function(ajaxResponse, start) {
  1569. var newRows = this.loadRows(ajaxResponse);
  1570. if (this.rows.length == 0) { // initial load
  1571. this.rows = newRows;
  1572. this.size = this.rows.length;
  1573. this.startPos = start;
  1574. return;
  1575. }
  1576. if (start > this.startPos) { //appending
  1577. if (this.startPos + this.rows.length < start) {
  1578. this.rows = newRows;
  1579. this.startPos = start;//
  1580. } else {
  1581. this.rows = this.rows.concat( newRows.slice(0, newRows.length));
  1582. if (this.rows.length > this.maxBufferSize) {
  1583. var fullSize = this.rows.length;
  1584. this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
  1585. this.startPos = this.startPos + (fullSize - this.rows.length);
  1586. }
  1587. }
  1588. } else { //prepending
  1589. if (start + newRows.length < this.startPos) {
  1590. this.rows = newRows;
  1591. } else {
  1592. this.rows = newRows.slice(0, this.startPos).concat(this.rows);
  1593. if (this.rows.length > this.maxBufferSize)
  1594. this.rows = this.rows.slice(0, this.maxBufferSize)
  1595. }
  1596. this.startPos = start;
  1597. }
  1598. this.size = this.rows.length;
  1599. },
  1600. clear: function() {
  1601. this.rows = new Array();
  1602. this.startPos = 0;
  1603. this.size = 0;
  1604. },
  1605. isOverlapping: function(start, size) {
  1606. return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
  1607. },
  1608. isInRange: function(position) {
  1609. return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos());
  1610. //&& this.size() != 0;
  1611. },
  1612. isNearingTopLimit: function(position) {
  1613. return position - this.startPos < this.metaData.getLimitTolerance();
  1614. },
  1615. endPos: function() {
  1616. return this.startPos + this.rows.length;
  1617. },
  1618. isNearingBottomLimit: function(position) {
  1619. return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
  1620. },
  1621. isAtTop: function() {
  1622. return this.startPos == 0;
  1623. },
  1624. isAtBottom: function() {
  1625. return this.endPos() == this.metaData.getTotalRows();
  1626. },
  1627. isNearingLimit: function(position) {
  1628. return ( !this.isAtTop() && this.isNearingTopLimit(position)) ||
  1629. ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
  1630. },
  1631. getFetchSize: function(offset) {
  1632. var adjustedOffset = this.getFetchOffset(offset);
  1633. var adjustedSize = 0;
  1634. if (adjustedOffset >= this.startPos) { //apending
  1635. var endFetchOffset = this.maxFetchSize + adjustedOffset;
  1636. if (endFetchOffset > this.metaData.totalRows)
  1637. endFetchOffset = this.metaData.totalRows;
  1638. adjustedSize = endFetchOffset - adjustedOffset;
  1639. } else {//prepending
  1640. var adjustedSize = this.startPos - adjustedOffset;
  1641. if (adjustedSize > this.maxFetchSize)
  1642. adjustedSize = this.maxFetchSize;
  1643. }
  1644. return adjustedSize;
  1645. },
  1646. getFetchOffset: function(offset) {
  1647. var adjustedOffset = offset;
  1648. if (offset > this.startPos) //apending
  1649. adjustedOffset = (offset > this.endPos()) ? offset : this.endPos();
  1650. else { //prepending
  1651. if (offset + this.maxFetchSize >= this.startPos) {
  1652. var adjustedOffset = this.startPos - this.maxFetchSize;
  1653. if (adjustedOffset < 0)
  1654. adjustedOffset = 0;
  1655. }
  1656. }
  1657. this.lastOffset = adjustedOffset;
  1658. return adjustedOffset;
  1659. },
  1660. getRows: function(start, count) {
  1661. var begPos = start - this.startPos
  1662. var endPos = begPos + count
  1663. // er? need more data...
  1664. if ( endPos > this.size )
  1665. endPos = this.size
  1666. var results = new Array()
  1667. var index = 0;
  1668. for ( var i=begPos ; i < endPos; i++ ) {
  1669. results[index++] = this.rows[i]
  1670. }
  1671. return results
  1672. },
  1673. convertSpaces: function(s) {
  1674. return s.split(" ").join("&nbsp;");
  1675. }
  1676. };
  1677. //Rico.GridViewPort --------------------------------------------------
  1678. Rico.GridViewPort = Class.create();
  1679. Rico.GridViewPort.prototype = {
  1680. initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) {
  1681. this.lastDisplayedStartPos = 0;
  1682. this.div = table.parentNode;
  1683. this.table = table
  1684. this.rowHeight = rowHeight;
  1685. this.div.style.height = this.rowHeight * visibleRows;
  1686. this.div.style.overflow = "hidden";
  1687. this.buffer = buffer;
  1688. this.liveGrid = liveGrid;
  1689. this.visibleRows = visibleRows + 1;
  1690. this.lastPixelOffset = 0;
  1691. this.startPos = 0;
  1692. },
  1693. populateRow: function(htmlRow, row) {
  1694. for (var j=0; j < row.length; j++) {
  1695. htmlRow.cells[j].innerHTML = row[j]
  1696. }
  1697. },
  1698. bufferChanged: function() {
  1699. this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
  1700. },
  1701. clearRows: function() {
  1702. if (!this.isBlank) {
  1703. for (var i=0; i < this.visibleRows; i++)
  1704. this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
  1705. this.isBlank = true;
  1706. }
  1707. },
  1708. clearContents: function() {
  1709. this.clearRows();
  1710. this.scrollTo(0);
  1711. this.startPos = 0;
  1712. this.lastStartPos = -1;
  1713. },
  1714. refreshContents: function(startPos) {
  1715. if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
  1716. return;
  1717. }
  1718. if ((startPos + this.visibleRows < this.buffer.startPos)
  1719. || (this.buffer.startPos + this.buffer.size < star