Replaced utils setTitle and scrollTitle by a dedicated service
- Adds a Page service that will control the page's title from anywhere. - Adds a setTitleSong method. It takes a song as parameter, that way player-directive isn't responsible for correctly formatting the title. It also scrolls the title if the global setting is true - Removes the title-related methods from utils-service
This commit is contained in:
parent
0646b02e94
commit
c478f0116f
7 changed files with 138 additions and 47 deletions
|
@ -1,6 +1,6 @@
|
||||||
angular.module('JamStash')
|
angular.module('JamStash')
|
||||||
.controller('AppController', ['$scope', '$rootScope', '$document', '$window', '$location', '$cookieStore', '$http', 'utils', 'globals', 'model', 'notifications', 'player', 'persistence',
|
.controller('AppController', ['$scope', '$rootScope', '$document', '$window', '$location', '$cookieStore', '$http', 'utils', 'globals', 'model', 'notifications', 'player', 'persistence', 'Page',
|
||||||
function($scope, $rootScope, $document, $window, $location, $cookieStore, $http, utils, globals, model, notifications, player, persistence) {
|
function($scope, $rootScope, $document, $window, $location, $cookieStore, $http, utils, globals, model, notifications, player, persistence, Page) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
$rootScope.settings = globals.settings;
|
$rootScope.settings = globals.settings;
|
||||||
|
@ -13,6 +13,7 @@ angular.module('JamStash')
|
||||||
|
|
||||||
$rootScope.SelectedMusicFolder = "";
|
$rootScope.SelectedMusicFolder = "";
|
||||||
$rootScope.unity = null;
|
$rootScope.unity = null;
|
||||||
|
$scope.Page = Page;
|
||||||
$rootScope.loggedIn = function () {
|
$rootScope.loggedIn = function () {
|
||||||
if (globals.settings.Server !== '' && globals.settings.Username !== '' && globals.settings.Password !== '') {
|
if (globals.settings.Server !== '' && globals.settings.Username !== '' && globals.settings.Password !== '') {
|
||||||
return true;
|
return true;
|
||||||
|
|
64
app/common/page-service.js
Normal file
64
app/common/page-service.js
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
/**
|
||||||
|
* jamstash.page Module
|
||||||
|
*
|
||||||
|
* Set the page's title from anywhere, the angular way
|
||||||
|
*/
|
||||||
|
angular.module('jamstash.page', ['jamstash.settings', 'jamstash.utils'])
|
||||||
|
|
||||||
|
.factory('Page', ['$interval', 'globals', 'utils', function($interval, globals, utils){
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var title = 'Jamstash';
|
||||||
|
var timer;
|
||||||
|
return {
|
||||||
|
title: function() { return title; },
|
||||||
|
setTitle: function(newTitle) {
|
||||||
|
title = newTitle;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
setTitleSong: function(song) {
|
||||||
|
if (song.artist !== undefined && song.name !== undefined) {
|
||||||
|
title = utils.toHTML.un(song.artist) + " - " + utils.toHTML.un(song.name);
|
||||||
|
} else {
|
||||||
|
title = 'Jamstash';
|
||||||
|
}
|
||||||
|
if (globals.settings.ScrollTitle) {
|
||||||
|
this.scrollTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
scrollTitle: function() {
|
||||||
|
var shift = {
|
||||||
|
"left": function (a) {
|
||||||
|
a.push(a.shift());
|
||||||
|
},
|
||||||
|
"right": function (a) {
|
||||||
|
a.unshift(a.pop());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var opts = {
|
||||||
|
text: title,
|
||||||
|
dir: "left",
|
||||||
|
speed: 1200
|
||||||
|
};
|
||||||
|
|
||||||
|
var t = (opts.text).split("");
|
||||||
|
if (!t) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t.push(" ");
|
||||||
|
if (timer !== undefined) {
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
timer = $interval(function () {
|
||||||
|
var f = shift[opts.dir];
|
||||||
|
if (f) {
|
||||||
|
f(t);
|
||||||
|
title = t.join("");
|
||||||
|
}
|
||||||
|
}, opts.speed);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}]);
|
54
app/common/page-service_test.js
Normal file
54
app/common/page-service_test.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
describe("Page service", function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var mockGlobals, Page, utils, $interval;
|
||||||
|
beforeEach(function() {
|
||||||
|
|
||||||
|
mockGlobals = {
|
||||||
|
settings: {
|
||||||
|
ScrollTitle: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module('jamstash.page', function ($provide) {
|
||||||
|
$provide.value('globals', mockGlobals);
|
||||||
|
});
|
||||||
|
|
||||||
|
inject(function (_Page_, _utils_, _$interval_) {
|
||||||
|
Page = _Page_;
|
||||||
|
utils = _utils_;
|
||||||
|
$interval = _$interval_;
|
||||||
|
});
|
||||||
|
spyOn(utils.toHTML, "un").and.callFake(function (arg) { return arg; });
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Given a song,", function() {
|
||||||
|
var song;
|
||||||
|
beforeEach(function() {
|
||||||
|
song = {
|
||||||
|
artist: 'Merlyn Nurse',
|
||||||
|
name: 'Exsiccator tumble'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it("it displays its artist and its name as the page's title", function() {
|
||||||
|
Page.setTitleSong(song);
|
||||||
|
expect(Page.title()).toBe('Merlyn Nurse - Exsiccator tumble');
|
||||||
|
});
|
||||||
|
|
||||||
|
it("if the global setting 'ScrollTitle' is true, it scrolls the page title", function() {
|
||||||
|
spyOn(Page, "scrollTitle");
|
||||||
|
mockGlobals.settings.ScrollTitle = true;
|
||||||
|
|
||||||
|
Page.setTitleSong(song);
|
||||||
|
|
||||||
|
expect(Page.scrollTitle).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Given a title, it can scroll it", function() {
|
||||||
|
Page.setTitle('unbeloved omnificent supergravitate').scrollTitle();
|
||||||
|
$interval.flush(1201);
|
||||||
|
expect(Page.title()).toBe('nbeloved omnificent supergravitate u');
|
||||||
|
});
|
||||||
|
});
|
|
@ -251,41 +251,6 @@ angular.module('jamstash.utils', ['jamstash.settings'])
|
||||||
var u = strurl.substring(0, strurl.indexOf('?'));
|
var u = strurl.substring(0, strurl.indexOf('?'));
|
||||||
return u;
|
return u;
|
||||||
};
|
};
|
||||||
this.setTitle = function (text) {
|
|
||||||
if (text !== "") {
|
|
||||||
document.title = text;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var timer = 0;
|
|
||||||
this.scrollTitle = function (text) {
|
|
||||||
var shift = {
|
|
||||||
"left": function (a) {
|
|
||||||
a.push(a.shift());
|
|
||||||
},
|
|
||||||
"right": function (a) {
|
|
||||||
a.unshift(a.pop());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var opts = {
|
|
||||||
text: text,
|
|
||||||
dir: "left",
|
|
||||||
speed: 1200
|
|
||||||
};
|
|
||||||
|
|
||||||
var t = (opts.text || document.title).split("");
|
|
||||||
if (!t) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
t.push(" ");
|
|
||||||
clearInterval(timer);
|
|
||||||
timer = setInterval(function () {
|
|
||||||
var f = shift[opts.dir];
|
|
||||||
if (f) {
|
|
||||||
f(t);
|
|
||||||
document.title = t.join("");
|
|
||||||
}
|
|
||||||
}, opts.speed);
|
|
||||||
};
|
|
||||||
this.parseVersionString = function (str) {
|
this.parseVersionString = function (str) {
|
||||||
if (typeof (str) !== 'string') { return false; }
|
if (typeof (str) !== 'string') { return false; }
|
||||||
var x = str.split('.');
|
var x = str.split('.');
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html lang="en" ng-app="JamStash">
|
<html lang="en" ng-app="JamStash" ng-controller="AppController">
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-type" content="text/html; charset=UTF-8">
|
||||||
<meta name="description" content="HTML5 Audio Streamer for Subsonic, Archive.org browsing and streaming">
|
<meta name="description" content="HTML5 Audio Streamer for Subsonic, Archive.org browsing and streaming">
|
||||||
<meta name="keywords" content="Subsonic, Archive.org, Live Music Archive, HTML5 Audio, Music Streaming, Live Music">
|
<meta name="keywords" content="Subsonic, Archive.org, Live Music Archive, HTML5 Audio, Music Streaming, Live Music">
|
||||||
<meta property="og:image" content="http://jamstash.com/images/fbpreview.png"/>
|
<meta property="og:image" content="http://jamstash.com/images/fbpreview.png"/>
|
||||||
<meta name=viewport content="width=device-width, initial-scale=1">
|
<meta name=viewport content="width=device-width, initial-scale=1">
|
||||||
<title>Jamstash</title>
|
<title ng-bind="Page.title()">Jamstash</title>
|
||||||
<link href="images/favicon_32x32.ico" rel="shortcut icon" />
|
<link href="images/favicon_32x32.ico" rel="shortcut icon" />
|
||||||
<link rel="icon" href="images/favicon_48x48.png" sizes="48x48"/>
|
<link rel="icon" href="images/favicon_48x48.png" sizes="48x48"/>
|
||||||
<link rel="icon" href="images/favicon_32x32.png" sizes="32x32"/>
|
<link rel="icon" href="images/favicon_32x32.png" sizes="32x32"/>
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
<link href="styles/Mobile.css" rel="stylesheet" type="text/css" data-name="main" />
|
<link href="styles/Mobile.css" rel="stylesheet" type="text/css" data-name="main" />
|
||||||
<link href="" rel="stylesheet" type="text/css" data-name="theme" />
|
<link href="" rel="stylesheet" type="text/css" data-name="theme" />
|
||||||
</head>
|
</head>
|
||||||
<body ng-controller="AppController">
|
<body>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div id="header">
|
<div id="header">
|
||||||
<div id="messages">
|
<div id="messages">
|
||||||
|
@ -102,6 +102,7 @@
|
||||||
<script src="settings/settings-service.js"></script>
|
<script src="settings/settings-service.js"></script>
|
||||||
<script src="common/model-service.js"></script>
|
<script src="common/model-service.js"></script>
|
||||||
<script src="common/utils-service.js"></script>
|
<script src="common/utils-service.js"></script>
|
||||||
|
<script src="common/page-service.js"></script>
|
||||||
<script src="common/notification-service.js"></script>
|
<script src="common/notification-service.js"></script>
|
||||||
<script src="common/persistence-service.js"></script>
|
<script src="common/persistence-service.js"></script>
|
||||||
<script src="common/main-controller.js"></script>
|
<script src="common/main-controller.js"></script>
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
* Encapsulates the jPlayer plugin. It watches the player service for the song to play, load or restart.
|
* Encapsulates the jPlayer plugin. It watches the player service for the song to play, load or restart.
|
||||||
* It also enables jPlayer to attach event handlers to our UI through css Selectors.
|
* It also enables jPlayer to attach event handlers to our UI through css Selectors.
|
||||||
*/
|
*/
|
||||||
angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstash.settings', 'jamstash.subsonic.service', 'jamstash.notifications', 'jamstash.persistence'])
|
angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstash.settings', 'jamstash.subsonic.service', 'jamstash.notifications', 'jamstash.persistence', 'jamstash.page'])
|
||||||
|
|
||||||
.directive('jplayer', ['player', 'globals', 'subsonic', 'notifications', '$interval', 'persistence',
|
.directive('jplayer', ['player', 'globals', 'subsonic', 'notifications', '$interval', 'persistence', 'Page',
|
||||||
function(playerService, globals, subsonic, notifications, $interval, persistence) {
|
function(playerService, globals, subsonic, notifications, $interval, persistence, Page) {
|
||||||
'use strict';
|
'use strict';
|
||||||
return {
|
return {
|
||||||
restrict: 'EA',
|
restrict: 'EA',
|
||||||
|
@ -91,6 +91,7 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
|
||||||
}, function (newSong) {
|
}, function (newSong) {
|
||||||
if(newSong !== undefined) {
|
if(newSong !== undefined) {
|
||||||
scope.currentSong = newSong;
|
scope.currentSong = newSong;
|
||||||
|
Page.setTitleSong(newSong);
|
||||||
$player.jPlayer('setMedia', {'mp3': newSong.url});
|
$player.jPlayer('setMedia', {'mp3': newSong.url});
|
||||||
if(playerService.loadSong === true) {
|
if(playerService.loadSong === true) {
|
||||||
// Do not play, only load
|
// Do not play, only load
|
||||||
|
|
|
@ -2,13 +2,15 @@ describe("jplayer directive", function() {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var element, scope, $player, playingSong, deferred,
|
var element, scope, $player, playingSong, deferred,
|
||||||
playerService, mockGlobals, subsonic, notifications, persistence, $interval;
|
playerService, mockGlobals, subsonic, notifications, persistence, Page, $interval;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
// We redefine globals because in some tests we need to alter the settings
|
// We redefine globals because in some tests we need to alter the settings
|
||||||
mockGlobals = {
|
mockGlobals = {
|
||||||
settings: {
|
settings: {
|
||||||
AutoPlay: false
|
AutoPlay: false,
|
||||||
|
NotificationSong: false,
|
||||||
|
SaveTrackPosition: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Redefined to avoid firing 'play' with a previous test song
|
// Redefined to avoid firing 'play' with a previous test song
|
||||||
|
@ -28,12 +30,13 @@ describe("jplayer directive", function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
spyOn($.fn, "jPlayer").and.callThrough();
|
spyOn($.fn, "jPlayer").and.callThrough();
|
||||||
inject(function($rootScope, $compile, _player_, _subsonic_, _notifications_, _persistence_, _$interval_, $q) {
|
inject(function($rootScope, $compile, _$interval_, $q, _player_, _subsonic_, _notifications_, _persistence_, _Page_) {
|
||||||
playerService = _player_;
|
playerService = _player_;
|
||||||
subsonic = _subsonic_;
|
subsonic = _subsonic_;
|
||||||
notifications = _notifications_;
|
notifications = _notifications_;
|
||||||
persistence = _persistence_;
|
persistence = _persistence_;
|
||||||
$interval = _$interval_;
|
$interval = _$interval_;
|
||||||
|
Page = _Page_;
|
||||||
// Compile the directive
|
// Compile the directive
|
||||||
scope = $rootScope.$new();
|
scope = $rootScope.$new();
|
||||||
element = '<div id="playdeck_1" jplayer></div>';
|
element = '<div id="playdeck_1" jplayer></div>';
|
||||||
|
@ -41,6 +44,7 @@ describe("jplayer directive", function() {
|
||||||
scope.$digest();
|
scope.$digest();
|
||||||
deferred = $q.defer();
|
deferred = $q.defer();
|
||||||
});
|
});
|
||||||
|
spyOn(Page, "setTitleSong");
|
||||||
$player = element.children('div');
|
$player = element.children('div');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -51,11 +55,12 @@ describe("jplayer directive", function() {
|
||||||
playingSong = {url: 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'};
|
playingSong = {url: 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'};
|
||||||
});
|
});
|
||||||
|
|
||||||
it("it sets jPlayer's media and stores the song for future scrobbling", function() {
|
it("it sets jPlayer's media, stores the song for future scrobbling and sets the page title with the song", function() {
|
||||||
scope.$apply();
|
scope.$apply();
|
||||||
|
|
||||||
expect($.fn.jPlayer).toHaveBeenCalledWith('setMedia', {'mp3': 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'});
|
expect($.fn.jPlayer).toHaveBeenCalledWith('setMedia', {'mp3': 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'});
|
||||||
expect(scope.currentSong).toEqual(playingSong);
|
expect(scope.currentSong).toEqual(playingSong);
|
||||||
|
expect(Page.setTitleSong).toHaveBeenCalledWith(playingSong);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("if the player service's loadSong flag is true, it does not play the song, it displays the player controls and sets the player to the song's supplied position", function() {
|
it("if the player service's loadSong flag is true, it does not play the song, it displays the player controls and sets the player to the song's supplied position", function() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue