rico.js
上传用户:shjgzm
上传日期:2017-08-31
资源大小:2757k
文件大小:88k
源码类别:

Ajax

开发平台:

Java

  1. /**
  2.   *
  3.   *  Copyright 2005 Sabre Airline Solutions
  4.   *
  5.   *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
  6.   *  file except in compliance with the License. You may obtain a copy of the License at
  7.   *
  8.   *         http://www.apache.org/licenses/LICENSE-2.0
  9.   *
  10.   *  Unless required by applicable law or agreed to in writing, software distributed under the
  11.   *  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  12.   *  either express or implied. See the License for the specific language governing permissions
  13.   *  and limitations under the License.
  14.   **/
  15. //-------------------- rico.js
  16. var Rico = {
  17.   Version: '1.1.2',
  18.   prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1])
  19. }
  20. if((typeof Prototype=='undefined') || Rico.prototypeVersion < 1.3)
  21.       throw("Rico requires the Prototype JavaScript framework >= 1.3");
  22. Rico.ArrayExtensions = new Array();
  23. if (Object.prototype.extend) {
  24.    Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
  25. }else{
  26.   Object.prototype.extend = function(object) {
  27.     return Object.extend.apply(this, [this, object]);
  28.   }
  29.   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
  30. }
  31. if (Array.prototype.push) {
  32.    Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push;
  33. }
  34. if (!Array.prototype.remove) {
  35.    Array.prototype.remove = function(dx) {
  36.       if( isNaN(dx) || dx > this.length )
  37.          return false;
  38.       for( var i=0,n=0; i<this.length; i++ )
  39.          if( i != dx )
  40.             this[n++]=this[i];
  41.       this.length-=1;
  42.    };
  43.   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
  44. }
  45. if (!Array.prototype.removeItem) {
  46.    Array.prototype.removeItem = function(item) {
  47.       for ( var i = 0 ; i < this.length ; i++ )
  48.          if ( this[i] == item ) {
  49.             this.remove(i);
  50.             break;
  51.          }
  52.    };
  53.   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
  54. }
  55. if (!Array.prototype.indices) {
  56.    Array.prototype.indices = function() {
  57.       var indexArray = new Array();
  58.       for ( index in this ) {
  59.          var ignoreThis = false;
  60.          for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
  61.             if ( this[index] == Rico.ArrayExtensions[i] ) {
  62.                ignoreThis = true;
  63.                break;
  64.             }
  65.          }
  66.          if ( !ignoreThis )
  67.             indexArray[ indexArray.length ] = index;
  68.       }
  69.       return indexArray;
  70.    }
  71.   Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
  72. }
  73. // Create the loadXML method and xml getter for Mozilla
  74. if ( window.DOMParser &&
  75.   window.XMLSerializer &&
  76.   window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
  77.    if (!Document.prototype.loadXML) {
  78.       Document.prototype.loadXML = function (s) {
  79.          var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
  80.          while (this.hasChildNodes())
  81.             this.removeChild(this.lastChild);
  82.          for (var i = 0; i < doc2.childNodes.length; i++) {
  83.             this.appendChild(this.importNode(doc2.childNodes[i], true));
  84.          }
  85.       };
  86. }
  87. Document.prototype.__defineGetter__( "xml",
  88.    function () {
  89.    return (new XMLSerializer()).serializeToString(this);
  90.    }
  91.  );
  92. }
  93. document.getElementsByTagAndClassName = function(tagName, className) {
  94.   if ( tagName == null )
  95.      tagName = '*';
  96.   var children = document.getElementsByTagName(tagName) || document.all;
  97.   var elements = new Array();
  98.   if ( className == null )
  99.     return children;
  100.   for (var i = 0; i < children.length; i++) {
  101.     var child = children[i];
  102.     var classNames = child.className.split(' ');
  103.     for (var j = 0; j < classNames.length; j++) {
  104.       if (classNames[j] == className) {
  105.         elements.push(child);
  106.         break;
  107.       }
  108.     }
  109.   }
  110.   return elements;
  111. }
  112. //-------------------- ricoAccordion.js
  113. Rico.Accordion = Class.create();
  114. Rico.Accordion.prototype = {
  115.    initialize: function(container, options) {
  116.       this.container            = $(container);
  117.       this.lastExpandedTab      = null;
  118.       this.accordionTabs        = new Array();
  119.       this.setOptions(options);
  120.       this._attachBehaviors();
  121.       if(!container) return;
  122.       this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
  123.       // validate onloadShowTab
  124.        if (this.options.onLoadShowTab >= this.accordionTabs.length)
  125.         this.options.onLoadShowTab = 0;
  126.       // set the initial visual state...
  127.       for ( var i=0 ; i < this.accordionTabs.length ; i++ )
  128.       {
  129.         if (i != this.options.onLoadShowTab){
  130.          this.accordionTabs[i].collapse();
  131.          this.accordionTabs[i].content.style.display = 'none';
  132.         }
  133.       }
  134.       this.lastExpandedTab = this.accordionTabs[this.options.onLoadShowTab];
  135.       if (this.options.panelHeight == 'auto'){
  136.           var tabToCheck = (this.options.onloadShowTab === 0)? 1 : 0;
  137.           var titleBarSize = parseInt(RicoUtil.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height'));
  138.           if (isNaN(titleBarSize))
  139.             titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight;
  140.           
  141.           var totalTitleBarSize = this.accordionTabs.length * titleBarSize;
  142.           var parentHeight = parseInt(RicoUtil.getElementsComputedStyle(this.container.parentNode, 'height'));
  143.           if (isNaN(parentHeight))
  144.             parentHeight = this.container.parentNode.offsetHeight;
  145.           
  146.           this.options.panelHeight = parentHeight - totalTitleBarSize-2;
  147.       }
  148.       
  149.       this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
  150.       this.lastExpandedTab.showExpanded();
  151.       this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
  152.    },
  153.    setOptions: function(options) {
  154.       this.options = {
  155.          expandedBg          : '#63699c',
  156.          hoverBg             : '#63699c',
  157.          collapsedBg         : '#6b79a5',
  158.          expandedTextColor   : '#ffffff',
  159.          expandedFontWeight  : 'bold',
  160.          hoverTextColor      : '#ffffff',
  161.          collapsedTextColor  : '#ced7ef',
  162.          collapsedFontWeight : 'normal',
  163.          hoverTextColor      : '#ffffff',
  164.          borderColor         : '#1f669b',
  165.          panelHeight         : 200,
  166.          onHideTab           : null,
  167.          onShowTab           : null,
  168.          onLoadShowTab       : 0
  169.       }
  170.       Object.extend(this.options, options || {});
  171.    },
  172.    showTabByIndex: function( anIndex, animate ) {
  173.       var doAnimate = arguments.length == 1 ? true : animate;
  174.       this.showTab( this.accordionTabs[anIndex], doAnimate );
  175.    },
  176.    showTab: function( accordionTab, animate ) {
  177.      if ( this.lastExpandedTab == accordionTab )
  178.         return;
  179.       var doAnimate = arguments.length == 1 ? true : animate;
  180.       if ( this.options.onHideTab )
  181.          this.options.onHideTab(this.lastExpandedTab);
  182.       this.lastExpandedTab.showCollapsed(); 
  183.       var accordion = this;
  184.       var lastExpandedTab = this.lastExpandedTab;
  185.       this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
  186.       accordionTab.content.style.display = '';
  187.       accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
  188.       if ( doAnimate ) {
  189.          new Rico.Effect.AccordionSize( this.lastExpandedTab.content,
  190.                                    accordionTab.content,
  191.                                    1,
  192.                                    this.options.panelHeight,
  193.                                    100, 10,
  194.                                    { complete: function() {accordion.showTabDone(lastExpandedTab)} } );
  195.          this.lastExpandedTab = accordionTab;
  196.       }
  197.       else {
  198.          this.lastExpandedTab.content.style.height = "1px";
  199.          accordionTab.content.style.height = this.options.panelHeight + "px";
  200.          this.lastExpandedTab = accordionTab;
  201.          this.showTabDone(lastExpandedTab);
  202.       }
  203.    },
  204.    showTabDone: function(collapsedTab) {
  205.       collapsedTab.content.style.display = 'none';
  206.       this.lastExpandedTab.showExpanded();
  207.       if ( this.options.onShowTab )
  208.          this.options.onShowTab(this.lastExpandedTab);
  209.    },
  210.    _attachBehaviors: function() {
  211.       var panels = this._getDirectChildrenByTag(this.container, 'DIV');
  212.       for ( var i = 0 ; i < panels.length ; i++ ) {
  213.          var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
  214.          if ( tabChildren.length != 2 )
  215.             continue; // unexpected
  216.          var tabTitleBar   = tabChildren[0];
  217.          var tabContentBox = tabChildren[1];
  218.          this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
  219.       }
  220.    },
  221.    _getDirectChildrenByTag: function(e, tagName) {
  222.       var kids = new Array();
  223.       var allKids = e.childNodes;
  224.       for( var i = 0 ; i < allKids.length ; i++ )
  225.          if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
  226.             kids.push(allKids[i]);
  227.       return kids;
  228.    }
  229. };
  230. Rico.Accordion.Tab = Class.create();
  231. Rico.Accordion.Tab.prototype = {
  232.    initialize: function(accordion, titleBar, content) {
  233.       this.accordion = accordion;
  234.       this.titleBar  = titleBar;
  235.       this.content   = content;
  236.       this._attachBehaviors();
  237.    },
  238.    collapse: function() {
  239.       this.showCollapsed();
  240.       this.content.style.height = "1px";
  241.    },
  242.    showCollapsed: function() {
  243.       this.expanded = false;
  244.       this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
  245.       this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
  246.       this.titleBar.style.fontWeight      = this.accordion.options.collapsedFontWeight;
  247.       this.content.style.overflow = "hidden";
  248.    },
  249.    showExpanded: function() {
  250.       this.expanded = true;
  251.       this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
  252.       this.titleBar.style.color           = this.accordion.options.expandedTextColor;
  253.       this.content.style.overflow         = "auto";
  254.    },
  255.    titleBarClicked: function(e) {
  256.       if ( this.accordion.lastExpandedTab == this )
  257.          return;
  258.       this.accordion.showTab(this);
  259.    },
  260.    hover: function(e) {
  261. this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
  262. this.titleBar.style.color           = this.accordion.options.hoverTextColor;
  263.    },
  264.    unhover: function(e) {
  265.       if ( this.expanded ) {
  266.          this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
  267.          this.titleBar.style.color           = this.accordion.options.expandedTextColor;
  268.       }
  269.       else {
  270.          this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
  271.          this.titleBar.style.color           = this.accordion.options.collapsedTextColor;
  272.       }
  273.    },
  274.    _attachBehaviors: function() {
  275.       this.content.style.border = "1px solid " + this.accordion.options.borderColor;
  276.       this.content.style.borderTopWidth    = "0px";
  277.       this.content.style.borderBottomWidth = "0px";
  278.       this.content.style.margin            = "0px";
  279.       this.titleBar.onclick     = this.titleBarClicked.bindAsEventListener(this);
  280.       this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
  281.       this.titleBar.onmouseout  = this.unhover.bindAsEventListener(this);
  282.    }
  283. };
  284. //-------------------- ricoAjaxEngine.js
  285. Rico.AjaxEngine = Class.create();
  286. Rico.AjaxEngine.prototype = {
  287.    initialize: function() {
  288.       this.ajaxElements = new Array();
  289.       this.ajaxObjects  = new Array();
  290.       this.requestURLS  = new Array();
  291.       this.options = {};
  292.    },
  293.    registerAjaxElement: function( anId, anElement ) {
  294.       if ( !anElement )
  295.          anElement = $(anId);
  296.       this.ajaxElements[anId] = anElement;
  297.    },
  298.    registerAjaxObject: function( anId, anObject ) {
  299.       this.ajaxObjects[anId] = anObject;
  300.    },
  301.    registerRequest: function (requestLogicalName, requestURL) {
  302.       this.requestURLS[requestLogicalName] = requestURL;
  303.    },
  304.    sendRequest: function(requestName, options) {
  305.       // Allow for backwards Compatibility
  306.       if ( arguments.length >= 2 )
  307.        if (typeof arguments[1] == 'string')
  308.          options = {parameters: this._createQueryString(arguments, 1)};
  309.       this.sendRequestWithData(requestName, null, options);
  310.    },
  311.    sendRequestWithData: function(requestName, xmlDocument, options) {
  312.       var requestURL = this.requestURLS[requestName];
  313.       if ( requestURL == null )
  314.          return;
  315.       // Allow for backwards Compatibility
  316.       if ( arguments.length >= 3 )
  317.         if (typeof arguments[2] == 'string')
  318.           options.parameters = this._createQueryString(arguments, 2);
  319.       new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument));
  320.    },
  321.    sendRequestAndUpdate: function(requestName,container,options) {
  322.       // Allow for backwards Compatibility
  323.       if ( arguments.length >= 3 )
  324.         if (typeof arguments[2] == 'string')
  325.           options.parameters = this._createQueryString(arguments, 2);
  326.       this.sendRequestWithDataAndUpdate(requestName, null, container, options);
  327.    },
  328.    sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
  329.       var requestURL = this.requestURLS[requestName];
  330.       if ( requestURL == null )
  331.          return;
  332.       // Allow for backwards Compatibility
  333.       if ( arguments.length >= 4 )
  334.         if (typeof arguments[3] == 'string')
  335.           options.parameters = this._createQueryString(arguments, 3);
  336.       var updaterOptions = this._requestOptions(options,xmlDocument);
  337.       new Ajax.Updater(container, requestURL, updaterOptions);
  338.    },
  339.    // Private -- not part of intended engine API --------------------------------------------------------------------
  340.    _requestOptions: function(options,xmlDoc) {
  341.       var requestHeaders = ['X-Rico-Version', Rico.Version ];
  342.       var sendMethod = 'post';
  343.       if ( xmlDoc == null )
  344.         if (Rico.prototypeVersion < 1.4)
  345.         requestHeaders.push( 'Content-type', 'text/xml' );
  346.       else
  347.           sendMethod = 'get';
  348.       (!options) ? options = {} : '';
  349.       if (!options._RicoOptionsProcessed){
  350.       // Check and keep any user onComplete functions
  351.         if (options.onComplete)
  352.              options.onRicoComplete = options.onComplete;
  353.         // Fix onComplete
  354.         if (options.overrideOnComplete)
  355.           options.onComplete = options.overrideOnComplete;
  356.         else
  357.           options.onComplete = this._onRequestComplete.bind(this);
  358.         options._RicoOptionsProcessed = true;
  359.       }
  360.      // Set the default options and extend with any user options
  361.      this.options = {
  362.                      requestHeaders: requestHeaders,
  363.                      parameters:     options.parameters,
  364.                      postBody:       xmlDoc,
  365.                      method:         sendMethod,
  366.                      onComplete:     options.onComplete
  367.                     };
  368.      // Set any user options:
  369.      Object.extend(this.options, options);
  370.      return this.options;
  371.    },
  372.    _createQueryString: function( theArgs, offset ) {
  373.       var queryString = ""
  374.       for ( var i = offset ; i < theArgs.length ; i++ ) {
  375.           if ( i != offset )
  376.             queryString += "&";
  377.           var anArg = theArgs[i];
  378.           if ( anArg.name != undefined && anArg.value != undefined ) {
  379.             queryString += anArg.name +  "=" + escape(anArg.value);
  380.           }
  381.           else {
  382.              var ePos  = anArg.indexOf('=');
  383.              var argName  = anArg.substring( 0, ePos );
  384.              var argValue = anArg.substring( ePos + 1 );
  385.              queryString += argName + "=" + escape(argValue);
  386.           }
  387.       }
  388.       return queryString;
  389.    },
  390.    _onRequestComplete : function(request) {
  391.       if(!request)
  392.           return;
  393.       // User can set an onFailure option - which will be called by prototype
  394.       if (request.status != 200)
  395.         return;
  396.       var response = request.responseXML.getElementsByTagName("ajax-response");
  397.       if (response == null || response.length != 1)
  398.          return;
  399.       this._processAjaxResponse( response[0].childNodes );
  400.       
  401.       // Check if user has set a onComplete function
  402.       var onRicoComplete = this.options.onRicoComplete;
  403.       if (onRicoComplete != null)
  404.           onRicoComplete();
  405.    },
  406.    _processAjaxResponse: function( xmlResponseElements ) {
  407.       for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) {
  408.          var responseElement = xmlResponseElements[i];
  409.          // only process nodes of type element.....
  410.          if ( responseElement.nodeType != 1 )
  411.             continue;
  412.          var responseType = responseElement.getAttribute("type");
  413.          var responseId   = responseElement.getAttribute("id");
  414.          if ( responseType == "object" )
  415.             this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement );
  416.          else if ( responseType == "element" )
  417.             this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement );
  418.          else
  419.             alert('unrecognized AjaxResponse type : ' + responseType );
  420.       }
  421.    },
  422.    _processAjaxObjectUpdate: function( ajaxObject, responseElement ) {
  423.       ajaxObject.ajaxUpdate( responseElement );
  424.    },
  425.    _processAjaxElementUpdate: function( ajaxElement, responseElement ) {
  426.       ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
  427.    }
  428. }
  429. var ajaxEngine = new Rico.AjaxEngine();
  430. //-------------------- ricoColor.js
  431. Rico.Color = Class.create();
  432. Rico.Color.prototype = {
  433.    initialize: function(red, green, blue) {
  434.       this.rgb = { r: red, g : green, b : blue };
  435.    },
  436.    setRed: function(r) {
  437.       this.rgb.r = r;
  438.    },
  439.    setGreen: function(g) {
  440.       this.rgb.g = g;
  441.    },
  442.    setBlue: function(b) {
  443.       this.rgb.b = b;
  444.    },
  445.    setHue: function(h) {
  446.       // get an HSB model, and set the new hue...
  447.       var hsb = this.asHSB();
  448.       hsb.h = h;
  449.       // convert back to RGB...
  450.       this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
  451.    },
  452.    setSaturation: function(s) {
  453.       // get an HSB model, and set the new hue...
  454.       var hsb = this.asHSB();
  455.       hsb.s = s;
  456.       // convert back to RGB and set values...
  457.       this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b);
  458.    },
  459.    setBrightness: function(b) {
  460.       // get an HSB model, and set the new hue...
  461.       var hsb = this.asHSB();
  462.       hsb.b = b;
  463.       // convert back to RGB and set values...
  464.       this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b );
  465.    },
  466.    darken: function(percent) {
  467.       var hsb  = this.asHSB();
  468.       this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0));
  469.    },
  470.    brighten: function(percent) {
  471.       var hsb  = this.asHSB();
  472.       this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1));
  473.    },
  474.    blend: function(other) {
  475.       this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2);
  476.       this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2);
  477.       this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2);
  478.    },
  479.    isBright: function() {
  480.       var hsb = this.asHSB();
  481.       return this.asHSB().b > 0.5;
  482.    },
  483.    isDark: function() {
  484.       return ! this.isBright();
  485.    },
  486.    asRGB: function() {
  487.       return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")";
  488.    },
  489.    asHex: function() {
  490.       return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart();
  491.    },
  492.    asHSB: function() {
  493.       return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b);
  494.    },
  495.    toString: function() {
  496.       return this.asHex();
  497.    }
  498. };
  499. Rico.Color.createFromHex = function(hexCode) {
  500.   if(hexCode.length==4) {
  501.     var shortHexCode = hexCode; 
  502.     var hexCode = '#';
  503.     for(var i=1;i<4;i++) hexCode += (shortHexCode.charAt(i) + 
  504. shortHexCode.charAt(i));
  505.   }
  506.    if ( hexCode.indexOf('#') == 0 )
  507.       hexCode = hexCode.substring(1);
  508.    var red   = hexCode.substring(0,2);
  509.    var green = hexCode.substring(2,4);
  510.    var blue  = hexCode.substring(4,6);
  511.    return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) );
  512. }
  513. /**
  514.  * Factory method for creating a color from the background of
  515.  * an HTML element.
  516.  */
  517. Rico.Color.createColorFromBackground = function(elem) {
  518.    var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color");
  519.    if ( actualColor == "transparent" && elem.parentNode )
  520.       return Rico.Color.createColorFromBackground(elem.parentNode);
  521.    if ( actualColor == null )
  522.       return new Rico.Color(255,255,255);
  523.    if ( actualColor.indexOf("rgb(") == 0 ) {
  524.       var colors = actualColor.substring(4, actualColor.length - 1 );
  525.       var colorArray = colors.split(",");
  526.       return new Rico.Color( parseInt( colorArray[0] ),
  527.                             parseInt( colorArray[1] ),
  528.                             parseInt( colorArray[2] )  );
  529.    }
  530.    else if ( actualColor.indexOf("#") == 0 ) {
  531.       return Rico.Color.createFromHex(actualColor);
  532.    }
  533.    else
  534.       return new Rico.Color(255,255,255);
  535. }
  536. Rico.Color.HSBtoRGB = function(hue, saturation, brightness) {
  537.    var red   = 0;
  538. var green = 0;
  539. var blue  = 0;
  540.    if (saturation == 0) {
  541.       red = parseInt(brightness * 255.0 + 0.5);
  542.    green = red;
  543.    blue = red;
  544. }
  545. else {
  546.       var h = (hue - Math.floor(hue)) * 6.0;
  547.       var f = h - Math.floor(h);
  548.       var p = brightness * (1.0 - saturation);
  549.       var q = brightness * (1.0 - saturation * f);
  550.       var t = brightness * (1.0 - (saturation * (1.0 - f)));
  551.       switch (parseInt(h)) {
  552.          case 0:
  553.             red   = (brightness * 255.0 + 0.5);
  554.             green = (t * 255.0 + 0.5);
  555.             blue  = (p * 255.0 + 0.5);
  556.             break;
  557.          case 1:
  558.             red   = (q * 255.0 + 0.5);
  559.             green = (brightness * 255.0 + 0.5);
  560.             blue  = (p * 255.0 + 0.5);
  561.             break;
  562.          case 2:
  563.             red   = (p * 255.0 + 0.5);
  564.             green = (brightness * 255.0 + 0.5);
  565.             blue  = (t * 255.0 + 0.5);
  566.             break;
  567.          case 3:
  568.             red   = (p * 255.0 + 0.5);
  569.             green = (q * 255.0 + 0.5);
  570.             blue  = (brightness * 255.0 + 0.5);
  571.             break;
  572.          case 4:
  573.             red   = (t * 255.0 + 0.5);
  574.             green = (p * 255.0 + 0.5);
  575.             blue  = (brightness * 255.0 + 0.5);
  576.             break;
  577.           case 5:
  578.             red   = (brightness * 255.0 + 0.5);
  579.             green = (p * 255.0 + 0.5);
  580.             blue  = (q * 255.0 + 0.5);
  581.             break;
  582.     }
  583. }
  584.    return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) };
  585. }
  586. Rico.Color.RGBtoHSB = function(r, g, b) {
  587.    var hue;
  588.    var saturation;
  589.    var brightness;
  590.    var cmax = (r > g) ? r : g;
  591.    if (b > cmax)
  592.       cmax = b;
  593.    var cmin = (r < g) ? r : g;
  594.    if (b < cmin)
  595.       cmin = b;
  596.    brightness = cmax / 255.0;
  597.    if (cmax != 0)
  598.       saturation = (cmax - cmin)/cmax;
  599.    else
  600.       saturation = 0;
  601.    if (saturation == 0)
  602.       hue = 0;
  603.    else {
  604.       var redc   = (cmax - r)/(cmax - cmin);
  605.      var greenc = (cmax - g)/(cmax - cmin);
  606.      var bluec  = (cmax - b)/(cmax - cmin);
  607.      if (r == cmax)
  608.         hue = bluec - greenc;
  609.      else if (g == cmax)
  610.         hue = 2.0 + redc - bluec;
  611.       else
  612.         hue = 4.0 + greenc - redc;
  613.      hue = hue / 6.0;
  614.      if (hue < 0)
  615.         hue = hue + 1.0;
  616.    }
  617.    return { h : hue, s : saturation, b : brightness };
  618. }
  619. //-------------------- ricoCorner.js
  620. Rico.Corner = {
  621.    round: function(e, options) {
  622.       var e = $(e);
  623.       this._setOptions(options);
  624.       var color = this.options.color;
  625.       if ( this.options.color == "fromElement" )
  626.          color = this._background(e);
  627.       var bgColor = this.options.bgColor;
  628.       if ( this.options.bgColor == "fromParent" )
  629.          bgColor = this._background(e.offsetParent);
  630.       this._roundCornersImpl(e, color, bgColor);
  631.    },
  632.    _roundCornersImpl: function(e, color, bgColor) {
  633.       if(this.options.border)
  634.          this._renderBorder(e,bgColor);
  635.       if(this._isTopRounded())
  636.          this._roundTopCorners(e,color,bgColor);
  637.       if(this._isBottomRounded())
  638.          this._roundBottomCorners(e,color,bgColor);
  639.    },
  640.    _renderBorder: function(el,bgColor) {
  641.       var borderValue = "1px solid " + this._borderColor(bgColor);
  642.       var borderL = "border-left: "  + borderValue;
  643.       var borderR = "border-right: " + borderValue;
  644.       var style   = "style='" + borderL + ";" + borderR +  "'";
  645.       el.innerHTML = "<div " + style + ">" + el.innerHTML + "</div>"
  646.    },
  647.    _roundTopCorners: function(el, color, bgColor) {
  648.       var corner = this._createCorner(bgColor);
  649.       for(var i=0 ; i < this.options.numSlices ; i++ )
  650.          corner.appendChild(this._createCornerSlice(color,bgColor,i,"top"));
  651.       el.style.paddingTop = 0;
  652.       el.insertBefore(corner,el.firstChild);
  653.    },
  654.    _roundBottomCorners: function(el, color, bgColor) {
  655.       var corner = this._createCorner(bgColor);
  656.       for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- )
  657.          corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom"));
  658.       el.style.paddingBottom = 0;
  659.       el.appendChild(corner);
  660.    },
  661.    _createCorner: function(bgColor) {
  662.       var corner = document.createElement("div");
  663.       corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor);
  664.       return corner;
  665.    },
  666.    _createCornerSlice: function(color,bgColor, n, position) {
  667.       var slice = document.createElement("span");
  668.       var inStyle = slice.style;
  669.       inStyle.backgroundColor = color;
  670.       inStyle.display  = "block";
  671.       inStyle.height   = "1px";
  672.       inStyle.overflow = "hidden";
  673.       inStyle.fontSize = "1px";
  674.       var borderColor = this._borderColor(color,bgColor);
  675.       if ( this.options.border && n == 0 ) {
  676.          inStyle.borderTopStyle    = "solid";
  677.          inStyle.borderTopWidth    = "1px";
  678.          inStyle.borderLeftWidth   = "0px";
  679.          inStyle.borderRightWidth  = "0px";
  680.          inStyle.borderBottomWidth = "0px";
  681.          inStyle.height            = "0px"; // assumes css compliant box model
  682.          inStyle.borderColor       = borderColor;
  683.       }
  684.       else if(borderColor) {
  685.          inStyle.borderColor = borderColor;
  686.          inStyle.borderStyle = "solid";
  687.          inStyle.borderWidth = "0px 1px";
  688.       }
  689.       if ( !this.options.compact && (n == (this.options.numSlices-1)) )
  690.          inStyle.height = "2px";
  691.       this._setMargin(slice, n, position);
  692.       this._setBorder(slice, n, position);
  693.       return slice;
  694.    },
  695.    _setOptions: function(options) {
  696.       this.options = {
  697.          corners : "all",
  698.          color   : "fromElement",
  699.          bgColor : "fromParent",
  700.          blend   : true,
  701.          border  : false,
  702.          compact : false
  703.       }
  704.       Object.extend(this.options, options || {});
  705.       this.options.numSlices = this.options.compact ? 2 : 4;
  706.       if ( this._isTransparent() )
  707.          this.options.blend = false;
  708.    },
  709.    _whichSideTop: function() {
  710.       if ( this._hasString(this.options.corners, "all", "top") )
  711.          return "";
  712.       if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 )
  713.          return "";
  714.       if (this.options.corners.indexOf("tl") >= 0)
  715.          return "left";
  716.       else if (this.options.corners.indexOf("tr") >= 0)
  717.           return "right";
  718.       return "";
  719.    },
  720.    _whichSideBottom: function() {
  721.       if ( this._hasString(this.options.corners, "all", "bottom") )
  722.          return "";
  723.       if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 )
  724.          return "";
  725.       if(this.options.corners.indexOf("bl") >=0)
  726.          return "left";
  727.       else if(this.options.corners.indexOf("br")>=0)
  728.          return "right";
  729.       return "";
  730.    },
  731.    _borderColor : function(color,bgColor) {
  732.       if ( color == "transparent" )
  733.          return bgColor;
  734.       else if ( this.options.border )
  735.          return this.options.border;
  736.       else if ( this.options.blend )
  737.          return this._blend( bgColor, color );
  738.       else
  739.          return "";
  740.    },
  741.    _setMargin: function(el, n, corners) {
  742.       var marginSize = this._marginSize(n);
  743.       var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
  744.       if ( whichSide == "left" ) {
  745.          el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px";
  746.       }
  747.       else if ( whichSide == "right" ) {
  748.          el.style.marginRight = marginSize + "px"; el.style.marginLeft  = "0px";
  749.       }
  750.       else {
  751.          el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px";
  752.       }
  753.    },
  754.    _setBorder: function(el,n,corners) {
  755.       var borderSize = this._borderSize(n);
  756.       var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom();
  757.       if ( whichSide == "left" ) {
  758.          el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px";
  759.       }
  760.       else if ( whichSide == "right" ) {
  761.          el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth  = "0px";
  762.       }
  763.       else {
  764.          el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
  765.       }
  766.       if (this.options.border != false)
  767.         el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px";
  768.    },
  769.    _marginSize: function(n) {
  770.       if ( this._isTransparent() )
  771.          return 0;
  772.       var marginSizes          = [ 5, 3, 2, 1 ];
  773.       var blendedMarginSizes   = [ 3, 2, 1, 0 ];
  774.       var compactMarginSizes   = [ 2, 1 ];
  775.       var smBlendedMarginSizes = [ 1, 0 ];
  776.       if ( this.options.compact && this.options.blend )
  777.          return smBlendedMarginSizes[n];
  778.       else if ( this.options.compact )
  779.          return compactMarginSizes[n];
  780.       else if ( this.options.blend )
  781.          return blendedMarginSizes[n];
  782.       else
  783.          return marginSizes[n];
  784.    },
  785.    _borderSize: function(n) {
  786.       var transparentBorderSizes = [ 5, 3, 2, 1 ];
  787.       var blendedBorderSizes     = [ 2, 1, 1, 1 ];
  788.       var compactBorderSizes     = [ 1, 0 ];
  789.       var actualBorderSizes      = [ 0, 2, 0, 0 ];
  790.       if ( this.options.compact && (this.options.blend || this._isTransparent()) )
  791.          return 1;
  792.       else if ( this.options.compact )
  793.          return compactBorderSizes[n];
  794.       else if ( this.options.blend )
  795.          return blendedBorderSizes[n];
  796.       else if ( this.options.border )
  797.          return actualBorderSizes[n];
  798.       else if ( this._isTransparent() )
  799.          return transparentBorderSizes[n];
  800.       return 0;
  801.    },
  802.    _hasString: function(str) { for(var i=1 ; i<arguments.length ; i++) if (str.indexOf(arguments[i]) >= 0) return true; return false; },
  803.    _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; },
  804.    _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } },
  805.    _isTransparent: function() { return this.options.color == "transparent"; },
  806.    _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); },
  807.    _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); },
  808.    _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; }
  809. }
  810. //-------------------- ricoDragAndDrop.js
  811. Rico.DragAndDrop = Class.create();
  812. Rico.DragAndDrop.prototype = {
  813.    initialize: function() {
  814.       this.dropZones                = new Array();
  815.       this.draggables               = new Array();
  816.       this.currentDragObjects       = new Array();
  817.       this.dragElement              = null;
  818.       this.lastSelectedDraggable    = null;
  819.       this.currentDragObjectVisible = false;
  820.       this.interestedInMotionEvents = false;
  821.       this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
  822.       this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
  823.       this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
  824.    },
  825.    registerDropZone: function(aDropZone) {
  826.       this.dropZones[ this.dropZones.length ] = aDropZone;
  827.    },
  828.    deregisterDropZone: function(aDropZone) {
  829.       var newDropZones = new Array();
  830.       var j = 0;
  831.       for ( var i = 0 ; i < this.dropZones.length ; i++ ) {
  832.          if ( this.dropZones[i] != aDropZone )
  833.             newDropZones[j++] = this.dropZones[i];
  834.       }
  835.       this.dropZones = newDropZones;
  836.    },
  837.    clearDropZones: function() {
  838.       this.dropZones = new Array();
  839.    },
  840.    registerDraggable: function( aDraggable ) {
  841.       this.draggables[ this.draggables.length ] = aDraggable;
  842.       this._addMouseDownHandler( aDraggable );
  843.    },
  844.    clearSelection: function() {
  845.       for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
  846.          this.currentDragObjects[i].deselect();
  847.       this.currentDragObjects = new Array();
  848.       this.lastSelectedDraggable = null;
  849.    },
  850.    hasSelection: function() {
  851.       return this.currentDragObjects.length > 0;
  852.    },
  853.    setStartDragFromElement: function( e, mouseDownElement ) {
  854.       this.origPos = RicoUtil.toDocumentPosition(mouseDownElement);
  855.       this.startx = e.screenX - this.origPos.x
  856.       this.starty = e.screenY - this.origPos.y
  857.       //this.startComponentX = e.layerX ? e.layerX : e.offsetX;
  858.       //this.startComponentY = e.layerY ? e.layerY : e.offsetY;
  859.       //this.adjustedForDraggableSize = false;
  860.       this.interestedInMotionEvents = this.hasSelection();
  861.       this._terminateEvent(e);
  862.    },
  863.    updateSelection: function( draggable, extendSelection ) {
  864.       if ( ! extendSelection )
  865.          this.clearSelection();
  866.       if ( draggable.isSelected() ) {
  867.          this.currentDragObjects.removeItem(draggable);
  868.          draggable.deselect();
  869.          if ( draggable == this.lastSelectedDraggable )
  870.             this.lastSelectedDraggable = null;
  871.       }
  872.       else {
  873.          this.currentDragObjects[ this.currentDragObjects.length ] = draggable;
  874.          draggable.select();
  875.          this.lastSelectedDraggable = draggable;
  876.       }
  877.    },
  878.    _mouseDownHandler: function(e) {
  879.       if ( arguments.length == 0 )
  880.          e = event;
  881.       // if not button 1 ignore it...
  882.       var nsEvent = e.which != undefined;
  883.       if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
  884.          return;
  885.       var eventTarget      = e.target ? e.target : e.srcElement;
  886.       var draggableObject  = eventTarget.draggable;
  887.       var candidate = eventTarget;
  888.       while (draggableObject == null && candidate.parentNode) {
  889.          candidate = candidate.parentNode;
  890.          draggableObject = candidate.draggable;
  891.       }
  892.    
  893.       if ( draggableObject == null )
  894.          return;
  895.       this.updateSelection( draggableObject, e.ctrlKey );
  896.       // clear the drop zones postion cache...
  897.       if ( this.hasSelection() )
  898.          for ( var i = 0 ; i < this.dropZones.length ; i++ )
  899.             this.dropZones[i].clearPositionCache();
  900.       this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() );
  901.    },
  902.    _mouseMoveHandler: function(e) {
  903.       var nsEvent = e.which != undefined;
  904.       if ( !this.interestedInMotionEvents ) {
  905.          //this._terminateEvent(e);
  906.          return;
  907.       }
  908.       if ( ! this.hasSelection() )
  909.          return;
  910.       if ( ! this.currentDragObjectVisible )
  911.          this._startDrag(e);
  912.       if ( !this.activatedDropZones )
  913.          this._activateRegisteredDropZones();
  914.       //if ( !this.adjustedForDraggableSize )
  915.       //   this._adjustForDraggableSize(e);
  916.       this._updateDraggableLocation(e);
  917.       this._updateDropZonesHover(e);
  918.       this._terminateEvent(e);
  919.    },
  920.    _makeDraggableObjectVisible: function(e)
  921.    {
  922.       if ( !this.hasSelection() )
  923.          return;
  924.       var dragElement;
  925.       if ( this.currentDragObjects.length > 1 )
  926.          dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects);
  927.       else
  928.          dragElement = this.currentDragObjects[0].getSingleObjectDragGUI();
  929.       // go ahead and absolute position it...
  930.       if ( RicoUtil.getElementsComputedStyle(dragElement, "position")  != "absolute" )
  931.          dragElement.style.position = "absolute";
  932.       // need to parent him into the document...
  933.       if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 )
  934.          document.body.appendChild(dragElement);
  935.       this.dragElement = dragElement;
  936.       this._updateDraggableLocation(e);
  937.       this.currentDragObjectVisible = true;
  938.    },
  939.    /**
  940.    _adjustForDraggableSize: function(e) {
  941.       var dragElementWidth  = this.dragElement.offsetWidth;
  942.       var dragElementHeight = this.dragElement.offsetHeight;
  943.       if ( this.startComponentX > dragElementWidth )
  944.          this.startx -= this.startComponentX - dragElementWidth + 2;
  945.       if ( e.offsetY ) {
  946.          if ( this.startComponentY > dragElementHeight )
  947.             this.starty -= this.startComponentY - dragElementHeight + 2;
  948.       }
  949.       this.adjustedForDraggableSize = true;
  950.    },
  951.    **/
  952.    _leftOffset: function(e) {
  953.    return e.offsetX ? document.body.scrollLeft : 0
  954. },
  955.    _topOffset: function(e) {
  956.    return e.offsetY ? document.body.scrollTop:0
  957. },
  958.    _updateDraggableLocation: function(e) {
  959.       var dragObjectStyle = this.dragElement.style;
  960.       dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
  961.       dragObjectStyle.top  = (e.screenY + this._topOffset(e) - this.starty) + "px";
  962.    },
  963.    _updateDropZonesHover: function(e) {
  964.       var n = this.dropZones.length;
  965.       for ( var i = 0 ; i < n ; i++ ) {
  966.          if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) )
  967.             this.dropZones[i].hideHover();
  968.       }
  969.       for ( var i = 0 ; i < n ; i++ ) {
  970.          if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
  971.             if ( this.dropZones[i].canAccept(this.currentDragObjects) )
  972.                this.dropZones[i].showHover();
  973.          }
  974.       }
  975.    },
  976.    _startDrag: function(e) {
  977.       for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
  978.          this.currentDragObjects[i].startDrag();
  979.       this._makeDraggableObjectVisible(e);
  980.    },
  981.    _mouseUpHandler: function(e) {
  982.       if ( ! this.hasSelection() )
  983.          return;
  984.       var nsEvent = e.which != undefined;
  985.       if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1))
  986.          return;
  987.       this.interestedInMotionEvents = false;
  988.       if ( this.dragElement == null ) {
  989.          this._terminateEvent(e);
  990.          return;
  991.       }
  992.       if ( this._placeDraggableInDropZone(e) )
  993.          this._completeDropOperation(e);
  994.       else {
  995.          this._terminateEvent(e);
  996.          new Rico.Effect.Position( this.dragElement,
  997.                               this.origPos.x,
  998.                               this.origPos.y,
  999.                               200,
  1000.                               20,
  1001.                               { complete : this._doCancelDragProcessing.bind(this) } );
  1002.       }
  1003.      Event.stopObserving(document.body, "mousemove", this._mouseMove);
  1004.      Event.stopObserving(document.body, "mouseup",  this._mouseUp);
  1005.    },
  1006.    _retTrue: function () {
  1007.       return true;
  1008.    },
  1009.    _completeDropOperation: function(e) {
  1010.       if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) {
  1011.          if ( this.dragElement.parentNode != null )
  1012.             this.dragElement.parentNode.removeChild(this.dragElement);
  1013.       }
  1014.       this._deactivateRegisteredDropZones();
  1015.       this._endDrag();
  1016.       this.clearSelection();
  1017.       this.dragElement = null;
  1018.       this.currentDragObjectVisible = false;
  1019.       this._terminateEvent(e);
  1020.    },
  1021.    _doCancelDragProcessing: function() {
  1022.       this._cancelDrag();
  1023.         if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() && this.dragElement)
  1024.            if ( this.dragElement.parentNode != null )
  1025.               this.dragElement.parentNode.removeChild(this.dragElement);
  1026.       this._deactivateRegisteredDropZones();
  1027.       this.dragElement = null;
  1028.       this.currentDragObjectVisible = false;
  1029.    },
  1030.    _placeDraggableInDropZone: function(e) {
  1031.       var foundDropZone = false;
  1032.       var n = this.dropZones.length;
  1033.       for ( var i = 0 ; i < n ; i++ ) {
  1034.          if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) {
  1035.             if ( this.dropZones[i].canAccept(this.currentDragObjects) ) {
  1036.                this.dropZones[i].hideHover();
  1037.                this.dropZones[i].accept(this.currentDragObjects);
  1038.                foundDropZone = true;
  1039.                break;
  1040.             }
  1041.          }
  1042.       }
  1043.       return foundDropZone;
  1044.    },
  1045.    _cancelDrag: function() {
  1046.       for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
  1047.          this.currentDragObjects[i].cancelDrag();
  1048.    },
  1049.    _endDrag: function() {
  1050.       for ( var i = 0 ; i < this.currentDragObjects.length ; i++ )
  1051.          this.currentDragObjects[i].endDrag();
  1052.    },
  1053.    _mousePointInDropZone: function( e, dropZone ) {
  1054.       var absoluteRect = dropZone.getAbsoluteRect();
  1055.       return e.clientX  > absoluteRect.left + this._leftOffset(e) &&
  1056.              e.clientX  < absoluteRect.right + this._leftOffset(e) &&
  1057.              e.clientY  > absoluteRect.top + this._topOffset(e)   &&
  1058.              e.clientY  < absoluteRect.bottom + this._topOffset(e);
  1059.    },
  1060.    _addMouseDownHandler: function( aDraggable )
  1061.    {
  1062.        htmlElement  = aDraggable.getMouseDownHTMLElement();
  1063.       if ( htmlElement  != null ) { 
  1064.          htmlElement.draggable = aDraggable;
  1065.          Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
  1066.          Event.observe(htmlElement, "mousedown", this._mouseDown);
  1067.       }
  1068.    },
  1069.    _activateRegisteredDropZones: function() {
  1070.       var n = this.dropZones.length;
  1071.       for ( var i = 0 ; i < n ; i++ ) {
  1072.          var dropZone = this.dropZones[i];
  1073.          if ( dropZone.canAccept(this.currentDragObjects) )
  1074.             dropZone.activate();
  1075.       }
  1076.       this.activatedDropZones = true;
  1077.    },
  1078.    _deactivateRegisteredDropZones: function() {
  1079.       var n = this.dropZones.length;
  1080.       for ( var i = 0 ; i < n ; i++ )
  1081.          this.dropZones[i].deactivate();
  1082.       this.activatedDropZones = false;
  1083.    },
  1084.    _onmousedown: function () {
  1085.      Event.observe(document.body, "mousemove", this._mouseMove);
  1086.      Event.observe(document.body, "mouseup",  this._mouseUp);
  1087.    },
  1088.    _terminateEvent: function(e) {
  1089.       if ( e.stopPropagation != undefined )
  1090.          e.stopPropagation();
  1091.       else if ( e.cancelBubble != undefined )
  1092.          e.cancelBubble = true;
  1093.       if ( e.preventDefault != undefined )
  1094.          e.preventDefault();
  1095.       else
  1096.          e.returnValue = false;
  1097.    },
  1098.    initializeEventHandlers: function() {
  1099.       if ( typeof document.implementation != "undefined" &&
  1100.          document.implementation.hasFeature("HTML",   "1.0") &&
  1101.          document.implementation.hasFeature("Events", "2.0") &&
  1102.          document.implementation.hasFeature("CSS",    "2.0") ) {
  1103.          document.addEventListener("mouseup",   this._mouseUpHandler.bindAsEventListener(this),  false);
  1104.          document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false);
  1105.       }
  1106.       else {
  1107.          document.attachEvent( "onmouseup",   this._mouseUpHandler.bindAsEventListener(this) );
  1108.          document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) );
  1109.       }
  1110.    }
  1111. }
  1112. var dndMgr = new Rico.DragAndDrop();
  1113. dndMgr.initializeEventHandlers();
  1114. //-------------------- ricoDraggable.js
  1115. Rico.Draggable = Class.create();
  1116. Rico.Draggable.prototype = {
  1117.    initialize: function( type, htmlElement ) {
  1118.       this.type          = type;
  1119.       this.htmlElement   = $(htmlElement);
  1120.       this.selected      = false;
  1121.    },
  1122.    /**
  1123.     *   Returns the HTML element that should have a mouse down event
  1124.     *   added to it in order to initiate a drag operation
  1125.     *
  1126.     **/
  1127.    getMouseDownHTMLElement: function() {
  1128.       return this.htmlElement;
  1129.    },
  1130.    select: function() {
  1131.       this.selected = true;
  1132.       if ( this.showingSelected )
  1133.          return;
  1134.       var htmlElement = this.getMouseDownHTMLElement();
  1135.       var color = Rico.Color.createColorFromBackground(htmlElement);
  1136.       color.isBright() ? color.darken(0.033) : color.brighten(0.033);
  1137.       this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color");
  1138.       htmlElement.style.backgroundColor = color.asHex();
  1139.       this.showingSelected = true;
  1140.    },
  1141.    deselect: function() {
  1142.       this.selected = false;
  1143.       if ( !this.showingSelected )
  1144.          return;
  1145.       var htmlElement = this.getMouseDownHTMLElement();
  1146.       htmlElement.style.backgroundColor = this.saveBackground;
  1147.       this.showingSelected = false;
  1148.    },
  1149.    isSelected: function() {
  1150.       return this.selected;
  1151.    },
  1152.    startDrag: function() {
  1153.    },
  1154.    cancelDrag: function() {
  1155.    },
  1156.    endDrag: function() {
  1157.    },
  1158.    getSingleObjectDragGUI: function() {
  1159.       return this.htmlElement;
  1160.    },
  1161.    getMultiObjectDragGUI: function( draggables ) {
  1162.       return this.htmlElement;
  1163.    },
  1164.    getDroppedGUI: function() {
  1165.       return this.htmlElement;
  1166.    },
  1167.    toString: function() {
  1168.       return this.type + ":" + this.htmlElement + ":";
  1169.    }
  1170. }
  1171. //-------------------- ricoDropzone.js
  1172. Rico.Dropzone = Class.create();
  1173. Rico.Dropzone.prototype = {
  1174.    initialize: function( htmlElement ) {
  1175.       this.htmlElement  = $(htmlElement);
  1176.       this.absoluteRect = null;
  1177.    },
  1178.    getHTMLElement: function() {
  1179.       return this.htmlElement;
  1180.    },
  1181.    clearPositionCache: function() {
  1182.       this.absoluteRect = null;
  1183.    },
  1184.    getAbsoluteRect: function() {
  1185.       if ( this.absoluteRect == null ) {
  1186.          var htmlElement = this.getHTMLElement();
  1187.          var pos = RicoUtil.toViewportPosition(htmlElement);
  1188.          this.absoluteRect = {
  1189.             top:    pos.y,
  1190.             left:   pos.x,
  1191.             bottom: pos.y + htmlElement.offsetHeight,
  1192.             right:  pos.x + htmlElement.offsetWidth
  1193.          };
  1194.       }
  1195.       return this.absoluteRect;
  1196.    },
  1197.    activate: function() {
  1198.       var htmlElement = this.getHTMLElement();
  1199.       if (htmlElement == null  || this.showingActive)
  1200.          return;
  1201.       this.showingActive = true;
  1202.       this.saveBackgroundColor = htmlElement.style.backgroundColor;
  1203.       var fallbackColor = "#ffea84";
  1204.       var currentColor = Rico.Color.createColorFromBackground(htmlElement);
  1205.       if ( currentColor == null )
  1206.          htmlElement.style.backgroundColor = fallbackColor;
  1207.       else {
  1208.          currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2);
  1209.          htmlElement.style.backgroundColor = currentColor.asHex();
  1210.       }
  1211.    },
  1212.    deactivate: function() {
  1213.       var htmlElement = this.getHTMLElement();
  1214.       if (htmlElement == null || !this.showingActive)
  1215.          return;
  1216.       htmlElement.style.backgroundColor = this.saveBackgroundColor;
  1217.       this.showingActive = false;
  1218.       this.saveBackgroundColor = null;
  1219.    },
  1220.    showHover: function() {
  1221.       var htmlElement = this.getHTMLElement();
  1222.       if ( htmlElement == null || this.showingHover )
  1223.          return;
  1224.       this.saveBorderWidth = htmlElement.style.borderWidth;
  1225.       this.saveBorderStyle = htmlElement.style.borderStyle;
  1226.       this.saveBorderColor = htmlElement.style.borderColor;
  1227.       this.showingHover = true;
  1228.       htmlElement.style.borderWidth = "1px";
  1229.       htmlElement.style.borderStyle = "solid";
  1230.       //htmlElement.style.borderColor = "#ff9900";
  1231.       htmlElement.style.borderColor = "#ffff00";
  1232.    },
  1233.    hideHover: function() {
  1234.       var htmlElement = this.getHTMLElement();
  1235.       if ( htmlElement == null || !this.showingHover )
  1236.          return;
  1237.       htmlElement.style.borderWidth = this.saveBorderWidth;
  1238.       htmlElement.style.borderStyle = this.saveBorderStyle;
  1239.       htmlElement.style.borderColor = this.saveBorderColor;
  1240.       this.showingHover = false;
  1241.    },
  1242.    canAccept: function(draggableObjects) {
  1243.       return true;
  1244.    },
  1245.    accept: function(draggableObjects) {
  1246.       var htmlElement = this.getHTMLElement();
  1247.       if ( htmlElement == null )
  1248.          return;
  1249.       n = draggableObjects.length;
  1250.       for ( var i = 0 ; i < n ; i++ )
  1251.       {
  1252.          var theGUI = draggableObjects[i].getDroppedGUI();
  1253.          if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" )
  1254.          {
  1255.             theGUI.style.position = "static";
  1256.             theGUI.style.top = "";
  1257.             theGUI.style.top = "";
  1258.          }
  1259.          htmlElement.appendChild(theGUI);
  1260.       }
  1261.    }
  1262. }
  1263. //-------------------- ricoEffects.js
  1264. Rico.Effect = {};
  1265. Rico.Effect.SizeAndPosition = Class.create();
  1266. Rico.Effect.SizeAndPosition.prototype = {
  1267.    initialize: function(element, x, y, w, h, duration, steps, options) {
  1268.       this.element = $(element);
  1269.       this.x = x;
  1270.       this.y = y;
  1271.       this.w = w;
  1272.       this.h = h;
  1273.       this.duration = duration;
  1274.       this.steps    = steps;
  1275.       this.options  = arguments[7] || {};
  1276.       this.sizeAndPosition();
  1277.    },
  1278.    sizeAndPosition: function() {
  1279.       if (this.isFinished()) {
  1280.          if(this.options.complete) this.options.complete(this);
  1281.          return;
  1282.       }
  1283.       if (this.timer)
  1284.          clearTimeout(this.timer);
  1285.       var stepDuration = Math.round(this.duration/this.steps) ;
  1286.       // Get original values: x,y = top left corner;  w,h = width height
  1287.       var currentX = this.element.offsetLeft;
  1288.       var currentY = this.element.offsetTop;
  1289.       var currentW = this.element.offsetWidth;
  1290.       var currentH = this.element.offsetHeight;
  1291.       // If values not set, or zero, we do not modify them, and take original as final as well
  1292.       this.x = (this.x) ? this.x : currentX;
  1293.       this.y = (this.y) ? this.y : currentY;
  1294.       this.w = (this.w) ? this.w : currentW;
  1295.       this.h = (this.h) ? this.h : currentH;
  1296.       // how much do we need to modify our values for each step?
  1297.       var difX = this.steps >  0 ? (this.x - currentX)/this.steps : 0;
  1298.       var difY = this.steps >  0 ? (this.y - currentY)/this.steps : 0;
  1299.       var difW = this.steps >  0 ? (this.w - currentW)/this.steps : 0;
  1300.       var difH = this.steps >  0 ? (this.h - currentH)/this.steps : 0;
  1301.       this.moveBy(difX, difY);
  1302.       this.resizeBy(difW, difH);
  1303.       this.duration -= stepDuration;
  1304.       this.steps--;
  1305.       this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration);
  1306.    },
  1307.    isFinished: function() {
  1308.       return this.steps <= 0;
  1309.    },
  1310.    moveBy: function( difX, difY ) {
  1311.       var currentLeft = this.element.offsetLeft;
  1312.       var currentTop  = this.element.offsetTop;
  1313.       var intDifX     = parseInt(difX);
  1314.       var intDifY     = parseInt(difY);
  1315.       var style = this.element.style;
  1316.       if ( intDifX != 0 )
  1317.          style.left = (currentLeft + intDifX) + "px";
  1318.       if ( intDifY != 0 )
  1319.          style.top  = (currentTop + intDifY) + "px";
  1320.    },
  1321.    resizeBy: function( difW, difH ) {
  1322.       var currentWidth  = this.element.offsetWidth;
  1323.       var currentHeight = this.element.offsetHeight;
  1324.       var intDifW       = parseInt(difW);
  1325.       var intDifH       = parseInt(difH);
  1326.       var style = this.element.style;
  1327.       if ( intDifW != 0 )
  1328.          style.width   = (currentWidth  + intDifW) + "px";
  1329.       if ( intDifH != 0 )
  1330.          style.height  = (currentHeight + intDifH) + "px";
  1331.    }
  1332. }
  1333. Rico.Effect.Size = Class.create();
  1334. Rico.Effect.Size.prototype = {
  1335.    initialize: function(element, w, h, duration, steps, options) {
  1336.       new Rico.Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
  1337.   }
  1338. }
  1339. Rico.Effect.Position = Class.create();
  1340. Rico.Effect.Position.prototype = {
  1341.    initialize: function(element, x, y, duration, steps, options) {
  1342.       new Rico.Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
  1343.   }
  1344. }
  1345. Rico.Effect.Round = Class.create();
  1346. Rico.Effect.Round.prototype = {
  1347.    initialize: function(tagName, className, options) {
  1348.       var elements = document.getElementsByTagAndClassName(tagName,className);
  1349.       for ( var i = 0 ; i < elements.length ; i++ )
  1350.          Rico.Corner.round( elements[i], options );
  1351.    }
  1352. };
  1353. Rico.Effect.FadeTo = Class.create();
  1354. Rico.Effect.FadeTo.prototype = {
  1355.    initialize: function( element, opacity, duration, steps, options) {
  1356.       this.element  = $(element);
  1357.       this.opacity  = opacity;
  1358.       this.duration = duration;
  1359.       this.steps    = steps;
  1360.       this.options  = arguments[4] || {};
  1361.       this.fadeTo();
  1362.    },
  1363.    fadeTo: function() {
  1364.       if (this.isFinished()) {
  1365.          if(this.options.complete) this.options.complete(this);
  1366.          return;
  1367.       }
  1368.       if (this.timer)
  1369.          clearTimeout(this.timer);
  1370.       var stepDuration = Math.round(this.duration/this.steps) ;
  1371.       var currentOpacity = this.getElementOpacity();
  1372.       var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0;
  1373.       this.changeOpacityBy(delta);
  1374.       this.duration -= stepDuration;
  1375.       this.steps--;
  1376.       this.timer = setTimeout(this.fadeTo.bind(this), stepDuration);
  1377.    },
  1378.    changeOpacityBy: function(v) {
  1379.       var currentOpacity = this.getElementOpacity();
  1380.       var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1));
  1381.       this.element.ricoOpacity = newOpacity;
  1382.       this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")";
  1383.       this.element.style.opacity = newOpacity; /*//*/;
  1384.    },
  1385.    isFinished: function() {
  1386.       return this.steps <= 0;
  1387.    },
  1388.    getElementOpacity: function() {
  1389.       if ( this.element.ricoOpacity == undefined ) {
  1390.          var opacity = RicoUtil.getElementsComputedStyle(this.element, 'opacity');
  1391.          this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
  1392.       }
  1393.       return parseFloat(this.element.ricoOpacity);
  1394.    }
  1395. }
  1396. Rico.Effect.AccordionSize = Class.create();
  1397. Rico.Effect.AccordionSize.prototype = {
  1398.    initialize: function(e1, e2, start, end, duration, steps, options) {
  1399.       this.e1       = $(e1);
  1400.       this.e2       = $(e2);
  1401.       this.start    = start;
  1402.       this.end      = end;
  1403.       this.duration = duration;
  1404.       this.steps    = steps;
  1405.       this.options  = arguments[6] || {};
  1406.       this.accordionSize();
  1407.    },
  1408.    accordionSize: function() {
  1409.       if (this.isFinished()) {
  1410.          // just in case there are round errors or such...
  1411.          this.e1.style.height = this.start + "px";
  1412.          this.e2.style.height = this.end + "px";
  1413.          if(this.options.complete)
  1414.             this.options.complete(this);
  1415.          return;
  1416.       }
  1417.       if (this.timer)
  1418.          clearTimeout(this.timer);
  1419.       var stepDuration = Math.round(this.duration/this.steps) ;
  1420.       var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0;
  1421.       this.resizeBy(diff);
  1422.       this.duration -= stepDuration;
  1423.       this.steps--;
  1424.       this.timer = setTimeout(this.accordionSize.bind(this), stepDuration);
  1425.    },
  1426.    isFinished: function() {
  1427.       return this.steps <= 0;
  1428.    },
  1429.    resizeBy: function(diff) {
  1430.       var h1Height = this.e1.offsetHeight;
  1431.       var h2Height = this.e2.offsetHeight;
  1432.       var intDiff = parseInt(diff);
  1433.       if ( diff != 0 ) {
  1434.          this.e1.style.height = (h1Height - intDiff) + "px";
  1435.          this.e2.style.height = (h2Height + intDiff) + "px";
  1436.       }
  1437.    }
  1438. };
  1439. //-------------------- ricoLiveGrid.js
  1440. // Rico.LiveGridMetaData -----------------------------------------------------
  1441. Rico.LiveGridMetaData = Class.create();
  1442. Rico.LiveGridMetaData.prototype = {
  1443.    initialize: function( pageSize, totalRows, columnCount, options ) {
  1444.       this.pageSize  = pageSize;
  1445.       this.totalRows = totalRows;
  1446.       this.setOptions(options);
  1447.       this.ArrowHeight = 16;
  1448.       this.columnCount = columnCount;
  1449.    },
  1450.    setOptions: function(options) {
  1451.       this.options = {
  1452.          largeBufferSize    : 7.0,   // 7 pages
  1453.          nearLimitFactor    : 0.2    // 20% of buffer
  1454.       };
  1455.       Object.extend(this.options, options || {});
  1456.    },
  1457.    getPageSize: function() {
  1458.       return this.pageSize;
  1459.    },
  1460.    getTotalRows: function() {
  1461.       return this.totalRows;
  1462.    },
  1463.    setTotalRows: function(n) {
  1464.       this.totalRows = n;
  1465.    },
  1466.    getLargeBufferSize: function() {
  1467.       return parseInt(this.options.largeBufferSize * this.pageSize);
  1468.    },
  1469.    getLimitTolerance: function() {
  1470.       return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
  1471.    }
  1472. };
  1473. // Rico.LiveGridScroller -----------------------------------------------------
  1474. Rico.LiveGridScroller = Class.create();
  1475. Rico.LiveGridScroller.prototype = {
  1476.    initialize: function(liveGrid, viewPort) {
  1477.       this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
  1478.       this.liveGrid = liveGrid;
  1479.       this.metaData = liveGrid.metaData;
  1480.       this.createScrollBar();
  1481.       this.scrollTimeout = null;
  1482.       this.lastScrollPos = 0;
  1483.       this.viewPort = viewPort;
  1484.       this.rows = new Array();
  1485.    },
  1486.    isUnPlugged: function() {
  1487.       return this.scrollerDiv.onscroll == null;
  1488.    },
  1489.    plugin: function() {
  1490.       this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
  1491.    },
  1492.    unplug: function() {
  1493.       this.scrollerDiv.onscroll = null;
  1494.    },
  1495.    sizeIEHeaderHack: function() {
  1496.       if ( !this.isIE ) return;
  1497.       var headerTable = $(this.liveGrid.tableId + "_header");
  1498.       if ( headerTable )
  1499.          headerTable.rows[0].cells[0].style.width =
  1500.             (headerTable.rows[0].cells[0].offsetWidth + 1) + "px";
  1501.    },
  1502.    createScrollBar: function() {
  1503.       var visibleHeight = this.liveGrid.viewPort.visibleHeight();
  1504.       // create the outer div...
  1505.       this.scrollerDiv  = document.createElement("div");
  1506.       var scrollerStyle = this.scrollerDiv.style;
  1507.       scrollerStyle.borderRight = this.liveGrid.options.scrollerBorderRight;
  1508.       scrollerStyle.position    = "relative";
  1509.       scrollerStyle.left        = this.isIE ? "-6px" : "-3px";
  1510.       scrollerStyle.width       = "19px";
  1511.       scrollerStyle.height      = visibleHeight + "px";
  1512.       scrollerStyle.overflow    = "auto";
  1513.       // create the inner div...
  1514.       this.heightDiv = document.createElement("div");
  1515.       this.heightDiv.style.width  = "1px";
  1516.       this.heightDiv.style.height = parseInt(visibleHeight *
  1517.                         this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ;
  1518.       this.scrollerDiv.appendChild(this.heightDiv);
  1519.       this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
  1520.      var table = this.liveGrid.table;
  1521.      table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
  1522.      var eventName = this.isIE ? "mousewheel" : "DOMMouseScroll";
  1523.   Event.observe(table, eventName, 
  1524.                 function(evt) {
  1525.                    if (evt.wheelDelta>=0 || evt.detail < 0) //wheel-up
  1526.                       this.scrollerDiv.scrollTop -= (2*this.viewPort.rowHeight);
  1527.                    else
  1528.                       this.scrollerDiv.scrollTop += (2*this.viewPort.rowHeight);
  1529.                    this.handleScroll(false);
  1530.                 }.bindAsEventListener(this), 
  1531.                 false);
  1532.      },
  1533.    updateSize: function() {
  1534.       var table = this.liveGrid.table;
  1535.       var visibleHeight = this.viewPort.visibleHeight();
  1536.       this.heightDiv.style.height = parseInt(visibleHeight *
  1537.                                   this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
  1538.    },
  1539.    rowToPixel: function(rowOffset) {
  1540.       return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
  1541.    },
  1542.    
  1543.    moveScroll: function(rowOffset) {
  1544.       this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
  1545.       if ( this.metaData.options.onscroll )
  1546.          this.metaData.options.onscroll( this.liveGrid, rowOffset );
  1547.    },
  1548.    handleScroll: function() {
  1549.      if ( this.scrollTimeout )
  1550.          clearTimeout( this.scrollTimeout );
  1551.     var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop;
  1552.     if (scrollDiff != 0.00) {
  1553.        var r = this.scrollerDiv.scrollTop % this.viewPort.rowHeight;
  1554.        if (r != 0) {
  1555.           this.unplug();
  1556.           if ( scrollDiff < 0 ) {
  1557.              this.scrollerDiv.scrollTop += (this.viewPort.rowHeight-r);
  1558.           } else {
  1559.              this.scrollerDiv.scrollTop -= r;
  1560.           }
  1561.           this.plugin();
  1562.        }
  1563.     }
  1564.     var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
  1565.     this.liveGrid.requestContentRefresh(contentOffset);
  1566.     this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
  1567.     if ( this.metaData.options.onscroll )
  1568.        this.metaData.options.onscroll( this.liveGrid, contentOffset );
  1569.     this.scrollTimeout = setTimeout(this.scrollIdle.bind(this), 1200 );
  1570.     this.lastScrollPos = this.scrollerDiv.scrollTop;
  1571.    },
  1572.    scrollIdle: function() {
  1573.       if ( this.metaData.options.onscrollidle )
  1574.          this.metaData.options.onscrollidle();
  1575.    }
  1576. };
  1577. // Rico.LiveGridBuffer -----------------------------------------------------
  1578. Rico.LiveGridBuffer = Class.create();
  1579. Rico.LiveGridBuffer.prototype = {
  1580.    initialize: function(metaData, viewPort) {
  1581.       this.startPos = 0;
  1582.       this.size     = 0;
  1583.       this.metaData = metaData;
  1584.       this.rows     = new Array();
  1585.       this.updateInProgress = false;
  1586.       this.viewPort = viewPort;
  1587.       this.maxBufferSize = metaData.getLargeBufferSize() * 2;
  1588.       this.maxFetchSize = metaData.getLargeBufferSize();
  1589.       this.lastOffset = 0;
  1590.    },
  1591.    getBlankRow: function() {
  1592.       if (!this.blankRow ) {
  1593.          this.blankRow = new Array();
  1594.          for ( var i=0; i < this.metaData.columnCount ; i++ ) 
  1595.             this.blankRow[i] = "&nbsp;";
  1596.      }
  1597.      return this.blankRow;
  1598.    },
  1599.    loadRows: function(ajaxResponse) {
  1600.       var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
  1601.       this.updateUI = rowsElement.getAttribute("update_ui") == "true"
  1602.       var newRows = new Array()
  1603.       var trs = rowsElement.getElementsByTagName("tr");
  1604.       for ( var i=0 ; i < trs.length; i++ ) {
  1605.          var row = newRows[i] = new Array(); 
  1606.          var cells = trs[i].getElementsByTagName("td");
  1607.          for ( var j=0; j < cells.length ; j++ ) {
  1608.             var cell = cells[j];
  1609.             var convertSpaces = cell.getAttribute("convert_spaces") == "true";
  1610.             var cellContent = RicoUtil.getContentAsString(cell);
  1611.             row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
  1612.             if (!row[j]) 
  1613.                row[j] = '&nbsp;';
  1614.          }
  1615.       }
  1616.       return newRows;
  1617.    },
  1618.       
  1619.    update: function(ajaxResponse, start) {
  1620.      var newRows = this.loadRows(ajaxResponse);
  1621.       if (this.rows.length == 0) { // initial load
  1622.          this.rows = newRows;
  1623.          this.size = this.rows.length;
  1624.          this.startPos = start;
  1625.          return;
  1626.       }
  1627.       if (start > this.startPos) { //appending
  1628.          if (this.startPos + this.rows.length < start) {
  1629.             this.rows =  newRows;
  1630.             this.startPos = start;//
  1631.          } else {
  1632.               this.rows = this.rows.concat( newRows.slice(0, newRows.length));
  1633.             if (this.rows.length > this.maxBufferSize) {
  1634.                var fullSize = this.rows.length;
  1635.                this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
  1636.                this.startPos = this.startPos +  (fullSize - this.rows.length);
  1637.             }
  1638.          }
  1639.       } else { //prepending
  1640.          if (start + newRows.length < this.startPos) {
  1641.             this.rows =  newRows;
  1642.          } else {
  1643.             this.rows = newRows.slice(0, this.startPos).concat(this.rows);
  1644.             if (this.rows.length > this.maxBufferSize) 
  1645.                this.rows = this.rows.slice(0, this.maxBufferSize)
  1646.          }
  1647.          this.startPos =  start;
  1648.       }
  1649.       this.size = this.rows.length;
  1650.    },
  1651.    
  1652.    clear: function() {
  1653.       this.rows = new Array();
  1654.       this.startPos = 0;
  1655.       this.size = 0;
  1656.    },
  1657.    isOverlapping: function(start, size) {
  1658.       return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
  1659.    },
  1660.    isInRange: function(position) {
  1661.       return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos()); 
  1662.              //&& this.size()  != 0;
  1663.    },
  1664.    isNearingTopLimit: function(position) {
  1665.       return position - this.startPos < this.metaData.getLimitTolerance();
  1666.    },
  1667.    endPos: function() {
  1668.       return this.startPos + this.rows.length;
  1669.    },
  1670.    
  1671.    isNearingBottomLimit: function(position) {
  1672.       return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
  1673.    },
  1674.    isAtTop: function() {
  1675.       return this.startPos == 0;
  1676.    },
  1677.    isAtBottom: function() {
  1678.       return this.endPos() == this.metaData.getTotalRows();
  1679.    },
  1680.    isNearingLimit: function(position) {
  1681.       return ( !this.isAtTop()    && this.isNearingTopLimit(position)) ||
  1682.              ( !this.isAtBottom() && this.isNearingBottomLimit(position) )
  1683.    },
  1684.    getFetchSize: function(offset) {
  1685.       var adjustedOffset = this.getFetchOffset(offset);
  1686.       var adjustedSize = 0;
  1687.       if (adjustedOffset >= this.startPos) { //apending
  1688.          var endFetchOffset = this.maxFetchSize  + adjustedOffset;
  1689.          if (endFetchOffset > this.metaData.totalRows)
  1690.             endFetchOffset = this.metaData.totalRows;
  1691.          adjustedSize = endFetchOffset - adjustedOffset;  
  1692. if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize){
  1693.    adjustedSize = this.maxFetchSize;
  1694. }
  1695.       } else {//prepending
  1696.          var adjustedSize = this.startPos - adjustedOffset;
  1697.          if (adjustedSize > this.maxFetchSize)
  1698.             adjustedSize = this.maxFetchSize;
  1699.       }
  1700.       return adjustedSize;
  1701.    }, 
  1702.    getFetchOffset: function(offset) {
  1703.       var adjustedOffset = offset;
  1704.       if (offset > this.startPos)  //apending
  1705.          adjustedOffset = (offset > this.endPos()) ? offset :  this.endPos(); 
  1706.       else { //prepending
  1707.          if (offset + this.maxFetchSize >= this.startPos) {
  1708.             var adjustedOffset = this.startPos - this.maxFetchSize;
  1709.             if (adjustedOffset < 0)
  1710.                adjustedOffset = 0;
  1711.          }
  1712.       }
  1713.       this.lastOffset = adjustedOffset;
  1714.       return adjustedOffset;
  1715.    },
  1716.    getRows: function(start, count) {
  1717.       var begPos = start - this.startPos
  1718.       var endPos = begPos + count
  1719.       // er? need more data...
  1720.       if ( endPos > this.size )
  1721.          endPos = this.size
  1722.       var results = new Array()
  1723.       var index = 0;
  1724.       for ( var i=begPos ; i < endPos; i++ ) {
  1725.          results[index++] = this.rows[i]
  1726.       }
  1727.       return results
  1728.    },
  1729.    convertSpaces: function(s) {
  1730.       return s.split(" ").join("&nbsp;");
  1731.    }
  1732. };
  1733. //Rico.GridViewPort --------------------------------------------------
  1734. Rico.GridViewPort = Class.create();
  1735. Rico.GridViewPort.prototype = {
  1736.    initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) {
  1737.       this.lastDisplayedStartPos = 0;
  1738.       this.div = table.parentNode;
  1739.       this.table = table
  1740.       this.rowHeight = rowHeight;
  1741.       this.div.style.height = (this.rowHeight * visibleRows) + "px";
  1742.       this.div.style.overflow = "hidden";
  1743.       this.buffer = buffer;
  1744.       this.liveGrid = liveGrid;
  1745.       this.visibleRows = visibleRows + 1;
  1746.       this.lastPixelOffset = 0;
  1747.       this.startPos = 0;
  1748.    },
  1749.    populateRow: function(htmlRow, row) {
  1750.       for (var j=0; j < row.length; j++) {
  1751.          htmlRow.cells[j].innerHTML = row[j]
  1752.       }
  1753.    },
  1754.    
  1755.    bufferChanged: function() {
  1756.       this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
  1757.    },
  1758.    
  1759.    clearRows: function() {
  1760.       if (!this.isBlank) {
  1761.          this.liveGrid.table.className = this.liveGrid.options.loadingClass;
  1762.          for (var i=0; i < this.visibleRows; i++)
  1763.             this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
  1764.          this.isBlank = true;
  1765.       }
  1766.    },
  1767.    
  1768.    clearContents: function() {   
  1769.       this.clearRows();
  1770.       this.scrollTo(0);
  1771.       this.startPos = 0;
  1772.       this.lastStartPos = -1;   
  1773.    },
  1774.    
  1775.    refreshContents: function(startPos) {
  1776.       if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
  1777.          return;
  1778.       }
  1779.       if ((startPos + this.visibleRows < this.buffer.startPos)  
  1780.           || (this.buffer.startPos + this.buffer.size < startPos) 
  1781.           || (this.buffer.size == 0)) {
  1782.          this.clearRows();
  1783.          return;
  1784.       }
  1785.       this.isBlank = false;
  1786.       var viewPrecedesBuffer = this.buffer.startPos > startPos
  1787.       var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos; 
  1788.       var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows) 
  1789.                                  ? this.buffer.startPos + this.buffer.size
  1790.                                  : startPos + this.visibleRows;
  1791.       var rowSize = contentEndPos - contentStartPos;
  1792.       var rows = this.buffer.getRows(contentStartPos, rowSize ); 
  1793.       var blankSize = this.visibleRows - rowSize;
  1794.       var blankOffset = viewPrecedesBuffer ? 0: rowSize;
  1795.       var contentOffset = viewPrecedesBuffer ? blankSize: 0;
  1796.       for (var i=0; i < rows.length; i++) {//initialize what we have
  1797.         this.populateRow(this.table.rows[i + contentOffset], rows[i]);
  1798.       }
  1799.       for (var i=0; i < blankSize; i++) {// blank out the rest 
  1800.         this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow());
  1801.       }
  1802.       this.isPartialBlank = blankSize > 0;
  1803.       this.lastRowPos = startPos;
  1804.        this.liveGrid.table.className = this.liveGrid.options.tableClass;
  1805.        // Check if user has set a onRefreshComplete function
  1806.        var onRefreshComplete = this.liveGrid.options.onRefreshComplete;
  1807.        if (onRefreshComplete != null)
  1808.            onRefreshComplete();
  1809.    },
  1810.    scrollTo: function(pixelOffset) {      
  1811.       if (this.lastPixelOffset == pixelOffset)
  1812.          return;
  1813.       this.refreshContents(parseInt(pixelOffset / this.rowHeight))
  1814.       this.div.scrollTop = pixelOffset % this.rowHeight        
  1815.       
  1816.       this.lastPixelOffset = pixelOffset;
  1817.    },
  1818.    
  1819.    visibleHeight: function() {
  1820.       return parseInt(RicoUtil.getElementsComputedStyle(this.div, 'height'));
  1821.    }
  1822. };
  1823. Rico.LiveGridRequest = Class.create();
  1824. Rico.LiveGridRequest.prototype = {
  1825.    initialize: function( requestOffset, options ) {
  1826.       this.requestOffset = requestOffset;
  1827.    }
  1828. };
  1829. // Rico.LiveGrid -----------------------------------------------------
  1830. Rico.LiveGrid = Class.create();
  1831. Rico.LiveGrid.prototype = {
  1832.    initialize: function( tableId, visibleRows, totalRows, url, options, ajaxOptions ) {
  1833.      this.options = {
  1834.                 tableClass:           $(tableId).className,
  1835.                 loadingClass:         $(tableId).className,
  1836.                 scrollerBorderRight: '1px solid #ababab',
  1837.                 bufferTimeout:        20000,
  1838.                 sortAscendImg:        'images/sort_asc.gif',
  1839.                 sortDescendImg:       'images/sort_desc.gif',
  1840.                 sortImageWidth:       9,
  1841.                 sortImageHeight:      5,
  1842.                 ajaxSortURLParms:     [],
  1843.                 onRefreshComplete:    null,
  1844.                 requestParameters:    null,
  1845.                 inlineStyles:         true
  1846.                 };
  1847.       Object.extend(this.options, options || {});
  1848.       this.ajaxOptions = {parameters: null};
  1849.       Object.extend(this.ajaxOptions, ajaxOptions || {});
  1850.       this.tableId     = tableId; 
  1851.       this.table       = $(tableId);
  1852.       this.addLiveGridHtml();
  1853.       var columnCount  = this.table.rows[0].cells.length;
  1854.       this.metaData    = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options);
  1855.       this.buffer      = new Rico.LiveGridBuffer(this.metaData);
  1856.       var rowCount = this.table.rows.length;
  1857.       this.viewPort =  new Rico.GridViewPort(this.table, 
  1858.                                             this.table.offsetHeight/rowCount,
  1859.                                             visibleRows,
  1860.                                             this.buffer, this);
  1861.       this.scroller    = new Rico.LiveGridScroller(this,this.viewPort);
  1862.       this.options.sortHandler = this.sortHandler.bind(this);
  1863.       if ( $(tableId + '_header') )
  1864.          this.sort = new Rico.LiveGridSort(tableId + '_header', this.options)
  1865.       this.processingRequest = null;
  1866.       this.unprocessedRequest = null;
  1867.       this.initAjax(url);
  1868.       if ( this.options.prefetchBuffer || this.options.prefetchOffset > 0) {
  1869.          var offset = 0;
  1870.          if (this.options.offset ) {
  1871.             offset = this.options.offset;            
  1872.             this.scroller.moveScroll(offset);
  1873.             this.viewPort.scrollTo(this.scroller.rowToPixel(offset));            
  1874.          }
  1875.          if (this.options.sortCol) {
  1876.              this.sortCol = options.sortCol;
  1877.              this.sortDir = options.sortDir;
  1878.          }
  1879.          this.requestContentRefresh(offset);
  1880.       }
  1881.    },
  1882.    addLiveGridHtml: function() {
  1883.      // Check to see if need to create a header table.
  1884.      if (this.table.getElementsByTagName("thead").length > 0){
  1885.        // Create Table this.tableId+'_header'
  1886.        var tableHeader = this.table.cloneNode(true);
  1887.        tableHeader.setAttribute('id', this.tableId+'_header');
  1888.        tableHeader.setAttribute('class', this.table.className+'_header');
  1889.        // Clean up and insert
  1890.        for( var i = 0; i < tableHeader.tBodies.length; i++ ) 
  1891.        tableHeader.removeChild(tableHeader.tBodies[i]);
  1892.        this.table.deleteTHead();
  1893.        this.table.parentNode.insertBefore(tableHeader,this.table);
  1894.      }
  1895.     new Insertion.Before(this.table, "<div id='"+this.tableId+"_container'></div>");
  1896.     this.table.previousSibling.appendChild(this.table);
  1897.     new Insertion.Before(this.table,"<div id='"+this.tableId+"_viewport' style='float:left;'></div>");
  1898.     this.table.previousSibling.appendChild(this.table);
  1899.    },
  1900.    resetContents: function() {
  1901.       this.scroller.moveScroll(0);
  1902.       this.buffer.clear();
  1903.       this.viewPort.clearContents();
  1904.    },
  1905.    
  1906.    sortHandler: function(column) {
  1907.    if(!column) return ;
  1908.       this.sortCol = column.name;
  1909.       this.sortDir = column.currentSort;
  1910.       this.resetContents();
  1911.       this.requestContentRefresh(0) 
  1912.    },
  1913.    adjustRowSize: function() {
  1914.   
  1915. },
  1916.    setTotalRows: function( newTotalRows ) {
  1917.       this.resetContents();
  1918.       this.metaData.setTotalRows(newTotalRows);
  1919.       this.scroller.updateSize();
  1920.    },
  1921.    initAjax: function(url) {
  1922.       ajaxEngine.registerRequest( this.tableId + '_request', url );
  1923.       ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
  1924.    },
  1925.    invokeAjax: function() {
  1926.    },
  1927.    handleTimedOut: function() {
  1928.       //server did not respond in 4 seconds... assume that there could have been
  1929.       //an error or something, and allow requests to be processed again...
  1930.       this.processingRequest = null;
  1931.       this.processQueuedRequest();
  1932.    },
  1933.    fetchBuffer: function(offset) {
  1934.       if ( this.buffer.isInRange(offset) &&
  1935.          !this.buffer.isNearingLimit(offset)) {
  1936.          return;
  1937.          }
  1938.       if (this.processingRequest) {
  1939.           this.unprocessedRequest = new Rico.LiveGridRequest(offset);
  1940.          return;
  1941.       }
  1942.       var bufferStartPos = this.buffer.getFetchOffset(offset);
  1943.       this.processingRequest = new Rico.LiveGridRequest(offset);
  1944.       this.processingRequest.bufferOffset = bufferStartPos;   
  1945.       var fetchSize = this.buffer.getFetchSize(offset);
  1946.       var partialLoaded = false;
  1947.       
  1948.       var queryString
  1949.       if (this.options.requestParameters)
  1950.          queryString = this._createQueryString(this.options.requestParameters, 0);
  1951.         queryString = (queryString == null) ? '' : queryString+'&';
  1952.         queryString  = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos;
  1953.         if (this.sortCol)
  1954.             queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir;
  1955.         this.ajaxOptions.parameters = queryString;
  1956.        ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions );
  1957.        this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
  1958.    },
  1959.    setRequestParams: function() {
  1960.       this.options.requestParameters = [];
  1961.       for ( var i=0 ; i < arguments.length ; i++ )
  1962.          this.options.requestParameters[i] = arguments[i];
  1963.    },
  1964.    requestContentRefresh: function(contentOffset) {
  1965.       this.fetchBuffer(contentOffset);
  1966.    },
  1967.    ajaxUpdate: function(ajaxResponse) {
  1968.       try {
  1969.          clearTimeout( this.timeoutHandler );
  1970.          this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
  1971.          this.viewPort.bufferChanged();
  1972.       }
  1973.       catch(err) {}
  1974.       finally {this.processingRequest = null; }
  1975.       this.processQueuedRequest();
  1976.    },
  1977.    _createQueryString: function( theArgs, offset ) {
  1978.       var queryString = ""
  1979.       if (!theArgs)
  1980.           return queryString;
  1981.       for ( var i = offset ; i < theArgs.length ; i++ ) {
  1982.           if ( i != offset )
  1983.             queryString += "&";
  1984.           var anArg = theArgs[i];
  1985.           if ( anArg.name != undefined && anArg.value != undefined ) {
  1986.             queryString += anArg.name +  "=" + escape(anArg.value);
  1987.           }
  1988.           else {
  1989.              var ePos  = anArg.indexOf('=');
  1990.              var argName  = anArg.substring( 0, ePos );
  1991.              var argValue = anArg.substring( ePos + 1 );
  1992.              queryString += argName + "=" + escape(argValue);
  1993.           }
  1994.       }
  1995.       return queryString;
  1996.    },
  1997.    processQueuedRequest: function() {
  1998.       if (this.unprocessedRequest != null) {
  1999.          this.requestContentRefresh(this.unprocessedRequest.requestOffset);
  2000.          this.unprocessedRequest = null
  2001.       }
  2002.    }
  2003. };
  2004. //-------------------- ricoLiveGridSort.js
  2005. Rico.LiveGridSort = Class.create();
  2006. Rico.LiveGridSort.prototype = {
  2007.    initialize: function(headerTableId, options) {
  2008.       this.headerTableId = headerTableId;
  2009.       this.headerTable   = $(headerTableId);
  2010.       this.options = options;
  2011.       this.setOptions();
  2012.       this.applySortBehavior();
  2013.       if ( this.options.sortCol ) {
  2014.          this.setSortUI( this.options.sortCol, this.options.sortDir );
  2015.       }
  2016.    },
  2017.    setSortUI: function( columnName, sortDirection ) {
  2018.       var cols = this.options.columns;
  2019.       for ( var i = 0 ; i < cols.length ; i++ ) {
  2020.          if ( cols[i].name == columnName ) {
  2021.             this.setColumnSort(i, sortDirection);
  2022.             break;
  2023.          }
  2024.       }
  2025.    },
  2026.    setOptions: function() {
  2027.       // preload the images...
  2028.       new Image().src = this.options.sortAscendImg;
  2029.       new Image().src = this.options.sortDescendImg;
  2030.       this.sort = this.options.sortHandler;
  2031.       if ( !this.options.columns )
  2032.          this.options.columns = this.introspectForColumnInfo();
  2033.       else {
  2034.          // allow client to pass { columns: [ ["a", true], ["b", false] ] }
  2035.          // and convert to an array of Rico.TableColumn objs...
  2036.          this.options.columns = this.convertToTableColumns(this.options.columns);
  2037.       }
  2038.    },
  2039.    applySortBehavior: function() {
  2040.       var headerRow   = this.headerTable.rows[0];
  2041.       var headerCells = headerRow.cells;
  2042.       for ( var i = 0 ; i < headerCells.length ; i++ ) {
  2043.          this.addSortBehaviorToColumn( i, headerCells[i] );
  2044.       }
  2045.    },
  2046.    addSortBehaviorToColumn: function( n, cell ) {
  2047.       if ( this.options.columns[n].isSortable() ) {
  2048.          cell.id            = this.headerTableId + '_' + n;
  2049.          cell.style.cursor  = 'pointer';
  2050.          cell.onclick       = this.headerCellClicked.bindAsEventListener(this);
  2051.          cell.innerHTML     = cell.innerHTML + '<span id="' + this.headerTableId + '_img_' + n + '">'
  2052.                            + '&nbsp;&nbsp;&nbsp;</span>';
  2053.       }
  2054.    },
  2055.    // event handler....
  2056.    headerCellClicked: function(evt) {
  2057.       var eventTarget = evt.target ? evt.target : evt.srcElement;
  2058.       var cellId = eventTarget.id;
  2059.       var columnNumber = parseInt(cellId.substring( cellId.lastIndexOf('_') + 1 ));
  2060.       var sortedColumnIndex = this.getSortedColumnIndex();
  2061.       if ( sortedColumnIndex != -1 ) {
  2062.          if ( sortedColumnIndex != columnNumber ) {
  2063.             this.removeColumnSort(sortedColumnIndex);
  2064.             this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
  2065.          }
  2066.          else
  2067.             this.toggleColumnSort(sortedColumnIndex);
  2068.       }
  2069.       else
  2070.          this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
  2071.       if (this.options.sortHandler) {
  2072.          this.options.sortHandler(this.options.columns[columnNumber]);
  2073.       }
  2074.    },
  2075.    removeColumnSort: function(n) {
  2076.       this.options.columns[n].setUnsorted();
  2077.       this.setSortImage(n);
  2078.    },
  2079.    setColumnSort: function(n, direction) {
  2080.     if(isNaN(n)) return ;
  2081.       this.options.columns[n].setSorted(direction);
  2082.       this.setSortImage(n);
  2083.    },
  2084.    toggleColumnSort: function(n) {
  2085.       this.options.columns[n].toggleSort();
  2086.       this.setSortImage(n);
  2087.    },
  2088.    setSortImage: function(n) {
  2089.       var sortDirection = this.options.columns[n].getSortDirection();
  2090.       var sortImageSpan = $( this.headerTableId + '_img_' + n );
  2091.       if ( sortDirection == Rico.TableColumn.UNSORTED )
  2092.          sortImageSpan.innerHTML = '&nbsp;&nbsp;';
  2093.       else if ( sortDirection == Rico.TableColumn.SORT_ASC )
  2094.          sortImageSpan.innerHTML = '&nbsp;&nbsp;<img width="'  + this.options.sortImageWidth    + '" ' +
  2095.                                                      'height="'+ this.options.sortImageHeight   + '" ' +
  2096.                                                      'src="'   + this.options.sortAscendImg + '"/>';
  2097.       else if ( sortDirection == Rico.TableColumn.SORT_DESC )
  2098.          sortImageSpan.innerHTML = '&nbsp;&nbsp;<img width="'  + this.options.sortImageWidth    + '" ' +
  2099.                                                      'height="'+ this.options.sortImageHeight   + '" ' +
  2100.                                                      'src="'   + this.options.sortDescendImg + '"/>';
  2101.    },
  2102.    getSortedColumnIndex: function() {
  2103.       var cols = this.options.columns;
  2104.       for ( var i = 0 ; i < cols.length ; i++ ) {
  2105.          if ( cols[i].isSorted() )
  2106.             return i;
  2107.       }
  2108.       return -1;
  2109.    },
  2110.    introspectForColumnInfo: function() {
  2111.       var columns = new Array();
  2112.       var headerRow   = this.headerTable.rows[0];
  2113.       var headerCells = headerRow.cells;
  2114.       for ( var i = 0 ; i < headerCells.length ; i++ )
  2115.          columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) );
  2116.       return columns;
  2117.    },
  2118.    convertToTableColumns: function(cols) {
  2119.       var columns = new Array();
  2120.       for ( var i = 0 ; i < cols.length ; i++ )
  2121.          columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) );
  2122.       return columns;
  2123.    },
  2124.    deriveColumnNameFromCell: function(cell,columnNumber) {
  2125.       var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent;
  2126.       return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber;
  2127.    }
  2128. };
  2129. Rico.TableColumn = Class.create();
  2130. Rico.TableColumn.UNSORTED  = 0;
  2131. Rico.TableColumn.SORT_ASC  = "ASC";
  2132. Rico.TableColumn.SORT_DESC = "DESC";
  2133. Rico.TableColumn.prototype = {
  2134.    initialize: function(name, sortable) {
  2135.       this.name        = name;
  2136.       this.sortable    = sortable;
  2137.       this.currentSort = Rico.TableColumn.UNSORTED;
  2138.    },
  2139.    isSortable: function() {
  2140.       return this.sortable;
  2141.    },
  2142.    isSorted: function() {
  2143.       return this.currentSort != Rico.TableColumn.UNSORTED;
  2144.    },
  2145.    getSortDirection: function() {
  2146.       return this.currentSort;
  2147.    },
  2148.    toggleSort: function() {
  2149.       if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC )
  2150.          this.currentSort = Rico.TableColumn.SORT_ASC;
  2151.       else if ( this.currentSort == Rico.TableColumn.SORT_ASC )
  2152.          this.currentSort = Rico.TableColumn.SORT_DESC;
  2153.    },
  2154.    setUnsorted: function(direction) {
  2155.       this.setSorted(Rico.TableColumn.UNSORTED);
  2156.    },
  2157.    setSorted: function(direction) {
  2158.       // direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SORT_DESC...
  2159.       this.currentSort = direction;
  2160.    }
  2161. };
  2162. //-------------------- ricoUtil.js
  2163. var RicoUtil = {
  2164.    getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) {
  2165.       if ( arguments.length == 2 )
  2166.          mozillaEquivalentCSS = cssProperty;
  2167.       var el = $(htmlElement);
  2168.       if ( el.currentStyle )
  2169.          return el.currentStyle[cssProperty];
  2170.       else
  2171.          return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS);
  2172.    },
  2173.    createXmlDocument : function() {
  2174.       if (document.implementation && document.implementation.createDocument) {
  2175.          var doc = document.implementation.createDocument("", "", null);
  2176.          if (doc.readyState == null) {
  2177.             doc.readyState = 1;
  2178.             doc.addEventListener("load", function () {
  2179.                doc.readyState = 4;
  2180.                if (typeof doc.onreadystatechange == "function")
  2181.                   doc.onreadystatechange();
  2182.             }, false);
  2183.          }
  2184.          return doc;
  2185.       }
  2186.       if (window.ActiveXObject)
  2187.           return Try.these(
  2188.             function() { return new ActiveXObject('MSXML2.DomDocument')   },
  2189.             function() { return new ActiveXObject('Microsoft.DomDocument')},
  2190.             function() { return new ActiveXObject('MSXML.DomDocument')    },
  2191.             function() { return new ActiveXObject('MSXML3.DomDocument')   }
  2192.           ) || false;
  2193.       return null;
  2194.    },
  2195.    getContentAsString: function( parentNode ) {
  2196.       return parentNode.xml != undefined ? 
  2197.          this._getContentAsStringIE(parentNode) :
  2198.          this._getContentAsStringMozilla(parentNode);
  2199.    },
  2200.   _getContentAsStringIE: function(parentNode) {
  2201.      var contentStr = "";
  2202.      for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
  2203.          var n = parentNode.childNodes[i];
  2204.          if (n.nodeType == 4) {
  2205.              contentStr += n.nodeValue;
  2206.          }
  2207.          else {
  2208.            contentStr += n.xml;
  2209.        }
  2210.      }
  2211.      return contentStr;
  2212.   },
  2213.   _getContentAsStringMozilla: function(parentNode) {
  2214.      var xmlSerializer = new XMLSerializer();
  2215.      var contentStr = "";
  2216.      for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
  2217.           var n = parentNode.childNodes[i];
  2218.           if (n.nodeType == 4) { // CDATA node
  2219.               contentStr += n.nodeValue;
  2220.           }
  2221.           else {
  2222.             contentStr += xmlSerializer.serializeToString(n);
  2223.         }
  2224.      }
  2225.      return contentStr;
  2226.   },
  2227.    toViewportPosition: function(element) {
  2228.       return this._toAbsolute(element,true);
  2229.    },
  2230.    toDocumentPosition: function(element) {
  2231.       return this._toAbsolute(element,false);
  2232.    },
  2233.    /**
  2234.     *  Compute the elements position in terms of the window viewport
  2235.     *  so that it can be compared to the position of the mouse (dnd)
  2236.     *  This is additions of all the offsetTop,offsetLeft values up the
  2237.     *  offsetParent hierarchy, ...taking into account any scrollTop,
  2238.     *  scrollLeft values along the way...
  2239.     *
  2240.     * IE has a bug reporting a correct offsetLeft of elements within a
  2241.     * a relatively positioned parent!!!
  2242.     **/
  2243.    _toAbsolute: function(element,accountForDocScroll) {
  2244.       if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 )
  2245.          return this._toAbsoluteMozilla(element,accountForDocScroll);
  2246.       var x = 0;
  2247.       var y = 0;
  2248.       var parent = element;
  2249.       while ( parent ) {
  2250.          var borderXOffset = 0;
  2251.          var borderYOffset = 0;
  2252.          if ( parent != element ) {
  2253.             var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" ));
  2254.             var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" ));
  2255.             borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset;
  2256.             borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset;
  2257.          }
  2258.          x += parent.offsetLeft - parent.scrollLeft + borderXOffset;
  2259.          y += parent.offsetTop - parent.scrollTop + borderYOffset;
  2260.          parent = parent.offsetParent;
  2261.       }
  2262.       if ( accountForDocScroll ) {
  2263.          x -= this.docScrollLeft();
  2264.          y -= this.docScrollTop();
  2265.       }
  2266.       return { x:x, y:y };
  2267.    },
  2268.    /**
  2269.     *  Mozilla did not report all of the parents up the hierarchy via the
  2270.     *  offsetParent property that IE did.  So for the calculation of the
  2271.     *  offsets we use the offsetParent property, but for the calculation of
  2272.     *  the scrollTop/scrollLeft adjustments we navigate up via the parentNode
  2273.     *  property instead so as to get the scroll offsets...
  2274.     *
  2275.     **/
  2276.    _toAbsoluteMozilla: function(element,accountForDocScroll) {
  2277.       var x = 0;
  2278.       var y = 0;
  2279.       var parent = element;
  2280.       while ( parent ) {
  2281.          x += parent.offsetLeft;
  2282.          y += parent.offsetTop;
  2283.          parent = parent.offsetParent;
  2284.       }
  2285.       parent = element;
  2286.       while ( parent &&
  2287.               parent != document.body &&
  2288.               parent != document.documentElement ) {
  2289.          if ( parent.scrollLeft  )
  2290.             x -= parent.scrollLeft;
  2291.          if ( parent.scrollTop )
  2292.             y -= parent.scrollTop;
  2293.          parent = parent.parentNode;
  2294.       }
  2295.       if ( accountForDocScroll ) {
  2296.          x -= this.docScrollLeft();
  2297.          y -= this.docScrollTop();
  2298.       }
  2299.       return { x:x, y:y };
  2300.    },
  2301.    docScrollLeft: function() {
  2302.       if ( window.pageXOffset )
  2303.          return window.pageXOffset;
  2304.       else if ( document.documentElement && document.documentElement.scrollLeft )
  2305.          return document.documentElement.scrollLeft;
  2306.       else if ( document.body )
  2307.          return document.body.scrollLeft;
  2308.       else
  2309.          return 0;
  2310.    },
  2311.    docScrollTop: function() {
  2312.       if ( window.pageYOffset )
  2313.          return window.pageYOffset;
  2314.       else if ( document.documentElement && document.documentElement.scrollTop )
  2315.          return document.documentElement.scrollTop;
  2316.       else if ( document.body )
  2317.          return document.body.scrollTop;
  2318.       else
  2319.          return 0;
  2320.    }
  2321. };