mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
move emby-webcomponents to components and reflect paths
This commit is contained in:
parent
e91cbf8438
commit
6ddc62857d
275 changed files with 20 additions and 20 deletions
69
src/components/viewmanager/viewcontainer-lite.css
Normal file
69
src/components/viewmanager/viewcontainer-lite.css
Normal file
|
@ -0,0 +1,69 @@
|
|||
.mainAnimatedPage {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
contain: layout style size;
|
||||
/* Can't use will-change because it causes the alpha picker to move when the page scrolls*/
|
||||
/*will-change: transform;*/
|
||||
}
|
||||
|
||||
@keyframes view-fadeout {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@keyframes view-fadein {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes view-slideleft {
|
||||
from {
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes view-slideleft-r {
|
||||
from {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes view-slideright {
|
||||
from {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes view-slideright-r {
|
||||
from {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
||||
}
|
313
src/components/viewmanager/viewcontainer-lite.js
Normal file
313
src/components/viewmanager/viewcontainer-lite.js
Normal file
|
@ -0,0 +1,313 @@
|
|||
define(['browser', 'dom', 'layoutManager', 'css!./viewcontainer-lite'], function (browser, dom, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
var mainAnimatedPages = document.querySelector('.mainAnimatedPages');
|
||||
var allPages = [];
|
||||
var currentUrls = [];
|
||||
var pageContainerCount = 3;
|
||||
var selectedPageIndex = -1;
|
||||
|
||||
function enableAnimation() {
|
||||
|
||||
// too slow
|
||||
if (browser.tv) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return browser.supportsCssAnimation();
|
||||
}
|
||||
|
||||
function findLastView(parent, className) {
|
||||
|
||||
var nodes = parent.childNodes;
|
||||
for (var i = nodes.length - 1; i >= 0; i--) {
|
||||
var node = nodes[i];
|
||||
var classList = node.classList;
|
||||
if (classList && classList.contains(className)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function findViewBefore(elem, className) {
|
||||
|
||||
var node = elem.previousSibling;
|
||||
while (node) {
|
||||
var classList = node.classList;
|
||||
if (classList && classList.contains(className)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
node = node.previousSibling;
|
||||
}
|
||||
}
|
||||
|
||||
function loadView(options) {
|
||||
|
||||
if (options.cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
cancelActiveAnimations();
|
||||
|
||||
var selected = selectedPageIndex;
|
||||
var previousAnimatable = selected === -1 ? null : allPages[selected];
|
||||
var pageIndex = selected + 1;
|
||||
|
||||
if (pageIndex >= pageContainerCount) {
|
||||
pageIndex = 0;
|
||||
}
|
||||
|
||||
var viewHtml = options.view;
|
||||
|
||||
var properties = [];
|
||||
if (options.fullscreen) {
|
||||
properties.push('fullscreen');
|
||||
}
|
||||
|
||||
var currentPage = allPages[pageIndex];
|
||||
|
||||
var view;
|
||||
|
||||
if (currentPage) {
|
||||
triggerDestroy(currentPage);
|
||||
currentPage.insertAdjacentHTML('beforebegin', viewHtml);
|
||||
view = findViewBefore(currentPage, 'view');
|
||||
|
||||
mainAnimatedPages.removeChild(currentPage);
|
||||
|
||||
} else {
|
||||
mainAnimatedPages.insertAdjacentHTML('beforeend', viewHtml);
|
||||
|
||||
view = findLastView(mainAnimatedPages, 'view');
|
||||
}
|
||||
|
||||
view.classList.add('mainAnimatedPage');
|
||||
|
||||
if (properties.length) {
|
||||
view.setAttribute('data-properties', properties.join(','));
|
||||
}
|
||||
|
||||
if (options.type) {
|
||||
view.setAttribute('data-type', options.type);
|
||||
}
|
||||
|
||||
allPages[pageIndex] = view;
|
||||
|
||||
if (onBeforeChange) {
|
||||
onBeforeChange(view, false, options);
|
||||
}
|
||||
|
||||
beforeAnimate(allPages, pageIndex, selected);
|
||||
|
||||
// animate here
|
||||
return animate(view, previousAnimatable, options.transition, options.isBack).then(function () {
|
||||
|
||||
selectedPageIndex = pageIndex;
|
||||
currentUrls[pageIndex] = options.url;
|
||||
if (!options.cancel && previousAnimatable) {
|
||||
afterAnimate(allPages, pageIndex);
|
||||
}
|
||||
|
||||
return view;
|
||||
});
|
||||
}
|
||||
|
||||
function beforeAnimate(allPages, newPageIndex, oldPageIndex) {
|
||||
for (var i = 0, length = allPages.length; i < length; i++) {
|
||||
if (newPageIndex === i || oldPageIndex === i) {
|
||||
//allPages[i].classList.remove('hide');
|
||||
} else {
|
||||
allPages[i].classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function afterAnimate(allPages, newPageIndex) {
|
||||
for (var i = 0, length = allPages.length; i < length; i++) {
|
||||
if (newPageIndex === i) {
|
||||
//allPages[i].classList.remove('hide');
|
||||
} else {
|
||||
allPages[i].classList.add('hide');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function animate(newAnimatedPage, oldAnimatedPage, transition, isBack) {
|
||||
|
||||
if (enableAnimation() && oldAnimatedPage) {
|
||||
if (transition === 'slide') {
|
||||
return slide(newAnimatedPage, oldAnimatedPage, transition, isBack);
|
||||
} else if (transition === 'fade') {
|
||||
return fade(newAnimatedPage, oldAnimatedPage, transition, isBack);
|
||||
} else {
|
||||
clearAnimation(newAnimatedPage);
|
||||
if (oldAnimatedPage) {
|
||||
clearAnimation(oldAnimatedPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
function clearAnimation(elem) {
|
||||
setAnimation(elem, 'none');
|
||||
}
|
||||
|
||||
function slide(newAnimatedPage, oldAnimatedPage, transition, isBack) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var duration = layoutManager.tv ? 450 : 160;
|
||||
|
||||
var animations = [];
|
||||
|
||||
if (oldAnimatedPage) {
|
||||
if (isBack) {
|
||||
setAnimation(oldAnimatedPage, 'view-slideright-r ' + duration + 'ms ease-out normal both');
|
||||
} else {
|
||||
setAnimation(oldAnimatedPage, 'view-slideleft-r ' + duration + 'ms ease-out normal both');
|
||||
}
|
||||
animations.push(oldAnimatedPage);
|
||||
}
|
||||
|
||||
if (isBack) {
|
||||
setAnimation(newAnimatedPage, 'view-slideright ' + duration + 'ms ease-out normal both');
|
||||
} else {
|
||||
setAnimation(newAnimatedPage, 'view-slideleft ' + duration + 'ms ease-out normal both');
|
||||
}
|
||||
animations.push(newAnimatedPage);
|
||||
|
||||
currentAnimations = animations;
|
||||
|
||||
var onAnimationComplete = function () {
|
||||
dom.removeEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
resolve();
|
||||
};
|
||||
|
||||
dom.addEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function fade(newAnimatedPage, oldAnimatedPage, transition, isBack) {
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var duration = layoutManager.tv ? 450 : 270;
|
||||
var animations = [];
|
||||
|
||||
newAnimatedPage.style.opacity = 0;
|
||||
setAnimation(newAnimatedPage, 'view-fadein ' + duration + 'ms ease-in normal both');
|
||||
animations.push(newAnimatedPage);
|
||||
|
||||
if (oldAnimatedPage) {
|
||||
setAnimation(oldAnimatedPage, 'view-fadeout ' + duration + 'ms ease-out normal both');
|
||||
animations.push(oldAnimatedPage);
|
||||
}
|
||||
|
||||
currentAnimations = animations;
|
||||
|
||||
var onAnimationComplete = function () {
|
||||
dom.removeEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
resolve();
|
||||
};
|
||||
|
||||
dom.addEventListener(newAnimatedPage, dom.whichAnimationEvent(), onAnimationComplete, {
|
||||
once: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setAnimation(elem, value) {
|
||||
|
||||
requestAnimationFrame(function () {
|
||||
elem.style.animation = value;
|
||||
});
|
||||
}
|
||||
|
||||
var currentAnimations = [];
|
||||
function cancelActiveAnimations() {
|
||||
|
||||
var animations = currentAnimations;
|
||||
for (var i = 0, length = animations.length; i < length; i++) {
|
||||
animations[i].style.animation = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
var onBeforeChange;
|
||||
function setOnBeforeChange(fn) {
|
||||
onBeforeChange = fn;
|
||||
}
|
||||
|
||||
function tryRestoreView(options) {
|
||||
|
||||
var url = options.url;
|
||||
var index = currentUrls.indexOf(url);
|
||||
|
||||
if (index !== -1) {
|
||||
|
||||
var animatable = allPages[index];
|
||||
var view = animatable;
|
||||
|
||||
if (view) {
|
||||
|
||||
if (options.cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
cancelActiveAnimations();
|
||||
|
||||
var selected = selectedPageIndex;
|
||||
var previousAnimatable = selected === -1 ? null : allPages[selected];
|
||||
|
||||
if (onBeforeChange) {
|
||||
onBeforeChange(view, true, options);
|
||||
}
|
||||
|
||||
beforeAnimate(allPages, index, selected);
|
||||
|
||||
animatable.classList.remove('hide');
|
||||
|
||||
return animate(animatable, previousAnimatable, options.transition, options.isBack).then(function () {
|
||||
|
||||
selectedPageIndex = index;
|
||||
if (!options.cancel && previousAnimatable) {
|
||||
afterAnimate(allPages, index);
|
||||
}
|
||||
return view;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
function triggerDestroy(view) {
|
||||
|
||||
view.dispatchEvent(new CustomEvent('viewdestroy', {
|
||||
cancelable: false
|
||||
}));
|
||||
}
|
||||
|
||||
function reset() {
|
||||
|
||||
allPages = [];
|
||||
currentUrls = [];
|
||||
mainAnimatedPages.innerHTML = '';
|
||||
selectedPageIndex = -1;
|
||||
}
|
||||
|
||||
return {
|
||||
loadView: loadView,
|
||||
tryRestoreView: tryRestoreView,
|
||||
reset: reset,
|
||||
setOnBeforeChange: setOnBeforeChange
|
||||
};
|
||||
});
|
183
src/components/viewmanager/viewmanager.js
Normal file
183
src/components/viewmanager/viewmanager.js
Normal file
|
@ -0,0 +1,183 @@
|
|||
define(['viewcontainer', 'focusManager', 'queryString', 'layoutManager'], function (viewcontainer, focusManager, queryString, layoutManager) {
|
||||
'use strict';
|
||||
|
||||
var currentView;
|
||||
var dispatchPageEvents;
|
||||
|
||||
viewcontainer.setOnBeforeChange(function (newView, isRestored, options) {
|
||||
|
||||
var lastView = currentView;
|
||||
if (lastView) {
|
||||
|
||||
var beforeHideResult = dispatchViewEvent(lastView, null, 'viewbeforehide', true);
|
||||
|
||||
if (!beforeHideResult) {
|
||||
// todo: cancel
|
||||
}
|
||||
}
|
||||
|
||||
var eventDetail = getViewEventDetail(newView, options, isRestored);
|
||||
|
||||
if (!newView.initComplete) {
|
||||
newView.initComplete = true;
|
||||
|
||||
if (options.controllerFactory) {
|
||||
|
||||
// Use controller method
|
||||
var controller = new options.controllerFactory(newView, eventDetail.detail.params);
|
||||
}
|
||||
|
||||
if (!options.controllerFactory || dispatchPageEvents) {
|
||||
dispatchViewEvent(newView, eventDetail, 'viewinit');
|
||||
}
|
||||
}
|
||||
|
||||
dispatchViewEvent(newView, eventDetail, 'viewbeforeshow');
|
||||
});
|
||||
|
||||
function onViewChange(view, options, isRestore) {
|
||||
|
||||
var lastView = currentView;
|
||||
if (lastView) {
|
||||
dispatchViewEvent(lastView, null, 'viewhide');
|
||||
}
|
||||
|
||||
currentView = view;
|
||||
|
||||
var eventDetail = getViewEventDetail(view, options, isRestore);
|
||||
|
||||
if (!isRestore) {
|
||||
if (options.autoFocus !== false) {
|
||||
focusManager.autoFocus(view);
|
||||
}
|
||||
}
|
||||
else if (!layoutManager.mobile) {
|
||||
if (view.activeElement && document.body.contains(view.activeElement) && focusManager.isCurrentlyFocusable(view.activeElement)) {
|
||||
focusManager.focus(view.activeElement);
|
||||
} else {
|
||||
focusManager.autoFocus(view);
|
||||
}
|
||||
}
|
||||
|
||||
view.dispatchEvent(new CustomEvent('viewshow', eventDetail));
|
||||
|
||||
if (dispatchPageEvents) {
|
||||
view.dispatchEvent(new CustomEvent('pageshow', eventDetail));
|
||||
}
|
||||
}
|
||||
|
||||
function getProperties(view) {
|
||||
var props = view.getAttribute('data-properties');
|
||||
|
||||
if (props) {
|
||||
return props.split(',');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function dispatchViewEvent(view, eventInfo, eventName, isCancellable) {
|
||||
|
||||
if (!eventInfo) {
|
||||
eventInfo = {
|
||||
detail: {
|
||||
type: view.getAttribute('data-type'),
|
||||
properties: getProperties(view)
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: isCancellable
|
||||
};
|
||||
}
|
||||
|
||||
eventInfo.cancelable = isCancellable || false;
|
||||
|
||||
var eventResult = view.dispatchEvent(new CustomEvent(eventName, eventInfo));
|
||||
|
||||
if (dispatchPageEvents) {
|
||||
eventInfo.cancelable = false;
|
||||
view.dispatchEvent(new CustomEvent(eventName.replace('view', 'page'), eventInfo));
|
||||
}
|
||||
|
||||
return eventResult;
|
||||
}
|
||||
|
||||
function getViewEventDetail(view, options, isRestore) {
|
||||
|
||||
var url = options.url;
|
||||
var index = url.indexOf('?');
|
||||
var params = index === -1 ? {} : queryString.parse(url.substring(index + 1));
|
||||
|
||||
return {
|
||||
detail: {
|
||||
type: view.getAttribute('data-type'),
|
||||
properties: getProperties(view),
|
||||
params: params,
|
||||
isRestored: isRestore,
|
||||
state: options.state,
|
||||
|
||||
// The route options
|
||||
options: options.options || {}
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
};
|
||||
}
|
||||
|
||||
function resetCachedViews() {
|
||||
// Reset all cached views whenever the skin changes
|
||||
viewcontainer.reset();
|
||||
}
|
||||
|
||||
document.addEventListener('skinunload', resetCachedViews);
|
||||
|
||||
function ViewManager() {
|
||||
}
|
||||
|
||||
ViewManager.prototype.loadView = function (options) {
|
||||
|
||||
var lastView = currentView;
|
||||
|
||||
// Record the element that has focus
|
||||
if (lastView) {
|
||||
lastView.activeElement = document.activeElement;
|
||||
}
|
||||
|
||||
if (options.cancel) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewcontainer.loadView(options).then(function (view) {
|
||||
|
||||
onViewChange(view, options);
|
||||
});
|
||||
};
|
||||
|
||||
ViewManager.prototype.tryRestoreView = function (options, onViewChanging) {
|
||||
|
||||
if (options.cancel) {
|
||||
return Promise.reject({ cancelled: true });
|
||||
}
|
||||
|
||||
// Record the element that has focus
|
||||
if (currentView) {
|
||||
currentView.activeElement = document.activeElement;
|
||||
}
|
||||
|
||||
return viewcontainer.tryRestoreView(options).then(function (view) {
|
||||
|
||||
onViewChanging();
|
||||
onViewChange(view, options, true);
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
ViewManager.prototype.currentView = function () {
|
||||
return currentView;
|
||||
};
|
||||
|
||||
ViewManager.prototype.dispatchPageEvents = function (value) {
|
||||
dispatchPageEvents = value;
|
||||
};
|
||||
|
||||
return new ViewManager();
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue