Commit 6ec9a91f authored by Jazz Xu's avatar Jazz Xu Committed by Commit Bot

[Media Controls] Overflow menu item wave animation

This CL achieve the animation by adding sequential labeled CSS class
to overflow menu list item so that we can add delays to each visible
items to let the items appear one after another.

Bug: 814507
Change-Id: I46ee3b6e6a8cbadaad33d2417454267ff4d62a66
Reviewed-on: https://chromium-review.googlesource.com/c/1357462
Commit-Queue: Jazz Xu <jazzhsu@chromium.org>
Reviewed-by: default avatarTommy Steimel <steimel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#613224}
parent 098da25c
......@@ -30,6 +30,8 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_html.h"
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
#include "third_party/blink/renderer/core/dom/mutation_observer.h"
#include "third_party/blink/renderer/core/dom/mutation_observer_init.h"
......@@ -1414,6 +1416,28 @@ void MediaControlsImpl::UpdateOverflowMenuWanted() const {
download_iph_manager_->UpdateInProductHelp();
UpdateOverflowAndTrackListCSSClassForPip();
UpdateOverflowMenuItemCSSClass();
}
// This method is responsible for adding css class to overflow menu list
// items to achieve the animation that items appears one after another when
// open the overflow menu.
void MediaControlsImpl::UpdateOverflowMenuItemCSSClass() const {
unsigned int id = 0;
for (Element* item = ElementTraversal::LastChild(*overflow_list_); item;
item = ElementTraversal::PreviousSibling(*item)) {
const CSSPropertyValueSet* inline_style = item->InlineStyle();
DOMTokenList& class_list = item->classList();
// We don't care if the hidden element still have animated-* CSS class
if (inline_style->GetPropertyValue(CSSPropertyDisplay) == "none")
continue;
AtomicString css_class =
AtomicString("animated-") + AtomicString::Number(id++);
if (!class_list.contains(css_class))
class_list.setValue(css_class);
}
}
void MediaControlsImpl::UpdateScrubbingMessageFits() const {
......
......@@ -287,6 +287,7 @@ class MODULES_EXPORT MediaControlsImpl final : public HTMLDivElement,
void ComputeWhichControlsFit();
void UpdateOverflowMenuWanted() const;
void UpdateOverflowMenuItemCSSClass() const;
void UpdateScrubbingMessageFits() const;
void UpdateOverflowAndTrackListCSSClassForPip() const;
void UpdateSizingCSSClass();
......
......@@ -640,7 +640,7 @@ 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;
transition: transform .4s ease-out, opacity .3s linear;
transform-origin: bottom right;
}
......@@ -650,19 +650,6 @@ video::-internal-media-controls-overflow-menu-list.closed {
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,
......@@ -726,6 +713,55 @@ label[pseudo="-internal-media-controls-overflow-menu-list-item"] div span.subtit
color: rgba(0,0,0,0.54);
}
/*
* Overflow menu list item animation
*/
audio::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].closed > label,
video::-webkit-media-controls div[pseudo="-internal-media-controls-overflow-menu-list" i].closed > label {
transform: translate(0px, 15px);
opacity: 0;
}
audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i],
video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i] {
transition: transform .3s, opacity .5s;
}
audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-0,
video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-0 {
transition: opacity .5s .2s ease-in;
}
audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-1,
video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-1 {
transition-delay: .25s;
}
audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-2,
video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-2 {
transition-delay: .3s;
}
audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-3,
video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-3 {
transition-delay: .35s;
}
audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-4,
video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-4 {
transition-delay: .4s;
}
audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-5,
video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-5 {
transition-delay: .45s
}
audio::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-6,
video::-webkit-media-controls label[pseudo="-internal-media-controls-overflow-menu-list-item" i].animated-6 {
transition-delay: .5s
}
audio::-internal-media-controls-text-track-list-header:focus,
video::-internal-media-controls-text-track-list-header:focus,
audio::-internal-media-controls-overflow-menu-list-item:focus,
......
<!DOCTYPE html>
<title>Media Controls: overflow menu item list 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.onloadedmetadata = t.step_func(() => {
const menu = overflowMenu(video);
const testCasesWidth = [400, 150, 100];
runTestCase(0);
function runTestCase(index) {
video.width = testCasesWidth[index];
testRunner.layoutAndPaintAsyncThen(t.step_func(() => {
// Go through item list, check 'animated-##' class is presented if item is displayed
// and check if the items' classes are in sequential order
let id = 0;
for (let menuItem = menu.lastChild; menuItem; menuItem = menuItem.previousElementSibling) {
const classes = menuItem.classList;
if (getComputedStyle(menuItem).display == 'none') {
assert_true(classes.length < 2, 'invisible item should have 0 or 1 class');
continue;
}
assert_equals(classes.length, 1, 'menu item should have exactly one class');
assert_true(!!classes.item(0).match('animated-[0-9]+'),
'overflow menu item should not have classes other than animated-##')
const currentId = classes.item(0).split('-')[1];
assert_true(id < 7, 'we should not have more than 7 items in menu list');
assert_true(id++ == currentId, 'animated id should be in sequential order');
}
let nextIndex = index + 1;
if (nextIndex === testCasesWidth.length) {
t.done();
return;
}
runTestCase(nextIndex);
}));
}
});
});
</script>
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