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>',
601
610
eachSlice: function(number, iterator, context) {
602
iterator = iterator ? iterator.bind(context) : Prototype.K;
603
611
var index = -number, slices = [], array = this.toArray();
612
if (number < 1) return array;
604
613
while ((index += number) < array.length)
605
614
slices.push(array.slice(index, index+number));
606
615
return slices.collect(iterator, context);
609
618
all: function(iterator, context) {
610
iterator = iterator ? iterator.bind(context) : Prototype.K;
619
iterator = iterator || Prototype.K;
611
620
var result = true;
612
621
this.each(function(value, index) {
613
result = result && !!iterator(value, index);
622
result = result && !!iterator.call(context, value, index);
614
623
if (!result) throw $break;
619
628
any: function(iterator, context) {
620
iterator = iterator ? iterator.bind(context) : Prototype.K;
629
iterator = iterator || Prototype.K;
621
630
var result = false;
622
631
this.each(function(value, index) {
623
if (result = !!iterator(value, index))
632
if (result = !!iterator.call(context, value, index))
629
638
collect: function(iterator, context) {
630
iterator = iterator ? iterator.bind(context) : Prototype.K;
639
iterator = iterator || Prototype.K;
631
640
var results = [];
632
641
this.each(function(value, index) {
633
results.push(iterator(value, index));
642
results.push(iterator.call(context, value, index));
638
647
detect: function(iterator, context) {
639
iterator = iterator.bind(context);
641
649
this.each(function(value, index) {
642
if (iterator(value, index)) {
650
if (iterator.call(context, value, index)) {
711
717
max: function(iterator, context) {
712
iterator = iterator ? iterator.bind(context) : Prototype.K;
718
iterator = iterator || Prototype.K;
714
720
this.each(function(value, index) {
715
value = iterator(value, index);
716
if (result == undefined || value >= result)
721
value = iterator.call(context, value, index);
722
if (result == null || value >= result)
722
728
min: function(iterator, context) {
723
iterator = iterator ? iterator.bind(context) : Prototype.K;
729
iterator = iterator || Prototype.K;
725
731
this.each(function(value, index) {
726
value = iterator(value, index);
727
if (result == undefined || value < result)
732
value = iterator.call(context, value, index);
733
if (result == null || value < result)
733
739
partition: function(iterator, context) {
734
iterator = iterator ? iterator.bind(context) : Prototype.K;
740
iterator = iterator || Prototype.K;
735
741
var trues = [], falses = [];
736
742
this.each(function(value, index) {
737
(iterator(value, index) ?
743
(iterator.call(context, value, index) ?
738
744
trues : falses).push(value);
740
746
return [trues, falses];
751
757
reject: function(iterator, context) {
752
iterator = iterator.bind(context);
753
758
var results = [];
754
759
this.each(function(value, index) {
755
if (!iterator(value, index))
760
if (!iterator.call(context, value, index))
756
761
results.push(value);
761
766
sortBy: function(iterator, context) {
762
iterator = iterator.bind(context);
763
767
return this.map(function(value, index) {
764
return {value: value, criteria: iterator(value, index)};
770
criteria: iterator.call(context, value, index)
765
772
}).sort(function(left, right) {
766
773
var a = left.criteria, b = right.criteria;
767
774
return a < b ? -1 : a > b ? 1 : 0;
805
812
function $A(iterable) {
806
813
if (!iterable) return [];
807
814
if (iterable.toArray) return iterable.toArray();
808
var length = iterable.length, results = new Array(length);
815
var length = iterable.length || 0, results = new Array(length);
809
816
while (length--) results[length] = iterable[length];
813
820
if (Prototype.Browser.WebKit) {
814
function $A(iterable) {
821
$A = function(iterable) {
815
822
if (!iterable) return [];
816
if (!(Object.isFunction(iterable) && iterable == '[object NodeList]') &&
817
iterable.toArray) return iterable.toArray();
818
var length = iterable.length, results = new Array(length);
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();
829
var length = iterable.length || 0, results = new Array(length);
819
830
while (length--) results[length] = iterable[length];
1628
1634
Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
1629
1635
insertions = {bottom:insertions};
1631
var content, t, range;
1637
var content, insert, tagName, childNodes;
1633
for (position in insertions) {
1639
for (var position in insertions) {
1634
1640
content = insertions[position];
1635
1641
position = position.toLowerCase();
1636
t = Element._insertionTranslations[position];
1642
insert = Element._insertionTranslations[position];
1638
1644
if (content && content.toElement) content = content.toElement();
1639
1645
if (Object.isElement(content)) {
1640
t.insert(element, content);
1646
insert(element, content);
1644
1650
content = Object.toHTML(content);
1646
range = element.ownerDocument.createRange();
1647
t.initializeRange(element, range);
1648
t.insert(element, range.createContextualFragment(content.stripScripts()));
1652
tagName = ((position == 'before' || position == 'after')
1653
? element.parentNode : element).tagName.toUpperCase();
1655
childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
1657
if (position == 'top' || position == 'after') childNodes.reverse();
1658
childNodes.each(insert.curry(element));
1650
1660
content.evalScripts.bind(content).defer();
1729
1739
element = $(element);
1730
1740
if (arguments.length == 1) return $(element.parentNode);
1731
1741
var ancestors = element.ancestors();
1732
return expression ? Selector.findElement(ancestors, expression, index) :
1733
ancestors[index || 0];
1742
return Object.isNumber(expression) ? ancestors[expression] :
1743
Selector.findElement(ancestors, expression, index);
1736
1746
down: function(element, expression, index) {
1737
1747
element = $(element);
1738
1748
if (arguments.length == 1) return element.firstDescendant();
1739
var descendants = element.descendants();
1740
return expression ? Selector.findElement(descendants, expression, index) :
1741
descendants[index || 0];
1749
return Object.isNumber(expression) ? element.descendants()[expression] :
1750
Element.select(element, expression)[index || 0];
1744
1753
previous: function(element, expression, index) {
1745
1754
element = $(element);
1746
1755
if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element));
1747
1756
var previousSiblings = element.previousSiblings();
1748
return expression ? Selector.findElement(previousSiblings, expression, index) :
1749
previousSiblings[index || 0];
1757
return Object.isNumber(expression) ? previousSiblings[expression] :
1758
Selector.findElement(previousSiblings, expression, index);
1752
1761
next: function(element, expression, index) {
1753
1762
element = $(element);
1754
1763
if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element));
1755
1764
var nextSiblings = element.nextSiblings();
1756
return expression ? Selector.findElement(nextSiblings, expression, index) :
1757
nextSiblings[index || 0];
1765
return Object.isNumber(expression) ? nextSiblings[expression] :
1766
Selector.findElement(nextSiblings, expression, index);
1760
1769
select: function() {
2175
if (!document.createRange || Prototype.Browser.Opera) {
2176
Element.Methods.insert = function(element, insertions) {
2177
element = $(element);
2179
if (Object.isString(insertions) || Object.isNumber(insertions) ||
2180
Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML)))
2181
insertions = { bottom: insertions };
2183
var t = Element._insertionTranslations, content, position, pos, tagName;
2185
for (position in insertions) {
2186
content = insertions[position];
2187
position = position.toLowerCase();
2190
if (content && content.toElement) content = content.toElement();
2191
if (Object.isElement(content)) {
2192
pos.insert(element, content);
2196
content = Object.toHTML(content);
2197
tagName = ((position == 'before' || position == 'after')
2198
? element.parentNode : element).tagName.toUpperCase();
2200
if (t.tags[tagName]) {
2201
var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts());
2202
if (position == 'top' || position == 'after') fragments.reverse();
2203
fragments.each(pos.insert.curry(element));
2205
else element.insertAdjacentHTML(pos.adjacency, content.stripScripts());
2207
content.evalScripts.bind(content).defer();
2214
2178
if (Prototype.Browser.Opera) {
2215
Element.Methods._getStyle = Element.Methods.getStyle;
2216
Element.Methods.getStyle = function(element, style) {
2222
if (Element._getStyle(element, 'position') == 'static') return null;
2223
default: return Element._getStyle(element, style);
2226
Element.Methods._readAttribute = Element.Methods.readAttribute;
2227
Element.Methods.readAttribute = function(element, attribute) {
2228
if (attribute == 'title') return element.title;
2229
return Element._readAttribute(element, attribute);
2179
Element.Methods.getStyle = Element.Methods.getStyle.wrap(
2180
function(proceed, element, style) {
2182
case 'left': case 'top': case 'right': case 'bottom':
2183
if (proceed(element, 'position') === 'static') return null;
2184
case 'height': case 'width':
2185
// returns '0px' for hidden elements; we want it to return null
2186
if (!Element.visible(element)) return null;
2188
// returns the border-box dimensions rather than the content-box
2189
// dimensions, so we subtract padding and borders from the value
2190
var dim = parseInt(proceed(element, style), 10);
2192
if (dim !== element['offset' + style.capitalize()])
2196
if (style === 'height') {
2197
properties = ['border-top-width', 'padding-top',
2198
'padding-bottom', 'border-bottom-width'];
2201
properties = ['border-left-width', 'padding-left',
2202
'padding-right', 'border-right-width'];
2204
return properties.inject(dim, function(memo, property) {
2205
var val = proceed(element, property);
2206
return val === null ? memo : memo - parseInt(val, 10);
2208
default: return proceed(element, style);
2213
Element.Methods.readAttribute = Element.Methods.readAttribute.wrap(
2214
function(proceed, element, attribute) {
2215
if (attribute === 'title') return element.title;
2216
return proceed(element, attribute);
2233
2221
else if (Prototype.Browser.IE) {
2234
$w('positionedOffset getOffsetParent viewportOffset').each(function(method) {
2222
// IE doesn't report offsets correctly for static elements, so we change them
2223
// to "relative" to get the values, then change them back.
2224
Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap(
2225
function(proceed, element) {
2226
element = $(element);
2227
// IE throws an error if element is not in document
2228
try { element.offsetParent }
2229
catch(e) { return $(document.body) }
2230
var position = element.getStyle('position');
2231
if (position !== 'static') return proceed(element);
2232
element.setStyle({ position: 'relative' });
2233
var value = proceed(element);
2234
element.setStyle({ position: position });
2239
$w('positionedOffset viewportOffset').each(function(method) {
2235
2240
Element.Methods[method] = Element.Methods[method].wrap(
2236
2241
function(proceed, element) {
2237
2242
element = $(element);
2243
try { element.offsetParent }
2244
catch(e) { return Element._returnOffset(0,0) }
2238
2245
var position = element.getStyle('position');
2239
if (position != 'static') return proceed(element);
2246
if (position !== 'static') return proceed(element);
2247
// Trigger hasLayout on the offset parent so that IE6 reports
2248
// accurate offsetTop and offsetLeft values for position: fixed.
2249
var offsetParent = element.getOffsetParent();
2250
if (offsetParent && offsetParent.getStyle('position') === 'fixed')
2251
offsetParent.setStyle({ zoom: 1 });
2240
2252
element.setStyle({ position: 'relative' });
2241
2253
var value = proceed(element);
2242
2254
element.setStyle({ position: position });
2477
2500
Element._getContentFromAnonymousElement = function(tagName, html) {
2478
2501
var div = new Element('div'), t = Element._insertionTranslations.tags[tagName];
2479
div.innerHTML = t[0] + html + t[1];
2480
t[2].times(function() { div = div.firstChild });
2503
div.innerHTML = t[0] + html + t[1];
2504
t[2].times(function() { div = div.firstChild });
2505
} else div.innerHTML = html;
2481
2506
return $A(div.childNodes);
2484
2509
Element._insertionTranslations = {
2486
adjacency: 'beforeBegin',
2487
insert: function(element, node) {
2488
element.parentNode.insertBefore(node, element);
2490
initializeRange: function(element, range) {
2491
range.setStartBefore(element);
2495
adjacency: 'afterBegin',
2496
insert: function(element, node) {
2497
element.insertBefore(node, element.firstChild);
2499
initializeRange: function(element, range) {
2500
range.selectNodeContents(element);
2501
range.collapse(true);
2505
adjacency: 'beforeEnd',
2506
insert: function(element, node) {
2507
element.appendChild(node);
2511
adjacency: 'afterEnd',
2512
insert: function(element, node) {
2513
element.parentNode.insertBefore(node, element.nextSibling);
2515
initializeRange: function(element, range) {
2516
range.setStartAfter(element);
2510
before: function(element, node) {
2511
element.parentNode.insertBefore(node, element);
2513
top: function(element, node) {
2514
element.insertBefore(node, element.firstChild);
2516
bottom: function(element, node) {
2517
element.appendChild(node);
2519
after: function(element, node) {
2520
element.parentNode.insertBefore(node, element.nextSibling);
2520
2523
TABLE: ['<table>', '</table>', 1],
2709
2718
window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop);
2712
/* 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,
2713
2722
* part of YUI-Ext version 0.40, distributed under the terms of an MIT-style
2714
2723
* license. Please see http://www.yui-ext.com/ for more information. */
2716
2725
var Selector = Class.create({
2717
2726
initialize: function(expression) {
2718
2727
this.expression = expression.strip();
2719
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();
2741
shouldUseXPath: function() {
2742
if (!Prototype.BrowserFeatures.XPath) return false;
2744
var e = this.expression;
2746
// Safari 3 chokes on :*-of-type and :empty
2747
if (Prototype.Browser.WebKit &&
2748
(e.include("-of-type") || e.include(":empty")))
2751
// XPath can't do namespaced attributes, nor can it read
2752
// the "checked" property from DOM nodes
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);
2722
2775
compileMatcher: function() {
2723
// Selectors with namespaced attributes can't use the XPath version
2724
if (Prototype.BrowserFeatures.XPath && !(/(\[[\w-]*?:|:checked)/).test(this.expression))
2725
return this.compileXPathMatcher();
2727
2776
var e = this.expression, ps = Selector.patterns, h = Selector.handlers,
2728
2777
c = Selector.criteria, le, p, m;
2868
2940
'first-child': '[not(preceding-sibling::*)]',
2869
2941
'last-child': '[not(following-sibling::*)]',
2870
2942
'only-child': '[not(preceding-sibling::* or following-sibling::*)]',
2871
'empty': "[count(*) = 0 and (count(text()) = 0 or translate(text(), ' \t\r\n', '') = '')]",
2943
'empty': "[count(*) = 0 and (count(text()) = 0)]",
2872
2944
'checked': "[@checked]",
2873
'disabled': "[@disabled]",
2874
'enabled': "[not(@disabled)]",
2945
'disabled': "[(@disabled) and (@type!='hidden')]",
2946
'enabled': "[not(@disabled) and (@type!='hidden')]",
2875
2947
'not': function(m) {
2876
2948
var e = m[6], p = Selector.patterns,
2877
x = Selector.xpath, le, m, v;
2949
x = Selector.xpath, le, v;
2879
2951
var exclusion = [];
2880
2952
while (e && le != e && (/\S/).test(e)) {
2934
tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
2935
className: 'n = h.className(n, r, "#{1}", c); c = false;',
2936
id: 'n = h.id(n, r, "#{1}", c); c = false;',
2937
attrPresence: 'n = h.attrPresence(n, r, "#{1}"); c = false;',
3006
tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;',
3007
className: 'n = h.className(n, r, "#{1}", c); c = false;',
3008
id: 'n = h.id(n, r, "#{1}", c); c = false;',
3009
attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;',
2938
3010
attr: function(m) {
2939
3011
m[3] = (m[5] || m[6]);
2940
return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}"); c = false;').evaluate(m);
3012
return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m);
2942
3014
pseudo: function(m) {
2943
3015
if (m[6]) m[6] = m[6].replace(/"/g, '\\"');
3146
3220
return results;
3149
attrPresence: function(nodes, root, attr) {
3223
attrPresence: function(nodes, root, attr, combinator) {
3150
3224
if (!nodes) nodes = root.getElementsByTagName("*");
3225
if (nodes && combinator) nodes = this[combinator](nodes);
3151
3226
var results = [];
3152
3227
for (var i = 0, node; node = nodes[i]; i++)
3153
3228
if (Element.hasAttribute(node, attr)) results.push(node);
3154
3229
return results;
3157
attr: function(nodes, root, attr, value, operator) {
3232
attr: function(nodes, root, attr, value, operator, combinator) {
3158
3233
if (!nodes) nodes = root.getElementsByTagName("*");
3234
if (nodes && combinator) nodes = this[combinator](nodes);
3159
3235
var handler = Selector.operators[operator], results = [];
3160
3236
for (var i = 0, node; node = nodes[i]; i++) {
3161
3237
var nodeValue = Element.readAttribute(node, attr);
3300
3377
'=': function(nv, v) { return nv == v; },
3301
3378
'!=': function(nv, v) { return nv != v; },
3302
'^=': 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); },
3303
3382
'$=': function(nv, v) { return nv.endsWith(v); },
3304
3383
'*=': function(nv, v) { return nv.include(v); },
3305
3384
'~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); },
3306
'|=': function(nv, v) { return ('-' + nv.toUpperCase() + '-').include('-' + v.toUpperCase() + '-'); }
3385
'|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() +
3386
'-').include('-' + (v || "").toUpperCase() + '-'); }
3389
split: function(expression) {
3390
var expressions = [];
3391
expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) {
3392
expressions.push(m[1].strip());
3309
3397
matchElements: function(elements, expression) {
3310
var matches = new Selector(expression).findElements(), h = Selector.handlers;
3398
var matches = $$(expression), h = Selector.handlers;
3311
3399
h.mark(matches);
3312
3400
for (var i = 0, results = [], element; element = elements[i]; i++)
3313
if (element._counted) results.push(element);
3401
if (element._countedByPrototype) results.push(element);
3314
3402
h.unmark(matches);
3315
3403
return results;
3547
3650
inputSelector: function(element, value) {
3548
if (value === undefined) return element.checked ? element.value : null;
3651
if (Object.isUndefined(value)) return element.checked ? element.value : null;
3549
3652
else element.checked = !!value;
3552
3655
textarea: function(element, value) {
3553
if (value === undefined) return element.value;
3656
if (Object.isUndefined(value)) return element.value;
3554
3657
else element.value = value;
3557
select: function(element, index) {
3558
if (index === undefined)
3660
select: function(element, value) {
3661
if (Object.isUndefined(value))
3559
3662
return this[element.type == 'select-one' ?
3560
3663
'selectOne' : 'selectMany'](element);
3562
var opt, value, single = !Object.isArray(index);
3665
var opt, currentValue, single = !Object.isArray(value);
3563
3666
for (var i = 0, length = element.length; i < length; i++) {
3564
3667
opt = element.options[i];
3565
value = this.optionValue(opt);
3668
currentValue = this.optionValue(opt);
3567
if (value == index) {
3670
if (currentValue == value) {
3568
3671
opt.selected = true;
3572
else opt.selected = index.include(value);
3675
else opt.selected = value.include(currentValue);
3740
3843
isRightClick: function(event) { return isButton(event, 2) },
3742
3845
element: function(event) {
3743
var node = Event.extend(event).target;
3744
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);
3747
3865
findElement: function(event, expression) {
3748
3866
var element = Event.element(event);
3749
return element.match(expression) ? element : element.up(expression);
3867
if (!expression) return element;
3868
var elements = [element].concat(element.ancestors());
3869
return Selector.findElement(elements, expression, 0);
3752
3872
pointer: function(event) {
3873
var docElement = document.documentElement,
3874
body = document.body || { scrollLeft: 0, scrollTop: 0 };
3754
3876
x: event.pageX || (event.clientX +
3755
(document.documentElement.scrollLeft || document.body.scrollLeft)),
3877
(docElement.scrollLeft || body.scrollLeft) -
3878
(docElement.clientLeft || 0)),
3756
3879
y: event.pageY || (event.clientY +
3757
(document.documentElement.scrollTop || document.body.scrollTop))
3880
(docElement.scrollTop || body.scrollTop) -
3881
(docElement.clientTop || 0))