1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

update notifications

This commit is contained in:
Luke Pulverenti 2016-07-28 01:19:24 -04:00
parent d10ba94be9
commit e9151896b2
27 changed files with 710 additions and 667 deletions

View file

@ -14,12 +14,12 @@
}, },
"devDependencies": {}, "devDependencies": {},
"ignore": [], "ignore": [],
"version": "1.4.123", "version": "1.4.124",
"_release": "1.4.123", "_release": "1.4.124",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "1.4.123", "tag": "1.4.124",
"commit": "9939e23191c1f45c2ea59e41a4e55c22c2839bb7" "commit": "308546fe094fa18c356480d1d13c8790d43de971"
}, },
"_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

@ -53,12 +53,18 @@ define(['browser'], function (browser) {
if (browser.tizen) { if (browser.tizen) {
return true; return true;
} }
if (isEdgeUniversal()) {
return true;
}
} }
else if (format == 'wma') { else if (format == 'wma') {
if (browser.tizen) { if (browser.tizen) {
return true; return true;
} }
if (isEdgeUniversal()) {
return true;
}
} }
else if (format == 'opus') { else if (format == 'opus') {
@ -84,13 +90,31 @@ define(['browser'], function (browser) {
return false; return false;
} }
function testCanPlayMkv() { function isEdgeUniversal() {
if (browser.edge) {
var userAgent = navigator.userAgent.toLowerCase();
if (userAgent.indexOf('msapphost') != -1) {
return true;
}
}
return false;
}
function testCanPlayMkv(videoTestElement) {
if (videoTestElement.canPlayType('video/x-matroska') ||
videoTestElement.canPlayType('video/mkv')) {
return true;
}
var userAgent = navigator.userAgent.toLowerCase();
// Unfortunately there's no real way to detect mkv support // Unfortunately there's no real way to detect mkv support
if (browser.chrome) { if (browser.chrome) {
var userAgent = navigator.userAgent.toLowerCase();
// Not supported on opera tv // Not supported on opera tv
if (browser.operaTv) { if (browser.operaTv) {
return false; return false;
@ -108,6 +132,11 @@ define(['browser'], function (browser) {
return true; return true;
} }
if (isEdgeUniversal()) {
return true;
}
return false; return false;
} }
@ -122,9 +151,11 @@ define(['browser'], function (browser) {
switch (container) { switch (container) {
case 'asf':
supported = browser.tizen || isEdgeUniversal();
break;
case '3gp': case '3gp':
case 'avi': case 'avi':
case 'asf':
case 'flv': case 'flv':
case 'mpg': case 'mpg':
case 'mpeg': case 'mpeg':
@ -135,9 +166,11 @@ define(['browser'], function (browser) {
supported = browser.tizen; supported = browser.tizen;
break; break;
case 'm2ts': case 'm2ts':
case 'wmv':
supported = browser.tizen || browser.web0s; supported = browser.tizen || browser.web0s;
break; break;
case 'wmv':
supported = browser.tizen || browser.web0s || isEdgeUniversal();
break;
case 'ts': case 'ts':
supported = browser.tizen || browser.web0s; supported = browser.tizen || browser.web0s;
if (supported) { if (supported) {
@ -199,7 +232,7 @@ define(['browser'], function (browser) {
var canPlayWebm = videoTestElement.canPlayType('video/webm').replace(/no/, ''); var canPlayWebm = videoTestElement.canPlayType('video/webm').replace(/no/, '');
var canPlayMkv = testCanPlayMkv(); var canPlayMkv = testCanPlayMkv(videoTestElement);
var canPlayTs = testCanPlayTs(); var canPlayTs = testCanPlayTs();
var profile = {}; var profile = {};
@ -218,7 +251,7 @@ define(['browser'], function (browser) {
// Only put mp3 first if mkv support is there // Only put mp3 first if mkv support is there
// Otherwise with HLS and mp3 audio we're seeing some browsers // Otherwise with HLS and mp3 audio we're seeing some browsers
if (videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/, '')) { if (videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/, '') || isEdgeUniversal()) {
// safari is lying // safari is lying
if (!browser.safari) { if (!browser.safari) {
videoAudioCodecs.push('ac3'); videoAudioCodecs.push('ac3');
@ -266,7 +299,7 @@ define(['browser'], function (browser) {
} }
// These are formats we can't test for but some devices will support // These are formats we can't test for but some devices will support
['m2ts', 'wmv', 'ts'].map(getDirectPlayProfileForVideoContainer).filter(function (i) { ['m2ts', 'wmv', 'ts', 'asf'].map(getDirectPlayProfileForVideoContainer).filter(function (i) {
return i != null; return i != null;
}).forEach(function (i) { }).forEach(function (i) {

View file

@ -1,117 +0,0 @@
define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focusManager', 'embyRouter'], function (connectionManager, playbackManager, events, inputManager, focusManager, embyRouter) {
function onOneDocumentClick() {
document.removeEventListener('click', onOneDocumentClick);
document.removeEventListener('keydown', onOneDocumentClick);
if (window.Notification) {
Notification.requestPermission();
}
}
document.addEventListener('click', onOneDocumentClick);
document.addEventListener('keydown', onOneDocumentClick);
function onLibraryChanged(data, apiClient) {
var newItems = data.ItemsAdded;
if (!newItems.length || /*AppInfo.isNativeApp ||*/ !window.Notification || Notification.permission !== "granted") {
return;
}
if (playbackManager.isPlayingVideo()) {
return;
}
apiClient.getItems(apiClient.getCurrentUserId(), {
Recursive: true,
Limit: 3,
IsFolder: false,
SortBy: "DateCreated",
SortOrder: "Descending",
ImageTypes: "Primary",
Ids: newItems.join(',')
}).then(function (result) {
var items = result.Items;
for (var i = 0, length = items.length ; i < length; i++) {
var item = items[i];
var notification = {
title: "New " + item.Type,
body: item.Name,
timeout: 15000,
vibrate: true,
data: {
//options: {
// url: LibraryBrowser.getHref(item)
//}
}
};
var imageTags = item.ImageTags || {};
if (imageTags.Primary) {
notification.icon = apiClient.getScaledImageUrl(item.Id, {
width: 80,
tag: imageTags.Primary,
type: "Primary"
});
}
var notif = new Notification(notification.title, notification);
if (notif.show) {
notif.show();
}
if (notification.timeout) {
setTimeout(function () {
if (notif.close) {
notif.close();
}
else if (notif.cancel) {
notif.cancel();
}
}, notification.timeout);
}
}
});
}
function onWebSocketMessageReceived(e, msg) {
var apiClient = this;
if (msg.MessageType === "LibraryChanged") {
var cmd = msg.Data;
onLibraryChanged(cmd, apiClient);
}
}
function bindEvents(apiClient) {
if (!apiClient) {
return;
}
events.off(apiClient, "websocketmessage", onWebSocketMessageReceived);
events.on(apiClient, "websocketmessage", onWebSocketMessageReceived);
}
bindEvents(connectionManager.currentApiClient());
events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {
bindEvents(newApiClient);
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,182 @@
define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'require'], function (serverNotifications, playbackManager, events, globalize, require) {
function onOneDocumentClick() {
document.removeEventListener('click', onOneDocumentClick);
document.removeEventListener('keydown', onOneDocumentClick);
if (window.Notification) {
Notification.requestPermission();
}
}
document.addEventListener('click', onOneDocumentClick);
document.addEventListener('keydown', onOneDocumentClick);
function closeAfter(notification, timeoutMs) {
setTimeout(function () {
if (notification.close) {
notification.close();
}
else if (notification.cancel) {
notification.cancel();
}
}, timeoutMs);
}
function show(title, options, timeoutMs) {
try {
var notif = new Notification(title, options);
if (notif.show) {
notif.show();
}
if (timeoutMs) {
closeAfter(notif, timeoutMs);
}
} catch (err) {
if (options.actions) {
options.actions = [];
show(title, options, timeoutMs);
} else {
throw err;
}
}
}
function showNewItemNotification(item, apiClient) {
var notification = {
title: "New " + item.Type,
body: item.Name,
vibrate: true,
tag: "newItem" + item.Id,
data: {
//options: {
// url: LibraryBrowser.getHref(item)
//}
}
};
var imageTags = item.ImageTags || {};
if (imageTags.Primary) {
notification.icon = apiClient.getScaledImageUrl(item.Id, {
width: 80,
tag: imageTags.Primary,
type: "Primary"
});
}
show(notification.title, notification, 15000);
}
function onLibraryChanged(data, apiClient) {
var newItems = data.ItemsAdded;
if (!newItems.length || !window.Notification || Notification.permission !== "granted") {
return;
}
if (playbackManager.isPlayingVideo()) {
return;
}
apiClient.getItems(apiClient.getCurrentUserId(), {
Recursive: true,
Limit: 3,
IsFolder: false,
SortBy: "DateCreated",
SortOrder: "Descending",
ImageTypes: "Primary",
Ids: newItems.join(',')
}).then(function (result) {
var items = result.Items;
for (var i = 0, length = items.length ; i < length; i++) {
showNewItemNotification(items[i], apiClient);
}
});
}
function getIconUrl(name) {
return require.toUrl('.').split('?')[0] + '/' + name;
}
function showPackageInstallNotification(apiClient, installation, status) {
apiClient.getCurrentUser().then(function (user) {
if (!user.Policy.IsAdministrator) {
return;
}
var notification = {
tag: "install" + installation.Id,
data: {},
icon: getIconUrl('/notificationicon.png')
};
if (status == 'completed') {
notification.title = globalize.translate('LabelPackageInstallCompleted').replace('{0}', installation.Name + ' ' + installation.Version);
notification.vibrate = true;
}
else if (status == 'cancelled') {
notification.title = globalize.translate('LabelPackageInstallCancelled').replace('{0}', installation.Name + ' ' + installation.Version);
}
else if (status == 'failed') {
notification.title = globalize.translate('LabelPackageInstallFailed').replace('{0}', installation.Name + ' ' + installation.Version);
notification.vibrate = true;
}
else if (status == 'progress') {
notification.title = globalize.translate('LabelInstallingPackage').replace('{0}', installation.Name + ' ' + installation.Version);
notification.actions =
[
{ action: 'cancel', title: globalize.translate('ButtonCancel')/*, icon: 'https://example/like.png'*/ }
];
}
if (status == 'progress') {
var percentComplete = Math.round(installation.PercentComplete || 0);
notification.body = percentComplete + '% complete.';
}
var timeout = status == 'cancelled' ? 5000 : 0;
show(notification.title, notification, timeout);
});
}
events.on(serverNotifications, 'LibraryChanged', function (e, apiClient, data) {
onLibraryChanged(data, apiClient);
});
events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) {
showPackageInstallNotification(apiClient, data, "completed");
});
events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) {
showPackageInstallNotification(apiClient, data, "failed");
});
events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) {
showPackageInstallNotification(apiClient, data, "cancelled");
});
events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) {
showPackageInstallNotification(apiClient, data, "progress");
});
});

View file

@ -6,18 +6,7 @@ define(['connectionManager', 'events'], function (connectionManager, events) {
var apiClient = this; var apiClient = this;
if (msg.MessageType === "LibraryChanged") { if (msg.MessageType === "UserDataChanged") {
}
else if (msg.MessageType === "ServerShuttingDown") {
events.trigger(serverNotifications, 'ServerShuttingDown', [apiClient]);
}
else if (msg.MessageType === "ServerRestarting") {
events.trigger(serverNotifications, 'ServerRestarting', [apiClient]);
}
else if (msg.MessageType === "RestartRequired") {
events.trigger(serverNotifications, 'RestartRequired', [apiClient]);
}
else if (msg.MessageType === "UserDataChanged") {
if (msg.Data.UserId == apiClient.getCurrentUserId()) { if (msg.Data.UserId == apiClient.getCurrentUserId()) {
@ -26,7 +15,7 @@ define(['connectionManager', 'events'], function (connectionManager, events) {
} }
} }
} }
else if (msg.MessageType === "TimerCreated" || msg.MessageType === "SeriesTimerCreated" || msg.MessageType === "TimerCancelled" || msg.MessageType === "SeriesTimerCancelled") { else {
events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]); events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]);
} }
@ -38,10 +27,10 @@ define(['connectionManager', 'events'], function (connectionManager, events) {
events.on(apiClient, "websocketmessage", onWebSocketMessageReceived); events.on(apiClient, "websocketmessage", onWebSocketMessageReceived);
} }
//var current = connectionManager.currentApiClient(); var current = connectionManager.currentApiClient();
//if (current) { if (current) {
// bindEvents(current); bindEvents(current);
//} }
events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) { events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) {

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-location", "name": "iron-location",
"version": "0.8.5", "version": "0.8.6",
"description": "Bidirectional data binding into the page's URL.", "description": "Bidirectional data binding into the page's URL.",
"private": true, "private": true,
"authors": [ "authors": [
@ -37,11 +37,11 @@
"webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0", "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0",
"iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.2.3" "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.2.3"
}, },
"_release": "0.8.5", "_release": "0.8.6",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v0.8.5", "tag": "0.8.6",
"commit": "d7c5a9c991bf5e94094c16e94eb34e2eb30db4b0" "commit": "8f628b3477fcba70da47d75e521a8afe8f12e4f7"
}, },
"_source": "git://github.com/PolymerElements/iron-location.git", "_source": "git://github.com/PolymerElements/iron-location.git",
"_target": "^0.8.0", "_target": "^0.8.0",

View file

@ -5,19 +5,19 @@ addons:
firefox: '46.0' firefox: '46.0'
apt: apt:
sources: sources:
- google-chrome - google-chrome
packages: packages:
- google-chrome-stable - google-chrome-stable
sauce_connect: true sauce_connect: true
before_script: before_script:
- npm install -g bower polylint web-component-tester - npm install -g bower polylint web-component-tester
- bower install - bower install
- polylint - polylint
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
env: env:
global: global:
- secure: GQ+cUlta7BWa8Gq4YXrBStPzwRpHT2QG79T4pbDTz2Zs1RvT0GYQaEUksPQnsNCwnTF8ondXhUfMxHcC/r8p7YTCt2hSJSsKkx0lMertsjbKW38ZG28liaAN8msYGb9hnTs4qxhpVEX1pZtOI13RKBU85dw+jKbtxKDX/jVrMn42XCMhEmTeLxM4z8dW5nBu6LW6F3nwABQIUfdc/3OeIYG+2n+84zkXIsX1BFeejq28E6fYJAoMJgqfugLPgPu4IEVCWZJwYl2SgdXwxAcJ2auPph5GJ3DLd0fRRD1TZ94/u0A+eJcQ0OPiPu8hLpQNXOkCgAnO5jkpTCDERNQnB4nY8VfZeZdf1RLAB4VmxzOAbJwJcnqGrh89H6RhKKXyhcuFCgFACYfkzncBCs+co5KwVcwLq88cDOUbnmo3DlwQWpkfusvKy/ZrMrFrX1zycJWN4u8rDsIH4ELasSQh/J3OIa9l2mKfL/OEvqCmpv/ZLGlOVSvNLpr4U7vTVdZBP6C9rtwVXX7VzrClttiidHfoxztAMrNh2GBMjNH9n3FuWMoA/OSoxQGc7RreTsuzdniw3iJYUHIeG08R9bqRtSVA71AlQrbqUaHR+WM7rf7GUx6xG0uDop5vH0RDkE0Nld1W8XuVhHQUg3y3fd4AHJAQVmM7Zsfa3AY1gSr3hV0= - secure: LSHof0ip5tJswHk4wAIXXsf8Z0WL44Y1pB1XmqFtIsjQLl+2K5bdhRq6Hd6RUZYcpTL29cMStCLQJEG1hxnMks37omHuVFWRtk0NaYlGnJY4i/m/ukUBmM7Yr7LROWRnBgU75PVUvc4YMbCjvlQ9KKjdgBbQBFH2KjhKr9GUN+ihB1yaKRMADvFtC6JWisG4RPv1pRxF6UgvGkOsaCdVb9H9AbKA0psAI1cpg8IMGgUBslbwhYw+viMEQdZ5lW++T3Tb9cwzCVaTqBgvkQCXW4I6T4En9yvUWbV0Ry8uChchvs6BJfwpgN/nksYnLCbCLmN+Rw5eU0+XyWZDLiki/HpsNQblqVEW7vHo1hmtpK24GUv2g8kuE1OjjW7K/l+Q20D8FJFIcPdFjmZ/XgLWxdtXbgNC8n4Z1XBEqKuV1BJ29ojvZk5a5/gFBf9PWdMNTVwSepk7+LoEVQW17vzSHT/HDF7WYEs14uZ0x9I0AV2+339RG7iCcVFMZKYgIif0DmZVysnm0Z9j+wRRk227JpiF9MHeVkFUaXl3+3XIQMz04t+H1wOXiDRlJLJG9IUrzFs+KYuCA+OxNc0XrxjA6Zkl75AQAjAY5vMEWYD+N2OGjkfwD7dB4JtltmZ4llMhEZUt/RPLeZJvL4Sus8hfA6SNG9/tdVgef0mQ91acxZg=
- secure: He0JAbtg9jFzuEBRHQdFWHJ33uueY/9Hxq4NB5PCAI1Z9ebIiTs73ofdNy6e+ftBqlQnBuhoKLfIpuD8Qj2kSdLHQvg1s6ojvNDmAvau1ZINCJRgOSKbGC0TvCVx9rT9Kqc83eqKvKDzr/rcpaIArgMYJzBrSG0D2Kn4luUQnWkKfo1knn17ytJFCvzqQvPWZTIZ6beJ7MRKXRU093a4wYMsKIxQHH65T4Ypj+RBsgv6Xnidjb8qZbNsEwaeOwExfsh30WUo/hSygRi2CP3KSRSc/vsMgSrGpFghZpnhjeDJAGTiDzCTxpJkAkHXereJT4agsWErcgSrRTaxi5G6f18o56pRS+I61BC5DuGGwSL7hOHWSC8pGzkwVFyz31MB2ll0HO3iQHMmcSjY37+G7toEP/vJ/UHm6SZoQq36HGJea7Ycv/2mk4HAHcVEDxhYG42bXXflxevFeqAkVUI7SxSaQpQuZF76/4th4uKFmAHPvRVj5yx8OWil9Lt6cG8DIEZaxXdJVueGgiODmmul7lAd5osO/1UCg4CTy1OnmuSJj7ax9LBa6YY2+3uvnBfE7fNUVKmVmVhlLsF0QAdj0LaFoSU0eQFWdReYqBxEvc4gOT3AtEpaAvfZnL11Q6wVyI7kCHhTHrltA4WENPOSA2u7W//WsQfHX3gRdpIVIVI= - secure: h0j4eT4lJqbDkEVz4OjkPuAHxxT0Cy7bWbT71oDllhDAvl9zXxIn5BHSnCaUfO0xUhXVpwNuVmDzOE6yQETJ3MamoqL2Hrbg0VCr4hux9/2ipa4tlCTjQ2Y/YaIoID7CpCchdoOQAjrxeg0ZhpMnwxV18NHTqlxNrsdoSDDSmCdffWQwgjVI07O4h1ISIWx6oY0i1Z+9nJI001iZIw5vGopK8zACa5hfSu9my8Nog5gYOBOEoYmT8lNBaKkNuZacGAkHmXPmeeWiflM49sRO5MfyCgVvNtn6yohXs5D1QD2KUZs4mTzVBebT3vPuV7I9NFd+ZY9GT9YeH9BLuxKpYhGlnjL2HhGAvGjIcKX8315EOCpVvgwX3VE1f9PJe3K9q6LP/sFUqf8cUrbj9FhiAVp79IPJkvLUc+1hUG3iQ8X83mjQxcrCt6I50BINOLgjsfzCmnvv12g3FuRry2EBRxEultvPLRCNc2bJCPqol6kiWzs8ySOPXCYOcXqW5/6Z4DYLMTYevapkJZhErcTBuIH7rXEX4tGsdBjtGjTepcW7k2dsCElrul79czZA3AwdLEK/fuygxXR8eMCeS8Tdh4+Ba4M9TfXtAjjnR30NayTOCwyWW9IvTJeWeXKd6SilJcGVO7r546ayGWJ2G+Fltyi7RGixMplRMm8y6YfeM9k=
dist: trusty dist: trusty

View file

@ -1,6 +1,6 @@
{ {
"name": "iron-location", "name": "iron-location",
"version": "0.8.5", "version": "0.8.6",
"description": "Bidirectional data binding into the page's URL.", "description": "Bidirectional data binding into the page's URL.",
"private": true, "private": true,
"authors": [ "authors": [

View file

@ -50,281 +50,287 @@ milliseconds.
--> -->
<script> <script>
'use strict'; (function() {
'use strict';
Polymer({ Polymer({
is: 'iron-location', is: 'iron-location',
properties: { properties: {
/** /**
* The pathname component of the URL. * The pathname component of the URL.
*/ */
path: { path: {
type: String, type: String,
notify: true, notify: true,
value: function() { value: function() {
return window.location.pathname; return window.decodeURIComponent(window.location.pathname);
}
},
/**
* The query string portion of the URL.
*/
query: {
type: String,
notify: true,
value: function() {
return window.decodeURIComponent(window.location.search.slice(1));
}
},
/**
* The hash component of the URL.
*/
hash: {
type: String,
notify: true,
value: function() {
return window.decodeURIComponent(window.location.hash.slice(1));
}
},
/**
* If the user was on a URL for less than `dwellTime` milliseconds, it
* won't be added to the browser's history, but instead will be replaced
* by the next entry.
*
* This is to prevent large numbers of entries from clogging up the user's
* browser history. Disable by setting to a negative number.
*/
dwellTime: {
type: Number,
value: 2000
},
/**
* A regexp that defines the set of URLs that should be considered part
* of this web app.
*
* Clicking on a link that matches this regex won't result in a full page
* navigation, but will instead just update the URL state in place.
*
* This regexp is given everything after the origin in an absolute
* URL. So to match just URLs that start with /search/ do:
* url-space-regex="^/search/"
*
* @type {string|RegExp}
*/
urlSpaceRegex: {
type: String,
value: ''
},
/**
* urlSpaceRegex, but coerced into a regexp.
*
* @type {RegExp}
*/
_urlSpaceRegExp: {
computed: '_makeRegExp(urlSpaceRegex)'
},
_lastChangedAt: {
type: Number
},
_initialized: {
type: Boolean,
value: false
} }
}, },
/** hostAttributes: {
* The query string portion of the URL. hidden: true
*/ },
query: { observers: [
type: String, '_updateUrl(path, query, hash)'
notify: true, ],
value: function() { attached: function() {
return window.location.search.slice(1); this.listen(window, 'hashchange', '_hashChanged');
this.listen(window, 'location-changed', '_urlChanged');
this.listen(window, 'popstate', '_urlChanged');
this.listen(/** @type {!HTMLBodyElement} */(document.body), 'click', '_globalOnClick');
// Give a 200ms grace period to make initial redirects without any
// additions to the user's history.
this._lastChangedAt = window.performance.now() - (this.dwellTime - 200);
this._initialized = true;
this._urlChanged();
},
detached: function() {
this.unlisten(window, 'hashchange', '_hashChanged');
this.unlisten(window, 'location-changed', '_urlChanged');
this.unlisten(window, 'popstate', '_urlChanged');
this.unlisten(/** @type {!HTMLBodyElement} */(document.body), 'click', '_globalOnClick');
this._initialized = false;
},
_hashChanged: function() {
this.hash = window.decodeURIComponent(window.location.hash.substring(1));
},
_urlChanged: function() {
// We want to extract all info out of the updated URL before we
// try to write anything back into it.
//
// i.e. without _dontUpdateUrl we'd overwrite the new path with the old
// one when we set this.hash. Likewise for query.
this._dontUpdateUrl = true;
this._hashChanged();
this.path = window.decodeURIComponent(window.location.pathname);
this.query = window.decodeURIComponent(
window.location.search.substring(1));
this._dontUpdateUrl = false;
this._updateUrl();
},
_getUrl: function() {
var partiallyEncodedPath = window.encodeURI(
this.path).replace(/\#/g, '%23').replace(/\?/g, '%3F');
var partiallyEncodedQuery = '';
if (this.query) {
partiallyEncodedQuery = '?' + window.encodeURI(
this.query).replace(/\#/g, '%23');
} }
}, var partiallyEncodedHash = '';
/** if (this.hash) {
* The hash component of the URL. partiallyEncodedHash = '#' + window.encodeURI(this.hash);
*/
hash: {
type: String,
notify: true,
value: function() {
return window.location.hash.slice(1);
} }
return (
partiallyEncodedPath + partiallyEncodedQuery + partiallyEncodedHash);
}, },
/** _updateUrl: function() {
* If the user was on a URL for less than `dwellTime` milliseconds, it if (this._dontUpdateUrl || !this._initialized) {
* won't be added to the browser's history, but instead will be replaced return;
* by the next entry.
*
* This is to prevent large numbers of entries from clogging up the user's
* browser history. Disable by setting to a negative number.
*/
dwellTime: {
type: Number,
value: 2000
},
/**
* A regexp that defines the set of URLs that should be considered part
* of this web app.
*
* Clicking on a link that matches this regex won't result in a full page
* navigation, but will instead just update the URL state in place.
*
* This regexp is given everything after the origin in an absolute
* URL. So to match just URLs that start with /search/ do:
* url-space-regex="^/search/"
*
* @type {string|RegExp}
*/
urlSpaceRegex: {
type: String,
value: ''
},
/**
* urlSpaceRegex, but coerced into a regexp.
*
* @type {RegExp}
*/
_urlSpaceRegExp: {
computed: '_makeRegExp(urlSpaceRegex)'
},
_lastChangedAt: {
type: Number
},
_initialized: {
type: Boolean,
value: false
}
},
hostAttributes: {
hidden: true
},
observers: [
'_updateUrl(path, query, hash)'
],
attached: function() {
this.listen(window, 'hashchange', '_hashChanged');
this.listen(window, 'location-changed', '_urlChanged');
this.listen(window, 'popstate', '_urlChanged');
this.listen(/** @type {!HTMLBodyElement} */(document.body), 'click', '_globalOnClick');
// Give a 200ms grace period to make initial redirects without any
// additions to the user's history.
this._lastChangedAt = window.performance.now() - (this.dwellTime - 200);
this._initialized = true;
this._urlChanged();
},
detached: function() {
this.unlisten(window, 'hashchange', '_hashChanged');
this.unlisten(window, 'location-changed', '_urlChanged');
this.unlisten(window, 'popstate', '_urlChanged');
this.unlisten(/** @type {!HTMLBodyElement} */(document.body), 'click', '_globalOnClick');
this._initialized = false;
},
_hashChanged: function() {
this.hash = window.location.hash.substring(1);
},
_urlChanged: function() {
// We want to extract all info out of the updated URL before we
// try to write anything back into it.
//
// i.e. without _dontUpdateUrl we'd overwrite the new path with the old
// one when we set this.hash. Likewise for query.
this._dontUpdateUrl = true;
this._hashChanged();
this.path = window.location.pathname;
this.query = window.location.search.substring(1);
this._dontUpdateUrl = false;
this._updateUrl();
},
_getUrl: function() {
var url = this.path;
var query = this.query;
if (query) {
url += '?' + query;
}
if (this.hash) {
url += '#' + this.hash;
}
return url;
},
_updateUrl: function() {
if (this._dontUpdateUrl || !this._initialized) {
return;
}
var newUrl = this._getUrl();
var currentUrl = (
window.location.pathname +
window.location.search +
window.location.hash
);
if (newUrl == currentUrl) {
// nothing to do, the URL didn't change
return;
}
// Need to use a full URL in case the containing page has a base URI.
var fullNewUrl = new URL(
newUrl, window.location.protocol + '//' + window.location.host).href;
var now = window.performance.now();
var shouldReplace =
this._lastChangedAt + this.dwellTime > now;
this._lastChangedAt = now;
if (shouldReplace) {
window.history.replaceState({}, '', fullNewUrl);
} else {
window.history.pushState({}, '', fullNewUrl);
}
this.fire('location-changed', {}, {node: window});
},
/**
* A necessary evil so that links work as expected. Does its best to
* bail out early if possible.
*
* @param {MouseEvent} event .
*/
_globalOnClick: function(event) {
// If another event handler has stopped this event then there's nothing
// for us to do. This can happen e.g. when there are multiple
// iron-location elements in a page.
if (event.defaultPrevented) {
return;
}
var href = this._getSameOriginLinkHref(event);
if (!href) {
return;
}
event.preventDefault();
// If the navigation is to the current page we shouldn't add a history
// entry or fire a change event.
if (href === window.location.href) {
return;
}
window.history.pushState({}, '', href);
this.fire('location-changed', {}, {node: window});
},
/**
* Returns the absolute URL of the link (if any) that this click event
* is clicking on, if we can and should override the resulting full
* page navigation. Returns null otherwise.
*
* @param {MouseEvent} event .
* @return {string?} .
*/
_getSameOriginLinkHref: function(event) {
// We only care about left-clicks.
if (event.button !== 0) {
return null;
}
// We don't want modified clicks, where the intent is to open the page
// in a new tab.
if (event.metaKey || event.ctrlKey) {
return null;
}
var eventPath = Polymer.dom(event).path;
var anchor = null;
for (var i = 0; i < eventPath.length; i++) {
var element = eventPath[i];
if (element.tagName === 'A' && element.href) {
anchor = element;
break;
} }
} if (this.path === window.decodeURIComponent(window.location.pathname) &&
this.query === window.decodeURIComponent(
// If there's no link there's nothing to do. window.location.search.substring(1)) &&
if (!anchor) { this.hash === window.decodeURIComponent(
return null; window.location.hash.substring(1))) {
} // Nothing to do, the current URL is a representation of our properties.
return;
// Target blank is a new tab, don't intercept. }
if (anchor.target === '_blank') { var newUrl = this._getUrl();
return null; // Need to use a full URL in case the containing page has a base URI.
} var fullNewUrl = new URL(
// If the link is for an existing parent frame, don't intercept. newUrl, window.location.protocol + '//' + window.location.host).href;
if ((anchor.target === '_top' || var now = window.performance.now();
anchor.target === '_parent') && var shouldReplace =
window.top !== window) { this._lastChangedAt + this.dwellTime > now;
return null; this._lastChangedAt = now;
} if (shouldReplace) {
window.history.replaceState({}, '', fullNewUrl);
var href = anchor.href; } else {
window.history.pushState({}, '', fullNewUrl);
// It only makes sense for us to intercept same-origin navigations. }
// pushState/replaceState don't work with cross-origin links. this.fire('location-changed', {}, {node: window});
var url; },
if (document.baseURI != null) { /**
url = new URL(href, /** @type {string} */(document.baseURI)); * A necessary evil so that links work as expected. Does its best to
} else { * bail out early if possible.
url = new URL(href); *
} * @param {MouseEvent} event .
*/
var origin; _globalOnClick: function(event) {
// If another event handler has stopped this event then there's nothing
// IE Polyfill // for us to do. This can happen e.g. when there are multiple
if (window.location.origin) { // iron-location elements in a page.
origin = window.location.origin; if (event.defaultPrevented) {
} else { return;
origin = window.location.protocol + '//' + window.location.hostname; }
var href = this._getSameOriginLinkHref(event);
if (window.location.port) { if (!href) {
origin += ':' + window.location.port; return;
}
event.preventDefault();
// If the navigation is to the current page we shouldn't add a history
// entry or fire a change event.
if (href === window.location.href) {
return;
}
window.history.pushState({}, '', href);
this.fire('location-changed', {}, {node: window});
},
/**
* Returns the absolute URL of the link (if any) that this click event
* is clicking on, if we can and should override the resulting full
* page navigation. Returns null otherwise.
*
* @param {MouseEvent} event .
* @return {string?} .
*/
_getSameOriginLinkHref: function(event) {
// We only care about left-clicks.
if (event.button !== 0) {
return null;
}
// We don't want modified clicks, where the intent is to open the page
// in a new tab.
if (event.metaKey || event.ctrlKey) {
return null;
}
var eventPath = Polymer.dom(event).path;
var anchor = null;
for (var i = 0; i < eventPath.length; i++) {
var element = eventPath[i];
if (element.tagName === 'A' && element.href) {
anchor = element;
break;
}
} }
}
if (url.origin !== origin) { // If there's no link there's nothing to do.
return null; if (!anchor) {
} return null;
var normalizedHref = url.pathname + url.search + url.hash; }
// If we've been configured not to handle this url... don't handle it! // Target blank is a new tab, don't intercept.
if (this._urlSpaceRegExp && if (anchor.target === '_blank') {
!this._urlSpaceRegExp.test(normalizedHref)) { return null;
return null; }
// If the link is for an existing parent frame, don't intercept.
if ((anchor.target === '_top' ||
anchor.target === '_parent') &&
window.top !== window) {
return null;
}
var href = anchor.href;
// It only makes sense for us to intercept same-origin navigations.
// pushState/replaceState don't work with cross-origin links.
var url;
if (document.baseURI != null) {
url = new URL(href, /** @type {string} */(document.baseURI));
} else {
url = new URL(href);
}
var origin;
// IE Polyfill
if (window.location.origin) {
origin = window.location.origin;
} else {
origin = window.location.protocol + '//' + window.location.hostname;
if (window.location.port) {
origin += ':' + window.location.port;
}
}
if (url.origin !== origin) {
return null;
}
var normalizedHref = url.pathname + url.search + url.hash;
// If we've been configured not to handle this url... don't handle it!
if (this._urlSpaceRegExp &&
!this._urlSpaceRegExp.test(normalizedHref)) {
return null;
}
// Need to use a full URL in case the containing page has a base URI.
var fullNormalizedHref = new URL(
normalizedHref, window.location.href).href;
return fullNormalizedHref;
},
_makeRegExp: function(urlSpaceRegex) {
return RegExp(urlSpaceRegex);
} }
// Need to use a full URL in case the containing page has a base URI. });
var fullNormalizedHref = new URL( })();
normalizedHref, window.location.href).href;
return fullNormalizedHref;
},
_makeRegExp: function(urlSpaceRegex) {
return RegExp(urlSpaceRegex);
}
});
</script> </script>

View file

@ -19,8 +19,30 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
<link rel="import" href="../../promise-polyfill/promise-polyfill.html"> <link rel="import" href="../../promise-polyfill/promise-polyfill.html">
<link rel="import" href="../iron-location.html"> <link rel="import" href="../iron-location.html">
<link rel="import" href="./redirection.html"> <link rel="import" href="./redirection.html">
<style>
#safari-cooldown {
font-size: 18px;
max-width: 300px;
}
#safari-cooldown div {
margin-bottom: 20px;
}
</style>
</head> </head>
<body> <body>
<div id='safari-cooldown' hidden>
<div>Danger: URL overheating.</div>
<div>
Safari requires a cooldown period before we call
pushState/replaceState any more.
</div>
<div>Testing will resume after 30 seconds.</div>
<div>
<a href="https://forums.developer.apple.com/thread/36650">More info</a>
</div>
</div>
<test-fixture id='Solo'> <test-fixture id='Solo'>
<template> <template>
<iron-location></iron-location> <iron-location></iron-location>
@ -78,8 +100,16 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
function ironLocationTests() { function ironLocationTests() {
suite('when used solo', function() { suite('when used solo', function() {
var urlElem; var urlElem;
var toRemove;
setup(function() { setup(function() {
replaceState('/');
urlElem = fixture('Solo'); urlElem = fixture('Solo');
toRemove = [];
});
teardown(function() {
for (var i = 0; i < toRemove.length; i++) {
document.body.removeChild(toRemove[i]);
}
}); });
test('basic functionality with #hash urls', function() { test('basic functionality with #hash urls', function() {
// Initialized to the window location's hash. // Initialized to the window location's hash.
@ -116,6 +146,75 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
window.dispatchEvent(new CustomEvent('location-changed')); window.dispatchEvent(new CustomEvent('location-changed'));
expect(urlElem.path).to.be.equal('/baz'); expect(urlElem.path).to.be.equal('/baz');
}); });
function makeTemporaryIronLocation() {
var ironLocation = document.createElement('iron-location');
document.body.appendChild(ironLocation);
toRemove.push(ironLocation);
return ironLocation
}
test('dealing with paths with unusual characters', function() {
var pathEncodingExamples = {
'/foo': '/foo',
'/': '/',
'/foo bar': '/foo%20bar',
'/foo#bar': '/foo%23bar',
'/foo?xyz': '/foo%3Fxyz',
'/foo\'bar\'baz': '/foo\'bar\'baz',
};
for (var plainTextPath in pathEncodingExamples) {
var encodedPath = pathEncodingExamples[plainTextPath];
urlElem.path = plainTextPath;
expect(window.location.pathname).to.be.equal(encodedPath);
expect(urlElem.path).to.be.equal(plainTextPath);
var temporaryIronLocation = makeTemporaryIronLocation();
expect(temporaryIronLocation.path).to.be.equal(plainTextPath);
}
});
test('dealing with hashes with unusual characters', function() {
var hashEncodingExamples = {
'foo': '#foo',
'': '',
'foo bar': ['#foo%20bar', '#foo bar'],
'foo#bar': '#foo#bar',
'foo?bar': '#foo?bar',
'/foo\'bar\'baz': ['#/foo%27bar%27baz', '#/foo\'bar\'baz'],
};
for (var plainTextHash in hashEncodingExamples) {
var encodedHashes = hashEncodingExamples[plainTextHash];
if (typeof encodedHashes === 'string') {
encodedHashes = [encodedHashes];
}
urlElem.hash = plainTextHash;
expect(encodedHashes).to.contain(window.location.hash);
expect(urlElem.hash).to.be.equal(plainTextHash);
expect(makeTemporaryIronLocation().hash).to.be.equal(plainTextHash);
}
});
test('dealing with queries with unusual characters', function() {
var queryEncodingExamples = {
'foo': '?foo',
'': '',
'foo bar': '?foo%20bar',
'foo#bar': '?foo%23bar',
'foo?bar': '?foo?bar',
'/foo\'bar\'baz': ['?/foo%27bar%27baz', '?/foo\'bar\'baz'],
};
for (var plainTextQuery in queryEncodingExamples) {
var encodedQueries = queryEncodingExamples[plainTextQuery];
if (typeof encodedQueries === 'string') {
encodedQueries = [encodedQueries];
}
expect(urlElem._initialized).to.be.eq(true);
urlElem.query = plainTextQuery;
expect(encodedQueries).to.contain(window.location.search);
expect(urlElem.query).to.be.equal(plainTextQuery);
expect(makeTemporaryIronLocation().query).to.be.equal(plainTextQuery);
}
});
test('assigning to a relative path URL', function() { test('assigning to a relative path URL', function() {
urlElem.path = '/foo/bar'; urlElem.path = '/foo/bar';
expect(window.location.pathname).to.be.equal('/foo/bar'); expect(window.location.pathname).to.be.equal('/foo/bar');
@ -167,80 +266,80 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
ironLocation.path = '/foo'; ironLocation.path = '/foo';
expect(replaceStateCalls).to.be.equal(1); expect(replaceStateCalls).to.be.equal(1);
expect(pushStateCalls).to.be.equal(0); expect(pushStateCalls).to.be.equal(0);
}); });
suite('when intercepting links', function() { suite('when intercepting links', function() {
/** /**
* Clicks the given link while an iron-location element with the given * Clicks the given link while an iron-location element with the given
* urlSpaceRegex is in the same document. Returns whether the * urlSpaceRegex is in the same document. Returns whether the
* iron-location prevented the default behavior of the click. * iron-location prevented the default behavior of the click.
* *
* No matter what, it prevents the default behavior of the click itself * No matter what, it prevents the default behavior of the click itself
* to ensure that no navigation occurs (as that would interrupt * to ensure that no navigation occurs (as that would interrupt
* running and reporting these tests!) * running and reporting these tests!)
*/ */
function isClickCaptured(anchor, urlSpaceRegex) { function isClickCaptured(anchor, urlSpaceRegex) {
var defaultWasPrevented; var defaultWasPrevented;
function handler(event) { function handler(event) {
expect(event.target).to.be.eq(anchor); expect(event.target).to.be.eq(anchor);
defaultWasPrevented = event.defaultPrevented; defaultWasPrevented = event.defaultPrevented;
event.preventDefault(); event.preventDefault();
expect(event.defaultPrevented).to.be.eq(true); expect(event.defaultPrevented).to.be.eq(true);
} }
window.addEventListener('click', handler); window.addEventListener('click', handler);
var ironLocation = fixture('Solo'); var ironLocation = fixture('Solo');
if (urlSpaceRegex != null) { if (urlSpaceRegex != null) {
ironLocation.urlSpaceRegex = urlSpaceRegex; ironLocation.urlSpaceRegex = urlSpaceRegex;
} }
document.body.appendChild(anchor); document.body.appendChild(anchor);
anchor.click(); anchor.click();
document.body.removeChild(anchor); document.body.removeChild(anchor);
window.removeEventListener('click', handler); window.removeEventListener('click', handler);
return defaultWasPrevented; return defaultWasPrevented;
}
test('simple link to / is intercepted', function() {
var anchor = document.createElement('a');
if (document.baseURI !== window.location.href) {
anchor.href = makeAbsoluteUrl('/');
} else {
anchor.href = '/';
} }
test('simple link to / is intercepted', function() { expect(isClickCaptured(anchor)).to.be.eq(true);
var anchor = document.createElement('a');
if (document.baseURI !== window.location.href) {
anchor.href = makeAbsoluteUrl('/');
} else {
anchor.href = '/';
}
expect(isClickCaptured(anchor)).to.be.eq(true);
expect(pushStateCalls).to.be.equal(1); expect(pushStateCalls).to.be.equal(1);
}); });
test('link that matches url space is intercepted', function() { test('link that matches url space is intercepted', function() {
var anchor = document.createElement('a'); var anchor = document.createElement('a');
anchor.href = makeAbsoluteUrl('/foo'); anchor.href = makeAbsoluteUrl('/foo');
expect(isClickCaptured(anchor, '/fo+')).to.be.eq(true); expect(isClickCaptured(anchor, '/fo+')).to.be.eq(true);
expect(pushStateCalls).to.be.equal(1); expect(pushStateCalls).to.be.equal(1);
}); });
test('link that doesn\'t match url space isn\'t intercepted', function() { test('link that doesn\'t match url space isn\'t intercepted', function() {
var anchor = document.createElement('a'); var anchor = document.createElement('a');
anchor.href = makeAbsoluteUrl('/bar'); anchor.href = makeAbsoluteUrl('/bar');
expect(isClickCaptured(anchor, '/fo+')).to.be.eq(false); expect(isClickCaptured(anchor, '/fo+')).to.be.eq(false);
expect(pushStateCalls).to.be.equal(0); expect(pushStateCalls).to.be.equal(0);
}); });
test('link to another domain isn\'t intercepted', function() { test('link to another domain isn\'t intercepted', function() {
var anchor = document.createElement('a'); var anchor = document.createElement('a');
anchor.href = 'http://example.com/'; anchor.href = 'http://example.com/';
expect(isClickCaptured(anchor)).to.be.eq(false); expect(isClickCaptured(anchor)).to.be.eq(false);
expect(pushStateCalls).to.be.equal(0); expect(pushStateCalls).to.be.equal(0);
}); });
test('a link with target=_blank isn\'t intercepted', function() { test('a link with target=_blank isn\'t intercepted', function() {
var anchor = document.createElement('a'); var anchor = document.createElement('a');
anchor.href = makeAbsoluteUrl('/'); anchor.href = makeAbsoluteUrl('/');
anchor.target = '_blank'; anchor.target = '_blank';
expect(isClickCaptured(anchor)).to.be.eq(false); expect(isClickCaptured(anchor)).to.be.eq(false);
expect(pushStateCalls).to.be.equal(0); expect(pushStateCalls).to.be.equal(0);
}); });
@ -273,8 +372,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
window.history.pushState = originalPushState; window.history.pushState = originalPushState;
expect(count).to.be.equal(0); expect(count).to.be.equal(0);
}) })
}); });
}); });
suite('when used with other iron-location elements', function() { suite('when used with other iron-location elements', function() {
var otherUrlElem; var otherUrlElem;
@ -345,7 +444,26 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
window.history.replaceState({}, '', initialUrl); window.history.replaceState({}, '', initialUrl);
}); });
ironLocationTests(); // This is as dumb as it looks. See #safari-cooldown in the dom above.
var cooldownFunction = function() {};
if (/^Apple/.test(navigator.vendor)) {
cooldownFunction = function(done) {
var cooldownPeriod = 30 * 1000;
this.timeout(cooldownPeriod + 5000);
var cooldownMessage = document.querySelector('#safari-cooldown');
cooldownMessage.removeAttribute('hidden');
setTimeout(function() {
done();
cooldownMessage.setAttribute('hidden', 'hidden');
}, cooldownPeriod);
};
}
suite('without a base URI', function() {
ironLocationTests();
suiteTeardown(cooldownFunction);
});
suite('with a base URI', function() { suite('with a base URI', function() {
var baseElem; var baseElem;
@ -360,7 +478,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
teardown(function() { teardown(function() {
document.head.removeChild(baseElem); document.head.removeChild(baseElem);
}); });
suiteTeardown(cooldownFunction);
ironLocationTests(); ironLocationTests();
}); });
}); });

View file

@ -31,14 +31,14 @@
"web-component-tester": "*" "web-component-tester": "*"
}, },
"private": true, "private": true,
"homepage": "https://github.com/polymer/polymer", "homepage": "https://github.com/Polymer/polymer",
"_release": "1.6.0", "_release": "1.6.0",
"_resolution": { "_resolution": {
"type": "version", "type": "version",
"tag": "v1.6.0", "tag": "v1.6.0",
"commit": "8715c83bf04a228de00ec662ed43eb6141e61b91" "commit": "8715c83bf04a228de00ec662ed43eb6141e61b91"
}, },
"_source": "git://github.com/polymer/polymer.git", "_source": "git://github.com/Polymer/polymer.git",
"_target": "^1.1.0", "_target": "^1.1.0",
"_originalSource": "polymer/polymer" "_originalSource": "Polymer/polymer"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View file

@ -86,10 +86,6 @@
background-position: center center; background-position: center center;
} }
.imgNotificationIcon {
background-size: 50% auto;
}
.imgNotificationNormal { .imgNotificationNormal {
background-color: #4d90fe; background-color: #4d90fe;
background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#4787ed)); background-image: -webkit-gradient(linear,left top,left bottom,from(#4d90fe),to(#4787ed));
@ -100,10 +96,6 @@
background-image: linear-gradient(top,#4d90fe,#4787ed); background-image: linear-gradient(top,#4d90fe,#4787ed);
} }
.imgNotificationNormal .imgNotificationInner {
background-image: url(images/notifications/info.png);
}
.imgNotificationError { .imgNotificationError {
background-color: #d14836; background-color: #d14836;
background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836)); background-image: -webkit-gradient(linear,left top,left bottom,from(#dd4b39),to(#d14836));
@ -114,14 +106,6 @@
background-image: linear-gradient(top,#dd4b39,#d14836); background-image: linear-gradient(top,#dd4b39,#d14836);
} }
.imgNotificationError .imgNotificationInner {
background-image: url(images/notifications/error.png);
}
.imgNotificationWarning { .imgNotificationWarning {
background-color: #FF7537; background-color: #FF7537;
} }
.imgNotificationWarning .imgNotificationInner {
background-image: url(images/notifications/error.png);
}

View file

@ -411,12 +411,6 @@ textarea {
border-top: 1px solid #555; border-top: 1px solid #555;
} }
.notificationIcon {
height: 24px;
margin-right: 1em;
vertical-align: middle;
}
/* /*
* Gradient Shadow * Gradient Shadow
*/ */

View file

@ -169,7 +169,6 @@
ApiClient.getNamedConfiguration("livetv").then(function (config) { ApiClient.getNamedConfiguration("livetv").then(function (config) {
loadPage(page, config); loadPage(page, config);
}); });
if (AppInfo.enableSupporterMembership) { if (AppInfo.enableSupporterMembership) {

View file

@ -263,6 +263,12 @@
loadPage(page, liveTvInfo); loadPage(page, liveTvInfo);
}, function () {
loadPage(page, {
Services: [],
IsEnabled: true
});
}); });
} }

View file

@ -172,58 +172,6 @@ var Dashboard = {
Dashboard.showDashboardRefreshNotification(); Dashboard.showDashboardRefreshNotification();
} }
} }
Dashboard.showInProgressInstallations(info.InProgressInstallations);
},
showInProgressInstallations: function (installations) {
installations = installations || [];
for (var i = 0, length = installations.length; i < length; i++) {
var installation = installations[i];
var percent = installation.PercentComplete || 0;
if (percent < 100) {
Dashboard.showPackageInstallNotification(installation, "progress");
}
}
if (installations.length) {
Dashboard.ensureInstallRefreshInterval();
} else {
Dashboard.stopInstallRefreshInterval();
}
},
ensureInstallRefreshInterval: function () {
if (!Dashboard.installRefreshInterval) {
if (ApiClient.isWebSocketOpen()) {
ApiClient.sendWebSocketMessage("SystemInfoStart", "0,500");
}
Dashboard.installRefreshInterval = 1;
}
},
stopInstallRefreshInterval: function () {
if (Dashboard.installRefreshInterval) {
if (ApiClient.isWebSocketOpen()) {
ApiClient.sendWebSocketMessage("SystemInfoStop");
}
Dashboard.installRefreshInterval = null;
}
},
cancelInstallation: function (id) {
ApiClient.cancelPackageInstallation(id).then(Dashboard.refreshSystemInfoFromServer, Dashboard.refreshSystemInfoFromServer);
}, },
showServerRestartWarning: function (systemInfo) { showServerRestartWarning: function (systemInfo) {
@ -780,105 +728,6 @@ var Dashboard = {
else if (msg.MessageType === "RestartRequired") { else if (msg.MessageType === "RestartRequired") {
Dashboard.updateSystemInfo(msg.Data); Dashboard.updateSystemInfo(msg.Data);
} }
else if (msg.MessageType === "PackageInstallationCompleted") {
Dashboard.getCurrentUser().then(function (currentUser) {
if (currentUser.Policy.IsAdministrator) {
Dashboard.showPackageInstallNotification(msg.Data, "completed");
Dashboard.refreshSystemInfoFromServer();
}
});
}
else if (msg.MessageType === "PackageInstallationFailed") {
Dashboard.getCurrentUser().then(function (currentUser) {
if (currentUser.Policy.IsAdministrator) {
Dashboard.showPackageInstallNotification(msg.Data, "failed");
Dashboard.refreshSystemInfoFromServer();
}
});
}
else if (msg.MessageType === "PackageInstallationCancelled") {
Dashboard.getCurrentUser().then(function (currentUser) {
if (currentUser.Policy.IsAdministrator) {
Dashboard.showPackageInstallNotification(msg.Data, "cancelled");
Dashboard.refreshSystemInfoFromServer();
}
});
}
else if (msg.MessaapiclientcgeType === "PackageInstalling") {
Dashboard.getCurrentUser().then(function (currentUser) {
if (currentUser.Policy.IsAdministrator) {
Dashboard.showPackageInstallNotification(msg.Data, "progress");
Dashboard.refreshSystemInfoFromServer();
}
});
}
},
showPackageInstallNotification: function (installation, status) {
if (AppInfo.isNativeApp) {
return;
}
var html = '';
if (status == 'completed') {
html += '<img src="css/images/notifications/done.png" class="notificationIcon" />';
}
else if (status == 'cancelled') {
html += '<img src="css/images/notifications/info.png" class="notificationIcon" />';
}
else if (status == 'failed') {
html += '<img src="css/images/notifications/error.png" class="notificationIcon" />';
}
else if (status == 'progress') {
html += '<img src="css/images/notifications/download.png" class="notificationIcon" />';
}
html += '<span style="margin-right: 1em;">';
if (status == 'completed') {
html += Globalize.translate('LabelPackageInstallCompleted').replace('{0}', installation.Name + ' ' + installation.Version);
}
else if (status == 'cancelled') {
html += Globalize.translate('LabelPackageInstallCancelled').replace('{0}', installation.Name + ' ' + installation.Version);
}
else if (status == 'failed') {
html += Globalize.translate('LabelPackageInstallFailed').replace('{0}', installation.Name + ' ' + installation.Version);
}
else if (status == 'progress') {
html += Globalize.translate('LabelInstallingPackage').replace('{0}', installation.Name + ' ' + installation.Version);
}
html += '</span>';
if (status == 'progress') {
var percentComplete = Math.round(installation.PercentComplete || 0);
html += '<progress style="margin-right: 1em;" max="100" value="' + percentComplete + '" title="' + percentComplete + '%">';
html += '' + percentComplete + '%';
html += '</progress>';
if (percentComplete < 100) {
html += '<button is="emby-button" type="button" class="raised cancelDark mini" onclick="this.disabled=\'disabled\';Dashboard.cancelInstallation(\'' + installation.Id + '\');"><i class="md-icon">cancel</i><span>' + Globalize.translate('ButtonCancel') + '</span></button>';
}
}
var timeout = 0;
if (status == 'cancelled') {
timeout = 2000;
}
var forceShow = status != "progress";
var allowHide = status != "progress" && status != 'cancelled';
Dashboard.showFooterNotification({ html: html, id: installation.Id, timeout: timeout, forceShow: forceShow, allowHide: allowHide });
}, },
setPageTitle: function (title, documentTitle) { setPageTitle: function (title, documentTitle) {
@ -2994,7 +2843,7 @@ var AppInfo = {};
postInitDependencies.push('bower_components/emby-webcomponents/input/api'); postInitDependencies.push('bower_components/emby-webcomponents/input/api');
if (window.Notification && !AppInfo.isNativeApp) { if (window.Notification && !AppInfo.isNativeApp) {
postInitDependencies.push('bower_components/emby-webcomponents/librarychangednotifications'); postInitDependencies.push('bower_components/emby-webcomponents/notifications/notifications');
} }
require(postInitDependencies); require(postInitDependencies);