HTML Preparation code:
x
 
1
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
2
3
<script>
4
    (function(exposeAs){
5
        var Dex = function(selector, nodes){
6
7
            // Return Dex object
8
            return new Dex.fn.init(selector, nodes);
9
10
        };
11
12
        Dex.fn = Dex.prototype = {
13
            init: function(selector, nodes){
14
                this.selector = selector;
15
16
                if(nodes){
17
                    this.nodes = nodes;
18
                } else {
19
                    this.nodes = document.querySelectorAll(selector);
20
                }
21
22
                return this;
23
            }
24
25
26
        };
27
28
        // CONSTANTS
29
        var UNDEFINED = "undefined";
30
31
        // HIDDEN VARIABLES
32
        var cachedSelections = {},
33
            delegatedEventListeners = {},
34
            mutationObservers = {},
35
            DOMMutationCallback = function(mutations, selector, parentNodes){
36
                var n, x, y,
37
                    mutationRecord,
38
                    addedNode,
39
                    removedNode,
40
                    modifiedNodeAttribute,
41
                    callbacks,
42
                    modifiedSelector,
43
                    _target,
44
                    executeCallbacks = function(queue, node, arg1, arg2){
45
                        var n = 0;
46
47
                        while(queue[n]){
48
                            // Call callback function
49
                            queue[n].callback.call(node, arg1, arg2);
50
51
                            if(!queue[n].persistant){
52
                                queue.splice(n, 1);
53
                            }
54
55
                            n++;
56
57
                        }
58
                    },
59
                    executeAttributecallbacks = function(queue, node, attrKey, attrValue){
60
                        y = 0;
61
62
                        while(queue[y]){
63
                            // Call callback function
64
                            if(queue[y].attrKey == attrKey){
65
                                queue[y].callback.call(node, attrKey, attrValue);
66
67
                                if(!queue[y].persistant){
68
                                    queue.splice(y, 1);
69
70
                                }
71
72
                            }
73
74
                            y++;
75
                        }
76
                    };
77
78
79
                // Loop through mutation records
80
                for(n = 0; n < mutations.length; n++){
81
                    mutationRecord = mutations[n];
82
83
                    // Loop through added nodes
84
                    if(mutationRecord.addedNodes.length > 0){
85
                        callbacks = mutationObservers[selector].callbacks.onOpen;
86
87
                        if(callbacks){
88
                            for(x = 0; x < mutationRecord.addedNodes.length; x++){
89
                                addedNode = mutationRecord.addedNodes[x];
90
91
                                // Check if node type is valid
92
                                if(addedNode.nodeType == 1){
93
94
                                    // Loop through callbacks
95
                                    for(_target in callbacks){
96
                                        modifiedSelector = callbacks[_target].matchType.modifiedSelector;
97
98
                                        // See if addedNode matches the _target of the callback
99
                                        switch(callbacks[_target].matchType.type){
100
                                            case "tag":
101
                                                if(addedNode.tagName.toUpperCase() == modifiedSelector){
102
                                                    // Loop through all callbacks
103
                                                    executeCallbacks(callbacks[_target].queue, addedNode);
104
105
                                                }
106
                                                break;
107
                                            case "id":
108
                                                if(addedNode.id == modifiedSelector){
109
                                                    // Loop through all callbacks
110
                                                    executeCallbacks(callbacks[_target].queue, addedNode);
111
112
                                                }
113
                                                break;
114
                                            case "classname":
115
                                                if(addedNode.classList.contains(modifiedSelector)){
116
                                                    // Loop through all callbacks
117
                                                    executeCallbacks(callbacks[_target].queue, addedNode, mutationRecord.addedNodes);
118
119
                                                }
120
                                                break;
121
                                            case "complex":
122
                                                if(addedNode.matches(modifiedSelector)){
123
                                                    // Loop through all callbacks
124
                                                    executeCallbacks(callbacks[_target].queue, addedNode);
125
126
                                                }
127
                                                break;
128
129
                                        }
130
131
                                    }
132
                                }
133
134
                            }
135
                        }
136
                    }
137
138
                    if(mutationRecord.removedNodes.length > 0){
139
                        callbacks = mutationObservers[selector].callbacks.onClose;
140
141
                        if(callbacks){
142
                            // Loop through removed nodes
143
                            for(x = 0; x < mutationRecord.removedNodes.length; x++){
144
                                removedNode = mutationRecord.removedNodes[x];
145
146
                                // Check if node type is valid
147
                                if(removedNode.nodeType == 1){
148
149
                                    // Loop through callbacks
150
                                    for(_target in callbacks){
151
152
                                        modifiedSelector = callbacks[_target].matchType.modifiedSelector;
153
154
                                        // See if removedNode matches the _target of the callback
155
                                        switch(callbacks[_target].matchType.type){
156
                                            case "tag":
157
                                                if(removedNode.tagName.toUpperCase() == modifiedSelector){
158
                                                    // Loop through all callbacks
159
                                                    executeCallbacks(callbacks[_target].queue, removedNode);
160
161
                                                }
162
                                                break;
163
                                            case "id":
164
                                                if(removedNode.id == modifiedSelector){
165
                                                    // Loop through all callbacks
166
                                                    executeCallbacks(callbacks[_target].queue, removedNode);
167
168
                                                }
169
                                                break;
170
                                            case "classname":
171
                                                if(removedNode.classList.contains(modifiedSelector)){
172
                                                    // Loop through all callbacks
173
                                                    executeCallbacks(callbacks[_target].queue, removedNode);
174
175
                                                }
176
                                                break;
177
                                            case "complex":
178
                                                if(removedNode.matches(modifiedSelector)){
179
                                                    // Loop through all callbacks
180
                                                    executeCallbacks(callbacks[_target].queue, removedNode);
181
182
                                                }
183
                                                break;
184
185
                                        }
186
187
                                    }
188
189
                                }
190
191
                            }
192
                        }
193
                    }
194
195
                    if(mutationRecord.attributeName){
196
                        callbacks = mutationObservers[selector].callbacks.onAttribute;
197
198
                        if(callbacks){
199
                            // Loop through modified attributes
200
                            modifiedNodeAttribute = mutationRecord.target;
201
202
                            // Loop through callbacks
203
                            for(_target in callbacks){
204
                                modifiedSelector = callbacks[_target].matchType.modifiedSelector;
205
206
                                // See if modifiedNodeAttribute matches the _target of the callback
207
                                switch(callbacks[_target].matchType.type){
208
                                    case "tag":
209
                                        if(modifiedNodeAttribute.tagName.toUpperCase() == modifiedSelector){
210
                                            // Loop through all callbacks
211
                                            if(mutationRecord.target.attributes[mutationRecord.attributeName]){ // Its a live list, so check it hasnt been removed
212
                                                executeAttributecallbacks(callbacks[_target].queue, modifiedNodeAttribute, mutationRecord.attributeName, mutationRecord.target.attributes[mutationRecord.attributeName].value);
213
214
                                            }
215
216
                                        }
217
                                        break;
218
                                    case "id":
219
                                        if(modifiedNodeAttribute.id == modifiedSelector){
220
                                            // Loop through all callbacks
221
                                            if(mutationRecord.target.attributes[mutationRecord.attributeName]){ // Its a live list, so check it hasnt been removed
222
                                                executeAttributecallbacks(callbacks[_target].queue, modifiedNodeAttribute, mutationRecord.attributeName, mutationRecord.target.attributes[mutationRecord.attributeName].value);
223
224
                                            }
225
                                        }
226
                                        break;
227
                                    case "classname":
228
                                        if(modifiedNodeAttribute.classList.contains(modifiedSelector)){
229
                                            // Loop through all callbacks
230
                                            if(mutationRecord.target.attributes[mutationRecord.attributeName]){ // Its a live list, so check it hasnt been removed
231
                                                executeAttributecallbacks(callbacks[_target].queue, modifiedNodeAttribute, mutationRecord.attributeName, mutationRecord.target.attributes[mutationRecord.attributeName].value);
232
233
                                            }
234
                                        }
235
                                        break;
236
                                    case "complex":
237
                                        if(modifiedNodeAttribute.matches(modifiedSelector)){
238
                                            // Loop through all callbacks
239
                                            if(mutationRecord.target.attributes[mutationRecord.attributeName]){ // Its a live list, so check it hasnt been removed
240
                                                executeAttributecallbacks(callbacks[_target].queue, modifiedNodeAttribute, mutationRecord.attributeName, mutationRecord.target.attributes[mutationRecord.attributeName].value);
241
242
                                            }
243
                                        }
244
                                        break;
245
                                }
246
247
                            }
248
                        }
249
                    }
250
251
                }
252
253
            },
254
            createEventListener = function(dexObject, eventType, selector, target, callback, persistant){
255
                // Check that the event type exists in queue
256
                if(!delegatedEventListeners[eventType]){
257
                    delegatedEventListeners[eventType] = {};
258
                }
259
260
                // Check that this selector is registered
261
                if(!delegatedEventListeners[eventType][selector]){
262
                    delegatedEventListeners[eventType][selector] = {};
263
264
                    // Setup listener
265
266
                    attachEventListeners(eventType, dexObject);
267
                }
268
269
                // Check that this target is registered
270
                if(!delegatedEventListeners[eventType][selector][target]){
271
                    delegatedEventListeners[eventType][selector][target] = [];
272
                }
273
274
                // register delegated event listener
275
                delegatedEventListeners[eventType][selector][target].push({
276
                    callback: callback,
277
                    persistant: persistant
278
                });
279
280
281
            },
282
            attachEventListeners = function(eventType, dexObject){
283
284
                var n,
285
                    selector = {
286
                        string: dexObject.selector
287
                    };
288
289
                for(n = 0; n < dexObject.nodes.length; n++){
290
                    selector.node = dexObject.nodes[n];
291
292
                    selector.node.addEventListener(eventType, function(e){
293
                        var eventHandlers = delegatedEventListeners[eventType][selector.string];
294
295
                        for(handlerSelector in eventHandlers){
296
297
                            clickedNode = e.target;
298
299
300
                            while(  clickedNode &&
301
                                    clickedNode !== document &&
302
                                    clickedNode !== selector.node) { // Stop looking when we hit the node that contains the event listener
303
304
                                if (clickedNode.matches(handlerSelector)) {
305
306
                                    var handlerIndex = 0;
307
308
                                    while (eventHandlers[handlerSelector][handlerIndex]){
309
                                        eventHandlers[handlerSelector][handlerIndex].callback.call(clickedNode, e);
310
311
                                        if(!eventHandlers[handlerSelector][handlerIndex].persistant){
312
                                            eventHandlers[handlerSelector].splice(handlerIndex, 1);
313
                                        }
314
315
                                        handlerIndex++;
316
                                    }
317
318
                                }
319
320
                                clickedNode = clickedNode.parentNode;
321
322
                            }
323
                        }
324
325
                    });
326
                }
327
328
329
            };
330
331
        // EXPOSED SELECTOR FUNCTIONS
332
        Dex.fn.init.prototype = {
333
334
            first: function(){
335
                /* Remove all nodes except first from node list */
336
337
                this.nodes = [this.nodes[0]];
338
339
                return this;
340
            },
341
342
            index: function(index){
343
                /* Remove all nodes except requested index */
344
345
                this.nodes = [this.nodes[index]];
346
347
                return this;
348
            },
349
350
            getNode: function(index){
351
                /* Return DOM node */
352
353
                return this.nodes[index];
354
            },
355
356
            exists: function(){
357
                /* See if the node list contains at least one node */
358
359
                return this.nodes[0] != null;
360
            },
361
362
            appendClone: function(node){
363
364
                var n;
365
366
                for(n = 0; n < this.nodes.length; n++){
367
                    this.nodes[n].appendChild(node.cloneNode(true));
368
                }
369
370
                return this;
371
372
            },
373
374
            append: function(node){
375
376
                var n;
377
378
                for(n = 0; n < this.nodes.length; n++){
379
                    this.nodes[n].appendChild(node);
380
                }
381
382
                return this;
383
384
            },
385
386
            remove: function(){
387
388
                var n;
389
390
                for(n = 0; n < this.nodes.length; n++){
391
                    this.nodes[n];
392
393
                    if (this.nodes[n].parentNode) {
394
                        this.nodes[n].parentNode.removeChild(this.nodes[n]);
395
                    }
396
                }
397
398
                return this;
399
400
            },
401
402
            clone: function(){
403
                var n,
404
                    clonedNodes = [];
405
406
                for(n = 0; n < this.nodes.length; n++){
407
                    clonedNodes.push(this.nodes[n].cloneNode(true));
408
                }
409
410
                this.nodes = clonedNodes;
411
412
                return this;
413
            },
414
415
            parent: function(){
416
417
                this.nodes = [this.nodes[0].parentNode];
418
419
                return this;
420
421
            },
422
423
            closest: function(matchSelector){
424
425
                var closest = [];
426
427
                node = this.nodes[0];
428
429
                // Go through parents
430
                while(node && node !== document) {
431
                    if (node.matches(matchSelector)) {
432
433
                        closest = [node];
434
                        break;
435
436
                    }
437
438
                    node = node.parentNode;
439
440
                }
441
442
                this.nodes = closest;
443
444
                return this;
445
446
            },
447
448
            filter: function(selector){
449
                /* Filter then current node list - note: only filters on the first node in list */
450
451
                this.nodes = this.nodes[0].querySelectorAll(selector);
452
453
                return this;
454
455
            },
456
457
            // DOM modification
458
            setHTML: function(value){
459
                /* Set innerHTML of all nodes in nodelist */
460
461
                var n;
462
463
                for(n = 0; n < this.nodes.length; n++){
464
                    this.nodes[n].innerHTML = value;
465
                }
466
467
                return this;
468
            },
469
470
            getHTML: function(value){
471
                /* Get innerHTML of all first node in nodelist */
472
473
                return this.nodes[0].innerHTML;
474
            },
475
476
            css: function(styles){
477
                /* Set CSS of all nodes in nodelist */
478
479
                var style,
480
                    n;
481
482
                for(n = 0; n < this.nodes.length; n++){
483
484
                    for(style in styles){
485
486
                        this.nodes[n].style[style] = styles[style];
487
488
                    }
489
490
                }
491
492
                return this;
493
494
495
496
            },
497
498
            setAttribute: function(key, value){
499
                /* Set attribute of all nodes in nodelist */
500
501
                var n;
502
503
                for(n = 0; n < this.nodes.length; n++){
504
                    this.nodes[n].setAttribute(key, value);
505
                }
506
507
                return this;
508
            },
509
510
            getAttribute: function(key){
511
                /* Get attribute of first node in nodelist */
512
513
                return this.nodes[0].getAttribute(key);
514
            },
515
516
            toggleAttribute: function(key, value){
517
                /* Get attribute of first node in nodelist */
518
519
                var n,
520
                    attrValue;
521
522
                for(n = 0; n < this.nodes.length; n++){
523
                    attrValue = this.nodes[n].getAttribute(key);
524
525
                    if(attrValue == value[0]){
526
                        this.nodes[n].setAttribute(key, value[1]);
527
                    } else {
528
                        this.nodes[n].setAttribute(key, value[0]);
529
                    }
530
                }
531
532
                return this;
533
            },
534
535
            cache: function(cacheID){
536
                /* Cache node list with cacheID as ID */
537
538
                cachedSelections[cacheID] = this;
539
            },
540
541
            // Classes
542
            addClass: function(classname){
543
                /* Add class to all nodes in nodelist */
544
545
546
                var n;
547
548
                for(n = 0; n < this.nodes.length; n++){
549
                    this.nodes[n].classList.add(classname);
550
                }
551
552
                return this;
553
            },
554
555
            removeClass: function(classname){
556
                /* Remove class from all nodes in nodelist */
557
558
                var n;
559
560
                for(n = 0; n < this.nodes.length; n++){
561
                    this.nodes[n].classList.remove(classname);
562
                }
563
                return this;
564
            },
565
566
            hasClass: function(classname){
567
                /* Check whether first node in list contains a classname */
568
569
                var result = false;
570
571
                if(this.nodes[0]){
572
                    result = this.nodes[0].classList.contains(classname);
573
                }
574
575
                return result;
576
577
            },
578
579
            toggleClass: function(classname){
580
                /* Toggle classnames on all nodes in nodelist */
581
582
                var n;
583
584
                for(n = 0; n < this.nodes.length; n++){
585
                    this.nodes[n].classList.toggle(classname);
586
                }
587
588
                return this;
589
            },
590
591
            replaceClass: function(old_classname, new_classname){
592
                /* Replace old_classname with new_classname on all nodes in nodelist */
593
594
                var n;
595
596
                for(n = 0; n < this.nodes.length; n++){
597
                    this.nodes[n].classList.replace(old_classname, new_classname);
598
                }
599
600
                return this;
601
            },
602
603
            trigger: function(eventType){
604
                /* Trigger eventType (click, mouseover, etc, ...) on all nodes in nodelist */
605
606
                if(this.nodes[0]){
607
                    var clickEvent = document.createEvent("MouseEvents");
608
609
                    clickEvent.initEvent(eventType, true, true);
610
                    this.nodes[0].dispatchEvent(clickEvent);
611
                }
612
613
                return this;
614
            },
615
616
            onOpen: function(target, callback){
617
                this.onMutation("onOpen", target, callback, {
618
                    children: false,
619
                    persistant: true
620
                });
621
622
                return this;
623
            },
624
625
            onceOpen: function(target, callback){
626
                this.onMutation("onOpen", target, callback, {
627
                    children: false,
628
                    persistant: false
629
                });
630
631
                return this;
632
            },
633
634
            onClose: function(target, callback){
635
636
                this.onMutation("onClose", target, callback, {
637
                    children: false,
638
                    persistant: true
639
                });
640
641
                return this;
642
            },
643
644
            onceClose: function(target, callback){
645
646
                this.onMutation("onClose", target, callback, {
647
                    children: false,
648
                    persistant: false
649
                });
650
651
                return this;
652
            },
653
654
            onAttribute: function(target, attrKey, callback){
655
                this.onMutation("onAttribute", target, callback, {
656
                    attrKey: attrKey,
657
                    persistant: true
658
                });
659
660
                return this;
661
            },
662
663
            onceAttribute: function(target, attrKey, callback){
664
                this.onMutation("onAttribute", target, callback, {
665
                    attrKey: attrKey,
666
                    persistant: false
667
                });
668
669
                return this;
670
            },
671
672
            onMutation: function(mutationType, target, callback, parameters){
673
                var selector = this.selector,
674
                    parentNodes = this.nodes,
675
                    matchType = function(target){
676
                        // This needs updating to cater for complex selectors.
677
678
                        var result;
679
680
                        if(target[0] == "."){
681
                            result = {
682
                                type: "classname",
683
                                modifiedSelector: target.slice(1)
684
                            }
685
686
687
                        } else if(target[0] == "#"){
688
                            result = {
689
                                type: "id",
690
                                modifiedSelector: target.slice(1)
691
                            }
692
693
                        } else if(target[0] == "["){
694
                            result = {
695
                                type: "complex",
696
                                modifiedSelector: target
697
                            }
698
699
                        } else {
700
                            result = {
701
                                type: "tag",
702
                                modifiedSelector: target.toUpperCase()
703
                            }
704
                        }
705
706
                        return result;
707
708
                    }(target),
709
                    n,
710
                    parameters = parameters || {};
711
712
713
                // See if we need to attach a mutation observer
714
715
716
                if(!mutationObservers[this.selector]){
717
                    mutationObservers[this.selector] = {
718
                        observer: new MutationObserver(function(mutations){
719
                            DOMMutationCallback(mutations, selector, parentNodes);
720
                        }),
721
                        callbacks: {}
722
                    }
723
724
                    // Attach observer to all matches nodes
725
                    for(n = 0; n < this.nodes.length; n++){
726
                        mutationObservers[this.selector].observer.observe(this.nodes[n], {
727
                            attributes: true,
728
                            childList: true,
729
                            characterData: false,
730
                            subtree: true
731
                        });
732
                    }
733
                }
734
735
736
737
                // See if there are already callbacks for mutationType
738
                if(!mutationObservers[this.selector].callbacks[mutationType]){
739
                    mutationObservers[this.selector].callbacks[mutationType] = {}
740
                }
741
742
                // See if there are already calbacks for this target
743
                if(!mutationObservers[this.selector].callbacks[mutationType][target]){
744
                    // mutationObservers[this.selector][childtree].callbacks[mutationType][target] = []
745
                    mutationObservers[this.selector].callbacks[mutationType][target] = {
746
                        matchType: matchType,
747
                        queue: []
748
                    }
749
                }
750
751
                // Save callback
752
                mutationObservers[this.selector].callbacks[mutationType][target].queue.push({
753
                    callback: callback,
754
                    attrKey: parameters.attrKey,
755
                    persistant: parameters.persistant
756
                });
757
            },
758
759
760
            onClick: function(target, callback){
761
                createEventListener(this, "click", this.selector, target, callback, true);
762
763
                return this;
764
765
            },
766
767
            oneClick: function(target, callback){
768
                createEventListener(this, "click", this.selector, target, callback, false);
769
770
                return this;
771
772
            },
773
774
            onMouseUp: function(target, callback){
775
                createEventListener(this, "mouseup", this.selector, target, callback, true);
776
777
                return this;
778
779
            },
780
781
            oneMouseUp: function(target, callback){
782
                createEventListener(this, "mouseup", this.selector, target, callback, false);
783
784
                return this;
785
786
            },
787
788
            onMouseDown: function(target, callback){
789
                createEventListener(this, "mousedown", this.selector, target, callback, true);
790
791
                return this;
792
793
            },
794
795
            oneMouseDown: function(target, callback){
796
                createEventListener(this, "mousedown", this.selector, target, callback, false);
797
798
                return this;
799
800
            },
801
802
            onMouseEnter: function(target, callback){
803
                createEventListener(this, "mouseenter", this.selector, target, callback, true);
804
805
                return this;
806
807
            },
808
809
            oneMouseEnter: function(target, callback){
810
                createEventListener(this, "mouseenter", this.selector, target, callback, false);
811
812
                return this;
813
814
            },
815
816
            onMouseLeave: function(target, callback){
817
                createEventListener(this, "mouseleave", this.selector, target, callback, true);
818
819
                return this;
820
821
            },
822
823
            oneMouseLeave: function(target, callback){
824
                createEventListener(this, "mouseleave", this.selector, target, callback, false);
825
826
                return this;
827
828
            },
829
830
            onMouseOver: function(target, callback){
831
                createEventListener(this, "mouseover", this.selector, target, callback, true);
832
833
                return this;
834
835
            },
836
837
            oneMouseOver: function(target, callback){
838
                createEventListener(this, "mouseover", this.selector, target, callback, false);
839
840
                return this;
841
842
            },
843
844
            onMouseOut: function(target, callback){
845
                createEventListener(this, "mouseout", this.selector, target, callback, true);
846
847
                return this;
848
849
            },
850
851
            oneMouseOut: function(target, callback){
852
                createEventListener(this, "mouseout", this.selector, target, callback, false);
853
854
                return this;
855
856
            },
857
858
859
        }
860
861
        Dex.appendCSS = function(url){
862
            var head = document.head,
863
                link = document.createElement('link');
864
865
              link.type = "text/css";
866
              link.rel = "stylesheet";
867
              link.href = url;
868
869
              head.appendChild(link);
870
871
              return link;
872
        }
873
874
        Dex.getCached = function(cacheID){
875
            return cachedSelections[cacheID];
876
        }
877
878
        Dex.clearCache = function(cacheID){
879
            delete cachedSelections[cacheID];
880
881
        }
882
883
        Dex.tag = function(tag){
884
            /* Use Tag() to select nodes using the getElementsByTagName */
885
886
            var nodes = document.getElementsByTagName(tag);
887
888
            return Dex(tag, nodes);
889
890
        }
891
892
        Dex.class = function(classname){
893
            /* Use Tag() to select nodes using the getElementsByClassName */
894
895
            var nodeCollection = document.getElementsByClassName(classname),
896
                nodes = Array.prototype.slice.call(nodeCollection);
897
898
            return Dex("." + classname, nodes);
899
900
        }
901
902
        Dex.iframe = function(selector){
903
904
            var iframe = document.querySelectorAll(selector)[0];
905
906
            return Dex.node(iframe.contentDocument || iframe.contentWindow.document);
907
908
        }
909
910
        Dex.id = function(id){
911
            /* Use Tag() to select nodes using the getElementById */
912
913
            var nodes = [document.getElementById(id)];
914
915
            return Dex("#" + id, nodes);
916
917
        }
918
919
        Dex.node = function(node){
920
            /* Use Node to create a Dex object with a DOM node directly */
921
922
            return Dex("node", [node]);
923
924
        }
925
926
        Dex.collection = function(nodeCollection){
927
            /* Use Node to create a Dex object with an HTML Node Collection  directly */
928
929
            var nodes = [];
930
931
            for(n = 0; n < nodeCollection.length; n++){
932
                nodes.push(nodeCollection[n]);
933
            }
934
935
            return Dex("node", nodes)
936
        }
937
938
        Dex.dump = function(object){
939
            console.log(mutationObservers);
940
        };
941
942
        if(exposeAs){
943
            window[exposeAs] = Dex;
944
        }
945
946
    })("DexV2");
947
</script>
948
949
<style>
950
        .add-colour {
951
            background: red;
952
        }
953
        .add-more-colour {
954
            background: red;
955
        }
956
</style>
957
958
<section>
959
            <table>
960
                <tbody>
961
                    <tr>
962
                        <td>
963
                            <div class="app-container">
964
                                <table>
965
                                    <tbody>
966
                                        <tr>
967
                                            <td>
968
                                                <div class="app-window">
969
                                                    App window
970
                                                    <table>
971
                                                        <tbody>
972
                                                            <tr>
973
                                                                <td>
974
                                                                    <div class="app-menu" id="the-menu">
975
                                                                        <h1 class="h1" id="h1" data-attr="hello there">Button</h1>
976
                                                                        app menu
977
                                                                        <div>
978
                                                                            <div>
979
                                                                                <ul>
980
                                                                                    <li class="add-more-colour">
981
                                                                                        <span class="title">This is a list item in an unordered list</span>
982
                                                                                    </li>
983
                                                                                    <li class="add-more-colour">
984
                                                                                        <button class="click-me-ul">ul .click-me</button>
985
                                                                                        <button class="and-me">ul .and-me</button>
986
                                                                                    </li>
987
988
                                                                                </ul>
989
990
                                                                                <ol>
991
                                                                                    <li class="add-more-colour">
992
                                                                                        <span class="title">This is a list item in an ordered list</span>
993
                                                                                    </li>
994
                                                                                    <li class="add-more-colour">
995
                                                                                        <button class="click-me-ol">ol .click-me</button>
996
                                                                                        <button class="and-me">ol .and-me</button>
997
                                                                                    </li>
998
                                                                                </ol>
999
                                                                            </div>
1000
                                                                            <span id="output">This is the output area</span>
1001
                                                                        </div>
1002
                                                                    </div>
1003
                                                                </td>
1004
                                                            </tr>
1005
                                                        </tbody>
1006
                                                    </table>
1007
                                                </div>
1008
                                            </td>
1009
                                        </tr>
1010
                                    </tbody>
1011
                                </table>
1012
                            </div>
1013
                        </td>
1014
                    </tr>
1015
                </tbody>
1016
            </table>
1017
        </section>
Script Preparation code:
 
var v1 = DexV2.tag("li");
var v2 = $("li");
Tests:
  • Dex ::: first()

     
    v1.first();
  • jQuery ::: first()

     
    v2.first();
Rendered benchmark preparation results:

Suite status: <idle, ready to run>

Previous results

Experimental features:

  • Test case name Result
    Dex ::: first()
    jQuery ::: first()

    Fastest: N/A

    Slowest: N/A

Latest run results:
Run details: (Test run date: 7 years ago)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
Chrome 61 on Mac OS X 10.13.0
View result in a separate tab
Test name Executions per second
Dex ::: first() 8974196.0 Ops/sec
jQuery ::: first() 3156151.0 Ops/sec