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:
Hyzual 2015-01-11 12:30:10 +01:00
parent 0646b02e94
commit c478f0116f
7 changed files with 138 additions and 47 deletions

View file

@ -1,6 +1,6 @@
angular.module('JamStash')
.controller('AppController', ['$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) {
.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, Page) {
'use strict';
$rootScope.settings = globals.settings;
@ -13,6 +13,7 @@ angular.module('JamStash')
$rootScope.SelectedMusicFolder = "";
$rootScope.unity = null;
$scope.Page = Page;
$rootScope.loggedIn = function () {
if (globals.settings.Server !== '' && globals.settings.Username !== '' && globals.settings.Password !== '') {
return true;

View 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;
}
};
}]);

View 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');
});
});

View file

@ -251,41 +251,6 @@ angular.module('jamstash.utils', ['jamstash.settings'])
var u = strurl.substring(0, strurl.indexOf('?'));
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) {
if (typeof (str) !== 'string') { return false; }
var x = str.split('.');

View file

@ -1,12 +1,12 @@
<!DOCTYPE HTML>
<html lang="en" ng-app="JamStash">
<html lang="en" ng-app="JamStash" ng-controller="AppController">
<head>
<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="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 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 rel="icon" href="images/favicon_48x48.png" sizes="48x48"/>
<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="" rel="stylesheet" type="text/css" data-name="theme" />
</head>
<body ng-controller="AppController">
<body>
<div id="container">
<div id="header">
<div id="messages">
@ -102,6 +102,7 @@
<script src="settings/settings-service.js"></script>
<script src="common/model-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/persistence-service.js"></script>
<script src="common/main-controller.js"></script>

View file

@ -4,10 +4,10 @@
* 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.
*/
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',
function(playerService, globals, subsonic, notifications, $interval, persistence) {
.directive('jplayer', ['player', 'globals', 'subsonic', 'notifications', '$interval', 'persistence', 'Page',
function(playerService, globals, subsonic, notifications, $interval, persistence, Page) {
'use strict';
return {
restrict: 'EA',
@ -91,6 +91,7 @@ angular.module('jamstash.player.directive', ['jamstash.player.service', 'jamstas
}, function (newSong) {
if(newSong !== undefined) {
scope.currentSong = newSong;
Page.setTitleSong(newSong);
$player.jPlayer('setMedia', {'mp3': newSong.url});
if(playerService.loadSong === true) {
// Do not play, only load

View file

@ -2,13 +2,15 @@ describe("jplayer directive", function() {
'use strict';
var element, scope, $player, playingSong, deferred,
playerService, mockGlobals, subsonic, notifications, persistence, $interval;
playerService, mockGlobals, subsonic, notifications, persistence, Page, $interval;
beforeEach(function() {
// We redefine globals because in some tests we need to alter the settings
mockGlobals = {
settings: {
AutoPlay: false
AutoPlay: false,
NotificationSong: false,
SaveTrackPosition: false
}
};
// Redefined to avoid firing 'play' with a previous test song
@ -28,12 +30,13 @@ describe("jplayer directive", function() {
});
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_;
subsonic = _subsonic_;
notifications = _notifications_;
persistence = _persistence_;
$interval = _$interval_;
Page = _Page_;
// Compile the directive
scope = $rootScope.$new();
element = '<div id="playdeck_1" jplayer></div>';
@ -41,6 +44,7 @@ describe("jplayer directive", function() {
scope.$digest();
deferred = $q.defer();
});
spyOn(Page, "setTitleSong");
$player = element.children('div');
});
@ -51,11 +55,12 @@ describe("jplayer directive", function() {
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();
expect($.fn.jPlayer).toHaveBeenCalledWith('setMedia', {'mp3': 'https://gantry.com/antemarital/vigorless?a=oropharyngeal&b=killcrop#eviscerate'});
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() {