mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Fix indentation issues
This commit is contained in:
parent
52c8cffc82
commit
f2726653ae
120 changed files with 30271 additions and 30631 deletions
|
@ -3,109 +3,106 @@ import dom from '../../scripts/dom';
|
|||
import './emby-checkbox.scss';
|
||||
import 'webcomponents.js/webcomponents-lite';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
const EmbyCheckboxPrototype = Object.create(HTMLInputElement.prototype);
|
||||
function onKeyDown(e) {
|
||||
// Don't submit form on enter
|
||||
// Real (non-emulator) Tizen does nothing on Space
|
||||
if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
|
||||
e.preventDefault();
|
||||
|
||||
function onKeyDown(e) {
|
||||
// Don't submit form on enter
|
||||
// Real (non-emulator) Tizen does nothing on Space
|
||||
if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
|
||||
e.preventDefault();
|
||||
this.checked = !this.checked;
|
||||
|
||||
this.checked = !this.checked;
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
const enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s ? true : false;
|
||||
|
||||
function forceRefresh(loading) {
|
||||
const elem = this.parentNode;
|
||||
|
||||
elem.style.webkitAnimationName = 'repaintChrome';
|
||||
elem.style.webkitAnimationDelay = (loading === true ? '500ms' : '');
|
||||
elem.style.webkitAnimationDuration = '10ms';
|
||||
elem.style.webkitAnimationIterationCount = '1';
|
||||
|
||||
setTimeout(function () {
|
||||
elem.style.webkitAnimationName = '';
|
||||
}, (loading === true ? 520 : 20));
|
||||
}
|
||||
|
||||
EmbyCheckboxPrototype.attachedCallback = function () {
|
||||
if (this.getAttribute('data-embycheckbox') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
const enableRefreshHack = browser.tizen || browser.orsay || browser.operaTv || browser.web0s ? true : false;
|
||||
this.setAttribute('data-embycheckbox', 'true');
|
||||
|
||||
function forceRefresh(loading) {
|
||||
const elem = this.parentNode;
|
||||
this.classList.add('emby-checkbox');
|
||||
|
||||
elem.style.webkitAnimationName = 'repaintChrome';
|
||||
elem.style.webkitAnimationDelay = (loading === true ? '500ms' : '');
|
||||
elem.style.webkitAnimationDuration = '10ms';
|
||||
elem.style.webkitAnimationIterationCount = '1';
|
||||
const labelElement = this.parentNode;
|
||||
labelElement.classList.add('emby-checkbox-label');
|
||||
|
||||
setTimeout(function () {
|
||||
elem.style.webkitAnimationName = '';
|
||||
}, (loading === true ? 520 : 20));
|
||||
const labelTextElement = labelElement.querySelector('span');
|
||||
|
||||
let outlineClass = 'checkboxOutline';
|
||||
|
||||
const customClass = this.getAttribute('data-outlineclass');
|
||||
if (customClass) {
|
||||
outlineClass += ' ' + customClass;
|
||||
}
|
||||
|
||||
EmbyCheckboxPrototype.attachedCallback = function () {
|
||||
if (this.getAttribute('data-embycheckbox') === 'true') {
|
||||
return;
|
||||
}
|
||||
const checkedIcon = this.getAttribute('data-checkedicon') || 'check';
|
||||
const uncheckedIcon = this.getAttribute('data-uncheckedicon') || '';
|
||||
const checkHtml = '<span class="material-icons checkboxIcon checkboxIcon-checked ' + checkedIcon + '" aria-hidden="true"></span>';
|
||||
const uncheckedHtml = '<span class="material-icons checkboxIcon checkboxIcon-unchecked ' + uncheckedIcon + '" aria-hidden="true"></span>';
|
||||
labelElement.insertAdjacentHTML('beforeend', '<span class="' + outlineClass + '">' + checkHtml + uncheckedHtml + '</span>');
|
||||
|
||||
this.setAttribute('data-embycheckbox', 'true');
|
||||
labelTextElement.classList.add('checkboxLabel');
|
||||
|
||||
this.classList.add('emby-checkbox');
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
|
||||
const labelElement = this.parentNode;
|
||||
labelElement.classList.add('emby-checkbox-label');
|
||||
|
||||
const labelTextElement = labelElement.querySelector('span');
|
||||
|
||||
let outlineClass = 'checkboxOutline';
|
||||
|
||||
const customClass = this.getAttribute('data-outlineclass');
|
||||
if (customClass) {
|
||||
outlineClass += ' ' + customClass;
|
||||
}
|
||||
|
||||
const checkedIcon = this.getAttribute('data-checkedicon') || 'check';
|
||||
const uncheckedIcon = this.getAttribute('data-uncheckedicon') || '';
|
||||
const checkHtml = '<span class="material-icons checkboxIcon checkboxIcon-checked ' + checkedIcon + '" aria-hidden="true"></span>';
|
||||
const uncheckedHtml = '<span class="material-icons checkboxIcon checkboxIcon-unchecked ' + uncheckedIcon + '" aria-hidden="true"></span>';
|
||||
labelElement.insertAdjacentHTML('beforeend', '<span class="' + outlineClass + '">' + checkHtml + uncheckedHtml + '</span>');
|
||||
|
||||
labelTextElement.classList.add('checkboxLabel');
|
||||
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
|
||||
if (enableRefreshHack) {
|
||||
forceRefresh.call(this, true);
|
||||
dom.addEventListener(this, 'click', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'blur', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'focus', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'change', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
EmbyCheckboxPrototype.detachedCallback = function () {
|
||||
this.removeEventListener('keydown', onKeyDown);
|
||||
|
||||
dom.removeEventListener(this, 'click', forceRefresh, {
|
||||
if (enableRefreshHack) {
|
||||
forceRefresh.call(this, true);
|
||||
dom.addEventListener(this, 'click', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'blur', forceRefresh, {
|
||||
dom.addEventListener(this, 'blur', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'focus', forceRefresh, {
|
||||
dom.addEventListener(this, 'focus', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'change', forceRefresh, {
|
||||
dom.addEventListener(this, 'change', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-checkbox', {
|
||||
prototype: EmbyCheckboxPrototype,
|
||||
extends: 'input'
|
||||
EmbyCheckboxPrototype.detachedCallback = function () {
|
||||
this.removeEventListener('keydown', onKeyDown);
|
||||
|
||||
dom.removeEventListener(this, 'click', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'blur', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'focus', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
dom.removeEventListener(this, 'change', forceRefresh, {
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
|
||||
document.registerElement('emby-checkbox', {
|
||||
prototype: EmbyCheckboxPrototype,
|
||||
extends: 'input'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -2,101 +2,98 @@ import './emby-collapse.scss';
|
|||
import 'webcomponents.js/webcomponents-lite';
|
||||
import '../emby-button/emby-button';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const EmbyButtonPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
const EmbyButtonPrototype = Object.create(HTMLDivElement.prototype);
|
||||
function slideDownToShow(button, elem) {
|
||||
requestAnimationFrame(() => {
|
||||
elem.classList.remove('hide');
|
||||
elem.classList.add('expanded');
|
||||
elem.style.height = 'auto';
|
||||
const height = elem.offsetHeight + 'px';
|
||||
elem.style.height = '0';
|
||||
// trigger reflow
|
||||
// TODO: Find a better way to do this
|
||||
const newHeight = elem.offsetHeight; /* eslint-disable-line no-unused-vars */
|
||||
elem.style.height = height;
|
||||
|
||||
function slideDownToShow(button, elem) {
|
||||
requestAnimationFrame(() => {
|
||||
elem.classList.remove('hide');
|
||||
elem.classList.add('expanded');
|
||||
setTimeout(function () {
|
||||
if (elem.classList.contains('expanded')) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
elem.style.height = 'auto';
|
||||
const height = elem.offsetHeight + 'px';
|
||||
elem.style.height = '0';
|
||||
// trigger reflow
|
||||
// TODO: Find a better way to do this
|
||||
const newHeight = elem.offsetHeight; /* eslint-disable-line no-unused-vars */
|
||||
elem.style.height = height;
|
||||
}, 300);
|
||||
|
||||
setTimeout(function () {
|
||||
if (elem.classList.contains('expanded')) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
elem.style.height = 'auto';
|
||||
}, 300);
|
||||
|
||||
const icon = button.querySelector('.material-icons');
|
||||
icon.classList.add('emby-collapse-expandIconExpanded');
|
||||
});
|
||||
}
|
||||
|
||||
function slideUpToHide(button, elem) {
|
||||
requestAnimationFrame(() => {
|
||||
elem.style.height = elem.offsetHeight + 'px';
|
||||
// trigger reflow
|
||||
// TODO: Find a better way to do this
|
||||
const newHeight = elem.offsetHeight; /* eslint-disable-line no-unused-vars */
|
||||
elem.classList.remove('expanded');
|
||||
elem.style.height = '0';
|
||||
|
||||
setTimeout(function () {
|
||||
if (elem.classList.contains('expanded')) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
}, 300);
|
||||
|
||||
const icon = button.querySelector('.material-icons');
|
||||
icon.classList.remove('emby-collapse-expandIconExpanded');
|
||||
});
|
||||
}
|
||||
|
||||
function onButtonClick() {
|
||||
const button = this;
|
||||
const collapseContent = button.parentNode.querySelector('.collapseContent');
|
||||
|
||||
if (collapseContent.expanded) {
|
||||
collapseContent.expanded = false;
|
||||
slideUpToHide(button, collapseContent);
|
||||
} else {
|
||||
collapseContent.expanded = true;
|
||||
slideDownToShow(button, collapseContent);
|
||||
}
|
||||
}
|
||||
|
||||
EmbyButtonPrototype.attachedCallback = function () {
|
||||
if (this.classList.contains('emby-collapse')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classList.add('emby-collapse');
|
||||
|
||||
const collapseContent = this.querySelector('.collapseContent');
|
||||
if (collapseContent) {
|
||||
collapseContent.classList.add('hide');
|
||||
}
|
||||
|
||||
const title = this.getAttribute('title');
|
||||
|
||||
const html = '<button is="emby-button" type="button" on-click="toggleExpand" id="expandButton" class="emby-collapsible-button iconRight"><h3 class="emby-collapsible-title" title="' + title + '">' + title + '</h3><span class="material-icons emby-collapse-expandIcon expand_more" aria-hidden="true"></span></button>';
|
||||
|
||||
this.insertAdjacentHTML('afterbegin', html);
|
||||
|
||||
const button = this.querySelector('.emby-collapsible-button');
|
||||
|
||||
button.addEventListener('click', onButtonClick);
|
||||
|
||||
if (this.getAttribute('data-expanded') === 'true') {
|
||||
onButtonClick.call(button);
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-collapse', {
|
||||
prototype: EmbyButtonPrototype,
|
||||
extends: 'div'
|
||||
const icon = button.querySelector('.material-icons');
|
||||
icon.classList.add('emby-collapse-expandIconExpanded');
|
||||
});
|
||||
}
|
||||
|
||||
function slideUpToHide(button, elem) {
|
||||
requestAnimationFrame(() => {
|
||||
elem.style.height = elem.offsetHeight + 'px';
|
||||
// trigger reflow
|
||||
// TODO: Find a better way to do this
|
||||
const newHeight = elem.offsetHeight; /* eslint-disable-line no-unused-vars */
|
||||
elem.classList.remove('expanded');
|
||||
elem.style.height = '0';
|
||||
|
||||
setTimeout(function () {
|
||||
if (elem.classList.contains('expanded')) {
|
||||
elem.classList.remove('hide');
|
||||
} else {
|
||||
elem.classList.add('hide');
|
||||
}
|
||||
}, 300);
|
||||
|
||||
const icon = button.querySelector('.material-icons');
|
||||
icon.classList.remove('emby-collapse-expandIconExpanded');
|
||||
});
|
||||
}
|
||||
|
||||
function onButtonClick() {
|
||||
const button = this;
|
||||
const collapseContent = button.parentNode.querySelector('.collapseContent');
|
||||
|
||||
if (collapseContent.expanded) {
|
||||
collapseContent.expanded = false;
|
||||
slideUpToHide(button, collapseContent);
|
||||
} else {
|
||||
collapseContent.expanded = true;
|
||||
slideDownToShow(button, collapseContent);
|
||||
}
|
||||
}
|
||||
|
||||
EmbyButtonPrototype.attachedCallback = function () {
|
||||
if (this.classList.contains('emby-collapse')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classList.add('emby-collapse');
|
||||
|
||||
const collapseContent = this.querySelector('.collapseContent');
|
||||
if (collapseContent) {
|
||||
collapseContent.classList.add('hide');
|
||||
}
|
||||
|
||||
const title = this.getAttribute('title');
|
||||
|
||||
const html = '<button is="emby-button" type="button" on-click="toggleExpand" id="expandButton" class="emby-collapsible-button iconRight"><h3 class="emby-collapsible-title" title="' + title + '">' + title + '</h3><span class="material-icons emby-collapse-expandIcon expand_more" aria-hidden="true"></span></button>';
|
||||
|
||||
this.insertAdjacentHTML('afterbegin', html);
|
||||
|
||||
const button = this.querySelector('.emby-collapsible-button');
|
||||
|
||||
button.addEventListener('click', onButtonClick);
|
||||
|
||||
if (this.getAttribute('data-expanded') === 'true') {
|
||||
onButtonClick.call(button);
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-collapse', {
|
||||
prototype: EmbyButtonPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -3,119 +3,116 @@ import dom from '../../scripts/dom';
|
|||
import './emby-input.scss';
|
||||
import 'webcomponents.js/webcomponents-lite';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const EmbyInputPrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
const EmbyInputPrototype = Object.create(HTMLInputElement.prototype);
|
||||
let inputId = 0;
|
||||
let supportsFloatingLabel = false;
|
||||
|
||||
let inputId = 0;
|
||||
let supportsFloatingLabel = false;
|
||||
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
|
||||
|
||||
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
|
||||
// descriptor returning null in webos
|
||||
if (descriptor && descriptor.configurable) {
|
||||
const baseSetMethod = descriptor.set;
|
||||
descriptor.set = function (value) {
|
||||
baseSetMethod.call(this, value);
|
||||
|
||||
// descriptor returning null in webos
|
||||
if (descriptor && descriptor.configurable) {
|
||||
const baseSetMethod = descriptor.set;
|
||||
descriptor.set = function (value) {
|
||||
baseSetMethod.call(this, value);
|
||||
this.dispatchEvent(new CustomEvent('valueset', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
};
|
||||
|
||||
this.dispatchEvent(new CustomEvent('valueset', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
};
|
||||
Object.defineProperty(HTMLInputElement.prototype, 'value', descriptor);
|
||||
supportsFloatingLabel = true;
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(HTMLInputElement.prototype, 'value', descriptor);
|
||||
supportsFloatingLabel = true;
|
||||
}
|
||||
EmbyInputPrototype.createdCallback = function () {
|
||||
if (!this.id) {
|
||||
this.id = 'embyinput' + inputId;
|
||||
inputId++;
|
||||
}
|
||||
|
||||
EmbyInputPrototype.createdCallback = function () {
|
||||
if (!this.id) {
|
||||
this.id = 'embyinput' + inputId;
|
||||
inputId++;
|
||||
}
|
||||
if (this.classList.contains('emby-input')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.classList.contains('emby-input')) {
|
||||
return;
|
||||
}
|
||||
this.classList.add('emby-input');
|
||||
|
||||
this.classList.add('emby-input');
|
||||
const parentNode = this.parentNode;
|
||||
const document = this.ownerDocument;
|
||||
const label = document.createElement('label');
|
||||
label.innerText = this.getAttribute('label') || '';
|
||||
label.classList.add('inputLabel');
|
||||
label.classList.add('inputLabelUnfocused');
|
||||
|
||||
const parentNode = this.parentNode;
|
||||
const document = this.ownerDocument;
|
||||
const label = document.createElement('label');
|
||||
label.innerText = this.getAttribute('label') || '';
|
||||
label.classList.add('inputLabel');
|
||||
label.classList.add('inputLabelUnfocused');
|
||||
label.htmlFor = this.id;
|
||||
parentNode.insertBefore(label, this);
|
||||
this.labelElement = label;
|
||||
|
||||
label.htmlFor = this.id;
|
||||
parentNode.insertBefore(label, this);
|
||||
this.labelElement = label;
|
||||
dom.addEventListener(this, 'focus', function () {
|
||||
onChange.call(this);
|
||||
|
||||
dom.addEventListener(this, 'focus', function () {
|
||||
onChange.call(this);
|
||||
|
||||
// For Samsung orsay devices
|
||||
if (document.attachIME) {
|
||||
document.attachIME(this);
|
||||
}
|
||||
|
||||
label.classList.add('inputLabelFocused');
|
||||
label.classList.remove('inputLabelUnfocused');
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(this, 'blur', function () {
|
||||
onChange.call(this);
|
||||
label.classList.remove('inputLabelFocused');
|
||||
label.classList.add('inputLabelUnfocused');
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(this, 'change', onChange, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'input', onChange, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'valueset', onChange, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
//Make sure the IME pops up if this is the first/default element on the page
|
||||
if (browser.orsay && this === document.activeElement && document.attachIME) {
|
||||
// For Samsung orsay devices
|
||||
if (document.attachIME) {
|
||||
document.attachIME(this);
|
||||
}
|
||||
};
|
||||
|
||||
function onChange() {
|
||||
const label = this.labelElement;
|
||||
if (this.value) {
|
||||
label.classList.remove('inputLabel-float');
|
||||
} else {
|
||||
const instanceSupportsFloat = supportsFloatingLabel && this.type !== 'date' && this.type !== 'time';
|
||||
|
||||
if (instanceSupportsFloat) {
|
||||
label.classList.add('inputLabel-float');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmbyInputPrototype.attachedCallback = function () {
|
||||
this.labelElement.htmlFor = this.id;
|
||||
onChange.call(this);
|
||||
};
|
||||
|
||||
EmbyInputPrototype.label = function (text) {
|
||||
this.labelElement.innerText = text;
|
||||
};
|
||||
|
||||
document.registerElement('emby-input', {
|
||||
prototype: EmbyInputPrototype,
|
||||
extends: 'input'
|
||||
label.classList.add('inputLabelFocused');
|
||||
label.classList.remove('inputLabelUnfocused');
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
dom.addEventListener(this, 'blur', function () {
|
||||
onChange.call(this);
|
||||
label.classList.remove('inputLabelFocused');
|
||||
label.classList.add('inputLabelUnfocused');
|
||||
}, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
dom.addEventListener(this, 'change', onChange, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'input', onChange, {
|
||||
passive: true
|
||||
});
|
||||
dom.addEventListener(this, 'valueset', onChange, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
//Make sure the IME pops up if this is the first/default element on the page
|
||||
if (browser.orsay && this === document.activeElement && document.attachIME) {
|
||||
document.attachIME(this);
|
||||
}
|
||||
};
|
||||
|
||||
function onChange() {
|
||||
const label = this.labelElement;
|
||||
if (this.value) {
|
||||
label.classList.remove('inputLabel-float');
|
||||
} else {
|
||||
const instanceSupportsFloat = supportsFloatingLabel && this.type !== 'date' && this.type !== 'time';
|
||||
|
||||
if (instanceSupportsFloat) {
|
||||
label.classList.add('inputLabel-float');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EmbyInputPrototype.attachedCallback = function () {
|
||||
this.labelElement.htmlFor = this.id;
|
||||
onChange.call(this);
|
||||
};
|
||||
|
||||
EmbyInputPrototype.label = function (text) {
|
||||
this.labelElement.innerText = text;
|
||||
};
|
||||
|
||||
document.registerElement('emby-input', {
|
||||
prototype: EmbyInputPrototype,
|
||||
extends: 'input'
|
||||
});
|
||||
|
||||
|
|
|
@ -5,73 +5,70 @@ import Events from '../../utils/events.ts';
|
|||
|
||||
import 'webcomponents.js/webcomponents-lite';
|
||||
|
||||
/* eslint-disable indent */
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
const localHandler = handler.bind(instance);
|
||||
Events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
const localHandler = handler.bind(instance);
|
||||
Events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
function removeNotificationEvent(instance, name) {
|
||||
const handler = instance[name];
|
||||
if (handler) {
|
||||
Events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function onRefreshProgress(e, apiClient, info) {
|
||||
const indicator = this;
|
||||
|
||||
if (!indicator.itemId) {
|
||||
indicator.itemId = dom.parentWithAttribute(indicator, 'data-id').getAttribute('data-id');
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name) {
|
||||
const handler = instance[name];
|
||||
if (handler) {
|
||||
Events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
if (info.ItemId === indicator.itemId) {
|
||||
const progress = parseFloat(info.Progress);
|
||||
|
||||
if (progress && progress < 100) {
|
||||
this.classList.remove('hide');
|
||||
} else {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
this.setAttribute('data-progress', progress);
|
||||
}
|
||||
}
|
||||
|
||||
const EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
|
||||
|
||||
EmbyItemRefreshIndicatorPrototype.createdCallback = function () {
|
||||
// base method
|
||||
if (EmbyProgressRing.createdCallback) {
|
||||
EmbyProgressRing.createdCallback.call(this);
|
||||
}
|
||||
|
||||
function onRefreshProgress(e, apiClient, info) {
|
||||
const indicator = this;
|
||||
addNotificationEvent(this, 'RefreshProgress', onRefreshProgress);
|
||||
};
|
||||
|
||||
if (!indicator.itemId) {
|
||||
indicator.itemId = dom.parentWithAttribute(indicator, 'data-id').getAttribute('data-id');
|
||||
}
|
||||
EmbyItemRefreshIndicatorPrototype.attachedCallback = function () {
|
||||
// base method
|
||||
if (EmbyProgressRing.attachedCallback) {
|
||||
EmbyProgressRing.attachedCallback.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
if (info.ItemId === indicator.itemId) {
|
||||
const progress = parseFloat(info.Progress);
|
||||
|
||||
if (progress && progress < 100) {
|
||||
this.classList.remove('hide');
|
||||
} else {
|
||||
this.classList.add('hide');
|
||||
}
|
||||
|
||||
this.setAttribute('data-progress', progress);
|
||||
}
|
||||
EmbyItemRefreshIndicatorPrototype.detachedCallback = function () {
|
||||
// base method
|
||||
if (EmbyProgressRing.detachedCallback) {
|
||||
EmbyProgressRing.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
const EmbyItemRefreshIndicatorPrototype = Object.create(EmbyProgressRing);
|
||||
removeNotificationEvent(this, 'RefreshProgress');
|
||||
this.itemId = null;
|
||||
};
|
||||
|
||||
EmbyItemRefreshIndicatorPrototype.createdCallback = function () {
|
||||
// base method
|
||||
if (EmbyProgressRing.createdCallback) {
|
||||
EmbyProgressRing.createdCallback.call(this);
|
||||
}
|
||||
document.registerElement('emby-itemrefreshindicator', {
|
||||
prototype: EmbyItemRefreshIndicatorPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
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'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -13,471 +13,468 @@ import 'webcomponents.js/webcomponents-lite';
|
|||
import ServerConnections from '../../components/ServerConnections';
|
||||
import Sortable from 'sortablejs';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const ItemsContainerPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
const ItemsContainerPrototype = Object.create(HTMLDivElement.prototype);
|
||||
function onClick(e) {
|
||||
const itemsContainer = this;
|
||||
const multiSelect = itemsContainer.multiSelect;
|
||||
|
||||
function onClick(e) {
|
||||
const itemsContainer = this;
|
||||
const multiSelect = itemsContainer.multiSelect;
|
||||
|
||||
if (multiSelect?.onContainerClick.call(itemsContainer, e) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
itemShortcuts.onClick.call(itemsContainer, e);
|
||||
if (multiSelect?.onContainerClick.call(itemsContainer, e) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
function disableEvent(e) {
|
||||
itemShortcuts.onClick.call(itemsContainer, e);
|
||||
}
|
||||
|
||||
function disableEvent(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
|
||||
function onContextMenu(e) {
|
||||
const target = e.target;
|
||||
const card = dom.parentWithAttribute(target, 'data-id');
|
||||
|
||||
// check for serverId, it won't be present on selectserver
|
||||
if (card && card.getAttribute('data-serverid')) {
|
||||
inputManager.handleCommand('menu', {
|
||||
sourceElement: card
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function onContextMenu(e) {
|
||||
const target = e.target;
|
||||
const card = dom.parentWithAttribute(target, 'data-id');
|
||||
|
||||
// check for serverId, it won't be present on selectserver
|
||||
if (card && card.getAttribute('data-serverid')) {
|
||||
inputManager.handleCommand('menu', {
|
||||
sourceElement: card
|
||||
});
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getShortcutOptions() {
|
||||
return {
|
||||
click: false
|
||||
};
|
||||
}
|
||||
|
||||
ItemsContainerPrototype.enableMultiSelect = function (enabled) {
|
||||
const current = this.multiSelect;
|
||||
|
||||
if (!enabled) {
|
||||
if (current) {
|
||||
current.destroy();
|
||||
this.multiSelect = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const self = this;
|
||||
import('../../components/multiSelect/multiSelect').then(({ default: MultiSelect }) => {
|
||||
self.multiSelect = new MultiSelect({
|
||||
container: self,
|
||||
bindOnClick: false
|
||||
});
|
||||
});
|
||||
function getShortcutOptions() {
|
||||
return {
|
||||
click: false
|
||||
};
|
||||
}
|
||||
|
||||
function onDrop(evt, itemsContainer) {
|
||||
const el = evt.item;
|
||||
ItemsContainerPrototype.enableMultiSelect = function (enabled) {
|
||||
const current = this.multiSelect;
|
||||
|
||||
const newIndex = evt.newIndex;
|
||||
const itemId = el.getAttribute('data-playlistitemid');
|
||||
const playlistId = el.getAttribute('data-playlistid');
|
||||
|
||||
if (!playlistId) {
|
||||
const oldIndex = evt.oldIndex;
|
||||
el.dispatchEvent(new CustomEvent('itemdrop', {
|
||||
detail: {
|
||||
oldIndex: oldIndex,
|
||||
newIndex: newIndex,
|
||||
playlistItemId: itemId
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
return;
|
||||
if (!enabled) {
|
||||
if (current) {
|
||||
current.destroy();
|
||||
this.multiSelect = null;
|
||||
}
|
||||
|
||||
const serverId = el.getAttribute('data-serverid');
|
||||
const apiClient = ServerConnections.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();
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
ItemsContainerPrototype.enableDragReordering = function (enabled) {
|
||||
const current = this.sortable;
|
||||
if (!enabled) {
|
||||
if (current) {
|
||||
current.destroy();
|
||||
this.sortable = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const self = this;
|
||||
import('../../components/multiSelect/multiSelect').then(({ default: MultiSelect }) => {
|
||||
self.multiSelect = new MultiSelect({
|
||||
container: self,
|
||||
bindOnClick: false
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function onDrop(evt, itemsContainer) {
|
||||
const el = evt.item;
|
||||
|
||||
const newIndex = evt.newIndex;
|
||||
const itemId = el.getAttribute('data-playlistitemid');
|
||||
const playlistId = el.getAttribute('data-playlistid');
|
||||
|
||||
if (!playlistId) {
|
||||
const oldIndex = evt.oldIndex;
|
||||
el.dispatchEvent(new CustomEvent('itemdrop', {
|
||||
detail: {
|
||||
oldIndex: oldIndex,
|
||||
newIndex: newIndex,
|
||||
playlistItemId: itemId
|
||||
},
|
||||
bubbles: true,
|
||||
cancelable: false
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
const serverId = el.getAttribute('data-serverid');
|
||||
const apiClient = ServerConnections.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) {
|
||||
const current = this.sortable;
|
||||
if (!enabled) {
|
||||
if (current) {
|
||||
return;
|
||||
current.destroy();
|
||||
this.sortable = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const self = this;
|
||||
self.sortable = new Sortable(self, {
|
||||
draggable: '.listItem',
|
||||
handle: '.listViewDragHandle',
|
||||
if (current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// dragging ended
|
||||
onEnd: function (evt) {
|
||||
return onDrop(evt, self);
|
||||
}
|
||||
});
|
||||
};
|
||||
const self = this;
|
||||
self.sortable = new Sortable(self, {
|
||||
draggable: '.listItem',
|
||||
handle: '.listViewDragHandle',
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
const itemsContainer = this;
|
||||
// dragging ended
|
||||
onEnd: function (evt) {
|
||||
return onDrop(evt, self);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
|
||||
cardBuilder.onUserDataChanged(userData, itemsContainer);
|
||||
});
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
const itemsContainer = this;
|
||||
|
||||
const eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
|
||||
cardBuilder.onUserDataChanged(userData, itemsContainer);
|
||||
});
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1
|
||||
const eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
|
||||
// TODO: Check user data change reason?
|
||||
if (eventsToMonitor.indexOf('markfavorite') !== -1
|
||||
|| eventsToMonitor.indexOf('markplayed') !== -1
|
||||
) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function getEventsToMonitor(itemsContainer) {
|
||||
const monitor = itemsContainer.getAttribute('data-monitor');
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
const itemsContainer = this;
|
||||
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
const programId = data.ProgramId;
|
||||
// This could be null, not supported by all tv providers
|
||||
const newTimerId = data.Id;
|
||||
|
||||
import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
|
||||
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onSeriesTimerCreated() {
|
||||
const itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
const itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
|
||||
cardBuilder.onTimerCancelled(data.Id, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
const itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
|
||||
cardBuilder.onSeriesTimerCancelled(data.Id, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
const itemsContainer = this;
|
||||
|
||||
const eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
const itemsAdded = data.ItemsAdded || [];
|
||||
const itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentId = itemsContainer.getAttribute('data-parentid');
|
||||
if (parentId) {
|
||||
const foldersAddedTo = data.FoldersAddedTo || [];
|
||||
const foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
const collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
const itemsContainer = this;
|
||||
const state = stopInfo.state;
|
||||
function getEventsToMonitor(itemsContainer) {
|
||||
const monitor = itemsContainer.getAttribute('data-monitor');
|
||||
if (monitor) {
|
||||
return monitor.split(',');
|
||||
}
|
||||
|
||||
const eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
} else if (state.NowPlayingItem?.MediaType === 'Audio' && eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
function onTimerCreated(e, apiClient, data) {
|
||||
const itemsContainer = this;
|
||||
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
const programId = data.ProgramId;
|
||||
// This could be null, not supported by all tv providers
|
||||
const newTimerId = data.Id;
|
||||
|
||||
import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
|
||||
cardBuilder.onTimerCreated(programId, newTimerId, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onSeriesTimerCreated() {
|
||||
const itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
function onTimerCancelled(e, apiClient, data) {
|
||||
const itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('timers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
|
||||
cardBuilder.onTimerCancelled(data.Id, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onSeriesTimerCancelled(e, apiClient, data) {
|
||||
const itemsContainer = this;
|
||||
if (getEventsToMonitor(itemsContainer).indexOf('seriestimers') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
import('../../components/cardbuilder/cardBuilder').then((cardBuilder) => {
|
||||
cardBuilder.onSeriesTimerCancelled(data.Id, itemsContainer);
|
||||
});
|
||||
}
|
||||
|
||||
function onLibraryChanged(e, apiClient, data) {
|
||||
const itemsContainer = this;
|
||||
|
||||
const eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (eventsToMonitor.indexOf('seriestimers') !== -1 || eventsToMonitor.indexOf('timers') !== -1) {
|
||||
// yes this is an assumption
|
||||
return;
|
||||
}
|
||||
|
||||
const itemsAdded = data.ItemsAdded || [];
|
||||
const itemsRemoved = data.ItemsRemoved || [];
|
||||
if (!itemsAdded.length && !itemsRemoved.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const parentId = itemsContainer.getAttribute('data-parentid');
|
||||
if (parentId) {
|
||||
const foldersAddedTo = data.FoldersAddedTo || [];
|
||||
const foldersRemovedFrom = data.FoldersRemovedFrom || [];
|
||||
const collectionFolders = data.CollectionFolders || [];
|
||||
|
||||
if (foldersAddedTo.indexOf(parentId) === -1 && foldersRemovedFrom.indexOf(parentId) === -1 && collectionFolders.indexOf(parentId) === -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
itemsContainer.notifyRefreshNeeded();
|
||||
}
|
||||
|
||||
function onPlaybackStopped(e, stopInfo) {
|
||||
const itemsContainer = this;
|
||||
const state = stopInfo.state;
|
||||
|
||||
const eventsToMonitor = getEventsToMonitor(itemsContainer);
|
||||
if (state.NowPlayingItem && state.NowPlayingItem.MediaType === 'Video') {
|
||||
if (eventsToMonitor.indexOf('videoplayback') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
} else if (state.NowPlayingItem?.MediaType === 'Audio' && eventsToMonitor.indexOf('audioplayback') !== -1) {
|
||||
itemsContainer.notifyRefreshNeeded(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
const localHandler = handler.bind(instance);
|
||||
function addNotificationEvent(instance, name, handler, owner) {
|
||||
const localHandler = handler.bind(instance);
|
||||
owner = owner || serverNotifications;
|
||||
Events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
const handler = instance['event_' + name];
|
||||
if (handler) {
|
||||
owner = owner || serverNotifications;
|
||||
Events.on(owner, name, localHandler);
|
||||
instance['event_' + name] = localHandler;
|
||||
Events.off(owner, name, handler);
|
||||
instance['event_' + name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name, owner) {
|
||||
const 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);
|
||||
}
|
||||
}
|
||||
|
||||
ItemsContainerPrototype.createdCallback = function () {
|
||||
this.classList.add('itemsContainer');
|
||||
};
|
||||
if (layoutManager.desktop || layoutManager.mobile && this.getAttribute('data-multiselect') !== 'false') {
|
||||
this.enableMultiSelect(true);
|
||||
}
|
||||
|
||||
ItemsContainerPrototype.attachedCallback = function () {
|
||||
this.addEventListener('click', onClick);
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('itemsContainer-tv');
|
||||
}
|
||||
|
||||
if (browser.touch) {
|
||||
this.addEventListener('contextmenu', disableEvent);
|
||||
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;
|
||||
|
||||
const refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
if (refreshIntervalEndTime) {
|
||||
const remainingMs = refreshIntervalEndTime - new Date().getTime();
|
||||
if (remainingMs > 0 && !this.needsRefresh) {
|
||||
resetRefreshInterval(this, remainingMs);
|
||||
} else {
|
||||
if (this.getAttribute('data-contextmenu') !== 'false') {
|
||||
this.addEventListener('contextmenu', onContextMenu);
|
||||
}
|
||||
this.needsRefresh = true;
|
||||
this.refreshIntervalEndTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (layoutManager.desktop || layoutManager.mobile && this.getAttribute('data-multiselect') !== 'false') {
|
||||
this.enableMultiSelect(true);
|
||||
}
|
||||
if (this.needsRefresh || (options && options.refresh)) {
|
||||
return this.refreshItems();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const refreshIntervalEndTime = this.refreshIntervalEndTime;
|
||||
if (refreshIntervalEndTime) {
|
||||
const 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();
|
||||
};
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return Promise.resolve();
|
||||
}
|
||||
function resetRefreshInterval(itemsContainer, intervalMs) {
|
||||
clearRefreshInterval(itemsContainer);
|
||||
|
||||
this.needsRefresh = false;
|
||||
if (!intervalMs) {
|
||||
intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0', 10);
|
||||
}
|
||||
|
||||
return this.fetchData().then(onDataFetched.bind(this));
|
||||
};
|
||||
if (intervalMs) {
|
||||
itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs);
|
||||
itemsContainer.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
ItemsContainerPrototype.notifyRefreshNeeded = function (isInForeground) {
|
||||
if (this.paused) {
|
||||
this.needsRefresh = true;
|
||||
return;
|
||||
}
|
||||
function onDataFetched(result) {
|
||||
const items = result.Items || result;
|
||||
|
||||
const timeout = this.refreshTimeout;
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
if (isInForeground === true) {
|
||||
this.refreshItems();
|
||||
const parentContainer = this.parentContainer;
|
||||
if (parentContainer) {
|
||||
if (items.length) {
|
||||
parentContainer.classList.remove('hide');
|
||||
} else {
|
||||
this.refreshTimeout = setTimeout(this.refreshItems.bind(this), 10000);
|
||||
parentContainer.classList.add('hide');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function clearRefreshInterval(itemsContainer, isPausing) {
|
||||
if (itemsContainer.refreshInterval) {
|
||||
clearInterval(itemsContainer.refreshInterval);
|
||||
itemsContainer.refreshInterval = null;
|
||||
const activeElement = document.activeElement;
|
||||
let focusId;
|
||||
let hasActiveElement;
|
||||
|
||||
if (!isPausing) {
|
||||
itemsContainer.refreshIntervalEndTime = null;
|
||||
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) {
|
||||
const newElement = itemsContainer.querySelector('[data-id="' + focusId + '"]');
|
||||
if (newElement) {
|
||||
try {
|
||||
focusManager.focus(newElement);
|
||||
return;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetRefreshInterval(itemsContainer, intervalMs) {
|
||||
clearRefreshInterval(itemsContainer);
|
||||
focusManager.autoFocus(itemsContainer);
|
||||
}
|
||||
|
||||
if (!intervalMs) {
|
||||
intervalMs = parseInt(itemsContainer.getAttribute('data-refreshinterval') || '0', 10);
|
||||
}
|
||||
document.registerElement('emby-itemscontainer', {
|
||||
prototype: ItemsContainerPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
if (intervalMs) {
|
||||
itemsContainer.refreshInterval = setInterval(itemsContainer.notifyRefreshNeeded.bind(itemsContainer), intervalMs);
|
||||
itemsContainer.refreshIntervalEndTime = new Date().getTime() + intervalMs;
|
||||
}
|
||||
}
|
||||
|
||||
function onDataFetched(result) {
|
||||
const items = result.Items || result;
|
||||
|
||||
const parentContainer = this.parentContainer;
|
||||
if (parentContainer) {
|
||||
if (items.length) {
|
||||
parentContainer.classList.remove('hide');
|
||||
} else {
|
||||
parentContainer.classList.add('hide');
|
||||
}
|
||||
}
|
||||
|
||||
const activeElement = document.activeElement;
|
||||
let focusId;
|
||||
let 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) {
|
||||
const 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'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -4,151 +4,148 @@ import Events from '../../utils/events.ts';
|
|||
import EmbyButtonPrototype from '../../elements/emby-button/emby-button';
|
||||
import ServerConnections from '../../components/ServerConnections';
|
||||
|
||||
/* eslint-disable indent */
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
const localHandler = handler.bind(instance);
|
||||
Events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
const localHandler = handler.bind(instance);
|
||||
Events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
function removeNotificationEvent(instance, name) {
|
||||
const handler = instance[name];
|
||||
if (handler) {
|
||||
Events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
function onClick() {
|
||||
const button = this;
|
||||
const id = button.getAttribute('data-id');
|
||||
const serverId = button.getAttribute('data-serverid');
|
||||
const apiClient = ServerConnections.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) {
|
||||
const button = this;
|
||||
if (userData.ItemId === button.getAttribute('data-id')) {
|
||||
setState(button, userData.Played);
|
||||
}
|
||||
}
|
||||
|
||||
function setState(button, played, updateAttribute) {
|
||||
let icon = button.iconElement;
|
||||
if (!icon) {
|
||||
button.iconElement = button.querySelector('.material-icons');
|
||||
icon = button.iconElement;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name) {
|
||||
const handler = instance[name];
|
||||
if (handler) {
|
||||
Events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
function onClick() {
|
||||
const button = this;
|
||||
const id = button.getAttribute('data-id');
|
||||
const serverId = button.getAttribute('data-serverid');
|
||||
const apiClient = ServerConnections.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);
|
||||
}
|
||||
if (updateAttribute !== false) {
|
||||
button.setAttribute('data-played', played);
|
||||
}
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
const button = this;
|
||||
if (userData.ItemId === button.getAttribute('data-id')) {
|
||||
setState(button, userData.Played);
|
||||
}
|
||||
setTitle(button, button.getAttribute('data-type'), played);
|
||||
}
|
||||
|
||||
function setTitle(button, itemType, played) {
|
||||
if (itemType !== 'AudioBook' && itemType !== 'AudioPodcast') {
|
||||
button.title = played ? globalize.translate('Watched') : globalize.translate('MarkPlayed');
|
||||
} else {
|
||||
button.title = played ? globalize.translate('Played') : globalize.translate('MarkPlayed');
|
||||
}
|
||||
|
||||
function setState(button, played, updateAttribute) {
|
||||
let icon = button.iconElement;
|
||||
if (!icon) {
|
||||
button.iconElement = button.querySelector('.material-icons');
|
||||
icon = button.iconElement;
|
||||
}
|
||||
const text = button.querySelector('.button-text');
|
||||
if (text) {
|
||||
text.innerText = button.title;
|
||||
}
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
function clearEvents(button) {
|
||||
button.removeEventListener('click', onClick);
|
||||
removeNotificationEvent(button, 'UserDataChanged');
|
||||
}
|
||||
|
||||
if (updateAttribute !== false) {
|
||||
button.setAttribute('data-played', played);
|
||||
}
|
||||
function bindEvents(button) {
|
||||
clearEvents(button);
|
||||
|
||||
setTitle(button, button.getAttribute('data-type'), played);
|
||||
button.addEventListener('click', onClick);
|
||||
addNotificationEvent(button, 'UserDataChanged', onUserDataChanged);
|
||||
}
|
||||
|
||||
const 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);
|
||||
}
|
||||
|
||||
function setTitle(button, itemType, played) {
|
||||
if (itemType !== 'AudioBook' && itemType !== 'AudioPodcast') {
|
||||
button.title = played ? globalize.translate('Watched') : globalize.translate('MarkPlayed');
|
||||
} else {
|
||||
button.title = played ? globalize.translate('Played') : globalize.translate('MarkPlayed');
|
||||
}
|
||||
const itemId = this.getAttribute('data-id');
|
||||
const serverId = this.getAttribute('data-serverid');
|
||||
if (itemId && serverId) {
|
||||
setState(this, this.getAttribute('data-played') === 'true', false);
|
||||
bindEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
const text = button.querySelector('.button-text');
|
||||
if (text) {
|
||||
text.innerText = button.title;
|
||||
}
|
||||
EmbyPlaystateButtonPrototype.detachedCallback = function () {
|
||||
// base method
|
||||
if (EmbyButtonPrototype.detachedCallback) {
|
||||
EmbyButtonPrototype.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
function clearEvents(button) {
|
||||
button.removeEventListener('click', onClick);
|
||||
removeNotificationEvent(button, 'UserDataChanged');
|
||||
}
|
||||
clearEvents(this);
|
||||
this.iconElement = null;
|
||||
};
|
||||
|
||||
function bindEvents(button) {
|
||||
clearEvents(button);
|
||||
|
||||
button.addEventListener('click', onClick);
|
||||
addNotificationEvent(button, 'UserDataChanged', onUserDataChanged);
|
||||
}
|
||||
|
||||
const 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);
|
||||
}
|
||||
|
||||
const itemId = this.getAttribute('data-id');
|
||||
const serverId = this.getAttribute('data-serverid');
|
||||
if (itemId && serverId) {
|
||||
setState(this, this.getAttribute('data-played') === 'true', false);
|
||||
bindEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyPlaystateButtonPrototype.detachedCallback = function () {
|
||||
// base method
|
||||
if (EmbyButtonPrototype.detachedCallback) {
|
||||
EmbyButtonPrototype.detachedCallback.call(this);
|
||||
}
|
||||
EmbyPlaystateButtonPrototype.setItem = function (item) {
|
||||
if (item) {
|
||||
this.setAttribute('data-id', item.Id);
|
||||
this.setAttribute('data-serverid', item.ServerId);
|
||||
this.setAttribute('data-type', item.Type);
|
||||
|
||||
const played = item.UserData && item.UserData.Played;
|
||||
setState(this, played);
|
||||
bindEvents(this);
|
||||
} else {
|
||||
this.removeAttribute('data-id');
|
||||
this.removeAttribute('data-serverid');
|
||||
this.removeAttribute('data-type');
|
||||
this.removeAttribute('data-played');
|
||||
clearEvents(this);
|
||||
this.iconElement = null;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
EmbyPlaystateButtonPrototype.setItem = function (item) {
|
||||
if (item) {
|
||||
this.setAttribute('data-id', item.Id);
|
||||
this.setAttribute('data-serverid', item.ServerId);
|
||||
this.setAttribute('data-type', item.Type);
|
||||
document.registerElement('emby-playstatebutton', {
|
||||
prototype: EmbyPlaystateButtonPrototype,
|
||||
extends: 'button'
|
||||
});
|
||||
|
||||
const played = item.UserData && item.UserData.Played;
|
||||
setState(this, played);
|
||||
bindEvents(this);
|
||||
} else {
|
||||
this.removeAttribute('data-id');
|
||||
this.removeAttribute('data-serverid');
|
||||
this.removeAttribute('data-type');
|
||||
this.removeAttribute('data-played');
|
||||
clearEvents(this);
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-playstatebutton', {
|
||||
prototype: EmbyPlaystateButtonPrototype,
|
||||
extends: 'button'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,42 +1,40 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
const ProgressBarPrototype = Object.create(HTMLDivElement.prototype);
|
||||
const ProgressBarPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
function onAutoTimeProgress() {
|
||||
const start = parseInt(this.getAttribute('data-starttime'), 10);
|
||||
const end = parseInt(this.getAttribute('data-endtime'), 10);
|
||||
function onAutoTimeProgress() {
|
||||
const start = parseInt(this.getAttribute('data-starttime'), 10);
|
||||
const end = parseInt(this.getAttribute('data-endtime'), 10);
|
||||
|
||||
const now = new Date().getTime();
|
||||
const total = end - start;
|
||||
let pct = 100 * ((now - start) / total);
|
||||
const now = new Date().getTime();
|
||||
const total = end - start;
|
||||
let pct = 100 * ((now - start) / total);
|
||||
|
||||
pct = Math.min(100, pct);
|
||||
pct = Math.max(0, pct);
|
||||
pct = Math.min(100, pct);
|
||||
pct = Math.max(0, pct);
|
||||
|
||||
const itemProgressBarForeground = this.querySelector('.itemProgressBarForeground');
|
||||
itemProgressBarForeground.style.width = pct + '%';
|
||||
const itemProgressBarForeground = this.querySelector('.itemProgressBarForeground');
|
||||
itemProgressBarForeground.style.width = pct + '%';
|
||||
}
|
||||
|
||||
ProgressBarPrototype.attachedCallback = function () {
|
||||
if (this.timeInterval) {
|
||||
clearInterval(this.timeInterval);
|
||||
}
|
||||
|
||||
ProgressBarPrototype.attachedCallback = function () {
|
||||
if (this.timeInterval) {
|
||||
clearInterval(this.timeInterval);
|
||||
}
|
||||
if (this.getAttribute('data-automode') === 'time') {
|
||||
this.timeInterval = setInterval(onAutoTimeProgress.bind(this), 60000);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
ProgressBarPrototype.detachedCallback = function () {
|
||||
if (this.timeInterval) {
|
||||
clearInterval(this.timeInterval);
|
||||
this.timeInterval = null;
|
||||
}
|
||||
};
|
||||
document.registerElement('emby-progressbar', {
|
||||
prototype: ProgressBarPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
document.registerElement('emby-progressbar', {
|
||||
prototype: ProgressBarPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -4,98 +4,95 @@ import template from './emby-progressring.template.html';
|
|||
import { getCurrentDateTimeLocale } from '../../scripts/globalize';
|
||||
import { toPercent } from '../../utils/number.ts';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const EmbyProgressRing = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
const EmbyProgressRing = Object.create(HTMLDivElement.prototype);
|
||||
EmbyProgressRing.createdCallback = function () {
|
||||
this.classList.add('progressring');
|
||||
this.setAttribute('dir', 'ltr');
|
||||
const instance = this;
|
||||
|
||||
EmbyProgressRing.createdCallback = function () {
|
||||
this.classList.add('progressring');
|
||||
this.setAttribute('dir', 'ltr');
|
||||
const instance = this;
|
||||
instance.innerHTML = template;
|
||||
|
||||
instance.innerHTML = template;
|
||||
|
||||
if (window.MutationObserver) {
|
||||
// create an observer instance
|
||||
const observer = new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function () {
|
||||
instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
|
||||
});
|
||||
if (window.MutationObserver) {
|
||||
// create an observer instance
|
||||
const observer = new MutationObserver(function (mutations) {
|
||||
mutations.forEach(function () {
|
||||
instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
|
||||
});
|
||||
});
|
||||
|
||||
// configuration of the observer:
|
||||
const config = { attributes: true, childList: false, characterData: false };
|
||||
// configuration of the observer:
|
||||
const config = { attributes: true, childList: false, characterData: false };
|
||||
|
||||
// pass in the target node, as well as the observer options
|
||||
observer.observe(instance, config);
|
||||
// pass in the target node, as well as the observer options
|
||||
observer.observe(instance, config);
|
||||
|
||||
instance.observer = observer;
|
||||
}
|
||||
instance.observer = observer;
|
||||
}
|
||||
|
||||
instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
|
||||
};
|
||||
instance.setProgress(parseFloat(instance.getAttribute('data-progress') || '0'));
|
||||
};
|
||||
|
||||
EmbyProgressRing.setProgress = function (progress) {
|
||||
progress = Math.floor(progress);
|
||||
EmbyProgressRing.setProgress = function (progress) {
|
||||
progress = Math.floor(progress);
|
||||
|
||||
let angle;
|
||||
let angle;
|
||||
|
||||
if (progress < 25) {
|
||||
angle = -90 + (progress / 100) * 360;
|
||||
if (progress < 25) {
|
||||
angle = -90 + (progress / 100) * 360;
|
||||
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
} else if (progress >= 25 && progress < 50) {
|
||||
angle = -90 + ((progress - 25) / 100) * 360;
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
} else if (progress >= 25 && progress < 50) {
|
||||
angle = -90 + ((progress - 25) / 100) * 360;
|
||||
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
} else if (progress >= 50 && progress < 75) {
|
||||
angle = -90 + ((progress - 50) / 100) * 360;
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(-90deg)';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
} else if (progress >= 50 && progress < 75) {
|
||||
angle = -90 + ((progress - 50) / 100) * 360;
|
||||
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'none';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'none';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
} else if (progress >= 75 && progress <= 100) {
|
||||
angle = -90 + ((progress - 75) / 100) * 360;
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(-90deg)';
|
||||
} else if (progress >= 75 && progress <= 100) {
|
||||
angle = -90 + ((progress - 75) / 100) * 360;
|
||||
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'none';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'none';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
}
|
||||
this.querySelector('.animate-0-25-b').style.transform = 'none';
|
||||
this.querySelector('.animate-25-50-b').style.transform = 'none';
|
||||
this.querySelector('.animate-50-75-b').style.transform = 'none';
|
||||
this.querySelector('.animate-75-100-b').style.transform = 'rotate(' + angle + 'deg)';
|
||||
}
|
||||
|
||||
this.querySelector('.progressring-text').innerHTML = toPercent(progress / 100, getCurrentDateTimeLocale());
|
||||
};
|
||||
this.querySelector('.progressring-text').innerHTML = toPercent(progress / 100, getCurrentDateTimeLocale());
|
||||
};
|
||||
|
||||
EmbyProgressRing.attachedCallback = function () {
|
||||
// no-op
|
||||
};
|
||||
EmbyProgressRing.attachedCallback = function () {
|
||||
// no-op
|
||||
};
|
||||
|
||||
EmbyProgressRing.detachedCallback = function () {
|
||||
const observer = this.observer;
|
||||
EmbyProgressRing.detachedCallback = function () {
|
||||
const observer = this.observer;
|
||||
|
||||
if (observer) {
|
||||
// later, you can stop observing
|
||||
observer.disconnect();
|
||||
if (observer) {
|
||||
// later, you can stop observing
|
||||
observer.disconnect();
|
||||
|
||||
this.observer = null;
|
||||
}
|
||||
};
|
||||
this.observer = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-progressring', {
|
||||
prototype: EmbyProgressRing,
|
||||
extends: 'div'
|
||||
});
|
||||
document.registerElement('emby-progressring', {
|
||||
prototype: EmbyProgressRing,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
export default EmbyProgressRing;
|
||||
export default EmbyProgressRing;
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -3,80 +3,77 @@ import browser from '../../scripts/browser';
|
|||
import 'webcomponents.js/webcomponents-lite';
|
||||
import './emby-radio.scss';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
const EmbyRadioPrototype = Object.create(HTMLInputElement.prototype);
|
||||
function onKeyDown(e) {
|
||||
// Don't submit form on enter
|
||||
// Real (non-emulator) Tizen does nothing on Space
|
||||
if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
|
||||
e.preventDefault();
|
||||
|
||||
function onKeyDown(e) {
|
||||
// Don't submit form on enter
|
||||
// Real (non-emulator) Tizen does nothing on Space
|
||||
if (e.keyCode === 13 || (e.keyCode === 32 && browser.tizen)) {
|
||||
e.preventDefault();
|
||||
if (!this.checked) {
|
||||
this.checked = true;
|
||||
|
||||
if (!this.checked) {
|
||||
this.checked = true;
|
||||
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
|
||||
return false;
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
EmbyRadioPrototype.attachedCallback = function () {
|
||||
const showFocus = !layoutManager.mobile;
|
||||
|
||||
if (this.getAttribute('data-radio') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
EmbyRadioPrototype.attachedCallback = function () {
|
||||
const showFocus = !layoutManager.mobile;
|
||||
this.setAttribute('data-radio', 'true');
|
||||
|
||||
if (this.getAttribute('data-radio') === 'true') {
|
||||
return;
|
||||
}
|
||||
this.classList.add('mdl-radio__button');
|
||||
|
||||
this.setAttribute('data-radio', 'true');
|
||||
const labelElement = this.parentNode;
|
||||
labelElement.classList.add('mdl-radio');
|
||||
labelElement.classList.add('mdl-js-radio');
|
||||
labelElement.classList.add('mdl-js-ripple-effect');
|
||||
if (showFocus) {
|
||||
labelElement.classList.add('show-focus');
|
||||
}
|
||||
|
||||
this.classList.add('mdl-radio__button');
|
||||
const labelTextElement = labelElement.querySelector('span');
|
||||
|
||||
const labelElement = this.parentNode;
|
||||
labelElement.classList.add('mdl-radio');
|
||||
labelElement.classList.add('mdl-js-radio');
|
||||
labelElement.classList.add('mdl-js-ripple-effect');
|
||||
if (showFocus) {
|
||||
labelElement.classList.add('show-focus');
|
||||
}
|
||||
labelTextElement.classList.add('radioButtonLabel');
|
||||
labelTextElement.classList.add('mdl-radio__label');
|
||||
|
||||
const labelTextElement = labelElement.querySelector('span');
|
||||
let html = '';
|
||||
|
||||
labelTextElement.classList.add('radioButtonLabel');
|
||||
labelTextElement.classList.add('mdl-radio__label');
|
||||
html += '<div class="mdl-radio__circles">';
|
||||
|
||||
let html = '';
|
||||
html += '<svg>';
|
||||
html += '<defs>';
|
||||
html += '<clipPath id="cutoff">';
|
||||
html += '<circle cx="50%" cy="50%" r="50%" />';
|
||||
html += '</clipPath>';
|
||||
html += '</defs>';
|
||||
html += '<circle class="mdl-radio__outer-circle" cx="50%" cy="50%" r="50%" fill="none" stroke="currentcolor" stroke-width="0.26em" clip-path="url(#cutoff)" />';
|
||||
html += '<circle class="mdl-radio__inner-circle" cx="50%" cy="50%" r="25%" fill="currentcolor" />';
|
||||
html += '</svg>';
|
||||
|
||||
html += '<div class="mdl-radio__circles">';
|
||||
if (showFocus) {
|
||||
html += '<div class="mdl-radio__focus-circle"></div>';
|
||||
}
|
||||
|
||||
html += '<svg>';
|
||||
html += '<defs>';
|
||||
html += '<clipPath id="cutoff">';
|
||||
html += '<circle cx="50%" cy="50%" r="50%" />';
|
||||
html += '</clipPath>';
|
||||
html += '</defs>';
|
||||
html += '<circle class="mdl-radio__outer-circle" cx="50%" cy="50%" r="50%" fill="none" stroke="currentcolor" stroke-width="0.26em" clip-path="url(#cutoff)" />';
|
||||
html += '<circle class="mdl-radio__inner-circle" cx="50%" cy="50%" r="25%" fill="currentcolor" />';
|
||||
html += '</svg>';
|
||||
html += '</div>';
|
||||
|
||||
if (showFocus) {
|
||||
html += '<div class="mdl-radio__focus-circle"></div>';
|
||||
}
|
||||
this.insertAdjacentHTML('afterend', html);
|
||||
|
||||
html += '</div>';
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
};
|
||||
|
||||
this.insertAdjacentHTML('afterend', html);
|
||||
document.registerElement('emby-radio', {
|
||||
prototype: EmbyRadioPrototype,
|
||||
extends: 'input'
|
||||
});
|
||||
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
};
|
||||
|
||||
document.registerElement('emby-radio', {
|
||||
prototype: EmbyRadioPrototype,
|
||||
extends: 'input'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -4,32 +4,119 @@ import Events from '../../utils/events.ts';
|
|||
import EmbyButtonPrototype from '../emby-button/emby-button';
|
||||
import ServerConnections from '../../components/ServerConnections';
|
||||
|
||||
/* eslint-disable indent */
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
const localHandler = handler.bind(instance);
|
||||
Events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
}
|
||||
|
||||
function addNotificationEvent(instance, name, handler) {
|
||||
const localHandler = handler.bind(instance);
|
||||
Events.on(serverNotifications, name, localHandler);
|
||||
instance[name] = localHandler;
|
||||
function removeNotificationEvent(instance, name) {
|
||||
const 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() {
|
||||
const button = this;
|
||||
const id = button.getAttribute('data-id');
|
||||
const serverId = button.getAttribute('data-serverid');
|
||||
const apiClient = ServerConnections.getApiClient(serverId);
|
||||
|
||||
let likes = this.getAttribute('data-likes');
|
||||
const isFavorite = this.getAttribute('data-isfavorite') === 'true';
|
||||
if (likes === 'true') {
|
||||
likes = true;
|
||||
} else if (likes === 'false') {
|
||||
likes = false;
|
||||
} else {
|
||||
likes = null;
|
||||
}
|
||||
|
||||
function removeNotificationEvent(instance, name) {
|
||||
const handler = instance[name];
|
||||
if (handler) {
|
||||
Events.off(serverNotifications, name, handler);
|
||||
instance[name] = null;
|
||||
showPicker(button, apiClient, id, likes, isFavorite).then(function (userData) {
|
||||
setState(button, userData.Likes, userData.IsFavorite);
|
||||
});
|
||||
}
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
const button = this;
|
||||
|
||||
if (userData.ItemId === button.getAttribute('data-id')) {
|
||||
setState(button, userData.Likes, userData.IsFavorite);
|
||||
}
|
||||
}
|
||||
|
||||
function setState(button, likes, isFavorite, updateAttribute) {
|
||||
const icon = button.querySelector('.material-icons');
|
||||
|
||||
if (isFavorite) {
|
||||
if (icon) {
|
||||
icon.classList.add('favorite');
|
||||
icon.classList.add('ratingbutton-icon-withrating');
|
||||
}
|
||||
|
||||
button.classList.add('ratingbutton-withrating');
|
||||
} else {
|
||||
if (icon) {
|
||||
icon.classList.add('favorite');
|
||||
icon.classList.remove('ratingbutton-icon-withrating');
|
||||
}
|
||||
button.classList.remove('ratingbutton-withrating');
|
||||
}
|
||||
|
||||
function showPicker(button, apiClient, itemId, likes, isFavorite) {
|
||||
return apiClient.updateFavoriteStatus(apiClient.getCurrentUserId(), itemId, !isFavorite);
|
||||
if (updateAttribute !== false) {
|
||||
button.setAttribute('data-isfavorite', isFavorite);
|
||||
|
||||
button.setAttribute('data-likes', (likes === null ? '' : likes));
|
||||
}
|
||||
|
||||
function onClick() {
|
||||
const button = this;
|
||||
const id = button.getAttribute('data-id');
|
||||
const serverId = button.getAttribute('data-serverid');
|
||||
const apiClient = ServerConnections.getApiClient(serverId);
|
||||
setTitle(button, isFavorite);
|
||||
}
|
||||
|
||||
function setTitle(button, isFavorite) {
|
||||
button.title = isFavorite ? globalize.translate('Favorite') : globalize.translate('AddToFavorites');
|
||||
|
||||
const text = button.querySelector('.button-text');
|
||||
if (text) {
|
||||
text.innerText = 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);
|
||||
}
|
||||
|
||||
const 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);
|
||||
}
|
||||
|
||||
const itemId = this.getAttribute('data-id');
|
||||
const serverId = this.getAttribute('data-serverid');
|
||||
if (itemId && serverId) {
|
||||
let likes = this.getAttribute('data-likes');
|
||||
const isFavorite = this.getAttribute('data-isfavorite') === 'true';
|
||||
if (likes === 'true') {
|
||||
|
@ -40,131 +127,41 @@ import ServerConnections from '../../components/ServerConnections';
|
|||
likes = null;
|
||||
}
|
||||
|
||||
showPicker(button, apiClient, id, likes, isFavorite).then(function (userData) {
|
||||
setState(button, userData.Likes, userData.IsFavorite);
|
||||
});
|
||||
setState(this, likes, isFavorite, false);
|
||||
bindEvents(this);
|
||||
} else {
|
||||
setTitle(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyRatingButtonPrototype.detachedCallback = function () {
|
||||
// base method
|
||||
if (EmbyButtonPrototype.detachedCallback) {
|
||||
EmbyButtonPrototype.detachedCallback.call(this);
|
||||
}
|
||||
|
||||
function onUserDataChanged(e, apiClient, userData) {
|
||||
const button = this;
|
||||
clearEvents(this);
|
||||
};
|
||||
|
||||
if (userData.ItemId === button.getAttribute('data-id')) {
|
||||
setState(button, userData.Likes, userData.IsFavorite);
|
||||
}
|
||||
}
|
||||
|
||||
function setState(button, likes, isFavorite, updateAttribute) {
|
||||
const icon = button.querySelector('.material-icons');
|
||||
|
||||
if (isFavorite) {
|
||||
if (icon) {
|
||||
icon.classList.add('favorite');
|
||||
icon.classList.add('ratingbutton-icon-withrating');
|
||||
}
|
||||
|
||||
button.classList.add('ratingbutton-withrating');
|
||||
} else {
|
||||
if (icon) {
|
||||
icon.classList.add('favorite');
|
||||
icon.classList.remove('ratingbutton-icon-withrating');
|
||||
}
|
||||
button.classList.remove('ratingbutton-withrating');
|
||||
}
|
||||
|
||||
if (updateAttribute !== false) {
|
||||
button.setAttribute('data-isfavorite', isFavorite);
|
||||
|
||||
button.setAttribute('data-likes', (likes === null ? '' : likes));
|
||||
}
|
||||
|
||||
setTitle(button, isFavorite);
|
||||
}
|
||||
|
||||
function setTitle(button, isFavorite) {
|
||||
button.title = isFavorite ? globalize.translate('Favorite') : globalize.translate('AddToFavorites');
|
||||
|
||||
const text = button.querySelector('.button-text');
|
||||
if (text) {
|
||||
text.innerText = 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);
|
||||
}
|
||||
|
||||
const 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);
|
||||
}
|
||||
|
||||
const itemId = this.getAttribute('data-id');
|
||||
const serverId = this.getAttribute('data-serverid');
|
||||
if (itemId && serverId) {
|
||||
let likes = this.getAttribute('data-likes');
|
||||
const 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);
|
||||
} else {
|
||||
setTitle(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyRatingButtonPrototype.detachedCallback = function () {
|
||||
// base method
|
||||
if (EmbyButtonPrototype.detachedCallback) {
|
||||
EmbyButtonPrototype.detachedCallback.call(this);
|
||||
}
|
||||
EmbyRatingButtonPrototype.setItem = function (item) {
|
||||
if (item) {
|
||||
this.setAttribute('data-id', item.Id);
|
||||
this.setAttribute('data-serverid', item.ServerId);
|
||||
|
||||
const 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);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
EmbyRatingButtonPrototype.setItem = function (item) {
|
||||
if (item) {
|
||||
this.setAttribute('data-id', item.Id);
|
||||
this.setAttribute('data-serverid', item.ServerId);
|
||||
document.registerElement('emby-ratingbutton', {
|
||||
prototype: EmbyRatingButtonPrototype,
|
||||
extends: 'button'
|
||||
});
|
||||
|
||||
const 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'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -3,198 +3,195 @@ import 'webcomponents.js/webcomponents-lite';
|
|||
import '../emby-button/paper-icon-button-light';
|
||||
import globalize from '../../scripts/globalize';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
const EmbyScrollButtonsPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
EmbyScrollButtonsPrototype.createdCallback = function () {
|
||||
// no-op
|
||||
};
|
||||
EmbyScrollButtonsPrototype.createdCallback = function () {
|
||||
// no-op
|
||||
};
|
||||
|
||||
function getScrollButtonHtml(direction) {
|
||||
let html = '';
|
||||
const icon = direction === 'left' ? 'chevron_left' : 'chevron_right';
|
||||
const title = direction === 'left' ? globalize.translate('Previous') : globalize.translate('Next') ;
|
||||
function getScrollButtonHtml(direction) {
|
||||
let html = '';
|
||||
const icon = direction === 'left' ? 'chevron_left' : 'chevron_right';
|
||||
const title = direction === 'left' ? globalize.translate('Previous') : globalize.translate('Next') ;
|
||||
|
||||
html += `<button type="button" is="paper-icon-button-light" data-ripple="false" data-direction="${direction}" title="${title}" class="emby-scrollbuttons-button">`;
|
||||
html += '<span class="material-icons ' + icon + '" aria-hidden="true"></span>';
|
||||
html += '</button>';
|
||||
html += `<button type="button" is="paper-icon-button-light" data-ripple="false" data-direction="${direction}" title="${title}" class="emby-scrollbuttons-button">`;
|
||||
html += '<span class="material-icons ' + icon + '" aria-hidden="true"></span>';
|
||||
html += '</button>';
|
||||
|
||||
return html;
|
||||
return html;
|
||||
}
|
||||
|
||||
function getScrollPosition(parent) {
|
||||
if (parent.getScrollPosition) {
|
||||
return parent.getScrollPosition();
|
||||
}
|
||||
|
||||
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) {
|
||||
let localeAwarePos = scrollPos;
|
||||
if (globalize.getIsElementRTL(scrollButtons)) {
|
||||
localeAwarePos *= -1;
|
||||
}
|
||||
|
||||
// TODO: Check if hack is really needed
|
||||
// hack alert add twenty for rounding errors
|
||||
if (scrollWidth <= scrollSize + 20) {
|
||||
scrollButtons.scrollButtonsLeft.classList.add('hide');
|
||||
scrollButtons.scrollButtonsRight.classList.add('hide');
|
||||
} else {
|
||||
scrollButtons.scrollButtonsLeft.classList.remove('hide');
|
||||
scrollButtons.scrollButtonsRight.classList.remove('hide');
|
||||
}
|
||||
|
||||
if (localeAwarePos > 0) {
|
||||
scrollButtons.scrollButtonsLeft.disabled = false;
|
||||
} else {
|
||||
scrollButtons.scrollButtonsLeft.disabled = true;
|
||||
}
|
||||
|
||||
const scrollPosEnd = localeAwarePos + scrollSize;
|
||||
if (scrollWidth > 0 && scrollPosEnd >= scrollWidth) {
|
||||
scrollButtons.scrollButtonsRight.disabled = true;
|
||||
} else {
|
||||
scrollButtons.scrollButtonsRight.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
const scrollButtons = this;
|
||||
const scroller = this.scroller;
|
||||
|
||||
const scrollSize = getScrollSize(scroller);
|
||||
const scrollPos = getScrollPosition(scroller);
|
||||
const scrollWidth = getScrollWidth(scroller);
|
||||
|
||||
updateScrollButtons(scrollButtons, scrollSize, scrollPos, scrollWidth);
|
||||
}
|
||||
|
||||
function getStyleValue(style, name) {
|
||||
let value = style.getPropertyValue(name);
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function getScrollWidth(parent) {
|
||||
if (parent.getScrollSize) {
|
||||
return parent.getScrollSize();
|
||||
}
|
||||
|
||||
value = value.replace('px', '');
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function updateScrollButtons(scrollButtons, scrollSize, scrollPos, scrollWidth) {
|
||||
let localeAwarePos = scrollPos;
|
||||
if (globalize.getIsElementRTL(scrollButtons)) {
|
||||
localeAwarePos *= -1;
|
||||
}
|
||||
|
||||
// TODO: Check if hack is really needed
|
||||
// hack alert add twenty for rounding errors
|
||||
if (scrollWidth <= scrollSize + 20) {
|
||||
scrollButtons.scrollButtonsLeft.classList.add('hide');
|
||||
scrollButtons.scrollButtonsRight.classList.add('hide');
|
||||
} else {
|
||||
scrollButtons.scrollButtonsLeft.classList.remove('hide');
|
||||
scrollButtons.scrollButtonsRight.classList.remove('hide');
|
||||
}
|
||||
|
||||
if (localeAwarePos > 0) {
|
||||
scrollButtons.scrollButtonsLeft.disabled = false;
|
||||
} else {
|
||||
scrollButtons.scrollButtonsLeft.disabled = true;
|
||||
}
|
||||
|
||||
const scrollPosEnd = localeAwarePos + scrollSize;
|
||||
if (scrollWidth > 0 && scrollPosEnd >= scrollWidth) {
|
||||
scrollButtons.scrollButtonsRight.disabled = true;
|
||||
} else {
|
||||
scrollButtons.scrollButtonsRight.disabled = false;
|
||||
}
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
const scrollButtons = this;
|
||||
const scroller = this.scroller;
|
||||
return value;
|
||||
}
|
||||
|
||||
const scrollSize = getScrollSize(scroller);
|
||||
const scrollPos = getScrollPosition(scroller);
|
||||
const scrollWidth = getScrollWidth(scroller);
|
||||
function getScrollSize(elem) {
|
||||
let scrollSize = elem.offsetWidth;
|
||||
let style = window.getComputedStyle(elem, null);
|
||||
|
||||
updateScrollButtons(scrollButtons, scrollSize, scrollPos, scrollWidth);
|
||||
let paddingLeft = getStyleValue(style, 'padding-left');
|
||||
if (paddingLeft) {
|
||||
scrollSize -= paddingLeft;
|
||||
}
|
||||
|
||||
function getStyleValue(style, name) {
|
||||
let value = style.getPropertyValue(name);
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = value.replace('px', '');
|
||||
if (!value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
let paddingRight = getStyleValue(style, 'padding-right');
|
||||
if (paddingRight) {
|
||||
scrollSize -= paddingRight;
|
||||
}
|
||||
|
||||
function getScrollSize(elem) {
|
||||
let scrollSize = elem.offsetWidth;
|
||||
let style = window.getComputedStyle(elem, null);
|
||||
const slider = elem.getScrollSlider();
|
||||
style = window.getComputedStyle(slider, null);
|
||||
|
||||
let paddingLeft = getStyleValue(style, 'padding-left');
|
||||
if (paddingLeft) {
|
||||
scrollSize -= paddingLeft;
|
||||
}
|
||||
|
||||
let paddingRight = getStyleValue(style, 'padding-right');
|
||||
if (paddingRight) {
|
||||
scrollSize -= paddingRight;
|
||||
}
|
||||
|
||||
const 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;
|
||||
paddingLeft = getStyleValue(style, 'padding-left');
|
||||
if (paddingLeft) {
|
||||
scrollSize -= paddingLeft;
|
||||
}
|
||||
|
||||
function onScrollButtonClick() {
|
||||
const scroller = this.parentNode.nextSibling;
|
||||
|
||||
const direction = this.getAttribute('data-direction');
|
||||
const scrollSize = getScrollSize(scroller);
|
||||
const scrollPos = getScrollPosition(scroller);
|
||||
|
||||
let newPos;
|
||||
if (direction === 'left') {
|
||||
newPos = Math.max(0, scrollPos - scrollSize);
|
||||
} else {
|
||||
newPos = scrollPos + scrollSize;
|
||||
}
|
||||
|
||||
if (globalize.getIsRTL() && direction === 'left') {
|
||||
newPos = scrollPos + scrollSize;
|
||||
} else if (globalize.getIsRTL()) {
|
||||
newPos = Math.min(0, scrollPos - scrollSize);
|
||||
}
|
||||
|
||||
scroller.scrollToPosition(newPos, false);
|
||||
paddingRight = getStyleValue(style, 'padding-right');
|
||||
if (paddingRight) {
|
||||
scrollSize -= paddingRight;
|
||||
}
|
||||
|
||||
EmbyScrollButtonsPrototype.attachedCallback = function () {
|
||||
const scroller = this.nextSibling;
|
||||
this.scroller = scroller;
|
||||
return scrollSize;
|
||||
}
|
||||
|
||||
const parent = this.parentNode;
|
||||
parent.classList.add('emby-scroller-container');
|
||||
function onScrollButtonClick() {
|
||||
const scroller = this.parentNode.nextSibling;
|
||||
|
||||
this.innerHTML = getScrollButtonHtml('left') + getScrollButtonHtml('right');
|
||||
const direction = this.getAttribute('data-direction');
|
||||
const scrollSize = getScrollSize(scroller);
|
||||
const scrollPos = getScrollPosition(scroller);
|
||||
|
||||
const buttons = this.querySelectorAll('.emby-scrollbuttons-button');
|
||||
buttons[0].addEventListener('click', onScrollButtonClick);
|
||||
buttons[1].addEventListener('click', onScrollButtonClick);
|
||||
this.scrollButtonsLeft = buttons[0];
|
||||
this.scrollButtonsRight = buttons[1];
|
||||
let newPos;
|
||||
if (direction === 'left') {
|
||||
newPos = Math.max(0, scrollPos - scrollSize);
|
||||
} else {
|
||||
newPos = scrollPos + scrollSize;
|
||||
}
|
||||
|
||||
const scrollHandler = onScroll.bind(this);
|
||||
this.scrollHandler = scrollHandler;
|
||||
scroller.addScrollEventListener(scrollHandler, {
|
||||
if (globalize.getIsRTL() && direction === 'left') {
|
||||
newPos = scrollPos + scrollSize;
|
||||
} else if (globalize.getIsRTL()) {
|
||||
newPos = Math.min(0, scrollPos - scrollSize);
|
||||
}
|
||||
|
||||
scroller.scrollToPosition(newPos, false);
|
||||
}
|
||||
|
||||
EmbyScrollButtonsPrototype.attachedCallback = function () {
|
||||
const scroller = this.nextSibling;
|
||||
this.scroller = scroller;
|
||||
|
||||
const parent = this.parentNode;
|
||||
parent.classList.add('emby-scroller-container');
|
||||
|
||||
this.innerHTML = getScrollButtonHtml('left') + getScrollButtonHtml('right');
|
||||
|
||||
const buttons = this.querySelectorAll('.emby-scrollbuttons-button');
|
||||
buttons[0].addEventListener('click', onScrollButtonClick);
|
||||
buttons[1].addEventListener('click', onScrollButtonClick);
|
||||
this.scrollButtonsLeft = buttons[0];
|
||||
this.scrollButtonsRight = buttons[1];
|
||||
|
||||
const scrollHandler = onScroll.bind(this);
|
||||
this.scrollHandler = scrollHandler;
|
||||
scroller.addScrollEventListener(scrollHandler, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
|
||||
EmbyScrollButtonsPrototype.detachedCallback = function () {
|
||||
const parent = this.scroller;
|
||||
this.scroller = null;
|
||||
|
||||
const scrollHandler = this.scrollHandler;
|
||||
if (parent && scrollHandler) {
|
||||
parent.removeScrollEventListener(scrollHandler, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
EmbyScrollButtonsPrototype.detachedCallback = function () {
|
||||
const parent = this.scroller;
|
||||
this.scroller = null;
|
||||
this.scrollHandler = null;
|
||||
this.scrollButtonsLeft = null;
|
||||
this.scrollButtonsRight = null;
|
||||
};
|
||||
|
||||
const scrollHandler = this.scrollHandler;
|
||||
if (parent && scrollHandler) {
|
||||
parent.removeScrollEventListener(scrollHandler, {
|
||||
capture: false,
|
||||
passive: true
|
||||
});
|
||||
}
|
||||
document.registerElement('emby-scrollbuttons', {
|
||||
prototype: EmbyScrollButtonsPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
this.scrollHandler = null;
|
||||
this.scrollButtonsLeft = null;
|
||||
this.scrollButtonsRight = null;
|
||||
};
|
||||
|
||||
document.registerElement('emby-scrollbuttons', {
|
||||
prototype: EmbyScrollButtonsPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -7,195 +7,192 @@ import browser from '../../scripts/browser';
|
|||
import 'webcomponents.js/webcomponents-lite';
|
||||
import './emby-scroller.scss';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const ScrollerPrototype = Object.create(HTMLDivElement.prototype);
|
||||
|
||||
const ScrollerPrototype = Object.create(HTMLDivElement.prototype);
|
||||
ScrollerPrototype.createdCallback = function () {
|
||||
this.classList.add('emby-scroller');
|
||||
};
|
||||
|
||||
ScrollerPrototype.createdCallback = function () {
|
||||
this.classList.add('emby-scroller');
|
||||
};
|
||||
|
||||
function initCenterFocus(elem, scrollerInstance) {
|
||||
dom.addEventListener(elem, 'focus', function (e) {
|
||||
const 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);
|
||||
function initCenterFocus(elem, scrollerInstance) {
|
||||
dom.addEventListener(elem, 'focus', function (e) {
|
||||
const focused = focusManager.focusableParent(e.target);
|
||||
if (focused) {
|
||||
scrollerInstance.toCenter(focused);
|
||||
}
|
||||
};
|
||||
|
||||
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) {
|
||||
const 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();
|
||||
}
|
||||
}
|
||||
|
||||
ScrollerPrototype.attachedCallback = function () {
|
||||
if (this.getAttribute('data-navcommands')) {
|
||||
inputManager.on(this, onInputCommand);
|
||||
}
|
||||
|
||||
const horizontal = this.getAttribute('data-horizontal') !== 'false';
|
||||
|
||||
const slider = this.querySelector('.scrollSlider');
|
||||
|
||||
if (horizontal) {
|
||||
slider.style['white-space'] = 'nowrap';
|
||||
}
|
||||
|
||||
const scrollFrame = this;
|
||||
const enableScrollButtons = layoutManager.desktop && horizontal && this.getAttribute('data-scrollbuttons') !== 'false';
|
||||
|
||||
const 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 || 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 (enableScrollButtons) {
|
||||
loadScrollButtons(this);
|
||||
}
|
||||
};
|
||||
|
||||
function loadScrollButtons(buttonsScroller) {
|
||||
import('../emby-scrollbuttons/emby-scrollbuttons').then(() => {
|
||||
buttonsScroller.insertAdjacentHTML('beforebegin', '<div is="emby-scrollbuttons" class="emby-scrollbuttons padded-right"></div>');
|
||||
});
|
||||
}
|
||||
|
||||
ScrollerPrototype.pause = function () {
|
||||
const headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.pause();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.resume = function () {
|
||||
const headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.resume();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.detachedCallback = function () {
|
||||
if (this.getAttribute('data-navcommands')) {
|
||||
inputManager.off(this, onInputCommand);
|
||||
}
|
||||
|
||||
const headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.destroy();
|
||||
this.headroom = null;
|
||||
}
|
||||
|
||||
const scrollerInstance = this.scroller;
|
||||
if (scrollerInstance) {
|
||||
scrollerInstance.destroy();
|
||||
this.scroller = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-scroller', {
|
||||
prototype: ScrollerPrototype,
|
||||
extends: 'div'
|
||||
}, {
|
||||
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) {
|
||||
const 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();
|
||||
}
|
||||
}
|
||||
|
||||
ScrollerPrototype.attachedCallback = function () {
|
||||
if (this.getAttribute('data-navcommands')) {
|
||||
inputManager.on(this, onInputCommand);
|
||||
}
|
||||
|
||||
const horizontal = this.getAttribute('data-horizontal') !== 'false';
|
||||
|
||||
const slider = this.querySelector('.scrollSlider');
|
||||
|
||||
if (horizontal) {
|
||||
slider.style['white-space'] = 'nowrap';
|
||||
}
|
||||
|
||||
const scrollFrame = this;
|
||||
const enableScrollButtons = layoutManager.desktop && horizontal && this.getAttribute('data-scrollbuttons') !== 'false';
|
||||
|
||||
const 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 || 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 (enableScrollButtons) {
|
||||
loadScrollButtons(this);
|
||||
}
|
||||
};
|
||||
|
||||
function loadScrollButtons(buttonsScroller) {
|
||||
import('../emby-scrollbuttons/emby-scrollbuttons').then(() => {
|
||||
buttonsScroller.insertAdjacentHTML('beforebegin', '<div is="emby-scrollbuttons" class="emby-scrollbuttons padded-right"></div>');
|
||||
});
|
||||
}
|
||||
|
||||
ScrollerPrototype.pause = function () {
|
||||
const headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.pause();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.resume = function () {
|
||||
const headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.resume();
|
||||
}
|
||||
};
|
||||
|
||||
ScrollerPrototype.detachedCallback = function () {
|
||||
if (this.getAttribute('data-navcommands')) {
|
||||
inputManager.off(this, onInputCommand);
|
||||
}
|
||||
|
||||
const headroom = this.headroom;
|
||||
if (headroom) {
|
||||
headroom.destroy();
|
||||
this.headroom = null;
|
||||
}
|
||||
|
||||
const scrollerInstance = this.scroller;
|
||||
if (scrollerInstance) {
|
||||
scrollerInstance.destroy();
|
||||
this.scroller = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-scroller', {
|
||||
prototype: ScrollerPrototype,
|
||||
extends: 'div'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -4,152 +4,149 @@ import actionsheet from '../../components/actionSheet/actionSheet';
|
|||
import './emby-select.scss';
|
||||
import 'webcomponents.js/webcomponents-lite';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const EmbySelectPrototype = Object.create(HTMLSelectElement.prototype);
|
||||
|
||||
const EmbySelectPrototype = Object.create(HTMLSelectElement.prototype);
|
||||
|
||||
function enableNativeMenu() {
|
||||
if (browser.edgeUwp || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Doesn't seem to work at all
|
||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Take advantage of the native input methods
|
||||
if (browser.tv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return !layoutManager.tv;
|
||||
function enableNativeMenu() {
|
||||
if (browser.edgeUwp || browser.xboxOne) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function triggerChange(select) {
|
||||
const evt = document.createEvent('HTMLEvents');
|
||||
evt.initEvent('change', false, true);
|
||||
select.dispatchEvent(evt);
|
||||
// Doesn't seem to work at all
|
||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function setValue(select, value) {
|
||||
select.value = value;
|
||||
// Take advantage of the native input methods
|
||||
if (browser.tv) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function showActionSheet(select) {
|
||||
const labelElem = getLabel(select);
|
||||
const title = labelElem ? (labelElem.textContent || labelElem.innerText) : null;
|
||||
return !layoutManager.tv;
|
||||
}
|
||||
|
||||
actionsheet.show({
|
||||
items: select.options,
|
||||
positionTo: select,
|
||||
title: title
|
||||
function triggerChange(select) {
|
||||
const evt = document.createEvent('HTMLEvents');
|
||||
evt.initEvent('change', false, true);
|
||||
select.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
}).then(function (value) {
|
||||
setValue(select, value);
|
||||
triggerChange(select);
|
||||
});
|
||||
}
|
||||
function setValue(select, value) {
|
||||
select.value = value;
|
||||
}
|
||||
|
||||
function getLabel(select) {
|
||||
let elem = select.previousSibling;
|
||||
while (elem && elem.tagName !== 'LABEL') {
|
||||
elem = elem.previousSibling;
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
function showActionSheet(select) {
|
||||
const labelElem = getLabel(select);
|
||||
const title = labelElem ? (labelElem.textContent || labelElem.innerText) : null;
|
||||
|
||||
function onFocus() {
|
||||
const label = getLabel(this);
|
||||
if (label) {
|
||||
label.classList.add('selectLabelFocused');
|
||||
}
|
||||
}
|
||||
actionsheet.show({
|
||||
items: select.options,
|
||||
positionTo: select,
|
||||
title: title
|
||||
|
||||
function onBlur() {
|
||||
const label = getLabel(this);
|
||||
if (label) {
|
||||
label.classList.remove('selectLabelFocused');
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
// e.button=0 for primary (left) mouse button click
|
||||
if (!e.button && !enableNativeMenu()) {
|
||||
e.preventDefault();
|
||||
showActionSheet(this);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDown(e) {
|
||||
switch (e.keyCode) {
|
||||
case 13:
|
||||
if (!enableNativeMenu()) {
|
||||
e.preventDefault();
|
||||
showActionSheet(this);
|
||||
}
|
||||
return;
|
||||
case 37:
|
||||
case 38:
|
||||
case 39:
|
||||
case 40:
|
||||
if (layoutManager.tv) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let inputId = 0;
|
||||
|
||||
EmbySelectPrototype.createdCallback = function () {
|
||||
if (!this.id) {
|
||||
this.id = 'embyselect' + inputId;
|
||||
inputId++;
|
||||
}
|
||||
|
||||
this.classList.add('emby-select-withcolor');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('emby-select-focusscale');
|
||||
}
|
||||
|
||||
this.addEventListener('mousedown', onMouseDown);
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
|
||||
this.addEventListener('focus', onFocus);
|
||||
this.addEventListener('blur', onBlur);
|
||||
};
|
||||
|
||||
EmbySelectPrototype.attachedCallback = function () {
|
||||
if (this.classList.contains('emby-select')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classList.add('emby-select');
|
||||
|
||||
const label = this.ownerDocument.createElement('label');
|
||||
label.innerText = this.getAttribute('label') || '';
|
||||
label.classList.add('selectLabel');
|
||||
label.htmlFor = this.id;
|
||||
this.parentNode?.insertBefore(label, this);
|
||||
|
||||
if (this.classList.contains('emby-select-withcolor')) {
|
||||
this.parentNode?.insertAdjacentHTML('beforeend', '<div class="selectArrowContainer"><div style="visibility:hidden;display:none;">0</div><span class="selectArrow material-icons keyboard_arrow_down" aria-hidden="true"></span></div>');
|
||||
}
|
||||
};
|
||||
|
||||
EmbySelectPrototype.setLabel = function (text) {
|
||||
const label = this.parentNode?.querySelector('label');
|
||||
|
||||
label.innerText = text;
|
||||
};
|
||||
|
||||
document.registerElement('emby-select', {
|
||||
prototype: EmbySelectPrototype,
|
||||
extends: 'select'
|
||||
}).then(function (value) {
|
||||
setValue(select, value);
|
||||
triggerChange(select);
|
||||
});
|
||||
}
|
||||
|
||||
function getLabel(select) {
|
||||
let elem = select.previousSibling;
|
||||
while (elem && elem.tagName !== 'LABEL') {
|
||||
elem = elem.previousSibling;
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
function onFocus() {
|
||||
const label = getLabel(this);
|
||||
if (label) {
|
||||
label.classList.add('selectLabelFocused');
|
||||
}
|
||||
}
|
||||
|
||||
function onBlur() {
|
||||
const label = getLabel(this);
|
||||
if (label) {
|
||||
label.classList.remove('selectLabelFocused');
|
||||
}
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
// e.button=0 for primary (left) mouse button click
|
||||
if (!e.button && !enableNativeMenu()) {
|
||||
e.preventDefault();
|
||||
showActionSheet(this);
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDown(e) {
|
||||
switch (e.keyCode) {
|
||||
case 13:
|
||||
if (!enableNativeMenu()) {
|
||||
e.preventDefault();
|
||||
showActionSheet(this);
|
||||
}
|
||||
return;
|
||||
case 37:
|
||||
case 38:
|
||||
case 39:
|
||||
case 40:
|
||||
if (layoutManager.tv) {
|
||||
e.preventDefault();
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let inputId = 0;
|
||||
|
||||
EmbySelectPrototype.createdCallback = function () {
|
||||
if (!this.id) {
|
||||
this.id = 'embyselect' + inputId;
|
||||
inputId++;
|
||||
}
|
||||
|
||||
this.classList.add('emby-select-withcolor');
|
||||
|
||||
if (layoutManager.tv) {
|
||||
this.classList.add('emby-select-focusscale');
|
||||
}
|
||||
|
||||
this.addEventListener('mousedown', onMouseDown);
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
|
||||
this.addEventListener('focus', onFocus);
|
||||
this.addEventListener('blur', onBlur);
|
||||
};
|
||||
|
||||
EmbySelectPrototype.attachedCallback = function () {
|
||||
if (this.classList.contains('emby-select')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.classList.add('emby-select');
|
||||
|
||||
const label = this.ownerDocument.createElement('label');
|
||||
label.innerText = this.getAttribute('label') || '';
|
||||
label.classList.add('selectLabel');
|
||||
label.htmlFor = this.id;
|
||||
this.parentNode?.insertBefore(label, this);
|
||||
|
||||
if (this.classList.contains('emby-select-withcolor')) {
|
||||
this.parentNode?.insertAdjacentHTML('beforeend', '<div class="selectArrowContainer"><div style="visibility:hidden;display:none;">0</div><span class="selectArrow material-icons keyboard_arrow_down" aria-hidden="true"></span></div>');
|
||||
}
|
||||
};
|
||||
|
||||
EmbySelectPrototype.setLabel = function (text) {
|
||||
const label = this.parentNode?.querySelector('label');
|
||||
|
||||
label.innerText = text;
|
||||
};
|
||||
|
||||
document.registerElement('emby-select', {
|
||||
prototype: EmbySelectPrototype,
|
||||
extends: 'select'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -7,334 +7,332 @@ import layoutManager from '../../components/layoutManager';
|
|||
import './emby-tabs.scss';
|
||||
import '../../styles/scrollstyles.scss';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const EmbyTabs = Object.create(HTMLDivElement.prototype);
|
||||
const buttonClass = 'emby-tab-button';
|
||||
const activeButtonClass = buttonClass + '-active';
|
||||
const EmbyTabs = Object.create(HTMLDivElement.prototype);
|
||||
const buttonClass = 'emby-tab-button';
|
||||
const activeButtonClass = buttonClass + '-active';
|
||||
|
||||
function setActiveTabButton(newButton) {
|
||||
newButton.classList.add(activeButtonClass);
|
||||
function setActiveTabButton(newButton) {
|
||||
newButton.classList.add(activeButtonClass);
|
||||
}
|
||||
|
||||
function getTabPanel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
function removeActivePanelClass() {
|
||||
const tabPanel = getTabPanel();
|
||||
if (tabPanel) {
|
||||
tabPanel.classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
function fadeInRight(elem) {
|
||||
const pct = browser.mobile ? '4%' : '0.5%';
|
||||
|
||||
const 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();
|
||||
}
|
||||
|
||||
function getTabPanel() {
|
||||
return null;
|
||||
const newPanel = getTabPanel();
|
||||
|
||||
if (newPanel) {
|
||||
// animate new panel ?
|
||||
if (newPanel.animate) {
|
||||
fadeInRight(newPanel);
|
||||
}
|
||||
|
||||
newPanel.classList.add('is-active');
|
||||
}
|
||||
}
|
||||
|
||||
function removeActivePanelClass() {
|
||||
const tabPanel = getTabPanel();
|
||||
if (tabPanel) {
|
||||
tabPanel.classList.remove('is-active');
|
||||
}
|
||||
}
|
||||
function onClick(e) {
|
||||
const tabs = this;
|
||||
|
||||
function fadeInRight(elem) {
|
||||
const pct = browser.mobile ? '4%' : '0.5%';
|
||||
const current = tabs.querySelector('.' + activeButtonClass);
|
||||
const tabButton = dom.parentWithClass(e.target, buttonClass);
|
||||
|
||||
const 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();
|
||||
if (tabButton && tabButton !== current) {
|
||||
if (current) {
|
||||
current.classList.remove(activeButtonClass);
|
||||
}
|
||||
|
||||
const newPanel = getTabPanel();
|
||||
const previousIndex = current ? parseInt(current.getAttribute('data-index'), 10) : null;
|
||||
|
||||
if (newPanel) {
|
||||
// animate new panel ?
|
||||
if (newPanel.animate) {
|
||||
fadeInRight(newPanel);
|
||||
}
|
||||
setActiveTabButton(tabButton);
|
||||
|
||||
newPanel.classList.add('is-active');
|
||||
}
|
||||
}
|
||||
const index = parseInt(tabButton.getAttribute('data-index'), 10);
|
||||
|
||||
function onClick(e) {
|
||||
const tabs = this;
|
||||
triggerBeforeTabChange(tabs, index, previousIndex);
|
||||
|
||||
const current = tabs.querySelector('.' + activeButtonClass);
|
||||
const tabButton = dom.parentWithClass(e.target, buttonClass);
|
||||
|
||||
if (tabButton && tabButton !== current) {
|
||||
if (current) {
|
||||
current.classList.remove(activeButtonClass);
|
||||
}
|
||||
|
||||
const previousIndex = current ? parseInt(current.getAttribute('data-index'), 10) : null;
|
||||
|
||||
setActiveTabButton(tabButton);
|
||||
|
||||
const index = parseInt(tabButton.getAttribute('data-index'), 10);
|
||||
|
||||
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 onFocusIn(e) {
|
||||
const tabs = this;
|
||||
const tabButton = dom.parentWithClass(e.target, buttonClass);
|
||||
if (tabButton && tabs.scroller) {
|
||||
tabs.scroller.toCenter(tabButton, false);
|
||||
}
|
||||
}
|
||||
|
||||
function onFocusOut(e) {
|
||||
const parentContainer = e.target.parentNode;
|
||||
const previousFocus = parentContainer.querySelector('.lastFocused');
|
||||
if (previousFocus) {
|
||||
previousFocus.classList.remove('lastFocused');
|
||||
}
|
||||
e.target.classList.add('lastFocused');
|
||||
}
|
||||
|
||||
function initScroller(tabs) {
|
||||
if (tabs.scroller) {
|
||||
return;
|
||||
}
|
||||
|
||||
const 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
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dom.addEventListener(this, 'focusin', onFocusIn, { passive: true });
|
||||
}
|
||||
|
||||
dom.addEventListener(this, 'focusout', onFocusOut);
|
||||
};
|
||||
|
||||
EmbyTabs.focus = function () {
|
||||
const selectedTab = this.querySelector('.' + activeButtonClass);
|
||||
const lastFocused = this.querySelector('.lastFocused');
|
||||
|
||||
if (lastFocused) {
|
||||
focusManager.focus(lastFocused);
|
||||
} else if (selectedTab) {
|
||||
focusManager.focus(selectedTab);
|
||||
} else {
|
||||
focusManager.autoFocus(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.refresh = function () {
|
||||
if (this.scroller) {
|
||||
this.scroller.reload();
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.attachedCallback = function () {
|
||||
initScroller(this);
|
||||
|
||||
const current = this.querySelector('.' + activeButtonClass);
|
||||
const currentIndex = current ? parseInt(current.getAttribute('data-index'), 10) : parseInt(this.getAttribute('data-index') || '0', 10);
|
||||
|
||||
if (currentIndex !== -1) {
|
||||
this.selectedTabIndex = currentIndex;
|
||||
|
||||
const tabButtons = this.querySelectorAll('.' + buttonClass);
|
||||
|
||||
const newTabButton = tabButtons[currentIndex];
|
||||
|
||||
if (newTabButton) {
|
||||
setActiveTabButton(newTabButton);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dom.removeEventListener(this, 'focusin', onFocusIn, { passive: true });
|
||||
}
|
||||
};
|
||||
|
||||
function getSelectedTabButton(elem) {
|
||||
return elem.querySelector('.' + activeButtonClass);
|
||||
}
|
||||
|
||||
EmbyTabs.selectedIndex = function (selected, triggerEvent) {
|
||||
const tabs = this;
|
||||
|
||||
if (selected == null) {
|
||||
return tabs.selectedTabIndex || 0;
|
||||
}
|
||||
|
||||
const current = tabs.selectedIndex();
|
||||
|
||||
tabs.selectedTabIndex = selected;
|
||||
|
||||
const tabButtons = tabs.querySelectorAll('.' + buttonClass);
|
||||
|
||||
if (current === selected || triggerEvent === false) {
|
||||
triggerBeforeTabChange(tabs, selected, current);
|
||||
// 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: selected
|
||||
selectedTabIndex: index,
|
||||
previousIndex: previousIndex
|
||||
}
|
||||
}));
|
||||
}, 120);
|
||||
|
||||
const currentTabButton = tabButtons[current];
|
||||
setActiveTabButton(tabButtons[selected]);
|
||||
|
||||
if (current !== selected && currentTabButton) {
|
||||
currentTabButton.classList.remove(activeButtonClass);
|
||||
}
|
||||
} else {
|
||||
onClick.call(tabs, {
|
||||
target: tabButtons[selected]
|
||||
});
|
||||
if (tabs.scroller) {
|
||||
tabs.scroller.toCenter(tabButton, false);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getSibling(elem, method) {
|
||||
let sibling = elem[method];
|
||||
function onFocusIn(e) {
|
||||
const tabs = this;
|
||||
const tabButton = dom.parentWithClass(e.target, buttonClass);
|
||||
if (tabButton && tabs.scroller) {
|
||||
tabs.scroller.toCenter(tabButton, false);
|
||||
}
|
||||
}
|
||||
|
||||
while (sibling) {
|
||||
if (sibling.classList.contains(buttonClass) && !sibling.classList.contains('hide')) {
|
||||
return sibling;
|
||||
}
|
||||
function onFocusOut(e) {
|
||||
const parentContainer = e.target.parentNode;
|
||||
const previousFocus = parentContainer.querySelector('.lastFocused');
|
||||
if (previousFocus) {
|
||||
previousFocus.classList.remove('lastFocused');
|
||||
}
|
||||
e.target.classList.add('lastFocused');
|
||||
}
|
||||
|
||||
sibling = sibling[method];
|
||||
}
|
||||
|
||||
return null;
|
||||
function initScroller(tabs) {
|
||||
if (tabs.scroller) {
|
||||
return;
|
||||
}
|
||||
|
||||
EmbyTabs.selectNext = function () {
|
||||
const current = getSelectedTabButton(this);
|
||||
const 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,
|
||||
|
||||
const sibling = getSibling(current, 'nextSibling');
|
||||
// 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');
|
||||
}
|
||||
}
|
||||
|
||||
if (sibling) {
|
||||
onClick.call(this, {
|
||||
target: sibling
|
||||
});
|
||||
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
|
||||
});
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dom.addEventListener(this, 'focusin', onFocusIn, { passive: true });
|
||||
}
|
||||
|
||||
dom.addEventListener(this, 'focusout', onFocusOut);
|
||||
};
|
||||
|
||||
EmbyTabs.focus = function () {
|
||||
const selectedTab = this.querySelector('.' + activeButtonClass);
|
||||
const lastFocused = this.querySelector('.lastFocused');
|
||||
|
||||
if (lastFocused) {
|
||||
focusManager.focus(lastFocused);
|
||||
} else if (selectedTab) {
|
||||
focusManager.focus(selectedTab);
|
||||
} else {
|
||||
focusManager.autoFocus(this);
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.refresh = function () {
|
||||
if (this.scroller) {
|
||||
this.scroller.reload();
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.attachedCallback = function () {
|
||||
initScroller(this);
|
||||
|
||||
const current = this.querySelector('.' + activeButtonClass);
|
||||
const currentIndex = current ? parseInt(current.getAttribute('data-index'), 10) : parseInt(this.getAttribute('data-index') || '0', 10);
|
||||
|
||||
if (currentIndex !== -1) {
|
||||
this.selectedTabIndex = currentIndex;
|
||||
|
||||
const tabButtons = this.querySelectorAll('.' + buttonClass);
|
||||
|
||||
const newTabButton = tabButtons[currentIndex];
|
||||
|
||||
if (newTabButton) {
|
||||
setActiveTabButton(newTabButton);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
EmbyTabs.selectPrevious = function () {
|
||||
const current = getSelectedTabButton(this);
|
||||
if (!this.readyFired) {
|
||||
this.readyFired = true;
|
||||
this.dispatchEvent(new CustomEvent('ready', {}));
|
||||
}
|
||||
};
|
||||
|
||||
const sibling = getSibling(current, 'previousSibling');
|
||||
EmbyTabs.detachedCallback = function () {
|
||||
if (this.scroller) {
|
||||
this.scroller.destroy();
|
||||
this.scroller = null;
|
||||
}
|
||||
|
||||
if (sibling) {
|
||||
onClick.call(this, {
|
||||
target: sibling
|
||||
});
|
||||
}
|
||||
};
|
||||
dom.removeEventListener(this, 'click', onClick, {
|
||||
passive: true
|
||||
});
|
||||
|
||||
EmbyTabs.triggerBeforeTabChange = function () {
|
||||
const tabs = this;
|
||||
if (layoutManager.tv) {
|
||||
dom.removeEventListener(this, 'focusin', onFocusIn, { passive: true });
|
||||
}
|
||||
};
|
||||
|
||||
triggerBeforeTabChange(tabs, tabs.selectedIndex());
|
||||
};
|
||||
function getSelectedTabButton(elem) {
|
||||
return elem.querySelector('.' + activeButtonClass);
|
||||
}
|
||||
|
||||
EmbyTabs.triggerTabChange = function () {
|
||||
const tabs = this;
|
||||
EmbyTabs.selectedIndex = function (selected, triggerEvent) {
|
||||
const tabs = this;
|
||||
|
||||
if (selected == null) {
|
||||
return tabs.selectedTabIndex || 0;
|
||||
}
|
||||
|
||||
const current = tabs.selectedIndex();
|
||||
|
||||
tabs.selectedTabIndex = selected;
|
||||
|
||||
const tabButtons = tabs.querySelectorAll('.' + buttonClass);
|
||||
|
||||
if (current === selected || triggerEvent === false) {
|
||||
triggerBeforeTabChange(tabs, selected, current);
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent('tabchange', {
|
||||
detail: {
|
||||
selectedTabIndex: tabs.selectedIndex()
|
||||
selectedTabIndex: selected
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
EmbyTabs.setTabEnabled = function (index, enabled) {
|
||||
const btn = this.querySelector('.emby-tab-button[data-index="' + index + '"]');
|
||||
const currentTabButton = tabButtons[current];
|
||||
setActiveTabButton(tabButtons[selected]);
|
||||
|
||||
if (enabled) {
|
||||
btn.classList.remove('hide');
|
||||
} else {
|
||||
btn.classList.remove('add');
|
||||
if (current !== selected && currentTabButton) {
|
||||
currentTabButton.classList.remove(activeButtonClass);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
onClick.call(tabs, {
|
||||
target: tabButtons[selected]
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
document.registerElement('emby-tabs', {
|
||||
prototype: EmbyTabs,
|
||||
extends: 'div'
|
||||
});
|
||||
function getSibling(elem, method) {
|
||||
let sibling = elem[method];
|
||||
|
||||
while (sibling) {
|
||||
if (sibling.classList.contains(buttonClass) && !sibling.classList.contains('hide')) {
|
||||
return sibling;
|
||||
}
|
||||
|
||||
sibling = sibling[method];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
EmbyTabs.selectNext = function () {
|
||||
const current = getSelectedTabButton(this);
|
||||
|
||||
const sibling = getSibling(current, 'nextSibling');
|
||||
|
||||
if (sibling) {
|
||||
onClick.call(this, {
|
||||
target: sibling
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.selectPrevious = function () {
|
||||
const current = getSelectedTabButton(this);
|
||||
|
||||
const sibling = getSibling(current, 'previousSibling');
|
||||
|
||||
if (sibling) {
|
||||
onClick.call(this, {
|
||||
target: sibling
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTabs.triggerBeforeTabChange = function () {
|
||||
const tabs = this;
|
||||
|
||||
triggerBeforeTabChange(tabs, tabs.selectedIndex());
|
||||
};
|
||||
|
||||
EmbyTabs.triggerTabChange = function () {
|
||||
const tabs = this;
|
||||
|
||||
tabs.dispatchEvent(new CustomEvent('tabchange', {
|
||||
detail: {
|
||||
selectedTabIndex: tabs.selectedIndex()
|
||||
}
|
||||
}));
|
||||
};
|
||||
|
||||
EmbyTabs.setTabEnabled = function (index, enabled) {
|
||||
const 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'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -19,119 +19,117 @@ function calculateOffset(textarea) {
|
|||
return offset;
|
||||
}
|
||||
|
||||
/* eslint-disable indent */
|
||||
function autoGrow(textarea, maxLines) {
|
||||
const self = this;
|
||||
function autoGrow(textarea, maxLines) {
|
||||
const self = this;
|
||||
|
||||
if (maxLines === undefined) {
|
||||
maxLines = 999;
|
||||
}
|
||||
|
||||
let offset;
|
||||
function reset() {
|
||||
textarea.rows = 1;
|
||||
offset = calculateOffset(textarea);
|
||||
self.rows = textarea.rows || 1;
|
||||
self.lineHeight = (textarea.scrollHeight / self.rows) - (offset / self.rows);
|
||||
self.maxAllowedHeight = (self.lineHeight * maxLines) - offset;
|
||||
}
|
||||
|
||||
function autogrowFn() {
|
||||
if (!self.lineHeight || self.lineHeight <= 0) {
|
||||
reset();
|
||||
}
|
||||
if (self.lineHeight <= 0) {
|
||||
textarea.style.overflowY = 'scroll';
|
||||
textarea.style.height = 'auto';
|
||||
textarea.rows = 3;
|
||||
return;
|
||||
}
|
||||
let newHeight = 0;
|
||||
|
||||
if ((textarea.scrollHeight - offset) > self.maxAllowedHeight) {
|
||||
textarea.style.overflowY = 'scroll';
|
||||
newHeight = self.maxAllowedHeight;
|
||||
} else {
|
||||
textarea.style.overflowY = 'hidden';
|
||||
textarea.style.height = 'auto';
|
||||
newHeight = textarea.scrollHeight/* - offset*/;
|
||||
}
|
||||
textarea.style.height = newHeight + 'px';
|
||||
}
|
||||
|
||||
// Call autogrowFn() when textarea's value is changed
|
||||
textarea.addEventListener('input', autogrowFn);
|
||||
textarea.addEventListener('focus', autogrowFn);
|
||||
textarea.addEventListener('valueset', autogrowFn);
|
||||
|
||||
autogrowFn();
|
||||
if (maxLines === undefined) {
|
||||
maxLines = 999;
|
||||
}
|
||||
|
||||
const EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype);
|
||||
|
||||
let elementId = 0;
|
||||
|
||||
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
|
||||
|
||||
// descriptor returning null in webos
|
||||
if (descriptor && descriptor.configurable) {
|
||||
const baseSetMethod = descriptor.set;
|
||||
descriptor.set = function (value) {
|
||||
baseSetMethod.call(this, value);
|
||||
|
||||
this.dispatchEvent(new CustomEvent('valueset', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
};
|
||||
|
||||
Object.defineProperty(HTMLTextAreaElement.prototype, 'value', descriptor);
|
||||
}
|
||||
let offset;
|
||||
function reset() {
|
||||
textarea.rows = 1;
|
||||
offset = calculateOffset(textarea);
|
||||
self.rows = textarea.rows || 1;
|
||||
self.lineHeight = (textarea.scrollHeight / self.rows) - (offset / self.rows);
|
||||
self.maxAllowedHeight = (self.lineHeight * maxLines) - offset;
|
||||
}
|
||||
|
||||
EmbyTextAreaPrototype.createdCallback = function () {
|
||||
if (!this.id) {
|
||||
this.id = 'embytextarea' + elementId;
|
||||
elementId++;
|
||||
function autogrowFn() {
|
||||
if (!self.lineHeight || self.lineHeight <= 0) {
|
||||
reset();
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTextAreaPrototype.attachedCallback = function () {
|
||||
if (this.classList.contains('emby-textarea')) {
|
||||
if (self.lineHeight <= 0) {
|
||||
textarea.style.overflowY = 'scroll';
|
||||
textarea.style.height = 'auto';
|
||||
textarea.rows = 3;
|
||||
return;
|
||||
}
|
||||
let newHeight = 0;
|
||||
|
||||
this.rows = 1;
|
||||
this.classList.add('emby-textarea');
|
||||
if ((textarea.scrollHeight - offset) > self.maxAllowedHeight) {
|
||||
textarea.style.overflowY = 'scroll';
|
||||
newHeight = self.maxAllowedHeight;
|
||||
} else {
|
||||
textarea.style.overflowY = 'hidden';
|
||||
textarea.style.height = 'auto';
|
||||
newHeight = textarea.scrollHeight/* - offset*/;
|
||||
}
|
||||
textarea.style.height = newHeight + 'px';
|
||||
}
|
||||
|
||||
const parentNode = this.parentNode;
|
||||
const label = this.ownerDocument.createElement('label');
|
||||
label.innerText = this.getAttribute('label') || '';
|
||||
label.classList.add('textareaLabel');
|
||||
// Call autogrowFn() when textarea's value is changed
|
||||
textarea.addEventListener('input', autogrowFn);
|
||||
textarea.addEventListener('focus', autogrowFn);
|
||||
textarea.addEventListener('valueset', autogrowFn);
|
||||
|
||||
label.htmlFor = this.id;
|
||||
parentNode.insertBefore(label, this);
|
||||
autogrowFn();
|
||||
}
|
||||
|
||||
this.addEventListener('focus', function () {
|
||||
label.classList.add('textareaLabelFocused');
|
||||
label.classList.remove('textareaLabelUnfocused');
|
||||
});
|
||||
this.addEventListener('blur', function () {
|
||||
label.classList.remove('textareaLabelFocused');
|
||||
label.classList.add('textareaLabelUnfocused');
|
||||
});
|
||||
const EmbyTextAreaPrototype = Object.create(HTMLTextAreaElement.prototype);
|
||||
|
||||
this.label = function (text) {
|
||||
label.innerText = text;
|
||||
let elementId = 0;
|
||||
|
||||
if (Object.getOwnPropertyDescriptor && Object.defineProperty) {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
|
||||
|
||||
// descriptor returning null in webos
|
||||
if (descriptor && descriptor.configurable) {
|
||||
const baseSetMethod = descriptor.set;
|
||||
descriptor.set = function (value) {
|
||||
baseSetMethod.call(this, value);
|
||||
|
||||
this.dispatchEvent(new CustomEvent('valueset', {
|
||||
bubbles: false,
|
||||
cancelable: false
|
||||
}));
|
||||
};
|
||||
|
||||
new autoGrow(this);
|
||||
};
|
||||
Object.defineProperty(HTMLTextAreaElement.prototype, 'value', descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
document.registerElement('emby-textarea', {
|
||||
prototype: EmbyTextAreaPrototype,
|
||||
extends: 'textarea'
|
||||
EmbyTextAreaPrototype.createdCallback = function () {
|
||||
if (!this.id) {
|
||||
this.id = 'embytextarea' + elementId;
|
||||
elementId++;
|
||||
}
|
||||
};
|
||||
|
||||
EmbyTextAreaPrototype.attachedCallback = function () {
|
||||
if (this.classList.contains('emby-textarea')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.rows = 1;
|
||||
this.classList.add('emby-textarea');
|
||||
|
||||
const parentNode = this.parentNode;
|
||||
const label = this.ownerDocument.createElement('label');
|
||||
label.innerText = this.getAttribute('label') || '';
|
||||
label.classList.add('textareaLabel');
|
||||
|
||||
label.htmlFor = this.id;
|
||||
parentNode.insertBefore(label, this);
|
||||
|
||||
this.addEventListener('focus', function () {
|
||||
label.classList.add('textareaLabelFocused');
|
||||
label.classList.remove('textareaLabelUnfocused');
|
||||
});
|
||||
this.addEventListener('blur', function () {
|
||||
label.classList.remove('textareaLabelFocused');
|
||||
label.classList.add('textareaLabelUnfocused');
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
this.label = function (text) {
|
||||
label.innerText = text;
|
||||
};
|
||||
|
||||
new autoGrow(this);
|
||||
};
|
||||
|
||||
document.registerElement('emby-textarea', {
|
||||
prototype: EmbyTextAreaPrototype,
|
||||
extends: 'textarea'
|
||||
});
|
||||
|
||||
|
|
|
@ -1,51 +1,48 @@
|
|||
import './emby-toggle.scss';
|
||||
import 'webcomponents.js/webcomponents-lite';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const EmbyTogglePrototype = Object.create(HTMLInputElement.prototype);
|
||||
|
||||
const EmbyTogglePrototype = Object.create(HTMLInputElement.prototype);
|
||||
function onKeyDown(e) {
|
||||
// Don't submit form on enter
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
|
||||
function onKeyDown(e) {
|
||||
// Don't submit form on enter
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
this.checked = !this.checked;
|
||||
|
||||
this.checked = !this.checked;
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
|
||||
this.dispatchEvent(new CustomEvent('change', {
|
||||
bubbles: true
|
||||
}));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EmbyTogglePrototype.attachedCallback = function () {
|
||||
if (this.getAttribute('data-embytoggle') === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
EmbyTogglePrototype.attachedCallback = function () {
|
||||
if (this.getAttribute('data-embytoggle') === 'true') {
|
||||
return;
|
||||
}
|
||||
this.setAttribute('data-embytoggle', 'true');
|
||||
|
||||
this.setAttribute('data-embytoggle', 'true');
|
||||
this.classList.add('mdl-switch__input');
|
||||
|
||||
this.classList.add('mdl-switch__input');
|
||||
const labelElement = this.parentNode;
|
||||
labelElement.classList.add('mdl-switch');
|
||||
labelElement.classList.add('mdl-js-switch');
|
||||
|
||||
const labelElement = this.parentNode;
|
||||
labelElement.classList.add('mdl-switch');
|
||||
labelElement.classList.add('mdl-js-switch');
|
||||
const labelTextElement = labelElement.querySelector('span');
|
||||
|
||||
const labelTextElement = labelElement.querySelector('span');
|
||||
labelElement.insertAdjacentHTML('beforeend', '<div class="mdl-switch__trackContainer"><div class="mdl-switch__track"></div><div class="mdl-switch__thumb"><span class="mdl-switch__focus-helper"></span></div></div>');
|
||||
|
||||
labelElement.insertAdjacentHTML('beforeend', '<div class="mdl-switch__trackContainer"><div class="mdl-switch__track"></div><div class="mdl-switch__thumb"><span class="mdl-switch__focus-helper"></span></div></div>');
|
||||
labelTextElement.classList.add('toggleButtonLabel');
|
||||
labelTextElement.classList.add('mdl-switch__label');
|
||||
|
||||
labelTextElement.classList.add('toggleButtonLabel');
|
||||
labelTextElement.classList.add('mdl-switch__label');
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
};
|
||||
|
||||
this.addEventListener('keydown', onKeyDown);
|
||||
};
|
||||
document.registerElement('emby-toggle', {
|
||||
prototype: EmbyTogglePrototype,
|
||||
extends: 'input'
|
||||
});
|
||||
|
||||
document.registerElement('emby-toggle', {
|
||||
prototype: EmbyTogglePrototype,
|
||||
extends: 'input'
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue