/* Modifed by BL to namespace the functions */ /* DISCLAIMER: THESE JAVASCRIPT FUNCTIONS ARE SUPPLIED 'AS IS', WITH NO WARRANTY EXPRESSED OR IMPLIED. YOU USE THEM AT YOUR OWN RISK. NEITHER PAUL STEPHENS NOR PC PLUS MAGAZINE ACCEPTS ANY LIABILITY FOR ANY LOSS OR DAMAGE RESULTING FROM THEIR USE, HOWEVER CAUSED. Paul Stephens' NetScape-based cookie-handling library http://web.ukonline.co.uk/paul.stephens/index.htm TO USE THIS LIBRARY, INSERT ITS CONTENTS IN A BLOCK IN THE SECTION OF YOUR WEB PAGE SOURCE, BEFORE ANY OTHER JAVASCRIPT ROUTINES. Feel free to use this code, but please leave this comment block in. */ var Cookies = { setCookie: function(name, value, lifespan, access_path) { var cookietext = name + "=" + escape(value) if (lifespan != null) { var today=new Date() var expiredate = new Date() expiredate.setTime(today.getTime() + 1000*60*60*24*lifespan) cookietext += "; expires=" + expiredate.toGMTString() } if (access_path != null) { cookietext += "; PATH="+access_path } document.cookie = cookietext return null }, setDatedCookie: function(name, value, expire, access_path) { var cookietext = name + "=" + escape(value) + ((expire == null) ? "" : ("; expires=" + expire.toGMTString())) if (access_path != null) { cookietext += "; PATH="+access_path } document.cookie = cookietext return null }, getCookie: function(Name) { var search = Name + "=" var CookieString = document.cookie var result = null if (CookieString.length > 0) { offset = CookieString.indexOf(search) if (offset != -1) { offset += search.length end = CookieString.indexOf(";", offset) if (end == -1) end = CookieString.length result = unescape(CookieString.substring(offset, end)) } } return result }, deleteCookie: function(name) { Cookies.setCookie(name, "Deleted", -1) } } var pc = navigator.userAgent.toLowerCase(); var ie4_win = (pc.indexOf("win")!=-1) && (pc.indexOf("msie") != -1) && (parseInt(navigator.appVersion) >= 4); var checked = false; // only builds based upon gecko later than Jan 8th support the selectionStart, selectionEnd properly var is_gecko = pc.indexOf("gecko/") != -1 && parseFloat(pc.substring(pc.indexOf("gecko/") + 6, pc.indexOf("gecko/") + 14)) > 20030108; function checkPost() { if (arguments.length > 0) { window.onbeforeunload = null; } if (!checked) { checked = true; return true; } return false; } function insertAtCursor(text, ta) { var end = 0; var scrollTop = ta.scrollTop; ta.focus(); if (document.selection && document.selection.createRange().parentElement().tagName == 'TEXTAREA') { var selected = document.selection.createRange().text; // now determine the cursor position end = getSelectionRangeEnd(ta); // update text document.selection.createRange().text = selected + text; // update end position end += text.length; } else if (typeof(ta.selectionStart) != 'undefined' && typeof(ta.selectionEnd) != 'undefined') { var selLength = ta.textLength; var selStart = ta.selectionStart; var selEnd = ta.selectionEnd; if (selEnd == 1 || selEnd == 2) { selEnd = selLength; } var s1 = (ta.value).substring(0, selEnd); var s2 = (ta.value).substring(selEnd, selLength); // update text ta.value = s1 + text + s2; // update end position end = selEnd + text.length; } else { ta.value += text; } if (end > 0) { setCaretTo(ta, end, scrollTop); } } function styleTag(tag, endtag, ta) { var end = 0; var scrollTop = ta.scrollTop; if (document.selection) { if (document.selection.createRange().parentElement().tagName == 'TEXTAREA') { var selected = document.selection.createRange().text; // now determine the cursor position end = getSelectionRangeEnd(ta); // r is an array var r = _markupText(selected, tag, endtag); // update text document.selection.createRange().text = r[0]; // update end position end += r[1]; } } else if (typeof(ta.selectionStart) != 'undefined' && typeof(ta.selectionEnd) != 'undefined') { if (ta.selectionStart == ta.selectionEnd) { return; } var selLength = ta.textLength; var selStart = ta.selectionStart; var selEnd = ta.selectionEnd; if (selEnd == 1 || selEnd == 2) { selEnd = selLength; } var s1 = (ta.value).substring(0, selStart); var s2 = (ta.value).substring(selStart, selEnd); var s3 = (ta.value).substring(selEnd, selLength); // r is an array var r = _markupText(s2, tag, endtag); // update text ta.value = s1 + r[0] + s3; // update end position end = selEnd + r[1]; } else { return; } if (end > 0) { setCaretTo(ta, end, scrollTop); } } function _markupText(text, tag, endtag) { // trim off leading whitespace from selection (includes newlines) var r = trimLeadingSpace(text); text = r[0]; var removeSpace = r[1]; // trim off trailing whitespace from selection (includes newlines) r = trimTrailingSpace(text); text = r[0]; var addSpace = r[1]; // determine if selection crosses multiple lines var addedCharacters = 0; if (text.indexOf('\n') > 0) { // wrap whole lines in the tag var lines = text.split('\n'); var newText = ''; for (var i = 0; i < lines.length; i++) { var line = lines[i]; r = trimLeadingSpace(line); line = r[0]; var leadingSpaces = r[1]; // trim off trailing whitespace from selection (includes newlines) r = trimTrailingSpace(line); line = r[0]; var trailingSpaces = r[1]; if (line == '') { newText += leadingSpaces + line + trailingSpaces; } else { newText += leadingSpaces + tag + line + endtag + trailingSpaces; addedCharacters += (tag.length + endtag.length); } if (i < lines.length -1) { newText += '\n'; } } text = removeSpace + newText + addSpace; } else { text = removeSpace + tag + text + endtag + addSpace; } r = new Array(2); r[0] = text; r[1] = addedCharacters; return r; } function trimLeadingSpace(text) { var removeSpace = ""; while (text.length > 0 && (text.charAt(0) == ' ' || text.charAt(0) == '\n' || text.charAt(0) == '\r')) { removeSpace += text.charAt(0); text = text.substring(1); } var r = new Array(2); r[0] = text; r[1] = removeSpace; return r; } function trimTrailingSpace(text) { var addSpace = ""; while (text.length > 0 && (text.charAt(text.length-1) == ' ' || text.charAt(text.length-1) == '\n' || text.charAt(text.length-1) == '\r')) { addSpace += text.charAt(text.length-1); text = text.substring(0, text.length-1); } var r = new Array(2); r[0] = text; r[1] = addSpace; return r; } function getSelectionRangeText(ta) { if (document.selection) { // The current selection return document.selection.createRange().text; } else if (is_gecko) { var start = ta.selectionStart; var end = ta.selectionEnd; return ta.value.substr(start, end-start); } else { return ''; } } function getSelectionRangeEnd(ta) { if (document.selection) { // The current selection var range = document.selection.createRange(); // We'll use this as a 'dummy' var stored_range = range.duplicate(); // Select all text stored_range.moveToElementText(ta); // Now move 'dummy' end point to end point of original range stored_range.setEndPoint('EndToEnd', range); // Now we can calculate start and end points var start = stored_range.text.length - range.text.length; return start + range.text.length; } else if (is_gecko) { return ta.selectionEnd; } else { return 0; } } function setCaretTo(ta, pos, scrollTop) { ta.focus(); if (ta.createTextRange) { // we need to determine the number of \r\n in IE because while they are two separate // characters they are treated as one for the purposes of position var i = 0; var count = 0; var text = ta.value; while (i > -1 && i < pos) { i = text.indexOf("\r\n", i); if (i >= 0) { count++; i += 2; } } // knock one off of count if (count > 1) { count--; } // position cursor var range = ta.createTextRange(); range.move("character", (pos - count)); range.select(); } else if (ta.selectionStart) { ta.setSelectionRange(pos, pos); } // scroll to the same location that the textarea was previously scrolled to if (scrollTop > 0) { ta.scrollTop = scrollTop; } } function caret(ta) { if (ie4_win && ta.createTextRange && document.selection.createRange().parentElement().tagName == 'TEXTAREA') { ta.caretPos = document.selection.createRange().duplicate(); } } // This function returns the name of a given function. It does this by // converting the function to a string, then using a regular expression // to extract the function name from the resulting code. function funcname(f) { var s = f.toString().match(/function (\w*)/)[1]; if ((s == null) || (s.length == 0)) return "anonymous"; return s; } // This function returns a string that contains a "stack trace." function stacktrace() { var s = ""; // This is the string we'll return. // Loop through the stack of functions, using the caller property of // one arguments object to refer to the next arguments object on the // stack. for(var a = arguments.caller; a != null; a = a.caller) { // Add the name of the current function to the return value. s += funcname(a.callee) + "\n"; // Because of a bug in Navigator 4.0, we need this line to break. // a.caller will equal a rather than null when we reach the end // of the stack. The following line works around this. if (a.caller == a) break; } return s; } function printStackTrace() { alert('stack trace is ' + stacktrace()); } // TODO: this shouldn't be conceptually tied to a "row" // "hashmap" for the row elements so we can remember the style before switching to the hilite one var hoverElements = new Array(); function onhover(el) { if (typeof(el) == "undefined" || typeof(el.className) != "undefined") { return; } hoverElements[el] = el.className; el.className = el.className + " hilite"; } function onhoverbyclass(el, cl) { hoverElements[el] = el.className; el.className = el.className + " " + cl; } function offhover(el) { if (hoverElements[el]) { el.className = hoverElements[el]; } } function onclick(el) { onhover(el); } /* todo: not working right now! */ function clearhover(el) { el.className = el.className.replace(/hilite/g, "") } /* Prototype JavaScript framework, version 1.5.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', 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: ']*>([\u0001-\uFFFF]*?)', 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}'); }, evalJSON: function(sanitize) { var json = this.unfilterJSON(); try { if (!sanitize || (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.test(json))) 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; for (var i = 0, length = children.length; i < length; i++) { child = children[i]; if (Element.hasClassName(child, className)) 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=http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.oprah.com/community/resources/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 scriptaculous.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007 // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // For details, see the script.aculo.us web site: http://script.aculo.us/ var Scriptaculous = { Version: '1.7.1_beta3', require: function(libraryName) { // inserting via DOM fails in Safari 2.0, so brute force approach document.write(''); }, REQUIRED_PROTOTYPE: '1.5.1', load: function() { function convertVersionString(versionString){ var r = versionString.split('.'); return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]); } if((typeof Prototype=='undefined') || (typeof Element == 'undefined') || (typeof Element.Methods=='undefined') || (convertVersionString(Prototype.Version) < convertVersionString(Scriptaculous.REQUIRED_PROTOTYPE))) throw("script.aculo.us requires the Prototype JavaScript framework >= " + Scriptaculous.REQUIRED_PROTOTYPE); $A(document.getElementsByTagName("script")).findAll( function(s) { return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/)) }).each( function(s) { var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,''); var includes = s.src.match(/\?.*load=([a-z,]*)/); (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider,sound').split(',').each( function(include) { Scriptaculous.require(path+include+'.js') }); }); } } Scriptaculous.load(); // script.aculo.us effects.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 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=http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.oprah.com/community/resources/$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=http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.oprah.com/community/resources/$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(); // script.aculo.us controls.js v1.7.1_beta3, Fri May 25 17:19:41 +0200 2007 // Copyright (c) 2005-2007 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005-2007 Ivan Krstic (http://blogs.law.harvard.edu/ivan) // (c) 2005-2007 Jon Tirsen (http://www.tirsen.com) // Contributors: // Richard Livsey // Rahul Bhargava // Rob Wills // // 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/ // Autocompleter.Base handles all the autocompletion functionality // that's independent of the data source for autocompletion. This // includes drawing the autocompletion menu, observing keyboard // and mouse events, and similar. // // Specific autocompleters need to provide, at the very least, // a getUpdatedChoices function that will be invoked every time // the text inside the monitored textbox changes. This method // should get the text for which to provide autocompletion by // invoking this.getToken(), NOT by directly accessing // this.element.value. This is to allow incremental tokenized // autocompletion. Specific auto-completion logic (AJAX, etc) // belongs in getUpdatedChoices. // // Tokenized incremental autocompletion is enabled automatically // when an autocompleter is instantiated with the 'tokens' option // in the options parameter, e.g.: // new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); // will incrementally autocomplete with a comma as the token. // Additionally, ',' in the above example can be replaced with // a token array, e.g. { tokens: [',', '\n'] } which // enables autocompletion on multiple tokens. This is most // useful when one of the tokens is \n (a newline), as it // allows smart autocompletion after linebreaks. if(typeof Effect == 'undefined') throw("controls.js requires including script.aculo.us' effects.js library"); var Autocompleter = {} Autocompleter.Base = function() {}; Autocompleter.Base.prototype = { baseInitialize: function(element, update, options) { element = $(element) this.element = element; this.update = $(update); this.hasFocus = false; this.changed = false; this.active = false; this.index = 0; this.entryCount = 0; if(this.setOptions) this.setOptions(options); else this.options = options || {}; this.options.paramName = this.options.paramName || this.element.name; this.options.tokens = this.options.tokens || []; this.options.frequency = this.options.frequency || 0.4; this.options.minChars = this.options.minChars || 1; this.options.onShow = this.options.onShow || function(element, update){ if(!update.style.position || update.style.position=='absolute') { update.style.position = 'absolute'; Position.clone(element, update, { setHeight: false, offsetTop: element.offsetHeight }); } Effect.Appear(update,{duration:0.15}); }; this.options.onHide = this.options.onHide || function(element, update){ new Effect.Fade(update,{duration:0.15}) }; if(typeof(this.options.tokens) == 'string') this.options.tokens = new Array(this.options.tokens); this.observer = null; this.element.setAttribute('autocomplete','off'); Element.hide(this.update); Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); Event.observe(this.element, 'keypress', this.onKeyPress.bindAsEventListener(this)); // Turn autocomplete back on when the user leaves the page, so that the // field's value will be remembered on Mozilla-based browsers. Event.observe(window, 'beforeunload', function(){ element.setAttribute('autocomplete', 'on'); }); }, show: function() { if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); if(!this.iefix && (Prototype.Browser.IE) && (Element.getStyle(this.update, 'position')=='absolute')) { new Insertion.After(this.update, ''); this.iefix = $(this.update.id+'_iefix'); } if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); }, fixIEOverlapping: function() { Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); this.iefix.style.zIndex = 1; this.update.style.zIndex = 2; Element.show(this.iefix); }, hide: function() { this.stopIndicator(); if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); if(this.iefix) Element.hide(this.iefix); }, startIndicator: function() { if(this.options.indicator) Element.show(this.options.indicator); }, stopIndicator: function() { if(this.options.indicator) Element.hide(this.options.indicator); }, onKeyPress: function(event) { if(this.active) switch(event.keyCode) { case Event.KEY_TAB: case Event.KEY_RETURN: this.selectEntry(); Event.stop(event); case Event.KEY_ESC: this.hide(); this.active = false; Event.stop(event); return; case Event.KEY_LEFT: case Event.KEY_RIGHT: return; case Event.KEY_UP: this.markPrevious(); this.render(); if(Prototype.Browser.WebKit) Event.stop(event); return; case Event.KEY_DOWN: this.markNext(); this.render(); if(Prototype.Browser.WebKit) Event.stop(event); return; } else if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; this.changed = true; this.hasFocus = true; if(this.observer) clearTimeout(this.observer); this.observer = setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); }, activate: function() { this.changed = false; this.hasFocus = true; this.getUpdatedChoices(); }, onHover: function(event) { var element = Event.findElement(event, 'LI'); if(this.index != element.autocompleteIndex) { this.index = element.autocompleteIndex; this.render(); } Event.stop(event); }, onClick: function(event) { var element = Event.findElement(event, 'LI'); this.index = element.autocompleteIndex; this.selectEntry(); this.hide(); }, onBlur: function(event) { // needed to make click events working setTimeout(this.hide.bind(this), 250); this.hasFocus = false; this.active = false; }, render: function() { if(this.entryCount > 0) { for (var i = 0; i < this.entryCount; i++) this.index==i ? Element.addClassName(this.getEntry(i),"selected") : Element.removeClassName(this.getEntry(i),"selected"); if(this.hasFocus) { this.show(); this.active = true; } } else { this.active = false; this.hide(); } }, markPrevious: function() { if(this.index > 0) this.index-- else this.index = this.entryCount-1; this.getEntry(this.index).scrollIntoView(true); }, markNext: function() { if(this.index < this.entryCount-1) this.index++ else this.index = 0; this.getEntry(this.index).scrollIntoView(false); }, getEntry: function(index) { return this.update.firstChild.childNodes[index]; }, getCurrentEntry: function() { return this.getEntry(this.index); }, selectEntry: function() { this.active = false; this.updateElement(this.getCurrentEntry()); }, updateElement: function(selectedElement) { if (this.options.updateElement) { this.options.updateElement(selectedElement); return; } var value = ''; if (this.options.select) { var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); } else value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); var lastTokenPos = this.findLastToken(); if (lastTokenPos != -1) { var newValue = this.element.value.substr(0, lastTokenPos + 1); var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); if (whitespace) newValue += whitespace[0]; this.element.value = newValue + value; } else { this.element.value = value; } this.element.focus(); if (this.options.afterUpdateElement) this.options.afterUpdateElement(this.element, selectedElement); }, updateChoices: function(choices) { if(!this.changed && this.hasFocus) { this.update.innerHTML = choices; Element.cleanWhitespace(this.update); Element.cleanWhitespace(this.update.down()); if(this.update.firstChild && this.update.down().childNodes) { this.entryCount = this.update.down().childNodes.length; for (var i = 0; i < this.entryCount; i++) { var entry = this.getEntry(i); entry.autocompleteIndex = i; this.addObservers(entry); } } else { this.entryCount = 0; } this.stopIndicator(); this.index = 0; if(this.entryCount==1 && this.options.autoSelect) { this.selectEntry(); this.hide(); } else { this.render(); } } }, addObservers: function(element) { Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); Event.observe(element, "click", this.onClick.bindAsEventListener(this)); }, onObserverEvent: function() { this.changed = false; if(this.getToken().length>=this.options.minChars) { this.getUpdatedChoices(); } else { this.active = false; this.hide(); } }, getToken: function() { var tokenPos = this.findLastToken(); if (tokenPos != -1) var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); else var ret = this.element.value; return /\n/.test(ret) ? '' : ret; }, findLastToken: function() { var lastTokenPos = -1; for (var i=0; i lastTokenPos) lastTokenPos = thisTokenPos; } return lastTokenPos; } } Ajax.Autocompleter = Class.create(); Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { initialize: function(element, update, url, options) { this.baseInitialize(element, update, options); this.options.asynchronous = true; this.options.onComplete = this.onComplete.bind(this); this.options.defaultParams = this.options.parameters || null; this.url = url; }, getUpdatedChoices: function() { this.startIndicator(); var entry = encodeURIComponent(this.options.paramName) + '=' + encodeURIComponent(this.getToken()); this.options.parameters = this.options.callback ? this.options.callback(this.element, entry) : entry; if(this.options.defaultParams) this.options.parameters += '&' + this.options.defaultParams; new Ajax.Request(this.url, this.options); }, onComplete: function(request) { this.updateChoices(request.responseText); } }); // The local array autocompleter. Used when you'd prefer to // inject an array of autocompletion options into the page, rather // than sending out Ajax queries, which can be quite slow sometimes. // // The constructor takes four parameters. The first two are, as usual, // the id of the monitored textbox, and id of the autocompletion menu. // The third is the array you want to autocomplete from, and the fourth // is the options block. // // Extra local autocompletion options: // - choices - How many autocompletion choices to offer // // - partialSearch - If false, the autocompleter will match entered // text only at the beginning of strings in the // autocomplete array. Defaults to true, which will // match text at the beginning of any *word* in the // strings in the autocomplete array. If you want to // search anywhere in the string, additionally set // the option fullSearch to true (default: off). // // - fullSsearch - Search anywhere in autocomplete array strings. // // - partialChars - How many characters to enter before triggering // a partial match (unlike minChars, which defines // how many characters are required to do any match // at all). Defaults to 2. // // - ignoreCase - Whether to ignore case when autocompleting. // Defaults to true. // // It's possible to pass in a custom function as the 'selector' // option, if you prefer to write your own autocompletion logic. // In that case, the other options above will not apply unless // you support them. Autocompleter.Local = Class.create(); Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { initialize: function(element, update, array, options) { this.baseInitialize(element, update, options); this.options.array = array; }, getUpdatedChoices: function() { this.updateChoices(this.options.selector(this)); }, setOptions: function(options) { this.options = Object.extend({ choices: 10, partialSearch: true, partialChars: 2, ignoreCase: true, fullSearch: false, selector: function(instance) { var ret = []; // Beginning matches var partial = []; // Inside matches var entry = instance.getToken(); var count = 0; for (var i = 0; i < instance.options.array.length && ret.length < instance.options.choices ; i++) { var elem = instance.options.array[i]; var foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase()) : elem.indexOf(entry); while (foundPos != -1) { if (foundPos == 0 && elem.length != entry.length) { ret.push("
  • " + elem.substr(0, entry.length) + "" + elem.substr(entry.length) + "
  • "); break; } else if (entry.length >= instance.options.partialChars && instance.options.partialSearch && foundPos != -1) { if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { partial.push("
  • " + elem.substr(0, foundPos) + "" + elem.substr(foundPos, entry.length) + "" + elem.substr( foundPos + entry.length) + "
  • "); break; } } foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : elem.indexOf(entry, foundPos + 1); } } if (partial.length) ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) return "
      " + ret.join('') + "
    "; } }, options || {}); } }); // AJAX in-place editor // // see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor // Use this if you notice weird scrolling problems on some browsers, // the DOM might be a bit confused when this gets called so do this // waits 1 ms (with setTimeout) until it does the activation Field.scrollFreeActivate = function(field) { setTimeout(function() { Field.activate(field); }, 1); } Ajax.InPlaceEditor = Class.create(); Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; Ajax.InPlaceEditor.prototype = { initialize: function(element, url, options) { this.url = url; this.element = $(element); this.options = Object.extend({ paramName: "value", okButton: true, okLink: false, okText: "ok", cancelButton: false, cancelLink: true, cancelText: "cancel", textBeforeControls: '', textBetweenControls: '', textAfterControls: '', savingText: "Saving...", clickToEditText: "Click to edit", okText: "ok", rows: 1, onComplete: function(transport, element) { new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); }, onFailure: function(transport) { alert("Error communicating with the server: " + transport.responseText.stripTags()); }, callback: function(form) { return Form.serialize(form); }, handleLineBreaks: true, loadingText: 'Loading...', savingClassName: 'inplaceeditor-saving', loadingClassName: 'inplaceeditor-loading', formClassName: 'inplaceeditor-form', highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, highlightendcolor: "#FFFFFF", externalControl: null, submitOnBlur: false, ajaxOptions: {}, evalScripts: false }, options || {}); if(!this.options.formId && this.element.id) { this.options.formId = this.element.id + "-inplaceeditor"; if ($(this.options.formId)) { // there's already a form with that name, don't specify an id this.options.formId = null; } } if (this.options.externalControl) { this.options.externalControl = $(this.options.externalControl); } this.originalBackground = Element.getStyle(this.element, 'background-color'); if (!this.originalBackground) { this.originalBackground = "transparent"; } this.element.title = this.options.clickToEditText; this.onclickListener = this.enterEditMode.bindAsEventListener(this); this.mouseoverListener = this.enterHover.bindAsEventListener(this); this.mouseoutListener = this.leaveHover.bindAsEventListener(this); Event.observe(this.element, 'click', this.onclickListener); Event.observe(this.element, 'mouseover', this.mouseoverListener); Event.observe(this.element, 'mouseout', this.mouseoutListener); if (this.options.externalControl) { Event.observe(this.options.externalControl, 'click', this.onclickListener); Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); } }, enterEditMode: function(evt) { if (this.saving) return; if (this.editing) return; this.editing = true; this.onEnterEditMode(); if (this.options.externalControl) { Element.hide(this.options.externalControl); } Element.hide(this.element); this.createForm(); this.element.parentNode.insertBefore(this.form, this.element); if (!this.options.loadTextURL) Field.scrollFreeActivate(this.editField); // stop the event to avoid a page refresh in Safari if (evt) { Event.stop(evt); } return false; }, createForm: function() { this.form = document.createElement("form"); this.form.id = this.options.formId; Element.addClassName(this.form, this.options.formClassName) this.form.onsubmit = this.onSubmit.bind(this); this.createEditField(); if (this.options.textarea) { var br = document.createElement("br"); this.form.appendChild(br); } if (this.options.textBeforeControls) this.form.appendChild(document.createTextNode(this.options.textBeforeControls)); if (this.options.okButton) { var okButton = document.createElement("input"); okButton.type = "submit"; okButton.value = this.options.okText; okButton.className = 'editor_ok_button'; this.form.appendChild(okButton); } if (this.options.okLink) { var okLink = document.createElement("a"); okLink.href="http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.oprah.com/community/resources/merge|global|;jsessionid=ac11087930d5c357f3c3e9a04348a426b4452b947645.e38KbxqSbxiNe34KaO0#"; okLink.appendChild(document.createTextNode(this.options.okText)); okLink.onclick = this.onSubmit.bind(this); okLink.className = 'editor_ok_link'; this.form.appendChild(okLink); } if (this.options.textBetweenControls && (this.options.okLink || this.options.okButton) && (this.options.cancelLink || this.options.cancelButton)) this.form.appendChild(document.createTextNode(this.options.textBetweenControls)); if (this.options.cancelButton) { var cancelButton = document.createElement("input"); cancelButton.type = "submit"; cancelButton.value = this.options.cancelText; cancelButton.onclick = this.onclickCancel.bind(this); cancelButton.className = 'editor_cancel_button'; this.form.appendChild(cancelButton); } if (this.options.cancelLink) { var cancelLink = document.createElement("a"); cancelLink.href="http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.oprah.com/community/resources/merge|global|;jsessionid=ac11087930d5c357f3c3e9a04348a426b4452b947645.e38KbxqSbxiNe34KaO0#"; cancelLink.appendChild(document.createTextNode(this.options.cancelText)); cancelLink.onclick = this.onclickCancel.bind(this); cancelLink.className = 'editor_cancel editor_cancel_link'; this.form.appendChild(cancelLink); } if (this.options.textAfterControls) this.form.appendChild(document.createTextNode(this.options.textAfterControls)); }, hasHTMLLineBreaks: function(string) { if (!this.options.handleLineBreaks) return false; return string.match(/
    /i); }, convertHTMLLineBreaks: function(string) { return string.replace(/
    /gi, "\n").replace(//gi, "\n").replace(/<\/p>/gi, "\n").replace(/

    /gi, ""); }, createEditField: function() { var text; if(this.options.loadTextURL) { text = this.options.loadingText; } else { text = this.getText(); } var obj = this; if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { this.options.textarea = false; var textField = document.createElement("input"); textField.obj = this; textField.type = "text"; textField.name = this.options.paramName; textField.value = text; textField.style.backgroundColor = this.options.highlightcolor; textField.className = 'editor_field'; var size = this.options.size || this.options.cols || 0; if (size != 0) textField.size = size; if (this.options.submitOnBlur) textField.onblur = this.onSubmit.bind(this); this.editField = textField; } else { this.options.textarea = true; var textArea = document.createElement("textarea"); textArea.obj = this; textArea.name = this.options.paramName; textArea.value = this.convertHTMLLineBreaks(text); textArea.rows = this.options.rows; textArea.cols = this.options.cols || 40; textArea.className = 'editor_field'; if (this.options.submitOnBlur) textArea.onblur = this.onSubmit.bind(this); this.editField = textArea; } if(this.options.loadTextURL) { this.loadExternalText(); } this.form.appendChild(this.editField); }, getText: function() { return this.element.innerHTML; }, loadExternalText: function() { Element.addClassName(this.form, this.options.loadingClassName); this.editField.disabled = true; new Ajax.Request( this.options.loadTextURL, Object.extend({ asynchronous: true, onComplete: this.onLoadedExternalText.bind(this) }, this.options.ajaxOptions) ); }, onLoadedExternalText: function(transport) { Element.removeClassName(this.form, this.options.loadingClassName); this.editField.disabled = false; this.editField.value = transport.responseText.stripTags(); Field.scrollFreeActivate(this.editField); }, onclickCancel: function() { this.onComplete(); this.leaveEditMode(); return false; }, onFailure: function(transport) { this.options.onFailure(transport); if (this.oldInnerHTML) { this.element.innerHTML = this.oldInnerHTML; this.oldInnerHTML = null; } return false; }, onSubmit: function() { // onLoading resets these so we need to save them away for the Ajax call var form = this.form; var value = this.editField.value; // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... // to be displayed indefinitely this.onLoading(); if (this.options.evalScripts) { new Ajax.Request( this.url, Object.extend({ parameters: this.options.callback(form, value), onComplete: this.onComplete.bind(this), onFailure: this.onFailure.bind(this), asynchronous:true, evalScripts:true }, this.options.ajaxOptions)); } else { new Ajax.Updater( { success: this.element, // don't update on failure (this could be an option) failure: null }, this.url, Object.extend({ parameters: this.options.callback(form, value), onComplete: this.onComplete.bind(this), onFailure: this.onFailure.bind(this) }, this.options.ajaxOptions)); } // stop the event to avoid a page refresh in Safari if (arguments.length > 1) { Event.stop(arguments[0]); } return false; }, onLoading: function() { this.saving = true; this.removeForm(); this.leaveHover(); this.showSaving(); }, showSaving: function() { this.oldInnerHTML = this.element.innerHTML; this.element.innerHTML = this.options.savingText; Element.addClassName(this.element, this.options.savingClassName); this.element.style.backgroundColor = this.originalBackground; Element.show(this.element); }, removeForm: function() { if(this.form) { if (this.form.parentNode) Element.remove(this.form); this.form = null; } }, enterHover: function() { if (this.saving) return; this.element.style.backgroundColor = this.options.highlightcolor; if (this.effect) { this.effect.cancel(); } Element.addClassName(this.element, this.options.hoverClassName) }, leaveHover: function() { if (this.options.backgroundColor) { this.element.style.backgroundColor = this.oldBackground; } Element.removeClassName(this.element, this.options.hoverClassName) if (this.saving) return; this.effect = new Effect.Highlight(this.element, { startcolor: this.options.highlightcolor, endcolor: this.options.highlightendcolor, restorecolor: this.originalBackground }); }, leaveEditMode: function() { Element.removeClassName(this.element, this.options.savingClassName); this.removeForm(); this.leaveHover(); this.element.style.backgroundColor = this.originalBackground; Element.show(this.element); if (this.options.externalControl) { Element.show(this.options.externalControl); } this.editing = false; this.saving = false; this.oldInnerHTML = null; this.onLeaveEditMode(); }, onComplete: function(transport) { this.leaveEditMode(); this.options.onComplete.bind(this)(transport, this.element); }, onEnterEditMode: function() {}, onLeaveEditMode: function() {}, dispose: function() { if (this.oldInnerHTML) { this.element.innerHTML = this.oldInnerHTML; } this.leaveEditMode(); Event.stopObserving(this.element, 'click', this.onclickListener); Event.stopObserving(this.element, 'mouseover', this.mouseoverListener); Event.stopObserving(this.element, 'mouseout', this.mouseoutListener); if (this.options.externalControl) { Event.stopObserving(this.options.externalControl, 'click', this.onclickListener); Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener); Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener); } } }; Ajax.InPlaceCollectionEditor = Class.create(); Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype); Object.extend(Ajax.InPlaceCollectionEditor.prototype, { createEditField: function() { if (!this.cached_selectTag) { var selectTag = document.createElement("select"); var collection = this.options.collection || []; var optionTag; collection.each(function(e,i) { optionTag = document.createElement("option"); optionTag.value = (e instanceof Array) ? e[0] : e; if((typeof this.options.value == 'undefined') && ((e instanceof Array) ? this.element.innerHTML == e[1] : e == optionTag.value)) optionTag.selected = true; if(this.options.value==optionTag.value) optionTag.selected = true; optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e)); selectTag.appendChild(optionTag); }.bind(this)); this.cached_selectTag = selectTag; } this.editField = this.cached_selectTag; if(this.options.loadTextURL) this.loadExternalText(); this.form.appendChild(this.editField); this.options.callback = function(form, value) { return "value=" + encodeURIComponent(value); } } }); // Delayed observer, like Form.Element.Observer, // but waits for delay after last key input // Ideal for live-search fields Form.Element.DelayedObserver = Class.create(); Form.Element.DelayedObserver.prototype = { initialize: function(element, delay, callback) { this.delay = delay || 0.5; this.element = $(element); this.callback = callback; this.timer = null; this.lastValue = $F(this.element); Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); }, delayedListener: function(event) { if(this.lastValue == $F(this.element)) return; if(this.timer) clearTimeout(this.timer); this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); this.lastValue = $F(this.element); }, onTimerEvent: function() { this.timer = null; this.callback(this.element, $F(this.element)); } }; /** $Id: domLib.js 2321 2006-06-12 06:45:41Z dallen $ */ // {{{ license /* * Copyright 2002-2005 Dan Allen, Mojavelinux.com (dan.allen@mojavelinux.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // }}} // {{{ intro /** * Title: DOM Library Core * Version: 0.70 * * Summary: * A set of commonly used functions that make it easier to create javascript * applications that rely on the DOM. * * Updated: 2005/05/17 * * Maintainer: Dan Allen * Maintainer: Jason Rust * * License: Apache 2.0 */ // }}} // {{{ global constants (DO NOT EDIT) // -- Browser Detection -- var domLib_userAgent = navigator.userAgent.toLowerCase(); var domLib_isMac = navigator.appVersion.indexOf('Mac') != -1; var domLib_isWin = domLib_userAgent.indexOf('windows') != -1; // NOTE: could use window.opera for detecting Opera var domLib_isOpera = domLib_userAgent.indexOf('opera') != -1; var domLib_isOpera7up = domLib_userAgent.match(/opera.(7|8)/i); var domLib_isSafari = domLib_userAgent.indexOf('safari') != -1; var domLib_isKonq = domLib_userAgent.indexOf('konqueror') != -1; // Both konqueror and safari use the khtml rendering engine var domLib_isKHTML = (domLib_isKonq || domLib_isSafari || domLib_userAgent.indexOf('khtml') != -1); var domLib_isIE = (!domLib_isKHTML && !domLib_isOpera && (domLib_userAgent.indexOf('msie 5') != -1 || domLib_userAgent.indexOf('msie 6') != -1 || domLib_userAgent.indexOf('msie 7') != -1)); var domLib_isIE5up = domLib_isIE; var domLib_isIE50 = (domLib_isIE && domLib_userAgent.indexOf('msie 5.0') != -1); var domLib_isIE55 = (domLib_isIE && domLib_userAgent.indexOf('msie 5.5') != -1); var domLib_isIE5 = (domLib_isIE50 || domLib_isIE55); // safari and konq may use string "khtml, like gecko", so check for destinctive / var domLib_isGecko = domLib_userAgent.indexOf('gecko/') != -1; var domLib_isMacIE = (domLib_isIE && domLib_isMac); var domLib_isIE55up = domLib_isIE5up && !domLib_isIE50 && !domLib_isMacIE; var domLib_isIE6up = domLib_isIE55up && !domLib_isIE55; // -- Browser Abilities -- var domLib_standardsMode = (document.compatMode && document.compatMode == 'CSS1Compat'); var domLib_useLibrary = (domLib_isOpera7up || domLib_isKHTML || domLib_isIE5up || domLib_isGecko || domLib_isMacIE || document.defaultView); // fixed in Konq3.2 var domLib_hasBrokenTimeout = (domLib_isMacIE || (domLib_isKonq && domLib_userAgent.match(/konqueror\/3.([2-9])/) == null)); var domLib_canFade = (domLib_isGecko || domLib_isIE || domLib_isSafari || domLib_isOpera); var domLib_canDrawOverSelect = (domLib_isMac || domLib_isOpera || domLib_isGecko); var domLib_canDrawOverFlash = (domLib_isMac || domLib_isWin); // -- Event Variables -- var domLib_eventTarget = domLib_isIE ? 'srcElement' : 'currentTarget'; var domLib_eventButton = domLib_isIE ? 'button' : 'which'; var domLib_eventTo = domLib_isIE ? 'toElement' : 'relatedTarget'; var domLib_stylePointer = domLib_isIE ? 'hand' : 'pointer'; // NOTE: a bug exists in Opera that prevents maxWidth from being set to 'none', so we make it huge var domLib_styleNoMaxWidth = domLib_isOpera ? '10000px' : 'none'; var domLib_hidePosition = '-1000px'; var domLib_scrollbarWidth = 14; var domLib_autoId = 1; var domLib_zIndex = 100; // -- Detection -- var domLib_collisionElements; var domLib_collisionsCached = false; var domLib_timeoutStateId = 0; var domLib_timeoutStates = new DomLibHash(); // }}} // {{{ DOM enhancements if (!document.ELEMENT_NODE) { document.ELEMENT_NODE = 1; document.ATTRIBUTE_NODE = 2; document.TEXT_NODE = 3; document.DOCUMENT_NODE = 9; document.DOCUMENT_FRAGMENT_NODE = 11; } function domLib_clone(obj) { var copy = {}; for (var i in obj) { var value = obj[i]; try { if (value != null && typeof(value) == 'object' && value != window && !value.nodeType) { copy[i] = domLib_clone(value); } else { copy[i] = value; } } catch(e) { copy[i] = value; } } return copy; } // }}} // {{{ class DomLibHash() function DomLibHash() { this.length = 0; this.numericLength = 0; this.elementData = []; for (var i = 0; i < arguments.length; i += 2) { if (typeof(arguments[i + 1]) != 'undefined') { this.elementData[arguments[i]] = arguments[i + 1]; this.length++; if (arguments[i] == parseInt(arguments[i])) { this.numericLength++; } } } } // using prototype as opposed to inner functions saves on memory DomLibHash.prototype.get = function(in_key) { if (typeof(this.elementData[in_key]) != 'undefined') { return this.elementData[in_key]; } return null; } DomLibHash.prototype.set = function(in_key, in_value) { if (typeof(in_value) != 'undefined') { if (typeof(this.elementData[in_key]) == 'undefined') { this.length++; if (in_key == parseInt(in_key)) { this.numericLength++; } } return this.elementData[in_key] = in_value; } return false; } DomLibHash.prototype.remove = function(in_key) { var tmp_value; if (typeof(this.elementData[in_key]) != 'undefined') { this.length--; if (in_key == parseInt(in_key)) { this.numericLength--; } tmp_value = this.elementData[in_key]; delete this.elementData[in_key]; } return tmp_value; } DomLibHash.prototype.size = function() { return this.length; } DomLibHash.prototype.has = function(in_key) { return typeof(this.elementData[in_key]) != 'undefined'; } DomLibHash.prototype.find = function(in_obj) { for (var tmp_key in this.elementData) { if (this.elementData[tmp_key] == in_obj) { return tmp_key; } } return null; } DomLibHash.prototype.merge = function(in_hash) { for (var tmp_key in in_hash.elementData) { if (typeof(this.elementData[tmp_key]) == 'undefined') { this.length++; if (tmp_key == parseInt(tmp_key)) { this.numericLength++; } } this.elementData[tmp_key] = in_hash.elementData[tmp_key]; } } DomLibHash.prototype.compare = function(in_hash) { if (this.length != in_hash.length) { return false; } for (var tmp_key in this.elementData) { if (this.elementData[tmp_key] != in_hash.elementData[tmp_key]) { return false; } } return true; } // }}} // {{{ domLib_isDescendantOf() function domLib_isDescendantOf(in_object, in_ancestor, in_bannedTags) { if (in_object == null) { return false; } if (in_object == in_ancestor) { return true; } if (typeof(in_bannedTags) != 'undefined' && (',' + in_bannedTags.join(',') + ',').indexOf(',' + in_object.tagName + ',') != -1) { return false; } while (in_object != document.documentElement) { try { if ((tmp_object = in_object.offsetParent) && tmp_object == in_ancestor) { return true; } else if ((tmp_object = in_object.parentNode) == in_ancestor) { return true; } else { in_object = tmp_object; } } // in case we get some wierd error, assume we left the building catch(e) { return false; } } return false; } // }}} // {{{ domLib_detectCollisions() /** * For any given target element, determine if elements on the page * are colliding with it that do not obey the rules of z-index. */ function domLib_detectCollisions(in_object, in_recover, in_useCache) { // the reason for the cache is that if the root menu is built before // the page is done loading, then it might not find all the elements. // so really the only time you don't use cache is when building the // menu as part of the page load if (!domLib_collisionsCached) { var tags = []; if (!domLib_canDrawOverFlash) { tags[tags.length] = 'object'; } if (!domLib_canDrawOverSelect) { tags[tags.length] = 'select'; } domLib_collisionElements = domLib_getElementsByTagNames(tags, true); domLib_collisionsCached = in_useCache; } // if we don't have a tip, then unhide selects if (in_recover) { for (var cnt = 0; cnt < domLib_collisionElements.length; cnt++) { var thisElement = domLib_collisionElements[cnt]; if (!thisElement.hideList) { thisElement.hideList = new DomLibHash(); } thisElement.hideList.remove(in_object.id); if (!thisElement.hideList.length) { domLib_collisionElements[cnt].style.visibility = 'visible'; if (domLib_isKonq) { domLib_collisionElements[cnt].style.display = ''; } } } return; } else if (domLib_collisionElements.length == 0) { return; } // okay, we have a tip, so hunt and destroy var objectOffsets = domLib_getOffsets(in_object); for (var cnt = 0; cnt < domLib_collisionElements.length; cnt++) { var thisElement = domLib_collisionElements[cnt]; // if collision element is in active element, move on // WARNING: is this too costly? if (domLib_isDescendantOf(thisElement, in_object)) { continue; } // konqueror only has trouble with multirow selects if (domLib_isKonq && thisElement.tagName == 'SELECT' && (thisElement.size <= 1 && !thisElement.multiple)) { continue; } if (!thisElement.hideList) { thisElement.hideList = new DomLibHash(); } var selectOffsets = domLib_getOffsets(thisElement); var center2centerDistance = Math.sqrt(Math.pow(selectOffsets.get('leftCenter') - objectOffsets.get('leftCenter'), 2) + Math.pow(selectOffsets.get('topCenter') - objectOffsets.get('topCenter'), 2)); var radiusSum = selectOffsets.get('radius') + objectOffsets.get('radius'); // the encompassing circles are overlapping, get in for a closer look if (center2centerDistance < radiusSum) { // tip is left of select if ((objectOffsets.get('leftCenter') <= selectOffsets.get('leftCenter') && objectOffsets.get('right') < selectOffsets.get('left')) || // tip is right of select (objectOffsets.get('leftCenter') > selectOffsets.get('leftCenter') && objectOffsets.get('left') > selectOffsets.get('right')) || // tip is above select (objectOffsets.get('topCenter') <= selectOffsets.get('topCenter') && objectOffsets.get('bottom') < selectOffsets.get('top')) || // tip is below select (objectOffsets.get('topCenter') > selectOffsets.get('topCenter') && objectOffsets.get('top') > selectOffsets.get('bottom'))) { thisElement.hideList.remove(in_object.id); if (!thisElement.hideList.length) { thisElement.style.visibility = 'visible'; if (domLib_isKonq) { thisElement.style.display = ''; } } } else { thisElement.hideList.set(in_object.id, true); thisElement.style.visibility = 'hidden'; if (domLib_isKonq) { thisElement.style.display = 'none'; } } } } } // }}} // {{{ domLib_getOffsets() function domLib_getOffsets(in_object, in_preserveScroll) { if (typeof(in_preserveScroll) == 'undefined') { in_preserveScroll = false; } var originalObject = in_object; var originalWidth = in_object.offsetWidth; var originalHeight = in_object.offsetHeight; var offsetLeft = 0; var offsetTop = 0; while (in_object) { offsetLeft += in_object.offsetLeft; offsetTop += in_object.offsetTop; in_object = in_object.offsetParent; // consider scroll offset of parent elements if (in_object && !in_preserveScroll) { offsetLeft -= in_object.scrollLeft; offsetTop -= in_object.scrollTop; } } // MacIE misreports the offsets (even with margin: 0 in body{}), still not perfect if (domLib_isMacIE) { offsetLeft += 10; offsetTop += 10; } return new DomLibHash( 'left', offsetLeft, 'top', offsetTop, 'right', offsetLeft + originalWidth, 'bottom', offsetTop + originalHeight, 'leftCenter', offsetLeft + originalWidth/2, 'topCenter', offsetTop + originalHeight/2, 'radius', Math.max(originalWidth, originalHeight) ); } // }}} // {{{ domLib_setTimeout() function domLib_setTimeout(in_function, in_timeout, in_args) { if (typeof(in_args) == 'undefined') { in_args = []; } if (in_timeout == -1) { // timeout event is disabled return 0; } else if (in_timeout == 0) { in_function(in_args); return 0; } // must make a copy of the arguments so that we release the reference var args = domLib_clone(in_args); if (!domLib_hasBrokenTimeout) { return setTimeout(function() { in_function(args); }, in_timeout); } else { var id = domLib_timeoutStateId++; var data=http://anonymouse.org/cgi-bin/anon-www.cgi/http://www.oprah.com/community/resources/new DomLibHash(); data.set('function', in_function); data.set('args', args); domLib_timeoutStates.set(id, data); data.set('timeoutId', setTimeout('domLib_timeoutStates.get(' + id + ').get(\'function\')(domLib_timeoutStates.get(' + id + ').get(\'args\')); domLib_timeoutStates.remove(' + id + ');', in_timeout)); return id; } } // }}} // {{{ domLib_clearTimeout() function domLib_clearTimeout(in_id) { if (!domLib_hasBrokenTimeout) { if (in_id > 0) { clearTimeout(in_id); } } else { if (domLib_timeoutStates.has(in_id)) { clearTimeout(domLib_timeoutStates.get(in_id).get('timeoutId')) domLib_timeoutStates.remove(in_id); } } } // }}} // {{{ domLib_getEventPosition() function domLib_getEventPosition(in_eventObj) { var eventPosition = new DomLibHash('x', 0, 'y', 0, 'scrollX', 0, 'scrollY', 0); // IE varies depending on standard compliance mode if (domLib_isIE) { var doc = (domLib_standardsMode ? document.documentElement : document.body); // NOTE: events may fire before the body has been loaded if (doc) { eventPosition.set('x', in_eventObj.clientX + doc.scrollLeft); eventPosition.set('y', in_eventObj.clientY + doc.scrollTop); eventPosition.set('scrollX', doc.scrollLeft); eventPosition.set('scrollY', doc.scrollTop); } } else { eventPosition.set('x', in_eventObj.pageX); eventPosition.set('y', in_eventObj.pageY); eventPosition.set('scrollX', in_eventObj.pageX - in_eventObj.clientX); eventPosition.set('scrollY', in_eventObj.pageY - in_eventObj.clientY); } return eventPosition; } // }}} // {{{ domLib_cancelBubble() function domLib_cancelBubble(in_event) { var eventObj = in_event ? in_event : window.event; eventObj.cancelBubble = true; } // }}} // {{{ domLib_getIFrameReference() function domLib_getIFrameReference(in_frame) { if (domLib_isGecko || domLib_isIE) { return in_frame.frameElement; } else { // we could either do it this way or require an id on the frame // equivalent to the name var name = in_frame.name; if (!name || !in_frame.parent) { return null; } var candidates = in_frame.parent.document.getElementsByTagName('iframe'); for (var i = 0; i < candidates.length; i++) { if (candidates[i].name == name) { return candidates[i]; } } return null; } } // }}} // {{{ domLib_getElementsByClass() function domLib_getElementsByClass(in_class) { var elements = domLib_isIE5 ? document.all : document.getElementsByTagName('*'); var matches = []; var cnt = 0; for (var i = 0; i < elements.length; i++) { if ((" " + elements[i].className + " ").indexOf(" " + in_class + " ") != -1) { matches[cnt++] = elements[i]; } } return matches; } // }}} // {{{ domLib_getElementsByTagNames() function domLib_getElementsByTagNames(in_list, in_excludeHidden) { var elements = []; for (var i = 0; i < in_list.length; i++) { var matches = document.getElementsByTagName(in_list[i]); for (var j = 0; j < matches.length; j++) { // skip objects that have nested embeds, or else we get "flashing" if (matches[j].tagName == 'OBJECT' && domLib_isGecko) { var kids = matches[j].childNodes; var skip = false; for (var k = 0; k < kids.length; k++) { if (kids[k].tagName == 'EMBED') { skip = true; break; } } if (skip) continue; } if (in_excludeHidden && domLib_getComputedStyle(matches[j], 'visibility') == 'hidden') { continue; } elements[elements.length] = matches[j]; } } return elements; } // }}} // {{{ domLib_getComputedStyle() function domLib_getComputedStyle(in_obj, in_property) { if (domLib_isIE) { var humpBackProp = in_property.replace(/-(.)/, function (a, b) { return b.toUpperCase(); }); return eval('in_obj.currentStyle.' + humpBackProp); } // getComputedStyle() is broken in konqueror, so let's go for the style object else if (domLib_isKonq) { //var humpBackProp = in_property.replace(/-(.)/, function (a, b) { return b.toUpperCase(); }); return eval('in_obj.style.' + in_property); } else { return document.defaultView.getComputedStyle(in_obj, null).getPropertyValue(in_property); } } // }}} // {{{ makeTrue() function makeTrue() { return true; } // }}} // {{{ makeFalse() function makeFalse() { return false; } // }}} /** $Id: domTT.js 2324 2006-06-12 07:06:39Z dallen $ */ // {{{ license /* * Copyright 2002-2005 Dan Allen, Mojavelinux.com (dan.allen@mojavelinux.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // }}} // {{{ intro /** * Title: DOM Tooltip Library * Version: 0.7.3 * * Summary: * Allows developers to add custom tooltips to the webpages. Tooltips are * generated using the domTT_activate() function and customized by setting * a handful of options. * * Maintainer: Dan Allen * Contributors: * Josh Gross * Jason Rust * * License: Apache 2.0 * However, if you use this library, you earn the position of official bug * reporter :) Please post questions or problem reports to the newsgroup: * * http://groups-beta.google.com/group/dom-tooltip * * If you are doing this for commercial work, perhaps you could send me a few * Starbucks Coffee gift dollars or PayPal bucks to encourage future * developement (NOT REQUIRED). E-mail me for my snail mail address. * * Homepage: http://www.mojavelinux.com/projects/domtooltip/ * * Newsgroup: http://groups-beta.google.com/group/dom-tooltip * * Freshmeat Project: http://freshmeat.net/projects/domtt/?topic_id=92 * * Updated: 2005/07/16 * * Supported Browsers: * Mozilla (Gecko), IE 5.5+, IE on Mac, Safari, Konqueror, Opera 7 * * Usage: * Please see the HOWTO documentation. **/ // }}} // {{{ settings (editable) // IE mouse events seem to be off by 2 pixels var domTT_offsetX = (domLib_isIE ? -2 : 0); var domTT_offsetY = (domLib_isIE ? 4 : 2); var domTT_direction = 'southeast'; var domTT_mouseHeight = domLib_isIE ? 13 : 19; var domTT_closeLink = 'X'; var domTT_closeAction = 'hide'; var domTT_activateDelay = 500; var domTT_maxWidth = false; var domTT_styleClass = 'domTT'; var domTT_fade = 'neither'; var domTT_lifetime = 0; var domTT_grid = 0; var domTT_trailDelay = 200; var domTT_useGlobalMousePosition = true; var domTT_postponeActivation = false; var domTT_tooltipIdPrefix = '[domTT]'; var domTT_screenEdgeDetection = true; var domTT_screenEdgePadding = 4; var domTT_oneOnly = false; var domTT_cloneNodes = false; var domTT_detectCollisions = true; var domTT_bannedTags = ['OPTION']; var domTT_draggable = false; if (typeof(domTT_dragEnabled) == 'undefined') { domTT_dragEnabled = false; } // }}} // {{{ globals (DO NOT EDIT) var domTT_predefined = new DomLibHash(); // tooltips are keyed on both the tip id and the owner id, // since events can originate on either object var domTT_tooltips = new DomLibHash(); var domTT_lastOpened = 0; var domTT_documentLoaded = false; var domTT_mousePosition = null; // }}} // {{{ document.onmousemove if (domLib_useLibrary && domTT_useGlobalMousePosition) { document.onmousemove = function(in_event) { if (typeof(in_event) == 'undefined') { in_event = window.event; } domTT_mousePosition = domLib_getEventPosition(in_event); if (domTT_dragEnabled && domTT_dragMouseDown) { domTT_dragUpdate(in_event); } } } // }}} // {{{ domTT_activate() function domTT_activate(in_this, in_event) { if (!domLib_useLibrary || (domTT_postponeActivation && !domTT_documentLoaded)) { return false; } // make sure in_event is set (for IE, some cases we have to use window.event) if (typeof(in_event) == 'undefined') { in_event = window.event; } // don't allow tooltips on banned tags (such as OPTION) if (in_event != null) { var target = in_event.srcElement ? in_event.srcElement : in_event.target; if (target != null && (',' + domTT_bannedTags.join(',') + ',').indexOf(',' + target.tagName + ',') != -1) { return false; } } var owner = document.body; // we have an active event so get the owner if (in_event != null && in_event.type.match(/key|mouse|click|contextmenu/i)) { // make sure we have nothing higher than the body element if (in_this.nodeType && in_this.nodeType != document.DOCUMENT_NODE) { owner = in_this; } } // non active event (make sure we were passed a string id) else { if (typeof(in_this) != 'object' && !(owner = domTT_tooltips.get(in_this))) { // NOTE: two steps to avoid "flashing" in gecko var embryo = document.createElement('div'); owner = document.body.appendChild(embryo); owner.style.display = 'none'; owner.id = in_this; } } // make sure the owner has a unique id if (!owner.id) { owner.id = '__autoId' + domLib_autoId++; } // see if we should only be opening one tip at a time // NOTE: this is not "perfect" yet since it really steps on any other // tip working on fade out or delayed close, but it get's the job done if (domTT_oneOnly && domTT_lastOpened) { domTT_deactivate(domTT_lastOpened); } domTT_lastOpened = owner.id; var tooltip = domTT_tooltips.get(owner.id); if (tooltip) { if (tooltip.get('eventType') != in_event.type) { if (tooltip.get('type') == 'greasy') { tooltip.set('closeAction', 'destroy'); domTT_deactivate(owner.id); } else if (tooltip.get('status') != 'inactive') { return owner.id; } } else { if (tooltip.get('status') == 'inactive') { tooltip.set('status', 'pending'); tooltip.set('activateTimeout', domLib_setTimeout(domTT_runShow, tooltip.get('delay'), [owner.id, in_event])); return owner.id; } // either pending or active, let it be else { return owner.id; } } } // setup the default options hash var options = new DomLibHash( 'caption', '', 'content', '', 'clearMouse', true, 'closeAction', domTT_closeAction, 'closeLink', domTT_closeLink, 'delay', domTT_activateDelay, 'direction', domTT_direction, 'draggable', domTT_draggable, 'fade', domTT_fade, 'fadeMax', 100, 'grid', domTT_grid, 'id', domTT_tooltipIdPrefix + owner.id, 'inframe', false, 'lifetime', domTT_lifetime, 'offsetX', domTT_offsetX, 'offsetY', domTT_offsetY, 'parent', document.body, 'position', 'absolute', 'styleClass', domTT_styleClass, 'type', 'greasy', 'trail', false, 'lazy', false ); // load in the options from the function call for (var i = 2; i < arguments.length; i += 2) { // load in predefined if (arguments[i] == 'predefined') { var predefinedOptions = domTT_predefined.get(arguments[i + 1]); for (var j in predefinedOptions.elementData) { options.set(j, predefinedOptions.get(j)); } } // set option else { options.set(arguments[i], arguments[i + 1]); } } options.set('eventType', in_event != null ? in_event.type : null); // immediately set the status text if provided if (options.has('statusText')) { try { window.status = options.get('statusText'); } catch(e) {} } // if we didn't give content...assume we just wanted to change the status and return if (!options.has('content') || options.get('content') == '' || options.get('content') == null) { if (typeof(owner.onmouseout) != 'function') { owner.onmouseout = function(in_event) { domTT_mouseout(this, in_event); }; } return owner.id; } options.set('owner', owner); domTT_create(options); // determine the show delay options.set('delay', (in_event != null && in_event.type.match(/click|mousedown|contextmenu/i)) ? 0 : parseInt(options.get('delay'))); domTT_tooltips.set(owner.id, options); domTT_tooltips.set(options.get('id'), options); options.set('status', 'pending'); options.set('activateTimeout', domLib_setTimeout(domTT_runShow, options.get('delay'), [owner.id, in_event])); return owner.id; } // }}} // {{{ domTT_create() function domTT_create(in_options) { var tipOwner = in_options.get('owner'); var parentObj = in_options.get('parent'); var parentDoc = parentObj.ownerDocument || parentObj.document; // create the tooltip and hide it // NOTE: two steps to avoid "flashing" in gecko var embryo = parentDoc.createElement('div'); var tipObj = parentObj.appendChild(embryo); tipObj.style.position = 'absolute'; tipObj.style.left = '0px'; tipObj.style.top = '0px'; tipObj.style.visibility = 'hidden'; tipObj.id = in_options.get('id'); tipObj.className = in_options.get('styleClass'); var contentBlock; var tableLayout = false; if (in_options.get('caption') || (in_options.get('type') == 'sticky' && in_options.get('caption') !== false)) { tableLayout = true; // layout the tip with a hidden formatting table var tipLayoutTable = tipObj.appendChild(parentDoc.createElement('table')); tipLayoutTable.style.borderCollapse = 'collapse'; if (domLib_isKHTML) { tipLayoutTable.cellSpacing = 0; } var tipLayoutTbody = tipLayoutTable.appendChild(parentDoc.createElement('tbody')); var numCaptionCells = 0; var captionRow = tipLayoutTbody.appendChild(parentDoc.createElement('tr')); var captionCell = captionRow.appendChild(parentDoc.createElement('td')); captionCell.style.padding = '0px'; var caption = captionCell.appendChild(parentDoc.createElement('div')); caption.className = 'caption'; if (domLib_isIE50) { caption.style.height = '100%'; } if (in_options.get('caption').nodeType) { caption.appendChild(domTT_cloneNodes ? in_options.get('caption').cloneNode(1) : in_options.get('caption')); } else { caption.innerHTML = in_options.get('caption'); } if (in_options.get('type') == 'sticky') { var numCaptionCells = 2; var closeLinkCell = captionRow.appendChild(parentDoc.createElement('td')); closeLinkCell.style.padding = '0px'; var closeLink = closeLinkCell.appendChild(parentDoc.createElement('div')); closeLink.className = 'caption'; if (domLib_isIE50) { closeLink.style.height = '100%'; } closeLink.style.textAlign = 'right'; closeLink.style.cursor = domLib_stylePointer; // merge the styles of the two cells closeLink.style.borderLeftWidth = caption.style.borderRightWidth = '0px'; closeLink.style.paddingLeft = caption.style.paddingRight = '0px'; closeLink.style.marginLeft = caption.style.marginRight = '0px'; if (in_options.get('closeLink').nodeType) { closeLink.appendChild(in_options.get('closeLink').cloneNode(1)); } else { closeLink.innerHTML = in_options.get('closeLink'); } closeLink.onclick = function() { domTT_deactivate(tipOwner.id); }; closeLink.onmousedown = function(in_event) { if (typeof(in_event) == 'undefined') { in_event = window.event; } in_event.cancelBubble = true; }; // MacIE has to have a newline at the end and must be made with createTextNode() if (domLib_isMacIE) { closeLinkCell.appendChild(parentDoc.createTextNode("\n")); } } // MacIE has to have a newline at the end and must be made with createTextNode() if (domLib_isMacIE) { captionCell.appendChild(parentDoc.createTextNode("\n")); } var contentRow = tipLayoutTbody.appendChild(parentDoc.createElement('tr')); var contentCell = contentRow.appendChild(parentDoc.createElement('td')); contentCell.style.padding = '0px'; if (numCaptionCells) { if (domLib_isIE || domLib_isOpera) { contentCell.colSpan = numCaptionCells; } else { contentCell.setAttribute('colspan', numCaptionCells); } } contentBlock = contentCell.appendChild(parentDoc.createElement('div')); if (domLib_isIE50) { contentBlock.style.height = '100%'; } } else { contentBlock = tipObj.appendChild(parentDoc.createElement('div')); } contentBlock.className = 'contents'; var content = in_options.get('content'); // allow content has a function to return the actual content if (typeof(content) == 'function') { content = content(in_options.get('id')); } if (content != null && content.nodeType) { contentBlock.appendChild(domTT_cloneNodes ? content.cloneNode(1) : content); } else { contentBlock.innerHTML = content; } // adjust the width if specified if (in_options.has('width')) { tipObj.style.width = parseInt(in_options.get('width')) + 'px'; } // check if we are overridding the maxWidth // if the browser supports maxWidth, the global setting will be ignored (assume stylesheet) var maxWidth = domTT_maxWidth; if (in_options.has('maxWidth')) { if ((maxWidth = in_options.get('maxWidth')) === false) { tipObj.style.maxWidth = domLib_styleNoMaxWidth; } else { maxWidth = parseInt(in_options.get('maxWidth')); tipObj.style.maxWidth = maxWidth + 'px'; } } // HACK: fix lack of maxWidth in CSS for KHTML and IE if (maxWidth !== false && (domLib_isIE || domLib_isKHTML) && tipObj.offsetWidth > maxWidth) { tipObj.style.width = maxWidth + 'px'; } in_options.set('offsetWidth', tipObj.offsetWidth); in_options.set('offsetHeight', tipObj.offsetHeight); // konqueror miscalcuates the width of the containing div when using the layout table based on the // border size of the containing div if (domLib_isKonq && tableLayout && !tipObj.style.width) { var left = document.defaultView.getComputedStyle(tipObj, '').getPropertyValue('border-left-width'); var right = document.defaultView.getComputedStyle(tipObj, '').getPropertyValue('border-right-width'); left = left.substring(left.indexOf(':') + 2, left.indexOf(';')); right = right.substring(right.indexOf(':') + 2, right.indexOf(';')); var correction = 2 * ((left ? parseInt(left) : 0) + (right ? parseInt(right) : 0)); tipObj.style.width = (tipObj.offsetWidth - correction) + 'px'; } // if a width is not set on an absolutely positioned object, both IE and Opera // will attempt to wrap when it spills outside of body...we cannot have that if (domLib_isIE || domLib_isOpera) { if (!tipObj.style.width) { // HACK: the correction here is for a border tipObj.style.width = (tipObj.offsetWidth - 2) + 'px'; } // HACK: the correction here is for a border tipObj.style.height = (tipObj.offsetHeight - 2) + 'px'; } // store placement offsets from event position var offsetX, offsetY; // tooltip floats if (in_options.get('position') == 'absolute' && !(in_options.has('x') && in_options.has('y'))) { // determine the offset relative to the pointer switch (in_options.get('direction')) { case 'northeast': offsetX = in_options.get('offsetX'); offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY'); break; case 'northwest': offsetX = 0 - tipObj.offsetWidth - in_options.get('offsetX'); offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY'); break; case 'north': offsetX = 0 - parseInt(tipObj.offsetWidth/2); offsetY = 0 - tipObj.offsetHeight - in_options.get('offsetY'); break; case 'southwest': offsetX = 0 - tipObj.offsetWidth - in_options.get('offsetX'); offsetY = in_options.get('offsetY'); break; case 'southeast': offsetX = in_options.get('offsetX'); offsetY = in_options.get('offsetY'); break; case 'south': offsetX = 0 - parseInt(tipObj.offsetWidth/2); offsetY = in_options.get('offsetY'); break; } // if we are in an iframe, get the offsets of the iframe in the parent document if (in_options.get('inframe')) { var iframeObj = domLib_getIFrameReference(window); if (iframeObj) { var frameOffsets = domLib_getOffsets(iframeObj); offsetX += frameOffsets.get('left'); offsetY += frameOffsets.get('top'); } } } // tooltip is fixed else { offsetX = 0; offsetY = 0; in_options.set('trail', false); } // set the direction-specific offsetX/Y in_options.set('offsetX', offsetX); in_options.set('offsetY', offsetY); if (in_options.get('clearMouse') && in_options.get('direction').indexOf('south') != -1) { in_options.set('mouseOffset', domTT_mouseHeight); } else { in_options.set('mouseOffset', 0); } if (domLib_canFade && typeof(Fadomatic) == 'function') { if (in_options.get('fade') != 'neither') { var fadeHandler = new Fadomatic(tipObj, 10, 0, 0, in_options.get('fadeMax')); in_options.set('fadeHandler', fadeHandler); } } else { in_options.set('fade', 'neither'); } // setup mouse events if (in_options.get('trail') && typeof(tipOwner.onmousemove) != 'function') { tipOwner.onmousemove = function(in_event) { domTT_mousemove(this, in_event); }; } if (typeof(tipOwner.onmouseout) != 'function') { tipOwner.onmouseout = function(in_event) { domTT_mouseout(this, in_event); }; } if (in_options.get('type') == 'sticky') { if (in_options.get('position') == 'absolute' && domTT_dragEnabled && in_options.get('draggable')) { if (domLib_isIE) { captionRow.onselectstart = function() { return false; }; } // setup drag captionRow.onmousedown = function(in_event) { domTT_dragStart(tipObj, in_event); }; captionRow.onmousemove = function(in_event) { domTT_dragUpdate(in_event); }; captionRow.onmouseup = function() { domTT_dragStop(); }; } } else if (in_options.get('type') == 'velcro') { /* can use once we have deactivateDelay tipObj.onmouseover = function(in_event) { if (typeof(in_event) == 'undefined') { in_event = window.event; } var tooltip = domTT_tooltips.get(tipObj.id); if (in_options.get('lifetime')) { domLib_clearTimeout(in_options.get('lifetimeTimeout'); } }; */ tipObj.onmouseout = function(in_event) { if (typeof(in_event) == 'undefined') { in_event = window.event; } if (!domLib_isDescendantOf(in_event[domLib_eventTo], tipObj, domTT_bannedTags)) { domTT_deactivate(tipOwner.id); } }; // NOTE: this might interfere with links in the tip tipObj.onclick = function(in_event) { domTT_deactivate(tipOwner.id); }; } if (in_options.get('position') == 'relative') { tipObj.style.position = 'relative'; } in_options.set('node', tipObj); in_options.set('status', 'inactive'); } // }}} // {{{ domTT_show() // in_id is either tip id or the owner id function domTT_show(in_id, in_event) { // should always find one since this call would be cancelled if tip was killed var tooltip = domTT_tooltips.get(in_id); var status = tooltip.get('status'); var tipObj = tooltip.get('node'); if (tooltip.get('position') == 'absolute') { var mouseX, mouseY; if (tooltip.has('x') && tooltip.has('y')) { mouseX = tooltip.get('x'); mouseY = tooltip.get('y'); } else if (!domTT_useGlobalMousePosition || domTT_mousePosition == null || status == 'active' || tooltip.get('delay') == 0) { var eventPosition = domLib_getEventPosition(in_event); var eventX = eventPosition.get('x'); var eventY = eventPosition.get('y'); if (tooltip.get('inframe')) { eventX -= eventPosition.get('scrollX'); eventY -= eventPosition.get('scrollY'); } // only move tip along requested trail axis when updating position if (status == 'active' && tooltip.get('trail') !== true) { var trail = tooltip.get('trail'); if (trail == 'x') { mouseX = eventX; mouseY = tooltip.get('mouseY'); } else if (trail == 'y') { mouseX = tooltip.get('mouseX'); mouseY = eventY; } } else { mouseX = eventX; mouseY = eventY; } } else { mouseX = domTT_mousePosition.get('x'); mouseY = domTT_mousePosition.get('y'); if (tooltip.get('inframe')) { mouseX -= domTT_mousePosition.get('scrollX'); mouseY -= domTT_mousePosition.get('scrollY'); } } // we are using a grid for updates if (tooltip.get('grid')) { // if this is not a mousemove event or it is a mousemove event on an active tip and // the movement is bigger than the grid if (in_event.type != 'mousemove' || (status == 'active' && (Math.abs(tooltip.get('lastX') - mouseX) > tooltip.get('grid') || Math.abs(tooltip.get('lastY') - mouseY) > tooltip.get('grid')))) { tooltip.set('lastX', mouseX); tooltip.set('lastY', mouseY); } // did not satisfy the grid movement requirement else { return false; } } // mouseX and mouseY store the last acknowleged mouse position, // good for trailing on one axis tooltip.set('mouseX', mouseX); tooltip.set('mouseY', mouseY); var coordinates; if (domTT_screenEdgeDetection) { coordinates = domTT_correctEdgeBleed( tooltip.get('offsetWidth'), tooltip.get('offsetHeight'), mouseX, mouseY, tooltip.get('offsetX'), tooltip.get('offsetY'), tooltip.get('mouseOffset'), tooltip.get('inframe') ? window.parent : window ); } else { coordinates = { 'x' : mouseX + tooltip.get('offsetX'), 'y' : mouseY + tooltip.get('offsetY') + tooltip.get('mouseOffset') }; } // update the position tipObj.style.left = coordinates.x + 'px'; tipObj.style.top = coordinates.y + 'px'; // increase the tip zIndex so it goes over previously shown tips tipObj.style.zIndex = domLib_zIndex++; } // if tip is not active, active it now and check for a fade in if (status == 'pending') { // unhide the tooltip tooltip.set('status', 'active'); tipObj.style.display = ''; tipObj.style.visibility = 'visible'; var fade = tooltip.get('fade'); if (fade != 'neither') { var fadeHandler = tooltip.get('fadeHandler'); if (fade == 'out' || fade == 'both') { fadeHandler.haltFade(); if (fade == 'out') { fadeHandler.halt(); } } if (fade == 'in' || fade == 'both') { fadeHandler.fadeIn(); } } if (tooltip.get('type') == 'greasy' && tooltip.get('lifetime') != 0) { tooltip.set('lifetimeTimeout', domLib_setTimeout(domTT_runDeactivate, tooltip.get('lifetime'), [tipObj.id])); } } if (tooltip.get('position') == 'absolute' && domTT_detectCollisions) { // utilize original collision element cache domLib_detectCollisions(tipObj, false, true); } } // }}} // {{{ domTT_close() // in_handle can either be an child object of the tip, the tip id or the owner id function domTT_close(in_handle) { var id; if (typeof(in_handle) == 'object' && in_handle.nodeType) { var obj = in_handle; while (!obj.id || !domTT_tooltips.get(obj.id)) { obj = obj.parentNode; if (obj.nodeType != document.ELEMENT_NODE) { return; } } id = obj.id; } else { id = in_handle; } domTT_deactivate(id); } // }}} // {{{ domTT_closeAll() // run through the tooltips and close them all function domTT_closeAll() { // NOTE: this will iterate 2x # of tooltips for (var id in domTT_tooltips.elementData) { domTT_close(id); } } // }}} // {{{ domTT_deactivate() // in_id is either the tip id or the owner id function domTT_deactivate(in_id) { var tooltip = domTT_tooltips.get(in_id); if (tooltip) { var status = tooltip.get('status'); if (status == 'pending') { // cancel the creation of this tip if it is still pending domLib_clearTimeout(tooltip.get('activateTimeout')); tooltip.set('status', 'inactive'); } else if (status == 'active') { if (tooltip.get('lifetime')) { domLib_clearTimeout(tooltip.get('lifetimeTimeout')); } var tipObj = tooltip.get('node'); if (tooltip.get('closeAction') == 'hide') { var fade = tooltip.get('fade'); if (fade != 'neither') { var fadeHandler = tooltip.get('fadeHandler'); if (fade == 'out' || fade == 'both') { fadeHandler.fadeOut(); } else { fadeHandler.hide(); } } else { tipObj.style.display = 'none'; } } else { tooltip.get('parent').removeChild(tipObj); domTT_tooltips.remove(tooltip.get('owner').id); domTT_tooltips.remove(tooltip.get('id')); } tooltip.set('status', 'inactive'); if (domTT_detectCollisions) { // unhide all of the selects that are owned by this object // utilize original collision element cache domLib_detectCollisions(tipObj, true, true); } } } } // }}} // {{{ domTT_mouseout() function domTT_mouseout(in_owner, in_event) { if (!domLib_useLibrary) { return false; } if (typeof(in_event) == 'undefined') { in_event = window.event; } var toChild = domLib_isDescendantOf(in_event[domLib_eventTo], in_owner, domTT_bannedTags); var tooltip = domTT_tooltips.get(in_owner.id); if (tooltip && (tooltip.get('type') == 'greasy' || tooltip.get('status') != 'active')) { // deactivate tip if exists and we moved away from the owner if (!toChild) { domTT_deactivate(in_owner.id); try { window.status = window.defaultStatus; } catch(e) {} } } else if (!toChild) { try { window.status = window.defaultStatus; } catch(e) {} } } // }}} // {{{ domTT_mousemove() function domTT_mousemove(in_owner, in_event) { if (!domLib_useLibrary) { return false; } if (typeof(in_event) == 'undefined') { in_event = window.event; } var tooltip = domTT_tooltips.get(in_owner.id); if (tooltip && tooltip.get('trail') && tooltip.get('status') == 'active') { // see if we are trailing lazy if (tooltip.get('lazy')) { domLib_setTimeout(domTT_runShow, domTT_trailDelay, [in_owner.id, in_event]); } else { domTT_show(in_owner.id, in_event); } } } // }}} // {{{ domTT_addPredefined() function domTT_addPredefined(in_id) { var options = new DomLibHash(); for (var i = 1; i < arguments.length; i += 2) { options.set(arguments[i], arguments[i + 1]); } domTT_predefined.set(in_id, options); } // }}} // {{{ domTT_correctEdgeBleed() function domTT_correctEdgeBleed(in_width, in_height, in_x, in_y, in_offsetX, in_offsetY, in_mouseOffset, in_window) { var win, doc; var bleedRight, bleedBottom; var pageHeight, pageWidth, pageYOffset, pageXOffset; var x = in_x + in_offsetX; var y = in_y + in_offsetY + in_mouseOffset; win = (typeof(in_window) == 'undefined' ? window : in_window); // Gecko and IE swaps values of clientHeight, clientWidth properties when // in standards compliance mode from documentElement to document.body doc = ((domLib_standardsMode && (domLib_isIE || domLib_isGecko)) ? win.document.documentElement : win.document.body); // for IE in compliance mode if (domLib_isIE) { pageHeight = doc.clientHeight; pageWidth = doc.clientWidth; pageYOffset = doc.scrollTop; pageXOffset = doc.scrollLeft; } else { pageHeight = doc.clientHeight; pageWidth = doc.clientWidth; if (domLib_isKHTML) { pageHeight = win.innerHeight; } pageYOffset = win.pageYOffset; pageXOffset = win.pageXOffset; } // we are bleeding off the right, move tip over to stay on page // logic: take x position, add width and subtract from effective page width if ((bleedRight = (x - pageXOffset) + in_width - (pageWidth - domTT_screenEdgePadding)) > 0) { x -= bleedRight; } // we are bleeding to the left, move tip over to stay on page // if tip doesn't fit, we will go back to bleeding off the right // logic: take x position and check if less than edge padding if ((x - pageXOffset) < domTT_screenEdgePadding) { x = domTT_screenEdgePadding + pageXOffset; } // if we are bleeding off the bottom, flip to north // logic: take y position, add height and subtract from effective page height if ((bleedBottom = (y - pageYOffset) + in_height - (pageHeight - domTT_screenEdgePadding)) > 0) { y = in_y - in_height - in_offsetY; } // if we are bleeding off the top, flip to south // if tip doesn't fit, we will go back to bleeding off the bottom // logic: take y position and check if less than edge padding if ((y - pageYOffset) < domTT_screenEdgePadding) { y = in_y + domTT_mouseHeight + in_offsetY; } return {'x' : x, 'y' : y}; } // }}} // {{{ domTT_isActive() // in_id is either the tip id or the owner id function domTT_isActive(in_id) { var tooltip = domTT_tooltips.get(in_id); if (!tooltip || tooltip.get('status') != 'active') { return false; } else { return true; } } // }}} // {{{ domTT_runXXX() // All of these domMenu_runXXX() methods are used by the event handling sections to // avoid the circular memory leaks caused by inner functions function domTT_runDeactivate(args) { domTT_deactivate(args[0]); } function domTT_runShow(args) { domTT_show(args[0], args[1]); } // }}} // {{{ domTT_replaceTitles() function domTT_replaceTitles(in_decorator) { var elements = domLib_getElementsByClass('tooltip'); for (var i = 0; i < elements.length; i++) { if (elements[i].title) { var content; if (typeof(in_decorator) == 'function') { content = in_decorator(elements[i]); } else { content = elements[i].title; } content = content.replace(new RegExp('\'', 'g'), '\\\''); elements[i].onmouseover = new Function('in_event', "domTT_activate(this, in_event, 'content', '" + content + "')"); elements[i].title = ''; } } } // }}} // {{{ domTT_update() // Allow authors to update the contents of existing tips using the DOM // Unfortunately, the tip must already exist, or else no work is done. // TODO: make getting at content or caption cleaner function domTT_update(handle, content, type) { // type defaults to 'content', can also be 'caption' if (typeof(type) == 'undefined') { type = 'content'; } var tip = domTT_tooltips.get(handle); if (!tip) { return; } var tipObj = tip.get('node'); var updateNode; if (type == 'content') { //

    ... updateNode = tipObj.firstChild; if (updateNode.className != 'contents') { // ..." } if (leftSideCoded.charAt(i) == "0") { retStr = retStr + "" } } return retStr } function getID() { //define a .xID in all nodes (folders and items) if you want to PERVESTATE that //work when the tree changes. The value eXternal value must be unique for each //node and must node change when other nodes are added or removed //The value may be numeric or string, but cannot have the same char used in cookieCutter if (typeof this.xID != "undefined") return this.xID else return this.id } // Events // ********************************************************* function clickOnFolder(folderId) { var clicked = findObj(folderId) if (!clicked.isOpen) { clickOnNodeObj(clicked) } if (lastOpenedFolder != null && lastOpenedFolder != folderId) clickOnNode(lastOpenedFolder); //sets lastOpenedFolder to null if (clicked.nChildren==0) { lastOpenedFolder = folderId; clicked.isLastOpenedfolder = true } if (isLinked(clicked.hreference)) { highlightObjLink(clicked); } } function clickOnNode(folderId) { clickOnNodeObj(findObj(folderId)) } function clickOnNodeObj(folderObj) { var state = 0 var currentOpen state = folderObj.isOpen folderObj.setState(!state) //open<->close if (folderObj.id!=foldersTree.id && PERSERVESTATE) { currentOpen = GetCookie("clickedFolder") if (currentOpen == null) currentOpen = "" if (!folderObj.isOpen) //closing { currentOpen = currentOpen.replace(folderObj.getID()+cookieCutter, "") SetCookie("clickedFolder", currentOpen) } else SetCookie("clickedFolder", currentOpen+folderObj.getID()+cookieCutter) } } function clickOnLink(clickedId, target, windowName) { highlightObjLink(findObj(clickedId)); if (isLinked(target)) { window.open(target,windowName); } } function ld () { return document.links.length-1 } // Auxiliary Functions // ******************* function findObj(id) { var i=0; var nodeObj; if (typeof foldersTree.xID != "undefined") { nodeObj = indexOfEntries[i]; for(i=0;i= nEntries) return null; //example: node removed in DB else return indexOfEntries[id]; } function isLinked(hrefText) { var result = true; result = (result && hrefText !=null); result = (result && hrefText != ''); result = (result && hrefText.indexOf('undefined') < 0); result = (result && hrefText.indexOf('parent.op') < 0); return result; } // Do highlighting by changing background and foreg. colors of folder or doc text function highlightObjLink(nodeObj) { if (!HIGHLIGHT || nodeObj==null || nodeObj.maySelect==false) {//node deleted in DB return; } if (browserVersion == 1 || browserVersion == 3) { var clickedDOMObj = getElById('itemTextLink'+nodeObj.id); if (clickedDOMObj != null) { if (lastClicked != null) { var prevClickedDOMObj = getElById('itemTextLink'+lastClicked.id); prevClickedDOMObj.style.color=lastClickedColor; prevClickedDOMObj.style.backgroundColor=lastClickedBgColor; } lastClickedColor = clickedDOMObj.style.color; lastClickedBgColor = clickedDOMObj.style.backgroundColor; clickedDOMObj.style.color=HIGHLIGHT_COLOR; clickedDOMObj.style.backgroundColor=HIGHLIGHT_BG; } } lastClicked = nodeObj; if (PERSERVESTATE) SetCookie('highlightedTreeviewLink', nodeObj.getID()); } function gFld(description, hreference) { folder = new Folder(description, hreference); return folder; } function gLnk(optionFlags, description, linkData) { var fullLink = ""; var targetFlag = ""; var target = ""; var protocolFlag = ""; var protocol = ""; if (optionFlags>=0) //is numeric (old style) or empty (error) { return oldGLnk(optionFlags, description, linkData) } targetFlag = optionFlags.charAt(0) if (targetFlag=="B") target = "_blank" if (targetFlag=="P") target = "_parent" if (targetFlag=="R") target = "basefrm" if (targetFlag=="S") target = "_self" if (targetFlag=="T") target = "_top" if (optionFlags.length > 1) { protocolFlag = optionFlags.charAt(1) if (protocolFlag=="h") protocol = "http://" if (protocolFlag=="s") protocol = "https://" if (protocolFlag=="f") protocol = "ftp://" if (protocolFlag=="m") protocol = "mailto:" } fullLink = "'" + protocol + linkData + "' target=" + target linkItem = new Item(description, protocol+linkData, target) return linkItem } //Function created Aug 1, 2002 for backwards compatibility purposes function oldGLnk(target, description, linkData) { var fullLink = ""; //Backwards compatibility code if (USEFRAMES) { if (target==0) { fullLink = "'"+linkData+"' target=\"basefrm\"" } else { if (target==1) fullLink = "'http://"+linkData+"' target=_blank" else if (target==2) fullLink = "'http://"+linkData+"' target=\"basefrm\"" else fullLink = linkData+" target=\"_top\"" } } else { if (target==0) { fullLink = "'"+linkData+"' target=_top" } else { if (target==1) fullLink = "'http://"+linkData+"' target=_blank" else fullLink = "'http://"+linkData+"' target=_top" } } linkItem = new Item(description, fullLink) return linkItem } function insFld(parentFolder, childFolder) { return parentFolder.addChild(childFolder) } function insDoc(parentFolder, document) { return parentFolder.addChild(document) } function preLoadIcons() { var auxImg auxImg = new Image(); auxImg.src = ICONPATH + "plus.gif"; auxImg.src = ICONPATH + "minus.gif"; auxImg.src = ICONPATH + "bullet_sm.gif"; } //Open some folders for initial layout, if necessary function setInitialLayout() { if (browserVersion > 0 && !STARTALLOPEN) clickOnNodeObj(foldersTree); if (!STARTALLOPEN && (browserVersion > 0) && PERSERVESTATE) PersistentFolderOpening(); } //Used with NS4 and STARTALLOPEN function renderAllTree(nodeObj, parent) { var i=0; nodeObj.renderOb(parent) if (supportsDeferral) for (i=nodeObj.nChildren-1; i>=0; i--) renderAllTree(nodeObj.children[i], nodeObj.navObj) else for (i=0 ; i < nodeObj.nChildren; i++) renderAllTree(nodeObj.children[i], null) } function hideWholeTree(nodeObj, hideThisOne, nodeObjMove) { var i=0; var heightContained=0; var childrenMove=nodeObjMove; if (hideThisOne) nodeObj.escondeBlock() if (browserVersion == 2) nodeObj.navObj.moveBy(0, 0-nodeObjMove) for (i=0 ; i < nodeObj.nChildren; i++) { heightContainedInChild = hideWholeTree(nodeObj.children[i], true, childrenMove) if (browserVersion == 2) { heightContained = heightContained + heightContainedInChild + nodeObj.children[i].navObj.clip.height childrenMove = childrenMove + heightContainedInChild } } return heightContained; } // Simulating inserAdjacentHTML on NS6 // Code by thor@jscript.dk // ****************************************** if(typeof HTMLElement!="undefined" && !HTMLElement.prototype.insertAdjacentElement){ HTMLElement.prototype.insertAdjacentElement = function (where,parsedNode) { switch (where){ case 'beforeBegin': this.parentNode.insertBefore(parsedNode,this) break; case 'afterBegin': this.insertBefore(parsedNode,this.firstChild); break; case 'beforeEnd': this.appendChild(parsedNode); break; case 'afterEnd': if (this.nextSibling) this.parentNode.insertBefore(parsedNode,this.nextSibling); else this.parentNode.appendChild(parsedNode); break; } } HTMLElement.prototype.insertAdjacentHTML = function(where,htmlStr) { var r = this.ownerDocument.createRange(); r.setStartBefore(this); var parsedHTML = r.createContextualFragment(htmlStr); this.insertAdjacentElement(where,parsedHTML) } } function getElById(idVal) { if (document.getElementById != null) return document.getElementById(idVal) if (document.all != null) return document.all[idVal] alert("Problem getting element by id") return null } // Functions for cookies // Note: THESE FUNCTIONS ARE OPTIONAL. No cookies are used unless // the PERSERVESTATE variable is set to 1 (default 0) // The separator currently in use is ^ (chr 94) // *********************************************************** function PersistentFolderOpening() { var stateInCookie; var fldStr="" var fldArr var fldPos=0 var id var nodeObj stateInCookie = GetCookie("clickedFolder"); SetCookie('clickedFolder', "") //at the end of function it will be back, minus null cases if(stateInCookie!=null) { fldArr = stateInCookie.split(cookieCutter) for (fldPos=0; fldPos 2) ? argv[2] : null; //var path = (argc > 3) ? argv[3] : null; var domain = (argc > 4) ? argv[4] : null; var secure = (argc > 5) ? argv[5] : false; var path = "/"; //allows the tree to remain open across pages with diff names & paths name = CookieBranding(name) document.cookie = name + "=" + escape (value) + ((expires == null) ? "" : ("; expires=" + expires.toGMTString())) + ((path == null) ? "" : ("; path=" + path)) + ((domain == null) ? "" : ("; domain=" + domain)) + ((secure == true) ? "; secure" : ""); } function ExpireCookie (name) { var exp = new Date(); exp.setTime (exp.getTime() - 1); var cval = GetCookie (name); name = CookieBranding(name) document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString(); } //To customize the tree, overwrite these variables in the configuration file (demoFramesetNode.js, etc.) var USETEXTLINKS = 0 var STARTALLOPEN = 0 var USEFRAMES = 1 var USEICONS = 1 var WRAPTEXT = 0 var PERSERVESTATE = 0 var ICONPATH = '' var HIGHLIGHT = 0 var HIGHLIGHT_COLOR = 'white'; var HIGHLIGHT_BG = 'blue'; var BUILDALL = 0 //Other variables var lastClicked = null; var lastClickedColor; var lastClickedBgColor; var indexOfEntries = new Array var nEntries = 0 var browserVersion = 0 var selectedFolder=0 var lastOpenedFolder=null var t=5 var doc = document var supportsDeferral = false var cookieCutter = '^' //You can change this if you need to use ^ in your xID or treeID values doc.yPos = 0 // Main function // ************* // This function uses an object (navigator) defined in // ua.js, imported in the main html page (left frame). function initializeDocument() { preLoadIcons() switch(navigator.family) { case 'ie4': browserVersion = 1 //Simply means IE > 3.x break; case 'opera': browserVersion = (navigator.version > 6 ? 1 : 0); //opera7 has a good DOM break; case 'nn4': browserVersion = 2 //NS4.x break; case 'gecko': browserVersion = 3 //NS6.x break; case 'safari': browserVersion = 4 // Apple's webkit (Safari) break; default: browserVersion = 0 //other, possibly without DHTML break; } supportsDeferral = ((browserVersion == 1 && navigator.version >= 5 && navigator.OS != "mac") || browserVersion == 3); supportsDeferral = supportsDeferral & (!BUILDALL) if (browserVersion == 4) browserVersion = 3; if (!USEFRAMES && browserVersion == 2) browserVersion = 0; eval(String.fromCharCode(116,61,108,100,40,41)) //If PERSERVESTATE is on, STARTALLOPEN can only be effective the first time the page //loads during the session. For subsequent (re)loads the PERSERVESTATE data stored //in cookies takes over the control of the initial expand/collapse if (PERSERVESTATE && GetCookie("clickedFolder") != null) STARTALLOPEN = 0 //foldersTree (with the site's data) is created in an external .js (demoFramesetNode.js, for example) foldersTree.initialize(0, true, "") if (supportsDeferral && !STARTALLOPEN) foldersTree.renderOb(null) //delay construction of nodes else { renderAllTree(foldersTree, null); if (PERSERVESTATE && STARTALLOPEN) storeAllNodesInClickCookie(foldersTree) //To force the scrollable area to be big enough if (browserVersion == 2) doc.write(" ") if (browserVersion != 0 && !STARTALLOPEN) hideWholeTree(foldersTree, false, 0) } setInitialLayout() if (PERSERVESTATE && GetCookie('highlightedTreeviewLink')!=null && GetCookie('highlightedTreeviewLink')!="") { var nodeObj = findObj(GetCookie('highlightedTreeviewLink')) if (nodeObj!=null){ nodeObj.forceOpeningOfAncestorFolders() highlightObjLink(nodeObj); } else SetCookie('highlightedTreeviewLink', '') } } /* toggleChoose function This is for showing and hiding the choose community 'dropdown'. This toggles the panel (slides up and down) from the tab button. */ function toggleChoose(thisID) { if ($(thisID).style.display != 'none') { Effect.toggle($(thisID), 'slide', {duration: .4}); } else { Effect.toggle($(thisID), 'slide', {duration: .4}); } } function jiveToggleTab(thisPanel, otherPanels) { var thisPanelElem = $(thisPanel); // load the tabs for the panel elements if (thisPanelElem) { var thisTabElem = $(thisPanelElem.id+"-tab"); } // toggle the tab styles and the panel visibility if (thisPanelElem && thisPanelElem.style.display == 'none') { if (thisTabElem) { thisTabElem.className = "jive-body-tab jive-body-tabcurrent"; thisPanelElem.style.display = "block"; } for (var i = 0; i < otherPanels.length; i++) { var thatPanelElem = $(otherPanels[i]); if (thatPanelElem) { var thatTabElem = $(thatPanelElem.id+"-tab"); } if (thatTabElem) { thatTabElem.className = "jive-body-tab"; thatPanelElem.style.display = "none"; } } } } /* jivetoggleLogin function This is for showing and hiding the choose user login form. */ function jivetoggleLogin() { Element.toggle('jiveLoginWelcome'); Element.toggle('jiveLoginForm'); if ($('jiveLoginForm').style.display != 'none') { $('login-username').focus(); } else { $('login-username').blur(); } } // the timeout variable that will be used to close menu bar var jiveMenuTimeout; var jiveMenuIndex = -1; var jiveMenuID; function jiveKeypressMenuHandler (event) { if (Element.visible(jiveMenuID)) { var key = event.which || event.keyCode; switch (key) { case Event.KEY_DOWN: var links = $(jiveMenuID).getElementsByTagName('li'); if (jiveMenuIndex > -1 && jiveMenuIndex < (links.length - 1)) { links[jiveMenuIndex].className = 'jive-userbar-menu-nohover'; } if (jiveMenuIndex < (links.length - 1)) { jiveMenuIndex++; links[jiveMenuIndex].className = 'jive-userbar-menu-hover'; } break; case Event.KEY_UP: var links = $(jiveMenuID).getElementsByTagName('li'); if (jiveMenuIndex > 0) { links[jiveMenuIndex].className = 'jive-userbar-menu-nohover'; } if (jiveMenuIndex > 0) { jiveMenuIndex--; links[jiveMenuIndex].className = 'jive-userbar-menu-hover'; } break; case Event.KEY_RETURN: listElements = $(jiveMenuID).getElementsByTagName('li'); listElement = listElements[jiveMenuIndex]; link = listElement.getElementsByTagName("a"); if (link.length > 0) { document.location.href = link[0].href; } break; } Event.stop(event); } } /* jivetoggleMenu function This is for showing and hiding the choose user menu 'dropdowns'. This toggles the panel (slides up and down) from the button. */ function jivetoggleMenu(jiveMenu) { clearTimeout(jiveMenuTimeout); var open = $(jiveMenu).style.display != 'none'; if (!open) { jiveCloseAllMenus(); Element.toggle($(jiveMenu)); $(jiveMenu + "Link").className = "jive-userbar-droplink-on"; jiveMenuID = jiveMenu; Event.observe(document, 'keypress', jiveKeypressMenuHandler, true); } } /* jiveSwapMenu function This is for showing and hiding the choose user menu 'dropdowns'. This toggles the panel (slides up and down) from the button. */ function jiveSwapMenu(jiveMenu) { clearTimeout(jiveMenuTimeout); var openMenu = null; var menus = document.getElementsByClassName('jive-userbar-menu'); for (var i = 0; i < menus.length; i++) { if (menus[i].style.display != 'none') { openMenu = menus[i]; break; } } if (openMenu != null) { if (openMenu.id != jiveMenu) { jiveCloseAllMenus(); Element.toggle($(jiveMenu)); $(jiveMenu + "Link").className = "jive-userbar-droplink-on"; } } } // cancels any timeout set to close a jive menu bar function jiveInsideMenu(evt) { clearTimeout(jiveMenuTimeout); } // sets a timeout that will close the jive menu bar function jiveOutsideMenu(evt) { try { var elem = evt.relatedTarget || evt.toElement; if (typeof(elem) != 'undefined') { while (elem.parentNode && (typeof(elem.tagName) == 'undefined' || elem.tagName.toUpperCase() != 'DIV')) { elem = elem.parentNode; } } if (typeof(elem) == 'undefined' || !elem.tagName || (!Element.hasClassName(elem, 'jive-userbar-menu'))) { jiveMenuTimeout = setTimeout('jiveCloseAllMenus()', 1500); } } catch (e) { jiveMenuTimeout = setTimeout('jiveCloseAllMenus()', 1500); } } // dynamically loads the jive menu positions function jiveLoadMenus() { var menus = document.getElementsByClassName('jive-userbar-menu'); for (var i = 0; i < menus.length; i++) { var link = document.getElementById(menus[i].id + "Link"); menus[i].style.left = jiveGetX(link) + "px"; menus[i].style.top = (jiveGetY(link) + 34) + "px"; } } // loops through all open menu bars and closes them function jiveCloseAllMenus() { var menus = document.getElementsByClassName('jive-userbar-menu'); for (var i = 0; i < menus.length; i++) { if (menus[i].style.display != "none") { Element.toggle(menus[i]); $(menus[i].id + "Link").className = ""; var links = menus[i].getElementsByTagName('li'); for (var k = 0; k < links.length; k++) { links[k].className = 'jive-userbar-menu-nohover'; } } } Event.stopObserving(document, 'keypress', jiveKeypressMenuHandler, true); jiveMenuIndex = -1; } // get pixel position of an object function jiveGetY(o){ var y = 0 if (o.offsetParent) while (o.offsetParent) { y += o.offsetTop; o = o.offsetParent } return y } function jiveGetX(o){ var x = 0 if (o.offsetParent) while (o.offsetParent) { x += o.offsetLeft; o = o.offsetParent } return x } // escape key and body click to close menu bars if (document.layers) { document.captureEvents(Event.KEYDOWN); } function jiveEscapeKey(evt) { var keyCode = document.layers ? evt.which : document.all ? event.keyCode : document.getElementById ? evt.keyCode : 0; if (keyCode == 27) { // esc - close open menu jiveCloseAllMenus(); } } function jiveBodyClick(evt) { evt = evt || window.event; // IE required window.event var elem = Event.findElement(evt, 'div'); // check parent or parent's parent for class dhtmlTreeStyle for tree dropdown in menu var parentElem = Event.element(evt).parentNode; if (!elem.tagName || (elem.id != 'jive-userbar-droplink' && !Element.hasClassName(elem, 'jive-userbar-menu') && !Element.hasClassName(parentElem, "dhtmlTreeStyle") && !Element.hasClassName(parentElem.parentNode, "dhtmlTreeStyle"))) { jiveCloseAllMenus(); } } /* jiveToggleOptions function Function for toggling the state of an options element. */ function jiveToggleOptions(optionName) { if ($(optionName + '-form').style.display != 'none') { Element.hide(optionName + '-form'); $(optionName + '-hdr').className = 'jive-compose-hdr-opt-closed'; } else { $(optionName + '-form').style.display = 'block'; $(optionName + '-hdr').className = 'jive-compose-hdr-opt'; } } function jiveShowTopicFilter(thisID) { if ($(thisID).style.display != 'none') { Element.toggle($(thisID)); //Effect.toggle($(thisID), 'slide', {duration: .4}); } else { Element.toggle($(thisID)); //Effect.toggle($(thisID), 'slide', {duration: .4}); } } function jiveToggleSpaceDetails(thisID) { Element.toggle($(thisID)); if ($(thisID).style.display != 'none') { $(thisID + '-less').style.display = ''; $(thisID + '-more').style.display = 'none'; } else { $(thisID + '-more').style.display = ''; $(thisID + '-less').style.display = 'none'; } } function jiveToggleSpaceDetails2(thisID) { if ($(thisID).className == 'jive-space-namedesc-full') { $(thisID).className = ''; $(thisID + '-more').style.display = ''; $(thisID + '-less').style.display = 'none'; } else { $(thisID).className = 'jive-space-namedesc-full'; $(thisID + '-less').style.display = ''; $(thisID + '-more').style.display = 'none'; } } function jiveHideProfile() { // hide any existing profile bubbles try { if ($('pcMain') && $('pcArrow')) { Element.remove($('pcMain')); Element.remove($('pcArrow')); } } catch(e) { //alert('hidePop error: '+ e + e.message + ' : ' + e.description); } } function jiveShowProfile(rootURL, profilelement, username) { jiveHideProfile() var formatPNGTag = function(properties) { var id = (properties.id) ? ' id="' + properties.id + '"' : ''; if (document.all) { return ''; } else { return ''; } } var elem = $(profilelement); iconId = elem.id; var top = Position.cumulativeOffset(elem)[1]; var left = Position.cumulativeOffset(elem)[0]; // alert(top + ' : ' + left) var poptop = 0 var popleft = 0 var arrowtop = 0 var arrowleft = 0 // 2ND ROW if (top < 540) { if (left < 400) { // DOWN RIGHT ARROW var arrowPNG = 'jive-profile-bubble-bottom-right.png'; offsetarrowtop = 3; offsetarrowleft = 5; if (left > 200) { // 2nd ROW offsetpoptop = -30; offsetpopleft = 45; } else { // DEFAULT offsetpoptop = -10; offsetpopleft = 115; } } else { // DOWN LEFT ARROW var arrowPNG = 'jive-profile-bubble-bottom-left.png'; offsetarrowtop = 3; offsetarrowleft = -100; if (left < 500) { // 3rd ROW offsetpoptop = -30; offsetpopleft = -450; } else { offsetpoptop = -10; offsetpopleft = -530; } } } else { // TOP > 540 if (left < 400) { // UP RIGHT ARROW var arrowPNG = 'jive-profile-bubble-top-right.png'; offsetarrowtop = -210; offsetarrowleft = 5; if (left > 200) { // 2nd ROW offsetpoptop = -210; offsetpopleft = 45; } else { // DEFAULT offsetpoptop = -250; offsetpopleft = 115; } } else { // UP LEFT ARROW var arrowPNG = 'jive-profile-bubble-top-left.png'; offsetarrowtop = -210; offsetarrowleft = -100; if (left < 500) { // 3rd ROW offsetpoptop = -250; offsetpopleft = -450; } else { // DEFAULT offsetpoptop = -250; offsetpopleft = -530; } } } poptop = top + offsetpoptop; popleft = left + offsetpopleft; arrowtop = top + offsetarrowtop; arrowleft = left + offsetarrowleft; var popup = document.createElement('div'); popup.setAttribute('id','pcMain'); new Insertion.Top(popup, formatPNGTag({ width: 450, height: 21, border: 0, src: rootURL + 'images/jive-profile-bubble-background-top.png' }) + '
    '); new Insertion.Bottom(popup, '
    '); new Insertion.Bottom(popup, formatPNGTag({ width: 450, height: 21, border: 0, src: rootURL + 'images/jive-profile-bubble-background-bottom.png' })); Element.setStyle(popup,{display: 'none', top: poptop + 'px', left: popleft + 'px' }); var arrow = document.createElement('div'); arrow.setAttribute('id','pcArrow'); new Insertion.Top(arrow, formatPNGTag({ width: 121, height: 226, border: 0, src: rootURL + 'images/' + arrowPNG }) + '
    '); Element.setStyle(arrow,{display: 'none', top: arrowtop + 'px', left: arrowleft + 'px'}); document.body.appendChild(popup); document.body.appendChild(arrow); Element.setStyle($('pcMain'),{display: 'block'}); Element.setStyle($('pcArrow'),{display: 'block'}); jiveGetUserContent(rootURL, username) } function jiveGetUserContent(rootURL, username) { try { $('pcContent').innerHTML = '
    '; // NOW LOAD DATA VIA AJAX var callback = function(originalRequest) { $('pcContent').innerHTML = originalRequest.responseText; } var error = function(originalRequest) { $('pcContent').innerHTML = 'Oops! There was an error getting this user\'s profile.' } var url = rootURL + 'profile-short.jspa?username=' + username; var myAjax = new Ajax.Request( url, { method: 'get', onComplete: callback, onFailure: error}); }catch(e) { alert(e.message) } } function callOnLoad(init) { if (window.addEventListener) { window.addEventListener("load", init, false); } else if (window.attachEvent) { window.attachEvent("onload", init); } else { window.onload = init; } } Jive = Class.create(); Jive.AlertMessage = function(element) { var options = arguments[1] || {} ; new Effect.Appear(element, { queue: 'front', scope: element, duration: 1, beforeStart:options.beforeStart, afterFinish:function(obj) { new Pause(1); new Effect.Fade(element, { queue: 'end', scope: obj, duration: 1, afterFinish:options.afterFinish }); } }); }; function Pause(duration, busy){ this.duration= duration * 1000; this.busywork = null; // function to call while waiting. this.runner = 0; if (arguments.length == 2) { this.busywork = busy; } this.pause(this.duration); } Pause.prototype.pause = function(duration){ if ( (duration == null) || (duration < 0)) {return;} var later = (new Date()).getTime() + duration; while(true){ if ((new Date()).getTime() > later) { break; } this.runner++; if (this.busywork != null) { this.busywork(this.runner); } } // while } // pause method /* * $Revision: 14166 $ * $Date: 2005-02-07 15:57:29 -0800 (Mon, 07 Feb 2005) $ * * Copyright (C) 1999-2007 Jive Software. All rights reserved. * * This software is the proprietary information of Jive Software. Use is subject to license terms. */ // ----------------------------------------------------------------------------------- // // Lightbox v2.03.3 // by Lokesh Dhakar - http://www.huddletogether.com // 5/21/06 // // For more information on this script, visit: // http://huddletogether.com/projects/lightbox2/ // // Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/ // // Credit also due to those who have helped, inspired, and made their code available to the public. // Including: Scott Upton(uptonic.com), Peter-Paul Koch(quirksmode.com), Thomas Fuchs(mir.aculo.us), and others. // // // ----------------------------------------------------------------------------------- // // Configuration // var fileLoadingImage = _jive_base_url + '/images/jive-image-loading.gif'; var fileBottomNavCloseImage = _jive_base_url + '/images/jive-image-close.gif'; var overlayOpacity = 0.8; // controls transparency of shadow overlay var animate = true; // toggles resizing animations var resizeSpeed = 7; // controls the speed of the image resizing animations (1=slowest and 10=fastest) var borderSize = 10; //if you adjust the padding in the CSS, you will need to update this variable // ----------------------------------------------------------------------------------- // // Global Variables // var imageArray = new Array; var activeImage; if(animate == true){ overlayDuration = 0.2; // shadow fade in/out duration if(resizeSpeed > 10){ resizeSpeed = 10;} if(resizeSpeed < 1){ resizeSpeed = 1;} resizeDuration = (11 - resizeSpeed) * 0.15; } else { overlayDuration = 0; resizeDuration = 0; } // ----------------------------------------------------------------------------------- // // Additional methods for Element added by SU, Couloir // - further additions by Lokesh Dhakar (huddletogether.com) // Object.extend(Element, { getWidth: function(element) { element = $(element); return element.offsetWidth; }, setWidth: function(element,w) { element = $(element); element.style.width = w +"px"; }, setHeight: function(element,h) { element = $(element); element.style.height = h +"px"; }, setTop: function(element,t) { element = $(element); element.style.top = t +"px"; }, setLeft: function(element,l) { element = $(element); element.style.left = l +"px"; }, setSrc: function(element,src) { element = $(element); element.src = src; }, setHref: function(element,href) { element = $(element); element.href = href; }, setInnerHTML: function(element,content) { element = $(element); element.innerHTML = content; } }); // ----------------------------------------------------------------------------------- // // Extending built-in Array object // - array.removeDuplicates() // - array.empty() // Array.prototype.removeDuplicates = function () { for(i = 0; i < this.length; i++){ for(j = this.length-1; j>i; j--){ if(this[i][0] == this[j][0]){ this.splice(j,1); } } } } // ----------------------------------------------------------------------------------- Array.prototype.empty = function () { for(i = 0; i <= this.length; i++){ this.shift(); } } // ----------------------------------------------------------------------------------- // // Lightbox Class Declaration // - initialize() // - start() // - changeImage() // - resizeImageContainer() // - showImage() // - updateDetails() // - updateNav() // - enableKeyboardNav() // - disableKeyboardNav() // - keyboardNavAction() // - preloadNeighborImages() // - end() // // Structuring of code inspired by Scott Upton (http://www.uptonic.com/) // var JiveImage = Class.create(); JiveImage.prototype = { // initialize() // Constructor runs on completion of the DOM loading. Calls updateImageList and then // the function inserts html at the bottom of the page which is used to display the shadow // overlay and the image container. // initialize: function() { this.updateImageList(); // Code inserts html at the bottom of the page that looks similar to this: // //
    // var objBody = document.getElementsByTagName("body").item(0); var objOverlay = document.createElement("div"); objOverlay.setAttribute('id','jive-overlay'); objOverlay.style.display = 'none'; objOverlay.onclick = function() { myJiveImage.end(); } objBody.appendChild(objOverlay); var objLightbox = document.createElement("div"); objLightbox.setAttribute('id','jive-lightbox'); objLightbox.style.display = 'none'; objLightbox.onclick = function(e) { // close Lightbox is user clicks shadow overlay if (!e) var e = window.event; var clickObj = Event.element(e).id; if ( clickObj == 'jive-lightbox') { myJiveImage.end(); } }; objBody.appendChild(objLightbox); var objOuterImageContainer = document.createElement("div"); objOuterImageContainer.setAttribute('id','jive-outerImageContainer'); objLightbox.appendChild(objOuterImageContainer); // When Lightbox starts it will resize itself from 250 by 250 to the current image dimension. // If animations are turned off, it will be hidden as to prevent a flicker of a // white 250 by 250 box. if(animate){ Element.setWidth('jive-outerImageContainer', 250); Element.setHeight('jive-outerImageContainer', 250); } else { Element.setWidth('jive-outerImageContainer', 1); Element.setHeight('jive-outerImageContainer', 1); } var objImageContainer = document.createElement("div"); objImageContainer.setAttribute('id','jive-imageContainer'); objOuterImageContainer.appendChild(objImageContainer); var objLightboxImage = document.createElement("img"); objLightboxImage.setAttribute('id','jive-lightboxImage'); objImageContainer.appendChild(objLightboxImage); var objHoverNav = document.createElement("div"); objHoverNav.setAttribute('id','jive-hoverNav'); objImageContainer.appendChild(objHoverNav); var objPrevLink = document.createElement("a"); objPrevLink.setAttribute('id','jive-prevLink'); objPrevLink.setAttribute('href','#'); objHoverNav.appendChild(objPrevLink); var objNextLink = document.createElement("a"); objNextLink.setAttribute('id','jive-nextLink'); objNextLink.setAttribute('href','#'); objHoverNav.appendChild(objNextLink); var objLoading = document.createElement("div"); objLoading.setAttribute('id','jive-loading'); objImageContainer.appendChild(objLoading); var objLoadingLink = document.createElement("a"); objLoadingLink.setAttribute('id','jive-loadingLink'); objLoadingLink.setAttribute('href','#'); objLoadingLink.onclick = function() { myJiveImage.end(); return false; } objLoading.appendChild(objLoadingLink); var objLoadingImage = document.createElement("img"); objLoadingImage.setAttribute('src', fileLoadingImage); objLoadingLink.appendChild(objLoadingImage); var objImageDataContainer = document.createElement("div"); objImageDataContainer.setAttribute('id','jive-imageDataContainer'); objLightbox.appendChild(objImageDataContainer); var objImageData = document.createElement("div"); objImageData.setAttribute('id','jive-imageData'); objImageDataContainer.appendChild(objImageData); var objImageDetails = document.createElement("div"); objImageDetails.setAttribute('id','jive-imageDetails'); objImageData.appendChild(objImageDetails); var objCaption = document.createElement("span"); objCaption.setAttribute('id','jive-caption'); objImageDetails.appendChild(objCaption); var objNumberDisplay = document.createElement("span"); objNumberDisplay.setAttribute('id','jive-numberDisplay'); objImageDetails.appendChild(objNumberDisplay); var objBottomNav = document.createElement("div"); objBottomNav.setAttribute('id','jive-bottomNav'); objImageData.appendChild(objBottomNav); var objBottomNavCloseLink = document.createElement("a"); objBottomNavCloseLink.setAttribute('id','jive-bottomNavClose'); objBottomNavCloseLink.setAttribute('href','#'); objBottomNavCloseLink.onclick = function() { myJiveImage.end(); return false; } objBottomNav.appendChild(objBottomNavCloseLink); var objBottomNavCloseImage = document.createElement("img"); objBottomNavCloseImage.setAttribute('src', fileBottomNavCloseImage); objBottomNavCloseLink.appendChild(objBottomNavCloseImage); }, // // updateImageList() // Loops through anchor tags looking for 'lightbox' references and applies onclick // events to appropriate links. You can rerun after dynamically adding images w/ajax. // updateImageList: function() { if (!document.getElementsByTagName){ return; } var images = document.getElementsByTagName('img'); // loop through all image tags for (var i=0; i= arrayPageSize[3]) { // Set new height of image to browser widh minus a 250px buffer var newHeight = arrayPageSize[3] - 250; // Set width accordingly var newWidth = (imgPreloader.width*newHeight)/imgPreloader.height; // Do it Element.setHeight('jive-lightboxImage',newHeight); Element.setWidth('jive-lightboxImage',newWidth); myJiveImage.resizeImageContainer(newWidth,newHeight); } // If image width is bigger or equal to window width, resize image else if(imgPreloader.width >= arrayPageSize[2]) { // Set new width of image to browser widh minus a 250px buffer var newWidth = arrayPageSize[2] - 250; // Set width accordingly var newHeight = (imgPreloader.height*newWidth)/imgPreloader.width; // Do it Element.setHeight('jive-lightboxImage',newHeight); Element.setWidth('jive-lightboxImage',newWidth); myJiveImage.resizeImageContainer(newWidth,newHeight); } else { Element.setHeight('jive-lightboxImage',imgPreloader.height); Element.setWidth('jive-lightboxImage',imgPreloader.width); myJiveImage.resizeImageContainer(imgPreloader.width, imgPreloader.height); } */ Element.setHeight('jive-lightboxImage',imgPreloader.height); Element.setWidth('jive-lightboxImage',imgPreloader.width); myJiveImage.resizeImageContainer(imgPreloader.width, imgPreloader.height); } imgPreloader.src = imageArray[activeImage][0]; }, // // resizeImageContainer() // resizeImageContainer: function( imgWidth, imgHeight) { // get curren width and height this.widthCurrent = Element.getWidth('jive-outerImageContainer'); this.heightCurrent = Element.getHeight('jive-outerImageContainer'); // get new width and height var widthNew = (imgWidth + (borderSize * 2)); var heightNew = (imgHeight + (borderSize * 2)); // scalars based on change from old to new this.xScale = ( widthNew / this.widthCurrent) * 100; this.yScale = ( heightNew / this.heightCurrent) * 100; // calculate size difference between new and old image, and resize if necessary wDiff = this.widthCurrent - widthNew; hDiff = this.heightCurrent - heightNew; if(!( hDiff == 0)){ new Effect.Scale('jive-outerImageContainer', this.yScale, {scaleX: false, duration: resizeDuration, queue: 'front'}); } if(!( wDiff == 0)){ new Effect.Scale('jive-outerImageContainer', this.xScale, {scaleY: false, delay: resizeDuration, duration: resizeDuration}); } // if new and old image are same size and no scaling transition is necessary, // do a quick pause to prevent image flicker. if((hDiff == 0) && (wDiff == 0)){ if (navigator.appVersion.indexOf("MSIE")!=-1){ pause(250); } else { pause(100);} } Element.setHeight('jive-prevLink', imgHeight); Element.setHeight('jive-nextLink', imgHeight); Element.setWidth( 'jive-imageDataContainer', widthNew); this.showImage(); }, // // showImage() // Display image and begin preloading neighbors. // showImage: function(){ Element.hide('jive-loading'); new Effect.Appear('jive-lightboxImage', { duration: resizeDuration, queue: 'end', afterFinish: function(){ myJiveImage.updateDetails(); } }); this.preloadNeighborImages(); }, // // updateDetails() // Display caption, image number, and bottom nav. // updateDetails: function() { // if caption is not null if(imageArray[activeImage][1]){ Element.show('jive-caption'); Element.setInnerHTML( 'jive-caption', imageArray[activeImage][1]); } // if image is part of set display 'Image x of x' if(imageArray.length > 1){ Element.show('jive-numberDisplay'); Element.setInnerHTML( 'jive-numberDisplay', "Image " + eval(activeImage + 1) + " of " + imageArray.length); } new Effect.Parallel( [ new Effect.SlideDown( 'jive-imageDataContainer', { sync: true, duration: resizeDuration, from: 0.0, to: 1.0 }), new Effect.Appear('jive-imageDataContainer', { sync: true, duration: resizeDuration }) ], { duration: resizeDuration, afterFinish: function() { // update overlay size and update nav var arrayPageSize = getPageSize(); Element.setHeight('jive-overlay', arrayPageSize[1]); myJiveImage.updateNav(); } } ); }, // // updateNav() // Display appropriate previous and next hover navigation. // updateNav: function() { Element.show('jive-hoverNav'); // if not first image in set, display prev image button if(activeImage != 0){ Element.show('jive-prevLink'); document.getElementById('jive-prevLink').onclick = function() { myJiveImage.changeImage(activeImage - 1); return false; } } // if not last image in set, display next image button if(activeImage != (imageArray.length - 1)){ Element.show('jive-nextLink'); document.getElementById('jive-nextLink').onclick = function() { myJiveImage.changeImage(activeImage + 1); return false; } } this.enableKeyboardNav(); }, // // enableKeyboardNav() // enableKeyboardNav: function() { document.onkeydown = this.keyboardAction; }, // // disableKeyboardNav() // disableKeyboardNav: function() { document.onkeydown = ''; }, // // keyboardAction() // keyboardAction: function(e) { if (e == null) { // ie keycode = event.keyCode; escapeKey = 27; } else { // mozilla keycode = e.keyCode; escapeKey = e.DOM_VK_ESCAPE; } key = String.fromCharCode(keycode).toLowerCase(); if((key == 'x') || (key == 'o') || (key == 'c') || (keycode == escapeKey)){ // close lightbox myJiveImage.end(); } else if((key == 'p') || (keycode == 37)){ // display previous image if(activeImage != 0){ myJiveImage.disableKeyboardNav(); myJiveImage.changeImage(activeImage - 1); } } else if((key == 'n') || (keycode == 39)){ // display next image if(activeImage != (imageArray.length - 1)){ myJiveImage.disableKeyboardNav(); myJiveImage.changeImage(activeImage + 1); } } }, // // preloadNeighborImages() // Preload previous and next images. // preloadNeighborImages: function(){ if((imageArray.length - 1) > activeImage){ preloadNextImage = new Image(); preloadNextImage.src = imageArray[activeImage + 1][0]; } if(activeImage > 0){ preloadPrevImage = new Image(); preloadPrevImage.src = imageArray[activeImage - 1][0]; } }, // // end() // end: function() { this.disableKeyboardNav(); Element.hide('jive-lightbox'); new Effect.Fade('jive-overlay', { duration: overlayDuration}); showSelectBoxes(); showFlash(); } } // ----------------------------------------------------------------------------------- // // getPageScroll() // Returns array with x,y page scroll values. // Core code from - quirksmode.com // function getPageScroll(){ var xScroll, yScroll; if (self.pageYOffset) { yScroll = self.pageYOffset; xScroll = self.pageXOffset; } else if (document.documentElement && document.documentElement.scrollTop){ // Explorer 6 Strict yScroll = document.documentElement.scrollTop; xScroll = document.documentElement.scrollLeft; } else if (document.body) {// all other Explorers yScroll = document.body.scrollTop; xScroll = document.body.scrollLeft; } arrayPageScroll = new Array(xScroll,yScroll) return arrayPageScroll; } // ----------------------------------------------------------------------------------- // // getPageSize() // Returns array with page width, height and window width, height // Core code from - quirksmode.com // Edit for Firefox by pHaez // function getPageSize(){ var xScroll, yScroll; if (window.innerHeight && window.scrollMaxY) { xScroll = window.innerWidth + window.scrollMaxX; yScroll = window.innerHeight + window.scrollMaxY; } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac xScroll = document.body.scrollWidth; yScroll = document.body.scrollHeight; } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari xScroll = document.body.offsetWidth; yScroll = document.body.offsetHeight; } var windowWidth, windowHeight; // console.log(self.innerWidth); // console.log(document.documentElement.clientWidth); if (self.innerHeight) { // all except Explorer if(document.documentElement.clientWidth){ windowWidth = document.documentElement.clientWidth; } else { windowWidth = self.innerWidth; } windowHeight = self.innerHeight; } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode windowWidth = document.documentElement.clientWidth; windowHeight = document.documentElement.clientHeight; } else if (document.body) { // other Explorers windowWidth = document.body.clientWidth; windowHeight = document.body.clientHeight; } // for small pages with total height less then height of the viewport if(yScroll < windowHeight){ pageHeight = windowHeight; } else { pageHeight = yScroll; } // console.log("xScroll " + xScroll) // console.log("windowWidth " + windowWidth) // for small pages with total width less then width of the viewport if(xScroll < windowWidth){ pageWidth = xScroll; } else { pageWidth = windowWidth; } // console.log("pageWidth " + pageWidth) arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight) return arrayPageSize; } // ----------------------------------------------------------------------------------- // // getKey(key) // Gets keycode. If 'x' is pressed then it hides the lightbox. // function getKey(e){ if (e == null) { // ie keycode = event.keyCode; } else { // mozilla keycode = e.which; } key = String.fromCharCode(keycode).toLowerCase(); if(key == 'x'){ } } // ----------------------------------------------------------------------------------- // // listenKey() // function listenKey () { document.onkeypress = getKey; } // --------------------------------------------------- function showSelectBoxes(){ var selects = document.getElementsByTagName("select"); for (i = 0; i != selects.length; i++) { selects[i].style.visibility = "visible"; } } // --------------------------------------------------- function hideSelectBoxes(){ var selects = document.getElementsByTagName("select"); for (i = 0; i != selects.length; i++) { selects[i].style.visibility = "hidden"; } } // --------------------------------------------------- function showFlash(){ var flashObjects = document.getElementsByTagName("object"); for (i = 0; i < flashObjects.length; i++) { flashObjects[i].style.visibility = "visible"; } var flashEmbeds = document.getElementsByTagName("embed"); for (i = 0; i < flashEmbeds.length; i++) { flashEmbeds[i].style.visibility = "visible"; } } // --------------------------------------------------- function hideFlash(){ var flashObjects = document.getElementsByTagName("object"); for (i = 0; i < flashObjects.length; i++) { flashObjects[i].style.visibility = "hidden"; } var flashEmbeds = document.getElementsByTagName("embed"); for (i = 0; i < flashEmbeds.length; i++) { flashEmbeds[i].style.visibility = "hidden"; } } // --------------------------------------------------- // // pause(numberMillis) // Pauses code execution for specified time. Uses busy code, not good. // Help from Ran Bar-On [ran2103@gmail.com] // function pause(ms){ var date = new Date(); curDate = null; do{var curDate = new Date();} while( curDate - date < ms); } /* function pause(numberMillis) { var curently = new Date().getTime() + sender; while (new Date().getTime(); } */ // --------------------------------------------------- function initJiveImage() { myJiveImage = new JiveImage(); } Event.observe(window, 'load', initJiveImage, false);
    ... updateNode = updateNode.firstChild.firstChild.nextSibling.firstChild.firstChild; } } else { updateNode = tipObj.firstChild; if (updateNode.className == 'contents') { // missing caption return; } // " else leftSide = leftSide + "" this.isRendered = 1 if (browserVersion == 2) { if (!doc.yPos) doc.yPos=20 } docW = this.blockStartHTML("folder"); docW = docW + "" + leftSide //;+ "" } if (WRAPTEXT) docW = docW + this.prependHTML+"" docW = docW + this.blockEndHTML() if (insertAtObj == null) { if (supportsDeferral) { doc.write("
    ") //transition between regular flow HTML, and node-insert DOM DHTML insertAtObj = getElById("domRoot") insertAtObj.insertAdjacentHTML("beforeEnd", docW) } else doc.write(docW) } else { insertAtObj.insertAdjacentHTML("afterEnd", docW) } if (browserVersion == 2) { this.navObj = doc.layers["folder"+this.id] if (USEICONS) this.iconImg = this.navObj.document.images["folderIcon"+this.id] this.nodeImg = this.navObj.document.images["nodeIcon"+this.id] doc.yPos=doc.yPos+this.navObj.clip.height } else if (browserVersion != 0) { this.navObj = getElById("folder"+this.id) if (USEICONS) this.iconImg = getElById("folderIcon"+this.id) this.nodeImg = getElById("nodeIcon"+this.id) } } function setStateFolder(isOpen) { var subEntries var totalHeight var fIt = 0 var i=0 var currentOpen if (isOpen == this.isOpen) return if (browserVersion == 2) { totalHeight = 0 for (i=0; i < this.nChildren; i++) totalHeight = totalHeight + this.children[i].navObj.clip.height subEntries = this.subEntries() if (this.isOpen) totalHeight = 0 - totalHeight for (fIt = this.id + subEntries + 1; fIt < nEntries; fIt++) indexOfEntries[fIt].navObj.moveBy(0, totalHeight) } this.isOpen = isOpen; if (this.getID()!=foldersTree.getID() && PERSERVESTATE && !this.isOpen) //closing { currentOpen = GetCookie("clickedFolder") if (currentOpen != null) { currentOpen = currentOpen.replace(this.getID()+cookieCutter, "") SetCookie("clickedFolder", currentOpen) } } if (!this.isOpen && this.isLastOpenedfolder) { lastOpenedFolder = null; this.isLastOpenedfolder = false; } propagateChangesInState(this) } function propagateChangesInState(folder) { var i=0 //Change icon if (folder.nChildren > 0 && folder.level>0) //otherwise the one given at render stays folder.nodeImg.src = folder.nodeImageSrc() //Change node if (USEICONS) folder.iconImg.src = folder.iconImageSrc() //Propagate changes for (i=folder.nChildren-1; i>=0; i--) if (folder.isOpen) folder.children[i].folderMstr(folder.navObj) else folder.children[i].esconde() } function escondeFolder() { this.escondeBlock() this.setState(0) } function linkFolderHTML(isTextLink) { var docW = ""; if (this.hreference) { if (USEFRAMES) docW = docW + " 0) docW = docW + "onClick='javascript:clickOnFolder(\""+this.getID()+"\")'" docW = docW + ">" } else docW = docW + "" return docW; } function addChild(childNode) { this.children[this.nChildren] = childNode childNode.parentObj = this this.nChildren++ return childNode } function folderSubEntries() { var i = 0 var se = this.nChildren for (i=0; i < this.nChildren; i++){ if (this.children[i].children) //is a folder se = se + this.children[i].subEntries() } return se } function nodeImageSrc() { var srcStr = ""; if (this.isLastNode) //the last child in the children array { if (this.nChildren == 0) srcStr = ICONPATH + "bullet_sm.gif" else if (this.isOpen) srcStr = ICONPATH + "minus.gif" else srcStr = ICONPATH + "plus.gif" } else { if (this.nChildren == 0) srcStr = ICONPATH + "bullet_sm.gif" else if (this.isOpen) srcStr = ICONPATH + "minus.gif" else srcStr = ICONPATH + "plus.gif" } return srcStr; } function iconImageSrc() { if (this.isOpen) return(this.iconSrc) else return(this.iconSrcClosed) } // Definition of class Item (a document or link inside a Folder) // ************************************************************* function Item(itemDescription, itemLink, target) // Constructor { // constant data this.desc = itemDescription this.link = itemLink this.id = -1 //initialized in initalize() this.navObj = 0 //initialized in render() this.iconImg = 0 //initialized in render() this.iconSrc = ICONPATH + "ftv2doc.gif" this.isRendered = 0 this.isLastNode = false this.level = 0 this.leftSideCoded = "" this.nChildren = 0 this.target = target this.parentObj = null this.maySelect=true this.prependHTML = "" // methods this.initialize = initializeItem this.createIndex = createEntryIndex this.escondeBlock = escondeBlock this.esconde = escondeBlock this.folderMstr = folderMstr this.renderOb = drawItem this.totalHeight = totalHeight this.blockStartHTML = blockStartHTML this.blockEndHTML = blockEndHTML this.getID = getID this.forceOpeningOfAncestorFolders = forceOpeningOfAncestorFolders } function initializeItem(level, lastNode, leftSide) { this.createIndex() this.level = level this.leftSideCoded = leftSide this.isLastNode = lastNode } function drawItem(insertAtObj) { var leftSide = leftSideHTML(this.leftSideCoded) var docW = "" var fullLink = "href=\""+this.link+"\" target=\""+this.target+"\" onClick=\"clickOnLink('"+this.getID()+"\', '"+this.link+"','"+this.target+"');return false;\""; this.isRendered = 1 if (this.level>0) if (this.isLastNode) //the last 'brother' in the children array { leftSide = leftSide + "" } else { leftSide = leftSide + "" } docW = docW + this.blockStartHTML("item") docW = docW + "" + leftSide; if (USEICONS) docW = docW + "" if (WRAPTEXT) docW = docW + this.prependHTML+"" docW = docW + this.blockEndHTML() if (insertAtObj == null) { doc.write(docW) } else { insertAtObj.insertAdjacentHTML("afterEnd", docW) } if (browserVersion == 2) { this.navObj = doc.layers["item"+this.id] if (USEICONS) this.iconImg = this.navObj.document.images["itemIcon"+this.id] doc.yPos=doc.yPos+this.navObj.clip.height } else if (browserVersion != 0) { this.navObj = getElById("item"+this.id) if (USEICONS) this.iconImg = getElById("itemIcon"+this.id) } } // Methods common to both objects (pseudo-inheritance) // ******************************************************** function forceOpeningOfAncestorFolders() { if (this.parentObj == null || this.parentObj.isOpen) return else { this.parentObj.forceOpeningOfAncestorFolders() clickOnNodeObj(this.parentObj) } } function escondeBlock() { if (browserVersion == 1 || browserVersion == 3) { if (this.navObj.style.display == "none") return this.navObj.style.display = "none" } else { if (this.navObj.visibility == "hiden") return this.navObj.visibility = "hiden" } } function folderMstr(domObj) { if (!this.isRendered) this.renderOb(domObj) else if (browserVersion == 1 || browserVersion == 3) this.navObj.style.display = "block" else this.navObj.visibility = "show" } function blockStartHTML(idprefix) { var idParam = "id='" + idprefix + this.id + "'" var docW = "" if (browserVersion == 2) docW = "" else if (browserVersion != 0) docW = "
    " docW = docW + "
    ... updateNode = updateNode.firstChild.firstChild.firstChild.firstChild; } // TODO: allow for a DOM node as content updateNode.innerHTML = content; } // }}} /* * $Log$ * Revision 1.2 2003/11/04 17:25:12 bruce * KB-301 (Related Document 'tree' not shown in Safari) * * Revision 1.1 2002/10/21 05:31:43 britchie * More dev. * * Revision 1.9 2002/07/22 14:06:21 bc6ix * fix license path, change version reporting to use 2 digits for each level * * Revision 1.8 2002/07/07 08:23:07 bc6ix * fix line endings * * Revision 1.7 2002/05/14 16:52:52 bc6ix * use CVS Log for revision history * * */ /* ***** BEGIN LICENSE BLOCK ***** * Licensed under Version: MPL 1.1/GPL 2.0/LGPL 2.1 * Full Terms at http://bclary.com/lib/js/license/mpl-tri-license.txt * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Netscape code. * * The Initial Developer of the Original Code is * Netscape Corporation. * Portions created by the Initial Developer are Copyright (C) 2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): Bob Clary * * ***** END LICENSE BLOCK ***** */ function xbDetectBrowser() { var oldOnError = window.onerror; var element = null; window.onerror = null; // work around bug in xpcdom Mozilla 0.9.1 window.saveNavigator = window.navigator; navigator.OS = ''; navigator.version = parseFloat(navigator.appVersion); navigator.org = ''; navigator.family = ''; var platform; if (typeof(window.navigator.platform) != 'undefined') { platform = window.navigator.platform.toLowerCase(); if (platform.indexOf('win') != -1) navigator.OS = 'win'; else if (platform.indexOf('mac') != -1) navigator.OS = 'mac'; else if (platform.indexOf('unix') != -1 || platform.indexOf('linux') != -1 || platform.indexOf('sun') != -1) navigator.OS = 'nix'; } var i = 0; var ua = window.navigator.userAgent.toLowerCase(); if (ua.indexOf('opera') != -1) { i = ua.indexOf('opera'); navigator.family = 'opera'; navigator.org = 'opera'; navigator.version = parseFloat('0' + ua.substr(i+6), 10); } else if ((i = ua.indexOf('msie')) != -1) { navigator.org = 'microsoft'; navigator.version = parseFloat('0' + ua.substr(i+5), 10); if (navigator.version < 4) navigator.family = 'ie3'; else navigator.family = 'ie4' } else if ((i = ua.indexOf('applewebkit')) != -1) { navigator.family = 'safari'; navigator.org = 'apple'; i = ua.indexOf('applewebkit'); navigator.version = parseFloat('0' + ua.substr(i+12), 10); } else if (ua.indexOf('gecko') != -1) { navigator.family = 'gecko'; var rvStart = ua.indexOf('rv:'); var rvEnd = ua.indexOf(')', rvStart); var rv = ua.substring(rvStart+3, rvEnd); var rvParts = rv.split('.'); var rvValue = 0; var exp = 1; for (var i = 0; i < rvParts.length; i++) { var val = parseInt(rvParts[i]); rvValue += val / exp; exp *= 100; } navigator.version = rvValue; if (ua.indexOf('netscape') != -1) navigator.org = 'netscape'; else if (ua.indexOf('compuserve') != -1) navigator.org = 'compuserve'; else navigator.org = 'mozilla'; } else if ((ua.indexOf('mozilla') !=-1) && (ua.indexOf('spoofer')==-1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera')==-1)&& (ua.indexOf('webtv')==-1) && (ua.indexOf('hotjava')==-1)) { var is_major = parseFloat(navigator.appVersion); if (is_major < 4) navigator.version = is_major; else { i = ua.lastIndexOf('/') navigator.version = parseFloat('0' + ua.substr(i+1), 10); } navigator.org = 'netscape'; navigator.family = 'nn' + parseInt(navigator.appVersion); } else if ((i = ua.indexOf('aol')) != -1 ) { // aol navigator.family = 'aol'; navigator.org = 'aol'; navigator.version = parseFloat('0' + ua.substr(i+4), 10); } else if ((i = ua.indexOf('hotjava')) != -1 ) { // hotjava navigator.family = 'hotjava'; navigator.org = 'sun'; navigator.version = parseFloat(navigator.appVersion); } window.onerror = oldOnError; } xbDetectBrowser(); //**************************************************************** // Keep this copyright notice: // This copy of the script is the property of the owner of the // particular web site you were visiting. // Do not download the script's files from there. // For a free download and full instructions go to: // http://www.treeview.net //**************************************************************** // Log of changes: // // 01 Mar 03 - VERSION 4.3 - Support for checkboxes // 21 Feb 03 - Added support for Opera 7 // 22 Sep 02 - Added maySelect member for node-by-node control // of selection and highlight // 21 Sep 02 - Cookie values are now separated by cookieCutter // 12 Sep 02 - VERSION 4.2 - Can highlight Selected Nodes and // can preserve state through external (DB) IDs // 29 Aug 02 - Fine tune 'supportDeferral' for IE4 and IE Mac // 25 Aug 02 - Fixes: STARTALLOPEN, and multi-page frameless // 09 Aug 02 - Fix repeated folder on Mozilla 1.x // 31 Jul 02 - VERSION 4.1 - Dramatic speed increase for trees // with hundreds or thousands of nodes; changes to the control // flags of the gLnk function // 18 Jul 02 - Changes in pre-load images function // 13 Jun 02 - Add ICONPATH var to allow for gif subdir // 20 Apr 02 - Improve support for frame-less layout // 07 Apr 02 - Minor changes to support server-side dynamic feeding // (example: FavoritesManagerASP) // Definition of class Folder // ***************************************************************** function Folder(folderDescription, hreference) //constructor { //constant data this.desc = folderDescription; this.hreference = hreference; this.id = -1; this.navObj = 0; this.iconImg = 0; this.nodeImg = 0; this.isLastNode = 0; this.iconSrc = ICONPATH + "ftv2folderopen.gif"; this.iconSrcClosed = ICONPATH + "ftv2folderclosed.gif"; this.children = new Array; this.nChildren = 0; this.level = 0; this.leftSideCoded = ""; this.isLastNode=false; this.parentObj = null; this.maySelect=true; this.prependHTML = "" //dynamic data this.isOpen = false this.isLastOpenedFolder = false this.isRendered = 0 //methods this.initialize = initializeFolder this.setState = setStateFolder this.addChild = addChild this.createIndex = createEntryIndex this.escondeBlock = escondeBlock this.esconde = escondeFolder this.folderMstr = folderMstr this.renderOb = drawFolder this.totalHeight = totalHeight this.subEntries = folderSubEntries this.linkHTML = linkFolderHTML this.blockStartHTML = blockStartHTML this.blockEndHTML = blockEndHTML this.nodeImageSrc = nodeImageSrc this.iconImageSrc = iconImageSrc this.getID = getID this.forceOpeningOfAncestorFolders = forceOpeningOfAncestorFolders } function initializeFolder(level, lastNode, leftSide) { var j=0 var i=0 nc = this.nChildren this.createIndex() this.level = level this.leftSideCoded = leftSide if (browserVersion == 0 || STARTALLOPEN==1) this.isOpen=true; if (level>0) if (lastNode) //the last child in the children array leftSide = leftSide + "0" else leftSide = leftSide + "1" this.isLastNode = lastNode if (nc > 0) { level = level + 1 for (i=0 ; i < this.nChildren; i++) { if (i == this.nChildren-1) this.children[i].initialize(level, 1, leftSide) else this.children[i].initialize(level, 0, leftSide) } } } function drawFolder(insertAtObj) { var nodeName = "" var auxEv = "" var docW = "" var leftSide = leftSideHTML(this.leftSideCoded) if (browserVersion > 0) auxEv = "" else auxEv = "" nodeName = this.nodeImageSrc() if (this.level>0) if (this.isLastNode) //the last child in the children array leftSide = leftSide + "
    " + auxEv + "" + auxEv + "
    "; if (USEICONS) { docW = docW + ""; docW = docW + this.linkHTML(false) docW = docW + "" else docW = docW + this.prependHTML+"" if (USETEXTLINKS) { docW = docW + this.linkHTML(true) docW = docW + this.desc + "" } else docW = docW + this.desc docW = docW + "
    " + "" + "" else docW = docW + this.prependHTML+"" if (USETEXTLINKS) docW = docW + "" + this.desc + "" else docW = docW + this.desc docW = docW + "
    " return docW } function blockEndHTML() { var docW = "" docW = "
    " if (browserVersion == 2) docW = docW + "" else if (browserVersion != 0) docW = docW + "
    " return docW } function createEntryIndex() { this.id = nEntries indexOfEntries[nEntries] = this nEntries++ } // total height of subEntries open function totalHeight() //used with browserVersion == 2 { var h = this.navObj.clip.height var i = 0 if (this.isOpen) //is a folder and _is_ open for (i=0 ; i < this.nChildren; i++) h = h + this.children[i].totalHeight() return h } function leftSideHTML(leftSideCoded) { var i; var retStr = ""; for (i=0; i