1 /* openrico.org rico.js */
5 * Copyright 2005 Sabre Airline Solutions
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
8 * file except in compliance with the License. You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software distributed under the
13 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
14 * either express or implied. See the License for the specific language governing permissions
15 * and limitations under the License.
18 // rico.js --------------------
24 Rico.ArrayExtensions = new Array();
26 if (Object.prototype.extend) {
28 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
31 if (Array.prototype.push) {
33 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
36 if (!Array.prototype.remove) {
37 Array.prototype.remove = function(dx) {
38 if( isNaN(dx) || dx > this.length )
40 for( var i=0,n=0; i<this.length; i++ )
45 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
48 if (!Array.prototype.removeItem) {
49 Array.prototype.removeItem = function(item) {
50 for ( var i = 0 ; i < this.length ; i++ )
51 if ( this[i] == item ) {
56 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
59 if (!Array.prototype.indices) {
60 Array.prototype.indices = function() {
61 var indexArray = new Array();
62 for ( index in this ) {
63 var ignoreThis = false;
64 for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
65 if ( this[index] == Rico.ArrayExtensions[i] ) {
71 indexArray[ indexArray.length ] = index;
75 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
78 // Create the loadXML method and xml getter for Mozilla
79 if ( window.DOMParser &&
80 window.XMLSerializer &&
81 window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
83 if (!Document.prototype.loadXML) {
84 Document.prototype.loadXML = function (s) {
85 var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
86 while (this.hasChildNodes())
87 this.removeChild(this.lastChild);
89 for (var i = 0; i < doc2.childNodes.length; i++) {
90 this.appendChild(this.importNode(doc2.childNodes[i], true));
95 Document.prototype.__defineGetter__( "xml",
97 return (new XMLSerializer()).serializeToString(this);
102 document.getElementsByTagAndClassName = function(tagName, className) {
103 if ( tagName == null )
106 var children = document.getElementsByTagName(tagName) || document.all;
107 var elements = new Array();
109 if ( className == null )
112 for (var i = 0; i < children.length; i++) {
113 var child = children[i];
114 var classNames = child.className.split(' ');
115 for (var j = 0; j < classNames.length; j++) {
116 if (classNames[j] == className) {
117 elements.push(child);
127 // ricoAccordion.js --------------------
130 Rico.Accordion = Class.create();
132 Rico.Accordion.prototype = {
134 initialize: function(container, options) {
135 this.container = $(container);
136 this.lastExpandedTab = null;
137 this.accordionTabs = new Array();
138 this.setOptions(options);
139 this._attachBehaviors();
141 this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
143 // set the initial visual state...
144 for ( var i=1 ; i < this.accordionTabs.length ; i++ )
146 this.accordionTabs[i].collapse();
147 this.accordionTabs[i].content.style.display = 'none';
149 this.lastExpandedTab = this.accordionTabs[0];
150 this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
151 this.lastExpandedTab.showExpanded();
152 this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
155 setOptions: function(options) {
157 expandedBg : '#63699c',
159 collapsedBg : '#6b79a5',
160 expandedTextColor : '#ffffff',
161 expandedFontWeight : 'bold',
162 hoverTextColor : '#ffffff',
163 collapsedTextColor : '#ced7ef',
164 collapsedFontWeight : 'normal',
165 hoverTextColor : '#ffffff',
166 borderColor : '#1f669b',
170 }.extend(options || {});
173 showTabByIndex: function( anIndex, animate ) {
174 var doAnimate = arguments.length == 1 ? true : animate;
175 this.showTab( this.accordionTabs[anIndex], doAnimate );
178 showTab: function( accordionTab, animate ) {
180 var doAnimate = arguments.length == 1 ? true : animate;
182 if ( this.options.onHideTab )
183 this.options.onHideTab(this.lastExpandedTab);
185 this.lastExpandedTab.showCollapsed();
186 var accordion = this;
187 var lastExpandedTab = this.lastExpandedTab;
189 this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
190 accordionTab.content.style.display = '';
192 accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
195 new Effect.AccordionSize( this.lastExpandedTab.content,
196 accordionTab.content,
198 this.options.panelHeight,
200 { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
201 this.lastExpandedTab = accordionTab;
204 this.lastExpandedTab.content.style.height = "1px";
205 accordionTab.content.style.height = this.options.panelHeight + "px";
206 this.lastExpandedTab = accordionTab;
207 this.showTabDone(lastExpandedTab);
211 showTabDone: function(collapsedTab) {
212 collapsedTab.content.style.display = 'none';
213 this.lastExpandedTab.showExpanded();
214 if ( this.options.onShowTab )
215 this.options.onShowTab(this.lastExpandedTab);
218 _attachBehaviors: function() {
219 var panels = this._getDirectChildrenByTag(this.container, 'DIV');
220 for ( var i = 0 ; i < panels.length ; i++ ) {
222 var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
223 if ( tabChildren.length != 2 )
224 continue; // unexpected
226 var tabTitleBar = tabChildren[0];
227 var tabContentBox = tabChildren[1];
228 this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
232 _getDirectChildrenByTag: function(e, tagName) {
233 var kids = new Array();
234 var allKids = e.childNodes;
235 for( var i = 0 ; i < allKids.length ; i++ )
236 if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
237 kids.push(allKids[i]);
243 Rico.Accordion.Tab = Class.create();
245 Rico.Accordion.Tab.prototype = {
247 initialize: function(accordion, titleBar, content) {
248 this.accordion = accordion;
249 this.titleBar = titleBar;
250 this.content = content;
251 this._attachBehaviors();
254 collapse: function() {
255 this.showCollapsed();
256 this.content.style.height = "1px";
259 showCollapsed: function() {
260 this.expanded = false;
261 this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
262 this.titleBar.style.color = this.accordion.options.collapsedTextColor;
263 this.titleBar.style.fontWeight = this.accordion.options.collapsedFontWeight;
264 this.content.style.overflow = "hidden";
267 showExpanded: function() {
268 this.expanded = true;
269 this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
270 this.titleBar.style.color = this.accordion.options.expandedTextColor;
271 this.content.style.overflow = "visible";
274 titleBarClicked: function(e) {
275 if ( this.accordion.lastExpandedTab == this )
277 this.accordion.showTab(this);
281 this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
282 this.titleBar.style.color = this.accordion.options.hoverTextColor;
285 unhover: function(e) {
286 if ( this.expanded ) {
287 this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
288 this.titleBar.style.color = this.accordion.options.expandedTextColor;
291 this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
292 this.titleBar.style.color = this.accordion.options.collapsedTextColor;
296 _attachBehaviors: function() {
297 this.content.style.border = "1px solid " + this.accordion.options.borderColor;
298 this.content.style.borderTopWidth = "0px";
299 this.content.style.borderBottomWidth = "0px";
300 this.content.style.margin = "0px";
302 this.titleBar.onclick = this.titleBarClicked.bindAsEventListener(this);
303 this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
304 this.titleBar.onmouseout = this.unhover.bindAsEventListener(this);
310 // ricoAjaxEngine.js --------------------
313 Rico.AjaxEngine = Class.create();
315 Rico.AjaxEngine.prototype = {
317 initialize: function() {
318 this.ajaxElements = new Array();
319 this.ajaxObjects = new Array();
320 this.requestURLS = new Array();
323 registerAjaxElement: function( anId, anElement ) {
324 if ( arguments.length == 1 )
326 this.ajaxElements[anId] = anElement;
329 registerAjaxObject: function( anId, anObject ) {
330 this.ajaxObjects[anId] = anObject;
333 registerRequest: function (requestLogicalName, requestURL) {
334 this.requestURLS[requestLogicalName] = requestURL;
337 sendRequest: function(requestName) {
338 var requestURL = this.requestURLS[requestName];
339 if ( requestURL == null )
342 var queryString = "";
343 if ( arguments.length > 1 )
344 queryString = this._createQueryString(arguments, 1);
346 new Ajax.Request(requestURL, this._requestOptions(queryString));
349 sendRequestWithData: function(requestName, xmlDocument) {
350 var requestURL = this.requestURLS[requestName];
351 if ( requestURL == null )
354 var queryString = "";
355 if ( arguments.length > 2 )
356 queryString = this._createQueryString(arguments, 2);
358 new Ajax.Request(requestURL + "?" + queryString, this._requestOptions(null,xmlDocument));
361 sendRequestAndUpdate: function(requestName,container,options) {
362 var requestURL = this.requestURLS[requestName];
363 if ( requestURL == null )
366 var queryString = "";
367 if ( arguments.length > 3 )
368 queryString = this._createQueryString(arguments, 3);
370 var updaterOptions = this._requestOptions(queryString);
371 updaterOptions.onComplete = null;
372 updaterOptions.extend(options);
374 new Ajax.Updater(container, requestURL, updaterOptions);
377 sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
378 var requestURL = this.requestURLS[requestName];
379 if ( requestURL == null )
382 var queryString = "";
383 if ( arguments.length > 4 )
384 queryString = this._createQueryString(arguments, 4);
387 var updaterOptions = this._requestOptions(queryString,xmlDocument);
388 updaterOptions.onComplete = null;
389 updaterOptions.extend(options);
391 new Ajax.Updater(container, requestURL + "?" + queryString, updaterOptions);
394 // Private -- not part of intended engine API --------------------------------------------------------------------
396 _requestOptions: function(queryString,xmlDoc) {
399 var requestHeaders = ['X-Rico-Version', Rico.Version ];
400 var sendMethod = "post"
402 requestHeaders.push( 'Content-type', 'text/xml' );
406 return { requestHeaders: requestHeaders,
407 parameters: queryString,
408 postBody: arguments[1] ? xmlDoc : null,
410 onComplete: self._onRequestComplete.bind(self) };
413 _createQueryString: function( theArgs, offset ) {
415 for ( var i = offset ; i < theArgs.length ; i++ ) {
419 var anArg = theArgs[i];
421 if ( anArg.name != undefined && anArg.value != undefined ) {
422 queryString += anArg.name + "=" + escape(anArg.value);
425 var ePos = anArg.indexOf('=');
426 var argName = anArg.substring( 0, ePos );
427 var argValue = anArg.substring( ePos + 1 );
428 queryString += argName + "=" + escape(argValue);
435 _onRequestComplete : function(request) {
437 //!!TODO: error handling infrastructure??
438 if (request.status != 200)
441 var response = request.responseXML.getElementsByTagName("ajax-response");
442 if (response == null || response.length != 1)
444 this._processAjaxResponse( response[0].childNodes );
447 _processAjaxResponse: function( xmlResponseElements ) {
448 for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
449 var responseElement = xmlResponseElements[i];
451 // only process nodes of type element.....
452 if ( responseElement.nodeType != 1 )
455 var responseType = responseElement.getAttribute("type");
456 var responseId = responseElement.getAttribute("id");
458 if ( responseType == "object" )
459 this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
460 else if ( responseType == "element" )
461 this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
463 alert('unrecognized AjaxResponse type : ' + responseType );
467 _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
468 ajaxObject.ajaxUpdate( responseElement );
471 _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
472 if ( responseElement.xml != undefined )
473 this._processAjaxElementUpdateIE( ajaxElement, responseElement );
475 this._processAjaxElementUpdateMozilla( ajaxElement, responseElement );
478 _processAjaxElementUpdateIE: function( ajaxElement, responseElement ) {
480 for ( var i = 0 ; i < responseElement.childNodes.length ; i++ )
481 newHTML += responseElement.childNodes[i].xml;
483 ajaxElement.innerHTML = newHTML;
486 _processAjaxElementUpdateMozilla: function( ajaxElement, responseElement ) {
487 var xmlSerializer = new XMLSerializer();
489 for ( var i = 0 ; i < responseElement.childNodes.length ; i++ )
490 newHTML += xmlSerializer.serializeToString(responseElement.childNodes[i]);
492 ajaxElement.innerHTML = newHTML;
496 var ajaxEngine = new Rico.AjaxEngine();
498 // ricoColor.js --------------------
500 Rico.Color = Class.create();
502 Rico.Color.prototype = {
504 initialize: function(red, green, blue) {
505 this.rgb = { r: red, g : green, b : blue };
508 setRed: function(r) {
512 setGreen: function(g) {
516 setBlue: function(b) {
520 setHue: function(h) {
522 // get an HSB model, and set the new hue...
523 var hsb = this.asHSB();
526 // convert back to RGB...
527 this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
530 setSaturation: function(s) {
531 // get an HSB model, and set the new hue...
532 var hsb = this.asHSB();
535 // convert back to RGB and set values...
536 this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
539 setBrightness: function(b) {
540 // get an HSB model, and set the new hue...
541 var hsb = this.asHSB();
544 // convert back to RGB and set values...
545 this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
548 darken: function(percent) {
549 var hsb = this.asHSB();
550 this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
553 brighten: function(percent) {
554 var hsb = this.asHSB();
555 this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
558 blend: function(other) {
559 this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
560 this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
561 this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
564 isBright: function() {
565 var hsb = this.asHSB();
566 return this.asHSB().b > 0.5;
570 return ! this.isBright();
574 return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
578 return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
582 return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
585 toString: function() {
591 Rico.Color.createFromHex = function(hexCode) {
593 if ( hexCode.indexOf('#') == 0 )
594 hexCode = hexCode.substring(1);
595 var red = hexCode.substring(0,2);
596 var green = hexCode.substring(2,4);
597 var blue = hexCode.substring(4,6);
598 return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
602 * Factory method for creating a color from the background of
605 Rico.Color.createColorFromBackground = function(elem) {
607 var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");
609 if ( actualColor == "transparent" && elem.parent )
610 return Rico.Color.createColorFromBackground(elem.parent);
612 if ( actualColor == null )
613 return new Rico.Color(255,255,255);
615 if ( actualColor.indexOf("rgb(") == 0 ) {
616 var colors = actualColor.substring(4, actualColor.length - 1 );
617 var colorArray = colors.split(",");
618 return new Rico.Color( parseInt( colorArray[0] ),
619 parseInt( colorArray[1] ),
620 parseInt( colorArray[2] ) );
623 else if ( actualColor.indexOf("#") == 0 ) {
624 var redPart = parseInt(actualColor.substring(1,3), 16);
625 var greenPart = parseInt(actualColor.substring(3,5), 16);
626 var bluePart = parseInt(actualColor.substring(5), 16);
627 return new Rico.Color( redPart, greenPart, bluePart );
630 return new Rico.Color(255,255,255);
633 Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
639 if (saturation == 0) {
640 red = parseInt(brightness * 255.0 + 0.5);
645 var h = (hue - Math.floor(hue)) * 6.0;
646 var f = h - Math.floor(h);
647 var p = brightness * (1.0 - saturation);
648 var q = brightness * (1.0 - saturation * f);
649 var t = brightness * (1.0 - (saturation * (1.0 - f)));
651 switch (parseInt(h)) {
653 red = (brightness * 255.0 + 0.5);
654 green = (t * 255.0 + 0.5);
655 blue = (p * 255.0 + 0.5);
658 red = (q * 255.0 + 0.5);
659 green = (brightness * 255.0 + 0.5);
660 blue = (p * 255.0 + 0.5);
663 red = (p * 255.0 + 0.5);
664 green = (brightness * 255.0 + 0.5);
665 blue = (t * 255.0 + 0.5);
668 red = (p * 255.0 + 0.5);
669 green = (q * 255.0 + 0.5);
670 blue = (brightness * 255.0 + 0.5);
673 red = (t * 255.0 + 0.5);
674 green = (p * 255.0 + 0.5);
675 blue = (brightness * 255.0 + 0.5);
678 red = (brightness * 255.0 + 0.5);
679 green = (p * 255.0 + 0.5);
680 blue = (q * 255.0 + 0.5);
685 return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
688 Rico.Color.RGBtoHSB = function(r, g, b) {
694 var cmax = (r > g) ? r : g;
698 var cmin = (r < g) ? r : g;
702 brightness = cmax / 255.0;
704 saturation = (cmax - cmin)/cmax;
711 var redc = (cmax - r)/(cmax - cmin);
712 var greenc = (cmax - g)/(cmax - cmin);
713 var bluec = (cmax - b)/(cmax - cmin);
716 hue = bluec - greenc;
718 hue = 2.0 + redc - bluec;
720 hue = 4.0 + greenc - redc;
727 return { h : hue, s : saturation, b : brightness };
730 // ricoCorner.js --------------------
735 round: function(e, options) {
737 this._setOptions(options);
739 var color = this.options.color;
740 if ( this.options.color == "fromElement" )
741 color = this._background(e);
743 var bgColor = this.options.bgColor;
744 if ( this.options.bgColor == "fromParent" )
745 bgColor = this._background(e.offsetParent);
747 this._roundCornersImpl(e, color, bgColor);
750 _roundCornersImpl: function(e, color, bgColor) {
751 if(this.options.border)
752 this._renderBorder(e,bgColor);
753 if(this._isTopRounded())
754 this._roundTopCorners(e,color,bgColor);
755 if(this._isBottomRounded())
756 this._roundBottomCorners(e,color,bgColor);
759 _renderBorder: function(el,bgColor) {
760 var borderValue = "1px solid " + this._borderColor(bgColor);
761 var borderL = "border-left: " + borderValue;
762 var borderR = "border-right: " + borderValue;
763 var style = "style='" + borderL + ";" + borderR + "'";
764 el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
767 _roundTopCorners: function(el, color, bgColor) {
768 var corner = this._createCorner(bgColor);
769 for(var i=0 ; i < this.options.numSlices ; i++ )
770 corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
771 el.style.paddingTop = 0;
772 el.insertBefore(corner,el.firstChild);
775 _roundBottomCorners: function(el, color, bgColor) {
776 var corner = this._createCorner(bgColor);
777 for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
778 corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
779 el.style.paddingBottom = 0;
780 el.appendChild(corner);
783 _createCorner: function(bgColor) {
784 var corner = document.createElement("div");
785 corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
789 _createCornerSlice: function(color,bgColor, n, position) {
790 var slice = document.createElement("span");
792 var inStyle = slice.style;
793 inStyle.backgroundColor = color;
794 inStyle.display = "block";
795 inStyle.height = "1px";
796 inStyle.overflow = "hidden";
797 inStyle.fontSize = "1px";
799 var borderColor = this._borderColor(color,bgColor);
800 if ( this.options.border && n == 0 ) {
801 inStyle.borderTopStyle = "solid";
802 inStyle.borderTopWidth = "1px";
803 inStyle.borderLeftWidth = "0px";
804 inStyle.borderRightWidth = "0px";
805 inStyle.borderBottomWidth = "0px";
806 inStyle.height = "0px"; // assumes css compliant box model
807 inStyle.borderColor = borderColor;
809 else if(borderColor) {
810 inStyle.borderColor = borderColor;
811 inStyle.borderStyle = "solid";
812 inStyle.borderWidth = "0px 1px";
815 if ( !this.options.compact && (n == (this.options.numSlices-1)) )
816 inStyle.height = "2px";
818 this._setMargin(slice, n, position);
819 this._setBorder(slice, n, position);
824 _setOptions: function(options) {
827 color : "fromElement",
828 bgColor : "fromParent",
832 }.extend(options || {});
834 this.options.numSlices = this.options.compact ? 2 : 4;
835 if ( this._isTransparent() )
836 this.options.blend = false;
839 _whichSideTop: function() {
840 if ( this._hasString(this.options.corners, "all", "top") )
843 if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
846 if (this.options.corners.indexOf("tl") >= 0)
848 else if (this.options.corners.indexOf("tr") >= 0)
853 _whichSideBottom: function() {
854 if ( this._hasString(this.options.corners, "all", "bottom") )
857 if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
860 if(this.options.corners.indexOf("bl") >=0)
862 else if(this.options.corners.indexOf("br")>=0)
867 _borderColor : function(color,bgColor) {
868 if ( color == "transparent" )
870 else if ( this.options.border )
871 return this.options.border;
872 else if ( this.options.blend )
873 return this._blend( bgColor, color );
879 _setMargin: function(el, n, corners) {
880 var marginSize = this._marginSize(n);
881 var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
883 if ( whichSide == "left" ) {
884 el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
886 else if ( whichSide == "right" ) {
887 el.style.marginRight = marginSize + "px"; el.style.marginLeft = "0px";
890 el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
894 _setBorder: function(el,n,corners) {
895 var borderSize = this._borderSize(n);
896 var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
898 if ( whichSide == "left" ) {
899 el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
901 else if ( whichSide == "right" ) {
902 el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth = "0px";
905 el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
909 _marginSize: function(n) {
910 if ( this._isTransparent() )
913 var marginSizes = [ 5, 3, 2, 1 ];
914 var blendedMarginSizes = [ 3, 2, 1, 0 ];
915 var compactMarginSizes = [ 2, 1 ];
916 var smBlendedMarginSizes = [ 1, 0 ];
918 if ( this.options.compact && this.options.blend )
919 return smBlendedMarginSizes[n];
920 else if ( this.options.compact )
921 return compactMarginSizes[n];
922 else if ( this.options.blend )
923 return blendedMarginSizes[n];
925 return marginSizes[n];
928 _borderSize: function(n) {
929 var transparentBorderSizes = [ 5, 3, 2, 1 ];
930 var blendedBorderSizes = [ 2, 1, 1, 1 ];
931 var compactBorderSizes = [ 1, 0 ];
932 var actualBorderSizes = [ 0, 2, 0, 0 ];
934 if ( this.options.compact && (this.options.blend || this._isTransparent()) )
936 else if ( this.options.compact )
937 return compactBorderSizes[n];
938 else if ( this.options.blend )
939 return blendedBorderSizes[n];
940 else if ( this.options.border )
941 return actualBorderSizes[n];
942 else if ( this._isTransparent() )
943 return transparentBorderSizes[n];
947 _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
948 _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
949 _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
950 _isTransparent: function() { return this.options.color == "transparent"; },
951 _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
952 _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
953 _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
956 // ricoDragAndDrop.js --------------------
958 Rico.DragAndDrop = Class.create();
960 Rico.DragAndDrop.prototype = {
962 initialize: function() {
963 this.dropZones = new Array();
964 this.draggables = new Array();
965 this.currentDragObjects = new Array();
966 this.dragElement = null;
967 this.lastSelectedDraggable = null;
968 this.currentDragObjectVisible = false;
969 this.interestedInMotionEvents = false;
972 registerDropZone: function(aDropZone) {
973 this.dropZones[ this.dropZones.length ] = aDropZone;
976 deregisterDropZone: function(aDropZone) {
977 var newDropZones = new Array();
979 for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
980 if ( this.dropZones[i] != aDropZone )
981 newDropZones[j++] = this.dropZones[i];
984 this.dropZones = newDropZones;
987 clearDropZones: function() {
988 this.dropZones = new Array();
991 registerDraggable: function( aDraggable ) {
992 this.draggables[ this.draggables.length ] = aDraggable;
993 this._addMouseDownHandler( aDraggable );
996 clearSelection: function() {
997 for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
998 this.currentDragObjects[i].deselect();
999 this.currentDragObjects = new Array();
1000 this.lastSelectedDraggable = null;
1003 hasSelection: function() {
1004 return this.currentDragObjects.length > 0;
1007 setStartDragFromElement: function( e, mouseDownElement ) {
1008 this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
1009 this.startx = e.screenX - this.origPos.x
1010 this.starty = e.screenY - this.origPos.y
1011 //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
1012 //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
1013 //this.adjustedForDraggableSize = false;
1015 this.interestedInMotionEvents = this.hasSelection();
1016 this._terminateEvent(e);
1019 updateSelection: function( draggable, extendSelection ) {
1020 if ( ! extendSelection )
1021 this.clearSelection();
1023 if ( draggable.isSelected() ) {
1024 this.currentDragObjects.removeItem(draggable);
1025 draggable.deselect();
1026 if ( draggable == this.lastSelectedDraggable )
1027 this.lastSelectedDraggable = null;
1030 this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
1032 this.lastSelectedDraggable = draggable;
1036 _mouseDownHandler: function(e) {
1037 if ( arguments.length == 0 )
1040 // if not button 1 ignore it...
1041 var nsEvent = e.which != undefined;
1042 if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
1045 var eventTarget = e.target ? e.target : e.srcElement;
1046 var draggableObject = eventTarget.draggable;
1048 this.updateSelection( draggableObject, e.ctrlKey );
1050 // clear the drop zones postion cache...
1051 if ( this.hasSelection() )
1052 for ( var i = 0 ; i < this.dropZones.length ; i++ )
1053 this.dropZones[i].clearPositionCache();
1055 this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
1059 _mouseMoveHandler: function(e) {
1060 var nsEvent = e.which != undefined;
1061 if ( !this.interestedInMotionEvents ) {
1062 this._terminateEvent(e);
1066 if ( ! this.hasSelection() )
1069 if ( ! this.currentDragObjectVisible )
1072 if ( !this.activatedDropZones )
1073 this._activateRegisteredDropZones();
1075 //if ( !this.adjustedForDraggableSize )
1076 // this._adjustForDraggableSize(e);
1078 this._updateDraggableLocation(e);
1079 this._updateDropZonesHover(e);
1081 this._terminateEvent(e);
1084 _makeDraggableObjectVisible: function(e)
1086 if ( !this.hasSelection() )
1090 if ( this.currentDragObjects.length > 1 )
1091 dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
1093 dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
1095 // go ahead and absolute position it...
1096 if ( RicoUtil.getElementsComputedStyle(dragElement, "position") != "absolute" )
1097 dragElement.style.position = "absolute";
1099 // need to parent him into the document...
1100 if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
1101 document.body.appendChild(dragElement);
1103 this.dragElement = dragElement;
1104 this._updateDraggableLocation(e);
1106 this.currentDragObjectVisible = true;
1110 _adjustForDraggableSize: function(e) {
1111 var dragElementWidth = this.dragElement.offsetWidth;
1112 var dragElementHeight = this.dragElement.offsetHeight;
1113 if ( this.startComponentX > dragElementWidth )
1114 this.startx -= this.startComponentX - dragElementWidth + 2;
1116 if ( this.startComponentY > dragElementHeight )
1117 this.starty -= this.startComponentY - dragElementHeight + 2;
1119 this.adjustedForDraggableSize = true;
1123 _updateDraggableLocation: function(e) {
1124 var dragObjectStyle = this.dragElement.style;
1125 dragObjectStyle.left = (e.screenX - this.startx) + "px"
1126 dragObjectStyle.top = (e.screenY - this.starty) + "px";
1129 _updateDropZonesHover: function(e) {
1130 var n = this.dropZones.length;
1131 for ( var i = 0 ; i < n ; i++ ) {
1132 if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
1133 this.dropZones[i].hideHover();
1136 for ( var i = 0 ; i < n ; i++ ) {
1137 if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
1138 if ( this.dropZones[i].canAccept(this.currentDragObjects) )
1139 this.dropZones[i].showHover();
1144 _startDrag: function(e) {
1145 for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
1146 this.currentDragObjects[i].startDrag();
1148 this._makeDraggableObjectVisible(e);
1151 _mouseUpHandler: function(e) {
1152 if ( ! this.hasSelection() )
1155 var nsEvent = e.which != undefined;
1156 if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
1159 this.interestedInMotionEvents = false;
1161 if ( this.dragElement == null ) {
1162 this._terminateEvent(e);
1166 if ( this._placeDraggableInDropZone(e) )
1167 this._completeDropOperation(e);
1169 this._terminateEvent(e);
1170 new Effect.Position( this.dragElement,
1175 { complete : this._doCancelDragProcessing.bind(this) } );
1179 _completeDropOperation: function(e) {
1180 if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
1181 if ( this.dragElement.parentNode != null )
1182 this.dragElement.parentNode.removeChild(this.dragElement);
1185 this._deactivateRegisteredDropZones();
1187 this.clearSelection();
1188 this.dragElement = null;
1189 this.currentDragObjectVisible = false;
1190 this._terminateEvent(e);
1193 _doCancelDragProcessing: function() {
1196 if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
1197 if ( this.dragElement.parentNode != null ) {
1198 this.dragElement.parentNode.removeChild(this.dragElement);
1202 this._deactivateRegisteredDropZones();
1203 this.dragElement = null;
1204 this.currentDragObjectVisible = false;
1207 _placeDraggableInDropZone: function(e) {
1208 var foundDropZone = false;
1209 var n = this.dropZones.length;
1210 for ( var i = 0 ; i < n ; i++ ) {
1211 if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
1212 if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
1213 this.dropZones[i].hideHover();
1214 this.dropZones[i].accept(this.currentDragObjects);
1215 foundDropZone = true;
1221 return foundDropZone;
1224 _cancelDrag: function() {
1225 for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
1226 this.currentDragObjects[i].cancelDrag();
1229 _endDrag: function() {
1230 for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
1231 this.currentDragObjects[i].endDrag();
1234 _mousePointInDropZone: function( e, dropZone ) {
1236 var absoluteRect = dropZone.getAbsoluteRect();
1238 return e.clientX > absoluteRect.left &&
1239 e.clientX < absoluteRect.right &&
1240 e.clientY > absoluteRect.top &&
1241 e.clientY < absoluteRect.bottom;
1244 _addMouseDownHandler: function( aDraggable )
1246 var htmlElement = aDraggable.getMouseDownHTMLElement();
1247 if ( htmlElement != null ) {
1248 htmlElement.draggable = aDraggable;
1249 this._addMouseDownEvent( htmlElement );
1253 _activateRegisteredDropZones: function() {
1254 var n = this.dropZones.length;
1255 for ( var i = 0 ; i < n ; i++ ) {
1256 var dropZone = this.dropZones[i];
1257 if ( dropZone.canAccept(this.currentDragObjects) )
1258 dropZone.activate();
1261 this.activatedDropZones = true;
1264 _deactivateRegisteredDropZones: function() {
1265 var n = this.dropZones.length;
1266 for ( var i = 0 ; i < n ; i++ )
1267 this.dropZones[i].deactivate();
1268 this.activatedDropZones = false;
1271 _addMouseDownEvent: function( htmlElement ) {
1272 if ( typeof document.implementation != "undefined" &&
1273 document.implementation.hasFeature("HTML", "1.0") &&
1274 document.implementation.hasFeature("Events", "2.0") &&
1275 document.implementation.hasFeature("CSS", "2.0") ) {
1276 htmlElement.addEventListener("mousedown", this._mouseDownHandler.bindAsEventListener(this), false);
1279 htmlElement.attachEvent( "onmousedown", this._mouseDownHandler.bindAsEventListener(this) );
1283 _terminateEvent: function(e) {
1284 if ( e.stopPropagation != undefined )
1285 e.stopPropagation();
1286 else if ( e.cancelBubble != undefined )
1287 e.cancelBubble = true;
1289 if ( e.preventDefault != undefined )
1292 e.returnValue = false;
1295 initializeEventHandlers: function() {
1296 if ( typeof document.implementation != "undefined" &&
1297 document.implementation.hasFeature("HTML", "1.0") &&
1298 document.implementation.hasFeature("Events", "2.0") &&
1299 document.implementation.hasFeature("CSS", "2.0") ) {
1300 document.addEventListener("mouseup", this._mouseUpHandler.bindAsEventListener(this), false);
1301 document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
1304 document.attachEvent( "onmouseup", this._mouseUpHandler.bindAsEventListener(this) );
1305 document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
1310 var dndMgr = new Rico.DragAndDrop();
1311 dndMgr.initializeEventHandlers();
1313 // ricoDraggable.js --------------------
1315 Rico.Draggable = Class.create();
1317 Rico.Draggable.prototype = {
1319 initialize: function( type, htmlElement ) {
1321 this.htmlElement = $(htmlElement);
1322 this.selected = false;
1326 * Returns the HTML element that should have a mouse down event
1327 * added to it in order to initiate a drag operation
1330 getMouseDownHTMLElement: function() {
1331 return this.htmlElement;
1334 select: function() {
1335 this.selected = true;
1337 if ( this.showingSelected )
1340 var htmlElement = this.getMouseDownHTMLElement();
1342 var color = Rico.Color.createColorFromBackground(htmlElement);
1343 color.isBright() ? color.darken(0.033) : color.brighten(0.033);
1345 this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
1346 htmlElement.style.backgroundColor = color.asHex();
1347 this.showingSelected = true;
1350 deselect: function() {
1351 this.selected = false;
1352 if ( !this.showingSelected )
1355 var htmlElement = this.getMouseDownHTMLElement();
1357 htmlElement.style.backgroundColor = this.saveBackground;
1358 this.showingSelected = false;
1361 isSelected: function() {
1362 return this.selected;
1365 startDrag: function() {
1368 cancelDrag: function() {
1371 endDrag: function() {
1374 getSingleObjectDragGUI: function() {
1375 return this.htmlElement;
1378 getMultiObjectDragGUI: function( draggables ) {
1379 return this.htmlElement;
1382 getDroppedGUI: function() {
1383 return this.htmlElement;
1386 toString: function() {
1387 return this.type + ":" + this.htmlElement + ":";
1392 // ricoDropzone.js --------------------
1394 Rico.Dropzone = Class.create();
1396 Rico.Dropzone.prototype = {
1398 initialize: function( htmlElement ) {
1399 this.htmlElement = $(htmlElement);
1400 this.absoluteRect = null;
1403 getHTMLElement: function() {
1404 return this.htmlElement;
1407 clearPositionCache: function() {
1408 this.absoluteRect = null;
1411 getAbsoluteRect: function() {
1412 if ( this.absoluteRect == null ) {
1413 var htmlElement = this.getHTMLElement();
1414 var pos = RicoUtil.toViewportPosition(htmlElement);
1416 this.absoluteRect = {
1419 bottom: pos.y + htmlElement.offsetHeight,
1420 right: pos.x + htmlElement.offsetWidth
1423 return this.absoluteRect;
1426 activate: function() {
1427 var htmlElement = this.getHTMLElement();
1428 if (htmlElement == null || this.showingActive)
1431 this.showingActive = true;
1432 this.saveBackgroundColor = htmlElement.style.backgroundColor;
1434 var fallbackColor = "#ffea84";
1435 var currentColor = Rico.Color.createColorFromBackground(htmlElement);
1436 if ( currentColor == null )
1437 htmlElement.style.backgroundColor = fallbackColor;
1439 currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
1440 htmlElement.style.backgroundColor = currentColor.asHex();
1444 deactivate: function() {
1445 var htmlElement = this.getHTMLElement();
1446 if (htmlElement == null || !this.showingActive)
1449 htmlElement.style.backgroundColor = this.saveBackgroundColor;
1450 this.showingActive = false;
1451 this.saveBackgroundColor = null;
1454 showHover: function() {
1455 var htmlElement = this.getHTMLElement();
1456 if ( htmlElement == null || this.showingHover )
1459 this.saveBorderWidth = htmlElement.style.borderWidth;
1460 this.saveBorderStyle = htmlElement.style.borderStyle;
1461 this.saveBorderColor = htmlElement.style.borderColor;
1463 this.showingHover = true;
1464 htmlElement.style.borderWidth = "1px";
1465 htmlElement.style.borderStyle = "solid";
1466 //htmlElement.style.borderColor = "#ff9900";
1467 htmlElement.style.borderColor = "#ffff00";
1470 hideHover: function() {
1471 var htmlElement = this.getHTMLElement();
1472 if ( htmlElement == null || !this.showingHover )
1475 htmlElement.style.borderWidth = this.saveBorderWidth;
1476 htmlElement.style.borderStyle = this.saveBorderStyle;
1477 htmlElement.style.borderColor = this.saveBorderColor;
1478 this.showingHover = false;
1481 canAccept: function(draggableObjects) {
1485 accept: function(draggableObjects) {
1486 var htmlElement = this.getHTMLElement();
1487 if ( htmlElement == null )
1490 n = draggableObjects.length;
1491 for ( var i = 0 ; i < n ; i++ )
1493 var theGUI = draggableObjects[i].getDroppedGUI();
1494 if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
1496 theGUI.style.position = "static";
1497 theGUI.style.top = "";
1498 theGUI.style.top = "";
1500 htmlElement.appendChild(theGUI);
1505 // ricoEffects.js --------------------
1508 Effect.SizeAndPosition = Class.create();
1509 Effect.SizeAndPosition.prototype = {
1511 initialize: function(element, x, y, w, h, duration, steps, options) {
1512 this.element = $(element);
1517 this.duration = duration;
1519 this.options = arguments[7] || {};
1521 this.sizeAndPosition();
1524 sizeAndPosition: function() {
1525 if (this.isFinished()) {
1526 if(this.options.complete) this.options.complete(this);
1531 clearTimeout(this.timer);
1533 var stepDuration = Math.round(this.duration/this.steps) ;
1535 // Get original values: x,y = top left corner; w,h = width height
1536 var currentX = this.element.offsetLeft;
1537 var currentY = this.element.offsetTop;
1538 var currentW = this.element.offsetWidth;
1539 var currentH = this.element.offsetHeight;
1541 // If values not set, or zero, we do not modify them, and take original as final as well
1542 this.x = (this.x) ? this.x : currentX;
1543 this.y = (this.y) ? this.y : currentY;
1544 this.w = (this.w) ? this.w : currentW;
1545 this.h = (this.h) ? this.h : currentH;
1547 // how much do we need to modify our values for each step?
1548 var difX = this.steps > 0 ? (this.x - currentX)/this.steps : 0;
1549 var difY = this.steps > 0 ? (this.y - currentY)/this.steps : 0;
1550 var difW = this.steps > 0 ? (this.w - currentW)/this.steps : 0;
1551 var difH = this.steps > 0 ? (this.h - currentH)/this.steps : 0;
1553 this.moveBy(difX, difY);
1554 this.resizeBy(difW, difH);
1556 this.duration -= stepDuration;
1559 this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
1562 isFinished: function() {
1563 return this.steps <= 0;
1566 moveBy: function( difX, difY ) {
1567 var currentLeft = this.element.offsetLeft;
1568 var currentTop = this.element.offsetTop;
1569 var intDifX = parseInt(difX);
1570 var intDifY = parseInt(difY);
1572 var style = this.element.style;
1574 style.left = (currentLeft + intDifX) + "px";
1576 style.top = (currentTop + intDifY) + "px";
1579 resizeBy: function( difW, difH ) {
1580 var currentWidth = this.element.offsetWidth;
1581 var currentHeight = this.element.offsetHeight;
1582 var intDifW = parseInt(difW);
1583 var intDifH = parseInt(difH);
1585 var style = this.element.style;
1587 style.width = (currentWidth + intDifW) + "px";
1589 style.height = (currentHeight + intDifH) + "px";
1593 Effect.Size = Class.create();
1594 Effect.Size.prototype = {
1596 initialize: function(element, w, h, duration, steps, options) {
1597 new Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
1601 Effect.Position = Class.create();
1602 Effect.Position.prototype = {
1604 initialize: function(element, x, y, duration, steps, options) {
1605 new Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
1609 Effect.Round = Class.create();
1610 Effect.Round.prototype = {
1612 initialize: function(tagName, className, options) {
1613 var elements = document.getElementsByTagAndClassName(tagName,className);
1614 for ( var i = 0 ; i < elements.length ; i++ )
1615 Rico.Corner.round( elements[i], options );
1619 Effect.FadeTo = Class.create();
1620 Effect.FadeTo.prototype = {
1622 initialize: function( element, opacity, duration, steps, options) {
1623 this.element = $(element);
1624 this.opacity = opacity;
1625 this.duration = duration;
1627 this.options = arguments[4] || {};
1631 fadeTo: function() {
1632 if (this.isFinished()) {
1633 if(this.options.complete) this.options.complete(this);
1638 clearTimeout(this.timer);
1640 var stepDuration = Math.round(this.duration/this.steps) ;
1641 var currentOpacity = this.getElementOpacity();
1642 var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
1644 this.changeOpacityBy(delta);
1645 this.duration -= stepDuration;
1648 this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
1651 changeOpacityBy: function(v) {
1652 var currentOpacity = this.getElementOpacity();
1653 var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
1654 this.element.ricoOpacity = newOpacity;
1656 this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
1657 this.element.style.opacity = newOpacity; /*//*/;
1660 isFinished: function() {
1661 return this.steps <= 0;
1664 getElementOpacity: function() {
1665 if ( this.element.ricoOpacity == undefined ) {
1667 if ( this.element.currentStyle ) {
1668 opacity = this.element.currentStyle.opacity;
1670 else if ( document.defaultView.getComputedStyle != undefined ) {
1671 var computedStyle = document.defaultView.getComputedStyle;
1672 opacity = computedStyle(this.element, null).getPropertyValue('opacity');
1675 this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
1678 return parseFloat(this.element.ricoOpacity);
1682 Effect.AccordionSize = Class.create();
1684 Effect.AccordionSize.prototype = {
1686 initialize: function(e1, e2, start, end, duration, steps, options) {
1691 this.duration = duration;
1693 this.options = arguments[6] || {};
1695 this.accordionSize();
1698 accordionSize: function() {
1700 if (this.isFinished()) {
1701 // just in case there are round errors or such...
1702 this.e1.style.height = this.start + "px";
1703 this.e2.style.height = this.end + "px";
1705 if(this.options.complete)
1706 this.options.complete(this);
1711 clearTimeout(this.timer);
1713 var stepDuration = Math.round(this.duration/this.steps) ;
1715 var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
1716 this.resizeBy(diff);
1718 this.duration -= stepDuration;
1721 this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
1724 isFinished: function() {
1725 return this.steps <= 0;
1728 resizeBy: function(diff) {
1729 var h1Height = this.e1.offsetHeight;
1730 var h2Height = this.e2.offsetHeight;
1731 var intDiff = parseInt(diff);
1733 this.e1.style.height = (h1Height - intDiff) + "px";
1734 this.e2.style.height = (h2Height + intDiff) + "px";
1741 // ricoLiveGrid.js --------------------
1744 // Rico.LiveGridMetaData -----------------------------------------------------
1746 Rico.LiveGridMetaData = Class.create();
1748 Rico.LiveGridMetaData.prototype = {
1750 initialize: function( pageSize, totalRows, options ) {
1751 this.pageSize = pageSize;
1752 this.totalRows = totalRows;
1753 this.setOptions(options);
1754 this.scrollArrowHeight = 16;
1757 setOptions: function(options) {
1759 largeBufferSize : 7.0, // 7 pages
1760 smallBufferSize : 1.0, // 1 page
1761 nearLimitFactor : 0.2 // 20% of buffer
1762 }.extend(options || {});
1765 getPageSize: function() {
1766 return this.pageSize;
1769 getTotalRows: function() {
1770 return this.totalRows;
1773 setTotalRows: function(n) {
1777 getLargeBufferSize: function() {
1778 return parseInt(this.options.largeBufferSize * this.pageSize);
1781 getSmallBufferSize: function() {
1782 return parseInt(this.options.smallBufferSize * this.pageSize);
1785 getLimitTolerance: function() {
1786 return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
1789 getBufferSize: function(isFull) {
1790 return isFull ? this.getLargeBufferSize() : this.getSmallBufferSize();
1794 // Rico.LiveGridScroller -----------------------------------------------------
1796 Rico.LiveGridScroller = Class.create();
1798 Rico.LiveGridScroller.prototype = {
1800 initialize: function(liveGrid) {
1801 this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
1802 this.liveGrid = liveGrid;
1803 this.metaData = liveGrid.metaData;
1804 this.createScrollBar();
1805 this.scrollTimeout = null;
1806 //this.sizeIEHeaderHack();
1807 this.lastScrollPos = 0;
1810 isUnPlugged: function() {
1811 return this.scrollerDiv.onscroll == null;
1814 plugin: function() {
1815 this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
1818 unplug: function() {
1819 this.scrollerDiv.onscroll = null;
1822 sizeIEHeaderHack: function() {
1823 if ( !this.isIE ) return;
1824 var headerTable = $(this.liveGrid.tableId + "_header");
1826 headerTable.rows[0].cells[0].style.width =
1827 (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
1830 createScrollBar: function() {
1831 var table = this.liveGrid.table;
1832 var visibleHeight = table.offsetHeight;
1834 // create the outer div...
1835 this.scrollerDiv = document.createElement("div");
1836 var scrollerStyle = this.scrollerDiv.style;
1837 scrollerStyle.borderRight = "1px solid #ababab"; // hard coded color!!!
1838 scrollerStyle.position = "relative";
1839 scrollerStyle.left = this.isIE ? "-6px" : "-3px";
1840 scrollerStyle.width = "19px";
1841 scrollerStyle.height = visibleHeight + "px";
1842 scrollerStyle.overflow = "auto";
1844 // create the inner div...
1845 this.heightDiv = document.createElement("div");
1846 this.heightDiv.style.width = "1px";
1847 this.heightDiv.style.height = parseInt(visibleHeight *
1848 this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
1849 this.lineHeight = visibleHeight/this.metaData.getPageSize();
1851 this.scrollerDiv.appendChild(this.heightDiv);
1852 this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
1853 table.parentNode.insertBefore( this.scrollerDiv, table.nextSibling );
1856 updateSize: function() {
1857 var table = this.liveGrid.table;
1858 var visibleHeight = table.offsetHeight;
1859 this.heightDiv.style.height = parseInt(visibleHeight *
1860 this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
1863 adjustScrollTop: function() {
1865 var rem = this.scrollerDiv.scrollTop % this.lineHeight;
1867 if (this.lastScrollPos < this.scrollerDiv.scrollTop)
1868 this.scrollerDiv.scrollTop = this.scrollerDiv.scrollTop + this.lineHeight -rem;
1870 this.scrollerDiv.scrollTop = this.scrollerDiv.scrollTop - rem;
1872 this.lastScrollPos = this.scrollerDiv.scrollTop;
1876 handleScroll: function() {
1877 if ( this.scrollTimeout )
1878 clearTimeout( this.scrollTimeout );
1880 //this.adjustScrollTop();
1881 var contentOffset = parseInt(this.scrollerDiv.scrollTop *
1882 this.metaData.getTotalRows() / this.heightDiv.offsetHeight);
1883 this.liveGrid.requestContentRefresh(contentOffset);
1884 if ( this.metaData.options.onscroll )
1885 this.metaData.options.onscroll( contentOffset, this.metaData );
1887 this.scrollTimeout = setTimeout( this.scrollIdle.bind(this), 1200 );
1890 scrollIdle: function() {
1891 if ( this.metaData.options.onscrollidle )
1892 this.metaData.options.onscrollidle();
1896 // Rico.LiveGridBuffer -----------------------------------------------------
1898 Rico.LiveGridBuffer = Class.create();
1900 Rico.LiveGridBuffer.prototype = {
1902 initialize: function(metaData) {
1905 this.metaData = metaData;
1906 this.rows = new Array();
1907 this.updateInProgress = false;
1910 update: function(ajaxResponse,start) {
1912 this.startPos = start;
1913 this.rows = new Array();
1915 var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
1916 this.updateUI = rowsElement.getAttribute("update_ui") == "true"
1917 var trs = rowsElement.getElementsByTagName("tr");
1918 for ( var i=0 ; i < trs.length; i++ ) {
1919 var row = this.rows[i] = new Array();
1920 var cells = trs[i].getElementsByTagName("td");
1921 for ( var j=0; j < cells.length ; j++ ) {
1922 var cell = cells[j];
1923 var convertSpaces = cell.getAttribute("convert_spaces") == "true";
1924 var cellContent = cell.text != undefined ? cell.text : cell.textContent;
1925 row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
1928 this.size = trs.length;
1931 isFullP: function() {
1932 return this.metaData.pageSize != this.size;
1935 isClose: function(start) {
1936 return (start < this.startPos + this.size + (this.size/2)) &&
1937 (start + this.size + (this.size/2) > this.startPos)
1940 isInRange: function(start, count) {
1941 return (start < this.startPos + this.size) && (start + count > this.startPos)
1944 isFullyInRange: function(position) {
1945 return (position >= this.startPos) && (position+this.metaData.getPageSize()) <= (this.startPos + this.size)
1948 isNearingTopLimit: function(position) {
1949 return position - this.startPos < this.metaData.getLimitTolerance();
1952 isNearingBottomLimit: function(position) {
1953 var myEnd = position + this.metaData.getPageSize();
1954 var bufferEnd = this.startPos + this.size;
1955 return bufferEnd - myEnd < this.metaData.getLimitTolerance();
1958 isAtTop: function() {
1959 return this.startPos == 0;
1962 isAtBottom: function() {
1963 return this.startPos + this.size == this.metaData.getTotalRows();
1966 isNearingLimit: function(position) {
1967 return ( !this.isAtTop() && this.isNearingTopLimit(position)) ||
1968 ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
1971 getRows: function(start, count) {
1972 var begPos = start - this.startPos
1973 var endPos = begPos + count
1975 // er? need more data...
1976 if ( endPos > this.size )
1979 var results = new Array()
1981 for ( var i=begPos ; i < endPos; i++ ) {
1982 results[index++] = this.rows[i]
1987 convertSpaces: function(s) {
1988 return s.split(" ").join(" ");
1993 Rico.LiveGridRequest = Class.create();
1994 Rico.LiveGridRequest.prototype = {
1995 initialize: function( requestOffset, options ) {
1996 this.requestOffset = requestOffset;
2000 // Rico.LiveGrid -----------------------------------------------------
2002 Rico.LiveGrid = Class.create();
2004 Rico.LiveGrid.prototype = {
2006 initialize: function( tableId, visibleRows, totalRows, url, options ) {
2008 if ( options == null )
2011 this.tableId = tableId;
2012 this.table = $(tableId);
2013 this.metaData = new Rico.LiveGridMetaData(visibleRows, totalRows, options);
2014 this.buffer = new Rico.LiveGridBuffer(this.metaData);
2015 this.scroller = new Rico.LiveGridScroller(this);
2017 this.lastDisplayedStartPos = 0;
2018 this.timeoutHander = null;
2019 this.additionalParms = options.requestParameters || [];
2021 this.processingRequest = null;
2022 this.unprocessedRequest = null;
2025 if ( options.prefetchBuffer )
2026 this.fetchBuffer(0, true);
2029 setRequestParams: function() {
2030 this.additionalParms = [];
2031 for ( var i=0 ; i < arguments.length ; i++ )
2032 this.additionalParms[i] = arguments[i];
2035 setTotalRows: function( newTotalRows ) {
2036 this.metaData.setTotalRows(newTotalRows);
2037 this.scroller.updateSize();
2040 initAjax: function(url) {
2041 ajaxEngine.registerRequest( this.tableId + '_request', url );
2042 ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
2045 invokeAjax: function() {
2048 largeBufferWindowStart: function(offset) {
2049 val = offset - ( (.5 * this.metaData.getLargeBufferSize()) - (.5 * this.metaData.getPageSize()) )
2050 return Math.max(parseInt(val), 0);
2053 handleTimedOut: function() {
2054 //server did not respond in 4 seconds... assume that there could have been
2055 //an error or something, and allow requests to be processed again...
2056 this.processingRequest = null;
2059 fetchBuffer: function(offset, fullBufferp) {
2060 if (this.processingRequest) {
2061 this.unprocessedRequest = new Rico.LiveGridRequest(offset);
2065 var fetchSize = this.metaData.getBufferSize(fullBufferp);
2066 bufferStartPos = Math.max(0,fullBufferp ? this.largeBufferWindowStart(offset) : offset);
2068 this.processingRequest = new Rico.LiveGridRequest(offset);
2069 this.processingRequest.bufferOffset = bufferStartPos;
2072 callParms.push(this.tableId + '_request');
2073 callParms.push('id=' + this.tableId);
2074 callParms.push('page_size=' + fetchSize);
2075 callParms.push('offset=' + bufferStartPos);
2077 for( var i=0 ; i < this.additionalParms.length ; i++ )
2078 callParms.push(this.additionalParms[i]);
2080 ajaxEngine.sendRequest.apply( ajaxEngine, callParms );
2081 this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), 4000 );
2084 requestContentRefresh: function(contentOffset) {
2085 if ( this.buffer && this.buffer.isFullyInRange(contentOffset) ) {
2086 this.updateContent(contentOffset);
2087 if (this.buffer.isNearingLimit(contentOffset))
2088 this.fetchBuffer(contentOffset, true);
2090 else if (this.buffer && this.buffer.isClose(contentOffset))
2091 this.fetchBuffer(contentOffset, true);
2093 this.fetchBuffer(contentOffset, false);
2096 ajaxUpdate: function(ajaxResponse) {
2098 clearTimeout( this.timeoutHandler );
2099 this.buffer = new Rico.LiveGridBuffer(this.metaData);
2100 this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
2101 if (this.unprocessedRequest == null) {
2102 offset = this.processingRequest.requestOffset;
2103 this.updateContent (offset);
2105 this.processingRequest = null;
2106 if (this.unprocessedRequest != null) {
2107 this.requestContentRefresh(this.unprocessedRequest.requestOffset);
2108 this.unprocessedRequest = null
2115 updateContent: function( offset ) {
2116 this.replaceCellContents(this.buffer, offset);
2119 replaceCellContents: function(buffer, startPos) {
2120 if (startPos == this.lastDisplayedStartPos){
2124 this.lastDisplayedStartPos = startPos
2125 var rows = buffer.getRows(startPos, this.metaData.getPageSize());
2126 for (var i=0; i < rows.length; i++) {
2128 for (var j=0; j < row.length; j++) {
2129 this.table.rows[i].cells[j].innerHTML = rows[i][j]
2135 // ricoUtil.js --------------------
2140 getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
2141 if ( arguments.length == 2 )
2142 mozillaEquivalentCSS = cssProperty;
2144 var el = $(htmlElement);
2145 if ( el.currentStyle )
2146 return el.currentStyle[cssProperty];
2148 return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
2151 createXmlDocument : function() {
2152 if (document.implementation && document.implementation.createDocument) {
2153 var doc = document.implementation.createDocument("", "", null);
2155 if (doc.readyState == null) {
2157 doc.addEventListener("load", function () {
2159 if (typeof doc.onreadystatechange == "function")
2160 doc.onreadystatechange();
2167 if (window.ActiveXObject)
2169 function() { return new ActiveXObject('MSXML2.DomDocument') },
2170 function() { return new ActiveXObject('Microsoft.DomDocument')},
2171 function() { return new ActiveXObject('MSXML.DomDocument') },
2172 function() { return new ActiveXObject('MSXML3.DomDocument') }
2178 toViewportPosition: function(element) {
2179 return this._toAbsolute(element,true);
2182 toDocumentPosition: function(element) {
2183 return this._toAbsolute(element,false);
2187 * Compute the elements position in terms of the window viewport
2188 * so that it can be compared to the position of the mouse (dnd)
2189 * This is additions of all the offsetTop,offsetLeft values up the
2190 * offsetParent hierarchy, ...taking into account any scrollTop,
2191 * scrollLeft values along the way...
2193 * IE has a bug reporting a correct offsetLeft of elements within a
2194 * a relatively positioned parent!!!
2196 _toAbsolute: function(element,accountForDocScroll) {
2198 if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
2199 return this._toAbsoluteMozilla(element,accountForDocScroll);
2203 var parent = element;
2206 var borderXOffset = 0;
2207 var borderYOffset = 0;
2208 if ( parent != element ) {
2209 var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
2210 var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
2211 borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
2212 borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
2215 x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
2216 y += parent.offsetTop - parent.scrollTop + borderYOffset;
2217 parent = parent.offsetParent;
2220 if ( accountForDocScroll ) {
2221 x -= this.docScrollLeft();
2222 y -= this.docScrollTop();
2225 return { x:x, y:y };
2229 * Mozilla did not report all of the parents up the hierarchy via the
2230 * offsetParent property that IE did. So for the calculation of the
2231 * offsets we use the offsetParent property, but for the calculation of
2232 * the scrollTop/scrollLeft adjustments we navigate up via the parentNode
2233 * property instead so as to get the scroll offsets...
2236 _toAbsoluteMozilla: function(element,accountForDocScroll) {
2239 var parent = element;
2241 x += parent.offsetLeft;
2242 y += parent.offsetTop;
2243 parent = parent.offsetParent;
2248 parent != document.body &&
2249 parent != document.documentElement ) {
2250 if ( parent.scrollLeft )
2251 x -= parent.scrollLeft;
2252 if ( parent.scrollTop )
2253 y -= parent.scrollTop;
2254 parent = parent.parentNode;
2257 if ( accountForDocScroll ) {
2258 x -= this.docScrollLeft();
2259 y -= this.docScrollTop();
2262 return { x:x, y:y };
2265 docScrollLeft: function() {
2266 if ( window.pageXOffset )
2267 return window.pageXOffset;
2268 else if ( document.documentElement && document.documentElement.scrollLeft )
2269 return document.documentElement.scrollLeft;
2270 else if ( document.body )
2271 return document.body.scrollLeft;
2276 docScrollTop: function() {
2277 if ( window.pageYOffset )
2278 return window.pageYOffset;
2279 else if ( document.documentElement && document.documentElement.scrollTop )
2280 return document.documentElement.scrollTop;
2281 else if ( document.body )
2282 return document.body.scrollTop;