mirror of
https://github.com/owntone/owntone-server.git
synced 2024-12-29 00:23:23 -05:00
8b46f4f586
Added rename playlist functionality. (click wait click on a playlist, type new name hit return) WARNING this will remove the smart playlist spec, use it only on static playlists (which you can't even add through the web interface)
2821 lines
88 KiB
JavaScript
2821 lines
88 KiB
JavaScript
/**
|
|
*
|
|
* 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.2',
|
|
prototypeVersion: parseFloat(Prototype.Version.split(".")[0] + "." + Prototype.Version.split(".")[1])
|
|
}
|
|
|
|
if((typeof Prototype=='undefined') || Rico.prototypeVersion < 1.3)
|
|
throw("Rico requires the Prototype JavaScript framework >= 1.3");
|
|
|
|
Rico.ArrayExtensions = new Array();
|
|
|
|
if (Object.prototype.extend) {
|
|
Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
|
|
}else{
|
|
Object.prototype.extend = function(object) {
|
|
return Object.extend.apply(this, [this, object]);
|
|
}
|
|
Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Object.prototype.extend;
|
|
}
|
|
|
|
if (Array.prototype.push) {
|
|
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<this.length; i++ )
|
|
if( i != dx )
|
|
this[n++]=this[i];
|
|
this.length-=1;
|
|
};
|
|
Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.remove;
|
|
}
|
|
|
|
if (!Array.prototype.removeItem) {
|
|
Array.prototype.removeItem = function(item) {
|
|
for ( var i = 0 ; i < this.length ; i++ )
|
|
if ( this[i] == item ) {
|
|
this.remove(i);
|
|
break;
|
|
}
|
|
};
|
|
Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.removeItem;
|
|
}
|
|
|
|
if (!Array.prototype.indices) {
|
|
Array.prototype.indices = function() {
|
|
var indexArray = new Array();
|
|
for ( index in this ) {
|
|
var ignoreThis = false;
|
|
for ( var i = 0 ; i < Rico.ArrayExtensions.length ; i++ ) {
|
|
if ( this[index] == Rico.ArrayExtensions[i] ) {
|
|
ignoreThis = true;
|
|
break;
|
|
}
|
|
}
|
|
if ( !ignoreThis )
|
|
indexArray[ indexArray.length ] = index;
|
|
}
|
|
return indexArray;
|
|
}
|
|
Rico.ArrayExtensions[ Rico.ArrayExtensions.length ] = Array.prototype.indices;
|
|
}
|
|
|
|
// Create the loadXML method and xml getter for Mozilla
|
|
if ( window.DOMParser &&
|
|
window.XMLSerializer &&
|
|
window.Node && Node.prototype && Node.prototype.__defineGetter__ ) {
|
|
|
|
if (!Document.prototype.loadXML) {
|
|
Document.prototype.loadXML = function (s) {
|
|
var doc2 = (new DOMParser()).parseFromString(s, "text/xml");
|
|
while (this.hasChildNodes())
|
|
this.removeChild(this.lastChild);
|
|
|
|
for (var i = 0; i < doc2.childNodes.length; i++) {
|
|
this.appendChild(this.importNode(doc2.childNodes[i], true));
|
|
}
|
|
};
|
|
}
|
|
|
|
Document.prototype.__defineGetter__( "xml",
|
|
function () {
|
|
return (new XMLSerializer()).serializeToString(this);
|
|
}
|
|
);
|
|
}
|
|
|
|
document.getElementsByTagAndClassName = function(tagName, className) {
|
|
if ( tagName == null )
|
|
tagName = '*';
|
|
|
|
var children = document.getElementsByTagName(tagName) || document.all;
|
|
var elements = new Array();
|
|
|
|
if ( className == null )
|
|
return children;
|
|
|
|
for (var i = 0; i < children.length; i++) {
|
|
var child = children[i];
|
|
var classNames = child.className.split(' ');
|
|
for (var j = 0; j < classNames.length; j++) {
|
|
if (classNames[j] == className) {
|
|
elements.push(child);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return elements;
|
|
}
|
|
|
|
|
|
//-------------------- ricoAccordion.js
|
|
Rico.Accordion = Class.create();
|
|
|
|
Rico.Accordion.prototype = {
|
|
|
|
initialize: function(container, options) {
|
|
this.container = $(container);
|
|
this.lastExpandedTab = null;
|
|
this.accordionTabs = new Array();
|
|
this.setOptions(options);
|
|
this._attachBehaviors();
|
|
if(!container) return;
|
|
|
|
this.container.style.borderBottom = '1px solid ' + this.options.borderColor;
|
|
// validate onloadShowTab
|
|
if (this.options.onLoadShowTab >= this.accordionTabs.length)
|
|
this.options.onLoadShowTab = 0;
|
|
|
|
// set the initial visual state...
|
|
for ( var i=0 ; i < this.accordionTabs.length ; i++ )
|
|
{
|
|
if (i != this.options.onLoadShowTab){
|
|
this.accordionTabs[i].collapse();
|
|
this.accordionTabs[i].content.style.display = 'none';
|
|
}
|
|
}
|
|
this.lastExpandedTab = this.accordionTabs[this.options.onLoadShowTab];
|
|
if (this.options.panelHeight == 'auto'){
|
|
var tabToCheck = (this.options.onloadShowTab === 0)? 1 : 0;
|
|
var titleBarSize = parseInt(RicoUtil.getElementsComputedStyle(this.accordionTabs[tabToCheck].titleBar, 'height'));
|
|
if (isNaN(titleBarSize))
|
|
titleBarSize = this.accordionTabs[tabToCheck].titleBar.offsetHeight;
|
|
|
|
var totalTitleBarSize = this.accordionTabs.length * titleBarSize;
|
|
var parentHeight = parseInt(RicoUtil.getElementsComputedStyle(this.container.parentNode, 'height'));
|
|
if (isNaN(parentHeight))
|
|
parentHeight = this.container.parentNode.offsetHeight;
|
|
|
|
this.options.panelHeight = parentHeight - totalTitleBarSize-2;
|
|
}
|
|
|
|
this.lastExpandedTab.content.style.height = this.options.panelHeight + "px";
|
|
this.lastExpandedTab.showExpanded();
|
|
this.lastExpandedTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
|
|
|
|
},
|
|
|
|
setOptions: function(options) {
|
|
this.options = {
|
|
expandedBg : '#63699c',
|
|
hoverBg : '#63699c',
|
|
collapsedBg : '#6b79a5',
|
|
expandedTextColor : '#ffffff',
|
|
expandedFontWeight : 'bold',
|
|
hoverTextColor : '#ffffff',
|
|
collapsedTextColor : '#ced7ef',
|
|
collapsedFontWeight : 'normal',
|
|
hoverTextColor : '#ffffff',
|
|
borderColor : '#1f669b',
|
|
panelHeight : 200,
|
|
onHideTab : null,
|
|
onShowTab : null,
|
|
onLoadShowTab : 0
|
|
}
|
|
Object.extend(this.options, options || {});
|
|
},
|
|
|
|
showTabByIndex: function( anIndex, animate ) {
|
|
var doAnimate = arguments.length == 1 ? true : animate;
|
|
this.showTab( this.accordionTabs[anIndex], doAnimate );
|
|
},
|
|
|
|
showTab: function( accordionTab, animate ) {
|
|
if ( this.lastExpandedTab == accordionTab )
|
|
return;
|
|
|
|
var doAnimate = arguments.length == 1 ? true : animate;
|
|
|
|
if ( this.options.onHideTab )
|
|
this.options.onHideTab(this.lastExpandedTab);
|
|
|
|
this.lastExpandedTab.showCollapsed();
|
|
var accordion = this;
|
|
var lastExpandedTab = this.lastExpandedTab;
|
|
|
|
this.lastExpandedTab.content.style.height = (this.options.panelHeight - 1) + 'px';
|
|
accordionTab.content.style.display = '';
|
|
|
|
accordionTab.titleBar.style.fontWeight = this.options.expandedFontWeight;
|
|
|
|
if ( doAnimate ) {
|
|
new Rico.Effect.AccordionSize( this.lastExpandedTab.content,
|
|
accordionTab.content,
|
|
1,
|
|
this.options.panelHeight,
|
|
50, 7,
|
|
{ complete: function() {accordion.showTabDone(lastExpandedTab)} } );
|
|
this.lastExpandedTab = accordionTab;
|
|
}
|
|
else {
|
|
this.lastExpandedTab.content.style.height = "1px";
|
|
accordionTab.content.style.height = this.options.panelHeight + "px";
|
|
this.lastExpandedTab = accordionTab;
|
|
this.showTabDone(lastExpandedTab);
|
|
}
|
|
},
|
|
|
|
showTabDone: function(collapsedTab) {
|
|
collapsedTab.content.style.display = 'none';
|
|
this.lastExpandedTab.showExpanded();
|
|
if ( this.options.onShowTab )
|
|
this.options.onShowTab(this.lastExpandedTab);
|
|
},
|
|
|
|
_attachBehaviors: function() {
|
|
var panels = this._getDirectChildrenByTag(this.container, 'DIV');
|
|
for ( var i = 0 ; i < panels.length ; i++ ) {
|
|
|
|
var tabChildren = this._getDirectChildrenByTag(panels[i],'DIV');
|
|
if ( tabChildren.length != 2 )
|
|
continue; // unexpected
|
|
|
|
var tabTitleBar = tabChildren[0];
|
|
var tabContentBox = tabChildren[1];
|
|
this.accordionTabs.push( new Rico.Accordion.Tab(this,tabTitleBar,tabContentBox) );
|
|
}
|
|
},
|
|
|
|
_getDirectChildrenByTag: function(e, tagName) {
|
|
var kids = new Array();
|
|
var allKids = e.childNodes;
|
|
for( var i = 0 ; i < allKids.length ; i++ )
|
|
if ( allKids[i] && allKids[i].tagName && allKids[i].tagName == tagName )
|
|
kids.push(allKids[i]);
|
|
return kids;
|
|
}
|
|
|
|
};
|
|
|
|
Rico.Accordion.Tab = Class.create();
|
|
|
|
Rico.Accordion.Tab.prototype = {
|
|
|
|
initialize: function(accordion, titleBar, content) {
|
|
this.accordion = accordion;
|
|
this.titleBar = titleBar;
|
|
this.content = content;
|
|
this._attachBehaviors();
|
|
},
|
|
|
|
collapse: function() {
|
|
this.showCollapsed();
|
|
this.content.style.height = "1px";
|
|
},
|
|
|
|
showCollapsed: function() {
|
|
this.expanded = false;
|
|
this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
|
|
this.titleBar.style.color = this.accordion.options.collapsedTextColor;
|
|
this.titleBar.style.fontWeight = this.accordion.options.collapsedFontWeight;
|
|
this.content.style.overflow = "hidden";
|
|
},
|
|
|
|
showExpanded: function() {
|
|
this.expanded = true;
|
|
this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
|
|
this.titleBar.style.color = this.accordion.options.expandedTextColor;
|
|
this.content.style.overflow = "auto";
|
|
},
|
|
|
|
titleBarClicked: function(e) {
|
|
if ( this.accordion.lastExpandedTab == this )
|
|
return;
|
|
this.accordion.showTab(this);
|
|
},
|
|
|
|
hover: function(e) {
|
|
this.titleBar.style.backgroundColor = this.accordion.options.hoverBg;
|
|
this.titleBar.style.color = this.accordion.options.hoverTextColor;
|
|
this.titleBar.style.cursor = 'pointer';
|
|
},
|
|
|
|
unhover: function(e) {
|
|
if ( this.expanded ) {
|
|
this.titleBar.style.backgroundColor = this.accordion.options.expandedBg;
|
|
this.titleBar.style.color = this.accordion.options.expandedTextColor;
|
|
}
|
|
else {
|
|
this.titleBar.style.backgroundColor = this.accordion.options.collapsedBg;
|
|
this.titleBar.style.color = this.accordion.options.collapsedTextColor;
|
|
}
|
|
this.titleBar.style.cursor = '';
|
|
},
|
|
|
|
_attachBehaviors: function() {
|
|
this.content.style.border = "1px solid " + this.accordion.options.borderColor;
|
|
this.content.style.borderTopWidth = "0px";
|
|
this.content.style.borderBottomWidth = "0px";
|
|
this.content.style.margin = "0px";
|
|
|
|
this.titleBar.onclick = this.titleBarClicked.bindAsEventListener(this);
|
|
this.titleBar.onmouseover = this.hover.bindAsEventListener(this);
|
|
this.titleBar.onmouseout = this.unhover.bindAsEventListener(this);
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//-------------------- ricoAjaxEngine.js
|
|
Rico.AjaxEngine = Class.create();
|
|
|
|
Rico.AjaxEngine.prototype = {
|
|
|
|
initialize: function() {
|
|
this.ajaxElements = new Array();
|
|
this.ajaxObjects = new Array();
|
|
this.requestURLS = new Array();
|
|
this.options = {};
|
|
},
|
|
|
|
registerAjaxElement: function( anId, anElement ) {
|
|
if ( !anElement )
|
|
anElement = $(anId);
|
|
this.ajaxElements[anId] = anElement;
|
|
},
|
|
|
|
registerAjaxObject: function( anId, anObject ) {
|
|
this.ajaxObjects[anId] = anObject;
|
|
},
|
|
|
|
registerRequest: function (requestLogicalName, requestURL) {
|
|
this.requestURLS[requestLogicalName] = requestURL;
|
|
},
|
|
|
|
sendRequest: function(requestName, options) {
|
|
// Allow for backwards Compatibility
|
|
if ( arguments.length >= 2 )
|
|
if (typeof arguments[1] == 'string')
|
|
options = {parameters: this._createQueryString(arguments, 1)};
|
|
this.sendRequestWithData(requestName, null, options);
|
|
},
|
|
|
|
sendRequestWithData: function(requestName, xmlDocument, options) {
|
|
var requestURL = this.requestURLS[requestName];
|
|
if ( requestURL == null )
|
|
return;
|
|
|
|
// Allow for backwards Compatibility
|
|
if ( arguments.length >= 3 )
|
|
if (typeof arguments[2] == 'string')
|
|
options.parameters = this._createQueryString(arguments, 2);
|
|
|
|
new Ajax.Request(requestURL, this._requestOptions(options,xmlDocument));
|
|
},
|
|
|
|
sendRequestAndUpdate: function(requestName,container,options) {
|
|
// Allow for backwards Compatibility
|
|
if ( arguments.length >= 3 )
|
|
if (typeof arguments[2] == 'string')
|
|
options.parameters = this._createQueryString(arguments, 2);
|
|
|
|
this.sendRequestWithDataAndUpdate(requestName, null, container, options);
|
|
},
|
|
|
|
sendRequestWithDataAndUpdate: function(requestName,xmlDocument,container,options) {
|
|
var requestURL = this.requestURLS[requestName];
|
|
if ( requestURL == null )
|
|
return;
|
|
|
|
// Allow for backwards Compatibility
|
|
if ( arguments.length >= 4 )
|
|
if (typeof arguments[3] == 'string')
|
|
options.parameters = this._createQueryString(arguments, 3);
|
|
|
|
var updaterOptions = this._requestOptions(options,xmlDocument);
|
|
|
|
new Ajax.Updater(container, requestURL, updaterOptions);
|
|
},
|
|
|
|
// Private -- not part of intended engine API --------------------------------------------------------------------
|
|
|
|
_requestOptions: function(options,xmlDoc) {
|
|
var requestHeaders = ['X-Rico-Version', Rico.Version ];
|
|
var sendMethod = 'post';
|
|
if ( xmlDoc == null )
|
|
if (Rico.prototypeVersion < 1.4)
|
|
requestHeaders.push( 'Content-type', 'text/xml' );
|
|
else
|
|
sendMethod = 'get';
|
|
(!options) ? options = {} : '';
|
|
|
|
if (!options._RicoOptionsProcessed){
|
|
// Check and keep any user onComplete functions
|
|
if (options.onComplete)
|
|
options.onRicoComplete = options.onComplete;
|
|
// Fix onComplete
|
|
if (options.overrideOnComplete)
|
|
options.onComplete = options.overrideOnComplete;
|
|
else
|
|
options.onComplete = this._onRequestComplete.bind(this);
|
|
options._RicoOptionsProcessed = true;
|
|
}
|
|
|
|
// Set the default options and extend with any user options
|
|
this.options = {
|
|
requestHeaders: requestHeaders,
|
|
parameters: options.parameters,
|
|
postBody: xmlDoc,
|
|
method: sendMethod,
|
|
onComplete: options.onComplete
|
|
};
|
|
// Set any user options:
|
|
Object.extend(this.options, options);
|
|
return this.options;
|
|
},
|
|
|
|
_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) {
|
|
if(!request)
|
|
return;
|
|
// User can set an onFailure option - which will be called by prototype
|
|
if (request.status != 200)
|
|
return;
|
|
|
|
var response = request.responseXML.getElementsByTagName("ajax-response");
|
|
if (response == null || response.length != 1)
|
|
return;
|
|
this._processAjaxResponse( response[0].childNodes );
|
|
|
|
// Check if user has set a onComplete function
|
|
var onRicoComplete = this.options.onRicoComplete;
|
|
if (onRicoComplete != null)
|
|
onRicoComplete();
|
|
},
|
|
|
|
_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 ) {
|
|
ajaxElement.innerHTML = RicoUtil.getContentAsString(responseElement);
|
|
}
|
|
|
|
}
|
|
|
|
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.length==4) {
|
|
var shortHexCode = hexCode;
|
|
var hexCode = '#';
|
|
for(var i=1;i<4;i++) hexCode += (shortHexCode.charAt(i) +
|
|
shortHexCode.charAt(i));
|
|
}
|
|
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.parentNode )
|
|
return Rico.Color.createColorFromBackground(elem.parentNode);
|
|
|
|
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 ) {
|
|
return Rico.Color.createFromHex(actualColor);
|
|
}
|
|
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 saturation;
|
|
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 = "<div " + style + ">" + el.innerHTML + "</div>"
|
|
},
|
|
|
|
_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
|
|
}
|
|
Object.extend(this.options, 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";
|
|
}
|
|
if (this.options.border != false)
|
|
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<arguments.length ; i++) if (str.indexOf(arguments[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;
|
|
this._mouseDown = this._mouseDownHandler.bindAsEventListener(this);
|
|
this._mouseMove = this._mouseMoveHandler.bindAsEventListener(this);
|
|
this._mouseUp = this._mouseUpHandler.bindAsEventListener(this);
|
|
},
|
|
|
|
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;
|
|
|
|
var candidate = eventTarget;
|
|
while (draggableObject == null && candidate.parentNode) {
|
|
candidate = candidate.parentNode;
|
|
draggableObject = candidate.draggable;
|
|
}
|
|
|
|
if ( draggableObject == null )
|
|
return;
|
|
|
|
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;
|
|
},
|
|
**/
|
|
|
|
_leftOffset: function(e) {
|
|
return e.offsetX ? document.body.scrollLeft : 0
|
|
},
|
|
|
|
_topOffset: function(e) {
|
|
return e.offsetY ? document.body.scrollTop:0
|
|
},
|
|
|
|
|
|
_updateDraggableLocation: function(e) {
|
|
var dragObjectStyle = this.dragElement.style;
|
|
dragObjectStyle.left = (e.screenX + this._leftOffset(e) - this.startx) + "px"
|
|
dragObjectStyle.top = (e.screenY + this._topOffset(e) - 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 Rico.Effect.Position( this.dragElement,
|
|
this.origPos.x,
|
|
this.origPos.y,
|
|
200,
|
|
20,
|
|
{ complete : this._doCancelDragProcessing.bind(this) } );
|
|
}
|
|
|
|
Event.stopObserving(document.body, "mousemove", this._mouseMove);
|
|
Event.stopObserving(document.body, "mouseup", this._mouseUp);
|
|
},
|
|
|
|
_retTrue: function () {
|
|
return true;
|
|
},
|
|
|
|
_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() && this.dragElement)
|
|
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 + this._leftOffset(e) &&
|
|
e.clientX < absoluteRect.right + this._leftOffset(e) &&
|
|
e.clientY > absoluteRect.top + this._topOffset(e) &&
|
|
e.clientY < absoluteRect.bottom + this._topOffset(e);
|
|
},
|
|
|
|
_addMouseDownHandler: function( aDraggable )
|
|
{
|
|
htmlElement = aDraggable.getMouseDownHTMLElement();
|
|
if ( htmlElement != null ) {
|
|
htmlElement.draggable = aDraggable;
|
|
Event.observe(htmlElement , "mousedown", this._onmousedown.bindAsEventListener(this));
|
|
Event.observe(htmlElement, "mousedown", this._mouseDown);
|
|
}
|
|
},
|
|
|
|
_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;
|
|
},
|
|
|
|
_onmousedown: function () {
|
|
Event.observe(document.body, "mousemove", this._mouseMove);
|
|
Event.observe(document.body, "mouseup", this._mouseUp);
|
|
},
|
|
|
|
_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
|
|
|
|
Rico.Effect = {};
|
|
|
|
Rico.Effect.SizeAndPosition = Class.create();
|
|
Rico.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";
|
|
}
|
|
}
|
|
|
|
Rico.Effect.Size = Class.create();
|
|
Rico.Effect.Size.prototype = {
|
|
|
|
initialize: function(element, w, h, duration, steps, options) {
|
|
new Rico.Effect.SizeAndPosition(element, null, null, w, h, duration, steps, options);
|
|
}
|
|
}
|
|
|
|
Rico.Effect.Position = Class.create();
|
|
Rico.Effect.Position.prototype = {
|
|
|
|
initialize: function(element, x, y, duration, steps, options) {
|
|
new Rico.Effect.SizeAndPosition(element, x, y, null, null, duration, steps, options);
|
|
}
|
|
}
|
|
|
|
Rico.Effect.Round = Class.create();
|
|
Rico.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 );
|
|
}
|
|
};
|
|
|
|
Rico.Effect.FadeTo = Class.create();
|
|
Rico.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 = RicoUtil.getElementsComputedStyle(this.element, 'opacity');
|
|
this.element.ricoOpacity = opacity != undefined ? opacity : 1.0;
|
|
}
|
|
return parseFloat(this.element.ricoOpacity);
|
|
}
|
|
}
|
|
|
|
Rico.Effect.AccordionSize = Class.create();
|
|
|
|
Rico.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, columnCount, options ) {
|
|
this.pageSize = pageSize;
|
|
this.totalRows = totalRows;
|
|
this.setOptions(options);
|
|
this.ArrowHeight = 16;
|
|
this.columnCount = columnCount;
|
|
},
|
|
|
|
setOptions: function(options) {
|
|
this.options = {
|
|
largeBufferSize : 7.0, // 7 pages
|
|
nearLimitFactor : 0.2 // 20% of buffer
|
|
};
|
|
Object.extend(this.options, 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);
|
|
},
|
|
|
|
getLimitTolerance: function() {
|
|
return parseInt(this.getLargeBufferSize() * this.options.nearLimitFactor);
|
|
}
|
|
};
|
|
|
|
// Rico.LiveGridScroller -----------------------------------------------------
|
|
|
|
Rico.LiveGridScroller = Class.create();
|
|
|
|
Rico.LiveGridScroller.prototype = {
|
|
|
|
initialize: function(liveGrid, viewPort) {
|
|
this.isIE = navigator.userAgent.toLowerCase().indexOf("msie") >= 0;
|
|
this.liveGrid = liveGrid;
|
|
this.metaData = liveGrid.metaData;
|
|
this.createScrollBar();
|
|
this.scrollTimeout = null;
|
|
this.lastScrollPos = 0;
|
|
this.viewPort = viewPort;
|
|
this.rows = new Array();
|
|
},
|
|
|
|
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 visibleHeight = this.liveGrid.viewPort.visibleHeight();
|
|
// create the outer div...
|
|
this.scrollerDiv = document.createElement("div");
|
|
var scrollerStyle = this.scrollerDiv.style;
|
|
scrollerStyle.borderRight = this.liveGrid.options.scrollerBorderRight;
|
|
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.scrollerDiv.appendChild(this.heightDiv);
|
|
this.scrollerDiv.onscroll = this.handleScroll.bindAsEventListener(this);
|
|
|
|
var table = this.liveGrid.table;
|
|
table.parentNode.parentNode.insertBefore( this.scrollerDiv, table.parentNode.nextSibling );
|
|
var eventName = this.isIE ? "mousewheel" : "DOMMouseScroll";
|
|
Event.observe(table, eventName,
|
|
function(evt) {
|
|
if (evt.wheelDelta>=0 || evt.detail < 0) //wheel-up
|
|
this.scrollerDiv.scrollTop -= (2*this.viewPort.rowHeight);
|
|
else
|
|
this.scrollerDiv.scrollTop += (2*this.viewPort.rowHeight);
|
|
this.handleScroll(false);
|
|
}.bindAsEventListener(this),
|
|
false);
|
|
},
|
|
|
|
updateSize: function() {
|
|
var table = this.liveGrid.table;
|
|
var visibleHeight = this.viewPort.visibleHeight();
|
|
this.heightDiv.style.height = parseInt(visibleHeight *
|
|
this.metaData.getTotalRows()/this.metaData.getPageSize()) + "px";
|
|
},
|
|
|
|
rowToPixel: function(rowOffset) {
|
|
return (rowOffset / this.metaData.getTotalRows()) * this.heightDiv.offsetHeight
|
|
},
|
|
|
|
moveScroll: function(rowOffset) {
|
|
this.scrollerDiv.scrollTop = this.rowToPixel(rowOffset);
|
|
if ( this.metaData.options.onscroll )
|
|
this.metaData.options.onscroll( this.liveGrid, rowOffset );
|
|
},
|
|
|
|
handleScroll: function() {
|
|
if ( this.scrollTimeout )
|
|
clearTimeout( this.scrollTimeout );
|
|
|
|
var scrollDiff = this.lastScrollPos-this.scrollerDiv.scrollTop;
|
|
if (scrollDiff != 0.00) {
|
|
var r = this.scrollerDiv.scrollTop % this.viewPort.rowHeight;
|
|
if (r != 0) {
|
|
this.unplug();
|
|
if ( scrollDiff < 0 ) {
|
|
this.scrollerDiv.scrollTop += (this.viewPort.rowHeight-r);
|
|
} else {
|
|
this.scrollerDiv.scrollTop -= r;
|
|
}
|
|
this.plugin();
|
|
}
|
|
}
|
|
var contentOffset = parseInt(this.scrollerDiv.scrollTop / this.viewPort.rowHeight);
|
|
this.liveGrid.requestContentRefresh(contentOffset);
|
|
this.viewPort.scrollTo(this.scrollerDiv.scrollTop);
|
|
|
|
if ( this.metaData.options.onscroll )
|
|
this.metaData.options.onscroll( this.liveGrid, contentOffset );
|
|
|
|
this.scrollTimeout = setTimeout(this.scrollIdle.bind(this), 1200 );
|
|
this.lastScrollPos = this.scrollerDiv.scrollTop;
|
|
|
|
},
|
|
|
|
scrollIdle: function() {
|
|
if ( this.metaData.options.onscrollidle )
|
|
this.metaData.options.onscrollidle();
|
|
}
|
|
};
|
|
|
|
// Rico.LiveGridBuffer -----------------------------------------------------
|
|
|
|
Rico.LiveGridBuffer = Class.create();
|
|
|
|
Rico.LiveGridBuffer.prototype = {
|
|
|
|
initialize: function(metaData, viewPort) {
|
|
this.startPos = 0;
|
|
this.size = 0;
|
|
this.metaData = metaData;
|
|
this.rows = new Array();
|
|
this.updateInProgress = false;
|
|
this.viewPort = viewPort;
|
|
this.maxBufferSize = metaData.getLargeBufferSize() * 2;
|
|
this.maxFetchSize = metaData.getLargeBufferSize();
|
|
this.lastOffset = 0;
|
|
},
|
|
|
|
getBlankRow: function() {
|
|
if (!this.blankRow ) {
|
|
this.blankRow = new Array();
|
|
for ( var i=0; i < this.metaData.columnCount ; i++ )
|
|
this.blankRow[i] = " ";
|
|
}
|
|
return this.blankRow;
|
|
},
|
|
|
|
loadRows: function(ajaxResponse) {
|
|
var rowsElement = ajaxResponse.getElementsByTagName('rows')[0];
|
|
this.updateUI = rowsElement.getAttribute("update_ui") == "true"
|
|
var newRows = new Array()
|
|
var trs = rowsElement.getElementsByTagName("tr");
|
|
for ( var i=0 ; i < trs.length; i++ ) {
|
|
var row = newRows[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 = RicoUtil.getContentAsString(cell);
|
|
row[j] = convertSpaces ? this.convertSpaces(cellContent) : cellContent;
|
|
if (!row[j])
|
|
row[j] = ' ';
|
|
}
|
|
}
|
|
return newRows;
|
|
},
|
|
|
|
update: function(ajaxResponse, start) {
|
|
var newRows = this.loadRows(ajaxResponse);
|
|
if (this.rows.length == 0) { // initial load
|
|
this.rows = newRows;
|
|
this.size = this.rows.length;
|
|
this.startPos = start;
|
|
return;
|
|
}
|
|
if (start > this.startPos) { //appending
|
|
if (this.startPos + this.rows.length < start) {
|
|
this.rows = newRows;
|
|
this.startPos = start;//
|
|
} else {
|
|
this.rows = this.rows.concat( newRows.slice(0, newRows.length));
|
|
if (this.rows.length > this.maxBufferSize) {
|
|
var fullSize = this.rows.length;
|
|
this.rows = this.rows.slice(this.rows.length - this.maxBufferSize, this.rows.length)
|
|
this.startPos = this.startPos + (fullSize - this.rows.length);
|
|
}
|
|
}
|
|
} else { //prepending
|
|
if (start + newRows.length < this.startPos) {
|
|
this.rows = newRows;
|
|
} else {
|
|
this.rows = newRows.slice(0, this.startPos).concat(this.rows);
|
|
if (this.rows.length > this.maxBufferSize)
|
|
this.rows = this.rows.slice(0, this.maxBufferSize)
|
|
}
|
|
this.startPos = start;
|
|
}
|
|
this.size = this.rows.length;
|
|
},
|
|
|
|
clear: function() {
|
|
this.rows = new Array();
|
|
this.startPos = 0;
|
|
this.size = 0;
|
|
},
|
|
|
|
isOverlapping: function(start, size) {
|
|
return ((start < this.endPos()) && (this.startPos < start + size)) || (this.endPos() == 0)
|
|
},
|
|
|
|
isInRange: function(position) {
|
|
return (position >= this.startPos) && (position + this.metaData.getPageSize() <= this.endPos());
|
|
//&& this.size() != 0;
|
|
},
|
|
|
|
isNearingTopLimit: function(position) {
|
|
return position - this.startPos < this.metaData.getLimitTolerance();
|
|
},
|
|
|
|
endPos: function() {
|
|
return this.startPos + this.rows.length;
|
|
},
|
|
|
|
isNearingBottomLimit: function(position) {
|
|
return this.endPos() - (position + this.metaData.getPageSize()) < this.metaData.getLimitTolerance();
|
|
},
|
|
|
|
isAtTop: function() {
|
|
return this.startPos == 0;
|
|
},
|
|
|
|
isAtBottom: function() {
|
|
return this.endPos() == this.metaData.getTotalRows();
|
|
},
|
|
|
|
isNearingLimit: function(position) {
|
|
return ( !this.isAtTop() && this.isNearingTopLimit(position)) ||
|
|
( !this.isAtBottom() && this.isNearingBottomLimit(position) )
|
|
},
|
|
|
|
getFetchSize: function(offset) {
|
|
var adjustedOffset = this.getFetchOffset(offset);
|
|
var adjustedSize = 0;
|
|
if (adjustedOffset >= this.startPos) { //apending
|
|
var endFetchOffset = this.maxFetchSize + adjustedOffset;
|
|
if (endFetchOffset > this.metaData.totalRows)
|
|
endFetchOffset = this.metaData.totalRows;
|
|
adjustedSize = endFetchOffset - adjustedOffset;
|
|
if(adjustedOffset == 0 && adjustedSize < this.maxFetchSize){
|
|
adjustedSize = this.maxFetchSize;
|
|
}
|
|
} else {//prepending
|
|
var adjustedSize = this.startPos - adjustedOffset;
|
|
if (adjustedSize > this.maxFetchSize)
|
|
adjustedSize = this.maxFetchSize;
|
|
}
|
|
return adjustedSize;
|
|
},
|
|
|
|
getFetchOffset: function(offset) {
|
|
var adjustedOffset = offset;
|
|
if (offset > this.startPos) //apending
|
|
adjustedOffset = (offset > this.endPos()) ? offset : this.endPos();
|
|
else { //prepending
|
|
if (offset + this.maxFetchSize >= this.startPos) {
|
|
var adjustedOffset = this.startPos - this.maxFetchSize;
|
|
if (adjustedOffset < 0)
|
|
adjustedOffset = 0;
|
|
}
|
|
}
|
|
this.lastOffset = adjustedOffset;
|
|
return adjustedOffset;
|
|
},
|
|
|
|
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.GridViewPort --------------------------------------------------
|
|
Rico.GridViewPort = Class.create();
|
|
|
|
Rico.GridViewPort.prototype = {
|
|
|
|
initialize: function(table, rowHeight, visibleRows, buffer, liveGrid) {
|
|
this.lastDisplayedStartPos = 0;
|
|
this.div = table.parentNode;
|
|
this.table = table
|
|
this.rowHeight = rowHeight;
|
|
this.div.style.height = (this.rowHeight * visibleRows) + "px";
|
|
this.div.style.overflow = "hidden";
|
|
this.buffer = buffer;
|
|
this.liveGrid = liveGrid;
|
|
this.visibleRows = visibleRows + 1;
|
|
this.lastPixelOffset = 0;
|
|
this.startPos = 0;
|
|
},
|
|
|
|
populateRow: function(htmlRow, row) {
|
|
for (var j=0; j < row.length; j++) {
|
|
htmlRow.cells[j].innerHTML = row[j]
|
|
}
|
|
},
|
|
|
|
bufferChanged: function() {
|
|
this.refreshContents( parseInt(this.lastPixelOffset / this.rowHeight));
|
|
},
|
|
|
|
clearRows: function() {
|
|
if (!this.isBlank) {
|
|
this.liveGrid.table.className = this.liveGrid.options.loadingClass;
|
|
for (var i=0; i < this.visibleRows; i++)
|
|
this.populateRow(this.table.rows[i], this.buffer.getBlankRow());
|
|
this.isBlank = true;
|
|
}
|
|
},
|
|
|
|
clearContents: function() {
|
|
this.clearRows();
|
|
this.scrollTo(0);
|
|
this.startPos = 0;
|
|
this.lastStartPos = -1;
|
|
},
|
|
|
|
refreshContents: function(startPos) {
|
|
if (startPos == this.lastRowPos && !this.isPartialBlank && !this.isBlank) {
|
|
return;
|
|
}
|
|
if ((startPos + this.visibleRows < this.buffer.startPos)
|
|
|| (this.buffer.startPos + this.buffer.size < startPos)
|
|
|| (this.buffer.size == 0)) {
|
|
this.clearRows();
|
|
return;
|
|
}
|
|
this.isBlank = false;
|
|
var viewPrecedesBuffer = this.buffer.startPos > startPos
|
|
var contentStartPos = viewPrecedesBuffer ? this.buffer.startPos: startPos;
|
|
var contentEndPos = (this.buffer.startPos + this.buffer.size < startPos + this.visibleRows)
|
|
? this.buffer.startPos + this.buffer.size
|
|
: startPos + this.visibleRows;
|
|
var rowSize = contentEndPos - contentStartPos;
|
|
var rows = this.buffer.getRows(contentStartPos, rowSize );
|
|
var blankSize = this.visibleRows - rowSize;
|
|
var blankOffset = viewPrecedesBuffer ? 0: rowSize;
|
|
var contentOffset = viewPrecedesBuffer ? blankSize: 0;
|
|
|
|
for (var i=0; i < rows.length; i++) {//initialize what we have
|
|
this.populateRow(this.table.rows[i + contentOffset], rows[i]);
|
|
}
|
|
for (var i=0; i < blankSize; i++) {// blank out the rest
|
|
this.populateRow(this.table.rows[i + blankOffset], this.buffer.getBlankRow());
|
|
}
|
|
this.isPartialBlank = blankSize > 0;
|
|
this.lastRowPos = startPos;
|
|
|
|
this.liveGrid.table.className = this.liveGrid.options.tableClass;
|
|
// Check if user has set a onRefreshComplete function
|
|
var onRefreshComplete = this.liveGrid.options.onRefreshComplete;
|
|
if (onRefreshComplete != null)
|
|
onRefreshComplete();
|
|
},
|
|
|
|
scrollTo: function(pixelOffset) {
|
|
if (this.lastPixelOffset == pixelOffset)
|
|
return;
|
|
|
|
this.refreshContents(parseInt(pixelOffset / this.rowHeight))
|
|
this.div.scrollTop = pixelOffset % this.rowHeight
|
|
|
|
this.lastPixelOffset = pixelOffset;
|
|
},
|
|
|
|
visibleHeight: function() {
|
|
return parseInt(RicoUtil.getElementsComputedStyle(this.div, 'height'));
|
|
}
|
|
|
|
};
|
|
|
|
|
|
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, ajaxOptions ) {
|
|
|
|
this.options = {
|
|
tableClass: $(tableId).className,
|
|
loadingClass: $(tableId).className,
|
|
scrollerBorderRight: '1px solid #ababab',
|
|
bufferTimeout: 20000,
|
|
sortAscendImg: 'images/sort_asc.gif',
|
|
sortDescendImg: 'images/sort_desc.gif',
|
|
sortImageWidth: 9,
|
|
sortImageHeight: 5,
|
|
ajaxSortURLParms: [],
|
|
onRefreshComplete: null,
|
|
requestParameters: null,
|
|
inlineStyles: true
|
|
};
|
|
Object.extend(this.options, options || {});
|
|
|
|
this.ajaxOptions = {parameters: null};
|
|
Object.extend(this.ajaxOptions, ajaxOptions || {});
|
|
|
|
this.tableId = tableId;
|
|
this.table = $(tableId);
|
|
|
|
this.addLiveGridHtml();
|
|
|
|
var columnCount = this.table.rows[0].cells.length;
|
|
this.metaData = new Rico.LiveGridMetaData(visibleRows, totalRows, columnCount, options);
|
|
this.buffer = new Rico.LiveGridBuffer(this.metaData);
|
|
|
|
var rowCount = this.table.rows.length;
|
|
this.viewPort = new Rico.GridViewPort(this.table,
|
|
this.table.offsetHeight/rowCount,
|
|
visibleRows,
|
|
this.buffer, this);
|
|
this.scroller = new Rico.LiveGridScroller(this,this.viewPort);
|
|
this.options.sortHandler = this.sortHandler.bind(this);
|
|
|
|
if ( $(tableId + '_header') )
|
|
this.sort = new Rico.LiveGridSort(tableId + '_header', this.options)
|
|
|
|
this.processingRequest = null;
|
|
this.unprocessedRequest = null;
|
|
|
|
this.initAjax(url);
|
|
if ( this.options.prefetchBuffer || this.options.prefetchOffset > 0) {
|
|
var offset = 0;
|
|
if (this.options.offset ) {
|
|
offset = this.options.offset;
|
|
this.scroller.moveScroll(offset);
|
|
this.viewPort.scrollTo(this.scroller.rowToPixel(offset));
|
|
}
|
|
if (this.options.sortCol) {
|
|
this.sortCol = options.sortCol;
|
|
this.sortDir = options.sortDir;
|
|
}
|
|
this.requestContentRefresh(offset);
|
|
}
|
|
},
|
|
|
|
addLiveGridHtml: function() {
|
|
// Check to see if need to create a header table.
|
|
if (this.table.getElementsByTagName("thead").length > 0){
|
|
// Create Table this.tableId+'_header'
|
|
var tableHeader = this.table.cloneNode(true);
|
|
tableHeader.setAttribute('id', this.tableId+'_header');
|
|
tableHeader.setAttribute('class', this.table.className+'_header');
|
|
|
|
// Clean up and insert
|
|
for( var i = 0; i < tableHeader.tBodies.length; i++ )
|
|
tableHeader.removeChild(tableHeader.tBodies[i]);
|
|
this.table.deleteTHead();
|
|
this.table.parentNode.insertBefore(tableHeader,this.table);
|
|
}
|
|
|
|
new Insertion.Before(this.table, "<div id='"+this.tableId+"_container'></div>");
|
|
this.table.previousSibling.appendChild(this.table);
|
|
new Insertion.Before(this.table,"<div id='"+this.tableId+"_viewport' style='float:left;'></div>");
|
|
this.table.previousSibling.appendChild(this.table);
|
|
},
|
|
|
|
|
|
resetContents: function() {
|
|
this.scroller.moveScroll(0);
|
|
this.buffer.clear();
|
|
this.viewPort.clearContents();
|
|
},
|
|
|
|
sortHandler: function(column) {
|
|
if(!column) return ;
|
|
this.sortCol = column.name;
|
|
this.sortDir = column.currentSort;
|
|
|
|
this.resetContents();
|
|
this.requestContentRefresh(0)
|
|
},
|
|
|
|
adjustRowSize: function() {
|
|
|
|
},
|
|
|
|
setTotalRows: function( newTotalRows ) {
|
|
this.resetContents();
|
|
this.metaData.setTotalRows(newTotalRows);
|
|
this.scroller.updateSize();
|
|
},
|
|
|
|
initAjax: function(url) {
|
|
ajaxEngine.registerRequest( this.tableId + '_request', url );
|
|
ajaxEngine.registerAjaxObject( this.tableId + '_updater', this );
|
|
},
|
|
|
|
invokeAjax: function() {
|
|
},
|
|
|
|
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;
|
|
this.processQueuedRequest();
|
|
},
|
|
|
|
fetchBuffer: function(offset) {
|
|
if ( this.buffer.isInRange(offset) &&
|
|
!this.buffer.isNearingLimit(offset)) {
|
|
return;
|
|
}
|
|
if (this.processingRequest) {
|
|
this.unprocessedRequest = new Rico.LiveGridRequest(offset);
|
|
return;
|
|
}
|
|
var bufferStartPos = this.buffer.getFetchOffset(offset);
|
|
this.processingRequest = new Rico.LiveGridRequest(offset);
|
|
this.processingRequest.bufferOffset = bufferStartPos;
|
|
var fetchSize = this.buffer.getFetchSize(offset);
|
|
var partialLoaded = false;
|
|
|
|
var queryString
|
|
if (this.options.requestParameters)
|
|
queryString = this._createQueryString(this.options.requestParameters, 0);
|
|
|
|
queryString = (queryString == null) ? '' : queryString+'&';
|
|
queryString = queryString+'id='+this.tableId+'&page_size='+fetchSize+'&offset='+bufferStartPos;
|
|
if (this.sortCol)
|
|
queryString = queryString+'&sort_col='+escape(this.sortCol)+'&sort_dir='+this.sortDir;
|
|
|
|
this.ajaxOptions.parameters = queryString;
|
|
|
|
ajaxEngine.sendRequest( this.tableId + '_request', this.ajaxOptions );
|
|
|
|
this.timeoutHandler = setTimeout( this.handleTimedOut.bind(this), this.options.bufferTimeout);
|
|
|
|
},
|
|
|
|
setRequestParams: function() {
|
|
this.options.requestParameters = [];
|
|
for ( var i=0 ; i < arguments.length ; i++ )
|
|
this.options.requestParameters[i] = arguments[i];
|
|
},
|
|
|
|
requestContentRefresh: function(contentOffset) {
|
|
this.fetchBuffer(contentOffset);
|
|
},
|
|
|
|
ajaxUpdate: function(ajaxResponse) {
|
|
try {
|
|
clearTimeout( this.timeoutHandler );
|
|
this.buffer.update(ajaxResponse,this.processingRequest.bufferOffset);
|
|
this.viewPort.bufferChanged();
|
|
}
|
|
catch(err) {}
|
|
finally {this.processingRequest = null; }
|
|
this.processQueuedRequest();
|
|
},
|
|
|
|
_createQueryString: function( theArgs, offset ) {
|
|
var queryString = ""
|
|
if (!theArgs)
|
|
return 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;
|
|
},
|
|
|
|
processQueuedRequest: function() {
|
|
if (this.unprocessedRequest != null) {
|
|
this.requestContentRefresh(this.unprocessedRequest.requestOffset);
|
|
this.unprocessedRequest = null
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
//-------------------- ricoLiveGridSort.js
|
|
Rico.LiveGridSort = Class.create();
|
|
|
|
Rico.LiveGridSort.prototype = {
|
|
|
|
initialize: function(headerTableId, options) {
|
|
this.headerTableId = headerTableId;
|
|
this.headerTable = $(headerTableId);
|
|
this.options = options;
|
|
this.setOptions();
|
|
this.applySortBehavior();
|
|
|
|
if ( this.options.sortCol ) {
|
|
this.setSortUI( this.options.sortCol, this.options.sortDir );
|
|
}
|
|
},
|
|
|
|
setSortUI: function( columnName, sortDirection ) {
|
|
var cols = this.options.columns;
|
|
for ( var i = 0 ; i < cols.length ; i++ ) {
|
|
if ( cols[i].name == columnName ) {
|
|
this.setColumnSort(i, sortDirection);
|
|
break;
|
|
}
|
|
}
|
|
},
|
|
|
|
setOptions: function() {
|
|
// preload the images...
|
|
new Image().src = this.options.sortAscendImg;
|
|
new Image().src = this.options.sortDescendImg;
|
|
|
|
this.sort = this.options.sortHandler;
|
|
if ( !this.options.columns )
|
|
this.options.columns = this.introspectForColumnInfo();
|
|
else {
|
|
// allow client to pass { columns: [ ["a", true], ["b", false] ] }
|
|
// and convert to an array of Rico.TableColumn objs...
|
|
this.options.columns = this.convertToTableColumns(this.options.columns);
|
|
}
|
|
},
|
|
|
|
applySortBehavior: function() {
|
|
var headerRow = this.headerTable.rows[0];
|
|
var headerCells = headerRow.cells;
|
|
for ( var i = 0 ; i < headerCells.length ; i++ ) {
|
|
this.addSortBehaviorToColumn( i, headerCells[i] );
|
|
}
|
|
},
|
|
|
|
addSortBehaviorToColumn: function( n, cell ) {
|
|
if ( this.options.columns[n].isSortable() ) {
|
|
cell.id = this.headerTableId + '_' + n;
|
|
cell.style.cursor = 'pointer';
|
|
cell.onclick = this.headerCellClicked.bindAsEventListener(this);
|
|
cell.innerHTML = cell.innerHTML + '<span id="' + this.headerTableId + '_img_' + n + '">'
|
|
+ ' </span>';
|
|
}
|
|
},
|
|
|
|
// event handler....
|
|
headerCellClicked: function(evt) {
|
|
var eventTarget = evt.target ? evt.target : evt.srcElement;
|
|
var cellId = eventTarget.id;
|
|
var columnNumber = parseInt(cellId.substring( cellId.lastIndexOf('_') + 1 ));
|
|
var sortedColumnIndex = this.getSortedColumnIndex();
|
|
if ( sortedColumnIndex != -1 ) {
|
|
if ( sortedColumnIndex != columnNumber ) {
|
|
this.removeColumnSort(sortedColumnIndex);
|
|
this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
|
|
}
|
|
else
|
|
this.toggleColumnSort(sortedColumnIndex);
|
|
}
|
|
else
|
|
this.setColumnSort(columnNumber, Rico.TableColumn.SORT_ASC);
|
|
|
|
if (this.options.sortHandler) {
|
|
this.options.sortHandler(this.options.columns[columnNumber]);
|
|
}
|
|
},
|
|
|
|
removeColumnSort: function(n) {
|
|
this.options.columns[n].setUnsorted();
|
|
this.setSortImage(n);
|
|
},
|
|
|
|
setColumnSort: function(n, direction) {
|
|
if(isNaN(n)) return ;
|
|
this.options.columns[n].setSorted(direction);
|
|
this.setSortImage(n);
|
|
},
|
|
|
|
toggleColumnSort: function(n) {
|
|
this.options.columns[n].toggleSort();
|
|
this.setSortImage(n);
|
|
},
|
|
|
|
setSortImage: function(n) {
|
|
var sortDirection = this.options.columns[n].getSortDirection();
|
|
|
|
var sortImageSpan = $( this.headerTableId + '_img_' + n );
|
|
if ( sortDirection == Rico.TableColumn.UNSORTED )
|
|
sortImageSpan.innerHTML = ' ';
|
|
else if ( sortDirection == Rico.TableColumn.SORT_ASC )
|
|
sortImageSpan.innerHTML = ' <img width="' + this.options.sortImageWidth + '" ' +
|
|
'height="'+ this.options.sortImageHeight + '" ' +
|
|
'src="' + this.options.sortAscendImg + '"/>';
|
|
else if ( sortDirection == Rico.TableColumn.SORT_DESC )
|
|
sortImageSpan.innerHTML = ' <img width="' + this.options.sortImageWidth + '" ' +
|
|
'height="'+ this.options.sortImageHeight + '" ' +
|
|
'src="' + this.options.sortDescendImg + '"/>';
|
|
},
|
|
|
|
getSortedColumnIndex: function() {
|
|
var cols = this.options.columns;
|
|
for ( var i = 0 ; i < cols.length ; i++ ) {
|
|
if ( cols[i].isSorted() )
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
},
|
|
|
|
introspectForColumnInfo: function() {
|
|
var columns = new Array();
|
|
var headerRow = this.headerTable.rows[0];
|
|
var headerCells = headerRow.cells;
|
|
for ( var i = 0 ; i < headerCells.length ; i++ )
|
|
columns.push( new Rico.TableColumn( this.deriveColumnNameFromCell(headerCells[i],i), true ) );
|
|
return columns;
|
|
},
|
|
|
|
convertToTableColumns: function(cols) {
|
|
var columns = new Array();
|
|
for ( var i = 0 ; i < cols.length ; i++ )
|
|
columns.push( new Rico.TableColumn( cols[i][0], cols[i][1] ) );
|
|
return columns;
|
|
},
|
|
|
|
deriveColumnNameFromCell: function(cell,columnNumber) {
|
|
var cellContent = cell.innerText != undefined ? cell.innerText : cell.textContent;
|
|
return cellContent ? cellContent.toLowerCase().split(' ').join('_') : "col_" + columnNumber;
|
|
}
|
|
};
|
|
|
|
Rico.TableColumn = Class.create();
|
|
|
|
Rico.TableColumn.UNSORTED = 0;
|
|
Rico.TableColumn.SORT_ASC = "ASC";
|
|
Rico.TableColumn.SORT_DESC = "DESC";
|
|
|
|
Rico.TableColumn.prototype = {
|
|
initialize: function(name, sortable) {
|
|
this.name = name;
|
|
this.sortable = sortable;
|
|
this.currentSort = Rico.TableColumn.UNSORTED;
|
|
},
|
|
|
|
isSortable: function() {
|
|
return this.sortable;
|
|
},
|
|
|
|
isSorted: function() {
|
|
return this.currentSort != Rico.TableColumn.UNSORTED;
|
|
},
|
|
|
|
getSortDirection: function() {
|
|
return this.currentSort;
|
|
},
|
|
|
|
toggleSort: function() {
|
|
if ( this.currentSort == Rico.TableColumn.UNSORTED || this.currentSort == Rico.TableColumn.SORT_DESC )
|
|
this.currentSort = Rico.TableColumn.SORT_ASC;
|
|
else if ( this.currentSort == Rico.TableColumn.SORT_ASC )
|
|
this.currentSort = Rico.TableColumn.SORT_DESC;
|
|
},
|
|
|
|
setUnsorted: function(direction) {
|
|
this.setSorted(Rico.TableColumn.UNSORTED);
|
|
},
|
|
|
|
setSorted: function(direction) {
|
|
// direction must by one of Rico.TableColumn.UNSORTED, .SORT_ASC, or .SORT_DESC...
|
|
this.currentSort = direction;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//-------------------- 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;
|
|
},
|
|
|
|
getContentAsString: function( parentNode ) {
|
|
return parentNode.xml != undefined ?
|
|
this._getContentAsStringIE(parentNode) :
|
|
this._getContentAsStringMozilla(parentNode);
|
|
},
|
|
|
|
_getContentAsStringIE: function(parentNode) {
|
|
var contentStr = "";
|
|
for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
|
|
var n = parentNode.childNodes[i];
|
|
if (n.nodeType == 4) {
|
|
contentStr += n.nodeValue;
|
|
}
|
|
else {
|
|
contentStr += n.xml;
|
|
}
|
|
}
|
|
return contentStr;
|
|
},
|
|
|
|
_getContentAsStringMozilla: function(parentNode) {
|
|
var xmlSerializer = new XMLSerializer();
|
|
var contentStr = "";
|
|
for ( var i = 0 ; i < parentNode.childNodes.length ; i++ ) {
|
|
var n = parentNode.childNodes[i];
|
|
if (n.nodeType == 4) { // CDATA node
|
|
contentStr += n.nodeValue;
|
|
}
|
|
else {
|
|
contentStr += xmlSerializer.serializeToString(n);
|
|
}
|
|
}
|
|
return contentStr;
|
|
},
|
|
|
|
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;
|
|
}
|
|
|
|
};
|