Commit 4fcaee53 authored by Jazz Xu's avatar Jazz Xu Committed by Commit Bot

[Media Controls] Added animation to overflow menu

Toggle "closed" class when open/close menu to achieve transition animation.
This CL only has opening animation.

TODO: Add close animation; Add wave like animation to label when opening menu.

Bug: 814507

Change-Id: I2a036297741f34905fe868c7ea0a99e9ea91cea3
Reviewed-on: https://chromium-review.googlesource.com/c/1286949
Commit-Queue: Jazz Xu <jazzhsu@google.com>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603116}
parent 17956924
......@@ -17,6 +17,7 @@ async_test(function(t) {
// Set up video
var video = document.querySelector("video");
video.src = "http://localhost:8000/media/resources/test.ogv";
enableTestMode(video);
video.onloadeddata = t.step_func(function() {
// Click on the download button
......
......@@ -17,6 +17,7 @@ async_test(function(t) {
// Set up video
var video = document.querySelector("video");
video.src = "resources/test.ogv";
enableTestMode(video);
video.onloadeddata = t.step_func(function() {
// Click on the download button
......
......@@ -17,6 +17,7 @@ async_test(function(t) {
video.src = "resources/test.ogv";
video.setAttribute("width", "60");
video.setAttribute("height", "100");
enableTestMode(video);
var controlID = "-internal-media-controls-download-button";
var downloadButton = mediaControlsElement(internals.shadowRoot(video).firstChild, controlID);
......
......@@ -10,6 +10,7 @@
<script>
async_test(t => {
var video = document.querySelector('video');
enableTestMode(video);
video.oncanplaythrough = t.step_func(_ => {
assert_true(isClosedCaptionsButtonEnabled(video));
......
......@@ -9,6 +9,8 @@ async_test(t => {
var captions = ['First', 'Second', 'Third'];
var video = document.querySelector('video');
enableTestMode(video);
video.oncanplaythrough = t.step_func(_ => {
var track1 = video.addTextTrack('captions');
var track2 = video.addTextTrack('captions');
......
......@@ -8,6 +8,7 @@
async_test(t => {
var captions = ["Caption"];
var video = document.querySelector("video");
enableTestMode(video);
video.oncanplaythrough = t.step_func(_ => {
var track1 = video.addTextTrack("captions");
......
......@@ -11,6 +11,8 @@ async_test(t => {
var trackLanguages = ['en', 'ru', 'fr', 'jp', 'de'];
var trackCueText = ['English', 'Russian', 'French', 'Japanese', 'German'];
enableTestMode(video);
video.oncanplaythrough = t.step_func(_ => {
for (var i = 0; i < trackLanguages.length; i++) {
var track = video.addTextTrack('captions', trackCueText[i], trackLanguages[i]);
......
......@@ -8,6 +8,7 @@
async_test(t => {
const video = document.querySelector('video');
video.src = '../content/test.ogv';
enableTestMode(video);
const track = video.addTextTrack('captions');
video.onloadeddata = t.step_func(() => {
......
<!DOCTYPE html>
<title>Media Controls: overflow menu toggle class for animation.</title>
<script src='../../resources/testharness.js'></script>
<script src='../../resources/testharnessreport.js'></script>
<script src='../media-controls.js'></script>
<video controls width=400></video>
<script>
async_test(t => {
const video = document.querySelector('video');
enableTestMode(video);
video.src = '../content/test.ogv';
video.addTextTrack('captions', 'foo');
video.addTextTrack('captions', 'bar');
video.onloadeddata = t.step_func(() => {
const menu = overflowMenu(video);
const captionsList = textTrackMenu(video);
// Open overflow => close overflow
expectAllMenuClosed();
singleTapOnControl(overflowButton(video), t.step_func(() => {
expectOpenMenu();
singleTapOutsideControl(menu, t.step_func(() => {
expectAllMenuClosed();
// End of scenario
// Open overflow => open captions list => close captions list
clickCaptionButton(video, t.step_func(() => {
expectOpenMenu();
singleTapOutsideControl(captionsList, t.step_func(() => {
expectAllMenuClosed();
// End of scenario
// Open overflow => open captions list => select track
clickTextTrackAtIndex(video, 0, t.step_func(() => {
expectAllMenuClosed();
// End of scenario
// Open overflow => open captions list => click back to overflow => close overflow
clickCaptionButton(video, t.step_func(() => {
expectOpenMenu();
const trackListHeader = textTrackListHeader(video);
singleTapOnControl(trackListHeader, t.step_func(() => {
expectOpenMenu();
singleTapOutsideControl(menu, t.step_func_done(() => {
expectAllMenuClosed();
// End of scenario
}));
}));
}));
}));
}));
}));
}));
}));
function expectClosedMenu() {
assert_true(menu.classList.contains('closed'));
}
function expectOpenMenu() {
assert_false(menu.classList.contains('closed'));
}
function expectAllMenuClosed() {
assert_equals(getComputedStyle(menu).display, 'none');
assert_equals(getComputedStyle(captionsList).display, 'none');
expectClosedMenu();
}
});
});
</script>
......@@ -66,9 +66,11 @@ async_test(t => {
assert_equals(video.textTracks.length, 2);
document.body.appendChild(video);
enableTestMode(video);
video.addEventListener('loadedmetadata', t.step_func(() => {
assert_true(isVisible(overflowButton(video)));
openOverflowAndClickButton(video, captionsOverflowItem(video), t.step_func_done(() => {
const menu = textTrackMenu(video);
assert_true(isVisible(menu));
......
......@@ -55,9 +55,11 @@ async_test(t => {
assert_equals(video.textTracks.length, 2);
document.body.appendChild(video);
enableTestMode(video);
video.addEventListener('loadedmetadata', t.step_func(() => {
assert_true(isVisible(overflowButton(video)));
openOverflowAndClickButton(video, captionsOverflowItem(video), t.step_func(() => {
const menu = textTrackMenu(video);
assert_true(isVisible(menu));
......
......@@ -106,6 +106,14 @@ function textTrackMenu(video)
return element;
}
function textTrackListHeader(video)
{
var element = textTrackMenu(video).childNodes[0];
if (!element)
throw 'Failed to find the track list header'
return element;
}
function overflowMenu(video)
{
var controlID = '-internal-media-controls-overflow-menu-list';
......@@ -529,6 +537,11 @@ function singleTapAtCoordinates(xPos, yPos, callback) {
], callback);
}
function singleTapOutsideControl(control, callback) {
const coordinates = coordinatesOutsideElement(control);
singleTapAtCoordinates(coordinates[0], coordinates[1], callback);
}
function singleTapOnControl(control, callback) {
const coordinates = elementCoordinates(control);
singleTapAtCoordinates(coordinates[0], coordinates[1], callback);
......
......@@ -13,6 +13,7 @@ async_test(t => {
var video = document.querySelector("video");
video.src = "../../content/test.ogv";
enableTestMode(video);
video.onloadedmetadata = t.step_func(function() {
assert_true(isPictureInPictureButtonEnabled(video), "button should exist");
......
......@@ -16,6 +16,7 @@ const testCases = [
];
const video = document.getElementsByTagName('video')[0];
enableTestMode(video);
function runSizingTest(t, num) {
if (num >= testCases.length)
......
......@@ -13,6 +13,7 @@ async_test(t => {
var video = document.querySelector("video");
video.src = "../content/test.ogv";
enableTestMode(video);
video.onloadedmetadata = t.step_func(function() {
assert_true(isPictureInPictureButtonEnabled(video), "button should exist");
......
......@@ -11,6 +11,7 @@
async_test(function(t) {
var trackCueText = "Bonjour";
var video = document.querySelector("video");
enableTestMode(video);
video.oncanplaythrough = t.step_func(function() {
var track = video.addTextTrack("captions", "French", "fr");
......
......@@ -11,6 +11,7 @@
<script>
async_test(function(t) {
var video = document.querySelector("video");
enableTestMode(video);
video.oncanplaythrough = t.step_func(function() {
clickCaptionButton(video, t.step_func_done(function() {
......
......@@ -19,6 +19,8 @@ async_test(function(t) {
video.addTextTrack("captions");
video.addTextTrack("captions");
enableTestMode(video);
video.onloadeddata = t.step_func_done(function() {
var overflowList = getOverflowList(video);
var overflowMenu = getOverflowMenuButton(video);
......
......@@ -16,6 +16,8 @@ async_test(function(t) {
video.setAttribute("width", "60");
video.setAttribute("height", "100");
enableTestMode(video);
window.addEventListener("load", t.step_func(function() {
var overflowList = getOverflowList(video);
var overflowMenu = getOverflowMenuButton(video);
......
......@@ -16,6 +16,8 @@ async_test(function(t) {
video.setAttribute("width", "60");
video.setAttribute("height", "100");
enableTestMode(video);
video.onloadeddata = t.step_func_done(function() {
var overflowList = getOverflowList(video);
var overflowMenu = getOverflowMenuButton(video);
......
......@@ -16,6 +16,8 @@ async_test(function(t) {
video.setAttribute("width", "60");
video.setAttribute("height", "100");
enableTestMode(video);
video.onloadeddata = t.step_func_done(function() {
var overflowList = getOverflowList(video);
var overflowMenu = getOverflowMenuButton(video);
......
......@@ -11,6 +11,7 @@
<script>
async_test(function(t) {
var video = document.querySelector("video");
enableTestMode(video);
var trackElements = document.querySelectorAll("track");
var textTracks = video.textTracks;
......
......@@ -6,6 +6,7 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/dom_token_list.h"
#include "third_party/blink/renderer/core/dom/events/event.h"
#include "third_party/blink/renderer/modules/media_controls/elements/media_control_overflow_menu_button_element.h"
#include "third_party/blink/renderer/modules/media_controls/media_controls_impl.h"
......@@ -13,11 +14,26 @@
namespace blink {
namespace {
const char kClosedCSSClass[] = "closed";
}
MediaControlOverflowMenuListElement::MediaControlOverflowMenuListElement(
MediaControlsImpl& media_controls)
: MediaControlPopupMenuElement(media_controls, kMediaOverflowList) {
SetShadowPseudoId(
AtomicString("-internal-media-controls-overflow-menu-list"));
CloseOverflowMenu();
}
void MediaControlOverflowMenuListElement::OpenOverflowMenu() {
classList().Remove(kClosedCSSClass);
}
void MediaControlOverflowMenuListElement::CloseOverflowMenu() {
classList().Add(kClosedCSSClass);
}
void MediaControlOverflowMenuListElement::MaybeRecordTimeTaken(
......@@ -47,6 +63,11 @@ void MediaControlOverflowMenuListElement::DefaultEventHandler(Event& event) {
void MediaControlOverflowMenuListElement::SetIsWanted(bool wanted) {
MediaControlPopupMenuElement::SetIsWanted(wanted);
if (wanted)
OpenOverflowMenu();
else if (!GetMediaControls().TextTrackListIsWanted())
CloseOverflowMenu();
// Record the time the overflow menu was shown to a histogram.
if (wanted) {
DCHECK(!time_shown_);
......
......@@ -21,6 +21,9 @@ class MediaControlOverflowMenuListElement final
public:
explicit MediaControlOverflowMenuListElement(MediaControlsImpl&);
void OpenOverflowMenu();
void CloseOverflowMenu();
// Override MediaControlPopupMenuElement
void SetIsWanted(bool) final;
Element* PopupAnchor() const final;
......
......@@ -63,6 +63,9 @@ void MediaControlTextTrackListElement::SetIsWanted(bool wanted) {
if (wanted)
RefreshTextTrackListMenu();
if (!wanted && !GetMediaControls().OverflowMenuIsWanted())
GetMediaControls().CloseOverflowMenu();
MediaControlPopupMenuElement::SetIsWanted(wanted);
}
......
......@@ -1154,6 +1154,10 @@ void MediaControlsImpl::DisableShowingTextTracks() {
}
}
bool MediaControlsImpl::TextTrackListIsWanted() {
return text_track_list_->IsWanted();
}
String MediaControlsImpl::GetTextTrackLabel(TextTrack* track) const {
if (!track) {
return MediaElement().GetLocale().QueryString(
......@@ -2098,6 +2102,18 @@ void MediaControlsImpl::NetworkStateChanged() {
UpdateCSSClassFromState();
}
void MediaControlsImpl::OpenOverflowMenu() {
overflow_list_->OpenOverflowMenu();
}
void MediaControlsImpl::CloseOverflowMenu() {
overflow_list_->CloseOverflowMenu();
}
bool MediaControlsImpl::OverflowMenuIsWanted() {
return overflow_list_->IsWanted();
}
bool MediaControlsImpl::OverflowMenuVisible() {
return overflow_list_ ? overflow_list_->IsWanted() : false;
}
......
......@@ -128,12 +128,17 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
void ToggleTextTrackList();
void ShowTextTrackAtIndex(unsigned);
void DisableShowingTextTracks();
bool TextTrackListIsWanted();
// Returns the label for the track when a valid track is passed in and "Off"
// when the parameter is null.
String GetTextTrackLabel(TextTrack*) const;
// Methods related to the overflow menu.
void OpenOverflowMenu();
void CloseOverflowMenu();
bool OverflowMenuIsWanted();
void ToggleOverflowMenu();
bool OverflowMenuVisible();
......
......@@ -637,8 +637,29 @@ video::-internal-media-controls-overflow-menu-list {
background: #FFFFFF;
box-shadow: 0 1px 9px 0 rgba(0,0,0,0.40);
border-radius: 2px;
transition: transform .2s ease-out, opacity .2s linear;
transform-origin: bottom right;
}
audio::-internal-media-controls-overflow-menu-list.closed,
video::-internal-media-controls-overflow-menu-list.closed {
transform: scale(0);
opacity: 0;
}
audio::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].closed > *,
video::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].closed > * {
opacity: 0;
}
audio::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i] > *,
video::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i] > * {
transition: opacity .2s linear .2s;
}
audio::-internal-media-controls-text-track-list-header,
video::-internal-media-controls-text-track-list-header,
audio::-internal-media-controls-text-track-list-item,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment