7
7
*--------------------------------------------------------------------------*/
13
IE: !!(window.attachEvent && !window.opera),
14
Opera: !!window.opera,
13
IE: !!(window.attachEvent &&
14
navigator.userAgent.indexOf('Opera') === -1),
15
Opera: navigator.userAgent.indexOf('Opera') > -1,
15
16
WebKit: navigator.userAgent.indexOf('AppleWebKit/') > -1,
16
Gecko: navigator.userAgent.indexOf('Gecko') > -1 && navigator.userAgent.indexOf('KHTML') == -1,
17
Gecko: navigator.userAgent.indexOf('Gecko') > -1 &&
18
navigator.userAgent.indexOf('KHTML') === -1,
17
19
MobileSafari: !!navigator.userAgent.match(/Apple.*Mobile.*Safari/)
21
23
XPath: !!document.evaluate,
24
SelectorsAPI: !!document.querySelector,
22
25
ElementExtensions: !!window.HTMLElement,
23
26
SpecificElementExtensions:
24
document.createElement('div').__proto__ &&
25
document.createElement('div').__proto__ !==
26
document.createElement('form').__proto__
27
document.createElement('div')['__proto__'] &&
28
document.createElement('div')['__proto__'] !==
29
document.createElement('form')['__proto__']
29
32
ScriptFragment: '<script[^>]*>([\\S\\s]*?)<\/script>',
83
86
var property = properties[i], value = source[property];
84
87
if (ancestor && Object.isFunction(value) &&
85
88
value.argumentNames().first() == "$super") {
86
var method = value, value = Object.extend((function(m) {
90
value = (function(m) {
87
91
return function() { return ancestor[m].apply(this, arguments) };
88
})(property).wrap(method), {
89
valueOf: function() { return method },
90
toString: function() { return method.toString() }
92
})(property).wrap(method);
94
value.valueOf = method.valueOf.bind(method);
95
value.toString = method.toString.bind(method);
93
97
this.prototype[property] = value;
199
203
Object.extend(Function.prototype, {
200
204
argumentNames: function() {
201
var names = this.toString().match(/^[\s\(]*function[^(]*\((.*?)\)/)[1].split(",").invoke("strip");
205
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^\)]*)\)/)[1]
206
.replace(/\s+/g, '').split(',');
202
207
return names.length == 1 && !names[0] ? [] : names;
530
538
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
532
540
unescapeHTML: function() {
533
return this.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
541
return this.stripTags().replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
547
555
text: document.createTextNode('')
550
with (String.prototype.escapeHTML) div.appendChild(text);
558
String.prototype.escapeHTML.div.appendChild(String.prototype.escapeHTML.text);
552
560
var Template = Class.create({
553
561
initialize: function(template, pattern) {
589
597
var Enumerable = {
590
598
each: function(iterator, context) {
592
iterator = iterator.bind(context);
594
601
this._each(function(value) {
595
iterator(value, index++);
602
iterator.call(context, value, index++);
598
605
if (e != $break) throw e;
603
610
eachSlice: function(number, iterator, context) {
604
iterator = iterator ? iterator.bind(context) : Prototype.K;
605
611
var index = -number, slices = [], array = this.toArray();
612
if (number < 1) return array;
606
613
while ((index += number) < array.length)
607
614
slices.push(array.slice(index, index+number));
608
615
return slices.collect(iterator, context);
611
618
all: function(iterator, context) {
612
iterator = iterator ? iterator.bind(context) : Prototype.K;
619
iterator = iterator || Prototype.K;
613
620
var result = true;
614
621
this.each(function(value, index) {
615
result = result && !!iterator(value, index);
622
result = result && !!iterator.call(context, value, index);
616
623
if (!result) throw $break;
621
628
any: function(iterator, context) {
622
iterator = iterator ? iterator.bind(context) : Prototype.K;
629
iterator = iterator || Prototype.K;
623
630
var result = false;
624
631
this.each(function(value, index) {
625
if (result = !!iterator(value, index))
632
if (result = !!iterator.call(context, value, index))
631
638
collect: function(iterator, context) {
632
iterator = iterator ? iterator.bind(context) : Prototype.K;
639
iterator = iterator || Prototype.K;
633
640
var results = [];
634
641
this.each(function(value, index) {
635
results.push(iterator(value, index));
642
results.push(iterator.call(context, value, index));
640
647
detect: function(iterator, context) {
641
iterator = iterator.bind(context);
643
649
this.each(function(value, index) {
644
if (iterator(value, index)) {
650
if (iterator.call(context, value, index)) {
652
658
findAll: function(iterator, context) {
653
iterator = iterator.bind(context);
654
659
var results = [];
655
660
this.each(function(value, index) {
656
if (iterator(value, index))
661
if (iterator.call(context, value, index))
657
662
results.push(value);
662
667
grep: function(filter, iterator, context) {
663
iterator = iterator ? iterator.bind(context) : Prototype.K;
668
iterator = iterator || Prototype.K;
664
669
var results = [];
666
671
if (Object.isString(filter))
698
703
inject: function(memo, iterator, context) {
699
iterator = iterator.bind(context);
700
704
this.each(function(value, index) {
701
memo = iterator(memo, value, index);
705
memo = iterator.call(context, memo, value, index);
713
717
max: function(iterator, context) {
714
iterator = iterator ? iterator.bind(context) : Prototype.K;
718
iterator = iterator || Prototype.K;
716
720
this.each(function(value, index) {
717
value = iterator(value, index);
721
value = iterator.call(context, value, index);
718
722
if (result == null || value >= result)
724
728
min: function(iterator, context) {
725
iterator = iterator ? iterator.bind(context) : Prototype.K;
729
iterator = iterator || Prototype.K;
727
731
this.each(function(value, index) {
728
value = iterator(value, index);
732
value = iterator.call(context, value, index);
729
733
if (result == null || value < result)
735
739
partition: function(iterator, context) {
736
iterator = iterator ? iterator.bind(context) : Prototype.K;
740
iterator = iterator || Prototype.K;
737
741
var trues = [], falses = [];
738
742
this.each(function(value, index) {
739
(iterator(value, index) ?
743
(iterator.call(context, value, index) ?
740
744
trues : falses).push(value);
742
746
return [trues, falses];
753
757
reject: function(iterator, context) {
754
iterator = iterator.bind(context);
755
758
var results = [];
756
759
this.each(function(value, index) {
757
if (!iterator(value, index))
760
if (!iterator.call(context, value, index))
758
761
results.push(value);
763
766
sortBy: function(iterator, context) {
764
iterator = iterator.bind(context);
765
767
return this.map(function(value, index) {
766
return {value: value, criteria: iterator(value, index)};
770
criteria: iterator.call(context, value, index)
767
772
}).sort(function(left, right) {
768
773
var a = left.criteria, b = right.criteria;
769
774
return a < b ? -1 : a > b ? 1 : 0;
815
820
if (Prototype.Browser.WebKit) {
816
821
$A = function(iterable) {
817
822
if (!iterable) return [];
818
if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
819
iterable.toArray) return iterable.toArray();
823
// In Safari, only use the `toArray` method if it's not a NodeList.
824
// A NodeList is a function, has an function `item` property, and a numeric
825
// `length` property. Adapted from Google Doctype.
826
if (!(typeof iterable === 'function' && typeof iterable.length ===
827
'number' && typeof iterable.item === 'function') && iterable.toArray)
828
return iterable.toArray();
820
829
var length = iterable.length || 0, results = new Array(length);
821
830
while (length--) results[length] = iterable[length];
966
times: function(iterator) {
967
$R(0, this, true).each(iterator);
975
times: function(iterator, context) {
976
$R(0, this, true).each(iterator, context);
1053
1064
toQueryString: function() {
1054
return this.map(function(pair) {
1065
return this.inject([], function(results, pair) {
1055
1066
var key = encodeURIComponent(pair.key), values = pair.value;
1057
1068
if (values && typeof values == 'object') {
1058
1069
if (Object.isArray(values))
1059
return values.map(toQueryPair.curry(key)).join('&');
1061
return toQueryPair(key, values);
1070
return results.concat(values.map(toQueryPair.curry(key)));
1071
} else results.push(toQueryPair(key, values));
1576
1588
hide: function(element) {
1577
$(element).style.display = 'none';
1589
element = $(element);
1590
element.style.display = 'none';
1578
1591
return element;
1581
1594
show: function(element) {
1582
$(element).style.display = '';
1595
element = $(element);
1596
element.style.display = '';
1583
1597
return element;
1733
1747
element = $(element);
1734
1748
if (arguments.length == 1) return element.firstDescendant();
1735
1749
return Object.isNumber(expression) ? element.descendants()[expression] :
1736
element.select(expression)[index || 0];
1750
Element.select(element, expression)[index || 0];
1739
1753
previous: function(element, expression, index) {
1864
1878
descendantOf: function(element, ancestor) {
1865
1879
element = $(element), ancestor = $(ancestor);
1866
var originalAncestor = ancestor;
1868
1881
if (element.compareDocumentPosition)
1869
1882
return (element.compareDocumentPosition(ancestor) & 8) === 8;
1871
if (element.sourceIndex && !Prototype.Browser.Opera) {
1872
var e = element.sourceIndex, a = ancestor.sourceIndex,
1873
nextAncestor = ancestor.nextSibling;
1874
if (!nextAncestor) {
1875
do { ancestor = ancestor.parentNode; }
1876
while (!(nextAncestor = ancestor.nextSibling) && ancestor.parentNode);
1878
if (nextAncestor && nextAncestor.sourceIndex)
1879
return (e > a && e < nextAncestor.sourceIndex);
1884
if (ancestor.contains)
1885
return ancestor.contains(element) && ancestor !== element;
1882
1887
while (element = element.parentNode)
1883
if (element == originalAncestor) return true;
1888
if (element == ancestor) return true;
1895
1901
element = $(element);
1896
1902
style = style == 'float' ? 'cssFloat' : style.camelize();
1897
1903
var value = element.style[style];
1904
if (!value || value == 'auto') {
1899
1905
var css = document.defaultView.getComputedStyle(element, null);
1900
1906
value = css ? css[style] : null;
1935
1941
getDimensions: function(element) {
1936
1942
element = $(element);
1937
var display = $(element).getStyle('display');
1943
var display = element.getStyle('display');
1938
1944
if (display != 'none' && display != null) // Safari bug
1939
1945
return {width: element.offsetWidth, height: element.offsetHeight};
2018
2024
valueL += element.offsetLeft || 0;
2019
2025
element = element.offsetParent;
2021
if (element.tagName == 'BODY') break;
2027
if (element.tagName.toUpperCase() == 'BODY') break;
2022
2028
var p = Element.getStyle(element, 'position');
2023
2029
if (p !== 'static') break;
2029
2035
absolutize: function(element) {
2030
2036
element = $(element);
2031
if (element.getStyle('position') == 'absolute') return;
2037
if (element.getStyle('position') == 'absolute') return element;
2032
2038
// Position.prepare(); // To be done manually by Scripty when it needs it.
2034
2040
var offsets = element.positionedOffset();
2053
2059
relativize: function(element) {
2054
2060
element = $(element);
2055
if (element.getStyle('position') == 'relative') return;
2061
if (element.getStyle('position') == 'relative') return element;
2056
2062
// Position.prepare(); // To be done manually by Scripty when it needs it.
2058
2064
element.style.position = 'relative';
2218
2224
Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
2219
2225
function(proceed, element) {
2220
2226
element = $(element);
2227
// IE throws an error if element is not in document
2228
try { element.offsetParent }
2229
catch(e) { return $(document.body) }
2221
2230
var position = element.getStyle('position');
2222
2231
if (position !== 'static') return proceed(element);
2223
2232
element.setStyle({ position: 'relative' });
2231
2240
Element.Methods[method] = Element.Methods[method].wrap(
2232
2241
function(proceed, element) {
2233
2242
element = $(element);
2243
try { element.offsetParent }
2244
catch(e) { return Element._returnOffset(0,0) }
2234
2245
var position = element.getStyle('position');
2235
2246
if (position !== 'static') return proceed(element);
2236
2247
// Trigger hasLayout on the offset parent so that IE6 reports
2260
Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap(
2261
function(proceed, element) {
2262
try { element.offsetParent }
2263
catch(e) { return Element._returnOffset(0,0) }
2264
return proceed(element);
2249
2268
Element.Methods.getStyle = function(element, style) {
2250
2269
element = $(element);
2251
2270
style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize();
2337
2356
Element._attributeTranslations.has = {};
2339
2358
$w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' +
2340
'encType maxLength readOnly longDesc').each(function(attr) {
2359
'encType maxLength readOnly longDesc frameBorder').each(function(attr) {
2341
2360
Element._attributeTranslations.write.names[attr.toLowerCase()] = attr;
2342
2361
Element._attributeTranslations.has[attr.toLowerCase()] = attr;
2521
2540
hasAttribute: function(element, attribute) {
2522
2541
attribute = Element._attributeTranslations.has[attribute] || attribute;
2523
2542
var node = $(element).getAttributeNode(attribute);
2524
return node && node.specified;
2543
return !!(node && node.specified);
2530
2549
Object.extend(Element, Element.Methods);
2532
2551
if (!Prototype.BrowserFeatures.ElementExtensions &&
2533
document.createElement('div').__proto__) {
2552
document.createElement('div')['__proto__']) {
2534
2553
window.HTMLElement = { };
2535
window.HTMLElement.prototype = document.createElement('div').__proto__;
2554
window.HTMLElement.prototype = document.createElement('div')['__proto__'];
2536
2555
Prototype.BrowserFeatures.ElementExtensions = true;
2547
2566
element.nodeType != 1 || element == window) return element;
2549
2568
var methods = Object.clone(Methods),
2550
tagName = element.tagName, property, value;
2569
tagName = element.tagName.toUpperCase(), property, value;
2552
2571
// extend methods for specific tags
2553
2572
if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]);
2670
2689
document.viewport = {
2671
2690
getDimensions: function() {
2672
var dimensions = { };
2673
var B = Prototype.Browser;
2691
var dimensions = { }, B = Prototype.Browser;
2674
2692
$w('width height').each(function(d) {
2675
2693
var D = d.capitalize();
2676
dimensions[d] = (B.WebKit && !document.evaluate) ? self['inner' + D] :
2677
(B.Opera) ? document.body['client' + D] : document.documentElement['client' + D];
2694
if (B.WebKit && !document.evaluate) {
2695
// Safari <3.0 needs self.innerWidth/Height
2696
dimensions[d] = self['inner' + D];
2697
} else if (B.Opera && parseFloat(window.opera.version()) < 9.5) {
2698
// Opera <9.5 needs document.body.clientWidth/Height
2699
dimensions[d] = document.body['client' + D]
2701
dimensions[d] = document.documentElement['client' + D];
2679
2704
return dimensions;
2693
2718
window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
2696
/* Portions of the Selector class are derived from Jack Slocum’s DomQuery,
2721
/* Portions of the Selector class are derived from Jack Slocum's DomQuery,
2697
2722
* part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2698
2723
* license. Please see http://www.yui-ext.com/ for more information. */
2700
2725
var Selector = Class.create({
2701
2726
initialize: function(expression) {
2702
2727
this.expression = expression.strip();
2703
this.compileMatcher();
2729
if (this.shouldUseSelectorsAPI()) {
2730
this.mode = 'selectorsAPI';
2731
} else if (this.shouldUseXPath()) {
2732
this.mode = 'xpath';
2733
this.compileXPathMatcher();
2735
this.mode = "normal";
2736
this.compileMatcher();
2706
2741
shouldUseXPath: function() {
2716
2751
// XPath can't do namespaced attributes, nor can it read
2717
2752
// the "checked" property from DOM nodes
2718
if ((/(\[[\w-]*?:|:checked)/).test(this.expression))
2753
if ((/(\[[\w-]*?:|:checked)/).test(e))
2759
shouldUseSelectorsAPI: function() {
2760
if (!Prototype.BrowserFeatures.SelectorsAPI) return false;
2762
if (!Selector._div) Selector._div = new Element('div');
2764
// Make sure the browser treats the selector as valid. Test on an
2765
// isolated element to minimize cost of this check.
2767
Selector._div.querySelector(this.expression);
2724
2775
compileMatcher: function() {
2725
if (this.shouldUseXPath())
2726
return this.compileXPathMatcher();
2728
2776
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2729
2777
c = Selector.criteria, le, p, m;
2782
2830
findElements: function(root) {
2783
2831
root = root || document;
2784
if (this.xpath) return document._getElementsByXPath(this.xpath, root);
2785
return this.matcher(root);
2832
var e = this.expression, results;
2834
switch (this.mode) {
2835
case 'selectorsAPI':
2836
// querySelectorAll queries document-wide, then filters to descendants
2837
// of the context element. That's not what we want.
2838
// Add an explicit context to the selector if necessary.
2839
if (root !== document) {
2840
var oldId = root.id, id = $(root).identify();
2841
e = "#" + id + " " + e;
2844
results = $A(root.querySelectorAll(e)).map(Element.extend);
2849
return document._getElementsByXPath(this.xpath, root);
2851
return this.matcher(root);
2788
2855
match: function(element) {
2873
2940
'first-child': '[not(preceding-sibling::*)]',
2874
2941
'last-child': '[not(following-sibling::*)]',
2875
2942
'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2876
'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2943
'empty': "[count(*) = 0 and (count(text()) = 0)]",
2877
2944
'checked': "[@checked]",
2878
'disabled': "[@disabled]",
2879
'enabled': "[not(@disabled)]",
2945
'disabled': "[(@disabled) and (@type!='hidden')]",
2946
'enabled': "[not(@disabled) and (@type!='hidden')]",
2880
2947
'not': function(m) {
2881
2948
var e = m[6], p = Selector.patterns,
2882
2949
x = Selector.xpath, le, v;
2968
3035
className: /^\.([\w\-\*]+)(\b|$)/,
2970
3037
/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
2971
attrPresence: /^\[([\w]+)\]/,
3038
attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
2972
3039
attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
3270
3337
'empty': function(nodes, value, root) {
3271
3338
for (var i = 0, results = [], node; node = nodes[i]; i++) {
3272
3339
// IE treats comments as element nodes
3273
if (node.tagName == '!' || (node.firstChild && !node.innerHTML.match(/^\s*$/))) continue;
3340
if (node.tagName == '!' || node.firstChild) continue;
3274
3341
results.push(node);
3276
3343
return results;
3289
3356
'enabled': function(nodes, value, root) {
3290
3357
for (var i = 0, results = [], node; node = nodes[i]; i++)
3291
if (!node.disabled) results.push(node);
3358
if (!node.disabled && (!node.type || node.type !== 'hidden'))
3292
3360
return results;
3309
3377
'=': function(nv, v) { return nv == v; },
3310
3378
'!=': function(nv, v) { return nv != v; },
3311
'^=': function(nv, v) { return nv.startsWith(v); },
3379
'^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); },
3380
'$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); },
3381
'*=': function(nv, v) { return nv == v || nv && nv.include(v); },
3312
3382
'$=': function(nv, v) { return nv.endsWith(v); },
3313
3383
'*=': function(nv, v) { return nv.include(v); },
3314
3384
'~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3315
'|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3385
'|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
3386
'-').include('-' + (v || "").toUpperCase() + '-'); }
3318
3389
split: function(expression) {
3386
3457
var data = elements.inject({ }, function(result, element) {
3387
3458
if (!element.disabled && element.name) {
3388
3459
key = element.name; value = $(element).getValue();
3389
if (value != null && (element.type != 'submit' || (!submitted &&
3460
if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted &&
3390
3461
submit !== false && (!submit || key == submit) && (submitted = true)))) {
3391
3462
if (key in result) {
3392
3463
// a key is already present; construct an array of values
3587
3657
else element.value = value;
3590
select: function(element, index) {
3591
if (Object.isUndefined(index))
3660
select: function(element, value) {
3661
if (Object.isUndefined(value))
3592
3662
return this[element.type == 'select-one' ?
3593
3663
'selectOne' : 'selectMany'](element);
3595
var opt, value, single = !Object.isArray(index);
3665
var opt, currentValue, single = !Object.isArray(value);
3596
3666
for (var i = 0, length = element.length; i < length; i++) {
3597
3667
opt = element.options[i];
3598
value = this.optionValue(opt);
3668
currentValue = this.optionValue(opt);
3600
if (value == index) {
3670
if (currentValue == value) {
3601
3671
opt.selected = true;
3605
else opt.selected = index.include(value);
3675
else opt.selected = value.include(currentValue);
3773
3843
isRightClick: function(event) { return isButton(event, 2) },
3775
3845
element: function(event) {
3776
var node = Event.extend(event).target;
3777
return Element.extend(node.nodeType == Node.TEXT_NODE ? node.parentNode : node);
3846
event = Event.extend(event);
3848
var node = event.target,
3850
currentTarget = event.currentTarget;
3852
if (currentTarget && currentTarget.tagName) {
3853
// Firefox screws up the "click" event when moving between radio buttons
3854
// via arrow keys. It also screws up the "load" and "error" events on images,
3855
// reporting the document as the target instead of the original image.
3856
if (type === 'load' || type === 'error' ||
3857
(type === 'click' && currentTarget.tagName.toLowerCase() === 'input'
3858
&& currentTarget.type === 'radio'))
3859
node = currentTarget;
3861
if (node.nodeType == Node.TEXT_NODE) node = node.parentNode;
3862
return Element.extend(node);
3780
3865
findElement: function(event, expression) {
3787
3872
pointer: function(event) {
3873
var docElement = document.documentElement,
3874
body = document.body || { scrollLeft: 0, scrollTop: 0 };
3789
3876
x: event.pageX || (event.clientX +
3790
(document.documentElement.scrollLeft || document.body.scrollLeft)),
3877
(docElement.scrollLeft || body.scrollLeft) -
3878
(docElement.clientLeft || 0)),
3791
3879
y: event.pageY || (event.clientY +
3792
(document.documentElement.scrollTop || document.body.scrollTop))
3880
(docElement.scrollTop || body.scrollTop) -
3881
(docElement.clientTop || 0))
3899
3988
cache[id][eventName] = null;
3992
// Internet Explorer needs to remove event handlers on page unload
3993
// in order to avoid memory leaks.
3902
3994
if (window.attachEvent) {
3903
3995
window.attachEvent("onunload", destroyCache);
3998
// Safari has a dummy event handler on page unload so that it won't
3999
// use its bfcache. Safari <= 3.1 has an issue with restoring the "document"
4000
// object when page is returned to via the back button using its bfcache.
4001
if (Prototype.Browser.WebKit) {
4002
window.addEventListener('unload', Prototype.emptyFunction, false);
3907
4006
observe: function(element, eventName, handler) {
3908
4007
element = $(element);