OLD | NEW |
| (Empty) |
1 (function(){ | |
2 | |
3 this.MooTools = { | |
4 version: '1.4.5', | |
5 build: 'ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0' | |
6 }; | |
7 | |
8 // typeOf, instanceOf | |
9 | |
10 var typeOf = this.typeOf = function(item){ | |
11 if (item == null) return 'null'; | |
12 if (item.$family != null) return item.$family(); | |
13 | |
14 if (item.nodeName){ | |
15 if (item.nodeType == 1) return 'element'; | |
16 if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'w
hitespace'; | |
17 } else if (typeof item.length == 'number'){ | |
18 if (item.callee) return 'arguments'; | |
19 if ('item' in item) return 'collection'; | |
20 } | |
21 | |
22 return typeof item; | |
23 }; | |
24 | |
25 var instanceOf = this.instanceOf = function(item, object){ | |
26 if (item == null) return false; | |
27 var constructor = item.$constructor || item.constructor; | |
28 while (constructor){ | |
29 if (constructor === object) return true; | |
30 constructor = constructor.parent; | |
31 } | |
32 /*<ltIE8>*/ | |
33 if (!item.hasOwnProperty) return false; | |
34 /*</ltIE8>*/ | |
35 return item instanceof object; | |
36 }; | |
37 | |
38 // Function overloading | |
39 | |
40 var Function = this.Function; | |
41 | |
42 var enumerables = true; | |
43 for (var i in {toString: 1}) enumerables = null; | |
44 if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'p
ropertyIsEnumerable', 'toLocaleString', 'toString', 'constructor']; | |
45 | |
46 Function.prototype.overloadSetter = function(usePlural){ | |
47 var self = this; | |
48 return function(a, b){ | |
49 if (a == null) return this; | |
50 if (usePlural || typeof a != 'string'){ | |
51 for (var k in a) self.call(this, k, a[k]); | |
52 if (enumerables) for (var i = enumerables.length; i--;){ | |
53 k = enumerables[i]; | |
54 if (a.hasOwnProperty(k)) self.call(this, k, a[k]); | |
55 } | |
56 } else { | |
57 self.call(this, a, b); | |
58 } | |
59 return this; | |
60 }; | |
61 }; | |
62 | |
63 Function.prototype.overloadGetter = function(usePlural){ | |
64 var self = this; | |
65 return function(a){ | |
66 var args, result; | |
67 if (typeof a != 'string') args = a; | |
68 else if (arguments.length > 1) args = arguments; | |
69 else if (usePlural) args = [a]; | |
70 if (args){ | |
71 result = {}; | |
72 for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, ar
gs[i]); | |
73 } else { | |
74 result = self.call(this, a); | |
75 } | |
76 return result; | |
77 }; | |
78 }; | |
79 | |
80 Function.prototype.extend = function(key, value){ | |
81 this[key] = value; | |
82 }.overloadSetter(); | |
83 | |
84 Function.prototype.implement = function(key, value){ | |
85 this.prototype[key] = value; | |
86 }.overloadSetter(); | |
87 | |
88 // From | |
89 | |
90 var slice = Array.prototype.slice; | |
91 | |
92 Function.from = function(item){ | |
93 return (typeOf(item) == 'function') ? item : function(){ | |
94 return item; | |
95 }; | |
96 }; | |
97 | |
98 Array.from = function(item){ | |
99 if (item == null) return []; | |
100 return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) ==
'array') ? item : slice.call(item) : [item]; | |
101 }; | |
102 | |
103 Number.from = function(item){ | |
104 var number = parseFloat(item); | |
105 return isFinite(number) ? number : null; | |
106 }; | |
107 | |
108 String.from = function(item){ | |
109 return item + ''; | |
110 }; | |
111 | |
112 // hide, protect | |
113 | |
114 Function.implement({ | |
115 | |
116 hide: function(){ | |
117 this.$hidden = true; | |
118 return this; | |
119 }, | |
120 | |
121 protect: function(){ | |
122 this.$protected = true; | |
123 return this; | |
124 } | |
125 | |
126 }); | |
127 | |
128 // Type | |
129 | |
130 var Type = this.Type = function(name, object){ | |
131 if (name){ | |
132 var lower = name.toLowerCase(); | |
133 var typeCheck = function(item){ | |
134 return (typeOf(item) == lower); | |
135 }; | |
136 | |
137 Type['is' + name] = typeCheck; | |
138 if (object != null){ | |
139 object.prototype.$family = (function(){ | |
140 return lower; | |
141 }).hide(); | |
142 | |
143 } | |
144 } | |
145 | |
146 if (object == null) return null; | |
147 | |
148 object.extend(this); | |
149 object.$constructor = Type; | |
150 object.prototype.$constructor = object; | |
151 | |
152 return object; | |
153 }; | |
154 | |
155 var toString = Object.prototype.toString; | |
156 | |
157 Type.isEnumerable = function(item){ | |
158 return (item != null && typeof item.length == 'number' && toString.call(item)
!= '[object Function]' ); | |
159 }; | |
160 | |
161 var hooks = {}; | |
162 | |
163 var hooksOf = function(object){ | |
164 var type = typeOf(object.prototype); | |
165 return hooks[type] || (hooks[type] = []); | |
166 }; | |
167 | |
168 var implement = function(name, method){ | |
169 if (method && method.$hidden) return; | |
170 | |
171 var hooks = hooksOf(this); | |
172 | |
173 for (var i = 0; i < hooks.length; i++){ | |
174 var hook = hooks[i]; | |
175 if (typeOf(hook) == 'type') implement.call(hook, name, method); | |
176 else hook.call(this, name, method); | |
177 } | |
178 | |
179 var previous = this.prototype[name]; | |
180 if (previous == null || !previous.$protected) this.prototype[name] = method; | |
181 | |
182 if (this[name] == null && typeOf(method) == 'function') extend.call(this, name
, function(item){ | |
183 return method.apply(item, slice.call(arguments, 1)); | |
184 }); | |
185 }; | |
186 | |
187 var extend = function(name, method){ | |
188 if (method && method.$hidden) return; | |
189 var previous = this[name]; | |
190 if (previous == null || !previous.$protected) this[name] = method; | |
191 }; | |
192 | |
193 Type.implement({ | |
194 | |
195 implement: implement.overloadSetter(), | |
196 | |
197 extend: extend.overloadSetter(), | |
198 | |
199 alias: function(name, existing){ | |
200 implement.call(this, name, this.prototype[existing]); | |
201 }.overloadSetter(), | |
202 | |
203 mirror: function(hook){ | |
204 hooksOf(this).push(hook); | |
205 return this; | |
206 } | |
207 | |
208 }); | |
209 | |
210 new Type('Type', Type); | |
211 | |
212 // Default Types | |
213 | |
214 var force = function(name, object, methods){ | |
215 var isType = (object != Object), | |
216 prototype = object.prototype; | |
217 | |
218 if (isType) object = new Type(name, object); | |
219 | |
220 for (var i = 0, l = methods.length; i < l; i++){ | |
221 var key = methods[i], | |
222 generic = object[key], | |
223 proto = prototype[key]; | |
224 | |
225 if (generic) generic.protect(); | |
226 if (isType && proto) object.implement(key, proto.protect()); | |
227 } | |
228 | |
229 if (isType){ | |
230 var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]); | |
231 object.forEachMethod = function(fn){ | |
232 if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){ | |
233 fn.call(prototype, prototype[methods[i]], methods[i]); | |
234 } | |
235 for (var key in prototype) fn.call(prototype, prototype[key], key) | |
236 }; | |
237 } | |
238 | |
239 return force; | |
240 }; | |
241 | |
242 force('String', String, [ | |
243 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote',
'replace', 'search', | |
244 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase' | |
245 ])('Array', Array, [ | |
246 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'joi
n', 'slice', | |
247 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce
', 'reduceRight' | |
248 ])('Number', Number, [ | |
249 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision' | |
250 ])('Function', Function, [ | |
251 'apply', 'call', 'bind' | |
252 ])('RegExp', RegExp, [ | |
253 'exec', 'test' | |
254 ])('Object', Object, [ | |
255 'create', 'defineProperty', 'defineProperties', 'keys', | |
256 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', | |
257 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen' | |
258 ])('Date', Date, ['now']); | |
259 | |
260 Object.extend = extend.overloadSetter(); | |
261 | |
262 Date.extend('now', function(){ | |
263 return +(new Date); | |
264 }); | |
265 | |
266 new Type('Boolean', Boolean); | |
267 | |
268 // fixes NaN returning as Number | |
269 | |
270 Number.prototype.$family = function(){ | |
271 return isFinite(this) ? 'number' : 'null'; | |
272 }.hide(); | |
273 | |
274 // Number.random | |
275 | |
276 Number.extend('random', function(min, max){ | |
277 return Math.floor(Math.random() * (max - min + 1) + min); | |
278 }); | |
279 | |
280 // forEach, each | |
281 | |
282 var hasOwnProperty = Object.prototype.hasOwnProperty; | |
283 Object.extend('forEach', function(object, fn, bind){ | |
284 for (var key in object){ | |
285 if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object
); | |
286 } | |
287 }); | |
288 | |
289 Object.each = Object.forEach; | |
290 | |
291 Array.implement({ | |
292 | |
293 forEach: function(fn, bind){ | |
294 for (var i = 0, l = this.length; i < l; i++){ | |
295 if (i in this) fn.call(bind, this[i], i, this); | |
296 } | |
297 }, | |
298 | |
299 each: function(fn, bind){ | |
300 Array.forEach(this, fn, bind); | |
301 return this; | |
302 } | |
303 | |
304 }); | |
305 | |
306 // Array & Object cloning, Object merging and appending | |
307 | |
308 var cloneOf = function(item){ | |
309 switch (typeOf(item)){ | |
310 case 'array': return item.clone(); | |
311 case 'object': return Object.clone(item); | |
312 default: return item; | |
313 } | |
314 }; | |
315 | |
316 Array.implement('clone', function(){ | |
317 var i = this.length, clone = new Array(i); | |
318 while (i--) clone[i] = cloneOf(this[i]); | |
319 return clone; | |
320 }); | |
321 | |
322 var mergeOne = function(source, key, current){ | |
323 switch (typeOf(current)){ | |
324 case 'object': | |
325 if (typeOf(source[key]) == 'object') Object.merge(source[key], current); | |
326 else source[key] = Object.clone(current); | |
327 break; | |
328 case 'array': source[key] = current.clone(); break; | |
329 default: source[key] = current; | |
330 } | |
331 return source; | |
332 }; | |
333 | |
334 Object.extend({ | |
335 | |
336 merge: function(source, k, v){ | |
337 if (typeOf(k) == 'string') return mergeOne(source, k, v); | |
338 for (var i = 1, l = arguments.length; i < l; i++){ | |
339 var object = arguments[i]; | |
340 for (var key in object) mergeOne(source, key, object[key]); | |
341 } | |
342 return source; | |
343 }, | |
344 | |
345 clone: function(object){ | |
346 var clone = {}; | |
347 for (var key in object) clone[key] = cloneOf(object[key]); | |
348 return clone; | |
349 }, | |
350 | |
351 append: function(original){ | |
352 for (var i = 1, l = arguments.length; i < l; i++){ | |
353 var extended = arguments[i] || {}; | |
354 for (var key in extended) original[key] = extended[key]; | |
355 } | |
356 return original; | |
357 } | |
358 | |
359 }); | |
360 | |
361 // Object-less types | |
362 | |
363 ['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(na
me){ | |
364 new Type(name); | |
365 }); | |
366 | |
367 // Unique ID | |
368 | |
369 var UID = Date.now(); | |
370 | |
371 String.extend('uniqueID', function(){ | |
372 return (UID++).toString(36); | |
373 }); | |
374 | |
375 | |
376 | |
377 })(); | |
378 | |
379 | |
380 /* | |
381 --- | |
382 | |
383 name: Array | |
384 | |
385 description: Contains Array Prototypes like each, contains, and erase. | |
386 | |
387 license: MIT-style license. | |
388 | |
389 requires: Type | |
390 | |
391 provides: Array | |
392 | |
393 ... | |
394 */ | |
395 | |
396 Array.implement({ | |
397 | |
398 /*<!ES5>*/ | |
399 every: function(fn, bind){ | |
400 for (var i = 0, l = this.length >>> 0; i < l; i++){ | |
401 if ((i in this) && !fn.call(bind, this[i], i, this)) return false; | |
402 } | |
403 return true; | |
404 }, | |
405 | |
406 filter: function(fn, bind){ | |
407 var results = []; | |
408 for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){ | |
409 value = this[i]; | |
410 if (fn.call(bind, value, i, this)) results.push(value); | |
411 } | |
412 return results; | |
413 }, | |
414 | |
415 indexOf: function(item, from){ | |
416 var length = this.length >>> 0; | |
417 for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length
; i++){ | |
418 if (this[i] === item) return i; | |
419 } | |
420 return -1; | |
421 }, | |
422 | |
423 map: function(fn, bind){ | |
424 var length = this.length >>> 0, results = Array(length); | |
425 for (var i = 0; i < length; i++){ | |
426 if (i in this) results[i] = fn.call(bind, this[i], i, this); | |
427 } | |
428 return results; | |
429 }, | |
430 | |
431 some: function(fn, bind){ | |
432 for (var i = 0, l = this.length >>> 0; i < l; i++){ | |
433 if ((i in this) && fn.call(bind, this[i], i, this)) return true; | |
434 } | |
435 return false; | |
436 }, | |
437 /*</!ES5>*/ | |
438 | |
439 clean: function(){ | |
440 return this.filter(function(item){ | |
441 return item != null; | |
442 }); | |
443 }, | |
444 | |
445 invoke: function(methodName){ | |
446 var args = Array.slice(arguments, 1); | |
447 return this.map(function(item){ | |
448 return item[methodName].apply(item, args); | |
449 }); | |
450 }, | |
451 | |
452 associate: function(keys){ | |
453 var obj = {}, length = Math.min(this.length, keys.length); | |
454 for (var i = 0; i < length; i++) obj[keys[i]] = this[i]; | |
455 return obj; | |
456 }, | |
457 | |
458 link: function(object){ | |
459 var result = {}; | |
460 for (var i = 0, l = this.length; i < l; i++){ | |
461 for (var key in object){ | |
462 if (object[key](this[i])){ | |
463 result[key] = this[i]; | |
464 delete object[key]; | |
465 break; | |
466 } | |
467 } | |
468 } | |
469 return result; | |
470 }, | |
471 | |
472 contains: function(item, from){ | |
473 return this.indexOf(item, from) != -1; | |
474 }, | |
475 | |
476 append: function(array){ | |
477 this.push.apply(this, array); | |
478 return this; | |
479 }, | |
480 | |
481 getLast: function(){ | |
482 return (this.length) ? this[this.length - 1] : null; | |
483 }, | |
484 | |
485 getRandom: function(){ | |
486 return (this.length) ? this[Number.random(0, this.length - 1)] : null; | |
487 }, | |
488 | |
489 include: function(item){ | |
490 if (!this.contains(item)) this.push(item); | |
491 return this; | |
492 }, | |
493 | |
494 combine: function(array){ | |
495 for (var i = 0, l = array.length; i < l; i++) this.include(array[i]); | |
496 return this; | |
497 }, | |
498 | |
499 erase: function(item){ | |
500 for (var i = this.length; i--;){ | |
501 if (this[i] === item) this.splice(i, 1); | |
502 } | |
503 return this; | |
504 }, | |
505 | |
506 empty: function(){ | |
507 this.length = 0; | |
508 return this; | |
509 }, | |
510 | |
511 flatten: function(){ | |
512 var array = []; | |
513 for (var i = 0, l = this.length; i < l; i++){ | |
514 var type = typeOf(this[i]); | |
515 if (type == 'null') continue; | |
516 array = array.concat((type == 'array' || type == 'collection' || type == '
arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]); | |
517 } | |
518 return array; | |
519 }, | |
520 | |
521 pick: function(){ | |
522 for (var i = 0, l = this.length; i < l; i++){ | |
523 if (this[i] != null) return this[i]; | |
524 } | |
525 return null; | |
526 }, | |
527 | |
528 hexToRgb: function(array){ | |
529 if (this.length != 3) return null; | |
530 var rgb = this.map(function(value){ | |
531 if (value.length == 1) value += value; | |
532 return value.toInt(16); | |
533 }); | |
534 return (array) ? rgb : 'rgb(' + rgb + ')'; | |
535 }, | |
536 | |
537 rgbToHex: function(array){ | |
538 if (this.length < 3) return null; | |
539 if (this.length == 4 && this[3] == 0 && !array) return 'transparent'; | |
540 var hex = []; | |
541 for (var i = 0; i < 3; i++){ | |
542 var bit = (this[i] - 0).toString(16); | |
543 hex.push((bit.length == 1) ? '0' + bit : bit); | |
544 } | |
545 return (array) ? hex : '#' + hex.join(''); | |
546 } | |
547 | |
548 }); | |
549 | |
550 | |
551 | |
552 | |
553 /* | |
554 --- | |
555 | |
556 name: Function | |
557 | |
558 description: Contains Function Prototypes like create, bind, pass, and delay. | |
559 | |
560 license: MIT-style license. | |
561 | |
562 requires: Type | |
563 | |
564 provides: Function | |
565 | |
566 ... | |
567 */ | |
568 | |
569 Function.extend({ | |
570 | |
571 attempt: function(){ | |
572 for (var i = 0, l = arguments.length; i < l; i++){ | |
573 try { | |
574 return arguments[i](); | |
575 } catch (e){} | |
576 } | |
577 return null; | |
578 } | |
579 | |
580 }); | |
581 | |
582 Function.implement({ | |
583 | |
584 attempt: function(args, bind){ | |
585 try { | |
586 return this.apply(bind, Array.from(args)); | |
587 } catch (e){} | |
588 | |
589 return null; | |
590 }, | |
591 | |
592 /*<!ES5-bind>*/ | |
593 bind: function(that){ | |
594 var self = this, | |
595 args = arguments.length > 1 ? Array.slice(arguments, 1) : null, | |
596 F = function(){}; | |
597 | |
598 var bound = function(){ | |
599 var context = that, length = arguments.length; | |
600 if (this instanceof bound){ | |
601 F.prototype = self.prototype; | |
602 context = new F; | |
603 } | |
604 var result = (!args && !length) | |
605 ? self.call(context) | |
606 : self.apply(context, args && length ? args.concat(Array.slice(arguments
)) : args || arguments); | |
607 return context == that ? result : context; | |
608 }; | |
609 return bound; | |
610 }, | |
611 /*</!ES5-bind>*/ | |
612 | |
613 pass: function(args, bind){ | |
614 var self = this; | |
615 if (args != null) args = Array.from(args); | |
616 return function(){ | |
617 return self.apply(bind, args || arguments); | |
618 }; | |
619 }, | |
620 | |
621 delay: function(delay, bind, args){ | |
622 return setTimeout(this.pass((args == null ? [] : args), bind), delay); | |
623 }, | |
624 | |
625 periodical: function(periodical, bind, args){ | |
626 return setInterval(this.pass((args == null ? [] : args), bind), periodical); | |
627 } | |
628 | |
629 }); | |
630 | |
631 | |
632 | |
633 | |
634 /* | |
635 --- | |
636 | |
637 name: Number | |
638 | |
639 description: Contains Number Prototypes like limit, round, times, and ceil. | |
640 | |
641 license: MIT-style license. | |
642 | |
643 requires: Type | |
644 | |
645 provides: Number | |
646 | |
647 ... | |
648 */ | |
649 | |
650 Number.implement({ | |
651 | |
652 limit: function(min, max){ | |
653 return Math.min(max, Math.max(min, this)); | |
654 }, | |
655 | |
656 round: function(precision){ | |
657 precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision
: 0); | |
658 return Math.round(this * precision) / precision; | |
659 }, | |
660 | |
661 times: function(fn, bind){ | |
662 for (var i = 0; i < this; i++) fn.call(bind, i, this); | |
663 }, | |
664 | |
665 toFloat: function(){ | |
666 return parseFloat(this); | |
667 }, | |
668 | |
669 toInt: function(base){ | |
670 return parseInt(this, base || 10); | |
671 } | |
672 | |
673 }); | |
674 | |
675 Number.alias('each', 'times'); | |
676 | |
677 (function(math){ | |
678 var methods = {}; | |
679 math.each(function(name){ | |
680 if (!Number[name]) methods[name] = function(){ | |
681 return Math[name].apply(null, [this].concat(Array.from(arguments))); | |
682 }; | |
683 }); | |
684 Number.implement(methods); | |
685 })(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log'
, 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']); | |
686 | |
687 | |
688 /* | |
689 --- | |
690 | |
691 name: String | |
692 | |
693 description: Contains String Prototypes like camelCase, capitalize, test, and to
Int. | |
694 | |
695 license: MIT-style license. | |
696 | |
697 requires: Type | |
698 | |
699 provides: String | |
700 | |
701 ... | |
702 */ | |
703 | |
704 String.implement({ | |
705 | |
706 test: function(regex, params){ | |
707 return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)
).test(this); | |
708 }, | |
709 | |
710 contains: function(string, separator){ | |
711 return (separator) ? (separator + this + separator).indexOf(separator + stri
ng + separator) > -1 : String(this).indexOf(string) > -1; | |
712 }, | |
713 | |
714 trim: function(){ | |
715 return String(this).replace(/^\s+|\s+$/g, ''); | |
716 }, | |
717 | |
718 clean: function(){ | |
719 return String(this).replace(/\s+/g, ' ').trim(); | |
720 }, | |
721 | |
722 camelCase: function(){ | |
723 return String(this).replace(/-\D/g, function(match){ | |
724 return match.charAt(1).toUpperCase(); | |
725 }); | |
726 }, | |
727 | |
728 hyphenate: function(){ | |
729 return String(this).replace(/[A-Z]/g, function(match){ | |
730 return ('-' + match.charAt(0).toLowerCase()); | |
731 }); | |
732 }, | |
733 | |
734 capitalize: function(){ | |
735 return String(this).replace(/\b[a-z]/g, function(match){ | |
736 return match.toUpperCase(); | |
737 }); | |
738 }, | |
739 | |
740 escapeRegExp: function(){ | |
741 return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1'); | |
742 }, | |
743 | |
744 toInt: function(base){ | |
745 return parseInt(this, base || 10); | |
746 }, | |
747 | |
748 toFloat: function(){ | |
749 return parseFloat(this); | |
750 }, | |
751 | |
752 hexToRgb: function(array){ | |
753 var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/); | |
754 return (hex) ? hex.slice(1).hexToRgb(array) : null; | |
755 }, | |
756 | |
757 rgbToHex: function(array){ | |
758 var rgb = String(this).match(/\d{1,3}/g); | |
759 return (rgb) ? rgb.rgbToHex(array) : null; | |
760 }, | |
761 | |
762 substitute: function(object, regexp){ | |
763 return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match,
name){ | |
764 if (match.charAt(0) == '\\') return match.slice(1); | |
765 return (object[name] != null) ? object[name] : ''; | |
766 }); | |
767 } | |
768 | |
769 }); | |
770 | |
771 | |
772 /* | |
773 --- | |
774 | |
775 name: Browser | |
776 | |
777 description: The Browser Object. Contains Browser initialization, Window and Doc
ument, and the Browser Hash. | |
778 | |
779 license: MIT-style license. | |
780 | |
781 requires: [Array, Function, Number, String] | |
782 | |
783 provides: [Browser, Window, Document] | |
784 | |
785 ... | |
786 */ | |
787 | |
788 (function(){ | |
789 | |
790 var document = this.document; | |
791 var window = document.window = this; | |
792 | |
793 var ua = navigator.userAgent.toLowerCase(), | |
794 platform = navigator.platform.toLowerCase(), | |
795 UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|
version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0], | |
796 mode = UA[1] == 'ie' && document.documentMode; | |
797 | |
798 var Browser = this.Browser = { | |
799 | |
800 extend: Function.prototype.extend, | |
801 | |
802 name: (UA[1] == 'version') ? UA[3] : UA[1], | |
803 | |
804 version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]), | |
805 | |
806 Platform: { | |
807 name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/)
|| platform.match(/mac|win|linux/) || ['other'])[0] | |
808 }, | |
809 | |
810 Features: { | |
811 xpath: !!(document.evaluate), | |
812 air: !!(window.runtime), | |
813 query: !!(document.querySelector), | |
814 json: !!(window.JSON) | |
815 }, | |
816 | |
817 Plugins: {} | |
818 | |
819 }; | |
820 | |
821 Browser[Browser.name] = true; | |
822 Browser[Browser.name + parseInt(Browser.version, 10)] = true; | |
823 Browser.Platform[Browser.Platform.name] = true; | |
824 | |
825 // Request | |
826 | |
827 Browser.Request = (function(){ | |
828 | |
829 var XMLHTTP = function(){ | |
830 return new XMLHttpRequest(); | |
831 }; | |
832 | |
833 var MSXML2 = function(){ | |
834 return new ActiveXObject('MSXML2.XMLHTTP'); | |
835 }; | |
836 | |
837 var MSXML = function(){ | |
838 return new ActiveXObject('Microsoft.XMLHTTP'); | |
839 }; | |
840 | |
841 return Function.attempt(function(){ | |
842 XMLHTTP(); | |
843 return XMLHTTP; | |
844 }, function(){ | |
845 MSXML2(); | |
846 return MSXML2; | |
847 }, function(){ | |
848 MSXML(); | |
849 return MSXML; | |
850 }); | |
851 | |
852 })(); | |
853 | |
854 Browser.Features.xhr = !!(Browser.Request); | |
855 | |
856 // Flash detection | |
857 | |
858 var version = (Function.attempt(function(){ | |
859 return navigator.plugins['Shockwave Flash'].description; | |
860 }, function(){ | |
861 return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$versio
n'); | |
862 }) || '0 r0').match(/\d+/g); | |
863 | |
864 Browser.Plugins.Flash = { | |
865 version: Number(version[0] || '0.' + version[1]) || 0, | |
866 build: Number(version[2]) || 0 | |
867 }; | |
868 | |
869 // String scripts | |
870 | |
871 Browser.exec = function(text){ | |
872 if (!text) return text; | |
873 if (window.execScript){ | |
874 window.execScript(text); | |
875 } else { | |
876 var script = document.createElement('script'); | |
877 script.setAttribute('type', 'text/javascript'); | |
878 script.text = text; | |
879 document.head.appendChild(script); | |
880 document.head.removeChild(script); | |
881 } | |
882 return text; | |
883 }; | |
884 | |
885 String.implement('stripScripts', function(exec){ | |
886 var scripts = ''; | |
887 var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, c
ode){ | |
888 scripts += code + '\n'; | |
889 return ''; | |
890 }); | |
891 if (exec === true) Browser.exec(scripts); | |
892 else if (typeOf(exec) == 'function') exec(scripts, text); | |
893 return text; | |
894 }); | |
895 | |
896 // Window, Document | |
897 | |
898 Browser.extend({ | |
899 Document: this.Document, | |
900 Window: this.Window, | |
901 Element: this.Element, | |
902 Event: this.Event | |
903 }); | |
904 | |
905 this.Window = this.$constructor = new Type('Window', function(){}); | |
906 | |
907 this.$family = Function.from('window').hide(); | |
908 | |
909 Window.mirror(function(name, method){ | |
910 window[name] = method; | |
911 }); | |
912 | |
913 this.Document = document.$constructor = new Type('Document', function(){}); | |
914 | |
915 document.$family = Function.from('document').hide(); | |
916 | |
917 Document.mirror(function(name, method){ | |
918 document[name] = method; | |
919 }); | |
920 | |
921 document.html = document.documentElement; | |
922 if (!document.head) document.head = document.getElementsByTagName('head')[0]; | |
923 | |
924 if (document.execCommand) try { | |
925 document.execCommand("BackgroundImageCache", false, true); | |
926 } catch (e){} | |
927 | |
928 /*<ltIE9>*/ | |
929 if (this.attachEvent && !this.addEventListener){ | |
930 var unloadEvent = function(){ | |
931 this.detachEvent('onunload', unloadEvent); | |
932 document.head = document.html = document.window = null; | |
933 }; | |
934 this.attachEvent('onunload', unloadEvent); | |
935 } | |
936 | |
937 // IE fails on collections and <select>.options (refers to <select>) | |
938 var arrayFrom = Array.from; | |
939 try { | |
940 arrayFrom(document.html.childNodes); | |
941 } catch(e){ | |
942 Array.from = function(item){ | |
943 if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'a
rray'){ | |
944 var i = item.length, array = new Array(i); | |
945 while (i--) array[i] = item[i]; | |
946 return array; | |
947 } | |
948 return arrayFrom(item); | |
949 }; | |
950 | |
951 var prototype = Array.prototype, | |
952 slice = prototype.slice; | |
953 ['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'jo
in', 'slice'].each(function(name){ | |
954 var method = prototype[name]; | |
955 Array[name] = function(item){ | |
956 return method.apply(Array.from(item), slice.call(arguments, 1)); | |
957 }; | |
958 }); | |
959 } | |
960 /*</ltIE9>*/ | |
961 | |
962 | |
963 | |
964 })(); | |
965 | |
966 | |
967 /* | |
968 --- | |
969 | |
970 name: Object | |
971 | |
972 description: Object generic methods | |
973 | |
974 license: MIT-style license. | |
975 | |
976 requires: Type | |
977 | |
978 provides: [Object, Hash] | |
979 | |
980 ... | |
981 */ | |
982 | |
983 (function(){ | |
984 | |
985 var hasOwnProperty = Object.prototype.hasOwnProperty; | |
986 | |
987 Object.extend({ | |
988 | |
989 subset: function(object, keys){ | |
990 var results = {}; | |
991 for (var i = 0, l = keys.length; i < l; i++){ | |
992 var k = keys[i]; | |
993 if (k in object) results[k] = object[k]; | |
994 } | |
995 return results; | |
996 }, | |
997 | |
998 map: function(object, fn, bind){ | |
999 var results = {}; | |
1000 for (var key in object){ | |
1001 if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[
key], key, object); | |
1002 } | |
1003 return results; | |
1004 }, | |
1005 | |
1006 filter: function(object, fn, bind){ | |
1007 var results = {}; | |
1008 for (var key in object){ | |
1009 var value = object[key]; | |
1010 if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object))
results[key] = value; | |
1011 } | |
1012 return results; | |
1013 }, | |
1014 | |
1015 every: function(object, fn, bind){ | |
1016 for (var key in object){ | |
1017 if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key))
return false; | |
1018 } | |
1019 return true; | |
1020 }, | |
1021 | |
1022 some: function(object, fn, bind){ | |
1023 for (var key in object){ | |
1024 if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) r
eturn true; | |
1025 } | |
1026 return false; | |
1027 }, | |
1028 | |
1029 keys: function(object){ | |
1030 var keys = []; | |
1031 for (var key in object){ | |
1032 if (hasOwnProperty.call(object, key)) keys.push(key); | |
1033 } | |
1034 return keys; | |
1035 }, | |
1036 | |
1037 values: function(object){ | |
1038 var values = []; | |
1039 for (var key in object){ | |
1040 if (hasOwnProperty.call(object, key)) values.push(object[key]); | |
1041 } | |
1042 return values; | |
1043 }, | |
1044 | |
1045 getLength: function(object){ | |
1046 return Object.keys(object).length; | |
1047 }, | |
1048 | |
1049 keyOf: function(object, value){ | |
1050 for (var key in object){ | |
1051 if (hasOwnProperty.call(object, key) && object[key] === value) return key; | |
1052 } | |
1053 return null; | |
1054 }, | |
1055 | |
1056 contains: function(object, value){ | |
1057 return Object.keyOf(object, value) != null; | |
1058 }, | |
1059 | |
1060 toQueryString: function(object, base){ | |
1061 var queryString = []; | |
1062 | |
1063 Object.each(object, function(value, key){ | |
1064 if (base) key = base + '[' + key + ']'; | |
1065 var result; | |
1066 switch (typeOf(value)){ | |
1067 case 'object': result = Object.toQueryString(value, key); break; | |
1068 case 'array': | |
1069 var qs = {}; | |
1070 value.each(function(val, i){ | |
1071 qs[i] = val; | |
1072 }); | |
1073 result = Object.toQueryString(qs, key); | |
1074 break; | |
1075 default: result = key + '=' + encodeURIComponent(value); | |
1076 } | |
1077 if (value != null) queryString.push(result); | |
1078 }); | |
1079 | |
1080 return queryString.join('&'); | |
1081 } | |
1082 | |
1083 }); | |
1084 | |
1085 })(); | |
1086 | |
1087 | |
1088 | |
1089 | |
1090 /* | |
1091 --- | |
1092 | |
1093 name: Event | |
1094 | |
1095 description: Contains the Event Type, to make the event object cross-browser. | |
1096 | |
1097 license: MIT-style license. | |
1098 | |
1099 requires: [Window, Document, Array, Function, String, Object] | |
1100 | |
1101 provides: Event | |
1102 | |
1103 ... | |
1104 */ | |
1105 | |
1106 (function() { | |
1107 | |
1108 var _keys = {}; | |
1109 | |
1110 var DOMEvent = this.DOMEvent = new Type('DOMEvent', function(event, win){ | |
1111 if (!win) win = window; | |
1112 event = event || win.event; | |
1113 if (event.$extended) return event; | |
1114 this.event = event; | |
1115 this.$extended = true; | |
1116 this.shift = event.shiftKey; | |
1117 this.control = event.ctrlKey; | |
1118 this.alt = event.altKey; | |
1119 this.meta = event.metaKey; | |
1120 var type = this.type = event.type; | |
1121 var target = event.target || event.srcElement; | |
1122 while (target && target.nodeType == 3) target = target.parentNode; | |
1123 this.target = document.id(target); | |
1124 | |
1125 if (type.indexOf('key') == 0){ | |
1126 var code = this.code = (event.which || event.keyCode); | |
1127 this.key = _keys[code]; | |
1128 if (type == 'keydown'){ | |
1129 if (code > 111 && code < 124) this.key = 'f' + (code - 111); | |
1130 else if (code > 95 && code < 106) this.key = code - 96; | |
1131 } | |
1132 if (this.key == null) this.key = String.fromCharCode(code).toLowerCase(); | |
1133 } else if (type == 'click' || type == 'dblclick' || type == 'contextmenu' || t
ype == 'DOMMouseScroll' || type.indexOf('mouse') == 0){ | |
1134 var doc = win.document; | |
1135 doc = (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.b
ody; | |
1136 this.page = { | |
1137 x: (event.pageX != null) ? event.pageX : event.clientX + doc.scrollLeft, | |
1138 y: (event.pageY != null) ? event.pageY : event.clientY + doc.scrollTop | |
1139 }; | |
1140 this.client = { | |
1141 x: (event.pageX != null) ? event.pageX - win.pageXOffset : event.clientX, | |
1142 y: (event.pageY != null) ? event.pageY - win.pageYOffset : event.clientY | |
1143 }; | |
1144 if (type == 'DOMMouseScroll' || type == 'mousewheel') | |
1145 this.wheel = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail
|| 0) / 3; | |
1146 | |
1147 this.rightClick = (event.which == 3 || event.button == 2); | |
1148 if (type == 'mouseover' || type == 'mouseout'){ | |
1149 var related = event.relatedTarget || event[(type == 'mouseover' ? 'from' :
'to') + 'Element']; | |
1150 while (related && related.nodeType == 3) related = related.parentNode; | |
1151 this.relatedTarget = document.id(related); | |
1152 } | |
1153 } else if (type.indexOf('touch') == 0 || type.indexOf('gesture') == 0){ | |
1154 this.rotation = event.rotation; | |
1155 this.scale = event.scale; | |
1156 this.targetTouches = event.targetTouches; | |
1157 this.changedTouches = event.changedTouches; | |
1158 var touches = this.touches = event.touches; | |
1159 if (touches && touches[0]){ | |
1160 var touch = touches[0]; | |
1161 this.page = {x: touch.pageX, y: touch.pageY}; | |
1162 this.client = {x: touch.clientX, y: touch.clientY}; | |
1163 } | |
1164 } | |
1165 | |
1166 if (!this.client) this.client = {}; | |
1167 if (!this.page) this.page = {}; | |
1168 }); | |
1169 | |
1170 DOMEvent.implement({ | |
1171 | |
1172 stop: function(){ | |
1173 return this.preventDefault().stopPropagation(); | |
1174 }, | |
1175 | |
1176 stopPropagation: function(){ | |
1177 if (this.event.stopPropagation) this.event.stopPropagation(); | |
1178 else this.event.cancelBubble = true; | |
1179 return this; | |
1180 }, | |
1181 | |
1182 preventDefault: function(){ | |
1183 if (this.event.preventDefault) this.event.preventDefault(); | |
1184 else this.event.returnValue = false; | |
1185 return this; | |
1186 } | |
1187 | |
1188 }); | |
1189 | |
1190 DOMEvent.defineKey = function(code, key){ | |
1191 _keys[code] = key; | |
1192 return this; | |
1193 }; | |
1194 | |
1195 DOMEvent.defineKeys = DOMEvent.defineKey.overloadSetter(true); | |
1196 | |
1197 DOMEvent.defineKeys({ | |
1198 '38': 'up', '40': 'down', '37': 'left', '39': 'right', | |
1199 '27': 'esc', '32': 'space', '8': 'backspace', '9': 'tab', | |
1200 '46': 'delete', '13': 'enter' | |
1201 }); | |
1202 | |
1203 })(); | |
1204 | |
1205 | |
1206 | |
1207 | |
1208 | |
1209 | |
1210 /* | |
1211 --- | |
1212 name: Slick.Parser | |
1213 description: Standalone CSS3 Selector parser | |
1214 provides: Slick.Parser | |
1215 ... | |
1216 */ | |
1217 | |
1218 ;(function(){ | |
1219 | |
1220 var parsed, | |
1221 separatorIndex, | |
1222 combinatorIndex, | |
1223 reversed, | |
1224 cache = {}, | |
1225 reverseCache = {}, | |
1226 reUnescape = /\\/g; | |
1227 | |
1228 var parse = function(expression, isReversed){ | |
1229 if (expression == null) return null; | |
1230 if (expression.Slick === true) return expression; | |
1231 expression = ('' + expression).replace(/^\s+|\s+$/g, ''); | |
1232 reversed = !!isReversed; | |
1233 var currentCache = (reversed) ? reverseCache : cache; | |
1234 if (currentCache[expression]) return currentCache[expression]; | |
1235 parsed = { | |
1236 Slick: true, | |
1237 expressions: [], | |
1238 raw: expression, | |
1239 reverse: function(){ | |
1240 return parse(this.raw, true); | |
1241 } | |
1242 }; | |
1243 separatorIndex = -1; | |
1244 while (expression != (expression = expression.replace(regexp, parser))); | |
1245 parsed.length = parsed.expressions.length; | |
1246 return currentCache[parsed.raw] = (reversed) ? reverse(parsed) : parsed; | |
1247 }; | |
1248 | |
1249 var reverseCombinator = function(combinator){ | |
1250 if (combinator === '!') return ' '; | |
1251 else if (combinator === ' ') return '!'; | |
1252 else if ((/^!/).test(combinator)) return combinator.replace(/^!/, ''); | |
1253 else return '!' + combinator; | |
1254 }; | |
1255 | |
1256 var reverse = function(expression){ | |
1257 var expressions = expression.expressions; | |
1258 for (var i = 0; i < expressions.length; i++){ | |
1259 var exp = expressions[i]; | |
1260 var last = {parts: [], tag: '*', combinator: reverseCombinator(exp[0].combin
ator)}; | |
1261 | |
1262 for (var j = 0; j < exp.length; j++){ | |
1263 var cexp = exp[j]; | |
1264 if (!cexp.reverseCombinator) cexp.reverseCombinator = ' '; | |
1265 cexp.combinator = cexp.reverseCombinator; | |
1266 delete cexp.reverseCombinator; | |
1267 } | |
1268 | |
1269 exp.reverse().push(last); | |
1270 } | |
1271 return expression; | |
1272 }; | |
1273 | |
1274 var escapeRegExp = function(string){// Credit: XRegExp 0.6.1 (c) 2007-2008 Steve
n Levithan <http://stevenlevithan.com/regex/xregexp/> MIT License | |
1275 return string.replace(/[-[\]{}()*+?.\\^$|,#\s]/g, function(match){ | |
1276 return '\\' + match; | |
1277 }); | |
1278 }; | |
1279 | |
1280 var regexp = new RegExp( | |
1281 /* | |
1282 #!/usr/bin/env ruby | |
1283 puts "\t\t" + DATA.read.gsub(/\(\?x\)|\s+#.*$|\s+|\\$|\\n/,'') | |
1284 __END__ | |
1285 "(?x)^(?:\ | |
1286 \\s* ( , ) \\s* # Separator \n\ | |
1287 | \\s* ( <combinator>+ ) \\s* # Combinator \n\ | |
1288 | ( \\s+ ) # CombinatorChildren \n\ | |
1289 | ( <unicode>+ | \\* ) # Tag \n\ | |
1290 | \\# ( <unicode>+ ) # ID \n\ | |
1291 | \\. ( <unicode>+ ) # ClassName \n\ | |
1292 | # Attribute \n\ | |
1293 \\[ \ | |
1294 \\s* (<unicode1>+) (?: \ | |
1295 \\s* ([*^$!~|]?=) (?: \ | |
1296 \\s* (?:\ | |
1297 ([\"']?)(.*?)\\9 \ | |
1298 )\ | |
1299 ) \ | |
1300 )? \\s* \ | |
1301 \\](?!\\]) \n\ | |
1302 | :+ ( <unicode>+ )(?:\ | |
1303 \\( (?:\ | |
1304 (?:([\"'])([^\\12]*)\\12)|((?:\\([^)]+\\)|[^()]*)+)\ | |
1305 ) \\)\ | |
1306 )?\ | |
1307 )" | |
1308 */ | |
1309 "^(?:\\s*(,)\\s*|\\s*(<combinator>+)\\s*|(\\s+)|(<unicode>+|\\*)|\\#(<unicode>
+)|\\.(<unicode>+)|\\[\\s*(<unicode1>+)(?:\\s*([*^$!~|]?=)(?:\\s*(?:([\"']?)(.*?
)\\9)))?\\s*\\](?!\\])|(:+)(<unicode>+)(?:\\((?:(?:([\"'])([^\\13]*)\\13)|((?:\\
([^)]+\\)|[^()]*)+))\\))?)" | |
1310 .replace(/<combinator>/, '[' + escapeRegExp(">+~`!@$%^&={}\\;</") + ']') | |
1311 .replace(/<unicode>/g, '(?:[\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') | |
1312 .replace(/<unicode1>/g, '(?:[:\\w\\u00a1-\\uFFFF-]|\\\\[^\\s0-9a-f])') | |
1313 ); | |
1314 | |
1315 function parser( | |
1316 rawMatch, | |
1317 | |
1318 separator, | |
1319 combinator, | |
1320 combinatorChildren, | |
1321 | |
1322 tagName, | |
1323 id, | |
1324 className, | |
1325 | |
1326 attributeKey, | |
1327 attributeOperator, | |
1328 attributeQuote, | |
1329 attributeValue, | |
1330 | |
1331 pseudoMarker, | |
1332 pseudoClass, | |
1333 pseudoQuote, | |
1334 pseudoClassQuotedValue, | |
1335 pseudoClassValue | |
1336 ){ | |
1337 if (separator || separatorIndex === -1){ | |
1338 parsed.expressions[++separatorIndex] = []; | |
1339 combinatorIndex = -1; | |
1340 if (separator) return ''; | |
1341 } | |
1342 | |
1343 if (combinator || combinatorChildren || combinatorIndex === -1){ | |
1344 combinator = combinator || ' '; | |
1345 var currentSeparator = parsed.expressions[separatorIndex]; | |
1346 if (reversed && currentSeparator[combinatorIndex]) | |
1347 currentSeparator[combinatorIndex].reverseCombinator = reverseCombinator(co
mbinator); | |
1348 currentSeparator[++combinatorIndex] = {combinator: combinator, tag: '*'}; | |
1349 } | |
1350 | |
1351 var currentParsed = parsed.expressions[separatorIndex][combinatorIndex]; | |
1352 | |
1353 if (tagName){ | |
1354 currentParsed.tag = tagName.replace(reUnescape, ''); | |
1355 | |
1356 } else if (id){ | |
1357 currentParsed.id = id.replace(reUnescape, ''); | |
1358 | |
1359 } else if (className){ | |
1360 className = className.replace(reUnescape, ''); | |
1361 | |
1362 if (!currentParsed.classList) currentParsed.classList = []; | |
1363 if (!currentParsed.classes) currentParsed.classes = []; | |
1364 currentParsed.classList.push(className); | |
1365 currentParsed.classes.push({ | |
1366 value: className, | |
1367 regexp: new RegExp('(^|\\s)' + escapeRegExp(className) + '(\\s|$)') | |
1368 }); | |
1369 | |
1370 } else if (pseudoClass){ | |
1371 pseudoClassValue = pseudoClassValue || pseudoClassQuotedValue; | |
1372 pseudoClassValue = pseudoClassValue ? pseudoClassValue.replace(reUnescape, '
') : null; | |
1373 | |
1374 if (!currentParsed.pseudos) currentParsed.pseudos = []; | |
1375 currentParsed.pseudos.push({ | |
1376 key: pseudoClass.replace(reUnescape, ''), | |
1377 value: pseudoClassValue, | |
1378 type: pseudoMarker.length == 1 ? 'class' : 'element' | |
1379 }); | |
1380 | |
1381 } else if (attributeKey){ | |
1382 attributeKey = attributeKey.replace(reUnescape, ''); | |
1383 attributeValue = (attributeValue || '').replace(reUnescape, ''); | |
1384 | |
1385 var test, regexp; | |
1386 | |
1387 switch (attributeOperator){ | |
1388 case '^=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue)
); break; | |
1389 case '$=' : regexp = new RegExp( escapeRegExp(attributeValue) +
'$' ); break; | |
1390 case '~=' : regexp = new RegExp( '(^|\\s)'+ escapeRegExp(attributeValue) +
'(\\s|$)' ); break; | |
1391 case '|=' : regexp = new RegExp( '^'+ escapeRegExp(attributeValue) +
'(-|$)' ); break; | |
1392 case '=' : test = function(value){ | |
1393 return attributeValue == value; | |
1394 }; break; | |
1395 case '*=' : test = function(value){ | |
1396 return value && value.indexOf(attributeValue) > -1; | |
1397 }; break; | |
1398 case '!=' : test = function(value){ | |
1399 return attributeValue != value; | |
1400 }; break; | |
1401 default : test = function(value){ | |
1402 return !!value; | |
1403 }; | |
1404 } | |
1405 | |
1406 if (attributeValue == '' && (/^[*$^]=$/).test(attributeOperator)) test = fun
ction(){ | |
1407 return false; | |
1408 }; | |
1409 | |
1410 if (!test) test = function(value){ | |
1411 return value && regexp.test(value); | |
1412 }; | |
1413 | |
1414 if (!currentParsed.attributes) currentParsed.attributes = []; | |
1415 currentParsed.attributes.push({ | |
1416 key: attributeKey, | |
1417 operator: attributeOperator, | |
1418 value: attributeValue, | |
1419 test: test | |
1420 }); | |
1421 | |
1422 } | |
1423 | |
1424 return ''; | |
1425 }; | |
1426 | |
1427 // Slick NS | |
1428 | |
1429 var Slick = (this.Slick || {}); | |
1430 | |
1431 Slick.parse = function(expression){ | |
1432 return parse(expression); | |
1433 }; | |
1434 | |
1435 Slick.escapeRegExp = escapeRegExp; | |
1436 | |
1437 if (!this.Slick) this.Slick = Slick; | |
1438 | |
1439 }).apply(window); | |
1440 | |
1441 | |
1442 /* | |
1443 --- | |
1444 name: Slick.Finder | |
1445 description: The new, superfast css selector engine. | |
1446 provides: Slick.Finder | |
1447 requires: Slick.Parser | |
1448 ... | |
1449 */ | |
1450 | |
1451 ;(function(){ | |
1452 | |
1453 var local = {}, | |
1454 featuresCache = {}, | |
1455 toString = Object.prototype.toString; | |
1456 | |
1457 // Feature / Bug detection | |
1458 | |
1459 local.isNativeCode = function(fn){ | |
1460 return (/\{\s*\[native code\]\s*\}/).test('' + fn); | |
1461 }; | |
1462 | |
1463 local.isXML = function(document){ | |
1464 return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document)
== '[object XMLDocument]') || | |
1465 (document.nodeType == 9 && document.documentElement.nodeName != 'HTML'); | |
1466 }; | |
1467 | |
1468 local.setDocument = function(document){ | |
1469 | |
1470 // convert elements / window arguments to document. if document cannot be extr
apolated, the function returns. | |
1471 var nodeType = document.nodeType; | |
1472 if (nodeType == 9); // document | |
1473 else if (nodeType) document = document.ownerDocument; // node | |
1474 else if (document.navigator) document = document.document; // window | |
1475 else return; | |
1476 | |
1477 // check if it's the old document | |
1478 | |
1479 if (this.document === document) return; | |
1480 this.document = document; | |
1481 | |
1482 // check if we have done feature detection on this document before | |
1483 | |
1484 var root = document.documentElement, | |
1485 rootUid = this.getUIDXML(root), | |
1486 features = featuresCache[rootUid], | |
1487 feature; | |
1488 | |
1489 if (features){ | |
1490 for (feature in features){ | |
1491 this[feature] = features[feature]; | |
1492 } | |
1493 return; | |
1494 } | |
1495 | |
1496 features = featuresCache[rootUid] = {}; | |
1497 | |
1498 features.root = root; | |
1499 features.isXMLDocument = this.isXML(document); | |
1500 | |
1501 features.brokenStarGEBTN | |
1502 = features.starSelectsClosedQSA | |
1503 = features.idGetsName | |
1504 = features.brokenMixedCaseQSA | |
1505 = features.brokenGEBCN | |
1506 = features.brokenCheckedQSA | |
1507 = features.brokenEmptyAttributeQSA | |
1508 = features.isHTMLDocument | |
1509 = features.nativeMatchesSelector | |
1510 = false; | |
1511 | |
1512 var starSelectsClosed, starSelectsComments, | |
1513 brokenSecondClassNameGEBCN, cachedGetElementsByClassName, | |
1514 brokenFormAttributeGetter; | |
1515 | |
1516 var selected, id = 'slick_uniqueid'; | |
1517 var testNode = document.createElement('div'); | |
1518 | |
1519 var testRoot = document.body || document.getElementsByTagName('body')[0] || ro
ot; | |
1520 testRoot.appendChild(testNode); | |
1521 | |
1522 // on non-HTML documents innerHTML and getElementsById doesnt work properly | |
1523 try { | |
1524 testNode.innerHTML = '<a id="'+id+'"></a>'; | |
1525 features.isHTMLDocument = !!document.getElementById(id); | |
1526 } catch(e){}; | |
1527 | |
1528 if (features.isHTMLDocument){ | |
1529 | |
1530 testNode.style.display = 'none'; | |
1531 | |
1532 // IE returns comment nodes for getElementsByTagName('*') for some documents | |
1533 testNode.appendChild(document.createComment('')); | |
1534 starSelectsComments = (testNode.getElementsByTagName('*').length > 1); | |
1535 | |
1536 // IE returns closed nodes (EG:"</foo>") for getElementsByTagName('*') for s
ome documents | |
1537 try { | |
1538 testNode.innerHTML = 'foo</foo>'; | |
1539 selected = testNode.getElementsByTagName('*'); | |
1540 starSelectsClosed = (selected && !!selected.length && selected[0].nodeName
.charAt(0) == '/'); | |
1541 } catch(e){}; | |
1542 | |
1543 features.brokenStarGEBTN = starSelectsComments || starSelectsClosed; | |
1544 | |
1545 // IE returns elements with the name instead of just id for getElementsById
for some documents | |
1546 try { | |
1547 testNode.innerHTML = '<a name="'+ id +'"></a><b id="'+ id +'"></b>'; | |
1548 features.idGetsName = document.getElementById(id) === testNode.firstChild; | |
1549 } catch(e){}; | |
1550 | |
1551 if (testNode.getElementsByClassName){ | |
1552 | |
1553 // Safari 3.2 getElementsByClassName caches results | |
1554 try { | |
1555 testNode.innerHTML = '<a class="f"></a><a class="b"></a>'; | |
1556 testNode.getElementsByClassName('b').length; | |
1557 testNode.firstChild.className = 'b'; | |
1558 cachedGetElementsByClassName = (testNode.getElementsByClassName('b').len
gth != 2); | |
1559 } catch(e){}; | |
1560 | |
1561 // Opera 9.6 getElementsByClassName doesnt detects the class if its not th
e first one | |
1562 try { | |
1563 testNode.innerHTML = '<a class="a"></a><a class="f b a"></a>'; | |
1564 brokenSecondClassNameGEBCN = (testNode.getElementsByClassName('a').lengt
h != 2); | |
1565 } catch(e){}; | |
1566 | |
1567 features.brokenGEBCN = cachedGetElementsByClassName || brokenSecondClassNa
meGEBCN; | |
1568 } | |
1569 | |
1570 if (testNode.querySelectorAll){ | |
1571 // IE 8 returns closed nodes (EG:"</foo>") for querySelectorAll('*') for s
ome documents | |
1572 try { | |
1573 testNode.innerHTML = 'foo</foo>'; | |
1574 selected = testNode.querySelectorAll('*'); | |
1575 features.starSelectsClosedQSA = (selected && !!selected.length && select
ed[0].nodeName.charAt(0) == '/'); | |
1576 } catch(e){}; | |
1577 | |
1578 // Safari 3.2 querySelectorAll doesnt work with mixedcase on quirksmode | |
1579 try { | |
1580 testNode.innerHTML = '<a class="MiX"></a>'; | |
1581 features.brokenMixedCaseQSA = !testNode.querySelectorAll('.MiX').length; | |
1582 } catch(e){}; | |
1583 | |
1584 // Webkit and Opera dont return selected options on querySelectorAll | |
1585 try { | |
1586 testNode.innerHTML = '<select><option selected="selected">a</option></se
lect>'; | |
1587 features.brokenCheckedQSA = (testNode.querySelectorAll(':checked').lengt
h == 0); | |
1588 } catch(e){}; | |
1589 | |
1590 // IE returns incorrect results for attr[*^$]="" selectors on querySelecto
rAll | |
1591 try { | |
1592 testNode.innerHTML = '<a class=""></a>'; | |
1593 features.brokenEmptyAttributeQSA = (testNode.querySelectorAll('[class*="
"]').length != 0); | |
1594 } catch(e){}; | |
1595 | |
1596 } | |
1597 | |
1598 // IE6-7, if a form has an input of id x, form.getAttribute(x) returns a ref
erence to the input | |
1599 try { | |
1600 testNode.innerHTML = '<form action="s"><input id="action"/></form>'; | |
1601 brokenFormAttributeGetter = (testNode.firstChild.getAttribute('action') !=
's'); | |
1602 } catch(e){}; | |
1603 | |
1604 // native matchesSelector function | |
1605 | |
1606 features.nativeMatchesSelector = root.matchesSelector || /*root.msMatchesSel
ector ||*/ root.mozMatchesSelector || root.webkitMatchesSelector; | |
1607 if (features.nativeMatchesSelector) try { | |
1608 // if matchesSelector trows errors on incorrect sintaxes we can use it | |
1609 features.nativeMatchesSelector.call(root, ':slick'); | |
1610 features.nativeMatchesSelector = null; | |
1611 } catch(e){}; | |
1612 | |
1613 } | |
1614 | |
1615 try { | |
1616 root.slick_expando = 1; | |
1617 delete root.slick_expando; | |
1618 features.getUID = this.getUIDHTML; | |
1619 } catch(e) { | |
1620 features.getUID = this.getUIDXML; | |
1621 } | |
1622 | |
1623 testRoot.removeChild(testNode); | |
1624 testNode = selected = testRoot = null; | |
1625 | |
1626 // getAttribute | |
1627 | |
1628 features.getAttribute = (features.isHTMLDocument && brokenFormAttributeGetter)
? function(node, name){ | |
1629 var method = this.attributeGetters[name]; | |
1630 if (method) return method.call(node); | |
1631 var attributeNode = node.getAttributeNode(name); | |
1632 return (attributeNode) ? attributeNode.nodeValue : null; | |
1633 } : function(node, name){ | |
1634 var method = this.attributeGetters[name]; | |
1635 return (method) ? method.call(node) : node.getAttribute(name); | |
1636 }; | |
1637 | |
1638 // hasAttribute | |
1639 | |
1640 features.hasAttribute = (root && this.isNativeCode(root.hasAttribute)) ? funct
ion(node, attribute) { | |
1641 return node.hasAttribute(attribute); | |
1642 } : function(node, attribute) { | |
1643 node = node.getAttributeNode(attribute); | |
1644 return !!(node && (node.specified || node.nodeValue)); | |
1645 }; | |
1646 | |
1647 // contains | |
1648 // FIXME: Add specs: local.contains should be different for xml and html docum
ents? | |
1649 var nativeRootContains = root && this.isNativeCode(root.contains), | |
1650 nativeDocumentContains = document && this.isNativeCode(document.contains); | |
1651 | |
1652 features.contains = (nativeRootContains && nativeDocumentContains) ? function(
context, node){ | |
1653 return context.contains(node); | |
1654 } : (nativeRootContains && !nativeDocumentContains) ? function(context, node){ | |
1655 // IE8 does not have .contains on document. | |
1656 return context === node || ((context === document) ? document.documentElemen
t : context).contains(node); | |
1657 } : (root && root.compareDocumentPosition) ? function(context, node){ | |
1658 return context === node || !!(context.compareDocumentPosition(node) & 16); | |
1659 } : function(context, node){ | |
1660 if (node) do { | |
1661 if (node === context) return true; | |
1662 } while ((node = node.parentNode)); | |
1663 return false; | |
1664 }; | |
1665 | |
1666 // document order sorting | |
1667 // credits to Sizzle (http://sizzlejs.com/) | |
1668 | |
1669 features.documentSorter = (root.compareDocumentPosition) ? function(a, b){ | |
1670 if (!a.compareDocumentPosition || !b.compareDocumentPosition) return 0; | |
1671 return a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; | |
1672 } : ('sourceIndex' in root) ? function(a, b){ | |
1673 if (!a.sourceIndex || !b.sourceIndex) return 0; | |
1674 return a.sourceIndex - b.sourceIndex; | |
1675 } : (document.createRange) ? function(a, b){ | |
1676 if (!a.ownerDocument || !b.ownerDocument) return 0; | |
1677 var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createR
ange(); | |
1678 aRange.setStart(a, 0); | |
1679 aRange.setEnd(a, 0); | |
1680 bRange.setStart(b, 0); | |
1681 bRange.setEnd(b, 0); | |
1682 return aRange.compareBoundaryPoints(Range.START_TO_END, bRange); | |
1683 } : null ; | |
1684 | |
1685 root = null; | |
1686 | |
1687 for (feature in features){ | |
1688 this[feature] = features[feature]; | |
1689 } | |
1690 }; | |
1691 | |
1692 // Main Method | |
1693 | |
1694 var reSimpleSelector = /^([#.]?)((?:[\w-]+|\*))$/, | |
1695 reEmptyAttribute = /\[.+[*$^]=(?:""|'')?\]/, | |
1696 qsaFailExpCache = {}; | |
1697 | |
1698 local.search = function(context, expression, append, first){ | |
1699 | |
1700 var found = this.found = (first) ? null : (append || []); | |
1701 | |
1702 if (!context) return found; | |
1703 else if (context.navigator) context = context.document; // Convert the node fr
om a window to a document | |
1704 else if (!context.nodeType) return found; | |
1705 | |
1706 // setup | |
1707 | |
1708 var parsed, i, | |
1709 uniques = this.uniques = {}, | |
1710 hasOthers = !!(append && append.length), | |
1711 contextIsDocument = (context.nodeType == 9); | |
1712 | |
1713 if (this.document !== (contextIsDocument ? context : context.ownerDocument)) t
his.setDocument(context); | |
1714 | |
1715 // avoid duplicating items already in the append array | |
1716 if (hasOthers) for (i = found.length; i--;) uniques[this.getUID(found[i])] = t
rue; | |
1717 | |
1718 // expression checks | |
1719 | |
1720 if (typeof expression == 'string'){ // expression is a string | |
1721 | |
1722 /*<simple-selectors-override>*/ | |
1723 var simpleSelector = expression.match(reSimpleSelector); | |
1724 simpleSelectors: if (simpleSelector) { | |
1725 | |
1726 var symbol = simpleSelector[1], | |
1727 name = simpleSelector[2], | |
1728 node, nodes; | |
1729 | |
1730 if (!symbol){ | |
1731 | |
1732 if (name == '*' && this.brokenStarGEBTN) break simpleSelectors; | |
1733 nodes = context.getElementsByTagName(name); | |
1734 if (first) return nodes[0] || null; | |
1735 for (i = 0; node = nodes[i++];){ | |
1736 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); | |
1737 } | |
1738 | |
1739 } else if (symbol == '#'){ | |
1740 | |
1741 if (!this.isHTMLDocument || !contextIsDocument) break simpleSelectors; | |
1742 node = context.getElementById(name); | |
1743 if (!node) return found; | |
1744 if (this.idGetsName && node.getAttributeNode('id').nodeValue != name) br
eak simpleSelectors; | |
1745 if (first) return node || null; | |
1746 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); | |
1747 | |
1748 } else if (symbol == '.'){ | |
1749 | |
1750 if (!this.isHTMLDocument || ((!context.getElementsByClassName || this.br
okenGEBCN) && context.querySelectorAll)) break simpleSelectors; | |
1751 if (context.getElementsByClassName && !this.brokenGEBCN){ | |
1752 nodes = context.getElementsByClassName(name); | |
1753 if (first) return nodes[0] || null; | |
1754 for (i = 0; node = nodes[i++];){ | |
1755 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); | |
1756 } | |
1757 } else { | |
1758 var matchClass = new RegExp('(^|\\s)'+ Slick.escapeRegExp(name) +'(\\s
|$)'); | |
1759 nodes = context.getElementsByTagName('*'); | |
1760 for (i = 0; node = nodes[i++];){ | |
1761 className = node.className; | |
1762 if (!(className && matchClass.test(className))) continue; | |
1763 if (first) return node; | |
1764 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); | |
1765 } | |
1766 } | |
1767 | |
1768 } | |
1769 | |
1770 if (hasOthers) this.sort(found); | |
1771 return (first) ? null : found; | |
1772 | |
1773 } | |
1774 /*</simple-selectors-override>*/ | |
1775 | |
1776 /*<query-selector-override>*/ | |
1777 querySelector: if (context.querySelectorAll) { | |
1778 | |
1779 if (!this.isHTMLDocument | |
1780 || qsaFailExpCache[expression] | |
1781 //TODO: only skip when expression is actually mixed case | |
1782 || this.brokenMixedCaseQSA | |
1783 || (this.brokenCheckedQSA && expression.indexOf(':checked') > -1) | |
1784 || (this.brokenEmptyAttributeQSA && reEmptyAttribute.test(expression)) | |
1785 || (!contextIsDocument //Abort when !contextIsDocument and... | |
1786 // there are multiple expressions in the selector | |
1787 // since we currently only fix non-document rooted QSA for single exp
ression selectors | |
1788 && expression.indexOf(',') > -1 | |
1789 ) | |
1790 || Slick.disableQSA | |
1791 ) break querySelector; | |
1792 | |
1793 var _expression = expression, _context = context; | |
1794 if (!contextIsDocument){ | |
1795 // non-document rooted QSA | |
1796 // credits to Andrew Dupont | |
1797 var currentId = _context.getAttribute('id'), slickid = 'slickid__'; | |
1798 _context.setAttribute('id', slickid); | |
1799 _expression = '#' + slickid + ' ' + _expression; | |
1800 context = _context.parentNode; | |
1801 } | |
1802 | |
1803 try { | |
1804 if (first) return context.querySelector(_expression) || null; | |
1805 else nodes = context.querySelectorAll(_expression); | |
1806 } catch(e) { | |
1807 qsaFailExpCache[expression] = 1; | |
1808 break querySelector; | |
1809 } finally { | |
1810 if (!contextIsDocument){ | |
1811 if (currentId) _context.setAttribute('id', currentId); | |
1812 else _context.removeAttribute('id'); | |
1813 context = _context; | |
1814 } | |
1815 } | |
1816 | |
1817 if (this.starSelectsClosedQSA) for (i = 0; node = nodes[i++];){ | |
1818 if (node.nodeName > '@' && !(hasOthers && uniques[this.getUID(node)])) f
ound.push(node); | |
1819 } else for (i = 0; node = nodes[i++];){ | |
1820 if (!(hasOthers && uniques[this.getUID(node)])) found.push(node); | |
1821 } | |
1822 | |
1823 if (hasOthers) this.sort(found); | |
1824 return found; | |
1825 | |
1826 } | |
1827 /*</query-selector-override>*/ | |
1828 | |
1829 parsed = this.Slick.parse(expression); | |
1830 if (!parsed.length) return found; | |
1831 } else if (expression == null){ // there is no expression | |
1832 return found; | |
1833 } else if (expression.Slick){ // expression is a parsed Slick object | |
1834 parsed = expression; | |
1835 } else if (this.contains(context.documentElement || context, expression)){ //
expression is a node | |
1836 (found) ? found.push(expression) : found = expression; | |
1837 return found; | |
1838 } else { // other junk | |
1839 return found; | |
1840 } | |
1841 | |
1842 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/ | |
1843 | |
1844 // cache elements for the nth selectors | |
1845 | |
1846 this.posNTH = {}; | |
1847 this.posNTHLast = {}; | |
1848 this.posNTHType = {}; | |
1849 this.posNTHTypeLast = {}; | |
1850 | |
1851 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/ | |
1852 | |
1853 // if append is null and there is only a single selector with one expression u
se pushArray, else use pushUID | |
1854 this.push = (!hasOthers && (first || (parsed.length == 1 && parsed.expressions
[0].length == 1))) ? this.pushArray : this.pushUID; | |
1855 | |
1856 if (found == null) found = []; | |
1857 | |
1858 // default engine | |
1859 | |
1860 var j, m, n; | |
1861 var combinator, tag, id, classList, classes, attributes, pseudos; | |
1862 var currentItems, currentExpression, currentBit, lastBit, expressions = parsed
.expressions; | |
1863 | |
1864 search: for (i = 0; (currentExpression = expressions[i]); i++) for (j = 0; (cu
rrentBit = currentExpression[j]); j++){ | |
1865 | |
1866 combinator = 'combinator:' + currentBit.combinator; | |
1867 if (!this[combinator]) continue search; | |
1868 | |
1869 tag = (this.isXMLDocument) ? currentBit.tag : currentBit.tag.toUpperC
ase(); | |
1870 id = currentBit.id; | |
1871 classList = currentBit.classList; | |
1872 classes = currentBit.classes; | |
1873 attributes = currentBit.attributes; | |
1874 pseudos = currentBit.pseudos; | |
1875 lastBit = (j === (currentExpression.length - 1)); | |
1876 | |
1877 this.bitUniques = {}; | |
1878 | |
1879 if (lastBit){ | |
1880 this.uniques = uniques; | |
1881 this.found = found; | |
1882 } else { | |
1883 this.uniques = {}; | |
1884 this.found = []; | |
1885 } | |
1886 | |
1887 if (j === 0){ | |
1888 this[combinator](context, tag, id, classes, attributes, pseudos, classList
); | |
1889 if (first && lastBit && found.length) break search; | |
1890 } else { | |
1891 if (first && lastBit) for (m = 0, n = currentItems.length; m < n; m++){ | |
1892 this[combinator](currentItems[m], tag, id, classes, attributes, pseudos,
classList); | |
1893 if (found.length) break search; | |
1894 } else for (m = 0, n = currentItems.length; m < n; m++) this[combinator](c
urrentItems[m], tag, id, classes, attributes, pseudos, classList); | |
1895 } | |
1896 | |
1897 currentItems = this.found; | |
1898 } | |
1899 | |
1900 // should sort if there are nodes in append and if you pass multiple expressio
ns. | |
1901 if (hasOthers || (parsed.expressions.length > 1)) this.sort(found); | |
1902 | |
1903 return (first) ? (found[0] || null) : found; | |
1904 }; | |
1905 | |
1906 // Utils | |
1907 | |
1908 local.uidx = 1; | |
1909 local.uidk = 'slick-uniqueid'; | |
1910 | |
1911 local.getUIDXML = function(node){ | |
1912 var uid = node.getAttribute(this.uidk); | |
1913 if (!uid){ | |
1914 uid = this.uidx++; | |
1915 node.setAttribute(this.uidk, uid); | |
1916 } | |
1917 return uid; | |
1918 }; | |
1919 | |
1920 local.getUIDHTML = function(node){ | |
1921 return node.uniqueNumber || (node.uniqueNumber = this.uidx++); | |
1922 }; | |
1923 | |
1924 // sort based on the setDocument documentSorter method. | |
1925 | |
1926 local.sort = function(results){ | |
1927 if (!this.documentSorter) return results; | |
1928 results.sort(this.documentSorter); | |
1929 return results; | |
1930 }; | |
1931 | |
1932 /*<pseudo-selectors>*//*<nth-pseudo-selectors>*/ | |
1933 | |
1934 local.cacheNTH = {}; | |
1935 | |
1936 local.matchNTH = /^([+-]?\d*)?([a-z]+)?([+-]\d+)?$/; | |
1937 | |
1938 local.parseNTHArgument = function(argument){ | |
1939 var parsed = argument.match(this.matchNTH); | |
1940 if (!parsed) return false; | |
1941 var special = parsed[2] || false; | |
1942 var a = parsed[1] || 1; | |
1943 if (a == '-') a = -1; | |
1944 var b = +parsed[3] || 0; | |
1945 parsed = | |
1946 (special == 'n') ? {a: a, b: b} : | |
1947 (special == 'odd') ? {a: 2, b: 1} : | |
1948 (special == 'even') ? {a: 2, b: 0} : {a: 0, b: a}; | |
1949 | |
1950 return (this.cacheNTH[argument] = parsed); | |
1951 }; | |
1952 | |
1953 local.createNTHPseudo = function(child, sibling, positions, ofType){ | |
1954 return function(node, argument){ | |
1955 var uid = this.getUID(node); | |
1956 if (!this[positions][uid]){ | |
1957 var parent = node.parentNode; | |
1958 if (!parent) return false; | |
1959 var el = parent[child], count = 1; | |
1960 if (ofType){ | |
1961 var nodeName = node.nodeName; | |
1962 do { | |
1963 if (el.nodeName != nodeName) continue; | |
1964 this[positions][this.getUID(el)] = count++; | |
1965 } while ((el = el[sibling])); | |
1966 } else { | |
1967 do { | |
1968 if (el.nodeType != 1) continue; | |
1969 this[positions][this.getUID(el)] = count++; | |
1970 } while ((el = el[sibling])); | |
1971 } | |
1972 } | |
1973 argument = argument || 'n'; | |
1974 var parsed = this.cacheNTH[argument] || this.parseNTHArgument(argument); | |
1975 if (!parsed) return false; | |
1976 var a = parsed.a, b = parsed.b, pos = this[positions][uid]; | |
1977 if (a == 0) return b == pos; | |
1978 if (a > 0){ | |
1979 if (pos < b) return false; | |
1980 } else { | |
1981 if (b < pos) return false; | |
1982 } | |
1983 return ((pos - b) % a) == 0; | |
1984 }; | |
1985 }; | |
1986 | |
1987 /*</nth-pseudo-selectors>*//*</pseudo-selectors>*/ | |
1988 | |
1989 local.pushArray = function(node, tag, id, classes, attributes, pseudos){ | |
1990 if (this.matchSelector(node, tag, id, classes, attributes, pseudos)) this.foun
d.push(node); | |
1991 }; | |
1992 | |
1993 local.pushUID = function(node, tag, id, classes, attributes, pseudos){ | |
1994 var uid = this.getUID(node); | |
1995 if (!this.uniques[uid] && this.matchSelector(node, tag, id, classes, attribute
s, pseudos)){ | |
1996 this.uniques[uid] = true; | |
1997 this.found.push(node); | |
1998 } | |
1999 }; | |
2000 | |
2001 local.matchNode = function(node, selector){ | |
2002 if (this.isHTMLDocument && this.nativeMatchesSelector){ | |
2003 try { | |
2004 return this.nativeMatchesSelector.call(node, selector.replace(/\[([^=]+)=\
s*([^'"\]]+?)\s*\]/g, '[$1="$2"]')); | |
2005 } catch(matchError) {} | |
2006 } | |
2007 | |
2008 var parsed = this.Slick.parse(selector); | |
2009 if (!parsed) return true; | |
2010 | |
2011 // simple (single) selectors | |
2012 var expressions = parsed.expressions, simpleExpCounter = 0, i; | |
2013 for (i = 0; (currentExpression = expressions[i]); i++){ | |
2014 if (currentExpression.length == 1){ | |
2015 var exp = currentExpression[0]; | |
2016 if (this.matchSelector(node, (this.isXMLDocument) ? exp.tag : exp.tag.toUp
perCase(), exp.id, exp.classes, exp.attributes, exp.pseudos)) return true; | |
2017 simpleExpCounter++; | |
2018 } | |
2019 } | |
2020 | |
2021 if (simpleExpCounter == parsed.length) return false; | |
2022 | |
2023 var nodes = this.search(this.document, parsed), item; | |
2024 for (i = 0; item = nodes[i++];){ | |
2025 if (item === node) return true; | |
2026 } | |
2027 return false; | |
2028 }; | |
2029 | |
2030 local.matchPseudo = function(node, name, argument){ | |
2031 var pseudoName = 'pseudo:' + name; | |
2032 if (this[pseudoName]) return this[pseudoName](node, argument); | |
2033 var attribute = this.getAttribute(node, name); | |
2034 return (argument) ? argument == attribute : !!attribute; | |
2035 }; | |
2036 | |
2037 local.matchSelector = function(node, tag, id, classes, attributes, pseudos){ | |
2038 if (tag){ | |
2039 var nodeName = (this.isXMLDocument) ? node.nodeName : node.nodeName.toUpperC
ase(); | |
2040 if (tag == '*'){ | |
2041 if (nodeName < '@') return false; // Fix for comment nodes and closed node
s | |
2042 } else { | |
2043 if (nodeName != tag) return false; | |
2044 } | |
2045 } | |
2046 | |
2047 if (id && node.getAttribute('id') != id) return false; | |
2048 | |
2049 var i, part, cls; | |
2050 if (classes) for (i = classes.length; i--;){ | |
2051 cls = this.getAttribute(node, 'class'); | |
2052 if (!(cls && classes[i].regexp.test(cls))) return false; | |
2053 } | |
2054 if (attributes) for (i = attributes.length; i--;){ | |
2055 part = attributes[i]; | |
2056 if (part.operator ? !part.test(this.getAttribute(node, part.key)) : !this.ha
sAttribute(node, part.key)) return false; | |
2057 } | |
2058 if (pseudos) for (i = pseudos.length; i--;){ | |
2059 part = pseudos[i]; | |
2060 if (!this.matchPseudo(node, part.key, part.value)) return false; | |
2061 } | |
2062 return true; | |
2063 }; | |
2064 | |
2065 var combinators = { | |
2066 | |
2067 ' ': function(node, tag, id, classes, attributes, pseudos, classList){ // all
child nodes, any level | |
2068 | |
2069 var i, item, children; | |
2070 | |
2071 if (this.isHTMLDocument){ | |
2072 getById: if (id){ | |
2073 item = this.document.getElementById(id); | |
2074 if ((!item && node.all) || (this.idGetsName && item && item.getAttribute
Node('id').nodeValue != id)){ | |
2075 // all[id] returns all the elements with that name or id inside node | |
2076 // if theres just one it will return the element, else it will be a co
llection | |
2077 children = node.all[id]; | |
2078 if (!children) return; | |
2079 if (!children[0]) children = [children]; | |
2080 for (i = 0; item = children[i++];){ | |
2081 var idNode = item.getAttributeNode('id'); | |
2082 if (idNode && idNode.nodeValue == id){ | |
2083 this.push(item, tag, null, classes, attributes, pseudos); | |
2084 break; | |
2085 } | |
2086 } | |
2087 return; | |
2088 } | |
2089 if (!item){ | |
2090 // if the context is in the dom we return, else we will try GEBTN, bre
aking the getById label | |
2091 if (this.contains(this.root, node)) return; | |
2092 else break getById; | |
2093 } else if (this.document !== node && !this.contains(node, item)) return; | |
2094 this.push(item, tag, null, classes, attributes, pseudos); | |
2095 return; | |
2096 } | |
2097 getByClass: if (classes && node.getElementsByClassName && !this.brokenGEBC
N){ | |
2098 children = node.getElementsByClassName(classList.join(' ')); | |
2099 if (!(children && children.length)) break getByClass; | |
2100 for (i = 0; item = children[i++];) this.push(item, tag, id, null, attrib
utes, pseudos); | |
2101 return; | |
2102 } | |
2103 } | |
2104 getByTag: { | |
2105 children = node.getElementsByTagName(tag); | |
2106 if (!(children && children.length)) break getByTag; | |
2107 if (!this.brokenStarGEBTN) tag = null; | |
2108 for (i = 0; item = children[i++];) this.push(item, tag, id, classes, attri
butes, pseudos); | |
2109 } | |
2110 }, | |
2111 | |
2112 '>': function(node, tag, id, classes, attributes, pseudos){ // direct children | |
2113 if ((node = node.firstChild)) do { | |
2114 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseu
dos); | |
2115 } while ((node = node.nextSibling)); | |
2116 }, | |
2117 | |
2118 '+': function(node, tag, id, classes, attributes, pseudos){ // next sibling | |
2119 while ((node = node.nextSibling)) if (node.nodeType == 1){ | |
2120 this.push(node, tag, id, classes, attributes, pseudos); | |
2121 break; | |
2122 } | |
2123 }, | |
2124 | |
2125 '^': function(node, tag, id, classes, attributes, pseudos){ // first child | |
2126 node = node.firstChild; | |
2127 if (node){ | |
2128 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseu
dos); | |
2129 else this['combinator:+'](node, tag, id, classes, attributes, pseudos); | |
2130 } | |
2131 }, | |
2132 | |
2133 '~': function(node, tag, id, classes, attributes, pseudos){ // next siblings | |
2134 while ((node = node.nextSibling)){ | |
2135 if (node.nodeType != 1) continue; | |
2136 var uid = this.getUID(node); | |
2137 if (this.bitUniques[uid]) break; | |
2138 this.bitUniques[uid] = true; | |
2139 this.push(node, tag, id, classes, attributes, pseudos); | |
2140 } | |
2141 }, | |
2142 | |
2143 '++': function(node, tag, id, classes, attributes, pseudos){ // next sibling a
nd previous sibling | |
2144 this['combinator:+'](node, tag, id, classes, attributes, pseudos); | |
2145 this['combinator:!+'](node, tag, id, classes, attributes, pseudos); | |
2146 }, | |
2147 | |
2148 '~~': function(node, tag, id, classes, attributes, pseudos){ // next siblings
and previous siblings | |
2149 this['combinator:~'](node, tag, id, classes, attributes, pseudos); | |
2150 this['combinator:!~'](node, tag, id, classes, attributes, pseudos); | |
2151 }, | |
2152 | |
2153 '!': function(node, tag, id, classes, attributes, pseudos){ // all parent node
s up to document | |
2154 while ((node = node.parentNode)) if (node !== this.document) this.push(node,
tag, id, classes, attributes, pseudos); | |
2155 }, | |
2156 | |
2157 '!>': function(node, tag, id, classes, attributes, pseudos){ // direct parent
(one level) | |
2158 node = node.parentNode; | |
2159 if (node !== this.document) this.push(node, tag, id, classes, attributes, ps
eudos); | |
2160 }, | |
2161 | |
2162 '!+': function(node, tag, id, classes, attributes, pseudos){ // previous sibli
ng | |
2163 while ((node = node.previousSibling)) if (node.nodeType == 1){ | |
2164 this.push(node, tag, id, classes, attributes, pseudos); | |
2165 break; | |
2166 } | |
2167 }, | |
2168 | |
2169 '!^': function(node, tag, id, classes, attributes, pseudos){ // last child | |
2170 node = node.lastChild; | |
2171 if (node){ | |
2172 if (node.nodeType == 1) this.push(node, tag, id, classes, attributes, pseu
dos); | |
2173 else this['combinator:!+'](node, tag, id, classes, attributes, pseudos); | |
2174 } | |
2175 }, | |
2176 | |
2177 '!~': function(node, tag, id, classes, attributes, pseudos){ // previous sibli
ngs | |
2178 while ((node = node.previousSibling)){ | |
2179 if (node.nodeType != 1) continue; | |
2180 var uid = this.getUID(node); | |
2181 if (this.bitUniques[uid]) break; | |
2182 this.bitUniques[uid] = true; | |
2183 this.push(node, tag, id, classes, attributes, pseudos); | |
2184 } | |
2185 } | |
2186 | |
2187 }; | |
2188 | |
2189 for (var c in combinators) local['combinator:' + c] = combinators[c]; | |
2190 | |
2191 var pseudos = { | |
2192 | |
2193 /*<pseudo-selectors>*/ | |
2194 | |
2195 'empty': function(node){ | |
2196 var child = node.firstChild; | |
2197 return !(child && child.nodeType == 1) && !(node.innerText || node.textConte
nt || '').length; | |
2198 }, | |
2199 | |
2200 'not': function(node, expression){ | |
2201 return !this.matchNode(node, expression); | |
2202 }, | |
2203 | |
2204 'contains': function(node, text){ | |
2205 return (node.innerText || node.textContent || '').indexOf(text) > -1; | |
2206 }, | |
2207 | |
2208 'first-child': function(node){ | |
2209 while ((node = node.previousSibling)) if (node.nodeType == 1) return false; | |
2210 return true; | |
2211 }, | |
2212 | |
2213 'last-child': function(node){ | |
2214 while ((node = node.nextSibling)) if (node.nodeType == 1) return false; | |
2215 return true; | |
2216 }, | |
2217 | |
2218 'only-child': function(node){ | |
2219 var prev = node; | |
2220 while ((prev = prev.previousSibling)) if (prev.nodeType == 1) return false; | |
2221 var next = node; | |
2222 while ((next = next.nextSibling)) if (next.nodeType == 1) return false; | |
2223 return true; | |
2224 }, | |
2225 | |
2226 /*<nth-pseudo-selectors>*/ | |
2227 | |
2228 'nth-child': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTH'), | |
2229 | |
2230 'nth-last-child': local.createNTHPseudo('lastChild', 'previousSibling', 'posNT
HLast'), | |
2231 | |
2232 'nth-of-type': local.createNTHPseudo('firstChild', 'nextSibling', 'posNTHType'
, true), | |
2233 | |
2234 'nth-last-of-type': local.createNTHPseudo('lastChild', 'previousSibling', 'pos
NTHTypeLast', true), | |
2235 | |
2236 'index': function(node, index){ | |
2237 return this['pseudo:nth-child'](node, '' + (index + 1)); | |
2238 }, | |
2239 | |
2240 'even': function(node){ | |
2241 return this['pseudo:nth-child'](node, '2n'); | |
2242 }, | |
2243 | |
2244 'odd': function(node){ | |
2245 return this['pseudo:nth-child'](node, '2n+1'); | |
2246 }, | |
2247 | |
2248 /*</nth-pseudo-selectors>*/ | |
2249 | |
2250 /*<of-type-pseudo-selectors>*/ | |
2251 | |
2252 'first-of-type': function(node){ | |
2253 var nodeName = node.nodeName; | |
2254 while ((node = node.previousSibling)) if (node.nodeName == nodeName) return
false; | |
2255 return true; | |
2256 }, | |
2257 | |
2258 'last-of-type': function(node){ | |
2259 var nodeName = node.nodeName; | |
2260 while ((node = node.nextSibling)) if (node.nodeName == nodeName) return fals
e; | |
2261 return true; | |
2262 }, | |
2263 | |
2264 'only-of-type': function(node){ | |
2265 var prev = node, nodeName = node.nodeName; | |
2266 while ((prev = prev.previousSibling)) if (prev.nodeName == nodeName) return
false; | |
2267 var next = node; | |
2268 while ((next = next.nextSibling)) if (next.nodeName == nodeName) return fals
e; | |
2269 return true; | |
2270 }, | |
2271 | |
2272 /*</of-type-pseudo-selectors>*/ | |
2273 | |
2274 // custom pseudos | |
2275 | |
2276 'enabled': function(node){ | |
2277 return !node.disabled; | |
2278 }, | |
2279 | |
2280 'disabled': function(node){ | |
2281 return node.disabled; | |
2282 }, | |
2283 | |
2284 'checked': function(node){ | |
2285 return node.checked || node.selected; | |
2286 }, | |
2287 | |
2288 'focus': function(node){ | |
2289 return this.isHTMLDocument && this.document.activeElement === node && (node.
href || node.type || this.hasAttribute(node, 'tabindex')); | |
2290 }, | |
2291 | |
2292 'root': function(node){ | |
2293 return (node === this.root); | |
2294 }, | |
2295 | |
2296 'selected': function(node){ | |
2297 return node.selected; | |
2298 } | |
2299 | |
2300 /*</pseudo-selectors>*/ | |
2301 }; | |
2302 | |
2303 for (var p in pseudos) local['pseudo:' + p] = pseudos[p]; | |
2304 | |
2305 // attributes methods | |
2306 | |
2307 var attributeGetters = local.attributeGetters = { | |
2308 | |
2309 'for': function(){ | |
2310 return ('htmlFor' in this) ? this.htmlFor : this.getAttribute('for'); | |
2311 }, | |
2312 | |
2313 'href': function(){ | |
2314 return ('href' in this) ? this.getAttribute('href', 2) : this.getAttribute('
href'); | |
2315 }, | |
2316 | |
2317 'style': function(){ | |
2318 return (this.style) ? this.style.cssText : this.getAttribute('style'); | |
2319 }, | |
2320 | |
2321 'tabindex': function(){ | |
2322 var attributeNode = this.getAttributeNode('tabindex'); | |
2323 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue
: null; | |
2324 }, | |
2325 | |
2326 'type': function(){ | |
2327 return this.getAttribute('type'); | |
2328 }, | |
2329 | |
2330 'maxlength': function(){ | |
2331 var attributeNode = this.getAttributeNode('maxLength'); | |
2332 return (attributeNode && attributeNode.specified) ? attributeNode.nodeValue
: null; | |
2333 } | |
2334 | |
2335 }; | |
2336 | |
2337 attributeGetters.MAXLENGTH = attributeGetters.maxLength = attributeGetters.maxle
ngth; | |
2338 | |
2339 // Slick | |
2340 | |
2341 var Slick = local.Slick = (this.Slick || {}); | |
2342 | |
2343 Slick.version = '1.1.7'; | |
2344 | |
2345 // Slick finder | |
2346 | |
2347 Slick.search = function(context, expression, append){ | |
2348 return local.search(context, expression, append); | |
2349 }; | |
2350 | |
2351 Slick.find = function(context, expression){ | |
2352 return local.search(context, expression, null, true); | |
2353 }; | |
2354 | |
2355 // Slick containment checker | |
2356 | |
2357 Slick.contains = function(container, node){ | |
2358 local.setDocument(container); | |
2359 return local.contains(container, node); | |
2360 }; | |
2361 | |
2362 // Slick attribute getter | |
2363 | |
2364 Slick.getAttribute = function(node, name){ | |
2365 local.setDocument(node); | |
2366 return local.getAttribute(node, name); | |
2367 }; | |
2368 | |
2369 Slick.hasAttribute = function(node, name){ | |
2370 local.setDocument(node); | |
2371 return local.hasAttribute(node, name); | |
2372 }; | |
2373 | |
2374 // Slick matcher | |
2375 | |
2376 Slick.match = function(node, selector){ | |
2377 if (!(node && selector)) return false; | |
2378 if (!selector || selector === node) return true; | |
2379 local.setDocument(node); | |
2380 return local.matchNode(node, selector); | |
2381 }; | |
2382 | |
2383 // Slick attribute accessor | |
2384 | |
2385 Slick.defineAttributeGetter = function(name, fn){ | |
2386 local.attributeGetters[name] = fn; | |
2387 return this; | |
2388 }; | |
2389 | |
2390 Slick.lookupAttributeGetter = function(name){ | |
2391 return local.attributeGetters[name]; | |
2392 }; | |
2393 | |
2394 // Slick pseudo accessor | |
2395 | |
2396 Slick.definePseudo = function(name, fn){ | |
2397 local['pseudo:' + name] = function(node, argument){ | |
2398 return fn.call(node, argument); | |
2399 }; | |
2400 return this; | |
2401 }; | |
2402 | |
2403 Slick.lookupPseudo = function(name){ | |
2404 var pseudo = local['pseudo:' + name]; | |
2405 if (pseudo) return function(argument){ | |
2406 return pseudo.call(this, argument); | |
2407 }; | |
2408 return null; | |
2409 }; | |
2410 | |
2411 // Slick overrides accessor | |
2412 | |
2413 Slick.override = function(regexp, fn){ | |
2414 local.override(regexp, fn); | |
2415 return this; | |
2416 }; | |
2417 | |
2418 Slick.isXML = local.isXML; | |
2419 | |
2420 Slick.uidOf = function(node){ | |
2421 return local.getUIDHTML(node); | |
2422 }; | |
2423 | |
2424 if (!this.Slick) this.Slick = Slick; | |
2425 | |
2426 }).apply(window); | |
2427 | |
2428 | |
2429 /* | |
2430 --- | |
2431 | |
2432 name: Element | |
2433 | |
2434 description: One of the most important items in MooTools. Contains the dollar fu
nction, the dollars function, and an handful of cross-browser, time-saver method
s to let you easily work with HTML Elements. | |
2435 | |
2436 license: MIT-style license. | |
2437 | |
2438 requires: [Window, Document, Array, String, Function, Object, Number, Slick.Pars
er, Slick.Finder] | |
2439 | |
2440 provides: [Element, Elements, $, $$, Iframe, Selectors] | |
2441 | |
2442 ... | |
2443 */ | |
2444 | |
2445 var Element = function(tag, props){ | |
2446 var konstructor = Element.Constructors[tag]; | |
2447 if (konstructor) return konstructor(props); | |
2448 if (typeof tag != 'string') return document.id(tag).set(props); | |
2449 | |
2450 if (!props) props = {}; | |
2451 | |
2452 if (!(/^[\w-]+$/).test(tag)){ | |
2453 var parsed = Slick.parse(tag).expressions[0][0]; | |
2454 tag = (parsed.tag == '*') ? 'div' : parsed.tag; | |
2455 if (parsed.id && props.id == null) props.id = parsed.id; | |
2456 | |
2457 var attributes = parsed.attributes; | |
2458 if (attributes) for (var attr, i = 0, l = attributes.length; i < l; i++){ | |
2459 attr = attributes[i]; | |
2460 if (props[attr.key] != null) continue; | |
2461 | |
2462 if (attr.value != null && attr.operator == '=') props[attr.key] = attr.val
ue; | |
2463 else if (!attr.value && !attr.operator) props[attr.key] = true; | |
2464 } | |
2465 | |
2466 if (parsed.classList && props['class'] == null) props['class'] = parsed.clas
sList.join(' '); | |
2467 } | |
2468 | |
2469 return document.newElement(tag, props); | |
2470 }; | |
2471 | |
2472 | |
2473 if (Browser.Element){ | |
2474 Element.prototype = Browser.Element.prototype; | |
2475 // IE8 and IE9 require the wrapping. | |
2476 Element.prototype._fireEvent = (function(fireEvent){ | |
2477 return function(type, event){ | |
2478 return fireEvent.call(this, type, event); | |
2479 }; | |
2480 })(Element.prototype.fireEvent); | |
2481 } | |
2482 | |
2483 new Type('Element', Element).mirror(function(name){ | |
2484 if (Array.prototype[name]) return; | |
2485 | |
2486 var obj = {}; | |
2487 obj[name] = function(){ | |
2488 var results = [], args = arguments, elements = true; | |
2489 for (var i = 0, l = this.length; i < l; i++){ | |
2490 var element = this[i], result = results[i] = element[name].apply(element,
args); | |
2491 elements = (elements && typeOf(result) == 'element'); | |
2492 } | |
2493 return (elements) ? new Elements(results) : results; | |
2494 }; | |
2495 | |
2496 Elements.implement(obj); | |
2497 }); | |
2498 | |
2499 if (!Browser.Element){ | |
2500 Element.parent = Object; | |
2501 | |
2502 Element.Prototype = { | |
2503 '$constructor': Element, | |
2504 '$family': Function.from('element').hide() | |
2505 }; | |
2506 | |
2507 Element.mirror(function(name, method){ | |
2508 Element.Prototype[name] = method; | |
2509 }); | |
2510 } | |
2511 | |
2512 Element.Constructors = {}; | |
2513 | |
2514 | |
2515 | |
2516 var IFrame = new Type('IFrame', function(){ | |
2517 var params = Array.link(arguments, { | |
2518 properties: Type.isObject, | |
2519 iframe: function(obj){ | |
2520 return (obj != null); | |
2521 } | |
2522 }); | |
2523 | |
2524 var props = params.properties || {}, iframe; | |
2525 if (params.iframe) iframe = document.id(params.iframe); | |
2526 var onload = props.onload || function(){}; | |
2527 delete props.onload; | |
2528 props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.n
ame) : 'IFrame_' + String.uniqueID()].pick(); | |
2529 iframe = new Element(iframe || 'iframe', props); | |
2530 | |
2531 var onLoad = function(){ | |
2532 onload.call(iframe.contentWindow); | |
2533 }; | |
2534 | |
2535 if (window.frames[props.id]) onLoad(); | |
2536 else iframe.addListener('load', onLoad); | |
2537 return iframe; | |
2538 }); | |
2539 | |
2540 var Elements = this.Elements = function(nodes){ | |
2541 if (nodes && nodes.length){ | |
2542 var uniques = {}, node; | |
2543 for (var i = 0; node = nodes[i++];){ | |
2544 var uid = Slick.uidOf(node); | |
2545 if (!uniques[uid]){ | |
2546 uniques[uid] = true; | |
2547 this.push(node); | |
2548 } | |
2549 } | |
2550 } | |
2551 }; | |
2552 | |
2553 Elements.prototype = {length: 0}; | |
2554 Elements.parent = Array; | |
2555 | |
2556 new Type('Elements', Elements).implement({ | |
2557 | |
2558 filter: function(filter, bind){ | |
2559 if (!filter) return this; | |
2560 return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? functi
on(item){ | |
2561 return item.match(filter); | |
2562 } : filter, bind)); | |
2563 }.protect(), | |
2564 | |
2565 push: function(){ | |
2566 var length = this.length; | |
2567 for (var i = 0, l = arguments.length; i < l; i++){ | |
2568 var item = document.id(arguments[i]); | |
2569 if (item) this[length++] = item; | |
2570 } | |
2571 return (this.length = length); | |
2572 }.protect(), | |
2573 | |
2574 unshift: function(){ | |
2575 var items = []; | |
2576 for (var i = 0, l = arguments.length; i < l; i++){ | |
2577 var item = document.id(arguments[i]); | |
2578 if (item) items.push(item); | |
2579 } | |
2580 return Array.prototype.unshift.apply(this, items); | |
2581 }.protect(), | |
2582 | |
2583 concat: function(){ | |
2584 var newElements = new Elements(this); | |
2585 for (var i = 0, l = arguments.length; i < l; i++){ | |
2586 var item = arguments[i]; | |
2587 if (Type.isEnumerable(item)) newElements.append(item); | |
2588 else newElements.push(item); | |
2589 } | |
2590 return newElements; | |
2591 }.protect(), | |
2592 | |
2593 append: function(collection){ | |
2594 for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]); | |
2595 return this; | |
2596 }.protect(), | |
2597 | |
2598 empty: function(){ | |
2599 while (this.length) delete this[--this.length]; | |
2600 return this; | |
2601 }.protect() | |
2602 | |
2603 }); | |
2604 | |
2605 | |
2606 | |
2607 (function(){ | |
2608 | |
2609 // FF, IE | |
2610 var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2}; | |
2611 | |
2612 splice.call(object, 1, 1); | |
2613 if (object[1] == 1) Elements.implement('splice', function(){ | |
2614 var length = this.length; | |
2615 var result = splice.apply(this, arguments); | |
2616 while (length >= this.length) delete this[length--]; | |
2617 return result; | |
2618 }.protect()); | |
2619 | |
2620 Array.forEachMethod(function(method, name){ | |
2621 Elements.implement(name, method); | |
2622 }); | |
2623 | |
2624 Array.mirror(Elements); | |
2625 | |
2626 /*<ltIE8>*/ | |
2627 var createElementAcceptsHTML; | |
2628 try { | |
2629 createElementAcceptsHTML = (document.createElement('<input name=x>').name ==
'x'); | |
2630 } catch (e){} | |
2631 | |
2632 var escapeQuotes = function(html){ | |
2633 return ('' + html).replace(/&/g, '&').replace(/"/g, '"'); | |
2634 }; | |
2635 /*</ltIE8>*/ | |
2636 | |
2637 Document.implement({ | |
2638 | |
2639 newElement: function(tag, props){ | |
2640 if (props && props.checked != null) props.defaultChecked = props.checked; | |
2641 /*<ltIE8>*/// Fix for readonly name and type properties in IE < 8 | |
2642 if (createElementAcceptsHTML && props){ | |
2643 tag = '<' + tag; | |
2644 if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"'; | |
2645 if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"'; | |
2646 tag += '>'; | |
2647 delete props.name; | |
2648 delete props.type; | |
2649 } | |
2650 /*</ltIE8>*/ | |
2651 return this.id(this.createElement(tag)).set(props); | |
2652 } | |
2653 | |
2654 }); | |
2655 | |
2656 })(); | |
2657 | |
2658 (function(){ | |
2659 | |
2660 Slick.uidOf(window); | |
2661 Slick.uidOf(document); | |
2662 | |
2663 Document.implement({ | |
2664 | |
2665 newTextNode: function(text){ | |
2666 return this.createTextNode(text); | |
2667 }, | |
2668 | |
2669 getDocument: function(){ | |
2670 return this; | |
2671 }, | |
2672 | |
2673 getWindow: function(){ | |
2674 return this.window; | |
2675 }, | |
2676 | |
2677 id: (function(){ | |
2678 | |
2679 var types = { | |
2680 | |
2681 string: function(id, nocash, doc){ | |
2682 id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1')); | |
2683 return (id) ? types.element(id, nocash) : null; | |
2684 }, | |
2685 | |
2686 element: function(el, nocash){ | |
2687 Slick.uidOf(el); | |
2688 if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName))
{ | |
2689 var fireEvent = el.fireEvent; | |
2690 // wrapping needed in IE7, or else crash | |
2691 el._fireEvent = function(type, event){ | |
2692 return fireEvent(type, event); | |
2693 }; | |
2694 Object.append(el, Element.Prototype); | |
2695 } | |
2696 return el; | |
2697 }, | |
2698 | |
2699 object: function(obj, nocash, doc){ | |
2700 if (obj.toElement) return types.element(obj.toElement(doc), nocash); | |
2701 return null; | |
2702 } | |
2703 | |
2704 }; | |
2705 | |
2706 types.textnode = types.whitespace = types.window = types.document = function
(zero){ | |
2707 return zero; | |
2708 }; | |
2709 | |
2710 return function(el, nocash, doc){ | |
2711 if (el && el.$family && el.uniqueNumber) return el; | |
2712 var type = typeOf(el); | |
2713 return (types[type]) ? types[type](el, nocash, doc || document) : null; | |
2714 }; | |
2715 | |
2716 })() | |
2717 | |
2718 }); | |
2719 | |
2720 if (window.$ == null) Window.implement('$', function(el, nc){ | |
2721 return document.id(el, nc, this.document); | |
2722 }); | |
2723 | |
2724 Window.implement({ | |
2725 | |
2726 getDocument: function(){ | |
2727 return this.document; | |
2728 }, | |
2729 | |
2730 getWindow: function(){ | |
2731 return this; | |
2732 } | |
2733 | |
2734 }); | |
2735 | |
2736 [Document, Element].invoke('implement', { | |
2737 | |
2738 getElements: function(expression){ | |
2739 return Slick.search(this, expression, new Elements); | |
2740 }, | |
2741 | |
2742 getElement: function(expression){ | |
2743 return document.id(Slick.find(this, expression)); | |
2744 } | |
2745 | |
2746 }); | |
2747 | |
2748 var contains = {contains: function(element){ | |
2749 return Slick.contains(this, element); | |
2750 }}; | |
2751 | |
2752 if (!document.contains) Document.implement(contains); | |
2753 if (!document.createElement('div').contains) Element.implement(contains); | |
2754 | |
2755 | |
2756 | |
2757 // tree walking | |
2758 | |
2759 var injectCombinator = function(expression, combinator){ | |
2760 if (!expression) return combinator; | |
2761 | |
2762 expression = Object.clone(Slick.parse(expression)); | |
2763 | |
2764 var expressions = expression.expressions; | |
2765 for (var i = expressions.length; i--;) | |
2766 expressions[i][0].combinator = combinator; | |
2767 | |
2768 return expression; | |
2769 }; | |
2770 | |
2771 Object.forEach({ | |
2772 getNext: '~', | |
2773 getPrevious: '!~', | |
2774 getParent: '!' | |
2775 }, function(combinator, method){ | |
2776 Element.implement(method, function(expression){ | |
2777 return this.getElement(injectCombinator(expression, combinator)); | |
2778 }); | |
2779 }); | |
2780 | |
2781 Object.forEach({ | |
2782 getAllNext: '~', | |
2783 getAllPrevious: '!~', | |
2784 getSiblings: '~~', | |
2785 getChildren: '>', | |
2786 getParents: '!' | |
2787 }, function(combinator, method){ | |
2788 Element.implement(method, function(expression){ | |
2789 return this.getElements(injectCombinator(expression, combinator)); | |
2790 }); | |
2791 }); | |
2792 | |
2793 Element.implement({ | |
2794 | |
2795 getFirst: function(expression){ | |
2796 return document.id(Slick.search(this, injectCombinator(expression, '>'))[0])
; | |
2797 }, | |
2798 | |
2799 getLast: function(expression){ | |
2800 return document.id(Slick.search(this, injectCombinator(expression, '>')).get
Last()); | |
2801 }, | |
2802 | |
2803 getWindow: function(){ | |
2804 return this.ownerDocument.window; | |
2805 }, | |
2806 | |
2807 getDocument: function(){ | |
2808 return this.ownerDocument; | |
2809 }, | |
2810 | |
2811 getElementById: function(id){ | |
2812 return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1')
)); | |
2813 }, | |
2814 | |
2815 match: function(expression){ | |
2816 return !expression || Slick.match(this, expression); | |
2817 } | |
2818 | |
2819 }); | |
2820 | |
2821 | |
2822 | |
2823 if (window.$$ == null) Window.implement('$$', function(selector){ | |
2824 if (arguments.length == 1){ | |
2825 if (typeof selector == 'string') return Slick.search(this.document, selector
, new Elements); | |
2826 else if (Type.isEnumerable(selector)) return new Elements(selector); | |
2827 } | |
2828 return new Elements(arguments); | |
2829 }); | |
2830 | |
2831 // Inserters | |
2832 | |
2833 var inserters = { | |
2834 | |
2835 before: function(context, element){ | |
2836 var parent = element.parentNode; | |
2837 if (parent) parent.insertBefore(context, element); | |
2838 }, | |
2839 | |
2840 after: function(context, element){ | |
2841 var parent = element.parentNode; | |
2842 if (parent) parent.insertBefore(context, element.nextSibling); | |
2843 }, | |
2844 | |
2845 bottom: function(context, element){ | |
2846 element.appendChild(context); | |
2847 }, | |
2848 | |
2849 top: function(context, element){ | |
2850 element.insertBefore(context, element.firstChild); | |
2851 } | |
2852 | |
2853 }; | |
2854 | |
2855 inserters.inside = inserters.bottom; | |
2856 | |
2857 | |
2858 | |
2859 // getProperty / setProperty | |
2860 | |
2861 var propertyGetters = {}, propertySetters = {}; | |
2862 | |
2863 // properties | |
2864 | |
2865 var properties = {}; | |
2866 Array.forEach([ | |
2867 'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'c
olSpan', | |
2868 'frameBorder', 'rowSpan', 'tabIndex', 'useMap' | |
2869 ], function(property){ | |
2870 properties[property.toLowerCase()] = property; | |
2871 }); | |
2872 | |
2873 properties.html = 'innerHTML'; | |
2874 properties.text = (document.createElement('div').textContent == null) ? 'innerTe
xt': 'textContent'; | |
2875 | |
2876 Object.forEach(properties, function(real, key){ | |
2877 propertySetters[key] = function(node, value){ | |
2878 node[real] = value; | |
2879 }; | |
2880 propertyGetters[key] = function(node){ | |
2881 return node[real]; | |
2882 }; | |
2883 }); | |
2884 | |
2885 // Booleans | |
2886 | |
2887 var bools = [ | |
2888 'compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', | |
2889 'disabled', 'readOnly', 'multiple', 'selected', 'noresize', | |
2890 'defer', 'defaultChecked', 'autofocus', 'controls', 'autoplay', | |
2891 'loop' | |
2892 ]; | |
2893 | |
2894 var booleans = {}; | |
2895 Array.forEach(bools, function(bool){ | |
2896 var lower = bool.toLowerCase(); | |
2897 booleans[lower] = bool; | |
2898 propertySetters[lower] = function(node, value){ | |
2899 node[bool] = !!value; | |
2900 }; | |
2901 propertyGetters[lower] = function(node){ | |
2902 return !!node[bool]; | |
2903 }; | |
2904 }); | |
2905 | |
2906 // Special cases | |
2907 | |
2908 Object.append(propertySetters, { | |
2909 | |
2910 'class': function(node, value){ | |
2911 ('className' in node) ? node.className = (value || '') : node.setAttribute('
class', value); | |
2912 }, | |
2913 | |
2914 'for': function(node, value){ | |
2915 ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value)
; | |
2916 }, | |
2917 | |
2918 'style': function(node, value){ | |
2919 (node.style) ? node.style.cssText = value : node.setAttribute('style', value
); | |
2920 }, | |
2921 | |
2922 'value': function(node, value){ | |
2923 node.value = (value != null) ? value : ''; | |
2924 } | |
2925 | |
2926 }); | |
2927 | |
2928 propertyGetters['class'] = function(node){ | |
2929 return ('className' in node) ? node.className || null : node.getAttribute('cla
ss'); | |
2930 }; | |
2931 | |
2932 /* <webkit> */ | |
2933 var el = document.createElement('button'); | |
2934 // IE sets type as readonly and throws | |
2935 try { el.type = 'button'; } catch(e){} | |
2936 if (el.type != 'button') propertySetters.type = function(node, value){ | |
2937 node.setAttribute('type', value); | |
2938 }; | |
2939 el = null; | |
2940 /* </webkit> */ | |
2941 | |
2942 /*<IE>*/ | |
2943 var input = document.createElement('input'); | |
2944 input.value = 't'; | |
2945 input.type = 'submit'; | |
2946 if (input.value != 't') propertySetters.type = function(node, type){ | |
2947 var value = node.value; | |
2948 node.type = type; | |
2949 node.value = value; | |
2950 }; | |
2951 input = null; | |
2952 /*</IE>*/ | |
2953 | |
2954 /* getProperty, setProperty */ | |
2955 | |
2956 /* <ltIE9> */ | |
2957 var pollutesGetAttribute = (function(div){ | |
2958 div.random = 'attribute'; | |
2959 return (div.getAttribute('random') == 'attribute'); | |
2960 })(document.createElement('div')); | |
2961 | |
2962 /* <ltIE9> */ | |
2963 | |
2964 Element.implement({ | |
2965 | |
2966 setProperty: function(name, value){ | |
2967 var setter = propertySetters[name.toLowerCase()]; | |
2968 if (setter){ | |
2969 setter(this, value); | |
2970 } else { | |
2971 /* <ltIE9> */ | |
2972 if (pollutesGetAttribute) var attributeWhiteList = this.retrieve('$attribu
teWhiteList', {}); | |
2973 /* </ltIE9> */ | |
2974 | |
2975 if (value == null){ | |
2976 this.removeAttribute(name); | |
2977 /* <ltIE9> */ | |
2978 if (pollutesGetAttribute) delete attributeWhiteList[name]; | |
2979 /* </ltIE9> */ | |
2980 } else { | |
2981 this.setAttribute(name, '' + value); | |
2982 /* <ltIE9> */ | |
2983 if (pollutesGetAttribute) attributeWhiteList[name] = true; | |
2984 /* </ltIE9> */ | |
2985 } | |
2986 } | |
2987 return this; | |
2988 }, | |
2989 | |
2990 setProperties: function(attributes){ | |
2991 for (var attribute in attributes) this.setProperty(attribute, attributes[att
ribute]); | |
2992 return this; | |
2993 }, | |
2994 | |
2995 getProperty: function(name){ | |
2996 var getter = propertyGetters[name.toLowerCase()]; | |
2997 if (getter) return getter(this); | |
2998 /* <ltIE9> */ | |
2999 if (pollutesGetAttribute){ | |
3000 var attr = this.getAttributeNode(name), attributeWhiteList = this.retrieve
('$attributeWhiteList', {}); | |
3001 if (!attr) return null; | |
3002 if (attr.expando && !attributeWhiteList[name]){ | |
3003 var outer = this.outerHTML; | |
3004 // segment by the opening tag and find mention of attribute name | |
3005 if (outer.substr(0, outer.search(/\/?['"]?>(?![^<]*<['"])/)).indexOf(nam
e) < 0) return null; | |
3006 attributeWhiteList[name] = true; | |
3007 } | |
3008 } | |
3009 /* </ltIE9> */ | |
3010 var result = Slick.getAttribute(this, name); | |
3011 return (!result && !Slick.hasAttribute(this, name)) ? null : result; | |
3012 }, | |
3013 | |
3014 getProperties: function(){ | |
3015 var args = Array.from(arguments); | |
3016 return args.map(this.getProperty, this).associate(args); | |
3017 }, | |
3018 | |
3019 removeProperty: function(name){ | |
3020 return this.setProperty(name, null); | |
3021 }, | |
3022 | |
3023 removeProperties: function(){ | |
3024 Array.each(arguments, this.removeProperty, this); | |
3025 return this; | |
3026 }, | |
3027 | |
3028 set: function(prop, value){ | |
3029 var property = Element.Properties[prop]; | |
3030 (property && property.set) ? property.set.call(this, value) : this.setProper
ty(prop, value); | |
3031 }.overloadSetter(), | |
3032 | |
3033 get: function(prop){ | |
3034 var property = Element.Properties[prop]; | |
3035 return (property && property.get) ? property.get.apply(this) : this.getPrope
rty(prop); | |
3036 }.overloadGetter(), | |
3037 | |
3038 erase: function(prop){ | |
3039 var property = Element.Properties[prop]; | |
3040 (property && property.erase) ? property.erase.apply(this) : this.removePrope
rty(prop); | |
3041 return this; | |
3042 }, | |
3043 | |
3044 hasClass: function(className){ | |
3045 return this.className.clean().contains(className, ' '); | |
3046 }, | |
3047 | |
3048 addClass: function(className){ | |
3049 if (!this.hasClass(className)) this.className = (this.className + ' ' + clas
sName).clean(); | |
3050 return this; | |
3051 }, | |
3052 | |
3053 removeClass: function(className){ | |
3054 this.className = this.className.replace(new RegExp('(^|\\s)' + className + '
(?:\\s|$)'), '$1'); | |
3055 return this; | |
3056 }, | |
3057 | |
3058 toggleClass: function(className, force){ | |
3059 if (force == null) force = !this.hasClass(className); | |
3060 return (force) ? this.addClass(className) : this.removeClass(className); | |
3061 }, | |
3062 | |
3063 adopt: function(){ | |
3064 var parent = this, fragment, elements = Array.flatten(arguments), length = e
lements.length; | |
3065 if (length > 1) parent = fragment = document.createDocumentFragment(); | |
3066 | |
3067 for (var i = 0; i < length; i++){ | |
3068 var element = document.id(elements[i], true); | |
3069 if (element) parent.appendChild(element); | |
3070 } | |
3071 | |
3072 if (fragment) this.appendChild(fragment); | |
3073 | |
3074 return this; | |
3075 }, | |
3076 | |
3077 appendText: function(text, where){ | |
3078 return this.grab(this.getDocument().newTextNode(text), where); | |
3079 }, | |
3080 | |
3081 grab: function(el, where){ | |
3082 inserters[where || 'bottom'](document.id(el, true), this); | |
3083 return this; | |
3084 }, | |
3085 | |
3086 inject: function(el, where){ | |
3087 inserters[where || 'bottom'](this, document.id(el, true)); | |
3088 return this; | |
3089 }, | |
3090 | |
3091 replaces: function(el){ | |
3092 el = document.id(el, true); | |
3093 el.parentNode.replaceChild(this, el); | |
3094 return this; | |
3095 }, | |
3096 | |
3097 wraps: function(el, where){ | |
3098 el = document.id(el, true); | |
3099 return this.replaces(el).grab(el, where); | |
3100 }, | |
3101 | |
3102 getSelected: function(){ | |
3103 this.selectedIndex; // Safari 3.2.1 | |
3104 return new Elements(Array.from(this.options).filter(function(option){ | |
3105 return option.selected; | |
3106 })); | |
3107 }, | |
3108 | |
3109 toQueryString: function(){ | |
3110 var queryString = []; | |
3111 this.getElements('input, select, textarea').each(function(el){ | |
3112 var type = el.type; | |
3113 if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type
== 'file' || type == 'image') return; | |
3114 | |
3115 var value = (el.get('tag') == 'select') ? el.getSelected().map(function(op
t){ | |
3116 // IE | |
3117 return document.id(opt).get('value'); | |
3118 }) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.
get('value'); | |
3119 | |
3120 Array.from(value).each(function(val){ | |
3121 if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.na
me) + '=' + encodeURIComponent(val)); | |
3122 }); | |
3123 }); | |
3124 return queryString.join('&'); | |
3125 } | |
3126 | |
3127 }); | |
3128 | |
3129 var collected = {}, storage = {}; | |
3130 | |
3131 var get = function(uid){ | |
3132 return (storage[uid] || (storage[uid] = {})); | |
3133 }; | |
3134 | |
3135 var clean = function(item){ | |
3136 var uid = item.uniqueNumber; | |
3137 if (item.removeEvents) item.removeEvents(); | |
3138 if (item.clearAttributes) item.clearAttributes(); | |
3139 if (uid != null){ | |
3140 delete collected[uid]; | |
3141 delete storage[uid]; | |
3142 } | |
3143 return item; | |
3144 }; | |
3145 | |
3146 var formProps = {input: 'checked', option: 'selected', textarea: 'value'}; | |
3147 | |
3148 Element.implement({ | |
3149 | |
3150 destroy: function(){ | |
3151 var children = clean(this).getElementsByTagName('*'); | |
3152 Array.each(children, clean); | |
3153 Element.dispose(this); | |
3154 return null; | |
3155 }, | |
3156 | |
3157 empty: function(){ | |
3158 Array.from(this.childNodes).each(Element.dispose); | |
3159 return this; | |
3160 }, | |
3161 | |
3162 dispose: function(){ | |
3163 return (this.parentNode) ? this.parentNode.removeChild(this) : this; | |
3164 }, | |
3165 | |
3166 clone: function(contents, keepid){ | |
3167 contents = contents !== false; | |
3168 var clone = this.cloneNode(contents), ce = [clone], te = [this], i; | |
3169 | |
3170 if (contents){ | |
3171 ce.append(Array.from(clone.getElementsByTagName('*'))); | |
3172 te.append(Array.from(this.getElementsByTagName('*'))); | |
3173 } | |
3174 | |
3175 for (i = ce.length; i--;){ | |
3176 var node = ce[i], element = te[i]; | |
3177 if (!keepid) node.removeAttribute('id'); | |
3178 /*<ltIE9>*/ | |
3179 if (node.clearAttributes){ | |
3180 node.clearAttributes(); | |
3181 node.mergeAttributes(element); | |
3182 node.removeAttribute('uniqueNumber'); | |
3183 if (node.options){ | |
3184 var no = node.options, eo = element.options; | |
3185 for (var j = no.length; j--;) no[j].selected = eo[j].selected; | |
3186 } | |
3187 } | |
3188 /*</ltIE9>*/ | |
3189 var prop = formProps[element.tagName.toLowerCase()]; | |
3190 if (prop && element[prop]) node[prop] = element[prop]; | |
3191 } | |
3192 | |
3193 /*<ltIE9>*/ | |
3194 if (Browser.ie){ | |
3195 var co = clone.getElementsByTagName('object'), to = this.getElementsByTagN
ame('object'); | |
3196 for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML; | |
3197 } | |
3198 /*</ltIE9>*/ | |
3199 return document.id(clone); | |
3200 } | |
3201 | |
3202 }); | |
3203 | |
3204 [Element, Window, Document].invoke('implement', { | |
3205 | |
3206 addListener: function(type, fn){ | |
3207 if (type == 'unload'){ | |
3208 var old = fn, self = this; | |
3209 fn = function(){ | |
3210 self.removeListener('unload', fn); | |
3211 old(); | |
3212 }; | |
3213 } else { | |
3214 collected[Slick.uidOf(this)] = this; | |
3215 } | |
3216 if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]); | |
3217 else this.attachEvent('on' + type, fn); | |
3218 return this; | |
3219 }, | |
3220 | |
3221 removeListener: function(type, fn){ | |
3222 if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments
[2]); | |
3223 else this.detachEvent('on' + type, fn); | |
3224 return this; | |
3225 }, | |
3226 | |
3227 retrieve: function(property, dflt){ | |
3228 var storage = get(Slick.uidOf(this)), prop = storage[property]; | |
3229 if (dflt != null && prop == null) prop = storage[property] = dflt; | |
3230 return prop != null ? prop : null; | |
3231 }, | |
3232 | |
3233 store: function(property, value){ | |
3234 var storage = get(Slick.uidOf(this)); | |
3235 storage[property] = value; | |
3236 return this; | |
3237 }, | |
3238 | |
3239 eliminate: function(property){ | |
3240 var storage = get(Slick.uidOf(this)); | |
3241 delete storage[property]; | |
3242 return this; | |
3243 } | |
3244 | |
3245 }); | |
3246 | |
3247 /*<ltIE9>*/ | |
3248 if (window.attachEvent && !window.addEventListener) window.addListener('unload',
function(){ | |
3249 Object.each(collected, clean); | |
3250 if (window.CollectGarbage) CollectGarbage(); | |
3251 }); | |
3252 /*</ltIE9>*/ | |
3253 | |
3254 Element.Properties = {}; | |
3255 | |
3256 | |
3257 | |
3258 Element.Properties.style = { | |
3259 | |
3260 set: function(style){ | |
3261 this.style.cssText = style; | |
3262 }, | |
3263 | |
3264 get: function(){ | |
3265 return this.style.cssText; | |
3266 }, | |
3267 | |
3268 erase: function(){ | |
3269 this.style.cssText = ''; | |
3270 } | |
3271 | |
3272 }; | |
3273 | |
3274 Element.Properties.tag = { | |
3275 | |
3276 get: function(){ | |
3277 return this.tagName.toLowerCase(); | |
3278 } | |
3279 | |
3280 }; | |
3281 | |
3282 Element.Properties.html = { | |
3283 | |
3284 set: function(html){ | |
3285 if (html == null) html = ''; | |
3286 else if (typeOf(html) == 'array') html = html.join(''); | |
3287 this.innerHTML = html; | |
3288 }, | |
3289 | |
3290 erase: function(){ | |
3291 this.innerHTML = ''; | |
3292 } | |
3293 | |
3294 }; | |
3295 | |
3296 /*<ltIE9>*/ | |
3297 // technique by jdbarlett - http://jdbartlett.com/innershiv/ | |
3298 var div = document.createElement('div'); | |
3299 div.innerHTML = '<nav></nav>'; | |
3300 var supportsHTML5Elements = (div.childNodes.length == 1); | |
3301 if (!supportsHTML5Elements){ | |
3302 var tags = 'abbr article aside audio canvas datalist details figcaption figure
footer header hgroup mark meter nav output progress section summary time video'
.split(' '), | |
3303 fragment = document.createDocumentFragment(), l = tags.length; | |
3304 while (l--) fragment.createElement(tags[l]); | |
3305 } | |
3306 div = null; | |
3307 /*</ltIE9>*/ | |
3308 | |
3309 /*<IE>*/ | |
3310 var supportsTableInnerHTML = Function.attempt(function(){ | |
3311 var table = document.createElement('table'); | |
3312 table.innerHTML = '<tr><td></td></tr>'; | |
3313 return true; | |
3314 }); | |
3315 | |
3316 /*<ltFF4>*/ | |
3317 var tr = document.createElement('tr'), html = '<td></td>'; | |
3318 tr.innerHTML = html; | |
3319 var supportsTRInnerHTML = (tr.innerHTML == html); | |
3320 tr = null; | |
3321 /*</ltFF4>*/ | |
3322 | |
3323 if (!supportsTableInnerHTML || !supportsTRInnerHTML || !supportsHTML5Elements){ | |
3324 | |
3325 Element.Properties.html.set = (function(set){ | |
3326 | |
3327 var translations = { | |
3328 table: [1, '<table>', '</table>'], | |
3329 select: [1, '<select>', '</select>'], | |
3330 tbody: [2, '<table><tbody>', '</tbody></table>'], | |
3331 tr: [3, '<table><tbody><tr>', '</tr></tbody></table>'] | |
3332 }; | |
3333 | |
3334 translations.thead = translations.tfoot = translations.tbody; | |
3335 | |
3336 return function(html){ | |
3337 var wrap = translations[this.get('tag')]; | |
3338 if (!wrap && !supportsHTML5Elements) wrap = [0, '', '']; | |
3339 if (!wrap) return set.call(this, html); | |
3340 | |
3341 var level = wrap[0], wrapper = document.createElement('div'), target = wra
pper; | |
3342 if (!supportsHTML5Elements) fragment.appendChild(wrapper); | |
3343 wrapper.innerHTML = [wrap[1], html, wrap[2]].flatten().join(''); | |
3344 while (level--) target = target.firstChild; | |
3345 this.empty().adopt(target.childNodes); | |
3346 if (!supportsHTML5Elements) fragment.removeChild(wrapper); | |
3347 wrapper = null; | |
3348 }; | |
3349 | |
3350 })(Element.Properties.html.set); | |
3351 } | |
3352 /*</IE>*/ | |
3353 | |
3354 /*<ltIE9>*/ | |
3355 var testForm = document.createElement('form'); | |
3356 testForm.innerHTML = '<select><option>s</option></select>'; | |
3357 | |
3358 if (testForm.firstChild.value != 's') Element.Properties.value = { | |
3359 | |
3360 set: function(value){ | |
3361 var tag = this.get('tag'); | |
3362 if (tag != 'select') return this.setProperty('value', value); | |
3363 var options = this.getElements('option'); | |
3364 for (var i = 0; i < options.length; i++){ | |
3365 var option = options[i], | |
3366 attr = option.getAttributeNode('value'), | |
3367 optionValue = (attr && attr.specified) ? option.value : option.get('text
'); | |
3368 if (optionValue == value) return option.selected = true; | |
3369 } | |
3370 }, | |
3371 | |
3372 get: function(){ | |
3373 var option = this, tag = option.get('tag'); | |
3374 | |
3375 if (tag != 'select' && tag != 'option') return this.getProperty('value'); | |
3376 | |
3377 if (tag == 'select' && !(option = option.getSelected()[0])) return ''; | |
3378 | |
3379 var attr = option.getAttributeNode('value'); | |
3380 return (attr && attr.specified) ? option.value : option.get('text'); | |
3381 } | |
3382 | |
3383 }; | |
3384 testForm = null; | |
3385 /*</ltIE9>*/ | |
3386 | |
3387 /*<IE>*/ | |
3388 if (document.createElement('div').getAttributeNode('id')) Element.Properties.id
= { | |
3389 set: function(id){ | |
3390 this.id = this.getAttributeNode('id').value = id; | |
3391 }, | |
3392 get: function(){ | |
3393 return this.id || null; | |
3394 }, | |
3395 erase: function(){ | |
3396 this.id = this.getAttributeNode('id').value = ''; | |
3397 } | |
3398 }; | |
3399 /*</IE>*/ | |
3400 | |
3401 })(); | |
3402 | |
3403 | |
3404 /* | |
3405 --- | |
3406 | |
3407 name: Element.Style | |
3408 | |
3409 description: Contains methods for interacting with the styles of Elements in a f
ashionable way. | |
3410 | |
3411 license: MIT-style license. | |
3412 | |
3413 requires: Element | |
3414 | |
3415 provides: Element.Style | |
3416 | |
3417 ... | |
3418 */ | |
3419 | |
3420 (function(){ | |
3421 | |
3422 var html = document.html; | |
3423 | |
3424 //<ltIE9> | |
3425 // Check for oldIE, which does not remove styles when they're set to null | |
3426 var el = document.createElement('div'); | |
3427 el.style.color = 'red'; | |
3428 el.style.color = null; | |
3429 var doesNotRemoveStyles = el.style.color == 'red'; | |
3430 el = null; | |
3431 //</ltIE9> | |
3432 | |
3433 Element.Properties.styles = {set: function(styles){ | |
3434 this.setStyles(styles); | |
3435 }}; | |
3436 | |
3437 var hasOpacity = (html.style.opacity != null), | |
3438 hasFilter = (html.style.filter != null), | |
3439 reAlpha = /alpha\(opacity=([\d.]+)\)/i; | |
3440 | |
3441 var setVisibility = function(element, opacity){ | |
3442 element.store('$opacity', opacity); | |
3443 element.style.visibility = opacity > 0 || opacity == null ? 'visible' : 'hidde
n'; | |
3444 }; | |
3445 | |
3446 var setOpacity = (hasOpacity ? function(element, opacity){ | |
3447 element.style.opacity = opacity; | |
3448 } : (hasFilter ? function(element, opacity){ | |
3449 var style = element.style; | |
3450 if (!element.currentStyle || !element.currentStyle.hasLayout) style.zoom = 1; | |
3451 if (opacity == null || opacity == 1) opacity = ''; | |
3452 else opacity = 'alpha(opacity=' + (opacity * 100).limit(0, 100).round() + ')'; | |
3453 var filter = style.filter || element.getComputedStyle('filter') || ''; | |
3454 style.filter = reAlpha.test(filter) ? filter.replace(reAlpha, opacity) : filte
r + opacity; | |
3455 if (!style.filter) style.removeAttribute('filter'); | |
3456 } : setVisibility)); | |
3457 | |
3458 var getOpacity = (hasOpacity ? function(element){ | |
3459 var opacity = element.style.opacity || element.getComputedStyle('opacity'); | |
3460 return (opacity == '') ? 1 : opacity.toFloat(); | |
3461 } : (hasFilter ? function(element){ | |
3462 var filter = (element.style.filter || element.getComputedStyle('filter')), | |
3463 opacity; | |
3464 if (filter) opacity = filter.match(reAlpha); | |
3465 return (opacity == null || filter == null) ? 1 : (opacity[1] / 100); | |
3466 } : function(element){ | |
3467 var opacity = element.retrieve('$opacity'); | |
3468 if (opacity == null) opacity = (element.style.visibility == 'hidden' ? 0 : 1); | |
3469 return opacity; | |
3470 })); | |
3471 | |
3472 var floatName = (html.style.cssFloat == null) ? 'styleFloat' : 'cssFloat'; | |
3473 | |
3474 Element.implement({ | |
3475 | |
3476 getComputedStyle: function(property){ | |
3477 if (this.currentStyle) return this.currentStyle[property.camelCase()]; | |
3478 var defaultView = Element.getDocument(this).defaultView, | |
3479 computed = defaultView ? defaultView.getComputedStyle(this, null) : null; | |
3480 return (computed) ? computed.getPropertyValue((property == floatName) ? 'flo
at' : property.hyphenate()) : null; | |
3481 }, | |
3482 | |
3483 setStyle: function(property, value){ | |
3484 if (property == 'opacity'){ | |
3485 if (value != null) value = parseFloat(value); | |
3486 setOpacity(this, value); | |
3487 return this; | |
3488 } | |
3489 property = (property == 'float' ? floatName : property).camelCase(); | |
3490 if (typeOf(value) != 'string'){ | |
3491 var map = (Element.Styles[property] || '@').split(' '); | |
3492 value = Array.from(value).map(function(val, i){ | |
3493 if (!map[i]) return ''; | |
3494 return (typeOf(val) == 'number') ? map[i].replace('@', Math.round(val))
: val; | |
3495 }).join(' '); | |
3496 } else if (value == String(Number(value))){ | |
3497 value = Math.round(value); | |
3498 } | |
3499 this.style[property] = value; | |
3500 //<ltIE9> | |
3501 if ((value == '' || value == null) && doesNotRemoveStyles && this.style.remo
veAttribute){ | |
3502 this.style.removeAttribute(property); | |
3503 } | |
3504 //</ltIE9> | |
3505 return this; | |
3506 }, | |
3507 | |
3508 getStyle: function(property){ | |
3509 if (property == 'opacity') return getOpacity(this); | |
3510 property = (property == 'float' ? floatName : property).camelCase(); | |
3511 var result = this.style[property]; | |
3512 if (!result || property == 'zIndex'){ | |
3513 result = []; | |
3514 for (var style in Element.ShortStyles){ | |
3515 if (property != style) continue; | |
3516 for (var s in Element.ShortStyles[style]) result.push(this.getStyle(s)); | |
3517 return result.join(' '); | |
3518 } | |
3519 result = this.getComputedStyle(property); | |
3520 } | |
3521 if (result){ | |
3522 result = String(result); | |
3523 var color = result.match(/rgba?\([\d\s,]+\)/); | |
3524 if (color) result = result.replace(color[0], color[0].rgbToHex()); | |
3525 } | |
3526 if (Browser.opera || Browser.ie){ | |
3527 if ((/^(height|width)$/).test(property) && !(/px$/.test(result))){ | |
3528 var values = (property == 'width') ? ['left', 'right'] : ['top', 'bottom
'], size = 0; | |
3529 values.each(function(value){ | |
3530 size += this.getStyle('border-' + value + '-width').toInt() + this.get
Style('padding-' + value).toInt(); | |
3531 }, this); | |
3532 return this['offset' + property.capitalize()] - size + 'px'; | |
3533 } | |
3534 if (Browser.ie && (/^border(.+)Width|margin|padding/).test(property) && is
NaN(parseFloat(result))){ | |
3535 return '0px'; | |
3536 } | |
3537 } | |
3538 return result; | |
3539 }, | |
3540 | |
3541 setStyles: function(styles){ | |
3542 for (var style in styles) this.setStyle(style, styles[style]); | |
3543 return this; | |
3544 }, | |
3545 | |
3546 getStyles: function(){ | |
3547 var result = {}; | |
3548 Array.flatten(arguments).each(function(key){ | |
3549 result[key] = this.getStyle(key); | |
3550 }, this); | |
3551 return result; | |
3552 } | |
3553 | |
3554 }); | |
3555 | |
3556 Element.Styles = { | |
3557 left: '@px', top: '@px', bottom: '@px', right: '@px', | |
3558 width: '@px', height: '@px', maxWidth: '@px', maxHeight: '@px', minWidth: '@px
', minHeight: '@px', | |
3559 backgroundColor: 'rgb(@, @, @)', backgroundPosition: '@px @px', color: 'rgb(@,
@, @)', | |
3560 fontSize: '@px', letterSpacing: '@px', lineHeight: '@px', clip: 'rect(@px @px
@px @px)', | |
3561 margin: '@px @px @px @px', padding: '@px @px @px @px', border: '@px @ rgb(@, @
, @) @px @ rgb(@, @, @) @px @ rgb(@, @, @)', | |
3562 borderWidth: '@px @px @px @px', borderStyle: '@ @ @ @', borderColor: 'rgb(@, @
, @) rgb(@, @, @) rgb(@, @, @) rgb(@, @, @)', | |
3563 zIndex: '@', 'zoom': '@', fontWeight: '@', textIndent: '@px', opacity: '@' | |
3564 }; | |
3565 | |
3566 | |
3567 | |
3568 | |
3569 | |
3570 Element.ShortStyles = {margin: {}, padding: {}, border: {}, borderWidth: {}, bor
derStyle: {}, borderColor: {}}; | |
3571 | |
3572 ['Top', 'Right', 'Bottom', 'Left'].each(function(direction){ | |
3573 var Short = Element.ShortStyles; | |
3574 var All = Element.Styles; | |
3575 ['margin', 'padding'].each(function(style){ | |
3576 var sd = style + direction; | |
3577 Short[style][sd] = All[sd] = '@px'; | |
3578 }); | |
3579 var bd = 'border' + direction; | |
3580 Short.border[bd] = All[bd] = '@px @ rgb(@, @, @)'; | |
3581 var bdw = bd + 'Width', bds = bd + 'Style', bdc = bd + 'Color'; | |
3582 Short[bd] = {}; | |
3583 Short.borderWidth[bdw] = Short[bd][bdw] = All[bdw] = '@px'; | |
3584 Short.borderStyle[bds] = Short[bd][bds] = All[bds] = '@'; | |
3585 Short.borderColor[bdc] = Short[bd][bdc] = All[bdc] = 'rgb(@, @, @)'; | |
3586 }); | |
3587 | |
3588 })(); | |
3589 | |
3590 | |
3591 /* | |
3592 --- | |
3593 | |
3594 name: Element.Event | |
3595 | |
3596 description: Contains Element methods for dealing with events. This file also in
cludes mouseenter and mouseleave custom Element Events, if necessary. | |
3597 | |
3598 license: MIT-style license. | |
3599 | |
3600 requires: [Element, Event] | |
3601 | |
3602 provides: Element.Event | |
3603 | |
3604 ... | |
3605 */ | |
3606 | |
3607 (function(){ | |
3608 | |
3609 Element.Properties.events = {set: function(events){ | |
3610 this.addEvents(events); | |
3611 }}; | |
3612 | |
3613 [Element, Window, Document].invoke('implement', { | |
3614 | |
3615 addEvent: function(type, fn){ | |
3616 var events = this.retrieve('events', {}); | |
3617 if (!events[type]) events[type] = {keys: [], values: []}; | |
3618 if (events[type].keys.contains(fn)) return this; | |
3619 events[type].keys.push(fn); | |
3620 var realType = type, | |
3621 custom = Element.Events[type], | |
3622 condition = fn, | |
3623 self = this; | |
3624 if (custom){ | |
3625 if (custom.onAdd) custom.onAdd.call(this, fn, type); | |
3626 if (custom.condition){ | |
3627 condition = function(event){ | |
3628 if (custom.condition.call(this, event, type)) return fn.call(this, eve
nt); | |
3629 return true; | |
3630 }; | |
3631 } | |
3632 if (custom.base) realType = Function.from(custom.base).call(this, type); | |
3633 } | |
3634 var defn = function(){ | |
3635 return fn.call(self); | |
3636 }; | |
3637 var nativeEvent = Element.NativeEvents[realType]; | |
3638 if (nativeEvent){ | |
3639 if (nativeEvent == 2){ | |
3640 defn = function(event){ | |
3641 event = new DOMEvent(event, self.getWindow()); | |
3642 if (condition.call(self, event) === false) event.stop(); | |
3643 }; | |
3644 } | |
3645 this.addListener(realType, defn, arguments[2]); | |
3646 } | |
3647 events[type].values.push(defn); | |
3648 return this; | |
3649 }, | |
3650 | |
3651 removeEvent: function(type, fn){ | |
3652 var events = this.retrieve('events'); | |
3653 if (!events || !events[type]) return this; | |
3654 var list = events[type]; | |
3655 var index = list.keys.indexOf(fn); | |
3656 if (index == -1) return this; | |
3657 var value = list.values[index]; | |
3658 delete list.keys[index]; | |
3659 delete list.values[index]; | |
3660 var custom = Element.Events[type]; | |
3661 if (custom){ | |
3662 if (custom.onRemove) custom.onRemove.call(this, fn, type); | |
3663 if (custom.base) type = Function.from(custom.base).call(this, type); | |
3664 } | |
3665 return (Element.NativeEvents[type]) ? this.removeListener(type, value, argum
ents[2]) : this; | |
3666 }, | |
3667 | |
3668 addEvents: function(events){ | |
3669 for (var event in events) this.addEvent(event, events[event]); | |
3670 return this; | |
3671 }, | |
3672 | |
3673 removeEvents: function(events){ | |
3674 var type; | |
3675 if (typeOf(events) == 'object'){ | |
3676 for (type in events) this.removeEvent(type, events[type]); | |
3677 return this; | |
3678 } | |
3679 var attached = this.retrieve('events'); | |
3680 if (!attached) return this; | |
3681 if (!events){ | |
3682 for (type in attached) this.removeEvents(type); | |
3683 this.eliminate('events'); | |
3684 } else if (attached[events]){ | |
3685 attached[events].keys.each(function(fn){ | |
3686 this.removeEvent(events, fn); | |
3687 }, this); | |
3688 delete attached[events]; | |
3689 } | |
3690 return this; | |
3691 }, | |
3692 | |
3693 fireEvent: function(type, args, delay){ | |
3694 var events = this.retrieve('events'); | |
3695 if (!events || !events[type]) return this; | |
3696 args = Array.from(args); | |
3697 | |
3698 events[type].keys.each(function(fn){ | |
3699 if (delay) fn.delay(delay, this, args); | |
3700 else fn.apply(this, args); | |
3701 }, this); | |
3702 return this; | |
3703 }, | |
3704 | |
3705 cloneEvents: function(from, type){ | |
3706 from = document.id(from); | |
3707 var events = from.retrieve('events'); | |
3708 if (!events) return this; | |
3709 if (!type){ | |
3710 for (var eventType in events) this.cloneEvents(from, eventType); | |
3711 } else if (events[type]){ | |
3712 events[type].keys.each(function(fn){ | |
3713 this.addEvent(type, fn); | |
3714 }, this); | |
3715 } | |
3716 return this; | |
3717 } | |
3718 | |
3719 }); | |
3720 | |
3721 Element.NativeEvents = { | |
3722 click: 2, dblclick: 2, mouseup: 2, mousedown: 2, contextmenu: 2, //mouse butto
ns | |
3723 mousewheel: 2, DOMMouseScroll: 2, //mouse wheel | |
3724 mouseover: 2, mouseout: 2, mousemove: 2, selectstart: 2, selectend: 2, //mouse
movement | |
3725 keydown: 2, keypress: 2, keyup: 2, //keyboard | |
3726 orientationchange: 2, // mobile | |
3727 touchstart: 2, touchmove: 2, touchend: 2, touchcancel: 2, // touch | |
3728 gesturestart: 2, gesturechange: 2, gestureend: 2, // gesture | |
3729 focus: 2, blur: 2, change: 2, reset: 2, select: 2, submit: 2, paste: 2, input:
2, //form elements | |
3730 load: 2, unload: 1, beforeunload: 2, resize: 1, move: 1, DOMContentLoaded: 1,
readystatechange: 1, //window | |
3731 error: 1, abort: 1, scroll: 1 //misc | |
3732 }; | |
3733 | |
3734 Element.Events = {mousewheel: { | |
3735 base: (Browser.firefox) ? 'DOMMouseScroll' : 'mousewheel' | |
3736 }}; | |
3737 | |
3738 if ('onmouseenter' in document.documentElement){ | |
3739 Element.NativeEvents.mouseenter = Element.NativeEvents.mouseleave = 2; | |
3740 } else { | |
3741 var check = function(event){ | |
3742 var related = event.relatedTarget; | |
3743 if (related == null) return true; | |
3744 if (!related) return false; | |
3745 return (related != this && related.prefix != 'xul' && typeOf(this) != 'docum
ent' && !this.contains(related)); | |
3746 }; | |
3747 | |
3748 Element.Events.mouseenter = { | |
3749 base: 'mouseover', | |
3750 condition: check | |
3751 }; | |
3752 | |
3753 Element.Events.mouseleave = { | |
3754 base: 'mouseout', | |
3755 condition: check | |
3756 }; | |
3757 } | |
3758 | |
3759 /*<ltIE9>*/ | |
3760 if (!window.addEventListener){ | |
3761 Element.NativeEvents.propertychange = 2; | |
3762 Element.Events.change = { | |
3763 base: function(){ | |
3764 var type = this.type; | |
3765 return (this.get('tag') == 'input' && (type == 'radio' || type == 'checkbo
x')) ? 'propertychange' : 'change' | |
3766 }, | |
3767 condition: function(event){ | |
3768 return this.type != 'radio' || (event.event.propertyName == 'checked' && t
his.checked); | |
3769 } | |
3770 } | |
3771 } | |
3772 /*</ltIE9>*/ | |
3773 | |
3774 | |
3775 | |
3776 })(); | |
3777 | |
3778 | |
3779 /* | |
3780 --- | |
3781 | |
3782 name: Element.Dimensions | |
3783 | |
3784 description: Contains methods to work with size, scroll, or positioning of Eleme
nts and the window object. | |
3785 | |
3786 license: MIT-style license. | |
3787 | |
3788 credits: | |
3789 - Element positioning based on the [qooxdoo](http://qooxdoo.org/) code and sma
rt browser fixes, [LGPL License](http://www.gnu.org/licenses/lgpl.html). | |
3790 - Viewport dimensions based on [YUI](http://developer.yahoo.com/yui/) code, [B
SD License](http://developer.yahoo.com/yui/license.html). | |
3791 | |
3792 requires: [Element, Element.Style] | |
3793 | |
3794 provides: [Element.Dimensions] | |
3795 | |
3796 ... | |
3797 */ | |
3798 | |
3799 (function(){ | |
3800 | |
3801 var element = document.createElement('div'), | |
3802 child = document.createElement('div'); | |
3803 element.style.height = '0'; | |
3804 element.appendChild(child); | |
3805 var brokenOffsetParent = (child.offsetParent === element); | |
3806 element = child = null; | |
3807 | |
3808 var isOffset = function(el){ | |
3809 return styleString(el, 'position') != 'static' || isBody(el); | |
3810 }; | |
3811 | |
3812 var isOffsetStatic = function(el){ | |
3813 return isOffset(el) || (/^(?:table|td|th)$/i).test(el.tagName); | |
3814 }; | |
3815 | |
3816 Element.implement({ | |
3817 | |
3818 scrollTo: function(x, y){ | |
3819 if (isBody(this)){ | |
3820 this.getWindow().scrollTo(x, y); | |
3821 } else { | |
3822 this.scrollLeft = x; | |
3823 this.scrollTop = y; | |
3824 } | |
3825 return this; | |
3826 }, | |
3827 | |
3828 getSize: function(){ | |
3829 if (isBody(this)) return this.getWindow().getSize(); | |
3830 return {x: this.offsetWidth, y: this.offsetHeight}; | |
3831 }, | |
3832 | |
3833 getScrollSize: function(){ | |
3834 if (isBody(this)) return this.getWindow().getScrollSize(); | |
3835 return {x: this.scrollWidth, y: this.scrollHeight}; | |
3836 }, | |
3837 | |
3838 getScroll: function(){ | |
3839 if (isBody(this)) return this.getWindow().getScroll(); | |
3840 return {x: this.scrollLeft, y: this.scrollTop}; | |
3841 }, | |
3842 | |
3843 getScrolls: function(){ | |
3844 var element = this.parentNode, position = {x: 0, y: 0}; | |
3845 while (element && !isBody(element)){ | |
3846 position.x += element.scrollLeft; | |
3847 position.y += element.scrollTop; | |
3848 element = element.parentNode; | |
3849 } | |
3850 return position; | |
3851 }, | |
3852 | |
3853 getOffsetParent: brokenOffsetParent ? function(){ | |
3854 var element = this; | |
3855 if (isBody(element) || styleString(element, 'position') == 'fixed') return n
ull; | |
3856 | |
3857 var isOffsetCheck = (styleString(element, 'position') == 'static') ? isOffse
tStatic : isOffset; | |
3858 while ((element = element.parentNode)){ | |
3859 if (isOffsetCheck(element)) return element; | |
3860 } | |
3861 return null; | |
3862 } : function(){ | |
3863 var element = this; | |
3864 if (isBody(element) || styleString(element, 'position') == 'fixed') return n
ull; | |
3865 | |
3866 try { | |
3867 return element.offsetParent; | |
3868 } catch(e) {} | |
3869 return null; | |
3870 }, | |
3871 | |
3872 getOffsets: function(){ | |
3873 if (this.getBoundingClientRect && !Browser.Platform.ios){ | |
3874 var bound = this.getBoundingClientRect(), | |
3875 html = document.id(this.getDocument().documentElement), | |
3876 htmlScroll = html.getScroll(), | |
3877 elemScrolls = this.getScrolls(), | |
3878 isFixed = (styleString(this, 'position') == 'fixed'); | |
3879 | |
3880 return { | |
3881 x: bound.left.toInt() + elemScrolls.x + ((isFixed) ? 0 : htmlScroll.x) -
html.clientLeft, | |
3882 y: bound.top.toInt() + elemScrolls.y + ((isFixed) ? 0 : htmlScroll.y) -
html.clientTop | |
3883 }; | |
3884 } | |
3885 | |
3886 var element = this, position = {x: 0, y: 0}; | |
3887 if (isBody(this)) return position; | |
3888 | |
3889 while (element && !isBody(element)){ | |
3890 position.x += element.offsetLeft; | |
3891 position.y += element.offsetTop; | |
3892 | |
3893 if (Browser.firefox){ | |
3894 if (!borderBox(element)){ | |
3895 position.x += leftBorder(element); | |
3896 position.y += topBorder(element); | |
3897 } | |
3898 var parent = element.parentNode; | |
3899 if (parent && styleString(parent, 'overflow') != 'visible'){ | |
3900 position.x += leftBorder(parent); | |
3901 position.y += topBorder(parent); | |
3902 } | |
3903 } else if (element != this && Browser.safari){ | |
3904 position.x += leftBorder(element); | |
3905 position.y += topBorder(element); | |
3906 } | |
3907 | |
3908 element = element.offsetParent; | |
3909 } | |
3910 if (Browser.firefox && !borderBox(this)){ | |
3911 position.x -= leftBorder(this); | |
3912 position.y -= topBorder(this); | |
3913 } | |
3914 return position; | |
3915 }, | |
3916 | |
3917 getPosition: function(relative){ | |
3918 var offset = this.getOffsets(), | |
3919 scroll = this.getScrolls(); | |
3920 var position = { | |
3921 x: offset.x - scroll.x, | |
3922 y: offset.y - scroll.y | |
3923 }; | |
3924 | |
3925 if (relative && (relative = document.id(relative))){ | |
3926 var relativePosition = relative.getPosition(); | |
3927 return {x: position.x - relativePosition.x - leftBorder(relative), y: posi
tion.y - relativePosition.y - topBorder(relative)}; | |
3928 } | |
3929 return position; | |
3930 }, | |
3931 | |
3932 getCoordinates: function(element){ | |
3933 if (isBody(this)) return this.getWindow().getCoordinates(); | |
3934 var position = this.getPosition(element), | |
3935 size = this.getSize(); | |
3936 var obj = { | |
3937 left: position.x, | |
3938 top: position.y, | |
3939 width: size.x, | |
3940 height: size.y | |
3941 }; | |
3942 obj.right = obj.left + obj.width; | |
3943 obj.bottom = obj.top + obj.height; | |
3944 return obj; | |
3945 }, | |
3946 | |
3947 computePosition: function(obj){ | |
3948 return { | |
3949 left: obj.x - styleNumber(this, 'margin-left'), | |
3950 top: obj.y - styleNumber(this, 'margin-top') | |
3951 }; | |
3952 }, | |
3953 | |
3954 setPosition: function(obj){ | |
3955 return this.setStyles(this.computePosition(obj)); | |
3956 } | |
3957 | |
3958 }); | |
3959 | |
3960 | |
3961 [Document, Window].invoke('implement', { | |
3962 | |
3963 getSize: function(){ | |
3964 var doc = getCompatElement(this); | |
3965 return {x: doc.clientWidth, y: doc.clientHeight}; | |
3966 }, | |
3967 | |
3968 getScroll: function(){ | |
3969 var win = this.getWindow(), doc = getCompatElement(this); | |
3970 return {x: win.pageXOffset || doc.scrollLeft, y: win.pageYOffset || doc.scro
llTop}; | |
3971 }, | |
3972 | |
3973 getScrollSize: function(){ | |
3974 var doc = getCompatElement(this), | |
3975 min = this.getSize(), | |
3976 body = this.getDocument().body; | |
3977 | |
3978 return {x: Math.max(doc.scrollWidth, body.scrollWidth, min.x), y: Math.max(d
oc.scrollHeight, body.scrollHeight, min.y)}; | |
3979 }, | |
3980 | |
3981 getPosition: function(){ | |
3982 return {x: 0, y: 0}; | |
3983 }, | |
3984 | |
3985 getCoordinates: function(){ | |
3986 var size = this.getSize(); | |
3987 return {top: 0, left: 0, bottom: size.y, right: size.x, height: size.y, widt
h: size.x}; | |
3988 } | |
3989 | |
3990 }); | |
3991 | |
3992 // private methods | |
3993 | |
3994 var styleString = Element.getComputedStyle; | |
3995 | |
3996 function styleNumber(element, style){ | |
3997 return styleString(element, style).toInt() || 0; | |
3998 } | |
3999 | |
4000 function borderBox(element){ | |
4001 return styleString(element, '-moz-box-sizing') == 'border-box'; | |
4002 } | |
4003 | |
4004 function topBorder(element){ | |
4005 return styleNumber(element, 'border-top-width'); | |
4006 } | |
4007 | |
4008 function leftBorder(element){ | |
4009 return styleNumber(element, 'border-left-width'); | |
4010 } | |
4011 | |
4012 function isBody(element){ | |
4013 return (/^(?:body|html)$/i).test(element.tagName); | |
4014 } | |
4015 | |
4016 function getCompatElement(element){ | |
4017 var doc = element.getDocument(); | |
4018 return (!doc.compatMode || doc.compatMode == 'CSS1Compat') ? doc.html : doc.bo
dy; | |
4019 } | |
4020 | |
4021 })(); | |
4022 | |
4023 //aliases | |
4024 Element.alias({position: 'setPosition'}); //compatability | |
4025 | |
4026 [Window, Document, Element].invoke('implement', { | |
4027 | |
4028 getHeight: function(){ | |
4029 return this.getSize().y; | |
4030 }, | |
4031 | |
4032 getWidth: function(){ | |
4033 return this.getSize().x; | |
4034 }, | |
4035 | |
4036 getScrollTop: function(){ | |
4037 return this.getScroll().y; | |
4038 }, | |
4039 | |
4040 getScrollLeft: function(){ | |
4041 return this.getScroll().x; | |
4042 }, | |
4043 | |
4044 getScrollHeight: function(){ | |
4045 return this.getScrollSize().y; | |
4046 }, | |
4047 | |
4048 getScrollWidth: function(){ | |
4049 return this.getScrollSize().x; | |
4050 }, | |
4051 | |
4052 getTop: function(){ | |
4053 return this.getPosition().y; | |
4054 }, | |
4055 | |
4056 getLeft: function(){ | |
4057 return this.getPosition().x; | |
4058 } | |
4059 | |
4060 }); | |
OLD | NEW |