1 |
|
2 |
|
3 |
|
4 | const K = require('kcore')
|
5 |
|
6 |
|
7 | const JSDOM = require('jsdom').JSDOM
|
8 | const dom = new JSDOM('')
|
9 | const window = dom.window
|
10 | const document = window.document
|
11 |
|
12 | global.window = window
|
13 | global.document = document
|
14 |
|
15 | window.K = K
|
16 |
|
17 | require('../src/KNateHtmlStatic')
|
18 | require('../src/KNateAbstractDom')
|
19 | require('../src/KNateHtmlDom')
|
20 | require('should')
|
21 |
|
22 |
|
23 | K.Elem = {
|
24 | isElem: function (o)
|
25 | {
|
26 | if (o.elem) {
|
27 |
|
28 | return false;
|
29 | } else {
|
30 |
|
31 | return true;
|
32 | }
|
33 | },
|
34 |
|
35 | isText: function (o)
|
36 | {
|
37 | return false;
|
38 | }
|
39 | }
|
40 |
|
41 |
|
42 | K.updateProperty = function (o, key, newContent) {
|
43 | if (o[key] != newContent) {
|
44 | o[key] = newContent
|
45 | }
|
46 | }
|
47 |
|
48 | function TestNateHtml(domMode) {
|
49 | let nRoot = null
|
50 | let nRootDiv = null
|
51 | let title = null
|
52 | let titlePrefix = null
|
53 |
|
54 | if (domMode) {
|
55 |
|
56 | nRoot = K.NateHtmlDom(document.body)
|
57 | title = 'NateHtmlDom'
|
58 | titlePrefix = 'DOM: '
|
59 | } else {
|
60 |
|
61 | nRoot = K.NateHtmlElem()
|
62 | title = 'NateHtmlStatic'
|
63 | titlePrefix = 'Static: '
|
64 | }
|
65 |
|
66 | const _suite = (title, cb) => {
|
67 | suite(titlePrefix + title, cb)
|
68 | }
|
69 |
|
70 | const _reset = () => {
|
71 |
|
72 | if (domMode) {
|
73 | nRoot.deleteAllChildren()
|
74 | } else {
|
75 | nRoot = K.NateHtmlElem()
|
76 | }
|
77 | }
|
78 |
|
79 | const _verifyResultHtml = (expectedHtml) => {
|
80 | if (domMode) {
|
81 | nRoot.elem.innerHTML.should.be.eql(expectedHtml)
|
82 | } else {
|
83 | nRoot.render().should.be.eql(expectedHtml)
|
84 | }
|
85 | }
|
86 |
|
87 | _suite(title, () => {
|
88 | _suite('Namespace', () => {
|
89 | let nElem1 = null
|
90 | let nElem2 = null
|
91 |
|
92 | let namespaceA = null
|
93 | let namespaceB = null
|
94 | let namespaceC = null
|
95 |
|
96 | const _testSetter = (nNode, key, value) => {
|
97 | nNode[key] = value
|
98 | }
|
99 |
|
100 | test('Init', () => {
|
101 | _reset()
|
102 |
|
103 |
|
104 | namespaceA = nRoot.getNamespace().createExtension('testA')
|
105 | namespaceB = nRoot.getNamespace().createExtension('testB')
|
106 |
|
107 | namespaceA.addSetter('testKeyA1', _testSetter)
|
108 | namespaceA.addSetter('testKeyA2', _testSetter)
|
109 |
|
110 | namespaceB.addSetter('testKeyB1', _testSetter)
|
111 | namespaceB.addSetter('testKeyB2', _testSetter)
|
112 | })
|
113 |
|
114 | test('Create element via namespace directly', () => {
|
115 | _reset()
|
116 |
|
117 |
|
118 | nElem1 = namespaceA.createNate(nRoot)
|
119 | nElem1.set('testKeyA1', 'valueA1.1')
|
120 | nElem1.set('testKeyA2', 'valueA2.1')
|
121 |
|
122 |
|
123 | nElem1.getNamespace().should.be.eql(namespaceA)
|
124 | nElem1.testKeyA1.should.be.eql('valueA1.1')
|
125 | nElem1.testKeyA2.should.be.eql('valueA2.1')
|
126 | })
|
127 |
|
128 | test('Inherit namespace from parent', () => {
|
129 |
|
130 | nElem2 = nElem1.newDiv()
|
131 | nElem2.getNamespace().should.be.eql(namespaceA)
|
132 |
|
133 |
|
134 | nElem1.getNamespace().should.be.eql(namespaceA)
|
135 | nElem1.testKeyA1.should.be.eql('valueA1.1')
|
136 | nElem1.testKeyA2.should.be.eql('valueA2.1')
|
137 |
|
138 |
|
139 | nElem2.set('testKeyA1', 'valueA1.2')
|
140 | nElem2.set('testKeyA2', 'valueA2.2')
|
141 |
|
142 | nElem2.testKeyA1.should.be.eql('valueA1.2')
|
143 | nElem2.testKeyA2.should.be.eql('valueA2.2')
|
144 | })
|
145 |
|
146 | test('Assign namespace directly', () => {
|
147 |
|
148 | nElem1.assignNamespace(namespaceB)
|
149 | nElem1.getNamespace().should.be.eql(namespaceB)
|
150 | nElem2.getNamespace().should.be.eql(namespaceA)
|
151 |
|
152 |
|
153 | nElem1.set('testKeyB1', 'valueB1.3')
|
154 | nElem1.set('testKeyB2', 'valueB2.3')
|
155 |
|
156 | nElem1.testKeyA1.should.be.eql('valueA1.1')
|
157 | nElem1.testKeyA2.should.be.eql('valueA2.1')
|
158 | nElem1.testKeyB1.should.be.eql('valueB1.3')
|
159 | nElem1.testKeyB2.should.be.eql('valueB2.3')
|
160 |
|
161 |
|
162 | nElem2.set('testKeyA1', 'valueA1.4')
|
163 | nElem2.set('testKeyA2', 'valueA2.4')
|
164 |
|
165 | nElem2.testKeyA1.should.be.eql('valueA1.4')
|
166 | nElem2.testKeyA2.should.be.eql('valueA2.4')
|
167 | })
|
168 |
|
169 | test('Create and delete functions', () => {
|
170 | const namespace = K.BSC.NateNamespace();
|
171 | namespace.addCreateFunction('tag1', function() {
|
172 | const rv = this.getNamespace().createNate()
|
173 | rv._createdBy_ = 'createTag1'
|
174 | return rv
|
175 | })
|
176 |
|
177 | namespace.addCreateFunction('tag2', function() {
|
178 | const rv = this.getNamespace().createNate()
|
179 | rv._createdBy_ = 'createTag2'
|
180 | return rv
|
181 | })
|
182 |
|
183 | namespace.addDeleteFunction('tag1', function() {this._deletedBy_ = 'deleteTag1'})
|
184 | namespace.addDeleteFunction('tag2', function() {this._deletedBy_ = 'deleteTag2'})
|
185 |
|
186 | const nRoot = namespace.createNate()
|
187 | const nTag1 = nRoot.newTag1()
|
188 | const nTag2 = nRoot.newTag2()
|
189 |
|
190 | nTag1.delete()
|
191 | nTag2.delete()
|
192 |
|
193 | nTag1._createdBy_.should.be.eql('createTag1')
|
194 | nTag2._createdBy_.should.be.eql('createTag2')
|
195 |
|
196 | nTag1._deletedBy_.should.be.eql('deleteTag1')
|
197 | nTag2._deletedBy_.should.be.eql('deleteTag2')
|
198 | })
|
199 | })
|
200 |
|
201 | _suite('Single tags (generic)', () => {
|
202 | const _createOneTagTest = (tagName, createFunction, expectedHtml) => {
|
203 | test(createFunction, () => {
|
204 | _reset()
|
205 | nRoot[createFunction]().setText('text')
|
206 | _verifyResultHtml(expectedHtml)
|
207 | })
|
208 |
|
209 | test('createNate(' + tagName + ')', () => {
|
210 | _reset()
|
211 | nRoot.newNate(tagName).setText('text')
|
212 | _verifyResultHtml(expectedHtml)
|
213 | })
|
214 | }
|
215 |
|
216 | _createOneTagTest('b' , 'newB' , '<b>text</b>')
|
217 | _createOneTagTest('br' , 'newBr' , '<br>')
|
218 | _createOneTagTest('div' , 'newDiv' , '<div>text</div>')
|
219 | _createOneTagTest('span' , 'newSpan' , '<span>text</span>')
|
220 | _createOneTagTest('canvas' , 'newCanvas' , '<canvas>text</canvas>')
|
221 | _createOneTagTest('h1' , 'newH1' , '<h1>text</h1>')
|
222 | _createOneTagTest('h2' , 'newH2' , '<h2>text</h2>')
|
223 | _createOneTagTest('h3' , 'newH3' , '<h3>text</h3>')
|
224 | _createOneTagTest('label' , 'newLabel' , '<label>text</label>')
|
225 | _createOneTagTest('ul' , 'newUl' , '<ul>text</ul>')
|
226 | _createOneTagTest('li' , 'newLi' , '<li>text</li>')
|
227 | _createOneTagTest('p' , 'newP' , '<p>text</p>')
|
228 | _createOneTagTest('pre' , 'newPre' , '<pre>text</pre>')
|
229 | _createOneTagTest('option' , 'newOption' , '<option>text</option>')
|
230 | _createOneTagTest('optGroup' , 'newOptGroup' , '<optgroup>text</optgroup>')
|
231 | _createOneTagTest('textArea' , 'newTextArea' , '<textarea>text</textarea>')
|
232 | _createOneTagTest('table' , 'newTable' , '<table>text</table>')
|
233 | _createOneTagTest('tBody' , 'newTBody' , '<tbody>text</tbody>')
|
234 | _createOneTagTest('tr' , 'newTr' , '<tr>text</tr>')
|
235 | _createOneTagTest('td' , 'newTd' , '<td>text</td>')
|
236 | _createOneTagTest('a' , 'newA' , '<a>text</a>')
|
237 |
|
238 | _createOneTagTest('inputCheckbox' , 'newInputCheckbox' , '<input type="checkbox">')
|
239 | _createOneTagTest('inputPassword' , 'newInputPassword' , '<input type="password">')
|
240 | _createOneTagTest('inputRadio' , 'newInputRadio' , '<input type="radio">')
|
241 | _createOneTagTest('inputText' , 'newInputText' , '<input type="text">')
|
242 | })
|
243 |
|
244 | test('Special property: textContent', () => {
|
245 | _reset()
|
246 | const nDiv = nRoot.newDiv()
|
247 |
|
248 | nDiv.set('textContent', 'this is some pure text content')
|
249 | _verifyResultHtml('<div>this is some pure text content</div>')
|
250 |
|
251 |
|
252 | nDiv.set('textContent', 'this is HTML escaped content: <>&\'"')
|
253 | _verifyResultHtml('<div>this is HTML escaped content: <>&\'"</div>')
|
254 |
|
255 |
|
256 | nDiv.set('textContent', 'line1\nline2')
|
257 | _verifyResultHtml('<div>line1\nline2</div>')
|
258 | })
|
259 |
|
260 | if (domMode) {
|
261 |
|
262 |
|
263 | test('Special property: innerText (SKIPPED!)', () => {
|
264 | })
|
265 |
|
266 | } else {
|
267 |
|
268 | test('Special property: innerText', () => {
|
269 | _reset()
|
270 | const nDiv = nRoot.newDiv()
|
271 |
|
272 | nDiv.set('innerText', 'this is some pure text content')
|
273 | _verifyResultHtml('<div>this is some pure text content</div>')
|
274 |
|
275 |
|
276 | nDiv.set('innerText', 'this is HTML escaped content: <>&\'"')
|
277 | _verifyResultHtml('<div>this is HTML escaped content: <>&\'"</div>')
|
278 |
|
279 |
|
280 | nDiv.set('innerText', 'line1\nline2')
|
281 | _verifyResultHtml('<div>line1<br>line2</div>')
|
282 |
|
283 |
|
284 | let nateError = null
|
285 | try {
|
286 | nDiv.newDiv()
|
287 | } catch (_nateError) {
|
288 | nateError = _nateError
|
289 | }
|
290 | nateError.getErrorCode().should.be.eql('nateChildNotAllowed')
|
291 | })
|
292 | }
|
293 |
|
294 | test('Special property: innerHTML', () => {
|
295 | _reset()
|
296 | const nDiv = nRoot.newDiv()
|
297 |
|
298 |
|
299 | nDiv.set('innerHTML', 'this is some pure text content')
|
300 | _verifyResultHtml('<div>this is some pure text content</div>')
|
301 |
|
302 |
|
303 | nDiv.set('innerHTML', 'this is HTML content: <b class="test-class">TEST1 & TEST2</b>')
|
304 | _verifyResultHtml('<div>this is HTML content: <b class="test-class">TEST1 & TEST2</b></div>')
|
305 |
|
306 |
|
307 | nDiv.set('innerHTML', 'line1\nline2')
|
308 | _verifyResultHtml('<div>line1\nline2</div>')
|
309 |
|
310 |
|
311 |
|
312 | let nateError = null
|
313 | try {
|
314 | nDiv.newSpan()
|
315 | } catch (_nateError) {
|
316 | nateError = _nateError
|
317 | }
|
318 | nateError.getErrorCode().should.be.eql('nateChildNotAllowed')
|
319 |
|
320 |
|
321 | _verifyResultHtml('<div>line1\nline2</div>')
|
322 | })
|
323 |
|
324 | test('Create nate child when direct content exists (should fail)', () => {
|
325 |
|
326 | _reset()
|
327 | const nDiv = nRoot.newDiv().set('innerHTML', 'test-html-content')
|
328 |
|
329 |
|
330 |
|
331 | let nateError = null
|
332 | try {
|
333 | nDiv.newSpan()
|
334 | } catch (_nateError) {
|
335 | nateError = _nateError
|
336 | }
|
337 | nateError.getErrorCode().should.be.eql('nateChildNotAllowed')
|
338 |
|
339 |
|
340 | nDiv.set('innerHTML', null)
|
341 | nDiv.newSpan()
|
342 |
|
343 | _verifyResultHtml('<div><span></span></div>')
|
344 | })
|
345 |
|
346 | test('Set content directly when nate children exists (should fail)', () => {
|
347 | _reset()
|
348 |
|
349 | const nDiv = nRoot.newDiv()
|
350 | nDiv.newDiv()
|
351 |
|
352 |
|
353 | let nateError = null
|
354 | try {
|
355 | nDiv.set('innerHTML', 'test-html-content')
|
356 | } catch (_nateError) {
|
357 | nateError = _nateError
|
358 | }
|
359 | nateError.getErrorCode().should.be.eql('nateChildrenAlreadyExists')
|
360 |
|
361 |
|
362 | nateError = null
|
363 | try {
|
364 | nDiv.set('textContent', 'test-text-content')
|
365 | } catch (_nateError) {
|
366 | nateError = _nateError
|
367 | }
|
368 | nateError.getErrorCode().should.be.eql('nateChildrenAlreadyExists')
|
369 |
|
370 |
|
371 | nDiv.deleteAllChildren()
|
372 | nDiv.set('innerHTML', 'test-html-content')
|
373 | _verifyResultHtml('<div>test-html-content</div>')
|
374 | })
|
375 |
|
376 | test('Raw text', () => {
|
377 | _reset()
|
378 | nRoot.newTxt('This is a line.')
|
379 | nRoot.br()
|
380 | nRoot.newTxt('And this is one more line.')
|
381 |
|
382 | _verifyResultHtml('This is a line.<br>And this is one more line.')
|
383 | })
|
384 |
|
385 | test('Meta tag', () => {
|
386 | _reset()
|
387 |
|
388 | nRoot.newMeta()
|
389 | .set('name', 'description')
|
390 | .set('content', 'This is test meta tag')
|
391 |
|
392 | _verifyResultHtml('<meta name="description" content="This is test meta tag">')
|
393 | })
|
394 |
|
395 | test('Simple table', () => {
|
396 |
|
397 |
|
398 |
|
399 | _reset()
|
400 |
|
401 | const nTable = nRoot.newTable()
|
402 |
|
403 | const nRowA = nTable.newTr()
|
404 | const nRowB = nTable.newTr()
|
405 | const nRowC = nTable.newTr()
|
406 |
|
407 | nRowA.newTh().newTxt('A1')
|
408 | nRowA.newTh().newTxt('A2')
|
409 | nRowA.newTh().newTxt('A3')
|
410 |
|
411 | nRowB.newTd().newTxt('B1')
|
412 | nRowB.newTd().newTxt('B2')
|
413 | nRowB.newTd().newTxt('B3')
|
414 |
|
415 | nRowC.newTd().newTxt('C1')
|
416 | nRowC.newTd().newTxt('C2')
|
417 | nRowC.newTd().newTxt('C3')
|
418 |
|
419 | _verifyResultHtml(
|
420 | '<table>' +
|
421 | '<tr><th>A1</th><th>A2</th><th>A3</th></tr>' +
|
422 | '<tr><td>B1</td><td>B2</td><td>B3</td></tr>' +
|
423 | '<tr><td>C1</td><td>C2</td><td>C3</td></tr>' +
|
424 | '</table>')
|
425 | })
|
426 |
|
427 | test('Table with rowspan', () => {
|
428 |
|
429 |
|
430 |
|
431 | _reset()
|
432 |
|
433 | const nTable = nRoot.newTable()
|
434 |
|
435 | const nRowA = nTable.newTr()
|
436 | const nRowB = nTable.newTr()
|
437 | const nRowC = nTable.newTr()
|
438 |
|
439 | nRowA.newTh().newTxt('A1')
|
440 | nRowA.newTh().set('rowSpan', 3).newTxt('2')
|
441 | nRowA.newTh().newTxt('A3')
|
442 |
|
443 | nRowB.newTd().newTxt('B1')
|
444 | nRowB.newTd().newTxt('B3')
|
445 |
|
446 | nRowC.newTd().newTxt('C1')
|
447 | nRowC.newTd().newTxt('C3')
|
448 |
|
449 | _verifyResultHtml(
|
450 | '<table>' +
|
451 | '<tr><th>A1</th><th rowspan="3">2</th><th>A3</th></tr>' +
|
452 | '<tr><td>B1</td>' + '<td>B3</td></tr>' +
|
453 | '<tr><td>C1</td>' + '<td>C3</td></tr>' +
|
454 | '</table>')
|
455 | })
|
456 |
|
457 | test('Table with colspan', () => {
|
458 |
|
459 |
|
460 |
|
461 | _reset()
|
462 |
|
463 | const nTable = nRoot.newTable()
|
464 |
|
465 | const nRowA = nTable.newTr()
|
466 | const nRowB = nTable.newTr()
|
467 | const nRowC = nTable.newTr()
|
468 |
|
469 | nRowA.newTh().newTxt('A1')
|
470 | nRowA.newTh().newTxt('A2')
|
471 | nRowA.newTh().newTxt('A3')
|
472 |
|
473 | nRowB.newTd().set('colSpan', 3).newTxt('B')
|
474 |
|
475 | nRowC.newTd().newTxt('C1')
|
476 | nRowC.newTd().newTxt('C2')
|
477 | nRowC.newTd().newTxt('C3')
|
478 |
|
479 | _verifyResultHtml(
|
480 | '<table>' +
|
481 | '<tr><th>A1</th><th>A2</th><th>A3</th></tr>' +
|
482 | '<tr><td colspan="3">B</td></tr>' +
|
483 | '<tr><td>C1</td><td>C2</td><td>C3</td></tr>' +
|
484 | '</table>')
|
485 | })
|
486 |
|
487 | _suite('Generic attributes', () => {
|
488 | const arrayOfAttributes = [
|
489 | {key: 'id' , value: 'this-is-the-item'},
|
490 | {key: 'class' , value: 'this-is-the-class'},
|
491 | {key: 'cols' , value: '1'},
|
492 | {key: 'name' , value: 'this-is-the-name'},
|
493 | {key: 'rows' , value: '2'},
|
494 | {key: 'wrap' , value: 'hard'},
|
495 | {key: 'itemscope' , value: 'this-is-the-itemscope'},
|
496 | {key: 'itemtype' , value: 'this-is-the-itemtype'},
|
497 | {key: 'itemprop' , value: 'this-is-the-itemprop'},
|
498 | {key: 'content' , value: 'this-is-the-content'},
|
499 | {key: 'style' , value: 'color: red; background-color: green;'},
|
500 |
|
501 | ]
|
502 |
|
503 | for (const idx in arrayOfAttributes) {
|
504 | const item = arrayOfAttributes[idx]
|
505 | const key = item.key
|
506 | const value = item.value
|
507 |
|
508 | test(key, () => {
|
509 | _reset()
|
510 | nRoot.newDiv().set(key, value).setText('text')
|
511 | _verifyResultHtml('<div ' + key + '="' + value + '">text</div>')
|
512 | })
|
513 | }
|
514 | })
|
515 |
|
516 | test('Apply many attributes to one element', () => {
|
517 | _reset()
|
518 |
|
519 |
|
520 | const nDiv = nRoot.newDiv()
|
521 | _verifyResultHtml('<div></div>')
|
522 |
|
523 |
|
524 | nDiv.set('id', 'this-is-the-id')
|
525 | _verifyResultHtml('<div id="this-is-the-id"></div>')
|
526 |
|
527 |
|
528 | nDiv.set('class', 'this-is-the-class1')
|
529 | _verifyResultHtml('<div id="this-is-the-id" class="this-is-the-class1"></div>')
|
530 |
|
531 |
|
532 | nDiv.set('name', 'jenny')
|
533 | _verifyResultHtml('<div id="this-is-the-id" class="this-is-the-class1" name="jenny"></div>')
|
534 |
|
535 |
|
536 | nDiv.set('class', 'this-is-the-class2')
|
537 | _verifyResultHtml('<div id="this-is-the-id" class="this-is-the-class2" name="jenny"></div>')
|
538 | })
|
539 |
|
540 | test('Set CSS text directly', () => {
|
541 | _reset()
|
542 | nRoot.newDiv().set('cssText', 'color: blue;')
|
543 | _verifyResultHtml('<div style="color: blue;"></div>')
|
544 | })
|
545 |
|
546 | test('Read-only input', () => {
|
547 | _reset()
|
548 | nRoot.newInputText().set('readOnly', true)
|
549 | _verifyResultHtml('<input type="text" readonly="">')
|
550 | })
|
551 |
|
552 | test('Checkbox #1: Simple checkbox with label', () => {
|
553 | _reset()
|
554 |
|
555 |
|
556 | nRoot.newLabel().set('for', 'john').newTxt('This is a checkbox')
|
557 | nRoot.newInputCheckbox().set('name', 'john')
|
558 |
|
559 | _verifyResultHtml(
|
560 | '<label for="john">This is a checkbox</label>' +
|
561 | '<input type="checkbox" name="john">')
|
562 | })
|
563 |
|
564 | test('Checkbox #2: Updated checked state on-the-fly', () => {
|
565 | _reset()
|
566 |
|
567 |
|
568 | const nCheckbox = nRoot.newInputCheckbox()
|
569 | _verifyResultHtml('<input type="checkbox">')
|
570 |
|
571 |
|
572 | if (domMode) {
|
573 |
|
574 | nCheckbox.set('checked', true)
|
575 | nCheckbox.elem.checked.should.be.eql(true)
|
576 |
|
577 | nCheckbox.set('checked', false)
|
578 | nCheckbox.elem.checked.should.be.eql(false)
|
579 | } else {
|
580 |
|
581 | nCheckbox.set('checked', true)
|
582 | _verifyResultHtml('<input type="checkbox" checked="checked">')
|
583 |
|
584 | nCheckbox.set('checked', false)
|
585 | _verifyResultHtml('<input type="checkbox">')
|
586 | }
|
587 | })
|
588 |
|
589 | test('Event handlers', () => {
|
590 | _reset()
|
591 | const _onclickCb = function() {alert('This is onclick handler!')}
|
592 | const _onscrollCb = function() {alert('This is onscroll handler!')}
|
593 |
|
594 | const nDiv = nRoot.newDiv()
|
595 | .set('onclick', _onclickCb)
|
596 | .set('onscroll', _onscrollCb)
|
597 |
|
598 | if (domMode) {
|
599 |
|
600 | nDiv.elem.onclick.should.be.eql(_onclickCb)
|
601 | nDiv.elem.onscroll.should.be.eql(_onscrollCb)
|
602 | } else {
|
603 |
|
604 | nRoot.render().should.be.eql(
|
605 | '<div' +
|
606 | ' onclick="alert(\'This is onclick handler!\')"' +
|
607 | ' onscroll="alert(\'This is onscroll handler!\')"' +
|
608 | '></div>')
|
609 | }
|
610 | })
|
611 |
|
612 | test('Simple link', () => {
|
613 | _reset()
|
614 |
|
615 | const nLink = nRoot.newA().set('href', 'http://ke.mu').setText('Kemu Studio')
|
616 | _verifyResultHtml('<a href="http://ke.mu">Kemu Studio</a>')
|
617 |
|
618 |
|
619 | nLink.set('target', '_blank')
|
620 | _verifyResultHtml('<a href="http://ke.mu" target="_blank">Kemu Studio</a>')
|
621 |
|
622 |
|
623 | nLink.set('href', 'http://calculla.com')
|
624 | _verifyResultHtml('<a href="http://calculla.com" target="_blank">Kemu Studio</a>')
|
625 | })
|
626 |
|
627 | test('Simple image', () => {
|
628 | _reset()
|
629 |
|
630 | const nImg = nRoot.newImg().set('src', 'http://calculla.com/g/calculla_logo_32.svg')
|
631 | _verifyResultHtml('<img src="http://calculla.com/g/calculla_logo_32.svg">')
|
632 |
|
633 |
|
634 | nImg.set('src', 'http://calculla.pl/g/calculla_logo_32.svg')
|
635 | _verifyResultHtml('<img src="http://calculla.pl/g/calculla_logo_32.svg">')
|
636 | })
|
637 |
|
638 | test('Select input #1: optgroups', () => {
|
639 | _reset()
|
640 | const nSelect = nRoot.newSelect()
|
641 |
|
642 | const nGroupA = nSelect.newOptGroup().set('label', 'A')
|
643 | nGroupA.newOption().set('value', 'value-a1').setText('A1')
|
644 | nGroupA.newOption().set('value', 'value-a2').setText('A2')
|
645 | nGroupA.newOption().set('value', 'value-a3').setText('A3')
|
646 |
|
647 | const nGroupB = nSelect.newOptGroup().set('label', 'B')
|
648 | nGroupB.newOption().set('value', 'value-b1').setText('B1')
|
649 | nGroupB.newOption().set('value', 'value-b2').setText('B2')
|
650 | nGroupB.newOption().set('value', 'value-b3').setText('B3')
|
651 |
|
652 | const nGroupC = nSelect.newOptGroup().set('label', 'C')
|
653 | nGroupC.newOption().set('value', 'value-c1').setText('C1')
|
654 | nGroupC.newOption().set('value', 'value-c2').setText('C2')
|
655 | nGroupC.newOption().set('value', 'value-c3').setText('C3')
|
656 |
|
657 | _verifyResultHtml(
|
658 | '<select>' +
|
659 | '<optgroup label="A">' +
|
660 | '<option value="value-a1">A1</option>' +
|
661 | '<option value="value-a2">A2</option>' +
|
662 | '<option value="value-a3">A3</option>' +
|
663 | '</optgroup>' +
|
664 | '<optgroup label="B">' +
|
665 | '<option value="value-b1">B1</option>' +
|
666 | '<option value="value-b2">B2</option>' +
|
667 | '<option value="value-b3">B3</option>' +
|
668 | '</optgroup>' +
|
669 | '<optgroup label="C">' +
|
670 | '<option value="value-c1">C1</option>' +
|
671 | '<option value="value-c2">C2</option>' +
|
672 | '<option value="value-c3">C3</option>' +
|
673 | '</optgroup>' +
|
674 | '</select>')
|
675 | })
|
676 |
|
677 | test('Select input #2: set selected item on-the-fly', () => {
|
678 | _reset()
|
679 |
|
680 |
|
681 | const nSelect = nRoot.newSelect()
|
682 | const nOption1 = nSelect.newOption().set('value', 'value1').setText('option1')
|
683 | const nOption2 = nSelect.newOption().set('value', 'value2').setText('option2')
|
684 | const nOption3 = nSelect.newOption().set('value', 'value3').setText('option3')
|
685 |
|
686 | _verifyResultHtml(
|
687 | '<select>' +
|
688 | '<option value="value1">option1</option>' +
|
689 | '<option value="value2">option2</option>' +
|
690 | '<option value="value3">option3</option>' +
|
691 | '</select>')
|
692 |
|
693 |
|
694 | nOption2.set('selected', true)
|
695 |
|
696 | if (domMode) {
|
697 |
|
698 | nOption1.elem.selected.should.be.eql(false)
|
699 | nOption2.elem.selected.should.be.eql(true)
|
700 | nOption3.elem.selected.should.be.eql(false)
|
701 | } else {
|
702 |
|
703 | _verifyResultHtml(
|
704 | '<select>' +
|
705 | '<option value="value1">option1</option>' +
|
706 | '<option value="value2" selected="selected">option2</option>' +
|
707 | '<option value="value3">option3</option>' +
|
708 | '</select>')
|
709 | }
|
710 | })
|
711 |
|
712 | _suite('Style attributes', () => {
|
713 | const arrayOfAttributes = [
|
714 |
|
715 | {key: 'cursor', value: 'pointer'},
|
716 | {key: 'float', value: 'left'},
|
717 | {key: 'height', value: '1px'},
|
718 | {key: 'width', value: '2px'},
|
719 | {key: 'left', value: '3px'},
|
720 | {key: 'top', value: '4px'},
|
721 | {key: 'right', value: '5px'},
|
722 | {key: 'bottom', value: '6px'},
|
723 | {key: 'margin', value: '7px'},
|
724 | {key: 'padding', value: '8px'},
|
725 | {key: 'overflow', value: 'hidden'},
|
726 | {key: 'font', value: '12px 12px'},
|
727 | {key: 'position', value: 'absolute'},
|
728 | {key: 'visibility', value: 'none'},
|
729 | {key: 'color', value: 'red'},
|
730 | {key: 'border', value: '8px solid green'},
|
731 | {key: 'display', value: 'block'},
|
732 |
|
733 |
|
734 | {key: 'overflowX' , cssKey: 'overflow-x' , value: 'auto'},
|
735 | {key: 'overflowY' , cssKey: 'overflow-y' , value: 'visible'},
|
736 | {key: 'zIndex' , cssKey: 'z-index' , value: '1234'},
|
737 | {key: 'textAlign' , cssKey: 'text-align' , value: 'center'},
|
738 | {key: 'verticalAlign' , cssKey: 'vertical-align' , value: 'bottom'},
|
739 | {key: 'backgroundColor' , cssKey: 'background-color' , value: 'blue'},
|
740 | {key: 'borderCollapse' , cssKey: 'border-collapse' , value: 'collapse'},
|
741 | {key: 'fontFamily' , cssKey: 'font-family' , value: 'arial'},
|
742 | {key: 'fontSize' , cssKey: 'font-size' , value: '50em'},
|
743 | {key: 'fontStyle' , cssKey: 'font-style' , value: 'italic'},
|
744 | {key: 'fontWeight' , cssKey: 'font-weight' , value: 'bold'}
|
745 | ]
|
746 |
|
747 | for (const idx in arrayOfAttributes) {
|
748 | const item = arrayOfAttributes[idx]
|
749 | const key = item.key
|
750 | const value = item.value
|
751 | const cssKey = item.cssKey ? item.cssKey : item.key
|
752 |
|
753 | test(key, () => {
|
754 | _reset()
|
755 | nRoot.newDiv().set(key, value).setText('text')
|
756 | _verifyResultHtml('<div style="' + cssKey + ': ' + value + ';">text</div>')
|
757 | })
|
758 | }
|
759 | })
|
760 |
|
761 | _suite('Dataset #1: Single attribute', () => {
|
762 | const _createTestGood = (key, jsKey, value) => {
|
763 | test('"' + key + '" => "' + value + '"', () => {
|
764 | _reset()
|
765 | nRoot.newDiv().setData(key, value)
|
766 | _verifyResultHtml('<div data-' + jsKey + '="' + value + '"></div>')
|
767 | })
|
768 | }
|
769 |
|
770 | const _createTestBadKey = (key) => {
|
771 | const keyForPreview = key ? JSON.stringify(key) : '' + key
|
772 | test(keyForPreview, () => {
|
773 | _reset()
|
774 | try {
|
775 | nRoot.newDiv().setData(key, 'value')
|
776 | }
|
777 | catch(err) {
|
778 | err.getErrorCode().should.be.eql('invalidKey')
|
779 | }
|
780 | })
|
781 | }
|
782 |
|
783 |
|
784 | _suite('Good examples', () => {
|
785 | _createTestGood('key' , 'key' , 'value')
|
786 | _createTestGood('123' , '123' , 'value')
|
787 | _createTestGood('_' , '_' , 'value')
|
788 | _createTestGood('_key', '_key' , 'value')
|
789 |
|
790 | _createTestGood('key' , 'key' , 'VALUE')
|
791 | _createTestGood('key' , 'key' , '123')
|
792 | _createTestGood('key' , 'key' , 'this-is-some-value')
|
793 | _createTestGood('key' , 'key' , '3.14')
|
794 | _createTestGood('key' , 'key' , '')
|
795 |
|
796 | _createTestGood('KEY' , 'key' , 'value')
|
797 | _createTestGood('KeY' , 'key' , 'value')
|
798 | _createTestGood('kEy' , 'key' , 'value')
|
799 | _createTestGood('key_abc', 'key_abc', 'value')
|
800 | _createTestGood('key-abc', 'key-abc', 'value')
|
801 | _createTestGood('key.abc', 'key.abc', 'value')
|
802 | _createTestGood('key:abc', 'key:abc', 'value')
|
803 | _createTestGood('a.b.c.d', 'a.b.c.d', 'value')
|
804 | })
|
805 |
|
806 |
|
807 | _suite('Bad keys', () => {
|
808 | _createTestBadKey()
|
809 | _createTestBadKey('')
|
810 | _createTestBadKey(' ')
|
811 | _createTestBadKey('a b')
|
812 | _createTestBadKey('.')
|
813 | _createTestBadKey(',')
|
814 | _createTestBadKey('-')
|
815 | _createTestBadKey(null)
|
816 | _createTestBadKey(123)
|
817 | _createTestBadKey(3.14)
|
818 | _createTestBadKey([])
|
819 | _createTestBadKey([1234])
|
820 | _createTestBadKey({})
|
821 | _createTestBadKey({x:1234})
|
822 | })
|
823 | })
|
824 | })
|
825 | }
|
826 |
|
827 | TestNateHtml(false)
|
828 | TestNateHtml(true)
|