]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/test/specs/ZIndexManager.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / test / specs / ZIndexManager.js
CommitLineData
6527f429
DM
1describe('Ext.ZIndexManager', function() {\r
2 function cancelFocus() {\r
3 var task = Ext.focusTask;\r
4 if (task) {\r
5 task.cancel();\r
6 }\r
7 }\r
8\r
9 describe('z-index stacking', function() {\r
10 var c1, c2, c3;\r
11\r
12 beforeEach(function() {\r
13 c1 = new Ext.window.Window({\r
14 title: 'c1',\r
15 id: 'c1',\r
16 height: 100,\r
17 width: 100,\r
18 focusOnToFront: false\r
19 });\r
20 c2 = new Ext.window.Window({\r
21 title: 'c2',\r
22 id: 'c2',\r
23 height: 100,\r
24 width: 100,\r
25 focusOnToFront: false\r
26 });\r
27 c3 = new Ext.window.Window({\r
28 title: 'c3',\r
29 id: 'c3',\r
30 height: 100,\r
31 width: 100,\r
32 focusOnToFront: false\r
33 });\r
34 });\r
35 afterEach(function() {\r
36 Ext.destroy(c1, c2, c3);\r
37 });\r
38 \r
39 it('should order the windows as they are rendered', function() {\r
40 c1.show();\r
41 c2.show();\r
42 c3.show();\r
43 // onMousedown quits if there is a pending focus task.\r
44 cancelFocus();\r
45\r
46 // Order bottom up should be c1, c2, c3\r
47 expect(c3.el.getZIndex()).toBeGreaterThan(c2.el.getZIndex());\r
48 expect(c2.el.getZIndex()).toBeGreaterThan(c1.el.getZIndex());\r
49 });\r
50 it('should re-order the windows on mousedown', function() {\r
51 c1.showAt(0, 0);\r
52 c2.showAt(50, 0);\r
53 c3.showAt(100, 0);\r
54 // onMousedown quits if there is a pending focus task.\r
55 cancelFocus();\r
56\r
57 // Fake mousedown because sythetic events won't work with capture which is what Floating's listener uses\r
58 c1.onMouseDown({\r
59 target: c1.el.dom\r
60 });\r
61 \r
62 // Mousedown moves to top\r
63 // Order bottom up should be c2, c3, c1\r
64 expect(c1.el.getZIndex()).toBeGreaterThan(c3.el.getZIndex());\r
65 expect(c3.el.getZIndex()).toBeGreaterThan(c2.el.getZIndex());\r
66 });\r
67 it('should honour alwaysOnTop', function() {\r
68 c1.setAlwaysOnTop(true);\r
69 c1.showAt(0, 0);\r
70 c2.showAt(50, 0);\r
71 c3.showAt(100, 0);\r
72 // onMousedown quits if there is a pending focus task.\r
73 cancelFocus();\r
74\r
75 // c1 should be glued to the top\r
76 // Order bottom up should be c2, c3, c1\r
77 expect(c1.el.getZIndex()).toBeGreaterThan(c3.el.getZIndex());\r
78 expect(c3.el.getZIndex()).toBeGreaterThan(c2.el.getZIndex());\r
79\r
80 // Fake mousedown because sythetic events won't work with capture which is what Floating's listener uses\r
81 c2.onMouseDown({\r
82 target: c2.el.dom\r
83 });\r
84\r
85 // Because there is a visible alwaysOnTop component, that mousedown should have changed nothing\r
86 // Order bottom up should still be c2, c3, c1\r
87 expect(c1.el.getZIndex()).toBeGreaterThan(c3.el.getZIndex());\r
88 expect(c3.el.getZIndex()).toBeGreaterThan(c2.el.getZIndex());\r
89\r
90 });\r
91 it('should sort to the bottom of the ZIndexStack if alwaysOnTop === -1', function() {\r
92 c3.setAlwaysOnTop(-1);\r
93 c1.showAt(0, 0);\r
94 c2.showAt(50, 0);\r
95 c3.showAt(100, 0);\r
96 // onMousedown quits if there is a pending focus task\r
97 cancelFocus();\r
98\r
99 // c3 should be glued to the bottom\r
100 // Order bottom up should be c3, c1, c2\r
101 expect(c2.el.getZIndex()).toBeGreaterThan(c1.el.getZIndex());\r
102 expect(c1.el.getZIndex()).toBeGreaterThan(c3.el.getZIndex());\r
103 });\r
104 it('should order parents', function() {\r
105 // c2's ZIndexManager now manages C3's zIndex\r
106 c2.add(c3);\r
107\r
108 c1.showAt(0, 0);\r
109 c2.showAt(50, 0);\r
110 c3.showAt(25, 25);\r
111 // onMousedown quits if there is a pending focus task.\r
112 cancelFocus();\r
113\r
114 // Fake mousedown because sythetic events won't work with capture which is what Floating's listener uses\r
115 c1.onMouseDown({\r
116 target: c1.el.dom\r
117 });\r
118\r
119 // c1 moved to top\r
120 // Order bottom up should be c2, c3, c1\r
121 expect(c1.el.getZIndex()).toBeGreaterThan(c3.el.getZIndex());\r
122 expect(c3.el.getZIndex()).toBeGreaterThan(c2.el.getZIndex());\r
123 // Fake mousedown because sythetic events won't work with capture which is what Floating's listener uses\r
124 c2.onMouseDown({\r
125 target: c2.el.dom\r
126 });\r
127\r
128 // onMousedown quits if there is a pending focus task.\r
129 cancelFocus();\r
130\r
131 // Mousedown on c2 should bring both c2 and c2 above c1 because c3 is a child of c2\r
132 // Order bottom up should be c1, c2, c3\r
133 expect(c3.el.getZIndex()).toBeGreaterThan(c2.el.getZIndex());\r
134 expect(c2.el.getZIndex()).toBeGreaterThan(c1.el.getZIndex());\r
135 });\r
136\r
137 it("should assign a z-index to a floater that is rendered visible", function() {\r
138 var c = new Ext.Component({\r
139 renderTo: Ext.getBody(),\r
140 floating: true,\r
141 html: 'Foo'\r
142 });\r
143 c.show();\r
144 expect(c.getEl().getZIndex()).toBe(Ext.WindowManager.zseed);\r
145 c.destroy();\r
146 });\r
147 });\r
148\r
149 describe("modal masking", function() {\r
150 var w, mask;\r
151\r
152 afterEach(function() {\r
153 Ext.destroy(w);\r
154 mask = w = null;\r
155 });\r
156\r
157 function makeWindow(config) {\r
158 w = new Ext.window.Window(Ext.applyIf(config || {}, {\r
159 width: 200,\r
160 height: 200,\r
161 title: 'Foo',\r
162 autoShow: true,\r
163 modal: true\r
164 }));\r
165 }\r
166\r
167 describe("mask visibility", function() {\r
168 beforeEach(function() {\r
169 makeWindow();\r
170 mask = w.zIndexManager.mask;\r
171 });\r
172\r
173 function getMaskIndex() {\r
174 return parseInt(w.zIndexManager.mask.getStyle('z-index'), 10);\r
175 }\r
176\r
177 it("should show the mask below the floater when open", function() {\r
178 expect(mask.isVisible()).toBe(true);\r
179 expect(getMaskIndex()).toBeLessThan(w.getEl().getZIndex());\r
180 });\r
181\r
182 it("should re-show the mask after hiding then showing", function() {\r
183 w.hide();\r
184 w.show();\r
185 expect(mask.isVisible()).toBe(true);\r
186 });\r
187\r
188 it("should hide the modal mask when hiding the last floater", function() {\r
189 w.hide();\r
190 expect(mask.isVisible()).toBe(false);\r
191 });\r
192\r
193 it("should hide the modal mask when destroying the last floater", function() {\r
194 w.destroy();\r
195 expect(mask.isVisible()).toBe(false);\r
196 });\r
197 });\r
198 \r
199 describe("element tabbability", function() {\r
200 var btn, tabbables;\r
201 \r
202 beforeEach(function() {\r
203 btn = new Ext.button.Button({\r
204 renderTo: Ext.getBody(),\r
205 text: 'foo'\r
206 });\r
207 });\r
208 \r
209 afterEach(function() {\r
210 Ext.destroy(btn);\r
211 btn = null;\r
212 });\r
213 \r
214 describe("components below mask", function() {\r
215 beforeEach(function() {\r
216 makeWindow();\r
217 });\r
218 \r
219 it("button should become untabbable on mask show", function() {\r
220 // skipSelf = true, skipChildren = false, excludeRoot = w.el\r
221 tabbables = Ext.getBody().findTabbableElements({\r
222 skipSelf: true,\r
223 excludeRoot: w.el\r
224 });\r
225 \r
226 expect(tabbables.length).toBe(0);\r
227 });\r
228 \r
229 it("button should become tabbable on mask hide", function() {\r
230 w.hide();\r
231 \r
232 // skipSelf = true, skipChildren = false, excludeRoot = w.el\r
233 tabbables = Ext.getBody().findTabbableElements({\r
234 skipSelf: true,\r
235 excludeRoot: w.el\r
236 });\r
237 \r
238 expect(tabbables).toEqual([ btn.getFocusEl().dom ]);\r
239 });\r
240 \r
241 it("button should become untabbable on mask show/hide/show", function() {\r
242 w.hide();\r
243 w.show();\r
244 \r
245 // skipSelf = true, skipChildren = false, excludeRoot = w.el\r
246 tabbables = Ext.getBody().findTabbableElements({\r
247 skipSelf: true,\r
248 excludeRoot: w.el\r
249 });\r
250 \r
251 expect(tabbables.length).toBe(0);\r
252 });\r
253 });\r
254 \r
255 describe("components above mask", function() {\r
256 beforeEach(function() {\r
257 makeWindow({\r
258 items: [\r
259 { xtype: 'textfield', fieldLabel: 'Login' },\r
260 { xtype: 'textfield', fieldLabel: 'Password' }\r
261 ],\r
262 \r
263 buttons: [\r
264 { text: 'OK' }\r
265 ]\r
266 });\r
267 });\r
268 \r
269 it("should keep items above the mask tabbable", function() {\r
270 tabbables = w.getEl().findTabbableElements({\r
271 skipSelf: true\r
272 });\r
273 \r
274 // 6 tababbles:\r
275 // - Top focus trap\r
276 // - Window header (it's a FocusableContainer)\r
277 // - textfield 1\r
278 // - textfield 2\r
279 // - Toolbar (FocusableContainer)\r
280 // - Bottom focus trap\r
281 expect(tabbables.length).toBe(6);\r
282 });\r
283 });\r
284 });\r
285\r
286 describe("mask size", function() {\r
287 // Not sure how to simulate a body resize here\r
288 it("should size the mask to the body if the manager is global", function() {\r
289 makeWindow();\r
290 mask = w.zIndexManager.mask;\r
291 expect(mask.getSize()).toEqual(Ext.Element.getViewSize());\r
292 expect(mask).toHaveCls(Ext.Component.prototype.borderBoxCls);\r
293 });\r
294\r
295 it("should set the mask to the size of the container", function() {\r
296 var ct = new Ext.container.Container({\r
297 renderTo: Ext.getBody(),\r
298 width: 400,\r
299 height: 400\r
300 });\r
301\r
302 w = ct.add({\r
303 xtype: 'window',\r
304 width: 100,\r
305 height: 100,\r
306 modal: true,\r
307 title: 'Foo'\r
308 });\r
309\r
310 w.show();\r
311 mask = w.zIndexManager.mask;\r
312 expect(mask.getSize()).toEqual({\r
313 width: 400,\r
314 height: 400\r
315 });\r
316 ct.destroy();\r
317 });\r
318\r
319 // This currently doesn't work, but probably should\r
320 xit("should resize the mask when the container resizes", function() {\r
321 var ct = new Ext.container.Container({\r
322 renderTo: Ext.getBody(),\r
323 width: 400,\r
324 height: 400\r
325 });\r
326\r
327 w = ct.add({\r
328 xtype: 'panel',\r
329 floating: true,\r
330 width: 100,\r
331 height: 100,\r
332 modal: true,\r
333 title: 'Foo'\r
334 });\r
335\r
336 w.show();\r
337 mask = w.zIndexManager.mask;\r
338 ct.setSize(200, 200);\r
339 expect(mask.getSize()).toEqual({\r
340 width: 200,\r
341 height: 200\r
342 });\r
343 ct.destroy();\r
344 });\r
345 });\r
346 });\r
347\r
348 describe("hideAll", function() {\r
349 it("should hide all visible items", function() {\r
350 var a = new Ext.window.Window({\r
351 width: 100,\r
352 height: 100,\r
353 autoShow: true\r
354 });\r
355 var b = new Ext.window.Window({\r
356 width: 100,\r
357 height: 100,\r
358 autoShow: true\r
359 });\r
360 var c = new Ext.window.Window({\r
361 width: 100,\r
362 height: 100,\r
363 autoShow: true\r
364 });\r
365\r
366 Ext.WindowManager.hideAll();\r
367 expect(a.isVisible()).toBe(false);\r
368 expect(b.isVisible()).toBe(false);\r
369 expect(c.isVisible()).toBe(false);\r
370\r
371 Ext.destroy(a, b, c);\r
372 });\r
373\r
374 it("should be able to show/hide the modal mask after a hideAll call", function() {\r
375 var a = new Ext.window.Window({\r
376 width: 100,\r
377 height: 100,\r
378 autoShow: true\r
379 });\r
380 var b = new Ext.window.Window({\r
381 width: 100,\r
382 height: 100,\r
383 autoShow: true\r
384 });\r
385 var c = new Ext.window.Window({\r
386 width: 100,\r
387 height: 100,\r
388 autoShow: true\r
389 });\r
390\r
391 Ext.WindowManager.hideAll();\r
392 expect(a.isVisible()).toBe(false);\r
393 expect(b.isVisible()).toBe(false);\r
394 expect(c.isVisible()).toBe(false);\r
395\r
396 var mask = a.zIndexManager.mask;\r
397 expect(mask.isVisible()).toBe(false);\r
398\r
399 var d = new Ext.window.Window({\r
400 width: 100,\r
401 height: 100,\r
402 modal: true,\r
403 autoShow: true\r
404 });\r
405\r
406 expect(mask.isVisible()).toBe(true);\r
407 d.hide();\r
408 expect(mask.isVisible()).toBe(false);\r
409\r
410 Ext.destroy(a, b, c, d);\r
411 });\r
412 });\r
413\r
414 // testcase for https://sencha.jira.com/browse/EXTJS-14046\r
415 describe("picker field's pickers should stick to back if alwaysOnTop is set to -1", function() {\r
416 it('should keep pickers below all other floating components', function() {\r
417 var windowCombo,\r
418 combo = new Ext.form.ComboBox({\r
419 store: ['A', 'b', 'C'],\r
420 editable: false,\r
421 fieldLabel: 'Combo',\r
422 renderTo: Ext.getBody(),\r
423 listConfig: {\r
424 alwaysOnTop: -1\r
425 }\r
426 }),\r
427 dateField = new Ext.form.Date({\r
428 editable: false,\r
429 fieldLabel: 'Date',\r
430 renderTo: Ext.getBody()\r
431 }),\r
432 window = new Ext.window.Window({\r
433 autoShow: true,\r
434 title: 'Test',\r
435 x:200,\r
436 y:0,\r
437 width: 400,\r
438 height: 400,\r
439 items: [\r
440 windowCombo = new Ext.form.ComboBox({\r
441 store: ['A', 'b', 'C'],\r
442 editable: false,\r
443 listCOnfig: {\r
444 alwaysOnTop: -1\r
445 }\r
446 })\r
447 ]\r
448 });\r
449 dateField.getPicker().setAlwaysOnTop(-1);\r
450\r
451 // The combo dropdown should be below the window\r
452 combo.expand();\r
453 expect(combo.getPicker().el.getZIndex()).toBeLessThan(window.el.getZIndex());\r
454 combo.collapse();\r
455\r
456 // The combo dropdown should be below the window\r
457 dateField.expand();\r
458 expect(dateField.getPicker().el.getZIndex()).toBeLessThan(window.el.getZIndex());\r
459 dateField.collapse();\r
460\r
461 // The combo dropdown in the window is realtive to the window's ZIndexManager.\r
462 // It should go above the window\r
463 windowCombo.expand();\r
464 expect(windowCombo.getPicker().el.getZIndex()).toBeGreaterThan(window.el.getZIndex());\r
465 windowCombo.collapse();\r
466\r
467 // The combo dropdown should be below the window\r
468 combo.expand();\r
469 expect(combo.getPicker().el.getZIndex()).toBeLessThan(window.el.getZIndex());\r
470 \r
471 Ext.destroy(combo, dateField, window);\r
472 });\r
473 });\r
474\r
475 describe("bringToFront", function() {\r
476 it("should return false when bringing to front a non-rendered window, when passing id", function() {\r
477 var win = new Ext.window.Window({\r
478 title: 'Win',\r
479 id: 'theWin',\r
480 width: 100,\r
481 height: 100\r
482 });\r
483 expect(Ext.WindowManager.bringToFront('theWin')).toBe(false);\r
484 win.destroy();\r
485 }); \r
486 });\r
487 \r
488 // This test would better fit a Floating test suite but it's not clear\r
489 // where the concerns are separated since Floating code is private\r
490 // and is supposed to be called by ZIndexManager only. So let it be here.\r
491 describe("focus handling", function() {\r
492 var focusAndWait = jasmine.focusAndWait,\r
493 waitForFocus = jasmine.waitForFocus,\r
494 expectFocused = jasmine.expectFocused,\r
495 btn, win, input1, input2;\r
496 \r
497 beforeEach(function() {\r
498 btn = new Ext.button.Button({\r
499 renderTo: Ext.getBody(),\r
500 text: 'foo'\r
501 });\r
502 \r
503 win = new Ext.window.Window({\r
504 title: 'bar',\r
505 width: 200,\r
506 height: 100,\r
507 x: 30,\r
508 y: 30,\r
509 closeAction: 'hide',\r
510 \r
511 items: [{\r
512 xtype: 'textfield',\r
513 itemId: 'input1'\r
514 }, {\r
515 xtype: 'textfield',\r
516 itemId: 'input2',\r
517 allowBlank: false\r
518 }]\r
519 });\r
520 \r
521 input1 = win.down('#input1');\r
522 input2 = win.down('#input2');\r
523 \r
524 focusAndWait(btn);\r
525 });\r
526 \r
527 afterEach(function() {\r
528 Ext.destroy(win, btn);\r
529 \r
530 btn = win = input1 = input2 = null;\r
531 });\r
532\r
533 describe("focusable floater show/hide with no animation", function() {\r
534 beforeEach(function() {\r
535 win.show();\r
536 \r
537 waitForFocus(win);\r
538 });\r
539 \r
540 it("should focus the window on show", function() {\r
541 expectFocused(win);\r
542 });\r
543 \r
544 it("should focus the button back on window hide", function() {\r
545 win.close();\r
546 \r
547 expectFocused(btn);\r
548 });\r
549 });\r
550 \r
551 describe("focusable floater show/hide with animation", function() {\r
552 beforeEach(function() {\r
553 win.show(btn);\r
554 \r
555 waitForFocus(win);\r
556 });\r
557 \r
558 it("should focus the window on show", function() {\r
559 expectFocused(win);\r
560 });\r
561 \r
562 it("should focus the button back on window hide", function() {\r
563 win.close(btn);\r
564 \r
565 expectFocused(btn);\r
566 });\r
567 });\r
568 \r
569 describe("non-focusable floater show/hide", function() {\r
570 var panel;\r
571 \r
572 beforeEach(function() {\r
573 panel = new Ext.panel.Panel({\r
574 floating: true,\r
575 title: 'floating',\r
576 width: 100,\r
577 height: 100,\r
578 x: 300,\r
579 y: 30,\r
580 html: 'floating panel'\r
581 });\r
582 \r
583 win.show();\r
584 \r
585 focusAndWait(input2);\r
586 });\r
587 \r
588 afterEach(function() {\r
589 Ext.destroy(panel);\r
590 });\r
591 \r
592 it("should not steal focus on floater show", function() {\r
593 panel.show();\r
594 \r
595 expectFocused(input2);\r
596 });\r
597 \r
598 it("should not munge focus on floater hide", function() {\r
599 panel.show();\r
600 panel.hide();\r
601 \r
602 expectFocused(input2);\r
603 });\r
604 });\r
605 \r
606 describe("event order", function() {\r
607 it("should fire floater hide event after sorting zIndexStack", function() {\r
608 var oldOnCollectionSort = Ext.WindowManager.onCollectionSort,\r
609 events = [],\r
610 win;\r
611 \r
612 win = new Ext.window.Window({\r
613 title: 'foo',\r
614 width: 300,\r
615 height: 200,\r
616 x: 10,\r
617 y: 10,\r
618 closeAction: 'hide',\r
619 listeners: {\r
620 hide: function() {\r
621 events.push('hide');\r
622 }\r
623 }\r
624 }).show();\r
625 \r
626 // Can't use jasmine spy here because it can't be chained\r
627 Ext.WindowManager.onCollectionSort = function() {\r
628 events.push('sort');\r
629 oldOnCollectionSort.call(Ext.WindowManager);\r
630 };\r
631 \r
632 // Event flow is synchronous here\r
633 win.close();\r
634 \r
635 expect(events).toEqual(['sort', 'hide']);\r
636 \r
637 Ext.WindowManager.onCollectionSort = oldOnCollectionSort;\r
638 \r
639 win.destroy();\r
640 \r
641 win = null;\r
642 });\r
643 });\r
644 });\r
645\r
646 describe('focus restoration after window drag', function() {\r
647 var win;\r
648 \r
649 afterEach(function() {\r
650 win.destroy();\r
651 win = null;\r
652 });\r
653 \r
654 it('should restore focus after showing', function() {\r
655 var xy, x, child, text;\r
656 \r
657 win = new Ext.window.Window({\r
658 title: 'Test Window',\r
659 width: 410,\r
660 height: 400\r
661 });\r
662\r
663 win.show();\r
664\r
665 xy = win.getXY();\r
666 x = win.header.getX();\r
667\r
668 child = new Ext.window.Window({\r
669 width: 200,\r
670 height: 100,\r
671 items: {\r
672 xtype: 'textfield'\r
673 }\r
674 });\r
675\r
676 win.add(child);\r
677 child.show();\r
678\r
679 text = child.items.first();\r
680\r
681 text.focus();\r
682\r
683 jasmine.waitForFocus(text);\r
684\r
685 runs(function() {\r
686 expect(text.hasFocus).toBe(true);\r
687 // Drag the Window by the header\r
688 jasmine.fireMouseEvent(win.header.el, 'mousedown', x);\r
689 jasmine.fireMouseEvent(win.header.el, 'mousemove', x + 100);\r
690\r
691 expect(child.isVisible()).toBe(false);\r
692\r
693 jasmine.fireMouseEvent(Ext.getBody(), 'mouseup');\r
694\r
695 // Window should have moved 100px right\r
696 xy[0] += 100;\r
697 expect(win.getXY()).toEqual(xy);\r
698 });\r
699\r
700 jasmine.waitForFocus(text);\r
701 runs(function() {\r
702 expect(text.hasFocus).toBe(true);\r
703 });\r
704 });\r
705 });\r
706});\r