mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Finish moving elements
This commit is contained in:
parent
6246dce320
commit
990b5c7237
15 changed files with 69 additions and 61 deletions
|
@ -1,77 +0,0 @@
|
|||
define(['emby-progressring', 'dom', 'serverNotifications', 'events', 'registerElement'], function (EmbyProgressRing, dom, serverNotifications, events) {
|
||||
'use strict';
|
||||
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
|
||||
var localHandler = handler.bind(instance);
|
||||
events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name) {
|
||||
|
||||
var handler = instance[name];
|
||||
if (handler) {
|
||||
events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function onRefreshProgress(e, apiClient, info) {
|
||||
|
||||
var indicator = this;
|
||||
|
||||
if (!indicator.itemId) {
|
||||
indicator.itemId = dom.parentWithAttribute(indicator, 'data-id').getAttribute('data-id');
|
||||
}
|
||||
|
||||
if (info.ItemId === indicator.itemId) {
|
||||
|
||||
var progress = parseFloat(info.Progress);
|
||||
|
||||
if (progress && progress < 100) {
|
||||
this.classList.remove('hide');
|
||||
} else {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
this.setProgress(progress);
|
||||
}
|
||||
}
|
||||
|
||||
var EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
|
||||
|
||||
EmbyItemRefreshIndicatorPrototype.createdCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyProgressRing.createdCallback) {
|
||||
EmbyProgressRing.createdCallback.call(this);
|
||||
}
|
||||
|
||||
addNotificationEvent(this, 'RefreshProgress', onRefreshProgress);
|
||||
};
|
||||
|
||||
EmbyItemRefreshIndicatorPrototype.attachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyProgressRing.attachedCallback) {
|
||||
EmbyProgressRing.attachedCallback.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyItemRefreshIndicatorPrototype.detachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyProgressRing.detachedCallback) {
|
||||
EmbyProgressRing.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
removeNotificationEvent(this, 'RefreshProgress');
|
||||
this.itemId = null;
|
||||
};
|
||||
|
||||
document.registerElement('emby-itemrefreshindicator', {
|
||||
prototype: EmbyItemRefreshIndicatorPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
|
@ -1,482 +0,0 @@
|
|||
define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', 'imageLoader', 'layoutManager', 'browser', 'dom', 'loading', 'focusManager', 'serverNotifications', 'events', 'registerElement'], function (itemShortcuts, inputManager, connectionManager, playbackManager, imageLoader, layoutManager, browser, dom, loading, focusManager, serverNotifications, events) {
|
||||
'use strict';
|
||||
|
||||
var ItemsContainerPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
function onClick(e) {
|
||||
var itemsContainer = this;
|
||||
var target = e.target;
|
||||
var multiSelect = itemsContainer.multiSelect;
|
||||
|
||||
if (multiSelect) {
|
||||
if (multiSelect.onContainerClick.call(itemsContainer, e) === false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
itemShortcuts.onClick.call(itemsContainer, e);
|
||||
}
|
||||
|
||||
function disableEvent(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
function onContextMenu(e) {
|
||||
var itemsContainer = this;
|
||||
var target = e.target;
|
||||
var card = dom.parentWithAttribute(target, 'data-id');
|
||||
|
||||
// check for serverId, it won't be present on selectserver
|
||||
if (card && card.getAttribute('data-serverid')) {
|
||||
inputManager.trigger('menu', {
|
||||
sourceElement: card
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getShortcutOptions() {
|
||||
return {
|
||||
click: false
|
||||
};
|
||||
}
|
||||
|
||||
ItemsContainerPrototype.enableMultiSelect = function (enabled) {
|
||||
var current = this.multiSelect;
|
||||
|
||||
if (!enabled) {
|
||||
if (current) {
|
||||
current.destroy();
|
||||
this.multiSelect = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (current) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
require(['multiSelect'], function (MultiSelect) {
|
||||
self.multiSelect = new MultiSelect({
|
||||
container: self,
|
||||
bindOnClick: false
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function onDrop(evt, itemsContainer) {
|
||||
var el = evt.item;
|
||||
|
||||
var newIndex = evt.newIndex;
|
||||
var itemId = el.getAttribute('data-playlistitemid');
|
||||
var playlistId = el.getAttribute('data-playlistid');
|
||||
|
||||
if (!playlistId) {
|
||||
var oldIndex = evt.oldIndex;
|
||||
el.dispatchEvent(new CustomEvent('itemdrop', {
|
||||
detail: {
|
||||
oldIndex: oldIndex,
|
||||
newIndex: newIndex,
|
||||
playlistItemId: itemId
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
var serverId = el.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
loading.show();
|
||||
|
||||
apiClient.ajax({
|
||||
url: apiClient.getUrl('Playlists/' + playlistId + '/Items/' + itemId + '/Move/' + newIndex),
|
||||
type: 'POST'
|
||||
}).then(function () {
|
||||
loading.hide();
|
||||
}, function () {
|
||||
loading.hide();
|
||||
itemsContainer.refreshItems();
|
||||
});
|
||||
}
|
||||
|
||||
ItemsContainerPrototype.enableDragReordering = function (enabled) {
|
||||
var current = this.sortable;
|
||||
if (!enabled) {
|
||||
if (current) {
|
||||
current.destroy();
|
||||
this.sortable = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (current) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
require(['sortable'], function (Sortable) {
|
||||
self.sortable = new Sortable(self, {
|
||||
draggable: ".listItem",
|
||||
handle: '.listViewDragHandle',
|
||||
|
||||
// dragging ended
|
||||
onEnd: function (evt) {
|
||||
return onDrop(evt, self);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
|
||||
var itemsContainer = this;
|
||||
|
||||
require(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.onUserDataChanged(userData, itemsContainer);
|
||||
});
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
} else if (eventsToMonitor.indexOf('markplayed') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function getEventsToMonitor(itemsContainer) {
|
||||
var monitor = itemsContainer.getAttribute('data-monitor');
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
|
||||
var itemsContainer = this;
|
||||
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
var programId = data.ProgramId;
|
||||
// This could be null, not supported by all tv providers
|
||||
var newTimerId = data.Id;
|
||||
|
||||
require(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onSeriesTimerCreated(e, apiClient, data) {
|
||||
var itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
var itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
require(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.onTimerCancelled(data.Id, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
var itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
require(['cardBuilder'], function (cardBuilder) {
|
||||
cardBuilder.onSeriesTimerCancelled(data.Id, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
var itemsContainer = this;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
var itemsAdded = data.ItemsAdded || [];
|
||||
var itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var parentId = itemsContainer.getAttribute('data-parentid');
|
||||
if (parentId) {
|
||||
var foldersAddedTo = data.FoldersAddedTo || [];
|
||||
var foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
var collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
var itemsContainer = this;
|
||||
var state = stopInfo.state;
|
||||
|
||||
var eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
} else if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Audio') {
|
||||
if (eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
var localHandler = handler.bind(instance);
|
||||
owner = owner || serverNotifications;
|
||||
events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
var handler = instance['event_' + name];
|
||||
if (handler) {
|
||||
owner = owner || serverNotifications;
|
||||
events.off(owner, name, handler);
|
||||
instance['event_' + name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
ItemsContainerPrototype.createdCallback = function () {
|
||||
this.classList.add('itemsContainer');
|
||||
};
|
||||
|
||||
ItemsContainerPrototype.attachedCallback = function () {
|
||||
this.addEventListener('click', onClick);
|
||||
|
||||
if (browser.touch) {
|
||||
this.addEventListener('contextmenu', disableEvent);
|
||||
} else {
|
||||
if (this.getAttribute('data-contextmenu') !== 'false') {
|
||||
this.addEventListener('contextmenu', onContextMenu);
|
||||
}
|
||||
}
|
||||
|
||||
if (layoutManager.desktop || layoutManager.mobile) {
|
||||
if (this.getAttribute('data-multiselect') !== 'false') {
|
||||
this.enableMultiSelect(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('itemsContainer-tv');
|
||||
}
|
||||
|
||||
itemShortcuts.on(this, getShortcutOptions());
|
||||
|
||||
addNotificationEvent(this, 'UserDataChanged', onUserDataChanged);
|
||||
addNotificationEvent(this, 'TimerCreated', onTimerCreated);
|
||||
addNotificationEvent(this, 'SeriesTimerCreated', onSeriesTimerCreated);
|
||||
addNotificationEvent(this, 'TimerCancelled', onTimerCancelled);
|
||||
addNotificationEvent(this, 'SeriesTimerCancelled', onSeriesTimerCancelled);
|
||||
addNotificationEvent(this, 'LibraryChanged', onLibraryChanged);
|
||||
addNotificationEvent(this, 'playbackstop', onPlaybackStopped, playbackManager);
|
||||
|
||||
if (this.getAttribute('data-dragreorder') === 'true') {
|
||||
this.enableDragReordering(true);
|
||||
}
|
||||
};
|
||||
|
||||
ItemsContainerPrototype.detachedCallback = function () {
|
||||
clearRefreshInterval(this);
|
||||
|
||||
this.enableMultiSelect(false);
|
||||
this.enableDragReordering(false);
|
||||
this.removeEventListener('click', onClick);
|
||||
this.removeEventListener('contextmenu', onContextMenu);
|
||||
this.removeEventListener('contextmenu', disableEvent);
|
||||
|
||||
itemShortcuts.off(this, getShortcutOptions());
|
||||
|
||||
removeNotificationEvent(this, 'UserDataChanged');
|
||||
removeNotificationEvent(this, 'TimerCreated');
|
||||
removeNotificationEvent(this, 'SeriesTimerCreated');
|
||||
removeNotificationEvent(this, 'TimerCancelled');
|
||||
removeNotificationEvent(this, 'SeriesTimerCancelled');
|
||||
removeNotificationEvent(this, 'LibraryChanged');
|
||||
removeNotificationEvent(this, 'playbackstop', playbackManager);
|
||||
|
||||
this.fetchData = null;
|
||||
this.getItemsHtml = null;
|
||||
this.parentContainer = null;
|
||||
};
|
||||
|
||||
ItemsContainerPrototype.pause = function () {
|
||||
clearRefreshInterval(this, true);
|
||||
this.paused = true;
|
||||
};
|
||||
|
||||
ItemsContainerPrototype.resume = function (options) {
|
||||
this.paused = false;
|
||||
|
||||
var refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
if (refreshIntervalEndTime) {
|
||||
|
||||
var remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
if (remainingMs > 0 && !this.needsRefresh) {
|
||||
resetRefreshInterval(this, remainingMs);
|
||||
} else {
|
||||
this.needsRefresh = true;
|
||||
this.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.needsRefresh || (options && options.refresh)) {
|
||||
return this.refreshItems();
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
ItemsContainerPrototype.refreshItems = function () {
|
||||
if (!this.fetchData) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
this.needsRefresh = false;
|
||||
|
||||
return this.fetchData().then(onDataFetched.bind(this));
|
||||
};
|
||||
|
||||
ItemsContainerPrototype.notifyRefreshNeeded = function (isInForeground) {
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var timeout = this.refreshTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
if (isInForeground === true) {
|
||||
this.refreshItems();
|
||||
} else {
|
||||
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
|
||||
}
|
||||
};
|
||||
|
||||
function clearRefreshInterval(itemsContainer, isPausing) {
|
||||
if (itemsContainer.refreshInterval) {
|
||||
clearInterval(itemsContainer.refreshInterval);
|
||||
itemsContainer.refreshInterval = null;
|
||||
|
||||
if (!isPausing) {
|
||||
itemsContainer.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(itemsContainer, intervalMs) {
|
||||
clearRefreshInterval(itemsContainer);
|
||||
|
||||
if (!intervalMs) {
|
||||
intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0');
|
||||
}
|
||||
|
||||
if (intervalMs) {
|
||||
itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs);
|
||||
itemsContainer.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
var items = result.Items || result;
|
||||
|
||||
var parentContainer = this.parentContainer;
|
||||
if (parentContainer) {
|
||||
if (items.length) {
|
||||
parentContainer.classList.remove('hide');
|
||||
} else {
|
||||
parentContainer.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
var activeElement = document.activeElement;
|
||||
var focusId;
|
||||
var hasActiveElement;
|
||||
|
||||
if (this.contains(activeElement)) {
|
||||
hasActiveElement = true;
|
||||
focusId = activeElement.getAttribute('data-id');
|
||||
}
|
||||
|
||||
this.innerHTML = this.getItemsHtml(items);
|
||||
|
||||
imageLoader.lazyChildren(this);
|
||||
|
||||
if (hasActiveElement) {
|
||||
setFocus(this, focusId);
|
||||
}
|
||||
|
||||
resetRefreshInterval(this);
|
||||
|
||||
if (this.afterRefresh) {
|
||||
this.afterRefresh(result);
|
||||
}
|
||||
}
|
||||
|
||||
function setFocus(itemsContainer, focusId) {
|
||||
if (focusId) {
|
||||
var newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]');
|
||||
if (newElement) {
|
||||
try {
|
||||
focusManager.focus(newElement);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
focusManager.autoFocus(itemsContainer);
|
||||
}
|
||||
|
||||
document.registerElement('emby-itemscontainer', {
|
||||
prototype: ItemsContainerPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
|
@ -1,19 +0,0 @@
|
|||
.emby-scrollbuttons {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 104px;
|
||||
min-height: 24px;
|
||||
padding-top: 1.25em;
|
||||
z-index: 1;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.emby-scrollbuttons-button > i {
|
||||
min-width: 24px;
|
||||
min-height: 24px;
|
||||
display: block;
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
define(['layoutManager', 'dom', 'css!./emby-scrollbuttons', 'registerElement', 'paper-icon-button-light'], function (layoutManager, dom) {
|
||||
'use strict';
|
||||
|
||||
var EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
EmbyScrollButtonsPrototype.createdCallback = function () {};
|
||||
|
||||
function getScrollButtonHtml(direction) {
|
||||
var html = '';
|
||||
var icon = direction === 'left' ? '' : '';
|
||||
|
||||
html += '<button type="button" is="paper-icon-button-light" data-ripple="false" data-direction="' + direction + '" class="emby-scrollbuttons-button">';
|
||||
html += '<i class="material-icons">' + icon + '</i>';
|
||||
html += '</button>';
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function getScrollPosition(parent) {
|
||||
if (parent.getScrollPosition) {
|
||||
return parent.getScrollPosition();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getScrollWidth(parent) {
|
||||
if (parent.getScrollSize) {
|
||||
return parent.getScrollSize();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function updateScrollButtons(scrollButtons, scrollSize, scrollPos, scrollWidth) {
|
||||
// hack alert add twenty for rounding errors
|
||||
if (scrollWidth <= scrollSize + 20) {
|
||||
scrollButtons.scrollButtonsLeft.classList.add('hide');
|
||||
scrollButtons.scrollButtonsRight.classList.add('hide');
|
||||
}
|
||||
|
||||
if (scrollPos > 0) {
|
||||
scrollButtons.scrollButtonsLeft.disabled = false;
|
||||
} else {
|
||||
scrollButtons.scrollButtonsLeft.disabled = true;
|
||||
}
|
||||
|
||||
var scrollPosEnd = scrollPos + scrollSize;
|
||||
if (scrollWidth > 0 && scrollPosEnd >= scrollWidth) {
|
||||
scrollButtons.scrollButtonsRight.disabled = true;
|
||||
} else {
|
||||
scrollButtons.scrollButtonsRight.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onScroll(e) {
|
||||
var scrollButtons = this;
|
||||
var scroller = this.scroller;
|
||||
|
||||
var scrollSize = getScrollSize(scroller);
|
||||
var scrollPos = getScrollPosition(scroller);
|
||||
var scrollWidth = getScrollWidth(scroller);
|
||||
|
||||
updateScrollButtons(scrollButtons, scrollSize, scrollPos, scrollWidth);
|
||||
}
|
||||
|
||||
function getStyleValue(style, name) {
|
||||
var value = style.getPropertyValue(name);
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = value.replace('px', '');
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = parseInt(value);
|
||||
if (isNaN(value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function getScrollSize(elem) {
|
||||
var scrollSize = elem.offsetWidth;
|
||||
var style = window.getComputedStyle(elem, null);
|
||||
|
||||
var paddingLeft = getStyleValue(style, 'padding-left');
|
||||
if (paddingLeft) {
|
||||
scrollSize -= paddingLeft;
|
||||
}
|
||||
|
||||
var paddingRight = getStyleValue(style, 'padding-right');
|
||||
if (paddingRight) {
|
||||
scrollSize -= paddingRight;
|
||||
}
|
||||
|
||||
var slider = elem.getScrollSlider();
|
||||
style = window.getComputedStyle(slider, null);
|
||||
|
||||
paddingLeft = getStyleValue(style, 'padding-left');
|
||||
if (paddingLeft) {
|
||||
scrollSize -= paddingLeft;
|
||||
}
|
||||
|
||||
paddingRight = getStyleValue(style, 'padding-right');
|
||||
if (paddingRight) {
|
||||
scrollSize -= paddingRight;
|
||||
}
|
||||
|
||||
return scrollSize;
|
||||
}
|
||||
|
||||
function onScrollButtonClick(e) {
|
||||
var scroller = this.parentNode.nextSibling;
|
||||
|
||||
var direction = this.getAttribute('data-direction');
|
||||
var scrollSize = getScrollSize(scroller);
|
||||
var scrollPos = getScrollPosition(scroller);
|
||||
var scrollWidth = getScrollWidth(scroller);
|
||||
|
||||
var newPos;
|
||||
if (direction === 'left') {
|
||||
newPos = Math.max(0, scrollPos - scrollSize);
|
||||
} else {
|
||||
newPos = scrollPos + scrollSize;
|
||||
}
|
||||
|
||||
scroller.scrollToPosition(newPos, false);
|
||||
}
|
||||
|
||||
EmbyScrollButtonsPrototype.attachedCallback = function () {
|
||||
var scroller = this.nextSibling;
|
||||
this.scroller = scroller;
|
||||
|
||||
var parent = this.parentNode;
|
||||
parent.classList.add('emby-scroller-container');
|
||||
|
||||
this.innerHTML = getScrollButtonHtml('left') + getScrollButtonHtml('right');
|
||||
|
||||
var buttons = this.querySelectorAll('.emby-scrollbuttons-button');
|
||||
buttons[0].addEventListener('click', onScrollButtonClick);
|
||||
buttons[1].addEventListener('click', onScrollButtonClick);
|
||||
this.scrollButtonsLeft = buttons[0];
|
||||
this.scrollButtonsRight = buttons[1];
|
||||
|
||||
var scrollHandler = onScroll.bind(this);
|
||||
this.scrollHandler = scrollHandler;
|
||||
scroller.addScrollEventListener(scrollHandler, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
|
||||
EmbyScrollButtonsPrototype.detachedCallback = function () {
|
||||
var parent = this.scroller;
|
||||
this.scroller = null;
|
||||
|
||||
var scrollHandler = this.scrollHandler;
|
||||
if (parent && scrollHandler) {
|
||||
parent.removeScrollEventListener(scrollHandler, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
this.scrollHandler = null;
|
||||
this.scrollButtonsLeft = null;
|
||||
this.scrollButtonsRight = null;
|
||||
};
|
||||
|
||||
document.registerElement('emby-scrollbuttons', {
|
||||
prototype: EmbyScrollButtonsPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
|
@ -1,27 +0,0 @@
|
|||
.emby-scroller-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.emby-scroller {
|
||||
margin-left: 3.3%;
|
||||
margin-right: 3.3%;
|
||||
}
|
||||
|
||||
/* align first card in scroller to heading */
|
||||
.itemsContainer > .card > .cardBox {
|
||||
margin-left: 0;
|
||||
margin-right: 1.2em;
|
||||
}
|
||||
|
||||
.servers > .card > .cardBox {
|
||||
margin-left: 0.6em;
|
||||
margin-right: 0.6em;
|
||||
}
|
||||
|
||||
.layout-tv .emby-scroller,
|
||||
.layout-mobile .emby-scroller {
|
||||
padding-left: 3.3%;
|
||||
padding-right: 3.3%;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
|
@ -1,209 +0,0 @@
|
|||
define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'browser', 'registerElement', 'css!./emby-scroller'], function (scroller, dom, layoutManager, inputManager, focusManager, browser) {
|
||||
'use strict';
|
||||
|
||||
var ScrollerPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
ScrollerPrototype.createdCallback = function () {
|
||||
this.classList.add('emby-scroller');
|
||||
};
|
||||
|
||||
function initCenterFocus(elem, scrollerInstance) {
|
||||
dom.addEventListener(elem, 'focus', function (e) {
|
||||
var focused = focusManager.focusableParent(e.target);
|
||||
if (focused) {
|
||||
scrollerInstance.toCenter(focused);
|
||||
}
|
||||
}, {
|
||||
capture: true,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
|
||||
ScrollerPrototype.scrollToBeginning = function () {
|
||||
if (this.scroller) {
|
||||
this.scroller.slideTo(0, true);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.toStart = function (elem, immediate) {
|
||||
if (this.scroller) {
|
||||
this.scroller.toStart(elem, immediate);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.toCenter = function (elem, immediate) {
|
||||
if (this.scroller) {
|
||||
this.scroller.toCenter(elem, immediate);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.scrollToPosition = function (pos, immediate) {
|
||||
if (this.scroller) {
|
||||
this.scroller.slideTo(pos, immediate);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.getScrollPosition = function () {
|
||||
if (this.scroller) {
|
||||
return this.scroller.getScrollPosition();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.getScrollSize = function () {
|
||||
if (this.scroller) {
|
||||
return this.scroller.getScrollSize();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.getScrollEventName = function () {
|
||||
if (this.scroller) {
|
||||
return this.scroller.getScrollEventName();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.getScrollSlider = function () {
|
||||
if (this.scroller) {
|
||||
return this.scroller.getScrollSlider();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.addScrollEventListener = function (fn, options) {
|
||||
if (this.scroller) {
|
||||
dom.addEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.removeScrollEventListener = function (fn, options) {
|
||||
if (this.scroller) {
|
||||
dom.removeEventListener(this.scroller.getScrollFrame(), this.scroller.getScrollEventName(), fn, options);
|
||||
}
|
||||
};
|
||||
|
||||
function onInputCommand(e) {
|
||||
var cmd = e.detail.command;
|
||||
if (cmd === 'end') {
|
||||
focusManager.focusLast(this, '.' + this.getAttribute('data-navcommands'));
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
} else if (cmd === 'pageup') {
|
||||
focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), -12);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
} else if (cmd === 'pagedown') {
|
||||
focusManager.moveFocus(e.target, this, '.' + this.getAttribute('data-navcommands'), 12);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
function initHeadroom(elem) {
|
||||
require(['headroom'], function (Headroom) {
|
||||
var headroom = new Headroom([], {
|
||||
scroller: elem
|
||||
});
|
||||
|
||||
headroom.add(document.querySelector('.skinHeader'));
|
||||
elem.headroom = headroom;
|
||||
});
|
||||
}
|
||||
|
||||
ScrollerPrototype.attachedCallback = function () {
|
||||
if (this.getAttribute('data-navcommands')) {
|
||||
inputManager.on(this, onInputCommand);
|
||||
}
|
||||
|
||||
var horizontal = this.getAttribute('data-horizontal') !== 'false';
|
||||
|
||||
var slider = this.querySelector('.scrollSlider');
|
||||
|
||||
if (horizontal) {
|
||||
slider.style['white-space'] = 'nowrap';
|
||||
}
|
||||
|
||||
var bindHeader = this.getAttribute('data-bindheader') === 'true';
|
||||
|
||||
var scrollFrame = this;
|
||||
var enableScrollButtons = layoutManager.desktop && horizontal && this.getAttribute('data-scrollbuttons') !== 'false';
|
||||
|
||||
var options = {
|
||||
horizontal: horizontal,
|
||||
mouseDragging: 1,
|
||||
mouseWheel: this.getAttribute('data-mousewheel') !== 'false',
|
||||
touchDragging: 1,
|
||||
slidee: slider,
|
||||
scrollBy: 200,
|
||||
speed: horizontal ? 270 : 240,
|
||||
elasticBounds: 1,
|
||||
dragHandle: 1,
|
||||
autoImmediate: true,
|
||||
skipSlideToWhenVisible: this.getAttribute('data-skipfocuswhenvisible') === 'true',
|
||||
dispatchScrollEvent: enableScrollButtons || bindHeader || this.getAttribute('data-scrollevent') === 'true',
|
||||
hideScrollbar: enableScrollButtons || this.getAttribute('data-hidescrollbar') === 'true',
|
||||
allowNativeSmoothScroll: this.getAttribute('data-allownativesmoothscroll') === 'true' && !enableScrollButtons,
|
||||
allowNativeScroll: !enableScrollButtons,
|
||||
forceHideScrollbars: enableScrollButtons,
|
||||
// In edge, with the native scroll, the content jumps around when hovering over the buttons
|
||||
requireAnimation: enableScrollButtons && browser.edge
|
||||
};
|
||||
|
||||
// If just inserted it might not have any height yet - yes this is a hack
|
||||
this.scroller = new scroller(scrollFrame, options);
|
||||
this.scroller.init();
|
||||
this.scroller.reload();
|
||||
|
||||
if (layoutManager.tv && this.getAttribute('data-centerfocus')) {
|
||||
initCenterFocus(this, this.scroller);
|
||||
}
|
||||
|
||||
if (bindHeader && layoutManager.mobile) {
|
||||
initHeadroom(this);
|
||||
}
|
||||
|
||||
if (enableScrollButtons) {
|
||||
loadScrollButtons(this);
|
||||
}
|
||||
};
|
||||
|
||||
function loadScrollButtons(scroller) {
|
||||
require(['emby-scrollbuttons'], function () {
|
||||
scroller.insertAdjacentHTML('beforebegin', '<div is="emby-scrollbuttons" class="emby-scrollbuttons padded-right"></div>');
|
||||
});
|
||||
}
|
||||
|
||||
ScrollerPrototype.pause = function () {
|
||||
var headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.pause();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.resume = function () {
|
||||
var headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.resume();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.detachedCallback = function () {
|
||||
if (this.getAttribute('data-navcommands')) {
|
||||
inputManager.off(this, onInputCommand);
|
||||
}
|
||||
|
||||
var headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.destroy();
|
||||
this.headroom = null;
|
||||
}
|
||||
|
||||
var scrollerInstance = this.scroller;
|
||||
if (scrollerInstance) {
|
||||
scrollerInstance.destroy();
|
||||
this.scroller = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-scroller', {
|
||||
prototype: ScrollerPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
|
@ -1,43 +0,0 @@
|
|||
.emby-tab-button {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
width: auto;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
flex-shrink: 0;
|
||||
margin: 0;
|
||||
padding: 1.5em 1.5em;
|
||||
position: relative;
|
||||
height: auto;
|
||||
min-width: initial;
|
||||
line-height: 1.25;
|
||||
border-radius: 0;
|
||||
overflow: hidden;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.emby-tab-button.show-focus:focus {
|
||||
/* these buttons are small so scale larger than usual */
|
||||
transform: scale(1.3) !important;
|
||||
background: 0 !important;
|
||||
}
|
||||
|
||||
.emby-tabs-slider {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.layout-mobile .emby-tabs-slider {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.tabContent:not(.is-active) {
|
||||
display: none;
|
||||
}
|
|
@ -1,341 +0,0 @@
|
|||
define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'registerElement', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser, layoutManager, focusManager) {
|
||||
'use strict';
|
||||
|
||||
var EmbyTabs = Object.create(HTMLDivElement.prototype);
|
||||
var buttonClass = 'emby-tab-button';
|
||||
var activeButtonClass = buttonClass + '-active';
|
||||
|
||||
function setActiveTabButton(tabs, newButton, oldButton, animate) {
|
||||
|
||||
newButton.classList.add(activeButtonClass);
|
||||
}
|
||||
|
||||
function getTabPanel(tabs, index) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function removeActivePanelClass(tabs, index) {
|
||||
var tabPanel = getTabPanel(tabs, index);
|
||||
if (tabPanel) {
|
||||
tabPanel.classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
function addActivePanelClass(tabs, index) {
|
||||
var tabPanel = getTabPanel(tabs, index);
|
||||
if (tabPanel) {
|
||||
tabPanel.classList.add('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
function fadeInRight(elem) {
|
||||
|
||||
var pct = browser.mobile ? '4%' : '0.5%';
|
||||
|
||||
var keyframes = [
|
||||
{ opacity: '0', transform: 'translate3d(' + pct + ', 0, 0)', offset: 0 },
|
||||
{ opacity: '1', transform: 'none', offset: 1 }];
|
||||
|
||||
elem.animate(keyframes, {
|
||||
duration: 160,
|
||||
iterations: 1,
|
||||
easing: 'ease-out'
|
||||
});
|
||||
}
|
||||
|
||||
function triggerBeforeTabChange(tabs, index, previousIndex) {
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent("beforetabchange", {
|
||||
detail: {
|
||||
selectedTabIndex: index,
|
||||
previousIndex: previousIndex
|
||||
}
|
||||
}));
|
||||
if (previousIndex != null && previousIndex !== index) {
|
||||
removeActivePanelClass(tabs, previousIndex);
|
||||
}
|
||||
|
||||
var newPanel = getTabPanel(tabs, index);
|
||||
|
||||
if (newPanel) {
|
||||
// animate new panel ?
|
||||
if (newPanel.animate) {
|
||||
fadeInRight(newPanel);
|
||||
}
|
||||
|
||||
newPanel.classList.add('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
|
||||
var tabs = this;
|
||||
|
||||
var current = tabs.querySelector('.' + activeButtonClass);
|
||||
var tabButton = dom.parentWithClass(e.target, buttonClass);
|
||||
|
||||
if (tabButton && tabButton !== current) {
|
||||
|
||||
if (current) {
|
||||
current.classList.remove(activeButtonClass);
|
||||
}
|
||||
|
||||
var previousIndex = current ? parseInt(current.getAttribute('data-index')) : null;
|
||||
|
||||
setActiveTabButton(tabs, tabButton, current, true);
|
||||
|
||||
var index = parseInt(tabButton.getAttribute('data-index'));
|
||||
|
||||
triggerBeforeTabChange(tabs, index, previousIndex);
|
||||
|
||||
// If toCenter is called syncronously within the click event, it sometimes ends up canceling it
|
||||
setTimeout(function () {
|
||||
|
||||
tabs.selectedTabIndex = index;
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
||||
detail: {
|
||||
selectedTabIndex: index,
|
||||
previousIndex: previousIndex
|
||||
}
|
||||
}));
|
||||
}, 120);
|
||||
|
||||
if (tabs.scroller) {
|
||||
tabs.scroller.toCenter(tabButton, false);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function initScroller(tabs) {
|
||||
|
||||
if (tabs.scroller) {
|
||||
return;
|
||||
}
|
||||
|
||||
var contentScrollSlider = tabs.querySelector('.emby-tabs-slider');
|
||||
if (contentScrollSlider) {
|
||||
tabs.scroller = new scroller(tabs, {
|
||||
horizontal: 1,
|
||||
itemNav: 0,
|
||||
mouseDragging: 1,
|
||||
touchDragging: 1,
|
||||
slidee: contentScrollSlider,
|
||||
smart: true,
|
||||
releaseSwing: true,
|
||||
scrollBy: 200,
|
||||
speed: 120,
|
||||
elasticBounds: 1,
|
||||
dragHandle: 1,
|
||||
dynamicHandle: 1,
|
||||
clickBar: 1,
|
||||
hiddenScroll: true,
|
||||
|
||||
// In safari the transform is causing the headers to occasionally disappear or flicker
|
||||
requireAnimation: !browser.safari,
|
||||
allowNativeSmoothScroll: true
|
||||
});
|
||||
tabs.scroller.init();
|
||||
} else {
|
||||
tabs.classList.add('scrollX');
|
||||
tabs.classList.add('hiddenScrollX');
|
||||
tabs.classList.add('smoothScrollX');
|
||||
}
|
||||
}
|
||||
|
||||
EmbyTabs.createdCallback = function () {
|
||||
|
||||
if (this.classList.contains('emby-tabs')) {
|
||||
return;
|
||||
}
|
||||
this.classList.add('emby-tabs');
|
||||
this.classList.add('focusable');
|
||||
|
||||
dom.addEventListener(this, 'click', onClick, {
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
|
||||
EmbyTabs.focus = function () {
|
||||
|
||||
var selected = this.querySelector('.' + activeButtonClass);
|
||||
|
||||
if (selected) {
|
||||
focusManager.focus(selected);
|
||||
} else {
|
||||
focusManager.autoFocus(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.refresh = function () {
|
||||
|
||||
if (this.scroller) {
|
||||
this.scroller.reload();
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.attachedCallback = function () {
|
||||
|
||||
initScroller(this);
|
||||
|
||||
var current = this.querySelector('.' + activeButtonClass);
|
||||
var currentIndex = current ? parseInt(current.getAttribute('data-index')) : parseInt(this.getAttribute('data-index') || '0');
|
||||
|
||||
if (currentIndex !== -1) {
|
||||
|
||||
this.selectedTabIndex = currentIndex;
|
||||
|
||||
var tabButtons = this.querySelectorAll('.' + buttonClass);
|
||||
|
||||
var newTabButton = tabButtons[currentIndex];
|
||||
|
||||
if (newTabButton) {
|
||||
setActiveTabButton(this, newTabButton, current, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.readyFired) {
|
||||
this.readyFired = true;
|
||||
this.dispatchEvent(new CustomEvent("ready", {}));
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.detachedCallback = function () {
|
||||
|
||||
if (this.scroller) {
|
||||
this.scroller.destroy();
|
||||
this.scroller = null;
|
||||
}
|
||||
|
||||
dom.removeEventListener(this, 'click', onClick, {
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
|
||||
function getSelectedTabButton(elem) {
|
||||
|
||||
return elem.querySelector('.' + activeButtonClass);
|
||||
}
|
||||
|
||||
EmbyTabs.selectedIndex = function (selected, triggerEvent) {
|
||||
|
||||
var tabs = this;
|
||||
|
||||
if (selected == null) {
|
||||
|
||||
return tabs.selectedTabIndex || 0;
|
||||
}
|
||||
|
||||
var current = tabs.selectedIndex();
|
||||
|
||||
tabs.selectedTabIndex = selected;
|
||||
|
||||
var tabButtons = tabs.querySelectorAll('.' + buttonClass);
|
||||
|
||||
if (current === selected || triggerEvent === false) {
|
||||
|
||||
triggerBeforeTabChange(tabs, selected, current);
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
||||
detail: {
|
||||
selectedTabIndex: selected
|
||||
}
|
||||
}));
|
||||
|
||||
var currentTabButton = tabButtons[current];
|
||||
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, false);
|
||||
|
||||
if (current !== selected && currentTabButton) {
|
||||
currentTabButton.classList.remove(activeButtonClass);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
onClick.call(tabs, {
|
||||
target: tabButtons[selected]
|
||||
});
|
||||
//tabButtons[selected].click();
|
||||
}
|
||||
};
|
||||
|
||||
function getSibling(elem, method) {
|
||||
|
||||
var sibling = elem[method];
|
||||
|
||||
while (sibling) {
|
||||
if (sibling.classList.contains(buttonClass)) {
|
||||
|
||||
if (!sibling.classList.contains('hide')) {
|
||||
return sibling;
|
||||
}
|
||||
}
|
||||
|
||||
sibling = sibling[method];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
EmbyTabs.selectNext = function () {
|
||||
|
||||
var current = getSelectedTabButton(this);
|
||||
|
||||
var sibling = getSibling(current, 'nextSibling');
|
||||
|
||||
if (sibling) {
|
||||
onClick.call(this, {
|
||||
target: sibling
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.selectPrevious = function () {
|
||||
|
||||
var current = getSelectedTabButton(this);
|
||||
|
||||
var sibling = getSibling(current, 'previousSibling');
|
||||
|
||||
if (sibling) {
|
||||
onClick.call(this, {
|
||||
target: sibling
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.triggerBeforeTabChange = function (selected) {
|
||||
|
||||
var tabs = this;
|
||||
|
||||
triggerBeforeTabChange(tabs, tabs.selectedIndex());
|
||||
};
|
||||
|
||||
EmbyTabs.triggerTabChange = function (selected) {
|
||||
|
||||
var tabs = this;
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
||||
detail: {
|
||||
selectedTabIndex: tabs.selectedIndex()
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
EmbyTabs.setTabEnabled = function (index, enabled) {
|
||||
|
||||
var tabs = this;
|
||||
var btn = this.querySelector('.emby-tab-button[data-index="' + index + '"]');
|
||||
|
||||
if (enabled) {
|
||||
btn.classList.remove('hide');
|
||||
} else {
|
||||
btn.classList.remove('add');
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-tabs', {
|
||||
prototype: EmbyTabs,
|
||||
extends: 'div'
|
||||
});
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'registerElement'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) {
|
||||
define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', 'scrollHelper', 'serverNotifications', 'loading', 'datetime', 'focusManager', 'playbackManager', 'userSettings', 'imageLoader', 'events', 'layoutManager', 'itemShortcuts', 'dom', 'css!./guide.css', 'programStyles', 'material-icons', 'scrollStyles', 'emby-programcell', 'emby-button', 'paper-icon-button-light', 'emby-tabs', 'emby-scroller', 'flexStyles', 'registerElement'], function (require, inputManager, browser, globalize, connectionManager, scrollHelper, serverNotifications, loading, datetime, focusManager, playbackManager, userSettings, imageLoader, events, layoutManager, itemShortcuts, dom) {
|
||||
'use strict';
|
||||
|
||||
function showViewSettings(instance) {
|
||||
|
@ -1252,18 +1252,5 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager',
|
|||
});
|
||||
}
|
||||
|
||||
var ProgramCellPrototype = Object.create(HTMLButtonElement.prototype);
|
||||
|
||||
ProgramCellPrototype.detachedCallback = function () {
|
||||
this.posLeft = null;
|
||||
this.posWidth = null;
|
||||
this.guideProgramName = null;
|
||||
};
|
||||
|
||||
document.registerElement('emby-programcell', {
|
||||
prototype: ProgramCellPrototype,
|
||||
extends: 'button'
|
||||
});
|
||||
|
||||
return Guide;
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['datetime', 'itemHelper', 'css!./indicators.css', 'material-icons'], function (datetime, itemHelper) {
|
||||
define(['datetime', 'itemHelper', 'emby-progressbar', 'css!./indicators.css', 'material-icons'], function (datetime, itemHelper) {
|
||||
'use strict';
|
||||
|
||||
function enableProgressIndicator(item) {
|
||||
|
@ -183,45 +183,6 @@ define(['datetime', 'itemHelper', 'css!./indicators.css', 'material-icons'], fun
|
|||
return '';
|
||||
}
|
||||
|
||||
var ProgressBarPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
function onAutoTimeProgress() {
|
||||
var start = parseInt(this.getAttribute('data-starttime'));
|
||||
var end = parseInt(this.getAttribute('data-endtime'));
|
||||
|
||||
var now = new Date().getTime();
|
||||
var total = end - start;
|
||||
var pct = 100 * ((now - start) / total);
|
||||
|
||||
pct = Math.min(100, pct);
|
||||
pct = Math.max(0, pct);
|
||||
|
||||
var itemProgressBarForeground = this.querySelector('.itemProgressBarForeground');
|
||||
itemProgressBarForeground.style.width = pct + '%';
|
||||
}
|
||||
|
||||
ProgressBarPrototype.attachedCallback = function () {
|
||||
if (this.timeInterval) {
|
||||
clearInterval(this.timeInterval);
|
||||
}
|
||||
|
||||
if (this.getAttribute('data-automode') === 'time') {
|
||||
this.timeInterval = setInterval(onAutoTimeProgress.bind(this), 60000);
|
||||
}
|
||||
};
|
||||
|
||||
ProgressBarPrototype.detachedCallback = function () {
|
||||
if (this.timeInterval) {
|
||||
clearInterval(this.timeInterval);
|
||||
this.timeInterval = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-progressbar', {
|
||||
prototype: ProgressBarPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
return {
|
||||
getProgressHtml: getProgressHtml,
|
||||
getProgressBarHtml: getProgressBarHtml,
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) {
|
||||
'use strict';
|
||||
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
var localHandler = handler.bind(instance);
|
||||
events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name) {
|
||||
var handler = instance[name];
|
||||
if (handler) {
|
||||
events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
|
||||
var button = this;
|
||||
var id = button.getAttribute('data-id');
|
||||
var serverId = button.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
if (!button.classList.contains('playstatebutton-played')) {
|
||||
apiClient.markPlayed(apiClient.getCurrentUserId(), id, new Date());
|
||||
setState(button, true);
|
||||
} else {
|
||||
apiClient.markUnplayed(apiClient.getCurrentUserId(), id, new Date());
|
||||
setState(button, false);
|
||||
}
|
||||
}
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
var button = this;
|
||||
if (userData.ItemId === button.getAttribute('data-id')) {
|
||||
setState(button, userData.Played);
|
||||
}
|
||||
}
|
||||
|
||||
function setState(button, played, updateAttribute) {
|
||||
var icon = button.iconElement;
|
||||
if (!icon) {
|
||||
button.iconElement = button.querySelector('i');
|
||||
icon = button.iconElement;
|
||||
}
|
||||
|
||||
if (played) {
|
||||
button.classList.add('playstatebutton-played');
|
||||
if (icon) {
|
||||
icon.classList.add('playstatebutton-icon-played');
|
||||
icon.classList.remove('playstatebutton-icon-unplayed');
|
||||
}
|
||||
} else {
|
||||
button.classList.remove('playstatebutton-played');
|
||||
if (icon) {
|
||||
icon.classList.remove('playstatebutton-icon-played');
|
||||
icon.classList.add('playstatebutton-icon-unplayed');
|
||||
}
|
||||
}
|
||||
|
||||
if (updateAttribute !== false) {
|
||||
button.setAttribute('data-played', played);
|
||||
}
|
||||
}
|
||||
|
||||
function setTitle(button, itemType) {
|
||||
|
||||
if (itemType !== 'AudioBook' && itemType !== 'AudioPodcast') {
|
||||
button.title = globalize.translate('Watched');
|
||||
} else {
|
||||
button.title = globalize.translate('Played');
|
||||
}
|
||||
|
||||
var text = button.querySelector('.button-text');
|
||||
if (text) {
|
||||
text.innerHTML = button.title;
|
||||
}
|
||||
}
|
||||
|
||||
function clearEvents(button) {
|
||||
|
||||
button.removeEventListener('click', onClick);
|
||||
removeNotificationEvent(button, 'UserDataChanged');
|
||||
}
|
||||
|
||||
function bindEvents(button) {
|
||||
|
||||
clearEvents(button);
|
||||
|
||||
button.addEventListener('click', onClick);
|
||||
addNotificationEvent(button, 'UserDataChanged', onUserDataChanged);
|
||||
}
|
||||
|
||||
var EmbyPlaystateButtonPrototype = Object.create(EmbyButtonPrototype);
|
||||
|
||||
EmbyPlaystateButtonPrototype.createdCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.createdCallback) {
|
||||
EmbyButtonPrototype.createdCallback.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyPlaystateButtonPrototype.attachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.attachedCallback) {
|
||||
EmbyButtonPrototype.attachedCallback.call(this);
|
||||
}
|
||||
|
||||
var itemId = this.getAttribute('data-id');
|
||||
var serverId = this.getAttribute('data-serverid');
|
||||
if (itemId && serverId) {
|
||||
|
||||
setState(this, this.getAttribute('data-played') === 'true', false);
|
||||
bindEvents(this);
|
||||
setTitle(this, this.getAttribute('data-type'));
|
||||
}
|
||||
};
|
||||
|
||||
EmbyPlaystateButtonPrototype.detachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.detachedCallback) {
|
||||
EmbyButtonPrototype.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
clearEvents(this);
|
||||
this.iconElement = null;
|
||||
};
|
||||
|
||||
EmbyPlaystateButtonPrototype.setItem = function (item) {
|
||||
|
||||
if (item) {
|
||||
|
||||
this.setAttribute('data-id', item.Id);
|
||||
this.setAttribute('data-serverid', item.ServerId);
|
||||
|
||||
var played = item.UserData && item.UserData.Played;
|
||||
setState(this, played);
|
||||
bindEvents(this);
|
||||
|
||||
setTitle(this, item.Type);
|
||||
|
||||
} else {
|
||||
|
||||
this.removeAttribute('data-id');
|
||||
this.removeAttribute('data-serverid');
|
||||
this.removeAttribute('data-played');
|
||||
clearEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-playstatebutton', {
|
||||
prototype: EmbyPlaystateButtonPrototype,
|
||||
extends: 'button'
|
||||
});
|
||||
});
|
|
@ -1,202 +0,0 @@
|
|||
define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby-button'], function (connectionManager, serverNotifications, events, globalize, EmbyButtonPrototype) {
|
||||
'use strict';
|
||||
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
|
||||
var localHandler = handler.bind(instance);
|
||||
events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name) {
|
||||
|
||||
var handler = instance[name];
|
||||
if (handler) {
|
||||
events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function showPicker(button, apiClient, itemId, likes, isFavorite) {
|
||||
|
||||
return apiClient.updateFavoriteStatus(apiClient.getCurrentUserId(), itemId, !isFavorite);
|
||||
}
|
||||
|
||||
function onClick(e) {
|
||||
|
||||
var button = this;
|
||||
var id = button.getAttribute('data-id');
|
||||
var serverId = button.getAttribute('data-serverid');
|
||||
var apiClient = connectionManager.getApiClient(serverId);
|
||||
|
||||
var likes = this.getAttribute('data-likes');
|
||||
var isFavorite = this.getAttribute('data-isfavorite') === 'true';
|
||||
if (likes === 'true') {
|
||||
likes = true;
|
||||
} else if (likes === 'false') {
|
||||
likes = false;
|
||||
} else {
|
||||
likes = null;
|
||||
}
|
||||
|
||||
showPicker(button, apiClient, id, likes, isFavorite).then(function (userData) {
|
||||
|
||||
setState(button, userData.Likes, userData.IsFavorite);
|
||||
});
|
||||
}
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
|
||||
var button = this;
|
||||
|
||||
if (userData.ItemId === button.getAttribute('data-id')) {
|
||||
|
||||
setState(button, userData.Likes, userData.IsFavorite);
|
||||
}
|
||||
}
|
||||
|
||||
function setState(button, likes, isFavorite, updateAttribute) {
|
||||
|
||||
var icon = button.querySelector('i');
|
||||
|
||||
if (isFavorite) {
|
||||
|
||||
if (icon) {
|
||||
icon.innerHTML = 'favorite';
|
||||
icon.classList.add('ratingbutton-icon-withrating');
|
||||
}
|
||||
|
||||
button.classList.add('ratingbutton-withrating');
|
||||
|
||||
} else if (likes) {
|
||||
|
||||
if (icon) {
|
||||
icon.innerHTML = 'favorite';
|
||||
icon.classList.remove('ratingbutton-icon-withrating');
|
||||
//icon.innerHTML = 'thumb_up';
|
||||
}
|
||||
button.classList.remove('ratingbutton-withrating');
|
||||
|
||||
} else if (likes === false) {
|
||||
|
||||
if (icon) {
|
||||
icon.innerHTML = 'favorite';
|
||||
icon.classList.remove('ratingbutton-icon-withrating');
|
||||
//icon.innerHTML = 'thumb_down';
|
||||
}
|
||||
button.classList.remove('ratingbutton-withrating');
|
||||
|
||||
} else {
|
||||
|
||||
if (icon) {
|
||||
icon.innerHTML = 'favorite';
|
||||
icon.classList.remove('ratingbutton-icon-withrating');
|
||||
//icon.innerHTML = 'thumbs_up_down';
|
||||
}
|
||||
button.classList.remove('ratingbutton-withrating');
|
||||
}
|
||||
|
||||
if (updateAttribute !== false) {
|
||||
button.setAttribute('data-isfavorite', isFavorite);
|
||||
|
||||
button.setAttribute('data-likes', (likes === null ? '' : likes));
|
||||
}
|
||||
}
|
||||
|
||||
function setTitle(button) {
|
||||
button.title = globalize.translate('Favorite');
|
||||
|
||||
var text = button.querySelector('.button-text');
|
||||
if (text) {
|
||||
text.innerHTML = button.title;
|
||||
}
|
||||
}
|
||||
|
||||
function clearEvents(button) {
|
||||
|
||||
button.removeEventListener('click', onClick);
|
||||
removeNotificationEvent(button, 'UserDataChanged');
|
||||
}
|
||||
|
||||
function bindEvents(button) {
|
||||
|
||||
clearEvents(button);
|
||||
|
||||
button.addEventListener('click', onClick);
|
||||
addNotificationEvent(button, 'UserDataChanged', onUserDataChanged);
|
||||
}
|
||||
|
||||
var EmbyRatingButtonPrototype = Object.create(EmbyButtonPrototype);
|
||||
|
||||
EmbyRatingButtonPrototype.createdCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.createdCallback) {
|
||||
EmbyButtonPrototype.createdCallback.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyRatingButtonPrototype.attachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.attachedCallback) {
|
||||
EmbyButtonPrototype.attachedCallback.call(this);
|
||||
}
|
||||
|
||||
var itemId = this.getAttribute('data-id');
|
||||
var serverId = this.getAttribute('data-serverid');
|
||||
if (itemId && serverId) {
|
||||
|
||||
var likes = this.getAttribute('data-likes');
|
||||
var isFavorite = this.getAttribute('data-isfavorite') === 'true';
|
||||
if (likes === 'true') {
|
||||
likes = true;
|
||||
} else if (likes === 'false') {
|
||||
likes = false;
|
||||
} else {
|
||||
likes = null;
|
||||
}
|
||||
|
||||
setState(this, likes, isFavorite, false);
|
||||
bindEvents(this);
|
||||
}
|
||||
|
||||
setTitle(this);
|
||||
};
|
||||
|
||||
EmbyRatingButtonPrototype.detachedCallback = function () {
|
||||
|
||||
// base method
|
||||
if (EmbyButtonPrototype.detachedCallback) {
|
||||
EmbyButtonPrototype.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
clearEvents(this);
|
||||
};
|
||||
|
||||
EmbyRatingButtonPrototype.setItem = function (item) {
|
||||
|
||||
if (item) {
|
||||
|
||||
this.setAttribute('data-id', item.Id);
|
||||
this.setAttribute('data-serverid', item.ServerId);
|
||||
|
||||
var userData = item.UserData || {};
|
||||
setState(this, userData.Likes, userData.IsFavorite);
|
||||
bindEvents(this);
|
||||
|
||||
} else {
|
||||
|
||||
this.removeAttribute('data-id');
|
||||
this.removeAttribute('data-serverid');
|
||||
this.removeAttribute('data-likes');
|
||||
this.removeAttribute('data-isfavorite');
|
||||
clearEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-ratingbutton', {
|
||||
prototype: EmbyRatingButtonPrototype,
|
||||
extends: 'button'
|
||||
});
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue