UNPKG

173 kBtext/coffeescriptView Raw
1@dimensions = import './simulate.coffee'
2@Dom = @DOM = window.quickdom
3mocha.setup('tdd')
4mocha.slow(400)
5mocha.timeout(12000)
6mocha.bail() unless window.location.hostname
7chai = import 'chai'
8chai.use import 'chai-style'
9chai.config.truncateThreshold = 1e3
10{expect} = chai
11
12sandbox = null
13restartSandbox = ()->
14 sandbox.parentElement.removeChild(sandbox) if sandbox
15 sandbox = document.createElement('div')
16 sandbox.id = 'sandbox'
17 sandbox.setAttribute 'style', 'border:1px solid; padding:20px; box-sizing:border-box'
18 document.body.appendChild(sandbox)
19
20checkChildStructure = (main)-> (children...)->
21 expect(main.children.length).to.equal(children.length)
22 for child,index in children
23 expect(main.children[index]).to.equal(child)
24 expect(child.el.parentNode).to.equal(main.el)
25 expect(child.parent).to.equal(main)
26 return
27
28
29suite "QuickDom", ()->
30 setup(restartSandbox)
31
32 test "Version Property", ()->
33 packageVersion = (import '../package $ version')
34 expect(Dom.version).to.equal(packageVersion)
35
36
37 suite "Element Creation", ()->
38 test "Basic Creation", ()->
39 div = Dom('div')
40 expect(typeof div).to.equal 'object'
41 expect(typeof div.el).to.equal 'object'
42 expect(div.el).to.be.instanceOf window.HTMLDivElement
43 expect(div.parent).to.be.undefined
44 expect(div.children.length).to.equal 0
45
46
47 test "Shortcuts", ()->
48 expect(Dom.a().el.constructor).to.equal(Dom('a').el.constructor)
49 expect(Dom.link().el.constructor).to.equal(Dom('a').el.constructor)
50 expect(Dom.anchor().el.constructor).to.equal(Dom('a').el.constructor)
51 expect(Dom.div().el.constructor).to.equal(Dom('div').el.constructor)
52 expect(Dom.text().el.constructor).to.equal(Dom('text').el.constructor)
53 expect(Dom.span().el.constructor).to.equal(Dom('span').el.constructor)
54 expect(Dom.h4().el.constructor).to.equal(Dom('h4').el.constructor)
55 expect(Dom.header().el.constructor).to.equal(Dom('header').el.constructor)
56 expect(Dom.footer().el.constructor).to.equal(Dom('footer').el.constructor)
57 expect(Dom.section().el.constructor).to.equal(Dom('section').el.constructor)
58 expect(Dom.button().el.constructor).to.equal(Dom('button').el.constructor)
59 expect(Dom.input().el.constructor).to.equal(Dom('input').el.constructor)
60 # expect(Dom.main().el.constructor).to.equal(Dom('main').el.constructor)
61 types = ['a','div','text','span','h4','header','footer','section','button','input']
62 for type in types
63 expect(Dom[type]().el.constructor.name).not.to.contain('Unknown')
64 return
65
66
67 test "Basic options", ()->
68 A = Dom.div(class:'abc-123', props:{'abc':123, 'def':456})
69 B = Dom.div(id:'B', className:'abc-123', attrs:{'data-abc':123, 'data-def':456})
70 C = Dom.input(type:'text', name:'abc', value:'hello')
71 D = Dom.input(type:'checkbox', checked:true)
72 E = Dom.option(name:'abc', value:'hello', selected:true)
73 F = Dom.link(href:'https://google.com/')
74 G = Dom.anchor(url:'https://google.com/')
75 H = Dom.text('Some text')
76 I = Dom.img(src:'https://google.com/')
77 J = Dom.div(relatedInstance: obj={a:1})
78
79 expect(A.el.className).to.equal('abc-123')
80 expect(A.el.abc).to.equal(123)
81 expect(A.el.def).to.equal(456)
82 expect(B.el.className).to.equal('abc-123')
83 expect(B.el.id).to.equal('B')
84 expect(B.el.getAttribute('data-abc')).to.equal('123')
85 expect(B.el.getAttribute('data-def')).to.equal('456')
86 expect(B.el.dataset.abc).to.equal('123') if B.el.dataset
87 expect(C.el.type).to.equal('text')
88 expect(C.el.name).to.equal('abc')
89 expect(C.el.value).to.equal('hello')
90 expect(D.el.checked).to.equal(true)
91 expect(E.el.name).to.equal('abc')
92 expect(E.el.selected).to.equal(true)
93 expect(F.el.href).to.equal('https://google.com/')
94 expect(G.el.href).to.equal('https://google.com/')
95 expect(H.el.nodeType).to.equal(3)
96 expect(H.el.textContent).to.equal('Some text')
97 expect(I.el.src).to.equal('https://google.com/')
98 expect(J.related).to.equal(obj)
99 expect(J.options.related).to.equal(obj)
100
101
102 test "Creation w/ children", ()->
103 A = Dom.div(null, 'Some text')
104 B = Dom.div(null, Dom.span(), 'Some text', Dom.span())
105
106 expect(A.el.childNodes.length).to.equal(1)
107 expect(A.el.children.length).to.equal(0)
108 expect(A.el.childNodes[0].nodeType).to.equal(3)
109 expect(A.el.childNodes[0].textContent).to.equal('Some text')
110 expect(A.children.length).to.equal(1)
111 expect(B.el.childNodes.length).to.equal(3)
112 expect(B.el.children.length).to.equal(2)
113 expect(B.el.childNodes[0].nodeType).to.equal(1)
114 expect(B.el.childNodes[0].nodeName.toLowerCase()).to.equal('span')
115 expect(B.el.childNodes[1].nodeType).to.equal(3)
116 expect(B.el.childNodes[1].textContent).to.equal('Some text')
117 expect(B.el.childNodes[2].nodeType).to.equal(1)
118 expect(B.el.childNodes[2].nodeName.toLowerCase()).to.equal('span')
119 expect(B.children.length).to.equal(3)
120
121
122 test "Array syntax", ()->
123 section = Dom(
124 ['section', {style:display:'inline'},
125 ['div', null, 'childA']
126 ['span', null,
127 ['strong', null, 'childB']
128 ]
129 ['div', null, 'childC',
130 ['span', null, 'childC_1']
131 ['span', null, 'childC_2']
132 ]
133 ]
134 ).appendTo(sandbox)
135
136 expect(section).not.to.equal(undefined)
137 expect(section.raw).to.have.style('display', 'inline')
138 expect(section.children.length).to.equal(3)
139 expect(section.children[0].children.length).to.equal(1)
140 expect(section.children[1].children.length).to.equal(1)
141 expect(section.children[2].children.length).to.equal(3)
142 expect(section.children[2].children[1].children.length).to.equal(1)
143 expect(section.children[2].children[2].children.length).to.equal(1)
144 expect(section.children[0].text).to.equal('childA')
145 expect(section.children[1].text).to.equal('childB')
146 expect(section.children[2].text).to.equal('childCchildC_1childC_2')
147 expect(section.children[2].children[1].text).to.equal('childC_1')
148 expect(section.children[2].children[2].text).to.equal('childC_2')
149
150
151 test "Existing Element", ()->
152 divRaw = document.createElement('div')
153 A = Dom(divRaw)
154 B = Dom(divRaw)
155 C = Dom(A)
156
157 expect(A.el).to.equal(divRaw)
158 expect(B.el).to.equal(divRaw)
159 expect(C.el).to.equal(divRaw)
160 expect(A).to.equal(B)
161 expect(B).to.equal(C)
162 expect(C).to.equal(divRaw._quickElement)
163
164
165 test "Existing Element w/ Options", ()->
166 divRaw = document.createElement('div')
167 divRaw.id = 'A'
168
169 div = Dom(divRaw, {id:'B', class:'abc-123'})
170 expect(divRaw.id).to.equal('B')
171 expect(divRaw.className).to.equal('abc-123')
172
173 div = Dom(div, {id:'C', class:'def-456'})
174 expect(divRaw.id).to.equal('C')
175 expect(divRaw.className).to.equal('def-456')
176
177
178 test "Existing Element from array-like objects", ()->
179 rawA = document.createElement('div')
180 rawB = document.createElement('div')
181 rawC = document.createElement('div')
182 parent = document.createElement('section')
183 parent.appendChild(rawA); parent.appendChild(rawB); parent.appendChild(rawC);
184 A = Dom([rawA, rawB, rawC])
185 B = Dom(parent.querySelectorAll('div'))
186 C = Dom(B)
187
188 expect(A.el).to.equal(rawA)
189 expect(B.el).to.equal(rawA)
190 expect(C.el).to.equal(rawA)
191 expect(A).to.equal(B)
192 expect(B).to.equal(C)
193 expect(C).to.equal(rawA._quickElement)
194
195
196
197 test "Document node", ()->
198 doc = Dom(document)
199 expect(doc).not.to.be.undefined
200 expect(doc.raw).to.equal(document)
201 expect(doc.parent).to.equal(undefined)
202 expect(doc.children.length).to.equal(1)
203 expect(Dom(sandbox).parents).not.to.contain(doc)
204 expect(Dom(sandbox).parents).to.contain(doc.children[0])
205
206
207 test "Window object", ()->
208 win = Dom(window)
209 expect(win).not.to.be.undefined
210 expect(win.raw is window).to.be.true
211 expect(win.parent).to.equal(undefined)
212 expect(win.children).to.equal(undefined)
213 expect(win.append).to.equal(undefined)
214 expect(win.html).to.equal(undefined)
215 expect(win.style).to.equal(undefined)
216 expect(Dom(sandbox).parents).not.to.contain(win)
217
218
219 test "Creation w/ styling", ()->
220 div = Dom.div style:
221 'width': '10px'
222 'height': 15
223 'lameo': '19px'
224 'background-color': 'blue'
225 'backgroundSize': 'cover'
226
227 sandbox.appendChild(div.el)
228 computedStyle = getComputedStyle(div.el)
229
230 expect(div.style.lameo).to.equal undefined
231 expect(computedStyle.lameo).to.equal undefined
232 expect(computedStyle.width).to.equal '10px'
233 expect(computedStyle.height).to.equal '15px'
234 expect(computedStyle.backgroundColor).not.to.equal ''
235 expect(computedStyle.backgroundSize).to.equal 'cover'
236
237
238 test "SVG elements can be created via a '*' in the element's type string", ()->
239 svgBad = Dom('svg').el
240 svgGood = Dom('*svg').el
241 svgPolyBad = Dom('polyline').el
242 svgPolyGood = Dom('*polyline').el
243 svgDiv = Dom('*div').el
244 regDiv = Dom('div').el
245
246 expect(svgBad).to.be.instanceOf(HTMLUnknownElement)
247 expect(svgPolyBad).to.be.instanceOf(HTMLUnknownElement)
248 expect(svgGood).to.be.instanceOf(SVGSVGElement)
249 expect(svgPolyGood).to.be.instanceOf(SVGPolylineElement)
250 # expect(svgDiv).to.be.instanceOf('SVGElement')
251 expect(svgDiv.constructor).not.to.equal(regDiv.constructor)
252
253
254 test "QuickDom.html() accepts an html string which would be parsed and converted into a QuickBatch instance", ()->
255 htmlString = "
256 <div>firstChildText</div><span>secondChildText</span>
257 textNode
258 <strong>abc123</strong>
259 "
260 window.batch = Dom.html(htmlString)
261
262 expect(typeof batch).to.equal 'object'
263 expect(batch.constructor.name).to.equal 'QuickBatch'
264 expect(batch.elements.length).to.equal 4
265 expect(batch.elements[0].type).to.equal 'div'
266 expect(batch.elements[1].type).to.equal 'span'
267 expect(batch.elements[2].type).to.equal 'text'
268 expect(batch.elements[3].type).to.equal 'strong'
269 expect(batch.elements[0].text).to.equal 'firstChildText'
270 expect(batch.elements[1].text).to.equal 'secondChildText'
271 expect(batch.elements[2].text).to.include 'textNode'
272 expect(batch.elements[3].text).to.equal 'abc123'
273
274
275 test "Method/Property aliases", ()->
276 div = Dom('div')
277 expect(div.raw).to.equal(div.el)
278 expect(div[0]).to.equal(div.el)
279 expect(div.css).to.equal(div.style)
280 expect(div.replaceWith).to.equal(div.replace)
281 expect(div.removeListener).to.equal(div.off)
282 expect(div.removeListener('eventA'))
283
284
285 test "user-defined methdods/getters/setters", ()->
286 divA = Dom.div()
287 divB = Dom.div methods:
288 scrollTop:
289 get: ()-> @raw.scrollTop
290 weight:
291 get: ()-> @raw.weight
292 value:
293 get: ()-> @raw.value
294 set: (value)-> @raw.value = value
295 name: true
296 bigIndex: ()-> @index * 10
297
298 sandbox.append divA
299 sandbox.append divB
300 divA.raw.value = divB.raw.value = 'abc'
301
302 expect(typeof divA.scrollTop).to.equal 'undefined'
303 expect(typeof divB.scrollTop).to.equal 'number'
304 expect(typeof divA.value).to.equal 'undefined'
305 expect(typeof divB.value).to.equal 'string'
306 expect(typeof divA.name).to.equal 'undefined'
307 expect(typeof divB.name).to.equal 'undefined'
308 expect(typeof divA.bigIndex).to.equal 'undefined'
309 expect(typeof divB.bigIndex).to.equal 'function'
310
311 expect(divB.scrollTop).to.equal divB.raw.scrollTop
312
313 divB.raw.weight = '1'
314 expect(divB.weight).to.equal '1'
315
316 divB.weight = '2'
317 expect(divB.weight).to.equal '1'
318
319 expect(divB.value).to.equal 'abc'
320 divB.value = '123'
321 expect(divB.value).to.equal '123'
322
323 expect(divB.bigIndex()).to.equal divB.index*10
324
325
326 suite "Events", ()->
327 test "Events can be listened to via the .on method", ()->
328 emitCountA = emitCountB = 0
329 div = Dom.div()
330 div.on 'myClick', (event)->
331 expect(typeof event).to.equal 'object'
332 expect(event.type).to.equal 'myClick'
333 emitCountA++
334
335
336 div.el.emitEvent('myClick')
337 expect(emitCountA).to.equal(1)
338 div.el.emitEvent('myClick')
339 expect(emitCountA).to.equal(2)
340
341 div.on 'myClick', (event)-> emitCountB++
342 div.el.emitEvent('myClick')
343 expect(emitCountB).to.equal(1)
344 expect(emitCountA).to.equal(3)
345 div.el.emitEvent('myClick')
346 expect(emitCountB).to.equal(2)
347 expect(emitCountA).to.equal(4)
348
349
350 test "Events can be emitted via the .emit method", ()->
351 emitCountA = emitCountB = 0
352 div = Dom.div()
353 div.on 'myEvent', ()-> emitCountA++
354 div.el.addEventListener 'myEvent', ()-> emitCountB++
355
356 expect(emitCountA).to.equal(0)
357 expect(emitCountB).to.equal(0)
358
359 div.emit('myEvent')
360 expect(emitCountA).to.equal(1)
361 expect(emitCountB).to.equal(1)
362
363 div.el.emitEvent('myEvent')
364 expect(emitCountA).to.equal(2)
365 expect(emitCountB).to.equal(2)
366
367
368 test "Event handlers can be manually invoked with a custom arg via the .emitPrivate method", ()->
369 emitCountA = emitCountB = 0
370 arg = null
371 div = Dom.div()
372 div.on 'myEvent', ()-> emitCountA++; arg = arguments[0]
373 div.el.addEventListener 'myEvent', ()-> emitCountB++
374
375 expect(emitCountA).to.equal(0)
376 expect(emitCountB).to.equal(0)
377 expect(arg).to.equal(null)
378
379 div.emitPrivate('myEvent')
380 expect(emitCountA).to.equal(1)
381 expect(emitCountB).to.equal(0)
382 expect(arg).to.equal(undefined)
383
384 div.emitPrivate('myEvent', 'abc123')
385 expect(emitCountA).to.equal(2)
386 expect(emitCountB).to.equal(0)
387 expect(arg).to.equal('abc123')
388
389 div.el.emitEvent('myEvent')
390 expect(emitCountA).to.equal(3)
391 expect(emitCountB).to.equal(1)
392 expect(arg).not.to.equal('abc123')
393 expect(typeof arg).to.equal('object')
394
395
396 test "Booleans can be passed for the 2nd and 3rd args of .emit to control event.bubbles and event.cancelable", ()->
397 emitCountA = emitCountB = emitCountC = 0
398 div = Dom.div()
399 div.on 'eventA', (event)-> emitCountA++; expect(event.bubbles).to.be.true; expect(event.cancelable).to.be.true
400 div.on 'eventB', (event)-> emitCountB++; expect(event.bubbles).to.be.false; expect(event.cancelable).to.be.true
401 div.on 'eventC', (event)-> emitCountC++; expect(event.bubbles).to.be.false; expect(event.cancelable).to.be.false
402
403 div.emit('eventA'); div.emit('eventB', false); div.emit('eventC', false, false);
404 expect(emitCountA).to.equal(1)
405 expect(emitCountB).to.equal(1)
406 expect(emitCountC).to.equal(1)
407
408
409 test "A data object can be passed as the 4th arg of .emit which will be extended onto the event object", ()->
410 div = DOM.div()
411 event = null
412 div.on 'mousedown', (e)-> event = e
413
414 expect(event).to.equal null
415 div.emit 'mousedown'
416 expect(event.type).to.equal 'mousedown'
417 expect(event.custom).to.equal undefined
418
419 div.emit 'mousedown', null, null, {custom:'custom', abc:123}
420 expect(event.type).to.equal 'mousedown'
421 expect(event.custom).to.equal 'custom'
422 expect(event.abc).to.equal 123
423
424 div.emit 'mousedown', null, null, true
425 expect(event.type).to.equal 'mousedown'
426 expect(event.custom).to.equal undefined
427
428
429 test "Event listeners can be removed via the .off method", ()->
430 emitCountA = emitCountB = emitCountC = emitCountD = 0
431 div = Dom.div()
432 div.on 'myEvent', ()-> emitCountA++
433 div.on 'myEvent', eventCB=()-> emitCountB++
434 div.on 'anotherEvent', ()-> emitCountC++
435 div.el.addEventListener 'myEvent', ()-> emitCountD++
436
437 expect(emitCountA).to.equal(0)
438 expect(emitCountB).to.equal(0)
439 expect(emitCountC).to.equal(0)
440 expect(emitCountD).to.equal(0)
441
442 div.emit('myEvent'); div.emit('anotherEvent');
443 expect(emitCountA).to.equal(1)
444 expect(emitCountB).to.equal(1)
445 expect(emitCountC).to.equal(1)
446 expect(emitCountD).to.equal(1)
447
448 div.off('myEvent', eventCB)
449 div.emit('myEvent'); div.emit('anotherEvent');
450 expect(emitCountA).to.equal(2)
451 expect(emitCountB).to.equal(1)
452 expect(emitCountC).to.equal(2)
453 expect(emitCountD).to.equal(2)
454
455 div.on 'myEvent', ()-> emitCountB++
456 div.off('myEvent')
457 div.emit('myEvent'); div.emit('anotherEvent');
458 expect(emitCountA).to.equal(2)
459 expect(emitCountB).to.equal(1)
460 expect(emitCountC).to.equal(3)
461 expect(emitCountD).to.equal(3)
462
463 div.on 'myEvent', ()-> emitCountA++
464 div.on 'myEvent', ()-> emitCountB++
465 div.off()
466 div.emit('myEvent'); div.emit('anotherEvent');
467 expect(emitCountA).to.equal(2)
468 expect(emitCountB).to.equal(1)
469 expect(emitCountC).to.equal(3)
470 expect(emitCountD).to.equal(4)
471
472
473 test "Events can be named via a '<event>.<name>' syntax which can be used to remove listeners later on without the original callbacks", ()->
474 emitCountA = emitCountB = 0
475 div = Dom.div().appendTo(sandbox)
476
477 attachListeners = ()->
478 div.on 'myEvent.someName', ()-> emitCountA++;
479 div.on 'myEvent', ()-> emitCountB++;
480
481 attachListeners()
482 expect(emitCountA).to.equal(0)
483 expect(emitCountB).to.equal(0)
484
485 div.emit('myEvent')
486 expect(emitCountA).to.equal(1)
487 expect(emitCountB).to.equal(1)
488
489 div.emit('myEvent.someName')
490 expect(emitCountA).to.equal(1)
491 expect(emitCountB).to.equal(1)
492
493 div.off('myEvent.someOtherName')
494 div.emit('myEvent')
495 expect(emitCountA).to.equal(2)
496 expect(emitCountB).to.equal(2)
497
498 div.off('myEvent.someName')
499 div.emit('myEvent')
500 expect(emitCountA).to.equal(2)
501 expect(emitCountB).to.equal(3)
502
503 div.off('myEvent')
504 attachListeners()
505 div.emit('myEvent')
506 expect(emitCountA).to.equal(3)
507 expect(emitCountB).to.equal(4)
508
509 div.off('myEvent')
510 div.emit('myEvent')
511 expect(emitCountA).to.equal(3)
512 expect(emitCountB).to.equal(4)
513
514
515 test "Multiple events can be registered/deregistered at once using whitespace separators", ()->
516 emitCount = 0
517 div = Dom.div()
518
519 div.on 'one two three', ()-> emitCount++
520 expect(emitCount).to.equal 0
521
522 div.emit('one')
523 expect(emitCount).to.equal 1
524
525 div.emit('two')
526 expect(emitCount).to.equal 2
527
528 div.emit('three')
529 expect(emitCount).to.equal 3
530
531 div.off('one three')
532 div.emit('one')
533 expect(emitCount).to.equal 3
534
535 div.emit('two')
536 expect(emitCount).to.equal 4
537
538 div.emit('three')
539 expect(emitCount).to.equal 4
540
541 div.off()
542 div.emit('one'); div.emit('two'); div.emit('three');
543 div.on 'one two three.someName', ()-> emitCount++
544 div.on 'one two three', ()-> emitCount++
545 expect(emitCount).to.equal 4
546
547 div.emit('one')
548 expect(emitCount).to.equal 6
549
550 div.emit('two')
551 expect(emitCount).to.equal 8
552
553 div.emit('three')
554 expect(emitCount).to.equal 10
555
556 div.off('two \tone.someName')
557 div.emit('one')
558 expect(emitCount).to.equal 11
559
560 div.emit('two')
561 expect(emitCount).to.equal 12
562
563 div.emit('three')
564 expect(emitCount).to.equal 14
565
566 div.off('one three')
567 div.emit('one')
568 expect(emitCount).to.equal 14
569
570 div.emit('two')
571 expect(emitCount).to.equal 15
572
573 div.emit('three')
574 expect(emitCount).to.equal 15
575
576
577 test "Events can be listened for once via the .once method", ()->
578 emitCountA = emitCountB = 0
579 div = Dom.div()
580 div.once 'myClick', (event)->
581 expect(typeof event).to.equal 'object'
582 expect(event.type).to.equal 'myClick'
583
584 div.on 'myClick', ()-> emitCountA++
585 div.once 'myClick', ()-> emitCountB++
586
587
588 expect(emitCountA).to.equal(0)
589 expect(emitCountB).to.equal(0)
590
591 div.el.emitEvent('myClick')
592 expect(emitCountA).to.equal(1)
593 expect(emitCountB).to.equal(1)
594
595 div.el.emitEvent('myClick')
596 expect(emitCountA).to.equal(2)
597 expect(emitCountB).to.equal(1)
598
599 div.once 'myClick', (event)-> emitCountB++
600
601 div.el.emitEvent('myClick')
602 expect(emitCountA).to.equal(3)
603 expect(emitCountB).to.equal(2)
604
605 div.el.emitEvent('myClick')
606 expect(emitCountA).to.equal(4)
607 expect(emitCountB).to.equal(2)
608
609
610 test "Pre-defined event listeners can be passed in options.events", ()->
611 emitCount = 0
612 emitContext = null
613 listeners =
614 'one two three': ()-> emitCount++
615 'four': ()-> emitCount++
616 'five': ()-> emitContext = @
617
618 div = Dom.div(events:listeners)
619 expect(emitCount).to.equal 0
620
621 div.emit('one')
622 expect(emitCount).to.equal 1
623
624 div.emit('two')
625 expect(emitCount).to.equal 2
626
627 div.emit('three')
628 expect(emitCount).to.equal 3
629
630 div.emit('four')
631 expect(emitCount).to.equal 4
632
633 div.off('one three')
634 div.emit('one')
635 expect(emitCount).to.equal 4
636
637 div.emit('two')
638 expect(emitCount).to.equal 5
639
640 div.emit('three')
641 expect(emitCount).to.equal 5
642
643 div.emit('five')
644 expect(emitContext).to.equal div
645
646 div.off()
647 div.emit('one'); div.emit('two'); div.emit('three'); div.emit('four');
648 expect(emitCount).to.equal 5
649
650 divB = Dom.div(events:listeners)
651 divB.emit('one'); divB.emit('three')
652 expect(emitCount).to.equal 7
653
654 expect(emitContext).to.equal div
655 divB.emit('five')
656 expect(emitContext).to.equal divB
657
658
659 test "the inserted event will be privately emitted when the element is inserted into the DOM", ()->
660 invokeCount = 0
661 parentA = Dom.section()
662 parentB = Dom.section()
663 masterParentB = Dom.div()
664 parentC = Dom.section().appendTo(sandbox)
665 div = Dom.div()
666
667 div.on 'inserted', (el)->
668 expect(@).to.equal(div)
669 expect(el).to.equal(div.parent)
670 expect(invokeCount++).to.equal(0)
671
672 expect(invokeCount).to.equal(0)
673 div.appendTo(parentA)
674 expect(invokeCount).to.equal(0)
675
676 div.appendTo(parentB.appendTo(masterParentB))
677 expect(invokeCount).to.equal(0)
678
679 parentA.appendTo(sandbox)
680 expect(invokeCount).to.equal(0)
681
682 div.appendTo(parentC)
683 expect(invokeCount).to.equal(1)
684
685 div.detach()
686 div.appendTo(parentB.appendTo(sandbox))
687 expect(invokeCount).to.equal(1)
688 expect(div.parent).to.equal parentB
689
690 div.on 'inserted', ()-> expect(invokeCount++).to.equal(1)
691 expect(invokeCount).to.equal(2)
692 expect(div.parent).to.equal parentB
693
694 div.appendTo(parentC)
695 expect(invokeCount).to.equal(2)
696 expect(div.parent).to.equal parentC
697
698 div.detach()
699 div.appendTo(parentA)
700 div.on 'inserted', ()-> invokeCount++
701 expect(invokeCount).to.equal(3)
702
703 div.detach()
704 div.appendTo(parentB)
705 expect(invokeCount).to.equal(3)
706
707
708 test "QuickElement.replace will trigger the inserted event", ()->
709 invokeCount = 0
710 parent = Dom.section().appendTo(sandbox)
711 A = Dom.div()
712 B = Dom.div()
713
714 B.on 'inserted', (el)->
715 expect(@).to.equal(B)
716 expect(el).to.equal(B.parent)
717 expect(invokeCount++).to.equal(0)
718
719 expect(invokeCount).to.equal 0
720 expect(A.parent).to.equal(undefined)
721 expect(B.parent).to.equal(undefined)
722
723 parent.append(A)
724 expect(invokeCount).to.equal 0
725 expect(A.parent).to.equal(parent)
726 expect(B.parent).to.equal(undefined)
727
728 A.replace(B)
729 expect(invokeCount).to.equal 1
730 expect(A.parent).to.equal(undefined)
731 expect(B.parent).to.equal(parent)
732
733
734
735
736
737
738 suite "Style", ()->
739 test "Styles can be set via the .style/.css method with args pair of [property, value]", ()->
740 div = Dom.div(style:{width:'15px'}).appendTo(sandbox)
741 computedStyle = getComputedStyle(div.el)
742
743 expect(computedStyle.width).to.equal('15px')
744
745 div.style 'width', '25px'
746 expect(div.el.style.width).to.equal('25px')
747 expect(computedStyle.width).to.equal('25px')
748
749 div.style 'width', '5vh'
750 expect(div.el.style.width).to.equal('5vh')
751 expect(computedStyle.width).to.contain('px')
752
753
754 test "Multiple Styles can be set via the .style/.css method by passing a style object", ()->
755 div = Dom.div(style:{width:'15px'}).appendTo(sandbox)
756 computedStyle = getComputedStyle(div.el)
757
758 expect(computedStyle.width).to.equal('15px')
759 expect(computedStyle.height).to.equal('0px')
760
761 div.style {width:25, height:'33'}
762 expect(computedStyle.width).to.equal('25px')
763 expect(computedStyle.height).to.equal('33px')
764
765
766 test "Styles defined in the options object will be applied via classNames and not inline style", ()->
767 divA = Dom.div(style:{width:15, height:30}).appendTo(sandbox)
768 divB = Dom.div().appendTo(sandbox).style {width:15, height:30}
769
770 expect(divA.raw).to.have.style('width', '15px')
771 expect(divB.raw).to.have.style('width', '15px')
772 expect(divA.raw).to.have.style('height', '30px')
773 expect(divB.raw).to.have.style('height', '30px')
774
775 expect(divA.raw.style.width).to.equal ''
776 expect(divB.raw.style.width).to.equal '15px'
777 expect(divA.raw.style.height).to.equal ''
778 expect(divB.raw.style.height).to.equal '30px'
779
780
781 test "If passed a property name without a value, the computed value for that property will be returned", ()->
782 div = Dom.div(style:{width:'15px'}).appendTo(sandbox)
783 computedStyle = getComputedStyle(div.el)
784
785 expect(div.style 'width').to.equal '15px'
786 expect(div.style 'height').to.equal '0px'
787
788 div.style width:null, height: 55
789 expect(div.style 'width').to.equal computedStyle.width
790 expect(div.style 'height').to.equal '55px'
791
792 div.style 'width', '19vw'
793 expect(div.style 'width').to.contain 'px'
794
795
796 test "Functions can be passed as values for properties in style objects which will be invoked with the element's options.relatedInstance as the only argument", ()->
797 div = Dom.div(rate:25).appendTo(sandbox)
798 applyWidth = (expectedInstance)->
799 div.style width: (instance)->
800 expect(typeof instance).to.equal 'object'
801 expect(instance).to.equal(expectedInstance)
802 return div.options.rate
803
804 applyWidth(div)
805 expect(div.options.rate).to.equal 25
806 expect(div.style 'width').to.equal '25px'
807
808 div.options.rate = 250
809 div.related = anotherObj = {}
810 applyWidth(anotherObj)
811 expect(div.style 'width').to.equal '250px'
812
813 div = Dom.div(style:{width:30, height:(->50), fontSize:(->20)}).appendTo(sandbox)
814 expect(div.raw).to.have.style 'width', '30px'
815 expect(div.raw).to.have.style 'height', '50px'
816 expect(div.raw).to.have.style 'fontSize', '20px'
817
818
819 test "A null value can be passed for a property in order to delete that style", ()->
820 div = Dom.div(style:{width:'15px', fontSize: -> 30}).appendTo(sandbox)
821 div.style 'height', 20
822
823 expect(div.el).to.have.style('width', '15px')
824 expect(div.el).to.have.style('height', '20px')
825 expect(div.el.style.width).to.equal ''
826 expect(div.el.style.height).to.equal '20px'
827
828 div.style {width:null, height:12}
829 expect(div.el).not.to.have.style('width', '15px')
830 expect(div.el).to.have.style('height', '12px')
831 expect(['unset','inherit','initial'].some (s)-> s is div.el.style.width).to.be.true
832 expect(div.el.style.height).to.equal '12px'
833
834 div.css 'height', null
835 expect(div.el.style.height).to.equal ''
836 expect(div.el.style.width).not.to.equal ''
837
838 div.el.style.width = null
839 expect(div.el.style.width).to.equal ''
840 expect(div.el).to.have.style('width', '15px')
841
842 div.css 'width', null
843 expect(div.el.style.width).not.to.equal ''
844 expect(div.el).not.to.have.style('width', '15px')
845
846 div.style 'height', -> 30
847 expect(div.el.style.height).to.equal '30px'
848
849 div.style 'height', -> null
850 expect(div.el.style.height).to.equal ''
851
852 expect(div.el.style.fontSize).to.equal '30px'
853 div.style 'fontSize', null
854 expect(div.el.style.fontSize).to.equal ''
855
856
857 test ".styleSafe() can be used to obtain the value for a given property even for non-inserted elements or elements with options.styleAfterInsert", ()->
858 style =
859 width: '8px'
860 height: '9px'
861 zIndex: (field)-> field.options.theIndex
862 $happy:
863 width: '18px'
864 zIndex: (field)-> field.options.theIndex*2
865 $relaxed:
866 height: '100%'
867 divA = Dom.div {style, theIndex:'12'}
868 divB = Dom.div {style, theIndex:'29', styleAfterInsert:true}
869 divA.style fontSize:10, position:'relative'
870 divB.style fontSize:10, position:'relative'
871 prop = (el,target)-> computed:el.style(target), inline:el.raw.style[target], safe:''+el.styleSafe(target)
872
873 expect(prop divA, 'fontSize').to.eql {computed:'', inline:'10px', safe:'10px'}
874 expect(prop divB, 'fontSize').to.eql {computed:'', inline:'10px', safe:'10px'}
875 expect(prop divA, 'width').to.eql {computed:'', inline:'', safe:'8px'}
876 expect(prop divB, 'width').to.eql {computed:'', inline:'', safe:'8px'}
877 expect(prop divA, 'height').to.eql {computed:'', inline:'', safe:'9px'}
878 expect(prop divB, 'height').to.eql {computed:'', inline:'', safe:'9px'}
879 expect(prop divA, 'zIndex').to.eql {computed:'', inline:'12', safe:'12'}
880 expect(prop divB, 'zIndex').to.eql {computed:'', inline:'', safe:'29'}
881
882 divA.state 'happy', on
883 divB.state 'happy', on
884 expect(prop divA, 'width').to.eql {computed:'', inline:'', safe:'18px'}
885 expect(prop divB, 'width').to.eql {computed:'', inline:'', safe:'18px'}
886 expect(prop divA, 'zIndex').to.eql {computed:'', inline:'24', safe:'24'}
887 expect(prop divB, 'zIndex').to.eql {computed:'', inline:'', safe:'58'}
888
889 divA.state 'relaxed', on
890 divB.state 'relaxed', on
891 expect(prop divA, 'height').to.eql {computed:'', inline:'', safe:'100%'}
892 expect(prop divB, 'height').to.eql {computed:'', inline:'', safe:'100%'}
893
894 divA.appendTo(sandbox)
895 divB.appendTo(sandbox)
896 heightA = getComputedStyle(divA.raw).height
897 heightB = getComputedStyle(divB.raw).height
898 expect(prop divA, 'zIndex').to.eql {computed:'24', inline:'24', safe:'24'}
899 expect(prop divB, 'zIndex').to.eql {computed:'58', inline:'58', safe:'58'}
900 expect(prop divA, 'height').to.eql {computed:heightA, inline:'', safe:heightA}
901 expect(prop divB, 'height').to.eql {computed:heightB, inline:'', safe:heightB}
902
903 expect(divA.styleSafe 'height').to.equal heightA
904 expect(divA.styleSafe 'height', true).to.equal '100%'
905 expect(divB.styleSafe 'height').to.equal heightB
906 expect(divB.styleSafe 'height', true).to.equal '100%'
907
908 divB.appendTo(sandbox)
909 expect(divB.style('height')).not.to.equal('')
910 expect(divB.style('height')).not.to.equal('100%')
911 expect(divB.style('height')).to.contain('px')
912 expect(divB.styleSafe('height')).to.equal(divB.style('height'))
913 expect(divB.styleSafe('height', true)).not.to.equal(divB.style('height'))
914 expect(divB.styleSafe('height', true)).to.equal('100%')
915 expect(divB.styleSafe('margin', true)).to.equal('')
916 expect(divB.style('width')).to.equal('18px')
917
918 expect(divA.styleSafe('fakeProp')).to.equal(divA)
919 expect(divA.styleSafe(123)).to.equal(divA)
920
921 text = Dom.text('abc123').appendTo(divA)
922 expect(text.styleSafe('fakeProp')).to.equal(undefined)
923 expect(text.styleSafe(123)).to.equal(undefined)
924
925
926 test ".styleSafe() will work with instances with no given base styles", ()->
927 divA = Dom.div()
928 divB = Dom(document.createElement 'div')
929
930 expect ()->
931 divA.styleSafe('height')
932 divB.styleSafe('height')
933 .not.to.throw()
934
935 expect(divA.styleSafe 'height').to.equal ''
936 expect(divB.styleSafe 'height').to.equal ''
937
938
939 test ".styleParsed() is a shorthand for parseFloat(.styleSafe())", ()->
940 style =
941 width: '8px'
942 height: '9px'
943 $happy:
944 width: '18px'
945 $relaxed:
946 height: '100%'
947 divA = Dom.div {style}
948 divB = Dom.div {style, styleAfterInsert:true}
949
950 expect(divA.style('width')).to.equal('')
951 expect(divA.styleSafe('width')).to.equal('8px')
952 expect(divA.styleParsed('width')).to.equal(parseFloat divA.styleSafe('width'))
953
954 expect(divA.style('height')).to.equal('')
955 expect(divA.styleSafe('height')).to.equal('9px')
956 expect(divA.styleParsed('height')).to.equal(parseFloat divA.styleSafe('height'))
957
958 expect(divB.style('width')).to.equal('')
959 expect(divB.styleSafe('width')).to.equal('8px')
960 expect(divB.styleParsed('width')).to.equal(parseFloat divB.styleSafe('width'))
961
962 divA.state 'happy', on
963 divB.state 'happy', on
964 expect(divA.style('width')).to.equal('')
965 expect(divA.styleSafe('width')).to.equal('18px')
966 expect(divA.styleParsed('width')).to.equal(parseFloat divA.styleSafe('width'))
967
968 expect(divA.style('height')).to.equal('')
969 expect(divA.styleSafe('height')).to.equal('9px')
970 expect(divA.styleParsed('height')).to.equal(parseFloat divA.styleSafe('height'))
971
972 expect(divB.style('width')).to.equal('')
973 expect(divB.styleSafe('width')).to.equal('18px')
974 expect(divB.styleParsed('width')).to.equal(parseFloat divB.styleSafe('width'))
975
976 divA.state 'relaxed', on
977 divB.state 'relaxed', on
978 expect(divA.style('width')).to.equal('')
979 expect(divA.styleSafe('width')).to.equal('18px')
980 expect(divA.styleParsed('width')).to.equal(parseFloat divA.styleSafe('width'))
981
982 expect(divA.style('height')).to.equal('')
983 expect(divA.styleSafe('height')).to.equal('100%')
984 expect(divA.styleParsed('height')).to.equal(parseFloat divA.styleSafe('height'))
985
986 expect(divB.style('width')).to.equal('')
987 expect(divB.styleSafe('width')).to.equal('18px')
988 expect(divB.styleParsed('width')).to.equal(parseFloat divB.styleSafe('width'))
989
990 divA.appendTo(sandbox)
991 divB.appendTo(sandbox)
992 divA.state 'relaxed', off
993 divB.state 'relaxed', off
994 expect(divA.style('width')).to.equal('18px')
995 expect(divA.styleSafe('width')).to.equal('18px')
996 expect(divA.styleParsed('width')).to.equal(parseFloat divA.styleSafe('width'))
997
998 expect(divA.style('height')).to.equal('9px')
999 expect(divA.styleSafe('height')).to.equal('9px')
1000 expect(divA.styleParsed('height')).to.equal(parseFloat divA.styleSafe('height'))
1001
1002 expect(divB.style('width')).to.equal('18px')
1003 expect(divB.styleSafe('width')).to.equal('18px')
1004 expect(divB.styleParsed('width')).to.equal(parseFloat divB.styleSafe('width'))
1005
1006
1007 test ".recalcStyle() re-applies all function-value styles", ()->
1008 count = A:0,B:0,C:0,D:0,E:0,F:0,G:0
1009 div = Dom.div style:
1010 width: ()-> ++count.A
1011 opacity: 1
1012 height: ()-> ++count.B
1013 fontSize: ()-> ++count.C
1014 $happy:
1015 opacity: 0.5
1016 fontSize: ()-> ++count.D
1017 $relaxed:
1018 height: ()-> ++count.E
1019 fontSize: ()-> ++count.F
1020 $funny:
1021 width: ()-> ++count.G
1022
1023 expect(count).to.eql A:1,B:1,C:1,D:0,E:0,F:0,G:0
1024
1025 div.recalcStyle()
1026 expect(count).to.eql A:2,B:2,C:2,D:0,E:0,F:0,G:0
1027
1028 div.state 'happy', on
1029 expect(count).to.eql A:2,B:2,C:2,D:1,E:0,F:0,G:0
1030
1031 div.recalcStyle()
1032 expect(count).to.eql A:3,B:3,C:2,D:2,E:0,F:0,G:0
1033
1034 div.state 'relaxed', on
1035 expect(count).to.eql A:3,B:3,C:2,D:2,E:1,F:1,G:0
1036
1037 div.recalcStyle()
1038 expect(count).to.eql A:4,B:3,C:2,D:2,E:2,F:2,G:0
1039
1040 div.state 'funny', on
1041 expect(count).to.eql A:4,B:3,C:2,D:2,E:2,F:2,G:1
1042
1043 div.recalcStyle()
1044 expect(count).to.eql A:4,B:3,C:2,D:2,E:3,F:3,G:2
1045
1046 div.state 'funny', off
1047 expect(count).to.eql A:5,B:3,C:2,D:2,E:3,F:3,G:2
1048
1049 div.recalcStyle()
1050 expect(count).to.eql A:6,B:3,C:2,D:2,E:4,F:4,G:2
1051
1052
1053 test ".recalcStyle() accepts a single argument to indicate if to recalc style on children", ()->
1054 count = A:0,B:0,C:0,D:0,E:0,F:0,G:0
1055 wrapperCount = 0
1056 wrapper = Dom.div style:
1057 width: ()-> ++wrapperCount
1058
1059 div = Dom.div style:
1060 width: ()-> ++count.A
1061 opacity: 1
1062 height: ()-> ++count.B
1063 fontSize: ()-> ++count.C
1064 $happy:
1065 opacity: 0.5
1066 fontSize: ()-> ++count.D
1067 $relaxed:
1068 height: ()-> ++count.E
1069 fontSize: ()-> ++count.F
1070 $funny:
1071 width: ()-> ++count.G
1072
1073 div.appendTo(wrapper)
1074 expect(wrapperCount).to.equal 1
1075 expect(count).to.eql A:1,B:1,C:1,D:0,E:0,F:0,G:0
1076
1077 wrapper.recalcStyle()
1078 expect(wrapperCount).to.equal 2
1079 expect(count).to.eql A:1,B:1,C:1,D:0,E:0,F:0,G:0
1080
1081 wrapper.recalcStyle(true)
1082 expect(wrapperCount).to.equal 3
1083 expect(count).to.eql A:2,B:2,C:2,D:0,E:0,F:0,G:0
1084
1085 div.state 'happy', on
1086 expect(count).to.eql A:2,B:2,C:2,D:1,E:0,F:0,G:0
1087
1088 wrapper.recalcStyle()
1089 expect(wrapperCount).to.equal 4
1090 expect(count).to.eql A:2,B:2,C:2,D:1,E:0,F:0,G:0
1091
1092 wrapper.recalcStyle(1)
1093 expect(wrapperCount).to.equal 5
1094 expect(count).to.eql A:3,B:3,C:2,D:2,E:0,F:0,G:0
1095
1096
1097 test "If options.recalcOnResize is set, .recalcStyle() will be invoked on each resize event", ()->
1098 count = A:0,B:0,C:0,D:0
1099 Dom.div
1100 style:
1101 width: ()-> ++count.A
1102 opacity: 1
1103 height: ()-> ++count.B
1104
1105 Dom.div
1106 recalcOnResize: true
1107 style:
1108 width: ()-> ++count.C
1109 opacity: 1
1110 height: ()-> ++count.D
1111
1112 expect(count).to.eql A:1,B:1,C:1,D:1
1113
1114 Dom(window).emit 'resize'
1115 expect(count).to.eql A:1,B:1,C:2,D:2
1116
1117 Dom(window).emit 'resize'
1118 expect(count).to.eql A:1,B:1,C:3,D:3
1119
1120
1121 test "If options.forceStyle is set, all registered styles will have the '!important' flag set", ()->
1122 style = DOM.style(props:innerHTML:".theDiv {width:50px}")
1123 divA = DOM.div(className:'theDiv', style:{width:100, height:100}).appendTo(sandbox)
1124 divB = DOM.div(className:'theDiv', style:{width:100, height:100}, forceStyle:true).appendTo(sandbox)
1125
1126 expect(divA.style 'width').to.equal '100px'
1127 expect(divB.style 'width').to.equal '100px'
1128
1129 style.appendTo(document.head)
1130 expect(divA.style 'width').to.equal '50px'
1131 expect(divB.style 'width').to.equal '100px'
1132
1133 expect(divA.attr('style') is '' or divA.attr('style') is null).to.be.true
1134 expect(divB.attr('style') is '' or divB.attr('style') is null).to.be.true
1135
1136 divA.style 'width', ()-> 75
1137 divB.style 'width', ()-> 75
1138 divA.style 'height', 85
1139 divB.style 'height', 85
1140 expect(divA.attr 'style').not.to.equal ''
1141 expect(divB.attr 'style').not.to.equal ''
1142 expect(divA.attr 'style').not.to.include '75px !important'
1143 expect(divB.attr 'style').to.include '75px !important'
1144 expect(divA.attr 'style').not.to.include '85px !important'
1145 expect(divB.attr 'style').to.include '85px !important'
1146 expect(divA.style 'width').to.equal '75px'
1147 expect(divB.style 'width').to.equal '75px'
1148 style.remove()
1149
1150
1151 test ".show()/.hide() will toggle the element's visibility", ()->
1152 div = Dom.div().appendTo sandbox
1153 expect(div.style('display')).to.equal 'block'
1154
1155 div.hide()
1156 expect(div.style('display')).to.equal 'none'
1157
1158 div.show()
1159 expect(div.style('display')).to.equal 'block'
1160
1161 div.show()
1162 expect(div.style('display')).to.equal 'block'
1163
1164
1165 test ".show() will set the element's display style to the provided argument, or to the value provided in the style object", ()->
1166 div = Dom.div(style:display:'inline').appendTo sandbox
1167 expect(div.style('display')).to.equal 'inline'
1168
1169 div.hide()
1170 expect(div.style('display')).to.equal 'none'
1171
1172 div.show()
1173 expect(div.style('display')).to.equal 'inline'
1174
1175 div.hide()
1176 div.show('inline-block')
1177 expect(div.style('display')).to.equal 'inline-block'
1178
1179
1180 test "SVG elements", ()->
1181 svg = Dom(
1182 ['*svg'
1183 style:
1184 display: 'block'
1185 width: 10
1186 height: 10
1187 $happy:
1188 width: 20
1189 height: 20
1190 ]
1191 ).appendTo(sandbox)
1192
1193 expect(svg.style 'width').to.equal '10px'
1194 expect(svg.style 'height').to.equal '10px'
1195
1196 svg.state 'happy', on
1197 expect(svg.style 'width').to.equal '20px'
1198 expect(svg.style 'height').to.equal '20px'
1199
1200
1201
1202
1203 suite "State", ()->
1204 test "States can be polled for a value by passing only the target state's name to .state & can be toggled on/off by passing a second argument", ()->
1205 div = Dom.div()
1206
1207 expect(div.state 'funny').to.be.false
1208
1209 div.state 'funny', true
1210 expect(div.state 'funny').to.be.true
1211
1212 div.state 'happy', true
1213 div.state 'relaxed', true
1214 expect(div.state 'funny').to.be.true
1215 expect(div.state 'happy').to.be.true
1216 expect(div.state 'relaxed').to.be.true
1217
1218 div.state 'funny', false
1219 expect(div.state 'funny').to.be.false
1220 expect(div.state 'happy').to.be.true
1221 expect(div.state 'relaxed').to.be.true
1222
1223 div.state '$funny', true
1224 div.state '$base', true
1225 expect(div.state 'funny').to.be.true
1226 expect(div.state 'base').to.be.false
1227
1228
1229 test "A key:value pair object can be passed to toggle state for multiple states at once", ()->
1230 div = Dom.div()
1231
1232 expect(div.state 'a').to.equal false
1233 expect(div.state 'b').to.equal false
1234 expect(div.state 'c').to.equal false
1235
1236 div.state a:true,b:1
1237 expect(div.state 'a').to.equal true
1238 expect(div.state 'b').to.equal true
1239 expect(div.state 'c').to.equal false
1240
1241 div.state b:false,c:'y'
1242 expect(div.state 'a').to.equal true
1243 expect(div.state 'b').to.equal false
1244 expect(div.state 'c').to.equal true
1245
1246
1247 test ".state() without arguments should return an array of active states", ()->
1248 el = DOM.div()
1249 expect(el.state()).to.eql []
1250
1251 el.state 'happy', on
1252 el.state 'relaxed', on
1253 expect(el.state()).to.eql ['happy','relaxed']
1254
1255 el.state 'happy', off
1256 expect(el.state()).to.eql ['relaxed']
1257
1258 el.state 'happy', on
1259 expect(el.state()).to.eql ['relaxed','happy']
1260
1261
1262 test "All states can be cleared/toggled off via .resetState", ()->
1263 div = Dom.div()
1264
1265 div.state 'funny', on
1266 div.state 'happy', on
1267 div.state 'relaxed', on
1268 expect(div.state 'funny').to.be.true
1269 expect(div.state 'happy').to.be.true
1270 expect(div.state 'relaxed').to.be.true
1271
1272 div.resetState()
1273 expect(div.state 'funny').to.be.false
1274 expect(div.state 'happy').to.be.false
1275 expect(div.state 'relaxed').to.be.false
1276
1277
1278 test "A state can be toggled on/off via .toggleState", ()->
1279 div = DOM.div()
1280 expect(div.state 'happy').to.equal off
1281
1282 div.toggleState('happy')
1283 expect(div.state 'happy').to.equal on
1284
1285 div.toggleState('happy')
1286 expect(div.state 'happy').to.equal off
1287
1288 div.toggleState('happy')
1289 expect(div.state 'happy').to.equal on
1290
1291
1292 test "Styles can be passed under specific states using a '$' prefix before the state name", ()->
1293 div = Dom.div style:
1294 $base:
1295 width: '15px'
1296 height: '15px'
1297 $happy:
1298 width: '25px'
1299 marginTop: '20px'
1300 $relaxed:
1301 width: '35px'
1302 marginLeft: '12px'
1303
1304 div.appendTo(sandbox)
1305 computedStyle = getComputedStyle(div.el)
1306 expect(computedStyle.width).to.equal('15px')
1307 expect(computedStyle.height).to.equal('15px')
1308 expect(computedStyle.marginTop).to.equal('0px')
1309 expect(computedStyle.marginLeft).to.equal('0px')
1310
1311 div.state 'happy', on
1312 expect(computedStyle.width).to.equal('25px')
1313 expect(computedStyle.height).to.equal('15px')
1314 expect(computedStyle.marginTop).to.equal('20px')
1315 expect(computedStyle.marginLeft).to.equal('0px')
1316
1317 div.state 'happy', off
1318 expect(computedStyle.width).to.equal('15px')
1319 expect(computedStyle.height).to.equal('15px')
1320 expect(computedStyle.marginTop).to.equal('0px')
1321 expect(computedStyle.marginLeft).to.equal('0px')
1322
1323 div.state 'happy', on
1324 div.state 'relaxed', on
1325 expect(computedStyle.width).to.equal('35px')
1326 expect(computedStyle.height).to.equal('15px')
1327 expect(computedStyle.marginTop).to.equal('20px')
1328 expect(computedStyle.marginLeft).to.equal('12px')
1329
1330 div.state 'happy', off
1331 expect(computedStyle.width).to.equal('35px')
1332 expect(computedStyle.height).to.equal('15px')
1333 expect(computedStyle.marginTop).to.equal('0px')
1334 expect(computedStyle.marginLeft).to.equal('12px')
1335
1336
1337 test "A state:eventName (or state:eventOpts) map can be passed set for options.stateTriggers", ()->
1338 div = Dom.div(
1339 stateTriggers:
1340 happy: {on:'becameHappy', off:'becameSad'}
1341 relaxed: 'isRelaxed'
1342 style:
1343 $base: width: '15px'
1344 $happy: width: '25px'
1345 $relaxed: width: '35px'
1346 ).appendTo(sandbox)
1347 computedStyle = getComputedStyle(div.el)
1348
1349 expect(div.state 'happy').to.be.false
1350 expect(div.state 'relaxed').to.be.false
1351 expect(computedStyle.width).to.equal('15px')
1352
1353 div.emit('becameHappy')
1354 expect(div.state 'happy').to.be.true
1355 expect(div.state 'relaxed').to.be.false
1356 expect(computedStyle.width).to.equal('25px')
1357
1358 div.emit('isRelaxed')
1359 expect(div.state 'happy').to.be.true
1360 expect(div.state 'relaxed').to.be.true
1361 expect(computedStyle.width).to.equal('35px')
1362
1363 div.emit('becameSad')
1364 expect(div.state 'happy').to.be.false
1365 expect(div.state 'relaxed').to.be.true
1366 expect(computedStyle.width).to.equal('35px')
1367
1368 div.state('relaxed', off)
1369 expect(computedStyle.width).to.equal('15px')
1370
1371
1372 test "options.stateTriggers won't be attached if they aren't being used in style object", ()->
1373 divA = Dom.div(style:{$hover: display:'block'})
1374 divB = Dom.div(style:{$focus: display:'block'})
1375
1376 expect(divA.state 'hover').to.equal off
1377 expect(divB.state 'hover').to.equal off
1378
1379 divA.el.emitEvent 'mouseenter'
1380 divB.el.emitEvent 'mouseenter'
1381 expect(divA.state 'hover').to.equal on
1382 expect(divB.state 'hover').to.equal off
1383
1384 divA.el.emitEvent 'mouseleave'
1385 divB.el.emitEvent 'mouseleave'
1386 expect(divA.state 'hover').to.equal off
1387 expect(divB.state 'hover').to.equal off
1388
1389 divA.el.emitEvent 'focus'
1390 divB.el.emitEvent 'focus'
1391 expect(divA.state 'focus').to.equal off
1392 expect(divB.state 'focus').to.equal on
1393
1394 divA.el.emitEvent 'blur'
1395 divB.el.emitEvent 'blur'
1396 expect(divA.state 'focus').to.equal off
1397 expect(divB.state 'focus').to.equal off
1398
1399
1400 test "options.stateTriggers can be forced to be attached even if they aren't being used in style object via ._attachStateEvents(true)", ()->
1401 attachStateEvents = if Dom.div()._attachStateEvents then '_attachStateEvents' else '_ae'
1402 divA = Dom.div(style:{$hover: display:'block'})
1403 divB = Dom.div(style:{$focus: display:'block'})
1404 divA[attachStateEvents](true)
1405 divB[attachStateEvents](true)
1406
1407 expect(divA.state 'hover').to.equal off
1408 expect(divB.state 'hover').to.equal off
1409
1410 divA.el.emitEvent 'mouseenter'
1411 divB.el.emitEvent 'mouseenter'
1412 expect(divA.state 'hover').to.equal on
1413 expect(divB.state 'hover').to.equal on
1414
1415 divA.el.emitEvent 'mouseleave'
1416 divB.el.emitEvent 'mouseleave'
1417 expect(divA.state 'hover').to.equal off
1418 expect(divB.state 'hover').to.equal off
1419
1420 divA.el.emitEvent 'focus'
1421 divB.el.emitEvent 'focus'
1422 expect(divA.state 'focus').to.equal on
1423 expect(divB.state 'focus').to.equal on
1424
1425 divA.el.emitEvent 'blur'
1426 divB.el.emitEvent 'blur'
1427 expect(divA.state 'focus').to.equal off
1428 expect(divB.state 'focus').to.equal off
1429
1430
1431 test "The hover and focus states will be listened for and toggled by default by their appropriate events", ()->
1432 div = Dom.div style:
1433 $base:
1434 width: '15px'
1435 height: '15px'
1436 backgroundColor: 'rgb(45, 45, 45)'
1437 $hover:
1438 width: '25px'
1439 marginTop: '20px'
1440 backgroundColor: 'rgb(155, 155, 155)'
1441 $focus:
1442 width: '35px'
1443 backgroundColor: 'rgb(200, 200, 200)'
1444
1445 div.appendTo(sandbox)
1446 expect(div.el).to.have.style('width', '15px')
1447 expect(div.el).to.have.style('height', '15px')
1448 expect(div.el).to.have.style('marginTop', '0px')
1449 expect(div.el).to.have.style('backgroundColor', 'rgb(45, 45, 45)')
1450 expect(div.el.style.marginTop).to.equal('')
1451
1452 div.emit 'mouseenter'
1453 expect(div.el).to.have.style('width', '25px')
1454 expect(div.el).to.have.style('height', '15px')
1455 expect(div.el).to.have.style('marginTop', '20px')
1456 expect(div.el).to.have.style('backgroundColor', 'rgb(155, 155, 155)')
1457 expect(div.el.style.marginTop).to.equal('')
1458
1459 div.emit 'mouseleave'
1460 expect(div.el).to.have.style('width', '15px')
1461 expect(div.el).to.have.style('height', '15px')
1462 expect(div.el).to.have.style('marginTop', '0px')
1463 expect(div.el).to.have.style('backgroundColor', 'rgb(45, 45, 45)')
1464 expect(div.el.style.marginTop).to.equal('')
1465
1466 div.emit 'mouseenter'
1467 div.emit 'focus'
1468 expect(div.el).to.have.style('width', '35px')
1469 expect(div.el).to.have.style('height', '15px')
1470 expect(div.el).to.have.style('marginTop', '20px')
1471 expect(div.el).to.have.style('backgroundColor', 'rgb(200, 200, 200)')
1472 expect(div.el.style.marginTop).to.equal('')
1473
1474 div.emit 'mouseleave'
1475 expect(div.el).to.have.style('width', '35px')
1476 expect(div.el).to.have.style('height', '15px')
1477 expect(div.el).to.have.style('marginTop', '0px')
1478 expect(div.el).to.have.style('backgroundColor', 'rgb(200, 200, 200)')
1479 expect(div.el.style.marginTop).to.equal('')
1480
1481
1482 test "If not passed a style map under the 'base' state, all non-state properties on the style object will be considered as 'base' state properties", ()->
1483 div = Dom.div style:
1484 width: '15px'
1485 height: '20px'
1486 $hover:
1487 width: '25px'
1488 height: '30px'
1489
1490 div.appendTo(sandbox)
1491 computedStyle = getComputedStyle(div.el)
1492 expect(computedStyle.width).to.equal('15px')
1493 expect(computedStyle.height).to.equal('20px')
1494
1495 div.emit 'mouseenter'
1496 expect(computedStyle.width).to.equal('25px')
1497 expect(computedStyle.height).to.equal('30px')
1498
1499 div.emit 'mouseleave'
1500 expect(computedStyle.width).to.equal('15px')
1501 expect(computedStyle.height).to.equal('20px')
1502
1503
1504 test "State-specific styles will be removed upon state turn off or restored to the base value", ()->
1505 div = Dom.div style:
1506 width: '15px'
1507 $hover:
1508 width: '25px'
1509 height: '30px'
1510
1511 div.appendTo(sandbox)
1512 computedStyle = getComputedStyle(div.el)
1513 expect(div.el).to.have.style('width', '15px')
1514 expect(div.el).to.have.style('height', '0px')
1515 expect(div.el.style.height).to.equal('')
1516
1517 div.emit 'mouseenter'
1518 expect(div.el).to.have.style('width', '25px')
1519 expect(div.el).to.have.style('height', '30px')
1520 expect(div.el.style.height).to.equal('')
1521
1522 div.emit 'mouseleave'
1523 expect(div.el).to.have.style('width', '15px')
1524 expect(div.el).to.have.style('height', '0px')
1525 expect(div.el.style.height).to.equal('')
1526
1527
1528 test "Higher order state styles will have a higher precedence than the 'base' style to be used as replacments for pending-removal state-styles", ()->
1529 div = Dom.div style:
1530 width: '15px'
1531 $hover:
1532 width: '25px'
1533 height: '30px'
1534 $focus:
1535 height: '45px'
1536
1537 div.appendTo(sandbox)
1538 computedStyle = getComputedStyle(div.el)
1539 expect(computedStyle.width).to.equal('15px')
1540 expect(computedStyle.height).to.equal('0px')
1541
1542 div.emit 'mouseenter'
1543 expect(computedStyle.width).to.equal('25px')
1544 expect(computedStyle.height).to.equal('30px')
1545
1546 div.emit 'focus'
1547 expect(computedStyle.width).to.equal('25px')
1548 expect(computedStyle.height).to.equal('45px')
1549
1550 div.emit 'mouseleave'
1551 expect(computedStyle.width).to.equal('15px')
1552 expect(computedStyle.height).to.equal('45px')
1553
1554 div.emit 'blur'
1555 div.emit 'focus'
1556 div.emit 'mouseenter'
1557 expect(computedStyle.width).to.equal('25px')
1558 expect(computedStyle.height).to.equal('45px')
1559
1560 div.emit 'blur'
1561 expect(computedStyle.width).to.equal('25px')
1562 expect(computedStyle.height).to.equal('30px')
1563
1564
1565 test "State toggles will be passed to children elements unless options.passStateToChildren is off", ()->
1566 Main = Dom.div()
1567 A = Dom.div().appendTo(Main)
1568 B = Dom.div().appendTo(A)
1569 C = Dom.div(passStateToChildren:false).appendTo(A)
1570
1571 expect(Main.state 'happy').to.be.false
1572 expect(A.state 'happy').to.be.false
1573 expect(B.state 'happy').to.be.false
1574 expect(C.state 'happy').to.be.false
1575
1576 Main.state 'happy', on
1577 expect(Main.state 'happy').to.be.true
1578 expect(A.state 'happy').to.be.true
1579 expect(B.state 'happy').to.be.true
1580 expect(C.state 'happy').to.be.true
1581
1582 Main.options.passStateToChildren = false
1583 Main.state 'happy', false
1584 expect(Main.state 'happy').to.be.false
1585 expect(A.state 'happy').to.be.true
1586 expect(B.state 'happy').to.be.true
1587 expect(C.state 'happy').to.be.true
1588
1589 Main.state 'happy', on
1590 Main.options.passStateToChildren = true
1591 A.options.passStateToChildren = false
1592 Main.state 'happy', false
1593 expect(Main.state 'happy').to.be.false
1594 expect(A.state 'happy').to.be.false
1595 expect(B.state 'happy').to.be.true
1596 expect(C.state 'happy').to.be.true
1597
1598
1599 test "State styles can be nested to trigger when all states are toggled on", ()->
1600 div = Dom.div style:
1601 $base:
1602 width: '12px'
1603 height: '12px'
1604 fontSize: '10px'
1605 $funny:
1606 fontSize: '15px'
1607 height: '15px'
1608 # width: '10px'
1609 $happy:
1610 width: '14px'
1611 fontSize: '14px'
1612 $relaxed:
1613 height: '11px'
1614 fontSize: '17px'
1615 $funny:
1616 width: '10px'
1617 height: '14px'
1618 $relaxed:
1619 width: '17px'
1620
1621 div.appendTo(sandbox)
1622 expect(div.style 'width').to.equal('12px')
1623 expect(div.style 'height').to.equal('12px')
1624 expect(div.style 'fontSize').to.equal('10px')
1625
1626 div.state 'funny', on
1627 expect(div.style 'width').to.equal('12px')
1628 expect(div.style 'height').to.equal('15px')
1629 expect(div.style 'fontSize').to.equal('15px')
1630
1631 div.state 'funny', off
1632 expect(div.style 'width').to.equal('12px')
1633 expect(div.style 'height').to.equal('12px')
1634 expect(div.style 'fontSize').to.equal('10px')
1635
1636 div.state 'happy', on
1637 expect(div.style 'width').to.equal('14px')
1638 expect(div.style 'height').to.equal('12px')
1639 expect(div.style 'fontSize').to.equal('14px')
1640
1641 div.state 'relaxed', on
1642 expect(div.style 'width').to.equal('17px')
1643 expect(div.style 'height').to.equal('11px')
1644 expect(div.style 'fontSize').to.equal('17px')
1645
1646 div.state 'happy', off
1647 expect(div.style 'width').to.equal('17px')
1648 expect(div.style 'height').to.equal('12px')
1649 expect(div.style 'fontSize').to.equal('10px')
1650
1651 div.state 'happy', on
1652 expect(div.style 'width').to.equal('17px')
1653 expect(div.style 'height').to.equal('11px')
1654 expect(div.style 'fontSize').to.equal('17px')
1655
1656 div.state 'funny', on
1657 expect(div.style 'width').to.equal('10px')
1658 expect(div.style 'height').to.equal('14px')
1659 expect(div.style 'fontSize').to.equal('17px')
1660
1661 div.state 'happy', off
1662 expect(div.style 'width').to.equal('17px')
1663 expect(div.style 'height').to.equal('15px')
1664 expect(div.style 'fontSize').to.equal('15px')
1665
1666
1667 test "QuickElement.rect should contain an updated version of the element's ClientRect", ()->
1668 div = Dom.div().appendTo(sandbox)
1669 rectA = div.rect
1670 rectB = div.rect
1671
1672 expect(rectA).to.be.instanceOf(ClientRect)
1673 expect(rectB).to.be.instanceOf(ClientRect)
1674 expect(rectA).to.eql(rectB)
1675
1676
1677 div.style 'width', '7px'
1678 rectC = div.rect
1679 expect(rectC).to.be.instanceOf(ClientRect)
1680 expect(rectA).to.eql(rectB)
1681 expect(rectA).not.to.eql(rectC)
1682 expect(rectA.width).not.to.equal(7)
1683 expect(rectB.width).not.to.equal(7)
1684 expect(rectC.width).to.equal(7)
1685
1686
1687 test "QuickElement.width should return the updated version of an element's computed width", ()->
1688 parent = Dom.div().appendTo(sandbox)
1689 div = Dom.div().appendTo(parent)
1690
1691 parent.style width:'1000px'
1692 div.style width:'50%'
1693 expect(div.width).to.equal(500)
1694
1695 div.style width:'10%'
1696 expect(div.width).to.equal(100)
1697
1698 div.style width:'97px'
1699 expect(div.width).to.equal(97)
1700
1701
1702 test "QuickElement.height should return the updated version of an element's computed height", ()->
1703 parent = Dom.div().appendTo(sandbox)
1704 div = Dom.div().appendTo(parent)
1705
1706 parent.style height:'1000px'
1707 div.style height:'50%'
1708 expect(div.height).to.equal(500)
1709
1710 div.style height:'10%'
1711 expect(div.height).to.equal(100)
1712
1713 div.style height:'97px'
1714 expect(div.height).to.equal(97)
1715
1716
1717 test "QuickElement.width/.height setters are shortcuts for .style() setters", ()->
1718 parent = Dom.div().appendTo(sandbox)
1719 div = Dom.div().appendTo(parent)
1720
1721 parent.style width:'1000px', height:'1000px'
1722 div.style width:'50%', height:'50%'
1723 div.width = div.height = '50%'
1724 expect(div.width).to.equal(500)
1725 expect(div.height).to.equal(500)
1726
1727 div.width = div.height = '10%'
1728 expect(div.width).to.equal(100)
1729 expect(div.height).to.equal(100)
1730
1731 div.width = div.height = '97px'
1732 expect(div.width).to.equal(97)
1733 expect(div.height).to.equal(97)
1734
1735
1736 test "QuickElement.orientation should return the updated version of an element's computed orientation", ()->
1737 parent = Dom.div().appendTo(sandbox)
1738 div = Dom.div().appendTo(parent)
1739
1740 div.style width:500, height:400
1741 expect(div.orientation).to.equal('landscape')
1742
1743 div.style width:550, height:600
1744 expect(div.orientation).to.equal('portrait')
1745
1746 div.style width:600, height:600
1747 expect(div.orientation).to.equal('portrait')
1748
1749 div.style width:601, height:600
1750 expect(div.orientation).to.equal('landscape')
1751
1752
1753 test "QuickElement.aspectRatio should return the updated version of an element's computed aspect-ratio", ()->
1754 parent = Dom.div().appendTo(sandbox)
1755 div = Dom.div().appendTo(parent)
1756
1757 div.style width:500, height:400
1758 expect(div.aspectRatio).to.equal(1.25)
1759
1760 div.style width:540, height:600
1761 expect(div.aspectRatio).to.equal(0.9)
1762
1763 div.style width:600, height:600
1764 expect(div.aspectRatio).to.equal(1)
1765
1766 div.style width:300, height:900
1767 expect(div.aspectRatio).to.equal(0.33333333333333333333333333)
1768
1769
1770 test "If options.styleAfterInsert is passed, function styles will be applied only after the element is inserted into the DOM", ()->
1771 parentOpacityGetter = ()-> if @parent then @parent.style('opacity') else '0.5'
1772 divReg = Dom.div(style:{height:'19px', opacity:parentOpacityGetter})
1773 divA = Dom.div(style:{height:'19px', opacity:parentOpacityGetter}, styleAfterInsert:true)
1774 divB = Dom.div(style:{height:'19px', opacity:parentOpacityGetter}, styleAfterInsert:true)
1775 divC = Dom.div(style:{height:'19px', opacity:parentOpacityGetter}, styleAfterInsert:true)
1776
1777 className = divReg.raw.className or 'no className'
1778 expect(divReg.raw.className).to.equal(className)
1779 expect(divA.raw.className).to.equal(className)
1780 expect(divB.raw.className).to.equal(className)
1781 expect(divC.raw.className).to.equal(className)
1782 expect(divReg.el.style.opacity).to.equal('0.5')
1783 expect(divA.el.style.opacity).to.equal('')
1784 expect(divB.el.style.opacity).to.equal('')
1785 expect(divC.el.style.opacity).to.equal('')
1786
1787 divA.appendTo(sandbox)
1788 expect(divA.el.style.opacity).to.equal('1')
1789 expect(divB.el.style.opacity).to.equal('')
1790 expect(divC.el.style.opacity).to.equal('')
1791
1792 divB.insertBefore(sandbox)
1793 expect(divA.el.style.opacity).to.equal('1')
1794 expect(divB.el.style.opacity).to.equal('1')
1795 expect(divC.el.style.opacity).to.equal('')
1796
1797 sandbox.appendChild(divC.el)
1798 expect(divA.el.style.opacity).to.equal('1')
1799 expect(divB.el.style.opacity).to.equal('1')
1800 expect(divC.el.style.opacity).to.equal('')
1801
1802 divC.parent
1803 expect(divA.el.style.opacity).to.equal('1')
1804 expect(divB.el.style.opacity).to.equal('1')
1805 expect(divC.el.style.opacity).to.equal('1')
1806 divC.appendTo(sandbox)
1807
1808
1809 test "Any styles applied by states before the element has been inserted into the DOM and when options.styleAfterInsert is on will be re-applied after insert", ()->
1810 divReg = Dom.div(style:{$base:{height:->'19px'}, $funny:{height:->'29px'}, $happy:{height:->'39px'}})
1811 divA = Dom.div(style:{$base:{height:->'19px'}, $funny:{height:->'29px'}, $happy:{height:->'39px'}}, styleAfterInsert:true)
1812
1813 expect(divReg.el.style.height).to.equal('19px')
1814 expect(divA.el.style.height).to.equal('')
1815
1816 divReg.state 'funny', on
1817 divA.state 'funny', on
1818 expect(divReg.el.style.height).to.equal('29px')
1819 expect(divA.el.style.height).to.equal('')
1820
1821 divReg.state 'happy', on
1822 divA.state 'happy', on
1823 expect(divReg.el.style.height).to.equal('39px')
1824 expect(divA.el.style.height).to.equal('')
1825
1826 divReg.appendTo(sandbox)
1827 divA.appendTo(sandbox)
1828 expect(divReg.el.style.height).to.equal('39px')
1829 expect(divA.el.style.height).to.equal('39px')
1830
1831
1832 test "If an element with options.styleAfterInsert is appended into a detached element, styles will be applied only after the parent is appended to the DOM", ()->
1833 detachedParent = Dom.div()
1834 divReg = Dom.div(style:{height:(->'19px'), $happy:$relaxed:{width:->'31px'}})
1835 divA = Dom.div(style:{height:(->'19px'), $happy:$relaxed:{width:->'31px'}}, styleAfterInsert:true)
1836
1837 divReg.state 'happy', on
1838 divReg.state 'relaxed', on
1839 divA.state 'happy', on
1840 divA.state 'relaxed', on
1841 divA.state 'relaxed', on
1842 divA.style 'visibility', 'hidden'
1843
1844 expect(divReg.el.style.height).to.equal('19px')
1845 expect(divReg.el.style.width).to.equal('31px')
1846 expect(divA.el.style.height).to.equal('')
1847 expect(divA.el.style.width).to.equal('')
1848 expect(divA.el.style.visibility).to.equal('hidden')
1849
1850 divA.appendTo(detachedParent)
1851 expect(divA.el.style.height).to.equal('')
1852 expect(divA.el.style.width).to.equal('')
1853 expect(divA.el.style.visibility).to.equal('hidden')
1854
1855 detachedParent.appendTo(sandbox)
1856 expect(divA.el.style.height).to.equal('19px')
1857 expect(divA.el.style.width).to.equal('31px')
1858 expect(divA.el.style.visibility).to.equal('hidden')
1859
1860
1861 test "QuickElement.pipeState can be used to redirect all state toggles to the provided target element", ()->
1862 parentA = Dom.div()
1863 parentB = Dom.div(passStateToChildren:false)
1864 divA = Dom.div(null).appendTo(parentA)
1865 divB = Dom.div(null).appendTo(parentB)
1866 childA = Dom.span().appendTo(divA)
1867 childB = Dom.span().appendTo(divB)
1868
1869 divA.pipeState()
1870 divA.state '1', on
1871 expect(parentA.state '1').to.equal off
1872 expect(divA.state '1').to.equal on
1873 expect(childA.state '1').to.equal on
1874
1875 divA.pipeState(parentA)
1876 divA.state '2', on
1877 expect(parentA.state '2').to.equal on
1878 expect(divA.state '2').to.equal on
1879 expect(childA.state '2').to.equal on
1880
1881 divA.pipeState(false)
1882 divA.state '2.5', on
1883 expect(parentA.state '2.5').to.equal off
1884 expect(divA.state '2.5').to.equal on
1885 expect(childA.state '2.5').to.equal on
1886
1887 divB.pipeState(true)
1888 divB.state '3', on
1889 expect(parentB.state '3').to.equal off
1890 expect(divB.state '3').to.equal on
1891 expect(childB.state '3').to.equal on
1892
1893 divB.pipeState(parentB)
1894 divB.state '4', on
1895 expect(parentB.state '4').to.equal on
1896 expect(divB.state '4').to.equal off
1897 expect(childB.state '4').to.equal off
1898
1899 divA.pipeState(parentB)
1900 divA.state '5', on
1901 expect(parentA.state '5').to.equal off
1902 expect(parentB.state '5').to.equal on
1903 expect(divA.state '5').to.equal off
1904 expect(divB.state '5').to.equal off
1905 expect(childA.state '5').to.equal off
1906 expect(childB.state '5').to.equal off
1907
1908 divA.pipeState(false)
1909 divB.pipeState(parentA)
1910 divB.state '6', on
1911 expect(parentA.state '6').to.equal on
1912 expect(parentB.state '6').to.equal off
1913 expect(divA.state '6').to.equal on
1914 expect(divB.state '6').to.equal off
1915 expect(childA.state '6').to.equal on
1916 expect(childB.state '6').to.equal off
1917
1918
1919 test "States can be marked as unpassable to avoid passing to children by including them in options.unpassableStates", ()->
1920 div = Dom.div(unpassableStates: ['B','D'])
1921 spanA = Dom.span().appendTo(div)
1922 spanB = Dom.span().appendTo(div)
1923 subSpan = Dom.span().appendTo(spanB)
1924
1925 expect(div.state 'A').to.equal off
1926 expect(spanA.state 'A').to.equal off
1927 expect(spanB.state 'A').to.equal off
1928 expect(subSpan.state 'A').to.equal off
1929
1930 div.state 'A', on
1931 expect(div.state 'A').to.equal on
1932 expect(spanA.state 'A').to.equal on
1933 expect(spanB.state 'A').to.equal on
1934 expect(subSpan.state 'A').to.equal on
1935
1936 div.state 'B', on
1937 expect(div.state 'B').to.equal on
1938 expect(spanA.state 'B').to.equal off
1939 expect(spanB.state 'B').to.equal off
1940 expect(subSpan.state 'B').to.equal off
1941
1942 div.state 'C', on
1943 expect(div.state 'C').to.equal on
1944 expect(spanA.state 'C').to.equal on
1945 expect(spanB.state 'C').to.equal on
1946 expect(subSpan.state 'C').to.equal on
1947
1948 div.state 'D', on
1949 expect(div.state 'D').to.equal on
1950 expect(spanA.state 'D').to.equal off
1951 expect(spanB.state 'D').to.equal off
1952 expect(subSpan.state 'D').to.equal off
1953
1954 spanB.state 'D', on
1955 expect(spanB.state 'D').to.equal on
1956 expect(subSpan.state 'D').to.equal on
1957
1958 div.state 'D', off
1959 expect(div.state 'D').to.equal off
1960 expect(spanB.state 'D').to.equal on
1961 expect(subSpan.state 'D').to.equal on
1962
1963
1964 test "When .state() receives a truthy value as the third argument the event will bubble up to parents instead of cascade to children", ()->
1965 parentA = Dom.section null,
1966 subParentA = Dom.div null,
1967 childA = Dom.div null,
1968 subChildA = Dom.div()
1969
1970 parentB = Dom.section null,
1971 subParentB = Dom.div null,
1972 childB = Dom.div null,
1973 subChildB = Dom.div()
1974
1975 expect(parentA.state 'happy').to.equal off
1976 expect(parentB.state 'happy').to.equal off
1977 expect(subParentA.state 'happy').to.equal off
1978 expect(subParentB.state 'happy').to.equal off
1979 expect(childA.state 'happy').to.equal off
1980 expect(childB.state 'happy').to.equal off
1981 expect(subChildA.state 'happy').to.equal off
1982 expect(subChildB.state 'happy').to.equal off
1983
1984 childA.state 'happy', on, true
1985 childB.state 'happy', on
1986
1987 expect(parentA.state 'happy').to.equal on
1988 expect(parentB.state 'happy').to.equal off
1989 expect(subParentA.state 'happy').to.equal on
1990 expect(subParentB.state 'happy').to.equal off
1991 expect(childA.state 'happy').to.equal on
1992 expect(childB.state 'happy').to.equal on
1993 expect(subChildA.state 'happy').to.equal off
1994 expect(subChildB.state 'happy').to.equal on
1995
1996 childA.state 'relaxed', on, null
1997 childB.state 'relaxed', on, 'on'
1998
1999 expect(parentA.state 'relaxed').to.equal off
2000 expect(parentB.state 'relaxed').to.equal on
2001 expect(subParentA.state 'relaxed').to.equal off
2002 expect(subParentB.state 'relaxed').to.equal on
2003 expect(childA.state 'relaxed').to.equal on
2004 expect(childB.state 'relaxed').to.equal on
2005 expect(subChildA.state 'relaxed').to.equal on
2006 expect(subChildB.state 'relaxed').to.equal off
2007
2008
2009 test "options.stateTriggers config objects can specify a 'force' property which will make them get attached even if they aren't used", ()->
2010 divA = Dom.div stateTriggers:{'happy': on:'happyON', off:'happyOFF', force:true}
2011 divB = Dom.div stateTriggers:{'happy': on:'happyON', off:'happyOFF'}
2012
2013 expect(divA.state 'happy').to.equal off
2014 expect(divB.state 'happy').to.equal off
2015
2016 divA.raw.emitEvent 'happyON'
2017 divB.raw.emitEvent 'happyON'
2018
2019 expect(divA.state 'happy').to.equal on
2020 expect(divB.state 'happy').to.equal off
2021
2022 divB.state 'happy', on
2023 divA.raw.emitEvent 'happyOFF'
2024 divB.raw.emitEvent 'happyOFF'
2025
2026 expect(divA.state 'happy').to.equal off
2027 expect(divB.state 'happy').to.equal on
2028
2029
2030 test "options.stateTriggers config objects can specify a 'bubbles' property which will cause the state to bubble to parents instead of cascade to children", ()->
2031 parentA = Dom.section null,
2032 subParentA = Dom.div null,
2033 childA = Dom.div stateTriggers:{'happy': on:'happyON', off:'happyOFF', bubbles:true, force:true},
2034 subChildA = Dom.div()
2035
2036 parentB = Dom.section null,
2037 subParentB = Dom.div null,
2038 childB = Dom.div stateTriggers:{'happy': on:'happyON', off:'happyOFF', force:true},
2039 subChildB = Dom.div()
2040
2041 expect(parentA.state 'happy').to.equal off
2042 expect(parentB.state 'happy').to.equal off
2043 expect(subParentA.state 'happy').to.equal off
2044 expect(subParentB.state 'happy').to.equal off
2045 expect(childA.state 'happy').to.equal off
2046 expect(childB.state 'happy').to.equal off
2047 expect(subChildA.state 'happy').to.equal off
2048 expect(subChildB.state 'happy').to.equal off
2049
2050 childA.raw.emitEvent 'happyON'
2051 childB.raw.emitEvent 'happyON'
2052
2053 expect(parentA.state 'happy').to.equal on
2054 expect(parentB.state 'happy').to.equal off
2055 expect(subParentA.state 'happy').to.equal on
2056 expect(subParentB.state 'happy').to.equal off
2057 expect(childA.state 'happy').to.equal on
2058 expect(childB.state 'happy').to.equal on
2059 expect(subChildA.state 'happy').to.equal off
2060 expect(subChildB.state 'happy').to.equal on
2061
2062 childA.raw.emitEvent 'happyOFF'
2063 childB.raw.emitEvent 'happyOFF'
2064
2065 expect(parentA.state 'happy').to.equal off
2066 expect(parentB.state 'happy').to.equal off
2067 expect(subParentA.state 'happy').to.equal off
2068 expect(subParentB.state 'happy').to.equal off
2069 expect(childA.state 'happy').to.equal off
2070 expect(childB.state 'happy').to.equal off
2071 expect(subChildA.state 'happy').to.equal off
2072 expect(subChildB.state 'happy').to.equal off
2073
2074
2075 test "wrappers created for existing elements should attempt to resolve if its inserted into the DOM on init", ()->
2076 divA_ = document.createElement('div')
2077 divB_ = document.createElement('div')
2078 sandbox.appendChild(divB_)
2079 divA = Dom(divA_)
2080 divB = Dom(divB_)
2081
2082 divA_.style.height = '100px'
2083 divB_.style.height = '100px'
2084
2085 expect(typeof divA.height).to.equal('number')
2086 expect(typeof divB.height).to.equal('number')
2087 expect(isNaN divA.height).to.be.true
2088 expect(isNaN divB.height).to.be.false
2089 expect(divA.styleSafe 'height').to.equal '100px'
2090
2091
2092 test "state-based text", ()->
2093 divA = Dom(
2094 ['div', null,
2095 ['text',
2096 text:
2097 $base: 'abc123'
2098 $happy: 'Happy'
2099 $relaxed: 'Relaxed'
2100 ]
2101 ]
2102 )
2103 divB = Dom(
2104 ['div', null,
2105 ['text',
2106 text:
2107 $happy: 'Happy'
2108 $relaxed: 'Relaxed'
2109 '$relaxed+funny': 'Funny & Relaxed'
2110 ]
2111 ]
2112 )
2113 divC = Dom.div(text:{$base:'def456', $happy:'ghi789'})
2114
2115 expect(divA.text).to.equal 'abc123'
2116 expect(divB.text).to.equal ''
2117 expect(divC.text).to.equal 'def456'
2118
2119 divA.state 'happy', on
2120 divB.state 'happy', on
2121 divC.state 'happy', on
2122 expect(divA.text).to.equal 'Happy'
2123 expect(divB.text).to.equal 'Happy'
2124 expect(divC.text).to.equal 'ghi789'
2125
2126 divA.state 'happy', off
2127 divB.state 'happy', off
2128 divC.state 'happy', off
2129 expect(divA.text).to.equal 'abc123'
2130 expect(divB.text).to.equal ''
2131 expect(divC.text).to.equal 'def456'
2132
2133 divA.state 'relaxed', on
2134 divB.state 'relaxed', on
2135 expect(divA.text).to.equal 'Relaxed'
2136 expect(divB.text).to.equal 'Relaxed'
2137
2138 divA.state 'happy', on
2139 divB.state 'happy', on
2140 expect(divA.text).to.equal 'Relaxed'
2141 expect(divB.text).to.equal 'Relaxed'
2142
2143 divA.state 'relaxed', off
2144 divB.state 'relaxed', off
2145 expect(divA.text).to.equal 'Happy'
2146 expect(divB.text).to.equal 'Happy'
2147
2148 divB.state 'relaxed', on
2149 divB.state 'funny', on
2150 expect(divB.text).to.equal 'Relaxed'
2151
2152 divB.state 'relaxed+funny', on
2153 expect(divB.text).to.equal 'Funny & Relaxed'
2154
2155
2156 test "state changes will emit a private stateChange:<state> event", ()->
2157 results = []
2158 div = Dom.div style:
2159 color: 'white'
2160 opacity: 1
2161 $happy: color: 'black'
2162
2163
2164 div.state 'any', on
2165 div.on 'stateChange:happy', (state)-> results.push ['happy', state]
2166 div.on 'stateChange:relaxed', (state)-> results.push ['relaxed', state]
2167 div.on 'stateChange:arbitrary', (state)-> results.push ['arbitrary', state]
2168 expect(results).to.deep.equal []
2169
2170 div.state 'happy', on
2171 expect(results).to.deep.equal [['happy',on]]
2172
2173 div.state 'happy', off
2174 expect(results).to.deep.equal [['happy',on], ['happy',off]]
2175
2176 div.state 'happy', on
2177 expect(results).to.deep.equal [['happy',on], ['happy',off], ['happy',on]]
2178
2179 div.state 'happy', on
2180 expect(results).to.deep.equal [['happy',on], ['happy',off], ['happy',on]]
2181
2182 div.state 'another', on
2183 expect(results).to.deep.equal [['happy',on], ['happy',off], ['happy',on]]
2184
2185 div.state 'relaxed', on
2186 expect(results).to.deep.equal [['happy',on], ['happy',off], ['happy',on], ['relaxed',on]]
2187
2188 div.state 'arbitrary', on
2189 expect(results).to.deep.equal [['happy',on], ['happy',off], ['happy',on], ['relaxed',on], ['arbitrary',on]]
2190
2191 div.state 'relaxed', on
2192 expect(results).to.deep.equal [['happy',on], ['happy',off], ['happy',on], ['relaxed',on], ['arbitrary',on]]
2193
2194
2195 test "state-based styles can be updated via QuickElement.updateStateStyles", ()->
2196 div = Dom.div(style:
2197 width: 5
2198 height: 5
2199 marginTop: 5
2200 $happy:
2201 marginTop: 10
2202 $relaxed:
2203 marginTop: 20
2204 width: 20
2205 $happy:
2206 height: 40
2207 marginTop: 40
2208 $somethingElse:
2209 width: 60
2210 marginTop: 60
2211 ).appendTo(sandbox)
2212 getStyles = ()-> width:div.style('width'), height:div.style('height'), marginTop:div.style('marginTop')
2213
2214 expect(getStyles()).to.eql width:'5px', height:'5px', marginTop:'5px'
2215
2216 div.state 'happy', on
2217 expect(getStyles()).to.eql width:'5px', height:'5px', marginTop:'10px'
2218
2219 div.updateStateStyles {width:7, height:8, $happy:{marginTop:12, height:12}}
2220 expect(getStyles()).to.eql width:'7px', height:'12px', marginTop:'12px'
2221
2222 div.state 'happy', off
2223 expect(getStyles()).to.eql width:'7px', height:'8px', marginTop:'5px'
2224
2225 div.state 'happy', on
2226 expect(getStyles()).to.eql width:'7px', height:'12px', marginTop:'12px'
2227 div.state 'happy', off
2228
2229 div.updateStateStyles
2230 $base:
2231 width: 2
2232 height: 9
2233 $relaxed:
2234 height: 20
2235 $happy:
2236 width: 40
2237 marginTop: -> 45
2238
2239 expect(getStyles()).to.eql width:'2px', height:'9px', marginTop:'5px'
2240
2241 div.state 'relaxed', on
2242 expect(getStyles()).to.eql width:'20px', height:'20px', marginTop:'20px'
2243
2244 div.state 'happy', on
2245 expect(getStyles()).to.eql width:'40px', height:'40px', marginTop:'45px'
2246
2247 div.state {happy:off, relaxed:off}
2248 div.el.style.marginTop = null
2249 expect(getStyles()).to.eql width:'2px', height:'9px', marginTop:'5px'
2250
2251 div.state 'somethingElse', on
2252 expect(getStyles()).to.eql width:'60px', height:'9px', marginTop:'60px'
2253
2254
2255 test "default states to apply to an element upon creation can be specified via options.state mapping", ()->
2256 el1 = DOM.div()
2257 el2 = DOM.div(state:{happy:on, relaxed:off})
2258 el3 = DOM.div(state:{relaxed:on})
2259 expect(el1.state 'happy').to.equal off
2260 expect(el1.state 'relaxed').to.equal off
2261 expect(el2.state 'happy').to.equal on
2262 expect(el2.state 'relaxed').to.equal off
2263 expect(el3.state 'happy').to.equal off
2264 expect(el3.state 'relaxed').to.equal on
2265
2266
2267
2268 suite "Media Queries", ()->
2269 suiteTeardown ()-> dimensions.restore() if Object.getOwnPropertyDescriptor(window, 'innerWidth')?.configurable
2270 suiteSetup ()-> @skip() if not Object.getOwnPropertyDescriptor(window, 'innerWidth')?.configurable
2271 teardown ()-> Dom.CSS.clearRegistered(level) for level in [0..3]
2272
2273
2274 test "Window dimensions", ()->
2275 dimensions.simulate(1000, 1000)
2276 div = Dom.div style:
2277 position: 'relative'
2278 zIndex: 2
2279 width: '300px'
2280 height: '300px'
2281 fontSize: '30px'
2282 lineHeight: '30px'
2283
2284 '@window(orientation:landscape)':
2285 marginTop: 6
2286
2287 '@window(orientation:portrait)':
2288 marginTop: 7
2289
2290 '@window(max-width:800)':
2291 zIndex: 3
2292 width: '280px'
2293
2294 '@window(max-width:700, max-height:1000)':
2295 zIndex: 4
2296 width: '250px'
2297 height: '250px'
2298
2299 '@window(max-height:1000)':
2300 fontSize: '25px'
2301
2302 '@window(min-width:900px)':
2303 fontSize: '23px'
2304
2305 '@window(aspect-ratio:0.5)':
2306 fontSize: '21px'
2307 lineHeight: '12px'
2308
2309 '@window(min-height:1200)':
2310 fontSize: '20px'
2311
2312 div.appendTo(sandbox)
2313
2314 expect(div.style 'zIndex').to.equal '2'
2315 expect(div.style 'width').to.equal '300px'
2316 expect(div.style 'height').to.equal '300px'
2317 expect(div.style 'fontSize').to.equal '23px'
2318 expect(div.style 'marginTop').to.equal '7px'
2319
2320 dimensions.simulate(900)
2321 expect(div.style 'fontSize').to.equal '23px'
2322
2323 dimensions.simulate(899)
2324 expect(div.style 'fontSize').to.equal '25px'
2325
2326 dimensions.simulate(899, 1100)
2327 expect(div.style 'fontSize').to.equal '30px'
2328
2329 dimensions.simulate(950)
2330 expect(div.style 'fontSize').to.equal '23px'
2331
2332 dimensions.simulate(950, 1900)
2333 expect(div.style 'fontSize').to.equal '20px'
2334 expect(div.style 'lineHeight').to.equal '12px'
2335
2336 dimensions.simulate(950, 1899)
2337 expect(div.style 'fontSize').to.equal '20px'
2338 expect(div.style 'lineHeight').to.equal '30px'
2339
2340 dimensions.simulate(790)
2341 expect(div.style 'zIndex').to.equal '3'
2342 expect(div.style 'width').to.equal '280px'
2343
2344 dimensions.simulate(810)
2345 expect(div.style 'zIndex').to.equal '2'
2346 expect(div.style 'width').to.equal '300px'
2347
2348 dimensions.simulate(791)
2349 expect(div.style 'zIndex').to.equal '3'
2350 expect(div.style 'width').to.equal '280px'
2351
2352 dimensions.simulate(701, 900)
2353 expect(div.style 'zIndex').to.equal '3'
2354 expect(div.style 'width').to.equal '280px'
2355 expect(div.style 'height').to.equal '300px'
2356
2357 dimensions.simulate(700, 900)
2358 expect(div.style 'zIndex').to.equal '4'
2359 expect(div.style 'width').to.equal '250px'
2360 expect(div.style 'height').to.equal '250px'
2361
2362 dimensions.simulate(700, 1001)
2363 expect(div.style 'zIndex').to.equal '3'
2364 expect(div.style 'width').to.equal '280px'
2365 expect(div.style 'height').to.equal '300px'
2366
2367 dimensions.simulate(700, 1000)
2368 expect(div.style 'zIndex').to.equal '4'
2369 expect(div.style 'width').to.equal '250px'
2370 expect(div.style 'height').to.equal '250px'
2371 expect(div.style 'marginTop').to.equal '7px'
2372
2373 dimensions.simulate(1100, 1000)
2374 expect(div.style 'marginTop').to.equal '6px'
2375
2376 dimensions.simulate(1100, 1101)
2377 expect(div.style 'marginTop').to.equal '7px'
2378
2379
2380 test "Self dimensions/styles", ()->
2381 parent = Dom.div().appendTo(sandbox)
2382 simulateParent = (width, height)->
2383 parent.style 'width', width if width
2384 parent.style 'height', height if height
2385 dimensions.simulate()
2386
2387 div = Dom.div style:
2388 position: 'relative'
2389 zIndex: 2
2390 top: '30px'
2391 width: '100%'
2392 height: '100%'
2393 fontSize: '30px'
2394 lineHeight: '30px'
2395
2396 '@self(orientation:landscape)':
2397 marginTop: 6
2398
2399 '@self(orientation:portrait)':
2400 marginTop: 7
2401
2402 '@self(position:relative)':
2403 top: '20px'
2404
2405 '@self(max-width:350)':
2406 zIndex: 3
2407 fontSize: '33px'
2408
2409 '@self(max-width:500, min-height:400)':
2410 zIndex: 4
2411 fontSize: '27px'
2412 lineHeight: '37px'
2413
2414 '@self(zIndex:4)':
2415 lineHeight: '15px'
2416
2417 '@self(min-zIndex:6)':
2418 opacity: '0'
2419
2420 '@self(max-fontSize:20)':
2421 lineHeight: '19px'
2422
2423 '@self(min-width:600px)':
2424 fontSize: '19px'
2425
2426 '@self(aspect-ratio:2.25)':
2427 fontSize: '22px'
2428 lineHeight: '12px'
2429
2430 '@self(min-height:700)':
2431 fontSize: '40px'
2432
2433 simulateParent(400, 300)
2434 div.appendTo(parent)
2435 expect(div.style 'zIndex').to.equal '2'
2436 expect(div.style 'width').to.equal '400px'
2437 expect(div.style 'height').to.equal '300px'
2438 expect(div.style 'fontSize').to.equal '30px'
2439 expect(div.style 'lineHeight').to.equal '30px'
2440 expect(div.style 'marginTop').to.equal '6px'
2441 expect(div.style 'top').to.equal '20px'
2442
2443 simulateParent(349, 420)
2444 expect(div.style 'zIndex').to.equal '4'
2445 expect(div.style 'fontSize').to.equal '27px'
2446 expect(div.style 'lineHeight').to.equal '15px'
2447
2448 simulateParent(349, 399)
2449 expect(div.style 'zIndex').to.equal '3'
2450 expect(div.style 'fontSize').to.equal '33px'
2451
2452 simulateParent(349, 401)
2453 expect(div.style 'zIndex').to.equal '4'
2454 expect(div.style 'fontSize').to.equal '27px'
2455 expect(div.style 'lineHeight').to.equal '15px'
2456 expect(div.style 'opacity').to.equal '1'
2457
2458 div.style('zIndex', 5)
2459 dimensions.simulate()
2460 expect(div.style 'opacity').to.equal '1'
2461 expect(div.style 'lineHeight').to.equal '37px'
2462
2463 div.style('zIndex', 17)
2464 expect(div.style 'opacity').to.equal '1'
2465
2466 dimensions.simulate()
2467 expect(div.style 'opacity').to.equal '0'
2468
2469 simulateParent(900)
2470 expect(div.style 'fontSize').to.equal '19px'
2471 expect(div.style 'lineHeight').to.equal '30px'
2472
2473 simulateParent(900)
2474 expect(div.style 'lineHeight').to.equal '19px'
2475
2476 simulateParent(900, 400)
2477 expect(div.style 'fontSize').to.equal '22px'
2478 expect(div.style 'lineHeight').to.equal '12px'
2479
2480 simulateParent(2025, 900)
2481 expect(div.style 'fontSize').to.equal '40px'
2482 expect(div.style 'lineHeight').to.equal '12px'
2483 expect(div.style 'marginTop').to.equal '6px'
2484
2485 simulateParent(2025, 2026)
2486 expect(div.style 'marginTop').to.equal '7px'
2487
2488
2489 test "Parent dimensions/styles", ()->
2490 parent = Dom.div(style:{position:'absolute'}).appendTo(sandbox)
2491 simulateParent = (width, height)->
2492 parent.style 'width', width if width
2493 parent.style 'height', height if height
2494 dimensions.simulate()
2495
2496 div = Dom.div style:
2497 position: 'relative'
2498 zIndex: 2
2499 top: '30px'
2500 width: '400px'
2501 height: '300px'
2502 fontSize: '30px'
2503 lineHeight: '30px'
2504
2505 '@parent(orientation:landscape)':
2506 marginBottom: 6
2507
2508 '@parent(orientation:portrait)':
2509 marginBottom: 7
2510
2511 '@parent(position:relative)':
2512 top: '21px'
2513
2514 '@parent(max-width:350)':
2515 zIndex: 3
2516 fontSize: '34px'
2517
2518 '@parent(max-width:500, min-height:400)':
2519 zIndex: 4
2520 fontSize: '27px'
2521 lineHeight: '37px'
2522
2523 '@parent(zIndex:7)':
2524 lineHeight: '16px'
2525
2526
2527 simulateParent(400, 300)
2528 div.appendTo(parent)
2529 expect(div.style 'zIndex').to.equal '2'
2530 expect(div.style 'width').to.equal '400px'
2531 expect(div.style 'height').to.equal '300px'
2532 expect(div.style 'fontSize').to.equal '30px'
2533 expect(div.style 'lineHeight').to.equal '30px'
2534 expect(div.style 'marginBottom').to.equal '6px'
2535 expect(div.style 'top').to.equal '30px'
2536
2537 parent.style 'position', 'relative'
2538 expect(div.style 'top').to.equal '30px'
2539
2540 simulateParent()
2541 expect(div.style 'top').to.equal '21px'
2542
2543 simulateParent(349, 420)
2544 expect(div.style 'zIndex').to.equal '4'
2545 expect(div.style 'fontSize').to.equal '27px'
2546 expect(div.style 'lineHeight').to.equal '37px'
2547
2548 simulateParent(349, 399)
2549 expect(div.style 'zIndex').to.equal '3'
2550 expect(div.style 'fontSize').to.equal '34px'
2551
2552 parent.style 'zIndex', '7'
2553 simulateParent(349, 401)
2554 expect(div.style 'zIndex').to.equal '4'
2555 expect(div.style 'fontSize').to.equal '27px'
2556 expect(div.style 'lineHeight').to.equal '16px'
2557 expect(div.style 'opacity').to.equal '1'
2558
2559
2560 test "Parent Ref dimensions/styles", ()->
2561 parent =
2562 Dom.div({ref:'abc'},
2563 Dom.div {id:'def'},
2564 Dom.div {ref:'ghi'}
2565 ).appendTo(sandbox)
2566
2567 div = Dom.div style:
2568 position: 'relative'
2569 zIndex: 2
2570 top: '30px'
2571 width: '400px'
2572 height: '300px'
2573 fontSize: '30px'
2574 lineHeight: '30px'
2575
2576 '@#abc(orientation:landscape)':
2577 fontWeight: 600
2578
2579 '@#abc(orientation:portrait)':
2580 fontWeight: 500
2581
2582 '@#def(position:relative)':
2583 top: '20px'
2584
2585 '@#def(max-width:350)':
2586 zIndex: 3
2587 fontSize: '33px'
2588
2589 '@#ghi(max-width:500, min-height:400)':
2590 zIndex: 4
2591 fontSize: '27px'
2592 lineHeight: '37px'
2593
2594 '@#abc(zIndex:7)':
2595 lineHeight: '15px'
2596
2597
2598 parent.style(width:400, height:300)
2599 parent.child.def.style(width:400, height:300)
2600 parent.child.ghi.style(width:400, height:300)
2601 div.appendTo(parent.child.ghi)
2602 expect(div.style 'zIndex').to.equal '2'
2603 expect(div.style 'width').to.equal '400px'
2604 expect(div.style 'height').to.equal '300px'
2605 expect(div.style 'fontSize').to.equal '30px'
2606 expect(div.style 'lineHeight').to.equal '30px'
2607 expect(div.style 'fontWeight').to.equal '600'
2608 expect(div.style 'top').to.equal '30px'
2609
2610 parent.style(width:400, height:900, position:'relative')
2611 dimensions.simulate()
2612 expect(div.style 'fontWeight').to.equal '500'
2613 expect(div.style 'top').to.equal '30px'
2614
2615 parent.child.def.style(position:'relative')
2616 expect(div.style 'top').to.equal '30px'
2617
2618 dimensions.simulate()
2619 expect(div.style 'top').to.equal '20px'
2620
2621 parent.child.def.style(width:349, height:420)
2622 dimensions.simulate()
2623 expect(div.style 'zIndex').to.equal '3'
2624 expect(div.style 'fontSize').to.equal '33px'
2625
2626 parent.child.ghi.style(width:450, height:420)
2627 dimensions.simulate()
2628 expect(div.style 'zIndex').to.equal '4'
2629 expect(div.style 'fontSize').to.equal '27px'
2630 expect(div.style 'lineHeight').to.equal '37px'
2631
2632 parent.style(zIndex:7)
2633 dimensions.simulate()
2634 expect(div.style 'zIndex').to.equal '4'
2635 expect(div.style 'fontSize').to.equal '27px'
2636 expect(div.style 'lineHeight').to.equal '15px'
2637 expect(div.style 'opacity').to.equal '1'
2638
2639
2640 test "Nested media queries", ()->
2641 dimensions.simulate(1000, 900)
2642 div = Dom.div style:
2643 zIndex: 2
2644
2645 $happy:
2646 marginRight: 5
2647 '@window(orientation:landscape)':
2648 marginRight: 6
2649
2650 '@window(orientation:portrait)':
2651 $relaxed:
2652 marginRight: 7
2653
2654
2655 div.appendTo(sandbox)
2656
2657 expect(div.style 'marginRight').to.equal '0px'
2658
2659 div.state 'happy', on
2660 expect(div.style 'marginRight').to.equal '6px'
2661
2662 dimensions.simulate(900, 1000)
2663 expect(div.style 'marginRight').to.equal '5px'
2664
2665 dimensions.simulate(1000, 900)
2666 expect(div.style 'marginRight').to.equal '6px'
2667
2668
2669 div.state 'relaxed', on
2670 expect(div.style 'marginRight').to.equal '6px'
2671
2672 dimensions.simulate(900, 1000)
2673 expect(div.style 'marginRight').to.equal '7px'
2674
2675 dimensions.simulate(1000, 900)
2676 expect(div.style 'marginRight').to.equal '6px'
2677
2678
2679
2680
2681
2682
2683 suite "Traversal", ()->
2684 test "Children", ()->
2685 div = Dom.div(null, Dom.div(), 'Some Text')
2686
2687 expect(div.children.length).to.equal(2)
2688 expect(div.elementChildren.length).to.equal(1)
2689 expect(div.el.childNodes.length).to.equal(2)
2690
2691 div.append(Dom.span())
2692 expect(div.children.length).to.equal(3)
2693 expect(div.elementChildren.length).to.equal(2)
2694 expect(div.el.childNodes.length).to.equal(3)
2695
2696 div.el.appendChild(document.createElement('div'))
2697 expect(div.children.length).to.equal(4)
2698 expect(div.elementChildren.length).to.equal(3)
2699 expect(div.el.childNodes.length).to.equal(4)
2700
2701 div = document.createElement('div')
2702 spanA = document.createElement('span')
2703 spanB = document.createElement('span')
2704 text = document.createTextNode('someTextNode')
2705 comment = document.createComment('someCommentNode')
2706
2707 div.appendChild(spanA)
2708 div.appendChild(comment)
2709 div.appendChild(spanB)
2710 div.appendChild(text)
2711 expect(div.childNodes.length).to.equal(4)
2712 expect(div.children.length).to.equal(2)
2713
2714 div$ = Dom(div)
2715 expect(div$.children.length).to.equal(3)
2716 expect(div$.elementChildren.length).to.equal(2)
2717 expect(div$.children[0].raw).to.equal(spanA)
2718 expect(div$.children[1].raw).to.equal(spanB)
2719 expect(div$.children[2].raw).to.equal(text)
2720
2721
2722 test "Parent", ()->
2723 A = Dom.div(null, Dom.div(), 'Some Text')
2724 B = Dom.div()
2725 C = Dom.div()
2726
2727 expect(A.parent).to.equal undefined
2728 expect(A.children[0].parent).to.equal A
2729 expect(A.children[0].el.parentNode).to.equal A.el
2730
2731 B.append(A)
2732 expect(A.parent).to.equal B
2733 expect(A.children[0].parent).to.equal A
2734 expect(A.children[0].el.parentNode).to.equal A.el
2735 expect(B.children.length).to.equal(1)
2736 expect(B.children[0]).to.equal(A)
2737
2738 C.append(A)
2739 expect(A.parent).to.equal C
2740 expect(A.children[0].parent).to.equal A
2741 expect(A.children[0].el.parentNode).to.equal A.el
2742 expect(B.children.length).to.equal(0)
2743 expect(C.children[0]).to.equal(A)
2744
2745
2746 test "Parents", ()->
2747 A = Dom.div().appendTo(sandbox)
2748 B = Dom.div().appendTo(A)
2749 C = Dom.div().appendTo(B)
2750
2751 expect(A.parent.el).to.equal(sandbox)
2752 expect(B.parent).to.equal(A)
2753 expect(C.parent).to.equal(B)
2754
2755 expect(A.parents.length).to.equal(B.parents.length-1)
2756 expect(B.parents.length).to.equal(C.parents.length-1)
2757 expect(B.parents[0]).to.equal(A)
2758 expect(C.parents[0]).to.equal(B)
2759 expect(C.parents.length).to.equal(5)
2760 expect(C.parents.slice(-1)[0].el).to.equal(document.documentElement)
2761
2762
2763 suite "Parent Matching", ()->
2764 teardown ()-> @els.A.detach()
2765 suiteSetup ()->
2766 A = Dom.section(ref:'A')
2767 B = Dom.div(ref:'B').appendTo(A)
2768 C = Dom.div(ref:'C').appendTo(B)
2769 D = Dom.span(ref:'D').appendTo(C)
2770 @els = {A,B,C,D}
2771
2772 test "function filter", ()->
2773 {A,B,C,D} = @els
2774 expect(D.parents).to.eql [C,B,A]
2775 expect(D.parentMatching(null)).to.equal(undefined)
2776 expect(D.parentMatching(B)).to.equal(undefined)
2777 expect(D.parentMatching ()-> false).to.equal(undefined)
2778 expect(D.parentMatching (el)-> el is B).to.equal(B)
2779 expect(D.parentMatching (el)-> el is A).to.equal(A)
2780 expect(D.parentMatching (el)-> el is C).to.equal(C)
2781
2782 A.appendTo(sandbox)
2783 expect(D.parentMatching (el)-> el.raw is document.documentElement).to.equal(Dom(document.documentElement))
2784
2785 test "ref filter", ()->
2786 {A,B,C,D} = @els
2787 expect(D.parents).to.eql [C,B,A]
2788 expect(D.parentMatching 'badRef').to.equal(undefined)
2789 expect(D.parentMatching 'B').to.equal(B)
2790 expect(D.parentMatching 'A').to.equal(A)
2791 expect(D.parentMatching 'C').to.equal(C)
2792
2793
2794 suite "Parents Until", ()->
2795 suiteSetup ()->
2796 A = Dom.section(ref:'A')
2797 B = Dom.div(ref:'B').appendTo(A)
2798 C = Dom.div(ref:'C').appendTo(B)
2799 D = Dom.span(ref:'D').appendTo(C)
2800 @els = {A,B,C,D}
2801
2802 test "function filter", ()->
2803 {A,B,C,D} = @els
2804 expect(D.parents).to.eql [C,B,A]
2805 expect(D.parentsUntil(null)).to.eql [C,B,A]
2806 expect(D.parentsUntil()).to.eql [C,B,A]
2807 expect(D.parentsUntil (el)-> el is A).to.eql [C,B]
2808 expect(D.parentsUntil (el)-> el is B).to.eql [C]
2809 expect(D.parentsUntil (el)-> false).to.eql [C,B,A]
2810
2811
2812 test "ref filter", ()->
2813 {A,B,C,D} = @els
2814 expect(D.parentsUntil 'A').to.eql [C,B]
2815 expect(D.parentsUntil 'B').to.eql [C]
2816 expect(D.parentsUntil 'badRef').to.eql [C,B,A]
2817
2818
2819 test "Next", ()->
2820 div = Dom.div(null, A=Dom.div(), B=Dom.div(), C=Dom.div(), D=Dom.div(), E=Dom.div())
2821
2822 expect(A.next).to.equal(B)
2823 expect(C.next).to.equal(D)
2824 expect(E.next).to.equal(undefined)
2825 expect(B.nextAll).to.eql([C,D,E])
2826
2827
2828 test "Next Element", ()->
2829 div = Dom.div(null, A=Dom.div(), B=Dom.text(), C=Dom.div(), D=Dom.text(), E=Dom.div())
2830
2831 expect(A.next).to.equal(B)
2832 expect(A.nextEl).to.equal(C)
2833 expect(B.nextEl).to.equal(C)
2834 expect(C.nextEl).to.equal(E)
2835 expect(E.nextEl).to.equal(undefined)
2836 expect(A.nextElAll).to.eql([C,E])
2837
2838
2839 test "Prev", ()->
2840 div = Dom.div(null, A=Dom.div(), B=Dom.div(), C=Dom.div(), D=Dom.div(), E=Dom.div())
2841
2842 expect(E.prev).to.equal(D)
2843 expect(C.prev).to.equal(B)
2844 expect(A.prev).to.equal(undefined)
2845 expect(D.prevAll).to.eql([C,B,A])
2846
2847
2848 test "Prev Element", ()->
2849 div = Dom.div(null, A=Dom.div(), B=Dom.text(), C=Dom.div(), D=Dom.text(), E=Dom.div())
2850
2851 expect(E.prev).to.equal(D)
2852 expect(E.prevEl).to.equal(C)
2853 expect(D.prevEl).to.equal(C)
2854 expect(C.prevEl).to.equal(A)
2855 expect(A.prevEl).to.equal(undefined)
2856 expect(E.prevElAll).to.eql([C,A])
2857
2858
2859 test "Siblings", ()->
2860 div = Dom.div(null, A=Dom.div(), B=Dom.text(), C=Dom.div(), D=Dom.text(), E=Dom.div())
2861
2862 expect(C.siblings).to.eql(C.prevAll.reverse().concat(C.nextAll))
2863 expect(C.siblings).to.eql([A,B,D,E])
2864 expect(C.elementSiblings).to.eql([A,E])
2865 expect(B.elementSiblings).to.eql([A,C,E])
2866
2867
2868 test "First/Last Child", ()->
2869 main = DOM.div(id:'main')
2870 divA = DOM.div(id:'divA').appendTo(main)
2871 divB = DOM.div(id:'divB').appendTo(main)
2872 divC = DOM.div(id:'divC').appendTo(main)
2873 divBA = DOM.div(id:'divBA').appendTo(divB)
2874 divBB = DOM.div(id:'divBB').appendTo(divB)
2875
2876 expect(main.firstChild).to.equal divA
2877 expect(main.lastChild).to.equal divC
2878 expect(divA.firstChild).to.equal undefined
2879 expect(divA.lastChild).to.equal undefined
2880 expect(divB.firstChild).to.equal divBA
2881 expect(divB.lastChild).to.equal divBB
2882
2883
2884 test "Child (by ref)", ()->
2885 divA =
2886 Dom.div {id:'divA'},
2887 Dom.div {id:'childA'},
2888 Dom.span {ref:'childA_1'}
2889 Dom.div {ref:'childA_2', id:'childA_2'}
2890 Dom.div {},
2891 Dom.span {ref:'childB_1'}
2892 Dom.text {id:'childB_2'}, 'The Text'
2893
2894
2895 divB = Dom.template(
2896 ['div', {id:'divB'},
2897 ['div', {id:'childA', style:{color:'pink'}},
2898 ['span', {ref:'childA_1'}]
2899 ['div', {ref:'childA_3', id:'childA_2'}]
2900 ]
2901 ['div', null,
2902 ['span', {ref:'childB_1'}]
2903 ]
2904 ]
2905 ).spawn()
2906
2907 divC = Dom.template(
2908 ['div', ref:'divC',
2909 ['div', ref:'childA',
2910 ['div', ref:'divB']
2911 ['div', ref:'divC']
2912 ]
2913 ['div', ref:'childB',
2914 ['div', ref:'divB']
2915 ['div', ref:'divC']
2916 ['div', ref:'divD',
2917 ['div', ref:'childB']
2918 ]
2919 ]
2920 ]
2921 ).spawn()
2922
2923
2924 expect(divA.child.childA).to.equal(divA.children[0])
2925 expect(divA.child.childA_1).to.equal(divA.children[0].children[0])
2926 expect(divA.child.childA_2).to.equal(divA.children[0].children[1])
2927 expect(divA.child.childA_3).to.equal(undefined)
2928 expect(divA.child.childB).to.equal(undefined)
2929 expect(divA.child.childB_1).to.equal(divA.children[1].children[0])
2930 expect(divA.child.childB_2).to.equal(divA.children[1].children[1])
2931 expect(divA.child.childB_2.type).to.equal('text')
2932
2933
2934 expect(divB.child.childA).to.equal(divB.children[0])
2935 expect(divB.child.childA_1).to.equal(divB.children[0].children[0])
2936 expect(divB.child.childA_2).to.equal(divB.children[0].children[1])
2937 expect(divB.child.childA_3).to.equal(undefined)
2938 expect(divB.child.childB).to.equal(undefined)
2939 expect(divB.child.childB_1).to.equal(divB.children[1].children[0])
2940 expect(divB.child.childB_2).to.equal(divB.children[1].children[1])
2941 expect(divB.child.childA.style('color')).to.equal('')
2942 expect(divB.child.childA.styleSafe('color')).not.to.equal('')
2943 expect(divB.child.childA.styleSafe('color').length >= 4).to.be.true
2944
2945
2946 expect(divA.child.childA.raw.getAttribute('id')).to.equal('childA')
2947 expect(divA.child.childA.raw.getAttribute('data-ref')).to.equal('childA')
2948 expect(divA.child.childA_1.raw.getAttribute('id')).to.equal(null)
2949 expect(divA.child.childA_1.raw.getAttribute('data-ref')).to.equal('childA_1')
2950 expect(divA.child.childA_2.raw.getAttribute('id')).to.equal('childA_2')
2951 expect(divA.child.childA_2.raw.getAttribute('data-ref')).to.equal('childA_2')
2952
2953 expect(divC.child.childA).to.equal(divC.children[0])
2954 expect(divC.child.childB).to.equal(divC.children[1])
2955 expect(divC.child.divB).to.equal(divC.children[0].children[0])
2956 expect(divC.child.divC).to.equal(divC)
2957 expect(divC.child.divD).to.equal(divC.children[1].children[2])
2958 expect(divC.children[0].child.divB).to.equal(divC.children[0].children[0])
2959 expect(divC.children[0].child.divC).to.equal(divC.children[0].children[1])
2960 expect(divC.children[1].child.divB).to.equal(divC.children[1].children[0])
2961 expect(divC.children[1].child.divC).to.equal(divC.children[1].children[1])
2962 expect(divC.children[1].child.divD).to.equal(divC.children[1].children[2])
2963 expect(divC.children[1].child.childB).to.equal(divC.children[1])
2964
2965 sandBox = Dom(sandbox)
2966 expect(sandBox.child.childA).to.equal(undefined)
2967 expect(sandBox.child.childB_2).to.equal(undefined)
2968 expect(sandBox.child.divA).to.equal(undefined)
2969
2970 sandBox.append(divA)
2971 expect(sandBox.child.childA).to.equal(undefined)
2972 expect(sandBox.child.childB_2).to.equal(undefined)
2973 expect(sandBox.child.divA).to.equal(undefined)
2974 expect(sandBox.childf.divA).to.equal(divA)
2975 expect(sandBox.child.childA).to.equal(divA.children[0])
2976 expect(sandBox.child.childB_2).to.equal(divA.children[1].children[1])
2977 expect(sandBox.child.divA).to.equal(divA)
2978
2979 newChild = Dom.div(ref:'newChild')
2980 newChildChild = Dom.div(ref:'newChildChild')
2981 expect(newChild.child.newChildChild).to.equal(undefined)
2982 expect(newChildChild.child.newChildChild).to.equal(newChildChild)
2983 expect(Object.keys(newChildChild.child).length).to.equal(1)
2984
2985 newChildChild.appendTo(newChild)
2986 expect(newChild.child.newChildChild).to.equal(undefined)
2987 expect(newChild.childf.newChildChild).to.equal(newChildChild)
2988 expect(newChild.child.newChildChild).to.equal(newChildChild)
2989 expect(Object.keys(newChildChild.child).length).to.equal(1)
2990
2991 newParent = Dom.div(ref:'newParent')
2992 newChild.appendTo(newParent)
2993 expect(newParent.child.newChildChild).to.equal(newChildChild)
2994
2995
2996 test "Index", ()->
2997 section =
2998 Dom.section(null,
2999 childA = Dom.div()
3000 childB = Dom.div()
3001 childC = Dom.span()
3002 childD = Dom.text()
3003 childE = Dom.span()
3004 childF = Dom.div()
3005 )
3006
3007 expect(childB.index).to.equal 1
3008 expect(childD.index).to.equal 3
3009 expect(childF.index).to.equal 5
3010
3011 childC.detach()
3012 expect(childB.index).to.equal 1
3013 expect(childD.index).to.equal 2
3014 expect(childF.index).to.equal 4
3015 expect(childC.index).to.equal null
3016
3017
3018 test "Index (by type)", ()->
3019 section =
3020 Dom.section(null,
3021 childA = Dom.div()
3022 childB = Dom.div()
3023 childC = Dom.span()
3024 childD = Dom.text()
3025 childE = Dom.span()
3026 childF = Dom.text()
3027 childG = Dom.div()
3028 )
3029
3030 expect(childB.indexType).to.equal 1
3031 expect(childD.indexType).to.equal 0
3032 expect(childF.indexType).to.equal 1
3033 expect(childG.indexType).to.equal 2
3034
3035 childC.detach()
3036 expect(childB.indexType).to.equal 1
3037 expect(childD.indexType).to.equal 0
3038 expect(childF.indexType).to.equal 1
3039 expect(childG.indexType).to.equal 2
3040
3041 childA.detach()
3042 expect(childB.indexType).to.equal 0
3043 expect(childD.indexType).to.equal 0
3044 expect(childF.indexType).to.equal 1
3045 expect(childG.indexType).to.equal 1
3046 expect(childA.indexType).to.equal null
3047 expect(childC.indexType).to.equal null
3048
3049
3050 test "Index (by ref)", ()->
3051 section =
3052 Dom.section(null,
3053 childA = Dom.div(ref:'abc')
3054 childB = Dom.div(ref:'abc')
3055 childC = Dom.span(ref:'def')
3056 childD = Dom.text(ref:'abc')
3057 childE = Dom.span(ref:'abc')
3058 childF = Dom.text(ref:'def')
3059 childG = Dom.div(ref:'abc')
3060 )
3061
3062 expect(childB.indexRef).to.equal 1
3063 expect(childD.indexRef).to.equal 2
3064 expect(childF.indexRef).to.equal 1
3065 expect(childG.indexRef).to.equal 4
3066
3067 childC.detach()
3068 expect(childB.indexRef).to.equal 1
3069 expect(childD.indexRef).to.equal 2
3070 expect(childF.indexRef).to.equal 0
3071 expect(childG.indexRef).to.equal 4
3072
3073 childA.detach()
3074 expect(childB.indexRef).to.equal 0
3075 expect(childD.indexRef).to.equal 1
3076 expect(childF.indexRef).to.equal 0
3077 expect(childG.indexRef).to.equal 3
3078 expect(childA.indexRef).to.equal null
3079 expect(childC.indexRef).to.equal null
3080
3081
3082 test "Query", ()->
3083 div = Dom.template(
3084 ['div', {class:'div-one', attrs:name:'abc123'},
3085 ['div', {class:'childA', style:{color:'pink'}},
3086 ['span', {class:'childA_1'}]
3087 ['div', {class:'childA_1'}]
3088 ['span', {class:'childA_1'}]
3089 ['div', {class:'childA_2'}]
3090 ]
3091 ['div', className:'childB',
3092 ['span', {class:'childB_1'}]
3093 ]
3094 ['section', className:'childB',
3095 ['span', {class:'childB_1'}]
3096 ]
3097 ]
3098 ).spawn().appendTo(sandBox = Dom(sandbox))
3099
3100 expect(div.query '.childA').to.equal(div.children[0])
3101 expect(div.query '.childB').to.equal(div.children[1])
3102 expect(div.query '.childB_1').to.equal(div.children[1].children[0])
3103 expect(div.query '.childA_1').to.equal(div.children[0].children[0])
3104 expect(div.query '.childA_2').to.equal(div.children[0].children[3])
3105 expect(sandBox.query '.div-one').to.equal(div)
3106 expect(sandBox.query '.childB_1').to.equal(div.children[1].children[0])
3107 expect(sandBox.query 'div[name="abc123"]').to.equal(div)
3108 expect(sandBox.query 'span[name="abc123"]').to.equal(undefined)
3109
3110
3111 test "QueryAll", ()->
3112 div = Dom.template(
3113 ['div', {class:'div-one', attrs:name:'abc123'},
3114 ['div', {class:'childA', style:{color:'pink'}},
3115 ['span', {class:'childA_1'}]
3116 ['div', {class:'childA_1'}]
3117 ['span', {class:'childA_1'}]
3118 ['div', {class:'childA_2'}]
3119 ]
3120 ['div', className:'childB',
3121 ['span', {class:'childB_1'}]
3122 ]
3123 ['section', className:'childB',
3124 ['span', {class:'childB_1'}]
3125 ]
3126 ]
3127 ).spawn().appendTo(sandBox = Dom(sandbox))
3128
3129 expect(div.queryAll('.childA').elements).to.eql([div.children[0]])
3130 expect(div.queryAll('.childB').elements).to.eql([div.children[1], div.children[2]])
3131 expect(div.queryAll('.childB_1').elements).to.eql([div.children[1].children[0], div.children[2].children[0]])
3132 expect(div.queryAll('.childA_1').elements).to.eql([div.children[0].children[0], div.children[0].children[1], div.children[0].children[2]])
3133 expect(div.queryAll('.childA_2').elements).to.eql([div.children[0].children[3]])
3134 expect(sandBox.queryAll('.div-one').elements).to.eql([div])
3135 expect(sandBox.queryAll('.childB_1').elements).to.eql([div.children[1].children[0], div.children[2].children[0]])
3136 expect(sandBox.queryAll('div[name="abc123"]').elements).to.eql([div])
3137 expect(sandBox.queryAll('span[name="abc123"]').elements).to.eql([])
3138 expect(div.text).to.equal('')
3139 expect(sandBox.queryAll('.childB_1').text('abc123').elements).to.eql([div.children[1].children[0], div.children[2].children[0]])
3140 expect(div.text).to.equal('abc123abc123')
3141
3142
3143 test "Query/QueryAll shortcuts", ()->
3144 expect(Dom.query('head')).to.equal(Dom(document).query('head'))
3145 expect(Dom.query('body')).to.equal(Dom(document).query('body'))
3146
3147 allA = Dom.queryAll('section').elements
3148 allB = Dom(document).queryAll('section').elements
3149 expect(allA.length).to.equal(allB.length)
3150 for el,index in allA
3151 expect(allA[index]).to.equal(allB[index])
3152 return
3153
3154
3155
3156 suite "Manipulation", ()->
3157 test ".append()", ()->
3158 A = Dom.div()
3159 B = Dom.div()
3160 C = Dom.text()
3161 D = Dom.div()
3162 MainA = Dom.div(null, A, B, C, D)
3163 MainB = Dom.div()
3164
3165 checkChildStructure(MainA)(A, B, C, D)
3166 checkChildStructure(MainB)()
3167
3168 MainB.append(A)
3169 checkChildStructure(MainA)(B, C, D)
3170 checkChildStructure(MainB)(A)
3171
3172 C.appendTo(MainB)
3173 checkChildStructure(MainA)(B, D)
3174 checkChildStructure(MainB)(A, C)
3175
3176
3177
3178 test ".prepend()", ()->
3179 A = Dom.div()
3180 B = Dom.div()
3181 C = Dom.text()
3182 D = Dom.div()
3183 MainA = Dom.div(null, A, B, C, D)
3184 MainB = Dom.div()
3185
3186 checkChildStructure(MainA)(A, B, C, D)
3187 checkChildStructure(MainB)()
3188
3189 MainB.prepend(A)
3190 checkChildStructure(MainA)(B, C, D)
3191 checkChildStructure(MainB)(A)
3192
3193 C.prependTo(MainB)
3194 checkChildStructure(MainA)(B, D)
3195 checkChildStructure(MainB)(C, A)
3196
3197
3198 test ".after()", ()->
3199 A = Dom.div()
3200 B = Dom.div()
3201 C = Dom.text()
3202 D = Dom.div()
3203 MainA = Dom.div(null, A, B, C, D)
3204 MainB = Dom.div()
3205
3206 checkChildStructure(MainA)(A, B, C, D)
3207 checkChildStructure(MainB)()
3208
3209 MainB.append(B)
3210 B.after(A)
3211 checkChildStructure(MainA)(C, D)
3212 checkChildStructure(MainB)(B, A)
3213
3214 C.insertAfter(B)
3215 checkChildStructure(MainA)(D)
3216 checkChildStructure(MainB)(B, C, A)
3217
3218
3219 test ".before()", ()->
3220 A = Dom.div()
3221 B = Dom.div()
3222 C = Dom.text()
3223 D = Dom.div()
3224 MainA = Dom.div(null, A, B, C, D)
3225 MainB = Dom.div()
3226
3227 checkChildStructure(MainA)(A, B, C, D)
3228 checkChildStructure(MainB)()
3229
3230 MainB.append(B)
3231 B.before(A)
3232 checkChildStructure(MainA)(C, D)
3233 checkChildStructure(MainB)(A, B)
3234
3235 C.insertBefore(B)
3236 checkChildStructure(MainA)(D)
3237 checkChildStructure(MainB)(A, C, B)
3238
3239
3240 test ".detach()", ()->
3241 emitCount = 0
3242 div = Dom.div(null, 'Inner Text Here')
3243 div.on 'beep', ()-> emitCount++
3244 div.state 'happy', on
3245 div.state 'relaxed', on
3246
3247 expect(div.parent).not.to.exist
3248 expect(emitCount).to.equal(0)
3249 expect(div.state 'happy').to.be.true
3250 expect(div.state 'relaxed').to.be.true
3251
3252 div.appendTo(sandbox)
3253 div.emit('beep')
3254 expect(sandbox.children.length).to.equal(1)
3255 expect(div.parent.el).to.equal(sandbox)
3256 expect(emitCount).to.equal(1)
3257 expect(div.state 'happy').to.be.true
3258 expect(div.state 'relaxed').to.be.true
3259
3260 div.detach()
3261 div.emit('beep')
3262 expect(sandbox.children.length).to.equal(0)
3263 expect(div.parent).not.to.exist
3264 expect(emitCount).to.equal(2)
3265 expect(div.state 'happy').to.be.true
3266 expect(div.state 'relaxed').to.be.true
3267
3268
3269 test ".remove()", ()->
3270 emitCount = 0
3271 div = Dom.div(null, 'Inner Text Here')
3272 div.on 'beep', ()-> emitCount++
3273 div.state 'happy', on
3274 div.state 'relaxed', on
3275
3276 expect(div.parent).not.to.exist
3277 expect(emitCount).to.equal(0)
3278 expect(div.state 'happy').to.be.true
3279 expect(div.state 'relaxed').to.be.true
3280
3281 div.appendTo(sandbox)
3282 div.emit('beep')
3283 expect(sandbox.children.length).to.equal(1)
3284 expect(div.parent.el).to.equal(sandbox)
3285 expect(emitCount).to.equal(1)
3286 expect(div.state 'happy').to.be.true
3287 expect(div.state 'relaxed').to.be.true
3288
3289 div.remove()
3290 div.emit('beep')
3291 expect(sandbox.children.length).to.equal(0)
3292 expect(div.parent).not.to.exist
3293 expect(emitCount).to.equal(1)
3294 expect(div.state 'happy').to.be.false
3295 expect(div.state 'relaxed').to.be.false
3296
3297
3298 test ".empty()", ()->
3299 Main = Dom.div()
3300 A = Dom.div().appendTo(Main)
3301 B = Dom.div().appendTo(Main)
3302 A.state 'happy', on
3303 B.state 'happy', on
3304
3305 checkChildStructure(Main)(A, B)
3306 expect(A.state 'happy').to.be.true
3307 expect(B.state 'happy').to.be.true
3308
3309 Main.empty()
3310 checkChildStructure(Main)()
3311 expect(A.parent).to.equal(undefined)
3312 expect(B.parent).to.equal(undefined)
3313 expect(A.state 'happy').to.be.true
3314 expect(B.state 'happy').to.be.true
3315
3316
3317 test ".wrap()", ()->
3318 Main = Dom.div()
3319 A = Dom.div().appendTo(Main)
3320 B = Dom.div().appendTo(Main)
3321 C = Dom.div()
3322 wrapA = Dom.section()
3323 wrapB = Dom.section()
3324 wrapC = Dom.section()
3325 A.state 'happy', on
3326 B.state 'happy', on
3327 C.state 'happy', on
3328 wrapA.state 'relaxed', on
3329 wrapB.state 'relaxed', on
3330 wrapC.state 'relaxed', on
3331 checkChildStructure(Main)(A, B)
3332
3333 A.wrap(wrapA)
3334 checkChildStructure(Main)(wrapA, B)
3335 checkChildStructure(wrapA)(A)
3336
3337 B.wrap(wrapB)
3338 checkChildStructure(Main)(wrapA, wrapB)
3339 checkChildStructure(wrapA)(A)
3340 checkChildStructure(wrapB)(B)
3341
3342 B.wrap(wrapA)
3343 checkChildStructure(Main)(wrapA, wrapB)
3344 checkChildStructure(wrapA)(A, B)
3345 checkChildStructure(wrapB)()
3346
3347 wrapC.appendTo(wrapB)
3348 C.wrap(wrapC)
3349 C.wrap()
3350 checkChildStructure(Main)(wrapA, wrapB)
3351 checkChildStructure(wrapA)(A, B)
3352 checkChildStructure(wrapB)(wrapC)
3353 checkChildStructure(wrapC)(C)
3354
3355 C.wrap(C)
3356 checkChildStructure(Main)(wrapA, wrapB)
3357 checkChildStructure(wrapA)(A, B)
3358 checkChildStructure(wrapB)(wrapC)
3359 checkChildStructure(wrapC)(C)
3360
3361 expect(A.state 'happy').to.be.true
3362 expect(B.state 'happy').to.be.true
3363 expect(C.state 'happy').to.be.true
3364 expect(wrapA.state 'relaxed').to.be.true
3365 expect(wrapB.state 'relaxed').to.be.true
3366 expect(wrapC.state 'relaxed').to.be.true
3367
3368
3369 test ".unwrap()", ()->
3370 Main = Dom.div()
3371 A = Dom.div().prependTo(Main)
3372 B = Dom.div().appendTo(A)
3373 C = Dom.div().appendTo(A)
3374 D = Dom.div().appendTo(C)
3375 E = Dom.div().appendTo(D)
3376 A.state 'happy', on
3377 B.state 'happy', on
3378 C.state 'happy', on
3379 D.state 'happy', on
3380 E.state 'happy', on
3381
3382 checkChildStructure(Main)(A)
3383 checkChildStructure(A)(B, C)
3384 checkChildStructure(B)()
3385 checkChildStructure(C)(D)
3386 checkChildStructure(D)(E)
3387
3388 E.unwrap()
3389 checkChildStructure(Main)(A)
3390 checkChildStructure(A)(B, C)
3391 checkChildStructure(B)()
3392 checkChildStructure(C)(E)
3393 checkChildStructure(D)()
3394
3395 B.unwrap()
3396 checkChildStructure(Main)(B, C)
3397 checkChildStructure(A)()
3398 checkChildStructure(B)()
3399 checkChildStructure(C)(E)
3400 checkChildStructure(D)()
3401
3402 E.unwrap()
3403 checkChildStructure(Main)(B, E)
3404 checkChildStructure(A)()
3405 checkChildStructure(B)()
3406 checkChildStructure(C)()
3407 checkChildStructure(D)()
3408
3409 A.insertAfter(B)
3410 C.appendTo(A)
3411 D.appendTo(A)
3412 checkChildStructure(Main)(B, A, E)
3413 checkChildStructure(A)(C, D)
3414 checkChildStructure(B)()
3415 checkChildStructure(C)()
3416 checkChildStructure(D)()
3417
3418 D.unwrap()
3419 checkChildStructure(Main)(B, C, D, E)
3420 checkChildStructure(A)()
3421 checkChildStructure(B)()
3422 checkChildStructure(C)()
3423 checkChildStructure(D)()
3424
3425
3426
3427 test ".replace()", ()->
3428 Main = Dom.div()
3429 A = Dom.div().appendTo(Main)
3430 B = Dom.div().appendTo(Main)
3431 C = Dom.div().appendTo(A)
3432 D = Dom.div().appendTo(A)
3433 E = Dom.div().appendTo(D)
3434
3435 A.replace(); E.replace()
3436 checkChildStructure(Main)(A, B)
3437 checkChildStructure(A)(C, D)
3438 checkChildStructure(B)()
3439 checkChildStructure(C)()
3440 checkChildStructure(D)(E)
3441
3442 C.replace(E).appendTo(B)
3443 checkChildStructure(Main)(A, B)
3444 checkChildStructure(A)(E, D)
3445 checkChildStructure(B)(C)
3446 checkChildStructure(C)()
3447 checkChildStructure(D)()
3448
3449 D.replace(E)
3450 checkChildStructure(Main)(A, B)
3451 checkChildStructure(A)(E)
3452 checkChildStructure(B)(C)
3453 checkChildStructure(C)()
3454 checkChildStructure(D)()
3455
3456 B.replace(C)
3457 checkChildStructure(Main)(A, C)
3458 checkChildStructure(A)(E)
3459 checkChildStructure(B)()
3460 checkChildStructure(C)()
3461 checkChildStructure(D)()
3462
3463 A.replace(D)
3464 checkChildStructure(Main)(D, C)
3465 checkChildStructure(A)(E)
3466 checkChildStructure(B)()
3467 checkChildStructure(C)()
3468 checkChildStructure(D)()
3469
3470 B.replace(D)
3471 checkChildStructure(Main)(C)
3472 checkChildStructure(A)(E)
3473 checkChildStructure(B)()
3474 checkChildStructure(C)()
3475 checkChildStructure(D)()
3476
3477
3478 test ".clone()", ()->
3479 emitCount = 0
3480 sandBox = Dom(sandbox)
3481 opts = {style: $base:{width:'34px'}, $happy:{height:'99px'}, $relaxed:{opacity:'0.5'}}
3482 A = Dom.div(opts, 'Some Inner Text').appendTo(sandbox)
3483 A.state 'happy', on
3484 A.on 'privateEvent', ()-> emitCount++
3485 childA = Dom.div().appendTo(A)
3486 childB = Dom.span().appendTo(A)
3487 B = A.clone()
3488
3489 A.state 'relaxed', on
3490 A.emit('privateEvent')
3491 expect(emitCount).to.equal(1)
3492 expect(A.parent).to.equal(sandBox)
3493 expect(A.css 'width').to.equal('34px')
3494 expect(A.css 'height').to.equal('99px')
3495 expect(A.css 'opacity').to.equal('0.5')
3496 expect(A.siblings.length).to.equal(0)
3497 expect(A.children.length).to.equal(3)
3498 expect(A.children[0].el.textContent).to.equal 'Some Inner Text'
3499 expect(A.children[1]).to.equal(childA)
3500 expect(A.children[2]).to.equal(childB)
3501 expect(B).not.to.equal(A)
3502 expect(B.parent).to.equal(undefined)
3503 sandBox.append(B)
3504
3505 expect(B.parent).to.equal(sandBox)
3506 expect(B.css 'width').to.equal('34px')
3507 expect(B.css 'height').to.equal('99px')
3508 expect(B.css 'opacity').to.equal('1')
3509 expect(B.siblings.length).to.equal(1)
3510 expect(B.children.length).to.equal(3)
3511 expect(B.children[0].el.textContent).to.equal 'Some Inner Text'
3512 expect(B.children[0]).not.to.equal(A.children[0])
3513 expect(B.children[1]).not.to.equal(childA)
3514 expect(B.children[2]).not.to.equal(childB)
3515 expect(B.state 'happy').to.be.true
3516 expect(B.state 'relaxed').to.be.false
3517
3518 expect(emitCount).to.equal(1)
3519 B.emit('privateEvent')
3520 expect(emitCount).to.equal(2)
3521
3522 A.off()
3523 A.emit('privateEvent')
3524 expect(emitCount).to.equal(2)
3525 B.emit('privateEvent')
3526 expect(emitCount).to.equal(3)
3527
3528
3529 test ".prop() - element property getter/setter", ()->
3530 div = Dom.div()
3531
3532 expect(div.prop 'myProp').to.equal undefined
3533 expect(div.prop 'myProp', 192).to.equal div
3534 expect(div.prop 'myProp').to.equal 192
3535 expect(div.prop 'myProp', '192').to.equal div
3536 expect(div.prop 'myProp').to.equal '192'
3537 expect(div.prop 'anotherProp', [1,2,3]).to.equal div
3538 expect(div.prop 'anotherProp').to.eql [1,2,3]
3539 expect(div.el.myProp).to.equal '192'
3540 expect(div.el.anotherProp).to.eql [1,2,3]
3541
3542 div.el.lastProp = 9999
3543 expect(div.el.lastProp).to.equal 9999
3544 expect(div.prop 'lastProp').to.equal 9999
3545
3546 expect(Object.keys(div.el)).not.to.contain('promiseIsLast')
3547
3548 div.prop 'promiseIsLast', 'over9k'
3549 expect(Object.keys(div.el)).to.contain('promiseIsLast')
3550
3551 div.prop 'promiseIsLast', undefined
3552 expect(Object.keys(div.el)).to.contain('promiseIsLast')
3553
3554 div.prop 'promiseIsLast', null
3555 expect(Object.keys(div.el)).to.contain('promiseIsLast')
3556
3557 div.prop {abc:123, def:456}
3558 expect(div.el.abc).to.equal 123
3559 expect(div.el.def).to.equal 456
3560
3561
3562 test ".attr() - element attribute getter/setter", ()->
3563 div = Dom.div()
3564
3565 expect(div.attr 'myAttr').to.equal null
3566 expect(div.attr 'myAttr', 192).to.equal div
3567 expect(div.attr 'myAttr').to.equal '192'
3568 expect(div.attr 'myAttr', '192').to.equal div
3569 expect(div.attr 'myAttr').to.equal '192'
3570 expect(div.attr 'anotherAttr', [1,2,3]).to.equal div
3571 expect(div.attr 'anotherAttr').to.equal '1,2,3'
3572 expect(div.el.getAttribute 'myAttr').to.equal '192'
3573 expect(div.el.getAttribute 'anotherAttr').to.eql '1,2,3'
3574
3575 div.el.setAttribute 'lastAttr', 9999
3576 expect(div.el.getAttribute 'lastAttr').to.equal '9999'
3577 expect(div.attr 'lastAttr').to.equal '9999'
3578
3579 expect(div.el.getAttribute 'promiseIsLast').to.equal null
3580
3581 div.attr 'promiseIsLast', 'over9k'
3582 expect(div.el.getAttribute 'promiseIsLast').to.equal 'over9k'
3583
3584 div.attr 'promiseIsLast'
3585 expect(div.el.getAttribute 'promiseIsLast').to.equal 'over9k'
3586
3587 div.attr 'promiseIsLast', null
3588 expect(div.el.getAttribute 'promiseIsLast').to.equal null
3589
3590 div.attr {abc:123, def:456}
3591 expect(div.el.getAttribute 'abc').to.equal '123'
3592 expect(div.el.getAttribute 'def').to.equal '456'
3593
3594 div.attr {abc:123, def:null}
3595 expect(div.el.getAttribute 'abc').to.equal '123'
3596 expect(div.el.getAttribute 'def').to.equal null
3597
3598
3599 test ".html - innerHTML getter/setter", ()->
3600 div = Dom.div(null, Dom.div(), 'Some text', Dom.span(), Dom.div())
3601
3602 expect(div.children.length).to.equal(4)
3603 expect(div.html).to.equal(div.el.innerHTML)
3604 expect(div.children.length).to.equal(4)
3605
3606 div.html = '<section ID="test"></section>'
3607 expect(div.html).to.equal('<section id="test"></section>')
3608 expect(div.children.length).to.equal(1)
3609 expect(div.children[0].el.id).to.equal('test')
3610 expect(div.children[0].el.nodeName.toLowerCase()).to.equal('section')
3611
3612
3613 test ".text - textContent getter/setter", ()->
3614 div = Dom.div(null, 'Some text', Dom.span(null, 'Inner Text'))
3615
3616 expect(div.children.length).to.equal(2)
3617 expect(div.text).to.equal(div.el.textContent)
3618 expect(div.text).to.equal('Some textInner Text')
3619 expect(div.children.length).to.equal(2)
3620
3621 div.text = 'newText'
3622 expect(div.text).to.equal('newText')
3623 expect(div.el.textContent).to.equal('newText')
3624 expect(div.children.length).to.equal(1)
3625 expect(div.children[0].el.nodeType).to.equal(3)
3626
3627
3628 test ".addClass", ()->
3629 div = Dom.div class:'some-selector anotherSelector .period annoying-_-selector '
3630
3631 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector '
3632
3633 div.addClass('new-selector')
3634 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector new-selector'
3635
3636 div.addClass('new-selector')
3637 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector new-selector'
3638
3639 div.raw.className = div.raw.className.replace 'new-selector', ' '
3640 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector '
3641
3642 div.addClass('new-selector')
3643 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector new-selector'
3644
3645 div.addClass('.period')
3646 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector new-selector'
3647
3648 div.addClass('period')
3649 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector new-selector period'
3650
3651
3652 test ".removeClass", ()->
3653 div = Dom.div class:'some-selector anotherSelector .period annoying-_-selector '
3654
3655 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector '
3656
3657 div.addClass('new-selector')
3658 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector new-selector'
3659
3660 div.removeClass('new-selector')
3661 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector'
3662
3663 div.removeClass('new-selector')
3664 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector'
3665
3666 div.removeClass('some-selector')
3667 expect(div.raw.className).to.equal 'anotherSelector .period annoying-_-selector'
3668
3669 div.removeClass('period')
3670 expect(div.raw.className).to.equal 'anotherSelector .period annoying-_-selector'
3671
3672 div.removeClass('.period')
3673 expect(div.raw.className).to.equal 'anotherSelector annoying-_-selector'
3674
3675
3676 test ".toggleClass", ()->
3677 div = Dom.div class:'some-selector anotherSelector .period annoying-_-selector '
3678
3679 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector '
3680
3681 div.toggleClass('new-selector')
3682 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector new-selector'
3683
3684 div.toggleClass('new-selector')
3685 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector'
3686
3687 div.toggleClass('new-selector')
3688 expect(div.raw.className).to.equal 'some-selector anotherSelector .period annoying-_-selector new-selector'
3689
3690 div.toggleClass('new-selector')
3691 div.toggleClass('some-selector')
3692 expect(div.raw.className).to.equal 'anotherSelector .period annoying-_-selector'
3693
3694 div.toggleClass('some-selector')
3695 expect(div.raw.className).to.equal 'anotherSelector .period annoying-_-selector some-selector'
3696
3697 div.toggleClass('period')
3698 expect(div.raw.className).to.equal 'anotherSelector .period annoying-_-selector some-selector period'
3699
3700 div.toggleClass('.period')
3701 expect(div.raw.className).to.equal 'anotherSelector annoying-_-selector some-selector period'
3702
3703 div.toggleClass('annoying-_-selector')
3704 expect(div.raw.className).to.equal 'anotherSelector some-selector period'
3705
3706
3707 test ".setRef", ()->
3708 el = DOM.div(ref:'name1')
3709 expect(el.ref).to.equal 'name1'
3710 expect(el.options.ref).to.equal 'name1'
3711 expect(el.attr 'data-ref').to.equal 'name1'
3712
3713 el.setRef 'name2'
3714 expect(el.ref).to.equal 'name2'
3715 expect(el.options.ref).to.equal 'name2'
3716 expect(el.attr 'data-ref').to.equal 'name2'
3717
3718
3719
3720
3721 test "Appending/prepending elements to a text node should do nothing", ()->
3722 text = Dom.text('abc123')
3723 expect(text.text).to.equal('abc123')
3724 expect(text.raw.childNodes.length).to.equal(0)
3725
3726 text.append(Dom.text('def'))
3727 expect(text.text).to.equal('abc123')
3728 expect(text.raw.childNodes.length).to.equal(0)
3729
3730 text.prepend(Dom.div(null, 'def'))
3731 expect(text.text).to.equal('abc123')
3732 expect(text.raw.childNodes.length).to.equal(0)
3733
3734 div = Dom.div(null, '456')
3735 div.appendTo(text)
3736 expect(text.text).to.equal('abc123')
3737 expect(text.raw.childNodes.length).to.equal(0)
3738 expect(div.parent).to.equal(undefined)
3739
3740
3741
3742
3743 suite "Batch", ()->
3744 test "Dom.batch() takes an iterable containing an array of elements or QuickDom elements and reveals the QuickElement API which will be applied for each element", ()->
3745 sandBox = Dom(sandbox)
3746 div = Dom.div()
3747 A = Dom.div().appendTo(div)
3748 B = Dom.section().appendTo(div)
3749 C = Dom.div().appendTo(div)
3750
3751 checkChildStructure(sandBox)()
3752 checkChildStructure(div)(A, B, C)
3753
3754 Dom.batch([A,B,C])
3755 .appendTo(sandBox)
3756 .style 'opacity', 0.5
3757 .css {height:30, backgroundColor:'pink'}
3758 .append 'Some Inner Text'
3759
3760 checkChildStructure(sandBox)(A, B, C)
3761 checkChildStructure(div)()
3762
3763 expect(getComputedStyle(A.el).opacity).to.equal('0.5')
3764 expect(getComputedStyle(C.el).opacity).to.equal('0.5')
3765 expect(getComputedStyle(B.el).height).to.equal('30px')
3766 expect(A.children.length).to.equal(1)
3767 expect(B.children.length).to.equal(1)
3768 expect(C.children.length).to.equal(1)
3769 expect(B.children[0].el.textContent).to.equal('Some Inner Text')
3770
3771
3772 test "If a truthy value is passed as the 2nd arg of Dom.batch(), an array will be returned for the first method invoked containing the result for each element provided", ()->
3773 sandBox = Dom(sandbox)
3774 A = Dom.div().appendTo(sandBox)
3775 B = Dom.section().appendTo(sandBox)
3776 C = Dom.div().appendTo(sandBox)
3777
3778 batch1 = Dom.batch([A,B,C])
3779 batch2 = Dom.batch([A,B,C], true)
3780
3781 expect(batch1.style('width')).to.equal(batch1)
3782 expect(batch1.style('width', 47)).to.equal(batch1)
3783 expect(batch2.style('width')).to.eql(['47px', '47px', '47px'])
3784 expect(batch2.style('width', 33)).to.eql([A,B,C])
3785 expect(batch2.style('width')).to.eql(['33px', '33px', '33px'])
3786
3787
3788 test "If the .return() method is invoked on the batch instance, it will return the result set from the last method invocation", ()->
3789 sandBox = Dom(sandbox)
3790 div = Dom.div()
3791 A = Dom.div().appendTo(div)
3792 B = Dom.section().appendTo(div)
3793 C = Dom.div().appendTo(div)
3794
3795 result = Dom.batch([A,B,C])
3796 .appendTo(sandBox)
3797 .style 'opacity', 0.5
3798 .css {height:30, backgroundColor:'pink'}
3799 .append 'Some Inner Text'
3800 .style 'opacity'
3801 .return()
3802
3803 expect(result).to.eql ['0.5','0.5','0.5']
3804 expect(Dom.batch([A,B,C]).css('width', '38px').css('width').return()).to.eql ['38px','38px','38px']
3805
3806
3807 test "If the .return() method is invoked with a truthy argument, it will cause the next method invocation to return the results of the invocation for each element provided", ()->
3808 sandBox = Dom(sandbox)
3809 div = Dom.div()
3810 A = Dom.div().appendTo(div)
3811 B = Dom.section().appendTo(div)
3812 C = Dom.div().appendTo(div)
3813
3814 result = Dom.batch([A,B,C])
3815 .appendTo(sandBox)
3816 .style 'opacity', 0.5
3817 .css {height:30, backgroundColor:'pink'}
3818 .append 'Some Inner Text'
3819 .return(true)
3820 .style 'opacity'
3821
3822 expect(result).to.eql ['0.5','0.5','0.5']
3823 expect(Dom.batch([A,B,C]).css('width', '38px').css('height', '28px').return(true).css('width')).to.eql ['38px','38px','38px']
3824
3825
3826 test "Invoking the .reverse() method on the batch instance will reverse the elements array in the batch and thus the execution order", ()->
3827 A = Dom.div(null, 'AAA').appendTo(sandbox)
3828 B = Dom.div(null, 'BBB').appendTo(sandbox)
3829 C = Dom.div(null, 'CCC').appendTo(sandbox)
3830 arr = [A,B,C]
3831 expect(Dom.batch(arr).elements).not.to.equal(arr)
3832 expect(Dom.batch(arr).elements).to.eql [A,B,C]
3833 expect(Dom.batch(arr).reverse().elements).to.eql [C,B,A]
3834 expect(Dom.batch(arr,1).text()).to.eql ['AAA','BBB','CCC']
3835 expect(Dom.batch(arr,1).reverse().text()).to.eql ['CCC','BBB','AAA']
3836 expect(Dom.batch(arr,1).reverse().text()).to.eql ['CCC','BBB','AAA']
3837 expect(Dom.batch(arr,1).reverse().reverse().text()).to.eql ['AAA','BBB','CCC']
3838
3839
3840 test "Batch.text/.html are methods instead of getters/setters", ()->
3841 divA = Dom.div(null, 'The divA')
3842 divB = Dom.div(null, 'The divB')
3843 batch = Dom.batch([divA, divB], true)
3844
3845 expect(batch.html()).to.eql ['The divA', 'The divB']
3846 expect(batch.text()).to.eql ['The divA', 'The divB']
3847
3848 batch.html('<span>The div</span>')
3849 expect(batch.html()).to.eql ['<span>The div</span>', '<span>The div</span>']
3850 expect(batch.text()).to.eql ['The div', 'The div']
3851
3852 batch.text('THE DIV')
3853 expect(batch.html()).to.eql ['THE DIV', 'THE DIV']
3854 expect(batch.text()).to.eql ['THE DIV', 'THE DIV']
3855
3856
3857
3858 suite "Templates", ()->
3859 test "A reusable template can be generated via QuickDom.template()", ()->
3860 template = Dom.template(['span', id:'theSpan'])
3861
3862 expect(typeof template).to.equal('object')
3863 expect(template.type).to.equal('span')
3864 expect(template.options).to.eql(id:'theSpan')
3865 expect(template.children).to.eql([])
3866
3867
3868 test "Templates can be turned into QuickDom instances via template.spawn() or by passing as arg to QuickDom", ()->
3869 template = Dom.template(['div', className:'some-div', 'Some Inner Text'])
3870 spawnA = template.spawn()
3871 spawnA.state 'happy', on
3872 spawnB = Dom(template)
3873
3874 expect(spawnA.el).to.be.instanceOf(HTMLDivElement)
3875 expect(spawnB.el).to.be.instanceOf(HTMLDivElement)
3876 expect(spawnA).not.to.equal(spawnB)
3877 expect(spawnA.el).not.to.equal(spawnB.el)
3878 expect(spawnA.state 'happy').to.be.true
3879 expect(spawnB.state 'happy').to.be.false
3880 expect(spawnA.el.textContent).to.equal('Some Inner Text')
3881 expect(spawnB.el.textContent).to.equal('Some Inner Text')
3882 expect(spawnA.el.className).to.equal('some-div')
3883
3884
3885 test "Templates can be created from QuickElement instances", ()->
3886 section = Dom.section(className:'singleSection', 'Some Inner Text')
3887 section.state 'happy', on
3888 sectionTemplate = section.toTemplate()
3889 templateSpawn = sectionTemplate.spawn()
3890
3891 expect(sectionTemplate).not.to.equal(section)
3892 expect(templateSpawn.el).not.to.equal(section.el)
3893 expect(templateSpawn.el.className).to.equal('singleSection')
3894 expect(templateSpawn.text).to.equal('Some Inner Text')
3895 expect(section.state 'happy').to.be.true
3896 expect(templateSpawn.state 'happy').to.be.false
3897
3898
3899 test "Templates can be created from DOM Elements", ()->
3900 sectionEl = document.createElement('section')
3901 sectionEl.className = 'singleSection'
3902 sectionEl.appendChild(document.createTextNode 'Some Inner Text')
3903 sectionTemplate = Dom.template(sectionEl)
3904 templateSpawn = sectionTemplate.spawn()
3905
3906 expect(templateSpawn.el).not.to.equal(sectionEl)
3907 expect(templateSpawn.el.className).to.equal('singleSection')
3908 expect(templateSpawn.text).to.equal('Some Inner Text')
3909
3910
3911 test "Templates can be extended via template.extend", ()->
3912 template = Dom.template(['div', className:'some-div', 'Some Inner Text'])
3913 templateCopyA = template.extend {type:'span', options:{className:'some-span'}, children:[]}
3914 templateCopyB = template.extend {options:{id:'theMainDiv'}, children:['The Other Inner Text']}
3915 templateCopyC = template.extend(
3916 ['section'
3917 className:'some-section'
3918 ['div', null, 'Very ']
3919 ['div', null
3920 ['span', {style:fontWeight:500},'Nested ']
3921 'Inner Text'
3922 ]
3923 ]
3924 )
3925
3926 expect(templateCopyA).not.to.equal(template)
3927 expect(templateCopyB).not.to.equal(template)
3928 spawn = template.spawn()
3929 spawnA = templateCopyA.spawn()
3930 spawnB = templateCopyB.spawn()
3931 spawnC = templateCopyC.spawn()
3932
3933 expect(spawn.el.nodeName.toLowerCase()).to.equal('div')
3934 expect(spawn.el.className).to.equal('some-div')
3935 expect(spawn.el.id).to.equal('')
3936 expect(spawn.text).to.equal('Some Inner Text')
3937
3938 expect(spawnA.el.nodeName.toLowerCase()).to.equal('span')
3939 expect(spawnA.el.className).to.equal('some-span')
3940 expect(spawnA.el.id).to.equal('')
3941 expect(spawnA.text).to.equal('Some Inner Text')
3942
3943 expect(spawnB.el.nodeName.toLowerCase()).to.equal('div')
3944 expect(spawnB.el.className).to.equal('some-div')
3945 expect(spawnB.el.id).to.equal('theMainDiv')
3946 expect(spawnB.text).to.equal('The Other Inner Text')
3947
3948 expect(spawnC.el.nodeName.toLowerCase()).to.equal('section')
3949 expect(spawnC.el.className).to.equal('some-section')
3950 expect(spawnC.el.id).to.equal('')
3951 expect(spawnC.text).to.equal('Very Nested Inner Text')
3952
3953
3954 test "Templates can be spawned via extended config by passing a new config object to template.spawn()", ()->
3955 template = Dom.template(
3956 ['div', className:'some-div',
3957 'Some Inner Text',
3958 ['strong', {className:'highlighted', style:{opacity:0.9}}, ' - Bolded Text']
3959 ]
3960 )
3961 spawnRaw = template.spawn().appendTo(sandbox)
3962 spawnA = template.spawn(type:'section', options:{className:'some-section', style:{opacity:0.7}}).appendTo(sandbox)
3963 spawnB = template.spawn(
3964 options:
3965 className: 'main-div'
3966 id: 'theMainDiv'
3967 style: opacity: 0.5
3968 children: [
3969 {
3970 type: 'span'
3971 children: [
3972 type:'text'
3973 options: {text: 'Main Inner Text'}
3974 ]
3975 }
3976 {
3977 type: 'b'
3978 options:
3979 className: 'super-highlighted'
3980 style: opacity: '0.2'
3981 children: [
3982 options: {text: ' - Very Bolded Text'}
3983 ]
3984 }
3985 {
3986 type: 'text'
3987 options: {text: ' + Other Text'}
3988 }
3989 ]
3990 ).appendTo(sandbox)
3991
3992 expect(spawnRaw.el.nodeName.toLowerCase()).to.equal('div')
3993 expect(spawnRaw.el.className).to.equal('some-div')
3994 expect(spawnRaw.el.id).to.equal('')
3995 expect(spawnRaw.text).to.equal('Some Inner Text - Bolded Text')
3996 expect(spawnRaw.el).to.have.style('opacity','1')
3997 expect(spawnRaw.el.childNodes.length).to.equal(2)
3998 expect(spawnRaw.el.childNodes[0].nodeName).to.equal('#text')
3999 expect(spawnRaw.el.childNodes[1].nodeName.toLowerCase()).to.equal('strong')
4000 expect(spawnRaw.el.childNodes[1].className).to.include('highlighted')
4001 expect(spawnRaw.el.childNodes[1]).to.have.style('opacity', '0.9')
4002
4003 expect(spawnA.el.nodeName.toLowerCase()).to.equal('section')
4004 expect(spawnA.el.className).to.include('some-section')
4005 expect(spawnA.el.id).to.equal('')
4006 expect(spawnA.text).to.equal('Some Inner Text - Bolded Text')
4007 expect(spawnA.el).to.have.style('opacity','0.7')
4008 expect(spawnA.el.childNodes.length).to.equal(2)
4009 expect(spawnA.el.childNodes[0].nodeName).to.equal('#text')
4010 expect(spawnA.el.childNodes[1].nodeName.toLowerCase()).to.equal('strong')
4011 expect(spawnA.el.childNodes[1].className).to.include('highlighted')
4012 expect(spawnA.el.childNodes[1]).to.have.style('opacity', '0.9')
4013
4014 expect(spawnB.el.nodeName.toLowerCase()).to.equal('div')
4015 expect(spawnB.el.className).to.include('main-div')
4016 expect(spawnB.el.id).to.equal('theMainDiv')
4017 expect(spawnB.text).to.equal('Main Inner Text - Very Bolded Text + Other Text')
4018 expect(spawnB.el).to.have.style('opacity','0.5')
4019 expect(spawnB.el.childNodes.length).to.equal(3)
4020 expect(spawnB.el.childNodes[0].nodeName.toLowerCase()).to.equal('span')
4021 expect(spawnB.el.childNodes[0].childNodes.length).to.equal(1)
4022 expect(spawnB.el.childNodes[1].nodeName.toLowerCase()).to.equal('b')
4023 expect(spawnB.el.childNodes[1].className).to.include('super-highlighted')
4024 expect(spawnB.el.childNodes[1]).to.have.style('opacity', '0.2')
4025
4026
4027 test "Template.extend/spawn() can accept a template tree array", ()->
4028 template = Dom.template ['div', style:{'opacity':0.5}, ['span', null, 'text of span'], ['div', null, 'text of div']]
4029 cloneA = template.extend(['section', style:{'opacity':0.8}])
4030 cloneB = template.extend(['span', null, ['div']])
4031 cloneC = template.extend(['section', {className:'the-section', style:{color:'blue'}}, ['section', null, 'text of subsection'], 'just a text node'])
4032 spawn = template.spawn(['span', style:{'width':190, 'opacity':0.4}, 'so nice']).appendTo(sandbox)
4033
4034 expect(template.type).to.equal 'div'
4035 expect(template.options).to.eql {style:{'opacity':0.5}}
4036 expect(template.children.length).to.equal 2
4037 expect(template.children[0].type).to.equal 'span'
4038 expect(template.children[0].children.length).to.equal 1
4039 expect(template.children[0].children[0].options.text).to.equal 'text of span'
4040 expect(template.children[1].type).to.equal 'div'
4041 expect(template.children[1].children.length).to.equal 1
4042 expect(template.children[1].children[0].options.text).to.equal 'text of div'
4043
4044 expect(cloneA.type).to.equal 'section'
4045 expect(cloneA.options).to.eql {style:{'opacity':0.8}}
4046 expect(cloneA.children.length).to.equal 2
4047 expect(cloneA.children[0].type).to.equal 'span'
4048 expect(cloneA.children[0].children.length).to.equal 1
4049 expect(cloneA.children[0].children[0].options.text).to.equal 'text of span'
4050 expect(cloneA.children[1].type).to.equal 'div'
4051 expect(cloneA.children[1].children.length).to.equal 1
4052 expect(cloneA.children[1].children[0].options.text).to.equal 'text of div'
4053
4054 expect(cloneB.type).to.equal 'span'
4055 expect(cloneB.options).to.eql {style:{'opacity':0.5}}
4056 expect(cloneB.children.length).to.equal 2
4057 expect(cloneB.children[0].type).to.equal 'div'
4058 expect(cloneB.children[0].children.length).to.equal 1
4059 expect(cloneB.children[0].children[0].options.text).to.equal 'text of span'
4060 expect(cloneB.children[1].type).to.equal 'div'
4061 expect(cloneB.children[1].children.length).to.equal 1
4062 expect(cloneB.children[1].children[0].options.text).to.equal 'text of div'
4063
4064 expect(cloneC.type).to.equal 'section'
4065 expect(cloneC.options).to.eql {className:'the-section', style:{'opacity':0.5, 'color':'blue'}}
4066 expect(cloneC.children.length).to.equal 2
4067 expect(cloneC.children[0].type).to.equal 'section'
4068 expect(cloneC.children[0].children.length).to.equal 1
4069 expect(cloneC.children[0].children[0].options.text).to.equal 'text of subsection'
4070 expect(cloneC.children[1].type).to.equal 'text'
4071 expect(cloneC.children[1].options.text).to.equal 'just a text node'
4072
4073 spawn.style 'display', 'block'
4074 expect(spawn.el.nodeName.toLowerCase()).to.equal 'span'
4075 expect(spawn.el).to.have.style 'opacity', '0.4'
4076 expect(spawn.el).to.have.style 'width', '190px'
4077 expect(spawn.el.childNodes.length).to.equal 2
4078 expect(spawn.el.childNodes[0].nodeType).to.equal 3
4079 expect(spawn.el.childNodes[0].textContent).to.equal 'so nice'
4080 expect(spawn.el.childNodes[1].nodeName.toLowerCase()).to.equal 'div'
4081 expect(spawn.el.childNodes[1].textContent).to.equal 'text of div'
4082
4083 # expect ()->
4084 # Dom.template(['div']).extend(['span', null, ['div', null, ['section']]])
4085 # .not.to.throw()
4086
4087
4088 test "Template.extend/spawn() can accept other template instances as children which will replace existing children", ()->
4089 template = Dom.template ['div', null, ['span', {style:opacity:0.5}], 'original text']
4090 childA = Dom.template ['div', {style:fontFamily:'pink'}]
4091 childB = Dom.template 'replaced text'
4092 childC = Dom.template ['section']
4093 templateCopy = template.extend(['span', {style:fontSize:'77px'}, childA, childB, childC])
4094 spawnedA = template.spawn().appendTo(sandbox)
4095 spawnedB = templateCopy.spawn().appendTo(sandbox)
4096 spawnedC = template.spawn(['span', {style:fontSize:'77px'}, childA, childB, childC]).appendTo(sandbox)
4097
4098 expect(spawnedA.type).to.equal('div')
4099 expect(spawnedA.children.length).to.equal(2)
4100 expect(spawnedA.children[0].type).to.equal('span')
4101 expect(spawnedA.children[0].raw).to.have.style('opacity', '0.5')
4102 expect(spawnedA.children[0].raw).to.have.style('fontFamily', '')
4103 expect(spawnedA.children[1].type).to.equal('text')
4104 expect(spawnedA.text).to.equal('original text')
4105
4106 expect(spawnedB.type).to.equal('span')
4107 expect(spawnedB.children.length).to.equal(3)
4108 expect(spawnedB.children[0].type).to.equal('div')
4109 expect(spawnedB.children[0].raw).to.have.style('opacity', '')
4110 expect(spawnedB.children[0].raw).to.have.style('fontFamily', 'pink')
4111 expect(spawnedB.children[1].type).to.equal('text')
4112 expect(spawnedB.text).to.equal('replaced text')
4113 expect(spawnedB.children[2].type).to.equal('section')
4114 expect(spawnedB.raw).to.have.style('fontSize', '77px')
4115
4116 expect(spawnedC.type).to.equal('span')
4117 expect(spawnedC.children.length).to.equal(3)
4118 expect(spawnedC.children[0].type).to.equal('div')
4119 expect(spawnedC.children[0].raw).to.have.style('opacity', '')
4120 expect(spawnedC.children[0].raw).to.have.style('fontFamily', 'pink')
4121 expect(spawnedC.children[1].type).to.equal('text')
4122 expect(spawnedC.text).to.equal('replaced text')
4123 expect(spawnedC.children[2].type).to.equal('section')
4124 expect(spawnedC.raw).to.have.style('fontSize', '77px')
4125
4126
4127 test "Template.extend/spawn() will consider the passed object as the options object if it doesn't contain template-related props", ()->
4128 template = DOM.template(
4129 ['div'
4130 defaults: text: 'default'
4131 computers: text: (text)-> @text = text
4132
4133 ['span', ref:'theSpan']
4134 ]
4135 )
4136
4137 expect(template.options.style).to.equal undefined
4138 expect(template.options.label).to.equal undefined
4139 expect(template.extend(options:label:'abc123').options.label).to.equal 'abc123'
4140 expect(template.extend(label:'def456').options.label).to.equal 'def456'
4141 expect(template.extend(style:'def456').options.style).to.equal 'def456'
4142 expect(template.extend(style:'def456', type:'section').options.style).to.equal undefined
4143 expect(template.extend(children:theSpan:style:'ghi789').child.theSpan.options.style).to.equal 'ghi789'
4144 expect(template.extend(children:[defaults:'ghi789']).child.theSpan.options.defaults).to.equal 'ghi789'
4145 expect(template.spawn(children:theSpan:className:'GHI789').child.theSpan.raw.className).to.equal 'GHI789'
4146 expect(template.spawn().text).to.equal 'default'
4147 expect(template.spawn(defaults:text:'diff').text).to.equal 'diff'
4148
4149
4150 test "Templates can have other templates as their children", ()->
4151 headerTemplate = Dom.template ['header', {style:'height':'200px'},
4152 ['span', {style:'textAlign':'center'}, 'This is bolded text']
4153 ' while this is not'
4154 ]
4155 headerTemplateClone = Dom.template(headerTemplate)
4156 sectionTemplate = Dom.template ['section', null, headerTemplate]
4157 section = sectionTemplate.spawn().appendTo(sandbox)
4158
4159 expect(headerTemplateClone).to.equal(headerTemplate)
4160 expect(sectionTemplate.children.length).to.equal(1)
4161 expect(sectionTemplate.children[0]).to.equal(headerTemplate)
4162 expect(sectionTemplate.children[0].children.length).to.equal(2)
4163 expect(section.children.length).to.equal(1)
4164 expect(section.children[0].type).to.equal('header')
4165 expect(section.children[0].children.length).to.equal(2)
4166 expect(section.text).to.equal('This is bolded text while this is not')
4167 expect(section.children[0].children[0].style('textAlign')).to.equal('center')
4168
4169
4170 test "A global options object can be passed as the 2nd arg to template.extend/spawn() which will be applied to all templates, spawns, & their children", ()->
4171 obj = myHeight:'150px'
4172 obj.obj = obj
4173 dynamicHeightStyle = 'height': (related)-> expect(related).to.equal(obj); related.myHeight
4174
4175 headerTemplate = Dom.template ['header', {style:'width':'23px'},
4176 ['div', {style:'width':'23px'}, 'This is bolded text']
4177 ' while this is not'
4178 ]
4179 sectionTemplate = Dom.template ['section', {style:'width':'23px'}, headerTemplate]
4180 section = sectionTemplate.spawn({options:{related:window}}, {related:obj, style:dynamicHeightStyle}).appendTo(sandbox)
4181
4182 expect(section.raw.style.height).to.equal('150px')
4183 expect(section.children[0].raw.style.height).to.equal('150px')
4184 expect(section.children[0].children[0].raw.style.height).to.equal('150px')
4185 expect(section.raw.style.width).to.equal('')
4186 expect(section.children[0].raw.style.width).to.equal('')
4187 expect(section.children[0].children[0].raw.style.width).to.equal('')
4188 expect(section.children.length).to.equal(1)
4189 expect(section.children[0].type).to.equal('header')
4190 expect(section.children[0].children.length).to.equal(2)
4191 expect(section.text).to.equal('This is bolded text while this is not')
4192
4193
4194 test "Template children can be navigated by ref using the .child property", ()->
4195 template =
4196 Dom.template ['div', {id:'divA'},
4197 ['div', {id:'childA'},
4198 ['span', {ref:'childA_1'}]
4199 ['div', {ref:'childA_2', id:'childA_2'}]
4200 ]
4201 ['div', null,
4202 ['span', {ref:'childB_1'}]
4203 ['text', {id:'childB_2', text:'The Text'}]
4204 ]
4205 ]
4206
4207 expect(typeof template.child).to.equal 'object'
4208 expect(Object.keys(template.child).length).to.equal(6)
4209 expect(template.child.divA).to.equal template
4210 expect(template.child.childA.type).to.equal 'div'
4211 expect(template.child.childA).to.equal template.children[0]
4212 expect(template.child.childA_1).to.equal template.children[0].children[0]
4213 expect(template.child.childA_2).to.equal template.children[0].children[1]
4214 expect(template.child.childB_1).to.equal template.children[1].children[0]
4215 expect(template.child.childB_2).to.equal template.children[1].children[1]
4216
4217 rendered = template.spawn()
4218 expect(rendered.child.childB_2).to.equal rendered.children[1].children[1]
4219 expect(rendered.text).to.equal('The Text')
4220
4221
4222 test "Template's children can be extend/spawned with a {ref:newChild} map instead of a positional array", ()->
4223 templateMain =
4224 Dom.template ['div', {id:'divA'},
4225 ['div', {id:'childA'},
4226 ['span', {ref:'childA_1'}]
4227 ['div', {ref:'childA_2', id:'childA_2'}]
4228 ]
4229 ['div', null,
4230 ['span', {ref:'childB_1'}]
4231 ['text', {id:'childB_2', text:'The Text'}]
4232 ]
4233 ]
4234 templateCopy = templateMain.extend ['section', null,
4235 childA:
4236 type: 'form'
4237 options:
4238 style: display: 'inline-block'
4239 childA_2:
4240 ['a', {id:'CHILDa_2', href:'http://google.com'},
4241 ['text', {ref:'childA_2_1', text:'New Text'}]
4242 ]
4243 childC:
4244 ['div', ref:'childD']
4245 ], {value:'theValue'}
4246
4247 templateCopy2 = templateMain.extend children:
4248 childA:
4249 children: newChild: ['div']
4250 childA_2:
4251 ['a', {id:'CHILDa_2', href:'http://google.com'},
4252 ['text', {ref:'childA_2_1', text:'New Text'}]
4253 ]
4254 childC:
4255 ['div', ref:'childD']
4256
4257 expect(typeof templateCopy.child.childA_2_1).not.to.equal 'undefined'
4258 expect(Object.keys(templateMain.child).length).to.equal(6)
4259 expect(Object.keys(templateCopy.child).length).to.equal(8)
4260 expect(templateCopy.children.length).to.equal(3)
4261 expect(templateCopy.child.divA).to.equal templateCopy
4262 expect(templateCopy.child.childA).to.equal templateCopy.children[0]
4263 expect(templateCopy.child.childA.type).to.equal 'form'
4264 expect(templateCopy.child.childA_1).to.equal templateCopy.children[0].children[0]
4265 expect(templateCopy.child.childA_2).to.equal undefined
4266 expect(templateCopy.child.CHILDa_2).to.equal templateCopy.children[0].children[1]
4267 expect(templateCopy.child.childA_2_1).to.equal templateCopy.children[0].children[1].children[0]
4268 expect(templateCopy.child.childA_2_1.options.text).to.equal 'New Text'
4269 expect(templateCopy.child.childB_1).to.equal templateCopy.children[1].children[0]
4270 expect(templateCopy.child.childB_2).to.equal templateCopy.children[1].children[1]
4271 expect(templateCopy.child.childC).to.equal undefined
4272 expect(templateCopy.child.childD).to.equal templateCopy.children[2]
4273
4274 rendered = templateCopy.spawn().appendTo(sandbox)
4275 expect(Object.keys(rendered.child).length).to.equal(8)
4276 expect(rendered.child.childB_2).to.equal rendered.children[1].children[1]
4277 expect(rendered.child.childA.raw).to.have.style 'display', 'inline-block'
4278 expect(rendered.child.CHILDa_2.prop('href')).to.contain 'http://google.com'
4279 expect(rendered.child.childB_1.prop('value')).to.equal('theValue')
4280 expect(rendered.child.childD.attr('data-ref')).to.equal('childD')
4281
4282
4283 test "Templates can be passed as replacement/new children in {ref:newChild} extension maps", ()->
4284 childA = Dom.template(
4285 ['div', {id:'childA'},
4286 ['span', {ref:'childA_1'}]
4287 ['div', {ref:'childA_2', id:'childA_2'}]
4288 ]
4289 )
4290 childB = Dom.template(
4291 ['div', ref:'childB',
4292 ['span', {ref:'childB_1'}]
4293 ['text', {id:'childB_2', text:'The Text'}]
4294 ]
4295 )
4296 childC = Dom.template(
4297 ['div', {id:'childC'},
4298 ['span', {ref:'childC_1'}]
4299 ['text', {id:'childC_2', text:'The Text'}]
4300 ]
4301 )
4302 templateMain =
4303 Dom.template ['div', {id:'divA'},
4304 childA,
4305 childB
4306 ]
4307 templateCopy = templateMain.extend ['section', null,
4308 childA: type: 'form'
4309 childB: childB.extend(ref:'ChildB')
4310 childC: childC.extend(ref:'ChildC')
4311 ], {value:'theValue'}
4312
4313 expect(Object.keys(templateMain.child).length).to.equal(7)
4314 expect(Object.keys(templateCopy.child).length).to.equal(10)
4315 expect(templateMain.children.length).to.equal(2)
4316 expect(templateCopy.children.length).to.equal(3)
4317 expect(templateCopy.child.divA).to.equal templateCopy
4318 expect(templateCopy.child.childA).to.equal templateCopy.children[0]
4319 expect(templateCopy.child.childA.type).to.equal 'form'
4320 expect(templateCopy.child.childA.children.length).to.equal(2)
4321 expect(templateCopy.child.ChildB).to.equal templateCopy.children[1]
4322 expect(templateCopy.child.childB_1).to.equal templateCopy.children[1].children[0]
4323 expect(templateCopy.child.childB_2).to.equal templateCopy.children[1].children[1]
4324 expect(templateMain.child.childC).to.equal undefined
4325 expect(templateCopy.child.childC).to.equal undefined
4326 expect(templateCopy.child.ChildC).to.equal templateCopy.children[2]
4327 expect(Object.keys(templateMain.spawn().child).length).to.equal(7)
4328 expect(Object.keys(templateCopy.spawn().child).length).to.equal(10)
4329
4330
4331 test "ref-children maps shouldn't be modified by the template extender", ()->
4332 config = children: childA_1: {type:'div', options: {style: {display:'none'}}}
4333 templateA = Dom.template(
4334 ['div', {ref:'divA'}
4335 ['div', {ref:'childA'}
4336 ['span', {ref:'childA_1'}]
4337 ]
4338 ]
4339 )
4340 templateA.child.childA_1
4341 templateB = templateA.extend()
4342 templateC = templateA.extend(config)
4343 templateD = templateA.extend(config)
4344 spawnA = templateA.spawn().appendTo(sandbox)
4345 spawnB = templateB.spawn().appendTo(sandbox)
4346 spawnC = templateC.spawn().appendTo(sandbox)
4347 spawnD = templateD.spawn().appendTo(sandbox)
4348 expect(spawnA.child.childA_1.type).to.equal 'span'
4349 expect(spawnA.child.childA_1.style 'display').to.equal 'inline'
4350 expect(spawnB.child.childA_1.type).to.equal 'span'
4351 expect(spawnB.child.childA_1.style 'display').to.equal 'inline'
4352 expect(spawnC.child.childA_1.type).to.equal 'div'
4353 expect(spawnC.child.childA_1.style 'display').to.equal 'none'
4354 expect(spawnD.child.childA_1.type).to.equal 'div'
4355 expect(spawnD.child.childA_1.style 'display').to.equal 'none'
4356
4357 test "Null values in ref-children map will remove the child from the template", ()->
4358 templateMain =
4359 Dom.template ['div', {id:'divA'},
4360 ['div', {id:'childA'},
4361 ['span', {ref:'childA_1'}]
4362 ['div', {ref:'childA_2', id:'childA_2'}]
4363 ]
4364 ['div', {ref:'childB'},
4365 ['span', {ref:'childB_1'}]
4366 ['text', {id:'childB_2', text:'The Text'}]
4367 ]
4368 ['div', {id:'childC'},
4369 ['span', {ref:'childC_1'}]
4370 ['text', {id:'childC_2', text:'The Text'}]
4371 ]
4372 ]
4373 templateCopy = templateMain.extend ['section', null,
4374 childA:
4375 type: 'form'
4376 options:
4377 style: display: 'inline-block'
4378
4379 childA_1: null
4380 childA_2:
4381 ['a', {id:'CHILDa_2', href:'http://google.com'},
4382 ['text', {ref:'childA_2_1', text:'New Text'}]
4383 ]
4384 childB_1: null
4385 childC: null
4386 ]
4387
4388 expect(typeof templateCopy.child.childA_2_1).not.to.equal 'undefined'
4389 expect(Object.keys(templateMain.child).length).to.equal(10)
4390 expect(Object.keys(templateCopy.child).length).to.equal(6)
4391 expect(templateCopy.children.length).to.equal(2)
4392 expect(templateCopy.child.divA).to.equal templateCopy
4393 expect(templateCopy.child.childA).to.equal templateCopy.children[0]
4394 expect(templateCopy.child.childA.type).to.equal 'form'
4395 expect(templateCopy.child.childA.children.length).to.equal(1)
4396 expect(templateMain.child.childA_1).to.equal templateMain.child.childA_1
4397 expect(templateCopy.child.childA_1).to.equal undefined
4398 expect(templateCopy.child.childA_2).to.equal undefined
4399 expect(templateCopy.child.CHILDa_2).to.equal templateCopy.children[0].children[0]
4400 expect(templateCopy.child.childA_2_1).to.equal templateCopy.children[0].children[0].children[0]
4401 expect(templateCopy.child.childA_2_1.options.text).to.equal 'New Text'
4402 expect(templateCopy.child.childB_1).to.equal undefined
4403 expect(templateCopy.child.childB_2).to.equal templateCopy.children[1].children[0]
4404 expect(templateMain.child.childB_1).to.equal templateMain.children[1].children[0]
4405 expect(templateMain.child.childB_2).to.equal templateMain.children[1].children[1]
4406 expect(templateMain.child.childC).to.equal templateMain.children[2]
4407 expect(templateCopy.child.childC).to.equal undefined
4408
4409
4410 test "Null values in options object will delete keys during template extension", ()->
4411 templateA = Dom.template(
4412 ['div'
4413 ref: 'theDiv'
4414 computers:
4415 valueA: ()-> 1
4416 valueB: ()-> 2
4417
4418 style:
4419 position: 'relative'
4420 width: 100
4421 height: 100
4422 $active:
4423 width: 200
4424 height: 200
4425 ]
4426 )
4427 templateB = templateA.extend(
4428 options:
4429 ref: null
4430 computers:
4431 valueA: null
4432 valueB: ()-> 3
4433
4434 style:
4435 height: null
4436 opacity: 1
4437 $active:
4438 width: null
4439 )
4440
4441 spawnA = templateA.spawn()
4442 spawnB = templateB.spawn()
4443
4444 expect(spawnA.ref).to.equal 'theDiv'
4445 expect(spawnB.ref).to.equal undefined
4446 expect(typeof spawnA.options.computers.valueA).to.equal 'function'
4447 expect(typeof spawnB.options.computers.valueA).to.equal 'undefined'
4448 expect(typeof spawnA.options.computers.valueB).to.equal 'function'
4449 expect(typeof spawnB.options.computers.valueB).to.equal 'function'
4450 expect(spawnA.options.computers.valueB()).to.equal 2
4451 expect(spawnB.options.computers.valueB()).to.equal 3
4452 expect(spawnA.options.style.position).to.equal 'relative'
4453 expect(spawnB.options.style.position).to.equal 'relative'
4454 expect(spawnA.options.style.width).to.equal 100
4455 expect(spawnB.options.style.width).to.equal 100
4456 expect(spawnA.options.style.height).to.equal 100
4457 expect(spawnB.options.style.height).to.equal undefined
4458 expect(spawnA.options.style.opacity).to.equal undefined
4459 expect(spawnB.options.style.opacity).to.equal 1
4460 expect(spawnA.options.style.$active.width).to.equal 200
4461 expect(spawnB.options.style.$active.width).to.equal undefined
4462 expect(spawnA.options.style.$active.height).to.equal 200
4463 expect(spawnB.options.style.$active.height).to.equal 200
4464
4465
4466 test "When spawning elements the options object passed to the spawns should be a clone of the template's options", ()->
4467 templateA = Dom.template ['div', style:{display:'block'}]
4468 templateB = Dom.template ['div', style:{display:'block'}]
4469 spawnA = templateA.spawn(ref:'a') # Passed options to merge with orig
4470 spawnB = templateA.spawn()
4471
4472 expect(spawnA.options).not.to.equal(templateA.options)
4473 expect(spawnA.options.style).not.to.equal(templateA.options.style)
4474 expect(templateA.options.style.$base).to.equal(undefined)
4475
4476 expect(spawnB.options).not.to.equal(templateB.options)
4477 expect(spawnB.options.style).not.to.equal(templateB.options.style)
4478 expect(templateB.options.style.$base).to.equal(undefined)
4479
4480
4481 test "Templates will be spawned when appended to DOM elements", ()->
4482 template = Dom.template(['span', {ref:'theSpan'}, 'someText'])
4483 div = Dom.div(null, 'label: ')
4484
4485 expect(div.children.length).to.equal 1
4486 expect(div.text).to.equal 'label: '
4487 div.append template
4488 expect(div.children.length).to.equal 2
4489 expect(div.text).to.equal 'label: someText'
4490 div.prepend template
4491 expect(div.children.length).to.equal 3
4492 expect(div.text).to.equal 'someTextlabel: someText'
4493
4494
4495 suite "Data computers", ()->
4496 test "Templates accept options.computers fn map which will be invoked with provided options.data upon spawning", ()->
4497 receivedData = null
4498 template = Dom.template(
4499 ['div'
4500 computers: 'someLabel': (data)-> receivedData = data or 'nothing'
4501 ]
4502 )
4503
4504 expect(receivedData).to.equal(null)
4505 template.spawn()
4506 expect(receivedData).to.equal(null)
4507
4508 template.spawn({data:'someLabel':'works'})
4509 expect(receivedData).to.equal('works')
4510
4511
4512 test "Computers will be have the spawned QuickElement instance as their context", ()->
4513 context = null
4514 template = Dom.template(
4515 ['div'
4516 computers: 'someLabel': (data)-> context = this
4517 ]
4518 )
4519
4520 expect(context).to.equal(null)
4521 template.spawn()
4522 expect(context).to.equal(null)
4523
4524 instance = template.spawn({data:'someLabel':undefined})
4525 expect(context).to.equal(instance)
4526
4527
4528 test "Values specified in options.defaults will be used if not specified in options.data upon spawning", ()->
4529 results = {}
4530 template = Dom.template(
4531 ['div'
4532 computers:
4533 'first': (data)-> results.first = data.toLowerCase()
4534 'second': (data)-> results.second = data.toLowerCase()
4535 'third': (data)-> results.third = data.toLowerCase()
4536 defaults:
4537 'first': 'firstValue here'
4538 'third': 'thirdValue here'
4539 ]
4540 )
4541 expect(results).to.deep.equal({})
4542 template.spawn()
4543 expect(results).to.deep.equal({first:'firstvalue here', third:'thirdvalue here'})
4544
4545 instance = template.spawn({data:'third':'customvalue here'})
4546 expect(results).to.deep.equal({first:'firstvalue here', third:'customvalue here'})
4547
4548
4549 test "Values can be of any type", ()->
4550 results = {}
4551 template = Dom.template(
4552 ['div'
4553 computers:
4554 'first': (data)-> results.first = data
4555 'second': (data)-> results.second = data
4556 'third': (data)-> results.third = data
4557 'fourth': (data)-> results.fourth = data
4558 'fifth': (data)-> results.fifth = data
4559 'sixth': (data)-> results.sixth = data
4560 defaults:
4561 'first': ['abc', '123']
4562 'third': {a:1, b:12}
4563 'sixth': 999
4564 ]
4565 )
4566
4567
4568 instance = template.spawn(data:
4569 'second': null
4570 'fourth': 19
4571 'fifth': false
4572 'sixth': undefined
4573 )
4574 expect(results).to.deep.equal
4575 first: ['abc', '123']
4576 second: null
4577 third: {a:1, b:12}
4578 fourth: 19
4579 fifth: false
4580 sixth: undefined
4581
4582 expect(Object.keys(results).length).to.equal(6)
4583
4584
4585 test "Values in options.data that do not have a matching computer will be skipped", ()->
4586 results = {}
4587 template = Dom.template(
4588 ['div'
4589 computers:
4590 'first': (data)-> results.first = data
4591 'second': (data)-> results.second = data
4592 'third': (data)-> results.third = data
4593 ]
4594 )
4595
4596
4597 instance = template.spawn(data:
4598 'first': 'first value'
4599 'second': 'second value'
4600 'third': 'third value'
4601 'fourth': 'fourth value'
4602 )
4603 expect(results).to.deep.equal
4604 'first': 'first value'
4605 'second': 'second value'
4606 'third': 'third value'
4607
4608 expect(Object.keys(results).length).to.equal(3)
4609
4610
4611 test "Computers in template children will receive the parent's options.data", ()->
4612 results = parent:{}, childA:{}, childB:{}, childC:{}
4613 template = Dom.template(
4614 ['div'
4615 computers:
4616 'first': (data)-> results.parent.first = data
4617 'second': (data)-> results.parent.second = data
4618 'third': (data)-> results.parent.third = data
4619
4620 ['div'
4621 computers:
4622 'first': (data)-> results.childA.first = data
4623 'second': (data)-> results.childA.second = data
4624 'third': (data)-> results.childA.third = data
4625 ]
4626 ['div', null,
4627 ['div'
4628 computers:
4629 'first': (data)-> results.childB.first = data
4630 'fourth': (data)-> results.childB.fourth = data
4631 ]
4632 ['div'
4633 computers:
4634 'first': (data)-> results.childC.first = data
4635 'sixth': (data)-> results.childC.sixth = data
4636 ]
4637 ]
4638 ]
4639 )
4640
4641
4642 instance = template.spawn(data:
4643 'first': 'first value'
4644 'second': 'second value'
4645 'third': 'third value'
4646 'fourth': 'fourth value'
4647 )
4648 expect(results.parent).to.deep.equal
4649 'first': 'first value'
4650 'second': 'second value'
4651 'third': 'third value'
4652
4653 expect(results.childA).to.deep.equal
4654 'first': 'first value'
4655 'second': 'second value'
4656 'third': 'third value'
4657
4658 expect(results.childB).to.deep.equal
4659 'first': 'first value'
4660 'fourth': 'fourth value'
4661
4662 expect(results.childC).to.deep.equal
4663 'first': 'first value'
4664
4665
4666 test "Parent defaults will not be passed to children", ()->
4667 results = parent:{}, child:{}
4668 template = Dom.template(
4669 ['div'
4670 computers:
4671 'first': (data)-> results.parent.first = data
4672 'second': (data)-> results.parent.second = data
4673 'third': (data)-> results.parent.third = data
4674 defaults:
4675 'second': 'second value'
4676 'fourth': 'fourth value'
4677
4678 ['div'
4679 computers:
4680 'first': (data)-> results.child.first = data
4681 'second': (data)-> results.child.second = data
4682 'third': (data)-> results.child.third = data
4683 'fourth': (data)-> results.child.fourth = data
4684 defaults:
4685 'first': 'first value'
4686 ]
4687 ]
4688 )
4689
4690 instance = template.spawn(data:
4691 'third': 'third value'
4692 )
4693 expect(results.parent).to.deep.equal
4694 'second': 'second value'
4695 'third': 'third value'
4696
4697 expect(results.child).to.deep.equal
4698 'first': 'first value'
4699 'third': 'third value'
4700
4701
4702 test "Defaults should only be applied once", ()->
4703 count = parent:0, child:0, childChild:0
4704 template = Dom.template(
4705 ['div'
4706 ref: 'parent'
4707 computers:
4708 'first': (data)-> count.parent++
4709 defaults:
4710 'first': 'first value'
4711
4712 ['div'
4713 ref: 'child'
4714 computers:
4715 'first': (data)-> count.parent++
4716 'second': (data)-> count.child++
4717 defaults:
4718 'second': 'second value'
4719
4720 ['div'
4721 ref: 'child'
4722 computers:
4723 'fourth': (data)-> count.childChild++
4724 defaults:
4725 'fourth': 'fourth value'
4726 ]
4727 ]
4728 ]
4729 )
4730
4731 template.spawn(data:'third':'third value')
4732 expect(count).to.eql parent:1, child:1, childChild:1
4733
4734 template.spawn()
4735 expect(count).to.eql parent:2, child:2, childChild:2
4736
4737
4738 test "Data/defaults should be applied even when parent doesn't have computers", ()->
4739 count = 0
4740 template = Dom.template(
4741 ['div', null,
4742 ['section', null,
4743 ['div'
4744 computers:
4745 'first': (data)-> count++
4746 defaults:
4747 'first': 'first value'
4748 ]
4749 ]
4750 ]
4751 )
4752
4753 template.spawn(data:'first':'second value')
4754 expect(count).to.equal(1)
4755
4756 template.spawn()
4757 expect(count).to.equal(2)
4758
4759
4760 test "Data can be re-applied via .applyData(data)", ()->
4761 results = {}; count = {a:0, b:0, c:0, d:0, e:0, f:0}
4762 template = Dom.template(
4763 ['div'
4764 computers:
4765 'a': (data)-> results.a = data; count.a++
4766 'b': (data)-> results.b = data; count.b++
4767 'c': (data)-> results.c = data; count.c++
4768 'd': (data)-> results.d = data; count.d++
4769 'e': (data)-> results.e = data; count.e++
4770 'f': (data)-> results.f = data; count.f++
4771 defaults:
4772 'a': 1
4773 'c': 3
4774 'f': 6
4775 ]
4776 )
4777
4778
4779 instance = template.spawn(data: {b:2, d:4, e:5, f:6})
4780 expect(results).to.deep.equal {a:1, b:2, c:3, d:4, e:5, f:6}
4781 expect(count).to.deep.equal {a:1, b:1, c:1, d:1, e:1, f:1}
4782
4783 instance.applyData(a:11, b:22, d:44, e:55)
4784 expect(results).to.deep.equal {a:11, b:22, c:3, d:44, e:55, f:6}
4785 expect(count).to.deep.equal {a:2, b:2, c:2, d:2, e:2, f:2}
4786
4787
4788 test "The '_init' computer will be run by default on template spawn regardless of data", ()->
4789 count = {}
4790 template = Dom.template(
4791 ['div'
4792 ref: 'divA'
4793 computers: _init: ()-> count[@ref]?=0; count[@ref]++
4794
4795 ['div'
4796 ref: 'divB'
4797 data: first: '1'
4798 computers: _init: ()-> count[@ref]?=0; count[@ref]++
4799 ]
4800
4801 ['div'
4802 ref: 'divC'
4803 ['div'
4804 ref: 'divD'
4805
4806 ['div'
4807 ref: 'divE'
4808 computers: _init: ()-> count[@ref]?=0; count[@ref]++
4809 ]
4810 ]
4811 ]
4812 ]
4813 )
4814
4815 expect(count).to.eql {}
4816 template.spawn()
4817 expect(count).to.eql divA:1, divB:1, divE:1
4818
4819 template.spawn()
4820 expect(count).to.eql divA:2, divB:2, divE:2
4821
4822 template.child.divB.spawn(data:second:'2')
4823 expect(count).to.eql divA:2, divB:3, divE:2
4824
4825 template.child.divC.spawn()
4826 expect(count).to.eql divA:2, divB:3, divE:3
4827
4828 template.child.divC.spawn()
4829 expect(count).to.eql divA:2, divB:3, divE:4
4830
4831
4832 test "The '_init' computer will be passed all of the data the template spawn receives", ()->
4833 result = divA:{}, divB:{}
4834 template = Dom.template(
4835 ['div'
4836 ref: 'divA'
4837 computers:
4838 href: (href)-> result[@ref].href = href
4839 name: (name)-> result[@ref].name = name
4840 _init: ()-> result[@ref]._init = arguments[0]
4841
4842 ['div'
4843 ref: 'divProxy'
4844
4845 ['div'
4846 ref: 'divB'
4847 defaults: first: '1'
4848 computers:
4849 href: (href)-> result[@ref].href = href
4850 name: (name)-> result[@ref].name = name
4851 _init: ()-> result[@ref]._init = arguments[0]
4852 ]
4853 ]
4854 ]
4855 )
4856 expected =
4857 href: 'abc'
4858 name: '123'
4859 _init: {href:'abc', name:'123', value:'def', size:'456'}
4860
4861
4862 expect(result).to.eql divA:{}, divB:{}
4863
4864 template.spawn(data:{href:'abc', name:'123', value:'def', size:'456'})
4865 expect(result).to.eql {divA:expected, divB:expected}
4866
4867 delete result.divA
4868 divB: null
4869 template.child.divB.spawn(data:{href:'abc', name:'123', value:'def', size:'456'})
4870 expect(result).to.eql {divB:expected}
4871
4872
4873 test "Data can be specified via options object", ()->
4874 receivedData = null
4875 template = Dom.template(
4876 ['div'
4877 computers: 'someLabel': (data)-> receivedData = data or 'nothing'
4878 ]
4879 )
4880 templateCopy = template.extend(options:data:{'someLabel':'works'})
4881
4882 template.spawn()
4883 expect(receivedData).to.equal(null)
4884 templateCopy.spawn()
4885 expect(receivedData).to.equal('works')
4886
4887 template.spawn(options:data:{'someLabel':'also works'})
4888 expect(receivedData).to.equal('also works')
4889
4890
4891 test "Data specified in children's options object will be merged with the parent's data", ()->
4892 receivedData = abc:null, def:null
4893 template = Dom.template(
4894 ['div', null
4895
4896 ['span'
4897 data: abc: 123
4898 computers:
4899 'abc': (data)-> receivedData.abc = data or 'nothing'
4900 'def': (data)-> receivedData.def = data or 'nothing'
4901 ]
4902 ]
4903 )
4904 templateCopy = template.extend(options:data:{def:456})
4905
4906 template.spawn()
4907 expect(receivedData).to.eql(abc:123, def:null)
4908 receivedData = abc:null, def:null
4909
4910 templateCopy.spawn()
4911 expect(receivedData).to.eql(abc:123, def:456)
4912 receivedData = abc:null, def:null
4913
4914 template.spawn(options:data:{def:789})
4915 expect(receivedData).to.eql(abc:123, def:789)
4916 receivedData = abc:null, def:null
4917
4918 template.spawn(options:data:{abc:789})
4919 expect(receivedData).to.eql(abc:789, def:null)
4920
4921
4922 test "Data won't be passed to children if options.passDataToChildren is false", ()->
4923 receivedData = parent:null, child:null
4924 template1 = DOM.template(
4925 ['div'
4926 computers: abc: (data)-> receivedData.parent = data
4927
4928 ['span'
4929 computers: abc: (data)-> receivedData.child = data
4930 ]
4931 ]
4932 )
4933 template2 = template1.extend(passDataToChildren:false)
4934
4935 expect(receivedData).to.eql parent:null, child:null
4936
4937 el1 = template1.spawn(data:{abc:123})
4938 expect(receivedData).to.eql parent:123, child:123
4939
4940 receivedData = parent:null, child:null
4941 el2 = template2.spawn(data:{abc:123})
4942 expect(receivedData).to.eql parent:123, child:null
4943
4944 receivedData = parent:null, child:null
4945 el1.applyData({abc:456})
4946 expect(receivedData).to.eql parent:456, child:456
4947
4948 receivedData = parent:null, child:null
4949 el2.applyData({abc:456})
4950 expect(receivedData).to.eql parent:456, child:null
4951
4952 el2.lastChild.applyData({abc:789})
4953 expect(receivedData).to.eql parent:456, child:789
4954
4955
4956 test "Data should be invoked for parents after invoked children", ()->
4957 history = []
4958 computers =
4959 _init: ()-> history.push(@ref)
4960 abc: ()-> history.push(@ref)
4961
4962 template = DOM.template(
4963 ['div'
4964 {computers, id:'parent'}
4965 ['div'
4966 {computers, id:'child1'}
4967 ['div'
4968 {computers, id:'child2'}
4969 ]
4970 ]
4971 ['div'
4972 {computers, id:'child3'}
4973 ]
4974 ]
4975 )
4976 expect(history).to.eql []
4977 el = template.spawn()
4978 expect(history).to.eql ['child2', 'child1', 'child3', 'parent']
4979
4980 history.length = 0
4981 el.applyData(abc:123)
4982 expect(history).to.eql ['child2', 'child1', 'child3', 'parent']
4983
4984
4985 test "Computers will be invoked only one time per element if options.invokeComputersOnce is on", ()->
4986 history = []
4987 computers = abc: ()-> history.push(@ref)
4988
4989 template = DOM.template(
4990 ['div'
4991 {computers, id:'parent', invokeComputersOnce:true}
4992 ['div'
4993 {computers, id:'child1'}
4994 ['div'
4995 {computers, id:'child2', invokeComputersOnce:true}
4996 ]
4997 ]
4998 ['div'
4999 {computers, id:'child3'}
5000 ]
5001 ]
5002 )
5003 expect(history).to.eql []
5004 el = template.spawn(data:abc:123)
5005 expect(history).to.eql ['child2', 'child1', 'child3', 'parent']
5006
5007 history.length = 0
5008 el.applyData(abc:123)
5009 expect(history).to.eql ['child1', 'child3']
5010
5011 history.length = 0
5012 el.applyData(abc:456)
5013 expect(history).to.eql ['child1', 'child3']
5014
5015
5016
5017 suite "Misc", ()->
5018 test "QuickDom.isTemplate", ()->
5019 expect(Dom.isTemplate Dom.template(['div'])).to.be.true
5020 expect(Dom.isTemplate Dom.div()).to.be.false
5021 expect(Dom.isTemplate Dom.div()[0]).to.be.false
5022 expect(Dom.isTemplate {}).to.be.false
5023 expect(Dom.isTemplate 'string').to.be.false
5024 expect(Dom.isTemplate 5).to.be.false
5025 expect(Dom.isTemplate false).to.be.false
5026 expect(Dom.isTemplate true).to.be.false
5027
5028
5029 test "QuickDom.isQuickEl", ()->
5030 expect(Dom.isQuickEl Dom.template(['div'])).to.be.false
5031 expect(Dom.isQuickEl Dom.div()).to.be.true
5032 expect(Dom.isQuickEl Dom.text()).to.be.true
5033 expect(Dom.isQuickEl Dom.div()[0]).to.be.false
5034 expect(Dom.isQuickEl {}).to.be.false
5035 expect(Dom.isQuickEl 'string').to.be.false
5036 expect(Dom.isQuickEl 5).to.be.false
5037 expect(Dom.isQuickEl false).to.be.false
5038 expect(Dom.isQuickEl true).to.be.false
5039
5040
5041 test "QuickDom.isEl", ()->
5042 expect(Dom.isEl Dom.template(['div'])).to.be.false
5043 expect(Dom.isEl Dom.div()).to.be.false
5044 expect(Dom.isEl Dom.text()).to.be.false
5045 expect(Dom.isEl Dom.div()[0]).to.be.true
5046 expect(Dom.isEl Dom.text()[0]).to.be.false
5047 expect(Dom.isEl {}).to.be.false
5048 expect(Dom.isEl 'string').to.be.false
5049 expect(Dom.isEl 5).to.be.false
5050 expect(Dom.isEl false).to.be.false
5051 expect(Dom.isEl true).to.be.false
5052
5053
5054 test "Stringification", ()->
5055 section = Dom(
5056 ['section',{
5057 id: 'theSection'
5058 className: 'theSectionClass'
5059 style:
5060 'position': 'relative'
5061 'opacity': 0.5
5062 'fontSize': ()-> '29px'
5063 $happy:
5064 fontSize: '11px'
5065 $relaxed:
5066 fontSize: '8px'
5067 }
5068 ['div', {id:'childA', style:position:'relative'}, 'childA-innertext']
5069 'section-innertext'
5070 ['span', {id:'childB', ref:'childB-ref!', style:position:'absolute'}
5071 'childB-innertext'
5072 ['text', {text:'childB-innertext 2'}]
5073 ['a', {url:'https://google.com'}]
5074 ]
5075 ]
5076 ).appendTo(sandbox)
5077 window.stringified = JSON.stringify(section, null, 2)
5078 sectionCopy = Dom(JSON.parse(stringified)).appendTo(sandbox)
5079
5080 expect(sectionCopy.type).to.equal(section.type)
5081 expect(sectionCopy.ref).to.equal(section.ref)
5082 expect(sectionCopy.el.id).to.equal(section.el.id)
5083 expect(sectionCopy.el.className).to.equal(section.el.className)
5084 expect(sectionCopy.style 'position').to.equal(section.style 'position')
5085 expect(sectionCopy.style 'opacity').to.equal(section.style 'opacity')
5086 expect(sectionCopy.style 'fontSize').not.to.equal(section.style 'fontSize')
5087
5088 section.style 'fontSize', null
5089 section.state 'happy', on
5090 sectionCopy.state 'happy', on
5091 expect(sectionCopy.style 'fontSize').to.equal(section.style 'fontSize')
5092
5093 section.state 'relaxed', on
5094 sectionCopy.state 'relaxed', on
5095 expect(sectionCopy.style 'fontSize').to.equal(section.style 'fontSize')
5096
5097 expect(sectionCopy.children.length).to.equal(section.children.length)
5098 expect(Object.keys(sectionCopy.child).length).to.equal(Object.keys(section.child).length)
5099 expect(sectionCopy.text).to.equal(section.text)
5100 expect(sectionCopy.html).to.equal(section.html)
5101 expect(sectionCopy.children[0].style 'position').to.equal(section.children[0].style 'position')
5102 expect(sectionCopy.children[2].style 'position').to.equal(section.children[2].style 'position')
5103 expect(sectionCopy.children[2].ref).to.equal(section.children[2].ref)
5104
5105
5106 test "Chaining", ()->
5107 div = Dom.div()
5108 chainResult = div
5109 .state('abc', on)
5110 .resetState()
5111 .style()
5112 .css('width', 12)
5113 .attr('test', 123)
5114 .prop('anotherTest', 123)
5115 .updateStateStyles({height:50})
5116 .updateStateTexts({$base:'abc'})
5117 .append()
5118 .appendTo()
5119 .prepend()
5120 .prependTo()
5121 .before()
5122 .after()
5123 .insertBefore()
5124 .insertAfter()
5125 .detach()
5126 .wrap(Dom.section())
5127 .unwrap()
5128 .wrap(Dom.header())
5129 .replace()
5130 .appendTo(sandbox)
5131 .wrap(head=Dom.header())
5132 .on('abc', ()->)
5133 .emit('abc')
5134 .off('abc')
5135 .off()
5136
5137 expect(chainResult).to.equal(div)
5138 expect(sandbox.children[0]).to.equal(head.el)
5139 expect(div.parent).to.equal(head)
5140 expect(div.css 'width').to.equal('12px')
5141
5142
5143 test "Invalid Arguments", ()->
5144 text = Dom.text('someText', {lostOpts:true})
5145 div = Dom.div({lostOpts:true})
5146
5147 expect(Dom()).to.equal undefined
5148 expect(Dom(null)).to.equal undefined
5149 expect(Dom({})).to.equal undefined
5150 expect(div.updateOptions()).to.equal div
5151 expect(text.options.lostOpts).to.equal undefined
5152 expect(div.options.lostOpts).to.equal true
5153 expect(div.on()).to.equal div
5154 expect(div.on('abc')).to.equal div
5155 expect(div.on('abc', {})).to.equal div
5156 expect(div.once('abc')).to.equal div
5157 expect(div.off('somethingFake')).to.equal div
5158
5159 emitCount = 0; div.on 'something', cb=()-> emitCount++
5160 expect(div.emit('')).to.equal(div)
5161 expect(div.emit()).to.equal(div)
5162 expect(div.emitPrivate('none')).to.equal(div)
5163 expect(div.emitPrivate('')).to.equal(div)
5164 expect(div.emitPrivate()).to.equal(div)
5165 expect(emitCount).to.equal(0)
5166 expect(div.emit('something')).to.equal(div)
5167 expect(emitCount).to.equal(1)
5168 expect(div.off('something', ()->)).to.equal(div)
5169 expect(div.emit('something')).to.equal(div)
5170 expect(emitCount).to.equal(2)
5171
5172 div.css(null, '129')
5173 expect(div.el.style.null).to.equal(undefined)
5174
5175 expect(div.state()).to.eql []
5176 expect(div.state(null, on)).to.equal undefined
5177 expect(div.state(123, on)).to.equal undefined
5178 expect(div.state 'base', on).to.equal div
5179 expect(div.state 'base').to.be.false
5180 expect(div.state '$whatevs', on).to.equal div
5181 expect(div.state 'whatevs').to.be.true
5182 expect(div.state 'another').to.be.false
5183 expect(div.state 'another', on).to.equal div
5184 expect(div.state 'another').to.be.true
5185 expect(div.state 'another', undefined).to.equal div
5186 expect(div.state 'another').to.be.false
5187
5188 expect(div.updateStateStyles {$base:{width:1}}).to.equal div
5189 expect(div.updateStateStyles null).to.equal div
5190 expect(div.updateStateTexts {$base:'abc'}).to.equal div
5191 expect(div.updateStateTexts null).to.equal div
5192
5193 div.appendTo(Dom sandbox)
5194 expect(div.parent).to.equal(Dom sandbox)
5195
5196 div.append(true)
5197 expect(div.children.length).to.equal(0)
5198 div.appendTo(document)
5199 expect(div.parent).to.equal(Dom sandbox)
5200 div.prepend(true)
5201 expect(div.children.length).to.equal(0)
5202 div.prependTo(true)
5203 expect(div.parent).to.equal(Dom sandbox)
5204 div.after(true)
5205 expect(div.children.length).to.equal(0)
5206 div.insertAfter(123)
5207 expect(div.parent).to.equal(Dom sandbox)
5208 div.before(true)
5209 expect(div.children.length).to.equal(0)
5210 div.insertBefore(123)
5211 expect(div.parent).to.equal(Dom sandbox)
5212 div.wrap(123)
5213 expect(div.parent).to.equal(Dom sandbox)
5214 div.replace(123)
5215 expect(div.parent).to.equal(Dom sandbox)
5216 div.detach()
5217 expect(div.parent).to.equal(undefined)
5218 div.unwrap()
5219 expect(div.parent).to.equal(undefined)
5220 expect(Dom(sandbox).children.length).to.equal 0
5221
5222 div.appendTo(Dom sandbox)
5223 expect(Dom(sandbox).children.length).to.equal 1
5224 if Dom(sandbox)._removeChild
5225 Dom(sandbox)._removeChild(text)
5226 Dom(sandbox)._removeChild(Dom.div())
5227 expect(Dom(sandbox).children.length).to.equal 1
5228
5229 expect ()-> Dom.batch()
5230 .to.throw()
5231
5232 expect ()-> Dom.batch({})
5233 .to.throw()
5234
5235 expect ()-> Dom.batch(5432)
5236 .to.throw()
5237
5238 expect ()-> Dom.batch([])
5239 .to.throw()
5240
5241 expect ()-> Dom.batch([12]).append(Dom.div())
5242 .to.throw()
5243
5244 expect ()-> Dom.batch([12])
5245 .not.to.throw()
5246
5247 # expect ()-> Dom.batch($('div'))
5248 # .not.to.throw()
5249
5250 expect ()-> Dom.template()
5251 .to.throw()
5252
5253 expect ()-> Dom.template(null)
5254 .to.throw()
5255
5256 expect ()-> Dom.template({})
5257 .to.throw()
5258
5259 expect ()-> Dom.template([8482, {className:'t'}])
5260 .to.throw()
5261
5262 expect ()-> Dom.template(['div', 'someString'])
5263 .to.throw()
5264
5265 expect ()-> Dom.template(['div', null, 'Some Inner Text'])
5266 .not.to.throw()
5267
5268 expect ()-> Dom.div(style:{opacity:0.5, '@abc(max-width:390)':{opacity:1}}).appendTo(sandbox)
5269 .not.to.throw()
5270
5271 expect(()->
5272 div = Dom.div()
5273 div.pipeState(div)
5274 div.state 'happy', on
5275 expect(div.state 'happy').to.equal on
5276 ).not.to.throw()
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292HTMLElement::onEvent = (eventName, callback)->
5293 if @addEventListener
5294 @addEventListener(eventName, callback)
5295 else
5296 @attachEvent("on#{eventName}", callback)
5297
5298
5299HTMLElement::removeEvent = (eventName, callback)->
5300 if @removeEventListener
5301 @removeEventListener(eventName, callback)
5302 else
5303 @detachEvent("on#{eventName}", callback)
5304
5305
5306HTMLElement::emitEvent = (eventName)->
5307 event = document.createEvent('Event')
5308 event.initEvent(eventName, true, false)
5309 @dispatchEvent(event)
5310
5311
5312if HTMLElement.name isnt 'HTMLElement'
5313 HTMLElement.name = 'HTMLElement'
5314 Text.name = 'Text'
5315 nonElementSuffix = [
5316 'OptionsCollection'
5317 'FormControlsCollection'
5318 'Document'
5319 'Collection'
5320 'AllCollection'
5321 ]
5322 elementSuffix = [
5323 "Video","Unknown","UList","Track","Title",
5324 "TextArea","Template","TableSection","TableRow",
5325 "Table","TableCol","TableCell","TableCaption",
5326 "Style","Span","Source","Slot","Shadow","Select",
5327 "Script","Quote","Progress","Pre","Picture",
5328 "Param","Paragraph","Output","Option","OptGroup",
5329 "Object","OList","Mod","Meter","Meta","Menu",
5330 "Media","Marquee","Map","Link","Legend","Label",
5331 "LI","Input","Image","IFrame","Html","Heading",
5332 "Head","HR","FrameSet","Frame","Form","Font",
5333 "FieldSet","Embed","Div","Directory","Dialog",
5334 "Details","DataList","DList","Content","Canvas",
5335 "Button","Body","Base","BR","Audio","Area","Anchor"
5336 ]
5337
5338 for creator in nonElementSuffix
5339 window["HTML#{creator}"]?.name = "HTML#{creator}"
5340
5341 for creator in elementSuffix
5342 window["HTML#{creator}Element"]?.name = "HTML#{creator}Element"
5343
5344 window.SVGElement?.name = 'SVGElement'
5345 window.SVGSVGElement?.name = 'SVGSVGElement'
5346 window.SVGPolylineElement?.name = 'SVGPolylineElement'
5347
5348window.ClientRect ?= DOMRect
5349
5350
5351
5352