/* Prototype JavaScript framework, version 1.5.1.1 * (c) 2005-2007 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/ * /*--------------------------------------------------------------------------*/ var Prototype = { Version: '1.5.1.1', Browser: { IE: !!(window.attachEvent && !window.opera), Opera: !!window.opera, WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 }, BrowserFeatures: { XPath: !!document.evaluate, ElementExtensions: !!window.HTMLElement, SpecificElementExtensions: (document.createElement('div').__proto__ !== document.createElement('form').__proto__) }, ScriptFragment: ']*>([\\S\\s]*?)<\/script>', JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, emptyFunction: function() { }, K: function(x) { return x } } var Class = { create: function() { return function() { this.initialize.apply(this, arguments); } } } var Abstract = new Object(); Object.extend = function(destination, source) { for (var property in source) { destination[property] = source[property]; } return destination; } Object.extend(Object, { inspect: function(object) { try { if (object === undefined) return 'undefined'; if (object === null) return 'null'; return object.inspect ? object.inspect() : object.toString(); } catch (e) { if (e instanceof RangeError) return '...'; throw e; } }, toJSON: function(object) { var type = typeof object; switch(type) { case 'undefined': case 'function': case 'unknown': return; case 'boolean': return object.toString(); } if (object === null) return 'null'; if (object.toJSON) return object.toJSON(); if (object.ownerDocument === document) return; var results = []; for (var property in object) { var value = Object.toJSON(object[property]); if (value !== undefined) results.push(property.toJSON()+': '+value); } return '{'+results.join(', ')+'}'; }, keys: function(object) { var keys = []; for (var property in object) keys.push(property); return keys; }, values: function(object) { var values = []; for (var property in object) values.push(object[property]); return values; }, clone: function(object) { return Object.extend({}, object); } }); Function.prototype.bind = function() { var __method = this, args = $A(arguments), object = args.shift(); return function() { return __method.apply(object, args.concat($A(arguments))); } } Function.prototype.bindAsEventListener = function(object) { var __method = this, args = $A(arguments), object = args.shift(); return function(event) { return __method.apply(object, [event || window.event].concat(args)); } } Object.extend(Number.prototype, { toColorPart: function() { return this.toPaddedString(2, 16); }, succ: function() { return this+1; }, times: function(iterator) { $R(0, this, true).each(iterator); return this; }, toPaddedString: function(length, radix) { var string = this.toString(radix || 10); return '0'.times(length - string.length)+string; }, toJSON: function() { return isFinite(this) ? this.toString() : 'null'; } }); Date.prototype.toJSON = function() { return '"'+this.getFullYear()+'-'+ (this.getMonth()+1).toPaddedString(2)+'-'+ this.getDate().toPaddedString(2)+'T'+ this.getHours().toPaddedString(2)+':'+ this.getMinutes().toPaddedString(2)+':'+ this.getSeconds().toPaddedString(2)+'"'; }; var Try = { these: function() { var returnValue; for (var i = 0, length = arguments.length; i < length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); break; } catch (e) {} } return returnValue; } } /*--------------------------------------------------------------------------*/ var PeriodicalExecuter = Class.create(); PeriodicalExecuter.prototype = { initialize: function(callback, frequency) { this.callback = callback; this.frequency = frequency; this.currentlyExecuting = false; this.registerCallback(); }, registerCallback: function() { this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, stop: function() { if (!this.timer) return; clearInterval(this.timer); this.timer = null; }, onTimerEvent: function() { if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; this.callback(this); } finally { this.currentlyExecuting = false; } } } } Object.extend(String, { interpret: function(value) { return value == null ? '' : String(value); }, specialChar: { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\\': '\\\\' } }); Object.extend(String.prototype, { gsub: function(pattern, replacement) { var result = '', source = this, match; replacement = arguments.callee.prepareReplacement(replacement); while (source.length > 0) { if (match = source.match(pattern)) { result+= source.slice(0, match.index); result+= String.interpret(replacement(match)); source = source.slice(match.index+match[0].length); } else { result+= source, source = ''; } } return result; }, sub: function(pattern, replacement, count) { replacement = this.gsub.prepareReplacement(replacement); count = count === undefined ? 1 : count; return this.gsub(pattern, function(match) { if (--count < 0) return match[0]; return replacement(match); }); }, scan: function(pattern, iterator) { this.gsub(pattern, iterator); return this; }, truncate: function(length, truncation) { length = length || 30; truncation = truncation === undefined ? '...' : truncation; return this.length > length ? this.slice(0, length - truncation.length)+truncation : this; }, strip: function() { return this.replace(/^\s+/, '').replace(/\s+$/, ''); }, stripTags: function() { return this.replace(/<\/?[^>]+>/gi, ''); }, stripScripts: function() { return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); }, extractScripts: function() { var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); }, evalScripts: function() { return this.extractScripts().map(function(script) { return eval(script) }); }, escapeHTML: function() { var self = arguments.callee; self.text.data = this; return self.div.innerHTML; }, unescapeHTML: function() { var div = document.createElement('div'); div.innerHTML = this.stripTags(); return div.childNodes[0] ? (div.childNodes.length > 1 ? $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : div.childNodes[0].nodeValue) : ''; }, toQueryParams: function(separator) { var match = this.strip().match(/([^?#]*)(#.*)?$/); if (!match) return {}; return match[1].split(separator || '&').inject({}, function(hash, pair) { if ((pair = pair.split('='))[0]) { var key = decodeURIComponent(pair.shift()); var value = pair.length > 1 ? pair.join('=') : pair[0]; if (value != undefined) value = decodeURIComponent(value); if (key in hash) { if (hash[key].constructor != Array) hash[key] = [hash[key]]; hash[key].push(value); } else hash[key] = value; } return hash; }); }, toArray: function() { return this.split(''); }, succ: function() { return this.slice(0, this.length - 1)+ String.fromCharCode(this.charCodeAt(this.length - 1)+1); }, times: function(count) { var result = ''; for (var i = 0; i < count; i++) result+= this; return result; }, camelize: function() { var parts = this.split('-'), len = parts.length; if (len == 1) return parts[0]; var camelized = this.charAt(0) == '-' ? parts[0].charAt(0).toUpperCase()+parts[0].substring(1) : parts[0]; for (var i = 1; i < len; i++) camelized+= parts[i].charAt(0).toUpperCase()+parts[i].substring(1); return camelized; }, capitalize: function() { return this.charAt(0).toUpperCase()+this.substring(1).toLowerCase(); }, underscore: function() { return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); }, dasherize: function() { return this.gsub(/_/,'-'); }, inspect: function(useDoubleQuotes) { var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { var character = String.specialChar[match[0]]; return character ? character : '\\u00'+match[0].charCodeAt().toPaddedString(2, 16); }); if (useDoubleQuotes) return '"'+escapedString.replace(/"/g, '\\"')+'"'; return "'"+escapedString.replace(/'/g, '\\\'')+"'"; }, toJSON: function() { return this.inspect(true); }, unfilterJSON: function(filter) { return this.sub(filter || Prototype.JSONFilter, '#{1}'); }, isJSON: function() { var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); }, evalJSON: function(sanitize) { var json = this.unfilterJSON(); try { if (!sanitize || json.isJSON()) return eval('('+json+')'); } catch (e) { } throw new SyntaxError('Badly formed JSON string: '+this.inspect()); }, include: function(pattern) { return this.indexOf(pattern) > -1; }, startsWith: function(pattern) { return this.indexOf(pattern) === 0; }, endsWith: function(pattern) { var d = this.length - pattern.length; return d >= 0 && this.lastIndexOf(pattern) === d; }, empty: function() { return this == ''; }, blank: function() { return /^\s*$/.test(this); } }); if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { escapeHTML: function() { return this.replace(/&/g,'&').replace(//g,'>'); }, unescapeHTML: function() { return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); } }); String.prototype.gsub.prepareReplacement = function(replacement) { if (typeof replacement == 'function') return replacement; var template = new Template(replacement); return function(match) { return template.evaluate(match) }; } String.prototype.parseQuery = String.prototype.toQueryParams; Object.extend(String.prototype.escapeHTML, { div: document.createElement('div'), text: document.createTextNode('') }); with (String.prototype.escapeHTML) div.appendChild(text); var Template = Class.create(); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; Template.prototype = { initialize: function(template, pattern) { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { return this.template.gsub(this.pattern, function(match) { var before = match[1]; if (before == '\\') return match[2]; return before+String.interpret(object[match[3]]); }); } } var $break = {}, $continue = new Error('"throw $continue" is deprecated, use "return" instead'); var Enumerable = { each: function(iterator) { var index = 0; try { this._each(function(value) { iterator(value, index++); }); } catch (e) { if (e != $break) throw e; } return this; }, eachSlice: function(number, iterator) { var index = -number, slices = [], array = this.toArray(); while ((index+= number) < array.length) slices.push(array.slice(index, index+number)); return slices.map(iterator); }, all: function(iterator) { var result = true; this.each(function(value, index) { result = result && !!(iterator || Prototype.K)(value, index); if (!result) throw $break; }); return result; }, any: function(iterator) { var result = false; this.each(function(value, index) { if (result = !!(iterator || Prototype.K)(value, index)) throw $break; }); return result; }, collect: function(iterator) { var results = []; this.each(function(value, index) { results.push((iterator || Prototype.K)(value, index)); }); return results; }, detect: function(iterator) { var result; this.each(function(value, index) { if (iterator(value, index)) { result = value; throw $break; } }); return result; }, findAll: function(iterator) { var results = []; this.each(function(value, index) { if (iterator(value, index)) results.push(value); }); return results; }, grep: function(pattern, iterator) { var results = []; this.each(function(value, index) { var stringValue = value.toString(); if (stringValue.match(pattern)) results.push((iterator || Prototype.K)(value, index)); }) return results; }, include: function(object) { var found = false; this.each(function(value) { if (value == object) { found = true; throw $break; } }); return found; }, inGroupsOf: function(number, fillWith) { fillWith = fillWith === undefined ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); }, inject: function(memo, iterator) { this.each(function(value, index) { memo = iterator(memo, value, index); }); return memo; }, invoke: function(method) { var args = $A(arguments).slice(1); return this.map(function(value) { return value[method].apply(value, args); }); }, max: function(iterator) { var result; this.each(function(value, index) { value = (iterator || Prototype.K)(value, index); if (result == undefined || value >= result) result = value; }); return result; }, min: function(iterator) { var result; this.each(function(value, index) { value = (iterator || Prototype.K)(value, index); if (result == undefined || value < result) result = value; }); return result; }, partition: function(iterator) { var trues = [], falses = []; this.each(function(value, index) { ((iterator || Prototype.K)(value, index) ? trues : falses).push(value); }); return [trues, falses]; }, pluck: function(property) { var results = []; this.each(function(value, index) { results.push(value[property]); }); return results; }, reject: function(iterator) { var results = []; this.each(function(value, index) { if (!iterator(value, index)) results.push(value); }); return results; }, sortBy: function(iterator) { return this.map(function(value, index) { return {value: value, criteria: iterator(value, index)}; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck('value'); }, toArray: function() { return this.map(); }, zip: function() { var iterator = Prototype.K, args = $A(arguments); if (typeof args.last() == 'function') iterator = args.pop(); var collections = [this].concat(args).map($A); return this.map(function(value, index) { return iterator(collections.pluck(index)); }); }, size: function() { return this.toArray().length; }, inspect: function() { return '#'; } } Object.extend(Enumerable, { map: Enumerable.collect, find: Enumerable.detect, select: Enumerable.findAll, member: Enumerable.include, entries: Enumerable.toArray }); var $A = Array.from = function(iterable) { if (!iterable) return []; if (iterable.toArray) { return iterable.toArray(); } else { var results = []; for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]); return results; } } if (Prototype.Browser.WebKit) { $A = Array.from = function(iterable) { if (!iterable) return []; if (!(typeof iterable == 'function' && iterable == '[object NodeList]') && iterable.toArray) { return iterable.toArray(); } else { var results = []; for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]); return results; } } } Object.extend(Array.prototype, Enumerable); if (!Array.prototype._reverse) Array.prototype._reverse = Array.prototype.reverse; Object.extend(Array.prototype, { _each: function(iterator) { for (var i = 0, length = this.length; i < length; i++) iterator(this[i]); }, clear: function() { this.length = 0; return this; }, first: function() { return this[0]; }, last: function() { return this[this.length - 1]; }, compact: function() { return this.select(function(value) { return value != null; }); }, flatten: function() { return this.inject([], function(array, value) { return array.concat(value && value.constructor == Array ? value.flatten() : [value]); }); }, without: function() { var values = $A(arguments); return this.select(function(value) { return !values.include(value); }); }, indexOf: function(object) { for (var i = 0, length = this.length; i < length; i++) if (this[i] == object) return i; return -1; }, reverse: function(inline) { return (inline !== false ? this : this.toArray())._reverse(); }, reduce: function() { return this.length > 1 ? this : this[0]; }, uniq: function(sorted) { return this.inject([], function(array, value, index) { if (0 == index || (sorted ? array.last() != value : !array.include(value))) array.push(value); return array; }); }, clone: function() { return [].concat(this); }, size: function() { return this.length; }, inspect: function() { return '['+this.map(Object.inspect).join(', ')+']'; }, toJSON: function() { var results = []; this.each(function(object) { var value = Object.toJSON(object); if (value !== undefined) results.push(value); }); return '['+results.join(', ')+']'; } }); Array.prototype.toArray = Array.prototype.clone; function $w(string) { string = string.strip(); return string ? string.split(/\s+/) : []; } if (Prototype.Browser.Opera){ Array.prototype.concat = function() { var array = []; for (var i = 0, length = this.length; i < length; i++) array.push(this[i]); for (var i = 0, length = arguments.length; i < length; i++) { if (arguments[i].constructor == Array) { for (var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++) array.push(arguments[i][j]); } else { array.push(arguments[i]); } } return array; } } var Hash = function(object) { if (object instanceof Hash) this.merge(object); else Object.extend(this, object || {}); }; Object.extend(Hash, { toQueryString: function(obj) { var parts = []; parts.add = arguments.callee.addPair; this.prototype._each.call(obj, function(pair) { if (!pair.key) return; var value = pair.value; if (value && typeof value == 'object') { if (value.constructor == Array) value.each(function(value) { parts.add(pair.key, value); }); return; } parts.add(pair.key, value); }); return parts.join('&'); }, toJSON: function(object) { var results = []; this.prototype._each.call(object, function(pair) { var value = Object.toJSON(pair.value); if (value !== undefined) results.push(pair.key.toJSON()+': '+value); }); return '{'+results.join(', ')+'}'; } }); Hash.toQueryString.addPair = function(key, value, prefix) { key = encodeURIComponent(key); if (value === undefined) this.push(key); else this.push(key+'='+(value == null ? '' : encodeURIComponent(value))); } Object.extend(Hash.prototype, Enumerable); Object.extend(Hash.prototype, { _each: function(iterator) { for (var key in this) { var value = this[key]; if (value && value == Hash.prototype[key]) continue; var pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } }, keys: function() { return this.pluck('key'); }, values: function() { return this.pluck('value'); }, merge: function(hash) { return $H(hash).inject(this, function(mergedHash, pair) { mergedHash[pair.key] = pair.value; return mergedHash; }); }, remove: function() { var result; for(var i = 0, length = arguments.length; i < length; i++) { var value = this[arguments[i]]; if (value !== undefined){ if (result === undefined) result = value; else { if (result.constructor != Array) result = [result]; result.push(value) } } delete this[arguments[i]]; } return result; }, toQueryString: function() { return Hash.toQueryString(this); }, inspect: function() { return '#'; }, toJSON: function() { return Hash.toJSON(this); } }); function $H(object) { if (object instanceof Hash) return object; return new Hash(object); }; // Safari iterates over shadowed properties if (function() { var i = 0, Test = function(value) { this.key = value }; Test.prototype.key = 'foo'; for (var property in new Test('bar')) i++; return i > 1; }()) Hash.prototype._each = function(iterator) { var cache = []; for (var key in this) { var value = this[key]; if ((value && value == Hash.prototype[key]) || cache.include(key)) continue; cache.push(key); var pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } }; ObjectRange = Class.create(); Object.extend(ObjectRange.prototype, Enumerable); Object.extend(ObjectRange.prototype, { initialize: function(start, end, exclusive) { this.start = start; this.end = end; this.exclusive = exclusive; }, _each: function(iterator) { var value = this.start; while (this.include(value)) { iterator(value); value = value.succ(); } }, include: function(value) { if (value < this.start) return false; if (this.exclusive) return value < this.end; return value <= this.end; } }); var $R = function(start, end, exclusive) { return new ObjectRange(start, end, exclusive); } var Ajax = { getTransport: function() { return Try.these( function() {return new XMLHttpRequest()}, function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Microsoft.XMLHTTP')} ) || false; }, activeRequestCount: 0 } Ajax.Responders = { responders: [], _each: function(iterator) { this.responders._each(iterator); }, register: function(responder) { if (!this.include(responder)) this.responders.push(responder); }, unregister: function(responder) { this.responders = this.responders.without(responder); }, dispatch: function(callback, request, transport, json) { this.each(function(responder) { if (typeof responder[callback] == 'function') { try { responder[callback].apply(responder, [request, transport, json]); } catch (e) {} } }); } }; Object.extend(Ajax.Responders, Enumerable); Ajax.Responders.register({ onCreate: function() { Ajax.activeRequestCount++; }, onComplete: function() { Ajax.activeRequestCount--; } }); Ajax.Base = function() {}; Ajax.Base.prototype = { setOptions: function(options) { this.options = { method: 'post', asynchronous: true, contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', parameters: '' } Object.extend(this.options, options || {}); this.options.method = this.options.method.toLowerCase(); if (typeof this.options.parameters == 'string') this.options.parameters = this.options.parameters.toQueryParams(); } } Ajax.Request = Class.create(); Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; Ajax.Request.prototype = Object.extend(new Ajax.Base(), { _complete: false, initialize: function(url, options) { this.transport = Ajax.getTransport(); this.setOptions(options); this.request(url); }, request: function(url) { this.url = url; this.method = this.options.method; var params = Object.clone(this.options.parameters); if (!['get', 'post'].include(this.method)) { // simulate other verbs over post params['_method'] = this.method; this.method = 'post'; } this.parameters = params; if (params = Hash.toQueryString(params)) { // when GET, append parameters to URL if (this.method == 'get') this.url+= (this.url.include('?') ? '&' : '?')+params; else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) params+= '&_='; } try { if (this.options.onCreate) this.options.onCreate(this.transport); Ajax.Responders.dispatch('onCreate', this, this.transport); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); if (this.options.asynchronous) setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); this.body = this.method == 'post' ? (this.options.postBody || params) : null; this.transport.send(this.body); /* Force Firefox to handle ready state 4 for synchronous requests */ if (!this.options.asynchronous && this.transport.overrideMimeType) this.onStateChange(); } catch (e) { this.dispatchException(e); } }, onStateChange: function() { var readyState = this.transport.readyState; if (readyState > 1 && !((readyState == 4) && this._complete)) this.respondToReadyState(this.transport.readyState); }, setRequestHeaders: function() { var headers = { 'X-Requested-With': 'XMLHttpRequest', 'X-Prototype-Version': Prototype.Version, 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' }; if (this.method == 'post') { headers['Content-type'] = this.options.contentType+ (this.options.encoding ? '; charset='+this.options.encoding : ''); /* Force "Connection: close" for older Mozilla browsers to work * around a bug where XMLHttpRequest sends an incorrect * Content-length header. See Mozilla Bugzilla #246651. */ if (this.transport.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) headers['Connection'] = 'close'; } // user-defined headers if (typeof this.options.requestHeaders == 'object') { var extras = this.options.requestHeaders; if (typeof extras.push == 'function') for (var i = 0, length = extras.length; i < length; i+= 2) headers[extras[i]] = extras[i+1]; else $H(extras).each(function(pair) { headers[pair.key] = pair.value }); } for (var name in headers) this.transport.setRequestHeader(name, headers[name]); }, success: function() { return !this.transport.status || (this.transport.status >= 200 && this.transport.status < 300); }, respondToReadyState: function(readyState) { var state = Ajax.Request.Events[readyState]; var transport = this.transport, json = this.evalJSON(); if (state == 'Complete') { try { this._complete = true; (this.options['on'+this.transport.status] || this.options['on'+(this.success() ? 'Success' : 'Failure')] || Prototype.emptyFunction)(transport, json); } catch (e) { this.dispatchException(e); } var contentType = this.getHeader('Content-type'); if (contentType && contentType.strip(). match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) this.evalResponse(); } try { (this.options['on'+state] || Prototype.emptyFunction)(transport, json); Ajax.Responders.dispatch('on'+state, this, transport, json); } catch (e) { this.dispatchException(e); } if (state == 'Complete') { // avoid memory leak in MSIE: clean up this.transport.onreadystatechange = Prototype.emptyFunction; } }, getHeader: function(name) { try { return this.transport.getResponseHeader(name); } catch (e) { return null } }, evalJSON: function() { try { var json = this.getHeader('X-JSON'); return json ? json.evalJSON() : null; } catch (e) { return null } }, evalResponse: function() { try { return eval((this.transport.responseText || '').unfilterJSON()); } catch (e) { this.dispatchException(e); } }, dispatchException: function(exception) { (this.options.onException || Prototype.emptyFunction)(this, exception); Ajax.Responders.dispatch('onException', this, exception); } }); Ajax.Updater = Class.create(); Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { initialize: function(container, url, options) { this.container = { success: (container.success || container), failure: (container.failure || (container.success ? null : container)) } this.transport = Ajax.getTransport(); this.setOptions(options); var onComplete = this.options.onComplete || Prototype.emptyFunction; this.options.onComplete = (function(transport, param) { this.updateContent(); onComplete(transport, param); }).bind(this); this.request(url); }, updateContent: function() { var receiver = this.container[this.success() ? 'success' : 'failure']; var response = this.transport.responseText; if (!this.options.evalScripts) response = response.stripScripts(); if (receiver = $(receiver)) { if (this.options.insertion) new this.options.insertion(receiver, response); else receiver.update(response); } if (this.success()) { if (this.onComplete) setTimeout(this.onComplete.bind(this), 10); } } }); Ajax.PeriodicalUpdater = Class.create(); Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { initialize: function(container, url, options) { this.setOptions(options); this.onComplete = this.options.onComplete; this.frequency = (this.options.frequency || 2); this.decay = (this.options.decay || 1); this.updater = {}; this.container = container; this.url = url; this.start(); }, start: function() { this.options.onComplete = this.updateComplete.bind(this); this.onTimerEvent(); }, stop: function() { this.updater.options.onComplete = undefined; clearTimeout(this.timer); (this.onComplete || Prototype.emptyFunction).apply(this, arguments); }, updateComplete: function(request) { if (this.options.decay) { this.decay = (request.responseText == this.lastText ? this.decay * this.options.decay : 1); this.lastText = request.responseText; } this.timer = setTimeout(this.onTimerEvent.bind(this), this.decay * this.frequency * 1000); }, onTimerEvent: function() { this.updater = new Ajax.Updater(this.container, this.url, this.options); } }); function $(element) { if (arguments.length > 1) { for (var i = 0, elements = [], length = arguments.length; i < length; i++) elements.push($(arguments[i])); return elements; } if (typeof element == 'string') element = document.getElementById(element); return Element.extend(element); } if (Prototype.BrowserFeatures.XPath) { document._getElementsByXPath = function(expression, parentElement) { var results = []; var query = document.evaluate(expression, $(parentElement) || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0, length = query.snapshotLength; i < length; i++) results.push(query.snapshotItem(i)); return results; }; document.getElementsByClassName = function(className, parentElement) { var q = ".//*[contains(concat(' ', @class, ' '), ' "+className+" ')]"; return document._getElementsByXPath(q, parentElement); } } else document.getElementsByClassName = function(className, parentElement) { var children = ($(parentElement) || document.body).getElementsByTagName('*'); var elements = [], child, pattern = new RegExp("(^|\\s)"+className+"(\\s|$)"); for (var i = 0, length = children.length; i < length; i++) { child = children[i]; var elementClassName = child.className; if (elementClassName.length == 0) continue; if (elementClassName == className || elementClassName.match(pattern)) elements.push(Element.extend(child)); } return elements; }; /*--------------------------------------------------------------------------*/ if (!window.Element) var Element = {}; Element.extend = function(element) { var F = Prototype.BrowserFeatures; if (!element || !element.tagName || element.nodeType == 3 || element._extended || F.SpecificElementExtensions || element == window) return element; var methods = {}, tagName = element.tagName, cache = Element.extend.cache, T = Element.Methods.ByTag; // extend methods for all tags (Safari doesn't need this) if (!F.ElementExtensions) { Object.extend(methods, Element.Methods), Object.extend(methods, Element.Methods.Simulated); } // extend methods for specific tags if (T[tagName]) Object.extend(methods, T[tagName]); for (var property in methods) { var value = methods[property]; if (typeof value == 'function' && !(property in element)) element[property] = cache.findOrStore(value); } element._extended = Prototype.emptyFunction; return element; }; Element.extend.cache = { findOrStore: function(value) { return this[value] = this[value] || function() { return value.apply(null, [this].concat($A(arguments))); } } }; Element.Methods = { visible: function(element) { return $(element).style.display != 'none'; }, toggle: function(element) { element = $(element); Element[Element.visible(element) ? 'hide' : 'show'](element); return element; }, hide: function(element) { $(element).style.display = 'none'; return element; }, show: function(element) { $(element).style.display = ''; return element; }, remove: function(element) { element = $(element); element.parentNode.removeChild(element); return element; }, update: function(element, html) { html = typeof html == 'undefined' ? '' : html.toString(); $(element).innerHTML = html.stripScripts(); setTimeout(function() {html.evalScripts()}, 10); return element; }, replace: function(element, html) { element = $(element); html = typeof html == 'undefined' ? '' : html.toString(); if (element.outerHTML) { element.outerHTML = html.stripScripts(); } else { var range = element.ownerDocument.createRange(); range.selectNodeContents(element); element.parentNode.replaceChild( range.createContextualFragment(html.stripScripts()), element); } setTimeout(function() {html.evalScripts()}, 10); return element; }, inspect: function(element) { element = $(element); var result = '<'+element.tagName.toLowerCase(); $H({'id': 'id', 'className': 'class'}).each(function(pair) { var property = pair.first(), attribute = pair.last(); var value = (element[property] || '').toString(); if (value) result+= ' '+attribute+'='+value.inspect(true); }); return result+'>'; }, recursivelyCollect: function(element, property) { element = $(element); var elements = []; while (element = element[property]) if (element.nodeType == 1) elements.push(Element.extend(element)); return elements; }, ancestors: function(element) { return $(element).recursivelyCollect('parentNode'); }, descendants: function(element) { return $A($(element).getElementsByTagName('*')).each(Element.extend); }, firstDescendant: function(element) { element = $(element).firstChild; while (element && element.nodeType != 1) element = element.nextSibling; return $(element); }, immediateDescendants: function(element) { if (!(element = $(element).firstChild)) return []; while (element && element.nodeType != 1) element = element.nextSibling; if (element) return [element].concat($(element).nextSiblings()); return []; }, previousSiblings: function(element) { return $(element).recursivelyCollect('previousSibling'); }, nextSiblings: function(element) { return $(element).recursivelyCollect('nextSibling'); }, siblings: function(element) { element = $(element); return element.previousSiblings().reverse().concat(element.nextSiblings()); }, match: function(element, selector) { if (typeof selector == 'string') selector = new Selector(selector); return selector.match($(element)); }, up: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(element.parentNode); var ancestors = element.ancestors(); return expression ? Selector.findElement(ancestors, expression, index) : ancestors[index || 0]; }, down: function(element, expression, index) { element = $(element); if (arguments.length == 1) return element.firstDescendant(); var descendants = element.descendants(); return expression ? Selector.findElement(descendants, expression, index) : descendants[index || 0]; }, previous: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); var previousSiblings = element.previousSiblings(); return expression ? Selector.findElement(previousSiblings, expression, index) : previousSiblings[index || 0]; }, next: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); var nextSiblings = element.nextSiblings(); return expression ? Selector.findElement(nextSiblings, expression, index) : nextSiblings[index || 0]; }, getElementsBySelector: function() { var args = $A(arguments), element = $(args.shift()); return Selector.findChildElements(element, args); }, getElementsByClassName: function(element, className) { return document.getElementsByClassName(className, element); }, readAttribute: function(element, name) { element = $(element); if (Prototype.Browser.IE) { if (!element.attributes) return null; var t = Element._attributeTranslations; if (t.values[name]) return t.values[name](element, name); if (t.names[name]) name = t.names[name]; var attribute = element.attributes[name]; return attribute ? attribute.nodeValue : null; } return element.getAttribute(name); }, getHeight: function(element) { return $(element).getDimensions().height; }, getWidth: function(element) { return $(element).getDimensions().width; }, classNames: function(element) { return new Element.ClassNames(element); }, hasClassName: function(element, className) { if (!(element = $(element))) return; var elementClassName = element.className; if (elementClassName.length == 0) return false; if (elementClassName == className || elementClassName.match(new RegExp("(^|\\s)"+className+"(\\s|$)"))) return true; return false; }, addClassName: function(element, className) { if (!(element = $(element))) return; Element.classNames(element).add(className); return element; }, removeClassName: function(element, className) { if (!(element = $(element))) return; Element.classNames(element).remove(className); return element; }, toggleClassName: function(element, className) { if (!(element = $(element))) return; Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); return element; }, observe: function() { Event.observe.apply(Event, arguments); return $A(arguments).first(); }, stopObserving: function() { Event.stopObserving.apply(Event, arguments); return $A(arguments).first(); }, // removes whitespace-only text node children cleanWhitespace: function(element) { element = $(element); var node = element.firstChild; while (node) { var nextNode = node.nextSibling; if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) element.removeChild(node); node = nextNode; } return element; }, empty: function(element) { return $(element).innerHTML.blank(); }, descendantOf: function(element, ancestor) { element = $(element), ancestor = $(ancestor); while (element = element.parentNode) if (element == ancestor) return true; return false; }, scrollTo: function(element) { element = $(element); var pos = Position.cumulativeOffset(element); window.scrollTo(pos[0], pos[1]); return element; }, getStyle: function(element, style) { element = $(element); style = style == 'float' ? 'cssFloat' : style.camelize(); var value = element.style[style]; if (!value) { var css = document.defaultView.getComputedStyle(element, null); value = css ? css[style] : null; } if (style == 'opacity') return value ? parseFloat(value) : 1.0; return value == 'auto' ? null : value; }, getOpacity: function(element) { return $(element).getStyle('opacity'); }, setStyle: function(element, styles, camelized) { element = $(element); var elementStyle = element.style; for (var property in styles) if (property == 'opacity') element.setOpacity(styles[property]) else elementStyle[(property == 'float' || property == 'cssFloat') ? (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') : (camelized ? property : property.camelize())] = styles[property]; return element; }, setOpacity: function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }, getDimensions: function(element) { element = $(element); var display = $(element).getStyle('display'); if (display != 'none' && display != null) // Safari bug return {width: element.offsetWidth, height: element.offsetHeight}; // All *Width and *Height properties give 0 on elements with display none, // so enable the element temporarily var els = element.style; var originalVisibility = els.visibility; var originalPosition = els.position; var originalDisplay = els.display; els.visibility = 'hidden'; els.position = 'absolute'; els.display = 'block'; var originalWidth = element.clientWidth; var originalHeight = element.clientHeight; els.display = originalDisplay; els.position = originalPosition; els.visibility = originalVisibility; return {width: originalWidth, height: originalHeight}; }, makePositioned: function(element) { element = $(element); var pos = Element.getStyle(element, 'position'); if (pos == 'static' || !pos) { element._madePositioned = true; element.style.position = 'relative'; // Opera returns the offset relative to the positioning context, when an // element is position relative but top and left have not been defined if (window.opera) { element.style.top = 0; element.style.left = 0; } } return element; }, undoPositioned: function(element) { element = $(element); if (element._madePositioned) { element._madePositioned = undefined; element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = ''; } return element; }, makeClipping: function(element) { element = $(element); if (element._overflow) return element; element._overflow = element.style.overflow || 'auto'; if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') element.style.overflow = 'hidden'; return element; }, undoClipping: function(element) { element = $(element); if (!element._overflow) return element; element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; element._overflow = null; return element; } }; Object.extend(Element.Methods, { childOf: Element.Methods.descendantOf, childElements: Element.Methods.immediateDescendants }); if (Prototype.Browser.Opera) { Element.Methods._getStyle = Element.Methods.getStyle; Element.Methods.getStyle = function(element, style) { switch(style) { case 'left': case 'top': case 'right': case 'bottom': if (Element._getStyle(element, 'position') == 'static') return null; default: return Element._getStyle(element, style); } }; } else if (Prototype.Browser.IE) { Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); var value = element.style[style]; if (!value && element.currentStyle) value = element.currentStyle[style]; if (style == 'opacity') { if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) if (value[1]) return parseFloat(value[1]) / 100; return 1.0; } if (value == 'auto') { if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) return element['offset'+style.capitalize()]+'px'; return null; } return value; }; Element.Methods.setOpacity = function(element, value) { element = $(element); var filter = element.getStyle('filter'), style = element.style; if (value == 1 || value === '') { style.filter = filter.replace(/alpha\([^\)]*\)/gi,''); return element; } else if (value < 0.00001) value = 0; style.filter = filter.replace(/alpha\([^\)]*\)/gi, '')+ 'alpha(opacity='+(value * 100)+')'; return element; }; // IE is missing .innerHTML support for TABLE-related elements Element.Methods.update = function(element, html) { element = $(element); html = typeof html == 'undefined' ? '' : html.toString(); var tagName = element.tagName.toUpperCase(); if (['THEAD','TBODY','TR','TD'].include(tagName)) { var div = document.createElement('div'); switch (tagName) { case 'THEAD': case 'TBODY': div.innerHTML = ''+html.stripScripts()+'
'; depth = 2; break; case 'TR': div.innerHTML = ''+html.stripScripts()+'
'; depth = 3; break; case 'TD': div.innerHTML = '
'+html.stripScripts()+'
'; depth = 4; } $A(element.childNodes).each(function(node) { element.removeChild(node) }); depth.times(function() { div = div.firstChild }); $A(div.childNodes).each(function(node) { element.appendChild(node) }); } else { element.innerHTML = html.stripScripts(); } setTimeout(function() { html.evalScripts() }, 10); return element; } } else if (Prototype.Browser.Gecko) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1) ? 0.999999 : (value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }; } Element._attributeTranslations = { names: { colspan: "colSpan", rowspan: "rowSpan", valign: "vAlign", datetime: "dateTime", accesskey: "accessKey", tabindex: "tabIndex", enctype: "encType", maxlength: "maxLength", readonly: "readOnly", longdesc: "longDesc" }, values: { _getAttr: function(element, attribute) { return element.getAttribute(attribute, 2); }, _flag: function(element, attribute) { return $(element).hasAttribute(attribute) ? attribute : null; }, style: function(element) { return element.style.cssText.toLowerCase(); }, title: function(element) { var node = element.getAttributeNode('title'); return node.specified ? node.nodeValue : null; } } }; (function() { Object.extend(this, { href: this._getAttr, src: this._getAttr, type: this._getAttr, disabled: this._flag, checked: this._flag, readonly: this._flag, multiple: this._flag }); }).call(Element._attributeTranslations.values); Element.Methods.Simulated = { hasAttribute: function(element, attribute) { var t = Element._attributeTranslations, node; attribute = t.names[attribute] || attribute; node = $(element).getAttributeNode(attribute); return node && node.specified; } }; Element.Methods.ByTag = {}; Object.extend(Element, Element.Methods); if (!Prototype.BrowserFeatures.ElementExtensions && document.createElement('div').__proto__) { window.HTMLElement = {}; window.HTMLElement.prototype = document.createElement('div').__proto__; Prototype.BrowserFeatures.ElementExtensions = true; } Element.hasAttribute = function(element, attribute) { if (element.hasAttribute) return element.hasAttribute(attribute); return Element.Methods.Simulated.hasAttribute(element, attribute); }; Element.addMethods = function(methods) { var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; if (!methods) { Object.extend(Form, Form.Methods); Object.extend(Form.Element, Form.Element.Methods); Object.extend(Element.Methods.ByTag, { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), "TEXTAREA": Object.clone(Form.Element.Methods) }); } if (arguments.length == 2) { var tagName = methods; methods = arguments[1]; } if (!tagName) Object.extend(Element.Methods, methods || {}); else { if (tagName.constructor == Array) tagName.each(extend); else extend(tagName); } function extend(tagName) { tagName = tagName.toUpperCase(); if (!Element.Methods.ByTag[tagName]) Element.Methods.ByTag[tagName] = {}; Object.extend(Element.Methods.ByTag[tagName], methods); } function copy(methods, destination, onlyIfAbsent) { onlyIfAbsent = onlyIfAbsent || false; var cache = Element.extend.cache; for (var property in methods) { var value = methods[property]; if (!onlyIfAbsent || !(property in destination)) destination[property] = cache.findOrStore(value); } } function findDOMClass(tagName) { var klass; var trans = { "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": "FrameSet", "IFRAME": "IFrame" }; if (trans[tagName]) klass = 'HTML'+trans[tagName]+'Element'; if (window[klass]) return window[klass]; klass = 'HTML'+tagName+'Element'; if (window[klass]) return window[klass]; klass = 'HTML'+tagName.capitalize()+'Element'; if (window[klass]) return window[klass]; window[klass] = {}; window[klass].prototype = document.createElement(tagName).__proto__; return window[klass]; } if (F.ElementExtensions) { copy(Element.Methods, HTMLElement.prototype); copy(Element.Methods.Simulated, HTMLElement.prototype, true); } if (F.SpecificElementExtensions) { for (var tag in Element.Methods.ByTag) { var klass = findDOMClass(tag); if (typeof klass == "undefined") continue; copy(T[tag], klass.prototype); } } Object.extend(Element, Element.Methods); delete Element.ByTag; }; var Toggle = { display: Element.toggle }; /*--------------------------------------------------------------------------*/ Abstract.Insertion = function(adjacency) { this.adjacency = adjacency; } Abstract.Insertion.prototype = { initialize: function(element, content) { this.element = $(element); this.content = content.stripScripts(); if (this.adjacency && this.element.insertAdjacentHTML) { try { this.element.insertAdjacentHTML(this.adjacency, this.content); } catch (e) { var tagName = this.element.tagName.toUpperCase(); if (['TBODY', 'TR'].include(tagName)) { this.insertContent(this.contentFromAnonymousTable()); } else { throw e; } } } else { this.range = this.element.ownerDocument.createRange(); if (this.initializeRange) this.initializeRange(); this.insertContent([this.range.createContextualFragment(this.content)]); } setTimeout(function() {content.evalScripts()}, 10); }, contentFromAnonymousTable: function() { var div = document.createElement('div'); div.innerHTML = ''+this.content+'
'; return $A(div.childNodes[0].childNodes[0].childNodes); } } var Insertion = new Object(); Insertion.Before = Class.create(); Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { initializeRange: function() { this.range.setStartBefore(this.element); }, insertContent: function(fragments) { fragments.each((function(fragment) { this.element.parentNode.insertBefore(fragment, this.element); }).bind(this)); } }); Insertion.Top = Class.create(); Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { initializeRange: function() { this.range.selectNodeContents(this.element); this.range.collapse(true); }, insertContent: function(fragments) { fragments.reverse(false).each((function(fragment) { this.element.insertBefore(fragment, this.element.firstChild); }).bind(this)); } }); Insertion.Bottom = Class.create(); Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { initializeRange: function() { this.range.selectNodeContents(this.element); this.range.collapse(this.element); }, insertContent: function(fragments) { fragments.each((function(fragment) { this.element.appendChild(fragment); }).bind(this)); } }); Insertion.After = Class.create(); Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { initializeRange: function() { this.range.setStartAfter(this.element); }, insertContent: function(fragments) { fragments.each((function(fragment) { this.element.parentNode.insertBefore(fragment, this.element.nextSibling); }).bind(this)); } }); /*--------------------------------------------------------------------------*/ Element.ClassNames = Class.create(); Element.ClassNames.prototype = { initialize: function(element) { this.element = $(element); }, _each: function(iterator) { this.element.className.split(/\s+/).select(function(name) { return name.length > 0; })._each(iterator); }, set: function(className) { this.element.className = className; }, add: function(classNameToAdd) { if (this.include(classNameToAdd)) return; this.set($A(this).concat(classNameToAdd).join(' ')); }, remove: function(classNameToRemove) { if (!this.include(classNameToRemove)) return; this.set($A(this).without(classNameToRemove).join(' ')); }, toString: function() { return $A(this).join(' '); } }; Object.extend(Element.ClassNames.prototype, Enumerable); /* Portions of the Selector class are derived from Jack Slocum’s DomQuery, * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style * license. Please see http://www.yui-ext.com/ for more information. */ var Selector = Class.create(); Selector.prototype = { initialize: function(expression) { this.expression = expression.strip(); this.compileMatcher(); }, compileMatcher: function() { // Selectors with namespaced attributes can't use the XPath version if (Prototype.BrowserFeatures.XPath && !(/\[[\w-]*?:/).test(this.expression)) return this.compileXPathMatcher(); var e = this.expression, ps = Selector.patterns, h = Selector.handlers, c = Selector.criteria, le, p, m; if (Selector._cache[e]) { this.matcher = Selector._cache[e]; return; } this.matcher = ["this.matcher = function(root) {", "var r = root, h = Selector.handlers, c = false, n;"]; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in ps) { p = ps[i]; if (m = e.match(p)) { this.matcher.push(typeof c[i] == 'function' ? c[i](m) : new Template(c[i]).evaluate(m)); e = e.replace(m[0], ''); break; } } } this.matcher.push("return h.unique(n);\n}"); eval(this.matcher.join('\n')); Selector._cache[this.expression] = this.matcher; }, compileXPathMatcher: function() { var e = this.expression, ps = Selector.patterns, x = Selector.xpath, le, m; if (Selector._cache[e]) { this.xpath = Selector._cache[e]; return; } this.matcher = ['.//*']; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in ps) { if (m = e.match(ps[i])) { this.matcher.push(typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m)); e = e.replace(m[0], ''); break; } } } this.xpath = this.matcher.join(''); Selector._cache[this.expression] = this.xpath; }, findElements: function(root) { root = root || document; if (this.xpath) return document._getElementsByXPath(this.xpath, root); return this.matcher(root); }, match: function(element) { return this.findElements(document).include(element); }, toString: function() { return this.expression; }, inspect: function() { return "#"; } }; Object.extend(Selector, { _cache: {}, xpath: { descendant: "//*", child: "/*", adjacent: "/following-sibling::*[1]", laterSibling: '/following-sibling::*', tagName: function(m) { if (m[1] == '*') return ''; return "[local-name()='"+m[1].toLowerCase()+ "' or local-name()='"+m[1].toUpperCase()+"']"; }, className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", id: "[@id='#{1}']", attrPresence: "[@#{1}]", attr: function(m) { m[3] = m[5] || m[6]; return new Template(Selector.xpath.operators[m[2]]).evaluate(m); }, pseudo: function(m) { var h = Selector.xpath.pseudos[m[1]]; if (!h) return ''; if (typeof h === 'function') return h(m); return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); }, operators: { '=': "[@#{1}='#{3}']", '!=': "[@#{1}!='#{3}']", '^=': "[starts-with(@#{1}, '#{3}')]", '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}')+1))='#{3}']", '*=': "[contains(@#{1}, '#{3}')]", '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" }, pseudos: { 'first-child': '[not(preceding-sibling::*)]', 'last-child': '[not(following-sibling::*)]', 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", 'checked': "[@checked]", 'disabled': "[@disabled]", 'enabled': "[not(@disabled)]", 'not': function(m) { var e = m[6], p = Selector.patterns, x = Selector.xpath, le, m, v; var exclusion = []; while (e && le != e && (/\S/).test(e)) { le = e; for (var i in p) { if (m = e.match(p[i])) { v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m); exclusion.push("("+v.substring(1, v.length - 1)+")"); e = e.replace(m[0], ''); break; } } } return "[not("+exclusion.join(" and ")+")]"; }, 'nth-child': function(m) { return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*)+1) ", m); }, 'nth-last-child': function(m) { return Selector.xpath.pseudos.nth("(count(./following-sibling::*)+1) ", m); }, 'nth-of-type': function(m) { return Selector.xpath.pseudos.nth("position() ", m); }, 'nth-last-of-type': function(m) { return Selector.xpath.pseudos.nth("(last()+1 - position()) ", m); }, 'first-of-type': function(m) { m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); }, 'last-of-type': function(m) { m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); }, 'only-of-type': function(m) { var p = Selector.xpath.pseudos; return p['first-of-type'](m)+p['last-of-type'](m); }, nth: function(fragment, m) { var mm, formula = m[6], predicate; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; if (mm = formula.match(/^(\d+)$/)) // digit only return '['+fragment+"= "+mm[1]+']'; if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b if (mm[1] == "-") mm[1] = -1; var a = mm[1] ? Number(mm[1]) : 1; var b = mm[2] ? Number(mm[2]) : 0; predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and "+ "((#{fragment} - #{b}) div #{a} >= 0)]"; return new Template(predicate).evaluate({ fragment: fragment, a: a, b: b }); } } } }, criteria: { tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', className: 'n = h.className(n, r, "#{1}", c); c = false;', id: 'n = h.id(n, r, "#{1}", c); c = false;', attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;', attr: function(m) { m[3] = (m[5] || m[6]); return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); }, pseudo: function(m) { if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); }, descendant: 'c = "descendant";', child: 'c = "child";', adjacent: 'c = "adjacent";', laterSibling: 'c = "laterSibling";' }, patterns: { // combinators must be listed first // (and descendant needs to be last combinator) laterSibling: /^\s*~\s*/, child: /^\s*>\s*/, adjacent: /^\s*\+\s*/, descendant: /^\s/, // selectors follow tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, id: /^#([\w\-\*]+)(\b|$)/, className: /^\.([\w\-\*]+)(\b|$)/, pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/, attrPresence: /^\[([\w]+)\]/, attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/ }, handlers: { // UTILITY FUNCTIONS // joins two collections concat: function(a, b) { for (var i = 0, node; node = b[i]; i++) a.push(node); return a; }, // marks an array of nodes for counting mark: function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node._counted = true; return nodes; }, unmark: function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node._counted = undefined; return nodes; }, // mark each child node with its position (for nth calls) // "ofType" flag indicates whether we're indexing for nth-of-type // rather than nth-child index: function(parentNode, reverse, ofType) { parentNode._counted = true; if (reverse) { for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { node = nodes[i]; if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; } } else { for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; } }, // filters out duplicates and extends all nodes unique: function(nodes) { if (nodes.length == 0) return nodes; var results = [], n; for (var i = 0, l = nodes.length; i < l; i++) if (!(n = nodes[i])._counted) { n._counted = true; results.push(Element.extend(n)); } return Selector.handlers.unmark(results); }, // COMBINATOR FUNCTIONS descendant: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) h.concat(results, node.getElementsByTagName('*')); return results; }, child: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) { for (var j = 0, children = [], child; child = node.childNodes[j]; j++) if (child.nodeType == 1 && child.tagName != '!') results.push(child); } return results; }, adjacent: function(nodes) { for (var i = 0, results = [], node; node = nodes[i]; i++) { var next = this.nextElementSibling(node); if (next) results.push(next); } return results; }, laterSibling: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) h.concat(results, Element.nextSiblings(node)); return results; }, nextElementSibling: function(node) { while (node = node.nextSibling) if (node.nodeType == 1) return node; return null; }, previousElementSibling: function(node) { while (node = node.previousSibling) if (node.nodeType == 1) return node; return null; }, // TOKEN FUNCTIONS tagName: function(nodes, root, tagName, combinator) { tagName = tagName.toUpperCase(); var results = [], h = Selector.handlers; if (nodes) { if (combinator) { // fastlane for ordinary descendant combinators if (combinator == "descendant") { for (var i = 0, node; node = nodes[i]; i++) h.concat(results, node.getElementsByTagName(tagName)); return results; } else nodes = this[combinator](nodes); if (tagName == "*") return nodes; } for (var i = 0, node; node = nodes[i]; i++) if (node.tagName.toUpperCase() == tagName) results.push(node); return results; } else return root.getElementsByTagName(tagName); }, id: function(nodes, root, id, combinator) { var targetNode = $(id), h = Selector.handlers; if (!nodes && root == document) return targetNode ? [targetNode] : []; if (nodes) { if (combinator) { if (combinator == 'child') { for (var i = 0, node; node = nodes[i]; i++) if (targetNode.parentNode == node) return [targetNode]; } else if (combinator == 'descendant') { for (var i = 0, node; node = nodes[i]; i++) if (Element.descendantOf(targetNode, node)) return [targetNode]; } else if (combinator == 'adjacent') { for (var i = 0, node; node = nodes[i]; i++) if (Selector.handlers.previousElementSibling(targetNode) == node) return [targetNode]; } else nodes = h[combinator](nodes); } for (var i = 0, node; node = nodes[i]; i++) if (node == targetNode) return [targetNode]; return []; } return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; }, className: function(nodes, root, className, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); return Selector.handlers.byClassName(nodes, root, className); }, byClassName: function(nodes, root, className) { if (!nodes) nodes = Selector.handlers.descendant([root]); var needle = ' '+className+' '; for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { nodeClassName = node.className; if (nodeClassName.length == 0) continue; if (nodeClassName == className || (' '+nodeClassName+' ').include(needle)) results.push(node); } return results; }, attrPresence: function(nodes, root, attr) { var results = []; for (var i = 0, node; node = nodes[i]; i++) if (Element.hasAttribute(node, attr)) results.push(node); return results; }, attr: function(nodes, root, attr, value, operator) { if (!nodes) nodes = root.getElementsByTagName("*"); var handler = Selector.operators[operator], results = []; for (var i = 0, node; node = nodes[i]; i++) { var nodeValue = Element.readAttribute(node, attr); if (nodeValue === null) continue; if (handler(nodeValue, value)) results.push(node); } return results; }, pseudo: function(nodes, name, value, root, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); if (!nodes) nodes = root.getElementsByTagName("*"); return Selector.pseudos[name](nodes, value, root); } }, pseudos: { 'first-child': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.previousElementSibling(node)) continue; results.push(node); } return results; }, 'last-child': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.nextElementSibling(node)) continue; results.push(node); } return results; }, 'only-child': function(nodes, value, root) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) results.push(node); return results; }, 'nth-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root); }, 'nth-last-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true); }, 'nth-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, false, true); }, 'nth-last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true, true); }, 'first-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, false, true); }, 'last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, true, true); }, 'only-of-type': function(nodes, formula, root) { var p = Selector.pseudos; return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); }, // handles the an+b logic getIndices: function(a, b, total) { if (a == 0) return b > 0 ? [b] : []; return $R(1, total).inject([], function(memo, i) { if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); return memo; }); }, // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type nth: function(nodes, formula, root, reverse, ofType) { if (nodes.length == 0) return []; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; var h = Selector.handlers, results = [], indexed = [], m; h.mark(nodes); for (var i = 0, node; node = nodes[i]; i++) { if (!node.parentNode._counted) { h.index(node.parentNode, reverse, ofType); indexed.push(node.parentNode); } } if (formula.match(/^\d+$/)) { // just a number formula = Number(formula); for (var i = 0, node; node = nodes[i]; i++) if (node.nodeIndex == formula) results.push(node); } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b if (m[1] == "-") m[1] = -1; var a = m[1] ? Number(m[1]) : 1; var b = m[2] ? Number(m[2]) : 0; var indices = Selector.pseudos.getIndices(a, b, nodes.length); for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { for (var j = 0; j < l; j++) if (node.nodeIndex == indices[j]) results.push(node); } } h.unmark(nodes); h.unmark(indexed); return results; }, 'empty': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { // IE treats comments as element nodes if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; results.push(node); } return results; }, 'not': function(nodes, selector, root) { var h = Selector.handlers, selectorType, m; var exclusions = new Selector(selector).findElements(root); h.mark(exclusions); for (var i = 0, results = [], node; node = nodes[i]; i++) if (!node._counted) results.push(node); h.unmark(exclusions); return results; }, 'enabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (!node.disabled) results.push(node); return results; }, 'disabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (node.disabled) results.push(node); return results; }, 'checked': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (node.checked) results.push(node); return results; } }, operators: { '=': function(nv, v) { return nv == v; }, '!=': function(nv, v) { return nv != v; }, '^=': function(nv, v) { return nv.startsWith(v); }, '$=': function(nv, v) { return nv.endsWith(v); }, '*=': function(nv, v) { return nv.include(v); }, '~=': function(nv, v) { return (' '+nv+' ').include(' '+v+' '); }, '|=': function(nv, v) { return ('-'+nv.toUpperCase()+'-').include('-'+v.toUpperCase()+'-'); } }, matchElements: function(elements, expression) { var matches = new Selector(expression).findElements(), h = Selector.handlers; h.mark(matches); for (var i = 0, results = [], element; element = elements[i]; i++) if (element._counted) results.push(element); h.unmark(matches); return results; }, findElement: function(elements, expression, index) { if (typeof expression == 'number') { index = expression; expression = false; } return Selector.matchElements(elements, expression || '*')[index || 0]; }, findChildElements: function(element, expressions) { var exprs = expressions.join(','), expressions = []; exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { expressions.push(m[1].strip()); }); var results = [], h = Selector.handlers; for (var i = 0, l = expressions.length, selector; i < l; i++) { selector = new Selector(expressions[i].strip()); h.concat(results, selector.findElements(element)); } return (l > 1) ? h.unique(results) : results; } }); function $$() { return Selector.findChildElements(document, $A(arguments)); } var Form = { reset: function(form) { $(form).reset(); return form; }, serializeElements: function(elements, getHash) { var data = elements.inject({}, function(result, element) { if (!element.disabled && element.name) { var key = element.name, value = $(element).getValue(); if (value != null) { if (key in result) { if (result[key].constructor != Array) result[key] = [result[key]]; result[key].push(value); } else result[key] = value; } } return result; }); return getHash ? data : Hash.toQueryString(data); } }; Form.Methods = { serialize: function(form, getHash) { return Form.serializeElements(Form.getElements(form), getHash); }, getElements: function(form) { return $A($(form).getElementsByTagName('*')).inject([], function(elements, child) { if (Form.Element.Serializers[child.tagName.toLowerCase()]) elements.push(Element.extend(child)); return elements; } ); }, getInputs: function(form, typeName, name) { form = $(form); var inputs = form.getElementsByTagName('input'); if (!typeName && !name) return $A(inputs).map(Element.extend); for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { var input = inputs[i]; if ((typeName && input.type != typeName) || (name && input.name != name)) continue; matchingInputs.push(Element.extend(input)); } return matchingInputs; }, disable: function(form) { form = $(form); Form.getElements(form).invoke('disable'); return form; }, enable: function(form) { form = $(form); Form.getElements(form).invoke('enable'); return form; }, findFirstElement: function(form) { return $(form).getElements().find(function(element) { return element.type != 'hidden' && !element.disabled && ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); }); }, focusFirstElement: function(form) { form = $(form); form.findFirstElement().activate(); return form; }, request: function(form, options) { form = $(form), options = Object.clone(options || {}); var params = options.parameters; options.parameters = form.serialize(true); if (params) { if (typeof params == 'string') params = params.toQueryParams(); Object.extend(options.parameters, params); } if (form.hasAttribute('method') && !options.method) options.method = form.method; return new Ajax.Request(form.readAttribute('action'), options); } } /*--------------------------------------------------------------------------*/ Form.Element = { focus: function(element) { $(element).focus(); return element; }, select: function(element) { $(element).select(); return element; } } Form.Element.Methods = { serialize: function(element) { element = $(element); if (!element.disabled && element.name) { var value = element.getValue(); if (value != undefined) { var pair = {}; pair[element.name] = value; return Hash.toQueryString(pair); } } return ''; }, getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); return Form.Element.Serializers[method](element); }, clear: function(element) { $(element).value = ''; return element; }, present: function(element) { return $(element).value != ''; }, activate: function(element) { element = $(element); try { element.focus(); if (element.select && (element.tagName.toLowerCase() != 'input' || !['button', 'reset', 'submit'].include(element.type))) element.select(); } catch (e) {} return element; }, disable: function(element) { element = $(element); element.blur(); element.disabled = true; return element; }, enable: function(element) { element = $(element); element.disabled = false; return element; } } /*--------------------------------------------------------------------------*/ var Field = Form.Element; var $F = Form.Element.Methods.getValue; /*--------------------------------------------------------------------------*/ Form.Element.Serializers = { input: function(element) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element); default: return Form.Element.Serializers.textarea(element); } }, inputSelector: function(element) { return element.checked ? element.value : null; }, textarea: function(element) { return element.value; }, select: function(element) { return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); }, selectOne: function(element) { var index = element.selectedIndex; return index >= 0 ? this.optionValue(element.options[index]) : null; }, selectMany: function(element) { var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; if (opt.selected) values.push(this.optionValue(opt)); } return values; }, optionValue: function(opt) { // extend element because hasAttribute may not be native return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } } /*--------------------------------------------------------------------------*/ Abstract.TimedObserver = function() {} Abstract.TimedObserver.prototype = { initialize: function(element, frequency, callback) { this.frequency = frequency; this.element = $(element); this.callback = callback; this.lastValue = this.getValue(); this.registerCallback(); }, registerCallback: function() { setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, onTimerEvent: function() { var value = this.getValue(); var changed = ('string' == typeof this.lastValue && 'string' == typeof value ? this.lastValue != value : String(this.lastValue) != String(value)); if (changed) { this.callback(this.element, value); this.lastValue = value; } } } Form.Element.Observer = Class.create(); Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { getValue: function() { return Form.Element.getValue(this.element); } }); Form.Observer = Class.create(); Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { getValue: function() { return Form.serialize(this.element); } }); /*--------------------------------------------------------------------------*/ Abstract.EventObserver = function() {} Abstract.EventObserver.prototype = { initialize: function(element, callback) { this.element = $(element); this.callback = callback; this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form') this.registerFormCallbacks(); else this.registerCallback(this.element); }, onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { this.callback(this.element, value); this.lastValue = value; } }, registerFormCallbacks: function() { Form.getElements(this.element).each(this.registerCallback.bind(this)); }, registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': Event.observe(element, 'click', this.onElementEvent.bind(this)); break; default: Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } } } } Form.Element.EventObserver = Class.create(); Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { getValue: function() { return Form.Element.getValue(this.element); } }); Form.EventObserver = Class.create(); Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { getValue: function() { return Form.serialize(this.element); } }); if (!window.Event) { var Event = new Object(); } Object.extend(Event, { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_RETURN: 13, KEY_ESC: 27, KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40, KEY_DELETE: 46, KEY_HOME: 36, KEY_END: 35, KEY_PAGEUP: 33, KEY_PAGEDOWN: 34, element: function(event) { return $(event.target || event.srcElement); }, isLeftClick: function(event) { return (((event.which) && (event.which == 1)) || ((event.button) && (event.button == 1))); }, pointerX: function(event) { return event.pageX || (event.clientX+ (document.documentElement.scrollLeft || document.body.scrollLeft)); }, pointerY: function(event) { return event.pageY || (event.clientY+ (document.documentElement.scrollTop || document.body.scrollTop)); }, stop: function(event) { if (event.preventDefault) { event.preventDefault(); event.stopPropagation(); } else { event.returnValue = false; event.cancelBubble = true; } }, // find the first node with the given tagName, starting from the // node the event was triggered on; traverses the DOM upwards findElement: function(event, tagName) { var element = Event.element(event); while (element.parentNode && (!element.tagName || (element.tagName.toUpperCase() != tagName.toUpperCase()))) element = element.parentNode; return element; }, observers: false, _observeAndCache: function(element, name, observer, useCapture) { if (!this.observers) this.observers = []; if (element.addEventListener) { this.observers.push([element, name, observer, useCapture]); element.addEventListener(name, observer, useCapture); } else if (element.attachEvent) { this.observers.push([element, name, observer, useCapture]); element.attachEvent('on'+name, observer); } }, unloadCache: function() { if (!Event.observers) return; for (var i = 0, length = Event.observers.length; i < length; i++) { Event.stopObserving.apply(this, Event.observers[i]); Event.observers[i][0] = null; } Event.observers = false; }, observe: function(element, name, observer, useCapture) { element = $(element); useCapture = useCapture || false; if (name == 'keypress' && (Prototype.Browser.WebKit || element.attachEvent)) name = 'keydown'; Event._observeAndCache(element, name, observer, useCapture); }, stopObserving: function(element, name, observer, useCapture) { element = $(element); useCapture = useCapture || false; if (name == 'keypress' && (Prototype.Browser.WebKit || element.attachEvent)) name = 'keydown'; if (element.removeEventListener) { element.removeEventListener(name, observer, useCapture); } else if (element.detachEvent) { try { element.detachEvent('on'+name, observer); } catch (e) {} } } }); /* prevent memory leaks in IE */ if (Prototype.Browser.IE) Event.observe(window, 'unload', Event.unloadCache, false); var Position = { // set to true if needed, warning: firefox performance problems // NOT neeeded for page scrolling, only if draggable contained in // scrollable elements includeScrollOffsets: false, // must be called before calling withinIncludingScrolloffset, every time the // page is scrolled prepare: function() { this.deltaX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; this.deltaY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; }, realOffset: function(element) { var valueT = 0, valueL = 0; do { valueT+= element.scrollTop || 0; valueL+= element.scrollLeft || 0; element = element.parentNode; } while (element); return [valueL, valueT]; }, cumulativeOffset: function(element) { var valueT = 0, valueL = 0; do { valueT+= element.offsetTop || 0; valueL+= element.offsetLeft || 0; element = element.offsetParent; } while (element); return [valueL, valueT]; }, positionedOffset: function(element) { var valueT = 0, valueL = 0; do { valueT+= element.offsetTop || 0; valueL+= element.offsetLeft || 0; element = element.offsetParent; if (element) { if(element.tagName=='BODY') break; var p = Element.getStyle(element, 'position'); if (p == 'relative' || p == 'absolute') break; } } while (element); return [valueL, valueT]; }, offsetParent: function(element) { if (element.offsetParent) return element.offsetParent; if (element == document.body) return element; while ((element = element.parentNode) && element != document.body) if (Element.getStyle(element, 'position') != 'static') return element; return document.body; }, // caches x/y coordinate pair to use with overlap within: function(element, x, y) { if (this.includeScrollOffsets) return this.withinIncludingScrolloffsets(element, x, y); this.xcomp = x; this.ycomp = y; this.offset = this.cumulativeOffset(element); return (y >= this.offset[1] && y < this.offset[1]+element.offsetHeight && x >= this.offset[0] && x < this.offset[0]+element.offsetWidth); }, withinIncludingScrolloffsets: function(element, x, y) { var offsetcache = this.realOffset(element); this.xcomp = x+offsetcache[0] - this.deltaX; this.ycomp = y+offsetcache[1] - this.deltaY; this.offset = this.cumulativeOffset(element); return (this.ycomp >= this.offset[1] && this.ycomp < this.offset[1]+element.offsetHeight && this.xcomp >= this.offset[0] && this.xcomp < this.offset[0]+element.offsetWidth); }, // within must be called directly before overlap: function(mode, element) { if (!mode) return 0; if (mode == 'vertical') return ((this.offset[1]+element.offsetHeight) - this.ycomp) / element.offsetHeight; if (mode == 'horizontal') return ((this.offset[0]+element.offsetWidth) - this.xcomp) / element.offsetWidth; }, page: function(forElement) { var valueT = 0, valueL = 0; var element = forElement; do { valueT+= element.offsetTop || 0; valueL+= element.offsetLeft || 0; // Safari fix if (element.offsetParent == document.body) if (Element.getStyle(element,'position')=='absolute') break; } while (element = element.offsetParent); element = forElement; do { if (!window.opera || element.tagName=='BODY') { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return [valueL, valueT]; }, clone: function(source, target) { var options = Object.extend({ setLeft: true, setTop: true, setWidth: true, setHeight: true, offsetTop: 0, offsetLeft: 0 }, arguments[2] || {}) // find page position of source source = $(source); var p = Position.page(source); // find coordinate system to use target = $(target); var delta = [0, 0]; var parent = null; // delta [0,0] will do fine with position: fixed elements, // position:absolute needs offsetParent deltas if (Element.getStyle(target,'position') == 'absolute') { parent = Position.offsetParent(target); delta = Position.page(parent); } // correct by body offsets (fixes Safari) if (parent == document.body) { delta[0] -= document.body.offsetLeft; delta[1] -= document.body.offsetTop; } // set position if(options.setLeft) target.style.left = (p[0] - delta[0]+options.offsetLeft)+'px'; if(options.setTop) target.style.top = (p[1] - delta[1]+options.offsetTop)+'px'; if(options.setWidth) target.style.width = source.offsetWidth+'px'; if(options.setHeight) target.style.height = source.offsetHeight+'px'; }, absolutize: function(element) { element = $(element); if (element.style.position == 'absolute') return; Position.prepare(); var offsets = Position.positionedOffset(element); var top = offsets[1]; var left = offsets[0]; var width = element.clientWidth; var height = element.clientHeight; element._originalLeft = left - parseFloat(element.style.left || 0); element._originalTop = top - parseFloat(element.style.top || 0); element._originalWidth = element.style.width; element._originalHeight = element.style.height; element.style.position = 'absolute'; element.style.top = top+'px'; element.style.left = left+'px'; element.style.width = width+'px'; element.style.height = height+'px'; }, relativize: function(element) { element = $(element); if (element.style.position == 'relative') return; Position.prepare(); element.style.position = 'relative'; var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); element.style.top = top+'px'; element.style.left = left+'px'; element.style.height = element._originalHeight; element.style.width = element._originalWidth; } } // Safari returns margins on body which is incorrect if the child is absolutely // positioned. For performance reasons, redefine Position.cumulativeOffset for // KHTML/WebKit only. if (Prototype.Browser.WebKit) { Position.cumulativeOffset = function(element) { var valueT = 0, valueL = 0; do { valueT+= element.offsetTop || 0; valueL+= element.offsetLeft || 0; if (element.offsetParent == document.body) if (Element.getStyle(element, 'position') == 'absolute') break; element = element.offsetParent; } while (element); return [valueL, valueT]; } } Element.addMethods();// script.aculo.us effects.js v1.7.1_beta1, Mon Mar 12 14:40:50+0100 2007 // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // Contributors: // Justin Palmer (http://encytemedia.com/) // Mark Pilgrim (http://diveintomark.org/) // Martin Bialasinki // // script.aculo.us is freely distributable under the terms of an MIT-style license. // For details, see the script.aculo.us web site: http://script.aculo.us/ // converts rgb() and #xxx to #xxxxxx format, // returns self (or first argument) if not convertable String.prototype.parseColor = function() { var color = '#'; if(this.slice(0,4) == 'rgb(') { var cols = this.slice(4,this.length-1).split(','); var i=0; do { color+= parseInt(cols[i]).toColorPart() } while (++i<3); } else { if(this.slice(0,1) == '#') { if(this.length==4) for(var i=1;i<4;i++) color+= (this.charAt(i)+this.charAt(i)).toLowerCase(); if(this.length==7) color = this.toLowerCase(); } } return(color.length==7 ? color : (arguments[0] || this)); } /*--------------------------------------------------------------------------*/ Element.collectTextNodes = function(element) { return $A($(element).childNodes).collect( function(node) { return (node.nodeType==3 ? node.nodeValue : (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); }).flatten().join(''); } Element.collectTextNodesIgnoreClass = function(element, className) { return $A($(element).childNodes).collect( function(node) { return (node.nodeType==3 ? node.nodeValue : ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? Element.collectTextNodesIgnoreClass(node, className) : '')); }).flatten().join(''); } Element.setContentZoom = function(element, percent) { element = $(element); element.setStyle({fontSize: (percent/100)+'em'}); if(Prototype.Browser.WebKit) window.scrollBy(0,0); return element; } Element.getInlineOpacity = function(element){ return $(element).style.opacity || ''; } Element.forceRerendering = function(element) { try { element = $(element); var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch(e) { } }; /*--------------------------------------------------------------------------*/ Array.prototype.call = function() { var args = arguments; this.each(function(f){ f.apply(this, args) }); } /*--------------------------------------------------------------------------*/ var Effect = { _elementDoesNotExistError: { name: 'ElementDoesNotExistError', message: 'The specified DOM element does not exist, but is required for this effect to operate' }, tagifyText: function(element) { if(typeof Builder == 'undefined') throw("Effect.tagifyText requires including script.aculo.us' builder.js library"); var tagifyStyle = 'position:relative'; if(Prototype.Browser.IE) tagifyStyle+= ';zoom:1'; element = $(element); $A(element.childNodes).each( function(child) { if(child.nodeType==3) { child.nodeValue.toArray().each( function(character) { element.insertBefore( Builder.node('span',{style: tagifyStyle}, character == ' ' ? String.fromCharCode(160) : character), child); }); Element.remove(child); } }); }, multiple: function(element, effect) { var elements; if(((typeof element == 'object') || (typeof element == 'function')) && (element.length)) elements = element; else elements = $(element).childNodes; var options = Object.extend({ speed: 0.1, delay: 0.0 }, arguments[2] || {}); var masterDelay = options.delay; $A(elements).each( function(element, index) { new effect(element, Object.extend(options, { delay: index * options.speed+masterDelay })); }); }, PAIRS: { 'slide': ['SlideDown','SlideUp'], 'blind': ['BlindDown','BlindUp'], 'appear': ['Appear','Fade'] }, toggle: function(element, effect) { element = $(element); effect = (effect || 'appear').toLowerCase(); var options = Object.extend({ queue: { position:'end', scope:(element.id || 'global'), limit: 1 } }, arguments[2] || {}); Effect[element.visible() ? Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); } }; var Effect2 = Effect; // deprecated /* ------------- transitions ------------- */ Effect.Transitions = { linear: Prototype.K, sinoidal: function(pos) { return (-Math.cos(pos*Math.PI)/2)+0.5; }, reverse: function(pos) { return 1-pos; }, flicker: function(pos) { var pos = ((-Math.cos(pos*Math.PI)/4)+0.75)+Math.random()/4; return (pos > 1 ? 1 : pos); }, wobble: function(pos) { return (-Math.cos(pos*Math.PI*(9*pos))/2)+0.5; }, pulse: function(pos, pulses) { pulses = pulses || 5; return ( Math.round((pos % (1/pulses)) * pulses) == 0 ? ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) ); }, none: function(pos) { return 0; }, full: function(pos) { return 1; } }; /* ------------- core effects ------------- */ Effect.ScopedQueue = Class.create(); Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { initialize: function() { this.effects = []; this.interval = null; }, _each: function(iterator) { this.effects._each(iterator); }, add: function(effect) { var timestamp = new Date().getTime(); var position = (typeof effect.options.queue == 'string') ? effect.options.queue : effect.options.queue.position; switch(position) { case 'front': // move unstarted effects after this effect this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { e.startOn+= effect.finishOn; e.finishOn+= effect.finishOn; }); break; case 'with-last': timestamp = this.effects.pluck('startOn').max() || timestamp; break; case 'end': // start effect after last queued effect has finished timestamp = this.effects.pluck('finishOn').max() || timestamp; break; } effect.startOn+= timestamp; effect.finishOn+= timestamp; if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) this.effects.push(effect); if(!this.interval) this.interval = setInterval(this.loop.bind(this), 15); }, remove: function(effect) { this.effects = this.effects.reject(function(e) { return e==effect }); if(this.effects.length == 0) { clearInterval(this.interval); this.interval = null; } }, loop: function() { var timePos = new Date().getTime(); for(var i=0, len=this.effects.length;i= this.startOn) { if(timePos >= this.finishOn) { this.render(1.0); this.cancel(); this.event('beforeFinish'); if(this.finish) this.finish(); this.event('afterFinish'); return; } var pos = (timePos - this.startOn) / this.totalTime, frame = Math.round(pos * this.totalFrames); if(frame > this.currentFrame) { this.render(pos); this.currentFrame = frame; } } }, cancel: function() { if(!this.options.sync) Effect.Queues.get(typeof this.options.queue == 'string' ? 'global' : this.options.queue.scope).remove(this); this.state = 'finished'; }, event: function(eventName) { if(this.options[eventName+'Internal']) this.options[eventName+'Internal'](this); if(this.options[eventName]) this.options[eventName](this); }, inspect: function() { var data = $H(); for(property in this) if(typeof this[property] != 'function') data[property] = this[property]; return '#'; } } Effect.Parallel = Class.create(); Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { initialize: function(effects) { this.effects = effects || []; this.start(arguments[1]); }, update: function(position) { this.effects.invoke('render', position); }, finish: function(position) { this.effects.each( function(effect) { effect.render(1.0); effect.cancel(); effect.event('beforeFinish'); if(effect.finish) effect.finish(position); effect.event('afterFinish'); }); } }); Effect.Event = Class.create(); Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), { initialize: function() { var options = Object.extend({ duration: 0 }, arguments[0] || {}); this.start(options); }, update: Prototype.emptyFunction }); Effect.Opacity = Class.create(); Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { initialize: function(element) { this.element = $(element); if(!this.element) throw(Effect._elementDoesNotExistError); // make this work on IE on elements without 'layout' if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) this.element.setStyle({zoom: 1}); var options = Object.extend({ from: this.element.getOpacity() || 0.0, to: 1.0 }, arguments[1] || {}); this.start(options); }, update: function(position) { this.element.setOpacity(position); } }); Effect.Move = Class.create(); Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { initialize: function(element) { this.element = $(element); if(!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ x: 0, y: 0, mode: 'relative' }, arguments[1] || {}); this.start(options); }, setup: function() { // Bug in Opera: Opera returns the "real" position of a static element or // relative element that does not have top/left explicitly set. // ==> Always set top and left for position relative elements in your stylesheets // (to 0 if you do not need them) this.element.makePositioned(); this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); this.originalTop = parseFloat(this.element.getStyle('top') || '0'); if(this.options.mode == 'absolute') { // absolute movement, so we need to calc deltaX and deltaY this.options.x = this.options.x - this.originalLeft; this.options.y = this.options.y - this.originalTop; } }, update: function(position) { this.element.setStyle({ left: Math.round(this.options.x * position+this.originalLeft)+'px', top: Math.round(this.options.y * position+this.originalTop)+'px' }); } }); // for backwards compatibility Effect.MoveBy = function(element, toTop, toLeft) { return new Effect.Move(element, Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); }; Effect.Scale = Class.create(); Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { initialize: function(element, percent) { this.element = $(element); if(!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ scaleX: true, scaleY: true, scaleContent: true, scaleFromCenter: false, scaleMode: 'box', // 'box' or 'contents' or {} with provided values scaleFrom: 100.0, scaleTo: percent }, arguments[2] || {}); this.start(options); }, setup: function() { this.restoreAfterFinish = this.options.restoreAfterFinish || false; this.elementPositioning = this.element.getStyle('position'); this.originalStyle = {}; ['top','left','width','height','fontSize'].each( function(k) { this.originalStyle[k] = this.element.style[k]; }.bind(this)); this.originalTop = this.element.offsetTop; this.originalLeft = this.element.offsetLeft; var fontSize = this.element.getStyle('font-size') || '100%'; ['em','px','%','pt'].each( function(fontSizeType) { if(fontSize.indexOf(fontSizeType)>0) { this.fontSize = parseFloat(fontSize); this.fontSizeType = fontSizeType; } }.bind(this)); this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; this.dims = null; if(this.options.scaleMode=='box') this.dims = [this.element.offsetHeight, this.element.offsetWidth]; if(/^content/.test(this.options.scaleMode)) this.dims = [this.element.scrollHeight, this.element.scrollWidth]; if(!this.dims) this.dims = [this.options.scaleMode.originalHeight, this.options.scaleMode.originalWidth]; }, update: function(position) { var currentScale = (this.options.scaleFrom/100.0)+(this.factor * position); if(this.options.scaleContent && this.fontSize) this.element.setStyle({fontSize: this.fontSize * currentScale+this.fontSizeType }); this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); }, finish: function(position) { if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle); }, setDimensions: function(height, width) { var d = {}; if(this.options.scaleX) d.width = Math.round(width)+'px'; if(this.options.scaleY) d.height = Math.round(height)+'px'; if(this.options.scaleFromCenter) { var topd = (height - this.dims[0])/2; var leftd = (width - this.dims[1])/2; if(this.elementPositioning == 'absolute') { if(this.options.scaleY) d.top = this.originalTop-topd+'px'; if(this.options.scaleX) d.left = this.originalLeft-leftd+'px'; } else { if(this.options.scaleY) d.top = -topd+'px'; if(this.options.scaleX) d.left = -leftd+'px'; } } this.element.setStyle(d); } }); Effect.Highlight = Class.create(); Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { initialize: function(element) { this.element = $(element); if(!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); this.start(options); }, setup: function() { // Prevent executing on elements not in the layout flow if(this.element.getStyle('display')=='none') { this.cancel(); return; } // Disable background image during the effect this.oldStyle = {}; if (!this.options.keepBackgroundImage) { this.oldStyle.backgroundImage = this.element.getStyle('background-image'); this.element.setStyle({backgroundImage: 'none'}); } if(!this.options.endcolor) this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); if(!this.options.restorecolor) this.options.restorecolor = this.element.getStyle('background-color'); // init color calculations this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); }, update: function(position) { this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); }, finish: function() { this.element.setStyle(Object.extend(this.oldStyle, { backgroundColor: this.options.restorecolor })); } }); Effect.ScrollTo = Class.create(); Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { initialize: function(element) { this.element = $(element); this.start(arguments[1] || {}); }, setup: function() { Position.prepare(); var offsets = Position.cumulativeOffset(this.element); if(this.options.offset) offsets[1]+= this.options.offset; var max = window.innerHeight ? window.height - window.innerHeight : document.body.scrollHeight - (document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight); this.scrollStart = Position.deltaY; this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; }, update: function(position) { Position.prepare(); window.scrollTo(Position.deltaX, this.scrollStart+(position*this.delta)); } }); /* ------------- combination effects ------------- */ Effect.Fade = function(element) { element = $(element); var oldOpacity = element.getInlineOpacity(); var options = Object.extend({ from: element.getOpacity() || 1.0, to: 0.0, afterFinishInternal: function(effect) { if(effect.options.to!=0) return; effect.element.hide().setStyle({opacity: oldOpacity}); }}, arguments[1] || {}); return new Effect.Opacity(element,options); } Effect.Appear = function(element) { element = $(element); var options = Object.extend({ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), to: 1.0, // force Safari to render floated elements properly afterFinishInternal: function(effect) { effect.element.forceRerendering(); }, beforeSetup: function(effect) { effect.element.setOpacity(effect.options.from).show(); }}, arguments[1] || {}); return new Effect.Opacity(element,options); } Effect.Puff = function(element) { element = $(element); var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position'), top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; return new Effect.Parallel( [ new Effect.Scale(element, 200, { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], Object.extend({ duration: 1.0, beforeSetupInternal: function(effect) { Position.absolutize(effect.effects[0].element) }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().setStyle(oldStyle); } }, arguments[1] || {}) ); } Effect.BlindUp = function(element) { element = $(element); element.makeClipping(); return new Effect.Scale(element, 0, Object.extend({ scaleContent: false, scaleX: false, restoreAfterFinish: true, afterFinishInternal: function(effect) { effect.element.hide().undoClipping(); } }, arguments[1] || {}) ); } Effect.BlindDown = function(element) { element = $(element); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: 0, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makeClipping().setStyle({height: '0px'}).show(); }, afterFinishInternal: function(effect) { effect.element.undoClipping(); } }, arguments[1] || {})); } Effect.SwitchOff = function(element) { element = $(element); var oldOpacity = element.getInlineOpacity(); return new Effect.Appear(element, Object.extend({ duration: 0.4, from: 0, transition: Effect.Transitions.flicker, afterFinishInternal: function(effect) { new Effect.Scale(effect.element, 1, { duration: 0.3, scaleFromCenter: true, scaleX: false, scaleContent: false, restoreAfterFinish: true, beforeSetup: function(effect) { effect.element.makePositioned().makeClipping(); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); } }) } }, arguments[1] || {})); } Effect.DropOut = function(element) { element = $(element); var oldStyle = { top: element.getStyle('top'), left: element.getStyle('left'), opacity: element.getInlineOpacity() }; return new Effect.Parallel( [ new Effect.Move(element, {x: 0, y: 100, sync: true }), new Effect.Opacity(element, { sync: true, to: 0.0 }) ], Object.extend( { duration: 0.5, beforeSetup: function(effect) { effect.effects[0].element.makePositioned(); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); } }, arguments[1] || {})); } Effect.Shake = function(element) { element = $(element); var oldStyle = { top: element.getStyle('top'), left: element.getStyle('left') }; return new Effect.Move(element, { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { effect.element.undoPositioned().setStyle(oldStyle); }}) }}) }}) }}) }}) }}); } Effect.SlideDown = function(element) { element = $(element).cleanWhitespace(); // SlideDown need to have the content of the element wrapped in a container element with fixed height! var oldInnerBottom = element.down().getStyle('bottom'); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: window.opera ? 0 : 1, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makePositioned(); effect.element.down().makePositioned(); if(window.opera) effect.element.setStyle({top: ''}); effect.element.makeClipping().setStyle({height: '0px'}).show(); }, afterUpdateInternal: function(effect) { effect.element.down().setStyle({bottom: (effect.dims[0] - effect.element.clientHeight)+'px' }); }, afterFinishInternal: function(effect) { effect.element.undoClipping().undoPositioned(); effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } }, arguments[1] || {}) ); } Effect.SlideUp = function(element) { element = $(element).cleanWhitespace(); var oldInnerBottom = element.down().getStyle('bottom'); return new Effect.Scale(element, window.opera ? 0 : 1, Object.extend({ scaleContent: false, scaleX: false, scaleMode: 'box', scaleFrom: 100, restoreAfterFinish: true, beforeStartInternal: function(effect) { effect.element.makePositioned(); effect.element.down().makePositioned(); if(window.opera) effect.element.setStyle({top: ''}); effect.element.makeClipping().show(); }, afterUpdateInternal: function(effect) { effect.element.down().setStyle({bottom: (effect.dims[0] - effect.element.clientHeight)+'px' }); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom}); effect.element.down().undoPositioned(); } }, arguments[1] || {}) ); } // Bug in opera makes the TD containing this element expand for a instance after finish Effect.Squish = function(element) { return new Effect.Scale(element, window.opera ? 1 : 0, { restoreAfterFinish: true, beforeSetup: function(effect) { effect.element.makeClipping(); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping(); } }); } Effect.Grow = function(element) { element = $(element); var options = Object.extend({ direction: 'center', moveTransition: Effect.Transitions.sinoidal, scaleTransition: Effect.Transitions.sinoidal, opacityTransition: Effect.Transitions.full }, arguments[1] || {}); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getInlineOpacity() }; var dims = element.getDimensions(); var initialMoveX, initialMoveY; var moveX, moveY; switch (options.direction) { case 'top-left': initialMoveX = initialMoveY = moveX = moveY = 0; break; case 'top-right': initialMoveX = dims.width; initialMoveY = moveY = 0; moveX = -dims.width; break; case 'bottom-left': initialMoveX = moveX = 0; initialMoveY = dims.height; moveY = -dims.height; break; case 'bottom-right': initialMoveX = dims.width; initialMoveY = dims.height; moveX = -dims.width; moveY = -dims.height; break; case 'center': initialMoveX = dims.width / 2; initialMoveY = dims.height / 2; moveX = -dims.width / 2; moveY = -dims.height / 2; break; } return new Effect.Move(element, { x: initialMoveX, y: initialMoveY, duration: 0.01, beforeSetup: function(effect) { effect.element.hide().makeClipping().makePositioned(); }, afterFinishInternal: function(effect) { new Effect.Parallel( [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), new Effect.Scale(effect.element, 100, { scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) ], Object.extend({ beforeSetup: function(effect) { effect.effects[0].element.setStyle({height: '0px'}).show(); }, afterFinishInternal: function(effect) { effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); } }, options) ) } }); } Effect.Shrink = function(element) { element = $(element); var options = Object.extend({ direction: 'center', moveTransition: Effect.Transitions.sinoidal, scaleTransition: Effect.Transitions.sinoidal, opacityTransition: Effect.Transitions.none }, arguments[1] || {}); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getInlineOpacity() }; var dims = element.getDimensions(); var moveX, moveY; switch (options.direction) { case 'top-left': moveX = moveY = 0; break; case 'top-right': moveX = dims.width; moveY = 0; break; case 'bottom-left': moveX = 0; moveY = dims.height; break; case 'bottom-right': moveX = dims.width; moveY = dims.height; break; case 'center': moveX = dims.width / 2; moveY = dims.height / 2; break; } return new Effect.Parallel( [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) ], Object.extend({ beforeStartInternal: function(effect) { effect.effects[0].element.makePositioned().makeClipping(); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } }, options) ); } Effect.Pulsate = function(element) { element = $(element); var options = arguments[1] || {}; var oldOpacity = element.getInlineOpacity(); var transition = options.transition || Effect.Transitions.sinoidal; var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) }; reverser.bind(transition); return new Effect.Opacity(element, Object.extend(Object.extend({ duration: 2.0, from: 0, afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } }, options), {transition: reverser})); } Effect.Fold = function(element) { element = $(element); var oldStyle = { top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; element.makeClipping(); return new Effect.Scale(element, 5, Object.extend({ scaleContent: false, scaleX: false, afterFinishInternal: function(effect) { new Effect.Scale(element, 1, { scaleContent: false, scaleY: false, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().setStyle(oldStyle); } }); }}, arguments[1] || {})); }; Effect.Morph = Class.create(); Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), { initialize: function(element) { this.element = $(element); if(!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ style: {} }, arguments[1] || {}); if (typeof options.style == 'string') { if(options.style.indexOf(':') == -1) { var cssText = '', selector = '.'+options.style; $A(document.styleSheets).reverse().each(function(styleSheet) { if (styleSheet.cssRules) cssRules = styleSheet.cssRules; else if (styleSheet.rules) cssRules = styleSheet.rules; $A(cssRules).reverse().each(function(rule) { if (selector == rule.selectorText) { cssText = rule.style.cssText; throw $break; } }); if (cssText) throw $break; }); this.style = cssText.parseStyle(); options.afterFinishInternal = function(effect){ effect.element.addClassName(effect.options.style); effect.transforms.each(function(transform) { if(transform.style != 'opacity') effect.element.style[transform.style] = ''; }); } } else this.style = options.style.parseStyle(); } else this.style = $H(options.style) this.start(options); }, setup: function(){ function parseColor(color){ if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; color = color.parseColor(); return $R(0,2).map(function(i){ return parseInt( color.slice(i*2+1,i*2+3), 16 ) }); } this.transforms = this.style.map(function(pair){ var property = pair[0], value = pair[1], unit = null; if(value.parseColor('#zzzzzz') != '#zzzzzz') { value = value.parseColor(); unit = 'color'; } else if(property == 'opacity') { value = parseFloat(value); if(Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) this.element.setStyle({zoom: 1}); } else if(Element.CSS_LENGTH.test(value)) { var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); value = parseFloat(components[1]); unit = (components.length == 3) ? components[2] : null; } var originalValue = this.element.getStyle(property); return { style: property.camelize(), originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), targetValue: unit=='color' ? parseColor(value) : value, unit: unit }; }.bind(this)).reject(function(transform){ return ( (transform.originalValue == transform.targetValue) || ( transform.unit != 'color' && (isNaN(transform.originalValue) || isNaN(transform.targetValue)) ) ) }); }, update: function(position) { var style = {}, transform, i = this.transforms.length; while(i--) style[(transform = this.transforms[i]).style] = transform.unit=='color' ? '#'+ (Math.round(transform.originalValue[0]+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart()+ (Math.round(transform.originalValue[1]+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart()+ (Math.round(transform.originalValue[2]+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : transform.originalValue+Math.round( ((transform.targetValue - transform.originalValue) * position) * 1000)/1000+transform.unit; this.element.setStyle(style, true); } }); Effect.Transform = Class.create(); Object.extend(Effect.Transform.prototype, { initialize: function(tracks){ this.tracks = []; this.options = arguments[1] || {}; this.addTracks(tracks); }, addTracks: function(tracks){ tracks.each(function(track){ var data = $H(track).values().first(); this.tracks.push($H({ ids: $H(track).keys().first(), effect: Effect.Morph, options: { style: data } })); }.bind(this)); return this; }, play: function(){ return new Effect.Parallel( this.tracks.map(function(track){ var elements = [$(track.ids) || $$(track.ids)].flatten(); return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) }); }).flatten(), this.options ); } }); Element.CSS_PROPERTIES = $w( 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle '+ 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth '+ 'borderRightColor borderRightStyle borderRightWidth borderSpacing '+ 'borderTopColor borderTopStyle borderTopWidth bottom clip color '+ 'fontSize fontWeight height left letterSpacing lineHeight '+ 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset '+ 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop '+ 'right textIndent top width wordSpacing zIndex'); Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; String.prototype.parseStyle = function(){ var element = document.createElement('div'); element.innerHTML = '
'; var style = element.childNodes[0].style, styleRules = $H(); Element.CSS_PROPERTIES.each(function(property){ if(style[property]) styleRules[property] = style[property]; }); if(Prototype.Browser.IE && this.indexOf('opacity') > -1) { styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]; } return styleRules; }; Element.morph = function(element, style) { new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {})); return element; }; ['getInlineOpacity','forceRerendering','setContentZoom', 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( function(f) { Element.Methods[f] = Element[f]; } ); Element.Methods.visualEffect = function(element, effect, options) { s = effect.dasherize().camelize(); effect_class = s.charAt(0).toUpperCase()+s.substring(1); new Effect[effect_class](element, options); return $(element); }; Element.addMethods(); Effect.PhaseIn = function(element) { element = $(element); new Effect.BlindDown(element, arguments[1] || {}); new Effect.Appear(element, arguments[2] || arguments[1] || {}); }; Effect.PhaseOut = function(element) { element = $(element); new Effect.Fade(element, arguments[1] || {}); new Effect.BlindUp(element, arguments[2] || arguments[1] || {}); }; Effect.Phase = function(element) { element = $(element); if (element.style.display == 'none') new Effect.PhaseIn(element, arguments[1] || {}, arguments[2] || arguments[1] || {}); else new Effect.PhaseOut(element, arguments[1] || {}, arguments[2] || arguments[1] || {}); };/*------------------------------------------------------------------------ True portable WYSIWYG tool built for SEO and easy integration. Copyright (C) 2007 Stephen L. Blum (LightTheSun) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LightTheSun hereby reserves all copyright interests in any LightTheSun, LTSun or LTS library written by Stephen L. Blum. Stephen L. Blum, 8 February 2007 President of LightTheSun ------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------- LTSun CMS (LightTheSun Content Managment Solution) -------------------------------------------------- Author: Stephen L. Blum Version: 0.1.2 Alpha Last Modified: 4:04 PM 02/03/2007 --------------------------------------------------------------------------------------*/ function LTSun_Engine() { /*---------------------------------------------------------------------------------------- Initiation Functions -------------------- This will hold all the init procedures for each of the modules loaded from the "ltsun.inc.php" file. ----------------------------------------------------------------------------------------*/ this.initiationFunctions = new Array(); this.onResizeFunctions = new Array(); this.onLoadFunctions = new Array(); } function LTSun_AddModule(varFunction) { LTSun.initiationFunctions.push(varFunction); } function AddOnResize(varFunction) { LTSun.onResizeFunctions.push(varFunction); } function AddOnLoadFunctions(varFunction) { LTSun.onLoadFunctions.push(varFunction); } LTSun_Engine.prototype = { init : function (settings) { var i = 0; /*---------------------------------------------------------------------------------------- Settings -------- This is an Array that is created and passed into the init function. These are standard global Engine settings used to configure the LTSun Engine. ----------------------------------------------------------------------------------------*/ this.settings = settings; /*---------------------------------------------------------------------------------------- Initiation Functions Loop ------------------------- Loops through all functions pushed into an array outside of this file. These array additions are pushed by modules that are included in the "ltsun.inc.php" file. ----------------------------------------------------------------------------------------*/ for(i=0;i"; closeDiv.style.cursor = "pointer"; closeDiv.style.width = 74; closeDiv.style.height = 55; closeDiv.style.position = "absolute"; closeDiv.style.top = screenCenterTop - Math.ceil(height / 2); closeDiv.style.left = screenCenterLeft - Math.ceil(width / 2)+width - 75; closeDiv.style.zIndex = args['zIndex'] - 3; closeDiv.onclick = function() { LTSun.hideWindow({ animationSpeed: args['animationSpeed'], animateOnExit: args['animateOnExit'], animationExitType: args['animationExitType'] }); }; /*------------- Background Div -------------*/ bgDiv.id = "window_bgDiv"; bgDiv.style.opacity = 0; bgDiv.style.filter = "alpha(opacity=0)"; bgDiv.style.width = width - 20; bgDiv.style.height = 0; bgDiv.style.position = "absolute"; bgDiv.style.lineHeight = 1; bgDiv.style.fontSize = 1; bgDiv.style.top = screenCenterTop - Math.ceil((height-20) / 2); bgDiv.style.left = screenCenterLeft - Math.ceil((width-20) / 2); bgDiv.style.zIndex = args['zIndex'] - 2; bgDiv.style.backgroundColor = args['bgFirstColor']; /*------------ Forground Div ------------*/ fgDiv.id = "window_fgDiv"; fgDiv.style.opacity = 0; fgDiv.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='LTSun-Engine/media/windows/"+args['size']+"-window.png') alpha(opacity=0)"; fgDiv.innerHTML = ""; fgDiv.style.width = width; fgDiv.style.height = height; fgDiv.style.position = "absolute"; fgDiv.style.top = screenCenterTop - Math.ceil(height / 2); fgDiv.style.left = screenCenterLeft - Math.ceil(width / 2); fgDiv.style.zIndex = args['zIndex'] - 1; /*---------- Content Div ----------*/ contentDiv.id = "window_contentDiv"; contentDiv.style.opacity = 0; contentDiv.style.filter = "alpha(opacity=0)"; contentDiv.style.width = width - 30; contentDiv.style.height = height - 30; contentDiv.style.position = "absolute"; contentDiv.style.top = screenCenterTop - Math.ceil((height-30) / 2); contentDiv.style.left = screenCenterLeft - Math.ceil((width-30) / 2); contentDiv.style.zIndex = args['zIndex']; html+= "
"+args['html']; if(args['url'].length > 0) { html+= ""; } else { if(args['okAvailable']=="available" || args['cancelAvailable']=="available") html+= "

"; if(args['okAvailable']=="available") html+= "      "; if(args['cancelAvailable']=="available") html+= ""; if(args['okAvailable']=="available" || args['cancelAvailable']=="available") html+= "
"; } html+= "
"; contentDiv.innerHTML = html; document.body.appendChild(screenLockDiv); document.body.appendChild(fgDiv); document.body.appendChild(bgDiv); document.body.appendChild(closeDiv); document.body.appendChild(contentDiv); if(args['url'].length > 0) $("utilityWindowIframe").src = args['url']; $("window_contentDiv").setStyle({ overflow: "-moz-scrollbars-vertical", overflow: "auto", overflowX: "hidden" }); AddOnResize(function() { if($("window_contentDiv") && $("window_fgDiv") && $("window_bgDiv")) { screenCenterTop = Math.ceil(document.body.clientHeight!=document.body.scrollHeight?document.body.clientHeight/2:window.innerHeight/2)+document.body.scrollTop; screenCenterLeft = Math.ceil(document.body.clientWidth / 2)+document.body.scrollLeft; $("window_contentDiv").style.top = screenCenterTop - Math.ceil((height-30) / 2); $("window_contentDiv").style.left = screenCenterLeft - Math.ceil((width-30) / 2); $("window_fgDiv").style.top = screenCenterTop - Math.ceil(height / 2); $("window_fgDiv").style.left = screenCenterLeft - Math.ceil(width / 2); $("window_closeDiv").style.top = screenCenterTop - Math.ceil(height / 2) - 23; $("window_closeDiv").style.left = screenCenterLeft - Math.ceil(width / 2)+width - 75; $("window_bgDiv").style.top = screenCenterTop - Math.ceil((height-20) / 2); $("window_bgDiv").style.left = screenCenterLeft - Math.ceil((width-20) / 2); } }); args['onCreate'](); new Effect.Opacity(screenLockDiv, {duration: 0.2 * (100/args['animationSpeed']), from: 0.0, to: 0.6, afterFinish: function() { new Effect.Parallel([ new Effect.Opacity(fgDiv, {sync: true, from: 0.0, to: 1.0}), new Effect.Opacity(bgDiv, {sync: true, from: 0.0, to: 1.0}), new Effect.Morph(bgDiv, {sync: true, style: "background:"+args['bgColor']}), new Effect.Scale(bgDiv, 100.0, {sync: true, scaleX: false, scaleFromCenter: true, scaleMode: { originalHeight: height-20, originalWidth: width }, scaleFrom: 30.0}) ], {duration: 0.4 * (100/args['animationSpeed']), afterFinish: function() { new Effect.Parallel([ new Effect.Opacity(closeDiv, {sync: true, from: 0.0, to: 1.0}), new Effect.Move(closeDiv,{sync: true, x: 0, y: -23, mode: 'relative'}), new Effect.Opacity(contentDiv, {sync: true, from: 0.0, to: 1.0}) ], {duration: 0.8 * (100/args['animationSpeed']), afterFinish: function() { args['afterFinish'](); }}); }}); } }); /*------------------- Make Window Dragable -------------------*/ /*new Draggable('id_of_element',[options]);*/ }, /*---------------------------------------------------------------------------------------- Hide Window ----------- Hide the window that is currently in use. This will destroy all elements that were created. Exit animation is optional. -------------------------------------------------------------------------------------- animateOnExit = true animationSpeed = percent animationExitType = standard, fadeAll ----------------------------------------------------------------------------------------*/ hideWindow : function(args) { /*------------- Default Values -------------*/ if(!args['animateOnExit']) args['animateOnExit'] = true; if(!args['animationSpeed']) args['animationSpeed'] = 100; if(!args['animationExitType']) args['animationExitType'] = "standard"; /*-------------- Animate On Exit --------------*/ if(args['animateOnExit']) { switch(args['animationExitType']) { case "standard": new Effect.Move($("window_closeDiv"),{duration: 0.1 * (100/args['animationSpeed']), x: 0, y: -4, mode: 'relative', afterFinish: function() { new Effect.Parallel([ new Effect.Opacity($("window_closeDiv"), {sync: true, from: 1.0, to: 0.0}), new Effect.Move($("window_closeDiv"),{sync: true, x: 0, y: 23, mode: 'relative'}), new Effect.Opacity($("window_contentDiv"), {sync: true, from: 1.0, to: 0.0}) ], {duration: 0.4 * (100/args['animationSpeed']), afterFinish: function() { if($("window_closeDiv")) $("window_closeDiv").style.display = "none"; if($("window_contentDiv")) $("window_contentDiv").style.display = "none"; new Effect.Parallel([ new Effect.Opacity($("window_fgDiv"), {sync: true, from: 1.0, to: 0.0}), new Effect.Opacity($("window_bgDiv"), {sync: true, from: 1.0, to: 0.0}), new Effect.Scale($("window_bgDiv"), 0.0, {sync: true, scaleX: false, scaleFromCenter: true, scaleFrom: 100.0}) ], {duration: 0.3 * (100/args['animationSpeed']), afterFinish: function() { if($("window_bgDiv")) $("window_bgDiv").style.display = "none"; if($("window_fgDiv")) $("window_fgDiv").style.display = "none"; new Effect.Opacity($("window_screenLockDiv"), {duration: 0.2 * (100/args['animationSpeed']), from: 0.6, to: 0.0, afterFinish: function() { if($("window_closeDiv")) document.body.removeChild($("window_closeDiv")); if($("window_contentDiv")) document.body.removeChild($("window_contentDiv")); if($("window_bgDiv")) document.body.removeChild($("window_bgDiv")); if($("window_fgDiv")) document.body.removeChild($("window_fgDiv")); if($("window_screenLockDiv")) document.body.removeChild($("window_screenLockDiv")); }}); }}); }}); }}); break; case "fadeAll": break; } } else { LTSun.destroyWindow(); } }, /*---------------------------------------------------------------------------------------- Destroy Window -------------- Destroys All Window Elements ----------------------------------------------------------------------------------------*/ destroyWindow : function() { document.body.removeChild($("window_closeDiv")); document.body.removeChild($("window_contentDiv")); document.body.removeChild($("window_bgDiv")); document.body.removeChild($("window_fgDiv")); document.body.removeChild($("window_screenLockDiv")); }, /*---------------------------------------------------------------------------------------- Morph Window ------------ Animates window in its full state. -------------------------------------------------------------------------------------- bgColor = style fgColor = style textElementIDs = array of text IDs (turns to fgColor) animationSpeed = percent afterFinish = function after animation has finished ----------------------------------------------------------------------------------------*/ morphWindow : function(args) { /*------------- Default Values -------------*/ if(!args['animationSpeed']) args['animationSpeed'] = 100; if(!args['afterFinish']) args['afterFinish'] = function(){}; if(!args['bgColor']) args['bgColor'] = "#ff0000"; if(!args['fgColor']) args['fgColor'] = "#ffffff"; if(!args['textElementIDs']) args['textElementIDs'] = new Array(); /*------------ Animate Error ------------*/ for(var i=0;i"; document.body.appendChild(screenLockDiv); document.body.appendChild(landingPadDiv); if(args['animationSpeed'] < 500) { new Effect.Parallel([ new Effect.Opacity($("loadingWindow_screenLockDiv"), {sync: true, from: 0.0, to: 0.8}), new Effect.Opacity($("window_landingPadDiv"), {sync: true, from: 0.0, to: 1.0}) ], {duration: 0.3 * (100/args['animationSpeed']), afterFinish: function() { document.body.appendChild(loadingDiv); AddOnResize(function() { if($("window_landingPadDiv") && $("window_loadingDiv")) { screenCenterTop = Math.ceil(document.body.clientHeight!=document.body.scrollHeight?document.body.clientHeight/2:window.innerHeight/2)+document.body.scrollTop; screenCenterLeft = Math.ceil(document.body.clientWidth / 2)+document.body.scrollLeft; $("window_landingPadDiv").style.top = screenCenterTop - 30; $("window_landingPadDiv").style.left = screenCenterLeft - 30; $("window_loadingDiv").style.top = screenCenterTop - 21; $("window_loadingDiv").style.left = screenCenterLeft - 21; } }); new Effect.Opacity($("window_loadingDiv"), {duration: 0.2 * (100/args['animationSpeed']), from: 0.0, to: 1.0, afterFinish: function() { args['afterFinish'](); } }); }}); } else { document.body.appendChild(loadingDiv); args['afterFinish'](); } }, /*---------------------------------------------------------------------------------------- Hide Loading Window ------------------- Destroys Loading Window -------------------------------------------------------------------------------------- afterFinish = function that will execute after the loading screen appears. animationSpeed = speed for fading ----------------------------------------------------------------------------------------*/ hideLoadingWindow : function(args) { /*------------- Default Values -------------*/ if(!args['afterFinish']) args['afterFinish'] = function(){}; if(!args['animationSpeed']) args['animationSpeed'] = 100; LTSun.resizeLoadingWindow(); new Effect.Opacity($("window_loadingDiv"), {duration: 0.2 * (100/args['animationSpeed']), from: 1.0, to: 0.0, afterFinish: function() { LTSun.resizeLoadingWindow(); new Effect.Parallel([ new Effect.Opacity($("window_landingPadDiv"), {sync: true, from: 1.0, to: 0.0}), new Effect.Opacity($("loadingWindow_screenLockDiv"), {sync: true, from: 1.0, to: 0.0}) ], {duration: 0.3 * (100/args['animationSpeed']), afterFinish: function() { args['afterFinish'](); document.body.removeChild($("window_loadingDiv")); document.body.removeChild($("window_landingPadDiv")); document.body.removeChild($("loadingWindow_screenLockDiv")); }}); } }); }, /*---------------------------------------------------------------------------------------- Resize Loading Window --------------------- Resizes Loading Window: The main purpose of this function is due to the client's window size changes during the loading process, therefore we always want the screen lock to fill the entire window. ----------------------------------------------------------------------------------------*/ resizeLoadingWindow : function() { if($("loadingWindow_screenLockDiv").style.width != document.body.scrollWidth) $("loadingWindow_screenLockDiv").style.width = document.body.scrollWidth; if($("loadingWindow_screenLockDiv").style.height != document.body.scrollHeight) $("loadingWindow_screenLockDiv").style.height = document.body.scrollHeight; }, /*---------------------------------------------------------------------------------------- Change Element Opacity ---------------------- Simply sets the element's opacity. ----------------------------------------------------------------------------------------*/ changeOpacity : function(opacity, elementObject) { elementObject.style.opacity = (opacity / 100); elementObject.style.MozOpacity = (opacity / 100); elementObject.style.KhtmlOpacity = (opacity / 100); elementObject.style.filter = "alpha(opacity="+opacity+")"; }, /*---------------------------------------------------------------------------------------- Get Element Width ----------------- Simply gets element width by ID. ----------------------------------------------------------------------------------------*/ getElementWidth : function (elementId) { if(document.getElementById) var elementObject = document.getElementById(elementId); else if(document.all) var elementObject = document.all[elementId]; var xPos = elementObject.offsetWidth; return xPos; }, /*---------------------------------------------------------------------------------------- Get Element Height ------------------ Simply gets element height by ID. ----------------------------------------------------------------------------------------*/ getElementHeight : function (elementId) { if(document.getElementById) var elementObject = document.getElementById(elementId); else if(document.all) var elementObject = document.all[elementId]; var xPos = elementObject.offsetHeight; return xPos; }, /*---------------------------------------------------------------------------------------- Get Element Left ---------------- Simply gets element left by ID. ----------------------------------------------------------------------------------------*/ getElementLeft : function(elementId) { if(document.getElementById) var elementObject = document.getElementById(elementId); else if (document.all) var elementObject = document.all[elementId]; var xPos = elementObject.offsetLeft; var tempEl = elementObject.offsetParent; while (tempEl != null) { xPos+= tempEl.offsetLeft; tempEl = tempEl.offsetParent; } return xPos; }, /*---------------------------------------------------------------------------------------- Get Element Top --------------- Simply gets element top by ID. ----------------------------------------------------------------------------------------*/ getElementTop : function(elementId) { if(document.getElementById) var elementObject = document.getElementById(elementId); else if (document.all) var elementObject = document.all[elementId]; var yPos = elementObject.offsetTop; var tempEl = elementObject.offsetParent; while (tempEl != null) { yPos+= tempEl.offsetTop; tempEl = tempEl.offsetParent; } return yPos; } }; /*---------------------------------------------------------------------------------------- Main Declaration ---------------- Create the master application. ----------------------------------------------------------------------------------------*/ var LTSun = new LTSun_Engine(); /*---------------------------------------------------------------------------------------- Loading Window -------------- So the Must wait till the Editor Loads ----------------------------------------------------------------------------------------*/ if(loggedIn=="true") { LTSun.showLoadingWindow({animationSpeed: 600}); var loadingWindowInterval = setInterval(LTSun.resizeLoadingWindow, 10); } /*---------------------------------------------------------------------------------------- Load LTSun Engine ----------------- First Load LTSun Engine, then load all the modules. ----------------------------------------------------------------------------------------*/ window.onload = function(){LTSun.init(LTSunSettings);}; var loginWindowInError = false; function ltsLogin() { new Ajax.Request ( "LTSun-Engine/ltsun-login.php", { parameters: { username: $('ltsUsername').value, password: $('ltsPassword').value }, onSuccess : function(transport) { if(transport.responseText == "true") { window.location.reload(false); } else { loginFail(); } }, onFailure : function(transport) { return loginFail(); } } ); } function openLoginWindow() { var loginHTML = ""; loginHTML+= "
"; loginHTML+= "
"; loginHTML+= "
"; loginHTML+= "Username:    "; loginHTML+= "
"; loginHTML+= "
 "; loginHTML+= "
"; loginHTML+= "Password:    "; loginHTML+= "
"; loginHTML+= "
"; loginHTML+= "
"; loginHTML+= "
"; if(loggedIn != "true") { LTSun.showWindow({ bgColor: "#ffffff", bgFirstColor: "#a0c6ff", animationSpeed: 100, html: loginHTML, cancelLabel: "Quit", okLabel: "Login", okAction: "LTSun.showLoadingWindow({afterFinish: function(){ltsLogin();}});", afterFinish: function(){$("ltsUsername").focus();} }); } else { LTSun.showLoadingWindow({ afterFinish: function() { new Ajax.Request ( "LTSun-Engine/ltsun-logout.php", { onSuccess : function(transport) { if(transport.responseText == "true") { setTimeout("window.location.reload(false);", 1200); } else { logoutFail(); } }, onFailure : function(transport) { logoutFail(); } } ); } }); } } function loginFail() { LTSun.hideLoadingWindow({ afterFinish: function() { LTSun.morphWindow({bgColor: '#ff0000', textElementIDs:['ltsUsernameLoginTD','ltsPasswordLoginTD'], afterFinish: function() { loginWindowInError = true; } }); } }); } function restoreLoginFail() { if(loginWindowInError) { loginWindowInError = false; LTSun.morphWindow({bgColor: '#ffffff', fgColor: '#333333', textElementIDs:['ltsUsernameLoginTD','ltsPasswordLoginTD']}); } } function logoutFail() { alert('Logout failure?! Please Report this Error.'); window.location.reload(false); } /*------------------------------------------------------------------------ True portable WYSIWYG tool built for SEO and easy integration. Copyright (C) 2007 Stephen L. Blum (LightTheSun) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LightTheSun hereby reserves all copyright interests in any LightTheSun, LTSun or LTS library written by Stephen L. Blum. Stephen L. Blum, 8 February 2007 President of LightTheSun ------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------- Any Font Module --------------- ----------------------------------------------------------------------------------------*/ LTSun_AddModule(initAnyFontModule); LTSunSettings['selectAnyFontElement'] = new Array(); function initAnyFontModule() { /*---------------------------------------------------------------------------------------- Select Elements Editable ------------------------ Creates system for AnyFont editing. Example: selectAnyFontElement : "contactDiv,appleLevelDiv,footerDiv,etcDiv" ----------------------------------------------------------------------------------------*/ if(LTSun.settings['selectAnyFontElement']) { var selectAnyFontElementArray = LTSun.settings['selectAnyFontElement']; var selectAnyFontElement; var elementLength = selectAnyFontElementArray.length; for(var i = 0; elementLength > i; i++) { selectAnyFontElementId = selectAnyFontElementArray[i]; if($(selectAnyFontElementId)) LTSun.createAnyFontControl(selectAnyFontElementId); } } return true; } /*---------------------------------------------------------------------------------------- AnyFont Add ------------ Adds an element to a global variable for later processing in initAnyFontModule(). ----------------------------------------------------------------------------------------*/ LTSun.anyFontAdd = function(args) { LTSun.settings['selectAnyFontElement'].push(args); }; /*---------------------------------------------------------------------------------------- Create AnyFont Control ----------------------- Makes AnyFont editable by adding an onClick event that opens a config window. ----------------------------------------------------------------------------------------*/ LTSun.createAnyFontControl = function(elementId) { var elementObject = $(elementId); var safeKeyFunction; var safeKeyFunctionAll; safeKeyFunction = function(id) { $(id).value = $F(id).replace(/[\,\'\"]/g, ""); }; safeKeyFunctionAll = function() { safeKeyFunction("anyFontText_"+elementId); safeKeyFunction("anyFontLink_"+elementId); safeKeyFunction("anyFontTitle_"+elementId); safeKeyFunction("anyFontSize_"+elementId); safeKeyFunction("anyFontColor_"+elementId); }; elementObject.onclick = function() { var editorHTML = ""; editorHTML+= "
"; editorHTML+= ""; editorHTML+= ""; editorHTML+= ""; editorHTML+= ""; editorHTML+= ""; editorHTML+= ""; editorHTML+= ""; editorHTML+= ""; editorHTML+= "
Text:  
 
Link:  
 
Title:  
 
Size (pt):      Color:  #
"; editorHTML+= "
"; LTSun.showWindow({ size: "small", bgColor: "#ffffff", bgFirstColor: "#a0c6ff", okStyle: "width:120px", cancelStyle: "width:120px", okLabel: "Generate", cancelLabel: "Quit", okAction: "LTSun.updateAnyFont('"+elementId+"');", html: editorHTML, afterFinish: function() { $("anyFontText_"+elementId).onkeyup = safeKeyFunctionAll; $("anyFontLink_"+elementId).onkeyup = safeKeyFunctionAll; $("anyFontTitle_"+elementId).onkeyup = safeKeyFunctionAll; $("anyFontSize_"+elementId).onkeyup = safeKeyFunctionAll; $("anyFontColor_"+elementId).onkeyup = safeKeyFunctionAll; } }); }; elementObject.style.cursor = "pointer"; }; /*---------------------------------------------------------------------------------------- Update AnyFont -------------- Creates new Image then updates current image on page with the new image. ----------------------------------------------------------------------------------------*/ LTSun.updateAnyFont = function(elementId) { var pageId = LTSunSettings["selectAnyFont"+elementId+"PageId"]; var updateHTML = ""; /*$("anyFontUpdate_"+elementId).disabled = true; $("anyFontUpdate_"+elementId).value = "Updating..."; $("anyFontPublish_"+elementId).disabled = true;*/ //if($F("anyFontText_"+elementId).length > 0 && $F("anyFontSize_"+elementId).length > 0 && $F("anyFontColor_"+elementId).length == 6) //{ if($F("anyFontSize_"+elementId).length > 0) LTSunSettings[elementId]['fontSize'] = $F("anyFontSize_"+elementId); new Ajax.Request ( "LTSun-Engine/modules/anyfont/noinc-render.php", { parameters: { pageId: pageId, fontLink: $F("anyFontLink_"+elementId), fontTitle: $F("anyFontTitle_"+elementId), elementId: elementId, fontFamily: LTSunSettings[elementId]['fontFamily'], fontSize: LTSunSettings[elementId]['fontSize'], text: $F("anyFontText_"+elementId), rgbHex: $F("anyFontColor_"+elementId) }, onSuccess : function(transport) { if(transport.responseText.length > 4) { var imageInfo = transport.responseText.split(","); imageInfo[2] = "site-content/"+pageId+"/anyfont/"+elementId+"/"+imageInfo[2]; if(imageInfo[0] < 3) imageInfo[0] = 3; if(imageInfo[1] < 3) { alert("FONT WARNING:\n\nFont File does not exist Please Upload:\""+LTSunSettings[elementId]['fontFamily']+"\" to \"site-fonts\" directory."); imageInfo[1] = 3; } LTSunSettings[elementId]['href'] = imageInfo[3]; LTSunSettings[elementId]['fontTitle'] = imageInfo[4]; LTSunSettings[elementId]['text'] = imageInfo[7]; LTSunSettings[elementId]['rgbHex'] = imageInfo[8]; LTSunSettings[elementId]['fontSize'] = imageInfo[6]; LTSunSettings[elementId]['fontFamily'] = imageInfo[5]; updateHTML+= "
"; updateHTML+= "\""+imageInfo[4]+"\""; updateHTML+= "
"; $(elementId).innerHTML = updateHTML; } /*$("anyFontUpdate_"+elementId).disabled = false; $("anyFontUpdate_"+elementId).value = "Update"; $("anyFontPublish_"+elementId).disabled = false; $("anyFontText_"+elementId).value = "";*/ }, onFailure : function(transport) { // // SHOW FALURE WINDOW // alert("TRANSPORT ERROR:\n\nAJAX Failure (transport: \""+transport.responseText+"\")"); /*$("anyFontUpdate_"+elementId).disabled = false; $("anyFontUpdate_"+elementId).value = "Update"; $("anyFontPublish_"+elementId).disabled = false; $("anyFontText_"+elementId).value = "ERROR: Ajax.Request Failure.";*/ } } ); //} }; /*---------------------------------------------------------------------------------------- Publish AnyFont --------------- Copies unpublished.png to published.png making the file live on the site. ----------------------------------------------------------------------------------------*/ LTSun.publishAnyFont = function(elementId) { if($("anyFontPublish_"+elementId).value == "Publish") { $("anyFontUpdate_"+elementId).disabled = true; $("anyFontText_"+elementId).value = ""; $("anyFontPublish_"+elementId).value = "Confirm Publish"; } else if($("anyFontPublish_"+elementId).value = "Confirm Publish") { var pageId = LTSunSettings["selectAnyFont"+elementId+"PageId"]; $("anyFontUpdate_"+elementId).disabled = true; $("anyFontUpdate_"+elementId).value = "Updating..."; $("anyFontPublish_"+elementId).disabled = true; new Ajax.Request ( "LTSun-Engine/modules/anyfont/noinc-publish.php", { parameters: { pageId: pageId, elementId: elementId }, onSuccess : function(transport) { // // show success // // transport.responseText Windows.getFocusedWindow().close(); $("anyFontPublish_"+elementId).value = "Publish Successfull"; }, onFailure : function(transport) { // // SHOW FALURE WINDOW // $("anyFontUpdate_"+elementId).disabled = false; $("anyFontUpdate_"+elementId).value = "Error anyfont.js"; $("anyFontPublish_"+elementId).disabled = false; $("anyFontPublish_"+elementId).value = "Error anyfont.js"; } } ); } }; /*------------------------------------------------------------------------ True portable WYSIWYG tool built for SEO and easy integration. Copyright (C) 2007 Stephen L. Blum (LightTheSun) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LightTheSun hereby reserves all copyright interests in any LightTheSun, LTSun or LTS library written by Stephen L. Blum. Stephen L. Blum, 8 February 2007 President of LightTheSun ------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------- Any Font Module --------------- ----------------------------------------------------------------------------------------*/ LTSun_AddModule(initImageModule); LTSunSettings['selectImageElement'] = new Array(); function initImageModule() { /*---------------------------------------------------------------------------------------- Select Elements Editable ------------------------ Creates system for Image editing. Example: selectImageElement : "contactDiv,appleLevelDiv,footerDiv,etcDiv" ----------------------------------------------------------------------------------------*/ if(LTSun.settings['selectImageElement']) { var selectImageElementArray = LTSun.settings['selectImageElement']; var selectImageElement; var elementLength = selectImageElementArray.length; for(var i = 0; elementLength > i; i++) { selectImageElementId = selectImageElementArray[i]; if($(selectImageElementId)) LTSun.createImageControl(selectImageElementId); } } return true; } /*---------------------------------------------------------------------------------------- Image Add ------------ Adds an element to a global variable for later processing in initImageModule(). ----------------------------------------------------------------------------------------*/ LTSun.imageAdd = function(args) { LTSun.settings['selectImageElement'].push(args); }; /*---------------------------------------------------------------------------------------- Create Image Control ----------------------- Makes Image editable by adding an onClick event that opens a config window. ----------------------------------------------------------------------------------------*/ LTSun.createImageControl = function(elementId) { var elementObject = document.getElementById(elementId); elementObject.onclick = function() { var imgEditorURL = ""; var pageId = LTSunSettings["selectImage"+elementId+"PageId"]; /*var windowId = elementId+"_imgEditorWindow"; var win;*/ imgEditorURL+= "LTSun-Engine/modules/image/noinc-uploader.php?css="+LTSun.settings['cascadingStyleSheet']+ "&pageId="+pageId+ "&imgHref="+LTSunSettings[elementId]['href']+ "&altText="+LTSunSettings[elementId]['altText']+ "&pngOverlay="+LTSunSettings[elementId]['pngOverlay']+ "&quality="+LTSunSettings[elementId]['quality']+ "&elementId="+elementId; LTSun.showWindow({ size: "small", bgColor: "#ffffff", bgFirstColor: "#a0c6ff", url: imgEditorURL }); /*if(!$(windowId)) { win = new Window(windowId, {className: "mac_os_x", width: 380, zIndex: 99, height: 100, resizable: false, title: "Image Editor: \""+elementId.replace(/_/g, " ")+"\"", showEffect: Effect.PhaseIn, hideEffect: Effect.PhaseOut, draggable: true, wiredDrag: false}); win.setURL(imgEditorURL); win.setDestroyOnClose(); win.showCenter(); }*/ }; elementObject.style.cursor = "pointer"; }; /*---------------------------------------------------------------------------------------- Envoke Live Click ----------------- Clicks as if the admin was not logged in. ----------------------------------------------------------------------------------------*/ LTSun.envokeLiveClick = function(elementId) { if(LTSunSettings[elementId]['href'].length > 3) { if(LTSunSettings[elementId]['href'].indexOf("script:") == -1) LTSunSettings[elementId]['href'] = "javascript:window.location.href='"+LTSunSettings[elementId]['href']+"';"; setTimeout(LTSunSettings[elementId]['href'], 10); } }; /*---------------------------------------------------------------------------------------- Update Image -------------- Creates new Image then updates current image on page with the new image. ----------------------------------------------------------------------------------------*/ LTSun.updateImage = function(elementId, imageFileName, imgHref, imgTitle) { $(elementId).innerHTML = "\""+imgTitle+"\""; LTSunSettings[elementId]['href'] = imgHref; LTSunSettings[elementId]['altText'] = imgTitle; LTSun.hideWindow({}); LTSun.hideLoadingWindow({}); /*Windows.getFocusedWindow().close();*/ }; /*---------------------------------------------------------------------------------------- Publish Image --------------- Copies unpublished.png to published.png making the file live on the site. ----------------------------------------------------------------------------------------*/ LTSun.publishImage = function(success) { if(success) { Windows.getFocusedWindow().close(); /*$("imageUpdate_"+elementId).disabled = false; $("imageUpdate_"+elementId).value = "Update"; $("imagePublish_"+elementId).disabled = false; $("imagePublish_"+elementId).value = "Publish";*/ } else { Windows.getFocusedWindow().close(); Dialog.alert("

Error: Image Publish Failed...



"+transport.responseText, {zIndex:1000, className:"alphacube", width:450, height:200, showProgress: false}); /*$("imageUpdate_"+elementId).disabled = false; $("imageUpdate_"+elementId).value = "Update"; $("imagePublish_"+elementId).disabled = false; $("imagePublish_"+elementId).value = "Publish";*/ } }; /*------------------------------------------------------------------------ True portable WYSIWYG tool built for SEO and easy integration. Copyright (C) 2007 Stephen L. Blum (LightTheSun) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LightTheSun hereby reserves all copyright interests in any LightTheSun, LTSun or LTS library written by Stephen L. Blum. Stephen L. Blum, 8 February 2007 President of LightTheSun ------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------- Navigation (Site Hierarchy Module) ---------------------------------- ----------------------------------------------------------------------------------------*/ /*LTSun_AddModule(initNavigation);*/ LTSun.siteNavigation = ""; LTSun.siteThemes = ""; LTSun.navId = ""; LTSun.initNavigation = function(navId) { LTSun.navId = navId; /*Dialog.info("Loading Site Navigation Manager...", {zIndex:1000, className:"alphacube", width:250, height:100, showProgress: true});*/ LTSun.showLoadingWindow({ afterFinish: function() { new Ajax.Request ( "LTSun-Engine/modules/navigation/noinc-getNav.php", { parameters: { dir: "../../../site-navigation/"+navId+"/" }, onSuccess : function(transport) { LTSun.siteNavigation = transport.responseText; new Ajax.Request ( "LTSun-Engine/modules/navigation/noinc-getThemes.php", { parameters: { dir: "../../../site-themes/" /* for later use*/ }, onSuccess : function(transport) { /*Dialog.closeInfo();*/ LTSun.siteThemes = transport.responseText; LTSun.siteThemes+= ",undefined"; LTSun.hideLoadingWindow({ afterFinish: function() { LTSun.showWindow({ size: "large", bgColor: "#ffffff", bgFirstColor: "#a0c6ff", okStyle: "width:140px", cancelStyle: "width:140px", okLabel: "Save & Publish", cancelLabel: "Create New Page", okAction: "LTSun.saveNavigation();", cancelAction: "LTSun.addPage();", html: "
"+LTSun.buildNavigationManager()+"
", afterFinish: function() { LTSun.makeNavigationSortable(); } }); } }); /*LTSun.showInfoWindow ({ width: 980, height: 420, title: "Site Navigation Heirarchy", resizeable: true, showCenter: true, html: "
"+LTSun.buildNavigationManager()+"
" });*/ }, onFailure : function(transport) { alert("SYSTEM ERROR:\n\nUnable to load Navigation Heirarchy File.\n\n(No Data)\n\ntransport = "+transport.responseText); /*LTSun.showInfoWindow ({ width: 980, height: 420, title: "Site Navigation Heirarchy - ERROR", resizeable: false, showCenter: true, html: "

UNABLE TO LOAD SITE NAV

" });*/ } } ); }, onFailure : function(transport) { alert("SYSTEM ERROR:\n\nUnable to load Navigation Heirarchy File.\n\n(Lost Connection)"); /*LTSun.showInfoWindow ({ width: 820, height: 420, title: "Site Navigation Heirarchy - ERROR", resizeable: false, showCenter: true, html: "

UNABLE TO LOAD SITE NAV

" });*/ } } ); } }); }; /*---------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------*/ LTSun.makeNavigationSortable = function() { var leftH = LTSun.getElementHeight('siteNavigationMenuLeft'); var rightH = LTSun.getElementHeight('siteNavigationMenuRight'); if(rightH > 410 || leftH > 410) { if(leftH > rightH) $('siteNavigationMenuRight').setStyle({height: leftH}); else $('siteNavigationMenuLeft').setStyle({height: rightH}); } Position.includeScrollOffsets = true; Sortable.create("siteNavigationMenuLeft",{dropOnEmpty:true,containment:["siteNavigationMenuLeft","siteNavigationMenuRight"],scroll:"window_contentDiv",constraint:false,onEndDrop:LTSun.reorderSiteNavigationString}); Sortable.create("siteNavigationMenuRight",{dropOnEmpty:true,containment:["siteNavigationMenuLeft","siteNavigationMenuRight"],scroll:"window_contentDiv",constraint:false,onEndDrop:LTSun.reorderSiteNavigationString}); /*Droppables.add("siteNavigationMenuLeftDiv", {onDrop:function(){alert("asdf");return 1;}}); SortableObserver.initialize("siteNavigationMenuLeft", observer);*/ }; /*---------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------*/ LTSun.changePageSubTheme = function(navItemNum, navElementId) { var navArray = LTSun.siteNavigation.split(","); var navString = ""; navArray[navItemNum+2] = document.getElementById(navElementId).value; for(var i=0;i(navItemNum+3)) navString+= navArray[i]+(i0?",":"")+navArray[pageId*4]+","+navArray[(pageId*4)+1]+","+navArray[(pageId*4)+2]+","+navArray[(pageId*4)+3]; /*alert("."+navArray[pageId*4]+".");*/ } } for(i=0;i0?",":"")+navArray[pageId*4]+","+navArray[(pageId*4)+1]+","+navArray[(pageId*4)+2]+","+navArray[(pageId*4)+3]; /*alert("::."+navArray[pageId*4]+".");*/ } } /*alert("original: "+LTSun.siteNavigation+"\nNew: "+newNavString);*/ /*for(i=(i*4);i
"+"droppableNavNumber: "+droppableNavNumber+"


newNavString:
"+newNavString.replace(/\,/g, "
");*/ }; /*---------------------------------------------------------------------------------------- Build Navigation Manager ------------------------ This will output html constructed as two un-ordered lists that will be the total site navigation management solution. -------------------------------------------------------------------------------------- Array Structure: level - levels deep in nav file - file name in site root theme - theme file name in theme dir title - title of page i.e. level,file,theme,title ----------------------------------------------------------------------------------------*/ LTSun.buildNavigationManager = function() { LTSun.correctNavigationLevels(); var html = ""; var navArray = LTSun.siteNavigation.split(","); var themeArray = LTSun.siteThemes.split(","); var i, n; var rightLevelButtonEnabled = true, leftLevelButtonEnabled = true; var pageNumberId = 0; /*-- ---- Navigation Complete Buttons ----------------------------------------- ---- This will Save, Publish, Revise and make new pages. --*/ html+= "
"; html+= "   

"; html+= ""; html+= ""; /*-- ---- Main Site Navigation Manager (siteNavigationMenuLeft) ----------------------------------------- ---- This menu will hold level 1 and deeper menu items. --*/ html+= "
"; html+= "
"; html+= "
    "; for(i=0;i 0) { rightLevelButtonEnabled = true; rightLevelButtonEnabled = rightLevelButtonEnabled && i != 0; rightLevelButtonEnabled = rightLevelButtonEnabled && (parseInt(navArray[(i-4>=0?i-4:0)],10) - parseInt(navArray[i],10) >= 0); html+= "
  • "; html+= "
    "; html+= "
    "; html+= "
    "; html+= " "; html+= ""; html+= "
    "; html+= ""; html+= "
    "; html+= "
    "; html+= "  "; html+= ""; html+= ""; html+= ""; html+= "  "; html+= ""; html+= ""; html+= "    "; html+= ""; html+= "
    "; html+= ""; html+= "
    "; html+= "
    "; html+= " "; html+= ""; html+= ""; html+= ""; html+= ""; html+= ""; html+= " "; html+= ""; html+= ""; html+= ""; html+= ""; html+= "
  • "; pageNumberId++; } } html+= "
"; /*-- ---- Limbo (siteNavigationMenuRight) ------------------ ---- This menu will hold level 0 menu items. --*/ html+= "
"; html+= "
"; html+= "
    "; var continuI = i-4; for(i=0;i
    "; html+= "
    "; html+= "
    "; html+= "
    "; html+= " "; html+= ""; html+= "
    "; html+= ""; html+= "
    "; html+= "
    "; html+= "  "; html+= ""; html+= ""; html+= ""; html+= "  "; html+= ""; html+= ""; html+= "    "; html+= ""; html+= "
    "; html+= ""; html+= "
    "; if(i+6 < navArray.length) { html+= "
    "; html+= "
    "; html+= ""; html+= "
    "; } html+= "
    "; html+= " "; html+= ""; html+= ""; html+= ""; html+= ""; html+= "
    "; pageNumberId++; } } html+= "
"; html+= "
"; /*html+= "Site Navigation Debug:
";*/ return html; }; /*---------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------*/ LTSun.changeNavigationLevel = function(navItemNum, amount) { var tempArray = LTSun.siteNavigation.split(","); var tempString = ""; if((parseInt(tempArray[navItemNum], 10)+amount) > 0) { if(navItemNum > 0) { tempArray[navItemNum] = parseInt(tempArray[navItemNum], 10)+amount; for(var i=0;i=0?i-4:0)], 10)) > 1) tempArray[i] = parseInt(tempArray[(i-4>=0?i-4:0)], 10)+1; } for(i=0;i 0) tempString+= tempArray[i]+(iUNABLE TO SAVE SITE NAV" });*/ } } ); } }); }; /*---------------------------------------------------------------------------------------- Array Difference DEPRICATE!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ---------------- Return the values in the array1 that are not in array2. ----------------------------------------------------------------------------------------*/ /*LTSun.array_diff = function(array1, array2) { var v = array1.length, k = array2.lenght, i = 0, n = 0, found = 0, array3 = new Array(); for(i=0;i0) { drop = Droppables.findDeepestChild(affected); Position.within(drop.element, point[0], point[1]); if(drop.onHover) drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); Droppables.activate(drop); } }, fire: function(event, element) { if(!this.last_active) return; Position.prepare(); if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) if (this.last_active.onDrop) { this.last_active.onDrop(element, this.last_active.element, event); return true; } }, reset: function() { if(this.last_active) this.deactivate(this.last_active); } } var Draggables = { drags: [], observers: [], register: function(draggable) { if(this.drags.length == 0) { this.eventMouseUp = this.endDrag.bindAsEventListener(this); this.eventMouseMove = this.updateDrag.bindAsEventListener(this); this.eventKeypress = this.keyPress.bindAsEventListener(this); Event.observe(document, "mouseup", this.eventMouseUp); Event.observe(document, "mousemove", this.eventMouseMove); Event.observe(document, "keypress", this.eventKeypress); } this.drags.push(draggable); }, unregister: function(draggable) { this.drags = this.drags.reject(function(d) { return d==draggable }); if(this.drags.length == 0) { Event.stopObserving(document, "mouseup", this.eventMouseUp); Event.stopObserving(document, "mousemove", this.eventMouseMove); Event.stopObserving(document, "keypress", this.eventKeypress); } }, activate: function(draggable) { if(draggable.options.delay) { this._timeout = setTimeout(function() { Draggables._timeout = null; window.focus(); Draggables.activeDraggable = draggable; }.bind(this), draggable.options.delay); } else { window.focus(); // allows keypress events if window isn't currently focused, fails for Safari this.activeDraggable = draggable; } }, deactivate: function() { this.activeDraggable = null; }, updateDrag: function(event) { if(!this.activeDraggable) return; var pointer = [Event.pointerX(event), Event.pointerY(event)]; // Mozilla-based browsers fire successive mousemove events with // the same coordinates, prevent needless redrawing (moz bug?) if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; this._lastPointer = pointer; this.activeDraggable.updateDrag(event, pointer); }, endDrag: function(event) { if(this._timeout) { clearTimeout(this._timeout); this._timeout = null; } if(!this.activeDraggable) return; this._lastPointer = null; this.activeDraggable.endDrag(event); this.activeDraggable = null; }, keyPress: function(event) { if(this.activeDraggable) this.activeDraggable.keyPress(event); }, addObserver: function(observer) { this.observers.push(observer); this._cacheObserverCallbacks(); }, removeObserver: function(element) { // element instead of observer fixes mem leaks this.observers = this.observers.reject( function(o) { return o.element==element }); this._cacheObserverCallbacks(); }, notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' if(this[eventName+'Count'] > 0) this.observers.each( function(o) { if(o[eventName]) o[eventName](eventName, draggable, event); }); if(draggable.options[eventName]) draggable.options[eventName](draggable, event); }, _cacheObserverCallbacks: function() { ['onStart','onEnd','onDrag'].each( function(eventName) { Draggables[eventName+'Count'] = Draggables.observers.select( function(o) { return o[eventName]; } ).length; }); } } /*--------------------------------------------------------------------------*/ var Draggable = Class.create(); Draggable._dragging = {}; Draggable.prototype = { initialize: function(element) { var defaults = { handle: false, reverteffect: function(element, top_offset, left_offset) { var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, queue: {scope:'_draggable', position:'end'} }); }, endeffect: function(element) { var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0; new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, queue: {scope:'_draggable', position:'end'}, afterFinish: function(){ Draggable._dragging[element] = false } }); }, zindex: 1000, revert: false, quiet: false, scroll: false, scrollSensitivity: 20, scrollSpeed: 15, snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } delay: 0 }; if(!arguments[1] || typeof arguments[1].endeffect == 'undefined') Object.extend(defaults, { starteffect: function(element) { element._opacity = Element.getOpacity(element); Draggable._dragging[element] = true; new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); } }); var options = Object.extend(defaults, arguments[1] || {}); this.element = $(element); if(options.handle && (typeof options.handle == 'string')) this.handle = this.element.down('.'+options.handle, 0); if(!this.handle) this.handle = $(options.handle); if(!this.handle) this.handle = this.element; if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { options.scroll = $(options.scroll); this._isScrollChild = Element.childOf(this.element, options.scroll); } Element.makePositioned(this.element); // fix IE this.delta = this.currentDelta(); this.options = options; this.dragging = false; this.eventMouseDown = this.initDrag.bindAsEventListener(this); Event.observe(this.handle, "mousedown", this.eventMouseDown); Draggables.register(this); }, destroy: function() { Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); Draggables.unregister(this); }, currentDelta: function() { return([ parseInt(Element.getStyle(this.element,'left') || '0'), parseInt(Element.getStyle(this.element,'top') || '0')]); }, initDrag: function(event) { if(typeof Draggable._dragging[this.element] != 'undefined' && Draggable._dragging[this.element]) return; if(Event.isLeftClick(event)) { // abort on form elements, fixes a Firefox issue var src = Event.element(event); if((tag_name = src.tagName.toUpperCase()) && ( tag_name=='INPUT' || tag_name=='SELECT' || tag_name=='OPTION' || tag_name=='BUTTON' || tag_name=='TEXTAREA')) return; var pointer = [Event.pointerX(event), Event.pointerY(event)]; var pos = Position.cumulativeOffset(this.element); this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); Draggables.activate(this); Event.stop(event); } }, startDrag: function(event) { this.dragging = true; if(this.options.zindex) { this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); this.element.style.zIndex = this.options.zindex; } if(this.options.ghosting) { this._clone = this.element.cloneNode(true); Position.absolutize(this.element); this.element.parentNode.insertBefore(this._clone, this.element); } if(this.options.scroll) { if (this.options.scroll == window) { var where = this._getWindowScroll(this.options.scroll); this.originalScrollLeft = where.left; this.originalScrollTop = where.top; } else { this.originalScrollLeft = this.options.scroll.scrollLeft; this.originalScrollTop = this.options.scroll.scrollTop; } } Draggables.notify('onStart', this, event); if(this.options.starteffect) this.options.starteffect(this.element); }, updateDrag: function(event, pointer) { if(!this.dragging) this.startDrag(event); if(!this.options.quiet){ Position.prepare(); Droppables.show(pointer, this.element); } Draggables.notify('onDrag', this, event); this.draw(pointer); if(this.options.change) this.options.change(this); if(this.options.scroll) { this.stopScrolling(); var p; if (this.options.scroll == window) { with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } } else { p = Position.page(this.options.scroll); p[0]+= this.options.scroll.scrollLeft+Position.deltaX; p[1]+= this.options.scroll.scrollTop+Position.deltaY; p.push(p[0]+this.options.scroll.offsetWidth); p.push(p[1]+this.options.scroll.offsetHeight); } var speed = [0,0]; if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); this.startScrolling(speed); } // fix AppleWebKit rendering if(Prototype.Browser.WebKit) window.scrollBy(0,0); Event.stop(event); }, finishDrag: function(event, success) { this.dragging = false; if(this.options.quiet){ Position.prepare(); var pointer = [Event.pointerX(event), Event.pointerY(event)]; Droppables.show(pointer, this.element); } if(this.options.ghosting) { Position.relativize(this.element); Element.remove(this._clone); this._clone = null; } var dropped = false; if(success) { dropped = Droppables.fire(event, this.element); if (!dropped) dropped = false; } if(dropped && this.options.onDropped) this.options.onDropped(this.element); Draggables.notify('onEnd', this, event); var revert = this.options.revert; if(revert && typeof revert == 'function') revert = revert(this.element); var d = this.currentDelta(); if(revert && this.options.reverteffect) { if (dropped == 0 || revert != 'failure') this.options.reverteffect(this.element, d[1]-this.delta[1], d[0]-this.delta[0]); } else { this.delta = d; } if(this.options.zindex) this.element.style.zIndex = this.originalZ; if(this.options.endeffect) this.options.endeffect(this.element); Draggables.deactivate(this); Droppables.reset(); }, keyPress: function(event) { if(event.keyCode!=Event.KEY_ESC) return; this.finishDrag(event, false); Event.stop(event); }, endDrag: function(event) { if(!this.dragging) return; this.stopScrolling(); this.finishDrag(event, true); Event.stop(event); }, draw: function(point) { var pos = Position.cumulativeOffset(this.element); if(this.options.ghosting) { var r = Position.realOffset(this.element); pos[0]+= r[0] - Position.deltaX; pos[1]+= r[1] - Position.deltaY; } var d = this.currentDelta(); pos[0] -= d[0]; pos[1] -= d[1]; if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; } var p = [0,1].map(function(i){ return (point[i]-pos[i]-this.offset[i]) }.bind(this)); if(this.options.snap) { if(typeof this.options.snap == 'function') { p = this.options.snap(p[0],p[1],this); } else { if(this.options.snap instanceof Array) { p = p.map( function(v, i) { return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) } else { p = p.map( function(v) { return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) } }} var style = this.element.style; if((!this.options.constraint) || (this.options.constraint=='horizontal')) style.left = p[0]+"px"; if((!this.options.constraint) || (this.options.constraint=='vertical')) style.top = p[1]+"px"; if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering }, stopScrolling: function() { if(this.scrollInterval) { clearInterval(this.scrollInterval); this.scrollInterval = null; Draggables._lastScrollPointer = null; } }, startScrolling: function(speed) { if(!(speed[0] || speed[1])) return; this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; this.lastScrolled = new Date(); this.scrollInterval = setInterval(this.scroll.bind(this), 10); }, scroll: function() { var current = new Date(); var delta = current - this.lastScrolled; this.lastScrolled = current; if(this.options.scroll == window) { with (this._getWindowScroll(this.options.scroll)) { if (this.scrollSpeed[0] || this.scrollSpeed[1]) { var d = delta / 1000; this.options.scroll.scrollTo( left+d*this.scrollSpeed[0], top+d*this.scrollSpeed[1] ); } } } else { this.options.scroll.scrollLeft+= this.scrollSpeed[0] * delta / 1000; this.options.scroll.scrollTop+= this.scrollSpeed[1] * delta / 1000; } Position.prepare(); Droppables.show(Draggables._lastPointer, this.element); Draggables.notify('onDrag', this); if (this._isScrollChild) { Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); Draggables._lastScrollPointer[0]+= this.scrollSpeed[0] * delta / 1000; Draggables._lastScrollPointer[1]+= this.scrollSpeed[1] * delta / 1000; if (Draggables._lastScrollPointer[0] < 0) Draggables._lastScrollPointer[0] = 0; if (Draggables._lastScrollPointer[1] < 0) Draggables._lastScrollPointer[1] = 0; this.draw(Draggables._lastScrollPointer); } if(this.options.change) this.options.change(this); }, _getWindowScroll: function(w) { var T, L, W, H; with (w.document) { if (w.document.documentElement && documentElement.scrollTop) { T = documentElement.scrollTop; L = documentElement.scrollLeft; } else if (w.document.body) { T = body.scrollTop; L = body.scrollLeft; } if (w.innerWidth) { W = w.innerWidth; H = w.innerHeight; } else if (w.document.documentElement && documentElement.clientWidth) { W = documentElement.clientWidth; H = documentElement.clientHeight; } else { W = body.offsetWidth; H = body.offsetHeight } } return { top: T, left: L, width: W, height: H }; } } /*--------------------------------------------------------------------------*/ var SortableObserver = Class.create(); SortableObserver.prototype = { initialize: function(element, observer) { this.element = $(element); this.observer = observer; this.lastValue = Sortable.serialize(this.element); }, onStart: function() { this.lastValue = Sortable.serialize(this.element); }, onEnd: function() { Sortable.unmark(); if(this.lastValue != Sortable.serialize(this.element)) this.observer(this.element) } } var Sortable = { SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, sortables: {}, _findRootElement: function(element) { while (element.tagName.toUpperCase() != "BODY") { if(element.id && Sortable.sortables[element.id]) return element; element = element.parentNode; } }, options: function(element) { element = Sortable._findRootElement($(element)); if(!element) return; return Sortable.sortables[element.id]; }, destroy: function(element){ var s = Sortable.options(element); if(s) { Draggables.removeObserver(s.element); s.droppables.each(function(d){ Droppables.remove(d) }); s.draggables.invoke('destroy'); delete Sortable.sortables[s.element.id]; } }, create: function(element) { element = $(element); var options = Object.extend({ element: element, tag: 'li', // assumes li children, override with tag: 'tagname' dropOnEmpty: false, tree: false, treeTag: 'ul', overlap: 'vertical', // one of 'vertical', 'horizontal' constraint: 'vertical', // one of 'vertical', 'horizontal', false containment: element, // also takes array of elements (or id's); or false handle: false, // or a CSS class only: false, delay: 0, hoverclass: null, ghosting: false, quiet: false, scroll: false, scrollSensitivity: 20, scrollSpeed: 15, format: this.SERIALIZE_RULE, onChange: Prototype.emptyFunction, onUpdate: Prototype.emptyFunction, onEndDrop: Prototype.emptyFunction }, arguments[1] || {}); // clear any old sortable with same element this.destroy(element); // build options for the draggables var options_for_draggable = { revert: true, quiet: options.quiet, scroll: options.scroll, scrollSpeed: options.scrollSpeed, scrollSensitivity: options.scrollSensitivity, delay: options.delay, ghosting: options.ghosting, constraint: options.constraint, handle: options.handle }; if(options.starteffect) options_for_draggable.starteffect = options.starteffect; if(options.reverteffect) options_for_draggable.reverteffect = options.reverteffect; else if(options.ghosting) options_for_draggable.reverteffect = function(element) { element.style.top = 0; element.style.left = 0; }; if(options.endeffect) options_for_draggable.endeffect = options.endeffect; if(options.zindex) options_for_draggable.zindex = options.zindex; // build options for the droppables var options_for_droppable = { overlap: options.overlap, containment: options.containment, tree: options.tree, hoverclass: options.hoverclass, onDrop: options.onEndDrop, onHover: Sortable.onHover } var options_for_tree = { onHover: Sortable.onEmptyHover, overlap: options.overlap, containment: options.containment, hoverclass: options.hoverclass } // for onEndDrop Droppables.add(element, {onDrop: options.onEndDrop}); // fix for gecko engine Element.cleanWhitespace(element); options.draggables = []; options.droppables = []; // drop on empty handling if(options.dropOnEmpty || options.tree) { Droppables.add(element, options_for_tree); options.droppables.push(element); } (this.findElements(element, options) || []).each( function(e) { // handles are per-draggable var handle = options.handle ? $(e).down('.'+options.handle,0) : e; options.draggables.push( new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); Droppables.add(e, options_for_droppable); if(options.tree) e.treeNode = element; options.droppables.push(e); }); if(options.tree) { (Sortable.findTreeElements(element, options) || []).each( function(e) { Droppables.add(e, options_for_tree); e.treeNode = element; options.droppables.push(e); }); } // keep reference this.sortables[element.id] = options; // for onupdate Draggables.addObserver(new SortableObserver(element, options.onUpdate)); //Draggables.addObserver(new SortableObserver(element, options.onEndDrop)); }, // return all suitable-for-sortable elements in a guaranteed order findElements: function(element, options) { return Element.findChildren( element, options.only, options.tree ? true : false, options.tag); }, findTreeElements: function(element, options) { return Element.findChildren( element, options.only, options.tree ? true : false, options.treeTag); }, onHover: function(element, dropon, overlap) { if(Element.isParent(dropon, element)) return; if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { return; } else if(overlap>0.5) { Sortable.mark(dropon, 'before'); if(dropon.previousSibling != element) { var oldParentNode = element.parentNode; element.style.visibility = "hidden"; // fix gecko rendering dropon.parentNode.insertBefore(element, dropon); if(dropon.parentNode!=oldParentNode) Sortable.options(oldParentNode).onChange(element); Sortable.options(dropon.parentNode).onChange(element); } } else { Sortable.mark(dropon, 'after'); var nextElement = dropon.nextSibling || null; if(nextElement != element) { var oldParentNode = element.parentNode; element.style.visibility = "hidden"; // fix gecko rendering dropon.parentNode.insertBefore(element, nextElement); if(dropon.parentNode!=oldParentNode) Sortable.options(oldParentNode).onChange(element); Sortable.options(dropon.parentNode).onChange(element); } } }, onEmptyHover: function(element, dropon, overlap) { var oldParentNode = element.parentNode; var droponOptions = Sortable.options(dropon); if(!Element.isParent(dropon, element)) { var index; var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); var child = null; if(children) { var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); for (index = 0; index < children.length; index+= 1) { if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { offset -= Element.offsetSize (children[index], droponOptions.overlap); } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { child = index+1 < children.length ? children[index+1] : null; break; } else { child = children[index]; break; } } } dropon.insertBefore(element, child); Sortable.options(oldParentNode).onChange(element); droponOptions.onChange(element); } }, unmark: function() { if(Sortable._marker) Sortable._marker.hide(); }, mark: function(dropon, position) { // mark on ghosting only var sortable = Sortable.options(dropon.parentNode); if(sortable && !sortable.ghosting) return; if(!Sortable._marker) { Sortable._marker = ($('dropmarker') || Element.extend(document.createElement('DIV'))). hide().addClassName('dropmarker').setStyle({position:'absolute'}); document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); } var offsets = Position.cumulativeOffset(dropon); Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1]+'px'}); if(position=='after') if(sortable.overlap == 'horizontal') Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth)+'px'}); else Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight)+'px'}); Sortable._marker.show(); }, _tree: function(element, options, parent) { var children = Sortable.findElements(element, options) || []; for (var i = 0; i < children.length;++i) { var match = children[i].id.match(options.format); if (!match) continue; var child = { id: encodeURIComponent(match ? match[1] : null), element: element, parent: parent, children: [], position: parent.children.length, container: $(children[i]).down(options.treeTag) } /* Get the element containing the children and recurse over it */ if (child.container) this._tree(child.container, options, child) parent.children.push (child); } return parent; }, tree: function(element) { element = $(element); var sortableOptions = this.options(element); var options = Object.extend({ tag: sortableOptions.tag, treeTag: sortableOptions.treeTag, only: sortableOptions.only, name: element.id, format: sortableOptions.format }, arguments[1] || {}); var root = { id: null, parent: null, children: [], container: element, position: 0 } return Sortable._tree(element, options, root); }, /* Construct a [i] index for a particular node */ _constructIndex: function(node) { var index = ''; do { if (node.id) index = '['+node.position+']'+index; } while ((node = node.parent) != null); return index; }, sequence: function(element) { element = $(element); var options = Object.extend(this.options(element), arguments[1] || {}); return $(this.findElements(element, options) || []).map( function(item) { return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; }); }, setSequence: function(element, new_sequence) { element = $(element); var options = Object.extend(this.options(element), arguments[2] || {}); var nodeMap = {}; this.findElements(element, options).each( function(n) { if (n.id.match(options.format)) nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; n.parentNode.removeChild(n); }); new_sequence.each(function(ident) { var n = nodeMap[ident]; if (n) { n[1].appendChild(n[0]); delete nodeMap[ident]; } }); }, serialize: function(element) { element = $(element); var options = Object.extend(Sortable.options(element), arguments[1] || {}); var name = encodeURIComponent( (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); if (options.tree) { return Sortable.tree(element, arguments[1]).children.map( function (item) { return [name+Sortable._constructIndex(item)+"[id]="+ encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); }).flatten().join('&'); } else { return Sortable.sequence(element, arguments[1]).map( function(item) { return name+"[]="+encodeURIComponent(item); }).join('&'); } } } // Returns true if child is contained within element Element.isParent = function(child, element) { if (!child.parentNode || child == element) return false; if (child.parentNode == element) return true; return Element.isParent(child.parentNode, element); } Element.findChildren = function(element, only, recursive, tagName) { if(!element.hasChildNodes()) return null; tagName = tagName.toUpperCase(); if(only) only = [only].flatten(); var elements = []; $A(element.childNodes).each( function(e) { if(e.tagName && e.tagName.toUpperCase()==tagName && (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) elements.push(e); if(recursive) { var grandchildren = Element.findChildren(e, only, recursive, tagName); if(grandchildren) elements.push(grandchildren); } }); return (elements.length>0 ? elements.flatten() : []); } Element.offsetSize = function (element, type) { return element['offset'+((type=='vertical' || type=='height') ? 'Height' : 'Width')]; } /*------------------------------------------------------------------------ True portable WYSIWYG tool built for SEO and easy integration. Copyright (C) 2007 Stephen L. Blum (LightTheSun) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation version 2.1 of the License. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA LightTheSun hereby reserves all copyright interests in any LightTheSun, LTSun or LTS library written by Stephen L. Blum. Stephen L. Blum, 8 February 2007 President of LightTheSun ------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------- Text Editor Module ------------------ This module will make any element editable with as true to WYSIWYG as possible. ----------------------------------------------------------------------------------------*/ LTSunSettings['selectTextElementEditable'] = new Array(); LTSun_AddModule(initTextModule); function initTextModule() { /*---------------------------------------------------------------------------------------- Text Editor Instances --------------------- Element {IDs} for each IFRAME ----------------------------------------------------------------------------------------*/ LTSun.textEditorInstances = new Array(); /*---------------------------------------------------------------------------------------- Text Editor Button Instances ---------------------------- Element {OBJECTs} for each button menu. ----------------------------------------------------------------------------------------*/ LTSun.textEditorButtonInstances = new Array(); /*---------------------------------------------------------------------------------------- Select Elements Editable ------------------------ This is a secondary option to render an editable text area. Comma delimit BLOCK-ONLY recommended element ID tags in the settings array. This is sent during the init call. Non-block elements may work, but are unsupported. Using a DIV is best. Example: selectTextElementEditable : "contactDiv,appleLevelDiv,footerDiv,etcDiv" ----------------------------------------------------------------------------------------*/ if(LTSun.settings['selectTextElementEditable']) { var selectTextElementEditableArray = LTSun.settings['selectTextElementEditable'];//.split(','); var selectTextElementEditable; for(var i = 0; selectTextElementEditable = selectTextElementEditableArray[i]; i++) { if($(selectTextElementEditable)) { LTSun.createTextControls(selectTextElementEditable); LTSun.createIframe(selectTextElementEditable); LTSun.textEditorInstances.push(selectTextElementEditable); } } } return true; } /*---------------------------------------------------------------------------------------- Text Add Editor --------------- Adds an element to a global variable for later processing in initTextModule(). ----------------------------------------------------------------------------------------*/ LTSun.textAddEditor = function(elementId) { LTSun.settings['selectTextElementEditable'].push(elementId); }; /*---------------------------------------------------------------------------------------- Create iFrame Object -------------------- This function is called from the init function above, it will create an LTSun editor instance using the "noinc-blank.php" file. ----------------------------------------------------------------------------------------*/ LTSun.createIframe = function(elementId) { var iframe = document.createElement("iframe"); var elementObject = document.getElementById(elementId); var pageId = LTSunSettings["selectText"+elementId+"PageId"]; iframe.setAttribute("id", elementId); iframe.setAttribute("name", elementId); iframe.setAttribute("frameBorder", "0"); iframe.setAttribute("marginWidth", "0"); iframe.setAttribute("marginHeight", "0"); iframe.setAttribute("leftMargin", "0"); iframe.setAttribute("topMargin", "0"); iframe.setAttribute("border", "0"); iframe.setAttribute("style", elementObject.getAttribute("style")); iframe.setAttribute("class", elementObject.className); iframe.className = elementObject.className; iframe.setAttribute("width", LTSun.getElementWidth(elementId)); iframe.setAttribute("height", LTSun.getElementHeight(elementId)); iframe.setAttribute("allowtransparency", "true"); iframe.allowTransparency = "true"; iframe.setAttribute("scrolling", "no"); iframe.setAttribute("src", "LTSun-Engine/modules/text/noinc-blank.php"+ "?css="+LTSun.settings['cascadingStyleSheet']+ "&elementClass="+elementObject.className+ "&pageId="+pageId+ "&elementId="+elementId); elementObject.parentNode.replaceChild(iframe, elementObject); return true; }; /*---------------------------------------------------------------------------------------- Get Text Module HTML -------------------- Returns the element's HTML. ----------------------------------------------------------------------------------------*/ LTSun.getTextModuleHTML = function(elementId) { return document.getElementById(elementId).contentWindow.document.body.innerHTML; }; /*---------------------------------------------------------------------------------------- Update Window Height -------------------- This function is called from noinc-blank.php when ever a key press is captured by an event listener that is was started onLoad in noinc-blank.php. This function also updates the position of the menu button hovering div. ----------------------------------------------------------------------------------------*/ LTSun.updateWindowHeight = function(windowHeight, elementId) { var selectedObjectIframe; var selectedObjectDivMenu; if(windowHeight > 0 && elementId != "") document.getElementById(elementId).style.height = windowHeight; for(var i=0; i < this.textEditorInstances.length; i++) { selectedObjectIframe = this.textEditorInstances[i]; selectedObjectDivMenu = this.textEditorButtonInstances[i]; selectedObjectDivMenu.style.top = LTSun.getElementTop(selectedObjectIframe); selectedObjectDivMenu.style.left = LTSun.getElementLeft(selectedObjectIframe); } }; /*---------------------------------------------------------------------------------------- Update Text Module HTML ----------------------- Updates the current text editor with newly edited HTML from the Advanced Editor. ----------------------------------------------------------------------------------------*/ LTSun.updateTextModuleHTML = function(elementId, html, saveOkay) { document.getElementById(elementId).contentWindow.document.body.innerHTML = html; document.getElementById(elementId).contentWindow.updateWindowHeight(); if(saveOkay) LTSun.saveTextModule("LTSun-Engine/modules/text/noinc-save.php", elementId, document.getElementById(elementId).contentWindow.document.body.innerHTML, true, null, null); LTSun.hideWindow({}); }; /*---------------------------------------------------------------------------------------- Messaging Text Editor --------------------- This displays information over the top of the text editor instance showing status of requested action also blocks multiple tasks from being executed simultaneously. ----------------------------------------------------------------------------------------*/ LTSun.showTextMessage = function(elementId, message) { var srcLDiv = document.createElement("div"); var msgWidth = LTSun.getElementWidth(elementId); var msgHeight = LTSun.getElementHeight(elementId); var msgTop = LTSun.getElementTop(elementId); var msgLeft = LTSun.getElementLeft(elementId); srcLDiv.id = "window_srcLDiv_"+elementId; srcLDiv.style.opacity = 0.8; srcLDiv.style.filter = "alpha(opacity=80)"; srcLDiv.style.width = msgWidth; srcLDiv.style.height = msgHeight; srcLDiv.style.position = "absolute"; srcLDiv.style.top = msgTop; srcLDiv.style.left = msgLeft; srcLDiv.style.zIndex = 2000; srcLDiv.style.backgroundColor = "#000000"; srcLDiv.innerHTML = "
"+message+"
"; document.body.appendChild(srcLDiv); } LTSun.changeTextMessage = function(elementId, message) { if($("window_srcLDiv_content_"+elementId)) $("window_srcLDiv_content_"+elementId).innerHTML = message; } LTSun.hideTextMessage = function(elementId) { if($("window_srcLDiv_"+elementId)) document.body.removeChild($("window_srcLDiv_"+elementId)); } /*---------------------------------------------------------------------------------------- Save Text --------- This button calls on noinc-save.php with AJAX to save the text then displays a window with confirmation where options of publishing are presented. ----------------------------------------------------------------------------------------*/ LTSun.saveTextModule = function(fileName, elementId, html, displayResponse, onSuccess, onFailure) { var pageId = LTSunSettings["selectText"+elementId+"PageId"]; var stringDataHTML = (html.length > 5 ? html : document.getElementById(elementId).contentWindow.document.body.innerHTML); if(displayResponse) { LTSun.showTextMessage(elementId, "Saving Content..."); } new Ajax.Request ( fileName, // "LTSun-Engine/modules/text/noinc-save.php" { parameters: { pageId: pageId, elementId: elementId, stringDataHTML: stringDataHTML }, onSuccess : onSuccess != null ? onSuccess : function(transport) { if(displayResponse) { if(transport.responseText == "1") { LTSun.changeTextMessage(elementId, "Saving Complete"); setTimeout("LTSun.hideTextMessage('"+elementId+"');", 1000); } else { LTSun.changeTextMessage(elementId, "Save ERROR!"); setTimeout("LTSun.hideTextMessage('"+elementId+"');", 2000); } } return true; }, onFailure : function(transport) { new Ajax.Request ( fileName.substr(fileName.lastIndexOf("/")+1, fileName.length-fileName.indexOf("?")-1), //"noinc-save.php", { parameters: { pageId: pageId, elementId: elementId, stringDataHTML: stringDataHTML }, onSuccess : onSuccess != null ? onSuccess : function(transport) { if(displayResponse) { if(transport.responseText == "1") { LTSun.changeTextMessage(elementId, "Saving Complete"); setTimeout("LTSun.hideTextMessage('"+elementId+"');", 1000); return true; } else { LTSun.changeTextMessage(elementId, "Save ERROR!"); setTimeout("LTSun.hideTextMessage('"+elementId+"');", 2000); return false; } } }, onFailure : onFailure != null ? onFailure : function(transport) { if(displayResponse) { LTSun.changeTextMessage(elementId, "Save ERROR!"); setTimeout("LTSun.hideTextMessage('"+elementId+"');", 2000); } return false; } } ); } } ); }; /*---------------------------------------------------------------------------------------- Create Control Menu ------------------- Creates a DIV Block that will hover around and over the editable area. This control menu will have functions to Save, tinyMCE, Revisions and Configure/Publish. ----------------------------------------------------------------------------------------*/ LTSun.createTextControls = function(elementId) { var menuDiv = document.createElement("div"); var menuTop = LTSun.getElementTop(elementId); var menuLeft = LTSun.getElementLeft(elementId); var menuHTML = ""; menuHTML+= "
"; menuHTML+= "
"; menuHTML+= ""; menuHTML+= ""; menuHTML+= ""; menuHTML+= ""; menuHTML+= ""; menuHTML+= ""; menuHTML+= ""; menuHTML+= ""; menuHTML+= ""; menuHTML+= "
   
"; menuHTML = menuHTML.replace(/elementId_/gi, elementId+"_"); menuDiv.innerHTML = menuHTML; menuDiv.style.position = "absolute"; menuDiv.style.overflow = "hidden"; menuDiv.style.top = menuTop; menuDiv.style.zIndex = 50; menuDiv.style.left = menuLeft; menuDiv.style.height = 30; LTSun.changeOpacity(30, menuDiv); menuDiv.onmouseover = function() { menuDiv.style.height = 30; LTSun.changeOpacity(100, menuDiv); }; menuDiv.onmouseout = function(){ menuDiv.style.height = 30; LTSun.changeOpacity(30, menuDiv); }; LTSun.textEditorButtonInstances.push(menuDiv); document.body.appendChild(menuDiv); /*---------------------------------------------------------------------------------------- Save Text --------- This button calls on noinc-save.php with AJAX to save the text then displays a window with confirmation where options of publishing are presented. ----------------------------------------------------------------------------------------*/ document.getElementById(elementId+"_saveText").onclick = function() { LTSun.saveTextModule("LTSun-Engine/modules/text/noinc-save.php", elementId, "", true, null, null); }; /*---------------------------------------------------------------------------------------- Publish Text ------------ Saves current text twice: once as published.htm and again as date-time.htm. ----------------------------------------------------------------------------------------*/ document.getElementById(elementId+"_publishText").onclick = function() { LTSun.showTextMessage(elementId, "Publishing Content..."); LTSun.saveTextModule("LTSun-Engine/modules/text/noinc-publish.php", elementId, "", false, null, null); LTSun.saveTextModule("LTSun-Engine/modules/text/noinc-save.php", elementId, "", false, function() { LTSun.changeTextMessage(elementId, "Publish Complete"); setTimeout("LTSun.hideTextMessage('"+elementId+"');", 2000); }, function() { LTSun.changeTextMessage(elementId, "Publish ERROR!"); setTimeout("LTSun.hideTextMessage('"+elementId+"');", 1000); }); }; /*---------------------------------------------------------------------------------------- Advanced Editor Text -------------------- Load an HTML editor that has all the supreme HTML customizing features. ----------------------------------------------------------------------------------------*/ document.getElementById(elementId+"_advancedEditorText").onclick = function() { var advEditorURL = ""; var pageId = LTSunSettings["selectText"+elementId+"PageId"]; advEditorURL+= "LTSun-Engine/modules/text/noinc-advEditor.php?css="+LTSun.settings['cascadingStyleSheet']+ "&elementClass="+$(elementId).className+ "&pageId="+pageId+ "&elementId="+elementId; LTSun.showWindow({ size: "large", bgColor: "#ffffff", animationSpeed: 100, url: advEditorURL, okAvailable: false, cancelAvailable: false }); }; /*---------------------------------------------------------------------------------------- Revisions for Text ------------------ Displays a window with all save history of the text editor instance. The user can restore any point thye wish guided by date and time markers. ----------------------------------------------------------------------------------------*/ document.getElementById(elementId+"_revisionsText").onclick = function() { var revisionsURL = ""; var pageId = LTSunSettings["selectText"+elementId+"PageId"]; revisionsURL+= "LTSun-Engine/modules/text/noinc-revisions.php?css="+LTSun.settings['cascadingStyleSheet']+ "&elementClass="+$(elementId).className+ "&pageId="+pageId+ "&elementId="+elementId; LTSun.showWindow({ size: "large", bgColor: "#ffffff", animationSpeed: 100, url: revisionsURL, okAvailable: false, cancelAvailable: false }); }; /*---------------------------------------------------------------------------------------- About LTSun-Engine ------------------ Opens an internal window which displays LightTheSun CMS About. ----------------------------------------------------------------------------------------*/ document.getElementById(elementId+"_aboutText").onclick = function() { //initNavigation(); }; return true; };