From d703f22eecb6c782b4fcf98c7bb8c60ebee24606 Mon Sep 17 00:00:00 2001 From: Stephan Reichholf Date: Mon, 17 May 2010 20:54:26 +0000 Subject: [PATCH] Split up into "Providers" and "Handlers"... Providers provide the data handlers handle it on the GUI side. Update to prototype 1.7_RC2 No "functional News" though. --- webinterface/src/web-data/handler.js | 519 +-- .../{prototype_1.7-rc1.js => prototype.js} | 2805 +++++++++-------- webinterface/src/web-data/provider.js | 412 +++ .../src/web-data/tpl/default/index.html | 8 +- 4 files changed, 1940 insertions(+), 1804 deletions(-) rename webinterface/src/web-data/lib/{prototype_1.7-rc1.js => prototype.js} (98%) create mode 100644 webinterface/src/web-data/provider.js diff --git a/webinterface/src/web-data/handler.js b/webinterface/src/web-data/handler.js index 4b1e19d78a..3f571fcd87 100644 --- a/webinterface/src/web-data/handler.js +++ b/webinterface/src/web-data/handler.js @@ -1,34 +1,19 @@ -/** - * AbstractContentHandler - * - * Abstract Class for "AbstractContentHandler" Classes - * A Content handler is a class that provides content for the webpage - * e.g. a list of channels, or a list of recordings and/or is able of - * doing the handling of all events for that content (e.g. deleting a recording) - */ - var AbstractContentHandler = Class.create({ - /** - * initialize - * Default constructor - * Parameters: - * @tpl - Name of the template to use - * @url - name of the url to use for requests - * @target - target html id for the content - * @onFinished - an array of functions that should be called after "this.show()" has finished - */ - initialize: function(tpl, url, target, onFinished){ + initialize: function(tpl, target, onFinished){ this.tpl = tpl; - this.url = url; this.target = target; - this.request = ''; this.onFinished = onFinished; - this.ajaxload = false; - this.parms = {}; - this.refresh = false; this.eventsRegistered = false; + this.provider = null; + this.ajaxload = false; }, + load: function(parms, fnc){ + this.requestStarted(); + this.provider.load(parms, fnc); + }, + + /** * requestStarted * if this.ajaxload is true setAjaxLoad(this.target) will be called @@ -49,166 +34,6 @@ var AbstractContentHandler = Class.create({ //TODO insert renderTpl, processTpl & Co. here or somewhere else... (maybe a separate class?) - /** - * getXML - * Converts the incoming transport result into a DOM object - * Parameters: - * @transport - the xmlhttp transport object - * - **/ - getXML: function(transport){ - var xmlDoc = ""; - - if(window.ActiveXObject){ // we're on IE - xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); - xmlDoc.async="false"; - xmlDoc.loadXML(transport.responseText); - } else { //we're not on IE - if (!window.google || !google.gears){ - xmlDoc = transport.responseXML; - } else { //no responseXML on gears - xmlDoc = (new DOMParser()).parseFromString(transport.responseText, "text/xml"); - } - } - - return xmlDoc; - }, - - /** - * renderXML - * renders the XML and returns what's required by this.show(); - */ - renderXML: function(xml){ - debug('[AbstractContentHandler] ERROR: renderXML not implemented in derived class!'); - return {}; - }, - - /** - * callback - * The default function that is being called for the onSuccess event of this.load(); - * Parameters: - * @transport - the xmlhttp transport object - **/ - callback: function(transport){ - var data = this.renderXML(this.getXML(transport)); - this.show(data); - }, - - /** - * errorback - * The default function that is being called for the onError event of this.load(); - * Parameters - * @transport - the xmlhttp transport object - */ - errorback: function(transport){ - var notif = "Request failed for: " + transport.request.url + "
Status: " + transport.status + " " + transport.statusText; - notify(notif, false); - }, - - /** - * load - * Calls this.getURL - * Parameters - * @parms - an json object containing {parameter : value} pairs for the request - * @fnc - function to replace this.callback (which is being called @ onSuccess) - */ - load: function(parms, fnc){ - // gears or not that's the question here - this.requestStarted(); - - this.parms = parms; - if(fnc !== undefined){ - this.callback = fnc; - } - - this.getUrl(this.url, parms, this.callback.bind(this), this.errorback.bind(this)); - }, - - /** - * getUrl - * creates a new Ajax.Request - * Parameters: - * @url - the url to fetch - * @parms - an json object containing {parameter : value} pairs for the request - * @callback - function to call @ onSuccess; - * @errorback - function to call @ onError; - */ - getUrl: function(url, parms, callback, errorback){ - if (!window.google || !google.gears){ //no gears - try{ - new Ajax.Request(url, - { - parameters: parms, - asynchronous: true, - method: 'GET', - requestHeaders: ['Cache-Control', 'no-cache,no-store', 'Expires', '-1'], - onException: function(o,e){ throw(e); }, - onSuccess: function (transport, json) { - if(callback !== undefined){ - callback(transport); - } - }.bind(this), - onFailure: function(transport){ - if(errorback !== undefined){ - errorback(transport); - } - }.bind(this), - onComplete: this.requestFinished.bind(this) - }); - } catch(e) { - debug('[AbstractContentHandler.getUrl] Exception: '+ e); - } - } else { //we're on gears! - try{ - url = url + "?" + $H(parms).toQueryString(); - - var request = google.gears.factory.create('beta.httprequest'); - request.open('GET', url); - - - request.onreadystatechange = function(){ - if(request.readyState == 4){ - if(request.status == 200){ - if( callback !== undefined ){ - callback(request); - } - } else { - this.errorback(request); - } - } - }.bind(this); - request.send(); - } catch(e) { - debug('[AbstractContentHandler.getUrl] Exception: '+ e); - } - } - }, - - registerEvents : function(){ - debug('[AbstractContentHandler] WARNING: registerEvents not implemented in derived class!'); - }, - - /** - * finished - * Calls all functions this.onFinished contains this.registerEvents - * Is usually called after this.show() has finished - */ - finished : function(){ - if(!this.eventsRegistered){ - this.registerEvents(); - this.eventsRegistered = true; - } - - if(this.onFinished !== undefined){ - for(var i = 0; i < this.onFinished.length; i++){ - var fnc = this.onFinished[i]; - if(typeof(fnc) === 'function'){ - fnc(); - } - } - } - }, - /** * show * Show the data that has been fetched by a request (and prepared by renderXML) @@ -244,29 +69,6 @@ var AbstractContentHandler = Class.create({ } }, - /** - * reload - * rexecute this.load() using this.parms and set this.refresh to false - * Parameters: - * @fnc - function to call @ onSuccess (passed through to this.load() ) - */ - reload: function(fnc){ - this.refresh = false; - this.load(this.parms, fnc); - }, - - /** - * simpleResultQuery - * Call any URL that returns a SimpleXMLResult with this.simpleResultCallback for - * @onSuccess - * Parameters: - * @url - the url to call - * @parms - an json object containing {parameter : value} pairs for the request - */ - simpleResultQuery: function(url, parms){ - this.getUrl(url, parms, this.simpleResultCallback.bind(this)); - }, - /** * simpleResultCallback * Callback for @ onSuccess of this.simpleResultQuery() @@ -275,76 +77,79 @@ var AbstractContentHandler = Class.create({ * @transport - the xmlhttp transport object */ simpleResultCallback: function(transport){ - var result = this.simpleResultRenderXML(this.getXML(transport)); - this.notify(result.getStateText(), result.getState()); - - if(this.refresh){ - this.reload(); - } - + this.provider.simpleResultCallback(transport, this.showSimpleResult.bind(this)); + }, + + showSimpleResult: function(result){ + this.notify(result.getStateText(), result.getState()); + }, + + registerEvents : function(){ + debug('[AbstractContentHandler] WARNING: registerEvents not implemented in derived class!'); }, /** - * simpleResultRenderXML - * Renders the result of this.simpleResultQuery() and returns an SimpleXMLResult object for it - * Parameters: - * @xml - a DOM object containing the XML to render + * finished + * Calls all functions this.onFinished contains this.registerEvents + * Is usually called after this.show() has finished */ - simpleResultRenderXML: function(xml){ - var result = new SimpleXMLResult(xml); - return result; + finished : function(){ + if(!this.eventsRegistered){ + this.registerEvents(); + this.eventsRegistered = true; + } + + if(this.onFinished !== undefined){ + for(var i = 0; i < this.onFinished.length; i++){ + var fnc = this.onFinished[i]; + if(typeof(fnc) === 'function'){ + fnc(); + } + } + } } - - }); -/** - * ServiceListHandler - * ContentHandler for service lists. - */ var ServiceListHandler = Class.create(AbstractContentHandler, { - /** - * initialize - * Parameters: - * @target: the html target id - * @epgp: Instance of ServiceListEpgProvider to show epgnow/next information - * @subsp: Instance of ServiceListSubserviceProvider to show subservices - */ - initialize: function($super, target, epgp, subsp){ - $super('tplServiceList', URL.getservices, - target, [this.getNowNext.bind(this),this.getSubservices.bind(this)] ); + initialize: function($super, target){ + $super('tplServiceList', target, [this.getNowNext.bind(this),this.getSubservices.bind(this)]); + //TODO ServiceListEpg-/ServiceListSubserviceHandler + this.provider = new ServiceListProvider(this.show.bind(this)); + this.epgHandler = new ServiceListEpgHandler(); + this.subServiceHandler = new ServiceListSubserviceHandler(); - this.epgProvider = epgp; - this.subServiceProvider = subsp; this.ajaxload = true; }, - - /** - * renderXML - * See the description in AbstractContentHandler - */ - renderXML: function(xml){ - var list = new ServiceList(xml).getArray(); - return {services : list}; - }, - + /** * getNowNext - * calls this.epgProvider.getNowNext to show Now/Next epg information + * calls this.epgHandler.getNowNext to show Now/Next epg information * using this.parms.sRef as the servicereference of the bouquet */ getNowNext: function(){ - this.epgProvider.getNowNext({bRef : this.parms.sRef}); + this.epgHandler.provider.getNowNext({bRef : this.provider.parms.sRef}); }, /** * getSubservices - * calls this.subServiceProvider.load() to show Now/Next epg information + * calls this.subServiceHandler.load() to show Now/Next epg information */ getSubservices: function(){ - this.subServiceProvider.load({}); + this.subServiceHandler.load({}); }, + /** + * call this to switch to a service + * Parameters: + * @servicereference - the (unescaped) reference to the service that should be shown + */ + zap: function(ref){ + this.provider.simpleResultQuery(URL.zap, {sRef : ref}, this.simpleResultCallback.bind(this)); + + //TODO replace this + setTimeout(updateItemsLazy, 7000); //reload epg and subservices + setTimeout(updateItems, 3000); + }, registerEvents : function(){ var parent = $(this.target); @@ -380,74 +185,39 @@ var ServiceListHandler = Class.create(AbstractContentHandler, { } ); - }, - - /** - * call this to switch to a service - * Parameters: - * @servicereference - the (unescaped) reference to the service that should be shown - */ - zap: function(ref){ - this.simpleResultQuery(URL.zap, {sRef : ref}); - - //TODO replace this - setTimeout(updateItemsLazy, 7000); //reload epg and subservices - setTimeout(updateItems, 3000); - } + } }); -/** - * ServiceListEpgProvider - * Handles EPG now/next for a ServiceListHandler - */ -var ServiceListEpgProvider = Class.create(AbstractContentHandler, { - //Constants - NOW : 'NOW', - NEXT : 'NEXT', - - /** - * initialize - * See the description in AbstractContentHandler - */ +var ServiceListEpgHandler = Class.create(AbstractContentHandler, { initialize: function($super){ - $super('tplServiceListEPGItem', URL.epgnow); - this.type = this.NOW; - this.url = URL.epgnow; - }, - - /** - * renderXML - * See the description in AbstractContentHandler - */ - renderXML: function(xml){ - var list = new EPGList(xml).getArray(); - return list; + $super('tplServiceListEPGItem'); + this.provider = new ServiceListEpgProvider(this.show.bind(this)); }, /** * show * calls this.showItem for each item of @list * @list - An array of EPGEvents - */ - show: function(list){ + */ + show: function(list, type){ for(var i = 0; i < list.length; i++){ - this.showItem(list[i]); + this.showItem(list[i], type); } this.finished(); }, /** - * showItem * Shows an EPGEvent item in the DOM * templates.tplServiceListEPGItem needs to be present! * Parameters: * @item - The EPGEvent object */ - showItem: function(item){ + //TODO: move showItem outta here + showItem: function(item, type){ if(item.eventid != ''){ - var data = { epg : item, nownext: this.type }; - var id = this.type + item.servicereference; + var data = { epg : item, nownext: type }; + var id = type + item.servicereference; if(templates.tplServiceListEPGItem !== undefined){ //TODO move templates.* maybe?!? @@ -462,86 +232,18 @@ var ServiceListEpgProvider = Class.create(AbstractContentHandler, { element.show(); } } - }, - - /** - * callback - * custom callback - * Parameters: - * @transport - xmlhttp transport object - */ - callback: function(transport){ - var data = this.renderXML(this.getXML(transport)); - this.show(data); - if(this.callbackType !== undefined){ - this.get(this.callbackType); - } - }, - - /** - * getNowNext - * call this.get to show epg-now and epg-next - * Parameters: - * @parms - an json object containing {parameter : value} pairs for the request - */ - getNowNext: function(parms){ - this.parms = parms; - this.get(this.NOW, this.NEXT); - }, - - /** - * get - * Load epg information for type and - if set - callbackType - * (ServiceListEpgProvider.NOW or ServiceListEpgProvider.NEXT) - * Parameters: - * @type - ServiceListEpgProvider.NOW or ServiceListEpgProvider.NEXT - * @callbackType - ServiceListEpgProvider.NOW or ServiceListEpgProvider.NEXT - */ - get: function(type, callbackType){ - this.type = type; - //just in case... don't do it twice... - if(type != callbackType){ - this.callbackType = callbackType; - } - - switch(this.type){ - case this.NOW: - this.url = URL.epgnow; - break; - case this.NEXT: - this.url = URL.epgnext; - break; - } - - this.load(this.parms); } }); -/** - * ServiceListSubserviceProvider - * Handles EPG now/next for a ServiceListHandler - */ -var ServiceListSubserviceProvider = Class.create(AbstractContentHandler, { +var ServiceListSubserviceHandler = Class.create(AbstractContentHandler, { //constants PREFIX : 'SUB', - - /** - * initialize - * See the description in AbstractContentHandler - */ + initialize: function($super){ - $super('tplSubServices', URL.subservices); + $super('tplSubServices'); + this.provider = new ServiceListSubserviceProvider(this.show.bind(this)); }, - - /** - * renderXML - * See the description in AbstractContentHandler - */ - renderXML: function(xml){ - var list = new ServiceList(xml).getArray(); - return list; - }, - + /** * show * Show all subervices of a service (if there are any) @@ -561,30 +263,14 @@ var ServiceListSubserviceProvider = Class.create(AbstractContentHandler, { } }); -/** - * MovieListHandler - * Handles a list of movies including deleting actions - */ -var MovieListHandler = Class.create(AbstractContentHandler, { - /** - * initialize - * See the description in AbstractContentHandler - */ +var MovieListHandler = Class.create(AbstractContentHandler, { initialize: function($super, target){ - $super('tplMovieList', URL.movielist, target ); + $super('tplMovieList', target); + this.provider = new MovieListProvider(this.show.bind(this)); this.ajaxload = true; }, - /** - * renderXML - * See the description in AbstractContentHandler - */ - renderXML: function(xml){ - var list = new MovieList(xml).getArray(); - return {movies : list}; - }, - /** * del * Deletes a movie @@ -601,11 +287,11 @@ var MovieListHandler = Class.create(AbstractContentHandler, { "Description: " + description + "\n"); if(result){ - debug("[MovieListHandler.del] ok confirm panel"); - this.simpleResultQuery(URL.moviedelete, {sRef : servicereference}); + debug("[MovieListProvider.del] ok confirm panel"); + this.provider.simpleResultQuery(URL.moviedelete, {sRef : servicereference}, this.simpleResultCallback.bind(this)); } else{ - debug("[MovieListHandler.del] cancel confirm panel"); + debug("[MovieListProvider.del] cancel confirm panel"); result = false; } @@ -614,25 +300,13 @@ var MovieListHandler = Class.create(AbstractContentHandler, { } }); -var TimerListHandler = Class.create(AbstractContentHandler, { - /** - * initialize - * See the description in AbstractContentHandler - */ +var TimerListHandler = Class.create(AbstractContentHandler, { initialize: function($super, target){ - $super('tplTimerList', URL.timerlist, target ); + $super('tplTimerList', target); + this.provider = new TimerListProvider(this.show.bind(this)); this.ajaxload = true; - }, - - /** - * renderXML - * See the description in AbstractContentHandler - */ - renderXML: function(xml){ - var list = new TimerList(xml).getArray(); - return {timer : list}; - } + } }); var TimerHandler = Class.create(AbstractContentHandler, { @@ -649,10 +323,10 @@ var TimerHandler = Class.create(AbstractContentHandler, { /** * initialize - * See the description in AbstractContentHandler + * See the description in AbstractContentProvider */ initialize: function($super, target){ - $super('tplTimerEdit', URL.timerlist, target ); + $super('tplTimerEdit', target); this.ajaxload = true; }, @@ -664,7 +338,7 @@ var TimerHandler = Class.create(AbstractContentHandler, { * Most of the data is already there or has to be created. * * Parameters: - * @element - the html element calling the load function ( onclick="TimerHandler.load(this)" ) + * @element - the html element calling the load function ( onclick="TimerProvider.load(this)" ) */ load : function(element){ var parent = element.up('.tListItem'); @@ -824,7 +498,7 @@ var TimerHandler = Class.create(AbstractContentHandler, { /** * renderXML - * See the description in AbstractContentHandler + * See the description in AbstractContentProvider */ renderXML: function(xml){ var list = new TimerList(xml).getArray(); @@ -832,20 +506,17 @@ var TimerHandler = Class.create(AbstractContentHandler, { }, registerEvents: function(){ - $('saveTimer').on('click', - function(event, element){ + $('saveTimer').on('click', function(event, element){ this.commitForm('timerEditForm'); }.bind(this) ); - $('month').on('change', - function(event, element){ + $('month').on('change', function(event, element){ this.reloadDays(); }.bind(this) ); - $('year').on('change', - function(event, element){ + $('year').on('change', function(event, element){ this.reloadDays(); }.bind(this) ); @@ -864,7 +535,10 @@ var TimerHandler = Class.create(AbstractContentHandler, { for(var i = 0; i < items.length; i++){ var item = items[i]; - var attrs = { value : item.value, selected : item.selected }; + var attrs = { value : item.value }; + if(item.selected == this.SELECTED){ + attrs = { value : item.value, selected : item.selected }; + } var option = new Element('option', attrs).update(item.txt); element.appendChild(option); @@ -872,8 +546,9 @@ var TimerHandler = Class.create(AbstractContentHandler, { } }); + //create required Instances -var serviceListHandler = new ServiceListHandler('contentServices', new ServiceListEpgProvider(), new ServiceListSubserviceProvider()); +var serviceListHandler = new ServiceListHandler('contentServices'); var movieListHandler = new MovieListHandler('contentMain'); var timerListHandler = new TimerListHandler('contentMain'); var timerHandler = new TimerHandler('contentMain'); \ No newline at end of file diff --git a/webinterface/src/web-data/lib/prototype_1.7-rc1.js b/webinterface/src/web-data/lib/prototype.js similarity index 98% rename from webinterface/src/web-data/lib/prototype_1.7-rc1.js rename to webinterface/src/web-data/lib/prototype.js index 63b1590b59..06249a6ae3 100644 --- a/webinterface/src/web-data/lib/prototype_1.7-rc1.js +++ b/webinterface/src/web-data/lib/prototype.js @@ -1,5 +1,5 @@ -/* Prototype JavaScript framework, version 1.7_rc1 - * (c) 2005-2009 Sam Stephenson +/* Prototype JavaScript framework, version 1.7_rc2 + * (c) 2005-2010 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. * For details, see the Prototype web site: http://www.prototypejs.org/ @@ -8,7 +8,7 @@ var Prototype = { - Version: '1.7_rc1', + Version: '1.7_rc2', Browser: (function(){ var ua = navigator.userAgent; @@ -1883,6 +1883,15 @@ if (!Node.ELEMENT_NODE) { Element.idCounter = 1; Element.cache = { }; +function purgeElement(element) { + var uid = element._prototypeUID; + if (uid) { + Element.stopObserving(element); + element._prototypeUID = void 0; + delete Element.Storage[uid]; + } +} + Element.Methods = { visible: function(element) { return $(element).style.display != 'none'; @@ -1956,6 +1965,10 @@ Element.Methods = { function update(element, content) { element = $(element); + var descendants = element.getElementsByTagName('*'), + i = descendants.length; + while (i--) purgeElement(descendants[i]); + if (content && content.toElement) content = content.toElement(); @@ -3201,8 +3214,8 @@ Element.addMethods({ uid = 0; } else { if (typeof element._prototypeUID === "undefined") - element._prototypeUID = [Element.Storage.UID++]; - uid = element._prototypeUID[0]; + element._prototypeUID = Element.Storage.UID++; + uid = element._prototypeUID; } if (!Element.Storage[uid]) @@ -3247,1662 +3260,1697 @@ Element.addMethods({ } } return Element.extend(clone); - } -}); -Prototype._original_property = window.Sizzle; -/*! - * Sizzle CSS Selector Engine - v1.0 - * Copyright 2009, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * More information: http://sizzlejs.com/ - */ -(function(){ + }, -var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, - done = 0, - toString = Object.prototype.toString, - hasDuplicate = false, - baseHasDuplicate = true; + purge: function(element) { + if (!(element = $(element))) return; + purgeElement(element); -[0, 0].sort(function(){ - baseHasDuplicate = false; - return 0; -}); + var descendants = element.getElementsByTagName('*'), + i = descendants.length; -var Sizzle = function(selector, context, results, seed) { - results = results || []; - var origContext = context = context || document; + while (i--) purgeElement(descendants[i]); - if ( context.nodeType !== 1 && context.nodeType !== 9 ) { - return []; - } + return null; + } +}); - if ( !selector || typeof selector !== "string" ) { - return results; - } +(function() { - var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), - soFar = selector; + function toDecimal(pctString) { + var match = pctString.match(/^(\d+)%?$/i); + if (!match) return null; + return (Number(match[1]) / 100); + } - while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { - soFar = m[3]; + function getPixelValue(value, property) { + if (Object.isElement(value)) { + element = value; + value = element.getStyle(property); + } + if (value === null) { + return null; + } - parts.push( m[1] ); + if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) { + return window.parseFloat(value); + } - if ( m[2] ) { - extra = m[3]; - break; - } - } + if (/\d/.test(value) && element.runtimeStyle) { + var style = element.style.left, rStyle = element.runtimeStyle.left; + element.runtimeStyle.left = element.currentStyle.left; + element.style.left = value || 0; + value = element.style.pixelLeft; + element.style.left = style; + element.runtimeStyle.left = rStyle; - if ( parts.length > 1 && origPOS.exec( selector ) ) { - if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { - set = posProcess( parts[0] + parts[1], context ); - } else { - set = Expr.relative[ parts[0] ] ? - [ context ] : - Sizzle( parts.shift(), context ); + return value; + } - while ( parts.length ) { - selector = parts.shift(); + if (value.include('%')) { + var decimal = toDecimal(value); + var whole; + if (property.include('left') || property.include('right') || + property.include('width')) { + whole = $(element.parentNode).measure('width'); + } else if (property.include('top') || property.include('bottom') || + property.include('height')) { + whole = $(element.parentNode).measure('height'); + } - if ( Expr.relative[ selector ] ) - selector += parts.shift(); + return whole * decimal; + } - set = posProcess( selector, set ); - } - } - } else { - if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && - Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { - var ret = Sizzle.find( parts.shift(), context, contextXML ); - context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; - } + return 0; + } - if ( context ) { - var ret = seed ? - { expr: parts.pop(), set: makeArray(seed) } : - Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); - set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + function toCSSPixels(number) { + if (Object.isString(number) && number.endsWith('px')) { + return number; + } + return number + 'px'; + } - if ( parts.length > 0 ) { - checkSet = makeArray(set); - } else { - prune = false; - } + function isDisplayed(element) { + var originalElement = element; + while (element && element.parentNode) { + var display = element.getStyle('display'); + if (display === 'none') { + return false; + } + element = $(element.parentNode); + } + return true; + } - while ( parts.length ) { - var cur = parts.pop(), pop = cur; + var hasLayout = Prototype.K; + if ('currentStyle' in document.documentElement) { + hasLayout = function(element) { + if (!element.currentStyle.hasLayout) { + element.style.zoom = 1; + } + return element; + }; + } - if ( !Expr.relative[ cur ] ) { - cur = ""; - } else { - pop = parts.pop(); - } + function cssNameFor(key) { + if (key.include('border')) key = key + '-width'; + return key.camelize(); + } - if ( pop == null ) { - pop = context; - } + Element.Layout = Class.create(Hash, { + initialize: function($super, element, preCompute) { + $super(); + this.element = $(element); - Expr.relative[ cur ]( checkSet, pop, contextXML ); - } - } else { - checkSet = parts = []; - } - } + Element.Layout.PROPERTIES.each( function(property) { + this._set(property, null); + }, this); - if ( !checkSet ) { - checkSet = set; - } + if (preCompute) { + this._preComputing = true; + this._begin(); + Element.Layout.PROPERTIES.each( this._compute, this ); + this._end(); + this._preComputing = false; + } + }, - if ( !checkSet ) { - throw "Syntax error, unrecognized expression: " + (cur || selector); - } + _set: function(property, value) { + return Hash.prototype.set.call(this, property, value); + }, - if ( toString.call(checkSet) === "[object Array]" ) { - if ( !prune ) { - results.push.apply( results, checkSet ); - } else if ( context && context.nodeType === 1 ) { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { - results.push( set[i] ); - } - } - } else { - for ( var i = 0; checkSet[i] != null; i++ ) { - if ( checkSet[i] && checkSet[i].nodeType === 1 ) { - results.push( set[i] ); - } - } - } - } else { - makeArray( checkSet, results ); - } + set: function(property, value) { + throw "Properties of Element.Layout are read-only."; + }, - if ( extra ) { - Sizzle( extra, origContext, results, seed ); - Sizzle.uniqueSort( results ); - } + get: function($super, property) { + var value = $super(property); + return value === null ? this._compute(property) : value; + }, - return results; -}; + _begin: function() { + if (this._prepared) return; -Sizzle.uniqueSort = function(results){ - if ( sortOrder ) { - hasDuplicate = baseHasDuplicate; - results.sort(sortOrder); + var element = this.element; + if (isDisplayed(element)) { + this._prepared = true; + return; + } - if ( hasDuplicate ) { - for ( var i = 1; i < results.length; i++ ) { - if ( results[i] === results[i-1] ) { - results.splice(i--, 1); - } - } - } - } + var originalStyles = { + position: element.style.position || '', + width: element.style.width || '', + visibility: element.style.visibility || '', + display: element.style.display || '' + }; - return results; -}; + element.store('prototype_original_styles', originalStyles); -Sizzle.matches = function(expr, set){ - return Sizzle(expr, null, null, set); -}; + var position = element.getStyle('position'), + width = element.getStyle('width'); -Sizzle.find = function(expr, context, isXML){ - var set, match; + element.setStyle({ + position: 'absolute', + visibility: 'hidden', + display: 'block' + }); - if ( !expr ) { - return []; - } + var positionedWidth = element.getStyle('width'); - for ( var i = 0, l = Expr.order.length; i < l; i++ ) { - var type = Expr.order[i], match; + var newWidth; + if (width && (positionedWidth === width)) { + newWidth = getPixelValue(width); + } else if (width && (position === 'absolute' || position === 'fixed')) { + newWidth = getPixelValue(width); + } else { + var parent = element.parentNode, pLayout = $(parent).getLayout(); - if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { - var left = match[1]; - match.splice(1,1); + newWidth = pLayout.get('width') - + this.get('margin-left') - + this.get('border-left') - + this.get('padding-left') - + this.get('padding-right') - + this.get('border-right') - + this.get('margin-right'); + } - if ( left.substr( left.length - 1 ) !== "\\" ) { - match[1] = (match[1] || "").replace(/\\/g, ""); - set = Expr.find[ type ]( match, context, isXML ); - if ( set != null ) { - expr = expr.replace( Expr.match[ type ], "" ); - break; - } - } - } - } + element.setStyle({ width: newWidth + 'px' }); - if ( !set ) { - set = context.getElementsByTagName("*"); - } + this._prepared = true; + }, - return {set: set, expr: expr}; -}; + _end: function() { + var element = this.element; + var originalStyles = element.retrieve('prototype_original_styles'); + element.store('prototype_original_styles', null); + element.setStyle(originalStyles); + this._prepared = false; + }, -Sizzle.filter = function(expr, set, inplace, not){ - var old = expr, result = [], curLoop = set, match, anyFound, - isXMLFilter = set && set[0] && isXML(set[0]); + _compute: function(property) { + var COMPUTATIONS = Element.Layout.COMPUTATIONS; + if (!(property in COMPUTATIONS)) { + throw "Property not found."; + } + return this._set(property, COMPUTATIONS[property].call(this, this.element)); + }, - while ( expr && set.length ) { - for ( var type in Expr.filter ) { - if ( (match = Expr.match[ type ].exec( expr )) != null ) { - var filter = Expr.filter[ type ], found, item; - anyFound = false; + toObject: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var obj = {}; + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + var value = this.get(key); + if (value != null) obj[key] = value; + }, this); + return obj; + }, - if ( curLoop == result ) { - result = []; - } + toHash: function() { + var obj = this.toObject.apply(this, arguments); + return new Hash(obj); + }, - if ( Expr.preFilter[ type ] ) { - match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + toCSS: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var css = {}; - if ( !match ) { - anyFound = found = true; - } else if ( match === true ) { - continue; - } - } + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; - if ( match ) { - for ( var i = 0; (item = curLoop[i]) != null; i++ ) { - if ( item ) { - found = filter( item, match, i, curLoop ); - var pass = not ^ !!found; + var value = this.get(key); + if (value != null) css[cssNameFor(key)] = value + 'px'; + }, this); + return css; + }, - if ( inplace && found != null ) { - if ( pass ) { - anyFound = true; - } else { - curLoop[i] = false; - } - } else if ( pass ) { - result.push( item ); - anyFound = true; - } - } - } - } + inspect: function() { + return "#"; + } + }); - if ( found !== undefined ) { - if ( !inplace ) { - curLoop = result; - } + Object.extend(Element.Layout, { + PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), - expr = expr.replace( Expr.match[ type ], "" ); + COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), - if ( !anyFound ) { - return []; - } + COMPUTATIONS: { + 'height': function(element) { + if (!this._preComputing) this._begin(); - break; - } - } - } + var bHeight = this.get('border-box-height'); + if (bHeight <= 0) return 0; - if ( expr == old ) { - if ( anyFound == null ) { - throw "Syntax error, unrecognized expression: " + expr; - } else { - break; - } - } + var bTop = this.get('border-top'), + bBottom = this.get('border-bottom'); - old = expr; - } + var pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); - return curLoop; -}; + if (!this._preComputing) this._end(); -var Expr = Sizzle.selectors = { - order: [ "ID", "NAME", "TAG" ], - match: { - ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, - NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, - ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, - TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, - CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, - POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, - PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ - }, - leftMatch: {}, - attrMap: { - "class": "className", - "for": "htmlFor" - }, - attrHandle: { - href: function(elem){ - return elem.getAttribute("href"); - } - }, - relative: { - "+": function(checkSet, part, isXML){ - var isPartStr = typeof part === "string", - isTag = isPartStr && !/\W/.test(part), - isPartStrNotTag = isPartStr && !isTag; + return bHeight - bTop - bBottom - pTop - pBottom; + }, - if ( isTag && !isXML ) { - part = part.toUpperCase(); - } + 'width': function(element) { + if (!this._preComputing) this._begin(); - for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { - if ( (elem = checkSet[i]) ) { - while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + var bWidth = this.get('border-box-width'); + if (bWidth <= 0) return 0; - checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? - elem || false : - elem === part; - } - } + var bLeft = this.get('border-left'), + bRight = this.get('border-right'); - if ( isPartStrNotTag ) { - Sizzle.filter( part, checkSet, true ); - } - }, - ">": function(checkSet, part, isXML){ - var isPartStr = typeof part === "string"; + var pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); - if ( isPartStr && !/\W/.test(part) ) { - part = isXML ? part : part.toUpperCase(); + if (!this._preComputing) this._end(); - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - var parent = elem.parentNode; - checkSet[i] = parent.nodeName === part ? parent : false; - } - } - } else { - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - checkSet[i] = isPartStr ? - elem.parentNode : - elem.parentNode === part; - } - } + return bWidth - bLeft - bRight - pLeft - pRight; + }, - if ( isPartStr ) { - Sizzle.filter( part, checkSet, true ); - } - } - }, - "": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; + 'padding-box-height': function(element) { + var height = this.get('height'), + pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); - if ( !/\W/.test(part) ) { - var nodeCheck = part = isXML ? part : part.toUpperCase(); - checkFn = dirNodeCheck; - } + return height + pTop + pBottom; + }, - checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); - }, - "~": function(checkSet, part, isXML){ - var doneName = done++, checkFn = dirCheck; + 'padding-box-width': function(element) { + var width = this.get('width'), + pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); - if ( typeof part === "string" && !/\W/.test(part) ) { - var nodeCheck = part = isXML ? part : part.toUpperCase(); - checkFn = dirNodeCheck; - } + return width + pLeft + pRight; + }, - checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); - } - }, - find: { - ID: function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? [m] : []; - } - }, - NAME: function(match, context, isXML){ - if ( typeof context.getElementsByName !== "undefined" ) { - var ret = [], results = context.getElementsByName(match[1]); + 'border-box-height': function(element) { + return element.offsetHeight; + }, - for ( var i = 0, l = results.length; i < l; i++ ) { - if ( results[i].getAttribute("name") === match[1] ) { - ret.push( results[i] ); - } - } + 'border-box-width': function(element) { + return element.offsetWidth; + }, - return ret.length === 0 ? null : ret; - } - }, - TAG: function(match, context){ - return context.getElementsByTagName(match[1]); - } - }, - preFilter: { - CLASS: function(match, curLoop, inplace, result, not, isXML){ - match = " " + match[1].replace(/\\/g, "") + " "; + 'margin-box-height': function(element) { + var bHeight = this.get('border-box-height'), + mTop = this.get('margin-top'), + mBottom = this.get('margin-bottom'); - if ( isXML ) { - return match; - } + if (bHeight <= 0) return 0; - for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { - if ( elem ) { - if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { - if ( !inplace ) - result.push( elem ); - } else if ( inplace ) { - curLoop[i] = false; - } - } - } + return bHeight + mTop + mBottom; + }, - return false; - }, - ID: function(match){ - return match[1].replace(/\\/g, ""); - }, - TAG: function(match, curLoop){ - for ( var i = 0; curLoop[i] === false; i++ ){} - return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); - }, - CHILD: function(match){ - if ( match[1] == "nth" ) { - var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( - match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || - !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + 'margin-box-width': function(element) { + var bWidth = this.get('border-box-width'), + mLeft = this.get('margin-left'), + mRight = this.get('margin-right'); - match[2] = (test[1] + (test[2] || 1)) - 0; - match[3] = test[3] - 0; - } + if (bWidth <= 0) return 0; - match[0] = done++; + return bWidth + mLeft + mRight; + }, - return match; - }, - ATTR: function(match, curLoop, inplace, result, not, isXML){ - var name = match[1].replace(/\\/g, ""); + 'top': function(element) { + var offset = element.positionedOffset(); + return offset.top; + }, - if ( !isXML && Expr.attrMap[name] ) { - match[1] = Expr.attrMap[name]; - } + 'bottom': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pHeight = parent.measure('height'); - if ( match[2] === "~=" ) { - match[4] = " " + match[4] + " "; - } + var mHeight = this.get('border-box-height'); - return match; - }, - PSEUDO: function(match, curLoop, inplace, result, not){ - if ( match[1] === "not" ) { - if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { - match[3] = Sizzle(match[3], null, null, curLoop); - } else { - var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); - if ( !inplace ) { - result.push.apply( result, ret ); - } - return false; - } - } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { - return true; - } + return pHeight - mHeight - offset.top; + }, - return match; - }, - POS: function(match){ - match.unshift( true ); - return match; - } - }, - filters: { - enabled: function(elem){ - return elem.disabled === false && elem.type !== "hidden"; - }, - disabled: function(elem){ - return elem.disabled === true; - }, - checked: function(elem){ - return elem.checked === true; - }, - selected: function(elem){ - elem.parentNode.selectedIndex; - return elem.selected === true; - }, - parent: function(elem){ - return !!elem.firstChild; - }, - empty: function(elem){ - return !elem.firstChild; - }, - has: function(elem, i, match){ - return !!Sizzle( match[3], elem ).length; - }, - header: function(elem){ - return /h\d/i.test( elem.nodeName ); - }, - text: function(elem){ - return "text" === elem.type; - }, - radio: function(elem){ - return "radio" === elem.type; - }, - checkbox: function(elem){ - return "checkbox" === elem.type; - }, - file: function(elem){ - return "file" === elem.type; - }, - password: function(elem){ - return "password" === elem.type; - }, - submit: function(elem){ - return "submit" === elem.type; - }, - image: function(elem){ - return "image" === elem.type; - }, - reset: function(elem){ - return "reset" === elem.type; - }, - button: function(elem){ - return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; - }, - input: function(elem){ - return /input|select|textarea|button/i.test(elem.nodeName); - } - }, - setFilters: { - first: function(elem, i){ - return i === 0; - }, - last: function(elem, i, match, array){ - return i === array.length - 1; - }, - even: function(elem, i){ - return i % 2 === 0; - }, - odd: function(elem, i){ - return i % 2 === 1; - }, - lt: function(elem, i, match){ - return i < match[3] - 0; - }, - gt: function(elem, i, match){ - return i > match[3] - 0; - }, - nth: function(elem, i, match){ - return match[3] - 0 == i; - }, - eq: function(elem, i, match){ - return match[3] - 0 == i; - } - }, - filter: { - PSEUDO: function(elem, match, i, array){ - var name = match[1], filter = Expr.filters[ name ]; + 'left': function(element) { + var offset = element.positionedOffset(); + return offset.left; + }, - if ( filter ) { - return filter( elem, i, match, array ); - } else if ( name === "contains" ) { - return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; - } else if ( name === "not" ) { - var not = match[3]; + 'right': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pWidth = parent.measure('width'); - for ( var i = 0, l = not.length; i < l; i++ ) { - if ( not[i] === elem ) { - return false; - } - } + var mWidth = this.get('border-box-width'); - return true; - } - }, - CHILD: function(elem, match){ - var type = match[1], node = elem; - switch (type) { - case 'only': - case 'first': - while ( (node = node.previousSibling) ) { - if ( node.nodeType === 1 ) return false; - } - if ( type == 'first') return true; - node = elem; - case 'last': - while ( (node = node.nextSibling) ) { - if ( node.nodeType === 1 ) return false; - } - return true; - case 'nth': - var first = match[2], last = match[3]; + return pWidth - mWidth - offset.left; + }, - if ( first == 1 && last == 0 ) { - return true; - } + 'padding-top': function(element) { + return getPixelValue(element, 'paddingTop'); + }, - var doneName = match[0], - parent = elem.parentNode; + 'padding-bottom': function(element) { + return getPixelValue(element, 'paddingBottom'); + }, - if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { - var count = 0; - for ( node = parent.firstChild; node; node = node.nextSibling ) { - if ( node.nodeType === 1 ) { - node.nodeIndex = ++count; - } - } - parent.sizcache = doneName; - } + 'padding-left': function(element) { + return getPixelValue(element, 'paddingLeft'); + }, - var diff = elem.nodeIndex - last; - if ( first == 0 ) { - return diff == 0; - } else { - return ( diff % first == 0 && diff / first >= 0 ); - } - } - }, - ID: function(elem, match){ - return elem.nodeType === 1 && elem.getAttribute("id") === match; - }, - TAG: function(elem, match){ - return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; - }, - CLASS: function(elem, match){ - return (" " + (elem.className || elem.getAttribute("class")) + " ") - .indexOf( match ) > -1; - }, - ATTR: function(elem, match){ - var name = match[1], - result = Expr.attrHandle[ name ] ? - Expr.attrHandle[ name ]( elem ) : - elem[ name ] != null ? - elem[ name ] : - elem.getAttribute( name ), - value = result + "", - type = match[2], - check = match[4]; + 'padding-right': function(element) { + return getPixelValue(element, 'paddingRight'); + }, - return result == null ? - type === "!=" : - type === "=" ? - value === check : - type === "*=" ? - value.indexOf(check) >= 0 : - type === "~=" ? - (" " + value + " ").indexOf(check) >= 0 : - !check ? - value && result !== false : - type === "!=" ? - value != check : - type === "^=" ? - value.indexOf(check) === 0 : - type === "$=" ? - value.substr(value.length - check.length) === check : - type === "|=" ? - value === check || value.substr(0, check.length + 1) === check + "-" : - false; - }, - POS: function(elem, match, i, array){ - var name = match[2], filter = Expr.setFilters[ name ]; + 'border-top': function(element) { + return Object.isNumber(element.clientTop) ? element.clientTop : + getPixelValue(element, 'borderTopWidth'); + }, - if ( filter ) { - return filter( elem, i, match, array ); - } - } - } -}; + 'border-bottom': function(element) { + return Object.isNumber(element.clientBottom) ? element.clientBottom : + getPixelValue(element, 'borderBottomWidth'); + }, -var origPOS = Expr.match.POS; + 'border-left': function(element) { + return Object.isNumber(element.clientLeft) ? element.clientLeft : + getPixelValue(element, 'borderLeftWidth'); + }, -for ( var type in Expr.match ) { - Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); - Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); -} + 'border-right': function(element) { + return Object.isNumber(element.clientRight) ? element.clientRight : + getPixelValue(element, 'borderRightWidth'); + }, -var makeArray = function(array, results) { - array = Array.prototype.slice.call( array, 0 ); + 'margin-top': function(element) { + return getPixelValue(element, 'marginTop'); + }, - if ( results ) { - results.push.apply( results, array ); - return results; - } + 'margin-bottom': function(element) { + return getPixelValue(element, 'marginBottom'); + }, - return array; -}; + 'margin-left': function(element) { + return getPixelValue(element, 'marginLeft'); + }, -try { - Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + 'margin-right': function(element) { + return getPixelValue(element, 'marginRight'); + } + } + }); -} catch(e){ - makeArray = function(array, results) { - var ret = results || []; + if ('getBoundingClientRect' in document.documentElement) { + Object.extend(Element.Layout.COMPUTATIONS, { + 'right': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); - if ( toString.call(array) === "[object Array]" ) { - Array.prototype.push.apply( ret, array ); - } else { - if ( typeof array.length === "number" ) { - for ( var i = 0, l = array.length; i < l; i++ ) { - ret.push( array[i] ); - } - } else { - for ( var i = 0; array[i]; i++ ) { - ret.push( array[i] ); - } - } - } + return (pRect.right - rect.right).round(); + }, - return ret; - }; -} + 'bottom': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); -var sortOrder; + return (pRect.bottom - rect.bottom).round(); + } + }); + } -if ( document.documentElement.compareDocumentPosition ) { - sortOrder = function( a, b ) { - if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { - if ( a == b ) { - hasDuplicate = true; - } - return 0; - } + Element.Offset = Class.create({ + initialize: function(left, top) { + this.left = left.round(); + this.top = top.round(); - var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( "sourceIndex" in document.documentElement ) { - sortOrder = function( a, b ) { - if ( !a.sourceIndex || !b.sourceIndex ) { - if ( a == b ) { - hasDuplicate = true; - } - return 0; - } + this[0] = this.left; + this[1] = this.top; + }, - var ret = a.sourceIndex - b.sourceIndex; - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} else if ( document.createRange ) { - sortOrder = function( a, b ) { - if ( !a.ownerDocument || !b.ownerDocument ) { - if ( a == b ) { - hasDuplicate = true; - } - return 0; - } + relativeTo: function(offset) { + return new Element.Offset( + this.left - offset.left, + this.top - offset.top + ); + }, - var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); - aRange.setStart(a, 0); - aRange.setEnd(a, 0); - bRange.setStart(b, 0); - bRange.setEnd(b, 0); - var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); - if ( ret === 0 ) { - hasDuplicate = true; - } - return ret; - }; -} + inspect: function() { + return "#".interpolate(this); + }, -(function(){ - var form = document.createElement("div"), - id = "script" + (new Date).getTime(); - form.innerHTML = ""; + toString: function() { + return "[#{left}, #{top}]".interpolate(this); + }, - var root = document.documentElement; - root.insertBefore( form, root.firstChild ); + toArray: function() { + return [this.left, this.top]; + } + }); - if ( !!document.getElementById( id ) ) { - Expr.find.ID = function(match, context, isXML){ - if ( typeof context.getElementById !== "undefined" && !isXML ) { - var m = context.getElementById(match[1]); - return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; - } - }; + function getLayout(element, preCompute) { + return new Element.Layout(element, preCompute); + } - Expr.filter.ID = function(elem, match){ - var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); - return elem.nodeType === 1 && node && node.nodeValue === match; - }; - } + function measure(element, property) { + return $(element).getLayout().get(property); + } - root.removeChild( form ); - root = form = null; // release memory in IE -})(); + function getDimensions(element) { + var layout = $(element).getLayout(); + return { + width: layout.get('width'), + height: layout.get('height') + }; + } -(function(){ + function getOffsetParent(element) { + if (isDetached(element)) return $(document.body); - var div = document.createElement("div"); - div.appendChild( document.createComment("") ); + var isInline = (Element.getStyle(element, 'display') === 'inline'); + if (!isInline && element.offsetParent) return $(element.offsetParent); + if (element === document.body) return $(element); - if ( div.getElementsByTagName("*").length > 0 ) { - Expr.find.TAG = function(match, context){ - var results = context.getElementsByTagName(match[1]); + while ((element = element.parentNode) && element !== document.body) { + if (Element.getStyle(element, 'position') !== 'static') { + return (element.nodeName === 'HTML') ? $(document.body) : $(element); + } + } - if ( match[1] === "*" ) { - var tmp = []; + return $(document.body); + } - for ( var i = 0; results[i]; i++ ) { - if ( results[i].nodeType === 1 ) { - tmp.push( results[i] ); - } - } - results = tmp; - } + function cumulativeOffset(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return new Element.Offset(valueL, valueT); + } - return results; - }; - } + function positionedOffset(element) { + var layout = element.getLayout(); - div.innerHTML = ""; - if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && - div.firstChild.getAttribute("href") !== "#" ) { - Expr.attrHandle.href = function(elem){ - return elem.getAttribute("href", 2); - }; - } + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (isBody(element)) break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); - div = null; // release memory in IE -})(); + valueL -= layout.get('margin-top'); + valueT -= layout.get('margin-left'); -if ( document.querySelectorAll ) (function(){ - var oldSizzle = Sizzle, div = document.createElement("div"); - div.innerHTML = "

"; + return new Element.Offset(valueL, valueT); + } - if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { - return; - } + function cumulativeScrollOffset(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return new Element.Offset(valueL, valueT); + } - Sizzle = function(query, context, extra, seed){ - context = context || document; + function viewportOffset(forElement) { + var valueT = 0, valueL = 0, docBody = document.body; - if ( !seed && context.nodeType === 9 && !isXML(context) ) { - try { - return makeArray( context.querySelectorAll(query), extra ); - } catch(e){} - } + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == docBody && + Element.getStyle(element, 'position') == 'absolute') break; + } while (element = element.offsetParent); - return oldSizzle(query, context, extra, seed); - }; + element = forElement; + do { + if (element != docBody) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + return new Element.Offset(valueL, valueT); + } - for ( var prop in oldSizzle ) { - Sizzle[ prop ] = oldSizzle[ prop ]; - } + function absolutize(element) { + element = $(element); - div = null; // release memory in IE -})(); + if (Element.getStyle(element, 'position') === 'absolute') { + return element; + } -if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ - var div = document.createElement("div"); - div.innerHTML = "
"; + var offsetParent = getOffsetParent(element); + var eOffset = element.viewportOffset(), + pOffset = offsetParent.viewportOffset(); - if ( div.getElementsByClassName("e").length === 0 ) - return; + var offset = eOffset.relativeTo(pOffset); + var layout = element.getLayout(); - div.lastChild.className = "e"; + element.store('prototype_absolutize_original_styles', { + left: element.getStyle('left'), + top: element.getStyle('top'), + width: element.getStyle('width'), + height: element.getStyle('height') + }); - if ( div.getElementsByClassName("e").length === 1 ) - return; + element.setStyle({ + position: 'absolute', + top: offset.top + 'px', + left: offset.left + 'px', + width: layout.get('width') + 'px', + height: layout.get('height') + 'px' + }); - Expr.order.splice(1, 0, "CLASS"); - Expr.find.CLASS = function(match, context, isXML) { - if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { - return context.getElementsByClassName(match[1]); - } - }; + return element; + } - div = null; // release memory in IE -})(); + function relativize(element) { + element = $(element); + if (Element.getStyle(element, 'position') === 'relative') { + return element; + } -function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - var sibDir = dir == "previousSibling" && !isXML; - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - if ( sibDir && elem.nodeType === 1 ){ - elem.sizcache = doneName; - elem.sizset = i; - } - elem = elem[dir]; - var match = false; + var originalStyles = + element.retrieve('prototype_absolutize_original_styles'); - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } + if (originalStyles) element.setStyle(originalStyles); + return element; + } - if ( elem.nodeType === 1 && !isXML ){ - elem.sizcache = doneName; - elem.sizset = i; - } + Element.addMethods({ + getLayout: getLayout, + measure: measure, + getDimensions: getDimensions, + getOffsetParent: getOffsetParent, + cumulativeOffset: cumulativeOffset, + positionedOffset: positionedOffset, + cumulativeScrollOffset: cumulativeScrollOffset, + viewportOffset: viewportOffset, + absolutize: absolutize, + relativize: relativize + }); - if ( elem.nodeName === cur ) { - match = elem; - break; - } + function isBody(element) { + return element.nodeName.toUpperCase() === 'BODY'; + } - elem = elem[dir]; - } + function isDetached(element) { + return element !== document.body && + !Element.descendantOf(element, document.body); + } - checkSet[i] = match; - } - } -} + if ('getBoundingClientRect' in document.documentElement) { + Element.addMethods({ + viewportOffset: function(element) { + element = $(element); + if (isDetached(element)) return new Element.Offset(0, 0); -function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { - var sibDir = dir == "previousSibling" && !isXML; - for ( var i = 0, l = checkSet.length; i < l; i++ ) { - var elem = checkSet[i]; - if ( elem ) { - if ( sibDir && elem.nodeType === 1 ) { - elem.sizcache = doneName; - elem.sizset = i; - } - elem = elem[dir]; - var match = false; + var rect = element.getBoundingClientRect(), + docEl = document.documentElement; + return new Element.Offset(rect.left - docEl.clientLeft, + rect.top - docEl.clientTop); + }, - while ( elem ) { - if ( elem.sizcache === doneName ) { - match = checkSet[elem.sizset]; - break; - } + positionedOffset: function(element) { + element = $(element); + var parent = element.getOffsetParent(); + if (isDetached(element)) return new Element.Offset(0, 0); - if ( elem.nodeType === 1 ) { - if ( !isXML ) { - elem.sizcache = doneName; - elem.sizset = i; - } - if ( typeof cur !== "string" ) { - if ( elem === cur ) { - match = true; - break; - } - - } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { - match = elem; - break; - } - } - - elem = elem[dir]; - } + if (element.offsetParent && + element.offsetParent.nodeName.toUpperCase() === 'HTML') { + return positionedOffset(element); + } - checkSet[i] = match; - } - } -} + var eOffset = element.viewportOffset(), + pOffset = isBody(parent) ? viewportOffset(parent) : + parent.viewportOffset(); + var retOffset = eOffset.relativeTo(pOffset); -var contains = document.compareDocumentPosition ? function(a, b){ - return a.compareDocumentPosition(b) & 16; -} : function(a, b){ - return a !== b && (a.contains ? a.contains(b) : true); -}; + var layout = element.getLayout(); + var top = retOffset.top - layout.get('margin-top'); + var left = retOffset.left - layout.get('margin-left'); -var isXML = function(elem){ - return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || - !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; + return new Element.Offset(left, top); + } + }); + } +})(); +window.$$ = function() { + var expression = $A(arguments).join(', '); + return Prototype.Selector.select(expression, document); }; -var posProcess = function(selector, context){ - var tmpSet = [], later = "", match, - root = context.nodeType ? [context] : context; - - while ( (match = Expr.match.PSEUDO.exec( selector )) ) { - later += match[0]; - selector = selector.replace( Expr.match.PSEUDO, "" ); - } - - selector = Expr.relative[selector] ? selector + "*" : selector; - - for ( var i = 0, l = root.length; i < l; i++ ) { - Sizzle( selector, root[i], tmpSet ); - } +Prototype.Selector = (function() { - return Sizzle.filter( later, tmpSet ); -}; + function select() { + throw new Error('Method "Prototype.Selector.select" must be defined.'); + } + function match() { + throw new Error('Method "Prototype.Selector.match" must be defined.'); + } -window.Sizzle = Sizzle; + function find(elements, expression, index) { + index = index || 0; + var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; -})(); + for (i = 0; i < length; i++) { + if (match(elements[i], expression) && index == matchIndex++) { + return Element.extend(elements[i]); + } + } + } -Prototype.Selector = (function(engine) { - function extend(elements) { + function extendElements(elements) { for (var i = 0, length = elements.length; i < length; i++) { Element.extend(elements[i]); } return elements; } - function select(selector, scope) { - return extend(engine(selector, scope || document)); - } - function match(element, selector) { - return engine.matches(selector, [element]).length == 1; - } + var K = Prototype.K; return { - engine: engine, - select: select, - match: match + select: select, + match: match, + find: find, + extendElements: (Element.extend === K) ? K : extendElements, + extendElement: Element.extend }; -})(Sizzle); - -window.Sizzle = Prototype._original_property; -delete Prototype._original_property; +})(); +Prototype._original_property = window.Sizzle; +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ -(function() { +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; - function toDecimal(pctString) { - var match = pctString.match(/^(\d+)%?$/i); - if (!match) return null; - return (Number(match[1]) / 100); - } +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); - function getPixelValue(value, property) { - if (Object.isElement(value)) { - element = value; - value = element.getStyle(property); - } - if (value === null) { - return null; - } +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; - if ((/^\d+(\.\d+)?(px)?$/i).test(value)) { - return window.parseFloat(value); - } + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } - if (/\d/.test(value) && element.runtimeStyle) { - var style = element.style.left, rStyle = element.runtimeStyle.left; - element.runtimeStyle.left = element.currentStyle.left; - element.style.left = value || 0; - value = element.style.pixelLeft; - element.style.left = style; - element.runtimeStyle.left = rStyle; + if ( !selector || typeof selector !== "string" ) { + return results; + } - return value; - } + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; - if (value.include('%')) { - var decimal = toDecimal(value); - var whole; - if (property.include('left') || property.include('right') || - property.include('width')) { - whole = $(element.parentNode).measure('width'); - } else if (property.include('top') || property.include('bottom') || - property.include('height')) { - whole = $(element.parentNode).measure('height'); - } + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; - return whole * decimal; - } + parts.push( m[1] ); - return 0; - } + if ( m[2] ) { + extra = m[3]; + break; + } + } - function toCSSPixels(number) { - if (Object.isString(number) && number.endsWith('px')) { - return number; - } - return number + 'px'; - } + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); - function isDisplayed(element) { - var originalElement = element; - while (element && element.parentNode) { - var display = element.getStyle('display'); - if (display === 'none') { - return false; - } - element = $(element.parentNode); - } - return true; - } + while ( parts.length ) { + selector = parts.shift(); - var hasLayout = Prototype.K; - if ('currentStyle' in document.documentElement) { - hasLayout = function(element) { - if (!element.currentStyle.hasLayout) { - element.style.zoom = 1; - } - return element; - }; - } + if ( Expr.relative[ selector ] ) + selector += parts.shift(); - function cssNameFor(key) { - if (key.includes('border')) return key + '-width'; - return key; - } + set = posProcess( selector, set ); + } + } + } else { + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } - Element.Layout = Class.create(Hash, { - initialize: function($super, element, preCompute) { - $super(); - this.element = $(element); + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; - Element.Layout.PROPERTIES.each( function(property) { - this._set(property, null); - }, this); + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } - if (preCompute) { - this._preComputing = true; - this._begin(); - Element.Layout.PROPERTIES.each( this._compute, this ); - this._end(); - this._preComputing = false; - } - }, + while ( parts.length ) { + var cur = parts.pop(), pop = cur; - _set: function(property, value) { - return Hash.prototype.set.call(this, property, value); - }, + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } - set: function(property, value) { - throw "Properties of Element.Layout are read-only."; - }, + if ( pop == null ) { + pop = context; + } - get: function($super, property) { - var value = $super(property); - return value === null ? this._compute(property) : value; - }, + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } - _begin: function() { - if (this._prepared) return; - - var element = this.element; - if (isDisplayed(element)) { - this._prepared = true; - return; - } - - var originalStyles = { - position: element.style.position || '', - width: element.style.width || '', - visibility: element.style.visibility || '', - display: element.style.display || '' - }; - - element.store('prototype_original_styles', originalStyles); - - var position = element.getStyle('position'), - width = element.getStyle('width'); - - element.setStyle({ - position: 'absolute', - visibility: 'hidden', - display: 'block' - }); - - var positionedWidth = element.getStyle('width'); + if ( !checkSet ) { + checkSet = set; + } - var newWidth; - if (width && (positionedWidth === width)) { - newWidth = getPixelValue(width); - } else if (width && (position === 'absolute' || position === 'fixed')) { - newWidth = getPixelValue(width); - } else { - var parent = element.parentNode, pLayout = $(parent).getLayout(); + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } - newWidth = pLayout.get('width') - - this.get('margin-left') - - this.get('border-left') - - this.get('padding-left') - - this.get('padding-right') - - this.get('border-right') - - this.get('margin-right'); - } + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } - element.setStyle({ width: newWidth + 'px' }); + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } - this._prepared = true; - }, + return results; +}; - _end: function() { - var element = this.element; - var originalStyles = element.retrieve('prototype_original_styles'); - element.store('prototype_original_styles', null); - element.setStyle(originalStyles); - this._prepared = false; - }, +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); - _compute: function(property) { - var COMPUTATIONS = Element.Layout.COMPUTATIONS; - if (!(property in COMPUTATIONS)) { - throw "Property not found."; - } - return this._set(property, COMPUTATIONS[property].call(this, this.element)); - }, + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } - toCSS: function() { - var args = $A(arguments); - var keys = (args.length === 0) ? Element.Layout.PROPERTIES : - args.join(' ').split(' '); - var css = {}; - keys.each( function(key) { - if (!Element.Layout.PROPERTIES.include(key)) return; - if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; + return results; +}; - var value = this.get(key); - if (value) css[cssNameFor(key)] = value + 'px'; - }); - return css; - }, +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; - inspect: function() { - return "#"; - } - }); +Sizzle.find = function(expr, context, isXML){ + var set, match; - Object.extend(Element.Layout, { - PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), + if ( !expr ) { + return []; + } - COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; - COMPUTATIONS: { - 'height': function(element) { - if (!this._preComputing) this._begin(); + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); - var bHeight = this.get('border-box-height'); - if (bHeight <= 0) return 0; + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } - var bTop = this.get('border-top'), - bBottom = this.get('border-bottom'); + if ( !set ) { + set = context.getElementsByTagName("*"); + } - var pTop = this.get('padding-top'), - pBottom = this.get('padding-bottom'); + return {set: set, expr: expr}; +}; - if (!this._preComputing) this._end(); +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); - return bHeight - bTop - bBottom - pTop - pBottom; - }, + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; - 'width': function(element) { - if (!this._preComputing) this._begin(); + if ( curLoop == result ) { + result = []; + } - var bWidth = this.get('border-box-width'); - if (bWidth <= 0) return 0; + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); - var bLeft = this.get('border-left'), - bRight = this.get('border-right'); + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } - var pLeft = this.get('padding-left'), - pRight = this.get('padding-right'); + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; - if (!this._preComputing) this._end(); + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } - return bWidth - bLeft - bRight - pLeft - pRight; - }, + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } - 'padding-box-height': function(element) { - var height = this.get('height'), - pTop = this.get('padding-top'), - pBottom = this.get('padding-bottom'); + expr = expr.replace( Expr.match[ type ], "" ); - return height + pTop + pBottom; - }, + if ( !anyFound ) { + return []; + } - 'padding-box-width': function(element) { - var width = this.get('width'), - pLeft = this.get('padding-left'), - pRight = this.get('padding-right'); + break; + } + } + } - return width + pLeft + pRight; - }, + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } - 'border-box-height': function(element) { - return element.offsetHeight; - }, + old = expr; + } - 'border-box-width': function(element) { - return element.offsetWidth; - }, + return curLoop; +}; - 'margin-box-height': function(element) { - var bHeight = this.get('border-box-height'), - mTop = this.get('margin-top'), - mBottom = this.get('margin-bottom'); +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; - if (bHeight <= 0) return 0; + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } - return bHeight + mTop + mBottom; - }, + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} - 'margin-box-width': function(element) { - var bWidth = this.get('border-box-width'), - mLeft = this.get('margin-left'), - mRight = this.get('margin-right'); + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } - if (bWidth <= 0) return 0; + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; - return bWidth + mLeft + mRight; - }, + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); - 'top': function(element) { - var offset = element.positionedOffset(); - return offset.top; - }, + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } - 'bottom': function(element) { - var offset = element.positionedOffset(), - parent = element.getOffsetParent(), - pHeight = parent.measure('height'); + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; - var mHeight = this.get('border-box-height'); + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } - return pHeight - mHeight - offset.top; - }, + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; - 'left': function(element) { - var offset = element.positionedOffset(); - return offset.left; - }, + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } - 'right': function(element) { - var offset = element.positionedOffset(), - parent = element.getOffsetParent(), - pWidth = parent.measure('width'); + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); - var mWidth = this.get('border-box-width'); + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } - return pWidth - mWidth - offset.left; - }, + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; - 'padding-top': function(element) { - return getPixelValue(element, 'paddingTop'); - }, + if ( isXML ) { + return match; + } - 'padding-bottom': function(element) { - return getPixelValue(element, 'paddingBottom'); - }, + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } - 'padding-left': function(element) { - return getPixelValue(element, 'paddingLeft'); - }, + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; - 'padding-right': function(element) { - return getPixelValue(element, 'paddingRight'); - }, +var origPOS = Expr.match.POS; - 'border-top': function(element) { - return Object.isNumber(element.clientTop) ? element.clientTop : - getPixelValue(element, 'borderTopWidth'); - }, +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} - 'border-bottom': function(element) { - return Object.isNumber(element.clientBottom) ? element.clientBottom : - getPixelValue(element, 'borderBottomWidth'); - }, +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); - 'border-left': function(element) { - return Object.isNumber(element.clientLeft) ? element.clientLeft : - getPixelValue(element, 'borderLeftWidth'); - }, + if ( results ) { + results.push.apply( results, array ); + return results; + } - 'border-right': function(element) { - return Object.isNumber(element.clientRight) ? element.clientRight : - getPixelValue(element, 'borderRightWidth'); - }, + return array; +}; - 'margin-top': function(element) { - return getPixelValue(element, 'marginTop'); - }, +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); - 'margin-bottom': function(element) { - return getPixelValue(element, 'marginBottom'); - }, +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; - 'margin-left': function(element) { - return getPixelValue(element, 'marginLeft'); - }, + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } - 'margin-right': function(element) { - return getPixelValue(element, 'marginRight'); - } - } - }); + return ret; + }; +} - if ('getBoundingClientRect' in document.documentElement) { - Object.extend(Element.Layout.COMPUTATIONS, { - 'right': function(element) { - var parent = hasLayout(element.getOffsetParent()); - var rect = element.getBoundingClientRect(), - pRect = parent.getBoundingClientRect(); +var sortOrder; - return (pRect.right - rect.right).round(); - }, +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } - 'bottom': function(element) { - var parent = hasLayout(element.getOffsetParent()); - var rect = element.getBoundingClientRect(), - pRect = parent.getBoundingClientRect(); + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } - return (pRect.bottom - rect.bottom).round(); - } - }); - } + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } - Element.Offset = Class.create({ - initialize: function(left, top) { - this.left = left.round(); - this.top = top.round(); + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} - this[0] = this.left; - this[1] = this.top; - }, +(function(){ + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; - relativeTo: function(offset) { - return new Element.Offset( - this.left - offset.left, - this.top - offset.top - ); - }, + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); - inspect: function() { - return "#".interpolate(this); - }, + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; - toString: function() { - return "[#{left}, #{top}]".interpolate(this); - }, + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } - toArray: function() { - return [this.left, this.top]; - } - }); + root.removeChild( form ); + root = form = null; // release memory in IE +})(); - function getLayout(element, preCompute) { - return new Element.Layout(element, preCompute); - } +(function(){ - function measure(element, property) { - return $(element).getLayout().get(property); - } + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); - function getDimensions(element) { - var layout = $(element).getLayout(); - return { - width: layout.get('width'), - height: layout.get('height') - }; - } + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); - function getOffsetParent(element) { - if (isDetached(element)) return $(document.body); + if ( match[1] === "*" ) { + var tmp = []; - var isInline = (Element.getStyle(element, 'display') === 'inline'); - if (!isInline && element.offsetParent) return $(element.offsetParent); - if (element === document.body) return $(element); + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } - while ((element = element.parentNode) && element !== document.body) { - if (Element.getStyle(element, 'position') !== 'static') { - return (element.nodeName === 'HTML') ? $(document.body) : $(element); - } - } + results = tmp; + } - return $(document.body); - } + return results; + }; + } + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } - function cumulativeOffset(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return new Element.Offset(valueL, valueT); - } + div = null; // release memory in IE +})(); - function positionedOffset(element) { - var layout = element.getLayout(); +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

"; - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (isBody(element)) break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } - valueL -= layout.get('margin-top'); - valueT -= layout.get('margin-left'); + Sizzle = function(query, context, extra, seed){ + context = context || document; - return new Element.Offset(valueL, valueT); - } + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } - function cumulativeScrollOffset(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return new Element.Offset(valueL, valueT); - } + return oldSizzle(query, context, extra, seed); + }; - function viewportOffset(forElement) { - var valueT = 0, valueL = 0, docBody = document.body; + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == docBody && - Element.getStyle(element, 'position') == 'absolute') break; - } while (element = element.offsetParent); + div = null; // release memory in IE +})(); - element = forElement; - do { - if (element != docBody) { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - return new Element.Offset(valueL, valueT); - } +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
"; - function absolutize(element) { - element = $(element); + if ( div.getElementsByClassName("e").length === 0 ) + return; - if (Element.getStyle(element, 'position') === 'absolute') { - return element; - } + div.lastChild.className = "e"; - var offsetParent = getOffsetParent(element); - var eOffset = element.viewportOffset(), pOffset = - offsetParent.viewportOffset(); + if ( div.getElementsByClassName("e").length === 1 ) + return; - var offset = eOffset.relativeTo(pOffset); - var layout = element.get('layout'); + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; - element.store('prototype_absolutize_original_styles', { - left: element.getStyle('left'), - top: element.getStyle('top'), - width: element.getStyle('width'), - height: element.getStyle('height') - }); + div = null; // release memory in IE +})(); - element.setStyle({ - position: 'absolute', - top: offset.top + 'px', - left: offset.left + 'px', - width: layout.get('width') + 'px', - height: layout.get('height') + 'px' - }); +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; - return element; - } + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } - function relativize(element) { - element = $(element); - if (Element.getStyle(element, 'position') === 'relative') { - return element; - } + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } - var originalStyles = - element.retrieve('prototype_absolutize_original_styles'); + if ( elem.nodeName === cur ) { + match = elem; + break; + } - if (originalStyles) element.setStyle(originalStyles); - return element; - } + elem = elem[dir]; + } - Element.addMethods({ - getLayout: getLayout, - measure: measure, - getDimensions: getDimensions, - getOffsetParent: getOffsetParent, - cumulativeOffset: cumulativeOffset, - positionedOffset: positionedOffset, - cumulativeScrollOffset: cumulativeScrollOffset, - viewportOffset: viewportOffset, - absolutize: absolutize, - relativize: relativize - }); + checkSet[i] = match; + } + } +} - function isBody(element) { - return element.nodeName.toUpperCase() === 'BODY'; - } +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; - function isDetached(element) { - return element !== document.body && - !Element.descendantOf(element, document.body); - } + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } - if ('getBoundingClientRect' in document.documentElement) { - Element.addMethods({ - viewportOffset: function(element) { - element = $(element); - if (isDetached(element)) return new Element.Offset(0, 0); + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } - var rect = element.getBoundingClientRect(), - docEl = document.documentElement; - return new Element.Offset(rect.left - docEl.clientLeft, - rect.top - docEl.clientTop); - }, + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } - cumulativeOffset: function(element) { - element = $(element); - if (isDetached(element)) return new Element.Offset(0, 0); + elem = elem[dir]; + } - var docOffset = $(document.documentElement).viewportOffset(), - elementOffset = element.viewportOffset(); - return elementOffset.relativeTo(docOffset); - }, + checkSet[i] = match; + } + } +} - positionedOffset: function(element) { - element = $(element); - var parent = element.getOffsetParent(); - if (isDetached(element)) return new Element.Offset(0, 0); +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; - if (element.offsetParent && - element.offsetParent.nodeName.toUpperCase() === 'HTML') { - return positionedOffset(element); - } +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; - var eOffset = element.viewportOffset(), - pOffset = isBody(parent) ? viewportOffset(parent) : - parent.viewportOffset(); - var retOffset = eOffset.relativeTo(pOffset); +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; - var layout = element.getLayout(); - var top = retOffset.top - layout.get('margin-top'); - var left = retOffset.left - layout.get('margin-left'); + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } - return new Element.Offset(left, top); - } - }); - } -})(); -window.$$ = function() { - var expression = $A(arguments).join(', '); - return Prototype.Selector.select(expression, document); -}; + selector = Expr.relative[selector] ? selector + "*" : selector; + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + return Sizzle.filter( later, tmpSet ); +}; +window.Sizzle = Sizzle; +})(); +;(function(engine) { + var extendElements = Prototype.Selector.extendElements; -if (!Prototype.Selector.find) { - Prototype.Selector.find = function(elements, expression, index) { - if (Object.isUndefined(index)) index = 0; - var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; + function select(selector, scope) { + return extendElements(engine(selector, scope || document)); + } - for (i = 0; i < length; i++) { - if (match(elements[i], expression) && index == matchIndex++) { - return Element.extend(elements[i]); - } - } + function match(element, selector) { + return engine.matches(selector, [element]).length == 1; } -} + Prototype.Selector.engine = engine; + Prototype.Selector.select = select; + Prototype.Selector.match = match; +})(Sizzle); + +window.Sizzle = Prototype._original_property; +delete Prototype._original_property; var Form = { reset: function(form) { @@ -5325,7 +5373,7 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { var element = Event.element(event); if (!expression) return element; while (element) { - if (Prototype.Selector.match(element, expression)) { + if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { return Element.extend(element); } element = element.parentNode; @@ -5629,9 +5677,8 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { }, handleEvent: function(event) { - var element = this.selector ? event.findElement(this.selector) : - this.element; - if (element) this.callback.call(element, event, element); + var element = event.findElement(this.selector); + if (element) this.callback.call(this.element, event, element); } }); diff --git a/webinterface/src/web-data/provider.js b/webinterface/src/web-data/provider.js new file mode 100644 index 0000000000..9affaa7d41 --- /dev/null +++ b/webinterface/src/web-data/provider.js @@ -0,0 +1,412 @@ +/** + * AbstractContentProvider + * + * Abstract Class for "AbstractContentProvider" Classes + * A Content handler is a class that provides content for the webpage + * e.g. a list of channels, or a list of recordings and/or is able of + * doing the handling of all events for that content (e.g. deleting a recording) + */ + +var AbstractContentProvider = Class.create({ + /** + * initialize + * Default constructor + * Parameters: + * @tpl - Name of the template to use + * @url - name of the url to use for requests + * @target - target html id for the content + * @onFinished - an array of functions that should be called after "this.show()" has finished + */ + initialize: function(url, showFnc, onFinished){ + this.url = url; + this.request = ''; + this.onFinished = onFinished; + this.show = showFnc; + this.parms = {}; + this.refresh = false; + this.eventsRegistered = false; + }, + + /** + * getXML + * Converts the incoming transport result into a DOM object + * Parameters: + * @transport - the xmlhttp transport object + * + **/ + getXML: function(transport){ + var xmlDoc = ""; + + if(window.ActiveXObject){ // we're on IE + xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async="false"; + xmlDoc.loadXML(transport.responseText); + } else { //we're not on IE + if (!window.google || !google.gears){ + xmlDoc = transport.responseXML; + } else { //no responseXML on gears + xmlDoc = (new DOMParser()).parseFromString(transport.responseText, "text/xml"); + } + } + + return xmlDoc; + }, + + /** + * renderXML + * renders the XML and returns what's required by this.show(); + */ + renderXML: function(xml){ + debug('[AbstractContentProvider] ERROR: renderXML not implemented in derived class!'); + return {}; + }, + + /** + * callback + * The default function that is being called for the onSuccess event of this.load(); + * Parameters: + * @transport - the xmlhttp transport object + **/ + callback: function(transport){ + var data = this.renderXML(this.getXML(transport)); + this.show(data); + }, + + /** + * errorback + * The default function that is being called for the onError event of this.load(); + * Parameters + * @transport - the xmlhttp transport object + */ + errorback: function(transport){ + var notif = "Request failed for: " + transport.request.url + "
Status: " + transport.status + " " + transport.statusText; + notify(notif, false); + }, + + /** + * load + * Calls this.getURL + * Parameters + * @parms - an json object containing {parameter : value} pairs for the request + * @fnc - function to replace this.callback (which is being called @ onSuccess) + */ + load: function(parms, fnc){ + this.parms = parms; + if(fnc !== undefined){ + this.callback = fnc; + } + + this.getUrl(this.url, parms, this.callback.bind(this), this.errorback.bind(this)); + }, + + /** + * getUrl + * creates a new Ajax.Request + * Parameters: + * @url - the url to fetch + * @parms - an json object containing {parameter : value} pairs for the request + * @callback - function to call @ onSuccess; + * @errorback - function to call @ onError; + */ + getUrl: function(url, parms, callback, errorback){ + if (!window.google || !google.gears){ //no gears + try{ + new Ajax.Request(url, + { + parameters: parms, + asynchronous: true, + method: 'GET', + requestHeaders: ['Cache-Control', 'no-cache,no-store', 'Expires', '-1'], + onException: function(o,e){ throw(e); }, + onSuccess: function (transport, json) { + if(callback !== undefined){ + callback(transport); + } + }.bind(this), + onFailure: function(transport){ + if(errorback !== undefined){ + errorback(transport); + } + }.bind(this) +// onComplete: this.requestFinished.bind(this) + }); + } catch(e) { + debug('[AbstractContentProvider.getUrl] Exception: '+ e); + } + } else { //we're on gears! + try{ + url = url + "?" + $H(parms).toQueryString(); + + var request = google.gears.factory.create('beta.httprequest'); + request.open('GET', url); + + + request.onreadystatechange = function(){ + if(request.readyState == 4){ + if(request.status == 200){ + if( callback !== undefined ){ + callback(request); + } + } else { + this.errorback(request); + } + } + }.bind(this); + request.send(); + } catch(e) { + debug('[AbstractContentProvider.getUrl] Exception: '+ e); + } + } + }, + + registerEvents : function(){ + debug('[AbstractContentProvider] WARNING: registerEvents not implemented in derived class!'); + }, + + /** + * finished + * Calls all functions this.onFinished contains this.registerEvents + * Is usually called after this.show() has finished + */ + finished : function(){ + if(!this.eventsRegistered){ + this.registerEvents(); + this.eventsRegistered = true; + } + + if(this.onFinished !== undefined){ + for(var i = 0; i < this.onFinished.length; i++){ + var fnc = this.onFinished[i]; + if(typeof(fnc) === 'function'){ + fnc(); + } + } + } + }, + + /** + * reload + * rexecute this.load() using this.parms and set this.refresh to false + * Parameters: + * @fnc - function to call @ onSuccess (passed through to this.load() ) + */ + reload: function(fnc){ + this.refresh = false; + this.load(this.parms, fnc); + }, + + /** + * simpleResultQuery + * Call any URL that returns a SimpleXMLResult with this.simpleResultCallback for + * @onSuccess + * Parameters: + * @url - the url to call + * @parms - an json object containing {parameter : value} pairs for the request + */ + simpleResultQuery: function(url, parms, callback){ + this.getUrl(url, parms, callback); + }, + + /** + * simpleResultCallback + * Callback for @ onSuccess of this.simpleResultQuery() + * if this.refresh == true this.reload is being called + * Parameters: + * @transport - the xmlhttp transport object + */ + simpleResultCallback: function(transport, callback){ + var result = this.simpleResultRenderXML(this.getXML(transport)); + if(typeof(callback) == "function"){ + callback(result); + } + + if(this.refresh){ + this.reload(); + } + + }, + + /** + * simpleResultRenderXML + * Renders the result of this.simpleResultQuery() and returns an SimpleXMLResult object for it + * Parameters: + * @xml - a DOM object containing the XML to render + */ + simpleResultRenderXML: function(xml){ + var result = new SimpleXMLResult(xml); + return result; + } + + +}); + +/** + * ServiceListProvider + * ContentHandler for service lists. + */ +var ServiceListProvider = Class.create(AbstractContentProvider, { + /** + * initialize + * Parameters: + * @target: the html target id + * @epgp: Instance of ServiceListEpgProvider to show epgnow/next information + * @subsp: Instance of ServiceListSubserviceProvider to show subservices + */ + initialize: function($super, showFnc, epgp, subsp){ + $super(URL.getservices, showFnc ); + }, + + /** + * renderXML + * See the description in AbstractContentProvider + */ + renderXML: function(xml){ + var list = new ServiceList(xml).getArray(); + return {services : list}; + } +}); + +/** + * ServiceListEpgProvider + * Handles EPG now/next for a ServiceListProvider + */ +var ServiceListEpgProvider = Class.create(AbstractContentProvider, { + //Constants + NOW : 'NOW', + NEXT : 'NEXT', + + /** + * initialize + * See the description in AbstractContentProvider + */ + initialize: function($super, showFnc){ + $super(URL.epgnow, showFnc); + this.type = this.NOW; + }, + + /** + * renderXML + * See the description in AbstractContentProvider + */ + renderXML: function(xml){ + var list = new EPGList(xml).getArray(); + return list; + }, + + /** + * callback + * custom callback + * Parameters: + * @transport - xmlhttp transport object + */ + callback: function(transport){ + var data = this.renderXML(this.getXML(transport)); + this.show(data, this.type); + if(this.callbackType !== undefined){ + this.get(this.callbackType); + } + }, + + /** + * getNowNext + * call this.get to show epg-now and epg-next + * Parameters: + * @parms - an json object containing {parameter : value} pairs for the request + */ + getNowNext: function(parms){ + this.parms = parms; + this.get(this.NOW, this.NEXT); + }, + + /** + * get + * Load epg information for type and - if set - callbackType + * (ServiceListEpgProvider.NOW or ServiceListEpgProvider.NEXT) + * Parameters: + * @type - ServiceListEpgProvider.NOW or ServiceListEpgProvider.NEXT + * @callbackType - ServiceListEpgProvider.NOW or ServiceListEpgProvider.NEXT + */ + get: function(type, callbackType){ + this.type = type; + //just in case... don't do it twice... + if(type != callbackType){ + this.callbackType = callbackType; + } + + switch(this.type){ + case this.NOW: + this.url = URL.epgnow; + break; + case this.NEXT: + this.url = URL.epgnext; + break; + } + + this.load(this.parms); + } +}); + +/** + * ServiceListSubserviceProvider + * Handles EPG now/next for a ServiceListProvider + */ +var ServiceListSubserviceProvider = Class.create(AbstractContentProvider, { + /** + * initialize + * See the description in AbstractContentProvider + */ + initialize: function($super, showFnc){ + $super(URL.subservices, showFnc); + }, + + /** + * renderXML + * See the description in AbstractContentProvider + */ + renderXML: function(xml){ + var list = new ServiceList(xml).getArray(); + return list; + } +}); + +/** + * MovieListProvider + * Handles a list of movies including deleting actions + */ +var MovieListProvider = Class.create(AbstractContentProvider, { + /** + * initialize + * See the description in AbstractContentProvider + */ + initialize: function($super, showFnc){ + $super(URL.movielist, showFnc); + }, + + /** + * renderXML + * See the description in AbstractContentProvider + */ + renderXML: function(xml){ + var list = new MovieList(xml).getArray(); + return {movies : list}; + } +}); + +var TimerListProvider = Class.create(AbstractContentProvider, { + /** + * initialize + * See the description in AbstractContentProvider + */ + initialize: function($super, showFnc){ + $super(URL.timerlist, showFnc); + }, + + /** + * renderXML + * See the description in AbstractContentProvider + */ + renderXML: function(xml){ + var list = new TimerList(xml).getArray(); + return {timer : list}; + } +}); \ No newline at end of file diff --git a/webinterface/src/web-data/tpl/default/index.html b/webinterface/src/web-data/tpl/default/index.html index 6663b48a66..10801d5f77 100644 --- a/webinterface/src/web-data/tpl/default/index.html +++ b/webinterface/src/web-data/tpl/default/index.html @@ -13,7 +13,7 @@ - + @@ -26,9 +26,11 @@ - - + + + +