Commit ca6178a6 authored by keishi@webkit.org's avatar keishi@webkit.org

Implement DataList UI for input type time on chromium

https://bugs.webkit.org/show_bug.cgi?id=98240

Reviewed by Kent Tamura.

Source/WebCore:

This adds datalist UI for input type time. We add the picker indicator to
BaseMultipleFieldsDateAndTimeInputType. We enclose the dateTimeEdit element
and picker indicator inside a new div element so we can position the picker
indicator in the same place as input type=date.

Tests: platform/chromium/fast/forms/time/time-suggestion-picker-appearance-rtl.html
       platform/chromium/fast/forms/time/time-suggestion-picker-appearance-with-scroll-bar.html
       platform/chromium/fast/forms/time/time-suggestion-picker-appearance.html
       platform/chromium/fast/forms/time/time-suggestion-picker-key-operations.html
       platform/chromium/fast/forms/time/time-suggestion-picker-mouse-operations.html

* css/html.css:
(input::-webkit-date-and-time-container):
* html/BaseMultipleFieldsDateAndTimeInputType.cpp:
(WebCore::BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType):
(WebCore::BaseMultipleFieldsDateAndTimeInputType::createShadowSubtree): Creates a picker indicator.
(WebCore::BaseMultipleFieldsDateAndTimeInputType::handleKeydownEvent): Open the picker on Alt+Down.
(WebCore):
(WebCore::BaseMultipleFieldsDateAndTimeInputType::listAttributeTargetChanged): Updates picker visibility.
(WebCore::BaseMultipleFieldsDateAndTimeInputType::updatePickerIndicatorVisibility): In the future, DateInputType can override
this so the picker indicator is always visible.
(WebCore::BaseMultipleFieldsDateAndTimeInputType::hidePickerIndicator):
(WebCore::BaseMultipleFieldsDateAndTimeInputType::showPickerIndicator):
* html/BaseMultipleFieldsDateAndTimeInputType.h:
(WebCore):
(BaseMultipleFieldsDateAndTimeInputType):
* html/shadow/DateTimeFieldElement.cpp:
(WebCore::DateTimeFieldElement::defaultKeyboardEventHandler): Ignore Alt+down because it should trigger the picker to open.
* rendering/RenderThemeChromiumCommon.cpp:
(WebCore::RenderThemeChromiumCommon::supportsDataListUI): Add time to the list.

LayoutTests:

* fast/forms/number/number-spinbutton-click-in-iframe.html:
* fast/forms/resources/common-spinbutton-click-in-iframe.js:
(getSpinButton): This broke because of the change to shadow DOM structure.
* fast/forms/resources/common.js:
(traverseNextNode):
(getElementByPseudoId): This finds a descendant node with a matching pseudo id.
* fast/forms/resources/suggestion-picker-common.js: Added.
(highlightedEntry):
(openPicker):
(sendKey):
* fast/forms/time-multiple-fields/time-multiple-fields-focus-style.html:
* fast/forms/time-multiple-fields/time-multiple-fields-spinbutton-click-in-iframe.html:
* platform/chromium-mac/platform/chromium/fast/forms/time/time-suggestion-picker-appearance-expected.png: Added.
* platform/chromium-mac/platform/chromium/fast/forms/time/time-suggestion-picker-appearance-rtl-expected.png: Added.
* platform/chromium-mac/platform/chromium/fast/forms/time/time-suggestion-picker-appearance-with-scroll-bar-expected.png: Added.
* platform/chromium/TestExpectations:
* platform/chromium/fast/forms/datalist/input-list-expected.txt:
* platform/chromium/fast/forms/date/date-suggestion-picker-mouse-operations-expected.txt:
* platform/chromium/fast/forms/date/date-suggestion-picker-mouse-operations.html:
* platform/chromium/fast/forms/date/date-suggestion-picker-mouse-operations.html:
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-rtl-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-rtl.html: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-with-scroll-bar-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-with-scroll-bar.html: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance.html: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-key-operations-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-key-operations.html: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-mouse-operations-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-mouse-operations.html: Added.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@130293 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent a71cb789
2012-10-03 Keishi Hattori <keishi@webkit.org>
Implement DataList UI for input type time on chromium
https://bugs.webkit.org/show_bug.cgi?id=98240
Reviewed by Kent Tamura.
* fast/forms/number/number-spinbutton-click-in-iframe.html:
* fast/forms/resources/common-spinbutton-click-in-iframe.js:
(getSpinButton): This broke because of the change to shadow DOM structure.
* fast/forms/resources/common.js:
(traverseNextNode):
(getElementByPseudoId): This finds a descendant node with a matching pseudo id.
* fast/forms/resources/suggestion-picker-common.js: Added.
(highlightedEntry):
(openPicker):
(sendKey):
* fast/forms/time-multiple-fields/time-multiple-fields-focus-style.html:
* fast/forms/time-multiple-fields/time-multiple-fields-spinbutton-click-in-iframe.html:
* platform/chromium-mac/platform/chromium/fast/forms/time/time-suggestion-picker-appearance-expected.png: Added.
* platform/chromium-mac/platform/chromium/fast/forms/time/time-suggestion-picker-appearance-rtl-expected.png: Added.
* platform/chromium-mac/platform/chromium/fast/forms/time/time-suggestion-picker-appearance-with-scroll-bar-expected.png: Added.
* platform/chromium/TestExpectations:
* platform/chromium/fast/forms/datalist/input-list-expected.txt:
* platform/chromium/fast/forms/date/date-suggestion-picker-mouse-operations-expected.txt:
* platform/chromium/fast/forms/date/date-suggestion-picker-mouse-operations.html:
* platform/chromium/fast/forms/date/date-suggestion-picker-mouse-operations.html:
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-rtl-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-rtl.html: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-with-scroll-bar-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance-with-scroll-bar.html: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-appearance.html: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-key-operations-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-key-operations.html: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-mouse-operations-expected.txt: Added.
* platform/chromium/fast/forms/time/time-suggestion-picker-mouse-operations.html: Added.
2012-10-03 Csaba Osztrogonác <ossy@webkit.org>
[Qt] Enable mock scrollbars
......
......@@ -2,6 +2,7 @@
<html>
<head>
<script src="../../../fast/js/resources/js-test-pre.js"></script>
<script src="../resources/common.js"></script>
<script src="../resources/common-spinbutton-click-in-iframe.js"></script>
</head>
<body>
......
......@@ -7,8 +7,7 @@ function getSpinButton(input)
{
if (!window.internals)
return null;
var editElement = window.internals.oldestShadowRoot(input);
return editElement.firstChild.lastChild;
return getElementByPseudoId(internals.oldestShadowRoot(input), "-webkit-inner-spin-button");
}
function mouseClick()
......
......@@ -151,3 +151,36 @@ function clickElement(element) {
eventSender.mouseDown();
eventSender.mouseUp();
}
function traverseNextNode(node, stayWithin) {
var nextNode = node.firstChild;
if (nextNode)
return nextNode;
if (stayWithin && node === stayWithin)
return null;
nextNode = node.nextSibling;
if (nextNode)
return nextNode;
nextNode = node;
while (nextNode && !nextNode.nextSibling && (!stayWithin || !nextNode.parentNode || nextNode.parentNode !== stayWithin))
nextNode = nextNode.parentNode;
if (!nextNode)
return null;
return nextNode.nextSibling;
}
function getElementByPseudoId(root, pseudoId) {
if (!window.internals)
return null;
var node = root;
while (node) {
if (node.nodeType === Node.ELEMENT_NODE && internals.shadowPseudoId(node) === pseudoId)
return node;
node = traverseNextNode(node, root);
}
return null;
}
window.jsTestIsAsync = true;
if (window.internals)
internals.settings.setEnableMockPagePopup(true);
var popupWindow = null;
function highlightedEntry() {
var activeElement = popupWindow.document.activeElement;
if (!activeElement)
return null;
var value = activeElement.dataset.value;
if (typeof value === "string")
return value;
var action = activeElement.dataset.action;
if (typeof action === "string")
return "@" + action;
return null;
}
function openPicker(input) {
sendKey(input, "Down", false, true);
popupWindow = document.getElementById('mock-page-popup').contentWindow;
}
function sendKey(input, keyName, ctrlKey, altKey) {
var event = document.createEvent('KeyboardEvent');
event.initKeyboardEvent('keydown', true, true, document.defaultView, keyName, 0, ctrlKey, altKey);
input.dispatchEvent(event);
}
......@@ -2,6 +2,7 @@
<html>
<head>
<script src="../../js/resources/js-test-pre.js"></script>
<script src="../resources/common.js"></script>
</head>
<body>
Please run this test within DumpRenderTree.
......@@ -28,7 +29,7 @@ var highlight = sampleStyle.backgroundColor;
testInput.focus();
var shadowRoot = internals.oldestShadowRoot(testInput);
var fields = shadowRoot.firstChild.childNodes;
var fields = getElementByPseudoId(shadowRoot, "-webkit-datetime-edit").childNodes;
for (var index = 0; index < fields.length; ++index) {
var field = fields[index];
if (field.nodeType != 1)
......
......@@ -2,6 +2,7 @@
<html>
<head>
<script src="../../../fast/js/resources/js-test-pre.js"></script>
<script src="../resources/common.js"></script>
<script src="../resources/common-spinbutton-click-in-iframe.js"></script>
</head>
<body>
......
......@@ -3640,6 +3640,9 @@ webkit.org/b/96961 platform/chromium/virtual/gpu/fast/canvas/webgl/oes-vertex-ar
webkit.org/b/97558 platform/chromium/fast/forms/date/date-suggestion-picker-appearance-rtl.html [ ImageOnlyFailure Pass ]
webkit.org/b/98094 [ Linux Win ] platform/chromium/fast/forms/date/date-suggestion-picker-appearance.html [ ImageOnlyFailure Pass ]
webkit.org/b/98094 platform/chromium/fast/forms/time/time-suggestion-picker-appearance.html [ ImageOnlyFailure Pass ]
webkit.org/b/98094 platform/chromium/fast/forms/time/time-suggestion-picker-appearance-with-scroll-bar.html [ ImageOnlyFailure Pass ]
webkit.org/b/98094 platform/chromium/fast/forms/time/time-suggestion-picker-appearance-rtl.html [ ImageOnlyFailure Pass ]
# Numerous failures in software compositing.
crbug.com/152953 [ Mac ] platform/chromium/virtual/softwarecompositing/geometry/fixed-position-iframe-composited-page-scale-down.html [ ImageOnlyFailure ]
......
......@@ -16,7 +16,7 @@ FAIL document.getElementById("datetime").list should be [object HTMLDataListElem
PASS document.getElementById("date").list is document.getElementById("dl1")
FAIL document.getElementById("month").list should be [object HTMLDataListElement]. Was null.
FAIL document.getElementById("week").list should be [object HTMLDataListElement]. Was null.
FAIL document.getElementById("time").list should be [object HTMLDataListElement]. Was null.
PASS document.getElementById("time").list is document.getElementById("dl1")
FAIL document.getElementById("datetime-local").list should be [object HTMLDataListElement]. Was null.
PASS document.getElementById("number").list is document.getElementById("dl1")
PASS document.getElementById("range").list is document.getElementById("dl1")
......
Tests that key bindings work as expected.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Check that page popup doesn't exist at first.
PASS document.getElementById("mock-page-popup") is null
Check that page popup exists.
PASS pickerWindow.pagePopupController.toString() is "[object PagePopupController]"
PASS popupWindow.pagePopupController.toString() is "[object PagePopupController]"
Check that hovering over an entry highlights it.
PASS highlightedEntry() is "2012-01-02"
Check that moving the mouse outside the popup de-highlights entries.
......
......@@ -3,6 +3,7 @@
<head>
<script src="../../../../../fast/js/resources/js-test-pre.js"></script>
<script src="../../../../../fast/forms/resources/common.js"></script>
<script src="../../../../../fast/forms/resources/suggestion-picker-common.js"></script>
</head>
<body style="background-color: #bbbbbb;">
<p id="description"></p>
......@@ -81,23 +82,17 @@
<option>foo</option> <!--invalid-->
</datalist>
<script>
description("Tests that key bindings work as expected.");
window.jsTestIsAsync = true;
if (window.internals)
internals.settings.setEnableMockPagePopup(true);
debug('Check that page popup doesn\'t exist at first.');
shouldBeNull('document.getElementById("mock-page-popup")');
var calendarPickerElement = window.internals.oldestShadowRoot(document.getElementById('date')).firstChild.lastChild;
sendMousedown(calendarPickerElement);
openPicker($('date'));
var pickerWindow = document.getElementById('mock-page-popup').contentWindow;
pickerWindow.addEventListener("resize", function() {
popupWindow.addEventListener("resize", function() {
debug('Check that page popup exists.');
shouldBe('pickerWindow.pagePopupController.toString()', '"[object PagePopupController]"');
shouldBe('popupWindow.pagePopupController.toString()', '"[object PagePopupController]"');
debug('Check that hovering over an entry highlights it.');
hoverOverElement(pickerWindow.document.querySelector(".suggestion-list-entry:nth-child(2)"));
hoverOverElement(popupWindow.document.querySelector(".suggestion-list-entry:nth-child(2)"));
shouldBe('highlightedEntry()', '"2012-01-02"');
debug('Check that moving the mouse outside the popup de-highlights entries.');
......@@ -105,32 +100,12 @@ pickerWindow.addEventListener("resize", function() {
shouldBeNull('highlightedEntry()');
debug('Check that mouse click closes the popup and sets the value.');
clickElement(pickerWindow.document.querySelector(".suggestion-list-entry:nth-child(3)"));
clickElement(popupWindow.document.querySelector(".suggestion-list-entry:nth-child(3)"));
shouldBeNull('document.getElementById("mock-page-popup")');
shouldBe('document.getElementById("date").value', '"2012-01-03"');
finishJSTest();
}, false);
function highlightedEntry() {
var activeElement = pickerWindow.document.activeElement;
if (!activeElement)
return null;
var value = activeElement.dataset.value;
if (typeof value === "string")
return value;
var action = activeElement.dataset.action;
if (typeof action === "string")
return "@" + action;
return null;
}
function sendMousedown(element) {
var event = document.createEvent('MouseEvent');
event.initEvent('click', true, true);
element.dispatchEvent(event);
}
</script>
<script src="../../../../../fast/js/resources/js-test-post.js"></script>
</body>
......
<!DOCTYPE html>
<html>
<head>
<script src="../../../../../fast/forms/resources/suggestion-picker-common.js"></script>
</head>
<body style="background-color: #eeffff; padding: 0 50px;" dir="rtl">
<input type=time id=time value="12:31" list="suggestions" style="width: 100px;">
<datalist id=suggestions>
<option label="Now">01:01</option>
<option label="Recommended">01:02</option>
<option>01:03</option>
<option>01:04</option>
<option>01:05</option>
<option>01:06</option>
<option>01:07</option>
<option>01:08</option>
<option>01:09</option>
<option>01:10</option>
<option>01:11</option>
<option>01:12</option>
<option>01:13</option>
<option>01:14</option>
<option>01:15</option>
<option>01:16</option>
<option>01:17</option>
<option>01:18</option>
<option>01:19</option>
<option>01:20</option>
</datalist>
<script>
function finishTest() {
popupWindow.removeEventListener('resize', finishTest);
popupWindow.focus();
eventSender.keyDown('downArrow');
setTimeout(function() {testRunner.notifyDone();}, 0);
}
testRunner.dumpAsText(true);
testRunner.waitUntilDone();
window.onload = function() {
var dateInput = document.getElementById('time');
dateInput.offsetTop;
openPicker(dateInput);
popupWindow.addEventListener('resize', finishTest, false);
};
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script src="../../../../../fast/forms/resources/suggestion-picker-common.js"></script>
</head>
<body style="background-color: #eeffff;">
<input type=time id=time value="12:31" list="suggestions" style="width: 100px;">
<datalist id=suggestions>
<option label="Now">01:01</option>
<option>01:02</option>
<option>01:03</option>
<option>01:04</option>
<option>01:05</option>
<option>01:06</option>
<option>01:07</option>
<option>01:08</option>
<option>01:09</option>
<option>01:10</option>
<option>01:11</option>
<option>01:12</option>
<option>01:13</option>
<option>01:14</option>
<option>01:15</option>
<option>01:16</option>
<option>01:17</option>
<option>01:18</option>
<option>01:19</option>
<option>01:20</option>
<option>01:21</option>
</datalist>
<script>
function finishTest() {
popupWindow.removeEventListener('resize', finishTest);
popupWindow.focus();
eventSender.keyDown('downArrow');
setTimeout(function() {testRunner.notifyDone();}, 0);
}
testRunner.dumpAsText(true);
testRunner.waitUntilDone();
window.onload = function() {
var dateInput = document.getElementById('time');
dateInput.offsetTop;
openPicker(dateInput);
popupWindow.addEventListener('resize', finishTest, false);
};
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script src="../../../../../fast/forms/resources/suggestion-picker-common.js"></script>
</head>
<body style="background-color: #eeffff;">
<input type=time id=time value="12:31" list="suggestions" style="width: 200px;" step="0.001">
<datalist id=suggestions>
<option>111:23</option> <!--invalid-->
<option>13:60</option> <!--invalid-->
<option>foo</option> <!--invalid-->
<option label="Now">01:01</option>
<option>14:23</option>
<option>12:34:56</option>
<option>01:23:45.678</option>
<option>01:05</option>
<option>01:06</option>
<option>01:07</option>
<option>01:08</option>
<option>01:09</option>
<option>01:10</option>
<option>01:11</option>
<option>01:12</option>
<option>01:13</option>
<option>01:14</option>
<option>01:15</option>
<option>01:16</option>
<option>01:17</option>
<option>01:18</option>
<option>01:19</option>
<option>01:20</option>
</datalist>
<script>
function finishTest() {
popupWindow.removeEventListener('resize', finishTest);
popupWindow.focus();
eventSender.keyDown('downArrow');
setTimeout(function() {testRunner.notifyDone();}, 0);
}
testRunner.dumpAsText(true);
testRunner.waitUntilDone();
window.onload = function() {
var dateInput = document.getElementById('time');
dateInput.offsetTop;
openPicker(dateInput);
popupWindow.addEventListener('resize', finishTest, false);
};
</script>
</body>
</html>
Check that page popup doesn't exist at first.
PASS document.getElementById("mock-page-popup") is null
PASS popupWindow.pagePopupController.toString() is "[object PagePopupController]"
Check that page popup exists.
PASS popupWindow.pagePopupController.toString() is "[object PagePopupController]"
Check that up/down arrow keys work.
PASS highlightedEntry() is null
PASS highlightedEntry() is "01:01"
PASS highlightedEntry() is "01:02"
PASS highlightedEntry() is "01:01"
Check that up arrow key at top of list does nothing.
PASS highlightedEntry() is "01:01"
PASS highlightedEntry() is "01:02"
Check that page up/down arrow keys work.
PASS highlightedEntry() is "01:40"
PASS highlightedEntry() is "02:00"
PASS highlightedEntry() is "01:21"
PASS highlightedEntry() is "02:00"
PASS highlightedEntry() is "02:08"
Check that down arrow key at bottom of list does nothing.
PASS highlightedEntry() is "02:08"
Check that enter key sets the highlighted value.
PASS highlightedEntry() is "02:07"
PASS document.getElementById("mock-page-popup") is null
PASS document.getElementById("time").value is "02:07"
Reopen popup.
Check that escape key closes the popup.
PASS document.getElementById("mock-page-popup") is null
PASS document.getElementById("time").value is "02:07"
Reopen popup.
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../../../../fast/js/resources/js-test-pre.js"></script>
<script src="../../../../../fast/forms/resources/common.js"></script>
<script src="../../../../../fast/forms/resources/suggestion-picker-common.js"></script>
</head>
<body style="background-color: #bbbbbb;">
<p id="description"></p>
<div id="console"></div>
<input type=time id=time value="01:00" list=suggestions>
<datalist id=suggestions>
<option label="Now">01:01</option>
<option>01:02</option>
<option>01:03</option>
<option>01:04</option>
<option>01:05</option>
<option>01:06</option>
<option>01:07</option>
<option>01:08</option>
<option>01:09</option>
<option>01:10</option>
<option>01:11</option>
<option>01:12</option>
<option>01:13</option>
<option>01:14</option>
<option>01:15</option>
<option>01:16</option>
<option>01:17</option>
<option>01:18</option>
<option>01:19</option>
<option>01:20</option>
<option>01:21</option>
<option>01:22</option>
<option>01:23</option>
<option>01:24</option>
<option>01:25</option>
<option>01:26</option>
<option>01:27</option>
<option>01:28</option>
<option>01:29</option>
<option>01:30</option>
<option>01:31</option>
<option>01:32</option>
<option>01:33</option>
<option>01:34</option>
<option>01:35</option>
<option>01:36</option>
<option>01:37</option>
<option>01:38</option>
<option>01:39</option>
<option>01:40</option>
<option>01:41</option>
<option>01:42</option>
<option>01:43</option>
<option>01:44</option>
<option>01:45</option>
<option>01:46</option>
<option>01:47</option>
<option>01:48</option>
<option>01:49</option>
<option>01:50</option>
<option>01:51</option>
<option>01:52</option>
<option>01:53</option>
<option>01:54</option>
<option>01:55</option>
<option>01:56</option>
<option>01:57</option>
<option>01:58</option>
<option>01:59</option>
<option>02:00</option>
<option>02:01</option>
<option>02:02</option>
<option>02:03</option>
<option>02:04</option>
<option>02:05</option>
<option>02:06</option>
<option>02:07</option>
<option>02:08</option>
</datalist>
<script>
debug('Check that page popup doesn\'t exist at first.');
shouldBeNull('document.getElementById("mock-page-popup")');
window.onload = function() {
openPicker(document.getElementById('time'));
shouldBe('popupWindow.pagePopupController.toString()', '"[object PagePopupController]"');
popupWindow.addEventListener("resize", test1, false);
};
var timeoutTimer = setTimeout(function() {
testFailed("Test timed out.");
finishJSTest();
}, 5000);
function test1() {
debug('Check that page popup exists.');
shouldBe('popupWindow.pagePopupController.toString()', '"[object PagePopupController]"');
popupWindow.focus();
popupWindow.removeEventListener("resize", test1, false);
debug('Check that up/down arrow keys work.');
shouldBeNull('highlightedEntry()');
eventSender.keyDown('downArrow');
shouldBe('highlightedEntry()', '"01:01"');
eventSender.keyDown('downArrow');
shouldBe('highlightedEntry()', '"01:02"');
eventSender.keyDown('upArrow');
shouldBe('highlightedEntry()', '"01:01"');
debug('Check that up arrow key at top of list does nothing.');
eventSender.keyDown('upArrow');
shouldBe('highlightedEntry()', '"01:01"');
eventSender.keyDown('downArrow');
shouldBe('highlightedEntry()', '"01:02"');
debug('Check that page up/down arrow keys work.');
eventSender.keyDown('pageDown');
shouldBe('highlightedEntry()', '"01:40"');
eventSender.keyDown('pageDown');