Merge pull request #1710 from MediaBrowser/dev

Dev
This commit is contained in:
Luke 2016-05-06 01:18:33 -04:00
commit 2f8757eb4e
73 changed files with 930 additions and 822 deletions

View file

@ -16,12 +16,12 @@
}, },
"devDependencies": {}, "devDependencies": {},
"ignore": [], "ignore": [],
"version": "1.2.58", "version": "1.2.61",
"_release": "1.2.58", "_release": "1.2.61",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "1.2.58", "tag": "1.2.61",
"commit": "523cb074208c7350bb68554c6fcde613142117f4" "commit": "d28f24510d524454f235f9f83979639e8b0913d6"
}, },
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git", "_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
"_target": "^1.2.0", "_target": "^1.2.0",

View file

@ -103,8 +103,27 @@
return false; return false;
}(); }();
function toLocaleDateString(date) {
var currentLocale = globalize.getCurrentLocale();
return currentLocale && toLocaleTimeStringSupportsLocales ?
date.toLocaleDateString(currentLocale) :
date.toLocaleDateString();
}
function getDisplayTime(date) { function getDisplayTime(date) {
if ((typeof date).toString().toLowerCase() === 'string') {
try {
date = parseISO8601Date(date, true);
} catch (err) {
return date;
}
}
var currentLocale = globalize.getCurrentLocale(); var currentLocale = globalize.getCurrentLocale();
var time = currentLocale && toLocaleTimeStringSupportsLocales ? var time = currentLocale && toLocaleTimeStringSupportsLocales ?
@ -115,7 +134,6 @@
if (timeLower.indexOf('am') != -1 || timeLower.indexOf('pm') != -1) { if (timeLower.indexOf('am') != -1 || timeLower.indexOf('pm') != -1) {
time = timeLower;
var hour = date.getHours() % 12; var hour = date.getHours() % 12;
var suffix = date.getHours() > 11 ? 'pm' : 'am'; var suffix = date.getHours() > 11 ? 'pm' : 'am';
if (!hour) { if (!hour) {
@ -144,6 +162,7 @@
return { return {
parseISO8601Date: parseISO8601Date, parseISO8601Date: parseISO8601Date,
getDisplayRunningTime: getDisplayRunningTime, getDisplayRunningTime: getDisplayRunningTime,
toLocaleDateString: toLocaleDateString,
getDisplayTime: getDisplayTime getDisplayTime: getDisplayTime
}; };
}); });

View file

@ -449,7 +449,7 @@
weekday[6] = globalize.translate('core#OptionSaturdayShort'); weekday[6] = globalize.translate('core#OptionSaturdayShort');
var day = weekday[date.getDay()]; var day = weekday[date.getDay()];
date = date.toLocaleDateString(); date = datetime.toLocaleDateString(date);
if (date.toLowerCase().indexOf(day.toLowerCase()) == -1) { if (date.toLowerCase().indexOf(day.toLowerCase()) == -1) {
return day + " " + date; return day + " " + date;
@ -600,6 +600,24 @@
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', baseUrl + '/tvguide.template.html', true); xhr.open('GET', baseUrl + '/tvguide.template.html', true);
var supportsCaptureOption = false;
try {
var opts = Object.defineProperty({}, 'capture', {
get: function () {
supportsCaptureOption = true;
}
});
window.addEventListener("test", null, opts);
} catch (e) { }
function addEventListenerWithOptions(target, type, handler, options) {
var optionsOrCapture = options;
if (!supportsCaptureOption) {
optionsOrCapture = options.capture;
}
target.addEventListener(type, handler, optionsOrCapture);
}
xhr.onload = function (e) { xhr.onload = function (e) {
var template = this.response; var template = this.response;
@ -610,13 +628,17 @@
var timeslotHeaders = context.querySelector('.timeslotHeaders'); var timeslotHeaders = context.querySelector('.timeslotHeaders');
programGrid.addEventListener('focus', onProgramGridFocus, true); programGrid.addEventListener('focus', onProgramGridFocus, true);
programGrid.addEventListener('scroll', function () {
addEventListenerWithOptions(programGrid, 'scroll', function () {
onProgramGridScroll(context, this, timeslotHeaders); onProgramGridScroll(context, this, timeslotHeaders);
}, {
passive: true
}); });
timeslotHeaders.addEventListener('scroll', function () { addEventListenerWithOptions(timeslotHeaders, 'scroll', function () {
onTimeslotHeadersScroll(context, this, programGrid); onTimeslotHeadersScroll(context, this, programGrid);
}, {
passive: true
}); });
context.querySelector('.btnSelectDate').addEventListener('click', function () { context.querySelector('.btnSelectDate').addEventListener('click', function () {

View file

@ -43,6 +43,24 @@ define(['visibleinviewport', 'imageFetcher'], function (visibleinviewport, image
} }
} }
var supportsCaptureOption = false;
try {
var opts = Object.defineProperty({}, 'capture', {
get: function () {
supportsCaptureOption = true;
}
});
window.addEventListener("test", null, opts);
} catch (e) { }
function addEventListenerWithOptions(target, type, handler, options) {
var optionsOrCapture = options;
if (!supportsCaptureOption) {
optionsOrCapture = options.capture;
}
target.addEventListener(type, handler, optionsOrCapture);
}
function unveilElements(images) { function unveilElements(images) {
if (!images.length) { if (!images.length) {
@ -103,10 +121,19 @@ define(['visibleinviewport', 'imageFetcher'], function (visibleinviewport, image
}, 1); }, 1);
} }
document.addEventListener('scroll', unveil, true); addEventListenerWithOptions(document, 'scroll', unveil, {
capture: true,
passive: true
});
document.addEventListener('focus', unveil, true); document.addEventListener('focus', unveil, true);
document.addEventListener(wheelEvent, unveil, true); addEventListenerWithOptions(document, wheelEvent, unveil, {
window.addEventListener('resize', unveil, true); capture: true,
passive: true
});
addEventListenerWithOptions(window, 'resize', unveil, {
capture: true,
passive: true
});
unveil(); unveil();
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-behaviors", "name": "iron-behaviors",
"version": "1.0.14", "version": "1.0.15",
"description": "Provides a set of behaviors for the iron elements", "description": "Provides a set of behaviors for the iron elements",
"private": true, "private": true,
"authors": [ "authors": [
@ -30,11 +30,11 @@
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/PolymerElements/iron-behaviors", "homepage": "https://github.com/PolymerElements/iron-behaviors",
"_release": "1.0.14", "_release": "1.0.15",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.14", "tag": "v1.0.15",
"commit": "c1d38a26219cf2e83b31a71a2bd8ae35ebee7ed7" "commit": "f91583bfae24235401a21a1d67bde8cacce13030"
}, },
"_source": "git://github.com/PolymerElements/iron-behaviors.git", "_source": "git://github.com/PolymerElements/iron-behaviors.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-behaviors", "name": "iron-behaviors",
"version": "1.0.14", "version": "1.0.15",
"description": "Provides a set of behaviors for the iron elements", "description": "Provides a set of behaviors for the iron elements",
"private": true, "private": true,
"authors": [ "authors": [

View file

@ -73,7 +73,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
if (event.target === this) { if (event.target === this) {
this._setFocused(event.type === 'focus'); this._setFocused(event.type === 'focus');
} else if (!this.shadowRoot && !this.isLightDescendant(event.target)) { } else if (!this.shadowRoot &&
!this.isLightDescendant(Polymer.dom(event).localTarget)) {
this.fire(event.type, {sourceEvent: event}, { this.fire(event.type, {sourceEvent: event}, {
node: this, node: this,
bubbles: event.bubbles, bubbles: event.bubbles,

View file

@ -31,10 +31,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
</template> </template>
</test-fixture> </test-fixture>
<test-fixture id="LightDOM"> <test-fixture id="LightDOM">
<template> <template>
<test-light-dom> <test-light-dom>
<input id="input"> <input id="input">
<nested-focusable></nested-focusable>
</test-light-dom> </test-light-dom>
</template> </template>
</test-fixture> </test-fixture>
@ -119,11 +120,13 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
suite('elements in the light dom', function() { suite('elements in the light dom', function() {
var lightDOM, input; var lightDOM, input, lightDescendantShadowInput;
setup(function() { setup(function() {
lightDOM = fixture('LightDOM'); lightDOM = fixture('LightDOM');
input = document.querySelector('#input'); input = document.querySelector('#input');
lightDescendantShadowInput = Polymer.dom(lightDOM)
.querySelector('nested-focusable').$.input;
}); });
test('should not fire the focus event', function() { test('should not fire the focus event', function() {
@ -138,6 +141,18 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
expect(nFocusEvents).to.be.equal(0); expect(nFocusEvents).to.be.equal(0);
}); });
test('should not fire the focus event from shadow descendants', function() {
var nFocusEvents = 0;
lightDOM.addEventListener('focus', function() {
nFocusEvents += 1;
});
MockInteractions.focus(lightDescendantShadowInput);
expect(nFocusEvents).to.be.equal(0);
});
}); });
</script> </script>

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-dropdown", "name": "iron-dropdown",
"version": "1.3.1", "version": "1.4.0",
"description": "An unstyled element that works similarly to a native browser select", "description": "An unstyled element that works similarly to a native browser select",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"
@ -36,11 +36,11 @@
"iron-image": "polymerelements/iron-image#^1.0.0" "iron-image": "polymerelements/iron-image#^1.0.0"
}, },
"ignore": [], "ignore": [],
"_release": "1.3.1", "_release": "1.4.0",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.3.1", "tag": "v1.4.0",
"commit": "f7a47d4cd6c6cb87adba08703ec1588c1b649f4d" "commit": "8e14da0aaeb791983ee4b254890c7263644f7851"
}, },
"_source": "git://github.com/PolymerElements/iron-dropdown.git", "_source": "git://github.com/PolymerElements/iron-dropdown.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-dropdown", "name": "iron-dropdown",
"version": "1.3.1", "version": "1.4.0",
"description": "An unstyled element that works similarly to a native browser select", "description": "An unstyled element that works similarly to a native browser select",
"authors": [ "authors": [
"The Polymer Authors" "The Polymer Authors"

View file

@ -81,6 +81,7 @@ method is called on the element.
/** /**
* The orientation against which to align the dropdown content * The orientation against which to align the dropdown content
* horizontally relative to the dropdown trigger. * horizontally relative to the dropdown trigger.
* Overridden from `Polymer.IronFitBehavior`.
*/ */
horizontalAlign: { horizontalAlign: {
type: String, type: String,
@ -91,6 +92,7 @@ method is called on the element.
/** /**
* The orientation against which to align the dropdown content * The orientation against which to align the dropdown content
* vertically relative to the dropdown trigger. * vertically relative to the dropdown trigger.
* Overridden from `Polymer.IronFitBehavior`.
*/ */
verticalAlign: { verticalAlign: {
type: String, type: String,
@ -98,54 +100,6 @@ method is called on the element.
reflectToAttribute: true reflectToAttribute: true
}, },
/**
* A pixel value that will be added to the position calculated for the
* given `horizontalAlign`, in the direction of alignment. You can think
* of it as increasing or decreasing the distance to the side of the
* screen given by `horizontalAlign`.
*
* If `horizontalAlign` is "left", this offset will increase or decrease
* the distance to the left side of the screen: a negative offset will
* move the dropdown to the left; a positive one, to the right.
*
* Conversely if `horizontalAlign` is "right", this offset will increase
* or decrease the distance to the right side of the screen: a negative
* offset will move the dropdown to the right; a positive one, to the left.
*/
horizontalOffset: {
type: Number,
value: 0,
notify: true
},
/**
* A pixel value that will be added to the position calculated for the
* given `verticalAlign`, in the direction of alignment. You can think
* of it as increasing or decreasing the distance to the side of the
* screen given by `verticalAlign`.
*
* If `verticalAlign` is "top", this offset will increase or decrease
* the distance to the top side of the screen: a negative offset will
* move the dropdown upwards; a positive one, downwards.
*
* Conversely if `verticalAlign` is "bottom", this offset will increase
* or decrease the distance to the bottom side of the screen: a negative
* offset will move the dropdown downwards; a positive one, upwards.
*/
verticalOffset: {
type: Number,
value: 0,
notify: true
},
/**
* The element that should be used to position the dropdown when
* it is opened.
*/
positionTarget: {
type: Object
},
/** /**
* An animation config. If provided, this will be used to animate the * An animation config. If provided, this will be used to animate the
* opening of the dropdown. * opening of the dropdown.
@ -199,12 +153,6 @@ method is called on the element.
'_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)' '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)'
], ],
attached: function() {
// Memoize this to avoid expensive calculations & relayouts.
this._isRTL = window.getComputedStyle(this).direction == 'rtl';
this.positionTarget = this.positionTarget || this._defaultPositionTarget;
},
/** /**
* The element that is contained by the dropdown, if any. * The element that is contained by the dropdown, if any.
*/ */
@ -220,72 +168,6 @@ method is called on the element.
return this.focusTarget || this.containedElement; return this.focusTarget || this.containedElement;
}, },
/**
* The element that should be used to position the dropdown when
* it opens, if no position target is configured.
*/
get _defaultPositionTarget() {
var parent = Polymer.dom(this).parentNode;
if (parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
parent = parent.host;
}
return parent;
},
/**
* The horizontal align value, accounting for the RTL/LTR text direction.
*/
get _localeHorizontalAlign() {
// In RTL, "left" becomes "right".
if (this._isRTL) {
return this.horizontalAlign === 'right' ? 'left' : 'right';
} else {
return this.horizontalAlign;
}
},
/**
* The horizontal offset value used to position the dropdown.
* @param {ClientRect} dropdownRect
* @param {ClientRect} positionRect
* @param {boolean=} fromRight
* @return {number} pixels
* @private
*/
_horizontalAlignTargetValue: function(dropdownRect, positionRect, fromRight) {
var target;
if (fromRight) {
target = document.documentElement.clientWidth - positionRect.right - (this._fitWidth - dropdownRect.right);
} else {
target = positionRect.left - dropdownRect.left;
}
target += this.horizontalOffset;
return Math.max(target, 0);
},
/**
* The vertical offset value used to position the dropdown.
* @param {ClientRect} dropdownRect
* @param {ClientRect} positionRect
* @param {boolean=} fromBottom
* @return {number} pixels
* @private
*/
_verticalAlignTargetValue: function(dropdownRect, positionRect, fromBottom) {
var target;
if (fromBottom) {
target = document.documentElement.clientHeight - positionRect.bottom - (this._fitHeight - dropdownRect.bottom);
} else {
target = positionRect.top - dropdownRect.top;
}
target += this.verticalOffset;
return Math.max(target, 0);
},
/** /**
* Called when the value of `opened` changes. * Called when the value of `opened` changes.
* Overridden from `IronOverlayBehavior` * Overridden from `IronOverlayBehavior`
@ -417,41 +299,6 @@ method is called on the element.
} }
}, },
/**
* Resets the target element's position and size constraints, and clear
* the memoized data.
*/
resetFit: function() {
Polymer.IronFitBehavior.resetFit.apply(this, arguments);
var hAlign = this._localeHorizontalAlign;
var vAlign = this.verticalAlign;
// Set to 0, 0 in order to discover any offset caused by parent stacking contexts.
this.style[hAlign] = this.style[vAlign] = '0px';
var dropdownRect = this.getBoundingClientRect();
var positionRect = this.positionTarget.getBoundingClientRect();
var horizontalValue = this._horizontalAlignTargetValue(dropdownRect, positionRect, hAlign === 'right');
var verticalValue = this._verticalAlignTargetValue(dropdownRect, positionRect, vAlign === 'bottom');
this.style[hAlign] = horizontalValue + 'px';
this.style[vAlign] = verticalValue + 'px';
},
/**
* Overridden from `IronFitBehavior`.
* Ensure positionedBy has correct values for horizontally & vertically.
*/
_discoverInfo: function() {
Polymer.IronFitBehavior._discoverInfo.apply(this, arguments);
// Note(valdrin): in Firefox, an element with style `position: fixed; bottom: 90vh; height: 20vh`
// would have `getComputedStyle(element).top < 0` (instead of being `auto`) http://jsbin.com/cofired/3/edit?html,output
// This would cause IronFitBehavior's `constrain` to wrongly calculate sizes
// (it would use `top` instead of `bottom`), so we ensure we give the correct values.
this._fitInfo.positionedBy.horizontally = this._localeHorizontalAlign;
this._fitInfo.positionedBy.vertically = this.verticalAlign;
},
/** /**
* Apply focus to focusTarget or containedElement * Apply focus to focusTarget or containedElement
*/ */

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-fit-behavior", "name": "iron-fit-behavior",
"version": "1.1.0", "version": "1.1.1",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "Fits an element inside another element", "description": "Fits an element inside another element",
"private": true, "private": true,
@ -29,11 +29,11 @@
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/PolymerElements/iron-fit-behavior", "homepage": "https://github.com/PolymerElements/iron-fit-behavior",
"_release": "1.1.0", "_release": "1.1.1",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.1.0", "tag": "v1.1.1",
"commit": "6602a102f425f5ccc9e05e9cc15139a3ad259081" "commit": "c87fd44553b9ce2c60f695146d667932a7be2f8f"
}, },
"_source": "git://github.com/PolymerElements/iron-fit-behavior.git", "_source": "git://github.com/PolymerElements/iron-fit-behavior.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-fit-behavior", "name": "iron-fit-behavior",
"version": "1.1.0", "version": "1.1.1",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "Fits an element inside another element", "description": "Fits an element inside another element",
"private": true, "private": true,

View file

@ -105,18 +105,8 @@ Use `noOverlap` to position the element around another element without overlappi
}, },
/** /**
* A pixel value that will be added to the position calculated for the * The same as setting margin-left and margin-right css properties.
* given `horizontalAlign`, in the direction of alignment. You can think * @deprecated
* of it as increasing or decreasing the distance to the side of the
* screen given by `horizontalAlign`.
*
* If `horizontalAlign` is "left", this offset will increase or decrease
* the distance to the left side of the screen: a negative offset will
* move the element to the left; a positive one, to the right.
*
* Conversely if `horizontalAlign` is "right", this offset will increase
* or decrease the distance to the right side of the screen: a negative
* offset will move the element to the right; a positive one, to the left.
*/ */
horizontalOffset: { horizontalOffset: {
type: Number, type: Number,
@ -125,18 +115,8 @@ Use `noOverlap` to position the element around another element without overlappi
}, },
/** /**
* A pixel value that will be added to the position calculated for the * The same as setting margin-top and margin-bottom css properties.
* given `verticalAlign`, in the direction of alignment. You can think * @deprecated
* of it as increasing or decreasing the distance to the side of the
* screen given by `verticalAlign`.
*
* If `verticalAlign` is "top", this offset will increase or decrease
* the distance to the top side of the screen: a negative offset will
* move the element upwards; a positive one, downwards.
*
* Conversely if `verticalAlign` is "bottom", this offset will increase
* or decrease the distance to the bottom side of the screen: a negative
* offset will move the element downwards; a positive one, upwards.
*/ */
verticalOffset: { verticalOffset: {
type: Number, type: Number,
@ -205,7 +185,7 @@ Use `noOverlap` to position the element around another element without overlappi
get _defaultPositionTarget() { get _defaultPositionTarget() {
var parent = Polymer.dom(this).parentNode; var parent = Polymer.dom(this).parentNode;
if (parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) { if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
parent = parent.host; parent = parent.host;
} }
@ -262,6 +242,7 @@ Use `noOverlap` to position the element around another element without overlappi
} }
var target = window.getComputedStyle(this); var target = window.getComputedStyle(this);
var sizer = window.getComputedStyle(this.sizingTarget); var sizer = window.getComputedStyle(this.sizingTarget);
this._fitInfo = { this._fitInfo = {
inlineStyle: { inlineStyle: {
top: this.style.top || '', top: this.style.top || '',
@ -292,6 +273,20 @@ Use `noOverlap` to position the element around another element without overlappi
left: parseInt(target.marginLeft, 10) || 0 left: parseInt(target.marginLeft, 10) || 0
} }
}; };
// Support these properties until they are removed.
if (this.verticalOffset) {
this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffset;
this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || '';
this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px';
}
if (this.horizontalOffset) {
this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOffset;
this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || '';
this._fitInfo.inlineStyle.marginRight = this.style.marginRight || '';
this.style.marginLeft = this.style.marginRight = this.horizontalOffset + 'px';
}
}, },
/** /**
@ -340,11 +335,15 @@ Use `noOverlap` to position the element around another element without overlappi
var positionRect = this.__getNormalizedRect(this.positionTarget); var positionRect = this.__getNormalizedRect(this.positionTarget);
var fitRect = this.__getNormalizedRect(this.fitInto); var fitRect = this.__getNormalizedRect(this.fitInto);
var alignRight = this.__isAlignRight(this._localeHorizontalAlign, rect, positionRect, fitRect); // Consider the margin as part of the size for position calculations.
var alignBottom = this.__isAlignBottom(this.verticalAlign, rect, positionRect, fitRect); var width = rect.width + this._fitInfo.margin.left + this._fitInfo.margin.right;
var height = rect.height + this._fitInfo.margin.top + this._fitInfo.margin.bottom;
var top = alignBottom ? positionRect.bottom - rect.height - this.verticalOffset : positionRect.top + this.verticalOffset; var alignRight = this.__isAlignRight(this._localeHorizontalAlign, width, positionRect, fitRect);
var left = alignRight ? positionRect.right - rect.width - this.horizontalOffset : positionRect.left + this.horizontalOffset; var alignBottom = this.__isAlignBottom(this.verticalAlign, height, positionRect, fitRect);
var top = alignBottom ? positionRect.bottom - height : positionRect.top;
var left = alignRight ? positionRect.right - width : positionRect.left;
if (this.noOverlap) { if (this.noOverlap) {
// We can overlap one of the dimensions, choose the one that minimizes the cropped area. // We can overlap one of the dimensions, choose the one that minimizes the cropped area.
@ -353,30 +352,34 @@ Use `noOverlap` to position the element around another element without overlappi
var areaOverlapLeft = this.__getCroppedArea({ var areaOverlapLeft = this.__getCroppedArea({
top: noOverlapTop, top: noOverlapTop,
left: left, left: left,
width: rect.width, width: width,
height: rect.height height: height
}, fitRect); }, fitRect);
var areaOverlapTop = this.__getCroppedArea({ var areaOverlapTop = this.__getCroppedArea({
top: top, top: top,
left: noOverlapLeft, left: noOverlapLeft,
width: rect.width, width: width,
height: rect.height height: height
}, fitRect); }, fitRect);
if (areaOverlapLeft < areaOverlapTop) { if (areaOverlapLeft >= areaOverlapTop) {
left = noOverlapLeft; left = noOverlapLeft;
} else { } else {
top = noOverlapTop; top = noOverlapTop;
} }
} }
left += this._fitInfo.margin.left;
top += this._fitInfo.margin.top;
// Use original size (without margin)
var right = left + rect.width; var right = left + rect.width;
var bottom = top + rect.height; var bottom = top + rect.height;
left = Math.max(left, 0); left = Math.max(left, this._fitInfo.margin.left);
top = Math.max(top, 0); top = Math.max(top, this._fitInfo.margin.top);
var maxWidth = Math.min(fitRect.right, right) - left; var maxWidth = Math.min(fitRect.right - this._fitInfo.margin.right, right) - left;
var maxHeight = Math.min(fitRect.bottom, bottom) - top; var maxHeight = Math.min(fitRect.bottom - this._fitInfo.margin.bottom, bottom) - top;
var minWidth = this._fitInfo.sizedBy.minWidth; var minWidth = this._fitInfo.sizedBy.minWidth;
var minHeight = this._fitInfo.sizedBy.minHeight; var minHeight = this._fitInfo.sizedBy.minHeight;
@ -503,24 +506,38 @@ Use `noOverlap` to position the element around another element without overlappi
return target.getBoundingClientRect(); return target.getBoundingClientRect();
}, },
__isAlignRight: function(hAlign, rect, positionRect, fitRect) { __isAlignRight: function(hAlign, size, positionRect, fitRect) {
if (hAlign === 'right') { if (hAlign === 'right') {
return true; return true;
} }
if (hAlign === 'auto') { if (hAlign === 'auto') {
return positionRect.left + positionRect.width/2 > fitRect.left + fitRect.width/2 || // We should align on the right if positionTarget is on the right of fitInto,
(!this.noOverlap && positionRect.left < 0 && positionRect.right - rect.width > positionRect.left); // or if we can overlap and aligning on the left would cause more cropping
// than aligning on the right.
var positionTargetCenter = positionRect.left + positionRect.width/2;
var fitIntoCenter = fitRect.left + fitRect.width/2;
var croppedLeft = Math.abs(Math.min(0, positionRect.left));
var croppedRight = Math.abs(Math.min(0, positionRect.right - size));
return positionTargetCenter > fitIntoCenter ||
(!this.noOverlap && croppedLeft > croppedRight);
} }
return false; return false;
}, },
__isAlignBottom: function(vAlign, rect, positionRect, fitRect) { __isAlignBottom: function(vAlign, size, positionRect, fitRect) {
if (vAlign === 'bottom') { if (vAlign === 'bottom') {
return true; return true;
} }
if (vAlign === 'auto') { if (vAlign === 'auto') {
return positionRect.top + positionRect.height/2 > fitRect.top + fitRect.height/2 || // We should align on the bottom if positionTarget is on the bottom of fitInto,
(!this.noOverlap && positionRect.top < 0 && positionRect.bottom - rect.height > positionRect.top); // or if we can overlap and aligning on the top would cause more cropping
// than aligning on the bottom.
var positionTargetCenter = positionRect.top + positionRect.height/2;
var fitIntoCenter = fitRect.top + fitRect.height/2;
var croppedTop = Math.abs(Math.min(0, positionRect.top));
var croppedBottom = Math.abs(Math.min(0, positionRect.bottom - size));
return positionTargetCenter > fitIntoCenter ||
(!this.noOverlap && croppedTop > croppedBottom);
} }
return false; return false;
}, },
@ -528,7 +545,7 @@ Use `noOverlap` to position the element around another element without overlappi
__getCroppedArea: function(rect, fitRect) { __getCroppedArea: function(rect, fitRect) {
var verticalCrop = Math.min(0, rect.top) + Math.min(0, fitRect.bottom - (rect.top + rect.height)); var verticalCrop = Math.min(0, rect.top) + Math.min(0, fitRect.bottom - (rect.top + rect.height));
var horizontalCrop = Math.min(0, rect.left) + Math.min(0, fitRect.right - (rect.left + rect.width)); var horizontalCrop = Math.min(0, rect.left) + Math.min(0, fitRect.right - (rect.left + rect.width));
return verticalCrop * rect.width + horizontalCrop * rect.height; return Math.abs(verticalCrop) * rect.width + Math.abs(horizontalCrop) * rect.height;
} }
}; };

View file

@ -453,6 +453,21 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
assert.equal(rect.height, elRect.height, 'no cropping'); assert.equal(rect.height, elRect.height, 'no cropping');
}); });
test('element margin is considered as offset', function() {
el.verticalAlign = 'top';
el.style.marginTop = '10px';
el.refit();
var rect = el.getBoundingClientRect();
assert.equal(rect.top, parentRect.top + 10, 'top ok');
assert.equal(rect.height, elRect.height, 'no cropping');
el.style.marginTop = '-10px';
el.refit();
rect = el.getBoundingClientRect();
assert.equal(rect.top, parentRect.top - 10, 'top ok');
assert.equal(rect.height, elRect.height, 'no cropping');
});
test('verticalOffset is applied', function() { test('verticalOffset is applied', function() {
el.verticalAlign = 'top'; el.verticalAlign = 'top';
el.verticalOffset = 10; el.verticalOffset = 10;
@ -499,6 +514,21 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
assert.equal(rect.height, elRect.height, 'no cropping'); assert.equal(rect.height, elRect.height, 'no cropping');
}); });
test('element margin is considered as offset', function() {
el.verticalAlign = 'bottom';
el.style.marginBottom = '10px';
el.refit();
var rect = el.getBoundingClientRect();
assert.equal(rect.bottom, parentRect.bottom - 10, 'bottom ok');
assert.equal(rect.height, elRect.height, 'no cropping');
el.style.marginBottom = '-10px';
el.refit();
rect = el.getBoundingClientRect();
assert.equal(rect.bottom, parentRect.bottom + 10, 'bottom ok');
assert.equal(rect.height, elRect.height, 'no cropping');
});
test('verticalOffset is applied', function() { test('verticalOffset is applied', function() {
el.verticalAlign = 'bottom'; el.verticalAlign = 'bottom';
el.verticalOffset = 10; el.verticalOffset = 10;
@ -596,6 +626,21 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
assert.equal(rect.width, elRect.width, 'no cropping'); assert.equal(rect.width, elRect.width, 'no cropping');
}); });
test('element margin is considered as offset', function() {
el.horizontalAlign = 'left';
el.style.marginLeft = '10px';
el.refit();
var rect = el.getBoundingClientRect();
assert.equal(rect.left, parentRect.left + 10, 'left ok');
assert.equal(rect.width, elRect.width, 'no cropping');
el.style.marginLeft = '-10px';
el.refit();
rect = el.getBoundingClientRect();
assert.equal(rect.left, parentRect.left - 10, 'left ok');
assert.equal(rect.width, elRect.width, 'no cropping');
});
test('horizontalOffset is applied', function() { test('horizontalOffset is applied', function() {
el.horizontalAlign = 'left'; el.horizontalAlign = 'left';
el.horizontalOffset = 10; el.horizontalOffset = 10;
@ -645,6 +690,21 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
assert.equal(rect.width, elRect.width, 'no cropping'); assert.equal(rect.width, elRect.width, 'no cropping');
}); });
test('element margin is considered as offset', function() {
el.horizontalAlign = 'right';
el.style.marginRight = '10px';
el.refit();
var rect = el.getBoundingClientRect();
assert.equal(rect.right, parentRect.right - 10, 'right ok');
assert.equal(rect.width, elRect.width, 'no cropping');
el.style.marginRight = '-10px';
el.refit();
rect = el.getBoundingClientRect();
assert.equal(rect.right, parentRect.right + 10, 'right ok');
assert.equal(rect.width, elRect.width, 'no cropping');
});
test('horizontalOffset is applied', function() { test('horizontalOffset is applied', function() {
el.horizontalAlign = 'right'; el.horizontalAlign = 'right';
el.horizontalOffset = 10; el.horizontalOffset = 10;

View file

@ -26,14 +26,14 @@
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"main": "iron-meta.html", "main": "iron-meta.html",
"homepage": "https://github.com/polymerelements/iron-meta", "homepage": "https://github.com/PolymerElements/iron-meta",
"_release": "1.1.1", "_release": "1.1.1",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.1.1", "tag": "v1.1.1",
"commit": "e171ee234b482219c9514e6f9551df48ef48bd9f" "commit": "e171ee234b482219c9514e6f9551df48ef48bd9f"
}, },
"_source": "git://github.com/polymerelements/iron-meta.git", "_source": "git://github.com/PolymerElements/iron-meta.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "polymerelements/iron-meta" "_originalSource": "PolymerElements/iron-meta"
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-overlay-behavior", "name": "iron-overlay-behavior",
"version": "1.7.0", "version": "1.7.1",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "Provides a behavior for making an element an overlay", "description": "Provides a behavior for making an element an overlay",
"private": true, "private": true,
@ -35,11 +35,11 @@
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/polymerelements/iron-overlay-behavior", "homepage": "https://github.com/polymerelements/iron-overlay-behavior",
"_release": "1.7.0", "_release": "1.7.1",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.7.0", "tag": "v1.7.1",
"commit": "d61575162a40904914fa3528ba20bb531d098001" "commit": "4655445cb91e19ef3cdae247ded2ffc9f50b46a8"
}, },
"_source": "git://github.com/polymerelements/iron-overlay-behavior.git", "_source": "git://github.com/polymerelements/iron-overlay-behavior.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-overlay-behavior", "name": "iron-overlay-behavior",
"version": "1.7.0", "version": "1.7.1",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "Provides a behavior for making an element an overlay", "description": "Provides a behavior for making an element an overlay",
"private": true, "private": true,

View file

@ -128,8 +128,12 @@ Custom property | Description | Default
} }
}, },
_openedChanged: function() { /**
if (this.opened) { * @param {boolean} opened
* @private
*/
_openedChanged: function(opened) {
if (opened) {
// Auto-attach. // Auto-attach.
this.prepare(); this.prepare();
} else { } else {

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-selector", "name": "iron-selector",
"version": "1.5.0", "version": "1.5.1",
"description": "Manages a set of elements that can be selected", "description": "Manages a set of elements that can be selected",
"private": true, "private": true,
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
@ -30,13 +30,13 @@
"web-component-tester": "^4.0.0", "web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"_release": "1.5.0", "_release": "1.5.1",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.5.0", "tag": "v1.5.1",
"commit": "c7402274efa2e3b2a905ffa25d70c2ff3309dc59" "commit": "e3e34408fad8f7cde59c4255cf3fe90f7dcf91d8"
}, },
"_source": "git://github.com/PolymerElements/iron-selector.git", "_source": "git://github.com/polymerelements/iron-selector.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "PolymerElements/iron-selector" "_originalSource": "polymerelements/iron-selector"
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-selector", "name": "iron-selector",
"version": "1.5.0", "version": "1.5.1",
"description": "Manages a set of elements that can be selected", "description": "Manages a set of elements that can be selected",
"private": true, "private": true,
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",

View file

@ -38,7 +38,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<div name="zot">Zot</div> <div name="zot">Zot</div>
</iron-selector> </iron-selector>
If no matching element is found using `attForSelected`, use `fallbackSelection` as fallback. You can specify a default fallback with `fallbackSelection` in case the `selected` attribute does
not match the `attrForSelected` attribute of any elements.
Example: Example:

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-validatable-behavior", "name": "iron-validatable-behavior",
"version": "1.1.0", "version": "1.1.1",
"description": "Provides a behavior for an element that validates user input", "description": "Provides a behavior for an element that validates user input",
"authors": "The Polymer Authors", "authors": "The Polymer Authors",
"keywords": [ "keywords": [
@ -30,11 +30,11 @@
"web-component-tester": "^4.0.0", "web-component-tester": "^4.0.0",
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
}, },
"_release": "1.1.0", "_release": "1.1.1",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.1.0", "tag": "v1.1.1",
"commit": "01ed585b28d8ab41367518f9aebd8442b9166bfe" "commit": "2ecd3f411e298733b29f1660f75cb9b03ea31d77"
}, },
"_source": "git://github.com/PolymerElements/iron-validatable-behavior.git", "_source": "git://github.com/PolymerElements/iron-validatable-behavior.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-validatable-behavior", "name": "iron-validatable-behavior",
"version": "1.1.0", "version": "1.1.1",
"description": "Provides a behavior for an element that validates user input", "description": "Provides a behavior for an element that validates user input",
"authors": "The Polymer Authors", "authors": "The Polymer Authors",
"keywords": [ "keywords": [

View file

@ -81,6 +81,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
}, },
_validator: { _validator: {
type: Object,
computed: '__computeValidator(validator)' computed: '__computeValidator(validator)'
} }
}, },

View file

@ -45,7 +45,7 @@
"tag": "v1.0.11", "tag": "v1.0.11",
"commit": "e3c1ab0c72905b58fb4d9adc2921ea73b5c085a5" "commit": "e3c1ab0c72905b58fb4d9adc2921ea73b5c085a5"
}, },
"_source": "git://github.com/PolymerElements/paper-behaviors.git", "_source": "git://github.com/polymerelements/paper-behaviors.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "PolymerElements/paper-behaviors" "_originalSource": "polymerelements/paper-behaviors"
} }

View file

@ -1,10 +1,13 @@
{ {
"name": "paper-icon-button", "name": "paper-icon-button",
"private": true, "private": true,
"version": "1.0.7", "version": "1.1.1",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "A material design icon button", "description": "A material design icon button",
"main": "paper-icon-button.html", "main": [
"paper-icon-button.html",
"paper-icon-button-light.html"
],
"author": [ "author": [
"The Polymer Authors" "The Polymer Authors"
], ],
@ -35,11 +38,11 @@
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/PolymerElements/paper-icon-button", "homepage": "https://github.com/PolymerElements/paper-icon-button",
"_release": "1.0.7", "_release": "1.1.1",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.7", "tag": "v1.1.1",
"commit": "7623d73efeb6e2e88e2abdb5e4d00641d39e400f" "commit": "f4a8a7a0666aa5a6e2049aa3672ee686bb60b5f3"
}, },
"_source": "git://github.com/PolymerElements/paper-icon-button.git", "_source": "git://github.com/PolymerElements/paper-icon-button.git",
"_target": "^1.0.0", "_target": "^1.0.0",

View file

@ -0,0 +1,33 @@
<!-- Instructions: https://github.com/PolymerElements/paper-icon-button/CONTRIBUTING.md#filing-issues -->
### Description
<!-- Example: The `paper-foo` element causes the page to turn pink when clicked. -->
### Expected outcome
<!-- Example: The page stays the same color. -->
### Actual outcome
<!-- Example: The page turns pink. -->
### Live Demo
<!-- Example: https://jsbin.com/cagaye/edit?html,output -->
### Steps to reproduce
<!-- Example
1. Put a `paper-foo` element in the page.
2. Open the page in a web browser.
3. Click the `paper-foo` element.
-->
### Browsers Affected
<!-- Check all that apply -->
- [ ] Chrome
- [ ] Firefox
- [ ] Safari 9
- [ ] Safari 8
- [ ] Safari 7
- [ ] Edge
- [ ] IE 11
- [ ] IE 10

View file

@ -1,5 +1,5 @@
language: node_js language: node_js
sudo: false sudo: required
before_script: before_script:
- npm install -g bower polylint web-component-tester - npm install -g bower polylint web-component-tester
- bower install - bower install
@ -8,18 +8,16 @@ env:
global: global:
- secure: A+iEL5FUMQWkkaOduE26bo0jW49LYKxDwWGZOty9H9fCDpBNQSADOhIvLzScGtjE7Rr3jVmowVsDN0XfVSRpJneEIvj7+tHAXUFoVey8vDVklOmhlR25IH2OczEmCkOS+sAKRiSF54aptdPeJhmpbMH0FyZfuX+jJfhdonJ+YQg= - secure: A+iEL5FUMQWkkaOduE26bo0jW49LYKxDwWGZOty9H9fCDpBNQSADOhIvLzScGtjE7Rr3jVmowVsDN0XfVSRpJneEIvj7+tHAXUFoVey8vDVklOmhlR25IH2OczEmCkOS+sAKRiSF54aptdPeJhmpbMH0FyZfuX+jJfhdonJ+YQg=
- secure: Ps1Hy0fzmYRYF/ur2Myg7ol43HpzpooCoDvqzpMbIBWkXjXcN0KlPoNc6lEFlhjSpjddMFavdajKYIO0j9adAjZA7HYlf+BglhxV45lz13o04+QlNbDSADNyAlKJLrIvFacn9DE3VXlvBwBu83m+ndHUN/uMyHyZo0VE1/ad9Iw= - secure: Ps1Hy0fzmYRYF/ur2Myg7ol43HpzpooCoDvqzpMbIBWkXjXcN0KlPoNc6lEFlhjSpjddMFavdajKYIO0j9adAjZA7HYlf+BglhxV45lz13o04+QlNbDSADNyAlKJLrIvFacn9DE3VXlvBwBu83m+ndHUN/uMyHyZo0VE1/ad9Iw=
- CXX=g++-4.8
node_js: stable node_js: stable
addons: addons:
firefox: latest firefox: latest
apt: apt:
sources: sources:
- google-chrome - google-chrome
- ubuntu-toolchain-r-test
packages: packages:
- google-chrome-stable - google-chrome-stable
- g++-4.8
sauce_connect: true sauce_connect: true
script: script:
- xvfb-run wct - xvfb-run wct
- "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi" - "if [ \"${TRAVIS_PULL_REQUEST}\" = \"false\" ]; then wct -s 'default'; fi"
dist: trusty

View file

@ -1,10 +1,13 @@
{ {
"name": "paper-icon-button", "name": "paper-icon-button",
"private": true, "private": true,
"version": "1.0.7", "version": "1.1.1",
"license": "http://polymer.github.io/LICENSE.txt", "license": "http://polymer.github.io/LICENSE.txt",
"description": "A material design icon button", "description": "A material design icon button",
"main": "paper-icon-button.html", "main": [
"paper-icon-button.html",
"paper-icon-button-light.html"
],
"author": [ "author": [
"The Polymer Authors" "The Polymer Authors"
], ],

View file

@ -0,0 +1,57 @@
<!doctype html>
<!--
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
<title>paper-icon-button-light demo</title>
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../../iron-icons/iron-icons.html">
<link rel="import" href="../../paper-styles/color.html">
<link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
<link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
<link rel="import" href="../paper-icon-button-light.html">
<style is="custom-style" include="demo-pages-shared-styles"></style>
</head>
<body unresolved>
<div class="vertical-section-container centered">
<h3>paper-icon-button-light can contain iron-icons or external images and can be disabled</h3>
<demo-snippet class="centered-demo">
<template>
<style is="custom-style">
button[is=paper-icon-button-light] {
width: 40px;
height: 40px;
padding: 8px;
margin: 10px;
}
button[is=paper-icon-button-light] > img {
width: 24px;
height: 24px;
}
</style>
<button is="paper-icon-button-light" title="heart">
<iron-icon icon="favorite"></iron-icon>
</button>
<button is="paper-icon-button-light" title="octocat">
<img src="https://assets-cdn.github.com/images/modules/logos_page/Octocat.png" alt="octocat">
</button>
<button is="paper-icon-button-light" title="reply" disabled>
<iron-icon icon="reply"></iron-icon>
</button>
</template>
</demo-snippet>
</div>
</body>
</html>

View file

@ -0,0 +1,88 @@
<!--
@license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../paper-behaviors/paper-ripple-behavior.html">
<!--
@group Paper Elements
@element paper-icon-button-light
@demo demo/paper-icon-button-light.html
-->
<dom-module id="paper-icon-button-light">
<template strip-whitespace>
<style>
:host {
vertical-align: middle;
color: inherit;
outline: none;
width: 24px;
height: 24px;
background: none;
margin: 0;
border: none;
padding: 0;
position: relative;
cursor: pointer;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
:host([disabled]) {
color: #9b9b9b;
pointer-events: none;
cursor: auto;
}
paper-ripple {
opacity: 0.6;
color: currentColor;
}
</style>
<content></content>
</template>
<script>
Polymer({
is: 'paper-icon-button-light',
extends: 'button',
behaviors: [
Polymer.PaperRippleBehavior
],
listeners: {
'down': '_rippleDown',
'up': '_rippleUp',
'focus': '_rippleDown',
'blur': '_rippleUp',
},
_rippleDown: function() {
this.getRipple().downAction();
},
_rippleUp: function() {
this.getRipple().upAction();
},
/**
* @param {...*} var_args
*/
ensureRipple: function(var_args) {
var lastRipple = this._ripple;
Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
if (this._ripple && this._ripple !== lastRipple) {
this._ripple.center = true;
this._ripple.classList.add('circle');
}
}
});
</script>
</dom-module>

View file

@ -54,7 +54,7 @@
"tag": "v1.1.11", "tag": "v1.1.11",
"commit": "8cfe5c5bf8c2e40d243443d046a94b6fe371983c" "commit": "8cfe5c5bf8c2e40d243443d046a94b6fe371983c"
}, },
"_source": "git://github.com/PolymerElements/paper-input.git", "_source": "git://github.com/polymerelements/paper-input.git",
"_target": "^1.0.0", "_target": "^1.0.9",
"_originalSource": "PolymerElements/paper-input" "_originalSource": "polymerelements/paper-input"
} }

View file

@ -38,7 +38,7 @@
"tag": "v1.0.6", "tag": "v1.0.6",
"commit": "6aef0896fcbc25f9f5bd1dd55f7679e6ab7f92ad" "commit": "6aef0896fcbc25f9f5bd1dd55f7679e6ab7f92ad"
}, },
"_source": "git://github.com/PolymerElements/paper-material.git", "_source": "git://github.com/polymerelements/paper-material.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "PolymerElements/paper-material" "_originalSource": "polymerelements/paper-material"
} }

View file

@ -32,14 +32,14 @@
"iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0" "iron-test-helpers": "PolymerElements/iron-test-helpers#^1.0.0"
}, },
"ignore": [], "ignore": [],
"homepage": "https://github.com/PolymerElements/paper-ripple", "homepage": "https://github.com/polymerelements/paper-ripple",
"_release": "1.0.5", "_release": "1.0.5",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.0.5", "tag": "v1.0.5",
"commit": "d72e7a9a8ab518b901ed18dde492df3b87a93be5" "commit": "d72e7a9a8ab518b901ed18dde492df3b87a93be5"
}, },
"_source": "git://github.com/PolymerElements/paper-ripple.git", "_source": "git://github.com/polymerelements/paper-ripple.git",
"_target": "^1.0.0", "_target": "^1.0.0",
"_originalSource": "PolymerElements/paper-ripple" "_originalSource": "polymerelements/paper-ripple"
} }

View file

@ -34,6 +34,6 @@
"commit": "11c987b2eb3c73b388a79fc8aaea8ca01624f514" "commit": "11c987b2eb3c73b388a79fc8aaea8ca01624f514"
}, },
"_source": "git://github.com/Polymer/polymer.git", "_source": "git://github.com/Polymer/polymer.git",
"_target": "^1.0.0", "_target": "^1.1.0",
"_originalSource": "Polymer/polymer" "_originalSource": "Polymer/polymer"
} }

View file

@ -1,4 +1,4 @@
define([], function () { define(['datetime'], function (datetime) {
/* /*
* Javascript Humane Dates * Javascript Humane Dates
@ -29,7 +29,7 @@
]; ];
var dt = new Date; var dt = new Date;
var date = parseISO8601Date(date_str, { toLocal: true }); var date = datetime.parseISO8601Date(date_str, true);
var seconds = ((dt - date) / 1000); var seconds = ((dt - date) / 1000);
var token = ' ago'; var token = ' ago';

View file

@ -1,4 +1,4 @@
define(['dialogHelper', 'jQuery', 'paper-checkbox', 'paper-input', 'paper-item-body', 'paper-icon-item', 'paper-textarea', 'paper-fab'], function (dialogHelper, $) { define(['dialogHelper', 'datetime', 'jQuery', 'paper-checkbox', 'paper-input', 'paper-item-body', 'paper-icon-item', 'paper-textarea', 'paper-fab'], function (dialogHelper, $, datetime) {
var currentContext; var currentContext;
var metadataEditorInfo; var metadataEditorInfo;
@ -96,7 +96,7 @@
if (currentItem[property]) { if (currentItem[property]) {
var date = parseISO8601Date(currentItem[property], { toLocal: true }); var date = datetime.parseISO8601Date(currentItem[property], true);
var parts = date.toISOString().split('T'); var parts = date.toISOString().split('T');
@ -278,7 +278,7 @@
ReplaceAllMetadata: true ReplaceAllMetadata: true
}); });
require(['toast'], function(toast) { require(['toast'], function (toast) {
toast(Globalize.translate('MessageRefreshQueued')); toast(Globalize.translate('MessageRefreshQueued'));
}); });
} }
@ -873,7 +873,7 @@
if (item.DateCreated) { if (item.DateCreated) {
try { try {
date = parseISO8601Date(item.DateCreated, { toLocal: true }); date = datetime.parseISO8601Date(item.DateCreated, true);
$('#txtDateAdded', context).val(date.toISOString().slice(0, 10)); $('#txtDateAdded', context).val(date.toISOString().slice(0, 10));
} catch (e) { } catch (e) {
@ -885,7 +885,7 @@
if (item.PremiereDate) { if (item.PremiereDate) {
try { try {
date = parseISO8601Date(item.PremiereDate, { toLocal: true }); date = datetime.parseISO8601Date(item.PremiereDate, true);
$('#txtPremiereDate', context).val(date.toISOString().slice(0, 10)); $('#txtPremiereDate', context).val(date.toISOString().slice(0, 10));
} catch (e) { } catch (e) {
@ -897,7 +897,7 @@
if (item.EndDate) { if (item.EndDate) {
try { try {
date = parseISO8601Date(item.EndDate, { toLocal: true }); date = datetime.parseISO8601Date(item.EndDate, true);
$('#txtEndDate', context).val(date.toISOString().slice(0, 10)); $('#txtEndDate', context).val(date.toISOString().slice(0, 10));
} catch (e) { } catch (e) {

View file

@ -1,4 +1,4 @@
define(['browser', 'jQuery', 'paper-fab', 'paper-tabs', 'paper-slider', 'paper-icon-button'], function (browser, $) { define(['browser', 'datetime', 'jQuery', 'paper-fab', 'paper-tabs', 'paper-slider', 'paper-icon-button'], function (browser, datetime, $) {
function showSlideshowMenu(context) { function showSlideshowMenu(context) {
require(['scripts/slideshow'], function () { require(['scripts/slideshow'], function () {
@ -343,11 +343,11 @@
if (playState.PositionTicks == null) { if (playState.PositionTicks == null) {
context.querySelector('.positionTime').innerHTML = '--:--'; context.querySelector('.positionTime').innerHTML = '--:--';
} else { } else {
context.querySelector('.positionTime').innerHTML = Dashboard.getDisplayTime(playState.PositionTicks); context.querySelector('.positionTime').innerHTML = datetime.getDisplayRunningTime(playState.PositionTicks);
} }
if (item && item.RunTimeTicks != null) { if (item && item.RunTimeTicks != null) {
context.querySelector('.runtime').innerHTML = Dashboard.getDisplayTime(item.RunTimeTicks); context.querySelector('.runtime').innerHTML = datetime.getDisplayRunningTime(item.RunTimeTicks);
} else { } else {
context.querySelector('.runtime').innerHTML = '--:--'; context.querySelector('.runtime').innerHTML = '--:--';
} }
@ -733,7 +733,7 @@
ticks /= 100; ticks /= 100;
ticks *= value; ticks *= value;
this.pinValue = Dashboard.getDisplayTime(ticks); this.pinValue = datetime.getDisplayRunningTime(ticks);
}; };
context.addEventListener('click', onContextClick); context.addEventListener('click', onContextClick);

View file

@ -1,4 +1,4 @@
(function () { define(['events'], function (events) {
function transferPlayback(oldPlayer) { function transferPlayback(oldPlayer) {
@ -25,7 +25,7 @@
}); });
} }
Events.on(MediaController, 'playerchange', function (e, newPlayer, newTarget, oldPlayer) { events.on(MediaController, 'playerchange', function (e, newPlayer, newTarget, oldPlayer) {
if (!oldPlayer) { if (!oldPlayer) {
console.log('Skipping remote control autoplay because oldPlayer is null'); console.log('Skipping remote control autoplay because oldPlayer is null');
@ -48,4 +48,4 @@
} }
}); });
})(); });

View file

@ -26,9 +26,13 @@
if (!result.dev && release.target_commitish == 'dev') { if (!result.dev && release.target_commitish == 'dev') {
result.dev = release; result.dev = release;
} }
} else {
if (!result.stable && release.target_commitish == 'master') {
result.stable = release;
}
} }
if (result.beta && result.dev) { if (result.beta && result.dev && result.stable) {
break; break;
} }
} }
@ -43,62 +47,59 @@
return str.split(find).join(replace); return str.split(find).join(replace);
} }
function showInternal() { function showInternal(releases) {
getReleases().then(function (releases) { require(['dialogHelper'], function (dialogHelper) {
var dlg = dialogHelper.createDialog({
size: 'small',
removeOnClose: true,
autoFocus: false
});
require(['dialogHelper'], function (dialogHelper) { dlg.classList.add('ui-body-b');
var dlg = dialogHelper.createDialog({ dlg.classList.add('background-theme-b');
size: 'small',
removeOnClose: true,
autoFocus: false
});
dlg.classList.add('ui-body-b'); var html = '';
dlg.classList.add('background-theme-b');
var html = ''; html += '<div class="dialogHeader">';
html += '<paper-icon-button icon="arrow-back" class="btnCancel" tabindex="-1"></paper-icon-button>';
html += '<div class="dialogHeaderTitle">';
html += 'Emby';
html += '</div>';
html += '</div>';
html += '<div class="dialogHeader">'; html += '<h1>Welcome Emby Tester!</h1>';
html += '<paper-icon-button icon="arrow-back" class="btnCancel" tabindex="-1"></paper-icon-button>';
html += '<div class="dialogHeaderTitle">'; html += '<p>If you\'re seeing this message, it\s because you\'re running a pre-release version of Emby Server. Thank you for being a part of the Emby pre-release testing process.</p>';
html += 'Emby';
html += '<p>Please take a moment to leave your testing feedback about this version in the <a target="_blank" href="https://emby.media/community">Emby Community.</a></p>';
html += '<a target="_blank" href="https://emby.media/community" class="clearLink" style="display:block;"><paper-button raised class="accent block">Visit Emby Community</paper-button></a>';
if (releases.beta) {
html += '<h1 style="margin-bottom:0;margin-top:1.5em;">Beta Release Notes</h1>';
html += '<div style="margin-top:0;">';
html += replaceAll((releases.beta.body || ''), '*', '<br/>');
html += '</div>'; html += '</div>';
}
if (releases.dev) {
html += '<h1 style="margin-bottom:0;margin-top:1.5em;">Dev Release Notes</h1>';
html += '<div style="margin-top:0;">';
html += replaceAll((releases.dev.body || ''), '*', '<br/>');
html += '</div>'; html += '</div>';
}
html += '<h1>Welcome Emby Tester!</h1>'; dlg.innerHTML = html;
document.body.appendChild(dlg);
html += '<p>If you\'re seeing this message, it\s because you\'re running a pre-release version of Emby Server. Thank you for being a part of the Emby pre-release testing process.</p>'; dialogHelper.open(dlg);
html += '<p>Please take a moment to leave your testing feedback about this version in the <a target="_blank" href="https://emby.media/community">Emby Community.</a></p>'; dlg.querySelector('.btnCancel', dlg).addEventListener('click', function () {
html += '<a target="_blank" href="https://emby.media/community" class="clearLink" style="display:block;"><paper-button raised class="accent block">Visit Emby Community</paper-button></a>'; dialogHelper.close(dlg);
if (releases.beta) {
html += '<h1 style="margin-bottom:0;margin-top:1.5em;">Beta Release Notes</h1>';
html += '<div style="margin-top:0;">';
html += replaceAll((releases.beta.body || ''), '*', '<br/>');
html += '</div>';
}
if (releases.dev) {
html += '<h1 style="margin-bottom:0;margin-top:1.5em;">Dev Release Notes</h1>';
html += '<div style="margin-top:0;">';
html += replaceAll((releases.dev.body || ''), '*', '<br/>');
html += '</div>';
}
dlg.innerHTML = html;
document.body.appendChild(dlg);
dialogHelper.open(dlg);
dlg.querySelector('.btnCancel', dlg).addEventListener('click', function () {
dialogHelper.close(dlg);
});
}); });
}); });
} }
@ -132,7 +133,7 @@
var key = 'servertestermessagetime'; var key = 'servertestermessagetime';
var lastShown = parseInt(appSettings.get(key) || '0'); var lastShown = parseInt(appSettings.get(key) || '0');
if ((new Date().getTime() - lastShown) < 259200000) { if ((new Date().getTime() - lastShown) < 345600000) {
return; return;
} }
@ -143,11 +144,12 @@
return; return;
} }
apiClient.getPublicSystemInfo().then(function (info) { getReleases().then(function (releases) {
apiClient.getPublicSystemInfo().then(function (info) {
if (compareVersions(info.Version, '3.0.5934') == 1) { if (releases.stable && compareVersions(info.Version, releases.stable.tag_name) == 1) {
showInternal(); showInternal(releases);
} }
});
}); });
} }

View file

@ -58,14 +58,6 @@ iron-list .card {
border-radius: 3px; border-radius: 3px;
} }
.defaultBackground .cardImage {
background-color: #303030;
}
.homeTopViews .defaultBackground .cardImage {
background-color: #181818;
}
.cardOverlayButtonContainer { .cardOverlayButtonContainer {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
@ -109,10 +101,13 @@ iron-list .card {
} }
.ui-body-b .visualCardBox { .ui-body-b .visualCardBox {
background: rgba(56,56,56,.85);
border-radius: 3px; border-radius: 3px;
} }
.defaultBackground .cardImage, .ui-body-b .visualCardBox {
background-color: #262626;
}
.cardScalable { .cardScalable {
position: relative; position: relative;
} }

View file

@ -3,7 +3,7 @@
outline: 0 !important; outline: 0 !important;
vertical-align: middle; vertical-align: middle;
width: auto; width: auto;
margin: 0 .7em; margin: 0;
} }
.btnNotificationsInner { .btnNotificationsInner {

View file

@ -63,7 +63,7 @@
<div class="listTopPaging"> <div class="listTopPaging">
</div> </div>
</div> </div>
<div id="items" class="itemsContainer" style="max-width: 800px; margin: 0 auto;"></div> <div id="items" class="itemsContainer"></div>
</div> </div>
<div class="pageTabContent recordingsTabContent hide" data-index="3"> <div class="pageTabContent recordingsTabContent hide" data-index="3">
<div id="activeRecordings" class="homePageSection hide"> <div id="activeRecordings" class="homePageSection hide">

View file

@ -39,6 +39,23 @@
<div class="fieldDescription">${LabelRecordingPathHelp}</div> <div class="fieldDescription">${LabelRecordingPathHelp}</div>
</div> </div>
<br /> <br />
<div>
<paper-checkbox id="chkEnableRecordingSubfolders">${OptionEnableRecordingSubfolders}</paper-checkbox>
</div>
<div class="hide">
<br />
<paper-input id="txtMovieRecordingPath" label="${LabelMovieRecordingPath}" style="width:84%;display:inline-block;"></paper-input>
<paper-icon-button id="btnSelectMovieRecordingPath" icon="search"></paper-icon-button>
</div>
<div class="hide">
<paper-input id="txtSeriesRecordingPath" label="${LabelSeriesRecordingPath}" style="width:84%;display:inline-block;"></paper-input>
<paper-icon-button id="btnSelectSeriesRecordingPath" icon="search"></paper-icon-button>
</div>
<br />
<div>
<paper-checkbox id="chkOrganize">${OptionSendRecordingsToAutoOrganize}</paper-checkbox>
</div>
<br />
<br /> <br />
<div> <div>
<paper-checkbox id="chkConvertRecordings">${OptionConvertRecordingsToStreamingFormat}</paper-checkbox> <paper-checkbox id="chkConvertRecordings">${OptionConvertRecordingsToStreamingFormat}</paper-checkbox>
@ -52,12 +69,6 @@
</div> </div>
<br /> <br />
<br /> <br />
<div>
<paper-checkbox id="chkOrganize">${OptionSendRecordingsToAutoOrganize}</paper-checkbox>
<div class="fieldDescription paperCheckboxFieldDescription">${OptionSendRecordingsToAutoOrganizeHelp}</div>
</div>
<br />
<br />
<div> <div>
<h1>${HeaderDefaultPadding}</h1> <h1>${HeaderDefaultPadding}</h1>
<div> <div>

View file

@ -1,4 +1,4 @@
define(['jQuery'], function ($) { define(['jQuery', 'datetime'], function ($, datetime) {
var query = { var query = {
@ -160,7 +160,7 @@
html += '<td>'; html += '<td>';
var date = parseISO8601Date(item.Date, { toLocal: true }); var date = datetime.parseISO8601Date(item.Date, true);
html += date.toLocaleDateString(); html += date.toLocaleDateString();
html += '</td>'; html += '</td>';

View file

@ -248,7 +248,7 @@
function updateFilterControls(page) { function updateFilterControls(page) {
var query = getQuery(page); var query = getQuery(page);
$('.alphabetPicker', page).alphaValue(query.NameStartsWith); $('.alphabetPicker', page).alphaValue(query.NameStartsWithOrGreater);
} }
pageIdOn('pageinit', "channelItemsPage", function () { pageIdOn('pageinit', "channelItemsPage", function () {

View file

@ -411,7 +411,7 @@
if (session.TranscodingInfo && session.TranscodingInfo.Framerate) { if (session.TranscodingInfo && session.TranscodingInfo.Framerate) {
html += ' - '+session.TranscodingInfo.Framerate + ' fps'; html += ' - ' + session.TranscodingInfo.Framerate + ' fps';
} }
} }
else if (session.PlayState.PlayMethod == 'DirectStream') { else if (session.PlayState.PlayMethod == 'DirectStream') {
@ -465,7 +465,7 @@
var html = ''; var html = '';
if (session.PlayState.PositionTicks) { if (session.PlayState.PositionTicks) {
html += Dashboard.getDisplayTime(session.PlayState.PositionTicks); html += datetime.getDisplayRunningTime(session.PlayState.PositionTicks);
} else { } else {
html += '--:--:--'; html += '--:--:--';
} }
@ -475,7 +475,7 @@
var nowPlayingItem = session.NowPlayingItem; var nowPlayingItem = session.NowPlayingItem;
if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { if (nowPlayingItem && nowPlayingItem.RunTimeTicks) {
html += Dashboard.getDisplayTime(nowPlayingItem.RunTimeTicks); html += datetime.getDisplayRunningTime(nowPlayingItem.RunTimeTicks);
} else { } else {
html += '--:--:--'; html += '--:--:--';
} }

View file

@ -1,4 +1,4 @@
define(['jQuery'], function ($) { define(['datetime', 'jQuery'], function (datetime, $) {
function getNode(item, folderState, selected) { function getNode(item, folderState, selected) {
@ -84,7 +84,7 @@
if (item.Type == "Episode" && item.LocationType == "Virtual") { if (item.Type == "Episode" && item.LocationType == "Virtual") {
try { try {
if (item.PremiereDate && (new Date().getTime() >= parseISO8601Date(item.PremiereDate, { toLocal: true }).getTime())) { if (item.PremiereDate && (new Date().getTime() >= datetime.parseISO8601Date(item.PremiereDate, true).getTime())) {
htmlName += '<img src="css/images/editor/missing.png" title="' + Globalize.translate('MissingEpisode') + '" />'; htmlName += '<img src="css/images/editor/missing.png" title="' + Globalize.translate('MissingEpisode') + '" />';
} }
} catch (err) { } catch (err) {
@ -446,7 +446,7 @@
} }
window.MetadataEditor = { window.MetadataEditor = {
getItemPromise: function() { getItemPromise: function () {
var currentItemId = getCurrentItemId(); var currentItemId = getCurrentItemId();
if (currentItemId) { if (currentItemId) {

View file

@ -39,63 +39,4 @@ function replaceQueryString(url, param, value) {
} }
return url; return url;
}
function parseISO8601Date(s, options) {
options = options || {};
// parenthese matches:
// year month day hours minutes seconds
// dotmilliseconds
// tzstring plusminus hours minutes
var re = /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(Z|([+-])(\d{2}):(\d{2}))?/;
var d = s.match(re);
// "2010-12-07T11:00:00.000-09:00" parses to:
// ["2010-12-07T11:00:00.000-09:00", "2010", "12", "07", "11",
// "00", "00", ".000", "-09:00", "-", "09", "00"]
// "2010-12-07T11:00:00.000Z" parses to:
// ["2010-12-07T11:00:00.000Z", "2010", "12", "07", "11",
// "00", "00", ".000", "Z", undefined, undefined, undefined]
if (!d) {
throw "Couldn't parse ISO 8601 date string '" + s + "'";
}
// parse strings, leading zeros into proper ints
var a = [1, 2, 3, 4, 5, 6, 10, 11];
for (var i in a) {
d[a[i]] = parseInt(d[a[i]], 10);
}
d[7] = parseFloat(d[7]);
// Date.UTC(year, month[, date[, hrs[, min[, sec[, ms]]]]])
// note that month is 0-11, not 1-12
// see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/UTC
var ms = Date.UTC(d[1], d[2] - 1, d[3], d[4], d[5], d[6]);
// if there are milliseconds, add them
if (d[7] > 0) {
ms += Math.round(d[7] * 1000);
}
// if there's a timezone, calculate it
if (d[8] != "Z" && d[10]) {
var offset = d[10] * 60 * 60 * 1000;
if (d[11]) {
offset += d[11] * 60 * 1000;
}
if (d[9] == "-") {
ms -= offset;
} else {
ms += offset;
}
} else if (!options.toLocal) {
ms += new Date().getTimezoneOffset() * 60000;
}
return new Date(ms);
} }

View file

@ -1,4 +1,4 @@
define(['appSettings', 'jQuery', 'paper-slider', 'paper-button'], function (appSettings, $) { define(['appSettings', 'datetime', 'jQuery', 'paper-slider', 'paper-button'], function (appSettings, datetime, $) {
function getDeviceProfile(serverAddress, deviceId, item, startPositionTicks, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex) { function getDeviceProfile(serverAddress, deviceId, item, startPositionTicks, maxBitrate, mediaSourceId, audioStreamIndex, subtitleStreamIndex) {
@ -322,7 +322,7 @@
var time = item.RunTimeTicks * (Number(pct) * .01); var time = item.RunTimeTicks * (Number(pct) * .01);
var tooltext = Dashboard.getDisplayTime(time); var tooltext = datetime.getDisplayRunningTime(time);
$('.sliderValue', elem).html(tooltext); $('.sliderValue', elem).html(tooltext);

View file

@ -1,4 +1,4 @@
define(['jQuery', 'scrollStyles'], function ($) { define(['datetime', 'scrollStyles'], function (datetime) {
function loadUpcoming(page) { function loadUpcoming(page) {
Dashboard.showLoadingMsg(); Dashboard.showLoadingMsg();
@ -59,7 +59,7 @@
if (item.PremiereDate) { if (item.PremiereDate) {
try { try {
var premiereDate = parseISO8601Date(item.PremiereDate, { toLocal: true }); var premiereDate = datetime.parseISO8601Date(item.PremiereDate, true);
if (premiereDate.getDate() == new Date().getDate() - 1) { if (premiereDate.getDate() == new Date().getDate() - 1) {
dateText = Globalize.translate('Yesterday'); dateText = Globalize.translate('Yesterday');

View file

@ -1,4 +1,4 @@
define(['layoutManager', 'jQuery', 'scrollStyles'], function (layoutManager, $) { define(['layoutManager', 'datetime', 'jQuery', 'scrollStyles'], function (layoutManager, datetime, $) {
var currentItem; var currentItem;
@ -93,7 +93,7 @@
var now = new Date(); var now = new Date();
if (now >= parseISO8601Date(item.StartDate, { toLocal: true }) && now < parseISO8601Date(item.EndDate, { toLocal: true })) { if (now >= datetime.parseISO8601Date(item.StartDate, true) && now < datetime.parseISO8601Date(item.EndDate, true)) {
$('.btnPlay', page).removeClass('hide'); $('.btnPlay', page).removeClass('hide');
canPlay = true; canPlay = true;
} else { } else {
@ -176,7 +176,7 @@
if (item.Type == "Person" && item.PremiereDate) { if (item.Type == "Person" && item.PremiereDate) {
try { try {
var birthday = parseISO8601Date(item.PremiereDate, { toLocal: true }).toDateString(); var birthday = datetime.parseISO8601Date(item.PremiereDate, true).toDateString();
$('#itemBirthday', page).show().html(Globalize.translate('BirthDateValue').replace('{0}', birthday)); $('#itemBirthday', page).show().html(Globalize.translate('BirthDateValue').replace('{0}', birthday));
} }
@ -190,7 +190,7 @@
if (item.Type == "Person" && item.EndDate) { if (item.Type == "Person" && item.EndDate) {
try { try {
var deathday = parseISO8601Date(item.EndDate, { toLocal: true }).toDateString(); var deathday = datetime.parseISO8601Date(item.EndDate, true).toDateString();
$('#itemDeathDate', page).show().html(Globalize.translate('DeathDateValue').replace('{0}', deathday)); $('#itemDeathDate', page).show().html(Globalize.translate('DeathDateValue').replace('{0}', deathday));
} }
@ -222,7 +222,7 @@
if (item.LocationType == "Virtual" && item.Type == "Episode") { if (item.LocationType == "Virtual" && item.Type == "Episode") {
try { try {
if (item.PremiereDate && (new Date().getTime() >= parseISO8601Date(item.PremiereDate, { toLocal: true }).getTime())) { if (item.PremiereDate && (new Date().getTime() >= datetime.parseISO8601Date(item.PremiereDate, true).getTime())) {
isMissingEpisode = true; isMissingEpisode = true;
} }
} catch (err) { } catch (err) {
@ -341,7 +341,7 @@
}); });
var itemsContainer = section.querySelector('.nextUpItems'); var itemsContainer = section.querySelector('.nextUpItems');
itemsContainer.innerHTML = html; itemsContainer.innerHTML = html;
ImageLoader.lazyChildren(itemsContainer); ImageLoader.lazyChildren(itemsContainer);
$(itemsContainer).createCardMenus(); $(itemsContainer).createCardMenus();
@ -1221,7 +1221,7 @@
try { try {
var date = parseISO8601Date(review.Date, { toLocal: true }).toLocaleDateString(); var date = datetime.parseISO8601Date(review.Date, true).toLocaleDateString();
html += '<span class="reviewDate">' + date + '</span>'; html += '<span class="reviewDate">' + date + '</span>';
} }
@ -1402,7 +1402,7 @@
html += '<div class="cardFooter">'; html += '<div class="cardFooter">';
html += '<div class="cardText">' + chapterName + '</div>'; html += '<div class="cardText">' + chapterName + '</div>';
html += '<div class="cardText">'; html += '<div class="cardText">';
html += Dashboard.getDisplayTime(chapter.StartPositionTicks); html += datetime.getDisplayRunningTime(chapter.StartPositionTicks);
html += '</div>'; html += '</div>';
//cardFooter //cardFooter
@ -1639,7 +1639,7 @@
html += '<div class="cardText">' + item.Name + '</div>'; html += '<div class="cardText">' + item.Name + '</div>';
html += '<div class="cardText">'; html += '<div class="cardText">';
if (item.RunTimeTicks != "") { if (item.RunTimeTicks != "") {
html += Dashboard.getDisplayTime(item.RunTimeTicks); html += datetime.getDisplayRunningTime(item.RunTimeTicks);
} }
else { else {
html += "&nbsp;"; html += "&nbsp;";

View file

@ -1,4 +1,4 @@
define(['playlistManager', 'appSettings', 'appStorage', 'apphost', 'jQuery', 'scrollStyles'], function (playlistManager, appSettings, appStorage, appHost, $) { define(['playlistManager', 'appSettings', 'appStorage', 'apphost', 'datetime', 'jQuery', 'scrollStyles'], function (playlistManager, appSettings, appStorage, appHost, datetime, $) {
var libraryBrowser = (function (window, document, screen) { var libraryBrowser = (function (window, document, screen) {
@ -1380,19 +1380,10 @@
} }
if (imgUrl) { if (imgUrl) {
var minLazyIndex = 16;
if (options.smallIcon) { if (options.smallIcon) {
if (index < minLazyIndex) { html += '<div class="listviewImage lazy small" data-src="' + imgUrl + '" item-icon></div>';
html += '<div class="listviewImage small" style="background-image:url(\'' + imgUrl + '\');" item-icon></div>';
} else {
html += '<div class="listviewImage lazy small" data-src="' + imgUrl + '" item-icon></div>';
}
} else { } else {
if (index < minLazyIndex) { html += '<div class="listviewImage lazy" data-src="' + imgUrl + '" item-icon></div>';
html += '<div class="listviewImage" style="background-image:url(\'' + imgUrl + '\');" item-icon></div>';
} else {
html += '<div class="listviewImage lazy" data-src="' + imgUrl + '" item-icon></div>';
}
} }
} else { } else {
if (options.smallIcon) { if (options.smallIcon) {
@ -1925,7 +1916,7 @@
if (item.StartDate) { if (item.StartDate) {
try { try {
dateText = LibraryBrowser.getFutureDateText(parseISO8601Date(item.StartDate, { toLocal: true }), true); dateText = LibraryBrowser.getFutureDateText(datetime.parseISO8601Date(item.StartDate, true), true);
} catch (err) { } catch (err) {
} }
@ -2421,6 +2412,15 @@
lines.push(item.ProductionYear || ''); lines.push(item.ProductionYear || '');
} }
if (item.Type == 'TvChannel') {
if (item.CurrentProgram) {
lines.push(LibraryBrowser.getPosterViewDisplayName(item.CurrentProgram));
} else {
lines.push('');
}
}
if (options.showSeriesYear) { if (options.showSeriesYear) {
if (item.Status == "Continuing") { if (item.Status == "Continuing") {
@ -2435,7 +2435,7 @@
if (options.showProgramAirInfo) { if (options.showProgramAirInfo) {
var date = parseISO8601Date(item.StartDate, { toLocal: true }); var date = datetime.parseISO8601Date(item.StartDate, true);
var text = item.StartDate ? var text = item.StartDate ?
date.toLocaleString() : date.toLocaleString() :
@ -2623,7 +2623,7 @@
if (item.Type == 'Episode') { if (item.Type == 'Episode') {
try { try {
var date = parseISO8601Date(item.PremiereDate, { toLocal: true }); var date = datetime.parseISO8601Date(item.PremiereDate, true);
if (item.PremiereDate && (new Date().getTime() < date.getTime())) { if (item.PremiereDate && (new Date().getTime() < date.getTime())) {
return '<div class="posterRibbon unairedPosterRibbon">' + Globalize.translate('HeaderUnaired') + '</div>'; return '<div class="posterRibbon unairedPosterRibbon">' + Globalize.translate('HeaderUnaired') + '</div>';
@ -3422,56 +3422,6 @@
detailImageProgressContainer.innerHTML = progressHtml || ''; detailImageProgressContainer.innerHTML = progressHtml || '';
}, },
getDisplayTime: function (date) {
if ((typeof date).toString().toLowerCase() === 'string') {
try {
date = parseISO8601Date(date, { toLocal: true });
} catch (err) {
return date;
}
}
var lower = date.toLocaleTimeString().toLowerCase();
var hours = date.getHours();
var minutes = date.getMinutes();
var text;
if (lower.indexOf('am') != -1 || lower.indexOf('pm') != -1) {
var suffix = hours > 11 ? 'pm' : 'am';
hours = (hours % 12) || 12;
text = hours;
if (minutes) {
text += ':';
if (minutes < 10) {
text += '0';
}
text += minutes;
}
text += suffix;
} else {
text = hours + ':';
if (minutes < 10) {
text += '0';
}
text += minutes;
}
return text;
},
getMiscInfoHtml: function (item) { getMiscInfoHtml: function (item) {
var miscInfo = []; var miscInfo = [];
@ -3501,7 +3451,7 @@
if (item.PremiereDate) { if (item.PremiereDate) {
try { try {
date = parseISO8601Date(item.PremiereDate, { toLocal: true }); date = datetime.parseISO8601Date(item.PremiereDate, true);
text = date.toLocaleDateString(); text = date.toLocaleDateString();
miscInfo.push(text); miscInfo.push(text);
@ -3515,13 +3465,13 @@
if (item.StartDate) { if (item.StartDate) {
try { try {
date = parseISO8601Date(item.StartDate, { toLocal: true }); date = datetime.parseISO8601Date(item.StartDate, true);
text = date.toLocaleDateString(); text = date.toLocaleDateString();
miscInfo.push(text); miscInfo.push(text);
if (item.Type != "Recording") { if (item.Type != "Recording") {
text = LibraryBrowser.getDisplayTime(date); text = datetime.getDisplayTime(date);
miscInfo.push(text); miscInfo.push(text);
} }
} }
@ -3544,10 +3494,10 @@
try { try {
var endYear = parseISO8601Date(item.EndDate, { toLocal: true }).getFullYear(); var endYear = datetime.parseISO8601Date(item.EndDate, true).getFullYear();
if (endYear != item.ProductionYear) { if (endYear != item.ProductionYear) {
text += "-" + parseISO8601Date(item.EndDate, { toLocal: true }).getFullYear(); text += "-" + datetime.parseISO8601Date(item.EndDate, true).getFullYear();
} }
} }
@ -3569,7 +3519,7 @@
else if (item.PremiereDate) { else if (item.PremiereDate) {
try { try {
text = parseISO8601Date(item.PremiereDate, { toLocal: true }).getFullYear(); text = datetime.parseISO8601Date(item.PremiereDate, true).getFullYear();
miscInfo.push(text); miscInfo.push(text);
} }
catch (e) { catch (e) {
@ -3584,7 +3534,7 @@
if (item.Type == "Audio") { if (item.Type == "Audio") {
miscInfo.push(Dashboard.getDisplayTime(item.RunTimeTicks)); miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks));
} else { } else {
minutes = item.RunTimeTicks / 600000000; minutes = item.RunTimeTicks / 600000000;
@ -3597,7 +3547,7 @@
if (item.CumulativeRunTimeTicks && item.Type != "Series" && item.Type != "Season") { if (item.CumulativeRunTimeTicks && item.Type != "Series" && item.Type != "Season") {
miscInfo.push(Dashboard.getDisplayTime(item.CumulativeRunTimeTicks)); miscInfo.push(datetime.getDisplayRunningTime(item.CumulativeRunTimeTicks));
} }
if (item.OfficialRating && item.Type !== "Season" && item.Type !== "Episode") { if (item.OfficialRating && item.Type !== "Season" && item.Type !== "Episode") {
@ -3737,7 +3687,7 @@
if (item.PremiereDate) { if (item.PremiereDate) {
try { try {
var date = parseISO8601Date(item.PremiereDate, { toLocal: true }); var date = datetime.parseISO8601Date(item.PremiereDate, true);
var translationKey = new Date().getTime() > date.getTime() ? "ValuePremiered" : "ValuePremieres"; var translationKey = new Date().getTime() > date.getTime() ? "ValuePremiered" : "ValuePremieres";

View file

@ -34,7 +34,7 @@
html += '<paper-icon-button icon="mic" class="headerButton headerButtonRight headerVoiceButton hide"></paper-icon-button>'; html += '<paper-icon-button icon="mic" class="headerButton headerButtonRight headerVoiceButton hide"></paper-icon-button>';
html += '<button class="headerButton headerButtonRight btnNotifications clearButton" type="button" title="Notifications"><div class="btnNotificationsInner">0</div></button>'; html += '<paper-button class="headerButton headerButtonRight btnNotifications clearButton" type="button" title="Notifications"><div class="btnNotificationsInner">0</div></paper-button>';
html += '<paper-icon-button icon="person" class="headerButton headerButtonRight headerUserButton"></paper-icon-button>'; html += '<paper-icon-button icon="person" class="headerButton headerButtonRight headerUserButton"></paper-icon-button>';
@ -1119,7 +1119,7 @@
var headerCreated; var headerCreated;
var userRequiresUpdateAfterHeader; var userRequiresUpdateAfterHeader;
require(['paper-icon-button', 'emby-icons'], function () { require(['paper-icon-button', 'emby-icons', 'paper-button'], function () {
renderHeader(); renderHeader();
headerCreated = true; headerCreated = true;

View file

@ -1,4 +1,4 @@
define(['jQuery'], function ($) { define(['datetime', 'tvguide'], function (datetime) {
function renderPrograms(page, result) { function renderPrograms(page, result) {
@ -12,10 +12,10 @@
var program = result.Items[i]; var program = result.Items[i];
var startDate = parseISO8601Date(program.StartDate, { toLocal: true }); var startDate = datetime.parseISO8601Date(program.StartDate, true);
var startDateText = LibraryBrowser.getFutureDateText(startDate); var startDateText = LibraryBrowser.getFutureDateText(startDate);
var endDate = parseISO8601Date(program.EndDate, { toLocal: true }); var endDate = datetime.parseISO8601Date(program.EndDate, true);
if (startDateText != currentIndexValue) { if (startDateText != currentIndexValue) {
@ -32,7 +32,7 @@
} }
html += '<div class="' + cssClass + '">'; html += '<div class="' + cssClass + '">';
html += '<div class="tvProgramTimeSlotInner">' + LibraryBrowser.getDisplayTime(startDate) + '</div>'; html += '<div class="tvProgramTimeSlotInner">' + datetime.getDisplayTime(startDate) + '</div>';
html += '</div>'; html += '</div>';
cssClass = "tvProgramInfo"; cssClass = "tvProgramInfo";
@ -96,7 +96,7 @@
html += '</a>'; html += '</a>';
} }
$('#childrenContent', page).html(html); page.querySelector('#childrenContent').innerHTML = html;
} }
function loadPrograms(page, channelId) { function loadPrograms(page, channelId) {

View file

@ -35,9 +35,13 @@
function getChannelsHtml(channels) { function getChannelsHtml(channels) {
return LibraryBrowser.getListViewHtml({ return LibraryBrowser.getPosterViewHtml({
items: channels, items: channels,
smallIcon: true shape: "square",
showTitle: true,
lazy: true,
cardLayout: true,
showDetailsMenu: true
}); });
} }

View file

@ -1,4 +1,4 @@
define([], function () { define(['datetime'], function (datetime) {
function getTimersHtml(timers) { function getTimersHtml(timers) {
@ -13,7 +13,7 @@
var timer = timers[i]; var timer = timers[i];
var startDateText = LibraryBrowser.getFutureDateText(parseISO8601Date(timer.StartDate, { toLocal: true })); var startDateText = LibraryBrowser.getFutureDateText(datetime.parseISO8601Date(timer.StartDate, true));
if (startDateText != index) { if (startDateText != index) {
@ -69,8 +69,8 @@
html += '</div>'; html += '</div>';
html += '<div secondary>'; html += '<div secondary>';
html += LibraryBrowser.getDisplayTime(timer.StartDate); html += datetime.getDisplayTime(timer.StartDate);
html += ' - ' + LibraryBrowser.getDisplayTime(timer.EndDate); html += ' - ' + datetime.getDisplayTime(timer.EndDate);
html += '</div>'; html += '</div>';
html += '</a>'; html += '</a>';
@ -130,7 +130,7 @@
if (airDate && item.IsRepeat) { if (airDate && item.IsRepeat) {
try { try {
airDate = parseISO8601Date(airDate, { toLocal: true }).toLocaleDateString(); airDate = datetime.parseISO8601Date(airDate, true).toLocaleDateString();
} }
catch (e) { catch (e) {
console.log("Error parsing date: " + airDate); console.log("Error parsing date: " + airDate);

View file

@ -1,4 +1,4 @@
define(['jQuery'], function ($) { define(['datetime', 'jQuery'], function (datetime, $) {
var currentItem; var currentItem;
@ -52,7 +52,7 @@
$('.time', page).html(Globalize.translate('LabelAnytime')).trigger('create'); $('.time', page).html(Globalize.translate('LabelAnytime')).trigger('create');
} }
else if (item.ChannelId) { else if (item.ChannelId) {
$('.time', page).html(LibraryBrowser.getDisplayTime(item.StartDate)).trigger('create'); $('.time', page).html(datetime.getDisplayTime(item.StartDate)).trigger('create');
} }
Dashboard.hideLoadingMsg(); Dashboard.hideLoadingMsg();

View file

@ -1,4 +1,4 @@
define(['jQuery'], function ($) { define(['datetime', 'jQuery'], function (datetime, $) {
var query = { var query = {
@ -63,7 +63,7 @@
html += ' - ' + Globalize.translate('LabelAnytime'); html += ' - ' + Globalize.translate('LabelAnytime');
} else { } else {
html += ' - ' + LibraryBrowser.getDisplayTime(timer.StartDate); html += ' - ' + datetime.getDisplayTime(timer.StartDate);
} }
html += '</div>'; html += '</div>';

View file

@ -12,11 +12,15 @@
$('#chkConvertRecordings', page).checked(config.EnableRecordingEncoding); $('#chkConvertRecordings', page).checked(config.EnableRecordingEncoding);
$('#chkPreserveAudio', page).checked(config.EnableOriginalAudioWithEncodedRecordings || false); $('#chkPreserveAudio', page).checked(config.EnableOriginalAudioWithEncodedRecordings || false);
$('#txtRecordingPath', page).val(config.RecordingPath || '');
$('#txtPrePaddingMinutes', page).val(config.PrePaddingSeconds / 60); $('#txtPrePaddingMinutes', page).val(config.PrePaddingSeconds / 60);
$('#txtPostPaddingMinutes', page).val(config.PostPaddingSeconds / 60); $('#txtPostPaddingMinutes', page).val(config.PostPaddingSeconds / 60);
page.querySelector('#txtRecordingPath').value = config.RecordingPath || '';
page.querySelector('#txtMovieRecordingPath').value = config.MovieRecordingPath || '';
page.querySelector('#txtSeriesRecordingPath').value = config.SeriesRecordingPath || '';
page.querySelector('#chkEnableRecordingSubfolders').checked = config.EnableRecordingSubfolders || false;
Dashboard.hideLoadingMsg(); Dashboard.hideLoadingMsg();
} }
@ -33,10 +37,13 @@
config.EnableAutoOrganize = $('#chkOrganize', form).checked(); config.EnableAutoOrganize = $('#chkOrganize', form).checked();
config.EnableRecordingEncoding = $('#chkConvertRecordings', form).checked(); config.EnableRecordingEncoding = $('#chkConvertRecordings', form).checked();
config.EnableOriginalAudioWithEncodedRecordings = $('#chkPreserveAudio', form).checked(); config.EnableOriginalAudioWithEncodedRecordings = $('#chkPreserveAudio', form).checked();
config.RecordingPath = $('#txtRecordingPath', form).val() || null; config.RecordingPath = form.querySelector('#txtRecordingPath').value || null;
config.MovieRecordingPath = form.querySelector('#txtMovieRecordingPath').value || null;
config.SeriesRecordingPath = form.querySelector('#txtSeriesRecordingPath').value || null;
config.PrePaddingSeconds = $('#txtPrePaddingMinutes', form).val() * 60; config.PrePaddingSeconds = $('#txtPrePaddingMinutes', form).val() * 60;
config.PostPaddingSeconds = $('#txtPostPaddingMinutes', form).val() * 60; config.PostPaddingSeconds = $('#txtPostPaddingMinutes', form).val() * 60;
config.EnableRecordingSubfolders = form.querySelector('#chkEnableRecordingSubfolders').checked;
ApiClient.updateNamedConfiguration("livetv", config).then(Dashboard.processServerConfigurationUpdateResult); ApiClient.updateNamedConfiguration("livetv", config).then(Dashboard.processServerConfigurationUpdateResult);
}); });
@ -86,6 +93,44 @@
}); });
}); });
$('#btnSelectMovieRecordingPath', page).on("click.selectDirectory", function () {
require(['directorybrowser'], function (directoryBrowser) {
var picker = new directoryBrowser();
picker.show({
callback: function (path) {
if (path) {
$('#txtMovieRecordingPath', page).val(path);
}
picker.close();
}
});
});
});
$('#btnSelectSeriesRecordingPath', page).on("click.selectDirectory", function () {
require(['directorybrowser'], function (directoryBrowser) {
var picker = new directoryBrowser();
picker.show({
callback: function (path) {
if (path) {
$('#txtSeriesRecordingPath', page).val(path);
}
picker.close();
}
});
});
});
}).on('pageshow', "#liveTvSettingsPage", function () { }).on('pageshow', "#liveTvSettingsPage", function () {
LibraryMenu.setTabs('livetvadmin', 1, getTabs); LibraryMenu.setTabs('livetvadmin', 1, getTabs);

View file

@ -1,4 +1,4 @@
define(['jQuery', 'paper-fab', 'paper-item-body', 'paper-icon-item'], function ($) { define(['datetime', 'jQuery', 'paper-fab', 'paper-item-body', 'paper-icon-item'], function (datetime, $) {
function getTabs() { function getTabs() {
return [ return [
@ -61,11 +61,11 @@
logHtml += "<div>" + log.Name + "</div>"; logHtml += "<div>" + log.Name + "</div>";
var date = parseISO8601Date(log.DateModified, { toLocal: true }); var date = datetime.parseISO8601Date(log.DateModified, true);
var text = date.toLocaleDateString(); var text = date.toLocaleDateString();
text += ' ' + LibraryBrowser.getDisplayTime(date); text += ' ' + datetime.getDisplayTime(date);
logHtml += '<div secondary>' + text + '</div>'; logHtml += '<div secondary>' + text + '</div>';

View file

@ -1,4 +1,4 @@
define(['appSettings', 'jQuery', 'scrollStyles'], function (appSettings, $) { define(['appSettings', 'datetime', 'jQuery', 'scrollStyles'], function (appSettings, datetime, $) {
function createVideoPlayer(self) { function createVideoPlayer(self) {
@ -495,7 +495,7 @@
if (c.Name) { if (c.Name) {
chapterHtml += '<div class="cardText">' + c.Name + '</div>'; chapterHtml += '<div class="cardText">' + c.Name + '</div>';
} }
chapterHtml += '<div class="cardText">' + Dashboard.getDisplayTime(c.StartPositionTicks) + '</div>'; chapterHtml += '<div class="cardText">' + datetime.getDisplayRunningTime(c.StartPositionTicks) + '</div>';
chapterHtml += '</div>'; chapterHtml += '</div>';
chapterHtml += '</div>'; chapterHtml += '</div>';
@ -789,7 +789,7 @@
ticks /= 100; ticks /= 100;
ticks *= value; ticks *= value;
this.pinValue = Dashboard.getDisplayTime(ticks); this.pinValue = datetime.getDisplayRunningTime(ticks);
}; };
volumeSlider = $('.videoVolumeSlider', parent).on('change', function () { volumeSlider = $('.videoVolumeSlider', parent).on('change', function () {

View file

@ -1,4 +1,4 @@
define(['appSettings', 'userSettings', 'appStorage'], function (appSettings, userSettings, appStorage) { define(['appSettings', 'userSettings', 'appStorage', 'datetime'], function (appSettings, userSettings, appStorage, datetime) {
function mediaPlayer() { function mediaPlayer() {
@ -44,216 +44,6 @@ define(['appSettings', 'userSettings', 'appStorage'], function (appSettings, use
return targets; return targets;
}; };
function updateDeviceProfileForAndroid(profile) {
// Just here as an easy escape out, if ever needed
var enableVlcVideo = true;
var enableVlcAudio = window.VlcAudio;
if (enableVlcVideo) {
profile.DirectPlayProfiles.push({
Container: "m4v,3gp,ts,mpegts,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm",
Type: 'Video',
AudioCodec: 'aac,aac_latm,mp3,ac3,wma,dca,pcm,PCM_S16LE,PCM_S24LE,opus,flac'
});
profile.CodecProfiles = profile.CodecProfiles.filter(function (i) {
return i.Type == 'Audio';
});
profile.SubtitleProfiles = [];
profile.SubtitleProfiles.push({
Format: 'srt',
Method: 'External'
});
profile.SubtitleProfiles.push({
Format: 'srt',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'subrip',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'ass',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'ssa',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'pgs',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'pgssub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'dvdsub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'vtt',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'sub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'idx',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'smi',
Method: 'Embed'
});
// These don't play very well
profile.CodecProfiles.push({
Type: 'VideoAudio',
Codec: 'dca',
Conditions: [
{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: 6
}
]
});
profile.CodecProfiles.push({
Type: 'VideoAudio',
Codec: 'aac,mp3',
Conditions: [
{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: '6'
}
]
});
profile.CodecProfiles.push({
Type: 'Video',
Codec: 'h264',
Conditions: [
{
Condition: 'EqualsAny',
Property: 'VideoProfile',
Value: 'high|main|baseline|constrained baseline'
},
{
Condition: 'LessThanEqual',
Property: 'VideoLevel',
Value: '41'
}]
});
profile.TranscodingProfiles.filter(function (p) {
return p.Type == 'Video' && p.CopyTimestamps == true;
}).forEach(function (p) {
// Vlc doesn't seem to handle this well
p.CopyTimestamps = false;
});
profile.TranscodingProfiles.filter(function (p) {
return p.Type == 'Video' && p.VideoCodec == 'h264';
}).forEach(function (p) {
p.AudioCodec += ',ac3';
});
}
if (enableVlcAudio) {
profile.DirectPlayProfiles.push({
Container: "aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus",
Type: 'Audio'
});
profile.CodecProfiles = profile.CodecProfiles.filter(function (i) {
return i.Type != 'Audio';
});
profile.CodecProfiles.push({
Type: 'Audio',
Conditions: [{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: '2'
}]
});
}
}
function updateDeviceProfileForIOS(profile) {
}
self.getDeviceProfile = function (maxHeight) {
return new Promise(function (resolve, reject) {
require(['browserdeviceprofile', 'qualityoptions'], function (profileBuilder, qualityoptions) {
var supportsCustomSeeking = false;
if (!browserInfo.mobile) {
supportsCustomSeeking = true;
} else if (AppInfo.isNativeApp && browserInfo.safari) {
if (navigator.userAgent.toLowerCase().indexOf('ipad') == -1) {
// Need to disable it in order to support picture in picture
supportsCustomSeeking = true;
}
} else if (AppInfo.isNativeApp) {
supportsCustomSeeking = true;
}
var profile = profileBuilder({
supportsCustomSeeking: supportsCustomSeeking
});
if (!(AppInfo.isNativeApp && browserInfo.android)) {
profile.SubtitleProfiles.push({
Format: 'ass',
Method: 'External'
});
profile.SubtitleProfiles.push({
Format: 'ssa',
Method: 'External'
});
}
var bitrateSetting = appSettings.maxStreamingBitrate();
if (!maxHeight) {
maxHeight = qualityoptions.getVideoQualityOptions(bitrateSetting).filter(function (q) {
return q.selected;
})[0].maxHeight;
}
if (AppInfo.isNativeApp && browserInfo.android) {
updateDeviceProfileForAndroid(profile);
}
else if (AppInfo.isNativeApp && browserInfo.safari) {
updateDeviceProfileForIOS(profile);
}
profile.MaxStreamingBitrate = bitrateSetting;
resolve(profile);
});
});
};
var supportsTextTracks; var supportsTextTracks;
self.supportsTextTracks = function () { self.supportsTextTracks = function () {
@ -378,7 +168,7 @@ define(['appSettings', 'userSettings', 'appStorage'], function (appSettings, use
var playSessionId = getParameterByName('PlaySessionId', currentSrc); var playSessionId = getParameterByName('PlaySessionId', currentSrc);
var liveStreamId = getParameterByName('LiveStreamId', currentSrc); var liveStreamId = getParameterByName('LiveStreamId', currentSrc);
self.getDeviceProfile().then(function (deviceProfile) { Dashboard.getDeviceProfile().then(function (deviceProfile) {
var audioStreamIndex = params.AudioStreamIndex == null ? (getParameterByName('AudioStreamIndex', currentSrc) || null) : params.AudioStreamIndex; var audioStreamIndex = params.AudioStreamIndex == null ? (getParameterByName('AudioStreamIndex', currentSrc) || null) : params.AudioStreamIndex;
if (typeof (audioStreamIndex) == 'string') { if (typeof (audioStreamIndex) == 'string') {
@ -481,12 +271,12 @@ define(['appSettings', 'userSettings', 'appStorage'], function (appSettings, use
// Convert to ticks // Convert to ticks
ticks = Math.floor(ticks); ticks = Math.floor(ticks);
var timeText = Dashboard.getDisplayTime(ticks); var timeText = datetime.getDisplayRunningTime(ticks);
var mediaRenderer = self.currentMediaRenderer; var mediaRenderer = self.currentMediaRenderer;
if (self.currentDurationTicks) { if (self.currentDurationTicks) {
timeText += " / " + Dashboard.getDisplayTime(self.currentDurationTicks); timeText += " / " + datetime.getDisplayRunningTime(self.currentDurationTicks);
if (positionSlider) { if (positionSlider) {
@ -864,7 +654,7 @@ define(['appSettings', 'userSettings', 'appStorage'], function (appSettings, use
} }
var onBitrateDetected = function () { var onBitrateDetected = function () {
self.getDeviceProfile().then(function (deviceProfile) { Dashboard.getDeviceProfile().then(function (deviceProfile) {
playOnDeviceProfileCreated(deviceProfile, item, startPosition, callback); playOnDeviceProfileCreated(deviceProfile, item, startPosition, callback);
}); });
}; };

View file

@ -206,7 +206,7 @@
var query = getQuery(page); var query = getQuery(page);
$('.alphabetPicker', page).alphaValue(query.NameStartsWith); $('.alphabetPicker', page).alphaValue(query.NameStartsWithOrGreater);
} }
function initPage(tabContent) { function initPage(tabContent) {

View file

@ -1,4 +1,4 @@
define(['jQuery'], function ($) { define(['datetime', 'jQuery'], function (datetime, $) {
var currentPlayer; var currentPlayer;
@ -247,7 +247,7 @@
ticks /= 100; ticks /= 100;
ticks *= value; ticks *= value;
this.pinValue = Dashboard.getDisplayTime(ticks); this.pinValue = datetime.getDisplayRunningTime(ticks);
}; };
}, 300); }, 300);
} }
@ -375,11 +375,11 @@
} }
} }
var timeText = Dashboard.getDisplayTime(playState.PositionTicks); var timeText = datetime.getDisplayRunningTime(playState.PositionTicks);
if (nowPlayingItem.RunTimeTicks) { if (nowPlayingItem.RunTimeTicks) {
timeText += " / " + Dashboard.getDisplayTime(nowPlayingItem.RunTimeTicks); timeText += " / " + datetime.getDisplayRunningTime(nowPlayingItem.RunTimeTicks);
} }

View file

@ -163,12 +163,14 @@
function getAppInfo() { function getAppInfo() {
if (AppInfo.nativeApp) { var frequency = 86400000;
return Promise.resolve('');
if (AppInfo.isNativeApp) {
frequency = 604800000;
} }
var cacheKey = 'lastappinfopresent5'; var cacheKey = 'lastappinfopresent5';
if ((new Date().getTime() - parseInt(appSettings.get(cacheKey) || '0')) < 86400000) { if ((new Date().getTime() - parseInt(appSettings.get(cacheKey) || '0')) < frequency) {
return Promise.resolve(''); return Promise.resolve('');
} }
@ -180,7 +182,11 @@
return ''; return '';
} }
var infos = [getTheaterInfo, getPremiereInfo]; var infos = [getPremiereInfo];
if (!browserInfo.safari || !AppInfo.isNativeApp) {
infos.push(getTheaterInfo);
}
appSettings.set(cacheKey, new Date().getTime()); appSettings.set(cacheKey, new Date().getTime());
@ -198,7 +204,9 @@
var html = ''; var html = '';
html += '<div>'; html += '<div>';
html += '<h1>Try Emby Theater<paper-icon-button icon="close" onclick="jQuery(this.parentNode.parentNode).remove();" style="margin-left:1em;"></paper-icon-button></h1>'; html += '<h1>Try Emby Theater<paper-icon-button icon="close" onclick="jQuery(this.parentNode.parentNode).remove();" style="margin-left:1em;"></paper-icon-button></h1>';
html += '<p>A beautiful app for your TV and large screen tablet. <a href="https://emby.media/download" target="_blank">Emby Theater</a> runs on Windows, Xbox One, Google Chrome, FireFox, Microsoft Edge and Opera.</p>';
var nameText = AppInfo.isNativeApp ? 'Emby Theater' : '<a href="https://emby.media/download" target="_blank">Emby Theater</a>';
html += '<p>A beautiful app for your TV and large screen tablet. ' + nameText + ' runs on Windows, Xbox One, Google Chrome, FireFox, Microsoft Edge and Opera.</p>';
html += '<div class="itemsContainer">'; html += '<div class="itemsContainer">';
html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater1.png', 'https://emby.media/download'); html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater1.png', 'https://emby.media/download');
html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater2.png', 'https://emby.media/download'); html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater2.png', 'https://emby.media/download');
@ -214,7 +222,10 @@
var html = ''; var html = '';
html += '<div>'; html += '<div>';
html += '<h1>Try Emby Premiere<paper-icon-button icon="close" onclick="jQuery(this.parentNode.parentNode).remove();" style="margin-left:1em;"></paper-icon-button></h1>'; html += '<h1>Try Emby Premiere<paper-icon-button icon="close" onclick="jQuery(this.parentNode.parentNode).remove();" style="margin-left:1em;"></paper-icon-button></h1>';
html += '<p>Design beautiful Cover Art, enjoy free access to Emby apps, and more. <a href="https://emby.media/premiere" target="_blank">Learn more</a></p>';
var learnMoreText = AppInfo.isNativeApp ? '' : '<a href="https://emby.media/premiere" target="_blank">Learn more</a>';
html += '<p>Design beautiful Cover Art, enjoy free access to Emby apps, and more. ' + learnMoreText + '</p>';
html += '<div class="itemsContainer">'; html += '<div class="itemsContainer">';
html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater1.png', 'https://emby.media/premiere'); html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater1.png', 'https://emby.media/premiere');
html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater2.png', 'https://emby.media/premiere'); html += getCard('https://raw.githubusercontent.com/MediaBrowser/Emby.Resources/master/apps/theater2.png', 'https://emby.media/premiere');

View file

@ -1,4 +1,4 @@
define(['jQuery'], function ($) { define(['datetime', 'jQuery'], function (datetime, $) {
function revoke(page, key) { function revoke(page, key) {
@ -59,9 +59,9 @@
html += '<td style="vertical-align:middle;">'; html += '<td style="vertical-align:middle;">';
var date = parseISO8601Date(item.DateCreated, { toLocal: true }); var date = datetime.parseISO8601Date(item.DateCreated, true);
html += date.toLocaleDateString() + ' ' + LibraryBrowser.getDisplayTime(date); html += datetime.toLocaleDateString(date) + ' ' + datetime.getDisplayTime(date);
html += '</td>'; html += '</td>';

View file

@ -1101,44 +1101,6 @@ var Dashboard = {
} }
}, },
getDisplayTime: function (ticks) {
var ticksPerHour = 36000000000;
var ticksPerMinute = 600000000;
var ticksPerSecond = 10000000;
var parts = [];
var hours = ticks / ticksPerHour;
hours = Math.floor(hours);
if (hours) {
parts.push(hours);
}
ticks -= (hours * ticksPerHour);
var minutes = ticks / ticksPerMinute;
minutes = Math.floor(minutes);
ticks -= (minutes * ticksPerMinute);
if (minutes < 10 && hours) {
minutes = '0' + minutes;
}
parts.push(minutes);
var seconds = ticks / ticksPerSecond;
seconds = Math.floor(seconds);
if (seconds < 10) {
seconds = '0' + seconds;
}
parts.push(seconds);
return parts.join(':');
},
getSupportedRemoteCommands: function () { getSupportedRemoteCommands: function () {
// Full list // Full list
@ -1249,6 +1211,209 @@ var Dashboard = {
exit: function () { exit: function () {
Dashboard.logout(); Dashboard.logout();
},
getDeviceProfile: function (maxHeight) {
return new Promise(function (resolve, reject) {
function updateDeviceProfileForAndroid(profile) {
// Just here as an easy escape out, if ever needed
var enableVlcVideo = true;
var enableVlcAudio = window.VlcAudio;
if (enableVlcVideo) {
profile.DirectPlayProfiles.push({
Container: "m4v,3gp,ts,mpegts,mov,xvid,vob,mkv,wmv,asf,ogm,ogv,m2v,avi,mpg,mpeg,mp4,webm",
Type: 'Video',
AudioCodec: 'aac,aac_latm,mp3,ac3,wma,dca,pcm,PCM_S16LE,PCM_S24LE,opus,flac'
});
profile.CodecProfiles = profile.CodecProfiles.filter(function (i) {
return i.Type == 'Audio';
});
profile.SubtitleProfiles = [];
profile.SubtitleProfiles.push({
Format: 'srt',
Method: 'External'
});
profile.SubtitleProfiles.push({
Format: 'srt',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'subrip',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'ass',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'ssa',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'pgs',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'pgssub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'dvdsub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'vtt',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'sub',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'idx',
Method: 'Embed'
});
profile.SubtitleProfiles.push({
Format: 'smi',
Method: 'Embed'
});
// These don't play very well
profile.CodecProfiles.push({
Type: 'VideoAudio',
Codec: 'dca',
Conditions: [
{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: 6
}
]
});
profile.CodecProfiles.push({
Type: 'VideoAudio',
Codec: 'aac,mp3',
Conditions: [
{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: '6'
}
]
});
profile.CodecProfiles.push({
Type: 'Video',
Codec: 'h264',
Conditions: [
{
Condition: 'EqualsAny',
Property: 'VideoProfile',
Value: 'high|main|baseline|constrained baseline'
},
{
Condition: 'LessThanEqual',
Property: 'VideoLevel',
Value: '41'
}]
});
profile.TranscodingProfiles.filter(function (p) {
return p.Type == 'Video' && p.CopyTimestamps == true;
}).forEach(function (p) {
// Vlc doesn't seem to handle this well
p.CopyTimestamps = false;
});
profile.TranscodingProfiles.filter(function (p) {
return p.Type == 'Video' && p.VideoCodec == 'h264';
}).forEach(function (p) {
p.AudioCodec += ',ac3';
});
}
if (enableVlcAudio) {
profile.DirectPlayProfiles.push({
Container: "aac,mp3,mpa,wav,wma,mp2,ogg,oga,webma,ape,opus",
Type: 'Audio'
});
profile.CodecProfiles = profile.CodecProfiles.filter(function (i) {
return i.Type != 'Audio';
});
profile.CodecProfiles.push({
Type: 'Audio',
Conditions: [{
Condition: 'LessThanEqual',
Property: 'AudioChannels',
Value: '2'
}]
});
}
}
require(['browserdeviceprofile', 'qualityoptions', 'appSettings'], function (profileBuilder, qualityoptions, appSettings) {
var supportsCustomSeeking = false;
if (!browserInfo.mobile) {
supportsCustomSeeking = true;
} else if (AppInfo.isNativeApp && browserInfo.safari) {
if (navigator.userAgent.toLowerCase().indexOf('ipad') == -1) {
// Need to disable it in order to support picture in picture
supportsCustomSeeking = true;
}
} else if (AppInfo.isNativeApp) {
supportsCustomSeeking = true;
}
var profile = profileBuilder({
supportsCustomSeeking: supportsCustomSeeking
});
if (!(AppInfo.isNativeApp && browserInfo.android)) {
profile.SubtitleProfiles.push({
Format: 'ass',
Method: 'External'
});
profile.SubtitleProfiles.push({
Format: 'ssa',
Method: 'External'
});
}
var bitrateSetting = appSettings.maxStreamingBitrate();
if (!maxHeight) {
maxHeight = qualityoptions.getVideoQualityOptions(bitrateSetting).filter(function (q) {
return q.selected;
})[0].maxHeight;
}
if (AppInfo.isNativeApp && browserInfo.android) {
updateDeviceProfileForAndroid(profile);
}
profile.MaxStreamingBitrate = bitrateSetting;
resolve(profile);
});
});
} }
}; };
@ -1377,9 +1542,7 @@ var AppInfo = {};
function getSyncProfile() { function getSyncProfile() {
return getRequirePromise(['scripts/mediaplayer']).then(function () { return Dashboard.getDeviceProfile(Math.max(screen.height, screen.width));
return MediaPlayer.getDeviceProfile(Math.max(screen.height, screen.width));
});
} }
function onApiClientCreated(e, newApiClient) { function onApiClientCreated(e, newApiClient) {
@ -1730,6 +1893,7 @@ var AppInfo = {};
define("paper-dialog-scrollable", ["html!" + bowerPath + "/paper-dialog-scrollable/paper-dialog-scrollable.html"]); define("paper-dialog-scrollable", ["html!" + bowerPath + "/paper-dialog-scrollable/paper-dialog-scrollable.html"]);
define("paper-button", ["html!" + bowerPath + "/paper-button/paper-button.html"]); define("paper-button", ["html!" + bowerPath + "/paper-button/paper-button.html"]);
define("paper-icon-button", ["html!" + bowerPath + "/paper-icon-button/paper-icon-button.html"]); define("paper-icon-button", ["html!" + bowerPath + "/paper-icon-button/paper-icon-button.html"]);
define("paper-icon-button-light", ["html!" + bowerPath + "/paper-icon-button/paper-icon-button-light.html"]);
define("paper-drawer-panel", ["html!" + bowerPath + "/paper-drawer-panel/paper-drawer-panel.html"]); define("paper-drawer-panel", ["html!" + bowerPath + "/paper-drawer-panel/paper-drawer-panel.html"]);
define("paper-radio-group", ["html!" + bowerPath + "/paper-radio-group/paper-radio-group.html"]); define("paper-radio-group", ["html!" + bowerPath + "/paper-radio-group/paper-radio-group.html"]);
define("paper-radio-button", ["html!" + bowerPath + "/paper-radio-button/paper-radio-button.html"]); define("paper-radio-button", ["html!" + bowerPath + "/paper-radio-button/paper-radio-button.html"]);

View file

@ -1,11 +1,11 @@
define(['jQuery', 'paper-progress', 'paper-fab', 'paper-item-body', 'paper-icon-item', 'paper-icon-button', 'paper-button'], function ($) { define(['jQuery', 'datetime', 'paper-progress', 'paper-fab', 'paper-item-body', 'paper-icon-item', 'paper-icon-button', 'paper-button'], function ($, datetime) {
function renderJob(page, job, dialogOptions) { function renderJob(page, job, dialogOptions) {
var html = ''; var html = '';
html += '<div>'; html += '<div>';
html += Globalize.translate('ValueDateCreated', parseISO8601Date(job.DateCreated, { toLocal: true }).toLocaleString()); html += Globalize.translate('ValueDateCreated', datetime.parseISO8601Date(job.DateCreated, true).toLocaleString());
html += '</div>'; html += '</div>';
html += '<br/>'; html += '<br/>';
html += '<div class="formFields"></div>'; html += '<div class="formFields"></div>';

View file

@ -183,7 +183,7 @@
function updateFilterControls(tabContent) { function updateFilterControls(tabContent) {
var query = getQuery(tabContent); var query = getQuery(tabContent);
$('.alphabetPicker', tabContent).alphaValue(query.NameStartsWith); $('.alphabetPicker', tabContent).alphaValue(query.NameStartsWithOrGreater);
} }
function initPage(tabContent) { function initPage(tabContent) {

View file

@ -1,4 +1,4 @@
define(['scrollStyles'], function () { define(['datetime', 'scrollStyles'], function (datetime) {
function loadUpcoming(context, params) { function loadUpcoming(context, params) {
@ -62,7 +62,7 @@
if (item.PremiereDate) { if (item.PremiereDate) {
try { try {
var premiereDate = parseISO8601Date(item.PremiereDate, { toLocal: true }); var premiereDate = datetime.parseISO8601Date(item.PremiereDate, true);
if (premiereDate.getDate() == new Date().getDate() - 1) { if (premiereDate.getDate() == new Date().getDate() - 1) {
dateText = Globalize.translate('Yesterday'); dateText = Globalize.translate('Yesterday');

View file

@ -347,8 +347,10 @@
"LabelCustomPaths": "Specify custom paths where desired. Leave fields empty to use the defaults.", "LabelCustomPaths": "Specify custom paths where desired. Leave fields empty to use the defaults.",
"LabelCachePath": "Cache path:", "LabelCachePath": "Cache path:",
"LabelCachePathHelp": "Specify a custom location for server cache files, such as images. Leave blank to use the server default.", "LabelCachePathHelp": "Specify a custom location for server cache files, such as images. Leave blank to use the server default.",
"LabelRecordingPath": "Recording path:", "LabelRecordingPath": "Default recording path:",
"LabelRecordingPathHelp": "Specify a custom location to save recordings. Leave blank to use the server default.", "LabelMovieRecordingPath": "Movie recording path (optional):",
"LabelSeriesRecordingPath": "Series recording path (optional):",
"LabelRecordingPathHelp": "Specify the default location to save recordings. If left empty, the server's program data folder will be used.",
"LabelImagesByNamePath": "Images by name path:", "LabelImagesByNamePath": "Images by name path:",
"LabelImagesByNamePathHelp": "Specify a custom location for downloaded actor, genre and studio images.", "LabelImagesByNamePathHelp": "Specify a custom location for downloaded actor, genre and studio images.",
"LabelMetadataPath": "Metadata path:", "LabelMetadataPath": "Metadata path:",
@ -1486,14 +1488,11 @@
"MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.", "MessageActiveSubscriptionRequiredSeriesRecordings": "An active Emby Premiere subscription is required in order to create automated series recordings.",
"HeaderSetupTVGuide": "Setup TV Guide", "HeaderSetupTVGuide": "Setup TV Guide",
"LabelDataProvider": "Data provider:", "LabelDataProvider": "Data provider:",
"OptionSendRecordingsToAutoOrganize": "Enable Auto-Organize for new recordings", "OptionSendRecordingsToAutoOrganize": "Automatically organize recordings into existing series folders in other libraries",
"OptionSendRecordingsToAutoOrganizeHelp": "New recordings will be sent to the Auto-Organize feature and imported into your media library.",
"HeaderDefaultPadding": "Default Padding", "HeaderDefaultPadding": "Default Padding",
"OptionEnableRecordingSubfolders": "Create sub-folders for categories such as Sports, Kids, etc.",
"HeaderSubtitles": "Subtitles", "HeaderSubtitles": "Subtitles",
"HeaderVideos": "Videos", "HeaderVideos": "Videos",
"OptionEnableVideoFrameAnalysis": "Enable frame by frame video analysis",
"OptionEnableVideoFrameAnalysisHelp": "Extract detailed information about videos that can be used to make transcoding as efficient as possible. This will cause library scans to take longer.",
"LabelVideoFrameAnalysisLimit": "Limit frame by frame analysis to videos less than:",
"LabelHardwareAccelerationType": "Hardware acceleration:", "LabelHardwareAccelerationType": "Hardware acceleration:",
"LabelHardwareAccelerationTypeHelp": "Available on supported systems only.", "LabelHardwareAccelerationTypeHelp": "Available on supported systems only.",
"ButtonServerDashboard": "Server Dashboard", "ButtonServerDashboard": "Server Dashboard",