|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 // ********** |
|
6 // Title: iq.js |
|
7 // Various helper functions, in the vein of jQuery. |
|
8 |
|
9 // ---------- |
|
10 // Function: iQ |
|
11 // Returns an iQClass object which represents an individual element or a group |
|
12 // of elements. It works pretty much like jQuery(), with a few exceptions, |
|
13 // most notably that you can't use strings with complex html, |
|
14 // just simple tags like '<div>'. |
|
15 function iQ(selector, context) { |
|
16 // The iQ object is actually just the init constructor 'enhanced' |
|
17 return new iQClass(selector, context); |
|
18 }; |
|
19 |
|
20 // A simple way to check for HTML strings or ID strings |
|
21 // (both of which we optimize for) |
|
22 let quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/; |
|
23 |
|
24 // Match a standalone tag |
|
25 let rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/; |
|
26 |
|
27 // ########## |
|
28 // Class: iQClass |
|
29 // The actual class of iQ result objects, representing an individual element |
|
30 // or a group of elements. |
|
31 // |
|
32 // ---------- |
|
33 // Function: iQClass |
|
34 // You don't call this directly; this is what's called by iQ(). |
|
35 function iQClass(selector, context) { |
|
36 |
|
37 // Handle $(""), $(null), or $(undefined) |
|
38 if (!selector) { |
|
39 return this; |
|
40 } |
|
41 |
|
42 // Handle $(DOMElement) |
|
43 if (selector.nodeType) { |
|
44 this.context = selector; |
|
45 this[0] = selector; |
|
46 this.length = 1; |
|
47 return this; |
|
48 } |
|
49 |
|
50 // The body element only exists once, optimize finding it |
|
51 if (selector === "body" && !context) { |
|
52 this.context = document; |
|
53 this[0] = document.body; |
|
54 this.selector = "body"; |
|
55 this.length = 1; |
|
56 return this; |
|
57 } |
|
58 |
|
59 // Handle HTML strings |
|
60 if (typeof selector === "string") { |
|
61 // Are we dealing with HTML string or an ID? |
|
62 |
|
63 let match = quickExpr.exec(selector); |
|
64 |
|
65 // Verify a match, and that no context was specified for #id |
|
66 if (match && (match[1] || !context)) { |
|
67 |
|
68 // HANDLE $(html) -> $(array) |
|
69 if (match[1]) { |
|
70 let doc = (context ? context.ownerDocument || context : document); |
|
71 |
|
72 // If a single string is passed in and it's a single tag |
|
73 // just do a createElement and skip the rest |
|
74 let ret = rsingleTag.exec(selector); |
|
75 |
|
76 if (ret) { |
|
77 if (Utils.isPlainObject(context)) { |
|
78 Utils.assert(false, 'does not support HTML creation with context'); |
|
79 } else { |
|
80 selector = [doc.createElement(ret[1])]; |
|
81 } |
|
82 |
|
83 } else { |
|
84 Utils.assert(false, 'does not support complex HTML creation'); |
|
85 } |
|
86 |
|
87 return Utils.merge(this, selector); |
|
88 |
|
89 // HANDLE $("#id") |
|
90 } else { |
|
91 let elem = document.getElementById(match[2]); |
|
92 |
|
93 if (elem) { |
|
94 this.length = 1; |
|
95 this[0] = elem; |
|
96 } |
|
97 |
|
98 this.context = document; |
|
99 this.selector = selector; |
|
100 return this; |
|
101 } |
|
102 |
|
103 // HANDLE $("TAG") |
|
104 } else if (!context && /^\w+$/.test(selector)) { |
|
105 this.selector = selector; |
|
106 this.context = document; |
|
107 selector = document.getElementsByTagName(selector); |
|
108 return Utils.merge(this, selector); |
|
109 |
|
110 // HANDLE $(expr, $(...)) |
|
111 } else if (!context || context.iq) { |
|
112 return (context || iQ(document)).find(selector); |
|
113 |
|
114 // HANDLE $(expr, context) |
|
115 // (which is just equivalent to: $(context).find(expr) |
|
116 } else { |
|
117 return iQ(context).find(selector); |
|
118 } |
|
119 |
|
120 // HANDLE $(function) |
|
121 // Shortcut for document ready |
|
122 } else if (typeof selector == "function") { |
|
123 Utils.log('iQ does not support ready functions'); |
|
124 return null; |
|
125 } |
|
126 |
|
127 if ("selector" in selector) { |
|
128 this.selector = selector.selector; |
|
129 this.context = selector.context; |
|
130 } |
|
131 |
|
132 let ret = this || []; |
|
133 if (selector != null) { |
|
134 // The window, strings (and functions) also have 'length' |
|
135 if (selector.length == null || typeof selector == "string" || selector.setInterval) { |
|
136 Array.push(ret, selector); |
|
137 } else { |
|
138 Utils.merge(ret, selector); |
|
139 } |
|
140 } |
|
141 return ret; |
|
142 }; |
|
143 |
|
144 iQClass.prototype = { |
|
145 |
|
146 // ---------- |
|
147 // Function: toString |
|
148 // Prints [iQ...] for debug use |
|
149 toString: function iQClass_toString() { |
|
150 if (this.length > 1) { |
|
151 if (this.selector) |
|
152 return "[iQ (" + this.selector + ")]"; |
|
153 else |
|
154 return "[iQ multi-object]"; |
|
155 } |
|
156 |
|
157 if (this.length == 1) |
|
158 return "[iQ (" + this[0].toString() + ")]"; |
|
159 |
|
160 return "[iQ non-object]"; |
|
161 }, |
|
162 |
|
163 // Start with an empty selector |
|
164 selector: "", |
|
165 |
|
166 // The default length of a iQ object is 0 |
|
167 length: 0, |
|
168 |
|
169 // ---------- |
|
170 // Function: each |
|
171 // Execute a callback for every element in the matched set. |
|
172 each: function iQClass_each(callback) { |
|
173 if (typeof callback != "function") { |
|
174 Utils.assert(false, "each's argument must be a function"); |
|
175 return null; |
|
176 } |
|
177 for (let i = 0; this[i] != null && callback(this[i]) !== false; i++) {} |
|
178 return this; |
|
179 }, |
|
180 |
|
181 // ---------- |
|
182 // Function: addClass |
|
183 // Adds the given class(es) to the receiver. |
|
184 addClass: function iQClass_addClass(value) { |
|
185 Utils.assertThrow(typeof value == "string" && value, |
|
186 'requires a valid string argument'); |
|
187 |
|
188 let length = this.length; |
|
189 for (let i = 0; i < length; i++) { |
|
190 let elem = this[i]; |
|
191 if (elem.nodeType === 1) { |
|
192 value.split(/\s+/).forEach(function(className) { |
|
193 elem.classList.add(className); |
|
194 }); |
|
195 } |
|
196 } |
|
197 |
|
198 return this; |
|
199 }, |
|
200 |
|
201 // ---------- |
|
202 // Function: removeClass |
|
203 // Removes the given class(es) from the receiver. |
|
204 removeClass: function iQClass_removeClass(value) { |
|
205 if (typeof value != "string" || !value) { |
|
206 Utils.assert(false, 'does not support function argument'); |
|
207 return null; |
|
208 } |
|
209 |
|
210 let length = this.length; |
|
211 for (let i = 0; i < length; i++) { |
|
212 let elem = this[i]; |
|
213 if (elem.nodeType === 1 && elem.className) { |
|
214 value.split(/\s+/).forEach(function(className) { |
|
215 elem.classList.remove(className); |
|
216 }); |
|
217 } |
|
218 } |
|
219 |
|
220 return this; |
|
221 }, |
|
222 |
|
223 // ---------- |
|
224 // Function: hasClass |
|
225 // Returns true is the receiver has the given css class. |
|
226 hasClass: function iQClass_hasClass(singleClassName) { |
|
227 let length = this.length; |
|
228 for (let i = 0; i < length; i++) { |
|
229 if (this[i].classList.contains(singleClassName)) { |
|
230 return true; |
|
231 } |
|
232 } |
|
233 return false; |
|
234 }, |
|
235 |
|
236 // ---------- |
|
237 // Function: find |
|
238 // Searches the receiver and its children, returning a new iQ object with |
|
239 // elements that match the given selector. |
|
240 find: function iQClass_find(selector) { |
|
241 let ret = []; |
|
242 let length = 0; |
|
243 |
|
244 let l = this.length; |
|
245 for (let i = 0; i < l; i++) { |
|
246 length = ret.length; |
|
247 try { |
|
248 Utils.merge(ret, this[i].querySelectorAll(selector)); |
|
249 } catch(e) { |
|
250 Utils.log('iQ.find error (bad selector)', e); |
|
251 } |
|
252 |
|
253 if (i > 0) { |
|
254 // Make sure that the results are unique |
|
255 for (let n = length; n < ret.length; n++) { |
|
256 for (let r = 0; r < length; r++) { |
|
257 if (ret[r] === ret[n]) { |
|
258 ret.splice(n--, 1); |
|
259 break; |
|
260 } |
|
261 } |
|
262 } |
|
263 } |
|
264 } |
|
265 |
|
266 return iQ(ret); |
|
267 }, |
|
268 |
|
269 // ---------- |
|
270 // Function: contains |
|
271 // Check to see if a given DOM node descends from the receiver. |
|
272 contains: function iQClass_contains(selector) { |
|
273 Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)'); |
|
274 |
|
275 // fast path when querySelector() can be used |
|
276 if ('string' == typeof selector) |
|
277 return null != this[0].querySelector(selector); |
|
278 |
|
279 let object = iQ(selector); |
|
280 Utils.assert(object.length <= 1, 'does not yet support multi-objects'); |
|
281 |
|
282 let elem = object[0]; |
|
283 if (!elem || !elem.parentNode) |
|
284 return false; |
|
285 |
|
286 do { |
|
287 elem = elem.parentNode; |
|
288 } while (elem && this[0] != elem); |
|
289 |
|
290 return this[0] == elem; |
|
291 }, |
|
292 |
|
293 // ---------- |
|
294 // Function: remove |
|
295 // Removes the receiver from the DOM. |
|
296 remove: function iQClass_remove(options) { |
|
297 if (!options || !options.preserveEventHandlers) |
|
298 this.unbindAll(); |
|
299 for (let i = 0; this[i] != null; i++) { |
|
300 let elem = this[i]; |
|
301 if (elem.parentNode) { |
|
302 elem.parentNode.removeChild(elem); |
|
303 } |
|
304 } |
|
305 return this; |
|
306 }, |
|
307 |
|
308 // ---------- |
|
309 // Function: empty |
|
310 // Removes all of the reciever's children and HTML content from the DOM. |
|
311 empty: function iQClass_empty() { |
|
312 for (let i = 0; this[i] != null; i++) { |
|
313 let elem = this[i]; |
|
314 while (elem.firstChild) { |
|
315 iQ(elem.firstChild).unbindAll(); |
|
316 elem.removeChild(elem.firstChild); |
|
317 } |
|
318 } |
|
319 return this; |
|
320 }, |
|
321 |
|
322 // ---------- |
|
323 // Function: width |
|
324 // Returns the width of the receiver, including padding and border. |
|
325 width: function iQClass_width() { |
|
326 return Math.floor(this[0].offsetWidth); |
|
327 }, |
|
328 |
|
329 // ---------- |
|
330 // Function: height |
|
331 // Returns the height of the receiver, including padding and border. |
|
332 height: function iQClass_height() { |
|
333 return Math.floor(this[0].offsetHeight); |
|
334 }, |
|
335 |
|
336 // ---------- |
|
337 // Function: position |
|
338 // Returns an object with the receiver's position in left and top |
|
339 // properties. |
|
340 position: function iQClass_position() { |
|
341 let bounds = this.bounds(); |
|
342 return new Point(bounds.left, bounds.top); |
|
343 }, |
|
344 |
|
345 // ---------- |
|
346 // Function: bounds |
|
347 // Returns a <Rect> with the receiver's bounds. |
|
348 bounds: function iQClass_bounds() { |
|
349 Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)'); |
|
350 let rect = this[0].getBoundingClientRect(); |
|
351 return new Rect(Math.floor(rect.left), Math.floor(rect.top), |
|
352 Math.floor(rect.width), Math.floor(rect.height)); |
|
353 }, |
|
354 |
|
355 // ---------- |
|
356 // Function: data |
|
357 // Pass in both key and value to attach some data to the receiver; |
|
358 // pass in just key to retrieve it. |
|
359 data: function iQClass_data(key, value) { |
|
360 let data = null; |
|
361 if (value === undefined) { |
|
362 Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)'); |
|
363 data = this[0].iQData; |
|
364 if (data) |
|
365 return data[key]; |
|
366 else |
|
367 return null; |
|
368 } |
|
369 |
|
370 for (let i = 0; this[i] != null; i++) { |
|
371 let elem = this[i]; |
|
372 data = elem.iQData; |
|
373 |
|
374 if (!data) |
|
375 data = elem.iQData = {}; |
|
376 |
|
377 data[key] = value; |
|
378 } |
|
379 |
|
380 return this; |
|
381 }, |
|
382 |
|
383 // ---------- |
|
384 // Function: html |
|
385 // Given a value, sets the receiver's innerHTML to it; otherwise returns |
|
386 // what's already there. |
|
387 html: function iQClass_html(value) { |
|
388 Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)'); |
|
389 if (value === undefined) |
|
390 return this[0].innerHTML; |
|
391 |
|
392 this[0].innerHTML = value; |
|
393 return this; |
|
394 }, |
|
395 |
|
396 // ---------- |
|
397 // Function: text |
|
398 // Given a value, sets the receiver's textContent to it; otherwise returns |
|
399 // what's already there. |
|
400 text: function iQClass_text(value) { |
|
401 Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)'); |
|
402 if (value === undefined) { |
|
403 return this[0].textContent; |
|
404 } |
|
405 |
|
406 return this.empty().append((this[0] && this[0].ownerDocument || document).createTextNode(value)); |
|
407 }, |
|
408 |
|
409 // ---------- |
|
410 // Function: val |
|
411 // Given a value, sets the receiver's value to it; otherwise returns what's already there. |
|
412 val: function iQClass_val(value) { |
|
413 Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)'); |
|
414 if (value === undefined) { |
|
415 return this[0].value; |
|
416 } |
|
417 |
|
418 this[0].value = value; |
|
419 return this; |
|
420 }, |
|
421 |
|
422 // ---------- |
|
423 // Function: appendTo |
|
424 // Appends the receiver to the result of iQ(selector). |
|
425 appendTo: function iQClass_appendTo(selector) { |
|
426 Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)'); |
|
427 iQ(selector).append(this); |
|
428 return this; |
|
429 }, |
|
430 |
|
431 // ---------- |
|
432 // Function: append |
|
433 // Appends the result of iQ(selector) to the receiver. |
|
434 append: function iQClass_append(selector) { |
|
435 let object = iQ(selector); |
|
436 Utils.assert(object.length == 1 && this.length == 1, |
|
437 'does not yet support multi-objects (or null objects)'); |
|
438 this[0].appendChild(object[0]); |
|
439 return this; |
|
440 }, |
|
441 |
|
442 // ---------- |
|
443 // Function: attr |
|
444 // Sets or gets an attribute on the element(s). |
|
445 attr: function iQClass_attr(key, value) { |
|
446 Utils.assert(typeof key === 'string', 'string key'); |
|
447 if (value === undefined) { |
|
448 Utils.assert(this.length == 1, 'retrieval does not support multi-objects (or null objects)'); |
|
449 return this[0].getAttribute(key); |
|
450 } |
|
451 |
|
452 for (let i = 0; this[i] != null; i++) |
|
453 this[i].setAttribute(key, value); |
|
454 |
|
455 return this; |
|
456 }, |
|
457 |
|
458 // ---------- |
|
459 // Function: css |
|
460 // Sets or gets CSS properties on the receiver. When setting certain numerical properties, |
|
461 // will automatically add "px". A property can be removed by setting it to null. |
|
462 // |
|
463 // Possible call patterns: |
|
464 // a: object, b: undefined - sets with properties from a |
|
465 // a: string, b: undefined - gets property specified by a |
|
466 // a: string, b: string/number - sets property specified by a to b |
|
467 css: function iQClass_css(a, b) { |
|
468 let properties = null; |
|
469 |
|
470 if (typeof a === 'string') { |
|
471 let key = a; |
|
472 if (b === undefined) { |
|
473 Utils.assert(this.length == 1, 'retrieval does not support multi-objects (or null objects)'); |
|
474 |
|
475 return window.getComputedStyle(this[0], null).getPropertyValue(key); |
|
476 } |
|
477 properties = {}; |
|
478 properties[key] = b; |
|
479 } else if (a instanceof Rect) { |
|
480 properties = { |
|
481 left: a.left, |
|
482 top: a.top, |
|
483 width: a.width, |
|
484 height: a.height |
|
485 }; |
|
486 } else { |
|
487 properties = a; |
|
488 } |
|
489 |
|
490 let pixels = { |
|
491 'left': true, |
|
492 'top': true, |
|
493 'right': true, |
|
494 'bottom': true, |
|
495 'width': true, |
|
496 'height': true |
|
497 }; |
|
498 |
|
499 for (let i = 0; this[i] != null; i++) { |
|
500 let elem = this[i]; |
|
501 for (let key in properties) { |
|
502 let value = properties[key]; |
|
503 |
|
504 if (pixels[key] && typeof value != 'string') |
|
505 value += 'px'; |
|
506 |
|
507 if (value == null) { |
|
508 elem.style.removeProperty(key); |
|
509 } else if (key.indexOf('-') != -1) |
|
510 elem.style.setProperty(key, value, ''); |
|
511 else |
|
512 elem.style[key] = value; |
|
513 } |
|
514 } |
|
515 |
|
516 return this; |
|
517 }, |
|
518 |
|
519 // ---------- |
|
520 // Function: animate |
|
521 // Uses CSS transitions to animate the element. |
|
522 // |
|
523 // Parameters: |
|
524 // css - an object map of the CSS properties to change |
|
525 // options - an object with various properites (see below) |
|
526 // |
|
527 // Possible "options" properties: |
|
528 // duration - how long to animate, in milliseconds |
|
529 // easing - easing function to use. Possibilities include |
|
530 // "tabviewBounce", "easeInQuad". Default is "ease". |
|
531 // complete - function to call once the animation is done, takes nothing |
|
532 // in, but "this" is set to the element that was animated. |
|
533 animate: function iQClass_animate(css, options) { |
|
534 Utils.assert(this.length == 1, 'does not yet support multi-objects (or null objects)'); |
|
535 |
|
536 if (!options) |
|
537 options = {}; |
|
538 |
|
539 let easings = { |
|
540 tabviewBounce: "cubic-bezier(0.0, 0.63, .6, 1.29)", |
|
541 easeInQuad: 'ease-in', // TODO: make it a real easeInQuad, or decide we don't care |
|
542 fast: 'cubic-bezier(0.7,0,1,1)' |
|
543 }; |
|
544 |
|
545 let duration = (options.duration || 400); |
|
546 let easing = (easings[options.easing] || 'ease'); |
|
547 |
|
548 if (css instanceof Rect) { |
|
549 css = { |
|
550 left: css.left, |
|
551 top: css.top, |
|
552 width: css.width, |
|
553 height: css.height |
|
554 }; |
|
555 } |
|
556 |
|
557 |
|
558 // The latest versions of Firefox do not animate from a non-explicitly |
|
559 // set css properties. So for each element to be animated, go through |
|
560 // and explicitly define 'em. |
|
561 let rupper = /([A-Z])/g; |
|
562 this.each(function(elem) { |
|
563 let cStyle = window.getComputedStyle(elem, null); |
|
564 for (let prop in css) { |
|
565 prop = prop.replace(rupper, "-$1").toLowerCase(); |
|
566 iQ(elem).css(prop, cStyle.getPropertyValue(prop)); |
|
567 } |
|
568 }); |
|
569 |
|
570 this.css({ |
|
571 'transition-property': Object.keys(css).join(", "), |
|
572 'transition-duration': (duration / 1000) + 's', |
|
573 'transition-timing-function': easing |
|
574 }); |
|
575 |
|
576 this.css(css); |
|
577 |
|
578 let self = this; |
|
579 setTimeout(function() { |
|
580 self.css({ |
|
581 'transition-property': 'none', |
|
582 'transition-duration': '', |
|
583 'transition-timing-function': '' |
|
584 }); |
|
585 |
|
586 if (typeof options.complete == "function") |
|
587 options.complete.apply(self); |
|
588 }, duration); |
|
589 |
|
590 return this; |
|
591 }, |
|
592 |
|
593 // ---------- |
|
594 // Function: fadeOut |
|
595 // Animates the receiver to full transparency. Calls callback on completion. |
|
596 fadeOut: function iQClass_fadeOut(callback) { |
|
597 Utils.assert(typeof callback == "function" || callback === undefined, |
|
598 'does not yet support duration'); |
|
599 |
|
600 this.animate({ |
|
601 opacity: 0 |
|
602 }, { |
|
603 duration: 400, |
|
604 complete: function() { |
|
605 iQ(this).css({display: 'none'}); |
|
606 if (typeof callback == "function") |
|
607 callback.apply(this); |
|
608 } |
|
609 }); |
|
610 |
|
611 return this; |
|
612 }, |
|
613 |
|
614 // ---------- |
|
615 // Function: fadeIn |
|
616 // Animates the receiver to full opacity. |
|
617 fadeIn: function iQClass_fadeIn() { |
|
618 this.css({display: ''}); |
|
619 this.animate({ |
|
620 opacity: 1 |
|
621 }, { |
|
622 duration: 400 |
|
623 }); |
|
624 |
|
625 return this; |
|
626 }, |
|
627 |
|
628 // ---------- |
|
629 // Function: hide |
|
630 // Hides the receiver. |
|
631 hide: function iQClass_hide() { |
|
632 this.css({display: 'none', opacity: 0}); |
|
633 return this; |
|
634 }, |
|
635 |
|
636 // ---------- |
|
637 // Function: show |
|
638 // Shows the receiver. |
|
639 show: function iQClass_show() { |
|
640 this.css({display: '', opacity: 1}); |
|
641 return this; |
|
642 }, |
|
643 |
|
644 // ---------- |
|
645 // Function: bind |
|
646 // Binds the given function to the given event type. Also wraps the function |
|
647 // in a try/catch block that does a Utils.log on any errors. |
|
648 bind: function iQClass_bind(type, func) { |
|
649 let handler = function(event) func.apply(this, [event]); |
|
650 |
|
651 for (let i = 0; this[i] != null; i++) { |
|
652 let elem = this[i]; |
|
653 if (!elem.iQEventData) |
|
654 elem.iQEventData = {}; |
|
655 |
|
656 if (!elem.iQEventData[type]) |
|
657 elem.iQEventData[type] = []; |
|
658 |
|
659 elem.iQEventData[type].push({ |
|
660 original: func, |
|
661 modified: handler |
|
662 }); |
|
663 |
|
664 elem.addEventListener(type, handler, false); |
|
665 } |
|
666 |
|
667 return this; |
|
668 }, |
|
669 |
|
670 // ---------- |
|
671 // Function: one |
|
672 // Binds the given function to the given event type, but only for one call; |
|
673 // automatically unbinds after the event fires once. |
|
674 one: function iQClass_one(type, func) { |
|
675 Utils.assert(typeof func == "function", 'does not support eventData argument'); |
|
676 |
|
677 let handler = function(e) { |
|
678 iQ(this).unbind(type, handler); |
|
679 return func.apply(this, [e]); |
|
680 }; |
|
681 |
|
682 return this.bind(type, handler); |
|
683 }, |
|
684 |
|
685 // ---------- |
|
686 // Function: unbind |
|
687 // Unbinds the given function from the given event type. |
|
688 unbind: function iQClass_unbind(type, func) { |
|
689 Utils.assert(typeof func == "function", 'Must provide a function'); |
|
690 |
|
691 for (let i = 0; this[i] != null; i++) { |
|
692 let elem = this[i]; |
|
693 let handler = func; |
|
694 if (elem.iQEventData && elem.iQEventData[type]) { |
|
695 let count = elem.iQEventData[type].length; |
|
696 for (let a = 0; a < count; a++) { |
|
697 let pair = elem.iQEventData[type][a]; |
|
698 if (pair.original == func) { |
|
699 handler = pair.modified; |
|
700 elem.iQEventData[type].splice(a, 1); |
|
701 if (!elem.iQEventData[type].length) { |
|
702 delete elem.iQEventData[type]; |
|
703 if (!Object.keys(elem.iQEventData).length) |
|
704 delete elem.iQEventData; |
|
705 } |
|
706 break; |
|
707 } |
|
708 } |
|
709 } |
|
710 |
|
711 elem.removeEventListener(type, handler, false); |
|
712 } |
|
713 |
|
714 return this; |
|
715 }, |
|
716 |
|
717 // ---------- |
|
718 // Function: unbindAll |
|
719 // Unbinds all event handlers. |
|
720 unbindAll: function iQClass_unbindAll() { |
|
721 for (let i = 0; this[i] != null; i++) { |
|
722 let elem = this[i]; |
|
723 |
|
724 for (let j = 0; j < elem.childElementCount; j++) |
|
725 iQ(elem.children[j]).unbindAll(); |
|
726 |
|
727 if (!elem.iQEventData) |
|
728 continue; |
|
729 |
|
730 Object.keys(elem.iQEventData).forEach(function (type) { |
|
731 while (elem.iQEventData && elem.iQEventData[type]) |
|
732 this.unbind(type, elem.iQEventData[type][0].original); |
|
733 }, this); |
|
734 } |
|
735 |
|
736 return this; |
|
737 } |
|
738 }; |
|
739 |
|
740 // ---------- |
|
741 // Create various event aliases |
|
742 let events = [ |
|
743 'keyup', |
|
744 'keydown', |
|
745 'keypress', |
|
746 'mouseup', |
|
747 'mousedown', |
|
748 'mouseover', |
|
749 'mouseout', |
|
750 'mousemove', |
|
751 'click', |
|
752 'dblclick', |
|
753 'resize', |
|
754 'change', |
|
755 'blur', |
|
756 'focus' |
|
757 ]; |
|
758 |
|
759 events.forEach(function(event) { |
|
760 iQClass.prototype[event] = function(func) { |
|
761 return this.bind(event, func); |
|
762 }; |
|
763 }); |