/* openrico.org rico.js */ /** * * Copyright 2005 Sabre Airline Solutions * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this * file except in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied. See the License for the specific language governing permissions * and limitations under the License. **/ // rico.js -------------------- var Rico = { Version: '1.1-beta' } Rico.ArrayExtensions = new Array(); if (Object.prototype.extend) { // in prototype.js... Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend; } if (Array.prototype.push) { // in prototype.js... Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.push; } if (!Array.prototype.remove) { Array.prototype.remove = function(dx) { if( isNaN(dx) || dx > this.length ) return false; for( var i=0,n=0; i 1 ) queryString = this._createQueryString(arguments, 1); new Ajax.Request(requestURL, this._requestOptions(queryString)); }, sendRequestWithData: function(requestName, xmlDocument) { var requestURL = this.requestURLS[requestName]; if ( requestURL == null ) return; var queryString = ""; if ( arguments.length > 2 ) queryString = this._createQueryString(arguments, 2); new Ajax.Request(requestURL + "?" + queryString, this._requestOptions(null,xmlDocument)); }, sendRequestAndUpdate: function(requestName,container,options) { var requestURL = this.requestURLS[requestName]; if ( requestURL == null ) return; var queryString = ""; if ( arguments.length > 3 ) queryString = this._createQueryString(arguments, 3); var updaterOptions = this._requestOptions(queryString); updaterOptions.onComplete = null; updaterOptions.extend(options); new Ajax.Updater(container, requestURL, updaterOptions); }, sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) { var requestURL = this.requestURLS[requestName]; if ( requestURL == null ) return; var queryString = ""; if ( arguments.length > 4 ) queryString = this._createQueryString(arguments, 4); var updaterOptions = this._requestOptions(queryString,xmlDocument); updaterOptions.onComplete = null; updaterOptions.extend(options); new Ajax.Updater(container, requestURL + "?" + queryString, updaterOptions); }, // Private -- not part of intended engine API -------------------------------------------------------------------- _requestOptions: function(queryString,xmlDoc) { var self = this; var requestHeaders = ['X-Rico-Version', Rico.Version ]; var sendMethod = "post"; if ( arguments[1] ) requestHeaders.push( 'Content-type', 'text/xml' ); else sendMethod = "get"; return { requestHeaders: requestHeaders, parameters: queryString, postBody: arguments[1] ? xmlDoc : null, method: sendMethod, onComplete: self._onRequestComplete.bind(self) }; }, _createQueryString: function( theArgs, offset ) { var queryString = ""; for ( var i = offset ; i < theArgs.length ; i++ ) { if ( i != offset ) queryString += "&"; var anArg = theArgs[i]; if ( anArg.name != undefined && anArg.value != undefined ) { queryString += anArg.name + "=" + escape(anArg.value); } else { var ePos = anArg.indexOf('='); var argName = anArg.substring( 0, ePos ); var argValue = anArg.substring( ePos + 1 ); queryString += argName + "=" + escape(argValue); } } return queryString; }, _onRequestComplete : function(request) { //!!TODO: error handling infrastructure?? if (request.status != 200) return; var response = request.responseXML.getElementsByTagName("ajax-response"); if (response == null || response.length != 1) return; this._processAjaxResponse( response[0].childNodes ); }, _processAjaxResponse: function( xmlResponseElements ) { for ( var i = 0 ; i < xmlResponseElements.length ; i++ ) { var responseElement = xmlResponseElements[i]; // only process nodes of type element..... if ( responseElement.nodeType != 1 ) continue; var responseType = responseElement.getAttribute("type"); var responseId = responseElement.getAttribute("id"); if ( responseType == "object" ) this._processAjaxObjectUpdate( this.ajaxObjects[ responseId ], responseElement ); else if ( responseType == "element" ) this._processAjaxElementUpdate( this.ajaxElements[ responseId ], responseElement ); else alert('unrecognized AjaxResponse type : ' + responseType ); } }, _processAjaxObjectUpdate: function( ajaxObject, responseElement ) { ajaxObject.ajaxUpdate( responseElement ); }, _processAjaxElementUpdate: function( ajaxElement, responseElement ) { if ( responseElement.xml != undefined ) this._processAjaxElementUpdateIE( ajaxElement, responseElement ); else this._processAjaxElementUpdateMozilla( ajaxElement, responseElement ); }, _processAjaxElementUpdateIE: function( ajaxElement, responseElement ) { var newHTML = ""; for ( var i = 0 ; i < responseElement.childNodes.length ; i++ ) newHTML += responseElement.childNodes[i].xml; ajaxElement.innerHTML = newHTML; }, _processAjaxElementUpdateMozilla: function( ajaxElement, responseElement ) { var xmlSerializer = new XMLSerializer(); var newHTML = ""; for ( var i = 0 ; i < responseElement.childNodes.length ; i++ ) newHTML += xmlSerializer.serializeToString(responseElement.childNodes[i]); ajaxElement.innerHTML = newHTML; } } var ajaxEngine = new Rico.AjaxEngine(); // ricoColor.js -------------------- Rico.Color = Class.create(); Rico.Color.prototype = { initialize: function(red, green, blue) { this.rgb = { r: red, g : green, b : blue }; }, setRed: function(r) { this.rgb.r = r; }, setGreen: function(g) { this.rgb.g = g; }, setBlue: function(b) { this.rgb.b = b; }, setHue: function(h) { // get an HSB model, and set the new hue... var hsb = this.asHSB(); hsb.h = h; // convert back to RGB... this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); }, setSaturation: function(s) { // get an HSB model, and set the new hue... var hsb = this.asHSB(); hsb.s = s; // convert back to RGB and set values... this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, hsb.b); }, setBrightness: function(b) { // get an HSB model, and set the new hue... var hsb = this.asHSB(); hsb.b = b; // convert back to RGB and set values... this.rgb = Rico.Color.HSBtoRGB( hsb.h, hsb.s, hsb.b ); }, darken: function(percent) { var hsb = this.asHSB(); this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.max(hsb.b - percent,0)); }, brighten: function(percent) { var hsb = this.asHSB(); this.rgb = Rico.Color.HSBtoRGB(hsb.h, hsb.s, Math.min(hsb.b + percent,1)); }, blend: function(other) { this.rgb.r = Math.floor((this.rgb.r + other.rgb.r)/2); this.rgb.g = Math.floor((this.rgb.g + other.rgb.g)/2); this.rgb.b = Math.floor((this.rgb.b + other.rgb.b)/2); }, isBright: function() { var hsb = this.asHSB(); return this.asHSB().b > 0.5; }, isDark: function() { return ! this.isBright(); }, asRGB: function() { return "rgb(" + this.rgb.r + "," + this.rgb.g + "," + this.rgb.b + ")"; }, asHex: function() { return "#" + this.rgb.r.toColorPart() + this.rgb.g.toColorPart() + this.rgb.b.toColorPart(); }, asHSB: function() { return Rico.Color.RGBtoHSB(this.rgb.r, this.rgb.g, this.rgb.b); }, toString: function() { return this.asHex(); } }; Rico.Color.createFromHex = function(hexCode) { if ( hexCode.indexOf('#') == 0 ) hexCode = hexCode.substring(1); var red = hexCode.substring(0,2); var green = hexCode.substring(2,4); var blue = hexCode.substring(4,6); return new Rico.Color( parseInt(red,16), parseInt(green,16), parseInt(blue,16) ); } /** * Factory method for creating a color from the background of * an HTML element. */ Rico.Color.createColorFromBackground = function(elem) { var actualColor = RicoUtil.getElementsComputedStyle($(elem), "backgroundColor", "background-color"); if ( actualColor == "transparent" && elem.parent ) return Rico.Color.createColorFromBackground(elem.parent); if ( actualColor == null ) return new Rico.Color(255,255,255); if ( actualColor.indexOf("rgb(") == 0 ) { var colors = actualColor.substring(4, actualColor.length - 1 ); var colorArray = colors.split(","); return new Rico.Color( parseInt( colorArray[0] ), parseInt( colorArray[1] ), parseInt( colorArray[2] ) ); } else if ( actualColor.indexOf("#") == 0 ) { var redPart = parseInt(actualColor.substring(1,3), 16); var greenPart = parseInt(actualColor.substring(3,5), 16); var bluePart = parseInt(actualColor.substring(5), 16); return new Rico.Color( redPart, greenPart, bluePart ); } else return new Rico.Color(255,255,255); } Rico.Color.HSBtoRGB = function(hue, saturation, brightness) { var red = 0; var green = 0; var blue = 0; if (saturation == 0) { red = parseInt(brightness * 255.0 + 0.5); green = red; blue = red; } else { var h = (hue - Math.floor(hue)) * 6.0; var f = h - Math.floor(h); var p = brightness * (1.0 - saturation); var q = brightness * (1.0 - saturation * f); var t = brightness * (1.0 - (saturation * (1.0 - f))); switch (parseInt(h)) { case 0: red = (brightness * 255.0 + 0.5); green = (t * 255.0 + 0.5); blue = (p * 255.0 + 0.5); break; case 1: red = (q * 255.0 + 0.5); green = (brightness * 255.0 + 0.5); blue = (p * 255.0 + 0.5); break; case 2: red = (p * 255.0 + 0.5); green = (brightness * 255.0 + 0.5); blue = (t * 255.0 + 0.5); break; case 3: red = (p * 255.0 + 0.5); green = (q * 255.0 + 0.5); blue = (brightness * 255.0 + 0.5); break; case 4: red = (t * 255.0 + 0.5); green = (p * 255.0 + 0.5); blue = (brightness * 255.0 + 0.5); break; case 5: red = (brightness * 255.0 + 0.5); green = (p * 255.0 + 0.5); blue = (q * 255.0 + 0.5); break; } } return { r : parseInt(red), g : parseInt(green) , b : parseInt(blue) }; } Rico.Color.RGBtoHSB = function(r, g, b) { var hue; var saturaton; var brightness; var cmax = (r > g) ? r : g; if (b > cmax) cmax = b; var cmin = (r < g) ? r : g; if (b < cmin) cmin = b; brightness = cmax / 255.0; if (cmax != 0) saturation = (cmax - cmin)/cmax; else saturation = 0; if (saturation == 0) hue = 0; else { var redc = (cmax - r)/(cmax - cmin); var greenc = (cmax - g)/(cmax - cmin); var bluec = (cmax - b)/(cmax - cmin); if (r == cmax) hue = bluec - greenc; else if (g == cmax) hue = 2.0 + redc - bluec; else hue = 4.0 + greenc - redc; hue = hue / 6.0; if (hue < 0) hue = hue + 1.0; } return { h : hue, s : saturation, b : brightness }; } // ricoCorner.js -------------------- Rico.Corner = { round: function(e, options) { var e = $(e); this._setOptions(options); var color = this.options.color; if ( this.options.color == "fromElement" ) color = this._background(e); var bgColor = this.options.bgColor; if ( this.options.bgColor == "fromParent" ) bgColor = this._background(e.offsetParent); this._roundCornersImpl(e, color, bgColor); }, _roundCornersImpl: function(e, color, bgColor) { if(this.options.border) this._renderBorder(e,bgColor); if(this._isTopRounded()) this._roundTopCorners(e,color,bgColor); if(this._isBottomRounded()) this._roundBottomCorners(e,color,bgColor); }, _renderBorder: function(el,bgColor) { var borderValue = "1px solid " + this._borderColor(bgColor); var borderL = "border-left: " + borderValue; var borderR = "border-right: " + borderValue; var style = "style='" + borderL + ";" + borderR + "'"; el.innerHTML = "
" + el.innerHTML + "
" }, _roundTopCorners: function(el, color, bgColor) { var corner = this._createCorner(bgColor); for(var i=0 ; i < this.options.numSlices ; i++ ) corner.appendChild(this._createCornerSlice(color,bgColor,i,"top")); el.style.paddingTop = 0; el.insertBefore(corner,el.firstChild); }, _roundBottomCorners: function(el, color, bgColor) { var corner = this._createCorner(bgColor); for(var i=(this.options.numSlices-1) ; i >= 0 ; i-- ) corner.appendChild(this._createCornerSlice(color,bgColor,i,"bottom")); el.style.paddingBottom = 0; el.appendChild(corner); }, _createCorner: function(bgColor) { var corner = document.createElement("div"); corner.style.backgroundColor = (this._isTransparent() ? "transparent" : bgColor); return corner; }, _createCornerSlice: function(color,bgColor, n, position) { var slice = document.createElement("span"); var inStyle = slice.style; inStyle.backgroundColor = color; inStyle.display = "block"; inStyle.height = "1px"; inStyle.overflow = "hidden"; inStyle.fontSize = "1px"; var borderColor = this._borderColor(color,bgColor); if ( this.options.border && n == 0 ) { inStyle.borderTopStyle = "solid"; inStyle.borderTopWidth = "1px"; inStyle.borderLeftWidth = "0px"; inStyle.borderRightWidth = "0px"; inStyle.borderBottomWidth = "0px"; inStyle.height = "0px"; // assumes css compliant box model inStyle.borderColor = borderColor; } else if(borderColor) { inStyle.borderColor = borderColor; inStyle.borderStyle = "solid"; inStyle.borderWidth = "0px 1px"; } if ( !this.options.compact && (n == (this.options.numSlices-1)) ) inStyle.height = "2px"; this._setMargin(slice, n, position); this._setBorder(slice, n, position); return slice; }, _setOptions: function(options) { this.options = { corners : "all", color : "fromElement", bgColor : "fromParent", blend : true, border : false, compact : false }.extend(options || {}); this.options.numSlices = this.options.compact ? 2 : 4; if ( this._isTransparent() ) this.options.blend = false; }, _whichSideTop: function() { if ( this._hasString(this.options.corners, "all", "top") ) return ""; if ( this.options.corners.indexOf("tl") >= 0 && this.options.corners.indexOf("tr") >= 0 ) return ""; if (this.options.corners.indexOf("tl") >= 0) return "left"; else if (this.options.corners.indexOf("tr") >= 0) return "right"; return ""; }, _whichSideBottom: function() { if ( this._hasString(this.options.corners, "all", "bottom") ) return ""; if ( this.options.corners.indexOf("bl")>=0 && this.options.corners.indexOf("br")>=0 ) return ""; if(this.options.corners.indexOf("bl") >=0) return "left"; else if(this.options.corners.indexOf("br")>=0) return "right"; return ""; }, _borderColor : function(color,bgColor) { if ( color == "transparent" ) return bgColor; else if ( this.options.border ) return this.options.border; else if ( this.options.blend ) return this._blend( bgColor, color ); else return ""; }, _setMargin: function(el, n, corners) { var marginSize = this._marginSize(n); var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); if ( whichSide == "left" ) { el.style.marginLeft = marginSize + "px"; el.style.marginRight = "0px"; } else if ( whichSide == "right" ) { el.style.marginRight = marginSize + "px"; el.style.marginLeft = "0px"; } else { el.style.marginLeft = marginSize + "px"; el.style.marginRight = marginSize + "px"; } }, _setBorder: function(el,n,corners) { var borderSize = this._borderSize(n); var whichSide = corners == "top" ? this._whichSideTop() : this._whichSideBottom(); if ( whichSide == "left" ) { el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = "0px"; } else if ( whichSide == "right" ) { el.style.borderRightWidth = borderSize + "px"; el.style.borderLeftWidth = "0px"; } else { el.style.borderLeftWidth = borderSize + "px"; el.style.borderRightWidth = borderSize + "px"; } }, _marginSize: function(n) { if ( this._isTransparent() ) return 0; var marginSizes = [ 5, 3, 2, 1 ]; var blendedMarginSizes = [ 3, 2, 1, 0 ]; var compactMarginSizes = [ 2, 1 ]; var smBlendedMarginSizes = [ 1, 0 ]; if ( this.options.compact && this.options.blend ) return smBlendedMarginSizes[n]; else if ( this.options.compact ) return compactMarginSizes[n]; else if ( this.options.blend ) return blendedMarginSizes[n]; else return marginSizes[n]; }, _borderSize: function(n) { var transparentBorderSizes = [ 5, 3, 2, 1 ]; var blendedBorderSizes = [ 2, 1, 1, 1 ]; var compactBorderSizes = [ 1, 0 ]; var actualBorderSizes = [ 0, 2, 0, 0 ]; if ( this.options.compact && (this.options.blend || this._isTransparent()) ) return 1; else if ( this.options.compact ) return compactBorderSizes[n]; else if ( this.options.blend ) return blendedBorderSizes[n]; else if ( this.options.border ) return actualBorderSizes[n]; else if ( this._isTransparent() ) return transparentBorderSizes[n]; return 0; }, _hasString: function(str) { for(var i=1 ; i= 0) return true; return false; }, _blend: function(c1, c2) { var cc1 = Rico.Color.createFromHex(c1); cc1.blend(Rico.Color.createFromHex(c2)); return cc1; }, _background: function(el) { try { return Rico.Color.createColorFromBackground(el).asHex(); } catch(err) { return "#ffffff"; } }, _isTransparent: function() { return this.options.color == "transparent"; }, _isTopRounded: function() { return this._hasString(this.options.corners, "all", "top", "tl", "tr"); }, _isBottomRounded: function() { return this._hasString(this.options.corners, "all", "bottom", "bl", "br"); }, _hasSingleTextChild: function(el) { return el.childNodes.length == 1 && el.childNodes[0].nodeType == 3; } } // ricoDragAndDrop.js -------------------- Rico.DragAndDrop = Class.create(); Rico.DragAndDrop.prototype = { initialize: function() { this.dropZones = new Array(); this.draggables = new Array(); this.currentDragObjects = new Array(); this.dragElement = null; this.lastSelectedDraggable = null; this.currentDragObjectVisible = false; this.interestedInMotionEvents = false; }, registerDropZone: function(aDropZone) { this.dropZones[ this.dropZones.length ] = aDropZone; }, deregisterDropZone: function(aDropZone) { var newDropZones = new Array(); var j = 0; for ( var i = 0 ; i < this.dropZones.length ; i++ ) { if ( this.dropZones[i] != aDropZone ) newDropZones[j++] = this.dropZones[i]; } this.dropZones = newDropZones; }, clearDropZones: function() { this.dropZones = new Array(); }, registerDraggable: function( aDraggable ) { this.draggables[ this.draggables.length ] = aDraggable; this._addMouseDownHandler( aDraggable ); }, clearSelection: function() { for ( var i = 0 ; i < this.currentDragObjects.length ; i++ ) this.currentDragObjects[i].deselect(); this.currentDragObjects = new Array(); this.lastSelectedDraggable = null; }, hasSelection: function() { return this.currentDragObjects.length > 0; }, setStartDragFromElement: function( e, mouseDownElement ) { this.origPos = RicoUtil.toDocumentPosition(mouseDownElement); this.startx = e.screenX - this.origPos.x; this.starty = e.screenY - this.origPos.y; //this.startComponentX = e.layerX ? e.layerX : e.offsetX; //this.startComponentY = e.layerY ? e.layerY : e.offsetY; //this.adjustedForDraggableSize = false; this.interestedInMotionEvents = this.hasSelection(); this._terminateEvent(e); }, updateSelection: function( draggable, extendSelection ) { if ( ! extendSelection ) this.clearSelection(); if ( draggable.isSelected() ) { this.currentDragObjects.removeItem(draggable); draggable.deselect(); if ( draggable == this.lastSelectedDraggable ) this.lastSelectedDraggable = null; } else { this.currentDragObjects[ this.currentDragObjects.length ] = draggable; draggable.select(); this.lastSelectedDraggable = draggable; } }, _mouseDownHandler: function(e) { if ( arguments.length == 0 ) e = event; // if not button 1 ignore it... var nsEvent = e.which != undefined; if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1)) return; var eventTarget = e.target ? e.target : e.srcElement; var draggableObject = eventTarget.draggable; this.updateSelection( draggableObject, e.ctrlKey ); // clear the drop zones postion cache... if ( this.hasSelection() ) for ( var i = 0 ; i < this.dropZones.length ; i++ ) this.dropZones[i].clearPositionCache(); this.setStartDragFromElement( e, draggableObject.getMouseDownHTMLElement() ); }, _mouseMoveHandler: function(e) { var nsEvent = e.which != undefined; if ( !this.interestedInMotionEvents ) { this._terminateEvent(e); return; } if ( ! this.hasSelection() ) return; if ( ! this.currentDragObjectVisible ) this._startDrag(e); if ( !this.activatedDropZones ) this._activateRegisteredDropZones(); //if ( !this.adjustedForDraggableSize ) // this._adjustForDraggableSize(e); this._updateDraggableLocation(e); this._updateDropZonesHover(e); this._terminateEvent(e); }, _makeDraggableObjectVisible: function(e) { if ( !this.hasSelection() ) return; var dragElement; if ( this.currentDragObjects.length > 1 ) dragElement = this.currentDragObjects[0].getMultiObjectDragGUI(this.currentDragObjects); else dragElement = this.currentDragObjects[0].getSingleObjectDragGUI(); // go ahead and absolute position it... if ( RicoUtil.getElementsComputedStyle(dragElement, "position") != "absolute" ) dragElement.style.position = "absolute"; // need to parent him into the document... if ( dragElement.parentNode == null || dragElement.parentNode.nodeType == 11 ) document.body.appendChild(dragElement); this.dragElement = dragElement; this._updateDraggableLocation(e); this.currentDragObjectVisible = true; }, /** _adjustForDraggableSize: function(e) { var dragElementWidth = this.dragElement.offsetWidth; var dragElementHeight = this.dragElement.offsetHeight; if ( this.startComponentX > dragElementWidth ) this.startx -= this.startComponentX - dragElementWidth + 2; if ( e.offsetY ) { if ( this.startComponentY > dragElementHeight ) this.starty -= this.startComponentY - dragElementHeight + 2; } this.adjustedForDraggableSize = true; }, **/ _updateDraggableLocation: function(e) { var dragObjectStyle = this.dragElement.style; dragObjectStyle.left = (e.screenX - this.startx) + "px"; dragObjectStyle.top = (e.screenY - this.starty) + "px"; }, _updateDropZonesHover: function(e) { var n = this.dropZones.length; for ( var i = 0 ; i < n ; i++ ) { if ( ! this._mousePointInDropZone( e, this.dropZones[i] ) ) this.dropZones[i].hideHover(); } for ( var i = 0 ; i < n ; i++ ) { if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) { if ( this.dropZones[i].canAccept(this.currentDragObjects) ) this.dropZones[i].showHover(); } } }, _startDrag: function(e) { for ( var i = 0 ; i < this.currentDragObjects.length ; i++ ) this.currentDragObjects[i].startDrag(); this._makeDraggableObjectVisible(e); }, _mouseUpHandler: function(e) { if ( ! this.hasSelection() ) return; var nsEvent = e.which != undefined; if ( (nsEvent && e.which != 1) || (!nsEvent && e.button != 1)) return; this.interestedInMotionEvents = false; if ( this.dragElement == null ) { this._terminateEvent(e); return; } if ( this._placeDraggableInDropZone(e) ) this._completeDropOperation(e); else { this._terminateEvent(e); new Effect.Position( this.dragElement, this.origPos.x, this.origPos.y, 200, 20, { complete : this._doCancelDragProcessing.bind(this) } ); } }, _completeDropOperation: function(e) { if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) { if ( this.dragElement.parentNode != null ) this.dragElement.parentNode.removeChild(this.dragElement); } this._deactivateRegisteredDropZones(); this._endDrag(); this.clearSelection(); this.dragElement = null; this.currentDragObjectVisible = false; this._terminateEvent(e); }, _doCancelDragProcessing: function() { this._cancelDrag(); if ( this.dragElement != this.currentDragObjects[0].getMouseDownHTMLElement() ) { if ( this.dragElement.parentNode != null ) { this.dragElement.parentNode.removeChild(this.dragElement); } } this._deactivateRegisteredDropZones(); this.dragElement = null; this.currentDragObjectVisible = false; }, _placeDraggableInDropZone: function(e) { var foundDropZone = false; var n = this.dropZones.length; for ( var i = 0 ; i < n ; i++ ) { if ( this._mousePointInDropZone( e, this.dropZones[i] ) ) { if ( this.dropZones[i].canAccept(this.currentDragObjects) ) { this.dropZones[i].hideHover(); this.dropZones[i].accept(this.currentDragObjects); foundDropZone = true; break; } } } return foundDropZone; }, _cancelDrag: function() { for ( var i = 0 ; i < this.currentDragObjects.length ; i++ ) this.currentDragObjects[i].cancelDrag(); }, _endDrag: function() { for ( var i = 0 ; i < this.currentDragObjects.length ; i++ ) this.currentDragObjects[i].endDrag(); }, _mousePointInDropZone: function( e, dropZone ) { var absoluteRect = dropZone.getAbsoluteRect(); return e.clientX > absoluteRect.left && e.clientX < absoluteRect.right && e.clientY > absoluteRect.top && e.clientY < absoluteRect.bottom; }, _addMouseDownHandler: function( aDraggable ) { var htmlElement = aDraggable.getMouseDownHTMLElement(); if ( htmlElement != null ) { htmlElement.draggable = aDraggable; this._addMouseDownEvent( htmlElement ); } }, _activateRegisteredDropZones: function() { var n = this.dropZones.length; for ( var i = 0 ; i < n ; i++ ) { var dropZone = this.dropZones[i]; if ( dropZone.canAccept(this.currentDragObjects) ) dropZone.activate(); } this.activatedDropZones = true; }, _deactivateRegisteredDropZones: function() { var n = this.dropZones.length; for ( var i = 0 ; i < n ; i++ ) this.dropZones[i].deactivate(); this.activatedDropZones = false; }, _addMouseDownEvent: function( htmlElement ) { if ( typeof document.implementation != "undefined" && document.implementation.hasFeature("HTML", "1.0") && document.implementation.hasFeature("Events", "2.0") && document.implementation.hasFeature("CSS", "2.0") ) { htmlElement.addEventListener("mousedown", this._mouseDownHandler.bindAsEventListener(this), false); } else { htmlElement.attachEvent( "onmousedown", this._mouseDownHandler.bindAsEventListener(this) ); } }, _terminateEvent: function(e) { if ( e.stopPropagation != undefined ) e.stopPropagation(); else if ( e.cancelBubble != undefined ) e.cancelBubble = true; if ( e.preventDefault != undefined ) e.preventDefault(); else { e.returnValue = false; } }, initializeEventHandlers: function() { if ( typeof document.implementation != "undefined" && document.implementation.hasFeature("HTML", "1.0") && document.implementation.hasFeature("Events", "2.0") && document.implementation.hasFeature("CSS", "2.0") ) { document.addEventListener("mouseup", this._mouseUpHandler.bindAsEventListener(this), false); document.addEventListener("mousemove", this._mouseMoveHandler.bindAsEventListener(this), false); } else { document.attachEvent( "onmouseup", this._mouseUpHandler.bindAsEventListener(this) ); document.attachEvent( "onmousemove", this._mouseMoveHandler.bindAsEventListener(this) ); } } }; var dndMgr = new Rico.DragAndDrop(); dndMgr.initializeEventHandlers(); // ricoDraggable.js -------------------- Rico.Draggable = Class.create(); Rico.Draggable.prototype = { initialize: function( type, htmlElement ) { this.type = type; this.htmlElement = $(htmlElement); this.selected = false; }, /** * Returns the HTML element that should have a mouse down event * added to it in order to initiate a drag operation * **/ getMouseDownHTMLElement: function() { return this.htmlElement; }, select: function() { this.selected = true; if ( this.showingSelected ) return; var htmlElement = this.getMouseDownHTMLElement(); var color = Rico.Color.createColorFromBackground(htmlElement); color.isBright() ? color.darken(0.033) : color.brighten(0.033); this.saveBackground = RicoUtil.getElementsComputedStyle(htmlElement, "backgroundColor", "background-color"); htmlElement.style.backgroundColor = color.asHex(); this.showingSelected = true; }, deselect: function() { this.selected = false; if ( !this.showingSelected ) return; var htmlElement = this.getMouseDownHTMLElement(); htmlElement.style.backgroundColor = this.saveBackground; this.showingSelected = false; }, isSelected: function() { return this.selected; }, startDrag: function() { }, cancelDrag: function() { }, endDrag: function() { }, getSingleObjectDragGUI: function() { return this.htmlElement; }, getMultiObjectDragGUI: function( draggables ) { return this.htmlElement; }, getDroppedGUI: function() { return this.htmlElement; }, toString: function() { return this.type + ":" + this.htmlElement + ":"; } } // ricoDropzone.js -------------------- Rico.Dropzone = Class.create(); Rico.Dropzone.prototype = { initialize: function( htmlElement ) { this.htmlElement = $(htmlElement); this.absoluteRect = null; }, getHTMLElement: function() { return this.htmlElement; }, clearPositionCache: function() { this.absoluteRect = null; }, getAbsoluteRect: function() { if ( this.absoluteRect == null ) { var htmlElement = this.getHTMLElement(); var pos = RicoUtil.toViewportPosition(htmlElement); this.absoluteRect = { top: pos.y, left: pos.x, bottom: pos.y + htmlElement.offsetHeight, right: pos.x + htmlElement.offsetWidth }; } return this.absoluteRect; }, activate: function() { var htmlElement = this.getHTMLElement(); if (htmlElement == null || this.showingActive) return; this.showingActive = true; this.saveBackgroundColor = htmlElement.style.backgroundColor; var fallbackColor = "#ffea84"; var currentColor = Rico.Color.createColorFromBackground(htmlElement); if ( currentColor == null ) htmlElement.style.backgroundColor = fallbackColor; else { currentColor.isBright() ? currentColor.darken(0.2) : currentColor.brighten(0.2); htmlElement.style.backgroundColor = currentColor.asHex(); } }, deactivate: function() { var htmlElement = this.getHTMLElement(); if (htmlElement == null || !this.showingActive) return; htmlElement.style.backgroundColor = this.saveBackgroundColor; this.showingActive = false; this.saveBackgroundColor = null; }, showHover: function() { var htmlElement = this.getHTMLElement(); if ( htmlElement == null || this.showingHover ) return; this.saveBorderWidth = htmlElement.style.borderWidth; this.saveBorderStyle = htmlElement.style.borderStyle; this.saveBorderColor = htmlElement.style.borderColor; this.showingHover = true; htmlElement.style.borderWidth = "1px"; htmlElement.style.borderStyle = "solid"; //htmlElement.style.borderColor = "#ff9900"; htmlElement.style.borderColor = "#ffff00"; }, hideHover: function() { var htmlElement = this.getHTMLElement(); if ( htmlElement == null || !this.showingHover ) return; htmlElement.style.borderWidth = this.saveBorderWidth; htmlElement.style.borderStyle = this.saveBorderStyle; htmlElement.style.borderColor = this.saveBorderColor; this.showingHover = false; }, canAccept: function(draggableObjects) { return true; }, accept: function(draggableObjects) { var htmlElement = this.getHTMLElement(); if ( htmlElement == null ) return; n = draggableObjects.length; for ( var i = 0 ; i < n ; i++ ) { var theGUI = draggableObjects[i].getDroppedGUI(); if ( RicoUtil.getElementsComputedStyle( theGUI, "position" ) == "absolute" ) { theGUI.style.position = "static"; theGUI.style.top = ""; theGUI.style.top = ""; } htmlElement.appendChild(theGUI); } } } // ricoEffects.js -------------------- Effect.SizeAndPosition = Class.create(); Effect.SizeAndPosition.prototype = { initialize: function(element, x, y, w, h, duration, steps, options) { this.element = $(element); this.x = x; this.y = y; this.w = w; this.h = h; this.duration = duration; this.steps = steps; this.options = arguments[7] || {}; this.sizeAndPosition(); }, sizeAndPosition: function() { if (this.isFinished()) { if(this.options.complete) this.options.complete(this); return; } if (this.timer) clearTimeout(this.timer); var stepDuration = Math.round(this.duration/this.steps) ; // Get original values: x,y = top left corner; w,h = width height var currentX = this.element.offsetLeft; var currentY = this.element.offsetTop; var currentW = this.element.offsetWidth; var currentH = this.element.offsetHeight; // If values not set, or zero, we do not modify them, and take original as final as well this.x = (this.x) ? this.x : currentX; this.y = (this.y) ? this.y : currentY; this.w = (this.w) ? this.w : currentW; this.h = (this.h) ? this.h : currentH; // how much do we need to modify our values for each step? var difX = this.steps > 0 ? (this.x - currentX)/this.steps : 0; var difY = this.steps > 0 ? (this.y - currentY)/this.steps : 0; var difW = this.steps > 0 ? (this.w - currentW)/this.steps : 0; var difH = this.steps > 0 ? (this.h - currentH)/this.steps : 0; this.moveBy(difX, difY); this.resizeBy(difW, difH); this.duration -= stepDuration; this.steps--; this.timer = setTimeout(this.sizeAndPosition.bind(this), stepDuration); }, isFinished: function() { return this.steps <= 0; }, moveBy: function( difX, difY ) { var currentLeft = this.element.offsetLeft; var currentTop = this.element.offsetTop; var intDifX = parseInt(difX); var intDifY = parseInt(difY); var style = this.element.style; if ( intDifX != 0 ) style.left = (currentLeft + intDifX) + "px"; if ( intDifY != 0 ) style.top = (currentTop + intDifY) + "px"; }, resizeBy: function( difW, difH ) { var currentWidth = this.element.offsetWidth; var currentHeight = this.element.offsetHeight; var intDifW = parseInt(difW); var intDifH = parseInt(difH); var style = this.element.style; if ( intDifW != 0 ) style.width = (currentWidth + intDifW) + "px"; if ( intDifH != 0 ) style.height = (currentHeight + intDifH) + "px"; } } Effect.Size = Class.create(); Effect.Size.prototype = { initialize: function(element, w, h, duration, steps, options) { new Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options); } } Effect.Position = Class.create(); Effect.Position.prototype = { initialize: function(element, x, y, duration, steps, options) { new Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options); } } Effect.Round = Class.create(); Effect.Round.prototype = { initialize: function(tagName, className, options) { var elements = document.getElementsByTagAndClassName(tagName,className); for ( var i = 0 ; i < elements.length ; i++ ) Rico.Corner.round( elements[i], options ); } }; Effect.FadeTo = Class.create(); Effect.FadeTo.prototype = { initialize: function( element, opacity, duration, steps, options) { this.element = $(element); this.opacity = opacity; this.duration = duration; this.steps = steps; this.options = arguments[4] || {}; this.fadeTo(); }, fadeTo: function() { if (this.isFinished()) { if(this.options.complete) this.options.complete(this); return; } if (this.timer) clearTimeout(this.timer); var stepDuration = Math.round(this.duration/this.steps) ; var currentOpacity = this.getElementOpacity(); var delta = this.steps > 0 ? (this.opacity - currentOpacity)/this.steps : 0; this.changeOpacityBy(delta); this.duration -= stepDuration; this.steps--; this.timer = setTimeout(this.fadeTo.bind(this), stepDuration); }, changeOpacityBy: function(v) { var currentOpacity = this.getElementOpacity(); var newOpacity = Math.max(0, Math.min(currentOpacity+v, 1)); this.element.ricoOpacity = newOpacity; this.element.style.filter = "alpha(opacity:"+Math.round(newOpacity*100)+")"; this.element.style.opacity = newOpacity; /*//*/; }, isFinished: function() { return this.steps <= 0; }, getElementOpacity: function() { if ( this.element.ricoOpacity == undefined ) { var opacity; if ( this.element.currentStyle ) { opacity = this.element.currentStyle.opacity; } else if ( document.defaultView.getComputedStyle != undefined ) { var computedStyle = document.defaultView.getComputedStyle; opacity = computedStyle(this.element, null).getPropertyValue('opacity'); } this.element.ricoOpacity = opacity != undefined ? opacity : 1.0; } return parseFloat(this.element.ricoOpacity); } } Effect.AccordionSize = Class.create(); Effect.AccordionSize.prototype = { initialize: function(e1, e2, start, end, duration, steps, options) { this.e1 = $(e1); this.e2 = $(e2); this.start = start; this.end = end; this.duration = duration; this.steps = steps; this.options = arguments[6] || {}; this.accordionSize(); }, accordionSize: function() { if (this.isFinished()) { // just in case there are round errors or such... this.e1.style.height = this.start + "px"; this.e2.style.height = this.end + "px"; if(this.options.complete) this.options.complete(this); return; } if (this.timer) clearTimeout(this.timer); var stepDuration = Math.round(this.duration/this.steps) ; var diff = this.steps > 0 ? (parseInt(this.e1.offsetHeight) - this.start)/this.steps : 0; this.resizeBy(diff); this.duration -= stepDuration; this.steps--; this.timer = setTimeout(this.accordionSize.bind(this), stepDuration); }, isFinished: function() { return this.steps <= 0; }, resizeBy: function(diff) { var h1Height = this.e1.offsetHeight; var h2Height = this.e2.offsetHeight; var intDiff = parseInt(diff); if ( diff != 0 ) { this.e1.style.height = (h1Height - intDiff) + "px"; this.e2.style.height = (h2Height + intDiff) + "px"; } } }; // ricoLiveGrid.js -------------------- // Rico.LiveGridMetaData ----------------------------------------------------- Rico.LiveGridMetaData = Class.create(); Rico.LiveGridMetaData.prototype = { initialize: function( pageSize, totalRows, options ) { this.pageSize = pageSize; this.totalRows = totalRows; this.setOptions(options); this.scrollArrowHeight = 16; }, setOptions: function(options) { this.options = { largeBufferSize : 7.0, // 7 pages smallBufferSize : 1.0, // 1 page nearLimitFactor : 0.2 // 20% of buffer }.extend(options || {}); }, getPageSize: function() { return this.pageSize; }, getTotalRows: function() { return this.totalRows; }, setTotalRows: function(n) { this.totalRows = n; }, getLargeBufferSize: function() { return parseInt(this.options.largeBufferSize * this.pageSize); }, getSmallBufferSize: function() { return parseInt(this.options.smallBufferSize * this.pageSize); }, getLimitTolerance: function() { return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor); }, getBufferSize: function(isFull) { return isFull ? this.getLargeBufferSize() : this.getSmallBufferSize(); } }; // Rico.LiveGridScroller ----------------------------------------------------- Rico.LiveGridScroller = Class.create(); Rico.LiveGridScroller.prototype = { initialize: function(liveGrid) { this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0; this.liveGrid = liveGrid; this.metaData = liveGrid.metaData; this.createScrollBar(); this.scrollTimeout = null; //this.sizeIEHeaderHack(); this.lastScrollPos = 0; }, isUnPlugged: function() { return this.scrollerDiv.onscroll == null; }, plugin: function() { this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this); }, unplug: function() { this.scrollerDiv.onscroll = null; }, sizeIEHeaderHack: function() { if ( !this.isIE ) return; var headerTable = $(this.liveGrid.tableId + "_header"); if ( headerTable ) headerTable.rows[0].cells[0].style.width = (headerTable.rows[0].cells[0].offsetWidth + 1) + "px"; }, createScrollBar: function() { var table = this.liveGrid.table; var visibleHeight = table.offsetHeight; // create the outer div... this.scrollerDiv = document.createElement("div"); var scrollerStyle = this.scrollerDiv.style; scrollerStyle.borderRight = "1px solid #ababab"; // hard coded color!!! scrollerStyle.position = "relative"; scrollerStyle.left = this.isIE ? "-6px" : "-3px"; scrollerStyle.width = "19px"; scrollerStyle.height = visibleHeight + "px"; scrollerStyle.overflow = "auto"; // create the inner div... this.heightDiv = document.createElement("div"); this.heightDiv.style.width = "1px"; this.heightDiv.style.height = parseInt(visibleHeight * this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px" ; this.lineHeight = visibleHeight/this.metaData.getPageSize(); this.scrollerDiv.appendChild(this.heightDiv); this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this); table.parentNode.insertBefore( this.scrollerDiv, table.nextSibling ); }, updateSize: function() { var table = this.liveGrid.table; var visibleHeight = table.offsetHeight; this.heightDiv.style.height = parseInt(visibleHeight * this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px"; }, adjustScrollTop: function() { this.unplug(); var rem = this.scrollerDiv.scrollTop % this.lineHeight; if (rem != 0) { if (this.lastScrollPos < this.scrollerDiv.scrollTop) this.scrollerDiv.scrollTop = this.scrollerDiv.scrollTop + this.lineHeight -rem; else this.scrollerDiv.scrollTop = this.scrollerDiv.scrollTop - rem; } this.lastScrollPos = this.scrollerDiv.scrollTop; this.plugin(); }, handleScroll: function() { if ( this.scrollTimeout ) clearTimeout( this.scrollTimeout ); //this.adjustScrollTop(); var contentOffset = parseInt(this.scrollerDiv.scrollTop * this.metaData.getTotalRows() / this.heightDiv.offsetHeight); this.liveGrid.requestContentRefresh(contentOffset); if ( this.metaData.options.onscroll ) this.metaData.options.onscroll( contentOffset, this.metaData ); this.scrollTimeout = setTimeout( this.scrollIdle.bind(this), 1200 ); }, scrollIdle: function() { if ( this.metaData.options.onscrollidle ) this.metaData.options.onscrollidle(); } }; // Rico.LiveGridBuffer ----------------------------------------------------- Rico.LiveGridBuffer = Class.create(); Rico.LiveGridBuffer.prototype = { initialize: function(metaData) { this.startPos = 0; this.size = 0; this.metaData = metaData; this.rows = new Array(); this.updateInProgress = false; }, update: function(ajaxResponse,start) { this.startPos = start; this.rows = new Array(); var rowsElement = ajaxResponse.getElementsByTagName('rows')[0]; this.updateUI = rowsElement.getAttribute("update_ui") == "true"; var trs = rowsElement.getElementsByTagName("tr"); for ( var i=0 ; i < trs.length; i++ ) { var row = this.rows[i] = new Array(); var cells = trs[i].getElementsByTagName("td"); for ( var j=0; j < cells.length ; j++ ) { var cell = cells[j]; var convertSpaces = cell.getAttribute("convert_spaces") == "true"; var cellContent = cell.text != undefined ? cell.text : cell.textContent; row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent; } } this.size = trs.length; }, isFullP: function() { return this.metaData.pageSize != this.size; }, isClose: function(start) { return (start < this.startPos + this.size + (this.size/2)) && (start + this.size + (this.size/2) > this.startPos) }, isInRange: function(start, count) { return (start < this.startPos + this.size) && (start + count > this.startPos) }, isFullyInRange: function(position) { return (position >= this.startPos) && (position+this.metaData.getPageSize()) <= (this.startPos + this.size) }, isNearingTopLimit: function(position) { return position - this.startPos < this.metaData.getLimitTolerance(); }, isNearingBottomLimit: function(position) { var myEnd = position + this.metaData.getPageSize(); var bufferEnd = this.startPos + this.size; return bufferEnd - myEnd < this.metaData.getLimitTolerance(); }, isAtTop: function() { return this.startPos == 0; }, isAtBottom: function() { return this.startPos + this.size == this.metaData.getTotalRows(); }, isNearingLimit: function(position) { return ( !this.isAtTop() && this.isNearingTopLimit(position)) || ( !this.isAtBottom() && this.isNearingBottomLimit(position) ) }, getRows: function(start, count) { var begPos = start - this.startPos; var endPos = begPos + count; // er? need more data... if ( endPos > this.size ) endPos = this.size; var results = new Array(); var index = 0; for ( var i=begPos ; i < endPos; i++ ) { results[index++] = this.rows[i] } return results }, convertSpaces: function(s) { return s.split(" ").join(" "); } }; Rico.LiveGridRequest = Class.create(); Rico.LiveGridRequest.prototype = { initialize: function( requestOffset, options ) { this.requestOffset = requestOffset; } }; // Rico.LiveGrid ----------------------------------------------------- Rico.LiveGrid = Class.create(); Rico.LiveGrid.prototype = { initialize: function( tableId, visibleRows, totalRows, url, options ) { if ( options == null ) options = {}; this.tableId = tableId; this.table = $(tableId); this.metaData = new Rico.LiveGridMetaData(visibleRows, totalRows, options); this.buffer = new Rico.LiveGridBuffer(this.metaData); this.scroller = new Rico.LiveGridScroller(this); this.lastDisplayedStartPos = 0; this.timeoutHander = null; this.additionalParms = options.requestParameters || []; this.processingRequest = null; this.unprocessedRequest = null; this.initAjax(url); if ( options.prefetchBuffer ) this.fetchBuffer(0, true); }, setRequestParams: function() { this.additionalParms = []; for ( var i=0 ; i < arguments.length ; i++ ) this.additionalParms[i] = arguments[i]; }, setTotalRows: function( newTotalRows ) { this.metaData.setTotalRows(newTotalRows); this.scroller.updateSize(); }, initAjax: function(url) { ajaxEngine.registerRequest( this.tableId + '_request', url ); ajaxEngine.registerAjaxObject( this.tableId + '_updater', this ); }, invokeAjax: function() { }, largeBufferWindowStart: function(offset) { val = offset - ( (.5 * this.metaData.getLargeBufferSize()) - (.5 * this.metaData.getPageSize()) ); return Math.max(parseInt(val), 0); }, handleTimedOut: function() { //server did not respond in 4 seconds... assume that there could have been //an error or something, and allow requests to be processed again... this.processingRequest = null; }, fetchBuffer: function(offset, fullBufferp) { if (this.processingRequest) { this.unprocessedRequest = new Rico.LiveGridRequest(offset); return; } var fetchSize = this.metaData.getBufferSize(fullBufferp); bufferStartPos = Math.max(0,fullBufferp ? this.largeBufferWindowStart(offset) : offset); this.processingRequest = new Rico.LiveGridRequest(offset); this.processingRequest.bufferOffset = bufferStartPos; var callParms = []; callParms.push(this.tableId + '_request'); callParms.push('id=' + this.tableId); callParms.push('page_size=' + fetchSize); callParms.push('offset=' + bufferStartPos); for( var i=0 ; i < this.additionalParms.length ; i++ ) callParms.push(this.additionalParms[i]); ajaxEngine.sendRequest.apply( ajaxEngine, callParms ); this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), 4000 ); }, requestContentRefresh: function(contentOffset) { if ( this.buffer && this.buffer.isFullyInRange(contentOffset) ) { this.updateContent(contentOffset); if (this.buffer.isNearingLimit(contentOffset)) this.fetchBuffer(contentOffset, true); } else if (this.buffer && this.buffer.isClose(contentOffset)) this.fetchBuffer(contentOffset, true); else this.fetchBuffer(contentOffset, false); }, ajaxUpdate: function(ajaxResponse) { try { clearTimeout( this.timeoutHandler ); this.buffer = new Rico.LiveGridBuffer(this.metaData); this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset); if (this.unprocessedRequest == null) { offset = this.processingRequest.requestOffset; this.updateContent (offset); } this.processingRequest = null; if (this.unprocessedRequest != null) { this.requestContentRefresh(this.unprocessedRequest.requestOffset); this.unprocessedRequest = null } } catch(err) { } }, updateContent: function( offset ) { this.replaceCellContents(this.buffer, offset); }, replaceCellContents: function(buffer, startPos) { if (startPos == this.lastDisplayedStartPos){ return; } this.lastDisplayedStartPos = startPos; var rows = buffer.getRows(startPos, this.metaData.getPageSize()); for (var i=0; i < rows.length; i++) { var row = rows[i]; for (var j=0; j < row.length; j++) { this.table.rows[i].cells[j].innerHTML = rows[i][j] } } } }; // ricoUtil.js -------------------- var RicoUtil = { getElementsComputedStyle: function ( htmlElement, cssProperty, mozillaEquivalentCSS) { if ( arguments.length == 2 ) mozillaEquivalentCSS = cssProperty; var el = $(htmlElement); if ( el.currentStyle ) return el.currentStyle[cssProperty]; else return document.defaultView.getComputedStyle(el, null).getPropertyValue(mozillaEquivalentCSS); }, createXmlDocument : function() { if (document.implementation && document.implementation.createDocument) { var doc = document.implementation.createDocument("", "", null); if (doc.readyState == null) { doc.readyState = 1; doc.addEventListener("load", function () { doc.readyState = 4; if (typeof doc.onreadystatechange == "function") doc.onreadystatechange(); }, false); } return doc; } if (window.ActiveXObject) return Try.these( function() { return new ActiveXObject('MSXML2.DomDocument') }, function() { return new ActiveXObject('Microsoft.DomDocument')}, function() { return new ActiveXObject('MSXML.DomDocument') }, function() { return new ActiveXObject('MSXML3.DomDocument') } ) || false; return null; }, toViewportPosition: function(element) { return this._toAbsolute(element,true); }, toDocumentPosition: function(element) { return this._toAbsolute(element,false); }, /** * Compute the elements position in terms of the window viewport * so that it can be compared to the position of the mouse (dnd) * This is additions of all the offsetTop,offsetLeft values up the * offsetParent hierarchy, ...taking into account any scrollTop, * scrollLeft values along the way... * * IE has a bug reporting a correct offsetLeft of elements within a * a relatively positioned parent!!! **/ _toAbsolute: function(element,accountForDocScroll) { if ( navigator.userAgent.toLowerCase().indexOf("msie") == -1 ) return this._toAbsoluteMozilla(element,accountForDocScroll); var x = 0; var y = 0; var parent = element; while ( parent ) { var borderXOffset = 0; var borderYOffset = 0; if ( parent != element ) { var borderXOffset = parseInt(this.getElementsComputedStyle(parent, "borderLeftWidth" )); var borderYOffset = parseInt(this.getElementsComputedStyle(parent, "borderTopWidth" )); borderXOffset = isNaN(borderXOffset) ? 0 : borderXOffset; borderYOffset = isNaN(borderYOffset) ? 0 : borderYOffset; } x += parent.offsetLeft - parent.scrollLeft + borderXOffset; y += parent.offsetTop - parent.scrollTop + borderYOffset; parent = parent.offsetParent; } if ( accountForDocScroll ) { x -= this.docScrollLeft(); y -= this.docScrollTop(); } return { x:x, y:y }; }, /** * Mozilla did not report all of the parents up the hierarchy via the * offsetParent property that IE did. So for the calculation of the * offsets we use the offsetParent property, but for the calculation of * the scrollTop/scrollLeft adjustments we navigate up via the parentNode * property instead so as to get the scroll offsets... * **/ _toAbsoluteMozilla: function(element,accountForDocScroll) { var x = 0; var y = 0; var parent = element; while ( parent ) { x += parent.offsetLeft; y += parent.offsetTop; parent = parent.offsetParent; } parent = element; while ( parent && parent != document.body && parent != document.documentElement ) { if ( parent.scrollLeft ) x -= parent.scrollLeft; if ( parent.scrollTop ) y -= parent.scrollTop; parent = parent.parentNode; } if ( accountForDocScroll ) { x -= this.docScrollLeft(); y -= this.docScrollTop(); } return { x:x, y:y }; }, docScrollLeft: function() { if ( window.pageXOffset ) return window.pageXOffset; else if ( document.documentElement && document.documentElement.scrollLeft ) return document.documentElement.scrollLeft; else if ( document.body ) return document.body.scrollLeft; else return 0; }, docScrollTop: function() { if ( window.pageYOffset ) return window.pageYOffset; else if ( document.documentElement && document.documentElement.scrollTop ) return document.documentElement.scrollTop; else if ( document.body ) return document.body.scrollTop; else return 0; } };