3 * Copyright 2005 Sabre Airline Solutions
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 //-------------------- rico.js
22 Rico.ArrayExtensions = new Array();
24 if (Object.prototype.extend) {
26 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
29 if (Array.prototype.push) {
31 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
34 if (!Array.prototype.remove) {
35 Array.prototype.remove = function(dx) {
36 if( isNaN(dx) || dx > this.length )
38 for( var i=0,n=0; i<this.length; i++ )
43 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
46 if (!Array.prototype.removeItem) {
47 Array.prototype.removeItem = function(item) {
48 for ( var i = 0 ; i < this.length ; i++ )
49 if ( this[i] == item ) {
54 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
57 if (!Array.prototype.indices) {
58 Array.prototype.indices = function() {
59 var indexArray = new Array();
60 for ( index in this ) {
61 var ignoreThis = false;
62 for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
63 if ( this[index] == Rico.ArrayExtensions[i] ) {
69 indexArray[ indexArray.length ] = index;
73 Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
76 // Create the loadXML method and xml getter for Mozilla
77 if ( window.DOMParser &&
78 window.XMLSerializer &&
79 window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
81 if (!Document.prototype.loadXML) {
82 Document.prototype.loadXML = function (s) {
83 var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
84 while (this.hasChildNodes())
85 this.removeChild(this.lastChild);
87 for (var i = 0; i < doc2.childNodes.length; i++) {
88 this.appendChild(this.importNode(doc2.childNodes[i], true));
93 Document.prototype.__defineGetter__( "xml",
95 return (new XMLSerializer()).serializeToString(this);
100 document.getElementsByTagAndClassName = function(tagName, className) {
101 if ( tagName == null )
104 var children = document.getElementsByTagName(tagName) || document.all;
105 var elements = new Array();
107 if ( className == null )
110 for (var i = 0; i < children.length; i++) {
111 var child = children[i];
112 var classNames = child.className.split(' ');
113 for (var j = 0; j < classNames.length; j++) {
114 if (classNames[j] == className) {
115 elements.push(child);
125 //-------------------- ricoAccordion.js
127 Rico.Accordion = Class.create();
129 Rico.Accordion.prototype = {
131 initialize: function(container, options) {
132 this.container = $(container);
133 this.lastExpandedTab = null;
134 this.accordionTabs = new Array();
135 this.setOptions(options);
136 this._attachBehaviors();
138 this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
140 // set the initial visual state...
141 for ( var i=1 ; i < this.accordionTabs.length ; i++ )
143 this.accordionTabs[i].collapse();
144 this.accordionTabs[i].content.style.display = 'none';
146 this.lastExpandedTab = this.accordionTabs[0];
147 this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
148 this.lastExpandedTab.showExpanded();
149 this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
152 setOptions: function(options) {
154 expandedBg : '#63699c',
156 collapsedBg : '#6b79a5',
157 expandedTextColor : '#ffffff',
158 expandedFontWeight : 'bold',
159 hoverTextColor : '#ffffff',
160 collapsedTextColor : '#ced7ef',
161 collapsedFontWeight : 'normal',
162 hoverTextColor : '#ffffff',
163 borderColor : '#1f669b',
167 }.extend(options || {});
170 showTabByIndex: function( anIndex, animate ) {
171 var doAnimate = arguments.length == 1 ? true : animate;
172 this.showTab( this.accordionTabs[anIndex], doAnimate );
175 showTab: function( accordionTab, animate ) {
177 var doAnimate = arguments.length == 1 ? true : animate;
179 if ( this.options.onHideTab )
180 this.options.onHideTab(this.lastExpandedTab);
182 this.lastExpandedTab.showCollapsed();
183 var accordion = this;
184 var lastExpandedTab = this.lastExpandedTab;
186 this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
187 accordionTab.content.style.display = '';
189 accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
192 new Effect.AccordionSize( this.lastExpandedTab.content,
193 accordionTab.content,
195 this.options.panelHeight,
197 { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
198 this.lastExpandedTab = accordionTab;
201 this.lastExpandedTab.content.style.height = "1px";
202 accordionTab.content.style.height = this.options.panelHeight + "px";
203 this.lastExpandedTab = accordionTab;
204 this.showTabDone(lastExpandedTab);
208 showTabDone: function(collapsedTab) {
209 collapsedTab.content.style.display = 'none';
210 this.lastExpandedTab.showExpanded();
211 if ( this.options.onShowTab )
212 this.options.onShowTab(this.lastExpandedTab);
215 _attachBehaviors: function() {
216 var panels = this._getDirectChildrenByTag(this.container, 'DIV');
217 for ( var i = 0 ; i < panels.length ; i++ ) {
219 var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
220 if ( tabChildren.length != 2 )
221 continue; // unexpected
223 var tabTitleBar = tabChildren[0];
224 var tabContentBox = tabChildren[1];
225 this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
229 _getDirectChildrenByTag: function(e, tagName) {
230 var kids = new Array();
231 var allKids = e.childNodes;
232 for( var i = 0 ; i < allKids.length ; i++ )
233 if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
234 kids.push(allKids[i]);
240 Rico.Accordion.Tab = Class.create();
242 Rico.Accordion.Tab.prototype = {
244 initialize: function(accordion, titleBar, content) {
245 this.accordion = accordion;
246 this.titleBar = titleBar;
247 this.content = content;
248 this._attachBehaviors();
251 collapse: function() {
252 this.showCollapsed();
253 this.content.style.height = "1px";
256 showCollapsed: function() {
257 this.expanded = false;
258 this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
259 this.titleBar.style.color = this.accordion.options.collapsedTextColor;
260 this.titleBar.style.fontWeight = this.accordion.options.collapsedFontWeight;
261 this.content.style.overflow = "hidden";
264 showExpanded: function() {
265 this.expanded = true;
266 this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
267 this.titleBar.style.color = this.accordion.options.expandedTextColor;
268 this.content.style.overflow = "visible";
271 titleBarClicked: function(e) {
272 if ( this.accordion.lastExpandedTab == this )
274 this.accordion.showTab(this);
278 this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
279 this.titleBar.style.color = this.accordion.options.hoverTextColor;
282 unhover: function(e) {
283 if ( this.expanded ) {
284 this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
285 this.titleBar.style.color = this.accordion.options.expandedTextColor;
288 this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
289 this.titleBar.style.color = this.accordion.options.collapsedTextColor;
293 _attachBehaviors: function() {
294 this.content.style.border = "1px solid " + this.accordion.options.borderColor;
295 this.content.style.borderTopWidth = "0px";
296 this.content.style.borderBottomWidth = "0px";
297 this.content.style.margin = "0px";
299 this.titleBar.onclick = this.titleBarClicked.bindAsEventListener(this);
300 this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
301 this.titleBar.onmouseout = this.unhover.bindAsEventListener(this);
307 //-------------------- ricoAjaxEngine.js
309 Rico.AjaxEngine = Class.create();
311 Rico.AjaxEngine.prototype = {
313 initialize: function() {
314 this.ajaxElements = new Array();
315 this.ajaxObjects = new Array();
316 this.requestURLS = new Array();
319 registerAjaxElement: function( anId, anElement ) {
320 if ( arguments.length == 1 )
322 this.ajaxElements[anId] = anElement;
325 registerAjaxObject: function( anId, anObject ) {
326 this.ajaxObjects[anId] = anObject;
329 registerRequest: function (requestLogicalName, requestURL) {
330 this.requestURLS[requestLogicalName] = requestURL;
333 sendRequest: function(requestName) {
334 var requestURL = this.requestURLS[requestName];
335 if ( requestURL == null )
338 var queryString = "";
339 if ( arguments.length > 1 )
340 queryString = this._createQueryString(arguments, 1);
342 new Ajax.Request(requestURL, this._requestOptions(queryString));
345 sendRequestWithData: function(requestName, xmlDocument) {
346 var requestURL = this.requestURLS[requestName];
347 if ( requestURL == null )
350 var queryString = "";
351 if ( arguments.length > 2 )
352 queryString = this._createQueryString(arguments, 2);
354 new Ajax.Request(requestURL + "?" + queryString, this._requestOptions(null,xmlDocument));
357 sendRequestAndUpdate: function(requestName,container,options) {
358 var requestURL = this.requestURLS[requestName];
359 if ( requestURL == null )
362 var queryString = "";
363 if ( arguments.length > 3 )
364 queryString = this._createQueryString(arguments, 3);
366 var updaterOptions = this._requestOptions(queryString);
367 updaterOptions.onComplete = null;
368 updaterOptions.extend(options);
370 new Ajax.Updater(container, requestURL, updaterOptions);
373 sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
374 var requestURL = this.requestURLS[requestName];
375 if ( requestURL == null )
378 var queryString = "";
379 if ( arguments.length > 4 )
380 queryString = this._createQueryString(arguments, 4);
383 var updaterOptions = this._requestOptions(queryString,xmlDocument);
384 updaterOptions.onComplete = null;
385 updaterOptions.extend(options);
387 new Ajax.Updater(container, requestURL + "?" + queryString, updaterOptions);
390 // Private -- not part of intended engine API --------------------------------------------------------------------
392 _requestOptions: function(queryString,xmlDoc) {
395 var requestHeaders = ['X-Rico-Version', Rico.Version ];
396 var sendMethod = "post"
398 requestHeaders.push( 'Content-type', 'text/xml' );
402 return { requestHeaders: requestHeaders,
403 parameters: queryString,
404 postBody: arguments[1] ? xmlDoc : null,
406 onComplete: self._onRequestComplete.bind(self) };
409 _createQueryString: function( theArgs, offset ) {
411 for ( var i = offset ; i < theArgs.length ; i++ ) {
415 var anArg = theArgs[i];
417 if ( anArg.name != undefined && anArg.value != undefined ) {
418 queryString += anArg.name + "=" + escape(anArg.value);
421 var ePos = anArg.indexOf('=');
422 var argName = anArg.substring( 0, ePos );
423 var argValue = anArg.substring( ePos + 1 );
424 queryString += argName + "=" + escape(argValue);
431 _onRequestComplete : function(request) {
433 //!!TODO: error handling infrastructure??
434 if (request.status != 200)
437 var response = request.responseXML.getElementsByTagName("ajax-response");
438 if (response == null || response.length != 1)
440 this._processAjaxResponse( response[0].childNodes );
443 _processAjaxResponse: function( xmlResponseElements ) {
444 for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
445 var responseElement = xmlResponseElements[i];
447 // only process nodes of type element.....
448 if ( responseElement.nodeType != 1 )
451 var responseType = responseElement.getAttribute("type");
452 var responseId = responseElement.getAttribute("id");
454 if ( responseType == "object" )
455 this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
456 else if ( responseType == "element" )
457 this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
459 alert('unrecognized AjaxResponse type : ' + responseType );
463 _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
464 ajaxObject.ajaxUpdate( responseElement );
467 _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
468 ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
473 var ajaxEngine = new Rico.AjaxEngine();
476 //-------------------- ricoColor.js
477 Rico.Color = Class.create();
479 Rico.Color.prototype = {
481 initialize: function(red, green, blue) {
482 this.rgb = { r: red, g : green, b : blue };
485 setRed: function(r) {
489 setGreen: function(g) {
493 setBlue: function(b) {
497 setHue: function(h) {
499 // get an HSB model, and set the new hue...
500 var hsb = this.asHSB();
503 // convert back to RGB...
504 this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
507 setSaturation: function(s) {
508 // get an HSB model, and set the new hue...
509 var hsb = this.asHSB();
512 // convert back to RGB and set values...
513 this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
516 setBrightness: function(b) {
517 // get an HSB model, and set the new hue...
518 var hsb = this.asHSB();
521 // convert back to RGB and set values...
522 this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
525 darken: function(percent) {
526 var hsb = this.asHSB();
527 this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
530 brighten: function(percent) {
531 var hsb = this.asHSB();
532 this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
535 blend: function(other) {
536 this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
537 this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
538 this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
541 isBright: function() {
542 var hsb = this.asHSB();
543 return this.asHSB().b > 0.5;
547 return ! this.isBright();
551 return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
555 return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
559 return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
562 toString: function() {
568 Rico.Color.createFromHex = function(hexCode) {
570 if ( hexCode.indexOf('#') == 0 )
571 hexCode = hexCode.substring(1);
572 var red = hexCode.substring(0,2);
573 var green = hexCode.substring(2,4);
574 var blue = hexCode.substring(4,6);
575 return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
579 * Factory method for creating a color from the background of
582 Rico.Color.createColorFromBackground = function(elem) {
584 var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");
586 if ( actualColor == "transparent" && elem.parent )
587 return Rico.Color.createColorFromBackground(elem.parent);
589 if ( actualColor == null )
590 return new Rico.Color(255,255,255);
592 if ( actualColor.indexOf("rgb(") == 0 ) {
593 var colors = actualColor.substring(4, actualColor.length - 1 );
594 var colorArray = colors.split(",");
595 return new Rico.Color( parseInt( colorArray[0] ),
596 parseInt( colorArray[1] ),
597 parseInt( colorArray[2] ) );
600 else if ( actualColor.indexOf("#") == 0 ) {
601 var redPart = parseInt(actualColor.substring(1,3), 16);
602 var greenPart = parseInt(actualColor.substring(3,5), 16);
603 var bluePart = parseInt(actualColor.substring(5), 16);
604 return new Rico.Color( redPart, greenPart, bluePart );
607 return new Rico.Color(255,255,255);
610 Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
616 if (saturation == 0) {
617 red = parseInt(brightness * 255.0 + 0.5);
622 var h = (hue - Math.floor(hue)) * 6.0;
623 var f = h - Math.floor(h);
624 var p = brightness * (1.0 - saturation);
625 var q = brightness * (1.0 - saturation * f);
626 var t = brightness * (1.0 - (saturation * (1.0 - f)));
628 switch (parseInt(h)) {
630 red = (brightness * 255.0 + 0.5);
631 green = (t * 255.0 + 0.5);
632 blue = (p * 255.0 + 0.5);
635 red = (q * 255.0 + 0.5);
636 green = (brightness * 255.0 + 0.5);
637 blue = (p * 255.0 + 0.5);
640 red = (p * 255.0 + 0.5);
641 green = (brightness * 255.0 + 0.5);
642 blue = (t * 255.0 + 0.5);
645 red = (p * 255.0 + 0.5);
646 green = (q * 255.0 + 0.5);
647 blue = (brightness * 255.0 + 0.5);
650 red = (t * 255.0 + 0.5);
651 green = (p * 255.0 + 0.5);
652 blue = (brightness * 255.0 + 0.5);
655 red = (brightness * 255.0 + 0.5);
656 green = (p * 255.0 + 0.5);
657 blue = (q * 255.0 + 0.5);
662 return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
665 Rico.Color.RGBtoHSB = function(r, g, b) {
671 var cmax = (r > g) ? r : g;
675 var cmin = (r < g) ? r : g;
679 brightness = cmax / 255.0;
681 saturation = (cmax - cmin)/cmax;
688 var redc = (cmax - r)/(cmax - cmin);
689 var greenc = (cmax - g)/(cmax - cmin);
690 var bluec = (cmax - b)/(cmax - cmin);
693 hue = bluec - greenc;
695 hue = 2.0 + redc - bluec;
697 hue = 4.0 + greenc - redc;
704 return { h : hue, s : saturation, b : brightness };
708 //-------------------- ricoCorner.js
712 round: function(e, options) {
714 this._setOptions(options);
716 var color = this.options.color;
717 if ( this.options.color == "fromElement" )
718 color = this._background(e);
720 var bgColor = this.options.bgColor;
721 if ( this.options.bgColor == "fromParent" )
722 bgColor = this._background(e.offsetParent);
724 this._roundCornersImpl(e, color, bgColor);
727 _roundCornersImpl: function(e, color, bgColor) {
728 if(this.options.border)
729 this._renderBorder(e,bgColor);
730 if(this._isTopRounded())
731 this._roundTopCorners(e,color,bgColor);
732 if(this._isBottomRounded())
733 this._roundBottomCorners(e,color,bgColor);
736 _renderBorder: function(el,bgColor) {
737 var borderValue = "1px solid " + this._borderColor(bgColor);
738 var borderL = "border-left: " + borderValue;
739 var borderR = "border-right: " + borderValue;
740 var style = "style='" + borderL + ";" + borderR + "'";
741 el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
744 _roundTopCorners: function(el, color, bgColor) {
745 var corner = this._createCorner(bgColor);
746 for(var i=0 ; i < this.options.numSlices ; i++ )
747 corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
748 el.style.paddingTop = 0;
749 el.insertBefore(corner,el.firstChild);
752 _roundBottomCorners: function(el, color, bgColor) {
753 var corner = this._createCorner(bgColor);
754 for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
755 corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
756 el.style.paddingBottom = 0;
757 el.appendChild(corner);
760 _createCorner: function(bgColor) {
761 var corner = document.createElement("div");
762 corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
766 _createCornerSlice: function(color,bgColor, n, position) {
767 var slice = document.createElement("span");
769 var inStyle = slice.style;
770 inStyle.backgroundColor = color;
771 inStyle.display = "block";
772 inStyle.height = "1px";
773 inStyle.overflow = "hidden";
774 inStyle.fontSize = "1px";
776 var borderColor = this._borderColor(color,bgColor);
777 if ( this.options.border && n == 0 ) {
778 inStyle.borderTopStyle = "solid";
779 inStyle.borderTopWidth = "1px";
780 inStyle.borderLeftWidth = "0px";
781 inStyle.borderRightWidth = "0px";
782 inStyle.borderBottomWidth = "0px";
783 inStyle.height = "0px"; // assumes css compliant box model
784 inStyle.borderColor = borderColor;
786 else if(borderColor) {
787 inStyle.borderColor = borderColor;
788 inStyle.borderStyle = "solid";
789 inStyle.borderWidth = "0px 1px";
792 if ( !this.options.compact && (n == (this.options.numSlices-1)) )
793 inStyle.height = "2px";
795 this._setMargin(slice, n, position);
796 this._setBorder(slice, n, position);
801 _setOptions: function(options) {
804 color : "fromElement",
805 bgColor : "fromParent",
809 }.extend(options || {});
811 this.options.numSlices = this.options.compact ? 2 : 4;
812 if ( this._isTransparent() )
813 this.options.blend = false;
816 _whichSideTop: function() {
817 if ( this._hasString(this.options.corners, "all", "top") )
820 if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
823 if (this.options.corners.indexOf("tl") >= 0)
825 else if (this.options.corners.indexOf("tr") >= 0)
830 _whichSideBottom: function() {
831 if ( this._hasString(this.options.corners, "all", "bottom") )
834 if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
837 if(this.options.corners.indexOf("bl") >=0)
839 else if(this.options.corners.indexOf("br")>=0)
844 _borderColor : function(color,bgColor) {
845 if ( color == "transparent" )
847 else if ( this.options.border )
848 return this.options.border;
849 else if ( this.options.blend )
850 return this._blend( bgColor, color );
856 _setMargin: function(el, n, corners) {
857 var marginSize = this._marginSize(n);
858 var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
860 if ( whichSide == "left" ) {
861 el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
863 else if ( whichSide == "right" ) {
864 el.style.marginRight = marginSize + "px"; el.style.marginLeft = "0px";
867 el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
871 _setBorder: function(el,n,corners) {
872 var borderSize = this._borderSize(n);
873 var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
875 if ( whichSide == "left" ) {
876 el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
878 else if ( whichSide == "right" ) {
879 el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth = "0px";
882 el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
886 _marginSize: function(n) {
887 if ( this._isTransparent() )
890 var marginSizes = [ 5, 3, 2, 1 ];
891 var blendedMarginSizes = [ 3, 2, 1, 0 ];
892 var compactMarginSizes = [ 2, 1 ];
893 var smBlendedMarginSizes = [ 1, 0 ];
895 if ( this.options.compact && this.options.blend )
896 return smBlendedMarginSizes[n];
897 else if ( this.options.compact )
898 return compactMarginSizes[n];
899 else if ( this.options.blend )
900 return blendedMarginSizes[n];
902 return marginSizes[n];
905 _borderSize: function(n) {
906 var transparentBorderSizes = [ 5, 3, 2, 1 ];
907 var blendedBorderSizes = [ 2, 1, 1, 1 ];
908 var compactBorderSizes = [ 1, 0 ];
909 var actualBorderSizes = [ 0, 2, 0, 0 ];
911 if ( this.options.compact && (this.options.blend || this._isTransparent()) )
913 else if ( this.options.compact )
914 return compactBorderSizes[n];
915 else if ( this.options.blend )
916 return blendedBorderSizes[n];
917 else if ( this.options.border )
918 return actualBorderSizes[n];
919 else if ( this._isTransparent() )
920 return transparentBorderSizes[n];
924 _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
925 _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
926 _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
927 _isTransparent: function() { return this.options.color == "transparent"; },
928 _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
929 _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
930 _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
934 //-------------------- ricoDragAndDrop.js
935 Rico.DragAndDrop = Class.create();
937 Rico.DragAndDrop.prototype = {
939 initialize: function() {
940 this.dropZones = new Array();
941 this.draggables = new Array();
942 this.currentDragObjects = new Array();
943 this.dragElement = null;
944 this.lastSelectedDraggable = null;
945 this.currentDragObjectVisible = false;
946 this.interestedInMotionEvents = false;
949 registerDropZone: function(aDropZone) {
950 this.dropZones[ this.dropZones.length ] = aDropZone;
953 deregisterDropZone: function(aDropZone) {
954 var newDropZones = new Array();
956 for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
957 if ( this.dropZones[i] != aDropZone )
958 newDropZones[j++] = this.dropZones[i];
961 this.dropZones = newDropZones;
964 clearDropZones: function() {
965 this.dropZones = new Array();
968 registerDraggable: function( aDraggable ) {
969 this.draggables[ this.draggables.length ] = aDraggable;
970 this._addMouseDownHandler( aDraggable );
973 clearSelection: function() {
974 for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
975 this.currentDragObjects[i].deselect();
976 this.currentDragObjects = new Array();
977 this.lastSelectedDraggable = null;
980 hasSelection: function() {
981 return this.currentDragObjects.length > 0;
984 setStartDragFromElement: function( e, mouseDownElement ) {
985 this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
986 this.startx = e.screenX - this.origPos.x
987 this.starty = e.screenY - this.origPos.y
988 //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
989 //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
990 //this.adjustedForDraggableSize = false;
992 this.interestedInMotionEvents = this.hasSelection();
993 this._terminateEvent(e);
996 updateSelection: function( draggable, extendSelection ) {
997 if ( ! extendSelection )
998 this.clearSelection();
1000 if ( draggable.isSelected() ) {
1001 this.currentDragObjects.removeItem(draggable);
1002 draggable.deselect();
1003 if ( draggable == this.lastSelectedDraggable )
1004 this.lastSelectedDraggable = null;
1007 this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
1009 this.lastSelectedDraggable = draggable;
1013 _mouseDownHandler: function(e) {
1014 if ( arguments.length == 0 )
1017 // if not button 1 ignore it...
1018 var nsEvent = e.which != undefined;
1019 if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
1022 var eventTarget = e.target ? e.target : e.srcElement;
1023 var draggableObject = eventTarget.draggable;
1025 var candidate = eventTarget;
1026 while (draggableObject == null && candidate.parentNode) {
1027 candidate = candidate.parentNode;
1028 draggableObject = candidate.draggable;
1031 if ( draggableObject == null )
1034 this.updateSelection( draggableObject, e.ctrlKey );
1036 // clear the drop zones postion cache...
1037 if ( this.hasSelection() )
1038 for ( var i = 0 ; i < this.dropZones.length ; i++ )
1039 this.dropZones[i].clearPositionCache();
1041 this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
1045 _mouseMoveHandler: function(e) {
1046 var nsEvent = e.which != undefined;
1047 if ( !this.interestedInMotionEvents ) {
1048 this._terminateEvent(e);
1052 if ( ! this.hasSelection() )
1055 if ( ! this.currentDragObjectVisible )
1058 if ( !this.activatedDropZones )
1059 this._activateRegisteredDropZones();
1061 //if ( !this.adjustedForDraggableSize )
1062 // this._adjustForDraggableSize(e);
1064 this._updateDraggableLocation(e);
1065 this._updateDropZonesHover(e);
1067 this._terminateEvent(e);
1070 _makeDraggableObjectVisible: function(e)
1072 if ( !this.hasSelection() )
1076 if ( this.currentDragObjects.length > 1 )
1077 dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
1079 dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
1081 // go ahead and absolute position it...
1082 if ( RicoUtil.getElementsComputedStyle(dragElement, "position") != "absolute" )
1083 dragElement.style.position = "absolute";
1085 // need to parent him into the document...
1086 if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
1087 document.body.appendChild(dragElement);
1089 this.dragElement = dragElement;
1090 this._updateDraggableLocation(e);
1092 this.currentDragObjectVisible = true;
1096 _adjustForDraggableSize: function(e) {
1097 var dragElementWidth = this.dragElement.offsetWidth;
1098 var dragElementHeight = this.dragElement.offsetHeight;
1099 if ( this.startComponentX > dragElementWidth )
1100 this.startx -= this.startComponentX - dragElementWidth + 2;
1102 if ( this.startComponentY > dragElementHeight )
1103 this.starty -= this.startComponentY - dragElementHeight + 2;
1105 this.adjustedForDraggableSize = true;
1109 _updateDraggableLocation: function(e) {
1110 var dragObjectStyle = this.dragElement.style;
1111 dragObjectStyle.left = (e.screenX - this.startx) + "px"
1112 dragObjectStyle.top = (e.screenY - this.starty) + "px";
1115 _updateDropZonesHover: function(e) {
1116 var n = this.dropZones.length;
1117 for ( var i = 0 ; i < n ; i++ ) {
1118 if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
1119 this.dropZones[i].hideHover();
1122 for ( var i = 0 ; i < n ; i++ ) {
1123 if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
1124 if ( this.dropZones[i].canAccept(this.currentDragObjects) )
1125 this.dropZones[i].showHover();
1130 _startDrag: function(e) {
1131 for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
1132 this.currentDragObjects[i].startDrag();
1134 this._makeDraggableObjectVisible(e);
1137 _mouseUpHandler: function(e) {
1138 if ( ! this.hasSelection() )
1141 var nsEvent = e.which != undefined;
1142 if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
1145 this.interestedInMotionEvents = false;
1147 if ( this.dragElement == null ) {
1148 this._terminateEvent(e);
1152 if ( this._placeDraggableInDropZone(e) )
1153 this._completeDropOperation(e);
1155 this._terminateEvent(e);
1156 new Effect.Position( this.dragElement,
1161 { complete : this._doCancelDragProcessing.bind(this) } );
1165 _completeDropOperation: function(e) {
1166 if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
1167 if ( this.dragElement.parentNode != null )
1168 this.dragElement.parentNode.removeChild(this.dragElement);
1171 this._deactivateRegisteredDropZones();
1173 this.clearSelection();
1174 this.dragElement = null;
1175 this.currentDragObjectVisible = false;
1176 this._terminateEvent(e);
1179 _doCancelDragProcessing: function() {
1182 if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
1183 if ( this.dragElement.parentNode != null ) {
1184 this.dragElement.parentNode.removeChild(this.dragElement);
1188 this._deactivateRegisteredDropZones();
1189 this.dragElement = null;
1190 this.currentDragObjectVisible = false;
1193 _placeDraggableInDropZone: function(e) {
1194 var foundDropZone = false;
1195 var n = this.dropZones.length;
1196 for ( var i = 0 ; i < n ; i++ ) {
1197 if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
1198 if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
1199 this.dropZones[i].hideHover();
1200 this.dropZones[i].accept(this.currentDragObjects);
1201 foundDropZone = true;
1207 return foundDropZone;
1210 _cancelDrag: function() {
1211 for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
1212 this.currentDragObjects[i].cancelDrag();
1215 _endDrag: function() {
1216 for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
1217 this.currentDragObjects[i].endDrag();
1220 _mousePointInDropZone: function( e, dropZone ) {
1222 var absoluteRect = dropZone.getAbsoluteRect();
1224 return e.clientX > absoluteRect.left &&
1225 e.clientX < absoluteRect.right &&
1226 e.clientY > absoluteRect.top &&
1227 e.clientY < absoluteRect.bottom;
1230 _addMouseDownHandler: function( aDraggable )
1232 var htmlElement = aDraggable.getMouseDownHTMLElement();
1233 if ( htmlElement != null ) {
1234 htmlElement.draggable = aDraggable;
1235 this._addMouseDownEvent( htmlElement );
1239 _activateRegisteredDropZones: function() {
1240 var n = this.dropZones.length;
1241 for ( var i = 0 ; i < n ; i++ ) {
1242 var dropZone = this.dropZones[i];
1243 if ( dropZone.canAccept(this.currentDragObjects) )
1244 dropZone.activate();
1247 this.activatedDropZones = true;
1250 _deactivateRegisteredDropZones: function() {
1251 var n = this.dropZones.length;
1252 for ( var i = 0 ; i < n ; i++ )
1253 this.dropZones[i].deactivate();
1254 this.activatedDropZones = false;
1257 _addMouseDownEvent: function( htmlElement ) {
1258 if ( typeof document.implementation != "undefined" &&
1259 document.implementation.hasFeature("HTML", "1.0") &&
1260 document.implementation.hasFeature("Events", "2.0") &&
1261 document.implementation.hasFeature("CSS", "2.0") ) {
1262 htmlElement.addEventListener("mousedown", this._mouseDownHandler.bindAsEventListener(this), false);
1265 htmlElement.attachEvent( "onmousedown", this._mouseDownHandler.bindAsEventListener(this) );
1269 _terminateEvent: function(e) {
1270 if ( e.stopPropagation != undefined )
1271 e.stopPropagation();
1272 else if ( e.cancelBubble != undefined )
1273 e.cancelBubble = true;
1275 if ( e.preventDefault != undefined )
1278 e.returnValue = false;
1281 initializeEventHandlers: function() {
1282 if ( typeof document.implementation != "undefined" &&
1283 document.implementation.hasFeature("HTML", "1.0") &&
1284 document.implementation.hasFeature("Events", "2.0") &&
1285 document.implementation.hasFeature("CSS", "2.0") ) {
1286 document.addEventListener("mouseup", this._mouseUpHandler.bindAsEventListener(this), false);
1287 document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
1290 document.attachEvent( "onmouseup", this._mouseUpHandler.bindAsEventListener(this) );
1291 document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
1296 var dndMgr = new Rico.DragAndDrop();
1297 dndMgr.initializeEventHandlers();
1300 //-------------------- ricoDraggable.js
1301 Rico.Draggable = Class.create();
1303 Rico.Draggable.prototype = {
1305 initialize: function( type, htmlElement ) {
1307 this.htmlElement = $(htmlElement);
1308 this.selected = false;
1312 * Returns the HTML element that should have a mouse down event
1313 * added to it in order to initiate a drag operation
1316 getMouseDownHTMLElement: function() {
1317 return this.htmlElement;
1320 select: function() {
1321 this.selected = true;
1323 if ( this.showingSelected )
1326 var htmlElement = this.getMouseDownHTMLElement();
1328 var color = Rico.Color.createColorFromBackground(htmlElement);
1329 color.isBright() ? color.darken(0.033) : color.brighten(0.033);
1331 this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
1332 htmlElement.style.backgroundColor = color.asHex();
1333 this.showingSelected = true;
1336 deselect: function() {
1337 this.selected = false;
1338 if ( !this.showingSelected )
1341 var htmlElement = this.getMouseDownHTMLElement();
1343 htmlElement.style.backgroundColor = this.saveBackground;
1344 this.showingSelected = false;
1347 isSelected: function() {
1348 return this.selected;
1351 startDrag: function() {
1354 cancelDrag: function() {
1357 endDrag: function() {
1360 getSingleObjectDragGUI: function() {
1361 return this.htmlElement;
1364 getMultiObjectDragGUI: function( draggables ) {
1365 return this.htmlElement;
1368 getDroppedGUI: function() {
1369 return this.htmlElement;
1372 toString: function() {
1373 return this.type + ":" + this.htmlElement + ":";
1379 //-------------------- ricoDropzone.js
1380 Rico.Dropzone = Class.create();
1382 Rico.Dropzone.prototype = {
1384 initialize: function( htmlElement ) {
1385 this.htmlElement = $(htmlElement);
1386 this.absoluteRect = null;
1389 getHTMLElement: function() {
1390 return this.htmlElement;
1393 clearPositionCache: function() {
1394 this.absoluteRect = null;
1397 getAbsoluteRect: function() {
1398 if ( this.absoluteRect == null ) {
1399 var htmlElement = this.getHTMLElement();
1400 var pos = RicoUtil.toViewportPosition(htmlElement);
1402 this.absoluteRect = {
1405 bottom: pos.y + htmlElement.offsetHeight,
1406 right: pos.x + htmlElement.offsetWidth
1409 return this.absoluteRect;
1412 activate: function() {
1413 var htmlElement = this.getHTMLElement();
1414 if (htmlElement == null || this.showingActive)
1417 this.showingActive = true;
1418 this.saveBackgroundColor = htmlElement.style.backgroundColor;
1420 var fallbackColor = "#ffea84";
1421 var currentColor = Rico.Color.createColorFromBackground(htmlElement);
1422 if ( currentColor == null )
1423 htmlElement.style.backgroundColor = fallbackColor;
1425 currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
1426 htmlElement.style.backgroundColor = currentColor.asHex();
1430 deactivate: function() {
1431 var htmlElement = this.getHTMLElement();
1432 if (htmlElement == null || !this.showingActive)
1435 htmlElement.style.backgroundColor = this.saveBackgroundColor;
1436 this.showingActive = false;
1437 this.saveBackgroundColor = null;
1440 showHover: function() {
1441 var htmlElement = this.getHTMLElement();
1442 if ( htmlElement == null || this.showingHover )
1445 this.saveBorderWidth = htmlElement.style.borderWidth;
1446 this.saveBorderStyle = htmlElement.style.borderStyle;
1447 this.saveBorderColor = htmlElement.style.borderColor;
1449 this.showingHover = true;
1450 htmlElement.style.borderWidth = "1px";
1451 htmlElement.style.borderStyle = "solid";
1452 //htmlElement.style.borderColor = "#ff9900";
1453 htmlElement.style.borderColor = "#ffff00";
1456 hideHover: function() {
1457 var htmlElement = this.getHTMLElement();
1458 if ( htmlElement == null || !this.showingHover )
1461 htmlElement.style.borderWidth = this.saveBorderWidth;
1462 htmlElement.style.borderStyle = this.saveBorderStyle;
1463 htmlElement.style.borderColor = this.saveBorderColor;
1464 this.showingHover = false;
1467 canAccept: function(draggableObjects) {
1471 accept: function(draggableObjects) {
1472 var htmlElement = this.getHTMLElement();
1473 if ( htmlElement == null )
1476 n = draggableObjects.length;
1477 for ( var i = 0 ; i < n ; i++ )
1479 var theGUI = draggableObjects[i].getDroppedGUI();
1480 if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
1482 theGUI.style.position = "static";
1483 theGUI.style.top = "";
1484 theGUI.style.top = "";
1486 htmlElement.appendChild(theGUI);
1492 //-------------------- ricoEffects.js
1495 * Use the Effect namespace for effects. If using scriptaculous effects
1496 * this will already be defined, otherwise we'll just create an empty
1499 if ( window.Effect == undefined )
1502 Effect.SizeAndPosition = Class.create();
1503 Effect.SizeAndPosition.prototype = {
1505 initialize: function(element, x, y, w, h, duration, steps, options) {
1506 this.element = $(element);
1511 this.duration = duration;
1513 this.options = arguments[7] || {};
1515 this.sizeAndPosition();
1518 sizeAndPosition: function() {
1519 if (this.isFinished()) {
1520 if(this.options.complete) this.options.complete(this);
1525 clearTimeout(this.timer);
1527 var stepDuration = Math.round(this.duration/this.steps) ;
1529 // Get original values: x,y = top left corner; w,h = width height
1530 var currentX = this.element.offsetLeft;
1531 var currentY = this.element.offsetTop;
1532 var currentW = this.element.offsetWidth;
1533 var currentH = this.element.offsetHeight;
1535 // If values not set, or zero, we do not modify them, and take original as final as well
1536 this.x = (this.x) ? this.x : currentX;
1537 this.y = (this.y) ? this.y : currentY;
1538 this.w = (this.w) ? this.w : currentW;
1539 this.h = (this.h) ? this.h : currentH;
1541 // how much do we need to modify our values for each step?
1542 var difX = this.steps > 0 ? (this.x - currentX)/this.steps : 0;
1543 var difY = this.steps > 0 ? (this.y - currentY)/this.steps : 0;
1544 var difW = this.steps > 0 ? (this.w - currentW)/this.steps : 0;
1545 var difH = this.steps > 0 ? (this.h - currentH)/this.steps : 0;
1547 this.moveBy(difX, difY);
1548 this.resizeBy(difW, difH);
1550 this.duration -= stepDuration;
1553 this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
1556 isFinished: function() {
1557 return this.steps <= 0;
1560 moveBy: function( difX, difY ) {
1561 var currentLeft = this.element.offsetLeft;
1562 var currentTop = this.element.offsetTop;
1563 var intDifX = parseInt(difX);
1564 var intDifY = parseInt(difY);
1566 var style = this.element.style;
1568 style.left = (currentLeft + intDifX) + "px";
1570 style.top = (currentTop + intDifY) + "px";
1573 resizeBy: function( difW, difH ) {
1574 var currentWidth = this.element.offsetWidth;
1575 var currentHeight = this.element.offsetHeight;
1576 var intDifW = parseInt(difW);
1577 var intDifH = parseInt(difH);
1579 var style = this.element.style;
1581 style.width = (currentWidth + intDifW) + "px";
1583 style.height = (currentHeight + intDifH) + "px";
1587 Effect.Size = Class.create();
1588 Effect.Size.prototype = {
1590 initialize: function(element, w, h, duration, steps, options) {
1591 new Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
1595 Effect.Position = Class.create();
1596 Effect.Position.prototype = {
1598 initialize: function(element, x, y, duration, steps, options) {
1599 new Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
1603 Effect.Round = Class.create();
1604 Effect.Round.prototype = {
1606 initialize: function(tagName, className, options) {
1607 var elements = document.getElementsByTagAndClassName(tagName,className);
1608 for ( var i = 0 ; i < elements.length ; i++ )
1609 Rico.Corner.round( elements[i], options );
1613 Effect.FadeTo = Class.create();
1614 Effect.FadeTo.prototype = {
1616 initialize: function( element, opacity, duration, steps, options) {
1617 this.element = $(element);
1618 this.opacity = opacity;
1619 this.duration = duration;
1621 this.options = arguments[4] || {};
1625 fadeTo: function() {
1626 if (this.isFinished()) {
1627 if(this.options.complete) this.options.complete(this);
1632 clearTimeout(this.timer);
1634 var stepDuration = Math.round(this.duration/this.steps) ;
1635 var currentOpacity = this.getElementOpacity();
1636 var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
1638 this.changeOpacityBy(delta);
1639 this.duration -= stepDuration;
1642 this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
1645 changeOpacityBy: function(v) {
1646 var currentOpacity = this.getElementOpacity();
1647 var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
1648 this.element.ricoOpacity = newOpacity;
1650 this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
1651 this.element.style.opacity = newOpacity; /*//*/;
1654 isFinished: function() {
1655 return this.steps <= 0;
1658 getElementOpacity: function() {
1659 if ( this.element.ricoOpacity == undefined ) {
1661 if ( this.element.currentStyle ) {
1662 opacity = this.element.currentStyle.opacity;
1664 else if ( document.defaultView.getComputedStyle != undefined ) {
1665 var computedStyle = document.defaultView.getComputedStyle;
1666 opacity = computedStyle(this.element, null).getPropertyValue('opacity');
1669 this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
1672 return parseFloat(this.element.ricoOpacity);
1676 Effect.AccordionSize = Class.create();
1678 Effect.AccordionSize.prototype = {
1680 initialize: function(e1, e2, start, end, duration, steps, options) {
1685 this.duration = duration;
1687 this.options = arguments[6] || {};
1689 this.accordionSize();
1692 accordionSize: function() {
1694 if (this.isFinished()) {
1695 // just in case there are round errors or such...
1696 this.e1.style.height = this.start + "px";
1697 this.e2.style.height = this.end + "px";
1699 if(this.options.complete)
1700 this.options.complete(this);
1705 clearTimeout(this.timer);
1707 var stepDuration = Math.round(this.duration/this.steps) ;
1709 var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
1710 this.resizeBy(diff);
1712 this.duration -= stepDuration;
1715 this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
1718 isFinished: function() {
1719 return this.steps <= 0;
1722 resizeBy: function(diff) {
1723 var h1Height = this.e1.offsetHeight;
1724 var h2Height = this.e2.offsetHeight;
1725 var intDiff = parseInt(diff);
1727 this.e1.style.height = (h1Height - intDiff) + "px";
1728 this.e2.style.height = (h2Height + intDiff) + "px";
1735 //-------------------- ricoLiveGrid.js
1737 // Rico.LiveGridMetaData -----------------------------------------------------
1739 Rico.LiveGridMetaData = Class.create();
1741 Rico.LiveGridMetaData.prototype = {
1743 initialize: function( pageSize, totalRows, columnCount, options ) {
1744 this.pageSize = pageSize;
1745 this.totalRows = totalRows;
1746 this.setOptions(options);
1747 this.scrollArrowHeight = 16;
1748 this.columnCount = columnCount;
1751 setOptions: function(options) {
1753 largeBufferSize : 7.0, // 7 pages
1754 nearLimitFactor : 0.2 // 20% of buffer
1755 }.extend(options || {});
1758 getPageSize: function() {
1759 return this.pageSize;
1762 getTotalRows: function() {
1763 return this.totalRows;
1766 setTotalRows: function(n) {
1770 getLargeBufferSize: function() {
1771 return parseInt(this.options.largeBufferSize * this.pageSize);
1774 getLimitTolerance: function() {
1775 return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
1779 // Rico.LiveGridScroller -----------------------------------------------------
1781 Rico.LiveGridScroller = Class.create();
1783 Rico.LiveGridScroller.prototype = {
1785 initialize: function(liveGrid, viewPort) {
1786 this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
1787 this.liveGrid = liveGrid;
1788 this.metaData = liveGrid.metaData;
1789 this.createScrollBar();
1790 this.scrollTimeout = null;
1791 this.lastScrollPos = 0;
1792 this.viewPort = viewPort;
1793 this.rows = new Array();
1796 isUnPlugged: function() {
1797 return this.scrollerDiv.onscroll == null;
1800 plugin: function() {
1801 this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
1804 unplug: function() {
1805 this.scrollerDiv.onscroll = null;
1808 sizeIEHeaderHack: function() {
1809 if ( !this.isIE ) return;
1810 var headerTable = $(this.liveGrid.tableId + "_header");
1812 headerTable.rows[0].cells[0].style.width =
1813 (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
1816 createScrollBar: function() {
1817 var visibleHeight = this.liveGrid.viewPort.visibleHeight();
1818 // create the outer div...
1819 this.scrollerDiv = document.createElement("div");
1820 var scrollerStyle = this.scrollerDiv.style;
1821 scrollerStyle.borderRight = "1px solid #ababab"; // hard coded color!!!
1822 scrollerStyle.position = "relative";
1823 scrollerStyle.left = this.isIE ? "-6px" : "-3px";
1824 scrollerStyle.width = "19px";
1825 scrollerStyle.height = visibleHeight + "px";
1826 scrollerStyle.overflow = "auto";
1828 // create the inner div...
1829 this.heightDiv = document.createElement("div");
1830 this.heightDiv.style.width = "1px";
1832 this.heightDiv.style.height = parseInt(visibleHeight *
1833 this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
1834 this.scrollerDiv.appendChild(this.heightDiv);
1835 this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
1837 var table = this.liveGrid.table;
1838 table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
1841 updateSize: function() {
1842 var table = this.liveGrid.table;
1843 var visibleHeight = this.viewPort.visibleHeight();
1844 this.heightDiv.style.height = parseInt(visibleHeight *
1845 this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
1848 rowToPixel: function(rowOffset) {
1849 return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
1852 moveScroll: function(rowOffset) {
1853 this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
1854 if ( this.metaData.options.onscroll )
1855 this.metaData.options.onscroll( this.liveGrid, rowOffset );
1858 handleScroll: function() {
1859 if ( this.scrollTimeout )
1860 clearTimeout( this.scrollTimeout );
1862 var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
1863 this.liveGrid.requestContentRefresh(contentOffset);
1864 this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
1866 if ( this.metaData.options.onscroll )
1867 this.metaData.options.onscroll( this.liveGrid, contentOffset );
1869 this.scrollTimeout = setTimeout( this.scrollIdle.bind(this), 1200 );
1872 scrollIdle: function() {
1873 if ( this.metaData.options.onscrollidle )
1874 this.metaData.options.onscrollidle();
1878 // Rico.LiveGridBuffer -----------------------------------------------------
1880 Rico.LiveGridBuffer = Class.create();
1882 Rico.LiveGridBuffer.prototype = {
1884 initialize: function(metaData, viewPort) {
1887 this.metaData = metaData;
1888 this.rows = new Array();
1889 this.updateInProgress = false;
1890 this.viewPort = viewPort;
1891 this.maxBufferSize = metaData.getLargeBufferSize() * 2;
1892 this.maxFetchSize = metaData.getLargeBufferSize();
1893 this.lastOffset = 0;
1896 getBlankRow: function() {
1897 if (!this.blankRow ) {
1898 this.blankRow = new Array();
1899 for ( var i=0; i < this.metaData.columnCount ; i++ )
1900 this.blankRow[i] = " ";
1902 return this.blankRow;
1905 loadRows: function(ajaxResponse) {
1906 var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
1907 this.updateUI = rowsElement.getAttribute("update_ui") == "true"
1908 var newRows = new Array()
1909 var trs = rowsElement.getElementsByTagName("tr");
1910 for ( var i=0 ; i < trs.length; i++ ) {
1911 var row = newRows[i] = new Array();
1912 var cells = trs[i].getElementsByTagName("td");
1913 for ( var j=0; j < cells.length ; j++ ) {
1914 var cell = cells[j];
1915 var convertSpaces = cell.getAttribute("convert_spaces") == "true";
1916 var cellContent = RicoUtil.getContentAsString(cell);
1917 row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
1925 update: function(ajaxResponse, start) {
1926 var newRows = this.loadRows(ajaxResponse);
1927 if (this.rows.length == 0) { // initial load
1928 this.rows = newRows;
1929 this.size = this.rows.length;
1930 this.startPos = start;
1933 if (start > this.startPos) { //appending
1934 if (this.startPos + this.rows.length < start) {
1935 this.rows = newRows;
1936 this.startPos = start;//
1938 this.rows = this.rows.concat( newRows.slice(0, newRows.length));
1939 if (this.rows.length > this.maxBufferSize) {
1940 var fullSize = this.rows.length;
1941 this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
1942 this.startPos = this.startPos + (fullSize - this.rows.length);
1945 } else { //prepending
1946 if (start + newRows.length < this.startPos) {
1947 this.rows = newRows;
1949 this.rows = newRows.slice(0, this.startPos).concat(this.rows);
1950 if (this.rows.length > this.maxBufferSize)
1951 this.rows = this.rows.slice(0, this.maxBufferSize)
1953 this.startPos = start;
1955 this.size = this.rows.length;
1959 this.rows = new Array();
1964 isOverlapping: function(start, size) {
1965 return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
1968 isInRange: function(position) {
1969 return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos());
1970 //&& this.size() != 0;
1973 isNearingTopLimit: function(position) {
1974 return position - this.startPos < this.metaData.getLimitTolerance();
1977 endPos: function() {
1978 return this.startPos + this.rows.length;
1981 isNearingBottomLimit: function(position) {
1982 return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
1985 isAtTop: function() {
1986 return this.startPos == 0;
1989 isAtBottom: function() {
1990 return this.endPos() == this.metaData.getTotalRows();
1993 isNearingLimit: function(position) {
1994 return ( !this.isAtTop() && this.isNearingTopLimit(position)) ||
1995 ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
1998 getFetchSize: function(offset) {
1999 var adjustedOffset = this.getFetchOffset(offset);
2000 var adjustedSize = 0;
2001 if (adjustedOffset >= this.startPos) { //apending
2002 var endFetchOffset = this.maxFetchSize + adjustedOffset;
2003 if (endFetchOffset > this.metaData.totalRows)
2004 endFetchOffset = this.metaData.totalRows;
2005 adjustedSize = endFetchOffset - adjustedOffset;
2006 } else {//prepending
2007 var adjustedSize = this.startPos - adjustedOffset;
2008 if (adjustedSize > this.maxFetchSize)
2009 adjustedSize = this.maxFetchSize;
2011 return adjustedSize;
2014 getFetchOffset: function(offset) {
2015 var adjustedOffset = offset;
2016 if (offset > this.startPos) //apending
2017 adjustedOffset = (offset > this.endPos()) ? offset : this.endPos();
2019 if (offset + this.maxFetchSize >= this.startPos) {
2020 var adjustedOffset = this.startPos - this.maxFetchSize;
2021 if (adjustedOffset < 0)
2025 this.lastOffset = adjustedOffset;
2026 return adjustedOffset;
2029 getRows: function(start, count) {
2030 var begPos = start - this.startPos
2031 var endPos = begPos + count
2033 // er? need more data...
2034 if ( endPos > this.size )
2037 var results = new Array()
2039 for ( var i=begPos ; i < endPos; i++ ) {
2040 results[index++] = this.rows[i]
2045 convertSpaces: function(s) {
2046 return s.split(" ").join(" ");
2052 //Rico.GridViewPort --------------------------------------------------
2053 Rico.GridViewPort = Class.create();
2055 Rico.GridViewPort.prototype = {
2057 initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) {
2058 this.lastDisplayedStartPos = 0;
2059 this.div = table.parentNode;
2061 this.rowHeight = rowHeight;
2062 this.div.style.height = this.rowHeight * visibleRows;
2063 this.div.style.overflow = "hidden";
2064 this.buffer = buffer;
2065 this.liveGrid = liveGrid;
2066 this.visibleRows = visibleRows + 1;
2067 this.lastPixelOffset = 0;
2071 populateRow: function(htmlRow, row) {
2072 for (var j=0; j < row.length; j++) {
2073 htmlRow.cells[j].innerHTML = row[j]
2077 bufferChanged: function() {
2078 this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
2081 clearRows: function() {
2082 if (!this.isBlank) {
2083 for (var i=0; i < this.visibleRows; i++)
2084 this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
2085 this.isBlank = true;
2089 clearContents: function() {
2093 this.lastStartPos = -1;
2096 refreshContents: function(startPos) {
2097 if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
2100 if ((startPos + this.visibleRows < this.buffer.startPos)
2101 || (this.buffer.startPos + this.buffer.size < startPos)
2102 || (this.buffer.size == 0)) {
2106 this.isBlank = false;
2107 var viewPrecedesBuffer = this.buffer.startPos > startPos
2108 var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos;
2110 var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows)
2111 ? this.buffer.startPos + this.buffer.size
2112 : startPos + this.visibleRows;
2113 var rowSize = contentEndPos - contentStartPos;
2114 var rows = this.buffer.getRows(contentStartPos, rowSize );
2115 var blankSize = this.visibleRows - rowSize;
2116 var blankOffset = viewPrecedesBuffer ? 0: rowSize;
2117 var contentOffset = viewPrecedesBuffer ? blankSize: 0;
2119 for (var i=0; i < rows.length; i++) {//initialize what we have
2120 this.populateRow(this.table.rows[i + contentOffset], rows[i]);
2122 for (var i=0; i < blankSize; i++) {// blank out the rest
2123 this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow());
2125 this.isPartialBlank = blankSize > 0;
2126 this.lastRowPos = startPos;
2129 scrollTo: function(pixelOffset) {
2130 if (this.lastPixelOffset == pixelOffset)
2133 this.refreshContents(parseInt(pixelOffset / this.rowHeight))
2134 this.div.scrollTop = pixelOffset % this.rowHeight
2136 this.lastPixelOffset = pixelOffset;
2139 visibleHeight: function() {
2140 return parseInt(this.div.style.height);
2146 Rico.LiveGridRequest = Class.create();
2147 Rico.LiveGridRequest.prototype = {
2148 initialize: function( requestOffset, options ) {
2149 this.requestOffset = requestOffset;
2153 // Rico.LiveGrid -----------------------------------------------------
2155 Rico.LiveGrid = Class.create();
2157 Rico.LiveGrid.prototype = {
2159 initialize: function( tableId, visibleRows, totalRows, url, options ) {
2160 if ( options == null )
2163 this.tableId = tableId;
2164 this.table = $(tableId);
2165 var columnCount = this.table.rows[0].cells.length
2166 this.metaData = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options);
2167 this.buffer = new Rico.LiveGridBuffer(this.metaData);
2169 var rowCount = this.table.rows.length;
2170 this.viewPort = new Rico.GridViewPort(this.table,
2171 this.table.offsetHeight/rowCount,
2174 this.scroller = new Rico.LiveGridScroller(this,this.viewPort);
2176 this.additionalParms = options.requestParameters || [];
2178 options.sortHandler = this.sortHandler.bind(this);
2180 if ( $(tableId + '_header') )
2181 this.sort = new Rico.LiveGridSort(tableId + '_header', options)
2183 this.processingRequest = null;
2184 this.unprocessedRequest = null;
2187 if ( options.prefetchBuffer || options.prefetchOffset > 0) {
2189 if (options.offset ) {
2190 offset = options.offset;
2191 this.scroller.moveScroll(offset);
2192 this.viewPort.scrollTo(this.scroller.rowToPixel(offset));
2194 if (options.sortCol) {
2195 this.sortCol = options.sortCol;
2196 this.sortDir = options.sortDir;
2198 this.requestContentRefresh(offset);
2202 resetContents: function() {
2203 this.scroller.moveScroll(0);
2204 this.buffer.clear();
2205 this.viewPort.clearContents();
2208 sortHandler: function(column) {
2209 this.sortCol = column.name;
2210 this.sortDir = column.currentSort;
2212 this.resetContents();
2213 this.requestContentRefresh(0)
2216 setRequestParams: function() {
2217 this.additionalParms = [];
2218 for ( var i=0 ; i < arguments.length ; i++ )
2219 this.additionalParms[i] = arguments[i];
2222 setTotalRows: function( newTotalRows ) {
2223 this.resetContents();
2224 this.metaData.setTotalRows(newTotalRows);
2225 this.scroller.updateSize();
2228 initAjax: function(url) {
2229 ajaxEngine.registerRequest( this.tableId + '_request', url );
2230 ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
2233 invokeAjax: function() {
2236 handleTimedOut: function() {
2237 //server did not respond in 4 seconds... assume that there could have been
2238 //an error or something, and allow requests to be processed again...
2239 this.processingRequest = null;
2240 this.processQueuedRequest();
2243 fetchBuffer: function(offset) {
2244 if ( this.buffer.isInRange(offset) &&
2245 !this.buffer.isNearingLimit(offset)) {
2248 if (this.processingRequest) {
2249 this.unprocessedRequest = new Rico.LiveGridRequest(offset);
2252 var bufferStartPos = this.buffer.getFetchOffset(offset);
2253 this.processingRequest = new Rico.LiveGridRequest(offset);
2254 this.processingRequest.bufferOffset = bufferStartPos;
2255 var fetchSize = this.buffer.getFetchSize(offset);
2256 var partialLoaded = false;
2258 callParms.push(this.tableId + '_request');
2259 callParms.push('id=' + this.tableId);
2260 callParms.push('page_size=' + fetchSize);
2261 callParms.push('offset=' + bufferStartPos);
2262 if ( this.sortCol) {
2263 callParms.push('sort_col=' + this.sortCol);
2264 callParms.push('sort_dir=' + this.sortDir);
2267 for( var i=0 ; i < this.additionalParms.length ; i++ )
2268 callParms.push(this.additionalParms[i]);
2269 ajaxEngine.sendRequest.apply( ajaxEngine, callParms );
2271 this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), 20000 ); //todo: make as option
2274 requestContentRefresh: function(contentOffset) {
2275 this.fetchBuffer(contentOffset);
2278 ajaxUpdate: function(ajaxResponse) {
2280 clearTimeout( this.timeoutHandler );
2281 this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
2282 this.viewPort.bufferChanged();
2285 finally {this.processingRequest = null; }
2286 this.processQueuedRequest();
2289 processQueuedRequest: function() {
2290 if (this.unprocessedRequest != null) {
2291 this.requestContentRefresh(this.unprocessedRequest.requestOffset);
2292 this.unprocessedRequest = null
2299 //-------------------- ricoLiveGridSort.js
2300 Rico.LiveGridSort = Class.create();
2302 Rico.LiveGridSort.prototype = {
2304 initialize: function(headerTableId, options) {
2305 this.headerTableId = headerTableId;
2306 this.headerTable = $(headerTableId);
2307 this.setOptions(options);
2308 this.applySortBehavior();
2310 if ( this.options.sortCol ) {
2311 this.setSortUI( this.options.sortCol, this.options.sortDir );
2315 setSortUI: function( columnName, sortDirection ) {
2316 var cols = this.options.columns;
2317 for ( var i = 0 ; i < cols.length ; i++ ) {
2318 if ( cols[i].name == columnName ) {
2319 this.setColumnSort(i, sortDirection);
2325 setOptions: function(options) {
2327 sortAscendImg: 'images/sort_asc.gif',
2328 sortDescendImg: 'images/sort_desc.gif',
2331 ajaxSortURLParms: []
2334 // preload the images...
2335 new Image().src = this.options.sortAscendImg;
2336 new Image().src = this.options.sortDescendImg;
2338 this.sort = options.sortHandler;
2339 if ( !this.options.columns )
2340 this.options.columns = this.introspectForColumnInfo();
2342 // allow client to pass { columns: [ ["a", true], ["b", false] ] }
2343 // and convert to an array of Rico.TableColumn objs...
2344 this.options.columns = this.convertToTableColumns(this.options.columns);
2348 applySortBehavior: function() {
2349 var headerRow = this.headerTable.rows[0];
2350 var headerCells = headerRow.cells;
2351 for ( var i = 0 ; i < headerCells.length ; i++ ) {
2352 this.addSortBehaviorToColumn( i, headerCells[i] );
2356 addSortBehaviorToColumn: function( n, cell ) {
2357 if ( this.options.columns[n].isSortable() ) {
2358 cell.id = this.headerTableId + '_' + n;
2359 cell.style.cursor = 'pointer';
2360 cell.onclick = this.headerCellClicked.bindAsEventListener(this);
2361 cell.innerHTML = cell.innerHTML + '<span id="' + this.headerTableId + '_img_' + n + '">'
2362 + ' </span>';
2366 // event handler....
2367 headerCellClicked: function(evt) {
2368 var eventTarget = evt.target ? evt.target : evt.srcElement;
2369 var cellId = eventTarget.id;
2370 var columnNumber = parseInt(cellId.substring( cellId.lastIndexOf('_') + 1 ));
2371 var sortedColumnIndex = this.getSortedColumnIndex();
2372 if ( sortedColumnIndex != -1 ) {
2373 if ( sortedColumnIndex != columnNumber ) {
2374 this.removeColumnSort(sortedColumnIndex);
2375 this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
2378 this.toggleColumnSort(sortedColumnIndex);
2381 this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
2383 if (this.options.sortHandler) {
2384 this.options.sortHandler(this.options.columns[columnNumber]);
2388 removeColumnSort: function(n) {
2389 this.options.columns[n].setUnsorted();
2390 this.setSortImage(n);
2393 setColumnSort: function(n, direction) {
2394 this.options.columns[n].setSorted(direction);
2395 this.setSortImage(n);
2398 toggleColumnSort: function(n) {
2399 this.options.columns[n].toggleSort();
2400 this.setSortImage(n);
2403 setSortImage: function(n) {
2404 var sortDirection = this.options.columns[n].getSortDirection();
2406 var sortImageSpan = $( this.headerTableId + '_img_' + n );
2407 if ( sortDirection == Rico.TableColumn.UNSORTED )
2408 sortImageSpan.innerHTML = ' ';
2409 else if ( sortDirection == Rico.TableColumn.SORT_ASC )
2410 sortImageSpan.innerHTML = ' <img width="' + this.options.imageWidth + '" ' +
2411 'height="'+ this.options.imageHeight + '" ' +
2412 'src="' + this.options.sortAscendImg + '"/>';
2413 else if ( sortDirection == Rico.TableColumn.SORT_DESC )
2414 sortImageSpan.innerHTML = ' <img width="' + this.options.imageWidth + '" ' +
2415 'height="'+ this.options.imageHeight + '" ' +
2416 'src="' + this.options.sortDescendImg + '"/>';
2419 getSortedColumnIndex: function() {
2420 var cols = this.options.columns;
2421 for ( var i = 0 ; i < cols.length ; i++ ) {
2422 if ( cols[i].isSorted() )
2429 introspectForColumnInfo: function() {
2430 var columns = new Array();
2431 var headerRow = this.headerTable.rows[0];
2432 var headerCells = headerRow.cells;
2433 for ( var i = 0 ; i < headerCells.length ; i++ )
2434 columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) );
2438 convertToTableColumns: function(cols) {
2439 var columns = new Array();
2440 for ( var i = 0 ; i < cols.length ; i++ )
2441 columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) );
2444 deriveColumnNameFromCell: function(cell,columnNumber) {
2445 var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent;
2446 return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber;
2450 Rico.TableColumn = Class.create();
2452 Rico.TableColumn.UNSORTED = 0;
2453 Rico.TableColumn.SORT_ASC = "ASC";
2454 Rico.TableColumn.SORT_DESC = "DESC";
2456 Rico.TableColumn.prototype = {
2457 initialize: function(name, sortable) {
2459 this.sortable = sortable;
2460 this.currentSort = Rico.TableColumn.UNSORTED;
2463 isSortable: function() {
2464 return this.sortable;
2467 isSorted: function() {
2468 return this.currentSort != Rico.TableColumn.UNSORTED;
2471 getSortDirection: function() {
2472 return this.currentSort;
2475 toggleSort: function() {
2476 if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC )
2477 this.currentSort = Rico.TableColumn.SORT_ASC;
2478 else if ( this.currentSort == Rico.TableColumn.SORT_ASC )
2479 this.currentSort = Rico.TableColumn.SORT_DESC;
2482 setUnsorted: function(direction) {
2483 this.setSorted(Rico.TableColumn.UNSORTED);
2486 setSorted: function(direction) {
2487 // direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SET_DESC...
2488 this.currentSort = direction;
2494 //-------------------- ricoUtil.js
2498 getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
2499 if ( arguments.length == 2 )
2500 mozillaEquivalentCSS = cssProperty;
2502 var el = $(htmlElement);
2503 if ( el.currentStyle )
2504 return el.currentStyle[cssProperty];
2506 return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
2509 createXmlDocument : function() {
2510 if (document.implementation && document.implementation.createDocument) {
2511 var doc = document.implementation.createDocument("", "", null);
2513 if (doc.readyState == null) {
2515 doc.addEventListener("load", function () {
2517 if (typeof doc.onreadystatechange == "function")
2518 doc.onreadystatechange();
2525 if (window.ActiveXObject)
2527 function() { return new ActiveXObject('MSXML2.DomDocument') },
2528 function() { return new ActiveXObject('Microsoft.DomDocument')},
2529 function() { return new ActiveXObject('MSXML.DomDocument') },
2530 function() { return new ActiveXObject('MSXML3.DomDocument') }
2536 getContentAsString: function( parentNode ) {
2537 return parentNode.xml != undefined ?
2538 this._getContentAsStringIE(parentNode) :
2539 this._getContentAsStringMozilla(parentNode);
2542 _getContentAsStringIE: function(parentNode) {
2543 var contentStr = "";
2544 for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
2545 contentStr += parentNode.childNodes[i].xml;
2549 _getContentAsStringMozilla: function(parentNode) {
2550 var xmlSerializer = new XMLSerializer();
2551 var contentStr = "";
2552 for ( var i = 0 ; i < parentNode.childNodes.length ; i++ )
2553 contentStr += xmlSerializer.serializeToString(parentNode.childNodes[i]);
2557 toViewportPosition: function(element) {
2558 return this._toAbsolute(element,true);
2561 toDocumentPosition: function(element) {
2562 return this._toAbsolute(element,false);
2566 * Compute the elements position in terms of the window viewport
2567 * so that it can be compared to the position of the mouse (dnd)
2568 * This is additions of all the offsetTop,offsetLeft values up the
2569 * offsetParent hierarchy, ...taking into account any scrollTop,
2570 * scrollLeft values along the way...
2572 * IE has a bug reporting a correct offsetLeft of elements within a
2573 * a relatively positioned parent!!!
2575 _toAbsolute: function(element,accountForDocScroll) {
2577 if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
2578 return this._toAbsoluteMozilla(element,accountForDocScroll);
2582 var parent = element;
2585 var borderXOffset = 0;
2586 var borderYOffset = 0;
2587 if ( parent != element ) {
2588 var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
2589 var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
2590 borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
2591 borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
2594 x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
2595 y += parent.offsetTop - parent.scrollTop + borderYOffset;
2596 parent = parent.offsetParent;
2599 if ( accountForDocScroll ) {
2600 x -= this.docScrollLeft();
2601 y -= this.docScrollTop();
2604 return { x:x, y:y };
2608 * Mozilla did not report all of the parents up the hierarchy via the
2609 * offsetParent property that IE did. So for the calculation of the
2610 * offsets we use the offsetParent property, but for the calculation of
2611 * the scrollTop/scrollLeft adjustments we navigate up via the parentNode
2612 * property instead so as to get the scroll offsets...
2615 _toAbsoluteMozilla: function(element,accountForDocScroll) {
2618 var parent = element;
2620 x += parent.offsetLeft;
2621 y += parent.offsetTop;
2622 parent = parent.offsetParent;
2627 parent != document.body &&
2628 parent != document.documentElement ) {
2629 if ( parent.scrollLeft )
2630 x -= parent.scrollLeft;
2631 if ( parent.scrollTop )
2632 y -= parent.scrollTop;
2633 parent = parent.parentNode;
2636 if ( accountForDocScroll ) {
2637 x -= this.docScrollLeft();
2638 y -= this.docScrollTop();
2641 return { x:x, y:y };
2644 docScrollLeft: function() {
2645 if ( window.pageXOffset )
2646 return window.pageXOffset;
2647 else if ( document.documentElement && document.documentElement.scrollLeft )
2648 return document.documentElement.scrollLeft;
2649 else if ( document.body )
2650 return document.body.scrollLeft;
2655 docScrollTop: function() {
2656 if ( window.pageYOffset )
2657 return window.pageYOffset;
2658 else if ( document.documentElement && document.documentElement.scrollTop )
2659 return document.documentElement.scrollTop;
2660 else if ( document.body )
2661 return document.body.scrollTop;