2019-01-10 15:39:37 +03:00
|
|
|
|
define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'registerElement', 'css!./emby-tabs', 'scrollStyles'], function (dom, scroller, browser, layoutManager, focusManager) {
|
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
var EmbyTabs = Object.create(HTMLDivElement.prototype);
|
|
|
|
|
var buttonClass = 'emby-tab-button';
|
|
|
|
|
var activeButtonClass = buttonClass + '-active';
|
2018-10-23 01:05:09 +03:00
|
|
|
|
|
|
|
|
|
function setActiveTabButton(tabs, newButton, oldButton, animate) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
newButton.classList.add(activeButtonClass);
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getFocusCallback(tabs, e) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
return function () {
|
|
|
|
|
onClick.call(tabs, e);
|
|
|
|
|
};
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onFocus(e) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
if (layoutManager.tv) {
|
|
|
|
|
|
|
|
|
|
if (this.focusTimeout) {
|
|
|
|
|
clearTimeout(this.focusTimeout);
|
|
|
|
|
}
|
|
|
|
|
this.focusTimeout = setTimeout(getFocusCallback(this, e), 700);
|
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getTabPanel(tabs, index) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
return null;
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function removeActivePanelClass(tabs, index) {
|
|
|
|
|
var tabPanel = getTabPanel(tabs, index);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
if (tabPanel) {
|
|
|
|
|
tabPanel.classList.remove('is-active');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function addActivePanelClass(tabs, index) {
|
|
|
|
|
var tabPanel = getTabPanel(tabs, index);
|
|
|
|
|
if (tabPanel) {
|
|
|
|
|
tabPanel.classList.add('is-active');
|
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function fadeInRight(elem) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
var pct = browser.mobile ? '4%' : '0.5%';
|
|
|
|
|
|
|
|
|
|
var keyframes = [
|
|
|
|
|
{ opacity: '0', transform: 'translate3d(' + pct + ', 0, 0)', offset: 0 },
|
|
|
|
|
{ opacity: '1', transform: 'none', offset: 1 }];
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
elem.animate(keyframes, {
|
|
|
|
|
duration: 160,
|
|
|
|
|
iterations: 1,
|
2019-01-10 15:39:37 +03:00
|
|
|
|
easing: 'ease-out'
|
|
|
|
|
});
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function triggerBeforeTabChange(tabs, index, previousIndex) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
tabs.dispatchEvent(new CustomEvent("beforetabchange", {
|
|
|
|
|
detail: {
|
|
|
|
|
selectedTabIndex: index,
|
|
|
|
|
previousIndex: previousIndex
|
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
}));
|
|
|
|
|
if (previousIndex != null && previousIndex !== index) {
|
|
|
|
|
removeActivePanelClass(tabs, previousIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
var newPanel = getTabPanel(tabs, index);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
if (newPanel) {
|
|
|
|
|
// animate new panel ?
|
|
|
|
|
if (newPanel.animate) {
|
|
|
|
|
fadeInRight(newPanel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newPanel.classList.add('is-active');
|
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onClick(e) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
if (this.focusTimeout) {
|
|
|
|
|
clearTimeout(this.focusTimeout);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var tabs = this;
|
|
|
|
|
|
|
|
|
|
var current = tabs.querySelector('.' + activeButtonClass);
|
|
|
|
|
var tabButton = dom.parentWithClass(e.target, buttonClass);
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
if (tabButton && tabButton !== current) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
if (current) {
|
|
|
|
|
current.classList.remove(activeButtonClass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var previousIndex = current ? parseInt(current.getAttribute('data-index')) : null;
|
|
|
|
|
|
|
|
|
|
setActiveTabButton(tabs, tabButton, current, true);
|
|
|
|
|
|
|
|
|
|
var index = parseInt(tabButton.getAttribute('data-index'));
|
|
|
|
|
|
|
|
|
|
triggerBeforeTabChange(tabs, index, previousIndex);
|
|
|
|
|
|
|
|
|
|
// If toCenter is called syncronously within the click event, it sometimes ends up canceling it
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
|
|
|
|
tabs.selectedTabIndex = index;
|
|
|
|
|
|
|
|
|
|
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
2018-10-23 01:05:09 +03:00
|
|
|
|
detail: {
|
|
|
|
|
selectedTabIndex: index,
|
|
|
|
|
previousIndex: previousIndex
|
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
}));
|
|
|
|
|
}, 120);
|
|
|
|
|
|
|
|
|
|
if (tabs.scroller) {
|
|
|
|
|
tabs.scroller.toCenter(tabButton, false);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function initScroller(tabs) {
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
if (tabs.scroller) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var contentScrollSlider = tabs.querySelector('.emby-tabs-slider');
|
|
|
|
|
if (contentScrollSlider) {
|
|
|
|
|
tabs.scroller = new scroller(tabs, {
|
2018-10-23 01:05:09 +03:00
|
|
|
|
horizontal: 1,
|
|
|
|
|
itemNav: 0,
|
|
|
|
|
mouseDragging: 1,
|
|
|
|
|
touchDragging: 1,
|
|
|
|
|
slidee: contentScrollSlider,
|
2019-01-10 15:39:37 +03:00
|
|
|
|
smart: true,
|
|
|
|
|
releaseSwing: true,
|
2018-10-23 01:05:09 +03:00
|
|
|
|
scrollBy: 200,
|
|
|
|
|
speed: 120,
|
|
|
|
|
elasticBounds: 1,
|
|
|
|
|
dragHandle: 1,
|
|
|
|
|
dynamicHandle: 1,
|
|
|
|
|
clickBar: 1,
|
2019-01-10 15:39:37 +03:00
|
|
|
|
hiddenScroll: true,
|
|
|
|
|
|
|
|
|
|
// In safari the transform is causing the headers to occasionally disappear or flicker
|
2018-10-23 01:05:09 +03:00
|
|
|
|
requireAnimation: !browser.safari,
|
2019-01-10 15:39:37 +03:00
|
|
|
|
allowNativeSmoothScroll: true
|
|
|
|
|
});
|
|
|
|
|
tabs.scroller.init();
|
|
|
|
|
} else {
|
|
|
|
|
tabs.classList.add('scrollX');
|
|
|
|
|
tabs.classList.add('hiddenScrollX');
|
|
|
|
|
tabs.classList.add('smoothScrollX');
|
|
|
|
|
}
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
|
|
|
|
|
2019-01-10 15:39:37 +03:00
|
|
|
|
EmbyTabs.createdCallback = function () {
|
2018-10-23 01:05:09 +03:00
|
|
|
|
|
2019-01-10 15:39:37 +03:00
|
|
|
|
if (this.classList.contains('emby-tabs')) {
|
|
|
|
|
return;
|
2018-10-23 01:05:09 +03:00
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
this.classList.add('emby-tabs');
|
|
|
|
|
this.classList.add('focusable');
|
|
|
|
|
|
|
|
|
|
dom.addEventListener(this, 'click', onClick, {
|
|
|
|
|
passive: true
|
|
|
|
|
});
|
|
|
|
|
dom.addEventListener(this, 'focus', onFocus, {
|
|
|
|
|
passive: true,
|
|
|
|
|
capture: true
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EmbyTabs.focus = function () {
|
|
|
|
|
|
|
|
|
|
var selected = this.querySelector('.' + activeButtonClass);
|
|
|
|
|
|
|
|
|
|
if (selected) {
|
|
|
|
|
focusManager.focus(selected);
|
|
|
|
|
} else {
|
|
|
|
|
focusManager.autoFocus(this);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EmbyTabs.refresh = function () {
|
|
|
|
|
|
|
|
|
|
if (this.scroller) {
|
|
|
|
|
this.scroller.reload();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EmbyTabs.attachedCallback = function () {
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
initScroller(this);
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
var current = this.querySelector('.' + activeButtonClass);
|
|
|
|
|
var currentIndex = current ? parseInt(current.getAttribute('data-index')) : parseInt(this.getAttribute('data-index') || '0');
|
|
|
|
|
|
|
|
|
|
if (currentIndex !== -1) {
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
this.selectedTabIndex = currentIndex;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
var tabButtons = this.querySelectorAll('.' + buttonClass);
|
|
|
|
|
|
|
|
|
|
var newTabButton = tabButtons[currentIndex];
|
|
|
|
|
|
|
|
|
|
if (newTabButton) {
|
|
|
|
|
setActiveTabButton(this, newTabButton, current, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!this.readyFired) {
|
|
|
|
|
this.readyFired = true;
|
|
|
|
|
this.dispatchEvent(new CustomEvent("ready", {}));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EmbyTabs.detachedCallback = function () {
|
|
|
|
|
|
|
|
|
|
if (this.scroller) {
|
|
|
|
|
this.scroller.destroy();
|
|
|
|
|
this.scroller = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dom.removeEventListener(this, 'click', onClick, {
|
|
|
|
|
passive: true
|
|
|
|
|
});
|
|
|
|
|
dom.removeEventListener(this, 'focus', onFocus, {
|
|
|
|
|
passive: true,
|
|
|
|
|
capture: true
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function getSelectedTabButton(elem) {
|
|
|
|
|
|
|
|
|
|
return elem.querySelector('.' + activeButtonClass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EmbyTabs.selectedIndex = function (selected, triggerEvent) {
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
var tabs = this;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
if (selected == null) {
|
|
|
|
|
|
|
|
|
|
return tabs.selectedTabIndex || 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
var current = tabs.selectedIndex();
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
tabs.selectedTabIndex = selected;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
var tabButtons = tabs.querySelectorAll('.' + buttonClass);
|
|
|
|
|
|
|
|
|
|
if (current === selected || triggerEvent === false) {
|
|
|
|
|
|
|
|
|
|
triggerBeforeTabChange(tabs, selected, current);
|
|
|
|
|
|
|
|
|
|
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
2018-10-23 01:05:09 +03:00
|
|
|
|
detail: {
|
|
|
|
|
selectedTabIndex: selected
|
|
|
|
|
}
|
|
|
|
|
}));
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
var currentTabButton = tabButtons[current];
|
2019-01-10 15:39:37 +03:00
|
|
|
|
setActiveTabButton(tabs, tabButtons[selected], currentTabButton, false);
|
|
|
|
|
|
|
|
|
|
if (current !== selected && currentTabButton) {
|
|
|
|
|
currentTabButton.classList.remove(activeButtonClass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
onClick.call(tabs, {
|
|
|
|
|
target: tabButtons[selected]
|
|
|
|
|
});
|
|
|
|
|
//tabButtons[selected].click();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function getSibling(elem, method) {
|
|
|
|
|
|
|
|
|
|
var sibling = elem[method];
|
|
|
|
|
|
|
|
|
|
while (sibling) {
|
|
|
|
|
if (sibling.classList.contains(buttonClass)) {
|
|
|
|
|
|
|
|
|
|
if (!sibling.classList.contains('hide')) {
|
|
|
|
|
return sibling;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sibling = sibling[method];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EmbyTabs.selectNext = function () {
|
|
|
|
|
|
|
|
|
|
var current = getSelectedTabButton(this);
|
|
|
|
|
|
|
|
|
|
var sibling = getSibling(current, 'nextSibling');
|
|
|
|
|
|
|
|
|
|
if (sibling) {
|
|
|
|
|
onClick.call(this, {
|
|
|
|
|
target: sibling
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EmbyTabs.selectPrevious = function () {
|
|
|
|
|
|
|
|
|
|
var current = getSelectedTabButton(this);
|
|
|
|
|
|
|
|
|
|
var sibling = getSibling(current, 'previousSibling');
|
|
|
|
|
|
|
|
|
|
if (sibling) {
|
|
|
|
|
onClick.call(this, {
|
|
|
|
|
target: sibling
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EmbyTabs.triggerBeforeTabChange = function (selected) {
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
var tabs = this;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
triggerBeforeTabChange(tabs, tabs.selectedIndex());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EmbyTabs.triggerTabChange = function (selected) {
|
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
var tabs = this;
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
2018-10-23 01:05:09 +03:00
|
|
|
|
tabs.dispatchEvent(new CustomEvent("tabchange", {
|
|
|
|
|
detail: {
|
|
|
|
|
selectedTabIndex: tabs.selectedIndex()
|
|
|
|
|
}
|
2019-01-10 15:39:37 +03:00
|
|
|
|
}));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
EmbyTabs.setTabEnabled = function (index, enabled) {
|
|
|
|
|
|
|
|
|
|
var tabs = this;
|
2018-10-23 01:05:09 +03:00
|
|
|
|
var btn = this.querySelector('.emby-tab-button[data-index="' + index + '"]');
|
2019-01-10 15:39:37 +03:00
|
|
|
|
|
|
|
|
|
if (enabled) {
|
|
|
|
|
btn.classList.remove('hide');
|
|
|
|
|
} else {
|
|
|
|
|
btn.classList.remove('add');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
document.registerElement('emby-tabs', {
|
2018-10-23 01:05:09 +03:00
|
|
|
|
prototype: EmbyTabs,
|
2019-01-10 15:39:37 +03:00
|
|
|
|
extends: 'div'
|
|
|
|
|
});
|
2018-10-23 01:05:09 +03:00
|
|
|
|
});
|