0
|
1 /*! Shoestring - v2.0.0 - 2017-02-14
|
|
2 * http://github.com/filamentgroup/shoestring/
|
|
3 * Copyright (c) 2017 Scott Jehl, Filament Group, Inc; Licensed MIT & GPLv2 */
|
|
4 (function( factory ) {
|
|
5 if( typeof define === 'function' && define.amd ) {
|
|
6 // AMD. Register as an anonymous module.
|
|
7 define( [ 'shoestring' ], factory );
|
|
8 } else if (typeof module === 'object' && module.exports) {
|
|
9 // Node/CommonJS
|
|
10 module.exports = factory();
|
|
11 } else {
|
|
12 // Browser globals
|
|
13 factory();
|
|
14 }
|
|
15 }(function () {
|
|
16 var win = typeof window !== "undefined" ? window : this;
|
|
17 var doc = win.document;
|
|
18
|
|
19
|
|
20 /**
|
|
21 * The shoestring object constructor.
|
|
22 *
|
|
23 * @param {string,object} prim The selector to find or element to wrap.
|
|
24 * @param {object} sec The context in which to match the `prim` selector.
|
|
25 * @returns shoestring
|
|
26 * @this window
|
|
27 */
|
|
28 function shoestring( prim, sec ){
|
|
29 var pType = typeof( prim ),
|
|
30 ret = [],
|
|
31 sel;
|
|
32
|
|
33 // return an empty shoestring object
|
|
34 if( !prim ){
|
|
35 return new Shoestring( ret );
|
|
36 }
|
|
37
|
|
38 // ready calls
|
|
39 if( prim.call ){
|
|
40 return shoestring.ready( prim );
|
|
41 }
|
|
42
|
|
43 // handle re-wrapping shoestring objects
|
|
44 if( prim.constructor === Shoestring && !sec ){
|
|
45 return prim;
|
|
46 }
|
|
47
|
|
48 // if string starting with <, make html
|
|
49 if( pType === "string" && prim.indexOf( "<" ) === 0 ){
|
|
50 var dfrag = doc.createElement( "div" );
|
|
51
|
|
52 dfrag.innerHTML = prim;
|
|
53
|
|
54 // TODO depends on children (circular)
|
|
55 return shoestring( dfrag ).children().each(function(){
|
|
56 dfrag.removeChild( this );
|
|
57 });
|
|
58 }
|
|
59
|
|
60 // if string, it's a selector, use qsa
|
|
61 if( pType === "string" ){
|
|
62 if( sec ){
|
|
63 return shoestring( sec ).find( prim );
|
|
64 }
|
|
65
|
|
66 sel = doc.querySelectorAll( prim );
|
|
67
|
|
68 return new Shoestring( sel, prim );
|
|
69 }
|
|
70
|
|
71 // array like objects or node lists
|
|
72 if( Object.prototype.toString.call( pType ) === '[object Array]' ||
|
|
73 (win.NodeList && prim instanceof win.NodeList) ){
|
|
74
|
|
75 return new Shoestring( prim, prim );
|
|
76 }
|
|
77
|
|
78 // if it's an array, use all the elements
|
|
79 if( prim.constructor === Array ){
|
|
80 return new Shoestring( prim, prim );
|
|
81 }
|
|
82
|
|
83 // otherwise assume it's an object the we want at an index
|
|
84 return new Shoestring( [prim], prim );
|
|
85 }
|
|
86
|
|
87 var Shoestring = function( ret, prim ) {
|
|
88 this.length = 0;
|
|
89 this.selector = prim;
|
|
90 shoestring.merge(this, ret);
|
|
91 };
|
|
92
|
|
93 // TODO only required for tests
|
|
94 Shoestring.prototype.reverse = [].reverse;
|
|
95
|
|
96 // For adding element set methods
|
|
97 shoestring.fn = Shoestring.prototype;
|
|
98
|
|
99 shoestring.Shoestring = Shoestring;
|
|
100
|
|
101 // For extending objects
|
|
102 // TODO move to separate module when we use prototypes
|
|
103 shoestring.extend = function( first, second ){
|
|
104 for( var i in second ){
|
|
105 if( second.hasOwnProperty( i ) ){
|
|
106 first[ i ] = second[ i ];
|
|
107 }
|
|
108 }
|
|
109
|
|
110 return first;
|
|
111 };
|
|
112
|
|
113 // taken directly from jQuery
|
|
114 shoestring.merge = function( first, second ) {
|
|
115 var len, j, i;
|
|
116
|
|
117 len = +second.length,
|
|
118 j = 0,
|
|
119 i = first.length;
|
|
120
|
|
121 for ( ; j < len; j++ ) {
|
|
122 first[ i++ ] = second[ j ];
|
|
123 }
|
|
124
|
|
125 first.length = i;
|
|
126
|
|
127 return first;
|
|
128 };
|
|
129
|
|
130 // expose
|
|
131 win.shoestring = shoestring;
|
|
132
|
|
133
|
|
134
|
|
135 /**
|
|
136 * Iterates over `shoestring` collections.
|
|
137 *
|
|
138 * @param {function} callback The callback to be invoked on each element and index
|
|
139 * @return shoestring
|
|
140 * @this shoestring
|
|
141 */
|
|
142 shoestring.fn.each = function( callback ){
|
|
143 return shoestring.each( this, callback );
|
|
144 };
|
|
145
|
|
146 shoestring.each = function( collection, callback ) {
|
|
147 var val;
|
|
148 for( var i = 0, il = collection.length; i < il; i++ ){
|
|
149 val = callback.call( collection[i], i, collection[i] );
|
|
150 if( val === false ){
|
|
151 break;
|
|
152 }
|
|
153 }
|
|
154
|
|
155 return collection;
|
|
156 };
|
|
157
|
|
158
|
|
159
|
|
160 /**
|
|
161 * Check for array membership.
|
|
162 *
|
|
163 * @param {object} needle The thing to find.
|
|
164 * @param {object} haystack The thing to find the needle in.
|
|
165 * @return {boolean}
|
|
166 * @this window
|
|
167 */
|
|
168 shoestring.inArray = function( needle, haystack ){
|
|
169 var isin = -1;
|
|
170 for( var i = 0, il = haystack.length; i < il; i++ ){
|
|
171 if( haystack.hasOwnProperty( i ) && haystack[ i ] === needle ){
|
|
172 isin = i;
|
|
173 }
|
|
174 }
|
|
175 return isin;
|
|
176 };
|
|
177
|
|
178
|
|
179
|
|
180 /**
|
|
181 * Bind callbacks to be run when the DOM is "ready".
|
|
182 *
|
|
183 * @param {function} fn The callback to be run
|
|
184 * @return shoestring
|
|
185 * @this shoestring
|
|
186 */
|
|
187 shoestring.ready = function( fn ){
|
|
188 if( ready && fn ){
|
|
189 fn.call( doc );
|
|
190 }
|
|
191 else if( fn ){
|
|
192 readyQueue.push( fn );
|
|
193 }
|
|
194 else {
|
|
195 runReady();
|
|
196 }
|
|
197
|
|
198 return [doc];
|
|
199 };
|
|
200
|
|
201 // TODO necessary?
|
|
202 shoestring.fn.ready = function( fn ){
|
|
203 shoestring.ready( fn );
|
|
204 return this;
|
|
205 };
|
|
206
|
|
207 // Empty and exec the ready queue
|
|
208 var ready = false,
|
|
209 readyQueue = [],
|
|
210 runReady = function(){
|
|
211 if( !ready ){
|
|
212 while( readyQueue.length ){
|
|
213 readyQueue.shift().call( doc );
|
|
214 }
|
|
215 ready = true;
|
|
216 }
|
|
217 };
|
|
218
|
|
219 // If DOM is already ready at exec time, depends on the browser.
|
|
220 // From: https://github.com/mobify/mobifyjs/blob/526841be5509e28fc949038021799e4223479f8d/src/capture.js#L128
|
|
221 if (doc.attachEvent ? doc.readyState === "complete" : doc.readyState !== "loading") {
|
|
222 runReady();
|
|
223 } else {
|
|
224 doc.addEventListener( "DOMContentLoaded", runReady, false );
|
|
225 doc.addEventListener( "readystatechange", runReady, false );
|
|
226 win.addEventListener( "load", runReady, false );
|
|
227 }
|
|
228
|
|
229
|
|
230
|
|
231 /**
|
|
232 * Checks the current set of elements against the selector, if one matches return `true`.
|
|
233 *
|
|
234 * @param {string} selector The selector to check.
|
|
235 * @return {boolean}
|
|
236 * @this {shoestring}
|
|
237 */
|
|
238 shoestring.fn.is = function( selector ){
|
|
239 var ret = false, self = this, parents, check;
|
|
240
|
|
241 // assume a dom element
|
|
242 if( typeof selector !== "string" ){
|
|
243 // array-like, ie shoestring objects or element arrays
|
|
244 if( selector.length && selector[0] ){
|
|
245 check = selector;
|
|
246 } else {
|
|
247 check = [selector];
|
|
248 }
|
|
249
|
|
250 return _checkElements(this, check);
|
|
251 }
|
|
252
|
|
253 parents = this.parent();
|
|
254
|
|
255 if( !parents.length ){
|
|
256 parents = shoestring( doc );
|
|
257 }
|
|
258
|
|
259 parents.each(function( i, e ) {
|
|
260 var children;
|
|
261
|
|
262 children = e.querySelectorAll( selector );
|
|
263
|
|
264 ret = _checkElements( self, children );
|
|
265 });
|
|
266
|
|
267 return ret;
|
|
268 };
|
|
269
|
|
270 function _checkElements(needles, haystack){
|
|
271 var ret = false;
|
|
272
|
|
273 needles.each(function() {
|
|
274 var j = 0;
|
|
275
|
|
276 while( j < haystack.length ){
|
|
277 if( this === haystack[j] ){
|
|
278 ret = true;
|
|
279 }
|
|
280
|
|
281 j++;
|
|
282 }
|
|
283 });
|
|
284
|
|
285 return ret;
|
|
286 }
|
|
287
|
|
288
|
|
289
|
|
290 /**
|
|
291 * Get data attached to the first element or set data values on all elements in the current set.
|
|
292 *
|
|
293 * @param {string} name The data attribute name.
|
|
294 * @param {any} value The value assigned to the data attribute.
|
|
295 * @return {any|shoestring}
|
|
296 * @this shoestring
|
|
297 */
|
|
298 shoestring.fn.data = function( name, value ){
|
|
299 if( name !== undefined ){
|
|
300 if( value !== undefined ){
|
|
301 return this.each(function(){
|
|
302 if( !this.shoestringData ){
|
|
303 this.shoestringData = {};
|
|
304 }
|
|
305
|
|
306 this.shoestringData[ name ] = value;
|
|
307 });
|
|
308 }
|
|
309 else {
|
|
310 if( this[ 0 ] ) {
|
|
311 if( this[ 0 ].shoestringData ) {
|
|
312 return this[ 0 ].shoestringData[ name ];
|
|
313 }
|
|
314 }
|
|
315 }
|
|
316 }
|
|
317 else {
|
|
318 return this[ 0 ] ? this[ 0 ].shoestringData || {} : undefined;
|
|
319 }
|
|
320 };
|
|
321
|
|
322
|
|
323 /**
|
|
324 * Remove data associated with `name` or all the data, for each element in the current set.
|
|
325 *
|
|
326 * @param {string} name The data attribute name.
|
|
327 * @return shoestring
|
|
328 * @this shoestring
|
|
329 */
|
|
330 shoestring.fn.removeData = function( name ){
|
|
331 return this.each(function(){
|
|
332 if( name !== undefined && this.shoestringData ){
|
|
333 this.shoestringData[ name ] = undefined;
|
|
334 delete this.shoestringData[ name ];
|
|
335 } else {
|
|
336 this[ 0 ].shoestringData = {};
|
|
337 }
|
|
338 });
|
|
339 };
|
|
340
|
|
341
|
|
342
|
|
343 /**
|
|
344 * An alias for the `shoestring` constructor.
|
|
345 */
|
|
346 win.$ = shoestring;
|
|
347
|
|
348
|
|
349
|
|
350 /**
|
|
351 * Add a class to each DOM element in the set of elements.
|
|
352 *
|
|
353 * @param {string} className The name of the class to be added.
|
|
354 * @return shoestring
|
|
355 * @this shoestring
|
|
356 */
|
|
357 shoestring.fn.addClass = function( className ){
|
|
358 var classes = className.replace(/^\s+|\s+$/g, '').split( " " );
|
|
359
|
|
360 return this.each(function(){
|
|
361 for( var i = 0, il = classes.length; i < il; i++ ){
|
|
362 if( this.className !== undefined &&
|
|
363 (this.className === "" ||
|
|
364 !this.className.match( new RegExp( "(^|\\s)" + classes[ i ] + "($|\\s)"))) ){
|
|
365 this.className += " " + classes[ i ];
|
|
366 }
|
|
367 }
|
|
368 });
|
|
369 };
|
|
370
|
|
371
|
|
372
|
|
373 /**
|
|
374 * Add elements matching the selector to the current set.
|
|
375 *
|
|
376 * @param {string} selector The selector for the elements to add from the DOM
|
|
377 * @return shoestring
|
|
378 * @this shoestring
|
|
379 */
|
|
380 shoestring.fn.add = function( selector ){
|
|
381 var ret = [];
|
|
382 this.each(function(){
|
|
383 ret.push( this );
|
|
384 });
|
|
385
|
|
386 shoestring( selector ).each(function(){
|
|
387 ret.push( this );
|
|
388 });
|
|
389
|
|
390 return shoestring( ret );
|
|
391 };
|
|
392
|
|
393
|
|
394
|
|
395 /**
|
|
396 * Insert an element or HTML string as the last child of each element in the set.
|
|
397 *
|
|
398 * @param {string|HTMLElement} fragment The HTML or HTMLElement to insert.
|
|
399 * @return shoestring
|
|
400 * @this shoestring
|
|
401 */
|
|
402 shoestring.fn.append = function( fragment ){
|
|
403 if( typeof( fragment ) === "string" || fragment.nodeType !== undefined ){
|
|
404 fragment = shoestring( fragment );
|
|
405 }
|
|
406
|
|
407 return this.each(function( i ){
|
|
408 for( var j = 0, jl = fragment.length; j < jl; j++ ){
|
|
409 this.appendChild( i > 0 ? fragment[ j ].cloneNode( true ) : fragment[ j ] );
|
|
410 }
|
|
411 });
|
|
412 };
|
|
413
|
|
414
|
|
415
|
|
416 /**
|
|
417 * Insert the current set as the last child of the elements matching the selector.
|
|
418 *
|
|
419 * @param {string} selector The selector after which to append the current set.
|
|
420 * @return shoestring
|
|
421 * @this shoestring
|
|
422 */
|
|
423 shoestring.fn.appendTo = function( selector ){
|
|
424 return this.each(function(){
|
|
425 shoestring( selector ).append( this );
|
|
426 });
|
|
427 };
|
|
428
|
|
429
|
|
430
|
|
431 /**
|
|
432 * Get the value of the first element of the set or set the value of all the elements in the set.
|
|
433 *
|
|
434 * @param {string} name The attribute name.
|
|
435 * @param {string} value The new value for the attribute.
|
|
436 * @return {shoestring|string|undefined}
|
|
437 * @this {shoestring}
|
|
438 */
|
|
439 shoestring.fn.attr = function( name, value ){
|
|
440 var nameStr = typeof( name ) === "string";
|
|
441
|
|
442 if( value !== undefined || !nameStr ){
|
|
443 return this.each(function(){
|
|
444 if( nameStr ){
|
|
445 this.setAttribute( name, value );
|
|
446 } else {
|
|
447 for( var i in name ){
|
|
448 if( name.hasOwnProperty( i ) ){
|
|
449 this.setAttribute( i, name[ i ] );
|
|
450 }
|
|
451 }
|
|
452 }
|
|
453 });
|
|
454 } else {
|
|
455 return this[ 0 ] ? this[ 0 ].getAttribute( name ) : undefined;
|
|
456 }
|
|
457 };
|
|
458
|
|
459
|
|
460
|
|
461 /**
|
|
462 * Insert an element or HTML string before each element in the current set.
|
|
463 *
|
|
464 * @param {string|HTMLElement} fragment The HTML or HTMLElement to insert.
|
|
465 * @return shoestring
|
|
466 * @this shoestring
|
|
467 */
|
|
468 shoestring.fn.before = function( fragment ){
|
|
469 if( typeof( fragment ) === "string" || fragment.nodeType !== undefined ){
|
|
470 fragment = shoestring( fragment );
|
|
471 }
|
|
472
|
|
473 return this.each(function( i ){
|
|
474 for( var j = 0, jl = fragment.length; j < jl; j++ ){
|
|
475 this.parentNode.insertBefore( i > 0 ? fragment[ j ].cloneNode( true ) : fragment[ j ], this );
|
|
476 }
|
|
477 });
|
|
478 };
|
|
479
|
|
480
|
|
481
|
|
482 /**
|
|
483 * Get the children of the current collection.
|
|
484 * @return shoestring
|
|
485 * @this shoestring
|
|
486 */
|
|
487 shoestring.fn.children = function(){
|
|
488 var ret = [],
|
|
489 childs,
|
|
490 j;
|
|
491 this.each(function(){
|
|
492 childs = this.children;
|
|
493 j = -1;
|
|
494
|
|
495 while( j++ < childs.length-1 ){
|
|
496 if( shoestring.inArray( childs[ j ], ret ) === -1 ){
|
|
497 ret.push( childs[ j ] );
|
|
498 }
|
|
499 }
|
|
500 });
|
|
501 return shoestring(ret);
|
|
502 };
|
|
503
|
|
504
|
|
505
|
|
506 /**
|
|
507 * Find an element matching the selector in the set of the current element and its parents.
|
|
508 *
|
|
509 * @param {string} selector The selector used to identify the target element.
|
|
510 * @return shoestring
|
|
511 * @this shoestring
|
|
512 */
|
|
513 shoestring.fn.closest = function( selector ){
|
|
514 var ret = [];
|
|
515
|
|
516 if( !selector ){
|
|
517 return shoestring( ret );
|
|
518 }
|
|
519
|
|
520 this.each(function(){
|
|
521 var element, $self = shoestring( element = this );
|
|
522
|
|
523 if( $self.is(selector) ){
|
|
524 ret.push( this );
|
|
525 return;
|
|
526 }
|
|
527
|
|
528 while( element.parentElement ) {
|
|
529 if( shoestring(element.parentElement).is(selector) ){
|
|
530 ret.push( element.parentElement );
|
|
531 break;
|
|
532 }
|
|
533
|
|
534 element = element.parentElement;
|
|
535 }
|
|
536 });
|
|
537
|
|
538 return shoestring( ret );
|
|
539 };
|
|
540
|
|
541
|
|
542
|
|
543 shoestring.cssExceptions = {
|
|
544 'float': [ 'cssFloat' ]
|
|
545 };
|
|
546
|
|
547
|
|
548
|
|
549 (function() {
|
|
550 var cssExceptions = shoestring.cssExceptions;
|
|
551
|
|
552 // IE8 uses marginRight instead of margin-right
|
|
553 function convertPropertyName( str ) {
|
|
554 return str.replace( /\-([A-Za-z])/g, function ( match, character ) {
|
|
555 return character.toUpperCase();
|
|
556 });
|
|
557 }
|
|
558
|
|
559 function _getStyle( element, property ) {
|
|
560 return win.getComputedStyle( element, null ).getPropertyValue( property );
|
|
561 }
|
|
562
|
|
563 var vendorPrefixes = [ '', '-webkit-', '-ms-', '-moz-', '-o-', '-khtml-' ];
|
|
564
|
|
565 /**
|
|
566 * Private function for getting the computed style of an element.
|
|
567 *
|
|
568 * **NOTE** Please use the [css](../css.js.html) method instead.
|
|
569 *
|
|
570 * @method _getStyle
|
|
571 * @param {HTMLElement} element The element we want the style property for.
|
|
572 * @param {string} property The css property we want the style for.
|
|
573 */
|
|
574 shoestring._getStyle = function( element, property ) {
|
|
575 var convert, value, j, k;
|
|
576
|
|
577 if( cssExceptions[ property ] ) {
|
|
578 for( j = 0, k = cssExceptions[ property ].length; j < k; j++ ) {
|
|
579 value = _getStyle( element, cssExceptions[ property ][ j ] );
|
|
580
|
|
581 if( value ) {
|
|
582 return value;
|
|
583 }
|
|
584 }
|
|
585 }
|
|
586
|
|
587 for( j = 0, k = vendorPrefixes.length; j < k; j++ ) {
|
|
588 convert = convertPropertyName( vendorPrefixes[ j ] + property );
|
|
589
|
|
590 // VendorprefixKeyName || key-name
|
|
591 value = _getStyle( element, convert );
|
|
592
|
|
593 if( convert !== property ) {
|
|
594 value = value || _getStyle( element, property );
|
|
595 }
|
|
596
|
|
597 if( vendorPrefixes[ j ] ) {
|
|
598 // -vendorprefix-key-name
|
|
599 value = value || _getStyle( element, vendorPrefixes[ j ] + property );
|
|
600 }
|
|
601
|
|
602 if( value ) {
|
|
603 return value;
|
|
604 }
|
|
605 }
|
|
606
|
|
607 return undefined;
|
|
608 };
|
|
609 })();
|
|
610
|
|
611
|
|
612
|
|
613 (function() {
|
|
614 var cssExceptions = shoestring.cssExceptions;
|
|
615
|
|
616 // IE8 uses marginRight instead of margin-right
|
|
617 function convertPropertyName( str ) {
|
|
618 return str.replace( /\-([A-Za-z])/g, function ( match, character ) {
|
|
619 return character.toUpperCase();
|
|
620 });
|
|
621 }
|
|
622
|
|
623 /**
|
|
624 * Private function for setting the style of an element.
|
|
625 *
|
|
626 * **NOTE** Please use the [css](../css.js.html) method instead.
|
|
627 *
|
|
628 * @method _setStyle
|
|
629 * @param {HTMLElement} element The element we want to style.
|
|
630 * @param {string} property The property being used to style the element.
|
|
631 * @param {string} value The css value for the style property.
|
|
632 */
|
|
633 shoestring._setStyle = function( element, property, value ) {
|
|
634 var convertedProperty = convertPropertyName(property);
|
|
635
|
|
636 element.style[ property ] = value;
|
|
637
|
|
638 if( convertedProperty !== property ) {
|
|
639 element.style[ convertedProperty ] = value;
|
|
640 }
|
|
641
|
|
642 if( cssExceptions[ property ] ) {
|
|
643 for( var j = 0, k = cssExceptions[ property ].length; j<k; j++ ) {
|
|
644 element.style[ cssExceptions[ property ][ j ] ] = value;
|
|
645 }
|
|
646 }
|
|
647 };
|
|
648 })();
|
|
649
|
|
650
|
|
651
|
|
652 /**
|
|
653 * Get the compute style property of the first element or set the value of a style property
|
|
654 * on all elements in the set.
|
|
655 *
|
|
656 * @method _setStyle
|
|
657 * @param {string} property The property being used to style the element.
|
|
658 * @param {string|undefined} value The css value for the style property.
|
|
659 * @return {string|shoestring}
|
|
660 * @this shoestring
|
|
661 */
|
|
662 shoestring.fn.css = function( property, value ){
|
|
663 if( !this[0] ){
|
|
664 return;
|
|
665 }
|
|
666
|
|
667 if( typeof property === "object" ) {
|
|
668 return this.each(function() {
|
|
669 for( var key in property ) {
|
|
670 if( property.hasOwnProperty( key ) ) {
|
|
671 shoestring._setStyle( this, key, property[key] );
|
|
672 }
|
|
673 }
|
|
674 });
|
|
675 } else {
|
|
676 // assignment else retrieve first
|
|
677 if( value !== undefined ){
|
|
678 return this.each(function(){
|
|
679 shoestring._setStyle( this, property, value );
|
|
680 });
|
|
681 }
|
|
682
|
|
683 return shoestring._getStyle( this[0], property );
|
|
684 }
|
|
685 };
|
|
686
|
|
687
|
|
688
|
|
689 /**
|
|
690 * Returns the indexed element wrapped in a new `shoestring` object.
|
|
691 *
|
|
692 * @param {integer} index The index of the element to wrap and return.
|
|
693 * @return shoestring
|
|
694 * @this shoestring
|
|
695 */
|
|
696 shoestring.fn.eq = function( index ){
|
|
697 if( this[index] ){
|
|
698 return shoestring( this[index] );
|
|
699 }
|
|
700
|
|
701 return shoestring([]);
|
|
702 };
|
|
703
|
|
704
|
|
705
|
|
706 /**
|
|
707 * Filter out the current set if they do *not* match the passed selector or
|
|
708 * the supplied callback returns false
|
|
709 *
|
|
710 * @param {string,function} selector The selector or boolean return value callback used to filter the elements.
|
|
711 * @return shoestring
|
|
712 * @this shoestring
|
|
713 */
|
|
714 shoestring.fn.filter = function( selector ){
|
|
715 var ret = [];
|
|
716
|
|
717 this.each(function( index ){
|
|
718 var wsel;
|
|
719
|
|
720 if( typeof selector === 'function' ) {
|
|
721 if( selector.call( this, index ) !== false ) {
|
|
722 ret.push( this );
|
|
723 }
|
|
724 } else {
|
|
725 if( !this.parentNode ){
|
|
726 var context = shoestring( doc.createDocumentFragment() );
|
|
727
|
|
728 context[ 0 ].appendChild( this );
|
|
729 wsel = shoestring( selector, context );
|
|
730 } else {
|
|
731 wsel = shoestring( selector, this.parentNode );
|
|
732 }
|
|
733
|
|
734 if( shoestring.inArray( this, wsel ) > -1 ){
|
|
735 ret.push( this );
|
|
736 }
|
|
737 }
|
|
738 });
|
|
739
|
|
740 return shoestring( ret );
|
|
741 };
|
|
742
|
|
743
|
|
744
|
|
745 /**
|
|
746 * Find descendant elements of the current collection.
|
|
747 *
|
|
748 * @param {string} selector The selector used to find the children
|
|
749 * @return shoestring
|
|
750 * @this shoestring
|
|
751 */
|
|
752 shoestring.fn.find = function( selector ){
|
|
753 var ret = [],
|
|
754 finds;
|
|
755 this.each(function(){
|
|
756 finds = this.querySelectorAll( selector );
|
|
757
|
|
758 for( var i = 0, il = finds.length; i < il; i++ ){
|
|
759 ret = ret.concat( finds[i] );
|
|
760 }
|
|
761 });
|
|
762 return shoestring( ret );
|
|
763 };
|
|
764
|
|
765
|
|
766
|
|
767 /**
|
|
768 * Returns the first element of the set wrapped in a new `shoestring` object.
|
|
769 *
|
|
770 * @return shoestring
|
|
771 * @this shoestring
|
|
772 */
|
|
773 shoestring.fn.first = function(){
|
|
774 return this.eq( 0 );
|
|
775 };
|
|
776
|
|
777
|
|
778
|
|
779 /**
|
|
780 * Returns the raw DOM node at the passed index.
|
|
781 *
|
|
782 * @param {integer} index The index of the element to wrap and return.
|
|
783 * @return {HTMLElement|undefined|array}
|
|
784 * @this shoestring
|
|
785 */
|
|
786 shoestring.fn.get = function( index ){
|
|
787
|
|
788 // return an array of elements if index is undefined
|
|
789 if( index === undefined ){
|
|
790 var elements = [];
|
|
791
|
|
792 for( var i = 0; i < this.length; i++ ){
|
|
793 elements.push( this[ i ] );
|
|
794 }
|
|
795
|
|
796 return elements;
|
|
797 } else {
|
|
798 return this[ index ];
|
|
799 }
|
|
800 };
|
|
801
|
|
802
|
|
803
|
|
804 var set = function( html ){
|
|
805 if( typeof html === "string" || typeof html === "number" ){
|
|
806 return this.each(function(){
|
|
807 this.innerHTML = "" + html;
|
|
808 });
|
|
809 } else {
|
|
810 var h = "";
|
|
811 if( typeof html.length !== "undefined" ){
|
|
812 for( var i = 0, l = html.length; i < l; i++ ){
|
|
813 h += html[i].outerHTML;
|
|
814 }
|
|
815 } else {
|
|
816 h = html.outerHTML;
|
|
817 }
|
|
818 return this.each(function(){
|
|
819 this.innerHTML = h;
|
|
820 });
|
|
821 }
|
|
822 };
|
|
823 /**
|
|
824 * Gets or sets the `innerHTML` from all the elements in the set.
|
|
825 *
|
|
826 * @param {string|undefined} html The html to assign
|
|
827 * @return {string|shoestring}
|
|
828 * @this shoestring
|
|
829 */
|
|
830 shoestring.fn.html = function( html ){
|
|
831 if( typeof html !== "undefined" ){
|
|
832 return set.call( this, html );
|
|
833 } else { // get
|
|
834 var pile = "";
|
|
835
|
|
836 this.each(function(){
|
|
837 pile += this.innerHTML;
|
|
838 });
|
|
839
|
|
840 return pile;
|
|
841 }
|
|
842 };
|
|
843
|
|
844
|
|
845
|
|
846 (function() {
|
|
847 function _getIndex( set, test ) {
|
|
848 var i, result, element;
|
|
849
|
|
850 for( i = result = 0; i < set.length; i++ ) {
|
|
851 element = set.item ? set.item(i) : set[i];
|
|
852
|
|
853 if( test(element) ){
|
|
854 return result;
|
|
855 }
|
|
856
|
|
857 // ignore text nodes, etc
|
|
858 // NOTE may need to be more permissive
|
|
859 if( element.nodeType === 1 ){
|
|
860 result++;
|
|
861 }
|
|
862 }
|
|
863
|
|
864 return -1;
|
|
865 }
|
|
866
|
|
867 /**
|
|
868 * Find the index in the current set for the passed selector.
|
|
869 * Without a selector it returns the index of the first node within the array of its siblings.
|
|
870 *
|
|
871 * @param {string|undefined} selector The selector used to search for the index.
|
|
872 * @return {integer}
|
|
873 * @this {shoestring}
|
|
874 */
|
|
875 shoestring.fn.index = function( selector ){
|
|
876 var self, children;
|
|
877
|
|
878 self = this;
|
|
879
|
|
880 // no arg? check the children, otherwise check each element that matches
|
|
881 if( selector === undefined ){
|
|
882 children = ( ( this[ 0 ] && this[0].parentNode ) || doc.documentElement).childNodes;
|
|
883
|
|
884 // check if the element matches the first of the set
|
|
885 return _getIndex(children, function( element ) {
|
|
886 return self[0] === element;
|
|
887 });
|
|
888 } else {
|
|
889
|
|
890 // check if the element matches the first selected node from the parent
|
|
891 return _getIndex(self, function( element ) {
|
|
892 return element === (shoestring( selector, element.parentNode )[ 0 ]);
|
|
893 });
|
|
894 }
|
|
895 };
|
|
896 })();
|
|
897
|
|
898
|
|
899
|
|
900 /**
|
|
901 * Insert the current set before the elements matching the selector.
|
|
902 *
|
|
903 * @param {string} selector The selector before which to insert the current set.
|
|
904 * @return shoestring
|
|
905 * @this shoestring
|
|
906 */
|
|
907 shoestring.fn.insertBefore = function( selector ){
|
|
908 return this.each(function(){
|
|
909 shoestring( selector ).before( this );
|
|
910 });
|
|
911 };
|
|
912
|
|
913
|
|
914
|
|
915 /**
|
|
916 * Returns the last element of the set wrapped in a new `shoestring` object.
|
|
917 *
|
|
918 * @return shoestring
|
|
919 * @this shoestring
|
|
920 */
|
|
921 shoestring.fn.last = function(){
|
|
922 return this.eq( this.length - 1 );
|
|
923 };
|
|
924
|
|
925
|
|
926
|
|
927 /**
|
|
928 * Returns a `shoestring` object with the set of siblings of each element in the original set.
|
|
929 *
|
|
930 * @return shoestring
|
|
931 * @this shoestring
|
|
932 */
|
|
933 shoestring.fn.next = function(){
|
|
934
|
|
935 var result = [];
|
|
936
|
|
937 // TODO need to implement map
|
|
938 this.each(function() {
|
|
939 var children, item, found;
|
|
940
|
|
941 // get the child nodes for this member of the set
|
|
942 children = shoestring( this.parentNode )[0].childNodes;
|
|
943
|
|
944 for( var i = 0; i < children.length; i++ ){
|
|
945 item = children.item( i );
|
|
946
|
|
947 // found the item we needed (found) which means current item value is
|
|
948 // the next node in the list, as long as it's viable grab it
|
|
949 // NOTE may need to be more permissive
|
|
950 if( found && item.nodeType === 1 ){
|
|
951 result.push( item );
|
|
952 break;
|
|
953 }
|
|
954
|
|
955 // find the current item and mark it as found
|
|
956 if( item === this ){
|
|
957 found = true;
|
|
958 }
|
|
959 }
|
|
960 });
|
|
961
|
|
962 return shoestring( result );
|
|
963 };
|
|
964
|
|
965
|
|
966
|
|
967 /**
|
|
968 * Removes elements from the current set.
|
|
969 *
|
|
970 * @param {string} selector The selector to use when removing the elements.
|
|
971 * @return shoestring
|
|
972 * @this shoestring
|
|
973 */
|
|
974 shoestring.fn.not = function( selector ){
|
|
975 var ret = [];
|
|
976
|
|
977 this.each(function(){
|
|
978 var found = shoestring( selector, this.parentNode );
|
|
979
|
|
980 if( shoestring.inArray(this, found) === -1 ){
|
|
981 ret.push( this );
|
|
982 }
|
|
983 });
|
|
984
|
|
985 return shoestring( ret );
|
|
986 };
|
|
987
|
|
988
|
|
989
|
|
990 /**
|
|
991 * Returns the set of first parents for each element in the current set.
|
|
992 *
|
|
993 * @return shoestring
|
|
994 * @this shoestring
|
|
995 */
|
|
996 shoestring.fn.parent = function(){
|
|
997 var ret = [],
|
|
998 parent;
|
|
999
|
|
1000 this.each(function(){
|
|
1001 // no parent node, assume top level
|
|
1002 // jQuery parent: return the document object for <html> or the parent node if it exists
|
|
1003 parent = (this === doc.documentElement ? doc : this.parentNode);
|
|
1004
|
|
1005 // if there is a parent and it's not a document fragment
|
|
1006 if( parent && parent.nodeType !== 11 ){
|
|
1007 ret.push( parent );
|
|
1008 }
|
|
1009 });
|
|
1010
|
|
1011 return shoestring(ret);
|
|
1012 };
|
|
1013
|
|
1014
|
|
1015
|
|
1016 /**
|
|
1017 * Add an HTML string or element before the children of each element in the current set.
|
|
1018 *
|
|
1019 * @param {string|HTMLElement} fragment The HTML string or element to add.
|
|
1020 * @return shoestring
|
|
1021 * @this shoestring
|
|
1022 */
|
|
1023 shoestring.fn.prepend = function( fragment ){
|
|
1024 if( typeof( fragment ) === "string" || fragment.nodeType !== undefined ){
|
|
1025 fragment = shoestring( fragment );
|
|
1026 }
|
|
1027
|
|
1028 return this.each(function( i ){
|
|
1029
|
|
1030 for( var j = 0, jl = fragment.length; j < jl; j++ ){
|
|
1031 var insertEl = i > 0 ? fragment[ j ].cloneNode( true ) : fragment[ j ];
|
|
1032 if ( this.firstChild ){
|
|
1033 this.insertBefore( insertEl, this.firstChild );
|
|
1034 } else {
|
|
1035 this.appendChild( insertEl );
|
|
1036 }
|
|
1037 }
|
|
1038 });
|
|
1039 };
|
|
1040
|
|
1041
|
|
1042
|
|
1043 /**
|
|
1044 * Returns a `shoestring` object with the set of *one* siblingx before each element in the original set.
|
|
1045 *
|
|
1046 * @return shoestring
|
|
1047 * @this shoestring
|
|
1048 */
|
|
1049 shoestring.fn.prev = function(){
|
|
1050
|
|
1051 var result = [];
|
|
1052
|
|
1053 // TODO need to implement map
|
|
1054 this.each(function() {
|
|
1055 var children, item, found;
|
|
1056
|
|
1057 // get the child nodes for this member of the set
|
|
1058 children = shoestring( this.parentNode )[0].childNodes;
|
|
1059
|
|
1060 for( var i = children.length -1; i >= 0; i-- ){
|
|
1061 item = children.item( i );
|
|
1062
|
|
1063 // found the item we needed (found) which means current item value is
|
|
1064 // the next node in the list, as long as it's viable grab it
|
|
1065 // NOTE may need to be more permissive
|
|
1066 if( found && item.nodeType === 1 ){
|
|
1067 result.push( item );
|
|
1068 break;
|
|
1069 }
|
|
1070
|
|
1071 // find the current item and mark it as found
|
|
1072 if( item === this ){
|
|
1073 found = true;
|
|
1074 }
|
|
1075 }
|
|
1076 });
|
|
1077
|
|
1078 return shoestring( result );
|
|
1079 };
|
|
1080
|
|
1081
|
|
1082
|
|
1083 /**
|
|
1084 * Returns a `shoestring` object with the set of *all* siblings before each element in the original set.
|
|
1085 *
|
|
1086 * @return shoestring
|
|
1087 * @this shoestring
|
|
1088 */
|
|
1089 shoestring.fn.prevAll = function(){
|
|
1090
|
|
1091 var result = [];
|
|
1092
|
|
1093 this.each(function() {
|
|
1094 var $previous = shoestring( this ).prev();
|
|
1095
|
|
1096 while( $previous.length ){
|
|
1097 result.push( $previous[0] );
|
|
1098 $previous = $previous.prev();
|
|
1099 }
|
|
1100 });
|
|
1101
|
|
1102 return shoestring( result );
|
|
1103 };
|
|
1104
|
|
1105
|
|
1106
|
|
1107 /**
|
|
1108 * Remove an attribute from each element in the current set.
|
|
1109 *
|
|
1110 * @param {string} name The name of the attribute.
|
|
1111 * @return shoestring
|
|
1112 * @this shoestring
|
|
1113 */
|
|
1114 shoestring.fn.removeAttr = function( name ){
|
|
1115 return this.each(function(){
|
|
1116 this.removeAttribute( name );
|
|
1117 });
|
|
1118 };
|
|
1119
|
|
1120
|
|
1121
|
|
1122 /**
|
|
1123 * Remove a class from each DOM element in the set of elements.
|
|
1124 *
|
|
1125 * @param {string} className The name of the class to be removed.
|
|
1126 * @return shoestring
|
|
1127 * @this shoestring
|
|
1128 */
|
|
1129 shoestring.fn.removeClass = function( cname ){
|
|
1130 var classes = cname.replace(/^\s+|\s+$/g, '').split( " " );
|
|
1131
|
|
1132 return this.each(function(){
|
|
1133 var newClassName, regex;
|
|
1134
|
|
1135 for( var i = 0, il = classes.length; i < il; i++ ){
|
|
1136 if( this.className !== undefined ){
|
|
1137 regex = new RegExp( "(^|\\s)" + classes[ i ] + "($|\\s)", "gmi" );
|
|
1138 newClassName = this.className.replace( regex, " " );
|
|
1139
|
|
1140 this.className = newClassName.replace(/^\s+|\s+$/g, '');
|
|
1141 }
|
|
1142 }
|
|
1143 });
|
|
1144 };
|
|
1145
|
|
1146
|
|
1147
|
|
1148 /**
|
|
1149 * Remove the current set of elements from the DOM.
|
|
1150 *
|
|
1151 * @return shoestring
|
|
1152 * @this shoestring
|
|
1153 */
|
|
1154 shoestring.fn.remove = function(){
|
|
1155 return this.each(function(){
|
|
1156 if( this.parentNode ) {
|
|
1157 this.parentNode.removeChild( this );
|
|
1158 }
|
|
1159 });
|
|
1160 };
|
|
1161
|
|
1162
|
|
1163
|
|
1164 /**
|
|
1165 * Replace each element in the current set with that argument HTML string or HTMLElement.
|
|
1166 *
|
|
1167 * @param {string|HTMLElement} fragment The value to assign.
|
|
1168 * @return shoestring
|
|
1169 * @this shoestring
|
|
1170 */
|
|
1171 shoestring.fn.replaceWith = function( fragment ){
|
|
1172 if( typeof( fragment ) === "string" ){
|
|
1173 fragment = shoestring( fragment );
|
|
1174 }
|
|
1175
|
|
1176 var ret = [];
|
|
1177
|
|
1178 if( fragment.length > 1 ){
|
|
1179 fragment = fragment.reverse();
|
|
1180 }
|
|
1181 this.each(function( i ){
|
|
1182 var clone = this.cloneNode( true ),
|
|
1183 insertEl;
|
|
1184 ret.push( clone );
|
|
1185
|
|
1186 // If there is no parentNode, this is pointless, drop it.
|
|
1187 if( !this.parentNode ){ return; }
|
|
1188
|
|
1189 if( fragment.length === 1 ){
|
|
1190 insertEl = i > 0 ? fragment[ 0 ].cloneNode( true ) : fragment[ 0 ];
|
|
1191 this.parentNode.replaceChild( insertEl, this );
|
|
1192 } else {
|
|
1193 for( var j = 0, jl = fragment.length; j < jl; j++ ){
|
|
1194 insertEl = i > 0 ? fragment[ j ].cloneNode( true ) : fragment[ j ];
|
|
1195 this.parentNode.insertBefore( insertEl, this.nextSibling );
|
|
1196 }
|
|
1197 this.parentNode.removeChild( this );
|
|
1198 }
|
|
1199 });
|
|
1200
|
|
1201 return shoestring( ret );
|
|
1202 };
|
|
1203
|
|
1204
|
|
1205
|
|
1206 /**
|
|
1207 * Get all of the sibling elements for each element in the current set.
|
|
1208 *
|
|
1209 * @return shoestring
|
|
1210 * @this shoestring
|
|
1211 */
|
|
1212 shoestring.fn.siblings = function(){
|
|
1213
|
|
1214 if( !this.length ) {
|
|
1215 return shoestring( [] );
|
|
1216 }
|
|
1217
|
|
1218 var sibs = [], el = this[ 0 ].parentNode.firstChild;
|
|
1219
|
|
1220 do {
|
|
1221 if( el.nodeType === 1 && el !== this[ 0 ] ) {
|
|
1222 sibs.push( el );
|
|
1223 }
|
|
1224
|
|
1225 el = el.nextSibling;
|
|
1226 } while( el );
|
|
1227
|
|
1228 return shoestring( sibs );
|
|
1229 };
|
|
1230
|
|
1231
|
|
1232
|
|
1233 var getText = function( elem ){
|
|
1234 var node,
|
|
1235 ret = "",
|
|
1236 i = 0,
|
|
1237 nodeType = elem.nodeType;
|
|
1238
|
|
1239 if ( !nodeType ) {
|
|
1240 // If no nodeType, this is expected to be an array
|
|
1241 while ( (node = elem[i++]) ) {
|
|
1242 // Do not traverse comment nodes
|
|
1243 ret += getText( node );
|
|
1244 }
|
|
1245 } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
|
|
1246 // Use textContent for elements
|
|
1247 // innerText usage removed for consistency of new lines (jQuery #11153)
|
|
1248 if ( typeof elem.textContent === "string" ) {
|
|
1249 return elem.textContent;
|
|
1250 } else {
|
|
1251 // Traverse its children
|
|
1252 for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
|
|
1253 ret += getText( elem );
|
|
1254 }
|
|
1255 }
|
|
1256 } else if ( nodeType === 3 || nodeType === 4 ) {
|
|
1257 return elem.nodeValue;
|
|
1258 }
|
|
1259 // Do not include comment or processing instruction nodes
|
|
1260
|
|
1261 return ret;
|
|
1262 };
|
|
1263
|
|
1264 /**
|
|
1265 * Recursively retrieve the text content of the each element in the current set.
|
|
1266 *
|
|
1267 * @return shoestring
|
|
1268 * @this shoestring
|
|
1269 */
|
|
1270 shoestring.fn.text = function() {
|
|
1271
|
|
1272 return getText( this );
|
|
1273 };
|
|
1274
|
|
1275
|
|
1276
|
|
1277
|
|
1278 /**
|
|
1279 * Get the value of the first element or set the value of all elements in the current set.
|
|
1280 *
|
|
1281 * @param {string} value The value to set.
|
|
1282 * @return shoestring
|
|
1283 * @this shoestring
|
|
1284 */
|
|
1285 shoestring.fn.val = function( value ){
|
|
1286 var el;
|
|
1287 if( value !== undefined ){
|
|
1288 return this.each(function(){
|
|
1289 if( this.tagName === "SELECT" ){
|
|
1290 var optionSet, option,
|
|
1291 options = this.options,
|
|
1292 values = [],
|
|
1293 i = options.length,
|
|
1294 newIndex;
|
|
1295
|
|
1296 values[0] = value;
|
|
1297 while ( i-- ) {
|
|
1298 option = options[ i ];
|
|
1299 if ( (option.selected = shoestring.inArray( option.value, values ) >= 0) ) {
|
|
1300 optionSet = true;
|
|
1301 newIndex = i;
|
|
1302 }
|
|
1303 }
|
|
1304 // force browsers to behave consistently when non-matching value is set
|
|
1305 if ( !optionSet ) {
|
|
1306 this.selectedIndex = -1;
|
|
1307 } else {
|
|
1308 this.selectedIndex = newIndex;
|
|
1309 }
|
|
1310 } else {
|
|
1311 this.value = value;
|
|
1312 }
|
|
1313 });
|
|
1314 } else {
|
|
1315 el = this[0];
|
|
1316
|
|
1317 if( el.tagName === "SELECT" ){
|
|
1318 if( el.selectedIndex < 0 ){ return ""; }
|
|
1319 return el.options[ el.selectedIndex ].value;
|
|
1320 } else {
|
|
1321 return el.value;
|
|
1322 }
|
|
1323 }
|
|
1324 };
|
|
1325
|
|
1326
|
|
1327
|
|
1328 /**
|
|
1329 * Private function for setting/getting the offset property for height/width.
|
|
1330 *
|
|
1331 * **NOTE** Please use the [width](width.js.html) or [height](height.js.html) methods instead.
|
|
1332 *
|
|
1333 * @param {shoestring} set The set of elements.
|
|
1334 * @param {string} name The string "height" or "width".
|
|
1335 * @param {float|undefined} value The value to assign.
|
|
1336 * @return shoestring
|
|
1337 * @this window
|
|
1338 */
|
|
1339 shoestring._dimension = function( set, name, value ){
|
|
1340 var offsetName;
|
|
1341
|
|
1342 if( value === undefined ){
|
|
1343 offsetName = name.replace(/^[a-z]/, function( letter ) {
|
|
1344 return letter.toUpperCase();
|
|
1345 });
|
|
1346
|
|
1347 return set[ 0 ][ "offset" + offsetName ];
|
|
1348 } else {
|
|
1349 // support integer values as pixels
|
|
1350 value = typeof value === "string" ? value : value + "px";
|
|
1351
|
|
1352 return set.each(function(){
|
|
1353 this.style[ name ] = value;
|
|
1354 });
|
|
1355 }
|
|
1356 };
|
|
1357
|
|
1358
|
|
1359
|
|
1360 /**
|
|
1361 * Gets the width value of the first element or sets the width for the whole set.
|
|
1362 *
|
|
1363 * @param {float|undefined} value The value to assign.
|
|
1364 * @return shoestring
|
|
1365 * @this shoestring
|
|
1366 */
|
|
1367 shoestring.fn.width = function( value ){
|
|
1368 return shoestring._dimension( this, "width", value );
|
|
1369 };
|
|
1370
|
|
1371
|
|
1372
|
|
1373 /**
|
|
1374 * Wraps the child elements in the provided HTML.
|
|
1375 *
|
|
1376 * @param {string} html The wrapping HTML.
|
|
1377 * @return shoestring
|
|
1378 * @this shoestring
|
|
1379 */
|
|
1380 shoestring.fn.wrapInner = function( html ){
|
|
1381 return this.each(function(){
|
|
1382 var inH = this.innerHTML;
|
|
1383
|
|
1384 this.innerHTML = "";
|
|
1385 shoestring( this ).append( shoestring( html ).html( inH ) );
|
|
1386 });
|
|
1387 };
|
|
1388
|
|
1389
|
|
1390
|
|
1391 function initEventCache( el, evt ) {
|
|
1392 if ( !el.shoestringData ) {
|
|
1393 el.shoestringData = {};
|
|
1394 }
|
|
1395 if ( !el.shoestringData.events ) {
|
|
1396 el.shoestringData.events = {};
|
|
1397 }
|
|
1398 if ( !el.shoestringData.loop ) {
|
|
1399 el.shoestringData.loop = {};
|
|
1400 }
|
|
1401 if ( !el.shoestringData.events[ evt ] ) {
|
|
1402 el.shoestringData.events[ evt ] = [];
|
|
1403 }
|
|
1404 }
|
|
1405
|
|
1406 function addToEventCache( el, evt, eventInfo ) {
|
|
1407 var obj = {};
|
|
1408 obj.isCustomEvent = eventInfo.isCustomEvent;
|
|
1409 obj.callback = eventInfo.callfunc;
|
|
1410 obj.originalCallback = eventInfo.originalCallback;
|
|
1411 obj.namespace = eventInfo.namespace;
|
|
1412
|
|
1413 el.shoestringData.events[ evt ].push( obj );
|
|
1414
|
|
1415 if( eventInfo.customEventLoop ) {
|
|
1416 el.shoestringData.loop[ evt ] = eventInfo.customEventLoop;
|
|
1417 }
|
|
1418 }
|
|
1419
|
|
1420 /**
|
|
1421 * Bind a callback to an event for the currrent set of elements.
|
|
1422 *
|
|
1423 * @param {string} evt The event(s) to watch for.
|
|
1424 * @param {object,function} data Data to be included with each event or the callback.
|
|
1425 * @param {function} originalCallback Callback to be invoked when data is define.d.
|
|
1426 * @return shoestring
|
|
1427 * @this shoestring
|
|
1428 */
|
|
1429 shoestring.fn.bind = function( evt, data, originalCallback ){
|
|
1430
|
|
1431 if( typeof data === "function" ){
|
|
1432 originalCallback = data;
|
|
1433 data = null;
|
|
1434 }
|
|
1435
|
|
1436 var evts = evt.split( " " );
|
|
1437
|
|
1438 // NOTE the `triggeredElement` is purely for custom events from IE
|
|
1439 function encasedCallback( e, namespace, triggeredElement ){
|
|
1440 var result;
|
|
1441
|
|
1442 if( e._namespace && e._namespace !== namespace ) {
|
|
1443 return;
|
|
1444 }
|
|
1445
|
|
1446 e.data = data;
|
|
1447 e.namespace = e._namespace;
|
|
1448
|
|
1449 var returnTrue = function(){
|
|
1450 return true;
|
|
1451 };
|
|
1452
|
|
1453 e.isDefaultPrevented = function(){
|
|
1454 return false;
|
|
1455 };
|
|
1456
|
|
1457 var originalPreventDefault = e.preventDefault;
|
|
1458 var preventDefaultConstructor = function(){
|
|
1459 if( originalPreventDefault ) {
|
|
1460 return function(){
|
|
1461 e.isDefaultPrevented = returnTrue;
|
|
1462 originalPreventDefault.call(e);
|
|
1463 };
|
|
1464 } else {
|
|
1465 return function(){
|
|
1466 e.isDefaultPrevented = returnTrue;
|
|
1467 e.returnValue = false;
|
|
1468 };
|
|
1469 }
|
|
1470 };
|
|
1471
|
|
1472 // thanks https://github.com/jonathantneal/EventListener
|
|
1473 e.target = triggeredElement || e.target || e.srcElement;
|
|
1474 e.preventDefault = preventDefaultConstructor();
|
|
1475 e.stopPropagation = e.stopPropagation || function () {
|
|
1476 e.cancelBubble = true;
|
|
1477 };
|
|
1478
|
|
1479 result = originalCallback.apply(this, [ e ].concat( e._args ) );
|
|
1480
|
|
1481 if( result === false ){
|
|
1482 e.preventDefault();
|
|
1483 e.stopPropagation();
|
|
1484 }
|
|
1485
|
|
1486 return result;
|
|
1487 }
|
|
1488
|
|
1489 return this.each(function(){
|
|
1490 var domEventCallback,
|
|
1491 customEventCallback,
|
|
1492 customEventLoop,
|
|
1493 oEl = this;
|
|
1494
|
|
1495 for( var i = 0, il = evts.length; i < il; i++ ){
|
|
1496 var split = evts[ i ].split( "." ),
|
|
1497 evt = split[ 0 ],
|
|
1498 namespace = split.length > 0 ? split[ 1 ] : null;
|
|
1499
|
|
1500 domEventCallback = function( originalEvent ) {
|
|
1501 if( oEl.ssEventTrigger ) {
|
|
1502 originalEvent._namespace = oEl.ssEventTrigger._namespace;
|
|
1503 originalEvent._args = oEl.ssEventTrigger._args;
|
|
1504
|
|
1505 oEl.ssEventTrigger = null;
|
|
1506 }
|
|
1507 return encasedCallback.call( oEl, originalEvent, namespace );
|
|
1508 };
|
|
1509 customEventCallback = null;
|
|
1510 customEventLoop = null;
|
|
1511
|
|
1512 initEventCache( this, evt );
|
|
1513
|
|
1514 this.addEventListener( evt, domEventCallback, false );
|
|
1515
|
|
1516 addToEventCache( this, evt, {
|
|
1517 callfunc: customEventCallback || domEventCallback,
|
|
1518 isCustomEvent: !!customEventCallback,
|
|
1519 customEventLoop: customEventLoop,
|
|
1520 originalCallback: originalCallback,
|
|
1521 namespace: namespace
|
|
1522 });
|
|
1523 }
|
|
1524 });
|
|
1525 };
|
|
1526
|
|
1527 shoestring.fn.on = shoestring.fn.bind;
|
|
1528
|
|
1529
|
|
1530
|
|
1531
|
|
1532 /**
|
|
1533 * Unbind a previous bound callback for an event.
|
|
1534 *
|
|
1535 * @param {string} event The event(s) the callback was bound to..
|
|
1536 * @param {function} callback Callback to unbind.
|
|
1537 * @return shoestring
|
|
1538 * @this shoestring
|
|
1539 */
|
|
1540 shoestring.fn.unbind = function( event, callback ){
|
|
1541
|
|
1542
|
|
1543 var evts = event ? event.split( " " ) : [];
|
|
1544
|
|
1545 return this.each(function(){
|
|
1546 if( !this.shoestringData || !this.shoestringData.events ) {
|
|
1547 return;
|
|
1548 }
|
|
1549
|
|
1550 if( !evts.length ) {
|
|
1551 unbindAll.call( this );
|
|
1552 } else {
|
|
1553 var split, evt, namespace;
|
|
1554 for( var i = 0, il = evts.length; i < il; i++ ){
|
|
1555 split = evts[ i ].split( "." ),
|
|
1556 evt = split[ 0 ],
|
|
1557 namespace = split.length > 0 ? split[ 1 ] : null;
|
|
1558
|
|
1559 if( evt ) {
|
|
1560 unbind.call( this, evt, namespace, callback );
|
|
1561 } else {
|
|
1562 unbindAll.call( this, namespace, callback );
|
|
1563 }
|
|
1564 }
|
|
1565 }
|
|
1566 });
|
|
1567 };
|
|
1568
|
|
1569 function unbind( evt, namespace, callback ) {
|
|
1570 var bound = this.shoestringData.events[ evt ];
|
|
1571 if( !(bound && bound.length) ) {
|
|
1572 return;
|
|
1573 }
|
|
1574
|
|
1575 var matched = [], j, jl;
|
|
1576 for( j = 0, jl = bound.length; j < jl; j++ ) {
|
|
1577 if( !namespace || namespace === bound[ j ].namespace ) {
|
|
1578 if( callback === undefined || callback === bound[ j ].originalCallback ) {
|
|
1579 this.removeEventListener( evt, bound[ j ].callback, false );
|
|
1580 matched.push( j );
|
|
1581 }
|
|
1582 }
|
|
1583 }
|
|
1584
|
|
1585 for( j = 0, jl = matched.length; j < jl; j++ ) {
|
|
1586 this.shoestringData.events[ evt ].splice( j, 1 );
|
|
1587 }
|
|
1588 }
|
|
1589
|
|
1590 function unbindAll( namespace, callback ) {
|
|
1591 for( var evtKey in this.shoestringData.events ) {
|
|
1592 unbind.call( this, evtKey, namespace, callback );
|
|
1593 }
|
|
1594 }
|
|
1595
|
|
1596 shoestring.fn.off = shoestring.fn.unbind;
|
|
1597
|
|
1598
|
|
1599 /**
|
|
1600 * Bind a callback to an event for the currrent set of elements, unbind after one occurence.
|
|
1601 *
|
|
1602 * @param {string} event The event(s) to watch for.
|
|
1603 * @param {function} callback Callback to invoke on the event.
|
|
1604 * @return shoestring
|
|
1605 * @this shoestring
|
|
1606 */
|
|
1607 shoestring.fn.one = function( event, callback ){
|
|
1608 var evts = event.split( " " );
|
|
1609
|
|
1610 return this.each(function(){
|
|
1611 var thisevt, cbs = {}, $t = shoestring( this );
|
|
1612
|
|
1613 for( var i = 0, il = evts.length; i < il; i++ ){
|
|
1614 thisevt = evts[ i ];
|
|
1615
|
|
1616 cbs[ thisevt ] = function( e ){
|
|
1617 var $t = shoestring( this );
|
|
1618
|
|
1619 for( var j in cbs ) {
|
|
1620 $t.unbind( j, cbs[ j ] );
|
|
1621 }
|
|
1622
|
|
1623 return callback.apply( this, [ e ].concat( e._args ) );
|
|
1624 };
|
|
1625
|
|
1626 $t.bind( thisevt, cbs[ thisevt ] );
|
|
1627 }
|
|
1628 });
|
|
1629 };
|
|
1630
|
|
1631
|
|
1632
|
|
1633 /**
|
|
1634 * Trigger an event on the first element in the set, no bubbling, no defaults.
|
|
1635 *
|
|
1636 * @param {string} event The event(s) to trigger.
|
|
1637 * @param {object} args Arguments to append to callback invocations.
|
|
1638 * @return shoestring
|
|
1639 * @this shoestring
|
|
1640 */
|
|
1641 shoestring.fn.triggerHandler = function( event, args ){
|
|
1642 var e = event.split( " " )[ 0 ],
|
|
1643 el = this[ 0 ],
|
|
1644 ret;
|
|
1645
|
|
1646 // See this.fireEvent( 'on' + evts[ i ], document.createEventObject() ); instead of click() etc in trigger.
|
|
1647 if( doc.createEvent && el.shoestringData && el.shoestringData.events && el.shoestringData.events[ e ] ){
|
|
1648 var bindings = el.shoestringData.events[ e ];
|
|
1649 for (var i in bindings ){
|
|
1650 if( bindings.hasOwnProperty( i ) ){
|
|
1651 event = doc.createEvent( "Event" );
|
|
1652 event.initEvent( e, true, true );
|
|
1653 event._args = args;
|
|
1654 args.unshift( event );
|
|
1655
|
|
1656 ret = bindings[ i ].originalCallback.apply( event.target, args );
|
|
1657 }
|
|
1658 }
|
|
1659 }
|
|
1660
|
|
1661 return ret;
|
|
1662 };
|
|
1663
|
|
1664
|
|
1665
|
|
1666 /**
|
|
1667 * Trigger an event on each of the DOM elements in the current set.
|
|
1668 *
|
|
1669 * @param {string} event The event(s) to trigger.
|
|
1670 * @param {object} args Arguments to append to callback invocations.
|
|
1671 * @return shoestring
|
|
1672 * @this shoestring
|
|
1673 */
|
|
1674 shoestring.fn.trigger = function( event, args ){
|
|
1675 var evts = event.split( " " );
|
|
1676
|
|
1677 return this.each(function(){
|
|
1678 var split, evt, namespace;
|
|
1679 for( var i = 0, il = evts.length; i < il; i++ ){
|
|
1680 split = evts[ i ].split( "." ),
|
|
1681 evt = split[ 0 ],
|
|
1682 namespace = split.length > 0 ? split[ 1 ] : null;
|
|
1683
|
|
1684 if( evt === "click" ){
|
|
1685 if( this.tagName === "INPUT" && this.type === "checkbox" && this.click ){
|
|
1686 this.click();
|
|
1687 return false;
|
|
1688 }
|
|
1689 }
|
|
1690
|
|
1691 if( doc.createEvent ){
|
|
1692 var event = doc.createEvent( "Event" );
|
|
1693 event.initEvent( evt, true, true );
|
|
1694 event._args = args;
|
|
1695 event._namespace = namespace;
|
|
1696
|
|
1697 this.dispatchEvent( event );
|
|
1698 }
|
|
1699 }
|
|
1700 });
|
|
1701 };
|
|
1702
|
|
1703
|
|
1704
|
|
1705 return shoestring;
|
|
1706 }));
|