aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/closure-library/closure/goog/ui/container_test.html
blob: 9adfb3caff558d4d6f40305b9fce2b7f963a68cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
<!DOCTYPE html>
<html>
<!--
Copyright 2008 The Closure Library Authors. All Rights Reserved.

Use of this source code is governed by the Apache License, Version 2.0.
See the COPYING file for details.
-->
<!--
Author:  attila@google.com (Attila Bodis)
-->
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Closure Unit Tests - goog.ui.Container</title>
  <script src="../base.js"></script>
  <script>
    goog.require('goog.Disposable');
    goog.require('goog.dom');
    goog.require('goog.dom.classes');
    goog.require('goog.testing.events');
    goog.require('goog.testing.jsunit');
    goog.require('goog.ui.Container');
    goog.require('goog.ui.Container.EventType');
    goog.require('goog.ui.Control');
  </script>
</head>
<body>
  <div id="sandbox"></div>
  <script>
    var sandbox = goog.dom.getElement('sandbox');
    var containerElement;
    var container;
    var keyContainer;
    var listContainer;

    function setUp() {
      container = new goog.ui.Container();
      keyContainer = null;
      listContainer = null;

      sandbox.innerHTML =
          '<div id="containerElement" class="goog-container">\n' +
          '  <div class="goog-control">Hello</div>\n' +
          '  <div class="goog-control">World</div>\n' +
          '</div>';
      containerElement = goog.dom.getElement('containerElement');
    }

    function tearDown() {
      goog.dom.removeChildren(sandbox);
      container.dispose();
      goog.events.removeAll();
      goog.dispose(keyContainer);
      goog.dispose(listContainer);
    }

    function testDecorateHidden() {
      containerElement.style.display = 'none';

      assertTrue('Container must be visible', container.isVisible());
      container.decorate(containerElement);
      assertFalse('Container must be hidden', container.isVisible());
      container.forEachChild(function(control) {
        assertTrue('Child control ' + control.getId() + ' must report being ' +
            'visible, even if in a hidden container', control.isVisible());
      });
    }

    function testDecorateDisabled() {
      goog.dom.classes.add(containerElement, 'goog-container-disabled');

      assertTrue('Container must be enabled', container.isEnabled());
      container.decorate(containerElement);
      assertFalse('Container must be disabled', container.isEnabled());
      container.forEachChild(function(control) {
        assertFalse('Child control ' + control.getId() + ' must be disabled, ' +
            'because the host container is disabled', control.isEnabled());
      });
    }

    function testDecorateFocusableContainer() {
      container.decorate(containerElement);
      assertTrue('Container must be focusable', container.isFocusable());
      container.forEachChild(function(control) {
        assertFalse('Child control ' + control.getId() + ' must not be ' +
            'focusable',
            control.isSupportedState(goog.ui.Component.State.FOCUSED));
      });
    }

    function testDecorateFocusableChildrenContainer() {
      container.setFocusable(false);
      container.setFocusableChildrenAllowed(true);
      container.decorate(containerElement);
      assertFalse('Container must not be focusable', container.isFocusable());
      container.forEachChild(function(control) {
        assertTrue('Child control ' + control.getId() + ' must be ' +
            'focusable',
            control.isSupportedState(goog.ui.Component.State.FOCUSED));
      });
    }

    function testHighlightOnEnter() {
      // This interaction test ensures that containers enforce that children
      // get highlighted on mouseover, and that one and only one child may
      // be highlighted at a time.  Although integration tests aren't the
      // best, it's difficult to test these event-based interactions due to
      // their disposition toward the "misunderstood contract" problem.

      container.decorate(containerElement);
      assertFalse('Child 0 should initially not be highlighted',
          container.getChildAt(0).isHighlighted());

      goog.testing.events.fireMouseOverEvent(
          container.getChildAt(0).getElement(), sandbox);
      assertTrue('Child 0 should become highlighted after a mouse over',
          container.getChildAt(0).isHighlighted());

      goog.testing.events.fireMouseOverEvent(
          container.getChildAt(1).getElement(),
          container.getChildAt(0).getElement());
      assertFalse('Child 0 should lose highlight when child 1 is moused ' +
          'over, even if no mouseout occurs.',
          container.getChildAt(0).isHighlighted());
      assertTrue('Child 1 should now be highlighted.',
          container.getChildAt(1).isHighlighted());
    }

    function testHighlightOnEnterPreventable() {
      container.decorate(containerElement);
      goog.events.listen(container, goog.ui.Component.EventType.ENTER,
          function(event) {
            event.preventDefault();
          });
      goog.testing.events.fireMouseOverEvent(
          container.getChildAt(0).getElement(), sandbox);
      assertFalse('Child 0 should not be highlighted if preventDefault called',
          container.getChildAt(0).isHighlighted());
    }

    function testHighlightDisabled() {
      // Another interaction test.  Already tested in control_test.
      container.decorate(containerElement);
      container.getChildAt(0).setEnabled(false);
      goog.testing.events.fireMouseOverEvent(
          container.getChildAt(0).getElement(), sandbox);
      assertFalse('Disabled children should not be highlighted',
          container.getChildAt(0).isHighlighted());
    }

    function testGetOwnerControl() {
      container.decorate(containerElement);

      assertEquals('Must return appropriate control given an element in the ' +
          'control.',
          container.getChildAt(1),
          container.getOwnerControl(container.getChildAt(1).getElement()));

      assertNull('Must return null for element not associated with control.',
          container.getOwnerControl(document.body));
      assertNull('Must return null if given null node',
          container.getOwnerControl(null));
    }

    function testShowEvent() {
      container.decorate(containerElement);
      container.setVisible(false);
      var eventFired = false;
      goog.events.listen(container, goog.ui.Component.EventType.SHOW,
          function() {
            assertFalse('Container must not be visible when SHOW event is ' +
                        'fired',
                        container.isVisible());
            eventFired = true;
          });
      container.setVisible(true);
      assertTrue('SHOW event expected', eventFired);
    }

    function testAfterShowEvent() {
      container.decorate(containerElement);
      container.setVisible(false);
      var eventFired = false;
      goog.events.listen(container, goog.ui.Container.EventType.AFTER_SHOW,
          function() {
            assertTrue('Container must be visible when AFTER_SHOW event is ' +
                       'fired',
                       container.isVisible());
            eventFired = true;
          });
      container.setVisible(true);
      assertTrue('AFTER_SHOW event expected', eventFired);
    }

    function testHideEvents() {
      var events = [];
      container.decorate(containerElement);
      container.setVisible(true);
      var eventFired = false;
      goog.events.listen(container, goog.ui.Component.EventType.HIDE,
          function(e) {
            assertTrue(
                'Container must be visible when HIDE event is fired',
                container.isVisible());
            events.push(e.type);
          });
      goog.events.listen(container, goog.ui.Container.EventType.AFTER_HIDE,
          function(e) {
            assertFalse(
                'Container must not be visible when AFTER_HIDE event is fired',
                container.isVisible());
            events.push(e.type);
          });
      container.setVisible(false);
      assertArrayEquals('HIDE event followed by AFTER_HIDE expected', [
            goog.ui.Component.EventType.HIDE,
            goog.ui.Container.EventType.AFTER_HIDE
          ], events);
    }

    /**
     * Test container to which the elements have to be added with
     * {@code container.addChild(element, false)}
     * @constructor
     * @extends {goog.ui.Container}
     */
    function ListContainer() {
      goog.ui.Container.call(this);
    }
    goog.inherits(ListContainer, goog.ui.Container);

    /** @override */
    ListContainer.prototype.createDom = function() {
      ListContainer.superClass_.createDom.call(this);
      var ul = this.getDomHelper().createDom('ul');
      this.forEachChild(function(child) {
        child.createDom();
        var childEl = child.getElement();
        ul.appendChild(this.getDomHelper().createDom('li', {}, childEl));
      }, this);
      this.getContentElement().appendChild(ul);
    };

    function testGetOwnerControlWithNoRenderingInAddChild() {
      listContainer = new ListContainer();
      var control = new goog.ui.Control('item');
      listContainer.addChild(control);
      listContainer.render();
      var ownerControl = listContainer.getOwnerControl(control.getElement());

      assertEquals('Control was added with addChild(control, false)',
          control, ownerControl);
    }

    /**
     * Test container for tracking key events being handled.
     * @constructor
     * @extends {goog.ui.Container}
     */
    function KeyHandlingContainer() {
      goog.ui.Container.call(this);
      this.keyEventsHandled = 0;
    }
    goog.inherits(KeyHandlingContainer, goog.ui.Container);

    /** @override */
    KeyHandlingContainer.prototype.handleKeyEventInternal = function() {
      this.keyEventsHandled++;
      return false;
    };

    function testHandleKeyEvent_onlyHandlesWhenVisible() {
      keyContainer = new KeyHandlingContainer();
      keyContainer.decorate(containerElement);

      keyContainer.setVisible(false);
      keyContainer.handleKeyEvent(new goog.events.Event());
      assertEquals('No key events should be handled',
          0, keyContainer.keyEventsHandled);

      keyContainer.setVisible(true);
      keyContainer.handleKeyEvent(new goog.events.Event());
      assertEquals('One key event should be handled',
          1, keyContainer.keyEventsHandled);
    }

    function testHandleKeyEvent_onlyHandlesWhenEnabled() {
      keyContainer = new KeyHandlingContainer();
      keyContainer.decorate(containerElement);
      keyContainer.setVisible(true);

      keyContainer.setEnabled(false);
      keyContainer.handleKeyEvent(new goog.events.Event());
      assertEquals('No key events should be handled',
          0, keyContainer.keyEventsHandled);

      keyContainer.setEnabled(true);
      keyContainer.handleKeyEvent(new goog.events.Event());
      assertEquals('One key event should be handled',
          1, keyContainer.keyEventsHandled);
    }

    function testHandleKeyEvent_childlessContainersIgnoreKeyEvents() {
      keyContainer = new KeyHandlingContainer();
      keyContainer.render();
      keyContainer.setVisible(true);

      keyContainer.handleKeyEvent(new goog.events.Event());
      assertEquals('No key events should be handled',
          0, keyContainer.keyEventsHandled);

      keyContainer.addChild(new goog.ui.Control());
      keyContainer.handleKeyEvent(new goog.events.Event());
      assertEquals('One key event should be handled',
          1, keyContainer.keyEventsHandled);
    }

    function testHandleKeyEvent_alwaysHandlesWithKeyEventTarget() {
      keyContainer = new KeyHandlingContainer();
      keyContainer.render();
      keyContainer.setKeyEventTarget(goog.dom.createDom('div'));
      keyContainer.setVisible(true);

      keyContainer.handleKeyEvent(new goog.events.Event());
      assertEquals('One key events should be handled',
          1, keyContainer.keyEventsHandled);
    }

    function testHandleKeyEventInternal_onlyHandlesUnmodified() {
      container.setKeyEventTarget(sandbox);
      var event = new goog.events.KeyEvent(
          goog.events.KeyCodes.ESC, 0, false, null);

      var propertyNames = [
        'shiftKey',
        'altKey',
        'ctrlKey',
        'metaKey'
      ];

      // Verify that the event is not handled whenever a modifier key is true.
      for (var i = 0, propertyName; propertyName = propertyNames[i]; i++) {
        assertTrue('Event should be handled when modifer key is not pressed.',
            container.handleKeyEventInternal(event));
        event[propertyName] = true;
        assertFalse('Event should not be handled when modifer key is pressed.',
            container.handleKeyEventInternal(event));
        event[propertyName] = false;
      }
    }

    function testOpenFollowsHighlight() {
      container.decorate(containerElement);
      container.setOpenFollowsHighlight(true);
      assertTrue('isOpenFollowsHighlight should return true',
          container.isOpenFollowsHighlight());

      // Make the children openable.
      container.forEachChild(function(child) {
        child.setSupportedState(goog.ui.Component.State.OPENED, true);
      });
      // Open child 1 initially.
      container.getChildAt(1).setOpen(true);

      assertFalse('Child 0 should initially not be highlighted',
          container.getChildAt(0).isHighlighted());
      goog.testing.events.fireMouseOverEvent(
          container.getChildAt(0).getElement(), sandbox);
      assertTrue('Child 0 should become highlighted after a mouse over',
          container.getChildAt(0).isHighlighted());
      assertTrue('Child 0 should become open after higlighted',
          container.getChildAt(0).isOpen());
      assertFalse('Child 1 should become closed once 0 is open',
          container.getChildAt(1).isOpen());
      assertEquals('OpenItem should be child 0',
          container.getChildAt(0), container.getOpenItem());
    }

    function testOpenNotFollowsHighlight() {
      container.decorate(containerElement);
      container.setOpenFollowsHighlight(false);
      assertFalse('isOpenFollowsHighlight should return false',
          container.isOpenFollowsHighlight());

      // Make the children openable.
      container.forEachChild(function(child) {
        child.setSupportedState(goog.ui.Component.State.OPENED, true);
      });
      // Open child 1 initially.
      container.getChildAt(1).setOpen(true);

      assertFalse('Child 0 should initially not be highlighted',
          container.getChildAt(0).isHighlighted());
      goog.testing.events.fireMouseOverEvent(
          container.getChildAt(0).getElement(), sandbox);
      assertTrue('Child 0 should become highlighted after a mouse over',
          container.getChildAt(0).isHighlighted());
      assertFalse('Child 0 should remain closed after higlighted',
          container.getChildAt(0).isOpen());
      assertTrue('Child 1 should remain open',
          container.getChildAt(1).isOpen());
      assertEquals('OpenItem should be child 1',
          container.getChildAt(1), container.getOpenItem());
    }

    function testRemoveChild() {
      goog.dom.removeChildren(containerElement);
      container.decorate(containerElement);

      var a = new goog.ui.Control('A');
      var b = new goog.ui.Control('B');
      var c = new goog.ui.Control('C');

      a.setId('a');
      b.setId('b');
      c.setId('c');

      container.addChild(a, true);
      container.addChild(b, true);
      container.addChild(c, true);

      container.setHighlightedIndex(2);

      assertEquals('Parent must remove and return child by ID', b,
          container.removeChild('b'));
      assertNull('Parent must no longer contain this child',
          container.getChild('b'));
      assertEquals('Highlighted index must be decreased', 1,
          container.getHighlightedIndex());
      assertTrue('The removed control must handle its own mouse events',
          b.isHandleMouseEvents());

      assertEquals('Parent must remove and return child', c,
          container.removeChild(c));
      assertNull('Parent must no longer contain this child',
          container.getChild('c'));
      assertFalse('This child must no longer be highlighted',
          c.isHighlighted());
      assertTrue('The removed control must handle its own mouse events',
          c.isHandleMouseEvents());

      assertEquals('Parent must remove and return child by index', a,
          container.removeChildAt(0));
      assertNull('Parent must no longer contain this child',
          container.getChild('a'));
      assertTrue('The removed control must handle its own mouse events',
          a.isHandleMouseEvents());
    }
  </script>
</body>
</html>