diff options
author | Walter Bender <walter@walter-laptop.(none)> | 2009-05-16 15:28:12 (GMT) |
---|---|---|
committer | Walter Bender <walter@walter-laptop.(none)> | 2009-05-16 15:28:12 (GMT) |
commit | ad6d464d95b79c3a244d48c23d7e4c9b43e9369b (patch) | |
tree | 520d7684822e369adc0a8ad28114192f2c32ab80 |
initial version
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | activity/.svn/all-wcprops | 17 | ||||
-rw-r--r-- | activity/.svn/entries | 52 | ||||
-rw-r--r-- | activity/.svn/format | 1 | ||||
-rw-r--r-- | activity/.svn/text-base/activity-xoEditor.svg.svn-base | 18 | ||||
-rw-r--r-- | activity/.svn/text-base/activity.info.svn-base | 8 | ||||
-rw-r--r-- | activity/activity-xoEditor.svg | 18 | ||||
-rw-r--r-- | activity/activity.info | 8 | ||||
-rw-r--r-- | html/.svn/all-wcprops | 17 | ||||
-rw-r--r-- | html/.svn/entries | 52 | ||||
-rw-r--r-- | html/.svn/format | 1 | ||||
-rw-r--r-- | html/.svn/text-base/prototype.js.svn-base | 3277 | ||||
-rw-r--r-- | html/.svn/text-base/xo-color.xml.svn-base | 964 | ||||
-rw-r--r-- | html/prototype.js | 3277 | ||||
-rw-r--r-- | html/xo-color.xml | 964 | ||||
-rw-r--r-- | logic.py | 48 | ||||
-rw-r--r-- | logic.pyc | bin | 0 -> 1380 bytes | |||
-rw-r--r-- | result.py | 25 | ||||
-rw-r--r-- | result.pyc | bin | 0 -> 539 bytes | |||
-rw-r--r-- | server.py | 59 | ||||
-rw-r--r-- | server.pyc | bin | 0 -> 2158 bytes | |||
-rw-r--r-- | setup.py | 22 | ||||
-rw-r--r-- | webviewer.py | 147 | ||||
-rw-r--r-- | webviewer.pyc | bin | 0 -> 5822 bytes | |||
-rw-r--r-- | xoEditorActivity.py | 74 | ||||
-rw-r--r-- | xoEditorActivity.pyc | bin | 0 -> 2200 bytes |
26 files changed, 9051 insertions, 0 deletions
@@ -0,0 +1,2 @@ +1 +* initial release
\ No newline at end of file diff --git a/activity/.svn/all-wcprops b/activity/.svn/all-wcprops new file mode 100644 index 0000000..567477f --- /dev/null +++ b/activity/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 60 +/public-svn/!svn/ver/302/xoEditor/xoEditor.activity/activity +END +activity.info +K 25 +svn:wc:ra_dav:version-url +V 74 +/public-svn/!svn/ver/302/xoEditor/xoEditor.activity/activity/activity.info +END +activity-xoEditor.svg +K 25 +svn:wc:ra_dav:version-url +V 82 +/public-svn/!svn/ver/300/xoEditor/xoEditor.activity/activity/activity-xoEditor.svg +END diff --git a/activity/.svn/entries b/activity/.svn/entries new file mode 100644 index 0000000..0babbe9 --- /dev/null +++ b/activity/.svn/entries @@ -0,0 +1,52 @@ +8 + +dir +311 +http://mediamods.com/public-svn/xoEditor/xoEditor.activity/activity +http://mediamods.com/public-svn + + + +2007-08-15T14:51:55.849657Z +302 +erikb + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +574bc980-5f2d-0410-acbc-c8f9f0eb14e0 + +activity-xoEditor.svg +file + + + + +2007-08-15T14:04:42.000000Z +600ea66ad02167ff50ca0d1fdba72d1f +2007-08-15T14:29:26.567131Z +300 +erikb + +activity.info +file + + + + +2007-08-15T14:19:39.000000Z +2458860c5877b081ef3bcc54bc445422 +2007-08-15T14:51:55.849657Z +302 +erikb + diff --git a/activity/.svn/format b/activity/.svn/format new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/activity/.svn/format @@ -0,0 +1 @@ +8 diff --git a/activity/.svn/text-base/activity-xoEditor.svg.svn-base b/activity/.svn/text-base/activity-xoEditor.svg.svn-base new file mode 100644 index 0000000..19b8f23 --- /dev/null +++ b/activity/.svn/text-base/activity-xoEditor.svg.svn-base @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_svg "http://www.w3.org/2000/svg"> + <!ENTITY ns_xlink "http://www.w3.org/1999/xlink"> + <!ENTITY stroke_color "#000000"> + <!ENTITY fill_color "#AAAAAA"> +]> +<svg version="1.1" id="Icon" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="44.938" height="34.271" + viewBox="0 0 44.938 34.271" overflow="visible" enable-background="new 0 0 44.938 34.271" xml:space="preserve"> +<rect id="Box" x="1.75" y="1.75" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" width="41.438" height="30.771"/> +<g id="Eye"> + <path id="Iris" d="M22.547,7.879c-9.26,0-16.976,9.235-16.976,9.235s7.715,9.276,16.976,9.271 + c9.261-0.008,16.978-9.284,16.978-9.284S31.808,7.872,22.547,7.879z M22.547,23.627c-3.585,0-6.492-2.91-6.492-6.494 + c0-3.578,2.906-6.493,6.492-6.493c3.581,0,6.49,2.915,6.49,6.493C29.038,20.717,26.128,23.627,22.547,23.627z" fill="&stroke_color;"/> + <circle id="Pupil" cx="22.548" cy="17.135" r="2.946" fill="&stroke_color;"/> +</g> +</svg>
\ No newline at end of file diff --git a/activity/.svn/text-base/activity.info.svn-base b/activity/.svn/text-base/activity.info.svn-base new file mode 100644 index 0000000..cddaf82 --- /dev/null +++ b/activity/.svn/text-base/activity.info.svn-base @@ -0,0 +1,8 @@ +[Activity] +name = xoEditor +activity_version = 1 +host_version = 1 +icon = activity-xoEditor +service_name = org.laptop.xoEditorActivity +class = xoEditorActivity.xoEditorActivity +show_launcher = 1 diff --git a/activity/activity-xoEditor.svg b/activity/activity-xoEditor.svg new file mode 100644 index 0000000..19b8f23 --- /dev/null +++ b/activity/activity-xoEditor.svg @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 12.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 51448) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_svg "http://www.w3.org/2000/svg"> + <!ENTITY ns_xlink "http://www.w3.org/1999/xlink"> + <!ENTITY stroke_color "#000000"> + <!ENTITY fill_color "#AAAAAA"> +]> +<svg version="1.1" id="Icon" xmlns="&ns_svg;" xmlns:xlink="&ns_xlink;" width="44.938" height="34.271" + viewBox="0 0 44.938 34.271" overflow="visible" enable-background="new 0 0 44.938 34.271" xml:space="preserve"> +<rect id="Box" x="1.75" y="1.75" fill="&fill_color;" stroke="&stroke_color;" stroke-width="3.5" width="41.438" height="30.771"/> +<g id="Eye"> + <path id="Iris" d="M22.547,7.879c-9.26,0-16.976,9.235-16.976,9.235s7.715,9.276,16.976,9.271 + c9.261-0.008,16.978-9.284,16.978-9.284S31.808,7.872,22.547,7.879z M22.547,23.627c-3.585,0-6.492-2.91-6.492-6.494 + c0-3.578,2.906-6.493,6.492-6.493c3.581,0,6.49,2.915,6.49,6.493C29.038,20.717,26.128,23.627,22.547,23.627z" fill="&stroke_color;"/> + <circle id="Pupil" cx="22.548" cy="17.135" r="2.946" fill="&stroke_color;"/> +</g> +</svg>
\ No newline at end of file diff --git a/activity/activity.info b/activity/activity.info new file mode 100644 index 0000000..cddaf82 --- /dev/null +++ b/activity/activity.info @@ -0,0 +1,8 @@ +[Activity] +name = xoEditor +activity_version = 1 +host_version = 1 +icon = activity-xoEditor +service_name = org.laptop.xoEditorActivity +class = xoEditorActivity.xoEditorActivity +show_launcher = 1 diff --git a/html/.svn/all-wcprops b/html/.svn/all-wcprops new file mode 100644 index 0000000..52c3d52 --- /dev/null +++ b/html/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 56 +/public-svn/!svn/ver/308/xoEditor/xoEditor.activity/html +END +xo-color.xml +K 25 +svn:wc:ra_dav:version-url +V 69 +/public-svn/!svn/ver/308/xoEditor/xoEditor.activity/html/xo-color.xml +END +prototype.js +K 25 +svn:wc:ra_dav:version-url +V 69 +/public-svn/!svn/ver/304/xoEditor/xoEditor.activity/html/prototype.js +END diff --git a/html/.svn/entries b/html/.svn/entries new file mode 100644 index 0000000..7082565 --- /dev/null +++ b/html/.svn/entries @@ -0,0 +1,52 @@ +8 + +dir +311 +http://mediamods.com/public-svn/xoEditor/xoEditor.activity/html +http://mediamods.com/public-svn + + + +2007-08-15T22:25:38.011753Z +308 +erikb + + +svn:special svn:externals svn:needs-lock + + + + + + + + + + + +574bc980-5f2d-0410-acbc-c8f9f0eb14e0 + +prototype.js +file + + + + +2007-08-15T20:51:58.000000Z +c88ad55f47e32f870a79c85e6ed7b9e1 +2007-08-15T21:14:58.627518Z +304 +erikb + +xo-color.xml +file + + + + +2007-08-15T22:02:52.000000Z +c8d70ba4d7c5d8d179388fdd098c3de6 +2007-08-15T22:25:38.011753Z +308 +erikb + diff --git a/html/.svn/format b/html/.svn/format new file mode 100644 index 0000000..45a4fb7 --- /dev/null +++ b/html/.svn/format @@ -0,0 +1 @@ +8 diff --git a/html/.svn/text-base/prototype.js.svn-base b/html/.svn/text-base/prototype.js.svn-base new file mode 100644 index 0000000..5806f35 --- /dev/null +++ b/html/.svn/text-base/prototype.js.svn-base @@ -0,0 +1,3277 @@ +/* Prototype JavaScript framework, version 1.5.1.1 + * (c) 2005-2007 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.5.1.1', + + Browser: { + IE: !!(window.attachEvent && !window.opera), + Opera: !!window.opera, + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 + }, + + BrowserFeatures: { + XPath: !!document.evaluate, + ElementExtensions: !!window.HTMLElement, + SpecificElementExtensions: + (document.createElement('div').__proto__ !== + document.createElement('form').__proto__) + }, + + ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.extend(Object, { + inspect: function(object) { + try { + if (object === undefined) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + toJSON: function(object) { + var type = typeof object; + switch(type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (object.ownerDocument === document) return; + var results = []; + for (var property in object) { + var value = Object.toJSON(object[property]); + if (value !== undefined) + results.push(property.toJSON() + ': ' + value); + } + return '{' + results.join(', ') + '}'; + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({}, object); + } +}); + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [event || window.event].concat(args)); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + return this.toPaddedString(2, 16); + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + }, + + toPaddedString: function(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + }, + + toJSON: function() { + return isFinite(this) ? this.toString() : 'null'; + } +}); + +Date.prototype.toJSON = function() { + return '"' + this.getFullYear() + '-' + + (this.getMonth() + 1).toPaddedString(2) + '-' + + this.getDate().toPaddedString(2) + 'T' + + this.getHours().toPaddedString(2) + ':' + + this.getMinutes().toPaddedString(2) + ':' + + this.getSeconds().toPaddedString(2) + '"'; +}; + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(this); + } finally { + this.currentlyExecuting = false; + } + } + } +} +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return this; + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : this; + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var self = arguments.callee; + self.text.data = this; + return self.div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return {}; + + return match[1].split(separator || '&').inject({}, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (hash[key].constructor != Array) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + times: function(count) { + var result = ''; + for (var i = 0; i < count; i++) result += this; + return result; + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { + var character = String.specialChar[match[0]]; + return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + }, + + toJSON: function() { + return this.inspect(true); + }, + + unfilterJSON: function(filter) { + return this.sub(filter || Prototype.JSONFilter, '#{1}'); + }, + + isJSON: function() { + var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + }, + + evalJSON: function(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + }, + + include: function(pattern) { + return this.indexOf(pattern) > -1; + }, + + startsWith: function(pattern) { + return this.indexOf(pattern) === 0; + }, + + endsWith: function(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + }, + + empty: function() { + return this == ''; + }, + + blank: function() { + return /^\s*$/.test(this); + } +}); + +if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { + escapeHTML: function() { + return this.replace(/&/g,'&').replace(/</g,'<').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 '#<Enumerable:' + this.toArray().inspect() + '>'; + } +} + +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 '#<Hash:{' + this.map(function(pair) { + return pair.map(Object.inspect).join(': '); + }).join(', ') + '}>'; + }, + + toJSON: function() { + return Hash.toJSON(this); + } +}); + +function $H(object) { + if (object instanceof Hash) return object; + return new Hash(object); +}; + +// Safari iterates over shadowed properties +if (function() { + var i = 0, Test = function(value) { this.key = value }; + Test.prototype.key = 'foo'; + for (var property in new Test('bar')) i++; + return i > 1; +}()) Hash.prototype._each = function(iterator) { + var cache = []; + for (var key in this) { + var value = this[key]; + if ((value && value == Hash.prototype[key]) || cache.include(key)) continue; + cache.push(key); + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } +}; +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '' + } + Object.extend(this.options, options || {}); + + this.options.method = this.options.method.toLowerCase(); + if (typeof this.options.parameters == 'string') + this.options.parameters = this.options.parameters.toQueryParams(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + _complete: false, + + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Hash.toQueryString(params)) { + // when GET, append parameters to URL + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + if (this.options.onCreate) this.options.onCreate(this.transport); + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) + setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (typeof extras.push == 'function') + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + return !this.transport.status + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + this.transport.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + var contentType = this.getHeader('Content-type'); + if (contentType && contentType.strip(). + match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + state, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) { return null } + }, + + evalJSON: function() { + try { + var json = this.getHeader('X-JSON'); + return json ? json.evalJSON() : null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, param) { + this.updateContent(); + onComplete(transport, param); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.container[this.success() ? 'success' : 'failure']; + var response = this.transport.responseText; + + if (!this.options.evalScripts) response = response.stripScripts(); + + if (receiver = $(receiver)) { + if (this.options.insertion) + new this.options.insertion(receiver, response); + else + receiver.update(response); + } + + if (this.success()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (typeof element == 'string') + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(query.snapshotItem(i)); + return results; + }; + + document.getElementsByClassName = function(className, parentElement) { + var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; + return document._getElementsByXPath(q, parentElement); + } + +} else document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + var elements = [], child, pattern = new RegExp("(^|\\s)" + className + "(\\s|$)"); + for (var i = 0, length = children.length; i < length; i++) { + child = children[i]; + var elementClassName = child.className; + if (elementClassName.length == 0) continue; + if (elementClassName == className || elementClassName.match(pattern)) + elements.push(Element.extend(child)); + } + return elements; +}; + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) var Element = {}; + +Element.extend = function(element) { + var F = Prototype.BrowserFeatures; + if (!element || !element.tagName || element.nodeType == 3 || + element._extended || F.SpecificElementExtensions || element == window) + return element; + + var methods = {}, tagName = element.tagName, cache = Element.extend.cache, + T = Element.Methods.ByTag; + + // extend methods for all tags (Safari doesn't need this) + if (!F.ElementExtensions) { + Object.extend(methods, Element.Methods), + Object.extend(methods, Element.Methods.Simulated); + } + + // extend methods for specific tags + if (T[tagName]) Object.extend(methods, T[tagName]); + + for (var property in methods) { + var value = methods[property]; + if (typeof value == 'function' && !(property in element)) + element[property] = cache.findOrStore(value); + } + + element._extended = Prototype.emptyFunction; + return element; +}; + +Element.extend.cache = { + findOrStore: function(value) { + return this[value] = this[value] || function() { + return value.apply(null, [this].concat($A(arguments))); + } + } +}; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + $(element).style.display = 'none'; + return element; + }, + + show: function(element) { + $(element).style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, html) { + html = typeof html == 'undefined' ? '' : html.toString(); + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + replace: function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + if (element.outerHTML) { + element.outerHTML = html.stripScripts(); + } else { + var range = element.ownerDocument.createRange(); + range.selectNodeContents(element); + element.parentNode.replaceChild( + range.createContextualFragment(html.stripScripts()), element); + } + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $A($(element).getElementsByTagName('*')).each(Element.extend); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (typeof selector == 'string') + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = element.ancestors(); + return expression ? Selector.findElement(ancestors, expression, index) : + ancestors[index || 0]; + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + var descendants = element.descendants(); + return expression ? Selector.findElement(descendants, expression, index) : + descendants[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = element.previousSiblings(); + return expression ? Selector.findElement(previousSiblings, expression, index) : + previousSiblings[index || 0]; + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = element.nextSiblings(); + return expression ? Selector.findElement(nextSiblings, expression, index) : + nextSiblings[index || 0]; + }, + + getElementsBySelector: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + getElementsByClassName: function(element, className) { + return document.getElementsByClassName(className, element); + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + if (!element.attributes) return null; + var t = Element._attributeTranslations; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + var attribute = element.attributes[name]; + return attribute ? attribute.nodeValue : null; + } + return element.getAttribute(name); + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + if (elementClassName.length == 0) return false; + if (elementClassName == className || + elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + return true; + return false; + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).add(className); + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).remove(className); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); + return element; + }, + + observe: function() { + Event.observe.apply(Event, arguments); + return $A(arguments).first(); + }, + + stopObserving: function() { + Event.stopObserving.apply(Event, arguments); + return $A(arguments).first(); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Position.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles, camelized) { + element = $(element); + var elementStyle = element.style; + + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]) + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') : + (camelized ? property : property.camelize())] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = $(element).getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = element.style.overflow || 'auto'; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + } +}; + +Object.extend(Element.Methods, { + childOf: Element.Methods.descendantOf, + childElements: Element.Methods.immediateDescendants +}); + +if (Prototype.Browser.Opera) { + Element.Methods._getStyle = Element.Methods.getStyle; + Element.Methods.getStyle = function(element, style) { + switch(style) { + case 'left': + case 'top': + case 'right': + case 'bottom': + if (Element._getStyle(element, 'position') == 'static') return null; + default: return Element._getStyle(element, style); + } + }; +} +else if (Prototype.Browser.IE) { + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset'+style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + element = $(element); + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + style.filter = filter.replace(/alpha\([^\)]*\)/gi,''); + return element; + } else if (value < 0.00001) value = 0; + style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + // IE is missing .innerHTML support for TABLE-related elements + Element.Methods.update = function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + var tagName = element.tagName.toUpperCase(); + if (['THEAD','TBODY','TR','TD'].include(tagName)) { + var div = document.createElement('div'); + switch (tagName) { + case 'THEAD': + case 'TBODY': + div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>'; + depth = 2; + break; + case 'TR': + div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>'; + depth = 3; + break; + case 'TD': + div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>'; + 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 = '<table><tbody>' + this.content + '</tbody></table>'; + 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 "#<Selector:" + this.expression.inspect() + ">"; + } +}; + +Object.extend(Selector, { + _cache: {}, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: "[@#{1}]", + attr: function(m) { + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (typeof h === 'function') return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", + 'checked': "[@checked]", + 'disabled': "[@disabled]", + 'enabled': "[not(@disabled)]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, m, v; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in p) { + if (m = e.match(p[i])) { + v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m); + exclusion.push("(" + v.substring(1, v.length - 1) + ")"); + e = e.replace(m[0], ''); + break; + } + } + } + return "[not(" + exclusion.join(" and ") + ")]"; + }, + 'nth-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); + }, + 'nth-last-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); + }, + 'nth-of-type': function(m) { + return Selector.xpath.pseudos.nth("position() ", m); + }, + 'nth-last-of-type': function(m) { + return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); + }, + 'first-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); + }, + 'last-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); + }, + 'only-of-type': function(m) { + var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); + }, + nth: function(fragment, m) { + var mm, formula = m[6], predicate; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + if (mm = formula.match(/^(\d+)$/)) // digit only + return '[' + fragment + "= " + mm[1] + ']'; + if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (mm[1] == "-") mm[1] = -1; + var a = mm[1] ? Number(mm[1]) : 1; + var b = mm[2] ? Number(mm[2]) : 0; + predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + + "((#{fragment} - #{b}) div #{a} >= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: { + // combinators must be listed first + // (and descendant needs to be last combinator) + laterSibling: /^\s*~\s*/, + child: /^\s*>\s*/, + adjacent: /^\s*\+\s*/, + descendant: /^\s/, + + // selectors follow + tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, + id: /^#([\w\-\*]+)(\b|$)/, + className: /^\.([\w\-\*]+)(\b|$)/, + pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/, + attrPresence: /^\[([\w]+)\]/, + attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/ + }, + + handlers: { + // UTILITY FUNCTIONS + // joins two collections + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + // marks an array of nodes for counting + mark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._counted = true; + return nodes; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._counted = undefined; + return nodes; + }, + + // mark each child node with its position (for nth calls) + // "ofType" flag indicates whether we're indexing for nth-of-type + // rather than nth-child + index: function(parentNode, reverse, ofType) { + parentNode._counted = true; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; + } + }, + + // filters out duplicates and extends all nodes + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (!(n = nodes[i])._counted) { + n._counted = true; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + // COMBINATOR FUNCTIONS + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, children = [], child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + // TOKEN FUNCTIONS + tagName: function(nodes, root, tagName, combinator) { + tagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + // fastlane for ordinary descendant combinators + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() == tagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + if (!nodes && root == document) return targetNode ? [targetNode] : []; + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr) { + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + // handles the an+b logic + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._counted) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + // IE treats comments as element nodes + if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._counted) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled) results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv.startsWith(v); }, + '$=': function(nv, v) { return nv.endsWith(v); }, + '*=': function(nv, v) { return nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } + }, + + matchElements: function(elements, expression) { + var matches = new Selector(expression).findElements(), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._counted) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (typeof expression == 'number') { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + var exprs = expressions.join(','), expressions = []; + exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, getHash) { + var data = elements.inject({}, function(result, element) { + if (!element.disabled && element.name) { + var key = element.name, value = $(element).getValue(); + if (value != null) { + if (key in result) { + if (result[key].constructor != Array) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return getHash ? data : Hash.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, getHash) { + return Form.serializeElements(Form.getElements(form), getHash); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + return $(form).getElements().find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || {}); + + var params = options.parameters; + options.parameters = form.serialize(true); + + if (params) { + if (typeof params == 'string') params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(form.readAttribute('action'), options); + } +} + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +} + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = {}; + pair[element.name] = value; + return Hash.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type))) + element.select(); + } catch (e) {} + return element; + }, + + disable: function(element) { + element = $(element); + element.blur(); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +} + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + default: + return Form.Element.Serializers.textarea(element); + } + }, + + inputSelector: function(element) { + return element.checked ? element.value : null; + }, + + textarea: function(element) { + return element.value; + }, + + select: function(element) { + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +} + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + var changed = ('string' == typeof this.lastValue && 'string' == typeof value + ? this.lastValue != value : String(this.lastValue) != String(value)); + if (changed) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback.bind(this)); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + + element: function(event) { + return $(event.target || event.srcElement); + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0, length = Event.observers.length; i < length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (Prototype.Browser.WebKit || element.attachEvent)) + name = 'keydown'; + + Event._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (Prototype.Browser.WebKit || element.attachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + try { + element.detachEvent('on' + name, observer); + } catch (e) {} + } + } +}); + +/* prevent memory leaks in IE */ +if (Prototype.Browser.IE) + Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if(element.tagName=='BODY') break; + var p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent == document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!window.opera || element.tagName=='BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (Prototype.Browser.WebKit) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} + +Element.addMethods();
\ No newline at end of file diff --git a/html/.svn/text-base/xo-color.xml.svn-base b/html/.svn/text-base/xo-color.xml.svn-base new file mode 100644 index 0000000..3fb9cee --- /dev/null +++ b/html/.svn/text-base/xo-color.xml.svn-base @@ -0,0 +1,964 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>change the XO colors and shape</title> + +<!-- +Author: Walter Bender (walter@laptop.org) +(CC-PD) Public Domain (do what you want to do...) + +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_svg "http://www.w3.org/2000/svg"> + <!ENTITY ns_xlink "http://www.w3.org/1999/xlink"> +]> +--> + + + + +// SVG version of OLPC XO man color changer and shape shifter +// Created by: Walter Bender (walter@laptop.org) on 27 January 2007 +// Last modified by: Walter Bender (walter@laptop.org) on 28 June 2007 +// Color tool designed in memory of: Nat Jacobson +// ajax hooks: Erik Blankinship (erikb@mediamods.com) on 15 August 2007 + +<script type="text/javascript"> +<![CDATA[ + var fillcolors = [ + // red, orange, yellow, green, blue, purple + "rgb(255,43,52)", "rgb(255,143,0)", "rgb(248,232,0)", "rgb(0,234,17)", "rgb(0,160,255)", "rgb(172,50,255)" + ]; + + + var strokecolors = [ + // M A+ C- C C+ A- + // dark fill + // red + "rgb(178,0,8)", "rgb(154,82,0)", "rgb(128,117,0)", "rgb(0,128,9)", "rgb(0,88,140)", "rgb(94,0,140)", + // orange + "rgb(154,82,0)", "rgb(128,117,0)", "rgb(0,128,9)", "rgb(0,88,140)", "rgb(94,0,140)", "rgb(178,0,8)", + // yellow + "rgb(128,117,0)", "rgb(0,128,9)", "rgb(0,88,140)", "rgb(94,0,140)", "rgb(178,0,8)", "rgb(154,82,0)", + // green + "rgb(0,128,9)", "rgb(0,88,140)", "rgb(94,0,140)", "rgb(178,0,8)", "rgb(154,82,0)", "rgb(128,117,0)", + // blue + "rgb(0,88,140)", "rgb(94,0,140)", "rgb(178,0,8)", "rgb(154,82,0)", "rgb(128,117,0)", "rgb(0,128,9)", + // purple + "rgb(94,0,140)", "rgb(178,0,8)", "rgb(154,82,0)", "rgb(128,117,0)", "rgb(0,128,9)", "rgb(0,88,140)", + + // medium fill + // red + "rgb(230,0,10)", "rgb(255,143,0)", "rgb(190,158,0)", "rgb(0,178,13)", "rgb(0,95,228)", "rgb(127,0,191)", + // orange + "rgb(201,126,0)", "rgb(190,158,0)", "rgb(0,178,13)", "rgb(0,95,228)", "rgb(167,0,255)", "rgb(255,43,52)", + // yellow + "rgb(190,158,0)", "rgb(0,234,17)", "rgb(0,160,255)", "rgb(172,50,255)", "rgb(255,43,52)", "rgb(255,143,0)", + // green + "rgb(0,178,13)", "rgb(0,95,228)", "rgb(127,0,191)", "rgb(255,43,52)", "rgb(255,143,0)", "rgb(190,158,0)", + // blue + "rgb(0,95,228)", "rgb(153,0,230)", "rgb(255,43,52)", "rgb(255,143,0)", "rgb(190,158,0)", "rgb(0,178,13)", + // purple + "rgb(127,0,191)", "rgb(255,43,52)", "rgb(255,143,0)", "rgb(190,158,0)", "rgb(0,178,13)", "rgb(0,95,228)", + + // light fill + // red + "rgb(255,173,206)", "rgb(255,193,105)", "rgb(248,232,0)", "rgb(139,255,122)", "rgb(188,205,255)", "rgb(209,163,255)", + // orange + "rgb(255,193,105)", "rgb(248,232,0)", "rgb(139,255,122)", "rgb(188,205,255)", "rgb(209,163,255)", "rgb(255,173,206)", + // yellow + "rgb(255,250,0)", "rgb(139,255,122)", "rgb(188,206,255)", "rgb(209,163,255)", "rgb(255,173,206)", "rgb(255,193,105)", + // green + "rgb(139,255,122)", "rgb(188,205,255)", "rgb(209,163,255)", "rgb(255,173,206)", "rgb(255,193,105)", "rgb(248,232,0)", + // blue + "rgb(188,205,255)", "rgb(209,163,255)", "rgb(255,173,206)", "rgb(255,193,105)", "rgb(248,232,0)", "rgb(139,255,122)", + // purple + "rgb(209,163,255)", "rgb(255,173,206)", "rgb(255,193,105)", "rgb(248,232,0)", "rgb(139,255,122)", "rgb(188,205,255)" + ]; + +// stroke values +var strokeLight = 2; +var strokeMedium = 1; +var strokeDark = 0; +var strokeCurrent = strokeMedium; + +// +var flip = 0; +var square = 0; +var xoff = 0; +var yoff = 2; + +// color variables +var strokeH = 0; +var fillH = 0; + +// Sugar stuff +// gridbox centers +var grid = [37.5, 112.5, 187.5, 262.5, 337.5, 412.5, 485.5, 562.5, 637.5, 712.5, 785.5, 862.5, 937.5, 1012.5, 1087.5, 1162.5]; +var radius = 22.5; +var strokeW = 9.5; + +var circlex1 = [0,1,2,3,4,5]; +var circley1 = [0,1,2,3,4,5]; +var circlex2 = [0,1,2,3,4,5]; +var circley2 = [0,1,2,3,4,5]; +var circlex3 = [0,1,2,3,4,5]; +var circley3 = [0,1,2,3,4,5]; +var circlex4 = [0,1,2,3,4,5]; +var circley4 = [0,1,2,3,4,5]; +var circlex5 = [0,1,2,3,4,5]; +var circley5 = [0,1,2,3,4,5]; +var circlex6 = [0,1,2,3,4,5]; +var circley6 = [0,1,2,3,4,5]; + +// Stuff needed for moving the xo man end and knot points +var xoL1X1=554.5; +var xoL1Y1=448; +var xoL1X2=645.5; +var xoL1Y2=357; +var xoL1K1X=580; +var xoL1K1Y=420.5; +var xoL1K2X=620; +var xoL1K2Y=380.5; +var xoL2X1=554.5; +var xoL2Y1=357; +var xoL2X2=645.5; +var xoL2Y2=448; +var xoL2K1X=580; +var xoL2K1Y=380.5; +var xoL2K2X=620; +var xoL2K2Y=420.5; +var xoCX=600; +var xoCY=318.5; +var xoL1X1Reset=554.5; +var xoL1Y1Reset=448; +var xoL1X2Reset=645.5; +var xoL1Y2Reset=357; +var xoL1K1XReset=580; +var xoL1K1YReset=420.5; +var xoL1K2XReset=620; +var xoL1K2YReset=380.5; +var xoL2X1Reset=554.5; +var xoL2Y1Reset=357; +var xoL2X2Reset=645.5; +var xoL2Y2Reset=448; +var xoL2K1XReset=580; +var xoL2K1YReset=380.5; +var xoL2K2XReset=620; +var xoL2K2YReset=420.5; +var xoCXReset=600; +var xoCYReset=318.5; +var xoCenterX = (xoL1X1+xoL1X2)/2; +var xoCenterY = (xoL1Y1+xoL1Y2)/2; +var moveOn=0; +var moveID=""; + +// calculate circle coordinates +function sincos (evt) { +var a; +var i; +var r1=75; +var r2=245; +var cx = [0,1,2,3,4,5]; +var cy = [0,1,2,3,4,5]; + + + for( i=0; i< 6; i++ ) + { + a = 1.05; + a *= i; + cx[i] = 600-r2*Math.sin(a); + cy[i] = 375-r2*Math.cos(a); + } + + for( i=0; i< 6; i++ ) + { + a = 1.05; + a *= i; + circlex1[i] = r1*Math.sin(a)+cx[0]; + circley1[i] = r1*Math.cos(a)+cy[0]; + circlex2[i] = r1*Math.sin(a)+cx[1]; + circley2[i] = r1*Math.cos(a)+cy[1]; + circlex3[i] = r1*Math.sin(a)+cx[2]; + circley3[i] = r1*Math.cos(a)+cy[2]; + circlex4[i] = r1*Math.sin(a)+cx[3]; + circley4[i] = r1*Math.cos(a)+cy[3]; + circlex5[i] = r1*Math.sin(a)+cx[4]; + circley5[i] = r1*Math.cos(a)+cy[4]; + circlex6[i] = r1*Math.sin(a)+cx[5]; + circley6[i] = r1*Math.cos(a)+cy[5]; + } +} + +function positionButton(evt,id,x,y) { + e = evt.target.ownerDocument.getElementById(id); + e.setAttribute("cx",grid[x]); + e.setAttribute("cy",grid[y]); +} + +function positionButtonOffset(evt,id,x,y) { + if( y < 0 ) { y+=6; } + e = evt.target.ownerDocument.getElementById(id); + e.setAttribute("cx",grid[x+xoff]); + e.setAttribute("cy",grid[y+yoff]); +} + +function positionCircle(evt,id,r,a) { + if( a > -1 && a < 6 ) + { + e = evt.target.ownerDocument.getElementById(id); + switch (r) + { + case 0: + e.setAttribute("cx",circlex1[a]); + e.setAttribute("cy",circley1[a]); + break; + case 1: + e.setAttribute("cx",circlex2[a]); + e.setAttribute("cy",circley2[a]); + break; + case 2: + e.setAttribute("cx",circlex3[a]); + e.setAttribute("cy",circley3[a]); + break; + case 3: + e.setAttribute("cx",circlex4[a]); + e.setAttribute("cy",circley4[a]); + break; + case 4: + e.setAttribute("cx",circlex5[a]); + e.setAttribute("cy",circley5[a]); + break; + case 5: + e.setAttribute("cx",circlex6[a]); + e.setAttribute("cy",circley6[a]); + break; + default : + } + } +} + +function buttonInit(evt) { + if( square == 1 ) + { + buttonInitSquare(evt); + } else { + buttonInitHex(evt); + } + +} + +// scale and position buttons in circles +function buttonInitHex(evt) { + + positionCircle(evt,"X",0,0); + + positionCircle(evt,"R",0,0); + positionCircle(evt,"YR",1,1); + positionCircle(evt,"Y",2,2); + positionCircle(evt,"G",3,3); + positionCircle(evt,"B",4,4); + positionCircle(evt,"P",5,5); + + positionCircle(evt,"RAm",0,1); + positionCircle(evt,"YRAm",1,2); + positionCircle(evt,"YAm",2,3); + positionCircle(evt,"GAm",3,4); + positionCircle(evt,"BAm",4,5); + positionCircle(evt,"PAm",5,0); + + positionCircle(evt,"RCp",0,2); + positionCircle(evt,"YRCp",1,3); + positionCircle(evt,"YCp",2,4); + positionCircle(evt,"GCp",3,5); + positionCircle(evt,"BCp",4,0); + positionCircle(evt,"PCp",5,1); + + positionCircle(evt,"RC",0,3); + positionCircle(evt,"YRC",1,4); + positionCircle(evt,"YC",2,5); + positionCircle(evt,"GC",3,0); + positionCircle(evt,"BC",4,1); + positionCircle(evt,"PC",5,2); + + positionCircle(evt,"RCm",0,4); + positionCircle(evt,"YRCm",1,5); + positionCircle(evt,"YCm",2,0); + positionCircle(evt,"GCm",3,1); + positionCircle(evt,"BCm",4,2); + positionCircle(evt,"PCm",5,3); + + positionCircle(evt,"RAp",0,5); + positionCircle(evt,"YRAp",1,0); + positionCircle(evt,"YAp",2,1); + positionCircle(evt,"GAp",3,2); + positionCircle(evt,"BAp",4,3); + positionCircle(evt,"PAp",5,4); +} + +// scale and position buttons on grid (col,row) +function buttonInitSquare(evt) { + + positionButtonOffset(evt,"X",0,0); + + positionButtonOffset(evt, "R",0,0); + positionButtonOffset(evt, "YR",5,5); + positionButtonOffset(evt, "Y",4,4); + positionButtonOffset(evt, "G",3,3); + positionButtonOffset(evt, "B",2,2); + positionButtonOffset(evt, "P",1,1); + + positionButtonOffset(evt, "RAm",0,1); + positionButtonOffset(evt,"YRAm",5,0); + positionButtonOffset(evt, "YAm",4,5); + positionButtonOffset(evt, "GAm",3,4); + positionButtonOffset(evt, "BAm",2,3); + positionButtonOffset(evt, "PAm",1,2); + + positionButtonOffset(evt, "RCp",0,2); + positionButtonOffset(evt,"YRCp",5,1); + positionButtonOffset(evt, "YCp",4,0); + positionButtonOffset(evt, "GCp",3,5); + positionButtonOffset(evt, "BCp",2,4); + positionButtonOffset(evt, "PCp",1,3); + + positionButtonOffset(evt, "RC",0,3); + positionButtonOffset(evt, "YRC",5,2); + positionButtonOffset(evt, "YC",4,1); + positionButtonOffset(evt, "GC",3,0); + positionButtonOffset(evt, "BC",2,5); + positionButtonOffset(evt, "PC",1,4); + + positionButtonOffset(evt, "RCm",0,4); + positionButtonOffset(evt,"YRCm",5,3); + positionButtonOffset(evt, "YCm",4,2); + positionButtonOffset(evt, "GCm",3,1); + positionButtonOffset(evt, "BCm",2,0); + positionButtonOffset(evt, "PCm",1,5); + + positionButtonOffset(evt, "RAp",0,5); + positionButtonOffset(evt,"YRAp",5,4); + positionButtonOffset(evt, "YAp",4,3); + positionButtonOffset(evt, "GAp",3,2); + positionButtonOffset(evt, "BAp",2,1); + positionButtonOffset(evt, "PAp",1,0); +} + +// recompute button color +// fill hue is 0,1,2,3,4,5 for r,o,y,g,b,p +// stroke hue is 0,1,2,3,4,5 for m,a+,c-,c,c+,a- plus an offset of 6*fillhue and 36*valuelevel +function colorButton(evt,id,fh,sh,sv) { +var e; + e = evt.target.ownerDocument.getElementById(id); + if( flip == 0 ) + { + e.setAttribute("stroke",strokecolors[fh*6+sv*36+sh]); + e.setAttribute("fill",fillcolors[fh]); + } else { + e.setAttribute("fill",strokecolors[fh*6+sv*36+sh]); + e.setAttribute("stroke",fillcolors[fh]); + } +} + +// update XO man and all buttons based on current hue and value +function colorUpdate(evt) { +var e; +var tmp; + + // update XO Man + colorButton(evt,"Circle",fillH,strokeH,strokeCurrent); + colorButton(evt,"iconCircle",fillH,strokeH,strokeCurrent); + if( flip == 0 ) + { + e = evt.target.ownerDocument.getElementById("Line1"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("Line2"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("Fill1"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("Fill2"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("iconLine1"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("iconLine2"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("iconFill1"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("iconFill2"); + e.setAttribute("stroke",fillcolors[fillH]); + } else { + e = evt.target.ownerDocument.getElementById("Line1"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("Line2"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("Fill1"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("Fill2"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("iconLine1"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("iconLine2"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("iconFill1"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("iconFill2"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + } + + tmp = flip; + flip = 0; + colorButton(evt,"vd",fillH,strokeH,strokeDark); + colorButton(evt,"vm",fillH,strokeH,strokeMedium); + colorButton(evt,"vl",fillH,strokeH,strokeLight); + flip = 1; + colorButton(evt,"vdf",fillH,strokeH,strokeDark); + colorButton(evt,"vmf",fillH,strokeH,strokeMedium); + flip = tmp; + + colorButton(evt,"R",0,0,strokeCurrent); + colorButton(evt,"YR",1,0,strokeCurrent); + colorButton(evt,"Y",2,0,strokeCurrent); + colorButton(evt,"G",3,0,strokeCurrent); + colorButton(evt,"B",4,0,strokeCurrent); + colorButton(evt,"P",5,0,strokeCurrent); + colorButton(evt,"RAp",0,1,strokeCurrent); + colorButton(evt,"YRAp",1,1,strokeCurrent); + colorButton(evt,"YAp",2,1,strokeCurrent); + colorButton(evt,"GAp",3,1,strokeCurrent); + colorButton(evt,"BAp",4,1,strokeCurrent); + colorButton(evt,"PAp",5,1,strokeCurrent); + colorButton(evt,"RCm",0,2,strokeCurrent); + colorButton(evt,"YRCm",1,2,strokeCurrent); + colorButton(evt,"YCm",2,2,strokeCurrent); + colorButton(evt,"GCm",3,2,strokeCurrent); + colorButton(evt,"BCm",4,2,strokeCurrent); + colorButton(evt,"PCm",5,2,strokeCurrent); + colorButton(evt,"RC",0,3,strokeCurrent); + colorButton(evt,"YRC",1,3,strokeCurrent); + colorButton(evt,"YC",2,3,strokeCurrent); + colorButton(evt,"GC",3,3,strokeCurrent); + colorButton(evt,"BC",4,3,strokeCurrent); + colorButton(evt,"PC",5,3,strokeCurrent); + colorButton(evt,"RCp",0,4,strokeCurrent); + colorButton(evt,"YRCp",1,4,strokeCurrent); + colorButton(evt,"YCp",2,4,strokeCurrent); + colorButton(evt,"GCp",3,4,strokeCurrent); + colorButton(evt,"BCp",4,4,strokeCurrent); + colorButton(evt,"PCp",5,4,strokeCurrent); + colorButton(evt,"RAm",0,5,strokeCurrent); + colorButton(evt,"YRAm",1,5,strokeCurrent); + colorButton(evt,"YAm",2,5,strokeCurrent); + colorButton(evt,"GAm",3,5,strokeCurrent); + colorButton(evt,"BAm",4,5,strokeCurrent); + colorButton(evt,"PAm",5,5,strokeCurrent); + + saveXo() +} + +function saveXo( ) +{ + var upXoDude = document.getElementById('upXo'); + var xos = ""; + for (var i=0; i<upXoDude.childNodes.length; i++) + { xoi = upXoDude.childNodes[i]; + if (xoi.nodeType == 1) + { xos = xos + "<" + xoi.nodeName + " "; + for (var j=0; j<xoi.attributes.length; j++) + { xoj = xoi.attributes[j]; + xos = xos + xoj.nodeName + "=\"" + xoj.nodeValue + "\" "; + } + xos = xos+ "/>"; + } + } + + //alert( xos ); + new Ajax.Request( 'saveXo', {method:'get', parameters:'upXo='+xos} ); +} + +// individual button functions +function updater(evt,fh,dh,a) { + fillHUndo = fillH; + fillH = fh; + strokeHUndo = strokeH; + strokeH = dh; + if( square == 1 ) + { + // a complete kludge because the order of the grid + // does not reflect the order of the delta hues + switch(fh) + { + case 0: + if( dh > 0 ) { dh = 6-dh; } + positionButtonOffset(evt,"X",0,dh); + break; + case 1: + positionButtonOffset(evt,"X",5,5-dh); + break; + case 2: + positionButtonOffset(evt,"X",4,4-dh); + break; + case 3: + positionButtonOffset(evt,"X",3,3-dh); + break; + case 4: + positionButtonOffset(evt,"X",2,2-dh); + break; + case 5: + positionButtonOffset(evt,"X",1,1-dh); + break; + } + } else { + // a kludge of a different sort fo the similar reasons as above + positionCircle(evt,"X",fh,a); + } + colorUpdate(evt); +} + +function valueDark(evt) { + strokeCurrent = strokeDark; + flip = 0; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","hidden"); + colorUpdate(evt); +} + +function valueDarkFlip(evt) { + strokeCurrent = strokeDark; + flip = 1; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","hidden"); + colorUpdate(evt); +} + +function valueMedium(evt) { + strokeCurrent = strokeMedium; + flip = 0; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","hidden"); + colorUpdate(evt); +} + +function valueMediumFlip(evt) { + strokeCurrent = strokeMedium; + flip = 1; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","hidden"); + colorUpdate(evt); +} + +function valueLight(evt) { + strokeCurrent = strokeLight; + flip = 0; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","visible"); + colorUpdate(evt); +} + +function hexGrid(evt) { + square = 0; + e = evt.target.ownerDocument.getElementById("bgsq"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bghex"); + e.setAttribute("visibility","visible"); + buttonInit(evt); +} + +function sqGrid(evt) { + square = 1; + e = evt.target.ownerDocument.getElementById("bgsq"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bghex"); + e.setAttribute("visibility","hidden"); + buttonInit(evt); +} + +function background(evt,a) { + e = evt.target.ownerDocument.getElementById("backgroundW"); + if( a == 0 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } + e = evt.target.ownerDocument.getElementById("backgroundW"); + if( a == 0 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } + e = evt.target.ownerDocument.getElementById("backgroundL"); + if( a == 1 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } + e = evt.target.ownerDocument.getElementById("backgroundM"); + if( a == 2 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } + e = evt.target.ownerDocument.getElementById("backgroundK"); + if( a == 3 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } +} + + +// the rest of these functions are for moving knot points +function showpoints(evt) +{ +var e; + + e = evt.target.ownerDocument.getElementById("L1Knot1"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL1K1X); + e.setAttribute("cy",xoL1K1Y); + e = evt.target.ownerDocument.getElementById("L1Knot2"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL1K2X); + e.setAttribute("cy",xoL1K2Y); + e = evt.target.ownerDocument.getElementById("L2Knot1"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL2K1X); + e.setAttribute("cy",xoL2K1Y); + e = evt.target.ownerDocument.getElementById("L2Knot2"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL2K2X); + e.setAttribute("cy",xoL2K2Y); + e = evt.target.ownerDocument.getElementById("L1End1"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL1X1); + e.setAttribute("cy",xoL1Y1); + e = evt.target.ownerDocument.getElementById("L2End1"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL2X1); + e.setAttribute("cy",xoL2Y1); + e = evt.target.ownerDocument.getElementById("L1End2"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL1X2); + e.setAttribute("cy",xoL1Y2); + e = evt.target.ownerDocument.getElementById("L2End2"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL2X2); + e.setAttribute("cy",xoL2Y2); + e = evt.target.ownerDocument.getElementById("Center"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoCX); + e.setAttribute("cy",xoCY); +} + +function hidepoints(evt) +{ + e = evt.target.ownerDocument.getElementById("L1Knot1"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L1Knot2"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L2Knot1"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L2Knot2"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L1End1"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L1End2"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L2End1"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L2End2"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("Center"); + e.setAttribute("visibility", "hidden"); +} + +// moves are constrained by level and restricted to XO box +function move(evt) +{ +var x,y; + + if( moveOn == 1 ) + { + //bug, see: http://dev.laptop.org/ticket/1657 + x = evt.clientX; + x = x * 1.43; + y = evt.clientY; + y = y * 1.43; + + if( x < (xoCenterX-80) ) { x = xoCenterX-80; } + if( x > (xoCenterX+80) ) { x = xoCenterX+80; } + if( y < (xoCenterY-100) ) { y = xoCenterY-100; } + if( y > (xoCenterY+80) ) { y = xoCenterY+80; } + e = evt.target.ownerDocument.getElementById(moveID); + e.setAttribute("cx",x); + e.setAttribute("cy",y); + switch (moveID) + { + case "Center": + xoCX = x; + xoCY = y; + break; + case "L1End1": + xoL1X1 = x; + xoL1Y1 = y; + break; + case "L1End2": + xoL1X2 = x; + xoL1Y2 = y; + break; + case "L2End1": + xoL2X1 = x; + xoL2Y1 = y; + break; + case "L2End2": + xoL2X2 = x; + xoL2Y2 = y; + break; + case "L1Knot1": + xoL1K1X = x; + xoL1K1Y = y; + break; + case "L1Knot2": + xoL1K2X = x; + xoL1K2Y = y; + break; + case "L2Knot1": + xoL2K1X = x; + xoL2K1Y = y; + break; + case "L2Knot2": + xoL2K2X = x; + xoL2K2Y = y; + break; + default : + } + } +} + +function setID (evt, id) +{ + moveID = id; +} + +function startmove(evt) +{ + moveOn = 1; +} + +function stopmove(evt) +{ + moveOn = 0; + moveID = ""; + e = evt.target.ownerDocument.getElementById("Circle"); + e.setAttribute("cx",xoCX); + e.setAttribute("cy",xoCY); + e = evt.target.ownerDocument.getElementById("Line1"); + e.setAttribute("d", "M"+xoL1X1+","+xoL1Y1+" C"+xoL1K1X+","+xoL1K1Y+" "+xoL1K2X+","+xoL1K2Y+" "+xoL1X2+","+xoL1Y2); + e = evt.target.ownerDocument.getElementById("Fill1"); + e.setAttribute("d", "M"+xoL1X1+","+xoL1Y1+" C"+xoL1K1X+","+xoL1K1Y+" "+xoL1K2X+","+xoL1K2Y+" "+xoL1X2+","+xoL1Y2); + e = evt.target.ownerDocument.getElementById("Line2"); + e.setAttribute("d", "M"+xoL2X1+","+xoL2Y1+" C"+xoL2K1X+","+xoL2K1Y+" "+xoL2K2X+","+xoL2K2Y+" "+xoL2X2+","+xoL2Y2); + e = evt.target.ownerDocument.getElementById("Fill2"); + e.setAttribute("d", "M"+xoL2X1+","+xoL2Y1+" C"+xoL2K1X+","+xoL2K1Y+" "+xoL2K2X+","+xoL2K2Y+" "+xoL2X2+","+xoL2Y2); +} + +function resetXO (evt) +{ +xoL1X1=xoL1X1Reset; +xoL1Y1=xoL1Y1Reset; +xoL1X2=xoL1X2Reset; +xoL1Y2=xoL1Y2Reset; +xoL1K1X=xoL1K1XReset; +xoL1K1Y=xoL1K1YReset; +xoL1K2X=xoL1K2XReset; +xoL1K2Y=xoL1K2YReset; +xoL2X1=xoL2X1Reset; +xoL2Y1=xoL2Y1Reset; +xoL2X2=xoL2X2Reset; +xoL2Y2=xoL2Y2Reset; +xoL2K1X=xoL2K1XReset; +xoL2K1Y=xoL2K1YReset; +xoL2K2X=xoL2K2XReset; +xoL2K2Y=xoL2K2YReset; +xoCX=xoCXReset; +xoCY=xoCYReset; + + e = evt.target.ownerDocument.getElementById("Circle"); + e.setAttribute("cx",xoCX); + e.setAttribute("cy",xoCY); + e = evt.target.ownerDocument.getElementById("Line1"); + e.setAttribute("d", "M"+xoL1X1+","+xoL1Y1+" C"+xoL1K1X+","+xoL1K1Y+" "+xoL1K2X+","+xoL1K2Y+" "+xoL1X2+","+xoL1Y2); + e = evt.target.ownerDocument.getElementById("Fill1"); + e.setAttribute("d", "M"+xoL1X1+","+xoL1Y1+" C"+xoL1K1X+","+xoL1K1Y+" "+xoL1K2X+","+xoL1K2Y+" "+xoL1X2+","+xoL1Y2); + e = evt.target.ownerDocument.getElementById("Line2"); + e.setAttribute("d", "M"+xoL2X1+","+xoL2Y1+" C"+xoL2K1X+","+xoL2K1Y+" "+xoL2K2X+","+xoL2K2Y+" "+xoL2X2+","+xoL2Y2); + e = evt.target.ownerDocument.getElementById("Fill2"); + e.setAttribute("d", "M"+xoL2X1+","+xoL2Y1+" C"+xoL2K1X+","+xoL2K1Y+" "+xoL2K2X+","+xoL2K2Y+" "+xoL2X2+","+xoL2Y2); +} + +]]> +</script> +<script src="prototype.js" type="text/javascript"></script> +</head> + +<body> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www,w3,org/1999/xlink" onload="colorUpdate(evt); sincos(evt); buttonInit(evt)"> + + +// SVG elements +// begin backgrounds + <rect id="backgroundM" width="1200" height="900" x="0" y="0" fill="rgb(76,77,79)" stroke="rgb(76,77,79)" stroke-width="1" visibility="hidden" /> + <rect id="backgroundL" width="1200" height="900" x="0" y="0" fill="rgb(231,231,233)" stroke="rgb(231,231,233)" stroke-width="1" visibility="hidden" /> + <rect id="backgroundW" width="1200" height="900" x="0" y="0" fill="rgb(255,255,255)" stroke="rgb(255,255,255)" stroke-width="1" visibility="hidden" /> + <rect id="backgroundK" width="1200" height="900" x="0" y="0" fill="rgb(0,0,0)" stroke="rgb(0,0,0)" stroke-width="1" visibility="visible" /> +// end background + +// start XO group +<g onmouseover="showpoints(evt)" onmouseout="hidepoints(evt)" onmousedown="startmove(evt)" onmouseup="stopmove(evt)" onmousemove="move(evt)" onkeyup="textProcess(evt)"> +<g id="upXo"> // begin XO man +<path id="Line1" d="M645.5,357 C600,400.5 600,400.5 554.5,448" stroke="rgb(216,75,24)" stroke-width="37" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="Line2" d="M645.5,448 C600,400.5 600,400.5 554.5,357" stroke="rgb(216,75,24)" stroke-width="37" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="Fill1" d="M645.5,357 C600,400.5 600,400.5 554.5,448" stroke="rgb(52,192,210)" stroke-width="19" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="Fill2" d="M645.5,448 C600,400.5 600,400.5 554.5,357" stroke="rgb(52,192,210)" stroke-width="19" stroke-linecap="round" fill="none" visibility="visible" /> +<circle id="Circle" cx="600" cy="318.5" r="28.5" fill="rgb(52,192,210)" stroke="rgb(216,75,24)" stroke-width="9" visibility="visible" /> +</g> // end XO man +<g> +// knot points +<circle id="L1Knot1" cx="112.5" cy="112.5" r="12" fill="rgb(255,255,0)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L1Knot1')" /> +<circle id="L1Knot2" cx="112.5" cy="112.5" r="12" fill="rgb(255,255,0)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L1Knot2')" /> +<circle id="L2Knot1" cx="112.5" cy="112.5" r="12" fill="rgb(255,0,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L2Knot1')" /> +<circle id="L2Knot2" cx="112.5" cy="112.5" r="12" fill="rgb(255,0,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L2Knot2')" /> +// end points +<circle id="L1End1" cx="112.5" cy="112.5" r="12" fill="rgb(255,255,0)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L1End1')" /> +<circle id="L1End2" cx="112.5" cy="112.5" r="12" fill="rgb(255,255,0)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L1End2')" /> +<circle id="L2End1" cx="112.5" cy="112.5" r="12" fill="rgb(255,0,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L2End1')" /> +<circle id="L2End2" cx="112.5" cy="112.5" r="12" fill="rgb(255,0,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L2End2')" /> +// center point +<circle id="Center" cx="112.5" cy="112.5" r="12" fill="rgb(0,255,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'Center')" /> +// end knot points +</g> +</g> +// end XO group + +// "cursor" +<circle id="X" title="X" alt="X marks the spot" cx="0" cy="0" r="36" stroke="rgb(160,160,160)" fill="rgb(160,160,160)" stroke-width="9.5" visibility="visible" /> + +// color buttons +<circle id="R" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,0,0)" visibility="visible" /> +<circle id="YR" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,0,1)" visibility="visible" /> +<circle id="Y" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,0,2)" visibility="visible" /> +<circle id="G" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,0,3)" visibility="visible" /> +<circle id="B" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,0,4)" visibility="visible" /> +<circle id="P" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,0,5)" visibility="visible" /> + +<circle id="RC" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,3,3)" visibility="visible" /> +<circle id="YRC" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,3,4)" visibility="visible" /> +<circle id="YC" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,3,5)" visibility="visible" /> +<circle id="GC" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,3,0)" visibility="visible" /> +<circle id="BC" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,3,1)" visibility="visible" /> +<circle id="PC" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,3,2)" visibility="visible" /> + +<circle id="RCp" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,4,2)" visibility="visible" /> +<circle id="YRCp" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,4,3)" visibility="visible" /> +<circle id="YCp" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,4,4)" visibility="visible" /> +<circle id="GCp" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,4,5)" visibility="visible" /> +<circle id="BCp" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,4,0)" visibility="visible" /> +<circle id="PCp" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,4,1)" visibility="visible" /> + +<circle id="RCm" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,2,4)" visibility="visible" /> +<circle id="YRCm" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,2,5)" visibility="visible" /> +<circle id="YCm" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,2,0)" visibility="visible" /> +<circle id="GCm" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,2,1)" visibility="visible" /> +<circle id="BCm" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,2,2)" visibility="visible" /> +<circle id="PCm" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,2,3)" visibility="visible" /> + +<circle id="RAp" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,1,5)" visibility="visible" /> +<circle id="YRAp" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,1,0)" visibility="visible" /> +<circle id="YAp" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,1,1)" visibility="visible" /> +<circle id="GAp" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,1,2)" visibility="visible" /> +<circle id="BAp" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,1,3)" visibility="visible" /> +<circle id="PAp" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,1,4)" visibility="visible" /> + +<circle id="RAm" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,5,1)" visibility="visible" /> +<circle id="YRAm" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,5,2)" visibility="visible" /> +<circle id="YAm" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,5,3)" visibility="visible" /> +<circle id="GAm" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,5,4)" visibility="visible" /> +<circle id="BAm" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,5,5)" visibility="visible" /> +<circle id="PAm" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,5,0)" visibility="visible" /> + +// controls +<rect id="bgd" width="75" height="75" x="0" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<rect id="bgdf" width="75" height="75" x="75" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<rect id="bgm" width="75" height="75" x="150" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="visible" /> +<rect id="bgmf" width="75" height="75" x="225" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<rect id="bgl" width="75" height="75" x="300" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<circle id="vd" title="dark" alt="dark stroke" cx="37.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueDark(evt)" visibility="visible" /> +<circle id="vdf" title="darkflip" alt="dark flip" cx="112.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueDarkFlip(evt)" visibility="visible" /> +<circle id="vm" title="medium" alt="medium stroke" cx="187.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueMedium(evt)" visibility="visible" /> +<circle id="vmf" title="mediumflip" alt="medium flip" cx="262.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueMediumFlip(evt)" visibility="visible" /> +<circle id="vl" title="light" alt="light stroke" cx="337.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueLight(evt)" visibility="visible" /> + +<rect id="bghex" width="75" height="75" x="150" y="675" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="visible" /> +<rect id="bgsq" width="75" height="75" x="75" y="675" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<circle id="hex" title="hex grid" alt="hex grid" cx="187.5" cy="712.5" r="22.5" stroke="rgb(100,100,100)" fill="rgb(100,100,100)" stroke-width="9.5" onclick="hexGrid(evt)" visibility="visible" /> +<rect id="sq" title="square grid" alt="square gird" width="45" height="45" x="90" y="690" fill="rgb(100,100,100)" stroke="rgb(100,100,100)" stroke-width="1" onclick="sqGrid(evt)" visibility="visible" /> + +<g onclick="resetXO(evt)"> // begin XO man icon +<path id="iconLine1" d="M53,700 C37.5,715.5 37.5,715.5 22,731" stroke="rgb(230,0,10)" stroke-width="11.5" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="iconLine2" d="M53,731 C37.5,715.5 37.5,715.5 22,700" stroke="rgb(230,0,10)" stroke-width="11.5" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="iconFill1" d="M53,700 C37.5,715.5 37.5,715.5 22,731" stroke="rgb(255,43,52)" stroke-width="4.5" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="iconFill2" d="M53,731 C37.5,715.5 37.5,715.5 22,700" stroke="rgb(255,43,52)" stroke-width="4.5" stroke-linecap="round" fill="none" visibility="visible" /> +<circle id="iconCircle" cx="37.5" cy="690" r="8" fill="rgb(255,43,52)" stroke="rgb(230,0,10)" stroke-width="3.5" visibility="visible" /> +</g> // end XO man icon + +// background controls + +<rect id="icon" width="75" height="75" x="1125" y="0" fill="rgb(255,255,255)" stroke="rgb(255,255,255)" stroke-width="1" visibility="visible" onclick="background(evt,0)" /> +<rect id="icon" width="75" height="75" x="1050" y="0" fill="rgb(231,231,233)" stroke="rgb(231,231,233)" stroke-width="1" visibility="visible" onclick="background(evt,1)" /> +<rect id="icon" width="75" height="75" x="975" y="0" fill="rgb(76,77,79)" stroke="rgb(76,77,79)" stroke-width="1" visibility="visible" onclick="background(evt,2)" /> +<rect id="icon" width="75" height="75" x="900" y="0" fill="rgb(0,0,0)" stroke="rgb(0,0,0)" stroke-width="1" visibility="visible" onclick="background(evt,3)" /> +</svg> +</body> +</html> diff --git a/html/prototype.js b/html/prototype.js new file mode 100644 index 0000000..5806f35 --- /dev/null +++ b/html/prototype.js @@ -0,0 +1,3277 @@ +/* Prototype JavaScript framework, version 1.5.1.1 + * (c) 2005-2007 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * +/*--------------------------------------------------------------------------*/ + +var Prototype = { + Version: '1.5.1.1', + + Browser: { + IE: !!(window.attachEvent && !window.opera), + Opera: !!window.opera, + WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1, + Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1 + }, + + BrowserFeatures: { + XPath: !!document.evaluate, + ElementExtensions: !!window.HTMLElement, + SpecificElementExtensions: + (document.createElement('div').__proto__ !== + document.createElement('form').__proto__) + }, + + ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + K: function(x) { return x } +} + +var Class = { + create: function() { + return function() { + this.initialize.apply(this, arguments); + } + } +} + +var Abstract = new Object(); + +Object.extend = function(destination, source) { + for (var property in source) { + destination[property] = source[property]; + } + return destination; +} + +Object.extend(Object, { + inspect: function(object) { + try { + if (object === undefined) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : object.toString(); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + }, + + toJSON: function(object) { + var type = typeof object; + switch(type) { + case 'undefined': + case 'function': + case 'unknown': return; + case 'boolean': return object.toString(); + } + if (object === null) return 'null'; + if (object.toJSON) return object.toJSON(); + if (object.ownerDocument === document) return; + var results = []; + for (var property in object) { + var value = Object.toJSON(object[property]); + if (value !== undefined) + results.push(property.toJSON() + ': ' + value); + } + return '{' + results.join(', ') + '}'; + }, + + keys: function(object) { + var keys = []; + for (var property in object) + keys.push(property); + return keys; + }, + + values: function(object) { + var values = []; + for (var property in object) + values.push(object[property]); + return values; + }, + + clone: function(object) { + return Object.extend({}, object); + } +}); + +Function.prototype.bind = function() { + var __method = this, args = $A(arguments), object = args.shift(); + return function() { + return __method.apply(object, args.concat($A(arguments))); + } +} + +Function.prototype.bindAsEventListener = function(object) { + var __method = this, args = $A(arguments), object = args.shift(); + return function(event) { + return __method.apply(object, [event || window.event].concat(args)); + } +} + +Object.extend(Number.prototype, { + toColorPart: function() { + return this.toPaddedString(2, 16); + }, + + succ: function() { + return this + 1; + }, + + times: function(iterator) { + $R(0, this, true).each(iterator); + return this; + }, + + toPaddedString: function(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + }, + + toJSON: function() { + return isFinite(this) ? this.toString() : 'null'; + } +}); + +Date.prototype.toJSON = function() { + return '"' + this.getFullYear() + '-' + + (this.getMonth() + 1).toPaddedString(2) + '-' + + this.getDate().toPaddedString(2) + 'T' + + this.getHours().toPaddedString(2) + ':' + + this.getMinutes().toPaddedString(2) + ':' + + this.getSeconds().toPaddedString(2) + '"'; +}; + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) {} + } + + return returnValue; + } +} + +/*--------------------------------------------------------------------------*/ + +var PeriodicalExecuter = Class.create(); +PeriodicalExecuter.prototype = { + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.callback(this); + } finally { + this.currentlyExecuting = false; + } + } + } +} +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, { + gsub: function(pattern, replacement) { + var result = '', source = this, match; + replacement = arguments.callee.prepareReplacement(replacement); + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + }, + + sub: function(pattern, replacement, count) { + replacement = this.gsub.prepareReplacement(replacement); + count = count === undefined ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + }, + + scan: function(pattern, iterator) { + this.gsub(pattern, iterator); + return this; + }, + + truncate: function(length, truncation) { + length = length || 30; + truncation = truncation === undefined ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : this; + }, + + strip: function() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + }, + + stripTags: function() { + return this.replace(/<\/?[^>]+>/gi, ''); + }, + + stripScripts: function() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + }, + + extractScripts: function() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); + var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + }, + + evalScripts: function() { + return this.extractScripts().map(function(script) { return eval(script) }); + }, + + escapeHTML: function() { + var self = arguments.callee; + self.text.data = this; + return self.div.innerHTML; + }, + + unescapeHTML: function() { + var div = document.createElement('div'); + div.innerHTML = this.stripTags(); + return div.childNodes[0] ? (div.childNodes.length > 1 ? + $A(div.childNodes).inject('', function(memo, node) { return memo+node.nodeValue }) : + div.childNodes[0].nodeValue) : ''; + }, + + toQueryParams: function(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return {}; + + return match[1].split(separator || '&').inject({}, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()); + var value = pair.length > 1 ? pair.join('=') : pair[0]; + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (hash[key].constructor != Array) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + }, + + toArray: function() { + return this.split(''); + }, + + succ: function() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + }, + + times: function(count) { + var result = ''; + for (var i = 0; i < count; i++) result += this; + return result; + }, + + camelize: function() { + var parts = this.split('-'), len = parts.length; + if (len == 1) return parts[0]; + + var camelized = this.charAt(0) == '-' + ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) + : parts[0]; + + for (var i = 1; i < len; i++) + camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); + + return camelized; + }, + + capitalize: function() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + }, + + underscore: function() { + return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase(); + }, + + dasherize: function() { + return this.gsub(/_/,'-'); + }, + + inspect: function(useDoubleQuotes) { + var escapedString = this.gsub(/[\x00-\x1f\\]/, function(match) { + var character = String.specialChar[match[0]]; + return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + }, + + toJSON: function() { + return this.inspect(true); + }, + + unfilterJSON: function(filter) { + return this.sub(filter || Prototype.JSONFilter, '#{1}'); + }, + + isJSON: function() { + var str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); + return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); + }, + + evalJSON: function(sanitize) { + var json = this.unfilterJSON(); + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + }, + + include: function(pattern) { + return this.indexOf(pattern) > -1; + }, + + startsWith: function(pattern) { + return this.indexOf(pattern) === 0; + }, + + endsWith: function(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.lastIndexOf(pattern) === d; + }, + + empty: function() { + return this == ''; + }, + + blank: function() { + return /^\s*$/.test(this); + } +}); + +if (Prototype.Browser.WebKit || Prototype.Browser.IE) Object.extend(String.prototype, { + escapeHTML: function() { + return this.replace(/&/g,'&').replace(/</g,'<').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 '#<Enumerable:' + this.toArray().inspect() + '>'; + } +} + +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 '#<Hash:{' + this.map(function(pair) { + return pair.map(Object.inspect).join(': '); + }).join(', ') + '}>'; + }, + + toJSON: function() { + return Hash.toJSON(this); + } +}); + +function $H(object) { + if (object instanceof Hash) return object; + return new Hash(object); +}; + +// Safari iterates over shadowed properties +if (function() { + var i = 0, Test = function(value) { this.key = value }; + Test.prototype.key = 'foo'; + for (var property in new Test('bar')) i++; + return i > 1; +}()) Hash.prototype._each = function(iterator) { + var cache = []; + for (var key in this) { + var value = this[key]; + if ((value && value == Hash.prototype[key]) || cache.include(key)) continue; + cache.push(key); + var pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } +}; +ObjectRange = Class.create(); +Object.extend(ObjectRange.prototype, Enumerable); +Object.extend(ObjectRange.prototype, { + initialize: function(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + }, + + _each: function(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + }, + + include: function(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } +}); + +var $R = function(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +} + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (typeof responder[callback] == 'function') { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) {} + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { + Ajax.activeRequestCount++; + }, + onComplete: function() { + Ajax.activeRequestCount--; + } +}); + +Ajax.Base = function() {}; +Ajax.Base.prototype = { + setOptions: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '' + } + Object.extend(this.options, options || {}); + + this.options.method = this.options.method.toLowerCase(); + if (typeof this.options.parameters == 'string') + this.options.parameters = this.options.parameters.toQueryParams(); + } +} + +Ajax.Request = Class.create(); +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + +Ajax.Request.prototype = Object.extend(new Ajax.Base(), { + _complete: false, + + initialize: function(url, options) { + this.transport = Ajax.getTransport(); + this.setOptions(options); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + // simulate other verbs over post + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Hash.toQueryString(params)) { + // when GET, append parameters to URL + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + if (this.options.onCreate) this.options.onCreate(this.transport); + Ajax.Responders.dispatch('onCreate', this, this.transport); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) + setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + // user-defined headers + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (typeof extras.push == 'function') + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + return !this.transport.status + || (this.transport.status >= 200 && this.transport.status < 300); + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState]; + var transport = this.transport, json = this.evalJSON(); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + this.transport.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(transport, json); + } catch (e) { + this.dispatchException(e); + } + + var contentType = this.getHeader('Content-type'); + if (contentType && contentType.strip(). + match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i)) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(transport, json); + Ajax.Responders.dispatch('on' + state, this, transport, json); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + // avoid memory leak in MSIE: clean up + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name); + } catch (e) { return null } + }, + + evalJSON: function() { + try { + var json = this.getHeader('X-JSON'); + return json ? json.evalJSON() : null; + } catch (e) { return null } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Updater = Class.create(); + +Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { + initialize: function(container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + } + + this.transport = Ajax.getTransport(); + this.setOptions(options); + + var onComplete = this.options.onComplete || Prototype.emptyFunction; + this.options.onComplete = (function(transport, param) { + this.updateContent(); + onComplete(transport, param); + }).bind(this); + + this.request(url); + }, + + updateContent: function() { + var receiver = this.container[this.success() ? 'success' : 'failure']; + var response = this.transport.responseText; + + if (!this.options.evalScripts) response = response.stripScripts(); + + if (receiver = $(receiver)) { + if (this.options.insertion) + new this.options.insertion(receiver, response); + else + receiver.update(response); + } + + if (this.success()) { + if (this.onComplete) + setTimeout(this.onComplete.bind(this), 10); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(); +Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { + initialize: function(container, url, options) { + this.setOptions(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = {}; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(request) { + if (this.options.decay) { + this.decay = (request.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = request.responseText; + } + this.timer = setTimeout(this.onTimerEvent.bind(this), + this.decay * this.frequency * 1000); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (typeof element == 'string') + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(query.snapshotItem(i)); + return results; + }; + + document.getElementsByClassName = function(className, parentElement) { + var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]"; + return document._getElementsByXPath(q, parentElement); + } + +} else document.getElementsByClassName = function(className, parentElement) { + var children = ($(parentElement) || document.body).getElementsByTagName('*'); + var elements = [], child, pattern = new RegExp("(^|\\s)" + className + "(\\s|$)"); + for (var i = 0, length = children.length; i < length; i++) { + child = children[i]; + var elementClassName = child.className; + if (elementClassName.length == 0) continue; + if (elementClassName == className || elementClassName.match(pattern)) + elements.push(Element.extend(child)); + } + return elements; +}; + +/*--------------------------------------------------------------------------*/ + +if (!window.Element) var Element = {}; + +Element.extend = function(element) { + var F = Prototype.BrowserFeatures; + if (!element || !element.tagName || element.nodeType == 3 || + element._extended || F.SpecificElementExtensions || element == window) + return element; + + var methods = {}, tagName = element.tagName, cache = Element.extend.cache, + T = Element.Methods.ByTag; + + // extend methods for all tags (Safari doesn't need this) + if (!F.ElementExtensions) { + Object.extend(methods, Element.Methods), + Object.extend(methods, Element.Methods.Simulated); + } + + // extend methods for specific tags + if (T[tagName]) Object.extend(methods, T[tagName]); + + for (var property in methods) { + var value = methods[property]; + if (typeof value == 'function' && !(property in element)) + element[property] = cache.findOrStore(value); + } + + element._extended = Prototype.emptyFunction; + return element; +}; + +Element.extend.cache = { + findOrStore: function(value) { + return this[value] = this[value] || function() { + return value.apply(null, [this].concat($A(arguments))); + } + } +}; + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + $(element).style.display = 'none'; + return element; + }, + + show: function(element) { + $(element).style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: function(element, html) { + html = typeof html == 'undefined' ? '' : html.toString(); + $(element).innerHTML = html.stripScripts(); + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + replace: function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + if (element.outerHTML) { + element.outerHTML = html.stripScripts(); + } else { + var range = element.ownerDocument.createRange(); + range.selectNodeContents(element); + element.parentNode.replaceChild( + range.createContextualFragment(html.stripScripts()), element); + } + setTimeout(function() {html.evalScripts()}, 10); + return element; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), attribute = pair.last(); + var value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property) { + element = $(element); + var elements = []; + while (element = element[property]) + if (element.nodeType == 1) + elements.push(Element.extend(element)); + return elements; + }, + + ancestors: function(element) { + return $(element).recursivelyCollect('parentNode'); + }, + + descendants: function(element) { + return $A($(element).getElementsByTagName('*')).each(Element.extend); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + if (!(element = $(element).firstChild)) return []; + while (element && element.nodeType != 1) element = element.nextSibling; + if (element) return [element].concat($(element).nextSiblings()); + return []; + }, + + previousSiblings: function(element) { + return $(element).recursivelyCollect('previousSibling'); + }, + + nextSiblings: function(element) { + return $(element).recursivelyCollect('nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return element.previousSiblings().reverse().concat(element.nextSiblings()); + }, + + match: function(element, selector) { + if (typeof selector == 'string') + selector = new Selector(selector); + return selector.match($(element)); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = element.ancestors(); + return expression ? Selector.findElement(ancestors, expression, index) : + ancestors[index || 0]; + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + var descendants = element.descendants(); + return expression ? Selector.findElement(descendants, expression, index) : + descendants[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); + var previousSiblings = element.previousSiblings(); + return expression ? Selector.findElement(previousSiblings, expression, index) : + previousSiblings[index || 0]; + }, + + next: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); + var nextSiblings = element.nextSiblings(); + return expression ? Selector.findElement(nextSiblings, expression, index) : + nextSiblings[index || 0]; + }, + + getElementsBySelector: function() { + var args = $A(arguments), element = $(args.shift()); + return Selector.findChildElements(element, args); + }, + + getElementsByClassName: function(element, className) { + return document.getElementsByClassName(className, element); + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + if (!element.attributes) return null; + var t = Element._attributeTranslations; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + var attribute = element.attributes[name]; + return attribute ? attribute.nodeValue : null; + } + return element.getAttribute(name); + }, + + getHeight: function(element) { + return $(element).getDimensions().height; + }, + + getWidth: function(element) { + return $(element).getDimensions().width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + if (elementClassName.length == 0) return false; + if (elementClassName == className || + elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) + return true; + return false; + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).add(className); + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element).remove(className); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className); + return element; + }, + + observe: function() { + Event.observe.apply(Event, arguments); + return $A(arguments).first(); + }, + + stopObserving: function() { + Event.stopObserving.apply(Event, arguments); + return $A(arguments).first(); + }, + + // removes whitespace-only text node children + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + while (element = element.parentNode) + if (element == ancestor) return true; + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Position.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value) { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles, camelized) { + element = $(element); + var elementStyle = element.style; + + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]) + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (elementStyle.styleFloat === undefined ? 'cssFloat' : 'styleFloat') : + (camelized ? property : property.camelize())] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + getDimensions: function(element) { + element = $(element); + var display = $(element).getStyle('display'); + if (display != 'none' && display != null) // Safari bug + return {width: element.offsetWidth, height: element.offsetHeight}; + + // All *Width and *Height properties give 0 on elements with display none, + // so enable the element temporarily + var els = element.style; + var originalVisibility = els.visibility; + var originalPosition = els.position; + var originalDisplay = els.display; + els.visibility = 'hidden'; + els.position = 'absolute'; + els.display = 'block'; + var originalWidth = element.clientWidth; + var originalHeight = element.clientHeight; + els.display = originalDisplay; + els.position = originalPosition; + els.visibility = originalVisibility; + return {width: originalWidth, height: originalHeight}; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + // Opera returns the offset relative to the positioning context, when an + // element is position relative but top and left have not been defined + if (window.opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = element.style.overflow || 'auto'; + if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + } +}; + +Object.extend(Element.Methods, { + childOf: Element.Methods.descendantOf, + childElements: Element.Methods.immediateDescendants +}); + +if (Prototype.Browser.Opera) { + Element.Methods._getStyle = Element.Methods.getStyle; + Element.Methods.getStyle = function(element, style) { + switch(style) { + case 'left': + case 'top': + case 'right': + case 'bottom': + if (Element._getStyle(element, 'position') == 'static') return null; + default: return Element._getStyle(element, style); + } + }; +} +else if (Prototype.Browser.IE) { + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset'+style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + element = $(element); + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + style.filter = filter.replace(/alpha\([^\)]*\)/gi,''); + return element; + } else if (value < 0.00001) value = 0; + style.filter = filter.replace(/alpha\([^\)]*\)/gi, '') + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + // IE is missing .innerHTML support for TABLE-related elements + Element.Methods.update = function(element, html) { + element = $(element); + html = typeof html == 'undefined' ? '' : html.toString(); + var tagName = element.tagName.toUpperCase(); + if (['THEAD','TBODY','TR','TD'].include(tagName)) { + var div = document.createElement('div'); + switch (tagName) { + case 'THEAD': + case 'TBODY': + div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>'; + depth = 2; + break; + case 'TR': + div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>'; + depth = 3; + break; + case 'TD': + div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>'; + 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 = '<table><tbody>' + this.content + '</tbody></table>'; + 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 "#<Selector:" + this.expression.inspect() + ">"; + } +}; + +Object.extend(Selector, { + _cache: {}, + + xpath: { + descendant: "//*", + child: "/*", + adjacent: "/following-sibling::*[1]", + laterSibling: '/following-sibling::*', + tagName: function(m) { + if (m[1] == '*') return ''; + return "[local-name()='" + m[1].toLowerCase() + + "' or local-name()='" + m[1].toUpperCase() + "']"; + }, + className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", + id: "[@id='#{1}']", + attrPresence: "[@#{1}]", + attr: function(m) { + m[3] = m[5] || m[6]; + return new Template(Selector.xpath.operators[m[2]]).evaluate(m); + }, + pseudo: function(m) { + var h = Selector.xpath.pseudos[m[1]]; + if (!h) return ''; + if (typeof h === 'function') return h(m); + return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); + }, + operators: { + '=': "[@#{1}='#{3}']", + '!=': "[@#{1}!='#{3}']", + '^=': "[starts-with(@#{1}, '#{3}')]", + '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", + '*=': "[contains(@#{1}, '#{3}')]", + '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", + '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" + }, + pseudos: { + 'first-child': '[not(preceding-sibling::*)]', + 'last-child': '[not(following-sibling::*)]', + 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', + 'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]", + 'checked': "[@checked]", + 'disabled': "[@disabled]", + 'enabled': "[not(@disabled)]", + 'not': function(m) { + var e = m[6], p = Selector.patterns, + x = Selector.xpath, le, m, v; + + var exclusion = []; + while (e && le != e && (/\S/).test(e)) { + le = e; + for (var i in p) { + if (m = e.match(p[i])) { + v = typeof x[i] == 'function' ? x[i](m) : new Template(x[i]).evaluate(m); + exclusion.push("(" + v.substring(1, v.length - 1) + ")"); + e = e.replace(m[0], ''); + break; + } + } + } + return "[not(" + exclusion.join(" and ") + ")]"; + }, + 'nth-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); + }, + 'nth-last-child': function(m) { + return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); + }, + 'nth-of-type': function(m) { + return Selector.xpath.pseudos.nth("position() ", m); + }, + 'nth-last-of-type': function(m) { + return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); + }, + 'first-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); + }, + 'last-of-type': function(m) { + m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); + }, + 'only-of-type': function(m) { + var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); + }, + nth: function(fragment, m) { + var mm, formula = m[6], predicate; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + if (mm = formula.match(/^(\d+)$/)) // digit only + return '[' + fragment + "= " + mm[1] + ']'; + if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (mm[1] == "-") mm[1] = -1; + var a = mm[1] ? Number(mm[1]) : 1; + var b = mm[2] ? Number(mm[2]) : 0; + predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + + "((#{fragment} - #{b}) div #{a} >= 0)]"; + return new Template(predicate).evaluate({ + fragment: fragment, a: a, b: b }); + } + } + } + }, + + criteria: { + tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', + className: 'n = h.className(n, r, "#{1}", c); c = false;', + id: 'n = h.id(n, r, "#{1}", c); c = false;', + attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;', + attr: function(m) { + m[3] = (m[5] || m[6]); + return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m); + }, + pseudo: function(m) { + if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); + return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); + }, + descendant: 'c = "descendant";', + child: 'c = "child";', + adjacent: 'c = "adjacent";', + laterSibling: 'c = "laterSibling";' + }, + + patterns: { + // combinators must be listed first + // (and descendant needs to be last combinator) + laterSibling: /^\s*~\s*/, + child: /^\s*>\s*/, + adjacent: /^\s*\+\s*/, + descendant: /^\s/, + + // selectors follow + tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, + id: /^#([\w\-\*]+)(\b|$)/, + className: /^\.([\w\-\*]+)(\b|$)/, + pseudo: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|\s|(?=:))/, + attrPresence: /^\[([\w]+)\]/, + attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\]]*?)\4|([^'"][^\]]*?)))?\]/ + }, + + handlers: { + // UTILITY FUNCTIONS + // joins two collections + concat: function(a, b) { + for (var i = 0, node; node = b[i]; i++) + a.push(node); + return a; + }, + + // marks an array of nodes for counting + mark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._counted = true; + return nodes; + }, + + unmark: function(nodes) { + for (var i = 0, node; node = nodes[i]; i++) + node._counted = undefined; + return nodes; + }, + + // mark each child node with its position (for nth calls) + // "ofType" flag indicates whether we're indexing for nth-of-type + // rather than nth-child + index: function(parentNode, reverse, ofType) { + parentNode._counted = true; + if (reverse) { + for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { + node = nodes[i]; + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; + } + } else { + for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) + if (node.nodeType == 1 && (!ofType || node._counted)) node.nodeIndex = j++; + } + }, + + // filters out duplicates and extends all nodes + unique: function(nodes) { + if (nodes.length == 0) return nodes; + var results = [], n; + for (var i = 0, l = nodes.length; i < l; i++) + if (!(n = nodes[i])._counted) { + n._counted = true; + results.push(Element.extend(n)); + } + return Selector.handlers.unmark(results); + }, + + // COMBINATOR FUNCTIONS + descendant: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName('*')); + return results; + }, + + child: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) { + for (var j = 0, children = [], child; child = node.childNodes[j]; j++) + if (child.nodeType == 1 && child.tagName != '!') results.push(child); + } + return results; + }, + + adjacent: function(nodes) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + var next = this.nextElementSibling(node); + if (next) results.push(next); + } + return results; + }, + + laterSibling: function(nodes) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + h.concat(results, Element.nextSiblings(node)); + return results; + }, + + nextElementSibling: function(node) { + while (node = node.nextSibling) + if (node.nodeType == 1) return node; + return null; + }, + + previousElementSibling: function(node) { + while (node = node.previousSibling) + if (node.nodeType == 1) return node; + return null; + }, + + // TOKEN FUNCTIONS + tagName: function(nodes, root, tagName, combinator) { + tagName = tagName.toUpperCase(); + var results = [], h = Selector.handlers; + if (nodes) { + if (combinator) { + // fastlane for ordinary descendant combinators + if (combinator == "descendant") { + for (var i = 0, node; node = nodes[i]; i++) + h.concat(results, node.getElementsByTagName(tagName)); + return results; + } else nodes = this[combinator](nodes); + if (tagName == "*") return nodes; + } + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName.toUpperCase() == tagName) results.push(node); + return results; + } else return root.getElementsByTagName(tagName); + }, + + id: function(nodes, root, id, combinator) { + var targetNode = $(id), h = Selector.handlers; + if (!nodes && root == document) return targetNode ? [targetNode] : []; + if (nodes) { + if (combinator) { + if (combinator == 'child') { + for (var i = 0, node; node = nodes[i]; i++) + if (targetNode.parentNode == node) return [targetNode]; + } else if (combinator == 'descendant') { + for (var i = 0, node; node = nodes[i]; i++) + if (Element.descendantOf(targetNode, node)) return [targetNode]; + } else if (combinator == 'adjacent') { + for (var i = 0, node; node = nodes[i]; i++) + if (Selector.handlers.previousElementSibling(targetNode) == node) + return [targetNode]; + } else nodes = h[combinator](nodes); + } + for (var i = 0, node; node = nodes[i]; i++) + if (node == targetNode) return [targetNode]; + return []; + } + return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; + }, + + className: function(nodes, root, className, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + return Selector.handlers.byClassName(nodes, root, className); + }, + + byClassName: function(nodes, root, className) { + if (!nodes) nodes = Selector.handlers.descendant([root]); + var needle = ' ' + className + ' '; + for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { + nodeClassName = node.className; + if (nodeClassName.length == 0) continue; + if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) + results.push(node); + } + return results; + }, + + attrPresence: function(nodes, root, attr) { + var results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (Element.hasAttribute(node, attr)) results.push(node); + return results; + }, + + attr: function(nodes, root, attr, value, operator) { + if (!nodes) nodes = root.getElementsByTagName("*"); + var handler = Selector.operators[operator], results = []; + for (var i = 0, node; node = nodes[i]; i++) { + var nodeValue = Element.readAttribute(node, attr); + if (nodeValue === null) continue; + if (handler(nodeValue, value)) results.push(node); + } + return results; + }, + + pseudo: function(nodes, name, value, root, combinator) { + if (nodes && combinator) nodes = this[combinator](nodes); + if (!nodes) nodes = root.getElementsByTagName("*"); + return Selector.pseudos[name](nodes, value, root); + } + }, + + pseudos: { + 'first-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.previousElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'last-child': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + if (Selector.handlers.nextElementSibling(node)) continue; + results.push(node); + } + return results; + }, + 'only-child': function(nodes, value, root) { + var h = Selector.handlers; + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) + results.push(node); + return results; + }, + 'nth-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root); + }, + 'nth-last-child': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true); + }, + 'nth-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, false, true); + }, + 'nth-last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, formula, root, true, true); + }, + 'first-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, false, true); + }, + 'last-of-type': function(nodes, formula, root) { + return Selector.pseudos.nth(nodes, "1", root, true, true); + }, + 'only-of-type': function(nodes, formula, root) { + var p = Selector.pseudos; + return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); + }, + + // handles the an+b logic + getIndices: function(a, b, total) { + if (a == 0) return b > 0 ? [b] : []; + return $R(1, total).inject([], function(memo, i) { + if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); + return memo; + }); + }, + + // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type + nth: function(nodes, formula, root, reverse, ofType) { + if (nodes.length == 0) return []; + if (formula == 'even') formula = '2n+0'; + if (formula == 'odd') formula = '2n+1'; + var h = Selector.handlers, results = [], indexed = [], m; + h.mark(nodes); + for (var i = 0, node; node = nodes[i]; i++) { + if (!node.parentNode._counted) { + h.index(node.parentNode, reverse, ofType); + indexed.push(node.parentNode); + } + } + if (formula.match(/^\d+$/)) { // just a number + formula = Number(formula); + for (var i = 0, node; node = nodes[i]; i++) + if (node.nodeIndex == formula) results.push(node); + } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b + if (m[1] == "-") m[1] = -1; + var a = m[1] ? Number(m[1]) : 1; + var b = m[2] ? Number(m[2]) : 0; + var indices = Selector.pseudos.getIndices(a, b, nodes.length); + for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { + for (var j = 0; j < l; j++) + if (node.nodeIndex == indices[j]) results.push(node); + } + } + h.unmark(nodes); + h.unmark(indexed); + return results; + }, + + 'empty': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) { + // IE treats comments as element nodes + if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue; + results.push(node); + } + return results; + }, + + 'not': function(nodes, selector, root) { + var h = Selector.handlers, selectorType, m; + var exclusions = new Selector(selector).findElements(root); + h.mark(exclusions); + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node._counted) results.push(node); + h.unmark(exclusions); + return results; + }, + + 'enabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (!node.disabled) results.push(node); + return results; + }, + + 'disabled': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.disabled) results.push(node); + return results; + }, + + 'checked': function(nodes, value, root) { + for (var i = 0, results = [], node; node = nodes[i]; i++) + if (node.checked) results.push(node); + return results; + } + }, + + operators: { + '=': function(nv, v) { return nv == v; }, + '!=': function(nv, v) { return nv != v; }, + '^=': function(nv, v) { return nv.startsWith(v); }, + '$=': function(nv, v) { return nv.endsWith(v); }, + '*=': function(nv, v) { return nv.include(v); }, + '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, + '|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); } + }, + + matchElements: function(elements, expression) { + var matches = new Selector(expression).findElements(), h = Selector.handlers; + h.mark(matches); + for (var i = 0, results = [], element; element = elements[i]; i++) + if (element._counted) results.push(element); + h.unmark(matches); + return results; + }, + + findElement: function(elements, expression, index) { + if (typeof expression == 'number') { + index = expression; expression = false; + } + return Selector.matchElements(elements, expression || '*')[index || 0]; + }, + + findChildElements: function(element, expressions) { + var exprs = expressions.join(','), expressions = []; + exprs.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { + expressions.push(m[1].strip()); + }); + var results = [], h = Selector.handlers; + for (var i = 0, l = expressions.length, selector; i < l; i++) { + selector = new Selector(expressions[i].strip()); + h.concat(results, selector.findElements(element)); + } + return (l > 1) ? h.unique(results) : results; + } +}); + +function $$() { + return Selector.findChildElements(document, $A(arguments)); +} +var Form = { + reset: function(form) { + $(form).reset(); + return form; + }, + + serializeElements: function(elements, getHash) { + var data = elements.inject({}, function(result, element) { + if (!element.disabled && element.name) { + var key = element.name, value = $(element).getValue(); + if (value != null) { + if (key in result) { + if (result[key].constructor != Array) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return getHash ? data : Hash.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, getHash) { + return Form.serializeElements(Form.getElements(form), getHash); + }, + + getElements: function(form) { + return $A($(form).getElementsByTagName('*')).inject([], + function(elements, child) { + if (Form.Element.Serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + } + ); + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + return $(form).getElements().find(function(element) { + return element.type != 'hidden' && !element.disabled && + ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || {}); + + var params = options.parameters; + options.parameters = form.serialize(true); + + if (params) { + if (typeof params == 'string') params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(form.readAttribute('action'), options); + } +} + +/*--------------------------------------------------------------------------*/ + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +} + +Form.Element.Methods = { + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = {}; + pair[element.name] = value; + return Hash.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !['button', 'reset', 'submit'].include(element.type))) + element.select(); + } catch (e) {} + return element; + }, + + disable: function(element) { + element = $(element); + element.blur(); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +} + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element); + default: + return Form.Element.Serializers.textarea(element); + } + }, + + inputSelector: function(element) { + return element.checked ? element.value : null; + }, + + textarea: function(element) { + return element.value; + }, + + select: function(element) { + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + // extend element because hasAttribute may not be native + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +} + +/*--------------------------------------------------------------------------*/ + +Abstract.TimedObserver = function() {} +Abstract.TimedObserver.prototype = { + initialize: function(element, frequency, callback) { + this.frequency = frequency; + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + this.registerCallback(); + }, + + registerCallback: function() { + setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + onTimerEvent: function() { + var value = this.getValue(); + var changed = ('string' == typeof this.lastValue && 'string' == typeof value + ? this.lastValue != value : String(this.lastValue) != String(value)); + if (changed) { + this.callback(this.element, value); + this.lastValue = value; + } + } +} + +Form.Element.Observer = Class.create(); +Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(); +Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = function() {} +Abstract.EventObserver.prototype = { + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback.bind(this)); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +} + +Form.Element.EventObserver = Class.create(); +Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(); +Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { + getValue: function() { + return Form.serialize(this.element); + } +}); +if (!window.Event) { + var Event = new Object(); +} + +Object.extend(Event, { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + + element: function(event) { + return $(event.target || event.srcElement); + }, + + isLeftClick: function(event) { + return (((event.which) && (event.which == 1)) || + ((event.button) && (event.button == 1))); + }, + + pointerX: function(event) { + return event.pageX || (event.clientX + + (document.documentElement.scrollLeft || document.body.scrollLeft)); + }, + + pointerY: function(event) { + return event.pageY || (event.clientY + + (document.documentElement.scrollTop || document.body.scrollTop)); + }, + + stop: function(event) { + if (event.preventDefault) { + event.preventDefault(); + event.stopPropagation(); + } else { + event.returnValue = false; + event.cancelBubble = true; + } + }, + + // find the first node with the given tagName, starting from the + // node the event was triggered on; traverses the DOM upwards + findElement: function(event, tagName) { + var element = Event.element(event); + while (element.parentNode && (!element.tagName || + (element.tagName.toUpperCase() != tagName.toUpperCase()))) + element = element.parentNode; + return element; + }, + + observers: false, + + _observeAndCache: function(element, name, observer, useCapture) { + if (!this.observers) this.observers = []; + if (element.addEventListener) { + this.observers.push([element, name, observer, useCapture]); + element.addEventListener(name, observer, useCapture); + } else if (element.attachEvent) { + this.observers.push([element, name, observer, useCapture]); + element.attachEvent('on' + name, observer); + } + }, + + unloadCache: function() { + if (!Event.observers) return; + for (var i = 0, length = Event.observers.length; i < length; i++) { + Event.stopObserving.apply(this, Event.observers[i]); + Event.observers[i][0] = null; + } + Event.observers = false; + }, + + observe: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (Prototype.Browser.WebKit || element.attachEvent)) + name = 'keydown'; + + Event._observeAndCache(element, name, observer, useCapture); + }, + + stopObserving: function(element, name, observer, useCapture) { + element = $(element); + useCapture = useCapture || false; + + if (name == 'keypress' && + (Prototype.Browser.WebKit || element.attachEvent)) + name = 'keydown'; + + if (element.removeEventListener) { + element.removeEventListener(name, observer, useCapture); + } else if (element.detachEvent) { + try { + element.detachEvent('on' + name, observer); + } catch (e) {} + } + } +}); + +/* prevent memory leaks in IE */ +if (Prototype.Browser.IE) + Event.observe(window, 'unload', Event.unloadCache, false); +var Position = { + // set to true if needed, warning: firefox performance problems + // NOT neeeded for page scrolling, only if draggable contained in + // scrollable elements + includeScrollOffsets: false, + + // must be called before calling withinIncludingScrolloffset, every time the + // page is scrolled + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + realOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return [valueL, valueT]; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return [valueL, valueT]; + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if(element.tagName=='BODY') break; + var p = Element.getStyle(element, 'position'); + if (p == 'relative' || p == 'absolute') break; + } + } while (element); + return [valueL, valueT]; + }, + + offsetParent: function(element) { + if (element.offsetParent) return element.offsetParent; + if (element == document.body) return element; + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return element; + + return document.body; + }, + + // caches x/y coordinate pair to use with overlap + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = this.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = this.realOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = this.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + // within must be called directly before + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + page: function(forElement) { + var valueT = 0, valueL = 0; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + // Safari fix + if (element.offsetParent == document.body) + if (Element.getStyle(element,'position')=='absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!window.opera || element.tagName=='BODY') { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return [valueL, valueT]; + }, + + clone: function(source, target) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || {}) + + // find page position of source + source = $(source); + var p = Position.page(source); + + // find coordinate system to use + target = $(target); + var delta = [0, 0]; + var parent = null; + // delta [0,0] will do fine with position: fixed elements, + // position:absolute needs offsetParent deltas + if (Element.getStyle(target,'position') == 'absolute') { + parent = Position.offsetParent(target); + delta = Position.page(parent); + } + + // correct by body offsets (fixes Safari) + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + // set position + if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if(options.setWidth) target.style.width = source.offsetWidth + 'px'; + if(options.setHeight) target.style.height = source.offsetHeight + 'px'; + }, + + absolutize: function(element) { + element = $(element); + if (element.style.position == 'absolute') return; + Position.prepare(); + + var offsets = Position.positionedOffset(element); + var top = offsets[1]; + var left = offsets[0]; + var width = element.clientWidth; + var height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + }, + + relativize: function(element) { + element = $(element); + if (element.style.position == 'relative') return; + Position.prepare(); + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); + var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + } +} + +// Safari returns margins on body which is incorrect if the child is absolutely +// positioned. For performance reasons, redefine Position.cumulativeOffset for +// KHTML/WebKit only. +if (Prototype.Browser.WebKit) { + Position.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return [valueL, valueT]; + } +} + +Element.addMethods();
\ No newline at end of file diff --git a/html/xo-color.xml b/html/xo-color.xml new file mode 100644 index 0000000..7cab5ef --- /dev/null +++ b/html/xo-color.xml @@ -0,0 +1,964 @@ +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <title>change the XO colors and shape</title> + +<!-- +Author: Walter Bender (walter@laptop.org) +(CC-PD) Public Domain (do what you want to do...) + +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [ + <!ENTITY ns_svg "http://www.w3.org/2000/svg"> + <!ENTITY ns_xlink "http://www.w3.org/1999/xlink"> +]> +--> + + + + +// SVG version of OLPC XO man color changer and shape shifter +// Created by: Walter Bender (walter@laptop.org) on 27 January 2007 +// Last modified by: Walter Bender (walter@laptop.org) on 28 June 2007 +// Color tool designed in memory of: Nat Jacobson +// ajax hooks: Erik Blankinship (erikb@mediamods.com) on 15 August 2007 + +<script type="text/javascript"> +<![CDATA[ + var fillcolors = [ + // red, orange, yellow, green, blue, purple + "rgb(255,43,52)", "rgb(255,143,0)", "rgb(248,232,0)", "rgb(0,234,17)", "rgb(0,160,255)", "rgb(172,50,255)" + ]; + + + var strokecolors = [ + // M A+ C- C C+ A- + // dark fill + // red + "rgb(178,0,8)", "rgb(154,82,0)", "rgb(128,117,0)", "rgb(0,128,9)", "rgb(0,88,140)", "rgb(94,0,140)", + // orange + "rgb(154,82,0)", "rgb(128,117,0)", "rgb(0,128,9)", "rgb(0,88,140)", "rgb(94,0,140)", "rgb(178,0,8)", + // yellow + "rgb(128,117,0)", "rgb(0,128,9)", "rgb(0,88,140)", "rgb(94,0,140)", "rgb(178,0,8)", "rgb(154,82,0)", + // green + "rgb(0,128,9)", "rgb(0,88,140)", "rgb(94,0,140)", "rgb(178,0,8)", "rgb(154,82,0)", "rgb(128,117,0)", + // blue + "rgb(0,88,140)", "rgb(94,0,140)", "rgb(178,0,8)", "rgb(154,82,0)", "rgb(128,117,0)", "rgb(0,128,9)", + // purple + "rgb(94,0,140)", "rgb(178,0,8)", "rgb(154,82,0)", "rgb(128,117,0)", "rgb(0,128,9)", "rgb(0,88,140)", + + // medium fill + // red + "rgb(230,0,10)", "rgb(255,143,0)", "rgb(190,158,0)", "rgb(0,178,13)", "rgb(0,95,228)", "rgb(127,0,191)", + // orange + "rgb(201,126,0)", "rgb(190,158,0)", "rgb(0,178,13)", "rgb(0,95,228)", "rgb(167,0,255)", "rgb(255,43,52)", + // yellow + "rgb(190,158,0)", "rgb(0,234,17)", "rgb(0,160,255)", "rgb(172,50,255)", "rgb(255,43,52)", "rgb(255,143,0)", + // green + "rgb(0,178,13)", "rgb(0,95,228)", "rgb(127,0,191)", "rgb(255,43,52)", "rgb(255,143,0)", "rgb(190,158,0)", + // blue + "rgb(0,95,228)", "rgb(153,0,230)", "rgb(255,43,52)", "rgb(255,143,0)", "rgb(190,158,0)", "rgb(0,178,13)", + // purple + "rgb(127,0,191)", "rgb(255,43,52)", "rgb(255,143,0)", "rgb(190,158,0)", "rgb(0,178,13)", "rgb(0,95,228)", + + // light fill + // red + "rgb(255,173,206)", "rgb(255,193,105)", "rgb(248,232,0)", "rgb(139,255,122)", "rgb(188,205,255)", "rgb(209,163,255)", + // orange + "rgb(255,193,105)", "rgb(248,232,0)", "rgb(139,255,122)", "rgb(188,205,255)", "rgb(209,163,255)", "rgb(255,173,206)", + // yellow + "rgb(255,250,0)", "rgb(139,255,122)", "rgb(188,206,255)", "rgb(209,163,255)", "rgb(255,173,206)", "rgb(255,193,105)", + // green + "rgb(139,255,122)", "rgb(188,205,255)", "rgb(209,163,255)", "rgb(255,173,206)", "rgb(255,193,105)", "rgb(248,232,0)", + // blue + "rgb(188,205,255)", "rgb(209,163,255)", "rgb(255,173,206)", "rgb(255,193,105)", "rgb(248,232,0)", "rgb(139,255,122)", + // purple + "rgb(209,163,255)", "rgb(255,173,206)", "rgb(255,193,105)", "rgb(248,232,0)", "rgb(139,255,122)", "rgb(188,205,255)" + ]; + +// stroke values +var strokeLight = 2; +var strokeMedium = 1; +var strokeDark = 0; +var strokeCurrent = strokeMedium; + +// +var flip = 0; +var square = 0; +var xoff = 0; +var yoff = 2; + +// color variables +var strokeH = 0; +var fillH = 0; + +// Sugar stuff +// gridbox centers +var grid = [37.5, 112.5, 187.5, 262.5, 337.5, 412.5, 485.5, 562.5, 637.5, 712.5, 785.5, 862.5, 937.5, 1012.5, 1087.5, 1162.5]; +var radius = 22.5; +var strokeW = 9.5; + +var circlex1 = [0,1,2,3,4,5]; +var circley1 = [0,1,2,3,4,5]; +var circlex2 = [0,1,2,3,4,5]; +var circley2 = [0,1,2,3,4,5]; +var circlex3 = [0,1,2,3,4,5]; +var circley3 = [0,1,2,3,4,5]; +var circlex4 = [0,1,2,3,4,5]; +var circley4 = [0,1,2,3,4,5]; +var circlex5 = [0,1,2,3,4,5]; +var circley5 = [0,1,2,3,4,5]; +var circlex6 = [0,1,2,3,4,5]; +var circley6 = [0,1,2,3,4,5]; + +// Stuff needed for moving the xo man end and knot points +var xoL1X1=554.5; +var xoL1Y1=448; +var xoL1X2=645.5; +var xoL1Y2=357; +var xoL1K1X=580; +var xoL1K1Y=420.5; +var xoL1K2X=620; +var xoL1K2Y=380.5; +var xoL2X1=554.5; +var xoL2Y1=357; +var xoL2X2=645.5; +var xoL2Y2=448; +var xoL2K1X=580; +var xoL2K1Y=380.5; +var xoL2K2X=620; +var xoL2K2Y=420.5; +var xoCX=600; +var xoCY=318.5; +var xoL1X1Reset=554.5; +var xoL1Y1Reset=448; +var xoL1X2Reset=645.5; +var xoL1Y2Reset=357; +var xoL1K1XReset=580; +var xoL1K1YReset=420.5; +var xoL1K2XReset=620; +var xoL1K2YReset=380.5; +var xoL2X1Reset=554.5; +var xoL2Y1Reset=357; +var xoL2X2Reset=645.5; +var xoL2Y2Reset=448; +var xoL2K1XReset=580; +var xoL2K1YReset=380.5; +var xoL2K2XReset=620; +var xoL2K2YReset=420.5; +var xoCXReset=600; +var xoCYReset=318.5; +var xoCenterX = (xoL1X1+xoL1X2)/2; +var xoCenterY = (xoL1Y1+xoL1Y2)/2; +var moveOn=0; +var moveID=""; + +// calculate circle coordinates +function sincos (evt) { +var a; +var i; +var r1=75; +var r2=245; +var cx = [0,1,2,3,4,5]; +var cy = [0,1,2,3,4,5]; + + + for( i=0; i< 6; i++ ) + { + a = 1.05; + a *= i; + cx[i] = 600-r2*Math.sin(a); + cy[i] = 375-r2*Math.cos(a); + } + + for( i=0; i< 6; i++ ) + { + a = 1.05; + a *= i; + circlex1[i] = r1*Math.sin(a)+cx[0]; + circley1[i] = r1*Math.cos(a)+cy[0]; + circlex2[i] = r1*Math.sin(a)+cx[1]; + circley2[i] = r1*Math.cos(a)+cy[1]; + circlex3[i] = r1*Math.sin(a)+cx[2]; + circley3[i] = r1*Math.cos(a)+cy[2]; + circlex4[i] = r1*Math.sin(a)+cx[3]; + circley4[i] = r1*Math.cos(a)+cy[3]; + circlex5[i] = r1*Math.sin(a)+cx[4]; + circley5[i] = r1*Math.cos(a)+cy[4]; + circlex6[i] = r1*Math.sin(a)+cx[5]; + circley6[i] = r1*Math.cos(a)+cy[5]; + } +} + +function positionButton(evt,id,x,y) { + e = evt.target.ownerDocument.getElementById(id); + e.setAttribute("cx",grid[x]); + e.setAttribute("cy",grid[y]); +} + +function positionButtonOffset(evt,id,x,y) { + if( y < 0 ) { y+=6; } + e = evt.target.ownerDocument.getElementById(id); + e.setAttribute("cx",grid[x+xoff]); + e.setAttribute("cy",grid[y+yoff]); +} + +function positionCircle(evt,id,r,a) { + if( a > -1 && a < 6 ) + { + e = evt.target.ownerDocument.getElementById(id); + switch (r) + { + case 0: + e.setAttribute("cx",circlex1[a]); + e.setAttribute("cy",circley1[a]); + break; + case 1: + e.setAttribute("cx",circlex2[a]); + e.setAttribute("cy",circley2[a]); + break; + case 2: + e.setAttribute("cx",circlex3[a]); + e.setAttribute("cy",circley3[a]); + break; + case 3: + e.setAttribute("cx",circlex4[a]); + e.setAttribute("cy",circley4[a]); + break; + case 4: + e.setAttribute("cx",circlex5[a]); + e.setAttribute("cy",circley5[a]); + break; + case 5: + e.setAttribute("cx",circlex6[a]); + e.setAttribute("cy",circley6[a]); + break; + default : + } + } +} + +function buttonInit(evt) { + if( square == 1 ) + { + buttonInitSquare(evt); + } else { + buttonInitHex(evt); + } + +} + +// scale and position buttons in circles +function buttonInitHex(evt) { + + positionCircle(evt,"X",0,0); + + positionCircle(evt,"R",0,0); + positionCircle(evt,"YR",1,1); + positionCircle(evt,"Y",2,2); + positionCircle(evt,"G",3,3); + positionCircle(evt,"B",4,4); + positionCircle(evt,"P",5,5); + + positionCircle(evt,"RAm",0,1); + positionCircle(evt,"YRAm",1,2); + positionCircle(evt,"YAm",2,3); + positionCircle(evt,"GAm",3,4); + positionCircle(evt,"BAm",4,5); + positionCircle(evt,"PAm",5,0); + + positionCircle(evt,"RCp",0,2); + positionCircle(evt,"YRCp",1,3); + positionCircle(evt,"YCp",2,4); + positionCircle(evt,"GCp",3,5); + positionCircle(evt,"BCp",4,0); + positionCircle(evt,"PCp",5,1); + + positionCircle(evt,"RC",0,3); + positionCircle(evt,"YRC",1,4); + positionCircle(evt,"YC",2,5); + positionCircle(evt,"GC",3,0); + positionCircle(evt,"BC",4,1); + positionCircle(evt,"PC",5,2); + + positionCircle(evt,"RCm",0,4); + positionCircle(evt,"YRCm",1,5); + positionCircle(evt,"YCm",2,0); + positionCircle(evt,"GCm",3,1); + positionCircle(evt,"BCm",4,2); + positionCircle(evt,"PCm",5,3); + + positionCircle(evt,"RAp",0,5); + positionCircle(evt,"YRAp",1,0); + positionCircle(evt,"YAp",2,1); + positionCircle(evt,"GAp",3,2); + positionCircle(evt,"BAp",4,3); + positionCircle(evt,"PAp",5,4); +} + +// scale and position buttons on grid (col,row) +function buttonInitSquare(evt) { + + positionButtonOffset(evt,"X",0,0); + + positionButtonOffset(evt, "R",0,0); + positionButtonOffset(evt, "YR",5,5); + positionButtonOffset(evt, "Y",4,4); + positionButtonOffset(evt, "G",3,3); + positionButtonOffset(evt, "B",2,2); + positionButtonOffset(evt, "P",1,1); + + positionButtonOffset(evt, "RAm",0,1); + positionButtonOffset(evt,"YRAm",5,0); + positionButtonOffset(evt, "YAm",4,5); + positionButtonOffset(evt, "GAm",3,4); + positionButtonOffset(evt, "BAm",2,3); + positionButtonOffset(evt, "PAm",1,2); + + positionButtonOffset(evt, "RCp",0,2); + positionButtonOffset(evt,"YRCp",5,1); + positionButtonOffset(evt, "YCp",4,0); + positionButtonOffset(evt, "GCp",3,5); + positionButtonOffset(evt, "BCp",2,4); + positionButtonOffset(evt, "PCp",1,3); + + positionButtonOffset(evt, "RC",0,3); + positionButtonOffset(evt, "YRC",5,2); + positionButtonOffset(evt, "YC",4,1); + positionButtonOffset(evt, "GC",3,0); + positionButtonOffset(evt, "BC",2,5); + positionButtonOffset(evt, "PC",1,4); + + positionButtonOffset(evt, "RCm",0,4); + positionButtonOffset(evt,"YRCm",5,3); + positionButtonOffset(evt, "YCm",4,2); + positionButtonOffset(evt, "GCm",3,1); + positionButtonOffset(evt, "BCm",2,0); + positionButtonOffset(evt, "PCm",1,5); + + positionButtonOffset(evt, "RAp",0,5); + positionButtonOffset(evt,"YRAp",5,4); + positionButtonOffset(evt, "YAp",4,3); + positionButtonOffset(evt, "GAp",3,2); + positionButtonOffset(evt, "BAp",2,1); + positionButtonOffset(evt, "PAp",1,0); +} + +// recompute button color +// fill hue is 0,1,2,3,4,5 for r,o,y,g,b,p +// stroke hue is 0,1,2,3,4,5 for m,a+,c-,c,c+,a- plus an offset of 6*fillhue and 36*valuelevel +function colorButton(evt,id,fh,sh,sv) { +var e; + e = evt.target.ownerDocument.getElementById(id); + if( flip == 0 ) + { + e.setAttribute("stroke",strokecolors[fh*6+sv*36+sh]); + e.setAttribute("fill",fillcolors[fh]); + } else { + e.setAttribute("fill",strokecolors[fh*6+sv*36+sh]); + e.setAttribute("stroke",fillcolors[fh]); + } +} + +// update XO man and all buttons based on current hue and value +function colorUpdate(evt) { +var e; +var tmp; + + // update XO Man + colorButton(evt,"Circle",fillH,strokeH,strokeCurrent); + colorButton(evt,"iconCircle",fillH,strokeH,strokeCurrent); + if( flip == 0 ) + { + e = evt.target.ownerDocument.getElementById("Line1"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("Line2"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("Fill1"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("Fill2"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("iconLine1"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("iconLine2"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("iconFill1"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("iconFill2"); + e.setAttribute("stroke",fillcolors[fillH]); + } else { + e = evt.target.ownerDocument.getElementById("Line1"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("Line2"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("Fill1"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("Fill2"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("iconLine1"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("iconLine2"); + e.setAttribute("stroke",fillcolors[fillH]); + e = evt.target.ownerDocument.getElementById("iconFill1"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + e = evt.target.ownerDocument.getElementById("iconFill2"); + e.setAttribute("stroke",strokecolors[fillH*6+strokeCurrent*36+strokeH]); + } + + tmp = flip; + flip = 0; + colorButton(evt,"vd",fillH,strokeH,strokeDark); + colorButton(evt,"vm",fillH,strokeH,strokeMedium); + colorButton(evt,"vl",fillH,strokeH,strokeLight); + flip = 1; + colorButton(evt,"vdf",fillH,strokeH,strokeDark); + colorButton(evt,"vmf",fillH,strokeH,strokeMedium); + flip = tmp; + + colorButton(evt,"R",0,0,strokeCurrent); + colorButton(evt,"YR",1,0,strokeCurrent); + colorButton(evt,"Y",2,0,strokeCurrent); + colorButton(evt,"G",3,0,strokeCurrent); + colorButton(evt,"B",4,0,strokeCurrent); + colorButton(evt,"P",5,0,strokeCurrent); + colorButton(evt,"RAp",0,1,strokeCurrent); + colorButton(evt,"YRAp",1,1,strokeCurrent); + colorButton(evt,"YAp",2,1,strokeCurrent); + colorButton(evt,"GAp",3,1,strokeCurrent); + colorButton(evt,"BAp",4,1,strokeCurrent); + colorButton(evt,"PAp",5,1,strokeCurrent); + colorButton(evt,"RCm",0,2,strokeCurrent); + colorButton(evt,"YRCm",1,2,strokeCurrent); + colorButton(evt,"YCm",2,2,strokeCurrent); + colorButton(evt,"GCm",3,2,strokeCurrent); + colorButton(evt,"BCm",4,2,strokeCurrent); + colorButton(evt,"PCm",5,2,strokeCurrent); + colorButton(evt,"RC",0,3,strokeCurrent); + colorButton(evt,"YRC",1,3,strokeCurrent); + colorButton(evt,"YC",2,3,strokeCurrent); + colorButton(evt,"GC",3,3,strokeCurrent); + colorButton(evt,"BC",4,3,strokeCurrent); + colorButton(evt,"PC",5,3,strokeCurrent); + colorButton(evt,"RCp",0,4,strokeCurrent); + colorButton(evt,"YRCp",1,4,strokeCurrent); + colorButton(evt,"YCp",2,4,strokeCurrent); + colorButton(evt,"GCp",3,4,strokeCurrent); + colorButton(evt,"BCp",4,4,strokeCurrent); + colorButton(evt,"PCp",5,4,strokeCurrent); + colorButton(evt,"RAm",0,5,strokeCurrent); + colorButton(evt,"YRAm",1,5,strokeCurrent); + colorButton(evt,"YAm",2,5,strokeCurrent); + colorButton(evt,"GAm",3,5,strokeCurrent); + colorButton(evt,"BAm",4,5,strokeCurrent); + colorButton(evt,"PAm",5,5,strokeCurrent); + + saveXo() +} + +function saveXo( ) +{ + var upXoDude = document.getElementById('upXo'); + var xos = ""; + for (var i=0; i<upXoDude.childNodes.length; i++) + { xoi = upXoDude.childNodes[i]; + if (xoi.nodeType == 1) + { xos = xos + "<" + xoi.nodeName + " "; + for (var j=0; j<xoi.attributes.length; j++) + { xoj = xoi.attributes[j]; + xos = xos + xoj.nodeName + "=\"" + xoj.nodeValue + "\" "; + } + xos = xos+ "/>"; + } + } + + //alert( xos ); + new Ajax.Request( 'saveXo', {method:'get', parameters:'upXo='+xos} ); +} + +// individual button functions +function updater(evt,fh,dh,a) { + fillHUndo = fillH; + fillH = fh; + strokeHUndo = strokeH; + strokeH = dh; + if( square == 1 ) + { + // a complete kludge because the order of the grid + // does not reflect the order of the delta hues + switch(fh) + { + case 0: + if( dh > 0 ) { dh = 6-dh; } + positionButtonOffset(evt,"X",0,dh); + break; + case 1: + positionButtonOffset(evt,"X",5,5-dh); + break; + case 2: + positionButtonOffset(evt,"X",4,4-dh); + break; + case 3: + positionButtonOffset(evt,"X",3,3-dh); + break; + case 4: + positionButtonOffset(evt,"X",2,2-dh); + break; + case 5: + positionButtonOffset(evt,"X",1,1-dh); + break; + } + } else { + // a kludge of a different sort fo the similar reasons as above + positionCircle(evt,"X",fh,a); + } + colorUpdate(evt); +} + +function valueDark(evt) { + strokeCurrent = strokeDark; + flip = 0; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","hidden"); + colorUpdate(evt); +} + +function valueDarkFlip(evt) { + strokeCurrent = strokeDark; + flip = 1; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","hidden"); + colorUpdate(evt); +} + +function valueMedium(evt) { + strokeCurrent = strokeMedium; + flip = 0; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","hidden"); + colorUpdate(evt); +} + +function valueMediumFlip(evt) { + strokeCurrent = strokeMedium; + flip = 1; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","hidden"); + colorUpdate(evt); +} + +function valueLight(evt) { + strokeCurrent = strokeLight; + flip = 0; + e = evt.target.ownerDocument.getElementById("bgd"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgdf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgm"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgmf"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bgl"); + e.setAttribute("visibility","visible"); + colorUpdate(evt); +} + +function hexGrid(evt) { + square = 0; + e = evt.target.ownerDocument.getElementById("bgsq"); + e.setAttribute("visibility","hidden"); + e = evt.target.ownerDocument.getElementById("bghex"); + e.setAttribute("visibility","visible"); + buttonInit(evt); +} + +function sqGrid(evt) { + square = 1; + e = evt.target.ownerDocument.getElementById("bgsq"); + e.setAttribute("visibility","visible"); + e = evt.target.ownerDocument.getElementById("bghex"); + e.setAttribute("visibility","hidden"); + buttonInit(evt); +} + +function background(evt,a) { + e = evt.target.ownerDocument.getElementById("backgroundW"); + if( a == 0 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } + e = evt.target.ownerDocument.getElementById("backgroundW"); + if( a == 0 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } + e = evt.target.ownerDocument.getElementById("backgroundL"); + if( a == 1 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } + e = evt.target.ownerDocument.getElementById("backgroundM"); + if( a == 2 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } + e = evt.target.ownerDocument.getElementById("backgroundK"); + if( a == 3 ) + { + e.setAttribute("visibility","visible"); + } else { + e.setAttribute("visibility","hidden"); + } +} + + +// the rest of these functions are for moving knot points +function showpoints(evt) +{ +var e; + + e = evt.target.ownerDocument.getElementById("L1Knot1"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL1K1X); + e.setAttribute("cy",xoL1K1Y); + e = evt.target.ownerDocument.getElementById("L1Knot2"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL1K2X); + e.setAttribute("cy",xoL1K2Y); + e = evt.target.ownerDocument.getElementById("L2Knot1"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL2K1X); + e.setAttribute("cy",xoL2K1Y); + e = evt.target.ownerDocument.getElementById("L2Knot2"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL2K2X); + e.setAttribute("cy",xoL2K2Y); + e = evt.target.ownerDocument.getElementById("L1End1"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL1X1); + e.setAttribute("cy",xoL1Y1); + e = evt.target.ownerDocument.getElementById("L2End1"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL2X1); + e.setAttribute("cy",xoL2Y1); + e = evt.target.ownerDocument.getElementById("L1End2"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL1X2); + e.setAttribute("cy",xoL1Y2); + e = evt.target.ownerDocument.getElementById("L2End2"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoL2X2); + e.setAttribute("cy",xoL2Y2); + e = evt.target.ownerDocument.getElementById("Center"); + e.setAttribute("visibility", "visible"); + e.setAttribute("cx",xoCX); + e.setAttribute("cy",xoCY); +} + +function hidepoints(evt) +{ + e = evt.target.ownerDocument.getElementById("L1Knot1"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L1Knot2"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L2Knot1"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L2Knot2"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L1End1"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L1End2"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L2End1"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("L2End2"); + e.setAttribute("visibility", "hidden"); + e = evt.target.ownerDocument.getElementById("Center"); + e.setAttribute("visibility", "hidden"); +} + +// moves are constrained by level and restricted to XO box +function move(evt) +{ +var x,y; + + if( moveOn == 1 ) + { + //bug, see: http://dev.laptop.org/ticket/1657 + x = evt.clientX; +// x = x * 1.43; + y = evt.clientY; +// y = y * 1.43; + + if( x < (xoCenterX-80) ) { x = xoCenterX-80; } + if( x > (xoCenterX+80) ) { x = xoCenterX+80; } + if( y < (xoCenterY-100) ) { y = xoCenterY-100; } + if( y > (xoCenterY+80) ) { y = xoCenterY+80; } + e = evt.target.ownerDocument.getElementById(moveID); + e.setAttribute("cx",x); + e.setAttribute("cy",y); + switch (moveID) + { + case "Center": + xoCX = x; + xoCY = y; + break; + case "L1End1": + xoL1X1 = x; + xoL1Y1 = y; + break; + case "L1End2": + xoL1X2 = x; + xoL1Y2 = y; + break; + case "L2End1": + xoL2X1 = x; + xoL2Y1 = y; + break; + case "L2End2": + xoL2X2 = x; + xoL2Y2 = y; + break; + case "L1Knot1": + xoL1K1X = x; + xoL1K1Y = y; + break; + case "L1Knot2": + xoL1K2X = x; + xoL1K2Y = y; + break; + case "L2Knot1": + xoL2K1X = x; + xoL2K1Y = y; + break; + case "L2Knot2": + xoL2K2X = x; + xoL2K2Y = y; + break; + default : + } + } +} + +function setID (evt, id) +{ + moveID = id; +} + +function startmove(evt) +{ + moveOn = 1; +} + +function stopmove(evt) +{ + moveOn = 0; + moveID = ""; + e = evt.target.ownerDocument.getElementById("Circle"); + e.setAttribute("cx",xoCX); + e.setAttribute("cy",xoCY); + e = evt.target.ownerDocument.getElementById("Line1"); + e.setAttribute("d", "M"+xoL1X1+","+xoL1Y1+" C"+xoL1K1X+","+xoL1K1Y+" "+xoL1K2X+","+xoL1K2Y+" "+xoL1X2+","+xoL1Y2); + e = evt.target.ownerDocument.getElementById("Fill1"); + e.setAttribute("d", "M"+xoL1X1+","+xoL1Y1+" C"+xoL1K1X+","+xoL1K1Y+" "+xoL1K2X+","+xoL1K2Y+" "+xoL1X2+","+xoL1Y2); + e = evt.target.ownerDocument.getElementById("Line2"); + e.setAttribute("d", "M"+xoL2X1+","+xoL2Y1+" C"+xoL2K1X+","+xoL2K1Y+" "+xoL2K2X+","+xoL2K2Y+" "+xoL2X2+","+xoL2Y2); + e = evt.target.ownerDocument.getElementById("Fill2"); + e.setAttribute("d", "M"+xoL2X1+","+xoL2Y1+" C"+xoL2K1X+","+xoL2K1Y+" "+xoL2K2X+","+xoL2K2Y+" "+xoL2X2+","+xoL2Y2); +} + +function resetXO (evt) +{ +xoL1X1=xoL1X1Reset; +xoL1Y1=xoL1Y1Reset; +xoL1X2=xoL1X2Reset; +xoL1Y2=xoL1Y2Reset; +xoL1K1X=xoL1K1XReset; +xoL1K1Y=xoL1K1YReset; +xoL1K2X=xoL1K2XReset; +xoL1K2Y=xoL1K2YReset; +xoL2X1=xoL2X1Reset; +xoL2Y1=xoL2Y1Reset; +xoL2X2=xoL2X2Reset; +xoL2Y2=xoL2Y2Reset; +xoL2K1X=xoL2K1XReset; +xoL2K1Y=xoL2K1YReset; +xoL2K2X=xoL2K2XReset; +xoL2K2Y=xoL2K2YReset; +xoCX=xoCXReset; +xoCY=xoCYReset; + + e = evt.target.ownerDocument.getElementById("Circle"); + e.setAttribute("cx",xoCX); + e.setAttribute("cy",xoCY); + e = evt.target.ownerDocument.getElementById("Line1"); + e.setAttribute("d", "M"+xoL1X1+","+xoL1Y1+" C"+xoL1K1X+","+xoL1K1Y+" "+xoL1K2X+","+xoL1K2Y+" "+xoL1X2+","+xoL1Y2); + e = evt.target.ownerDocument.getElementById("Fill1"); + e.setAttribute("d", "M"+xoL1X1+","+xoL1Y1+" C"+xoL1K1X+","+xoL1K1Y+" "+xoL1K2X+","+xoL1K2Y+" "+xoL1X2+","+xoL1Y2); + e = evt.target.ownerDocument.getElementById("Line2"); + e.setAttribute("d", "M"+xoL2X1+","+xoL2Y1+" C"+xoL2K1X+","+xoL2K1Y+" "+xoL2K2X+","+xoL2K2Y+" "+xoL2X2+","+xoL2Y2); + e = evt.target.ownerDocument.getElementById("Fill2"); + e.setAttribute("d", "M"+xoL2X1+","+xoL2Y1+" C"+xoL2K1X+","+xoL2K1Y+" "+xoL2K2X+","+xoL2K2Y+" "+xoL2X2+","+xoL2Y2); +} + +]]> +</script> +<script src="prototype.js" type="text/javascript"></script> +</head> + +<body> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www,w3,org/1999/xlink" onload="colorUpdate(evt); sincos(evt); buttonInit(evt)" viewBox="0 0 1200 900"> + + +// SVG elements +// begin backgrounds + <rect id="backgroundM" width="1200" height="900" x="0" y="0" fill="rgb(76,77,79)" stroke="rgb(76,77,79)" stroke-width="1" visibility="hidden" /> + <rect id="backgroundL" width="1200" height="900" x="0" y="0" fill="rgb(231,231,233)" stroke="rgb(231,231,233)" stroke-width="1" visibility="hidden" /> + <rect id="backgroundW" width="1200" height="900" x="0" y="0" fill="rgb(255,255,255)" stroke="rgb(255,255,255)" stroke-width="1" visibility="hidden" /> + <rect id="backgroundK" width="1200" height="900" x="0" y="0" fill="rgb(0,0,0)" stroke="rgb(0,0,0)" stroke-width="1" visibility="visible" /> +// end background + +// start XO group +<g onmouseover="showpoints(evt)" onmouseout="hidepoints(evt)" onmousedown="startmove(evt)" onmouseup="stopmove(evt)" onmousemove="move(evt)" onkeyup="textProcess(evt)"> +<g id="upXo"> // begin XO man +<path id="Line1" d="M645.5,357 C600,400.5 600,400.5 554.5,448" stroke="rgb(216,75,24)" stroke-width="37" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="Line2" d="M645.5,448 C600,400.5 600,400.5 554.5,357" stroke="rgb(216,75,24)" stroke-width="37" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="Fill1" d="M645.5,357 C600,400.5 600,400.5 554.5,448" stroke="rgb(52,192,210)" stroke-width="19" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="Fill2" d="M645.5,448 C600,400.5 600,400.5 554.5,357" stroke="rgb(52,192,210)" stroke-width="19" stroke-linecap="round" fill="none" visibility="visible" /> +<circle id="Circle" cx="600" cy="318.5" r="28.5" fill="rgb(52,192,210)" stroke="rgb(216,75,24)" stroke-width="9" visibility="visible" /> +</g> // end XO man +<g> +// knot points +<circle id="L1Knot1" cx="112.5" cy="112.5" r="12" fill="rgb(255,255,0)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L1Knot1')" /> +<circle id="L1Knot2" cx="112.5" cy="112.5" r="12" fill="rgb(255,255,0)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L1Knot2')" /> +<circle id="L2Knot1" cx="112.5" cy="112.5" r="12" fill="rgb(255,0,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L2Knot1')" /> +<circle id="L2Knot2" cx="112.5" cy="112.5" r="12" fill="rgb(255,0,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L2Knot2')" /> +// end points +<circle id="L1End1" cx="112.5" cy="112.5" r="12" fill="rgb(255,255,0)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L1End1')" /> +<circle id="L1End2" cx="112.5" cy="112.5" r="12" fill="rgb(255,255,0)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L1End2')" /> +<circle id="L2End1" cx="112.5" cy="112.5" r="12" fill="rgb(255,0,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L2End1')" /> +<circle id="L2End2" cx="112.5" cy="112.5" r="12" fill="rgb(255,0,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'L2End2')" /> +// center point +<circle id="Center" cx="112.5" cy="112.5" r="12" fill="rgb(0,255,255)" stroke="rgb(0,0,0)" stroke-width="3" visibility="hidden" onmousedown="setID(evt,'Center')" /> +// end knot points +</g> +</g> +// end XO group + +// "cursor" +<circle id="X" title="X" alt="X marks the spot" cx="0" cy="0" r="36" stroke="rgb(160,160,160)" fill="rgb(160,160,160)" stroke-width="9.5" visibility="visible" /> + +// color buttons +<circle id="R" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,0,0)" visibility="visible" /> +<circle id="YR" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,0,1)" visibility="visible" /> +<circle id="Y" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,0,2)" visibility="visible" /> +<circle id="G" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,0,3)" visibility="visible" /> +<circle id="B" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,0,4)" visibility="visible" /> +<circle id="P" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,0,5)" visibility="visible" /> + +<circle id="RC" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,3,3)" visibility="visible" /> +<circle id="YRC" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,3,4)" visibility="visible" /> +<circle id="YC" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,3,5)" visibility="visible" /> +<circle id="GC" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,3,0)" visibility="visible" /> +<circle id="BC" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,3,1)" visibility="visible" /> +<circle id="PC" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,3,2)" visibility="visible" /> + +<circle id="RCp" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,4,2)" visibility="visible" /> +<circle id="YRCp" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,4,3)" visibility="visible" /> +<circle id="YCp" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,4,4)" visibility="visible" /> +<circle id="GCp" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,4,5)" visibility="visible" /> +<circle id="BCp" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,4,0)" visibility="visible" /> +<circle id="PCp" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,4,1)" visibility="visible" /> + +<circle id="RCm" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,2,4)" visibility="visible" /> +<circle id="YRCm" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,2,5)" visibility="visible" /> +<circle id="YCm" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,2,0)" visibility="visible" /> +<circle id="GCm" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,2,1)" visibility="visible" /> +<circle id="BCm" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,2,2)" visibility="visible" /> +<circle id="PCm" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,2,3)" visibility="visible" /> + +<circle id="RAp" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,1,5)" visibility="visible" /> +<circle id="YRAp" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,1,0)" visibility="visible" /> +<circle id="YAp" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,1,1)" visibility="visible" /> +<circle id="GAp" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,1,2)" visibility="visible" /> +<circle id="BAp" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,1,3)" visibility="visible" /> +<circle id="PAp" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,1,4)" visibility="visible" /> + +<circle id="RAm" title="red" alt="red fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,0,5,1)" visibility="visible" /> +<circle id="YRAm" title="orange" alt="orange fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,1,5,2)" visibility="visible" /> +<circle id="YAm" title="yellow" alt="yellow fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,2,5,3)" visibility="visible" /> +<circle id="GAm" title="green" alt="green fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,3,5,4)" visibility="visible" /> +<circle id="BAm" title="blue" alt="blue fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,4,5,5)" visibility="visible" /> +<circle id="PAm" title="purple" alt="purple fill" cx="0" cy="0" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="updater(evt,5,5,0)" visibility="visible" /> + +// controls +<rect id="bgd" width="75" height="75" x="0" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<rect id="bgdf" width="75" height="75" x="75" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<rect id="bgm" width="75" height="75" x="150" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="visible" /> +<rect id="bgmf" width="75" height="75" x="225" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<rect id="bgl" width="75" height="75" x="300" y="0" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<circle id="vd" title="dark" alt="dark stroke" cx="37.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueDark(evt)" visibility="visible" /> +<circle id="vdf" title="darkflip" alt="dark flip" cx="112.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueDarkFlip(evt)" visibility="visible" /> +<circle id="vm" title="medium" alt="medium stroke" cx="187.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueMedium(evt)" visibility="visible" /> +<circle id="vmf" title="mediumflip" alt="medium flip" cx="262.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueMediumFlip(evt)" visibility="visible" /> +<circle id="vl" title="light" alt="light stroke" cx="337.5" cy="37.5" r="22.5" stroke="rgb(0,0,0)" fill="rgb(0,0,0)" stroke-width="9.5" onclick="valueLight(evt)" visibility="visible" /> + +<rect id="bghex" width="75" height="75" x="150" y="675" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="visible" /> +<rect id="bgsq" width="75" height="75" x="75" y="675" fill="rgb(160,160,160)" stroke="rgb(160,160,160)" stroke-width="1" visibility="hidden" /> +<circle id="hex" title="hex grid" alt="hex grid" cx="187.5" cy="712.5" r="22.5" stroke="rgb(100,100,100)" fill="rgb(100,100,100)" stroke-width="9.5" onclick="hexGrid(evt)" visibility="visible" /> +<rect id="sq" title="square grid" alt="square gird" width="45" height="45" x="90" y="690" fill="rgb(100,100,100)" stroke="rgb(100,100,100)" stroke-width="1" onclick="sqGrid(evt)" visibility="visible" /> + +<g onclick="resetXO(evt)"> // begin XO man icon +<path id="iconLine1" d="M53,700 C37.5,715.5 37.5,715.5 22,731" stroke="rgb(230,0,10)" stroke-width="11.5" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="iconLine2" d="M53,731 C37.5,715.5 37.5,715.5 22,700" stroke="rgb(230,0,10)" stroke-width="11.5" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="iconFill1" d="M53,700 C37.5,715.5 37.5,715.5 22,731" stroke="rgb(255,43,52)" stroke-width="4.5" stroke-linecap="round" fill="none" visibility="visible" /> +<path id="iconFill2" d="M53,731 C37.5,715.5 37.5,715.5 22,700" stroke="rgb(255,43,52)" stroke-width="4.5" stroke-linecap="round" fill="none" visibility="visible" /> +<circle id="iconCircle" cx="37.5" cy="690" r="8" fill="rgb(255,43,52)" stroke="rgb(230,0,10)" stroke-width="3.5" visibility="visible" /> +</g> // end XO man icon + +// background controls + +<rect id="icon" width="75" height="75" x="1125" y="0" fill="rgb(255,255,255)" stroke="rgb(255,255,255)" stroke-width="1" visibility="visible" onclick="background(evt,0)" /> +<rect id="icon" width="75" height="75" x="1050" y="0" fill="rgb(231,231,233)" stroke="rgb(231,231,233)" stroke-width="1" visibility="visible" onclick="background(evt,1)" /> +<rect id="icon" width="75" height="75" x="975" y="0" fill="rgb(76,77,79)" stroke="rgb(76,77,79)" stroke-width="1" visibility="visible" onclick="background(evt,2)" /> +<rect id="icon" width="75" height="75" x="900" y="0" fill="rgb(0,0,0)" stroke="rgb(0,0,0)" stroke-width="1" visibility="visible" onclick="background(evt,3)" /> +</svg> +</body> +</html> diff --git a/logic.py b/logic.py new file mode 100644 index 0000000..b035679 --- /dev/null +++ b/logic.py @@ -0,0 +1,48 @@ +#Copyright (c) 2007, Media Modifications Ltd. + +#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. + + +from result import ServerResult +import os +import urllib + +class ServerLogic: + def __init__(self, acty): + self.acty = acty + + def doServerLogic(self, url, path, params): + r = ServerResult() + + fileName = path[len(path)-1] + if (fileName == "saveXo"): + upXo = params[0][1] + upXo = urllib.unquote(upXo) + xoFile = open(os.path.join(self.acty.journalPath, "xo-dude.xml"), 'w') + xoFile.write(upXo) + xoFile.close() + else: + localfile = open(os.path.join(self.acty.htmlPath, fileName), 'r') + localdata = localfile.read() + localfile.close() + r.txt = localdata + #todo: dynamic mime type for js and xml, etc. + r.headers.append( ("Content-type", "text/xml") ) + + return r
\ No newline at end of file diff --git a/logic.pyc b/logic.pyc Binary files differnew file mode 100644 index 0000000..371ac24 --- /dev/null +++ b/logic.pyc diff --git a/result.py b/result.py new file mode 100644 index 0000000..5dbef40 --- /dev/null +++ b/result.py @@ -0,0 +1,25 @@ +#Copyright (c) 2007, Media Modifications Ltd. + +#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. + + +class ServerResult: + def __init__(self): + self.txt = "" + self.headers = []
\ No newline at end of file diff --git a/result.pyc b/result.pyc Binary files differnew file mode 100644 index 0000000..e3b4516 --- /dev/null +++ b/result.pyc diff --git a/server.py b/server.py new file mode 100644 index 0000000..25ffed8 --- /dev/null +++ b/server.py @@ -0,0 +1,59 @@ +#Copyright (c) 2007, Media Modifications Ltd. + +#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. + + +from sugar import network +import urlparse +import urllib +import posixpath + +class Server(network.GlibTCPServer): + def __init__(self, server_address, acty): + self.acty = acty + network.GlibTCPServer.__init__(self, server_address, RegHandler) + +#RegHandler extends SimpleHTTPServer.py (in python 2.4) +class RegHandler(network.ChunkedGlibHTTPRequestHandler): + def do_POST( self ): + self.translate_path() + + def do_GET( self ): + self.translate_path() + + def translate_path(self): + urlp = urlparse.urlparse(self.path) + + urls = urlp[2] + urls = posixpath.normpath(urllib.unquote(urls)) + urlPath = urls.split('/') + urlPath = filter(None, urlPath) + + params = urlp[4] + parama = [] + allParams = params.split('&') + for i in range (0, len(allParams)): + parama.append(allParams[i].split('=')) + + result = self.server.acty.slogic.doServerLogic(self.path,urlPath,parama) + self.send_response(200) + for i in range (0, len(result.headers)): + self.send_header( result.headers[i][0], result.headers[i][1] ) + self.end_headers() + self.wfile.write( result.txt )
\ No newline at end of file diff --git a/server.pyc b/server.pyc Binary files differnew file mode 100644 index 0000000..a9badae --- /dev/null +++ b/server.pyc diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..d204eea --- /dev/null +++ b/setup.py @@ -0,0 +1,22 @@ +#!/bin/env python + +# Copyright (C) 2006, Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from sugar.activity import bundlebuilder + +bundlebuilder.start("xoEditor") + diff --git a/webviewer.py b/webviewer.py new file mode 100644 index 0000000..f418f5f --- /dev/null +++ b/webviewer.py @@ -0,0 +1,147 @@ +# Copyright (C) 2006, Red Hat, Inc. +# Copyright (C) 2007, One Laptop Per Child +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from sugar import env + +import logging +import gobject +import gtk +import os +import hulahop +hulahop.startup(os.path.join(env.get_profile_path(), 'gecko')) +import xpcom +from xpcom.nsError import * +from xpcom import components +from xpcom.components import interfaces +from hulahop.webview import WebView + +#import sessionstore +#from dnd import DragDropHooks + +class WebViewer(WebView): + def __init__(self): + WebView.__init__(self) + + window_creator = WindowCreator(self) + cls = components.classes['@mozilla.org/embedcomp/window-watcher;1'] + window_watcher = cls.getService(interfaces.nsIWindowWatcher) + window_watcher.setWindowCreator(window_creator) + + self.connect('realize', self._realize_cb) + + def _realize_cb(self, widget): + #drag_drop_hooks = DragDropHooks(self) + + cls = components.classes['@mozilla.org/embedcomp/command-params;1'] + cmd_params = cls.createInstance('nsICommandParams') + #cmd_params.setISupportsValue('addhook', drag_drop_hooks) + + requestor = self.browser.queryInterface(interfaces.nsIInterfaceRequestor) + command_manager = requestor.getInterface(interfaces.nsICommandManager) + command_manager.doCommand('cmd_clipboardDragDropHook', cmd_params, self.dom_window) + + def get_session(self): + return sessionstore.get_session(self) + + def set_session(self, session_data): + return sessionstore.set_session(self, session_data) + +class WindowCreator: + _com_interfaces_ = interfaces.nsIWindowCreator + + def __init__(self, browser): + self._popup_creators = [] + self._browser = browser + + def createChromeWindow(self, parent, chrome_flags): + logging.debug('createChromeWindow: %r %r' % (parent, chrome_flags)) + + popup_creator = _PopupCreator(self._browser.get_toplevel()) + popup_creator.connect('popup-created', self._popup_created_cb) + + self._popup_creators.append(popup_creator) + + browser = popup_creator.get_embed() + + if chrome_flags & interfaces.nsIWebBrowserChrome.CHROME_OPENAS_CHROME: + logging.debug('Creating chrome window.') + browser.is_chrome = True + item = browser.browser.queryInterface(interfaces.nsIDocShellTreeItem) + item.itemType = interfaces.nsIDocShellTreeItem.typeChromeWrapper + else: + logging.debug('Creating browser window.') + item = browser.browser.queryInterface(interfaces.nsIDocShellTreeItem) + item.itemType = interfaces.nsIDocShellTreeItem.typeContentWrapper + + browser.realize() + + return browser.browser.containerWindow + + def _popup_created_cb(self, creator): + self._popup_creators.remove(creator) + +class _PopupCreator(gobject.GObject): + __gsignals__ = { + 'popup-created': (gobject.SIGNAL_RUN_FIRST, + gobject.TYPE_NONE, ([])), + } + + def __init__(self, parent_window): + gobject.GObject.__init__(self) + + logging.debug('Creating the popup widget') + + self._parent_window = parent_window + + self._dialog = gtk.Window() + self._dialog.set_resizable(True) + + self._dialog.realize() + self._dialog.window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + + self._embed = Browser() + self._vis_sid = self._embed.connect('notify::visible', self._notify_visible_cb) + self._dialog.add(self._embed) + + def _notify_visible_cb(self, embed, param): + self._embed.disconnect(self._vis_sid) + + if self._embed.type == Browser.TYPE_POPUP or self._embed.is_chrome: + logging.debug('Show the popup') + self._embed.show() + self._dialog.set_transient_for(self._parent_window) + self._dialog.show() + else: + logging.debug('Open a new activity for the popup') + self._dialog.remove(self._embed) + self._dialog.destroy() + self._dialog = None + + # FIXME We need a better way to handle this. + # It seem like a pretty special case though, I doubt + # other activities will need something similar. + from webactivity import WebActivity + from sugar.activity import activityfactory + from sugar.activity.activityhandle import ActivityHandle + handle = ActivityHandle(activityfactory.create_activity_id()) + activity = WebActivity(handle, self._embed) + activity.show() + + self.emit('popup-created') + + def get_embed(self): + return self._embed diff --git a/webviewer.pyc b/webviewer.pyc Binary files differnew file mode 100644 index 0000000..e2c812b --- /dev/null +++ b/webviewer.pyc diff --git a/xoEditorActivity.py b/xoEditorActivity.py new file mode 100644 index 0000000..5348025 --- /dev/null +++ b/xoEditorActivity.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +#Copyright (c) 2007, Media Modifications Ltd. + +#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. + +import gtk +import gobject +import os + +from sugar.activity import activity +from webviewer import WebViewer +from server import Server +from logic import ServerLogic +from result import ServerResult + +httpPort = 8889 +title = "xo Editor" +initHtml = "xo-color.xml" + +class xoEditorActivity(activity.Activity): + def __init__(self, handle): + activity.Activity.__init__(self, handle) + self.set_title( title ) + + #wait a moment so that our debug console capture mistakes + gobject.idle_add(self._initme, None) + + def _initme( self, userdata=None ): + self.basePath = activity.get_bundle_path() + self.htmlPath = os.path.join(self.basePath, "html") + self.journalPath = os.path.join(os.path.expanduser("~"), "Journal", title) + if (not os.path.exists(self.journalPath)): + os.makedirs(self.journalPath) + + #add sharing callback here + #self.connect( "shared", self._shared_cb ) + + #this includes the default sharing tab + toolbox = activity.ActivityToolbox(self) + self.set_toolbox(toolbox) + toolbox.show() + + #add components + self.browser = WebViewer( ) + self.set_canvas(self.browser) + self.browser.show() + + #fire up the web engine, spiderman! + self.slogic = ServerLogic(self); + self.server = Server( ("",httpPort), self ) + self.browser.load_uri( "http://localhost:" + str(httpPort) + "/" + initHtml ) + + #when the party's over, turn out the lights, turn out the lights + self.connect("destroy", self.destroy) + return False + + def destroy(self, *args): + gtk.main_quit() diff --git a/xoEditorActivity.pyc b/xoEditorActivity.pyc Binary files differnew file mode 100644 index 0000000..3a0d89b --- /dev/null +++ b/xoEditorActivity.pyc |