blob: 107f44dc374cd6f74c4e97fce6dc2bf701e66b87 [file] [log] [blame]
Akron45308ce2020-08-28 14:10:23 +02001define(['plugin/server','plugin/widget','panel', 'panel/query', 'panel/result', 'plugin/service', 'pipe', 'vc','util'], function (pluginServerClass, widgetClass, panelClass, queryPanelClass, resultPanelClass, serviceClass, pipeClass, vcClass) {
Akronb43c8c62018-07-04 18:27:28 +02002
3 describe('KorAP.Plugin.Server', function () {
4
5 it('should be initializable', function () {
6 var manager = pluginServerClass.create();
7 expect(manager).toBeTruthy();
8 manager.destroy();
9 });
10
11 it('should add a widget', function () {
12 var manager = pluginServerClass.create();
Akron4a703872018-07-26 10:59:41 +020013 var panel = panelClass.create();
Akronbb891982020-10-05 16:07:18 +020014 var id = manager.addWidget(panel, {"name": 'Example 1', "src": 'about:blank'});
Akronb43c8c62018-07-04 18:27:28 +020015 expect(id).toMatch(/^id-/);
Akron4a703872018-07-26 10:59:41 +020016
17 var panelE = panel.element();
18 var widgetE = panelE.firstChild.firstChild;
19 expect(widgetE.classList.contains('widget')).toBeTruthy();
20 expect(widgetE.firstChild.tagName).toEqual("IFRAME");
21 var iframe = widgetE.firstChild;
22 expect(iframe.getAttribute("src")).toEqual("about:blank");
23
24 expect(widgetE.lastChild.firstChild.textContent).toEqual("Close");
25 expect(widgetE.lastChild.lastChild.textContent).toEqual("Example 1");
26
Akronb43c8c62018-07-04 18:27:28 +020027 manager.destroy();
28 });
Akron10a47962018-07-12 21:17:10 +020029
Akron22598cd2019-12-09 14:59:03 +010030 it('should add a service', function () {
31 var manager = pluginServerClass.create();
32
33 var e = manager.element();
34
35 document.body.appendChild(e);
36
37 expect(document.getElementById("services")).toBeTruthy();
38
39 expect(e.getAttribute("id")).toBe("services");
40 expect(e.children.length).toBe(0);
41
Akronbb891982020-10-05 16:07:18 +020042 var id = manager.addService({"name":'Example 1', "src":'about:blank'});
Akron22598cd2019-12-09 14:59:03 +010043 expect(id).toMatch(/^id-/);
44
45 expect(e.children.length).toBe(1);
46
47 manager.destroy();
48
49 expect(document.getElementById("services")).toBeFalsy();
50
51 });
52
Akron4a703872018-07-26 10:59:41 +020053 it('should close a widget', function () {
54 var manager = pluginServerClass.create();
55 var panel = panelClass.create();
Akronbb891982020-10-05 16:07:18 +020056 var id = manager.addWidget(panel, {"name":'Example 2', "src":'about:blank'});
Akron4a703872018-07-26 10:59:41 +020057 expect(id).toMatch(/^id-/);
58
59 var panelE = panel.element();
60 var widgetE = panelE.firstChild.firstChild;
61 expect(widgetE.classList.contains('widget')).toBeTruthy();
62
63 expect(panelE.getElementsByClassName('view').length).toEqual(1);
64
Akron22598cd2019-12-09 14:59:03 +010065 var widget = manager.service(id);
66 expect(widget.isWidget).toBeTruthy();
Akron4a703872018-07-26 10:59:41 +020067 widget.close();
68
69 expect(panelE.getElementsByClassName('view').length).toEqual(0);
Akron4a703872018-07-26 10:59:41 +020070 manager.destroy();
71 });
72
73
74 it('should fail on invalid registrations', function () {
Akron10a47962018-07-12 21:17:10 +020075 var manager = pluginServerClass.create();
76
77 expect(
78 function() { manager.register({}) }
79 ).toThrow(new Error("Missing name of plugin"));
80
81 expect(
82 function() { manager.register({
83 name : 'Example',
84 embed : ''
85 })}
86 ).toThrow(new Error("Embedding of plugin is no list"));
87
88 expect(
89 function() { manager.register({
90 name : 'Example',
91 embed : [{
92 panel : ''
93 }]
94 })}
95 ).toThrow(new Error("Panel for plugin is invalid"));
Akron2d0d96d2019-11-18 19:49:50 +010096 manager.destroy();
97 });
98
99 it('should accept valid registrations for matches', function () {
100 var manager = pluginServerClass.create();
101
102 manager.register({
103 name : 'Check',
104 embed : [{
105 panel : 'match',
106 title : 'Translate',
107 onClick : {
108 template : 'test'
109 }
110 }]
111 });
112
113 expect(manager.buttonGroup('match').length).toEqual(1);
114 manager.destroy();
115 });
Akron3d013802020-10-07 15:03:38 +0200116
Akron2d0d96d2019-11-18 19:49:50 +0100117 it('should accept valid registrations for query temporary', function () {
118 var manager = pluginServerClass.create();
119
120 manager.register({
121 name : 'Check',
122 embed : [{
123 panel : 'query',
124 title : 'Translate',
125 onClick : {
126 template : 'test'
127 }
128 }]
129 });
130
131 expect(manager.buttonGroup('query').length).toEqual(1);
132 manager.destroy();
Akron10a47962018-07-12 21:17:10 +0200133 });
hebasta043e96f2019-11-28 12:33:00 +0100134
135
136 it('should accept valid registrations for result', function () {
137 var manager = pluginServerClass.create();
138
139 manager.register({
140 name : 'Check',
141 embed : [{
142 panel : 'result',
143 title : 'Translate',
144 onClick : {
145 template : 'test'
146 }
147 }]
148 });
149
150 expect(manager.buttonGroup('result').length).toEqual(1);
151 manager.destroy();
152 });
Akronba09ed22020-10-01 16:01:45 +0200153
154 it('should accept valid registrations for addWidget', function () {
155 let p = KorAP.Panel["result"] = panelClass.create();
156
157 let manager = pluginServerClass.create();
158
159 manager.register({
160 name : 'Check',
161 embed : [{
162 panel : 'result',
163 title : 'Add',
164 onClick : {
165 template : 'about:blank',
166 action : 'addWidget'
167 }
168 }]
169 });
170
Akron37ea1192021-07-28 10:40:14 +0200171 let b = p.actions().element().firstChild;
Akronba09ed22020-10-01 16:01:45 +0200172 expect(b.hasAttribute("data-icon")).toBeFalsy();
173 expect(b.hasAttribute("cls")).toBeFalsy();
174 expect(b.getAttribute("title")).toEqual("Add");
175
176 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
177
178 b.click();
179
180 expect(p.element().querySelectorAll("iframe").length).toEqual(1);
181 expect(p.element().querySelectorAll("div.view.widget").length).toEqual(1);
182 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
183
184 b.click();
185
186 expect(p.element().querySelectorAll("iframe").length).toEqual(2);
187 expect(p.element().querySelectorAll("div.view.widget").length).toEqual(2);
188 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(2);
189
190 manager.destroy();
191
192 KorAP.Panel["result"] = undefined;
193 });
194
Akronba09ed22020-10-01 16:01:45 +0200195 it('should accept valid registrations for setWidget', function () {
196 let p = KorAP.Panel["result"] = panelClass.create();
197
198 let manager = pluginServerClass.create();
199
200 manager.register({
201 name : 'Check',
202 embed : [{
203 panel : 'result',
204 title : 'Add',
205 onClick : {
206 template : 'about:blank',
Marc Kupietz0d0dc6b2026-02-15 08:43:12 +0100207 action : 'setWidget',
208 permissions: ['same-origin'] // Temporary
Akronba09ed22020-10-01 16:01:45 +0200209 }
210 }]
211 });
212
Akron37ea1192021-07-28 10:40:14 +0200213 let b = p.actions().element().firstChild;
Akronba09ed22020-10-01 16:01:45 +0200214 expect(b.hasAttribute("data-icon")).toBeFalsy();
215 expect(b.hasAttribute("cls")).toBeFalsy();
216 expect(b.getAttribute("title")).toEqual("Add");
217
218 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
219
220 b.click();
221
222 expect(p.element().querySelectorAll("iframe").length).toEqual(1);
223 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
224
225 b.click();
226
227 expect(p.element().querySelectorAll("iframe").length).toEqual(1);
228 expect(p.element().querySelectorAll("div.view.widget").length).toEqual(1);
229 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(0);
Akronfcf89db2020-10-01 17:40:20 +0200230
231 p.element().querySelector("span.close").click();
232
233 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
Akronda32e7a2021-11-16 17:28:57 +0100234
Akronfcf89db2020-10-01 17:40:20 +0200235 b.click();
236
237 expect(p.element().querySelectorAll("iframe").length).toEqual(1);
238 expect(p.element().querySelectorAll("div.view.widget").length).toEqual(1);
239 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
Akron24b570b2026-03-05 17:47:29 +0100240 expect(p.element().querySelector("iframe").getAttribute('sandbox')).toEqual('allow-same-origin'); // Temporary
Akronda32e7a2021-11-16 17:28:57 +0100241
Akronba09ed22020-10-01 16:01:45 +0200242 manager.destroy();
243
244 KorAP.Panel["result"] = undefined;
245 });
Akronfb11a962020-10-05 12:12:55 +0200246
Akronb0ae8412026-02-24 11:47:52 +0100247 it('should accept valid registrations for setWidget with active', function () {
248 let p = KorAP.Panel["result"] = panelClass.create();
249
250 let manager = pluginServerClass.create();
251
252 // Attach services container so addService works
253 document.body.appendChild(manager.element());
254
255 manager.register({
256 name : 'Check',
257 embed : [{
258 panel : 'result',
259 title : 'Map',
260 onClick : {
261 template : 'about:blank',
262 action : 'setWidget',
263 active : false
264 }
265 }]
266 });
267
268 let b = p.actions().element().firstChild;
269 expect(b.getAttribute("title")).toEqual("Map");
270
271 // Button should have a check element (marker-box)
272 expect(b.firstChild.classList.contains('check')).toBeTruthy();
273 expect(b.firstChild.classList.contains('button-icon')).toBeTruthy();
274
275 // active state should be set to false initially
276 expect(b.active).toBeDefined();
277 expect(b.active.get()).toBe(false);
278
279 // Check is not checked initially
280 expect(b.firstChild.classList.contains('checked')).toBeFalsy();
281
282 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
283
284 // Click on check (marker-box) - loads background service,
285 // no visible widget in the panel
286 b.firstChild.click();
287
288 // No iframe in the panel - service is in the services container
289 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
290 expect(manager.element().querySelectorAll("iframe").length).toEqual(1);
291
292 // No widget view element should exist in the panel
293 expect(p.element().querySelectorAll("div.view").length).toEqual(0);
294
295 // active state should have toggled to true
296 expect(b.active.get()).toBe(true);
297 expect(b.firstChild.classList.contains('checked')).toBeTruthy();
298
299 // Click on check again - should not add another service, just toggle active
300 b.firstChild.click();
301 expect(manager.element().querySelectorAll("iframe").length).toEqual(1);
302 expect(b.active.get()).toBe(false);
303 expect(b.firstChild.classList.contains('checked')).toBeFalsy();
304
305 // Click on title - should open the widget visibly
306 b.click();
307 expect(p.element().querySelectorAll("iframe").length).toEqual(1);
308 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
309
310 // Click title again - should toggle visibility (hide via state)
311 b.click();
312 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(0);
313
314 manager.destroy();
315 KorAP.Panel["result"] = undefined;
316 });
317
318 it('should not show any view element when checkbox is clicked', function () {
319 let p = KorAP.Panel["result"] = panelClass.create();
320 let manager = pluginServerClass.create();
321
322 document.body.appendChild(manager.element());
323
324 manager.register({
325 name : 'NoBar',
326 embed : [{
327 panel : 'result',
328 title : 'Map',
329 onClick : {
330 template : 'about:blank',
331 action : 'setWidget',
332 active : false
333 }
334 }]
335 });
336
337 let b = p.actions().element().firstChild;
338
339 // Click checkbox
340 b.firstChild.click();
341
342 // No view element must exist in the panel at all —
343 // not visible, not hidden, not minimized. The checkbox
344 // must only create a background service, never a widget.
345 expect(p.element().querySelectorAll("div.view").length).toEqual(0);
346 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
347
348 // The iframe must be in the services container instead
349 expect(manager.element().querySelectorAll("iframe").length).toEqual(1);
350
351 // Clicking the title afterwards must properly open the widget
352 b.click();
353 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
354 expect(p.element().querySelectorAll("iframe").length).toEqual(1);
355
356 manager.destroy();
357 KorAP.Panel["result"] = undefined;
358 });
359
360 it('should toggle active via checkbox when widget is open', function () {
361 let p = KorAP.Panel["result"] = panelClass.create();
362 let manager = pluginServerClass.create();
363
364 document.body.appendChild(manager.element());
365
366 manager.register({
367 name : 'Check',
368 embed : [{
369 panel : 'result',
370 title : 'Map',
371 onClick : {
372 template : 'about:blank',
373 action : 'setWidget',
374 active : false
375 }
376 }]
377 });
378
379 let b = p.actions().element().firstChild;
380
381 // Open the widget via title-click
382 b.click();
383 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
384 expect(b.active.get()).toBe(false);
385
386 let id = b['widgetID'];
387 expect(id).toBeDefined();
388
389 // Active association should exist on the widget
390 expect(b.active.associates()).toBeGreaterThan(0);
391
392 // Click checkbox to activate - should toggle active state
393 b.firstChild.click();
394 expect(b.active.get()).toBe(true);
395 expect(b.firstChild.classList.contains('checked')).toBeTruthy();
396
397 // Widget should still be visible
398 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
399
400 // widgetID should remain the same (no new service created)
401 expect(b['widgetID']).toEqual(id);
402
403 // Click checkbox again to deactivate
404 b.firstChild.click();
405 expect(b.active.get()).toBe(false);
406 expect(b.firstChild.classList.contains('checked')).toBeFalsy();
407
408 // Widget should still be visible
409 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
410
411 manager.destroy();
412 KorAP.Panel["result"] = undefined;
413 });
414
415 it('should not duplicate pipes when opening widget after checkbox', function () {
416 var tempPipe = KorAP.Pipe;
417 KorAP.Pipe = pipeClass.create();
418
419 let p = KorAP.Panel["result"] = panelClass.create();
420 let manager = pluginServerClass.create();
421
422 document.body.appendChild(manager.element());
423
424 manager.register({
425 name : 'PipeCheck',
426 embed : [{
427 panel : 'result',
428 title : 'Map',
429 onClick : {
430 template : 'about:blank',
431 action : 'setWidget',
432 active : false
433 }
434 }]
435 });
436
437 let b = p.actions().element().firstChild;
438
439 // Click checkbox - background service created, active becomes true
440 b.firstChild.click();
441 expect(b.active.get()).toBe(true);
442 expect(manager.element().querySelectorAll("iframe").length).toEqual(1);
443
444 // Simulate the plugin adding a pipe via the background service
445 let bgId = b['widgetID'];
446 manager._receiveMsg({
447 "data" : {
448 "originID" : bgId,
449 "action" : "pipe",
450 "job" : "add",
451 "service" : "https://mapper.example"
452 }
453 });
454 expect(KorAP.Pipe.toString()).toEqual("https://mapper.example");
455
456 // Click title - opens widget, closes background service
457 b.click();
458 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
459
460 // The new widget's plugin re-initializes and tries to add the
461 // same pipe again — the pipe system must deduplicate.
462 let wId = b['widgetID'];
463 manager._receiveMsg({
464 "data" : {
465 "originID" : wId,
466 "action" : "pipe",
467 "job" : "add",
468 "service" : "https://mapper.example"
469 }
470 });
471
472 // Pipe must still contain only one entry
473 expect(KorAP.Pipe.toString()).toEqual("https://mapper.example");
474 expect(KorAP.Pipe.size()).toEqual(1);
475
476 manager.destroy();
477 KorAP.Pipe = tempPipe;
478 KorAP.Panel["result"] = undefined;
479 });
480
481 it('should toggle checkbox visual when widget is open', function () {
482 let p = KorAP.Panel["result"] = panelClass.create();
483 let manager = pluginServerClass.create();
484
485 document.body.appendChild(manager.element());
486
487 manager.register({
488 name : 'VisualCheck',
489 embed : [{
490 panel : 'result',
491 title : 'Map',
492 onClick : {
493 template : 'about:blank',
494 action : 'setWidget',
495 active : false
496 }
497 }]
498 });
499
500 let b = p.actions().element().firstChild;
501 let check = b.firstChild;
502
503 // Open widget via title
504 b.click();
505 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
506 expect(check.classList.contains('checked')).toBeFalsy();
507
508 // Click checkbox - should visually check
509 check.click();
510 expect(b.active.get()).toBe(true);
511 expect(check.classList.contains('checked')).toBeTruthy();
512
513 // Click checkbox again - should visually uncheck
514 check.click();
515 expect(b.active.get()).toBe(false);
516 expect(check.classList.contains('checked')).toBeFalsy();
517
518 // Widget should still be visible throughout
519 expect(p.element().querySelectorAll("div.view.show.widget").length).toEqual(1);
520
521 manager.destroy();
522 KorAP.Panel["result"] = undefined;
523 });
524
525 it('should accept valid registrations for addWidget with active', function () {
526 let p = KorAP.Panel["result"] = panelClass.create();
527
528 let manager = pluginServerClass.create();
529
530 manager.register({
531 name : 'Check',
532 embed : [{
533 panel : 'result',
534 title : 'Export',
535 onClick : {
536 template : 'about:blank',
537 action : 'addWidget',
538 active : true
539 }
540 }]
541 });
542
543 let b = p.actions().element().firstChild;
544
545 // active state should be set to true initially
546 expect(b.active).toBeDefined();
547 expect(b.active.get()).toBe(true);
548 expect(b.firstChild.classList.contains('checked')).toBeTruthy();
549
550 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
551
552 // Click on check - only toggles active, no widget created
553 b.firstChild.click();
554 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
555 expect(b.active.get()).toBe(false);
556 expect(b.firstChild.classList.contains('checked')).toBeFalsy();
557
558 // Click on title - should load a widget visibly
559 b.click();
560 expect(p.element().querySelectorAll("iframe").length).toEqual(1);
561
562 manager.destroy();
563 KorAP.Panel["result"] = undefined;
564 });
565
566 it('should support changeTitle on buttons', function () {
567 let p = KorAP.Panel["result"] = panelClass.create();
568
569 let manager = pluginServerClass.create();
570
571 manager.register({
572 name : 'Check',
573 embed : [{
574 panel : 'result',
575 title : 'Map',
576 onClick : {
577 template : 'about:blank',
578 action : 'setWidget'
579 }
580 }]
581 });
582
583 let b = p.actions().element().firstChild;
584 expect(b.lastChild.textContent).toEqual("Map");
585
586 b.changeTitle("New Title");
587 expect(b.lastChild.textContent).toEqual("New Title");
588
589 manager.destroy();
590 KorAP.Panel["result"] = undefined;
591 });
592
593 it('should handle Title set message', function () {
594 let p = KorAP.Panel["result"] = panelClass.create();
595
596 let manager = pluginServerClass.create();
597
598 manager.register({
599 name : 'TitlePlugin',
600 embed : [{
601 panel : 'result',
602 title : 'Original',
603 onClick : {
604 template : 'about:blank',
605 action : 'setWidget'
606 }
607 }]
608 });
609
610 let b = p.actions().element().firstChild;
611 expect(b.lastChild.textContent).toEqual("Original");
612
613 // Click to open widget
614 b.click();
615
616 let id = b['widgetID'];
617 expect(id).toBeDefined();
618
619 // Send Title set message
620 manager._receiveMsg({
621 "data" : {
622 "originID" : id,
623 "action" : "set",
624 "key" : "Title",
625 "value" : "Changed"
626 }
627 });
628
629 expect(b.lastChild.textContent).toEqual("Changed");
630
631 manager.destroy();
632 KorAP.Panel["result"] = undefined;
633 });
634
635 it('should handle Active get/set messages', function () {
636 let p = KorAP.Panel["result"] = panelClass.create();
637
638 let manager = pluginServerClass.create();
639
640 manager.register({
641 name : 'ActivePlugin',
642 embed : [{
643 panel : 'result',
644 title : 'Map',
645 onClick : {
646 template : 'about:blank',
647 action : 'setWidget',
648 active : false
649 }
650 }]
651 });
652
653 let b = p.actions().element().firstChild;
654 expect(b.active.get()).toBe(false);
655
656 // Click title to open widget
657 b.click();
658
659 let id = b['widgetID'];
660 expect(id).toBeDefined();
661
662 // Get active state
663 let data = {
664 "originID" : id,
665 "action" : "get",
666 "key" : "Active"
667 };
668 manager._receiveMsg({ "data" : data });
669 expect(data.value).toBe(false);
670
671 // Set active state via message
672 manager._receiveMsg({
673 "data" : {
674 "originID" : id,
675 "action" : "set",
676 "key" : "Active",
677 "value" : true
678 }
679 });
680 expect(b.active.get()).toBe(true);
681 expect(b.firstChild.classList.contains('checked')).toBeTruthy();
682
683 // Roll active state via message (no value)
684 manager._receiveMsg({
685 "data" : {
686 "originID" : id,
687 "action" : "set",
688 "key" : "Active"
689 }
690 });
691 expect(b.active.get()).toBe(false);
692 expect(b.firstChild.classList.contains('checked')).toBeFalsy();
693
694 manager.destroy();
695 KorAP.Panel["result"] = undefined;
696 });
697
Akrona70b6892021-11-04 14:23:24 +0100698 it('should accept valid registrations for toggle', function () {
699 let p = KorAP.Panel["result"] = panelClass.create();
700
701 let manager = pluginServerClass.create();
702
703 manager.register({
704 name : 'Check',
705 embed : [{
706 panel : 'result',
707 title : 'Glemm',
Akron83a58bc2024-11-08 09:55:19 +0100708 desc : 'Start Glemm',
Akrona70b6892021-11-04 14:23:24 +0100709 onClick : {
Akronda32e7a2021-11-16 17:28:57 +0100710 state : 'check',
Akrona70b6892021-11-04 14:23:24 +0100711 template : 'about:blank',
712 action : 'toggle',
713 'default' : false
714 }
715 }]
716 });
717
718 let b = p.actions().element().firstChild;
719 expect(b.hasAttribute("data-icon")).toBeFalsy();
720 expect(b.hasAttribute("cls")).toBeFalsy();
Akron83a58bc2024-11-08 09:55:19 +0100721 expect(b.lastChild.innerText).toEqual("Glemm");
722 expect(b.getAttribute("title")).toEqual("Start Glemm");
Akrona70b6892021-11-04 14:23:24 +0100723 expect(b.firstChild.classList.contains('button-icon')).toBeTruthy();
724 expect(b.firstChild.classList.contains('check')).toBeTruthy();
725 expect(b.firstChild.classList.contains('checked')).toBeFalsy();
726
727 expect(p.element().querySelectorAll("iframe").length).toEqual(0);
728
Akronda32e7a2021-11-16 17:28:57 +0100729 expect(manager.states().toString()).toEqual("");
730
Akrona70b6892021-11-04 14:23:24 +0100731 b.click();
732
Akronda32e7a2021-11-16 17:28:57 +0100733 expect(manager.states().toString()).toEqual("\"check\":true");
734
Akron83a58bc2024-11-08 09:55:19 +0100735 expect(b.getAttribute("title")).toEqual("Start Glemm");
Akrona70b6892021-11-04 14:23:24 +0100736 expect(b.firstChild.classList.contains('button-icon')).toBeTruthy();
737 expect(b.firstChild.classList.contains('check')).toBeTruthy();
738 expect(b.firstChild.classList.contains('checked')).toBeTruthy();
739
740 // Check with true default
741 p = KorAP.Panel["result"] = panelClass.create();
742
743 manager = pluginServerClass.create();
744
745 manager.register({
746 name : 'Check',
747 embed : [{
748 panel : 'result',
749 title : 'Glemm',
750 onClick : {
751 template : 'about:blank',
752 action : 'toggle',
753 'default' : true
754 }
755 }]
756 });
757
758 b = p.actions().element().firstChild;
759 expect(b.hasAttribute("data-icon")).toBeFalsy();
760 expect(b.hasAttribute("cls")).toBeFalsy();
761 expect(b.getAttribute("title")).toEqual("Glemm");
762 expect(b.firstChild.classList.contains('button-icon')).toBeTruthy();
763 expect(b.firstChild.classList.contains('check')).toBeTruthy();
764 expect(b.firstChild.classList.contains('checked')).toBeTruthy();
765
766 manager.destroy();
767 KorAP.Panel["result"] = undefined;
768 });
769
770
Akron3d013802020-10-07 15:03:38 +0200771 it('should alert on plugin info (1)', function () {
772
773 let alertMsg;
774 spyOn(window, 'alert').and.callFake(function(msg) {
775 alertMsg = msg;
776 });
777
778 let p = KorAP.Panel["result"] = panelClass.create();
779
780 let manager = pluginServerClass.create();
781
782 manager.register({
783 name : 'Check',
784 embed : [{
785 panel : 'result',
786 title : 'Add',
787 onClick : {
788 template : 'about:blank',
789 action : 'setWidget'
790 }
791 }]
792 });
793
794 expect(alertMsg).toBeUndefined();
795
Akron37ea1192021-07-28 10:40:14 +0200796 let b = p.actions().element().firstChild;
Akron3d013802020-10-07 15:03:38 +0200797 b.click();
798
799 // This may only be temporary and should open the plugin window instead
800 p.element().querySelector("span.plugin").click();
801
802 expect(alertMsg).toEqual('Check');
803
804 manager.destroy();
805 KorAP.Panel["result"] = undefined;
806 });
807
808
809 it('should alert on plugin info (2)', function () {
810
811 let alertMsg;
812 spyOn(window, 'alert').and.callFake(function(msg) {
813 alertMsg = msg;
814 });
815
816 let p = KorAP.Panel["result"] = panelClass.create();
817
818 let manager = pluginServerClass.create();
819
820 manager.register({
821 name : 'Check',
822 desc : 'Simple Check plugin',
823 embed : [{
824 panel : 'result',
825 title : 'Add',
826 onClick : {
827 template : 'about:blank',
828 action : 'setWidget'
829 }
830 }]
831 });
832
833 expect(alertMsg).toBeUndefined();
834
Akron37ea1192021-07-28 10:40:14 +0200835 let b = p.actions().element().firstChild;
Akron3d013802020-10-07 15:03:38 +0200836 b.click();
837
838 // This may only be temporary and should open the plugin window instead
839 p.element().querySelector("span.plugin").click();
840
841 expect(alertMsg).toEqual("Check\n\nSimple Check plugin");
842
843 manager.destroy();
844 KorAP.Panel["result"] = undefined;
845 });
846
847
Akronfb11a962020-10-05 12:12:55 +0200848 it('should accept widget permissions', function () {
849 let p = KorAP.Panel["result"] = panelClass.create();
850
851 let manager = pluginServerClass.create();
852
853 manager.register({
854 name : 'Check',
855 embed : [{
856 panel : 'result',
857 title : 'Add',
Akron83a58bc2024-11-08 09:55:19 +0100858 desc : 'Add something',
Akronfb11a962020-10-05 12:12:55 +0200859 onClick : {
860 template : 'about:blank',
861 action : 'addWidget',
Akronce0d8822020-10-05 16:25:40 +0200862 permissions: ['scripts', 'forms', 'all']
Akronfb11a962020-10-05 12:12:55 +0200863 }
864 }]
865 });
866
Akron37ea1192021-07-28 10:40:14 +0200867 let b = p.actions().element().firstChild;
Akron83a58bc2024-11-08 09:55:19 +0100868 expect(b.lastChild.innerText).toEqual("Add");
869 expect(b.getAttribute("title")).toEqual("Add something");
Akronfb11a962020-10-05 12:12:55 +0200870 b.click();
871 expect(p.element().querySelectorAll("iframe").length).toEqual(1);
Marc Kupietz0d0dc6b2026-02-15 08:43:12 +0100872 expect(p.element().querySelector("iframe").getAttribute('sandbox')).toEqual('allow-forms allow-scripts');
Akronfb11a962020-10-05 12:12:55 +0200873 });
Akronb43c8c62018-07-04 18:27:28 +0200874 });
Marc Kupietz0d0dc6b2026-02-15 08:43:12 +0100875
Akronb43c8c62018-07-04 18:27:28 +0200876 describe('KorAP.Plugin.Widget', function () {
877 it('should be initializable', function () {
Akron22598cd2019-12-09 14:59:03 +0100878 expect(function () { widgetClass.create() }).toThrow(new Error("Service not well defined"));
Akron56a11af2018-07-27 18:28:45 +0200879
Akronbb891982020-10-05 16:07:18 +0200880 widget = widgetClass.create({"name" : "Test", "src":"https://example", "id":56});
Akronb43c8c62018-07-04 18:27:28 +0200881 expect(widget).toBeTruthy();
Akron56a11af2018-07-27 18:28:45 +0200882 expect(widget.id).toEqual(56);
883 expect(widget.name).toEqual("Test");
884 expect(widget.src).toEqual("https://example");
885 });
886
887 it('should create a view element', function () {
Akronbb891982020-10-05 16:07:18 +0200888 var widget = widgetClass.create({
889 "name":"Test",
890 "src":"https://example",
891 "id":56,
Akronce0d8822020-10-05 16:25:40 +0200892 "permissions":["scripts","forms"]
Akronbb891982020-10-05 16:07:18 +0200893 });
Akron56a11af2018-07-27 18:28:45 +0200894 var we = widget.element();
895
896 expect(we.tagName).toEqual("DIV");
897 expect(we.classList.contains('view')).toBeTruthy();
898 expect(we.classList.contains('widget')).toBeTruthy();
899
900 var iframe = we.firstChild;
901 expect(iframe.tagName).toEqual("IFRAME");
Marc Kupietz0d0dc6b2026-02-15 08:43:12 +0100902 expect(iframe.getAttribute("sandbox")).toEqual("allow-forms allow-scripts");
Akron56a11af2018-07-27 18:28:45 +0200903 expect(iframe.getAttribute("src")).toEqual("https://example");
904 expect(iframe.getAttribute("name")).toEqual("56");
Akronfb11a962020-10-05 12:12:55 +0200905
Akron56a11af2018-07-27 18:28:45 +0200906 var btn = we.lastChild;
907 expect(btn.classList.contains("button-group")).toBeTruthy();
908 expect(btn.classList.contains("button-view")).toBeTruthy();
909 expect(btn.classList.contains("widget")).toBeTruthy();
910
911 expect(btn.firstChild.tagName).toEqual("SPAN");
912 expect(btn.firstChild.classList.contains("button-icon")).toBeTruthy();
913 expect(btn.firstChild.classList.contains("close")).toBeTruthy();
914 expect(btn.firstChild.firstChild.tagName).toEqual("SPAN");
915
916 expect(btn.lastChild.tagName).toEqual("SPAN");
917 expect(btn.lastChild.classList.contains("button-icon")).toBeTruthy();
918 expect(btn.lastChild.classList.contains("plugin")).toBeTruthy();
919 expect(btn.lastChild.firstChild.tagName).toEqual("SPAN");
920 expect(btn.lastChild.textContent).toEqual("Test");
921 })
Akronfb11a962020-10-05 12:12:55 +0200922
Akron56a11af2018-07-27 18:28:45 +0200923 it('should be resizable', function () {
Akronbb891982020-10-05 16:07:18 +0200924 var widget = widgetClass.create({"name":"Test", "src":"https://example", "id":56});
Akron56a11af2018-07-27 18:28:45 +0200925 var iframe = widget.show();
926 expect(iframe.style.height).toEqual('0px');
927 widget.resize({ height : 9 });
928 expect(iframe.style.height).toEqual('9px');
Akronb43c8c62018-07-04 18:27:28 +0200929 });
Akron3d9ce5e2020-10-01 15:18:36 +0200930
931 it('should be minimizable', function () {
Akronbb891982020-10-05 16:07:18 +0200932 var widget = widgetClass.create({"name":"Test", "src":"https://example", "id":56});
Akron3d9ce5e2020-10-01 15:18:36 +0200933 var we = widget.element();
934 expect(we.classList.contains('show')).toBeTruthy();
935 widget.minimize();
936 expect(we.classList.contains('show')).toBeFalsy();
937 });
Akronb43c8c62018-07-04 18:27:28 +0200938 });
Akron2d0d96d2019-11-18 19:49:50 +0100939
Akron22598cd2019-12-09 14:59:03 +0100940 describe('KorAP.Plugin.Service', function () {
941 it('should be initializable', function () {
942 expect(function () { serviceClass.create() }).toThrow(new Error("Service not well defined"));
943
Akronbb891982020-10-05 16:07:18 +0200944 let service = serviceClass.create({"name":"Test", "src":"https://example", "id":56});
Akron22598cd2019-12-09 14:59:03 +0100945 expect(service).toBeTruthy();
946 expect(service.id).toEqual(56);
947 expect(service.name).toEqual("Test");
948 expect(service.src).toEqual("https://example");
949 });
950
951 it('should be loadable', function () {
Akronbb891982020-10-05 16:07:18 +0200952 let service = serviceClass.create({"name":"Test", "src":"https://example", "id":56});
Akron22598cd2019-12-09 14:59:03 +0100953 expect(service).toBeTruthy();
954
955 let i = service.load();
956 expect(i.tagName).toEqual("IFRAME");
957 expect(i.getAttribute("allowTransparency")).toEqual("true");
958 expect(i.getAttribute("frameborder")).toEqual(''+0);
959 expect(i.getAttribute("name")).toEqual(''+service.id);
960 expect(i.getAttribute("src")).toEqual(service.src);
961 });
Marc Kupietz0d0dc6b2026-02-15 08:43:12 +0100962
963 // Temporary
964 it('should grant same-origin for same-origin plugins', function () {
965 // about:blank inherits current origin
966 let service = serviceClass.create({
967 "name": "Test",
968 "src": window.location.origin + "/plugin.html",
969 "id": 1,
970 "permissions": ["same-origin"]
971 });
972 let iframe = service.load();
973 expect(iframe.getAttribute("sandbox")).toContain("allow-same-origin");
974 });
975 //Temporary
976 it('should deny same-origin for cross-origin plugins', function () {
977 let service = serviceClass.create({
978 "name": "Test",
979 "src": "https://evil.example.com/plugin.html",
980 "id": 2,
981 "permissions": ["same-origin"]
982 });
983 let iframe = service.load();
984 expect(iframe.getAttribute("sandbox")).not.toContain("allow-same-origin");
985 });
986
Akron22598cd2019-12-09 14:59:03 +0100987 });
988
Akron2d0d96d2019-11-18 19:49:50 +0100989 describe('KorAP.Plugin.QueryPanel', function () {
990 it('should establish a query plugin', function () {
991 var queryPanel = queryPanelClass.create();
992
993 var div = document.createElement('div');
994
995 div.appendChild(queryPanel.element());
996 KorAP.Panel = KorAP.Panel || {};
997 KorAP.Panel['query'] = queryPanel;
998
999 // Register plugin afterwards
1000 var manager = pluginServerClass.create();
1001
1002 manager.register({
1003 name : 'Check',
1004 embed : [{
1005 panel : 'query',
1006 title : 'Translate',
1007 onClick : {
1008 template : 'test'
1009 }
1010 }]
1011 });
1012
1013 expect(manager.buttonGroup('query').length).toEqual(0);
1014
1015 // Clean up
1016 KorAP.Panel['query'] = undefined;
1017 manager.destroy();
1018 });
hebastaf6adf8d2019-11-26 14:04:10 +01001019
1020 it('Plugin buttons should be cleared after adding to panel', function () {
1021
1022 // Register plugin first
1023 KorAP.Plugin = pluginServerClass.create();
1024
1025 KorAP.Plugin.register({
1026 name : 'Check',
1027 embed : [{
1028 panel : 'query',
1029 title : 'Translate',
1030 onClick : {
1031 template : 'test'
1032 }
1033 }]
1034 });
1035
1036
1037 var queryPanel = queryPanelClass.create();
1038 var div = document.createElement('div');
1039
1040 div.appendChild(queryPanel.element());
1041 KorAP.Panel = KorAP.Panel || {};
1042 KorAP.Panel['query'] = queryPanel;
1043 expect(KorAP.Plugin.buttonGroup('query').length).toEqual(0);
1044
1045 // Clean up
1046 KorAP.Panel['query'] = undefined;
1047 KorAP.Plugin.destroy();
1048 KorAP.Plugin = undefined;
1049 });
Akron2d0d96d2019-11-18 19:49:50 +01001050 });
hebasta043e96f2019-11-28 12:33:00 +01001051
Akron45308ce2020-08-28 14:10:23 +02001052 describe('KorAP.Plugin.ResultPanel', function () {
hebasta043e96f2019-11-28 12:33:00 +01001053 it('Plugin is registered second: buttons should be added to panel', function () {
1054
1055 var resultPanel = resultPanelClass.create();
1056 resultPanel.addAlignAction();
1057 var div = document.createElement('div');
1058
1059 div.appendChild(resultPanel.element());
1060 KorAP.Panel = KorAP.Panel || {};
1061 KorAP.Panel['result'] = resultPanel;
1062
1063 // Register plugin afterwards
1064 var manager = pluginServerClass.create();
1065
1066 manager.register({
1067 name : 'ResultPlugin',
1068 embed : [{
1069 panel : 'result',
1070 title : 'Dosomething',
1071 onClick : {
1072 template : 'test'
1073 }
1074 }]
1075 });
1076
1077 expect(manager.buttonGroup('result').length).toEqual(0);
Akron37ea1192021-07-28 10:40:14 +02001078 expect(KorAP.Panel['result'].actions().element().innerHTML).toContain('Dosomething');
hebasta043e96f2019-11-28 12:33:00 +01001079
1080 // Clean up
1081 KorAP.Panel['result'] = undefined;
1082 manager.destroy();
Akron45308ce2020-08-28 14:10:23 +02001083 });
hebasta043e96f2019-11-28 12:33:00 +01001084
1085 it('Plugin is registered first: Buttons should be added to panel and cleared', function () {
1086
1087 // Register plugin first
1088 KorAP.Plugin = pluginServerClass.create();
1089
1090 KorAP.Plugin.register({
1091 name : 'ResultPlugin',
1092 embed : [{
1093 panel : 'result',
1094 title : 'Dosomething',
1095 onClick : {
1096 template : 'test'
1097 }
1098 }]
1099 });
1100
1101 expect(KorAP.Plugin.buttonGroup('result').length).toEqual(1);
1102
1103 var resultPanel = resultPanelClass.create();
1104 var div = document.createElement('div');
1105 div.appendChild(resultPanel.element());
1106 KorAP.Panel = KorAP.Panel || {};
1107 KorAP.Panel['result'] = resultPanel;
1108 expect(KorAP.Plugin.buttonGroup('result').length).toEqual(0);
Akron37ea1192021-07-28 10:40:14 +02001109 expect(KorAP.Panel['result'].actions().element().innerHTML).toContain('Dosomething');
hebasta043e96f2019-11-28 12:33:00 +01001110
1111 // Clean up
1112 KorAP.Panel['result'] = undefined;
1113 KorAP.Plugin.destroy();
1114 KorAP.Plugin = undefined;
1115 });
1116 });
Akronfec66a32020-08-28 13:01:14 +02001117
1118 describe('KorAP.Plugin communications', function () {
1119 it('should receive messages', function () {
1120 var manager = pluginServerClass.create();
Akronbb891982020-10-05 16:07:18 +02001121 var id = manager.addService({"name":'Example 1', "src":'about:blank'});
Akronfec66a32020-08-28 13:01:14 +02001122 expect(id).toMatch(/^id-/);
Akronfec66a32020-08-28 13:01:14 +02001123 var temp = KorAP.koralQuery;
1124 KorAP.koralQuery = { "@type" : "koral:test" };
Akronfec66a32020-08-28 13:01:14 +02001125 let data = {
1126 "originID" : id,
1127 "action" : "get",
1128 "key" : "KQ"
1129 };
Akronfec66a32020-08-28 13:01:14 +02001130 manager._receiveMsg({
1131 "data" : data
1132 });
Akronfec66a32020-08-28 13:01:14 +02001133 manager.destroy();
Akronfec66a32020-08-28 13:01:14 +02001134 expect(data.value["@type"]).toEqual("koral:test");
Akronfec66a32020-08-28 13:01:14 +02001135 // Recreate initial state
1136 KorAP.koralQuery = temp;
1137 });
1138
Akronfec66a32020-08-28 13:01:14 +02001139 it('should add to pipe', function () {
1140 var manager = pluginServerClass.create();
Akronfec66a32020-08-28 13:01:14 +02001141 var temp = KorAP.Pipe;
1142 KorAP.Pipe = pipeClass.create();
Akronfec66a32020-08-28 13:01:14 +02001143 expect(KorAP.Pipe.toString()).toEqual("");
1144
Akronbb891982020-10-05 16:07:18 +02001145 var id = manager.addService({"name":'Example 2', "src":'about:blank'});
Akronfec66a32020-08-28 13:01:14 +02001146 expect(id).toMatch(/^id-/);
Akronfec66a32020-08-28 13:01:14 +02001147 manager._receiveMsg({
1148 "data" : {
1149 "originID" : id,
1150 "action" : "pipe",
1151 "job" : "add",
1152 "service" : "https://pipe-service.de"
1153 }
1154 });
Akronfec66a32020-08-28 13:01:14 +02001155 expect(KorAP.Pipe.toString()).toEqual("https://pipe-service.de");
Akronfec66a32020-08-28 13:01:14 +02001156 manager._receiveMsg({
1157 "data" : {
1158 "originID" : id,
1159 "action" : "pipe",
1160 "job" : "add",
1161 "service" : "https://pipe-service-2.de"
1162 }
1163 });
Akronfec66a32020-08-28 13:01:14 +02001164 expect(KorAP.Pipe.toString()).toEqual("https://pipe-service.de,https://pipe-service-2.de");
Akronfec66a32020-08-28 13:01:14 +02001165 manager._receiveMsg({
1166 "data" : {
1167 "originID" : id,
1168 "action" : "pipe",
1169 "job" : "del",
1170 "service" : "https://pipe-service.de"
1171 }
1172 });
Akronfec66a32020-08-28 13:01:14 +02001173 expect(KorAP.Pipe.toString()).toEqual("https://pipe-service-2.de");
Akronfec66a32020-08-28 13:01:14 +02001174 manager.destroy();
Akronfec66a32020-08-28 13:01:14 +02001175 // Recreate initial state
1176 KorAP.Pipe = temp;
1177 });
Akron45308ce2020-08-28 14:10:23 +02001178
Akron26d57f22021-09-10 16:48:57 +02001179 it('should reply to query information requests (queryform)', function () {
Akron45308ce2020-08-28 14:10:23 +02001180 var manager = pluginServerClass.create();
Akronbb891982020-10-05 16:07:18 +02001181 var id = manager.addService({"name":'Service', "src":'about:blank'});
Akron45308ce2020-08-28 14:10:23 +02001182 expect(id).toMatch(/^id-/);
1183 var temp = KorAP.vc;
1184 // Create form for query form information
1185 let f = document.createElement('form');
1186 var qfield = f.addE('input');
1187 qfield.setAttribute("id", "q-field");
1188 qfield.value = "[orth=Baum]";
1189 var qlfield = f.addE('select');
1190 qlfield.setAttribute("id", "ql-field");
1191 qlfield.addE('option').setAttribute('value', 'cosmas-2');
1192 qlfield.addE('option').setAttribute('value', 'poliqarp');
1193 qlfield.selectedIndex = 1;
1194
1195 KorAP.vc = vcClass.create().fromJson({
1196 "key" : "title",
1197 "type" : "type:regex",
1198 "value" : "[^b]ee.+?",
1199 "@type" : "koral:doc"
1200 });
1201 // console.log(KorAP.vc.toQuery());
1202
1203 document.body.appendChild(f);
1204 let data = {
1205 "originID" : id,
1206 "action" : "get",
1207 "key" : "QueryForm"
1208 };
1209 manager._receiveMsg({
1210 "data" : data
1211 });
1212 manager.destroy();
1213 expect(data.value["q"]).toEqual("[orth=Baum]");
1214 expect(data.value["ql"]).toEqual("poliqarp");
1215 expect(data.value["cq"]).toEqual("title = /[^b]ee.+?/");
Akron26d57f22021-09-10 16:48:57 +02001216
Akron45308ce2020-08-28 14:10:23 +02001217 // Recreate initial state
1218 KorAP.vc = temp;
1219 document.body.removeChild(f);
1220 });
Akron26d57f22021-09-10 16:48:57 +02001221
Akrone03faf62024-11-14 11:51:04 +01001222 it('should send messages', function () {
1223 let qel = document.createElement('input');
1224 qel.setAttribute('id','q-field');
1225
1226 let qlel = document.createElement('select');
1227 qlel.setAttribute('id','ql-field');
1228 qlel.innerHTML = '<option value="poliqarp">Poliqarp</option><option value="cosmas2">Cosmas II</option><option value="annis">Annis QL</option><option value="cqp">CQP (neu)</option><option value="cql">CQL v1.2</option><option value="fcsql">FCSQL</option>';
1229
1230 document.body.appendChild(qel);
1231 document.body.appendChild(qlel);
1232
1233 var manager = pluginServerClass.create();
1234 var id = manager.addService({"name":'Example 1', "src":'about:blank'});
1235 expect(id).toMatch(/^id-/);
1236
1237 let data = {
1238 "originID" : id,
1239 "action" : "set",
1240 "key" : "QueryForm",
1241 "value" : {
1242 "q" : "test3",
1243 "ql" : "cosmas2"
1244 }
1245 };
1246
1247 manager._receiveMsg({
1248 "data" : data
1249 });
1250 manager.destroy();
1251 expect(qel.value).toEqual("test3");
1252 expect(qlel.value).toEqual("cosmas2");
1253 // Recreate initial state
1254
1255 qel.remove();
1256 qlel.remove();
1257 });
1258
1259
Akron26d57f22021-09-10 16:48:57 +02001260 it('should reply to query information requests (pagination)', function () {
1261 var manager = pluginServerClass.create();
1262 var id = manager.addService({"name":'Service', "src":'about:blank'});
1263 expect(id).toMatch(/^id-/);
1264
1265 // Create pagination element for pagination information
1266 let p = document.createElement('div');
1267 p.setAttribute('id', 'pagination')
1268 p.setAttribute('data-page',3);
1269 p.setAttribute('data-total',30);
1270 p.setAttribute('data-count',25);
1271
1272 document.body.appendChild(p);
1273
1274 let data = {
1275 "originID" : id,
1276 "action" : "get",
1277 "key" : "Pagination"
1278 };
1279 manager._receiveMsg({
1280 "data" : data
1281 });
1282 manager.destroy();
1283 expect(data.value["count"]).toEqual(25);
1284 expect(data.value["page"]).toEqual(3);
1285 expect(data.value["total"]).toEqual(30);
1286
1287 // Recreate initial state
1288 document.body.removeChild(p);
1289 });
Akronfec66a32020-08-28 13:01:14 +02001290 });
Akronb43c8c62018-07-04 18:27:28 +02001291});