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
            var delegatedEventListeners = {},
29
            attachEventListeners = function(eventType, dexObject){
30
31
                var n,
32
                    selector = {
33
                        string: dexObject.selector
34
                    };
35
36
                for(n = 0; n < dexObject.nodes.length; n++){
37
                    selector.node = dexObject.nodes[n];
38
39
                    selector.node.addEventListener(eventType, function(e){
40
41
                        var eventHandlers = delegatedEventListeners[eventType][selector.string];
42
43
                        for(handlerSelector in eventHandlers){
44
45
                            clickedNode = e.target;
46
47
                            while(  clickedNode !== document &&
48
                                    clickedNode !== selector.node) { // Stop looking when we hit the node that contains the event listener
49
50
                                if (clickedNode.matches(handlerSelector)) {
51
52
                                    var handlerIndex = 0;
53
54
                                    while (eventHandlers[handlerSelector][handlerIndex]){
55
                                        eventHandlers[handlerSelector][handlerIndex].callback.call(clickedNode, e);
56
57
                                        if(!eventHandlers[handlerSelector][handlerIndex].persistant){
58
                                            delete eventHandlers[handlerSelector][handlerIndex];
59
                                        }
60
61
                                        handlerIndex++;
62
                                    }
63
64
                                }
65
66
                                clickedNode = clickedNode.parentNode;
67
68
                            }
69
                        }
70
71
                    });
72
                }
73
74
75
            };
76
77
            // EXPOSED SELECTOR FUNCTIONS
78
            Dex.fn.init.prototype = {
79
80
                first: function(){
81
                    /* Remove all nodes except first from node list */
82
83
                    this.nodes = [this.nodes[0]];
84
85
                    return this;
86
                },
87
88
                index: function(index){
89
                    /* Remove all nodes except requested index */
90
91
                    this.nodes = [this.nodes[index]];
92
93
                    return this;
94
                },
95
96
                getNode: function(index){
97
                    /* Return DOM node */
98
99
                    return this.nodes[index];
100
                },
101
102
                exists: function(){
103
                    /* See if the node list contains at least one node */
104
105
                    return this.nodes[0] != null;
106
                },
107
108
                append: function(node){
109
110
                    var n;
111
112
                    for(n = 0; n < this.nodes.length; n++){
113
                        this.nodes[n].appendChild(node);
114
                    }
115
116
                    return this;
117
118
                },
119
120
                remove: function(){
121
122
                    var n;
123
124
                    for(n = 0; n < this.nodes.length; n++){
125
                        this.nodes[n];
126
127
                        if (this.nodes[n].parentNode) {
128
                            this.nodes[n].parentNode.removeChild(this.nodes[n]);
129
                        }
130
                    }
131
132
                    return this;
133
134
                },
135
136
                parent: function(){
137
138
                    this.nodes = [this.nodes[0].parentNode];
139
140
                    return this;
141
142
                },
143
144
                closest: function(matchSelector){
145
146
                    var closest = [];
147
148
                    node = this.nodes[0];
149
150
                    // Go through parents
151
                    while(node && node !== document) {
152
                        if (node.matches(matchSelector)) {
153
154
                            closest = [node];
155
                            break;
156
157
                        }
158
159
                        node = node.parentNode;
160
161
                    }
162
163
                    this.nodes = closest;
164
165
                    return this;
166
167
                },
168
169
                filter: function(selector){
170
                    /* Filter then current node list - note: only filters on the first node in list */
171
172
                    this.nodes = this.nodes[0].querySelectorAll(selector);
173
174
                    return this;
175
176
                },
177
178
                // DOM modification
179
                setHTML: function(value){
180
                    /* Set innerHTML of all nodes in nodelist */
181
182
                    var n;
183
184
                    for(n = 0; n < this.nodes.length; n++){
185
                        this.nodes[n].innerHTML = value;
186
                    }
187
188
                    return this;
189
                },
190
191
                getHTML: function(value){
192
                    /* Get innerHTML of all first node in nodelist */
193
194
                    return this.nodes[0].innerHTML;
195
                },
196
197
                css: function(styles){
198
                    /* Set CSS of all nodes in nodelist */
199
200
                    var style,
201
                        n;
202
203
                    for(n = 0; n < this.nodes.length; n++){
204
205
                        for(style in styles){
206
207
                            this.nodes[n].style[style] = styles[style];
208
209
                        }
210
211
                    }
212
213
                    return this;
214
215
216
217
                },
218
219
                setAttribute: function(key, value){
220
                    /* Set attribute of all nodes in nodelist */
221
222
                    var n;
223
224
                    for(n = 0; n < this.nodes.length; n++){
225
                        this.nodes[n].setAttribute(key, value);
226
                    }
227
228
                    return this;
229
                },
230
231
                getAttribute: function(key){
232
                    /* Get attribute of first node in nodelist */
233
234
                    return this.nodes[0].getAttribute(key);
235
                },
236
237
                toggleAttribute: function(key, value){
238
                    /* Get attribute of first node in nodelist */
239
240
                    var n,
241
                        attrValue;
242
243
                    for(n = 0; n < this.nodes.length; n++){
244
                        attrValue = this.nodes[n].getAttribute(key);
245
246
                        if(attrValue == value[0]){
247
                            this.nodes[n].setAttribute(key, value[1]);
248
                        } else {
249
                            this.nodes[n].setAttribute(key, value[0]);
250
                        }
251
                    }
252
253
                    return this;
254
                },
255
256
                cache: function(cacheID){
257
                    /* Cache node list with cacheID as ID */
258
259
                    cachedSelections[cacheID] = this;
260
                },
261
262
                // Classes
263
                addClass: function(classname){
264
                    /* Add class to all nodes in nodelist */
265
266
                    var n;
267
268
                    for(n = 0; n < this.nodes.length; n++){
269
                        this.nodes[n].classList.add(classname);
270
                    }
271
272
                    return this;
273
                },
274
275
                removeClass: function(classname){
276
                    /* Remove class from all nodes in nodelist */
277
278
                    var n;
279
280
                    for(n = 0; n < this.nodes.length; n++){
281
                        this.nodes[n].classList.remove(classname);
282
                    }
283
                    return this;
284
                },
285
286
                hasClass: function(classname){
287
                    /* Check whether first node in list contains a classname */
288
289
                    var result = false;
290
291
                    if(this.nodes[0]){
292
                        result = this.nodes[0].classList.contains(classname);
293
                    }
294
295
                    return result;
296
297
                },
298
299
                toggleClass: function(classname){
300
                    /* Toggle classnames on all nodes in nodelist */
301
302
                    var n;
303
304
                    for(n = 0; n < this.nodes.length; n++){
305
                        this.nodes[n].classList.toggle(classname);
306
                    }
307
308
                    return this;
309
                },
310
311
                replaceClass: function(old_classname, new_classname){
312
                    /* Replace old_classname with new_classname on all nodes in nodelist */
313
314
                    var n;
315
316
                    for(n = 0; n < this.nodes.length; n++){
317
                        this.nodes[n].classList.replace(old_classname, new_classname);
318
                    }
319
320
                    return this;
321
                },
322
323
                trigger: function(eventType){
324
                    /* Trigger eventType (click, mouseover, etc, ...) on all nodes in nodelist */
325
326
                    if(this.nodes[0]){
327
                        var clickEvent = document.createEvent("MouseEvents");
328
329
                        clickEvent.initEvent(eventType, true, true);
330
                        this.nodes[0].dispatchEvent(clickEvent);
331
                    }
332
333
                    return this;
334
                },
335
336
                onClick: function(target, callback){
337
338
                    // Check that the event type exists in queue
339
                    if(!delegatedEventListeners["click"]){
340
                        delegatedEventListeners["click"] = {};
341
                    }
342
343
                    // Check that this selector is registered
344
                    if(!delegatedEventListeners["click"][this.selector]){
345
                        delegatedEventListeners["click"][this.selector] = {};
346
347
                        // Setup listener
348
349
                        attachEventListeners("click", this);
350
                    }
351
352
                    // Check that this target is registered
353
                    if(!delegatedEventListeners["click"][this.selector][target]){
354
                        delegatedEventListeners["click"][this.selector][target] = [];
355
                    }
356
357
                    // register delegated event listener
358
                    delegatedEventListeners["click"][this.selector][target].push({
359
                        callback: callback,
360
                        persistant: true
361
                    });
362
363
                    return this;
364
365
                },
366
367
368
            }
369
370
            Dex.appendCSS = function(url){
371
                var head = document.head,
372
                    link = document.createElement('link');
373
374
                  link.type = "text/css";
375
                  link.rel = "stylesheet";
376
                  link.href = url;
377
378
                  head.appendChild(link);
379
380
                  return link;
381
            }
382
383
            Dex.getCached = function(cacheID){
384
                return cachedSelections[cacheID];
385
            }
386
387
            Dex.clearCache = function(cacheID){
388
                delete cachedSelections[cacheID];
389
390
            }
391
392
            Dex.tag = function(tag){
393
                /* Use Tag() to select nodes using the getElementsByTagName */
394
395
                var nodes = document.getElementsByTagName(tag);
396
397
                return Dex(tag, nodes);
398
399
            }
400
401
            Dex.class = function(classname){
402
                /* Use Tag() to select nodes using the getElementsByClassName */
403
404
                var nodes = document.getElementsByClassName(classname);
405
406
                return Dex("." + classname, nodes);
407
408
            }
409
410
            Dex.iframe = function(selector){
411
412
                var iframe = document.querySelectorAll(selector)[0];
413
414
                return Dex.node(iframe.contentDocument || iframe.contentWindow.document);
415
416
            }
417
418
            Dex.id = function(id){
419
                /* Use Tag() to select nodes using the getElementById */
420
421
                var nodes = [document.getElementById(id)];
422
423
                return Dex("#" + id, nodes);
424
425
            }
426
427
            Dex.node = function(node){
428
                /* Use Node to create a Dex object with a DOM node directly */
429
430
                return Dex("node", [node]);
431
432
            }
433
434
            Dex.collection = function(nodeCollection){
435
                /* Use Node to create a Dex object with an HTML Node Collection  directly */
436
437
                var nodes = [];
438
439
                for(n = 0; n < nodeCollection.length; n++){
440
                    nodes.push(nodeCollection[n]);
441
                }
442
443
                return Dex("node", nodes)
444
            }
445
446
            if(exposeAs){
447
                window[exposeAs] = Dex;
448
            }
449
450
        })("Dex");
451
</script>
452
453
<style>
454
        .add-colour {
455
            background: red;
456
        }
457
        .add-more-colour {
458
            background: red;
459
        }
460
</style>
461
462
<section>
463
            <table>
464
                <tbody>
465
                    <tr>
466
                        <td>
467
                            <div class="app-container">
468
                                <table>
469
                                    <tbody>
470
                                        <tr>
471
                                            <td>
472
                                                <div class="app-window">
473
                                                    App window
474
                                                    <table>
475
                                                        <tbody>
476
                                                            <tr>
477
                                                                <td>
478
                                                                    <div class="app-menu">
479
                                                                        <h1 class="h1" id="h1" data-attr="hello there">Button</h1>
480
                                                                        app menu
481
                                                                        <div>
482
                                                                            <div>
483
                                                                                <ul>
484
                                                                                    <li class="add-more-colour">
485
                                                                                        <span class="title">This is a list item in an unordered list</span>
486
                                                                                    </li>
487
                                                                                    <li class="add-more-colour">
488
                                                                                        <button class="click-me-ul">ul .click-me</button>
489
                                                                                        <button class="and-me">ul .and-me</button>
490
                                                                                    </li>
491
492
                                                                                </ul>
493
494
                                                                                <ol>
495
                                                                                    <li class="add-more-colour">
496
                                                                                        <span class="title">This is a list item in an ordered list</span>
497
                                                                                    </li>
498
                                                                                    <li class="add-more-colour">
499
                                                                                        <button class="click-me-ol">ol .click-me</button>
500
                                                                                        <button class="and-me">ol .and-me</button>
501
                                                                                    </li>
502
                                                                                </ol>
503
                                                                            </div>
504
                                                                            <span id="output">This is the output area</span>
505
                                                                        </div>
506
                                                                    </div>
507
                                                                </td>
508
                                                            </tr>
509
                                                        </tbody>
510
                                                    </table>
511
                                                </div>
512
                                            </td>
513
                                        </tr>
514
                                    </tbody>
515
                                </table>
516
                            </div>
517
                        </td>
518
                    </tr>
519
                </tbody>
520
            </table>
521
        </section>
Tests:
  • Dex ::: addClass()

     
    Dex.tag("li").addClass("add-colour");
  • jQuery ::: addClass()

     
    $("li").addClass("add-colour");
  • Dex ::: removeClass()

     
    Dex.tag("li").removeClass("add-more-colour");
  • jQuery ::: removeClass()

     
    $("li").removeClass("add-more-colour");
  • Dex ::: toggleClass()

     
    Dex.tag("li").toggleClass("add-more-colour");
  • jQuery ::: toggleClass()

     
    $("li").toggleClass("add-more-colour");
  • Dex ::: replaceClass()

     
    Dex.tag("li").replaceClass("add-more-colour", "add-colour");
  • jQuery ::: replace class equivalent

     
    $("li")
      .removeClass("add-more-colour")
      .addClass("add-colour");
  • Dex ::: hasClass()

     
    var hasClass = Dex.tag("li").hasClass("add-colour");
  • jQuery ::: hasClass()

     
    var hasClass = $("li").hasClass("add-colour");
Rendered benchmark preparation results:

Suite status: <idle, ready to run>

Previous results

Experimental features:

  • Test case name Result
    Dex ::: addClass()
    jQuery ::: addClass()
    Dex ::: removeClass()
    jQuery ::: removeClass()
    Dex ::: toggleClass()
    jQuery ::: toggleClass()
    Dex ::: replaceClass()
    jQuery ::: replace class equivalent
    Dex ::: hasClass()
    jQuery ::: hasClass()

    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_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36
Chrome 61 on Mac OS X 10.12.5
View result in a separate tab
Test name Executions per second
Dex ::: addClass() 71075.3 Ops/sec
jQuery ::: addClass() 47934.9 Ops/sec
Dex ::: removeClass() 73879.7 Ops/sec
jQuery ::: removeClass() 50378.2 Ops/sec
Dex ::: toggleClass() 55735.7 Ops/sec
jQuery ::: toggleClass() 12949.2 Ops/sec
Dex ::: replaceClass() 193421.9 Ops/sec
jQuery ::: replace class equivalent 27351.8 Ops/sec
Dex ::: hasClass() 2399868.0 Ops/sec
jQuery ::: hasClass() 263288.0 Ops/sec