Diff
Modified: trunk/LayoutTests/ChangeLog (209181 => 209182)
--- trunk/LayoutTests/ChangeLog 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/LayoutTests/ChangeLog 2016-12-01 16:16:38 UTC (rev 209182)
@@ -1,3 +1,32 @@
+2016-12-01 Antoine Quint <grao...@apple.com>
+
+ [Modern Media Controls] Provide a UI object to show a list of tracks
+ https://bugs.webkit.org/show_bug.cgi?id=165239
+
+ Reviewed by Dean Jackson.
+
+ Adding new tests to cover new TracksPanel functionality.
+
+ * media/modern-media-controls/resources/media-controls-loader.js:
+ * media/modern-media-controls/tracks-panel/tracks-panel-expected.txt: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside-expected.txt: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside.html: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key-expected.txt: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key.html: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-hide-expected.txt: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-hide.html: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-population-expected.txt: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-population.html: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-right-x-expected.txt: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-right-x.html: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard-expected.txt: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard.html: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse-expected.txt: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse.html: Added.
+ * media/modern-media-controls/tracks-panel/tracks-panel.html: Added.
+ * platform/ios-simulator/TestExpectations:
+ * platform/mac/TestExpectations:
+
2016-11-30 Yusuke Suzuki <utatane....@gmail.com>
[JSC] Specifying same module entry point multiple times cause TypeError
Modified: trunk/LayoutTests/media/modern-media-controls/resources/media-controls-loader.js (209181 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/resources/media-controls-loader.js 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/LayoutTests/media/modern-media-controls/resources/media-controls-loader.js 2016-12-01 16:16:38 UTC (rev 209182)
@@ -3,7 +3,7 @@
const layoutTestsPath = window.location.href.substr(0, window.location.href.indexOf("/LayoutTests/"));
const modulePath = layoutTestsPath ? layoutTestsPath + "/Source/WebCore/Modules/modern-media-controls" : "/modern-media-controls";
- ["media-controls", "scrubber", "volume-slider", "slider", "button", "start-button", "icon-button", "airplay-button", "time-label", "status-label", "macos-inline-media-controls", "macos-fullscreen-media-controls", "ios-inline-media-controls", "buttons-container", "placard"].forEach(cssFile => {
+ ["media-controls", "scrubber", "volume-slider", "slider", "button", "start-button", "icon-button", "airplay-button", "time-label", "status-label", "macos-inline-media-controls", "macos-fullscreen-media-controls", "ios-inline-media-controls", "buttons-container", "placard", "tracks-panel"].forEach(cssFile => {
document.write(`<link rel="stylesheet" type="text/css" href=""
});
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-expected.txt (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-expected.txt (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-expected.txt 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,15 @@
+Testing the TracksPanel class properties.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Basic properties
+PASS tracksPanel.element.localName is "div"
+PASS tracksPanel.element.className is "tracks-panel"
+PASS tracksPanel.presented is false
+PASS tracksPanel.rightX is 0
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside-expected.txt (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside-expected.txt (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside-expected.txt 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,16 @@
+Testing a TracksPanel is hidden upon clicking outside of it.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+mediaControls.showTracksPanel()
+
+Clicking outside of the panel
+
+Transition ended
+PASS mediaControls.tracksPanel.presented is false
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside.html (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside.html (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside.html 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,39 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Testing a <code>TracksPanel</code> is hidden upon clicking outside of it.");
+
+const mediaControls = new MacOSInlineMediaControls({ width: 680, height: 300 });
+document.body.appendChild(mediaControls.element);
+
+debug("mediaControls.showTracksPanel()");
+mediaControls.showTracksPanel();
+
+scheduler.frameDidFire = function()
+{
+ window.requestAnimationFrame(() => {
+ debug("");
+ debug("Clicking outside of the panel");
+ eventSender.mouseMoveTo(10, 10);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ mediaControls.tracksPanel.element.addEventListener("transitionend", (event) => {
+ debug("");
+ debug("Transition ended");
+ shouldBeFalse("mediaControls.tracksPanel.presented");
+
+ debug("");
+ mediaControls.element.remove();
+ finishJSTest();
+ });
+ });
+ scheduler.frameDidFire = null;
+}
+
+</script>
+<script src=""
+</body>
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key-expected.txt (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key-expected.txt (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key-expected.txt 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,16 @@
+Testing a TracksPanel is hidden upon hitting the Esc. key.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+mediaControls.showTracksPanel()
+
+Pressing the Escape key
+
+Transition ended
+PASS mediaControls.tracksPanel.presented is false
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key.html (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key.html (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key.html 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,37 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Testing a <code>TracksPanel</code> is hidden upon hitting the Esc. key.");
+
+const mediaControls = new MacOSInlineMediaControls({ width: 680, height: 300 });
+document.body.appendChild(mediaControls.element);
+
+debug("mediaControls.showTracksPanel()");
+mediaControls.showTracksPanel();
+
+scheduler.frameDidFire = function()
+{
+ window.requestAnimationFrame(() => {
+ debug("");
+ debug("Pressing the Escape key");
+ eventSender.keyDown("Escape");
+ mediaControls.tracksPanel.element.addEventListener("transitionend", (event) => {
+ debug("");
+ debug("Transition ended");
+ shouldBeFalse("mediaControls.tracksPanel.presented");
+
+ debug("");
+ mediaControls.element.remove();
+ finishJSTest();
+ });
+ });
+ scheduler.frameDidFire = null;
+}
+
+</script>
+<script src=""
+</body>
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-expected.txt (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-expected.txt (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide-expected.txt 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,18 @@
+Testing a TracksPanel is hidden with an animation.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+tracksPanel.presentInParent(container)
+PASS tracksPanel.presented is true
+
+tracksPanel.hide()
+PASS tracksPanel.presented is true
+
+Transition ended
+PASS tracksPanel.presented is false
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide.html (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide.html (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-hide.html 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,40 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Testing a <code>TracksPanel</code> is hidden with an animation.");
+
+const tracksPanel = new TracksPanel;
+const container = new LayoutNode;
+
+document.body.appendChild(container.element);
+
+debug("tracksPanel.presentInParent(container)");
+tracksPanel.presentInParent(container);
+
+scheduler.frameDidFire = function()
+{
+ shouldBeTrue("tracksPanel.presented");
+
+ debug("");
+ debug("tracksPanel.hide()");
+ window.requestAnimationFrame(() => {
+ tracksPanel.hide();
+ shouldBeTrue("tracksPanel.presented");
+ tracksPanel.element.addEventListener("transitionend", (event) => {
+ debug("");
+ debug("Transition ended");
+ shouldBeFalse("tracksPanel.presented");
+ debug("");
+ finishJSTest();
+ });
+ });
+ scheduler.frameDidFire = null;
+}
+
+</script>
+<script src=""
+</body>
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-population-expected.txt (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-population-expected.txt (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-population-expected.txt 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,55 @@
+Populating a TracksPanel instance.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS tracksPanel.presented is true
+PASS tracksPanel.parent is container
+PASS tracksPanel.children.length is numberOfSections
+
+Hierarchy for section #0
+PASS tracksPanel.children[0].element.localName is "div"
+PASS tracksPanel.children[0].element.className is "tracks-panel-section"
+PASS tracksPanel.children[0].children.length is 2
+PASS tracksPanel.children[0].children[0].element.localName is "h3"
+PASS tracksPanel.children[0].children[0].element.textContent is "Title #0"
+PASS tracksPanel.children[0].children[1].element.localName is "ul"
+PASS tracksPanel.children[0].children[1].children.length is 3
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.localName is "li"
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.className is ""
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.textContent is "Track 0x0"
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.localName is "li"
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.className is "selected"
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.textContent is "Track 0x1"
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.localName is "li"
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.className is ""
+PASS tracksPanel.children[0].children[1].children[trackIndex].element.textContent is "Track 0x2"
+
+Hierarchy for section #1
+PASS tracksPanel.children[1].element.localName is "div"
+PASS tracksPanel.children[1].element.className is "tracks-panel-section"
+PASS tracksPanel.children[1].children.length is 2
+PASS tracksPanel.children[1].children[0].element.localName is "h3"
+PASS tracksPanel.children[1].children[0].element.textContent is "Title #1"
+PASS tracksPanel.children[1].children[1].element.localName is "ul"
+PASS tracksPanel.children[1].children[1].children.length is 5
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.localName is "li"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.className is ""
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.textContent is "Track 1x0"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.localName is "li"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.className is ""
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.textContent is "Track 1x1"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.localName is "li"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.className is ""
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.textContent is "Track 1x2"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.localName is "li"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.className is "selected"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.textContent is "Track 1x3"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.localName is "li"
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.className is ""
+PASS tracksPanel.children[1].children[1].children[trackIndex].element.textContent is "Track 1x4"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-population.html (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-population.html (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-population.html 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,70 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+description("Populating a <code>TracksPanel</code> instance.");
+
+const tracksPanel = new TracksPanel;
+
+const numberOfSections = 2;
+const numberOfTracksInSection = [3, 5];
+const selectedTracks = [[0, 1], [1, 3]];
+
+tracksPanel.dataSource = {
+ tracksPanelNumberOfSections: function()
+ {
+ return numberOfSections;
+ },
+
+ tracksPanelTitleForSection: function(sectionIndex)
+ {
+ return `Title #${sectionIndex}`;
+ },
+
+ tracksPanelNumberOfTracksInSection: function(sectionIndex)
+ {
+ return numberOfTracksInSection[sectionIndex];
+ },
+
+ tracksPanelTitleForTrackInSection: function(trackIndex, sectionIndex)
+ {
+ return `Track ${sectionIndex}x${trackIndex}`;
+ },
+
+ tracksPanelIsTrackInSectionSelected: function(trackIndex, sectionIndex)
+ {
+ return selectedTracks.some(selectedTrack => selectedTrack[0] === sectionIndex && selectedTrack[1] === trackIndex);
+ }
+};
+
+const container = new LayoutNode;
+tracksPanel.presentInParent(container);
+
+shouldBeTrue("tracksPanel.presented");
+shouldBe("tracksPanel.parent", "container");
+shouldBe("tracksPanel.children.length", "numberOfSections");
+
+let sectionIndex, trackIndex;
+for (sectionIndex = 0; sectionIndex < numberOfSections; ++sectionIndex) {
+ debug("");
+ debug(`Hierarchy for section #${sectionIndex}`);
+ shouldBeEqualToString(`tracksPanel.children[${sectionIndex}].element.localName`, "div");
+ shouldBeEqualToString(`tracksPanel.children[${sectionIndex}].element.className`, "tracks-panel-section");
+ shouldBe(`tracksPanel.children[${sectionIndex}].children.length`, "2");
+ shouldBeEqualToString(`tracksPanel.children[${sectionIndex}].children[0].element.localName`, "h3");
+ shouldBeEqualToString(`tracksPanel.children[${sectionIndex}].children[0].element.textContent`, tracksPanel.dataSource.tracksPanelTitleForSection(sectionIndex));
+ shouldBeEqualToString(`tracksPanel.children[${sectionIndex}].children[1].element.localName`, "ul");
+ shouldBe(`tracksPanel.children[${sectionIndex}].children[1].children.length`, `${numberOfTracksInSection[sectionIndex]}`);
+ for (trackIndex = 0; trackIndex < numberOfTracksInSection[sectionIndex]; ++trackIndex) {
+ shouldBeEqualToString(`tracksPanel.children[${sectionIndex}].children[1].children[trackIndex].element.localName`, "li");
+ shouldBeEqualToString(`tracksPanel.children[${sectionIndex}].children[1].children[trackIndex].element.className`, selectedTracks.some(selectedTrack => selectedTrack[0] === sectionIndex && selectedTrack[1] === trackIndex) ? "selected" : "");
+ shouldBeEqualToString(`tracksPanel.children[${sectionIndex}].children[1].children[trackIndex].element.textContent`, tracksPanel.dataSource.tracksPanelTitleForTrackInSection(trackIndex, sectionIndex));
+ }
+}
+
+debug("");
+
+</script>
+<script src=""
+</body>
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-right-x-expected.txt (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-right-x-expected.txt (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-right-x-expected.txt 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,12 @@
+Testing the TracksPanel class.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+tracksPanel.rightX = 10
+PASS tracksPanel.element.style.right is "10px"
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-right-x.html (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-right-x.html (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-right-x.html 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,25 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Testing the <code>TracksPanel</code> class.");
+
+const tracksPanel = new TracksPanel;
+
+tracksPanel.rightX = 10;
+debug("tracksPanel.rightX = 10");
+
+scheduler.frameDidFire = function()
+{
+ shouldBeEqualToString("tracksPanel.element.style.right", "10px");
+
+ debug("");
+ finishJSTest();
+};
+
+</script>
+<script src=""
+</body>
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard-expected.txt (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard-expected.txt (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard-expected.txt 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,19 @@
+Selecting a track in a TracksPanel with the keyboard.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+mediaControls.showTracksPanel()
+
+Focusing the second track by pressing the down arrow key twice
+Obtained focus event
+
+Activating the focused track by pressing the Enter key
+mediaControls.tracksPanel.uiDelegate.tracksPanelSelectionDidChange() called
+sectionIndex = 0
+trackIndex = 1
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard.html (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard.html (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard.html 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,91 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<style type="text/css" media="screen">
+
+ .media-controls {
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+
+</style>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Selecting a track in a <code>TracksPanel</code> with the keyboard.");
+
+const mediaControls = new MacOSInlineMediaControls({ width: 680, height: 300 });
+
+mediaControls.tracksPanel.dataSource = {
+ tracksPanelNumberOfSections: function()
+ {
+ return 1;
+ },
+
+ tracksPanelTitleForSection: function(sectionIndex)
+ {
+ return `Title`;
+ },
+
+ tracksPanelNumberOfTracksInSection: function(sectionIndex)
+ {
+ return 3;
+ },
+
+ tracksPanelTitleForTrackInSection: function(trackIndex, sectionIndex)
+ {
+ return `Track`;
+ },
+
+ tracksPanelIsTrackInSectionSelected: function(trackIndex, sectionIndex)
+ {
+ return false;
+ }
+};
+
+mediaControls.tracksPanel.uiDelegate = {
+ tracksPanelSelectionDidChange: function(trackIndex, sectionIndex)
+ {
+ debug("mediaControls.tracksPanel.uiDelegate.tracksPanelSelectionDidChange() called");
+ debug(`sectionIndex = ${sectionIndex}`);
+ debug(`trackIndex = ${trackIndex}`);
+
+ debug("");
+ mediaControls.element.remove();
+ finishJSTest();
+ }
+};
+
+document.body.appendChild(mediaControls.element);
+
+let trackElement;
+
+debug("mediaControls.showTracksPanel()");
+mediaControls.showTracksPanel();
+
+scheduler.frameDidFire = function()
+{
+ window.requestAnimationFrame(() => {
+ debug("");
+ debug("Focusing the second track by pressing the down arrow key twice");
+
+ trackElement = mediaControls.tracksPanel.element.querySelectorAll("li")[1];
+ trackElement.addEventListener("focus", () => {
+ debug("Obtained focus event");
+
+ debug("");
+ debug("Activating the focused track by pressing the Enter key");
+ eventSender.keyDown("Enter");
+ });
+
+ eventSender.keyDown("ArrowDown");
+ eventSender.keyDown("ArrowDown");
+ });
+ scheduler.frameDidFire = null;
+}
+
+</script>
+<script src=""
+</body>
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse-expected.txt (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse-expected.txt (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse-expected.txt 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,19 @@
+Selecting a track in a TracksPanel with the mouse.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+mediaControls.showTracksPanel()
+
+Mousing over the second track in the panel
+Obtained focus event
+
+Clicking on focused track
+mediaControls.tracksPanel.uiDelegate.tracksPanelSelectionDidChange() called
+sectionIndex = 0
+trackIndex = 1
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse.html (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse.html (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse.html 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,92 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<style type="text/css" media="screen">
+
+ .media-controls {
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+
+</style>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Selecting a track in a <code>TracksPanel</code> with the mouse.");
+
+const mediaControls = new MacOSInlineMediaControls({ width: 680, height: 300 });
+
+mediaControls.tracksPanel.dataSource = {
+ tracksPanelNumberOfSections: function()
+ {
+ return 1;
+ },
+
+ tracksPanelTitleForSection: function(sectionIndex)
+ {
+ return `Title`;
+ },
+
+ tracksPanelNumberOfTracksInSection: function(sectionIndex)
+ {
+ return 3;
+ },
+
+ tracksPanelTitleForTrackInSection: function(trackIndex, sectionIndex)
+ {
+ return `Track`;
+ },
+
+ tracksPanelIsTrackInSectionSelected: function(trackIndex, sectionIndex)
+ {
+ return false;
+ }
+};
+
+mediaControls.tracksPanel.uiDelegate = {
+ tracksPanelSelectionDidChange: function(trackIndex, sectionIndex)
+ {
+ debug("mediaControls.tracksPanel.uiDelegate.tracksPanelSelectionDidChange() called");
+ debug(`sectionIndex = ${sectionIndex}`);
+ debug(`trackIndex = ${trackIndex}`);
+
+ debug("");
+ mediaControls.element.remove();
+ finishJSTest();
+ }
+};
+
+document.body.appendChild(mediaControls.element);
+
+let trackElement;
+
+debug("mediaControls.showTracksPanel()");
+mediaControls.showTracksPanel();
+
+scheduler.frameDidFire = function()
+{
+ window.requestAnimationFrame(() => {
+ debug("");
+ debug("Mousing over the second track in the panel");
+
+ trackElement = mediaControls.tracksPanel.element.querySelectorAll("li")[1];
+ trackElement.addEventListener("focus", () => {
+ debug("Obtained focus event");
+
+ debug("");
+ debug("Clicking on focused track");
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+ });
+
+ const bounds = trackElement.getBoundingClientRect();
+ eventSender.mouseMoveTo(bounds.left + 1, bounds.top + 1);
+ });
+ scheduler.frameDidFire = null;
+}
+
+</script>
+<script src=""
+</body>
Added: trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel.html (0 => 209182)
--- trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel.html (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/tracks-panel/tracks-panel.html 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,20 @@
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<script type="text/_javascript_">
+
+description("Testing the <code>TracksPanel</code> class properties.");
+
+const tracksPanel = new TracksPanel;
+
+debug("Basic properties");
+shouldBeEqualToString("tracksPanel.element.localName", "div");
+shouldBeEqualToString("tracksPanel.element.className", "tracks-panel");
+shouldBeFalse("tracksPanel.presented");
+shouldBe("tracksPanel.rightX", "0");
+
+debug("");
+
+</script>
+<script src=""
+</body>
Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (209181 => 209182)
--- trunk/LayoutTests/platform/ios-simulator/TestExpectations 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations 2016-12-01 16:16:38 UTC (rev 209182)
@@ -2751,6 +2751,9 @@
media/modern-media-controls/media-controller/media-controller-fullscreen-change.html [ Skip ]
media/modern-media-controls/media-controller/media-controller-fullscreen-ltr.html [ Skip ]
+# These tests are all Mac-specific, we never show the tracks menu on iOS
+media/modern-media-controls/tracks-panel
+
webkit.org/b/164594 http/tests/cache/disk-cache/disk-cache-request-headers.html [ Pass Timeout ]
webkit.org/b/163046 js/regress-141098.html [ Pass Failure ]
Modified: trunk/LayoutTests/platform/mac/TestExpectations (209181 => 209182)
--- trunk/LayoutTests/platform/mac/TestExpectations 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/LayoutTests/platform/mac/TestExpectations 2016-12-01 16:16:38 UTC (rev 209182)
@@ -1452,6 +1452,7 @@
[ Yosemite ] media/modern-media-controls/placard-support [ Skip ]
[ Yosemite ] media/modern-media-controls/audio [ Skip ]
[ Yosemite ] media/modern-media-controls/media-controller/media-controller-fullscreen-ltr.html [ Skip ]
+[ Yosemite ] media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard.html [ Skip ]
webkit.org/b/164616 http/tests/media/modern-media-controls/skip-back-support/skip-back-support-button-click.html [ Pass Failure ]
webkit.org/b/164323 media/modern-media-controls/airplay-support/airplay-support.html [ Pass Failure ]
Modified: trunk/Source/WebCore/ChangeLog (209181 => 209182)
--- trunk/Source/WebCore/ChangeLog 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/ChangeLog 2016-12-01 16:16:38 UTC (rev 209182)
@@ -1,3 +1,91 @@
+2016-12-01 Antoine Quint <grao...@apple.com>
+
+ [Modern Media Controls] Provide a UI object to show a list of tracks
+ https://bugs.webkit.org/show_bug.cgi?id=165239
+
+ Reviewed by Dean Jackson.
+
+ We add a new TracksPanel object which we will be using to display a list of
+ audio and text tracks. The tracks panel can be shown by calling showTracksPanel()
+ on a MacOSMediaControls object and will be dismissed by hitting the Escape key
+ or mousing down outside of the panel's bounds. While the tracks panel is up,
+ arrows can be used to focus individual tracks which can be activated by either
+ pressing the Space bar or Enter key.
+
+ Activating a track will briefly animate its background to indicate selection and
+ dismissing the tracks panel is also animated with a quick fade-out animation.
+
+ Data for the tracks panel is provided by specifying a dataSource property and
+ implementing the required methods to provide the number of sections in the panel,
+ the number of tracks in each section, etc.
+
+ Tests: media/modern-media-controls/tracks-panel/tracks-panel-hide-click-outside.html
+ media/modern-media-controls/tracks-panel/tracks-panel-hide-esc-key.html
+ media/modern-media-controls/tracks-panel/tracks-panel-hide.html
+ media/modern-media-controls/tracks-panel/tracks-panel-population.html
+ media/modern-media-controls/tracks-panel/tracks-panel-right-x.html
+ media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard.html
+ media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-mouse.html
+ media/modern-media-controls/tracks-panel/tracks-panel.html
+
+ * Modules/modern-media-controls/controls/macos-fullscreen-media-controls.css:
+ (.media-controls.mac.fullscreen):
+ (.media-controls.mac.fullscreen > .controls-bar):
+ (.media-controls.mac.fullscreen .tracks-panel):
+ * Modules/modern-media-controls/controls/macos-inline-media-controls.css:
+ (.media-controls.mac.inline .tracks-panel):
+ * Modules/modern-media-controls/controls/macos-media-controls.js:
+ (MacOSMediaControls.prototype.showTracksPanel):
+ (MacOSMediaControls.prototype.hideTracksPanel):
+ (MacOSMediaControls):
+ * Modules/modern-media-controls/controls/media-controls.css:
+ (.media-controls):
+ * Modules/modern-media-controls/controls/placard.css:
+ (.placard):
+ * Modules/modern-media-controls/controls/status-label.css:
+ (.status-label):
+ * Modules/modern-media-controls/controls/tracks-panel.css: Added.
+ (.tracks-panel):
+ (.tracks-panel *):
+ (.tracks-panel.fade-out):
+ (.tracks-panel-section):
+ (.tracks-panel-section:first-of-type):
+ (.tracks-panel-section > h3):
+ (.tracks-panel-section > ul):
+ (.tracks-panel-section > ul > li):
+ (.tracks-panel-section > ul > li:focus):
+ (.tracks-panel-section > ul > li.selected:before):
+ (.tracks-panel-section > ul > li.animated):
+ (@keyframes tracks-panel-item-selection):
+ (22.22%):
+ * Modules/modern-media-controls/controls/tracks-panel.js: Added.
+ (TracksPanel.prototype.get presented):
+ (TracksPanel.prototype.presentInParent):
+ (TracksPanel.prototype.hide):
+ (TracksPanel.prototype.get rightX):
+ (TracksPanel.prototype.set rightX):
+ (TracksPanel.prototype.trackNodeSelectionAnimationDidEnd):
+ (TracksPanel.prototype.mouseMovedOverTrackNode):
+ (TracksPanel.prototype.mouseExitedTrackNode):
+ (TracksPanel.prototype.commitProperty):
+ (TracksPanel.prototype.handleEvent):
+ (TracksPanel.prototype._childrenFromDataSource.):
+ (TracksPanel.prototype._childrenFromDataSource):
+ (TracksPanel.prototype._handleMousedown):
+ (TracksPanel.prototype._handleKeydown):
+ (TracksPanel.prototype._dismiss):
+ (TracksPanel.prototype._focusTrackNode):
+ (TracksPanel.prototype._focusPreviousTrackNode):
+ (TracksPanel.prototype._focusNextTrackNode):
+ (TracksPanel.prototype._focusFirstTrackNode):
+ (TracksPanel.prototype._focusLastTrackNode):
+ (TrackNode):
+ (TrackNode.prototype.activate):
+ (TrackNode.prototype.handleEvent):
+ (TrackNode.prototype._animationDidEnd):
+ * Modules/modern-media-controls/js-files:
+ * WebCore.xcodeproj/project.pbxproj:
+
2016-12-01 Andreas Kling <akl...@apple.com>
Log some basic memory usage stats at interesting points in time
Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.css (209181 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.css 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.css 2016-12-01 16:16:38 UTC (rev 209182)
@@ -25,10 +25,15 @@
/* Controls bar */
+.media-controls.mac.fullscreen {
+ --controls-bar-width: 468px;
+ --tracks-panel-right-margin: 40px;
+}
+
.media-controls.mac.fullscreen > .controls-bar {
left: 50%;
bottom: 25px;
- width: 468px;
+ width: var(--controls-bar-width);
height: 75px;
transform: translateX(-50%);
overflow: hidden;
@@ -125,3 +130,11 @@
.media-controls.mac.fullscreen .scrubber {
top: 7px;
}
+
+/* Tracks Panel */
+
+.media-controls.mac.fullscreen .tracks-panel {
+ /* Half of the screen width minus half of the controls bar width minus the distance to the right edge of the tracks button */
+ right: calc(50% - var(--controls-bar-width) / 2 + var(--tracks-panel-right-margin));
+ bottom: 234px;
+}
Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.css (209181 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.css 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.css 2016-12-01 16:16:38 UTC (rev 209182)
@@ -126,3 +126,9 @@
left: -15px;
top: 40px;
}
+
+/* Tracks Panel */
+
+.media-controls.mac.inline .tracks-panel {
+ bottom: 51px;
+}
Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.js (209181 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.js 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.js 2016-12-01 16:16:38 UTC (rev 209182)
@@ -34,7 +34,26 @@
this.muteButton = new MuteButton(this);
this.tracksButton = new TracksButton(this);
+ this.tracksPanel = new TracksPanel;
this.volumeSlider = new VolumeSlider;
}
+ // Public
+
+ showTracksPanel()
+ {
+ this.tracksButton.on = true;
+ this.tracksButton.element.blur();
+ this.controlsBar.userInteractionEnabled = false;
+ this.tracksPanel.presentInParent(this);
+ }
+
+ hideTracksPanel()
+ {
+ this.tracksButton.on = false;
+ this.tracksButton.element.focus();
+ this.controlsBar.userInteractionEnabled = true;
+ this.tracksPanel.hide();
+ }
+
}
Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/media-controls.css (209181 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/controls/media-controls.css 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/media-controls.css 2016-12-01 16:16:38 UTC (rev 209182)
@@ -31,6 +31,7 @@
/* We need to use relative positioning due to webkit.org/b/163603 */
.media-controls {
position: relative;
+ font-family: -apple-system;
}
.media-controls > .controls-bar {
Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/placard.css (209181 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/controls/placard.css 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/placard.css 2016-12-01 16:16:38 UTC (rev 209182)
@@ -32,8 +32,6 @@
background-color: black;
color: rgb(164, 164, 164);
-
- font-family: -apple-system;
}
.placard .container {
Modified: trunk/Source/WebCore/Modules/modern-media-controls/controls/status-label.css (209181 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/controls/status-label.css 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/status-label.css 2016-12-01 16:16:38 UTC (rev 209182)
@@ -30,7 +30,6 @@
white-space: nowrap;
overflow: hidden;
- font-family: -apple-system;
font-size: 14px;
color: rgba(255, 255, 255, 0.572);
Added: trunk/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.css (0 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.css (rev 0)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.css 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.tracks-panel {
+ position: absolute;
+ display: inline-block;
+ border-radius: 7px;
+ /* FIXME: we want to use the real System Dark treatment here, see <rdar://problem/19993961> */
+ background-color: rgba(30, 30, 30, 0.45);
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
+}
+
+.tracks-panel * {
+ font-size: 14px;
+ font-weight: 500;
+}
+
+.tracks-panel.fade-out {
+ transition-property: opacity;
+ transition-duration: 265ms;
+ opacity: 0;
+}
+
+.tracks-panel-section {
+ border-top: 2px solid rgb(104, 104, 104);
+}
+
+.tracks-panel-section:first-of-type {
+ border-top: 0;
+}
+
+.tracks-panel-section > h3 {
+ color: rgb(150, 150, 150);
+ padding: 5px 20px 1px 21px;
+ margin: 0;
+}
+
+.tracks-panel-section > ul {
+ list-style-type: none;
+ margin-top: 0;
+ padding: 0;
+}
+
+.tracks-panel-section > ul > li {
+ position: relative;
+ padding: 1px 20px 1px 33px;
+ color: white;
+}
+
+.tracks-panel-section > ul > li:focus {
+ background-color: rgba(26, 68, 243, 0.6);
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
+ outline: none;
+}
+
+.tracks-panel-section > ul > li.selected:before {
+ position: absolute;
+ top: 3px;
+ left: 12px;
+ width: 12px;
+ display: inline-block;
+ content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"><polygon fill="white" points="252.301,4.477 126.667,194.104 43.358,108.3 6.868,161.408 132.515,290.814 297.732,49.926"/></svg>');
+}
+
+.tracks-panel-section > ul > li.animated {
+ animation-name: tracks-panel-item-selection;
+ animation-duration: 150ms;
+ animation-timing-function: step-end;
+ animation-fill-mode: forwards;
+}
+
+@keyframes tracks-panel-item-selection {
+ 0%, 55.55% {
+ background-color: rgba(26, 68, 243, 0.6);
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
+ }
+
+ 22.22% {
+ background: none;
+ -webkit-backdrop-filter: none;
+ }
+}
Added: trunk/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.js (0 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.js (rev 0)
+++ trunk/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.js 2016-12-01 16:16:38 UTC (rev 209182)
@@ -0,0 +1,277 @@
+
+class TracksPanel extends LayoutNode
+{
+
+ constructor()
+ {
+ super(`<div class="tracks-panel">`);
+ this._rightX = 0;
+ }
+
+ // Public
+
+ get presented()
+ {
+ return !!this.parent;
+ }
+
+ presentInParent(node)
+ {
+ if (this.parent === node)
+ return;
+
+ this.children = this._childrenFromDataSource();
+
+ node.addChild(this);
+
+ this.element.removeEventListener("transitionend", this);
+ this.element.classList.remove("fade-out");
+
+ window.addEventListener("mousedown", this, true);
+ window.addEventListener("keydown", this, true);
+
+ this._focusedTrackNode = null;
+ }
+
+ hide()
+ {
+ if (!this.presented)
+ return;
+
+ window.removeEventListener("mousedown", this, true);
+ window.removeEventListener("keydown", this, true);
+
+ this.element.addEventListener("transitionend", this);
+ this.element.classList.add("fade-out");
+ }
+
+ get rightX()
+ {
+ return this._rightX;
+ }
+
+ set rightX(x)
+ {
+ if (this._rightX === x)
+ return;
+
+ this._rightX = x;
+ this.markDirtyProperty("rightX");
+ }
+
+ // Protected
+
+ trackNodeSelectionAnimationDidEnd(trackNode)
+ {
+ if (this.uiDelegate && typeof this.uiDelegate.tracksPanelSelectionDidChange === "function")
+ this.uiDelegate.tracksPanelSelectionDidChange(trackNode.index, trackNode.sectionIndex);
+ }
+
+ mouseMovedOverTrackNode(trackNode)
+ {
+ this._focusTrackNode(trackNode);
+ }
+
+ mouseExitedTrackNode(trackNode)
+ {
+ this._focusedTrackNode.element.blur();
+ delete this._focusedTrackNode;
+ }
+
+ commitProperty(propertyName)
+ {
+ if (propertyName === "rightX")
+ this.element.style.right = `${this._rightX}px`;
+ else
+ super.commitProperty(propertyName);
+ }
+
+ handleEvent(event)
+ {
+ switch (event.type) {
+ case "mousedown":
+ this._handleMousedown(event);
+ break;
+ case "keydown":
+ this._handleKeydown(event);
+ break;
+ case "transitionend":
+ this.remove();
+ break;
+ }
+ }
+
+ // Private
+
+ _childrenFromDataSource()
+ {
+ const children = [];
+
+ this._trackNodes = [];
+
+ const dataSource = this.dataSource;
+ if (!dataSource)
+ return children;
+
+ const numberOfSections = dataSource.tracksPanelNumberOfSections();
+ if (numberOfSections == 0)
+ return children;
+
+ for (let sectionIndex = 0; sectionIndex < numberOfSections; ++sectionIndex) {
+ let sectionNode = new LayoutNode(`<div class="tracks-panel-section"></div>`);
+ sectionNode.addChild(new LayoutNode(`<h3>${dataSource.tracksPanelTitleForSection(sectionIndex)}</h3>`));
+
+ let tracksListNode = sectionNode.addChild(new LayoutNode(`<ul></ul>`));
+ let numberOfTracks = dataSource.tracksPanelNumberOfTracksInSection(sectionIndex);
+ for (let trackIndex = 0; trackIndex < numberOfTracks; ++trackIndex) {
+ let trackTitle = dataSource.tracksPanelTitleForTrackInSection(trackIndex, sectionIndex);
+ let trackSelected = dataSource.tracksPanelIsTrackInSectionSelected(trackIndex, sectionIndex)
+ let trackNode = tracksListNode.addChild(new TrackNode(trackIndex, sectionIndex, trackTitle, trackSelected, this));
+ this._trackNodes.push(trackNode);
+ }
+ children.push(sectionNode);
+ }
+
+ return children;
+ }
+
+ _handleMousedown(event)
+ {
+ if (this.element.contains(event.target))
+ return;
+
+ this._dismiss();
+
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ _handleKeydown(event)
+ {
+ switch (event.key) {
+ case "Home":
+ case "PageUp":
+ this._focusFirstTrackNode();
+ break;
+ case "End":
+ case "PageDown":
+ this._focusLastTrackNode();
+ break;
+ case "ArrowDown":
+ if (event.altKey || event.metaKey)
+ this._focusLastTrackNode();
+ else
+ this._focusNextTrackNode();
+ break;
+ case "ArrowUp":
+ if (event.altKey || event.metaKey)
+ this._focusFirstTrackNode();
+ else
+ this._focusPreviousTrackNode();
+ break;
+ case " ":
+ case "Enter":
+ if (this._focusedTrackNode)
+ this._focusedTrackNode.activate();
+ break;
+ case "Escape":
+ this._dismiss();
+ break;
+ }
+ }
+
+ _dismiss()
+ {
+ if (this.parent && typeof this.parent.hideTracksPanel === "function")
+ this.parent.hideTracksPanel();
+ }
+
+ _focusTrackNode(trackNode)
+ {
+ if (!trackNode || trackNode === this._focusedTrackNode)
+ return;
+
+ trackNode.element.focus();
+ this._focusedTrackNode = trackNode;
+ }
+
+ _focusPreviousTrackNode()
+ {
+ const previousIndex = this._focusedTrackNode ? this._trackNodes.indexOf(this._focusedTrackNode) - 1 : this._trackNodes.length - 1;
+ this._focusTrackNode(this._trackNodes[previousIndex]);
+ }
+
+ _focusNextTrackNode()
+ {
+ this._focusTrackNode(this._trackNodes[this._trackNodes.indexOf(this._focusedTrackNode) + 1]);
+ }
+
+ _focusFirstTrackNode()
+ {
+ this._focusTrackNode(this._trackNodes[0]);
+ }
+
+ _focusLastTrackNode()
+ {
+ this._focusTrackNode(this._trackNodes[this._trackNodes.length - 1]);
+ }
+
+}
+
+class TrackNode extends LayoutNode
+{
+
+ constructor(index, sectionIndex, title, selected, panel)
+ {
+ super(`<li tabindex="0">${title}</li>`);
+
+ this.index = index;
+ this.sectionIndex = sectionIndex;
+ this._panel = panel;
+ this._selected = selected;
+
+ if (selected)
+ this.element.classList.add("selected");
+
+ this.element.addEventListener("mousemove", this);
+ this.element.addEventListener("mouseleave", this);
+ this.element.addEventListener("click", this);
+ }
+
+ // Public
+
+ activate()
+ {
+ this.element.addEventListener("animationend", this);
+ this.element.classList.add("animated");
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ switch (event.type) {
+ case "mousemove":
+ this._panel.mouseMovedOverTrackNode(this);
+ break;
+ case "mouseleave":
+ this._panel.mouseExitedTrackNode(this);
+ break;
+ case "click":
+ this.activate();
+ break;
+ case "animationend":
+ this._animationDidEnd();
+ break;
+ }
+ }
+
+ // Private
+
+ _animationDidEnd()
+ {
+ this.element.removeEventListener("animationend", this);
+ this._panel.trackNodeSelectionAnimationDidEnd(this);
+ }
+
+}
Modified: trunk/Source/WebCore/Modules/modern-media-controls/js-files (209181 => 209182)
--- trunk/Source/WebCore/Modules/modern-media-controls/js-files 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/Modules/modern-media-controls/js-files 2016-12-01 16:16:38 UTC (rev 209182)
@@ -23,6 +23,7 @@
controls/buttons-container.js
controls/status-label.js
controls/controls-bar.js
+controls/tracks-panel.js
controls/media-controls.js
controls/ios-inline-media-controls.js
controls/macos-media-controls.js
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (209181 => 209182)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2016-12-01 16:15:27 UTC (rev 209181)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2016-12-01 16:16:38 UTC (rev 209182)
@@ -10038,6 +10038,8 @@
713E70AF1733E8B300A22D00 /* plugIns.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode._javascript_; path = plugIns.js; sourceTree = "<group>"; };
714131471DC9D6AF00336107 /* fullscreen-support.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "fullscreen-support.js"; sourceTree = "<group>"; };
714131481DC9D6EF00336107 /* js-files */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "js-files"; sourceTree = "<group>"; };
+ 7146DF8B1DEFC2ED0046F98B /* tracks-panel.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = "tracks-panel.css"; sourceTree = "<group>"; };
+ 7146DF8C1DEFC2ED0046F98B /* tracks-panel.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "tracks-panel.js"; sourceTree = "<group>"; };
714F5B051DEE5F740075BD17 /* invalid-placard.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; path = "invalid-placard.js"; sourceTree = "<group>"; };
714F5B061DEE5F8A0075BD17 /* invalid-plac...@1x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "invalid-plac...@1x.png"; sourceTree = "<group>"; };
714F5B071DEE5F8A0075BD17 /* invalid-plac...@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "invalid-plac...@2x.png"; sourceTree = "<group>"; };
@@ -18065,6 +18067,8 @@
716FA0D71DB26591007323CC /* controls */ = {
isa = PBXGroup;
children = (
+ 7146DF8B1DEFC2ED0046F98B /* tracks-panel.css */,
+ 7146DF8C1DEFC2ED0046F98B /* tracks-panel.js */,
716FA0D81DB26591007323CC /* airplay-button.css */,
716FA0D91DB26591007323CC /* airplay-button.js */,
716FA0DA1DB26591007323CC /* airplay-placard.js */,