Merge remote-tracking branch 'jerbob92/master' into develop-test
Conflicts: js/app.js
This commit is contained in:
commit
8361a247ba
14 changed files with 768 additions and 85 deletions
|
@ -33,6 +33,7 @@
|
||||||
<script src="js/plugins/jquery.scrollTo.min.js" type="text/javascript"></script>
|
<script src="js/plugins/jquery.scrollTo.min.js" type="text/javascript"></script>
|
||||||
<script src="js/plugins/UnityShim.js" type="text/javascript"></script>
|
<script src="js/plugins/UnityShim.js" type="text/javascript"></script>
|
||||||
<script src="js/plugins/jplayer/jquery.jplayer.min.js" type="text/javascript"></script>
|
<script src="js/plugins/jplayer/jquery.jplayer.min.js" type="text/javascript"></script>
|
||||||
|
<script src="js/plugins/notifyjs/notify.js" type="text/javascript"></script>
|
||||||
<script src="js/app.js" type="text/javascript"></script>
|
<script src="js/app.js" type="text/javascript"></script>
|
||||||
<script src="js/service.js" type="text/javascript"></script>
|
<script src="js/service.js" type="text/javascript"></script>
|
||||||
<script src="js/utils.js" type="text/javascript"></script>
|
<script src="js/utils.js" type="text/javascript"></script>
|
||||||
|
|
136
js/app.js
136
js/app.js
|
@ -1,6 +1,46 @@
|
||||||
/* Declare app level module */
|
/* Declare app level module */
|
||||||
var JamStash = angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize']);
|
var JamStash = angular.module('JamStash', ['ngCookies', 'ngRoute', 'ngSanitize']);
|
||||||
//var JamStash = angular.module('JamStash', ['ngCookies', 'ngRoute']);
|
//var JamStash = angular.module('JamStash', ['ngCookies', 'ngRoute']);
|
||||||
|
|
||||||
|
JamStash.service('globals', function (utils) {
|
||||||
|
this.settings = {
|
||||||
|
// Subsonic
|
||||||
|
/* Demo Server
|
||||||
|
Username: "android-guest"),
|
||||||
|
Password: "guest"),
|
||||||
|
Server: "http://subsonic.org/demo"),
|
||||||
|
*/
|
||||||
|
Url: "http://Jamstash.com/beta/#/archive/",
|
||||||
|
Username: "",
|
||||||
|
Password: "",
|
||||||
|
Server: "",
|
||||||
|
Timeout: 10000,
|
||||||
|
NotificationTimeout: 20000,
|
||||||
|
Protocol: "jsonp",
|
||||||
|
ApplicationName: "Jamstash",
|
||||||
|
ApiVersion: "1.6.0",
|
||||||
|
AutoPlaylists: "",
|
||||||
|
AutoPlaylistSize: 25,
|
||||||
|
AutoAlbumSize: 15,
|
||||||
|
// General
|
||||||
|
HideAZ: false,
|
||||||
|
ScrollTitle: true,
|
||||||
|
NotificationSong: true,
|
||||||
|
NotificationNowPlaying: false,
|
||||||
|
SaveTrackPosition: false,
|
||||||
|
ForceFlash: false,
|
||||||
|
Theme: "Default",
|
||||||
|
DefaultLibraryLayout: "grid",
|
||||||
|
AutoPlay: false,
|
||||||
|
LoopQueue: false,
|
||||||
|
Repeat: false,
|
||||||
|
Debug: false
|
||||||
|
};
|
||||||
|
this.SavedCollections = [];
|
||||||
|
this.SavedGenres = [];
|
||||||
|
this.BaseURL = function () { return this.settings.Server + '/rest'; };
|
||||||
|
this.BaseParams = function () { return 'u=' + this.settings.Username + '&p=' + this.settings.Password + '&f=' + this.settings.Protocol + '&v=' + this.settings.ApiVersion + '&c=' + this.settings.ApplicationName; };
|
||||||
|
});
|
||||||
/*
|
/*
|
||||||
JamStash.config(function ($sceDelegateProvider) {
|
JamStash.config(function ($sceDelegateProvider) {
|
||||||
$sceDelegateProvider.resourceUrlWhitelist(['/^\s*(https?|file|ms-appx):/', 'self']);
|
$sceDelegateProvider.resourceUrlWhitelist(['/^\s*(https?|file|ms-appx):/', 'self']);
|
||||||
|
@ -28,26 +68,78 @@ JamStash.config(function ($routeProvider) {
|
||||||
.when('/archive/:artist/:album', { templateUrl: 'js/partials/archive.html', controller: 'ArchiveCtrl' })
|
.when('/archive/:artist/:album', { templateUrl: 'js/partials/archive.html', controller: 'ArchiveCtrl' })
|
||||||
.otherwise({ redirectTo: '/index' });
|
.otherwise({ redirectTo: '/index' });
|
||||||
})
|
})
|
||||||
.run(['$rootScope', '$location', 'globals', 'utils', function ($rootScope, $location, globals, utils) {
|
|
||||||
$rootScope.$on("$locationChangeStart", function (event, next, current) {
|
|
||||||
$rootScope.loggedIn = false;
|
|
||||||
var path = $location.path().replace(/^\/([^\/]*).*$/, '$1');
|
|
||||||
if (globals.settings.Username !== "" && globals.settings.Password !== "" && globals.settings.Server !== "" && path != 'archive') {
|
|
||||||
$rootScope.loggedIn = true;
|
|
||||||
$.fancybox.close();
|
|
||||||
}
|
|
||||||
if (!$rootScope.loggedIn && (path != 'settings' && path != 'archive')) {
|
|
||||||
var url = '/settings';
|
|
||||||
$location.path(url);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}]);
|
|
||||||
|
|
||||||
/*
|
JamStash.config(function ($httpProvider) {
|
||||||
JamStash.config(function ($locationProvider) {
|
$httpProvider.interceptors.push(function ($rootScope, $location, $q, globals) {
|
||||||
$locationProvider.html5Mode(true);
|
return {
|
||||||
})
|
'request': function (request) {
|
||||||
JamStash.config(function ($httpProvider, globals) {
|
// if we're not logged-in to the AngularJS app, redirect to login page
|
||||||
$httpProvider.defaults.timeout = globals.settings.Timeout;
|
//$rootScope.loggedIn = $rootScope.loggedIn || globals.settings.Username;
|
||||||
})
|
$rootScope.loggedIn = false;
|
||||||
*/
|
if (globals.settings.Username != "" && globals.settings.Password != "" && globals.settings.Server != "") {
|
||||||
|
$rootScope.loggedIn = true;
|
||||||
|
}
|
||||||
|
if (!$rootScope.loggedIn && $location.path() != '/settings' && $location.path() != '/archive') {
|
||||||
|
$location.path('/settings');
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
},
|
||||||
|
'responseError': function (rejection) {
|
||||||
|
// if we're not logged-in to the web service, redirect to login page
|
||||||
|
if (rejection.status === 401 && $location.path() != '/settings') {
|
||||||
|
$rootScope.loggedIn = false;
|
||||||
|
$location.path('/settings');
|
||||||
|
}
|
||||||
|
return $q.reject(rejection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
JamStash.service('model', function (utils) {
|
||||||
|
this.Index = function (name, artist) {
|
||||||
|
this.name = name;
|
||||||
|
this.artist = artist;
|
||||||
|
}
|
||||||
|
this.Artist = function (id, name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
this.Album = function (id, parentid, name, artist, coverartthumb, coverartfull, date, starred, description, url) {
|
||||||
|
this.id = id;
|
||||||
|
this.parentid = parentid;
|
||||||
|
this.name = name;
|
||||||
|
this.artist = artist;
|
||||||
|
this.coverartthumb = coverartthumb;
|
||||||
|
this.coverartfull = coverartfull;
|
||||||
|
this.date = date;
|
||||||
|
this.starred = starred;
|
||||||
|
this.description = description;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
this.Song = function (id, parentid, track, name, artist, artistId, album, albumId, coverartthumb, coverartfull, duration, rating, starred, suffix, specs, url, position, description) {
|
||||||
|
this.id = id;
|
||||||
|
this.parentid = parentid;
|
||||||
|
this.track = track;
|
||||||
|
this.name = name;
|
||||||
|
this.artist = artist;
|
||||||
|
this.artistId = artistId;
|
||||||
|
this.album = album;
|
||||||
|
this.albumId = albumId;
|
||||||
|
this.coverartthumb = coverartthumb;
|
||||||
|
this.coverartfull = coverartfull;
|
||||||
|
this.duration = duration;
|
||||||
|
this.time = duration == '' ? '00:00' : utils.secondsToTime(duration);
|
||||||
|
this.rating = rating;
|
||||||
|
this.starred = starred;
|
||||||
|
this.suffix = suffix;
|
||||||
|
this.specs = specs;
|
||||||
|
this.url = url;
|
||||||
|
this.position = position;
|
||||||
|
this.selected = false;
|
||||||
|
this.playing = false;
|
||||||
|
this.description = description;
|
||||||
|
this.displayName = this.name + " - " + this.album + " - " + this.artist;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -31,13 +31,13 @@ function SettingsCtrl($rootScope, $scope, $routeParams, $location, utils, global
|
||||||
if ($scope.settings.Password !== '' && globals.settings.Password.substring(0, 4) != 'enc:') { $scope.settings.Password = 'enc:' + utils.HexEncode($scope.settings.Password); }
|
if ($scope.settings.Password !== '' && globals.settings.Password.substring(0, 4) != 'enc:') { $scope.settings.Password = 'enc:' + utils.HexEncode($scope.settings.Password); }
|
||||||
if ($scope.settings.NotificationSong) {
|
if ($scope.settings.NotificationSong) {
|
||||||
notifications.requestPermissionIfRequired();
|
notifications.requestPermissionIfRequired();
|
||||||
if (!notifications.hasNotificationPermission()) {
|
if (!notifications.hasNotificationSupport()) {
|
||||||
alert('HTML5 Notifications are not available for your current browser, Sorry :(');
|
alert('HTML5 Notifications are not available for your current browser, Sorry :(');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($scope.settings.NotificationNowPlaying) {
|
if ($scope.settings.NotificationNowPlaying) {
|
||||||
notifications.requestPermissionIfRequired();
|
notifications.requestPermissionIfRequired();
|
||||||
if (!notifications.hasNotificationPermission()) {
|
if (!notifications.hasNotificationSupport()) {
|
||||||
alert('HTML5 Notifications are not available for your current browser, Sorry :(');
|
alert('HTML5 Notifications are not available for your current browser, Sorry :(');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1
js/plugins/notifyjs/.gitignore
vendored
Normal file
1
js/plugins/notifyjs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
20
js/plugins/notifyjs/.jshintrc
Normal file
20
js/plugins/notifyjs/.jshintrc
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"globals": {
|
||||||
|
"define": false,
|
||||||
|
"Notification": false
|
||||||
|
},
|
||||||
|
"browser": true,
|
||||||
|
"node": true,
|
||||||
|
"esnext": true,
|
||||||
|
"curly": true,
|
||||||
|
"eqeqeq": true,
|
||||||
|
"immed": true,
|
||||||
|
"latedef": false,
|
||||||
|
"newcap": true,
|
||||||
|
"undef": true,
|
||||||
|
"strict": true,
|
||||||
|
"trailing": true,
|
||||||
|
"white": true,
|
||||||
|
"indent": false,
|
||||||
|
"unused": false
|
||||||
|
}
|
8
js/plugins/notifyjs/.travis.yml
Normal file
8
js/plugins/notifyjs/.travis.yml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
language: node_js
|
||||||
|
node_js:
|
||||||
|
- "0.8"
|
||||||
|
before_install:
|
||||||
|
- "export DISPLAY=:99.0"
|
||||||
|
- "sh -e /etc/init.d/xvfb start"
|
||||||
|
addons:
|
||||||
|
firefox: "22.0"
|
9
js/plugins/notifyjs/LICENSE.md
Normal file
9
js/plugins/notifyjs/LICENSE.md
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Copyright (c) 2013 Alex Gibson
|
||||||
|
|
||||||
|
http://alxgbsn.co.uk/
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction except as noted below, including without limitation the rights to use, copy, modify, merge, publish, distribute, and/or sublicense, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
|
92
js/plugins/notifyjs/README.md
Normal file
92
js/plugins/notifyjs/README.md
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
Notify.js
|
||||||
|
=========
|
||||||
|
|
||||||
|
[](https://travis-ci.org/alexgibson/notify.js)
|
||||||
|
|
||||||
|
A handy wrapper for using the [Web Notifications API](http://www.w3.org/TR/notifications/). Notify.js aims to simplify requesting user permission and associated Web Notification API events, as well as providing a few extra callbacks and convenience methods.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
* Download: [zip](https://github.com/alexgibson/notify.js/zipball/master)
|
||||||
|
* [Bower](https://github.com/twitter/bower/): `bower install notify.js`
|
||||||
|
* Git: `git clone https://github.com/alexgibson/notify.js`
|
||||||
|
|
||||||
|
Setup
|
||||||
|
---------
|
||||||
|
|
||||||
|
This component can be used as an AMD module, or a global.
|
||||||
|
|
||||||
|
To initialize a web notification create a new `Notify` instance, passing the message `title` as well as any other options you wish to use.
|
||||||
|
|
||||||
|
```
|
||||||
|
var myNotification = new Notify('Yo dawg!', {
|
||||||
|
body: 'This is an awesome notification',
|
||||||
|
notifyShow: onNotifyShow
|
||||||
|
});
|
||||||
|
|
||||||
|
function onNotifyShow() {
|
||||||
|
console.log('notification was shown!');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then show the notification.
|
||||||
|
|
||||||
|
```
|
||||||
|
myNotification.show();
|
||||||
|
```
|
||||||
|
|
||||||
|
Required parameters
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* title (string) - notification title
|
||||||
|
|
||||||
|
Optional parameters
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
* body: (string) - notification message body
|
||||||
|
* icon: (string) - path for icon to display in notification
|
||||||
|
* tag: (string) - unique identifier to stop duplicate notifications
|
||||||
|
* timeout: (integer) - number of seconds to close the notification automatically
|
||||||
|
* notifyShow: (function) - callback when notification is shown
|
||||||
|
* notifyClose: (function) - callback when notification is closed
|
||||||
|
* notifyClick: (function) - callback when notification is clicked
|
||||||
|
* notifyError: (function) - callback when notification throws an error
|
||||||
|
* permissionGranted: (function) - callback when user has granted permission
|
||||||
|
* permissionDenied: (function) - callback when user has denied permission
|
||||||
|
|
||||||
|
Useful methods
|
||||||
|
--------------
|
||||||
|
|
||||||
|
* `Notify.needsPermission()` - (returns boolean) check is permission is needed for the user to receive notifications.
|
||||||
|
* `Notify.requestPermission()` - requests permission from the user if needed and handles permission callbacks.
|
||||||
|
* `Notify.isSupported()` - (returns boolean) test for Web Notifications API browser support
|
||||||
|
|
||||||
|
A note about Chrome
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Unlike other browsers that implement the Web Notification API, Chrome does not permit requesting permission on page load (it must be as a result of user interaction, such as a `click` event). You can find out more in the [Chromium bug for this issue](https://code.google.com/p/chromium/issues/detail?id=274284).
|
||||||
|
|
||||||
|
Testing
|
||||||
|
-------
|
||||||
|
|
||||||
|
Install [Node](http://nodejs.org). Testing relies on the Karma test-runner, which can be installed globally using the following command.
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install -g karma
|
||||||
|
```
|
||||||
|
|
||||||
|
In the project root, to perform a single pass of the tests using Firefox run:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
|
Browser support
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
- Chrome (desktop)
|
||||||
|
- Safari
|
||||||
|
- Firefox
|
||||||
|
- Firefox OS (v1.2+)
|
||||||
|
- Firefox Mobile (Android)
|
27
js/plugins/notifyjs/bower.json
Normal file
27
js/plugins/notifyjs/bower.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "notify.js",
|
||||||
|
"description": "A handy wrapper for the Web Notifications API",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Alex Gibson",
|
||||||
|
"email": "alxgbsn@gmail.com"
|
||||||
|
},
|
||||||
|
"keywords": ["javascript", "web notifications", "notification", "notify"],
|
||||||
|
"main": "./notify.js",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/alexgibson/notify.js.git"
|
||||||
|
},
|
||||||
|
"readme": "README.md",
|
||||||
|
"licenses": [{
|
||||||
|
"type": "MIT",
|
||||||
|
"url": "http://opensource.org/licenses/MIT"
|
||||||
|
}],
|
||||||
|
"ignore": [
|
||||||
|
"test",
|
||||||
|
".jshintrc",
|
||||||
|
"karma.conf.js",
|
||||||
|
"package.json",
|
||||||
|
".travis.yml"
|
||||||
|
]
|
||||||
|
}
|
69
js/plugins/notifyjs/karma.conf.js
Normal file
69
js/plugins/notifyjs/karma.conf.js
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// Karma configuration
|
||||||
|
// Generated on Sun Aug 04 2013 21:16:15 GMT+0100 (BST)
|
||||||
|
|
||||||
|
|
||||||
|
// base path, that will be used to resolve files and exclude
|
||||||
|
basePath = '';
|
||||||
|
|
||||||
|
|
||||||
|
// list of files / patterns to load in the browser
|
||||||
|
files = [
|
||||||
|
JASMINE,
|
||||||
|
JASMINE_ADAPTER,
|
||||||
|
'notify.js',
|
||||||
|
'test/*.js',
|
||||||
|
|
||||||
|
{ pattern: 'node_modules/sinon/pkg/sinon.js', watched: false, included: true }
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// list of files to exclude
|
||||||
|
exclude = [
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
// test results reporter to use
|
||||||
|
// possible values: 'dots', 'progress', 'junit'
|
||||||
|
reporters = ['dots'];
|
||||||
|
|
||||||
|
|
||||||
|
// web server port
|
||||||
|
port = 9876;
|
||||||
|
|
||||||
|
|
||||||
|
// cli runner port
|
||||||
|
runnerPort = 9100;
|
||||||
|
|
||||||
|
|
||||||
|
// enable / disable colors in the output (reporters and logs)
|
||||||
|
colors = true;
|
||||||
|
|
||||||
|
|
||||||
|
// level of logging
|
||||||
|
// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
|
||||||
|
logLevel = LOG_INFO;
|
||||||
|
|
||||||
|
|
||||||
|
// enable / disable watching file and executing tests whenever any file changes
|
||||||
|
autoWatch = true;
|
||||||
|
|
||||||
|
|
||||||
|
// Start these browsers, currently available:
|
||||||
|
// - Chrome
|
||||||
|
// - ChromeCanary
|
||||||
|
// - Firefox
|
||||||
|
// - Opera
|
||||||
|
// - Safari (only Mac)
|
||||||
|
// - PhantomJS
|
||||||
|
// - IE (only Windows)
|
||||||
|
browsers = ['Firefox'];
|
||||||
|
|
||||||
|
|
||||||
|
// If browser does not capture in given timeout [ms], kill it
|
||||||
|
captureTimeout = 60000;
|
||||||
|
|
||||||
|
|
||||||
|
// Continuous Integration mode
|
||||||
|
// if true, it capture browsers, run tests and exit
|
||||||
|
singleRun = false;
|
193
js/plugins/notifyjs/notify.js
Normal file
193
js/plugins/notifyjs/notify.js
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
(function (root, factory) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD environment
|
||||||
|
define('notify', [], function () {
|
||||||
|
return factory(root, document);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Browser environment
|
||||||
|
root.Notify = factory(root, document);
|
||||||
|
}
|
||||||
|
|
||||||
|
}(this, function (w, d) {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function Notify(title, options) {
|
||||||
|
|
||||||
|
this.title = typeof title === 'string' ? title : null;
|
||||||
|
|
||||||
|
this.options = {
|
||||||
|
icon: '',
|
||||||
|
body: '',
|
||||||
|
tag: '',
|
||||||
|
notifyShow: null,
|
||||||
|
notifyClose: null,
|
||||||
|
notifyClick: null,
|
||||||
|
notifyError: null,
|
||||||
|
permissionGranted: null,
|
||||||
|
permissionDenied: null,
|
||||||
|
timeout: null
|
||||||
|
};
|
||||||
|
|
||||||
|
this.permission = null;
|
||||||
|
|
||||||
|
if (!Notify.isSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.title) {
|
||||||
|
throw new Error('Notify(): first arg (title) must be a string.');
|
||||||
|
}
|
||||||
|
|
||||||
|
//User defined options for notification content
|
||||||
|
if (typeof options === 'object') {
|
||||||
|
|
||||||
|
for (var i in options) {
|
||||||
|
if (options.hasOwnProperty(i)) {
|
||||||
|
this.options[i] = options[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//callback when notification is displayed
|
||||||
|
if (typeof this.options.notifyShow === 'function') {
|
||||||
|
this.onShowCallback = this.options.notifyShow;
|
||||||
|
}
|
||||||
|
|
||||||
|
//callback when notification is closed
|
||||||
|
if (typeof this.options.notifyClose === 'function') {
|
||||||
|
this.onCloseCallback = this.options.notifyClose;
|
||||||
|
}
|
||||||
|
|
||||||
|
//callback when notification is clicked
|
||||||
|
if (typeof this.options.notifyClick === 'function') {
|
||||||
|
this.onClickCallback = this.options.notifyClick;
|
||||||
|
}
|
||||||
|
|
||||||
|
//callback when notification throws error
|
||||||
|
if (typeof this.options.notifyError === 'function') {
|
||||||
|
this.onErrorCallback = this.options.notifyError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if the browser supports HTML5 Notification
|
||||||
|
Notify.isSupported = function () {
|
||||||
|
if ('Notification' in w) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns true if the permission is not granted
|
||||||
|
Notify.needsPermission = function () {
|
||||||
|
if (Notify.isSupported() && Notification.permission === 'granted') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// asks the user for permission to display notifications. Then calls the callback functions is supplied.
|
||||||
|
Notify.requestPermission = function (onPermissionGrantedCallback, onPermissionDeniedCallback) {
|
||||||
|
if (Notify.isSupported()) {
|
||||||
|
w.Notification.requestPermission(function (perm) {
|
||||||
|
switch (perm) {
|
||||||
|
case 'granted':
|
||||||
|
if (typeof onPermissionGrantedCallback === 'function') {
|
||||||
|
onPermissionGrantedCallback();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'denied':
|
||||||
|
if (typeof onPermissionDeniedCallback === 'function') {
|
||||||
|
onPermissionDeniedCallback();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Notify.prototype.show = function () {
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
if (!Notify.isSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.myNotify = new Notification(this.title, {
|
||||||
|
'body': this.options.body,
|
||||||
|
'tag' : this.options.tag,
|
||||||
|
'icon' : this.options.icon
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.options.timeout && !isNaN(this.options.timeout)) {
|
||||||
|
setTimeout(this.close.bind(this), this.options.timeout * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.myNotify.addEventListener('show', this, false);
|
||||||
|
this.myNotify.addEventListener('error', this, false);
|
||||||
|
this.myNotify.addEventListener('close', this, false);
|
||||||
|
this.myNotify.addEventListener('click', this, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
Notify.prototype.onShowNotification = function (e) {
|
||||||
|
if (this.onShowCallback) {
|
||||||
|
this.onShowCallback(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Notify.prototype.onCloseNotification = function () {
|
||||||
|
if (this.onCloseCallback) {
|
||||||
|
this.onCloseCallback();
|
||||||
|
}
|
||||||
|
this.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
Notify.prototype.onClickNotification = function () {
|
||||||
|
if (this.onClickCallback) {
|
||||||
|
this.onClickCallback();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Notify.prototype.onErrorNotification = function () {
|
||||||
|
if (this.onErrorCallback) {
|
||||||
|
this.onErrorCallback();
|
||||||
|
}
|
||||||
|
this.destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
Notify.prototype.destroy = function () {
|
||||||
|
this.myNotify.removeEventListener('show', this, false);
|
||||||
|
this.myNotify.removeEventListener('error', this, false);
|
||||||
|
this.myNotify.removeEventListener('close', this, false);
|
||||||
|
this.myNotify.removeEventListener('click', this, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
Notify.prototype.close = function () {
|
||||||
|
this.myNotify.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
Notify.prototype.handleEvent = function (e) {
|
||||||
|
switch (e.type) {
|
||||||
|
case 'show':
|
||||||
|
this.onShowNotification(e);
|
||||||
|
break;
|
||||||
|
case 'close':
|
||||||
|
this.onCloseNotification(e);
|
||||||
|
break;
|
||||||
|
case 'click':
|
||||||
|
this.onClickNotification(e);
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
this.onErrorNotification(e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Notify;
|
||||||
|
|
||||||
|
}));
|
27
js/plugins/notifyjs/package.json
Normal file
27
js/plugins/notifyjs/package.json
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"name": "notify.js",
|
||||||
|
"version": "1.1.0",
|
||||||
|
"description": "A handy wrapper for the Web Notifications API",
|
||||||
|
"main": "notify.js",
|
||||||
|
"devDependencies": {
|
||||||
|
"karma": "~0.8.5",
|
||||||
|
"sinon": "~1.7.3"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/alexgibson/notify.js.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"web",
|
||||||
|
"notification",
|
||||||
|
"nofity"
|
||||||
|
],
|
||||||
|
"author": "Alex Gibson",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/alexgibson/notify.js/issues"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "./node_modules/.bin/karma start --browsers Firefox --single-run"
|
||||||
|
}
|
||||||
|
}
|
97
js/plugins/notifyjs/test/tests.js
Normal file
97
js/plugins/notifyjs/test/tests.js
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
describe('instantiation', function () {
|
||||||
|
|
||||||
|
it('should create a new Notify instance', function () {
|
||||||
|
var notification = new Notify('foo');
|
||||||
|
expect(notification instanceof window.Notify).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an exception if has no title', function () {
|
||||||
|
expect(function () {
|
||||||
|
var notification = new Notify();
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('permission', function () {
|
||||||
|
|
||||||
|
it('should check if permission is needed', function () {
|
||||||
|
expect(Notify.needsPermission()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should request permission from the user', function () {
|
||||||
|
spyOn(window.Notification, 'requestPermission');
|
||||||
|
Notify.requestPermission();
|
||||||
|
expect(window.Notification.requestPermission).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('callbacks', function () {
|
||||||
|
|
||||||
|
var callback;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
callback = jasmine.createSpy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire show callback', function () {
|
||||||
|
var notification = new Notify('foo', {
|
||||||
|
notifyShow: callback
|
||||||
|
});
|
||||||
|
notification.onShowNotification();
|
||||||
|
expect(callback).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire close callback', function () {
|
||||||
|
var notification = new Notify('foo', {
|
||||||
|
notifyClose: callback
|
||||||
|
});
|
||||||
|
notification.show();
|
||||||
|
notification.onCloseNotification();
|
||||||
|
expect(callback).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire click callback', function () {
|
||||||
|
var notification = new Notify('foo', {
|
||||||
|
notifyClick: callback
|
||||||
|
});
|
||||||
|
notification.onClickNotification();
|
||||||
|
expect(callback).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire error callback', function () {
|
||||||
|
var notification = new Notify('foo', {
|
||||||
|
notifyError: callback
|
||||||
|
});
|
||||||
|
notification.show();
|
||||||
|
notification.onErrorNotification();
|
||||||
|
expect(callback).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should destroy a notification once closed', function () {
|
||||||
|
var notification = new Notify('foo', {
|
||||||
|
notifyClose: callback
|
||||||
|
});
|
||||||
|
spyOn(notification, 'destroy');
|
||||||
|
notification.onCloseNotification();
|
||||||
|
expect(notification.destroy).toHaveBeenCalled();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('timeout', function () {
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
jasmine.Clock.useMock();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should close a notification automatically', function () {
|
||||||
|
var notification = new Notify('foo', {
|
||||||
|
timeout: 1
|
||||||
|
});
|
||||||
|
spyOn(window.Notification.prototype, 'close');
|
||||||
|
notification.show();
|
||||||
|
expect(window.Notification.prototype.close).not.toHaveBeenCalled();
|
||||||
|
jasmine.Clock.tick(1000);
|
||||||
|
expect(window.Notification.prototype.close).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
167
js/service.js
167
js/service.js
|
@ -133,6 +133,74 @@ JamStash.service('globals', function () {
|
||||||
this.BaseURL = function () { return this.settings.Server + '/rest'; };
|
this.BaseURL = function () { return this.settings.Server + '/rest'; };
|
||||||
this.BaseParams = function () { return 'u=' + this.settings.Username + '&p=' + this.settings.Password + '&f=' + this.settings.Protocol + '&v=' + this.settings.ApiVersion + '&c=' + this.settings.ApplicationName; };
|
this.BaseParams = function () { return 'u=' + this.settings.Username + '&p=' + this.settings.Password + '&f=' + this.settings.Protocol + '&v=' + this.settings.ApiVersion + '&c=' + this.settings.ApplicationName; };
|
||||||
});
|
});
|
||||||
|
JamStash.service('notifications', function ($rootScope, globals) {
|
||||||
|
var msgIndex = 1;
|
||||||
|
this.updateMessage = function (msg, autohide) {
|
||||||
|
if (msg != '') {
|
||||||
|
var id = msgIndex;
|
||||||
|
$('#messages').append('<span id=\"msg_' + id + '\" class="message">' + msg + '</span>');
|
||||||
|
$('#messages').fadeIn();
|
||||||
|
$("#messages").scrollTo('100%');
|
||||||
|
var el = '#msg_' + id;
|
||||||
|
if (autohide) {
|
||||||
|
setTimeout(function () {
|
||||||
|
$(el).fadeOut(function () { $(this).remove(); });
|
||||||
|
}, globals.settings.NotificationTimeout);
|
||||||
|
} else {
|
||||||
|
$(el).click(function () {
|
||||||
|
$(el).fadeOut(function () { $(this).remove(); });
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
msgIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.requestPermissionIfRequired = function () {
|
||||||
|
if (window.Notify.isSupported() && window.Notify.needsPermission()) {
|
||||||
|
window.Notify.requestPermission();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.hasNotificationPermission = function () {
|
||||||
|
return (window.Notify.needsPermission() === false);
|
||||||
|
}
|
||||||
|
this.hasNotificationSupport = function () {
|
||||||
|
return window.Notify.isSupported();
|
||||||
|
}
|
||||||
|
var notifications = new Array();
|
||||||
|
|
||||||
|
this.showNotification = function (pic, title, text, type, bind) {
|
||||||
|
if (this.hasNotificationPermission()) {
|
||||||
|
//closeAllNotifications()
|
||||||
|
var settings = {}
|
||||||
|
if (bind = '#NextTrack') {
|
||||||
|
settings.notifyClick = function () {
|
||||||
|
$rootScope.nextTrack();
|
||||||
|
this.close();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (type == 'text') {
|
||||||
|
settings.body = text;
|
||||||
|
settings.icon = pic;
|
||||||
|
} else if (type == 'html') {
|
||||||
|
settings.body = text;
|
||||||
|
}
|
||||||
|
var notification = new Notify(title, settings);
|
||||||
|
notifications.push(notification);
|
||||||
|
setTimeout(function (notWin) {
|
||||||
|
notWin.close();
|
||||||
|
}, globals.settings.NotificationTimeout, notification);
|
||||||
|
notification.show();
|
||||||
|
} else {
|
||||||
|
console.log("showNotification: No Permission");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.closeAllNotifications = function () {
|
||||||
|
for (notification in notifications) {
|
||||||
|
notifications[notification].close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Directives
|
// Directives
|
||||||
JamStash.directive('layout', function () {
|
JamStash.directive('layout', function () {
|
||||||
return {
|
return {
|
||||||
|
@ -349,6 +417,30 @@ JamStash.directive('ngDownload', function ($compile) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
JamStash.directive('stopEvent', function () {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function (scope, element, attr) {
|
||||||
|
element.bind(attr.stopEvent, function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
JamStash.directive('ngEnter', function () {
|
||||||
|
return function (scope, element, attrs) {
|
||||||
|
element.bind("keydown keypress", function (event) {
|
||||||
|
if (event.which === 13) {
|
||||||
|
scope.$apply(function () {
|
||||||
|
scope.$eval(attrs.ngEnter);
|
||||||
|
});
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/* Factory */
|
/* Factory */
|
||||||
JamStash.factory('json', function ($http) { // Deferred loading
|
JamStash.factory('json', function ($http) { // Deferred loading
|
||||||
|
@ -413,6 +505,16 @@ JamStash.factory('subsonic', function ($http, globals, utils) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
JamStash.factory('json', function ($http) { // Deferred loading
|
||||||
|
return {
|
||||||
|
getCollections: function (callback) {
|
||||||
|
$http.get('js/json_collections.js').success(callback);
|
||||||
|
},
|
||||||
|
getChangeLog: function (callback) {
|
||||||
|
$http.get('js/json_changelog.js').success(callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/* Filters */
|
/* Filters */
|
||||||
JamStash.filter('capitalize', function () {
|
JamStash.filter('capitalize', function () {
|
||||||
|
@ -425,65 +527,10 @@ JamStash.filter('musicfolder', function () {
|
||||||
return items.slice(1, items.length);
|
return items.slice(1, items.length);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
JamStash.filter('capitalize', function () {
|
||||||
JamStash.service('notifications', function ($rootScope, globals) {
|
return function (input, scope) {
|
||||||
var msgIndex = 1;
|
return input.substring(0, 1).toUpperCase() + input.substring(1);
|
||||||
this.updateMessage = function (msg, autohide) {
|
|
||||||
if (msg !== '') {
|
|
||||||
var id = msgIndex;
|
|
||||||
$('#messages').append('<span id=\"msg_' + id + '\" class="message">' + msg + '</span>');
|
|
||||||
$('#messages').fadeIn();
|
|
||||||
$("#messages").scrollTo('100%');
|
|
||||||
var el = '#msg_' + id;
|
|
||||||
if (autohide) {
|
|
||||||
setTimeout(function () {
|
|
||||||
$(el).fadeOut(function () { $(this).remove(); });
|
|
||||||
}, globals.settings.Timeout);
|
|
||||||
}
|
}
|
||||||
$(el).click(function () {
|
|
||||||
$(el).fadeOut(function () { $(this).remove(); });
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
msgIndex++;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.requestPermissionIfRequired = function () {
|
|
||||||
if (!this.hasNotificationPermission() && (window.webkitNotifications)) {
|
|
||||||
window.webkitNotifications.requestPermission();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.hasNotificationPermission = function () {
|
|
||||||
return !!(window.webkitNotifications) && (window.webkitNotifications.checkPermission() === 0);
|
|
||||||
};
|
|
||||||
var notifications = [];
|
|
||||||
this.showNotification = function (pic, title, text, type, bind) {
|
|
||||||
if (this.hasNotificationPermission()) {
|
|
||||||
//closeAllNotifications()
|
|
||||||
var popup;
|
|
||||||
if (type == 'text') {
|
|
||||||
popup = window.webkitNotifications.createNotification(pic, title, text);
|
|
||||||
} else if (type == 'html') {
|
|
||||||
popup = window.webkitNotifications.createHTMLNotification(text);
|
|
||||||
}
|
|
||||||
if (bind == '#NextTrack') {
|
|
||||||
popup.addEventListener('click', function (bind) {
|
|
||||||
//$(bind).click();
|
|
||||||
$rootScope.nextTrack();
|
|
||||||
this.cancel();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
notifications.push(popup);
|
|
||||||
setTimeout(function (notWin) {
|
|
||||||
notWin.cancel();
|
|
||||||
}, globals.settings.Timeout, popup);
|
|
||||||
popup.show();
|
|
||||||
} else {
|
|
||||||
console.log("showNotification: No Permission");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.closeAllNotifications = function () {
|
|
||||||
for (notification in notifications) {
|
|
||||||
notifications[notification].cancel();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue