diff --git a/.csslintrc b/.csslintrc
new file mode 100644
index 0000000..a271b01
--- /dev/null
+++ b/.csslintrc
@@ -0,0 +1 @@
+--format=compact
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..dc14e5b
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,11 @@
+{
+ "extends": "standard",
+ "env": {
+ "jquery": true
+ },
+ "rules": {
+ "indent": [2, 4, {"SwitchCase": 1}],
+ "no-undef": 0, // TODO: Set this to '2' once Javascript has been modularised.
+ "no-unused-vars": 0, // TODO: Set this to '2' once Javascript has been modularised.
+ }
+}
diff --git a/.gitignore b/.gitignore
index 1b83512..b754965 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ docs/_build/
mopidy.log*
node_modules/
nosetests.xml
+npm-debug.log
.project
*.pbxproj
*.egg-info
diff --git a/.travis.yml b/.travis.yml
index 637d177..5ce0d3d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,6 +8,9 @@ python:
env:
- TOX_ENV=py27
- TOX_ENV=flake8
+ - TOX_ENV=eslint
+ - TOX_ENV=csslint
+ - TOX_ENV=tidy
install:
- "pip install tox"
diff --git a/README.rst b/README.rst
index 1dc0007..1a9ca35 100644
--- a/README.rst
+++ b/README.rst
@@ -10,14 +10,26 @@ Mopidy-MusicBox-Webclient
:target: https://pypi.python.org/pypi/Mopidy-MusicBox-Webclient/
:alt: Number of PyPI downloads
-With Mopidy MusicBox Webclient, you can play your music on your computer (`Rapsberry Pi `_)
+.. image:: https://img.shields.io/travis/pimusicbox/mopidy-musicbox-webclient/develop.svg?style=flat
+ :target: https://travis-ci.org/rectalogic/mopidy-pandora
+ :alt: Travis CI build status
+
+.. image:: https://img.shields.io/coveralls/pimusicbox/mopidy-musicbox-webclient/develop.svg?style=flat
+ :target: https://coveralls.io/r/rectalogic/mopidy-pandora?branch=develop
+ :alt: Test coverage
+
+.. image:: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat
+ :target: http://standardjs.com/
+ :alt: JavaScript Standard Style
+
+With Mopidy MusicBox Webclient (MMW), you can play your music on your computer (`Rapsberry Pi `_)
and remotely control it using your computer, tablet or phone.
-This is a responsive webclient especially written for Mopidy, a music server. Responsive, so it works on desktop and
-mobile browsers. You can browse, search and play albums, artists, playlists, and it has cover art from Last.fm.
+This is a responsive webclient especially written for `Mopidy `_: a music server that can play
+music from many different sources including Spotify, Google Music, SoundCloud, etc. or from your hard drive. The
+webclient is responsive, so it works on desktop and mobile browsers. You can browse, search and play albums, artists,
+playlists, and it has cover art from Last.fm.
-`Mopidy `_ is a music server which can play music from Spotify, Google Music, SoundCloud, etc.
-or from your hard drive.
If you want to run Mopidy with this webclient on a Raspberry Pi, do yourself a favor and use my custom built SD-image:
`Pi MusicBox `_.
@@ -30,7 +42,7 @@ Installation
Install by running::
- pip install Mopidy-MusicBox-Webclient
+ pip install mopidy-musicbox-webclient
Alternatively, clone the repository and run ``sudo python setup.py install`` from within the project directory. e.g. ::
@@ -58,6 +70,11 @@ Project resources
Changelog
=========
+v2.3.0 (UNRELEASED)
+-------------------
+
+- Enhance build workflow to include style checks and syntax validation for HTML, CSS, and Javascript.
+
v2.2.0 (2016-03-01)
-------------------
diff --git a/mopidy_musicbox_webclient/static/js/controls.js b/mopidy_musicbox_webclient/static/js/controls.js
index 2638886..a7821bb 100644
--- a/mopidy_musicbox_webclient/static/js/controls.js
+++ b/mopidy_musicbox_webclient/static/js/controls.js
@@ -35,7 +35,7 @@ function playBrowsedTracks(action, trackIndex) {
mopidy.playback.play({'tl_track': tlTracks[playIndex]});
}
};
-
+
switch (action) {
case PLAY_NOW:
case PLAY_NEXT:
@@ -65,7 +65,7 @@ function playTrack(action) {
if (action == PLAY_NOW && divid == 'search') {
action = PLAY_NOW_SEARCH;
}
-
+
$('#popupTracks').popup('close');
$('#controlspopup').popup('close');
toast('Loading...');
@@ -142,7 +142,7 @@ function playTrackByUri(track_uri, playlist_uri) {
toast('Loading...');
mopidy.tracklist.add({'uris': [playlist_uri]}).then(function(tlTracks) {
- // Can fail for all sorts of reasons. If so, just add individually.
+ // Can fail for all sorts of reasons. If so, just add individually.
if (tlTracks.length === 0) {
var trackUris = getTracksFromUri(playlist_uri, false);
mopidy.tracklist.add({'uris': trackUris}).then(findAndPlayTrack);
@@ -474,7 +474,7 @@ function playStreamUri(uri) {
}
function getCurrentlyPlaying() {
- $('#streamuriinput').val(songdata.track.uri);
+ $('#streamuriinput').val(songdata.track.uri);
var name = songdata.track.name;
if (songdata.track.artists) {
var artistStr = artistsToString(songdata.track.artists);
@@ -482,7 +482,7 @@ function getCurrentlyPlaying() {
name = artistStr + ' - ' + name;
}
}
- $('#streamnameinput').val(name);
+ $('#streamnameinput').val(name);
return true;
}
@@ -526,7 +526,7 @@ function getPlaylistFull(uri) {
}
function getFavourites() {
- return getPlaylistByName(STREAMS_PLAYLIST_NAME,
+ return getPlaylistByName(STREAMS_PLAYLIST_NAME,
STREAMS_PLAYLIST_SCHEME,
true).then(function(playlist) {
if (playlist) {
@@ -593,7 +593,7 @@ function showFavourites() {
return;
}
var tmp = '';
-
+
$.cookie.json = true;
if ($.cookie('streamUris')) {
tmp = '';
@@ -609,7 +609,7 @@ function showFavourites() {
}
}
$('#streamuristable').html(tmp);
- });
+ });
}
// TODO: Remove this upgrade path in next major release.
diff --git a/mopidy_musicbox_webclient/static/js/gui.js b/mopidy_musicbox_webclient/static/js/gui.js
index 827dc13..d1be849 100644
--- a/mopidy_musicbox_webclient/static/js/gui.js
+++ b/mopidy_musicbox_webclient/static/js/gui.js
@@ -235,7 +235,7 @@ function initSocketevents() {
getPlaylists();
getUriSchemes().then(function() {
showFavourites();
- });
+ });
getBrowseDir();
getSearchSchemes();
showLoading(false);
@@ -580,7 +580,7 @@ $(document).ready(function(event) {
return true;
}
});
-
+
if ($(window).width() < 980) {
$("#panel").panel("close");
diff --git a/mopidy_musicbox_webclient/static/js/process_ws.js b/mopidy_musicbox_webclient/static/js/process_ws.js
index d8cfeeb..605a398 100644
--- a/mopidy_musicbox_webclient/static/js/process_ws.js
+++ b/mopidy_musicbox_webclient/static/js/process_ws.js
@@ -240,7 +240,7 @@ function processAlbumResults(resultArr) {
return;
}
customTracklists[resultArr.uri] = resultArr;
-
+
albumTracksToTable(resultArr, ALBUM_TABLE, resultArr.uri);
var albumname = getAlbum(resultArr);
var artistname = getArtist(resultArr);
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..ee6c8e3
--- /dev/null
+++ b/package.json
@@ -0,0 +1,33 @@
+{
+ "name": "Mopidy-MusicBox-Webclient",
+ "version": "2.1.1",
+ "description": "Mopidy MusicBox web extension",
+ "main": "gui.js",
+ "directories": {
+ "test": "tests"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "eslint": "eslint mopidy_musicbox_webclient/static/js/**.js",
+ "csslint": "csslint mopidy_musicbox_webclient/static/css/**.css",
+ "tidy": "node tidy.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/pimusicbox/mopidy-musicbox-webclient.git"
+ },
+ "author": "Wouter van Wijk",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/pimusicbox/mopidy-musicbox-webclient/issues"
+ },
+ "devDependencies": {
+ "eslint": "latest",
+ "eslint-config-standard": "latest",
+ "eslint-plugin-standard": "latest",
+ "eslint-plugin-promise": "latest",
+ "csslint": "latest",
+ "tidy-html5": "latest"
+ },
+ "homepage": "https://github.com/pimusicbox/mopidy-musicbox-webclient#readme"
+}
diff --git a/tidy.js b/tidy.js
new file mode 100644
index 0000000..bf857e0
--- /dev/null
+++ b/tidy.js
@@ -0,0 +1,88 @@
+var tidy = require('tidy-html5').tidy_html5
+
+var fs = require('fs')
+
+// Traverse directory structure looking for 'html' or 'htm' files.
+var getAllHtmlFilesFromFolder = function (dir) {
+ var filesystem = require('fs')
+ var results = []
+ filesystem.readdirSync(dir).forEach(function (file) {
+ file = dir + '/' + file
+ var stat = filesystem.statSync(file)
+
+ if (stat && stat.isDirectory()) {
+ results = results.concat(getAllHtmlFilesFromFolder(file))
+ } else {
+ var extension = file.substr(file.lastIndexOf('.') + 1).toUpperCase()
+ if (extension === 'HTM' || extension === 'HTML') {
+ results.push(file)
+ }
+ }
+ })
+ return results
+}
+
+// Read file contents.
+function readFiles (dirname, onFileContent) {
+ var filenames = getAllHtmlFilesFromFolder(dirname)
+ filenames.forEach(function (filename) {
+ fs.readFile(filename, 'utf-8', function (err, content) {
+ if (err) {
+ throw (err)
+ }
+ onFileContent(filename, content)
+ })
+ })
+}
+
+var util = require('util')
+
+// Trap stderr output so that we can detect parsing errors.
+function hook_stderr (callback) {
+ var old_write = process.stderr.write
+
+ process.stderr.write = (function (write) {
+ return function (string, encoding, fd) {
+ write.apply(process.stdout, arguments)
+ callback(string, encoding, fd)
+ }
+ })(process.stderr.write)
+
+ return function () {
+ process.stderr.write = old_write
+ }
+}
+
+var unhook = hook_stderr(function (string, encoding, fd) {
+ if (string.indexOf('Error:') > 0) {
+ errors.push(string)
+ }
+})
+
+var errorsOccurred = false
+var errors = []
+
+// Exit with status 1 so that tox can detect errors.
+process.on('exit', function () {
+ if (errorsOccurred === true) {
+ process.exit(1)
+ }
+})
+
+// Start linter
+function processFiles (callback) {
+ console.log('Starting HTML linter...')
+ readFiles('mopidy_musicbox_webclient/static', function (filename, content) {
+ console.log('\n' + filename)
+ var result = tidy(content, {'quiet': true})
+ if (errors.length > 0) {
+ console.error('\nHTML errors detected:\n' + errors.join(''))
+ errors = []
+ errorsOccurred = true
+ }
+ })
+}
+
+processFiles(function () {
+ unhook()
+})
diff --git a/tox.ini b/tox.ini
index ead2ff1..96a5099 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = py27, flake8
+envlist = py27, flake8, eslint, csslint, tidy
[testenv]
deps =
@@ -13,11 +13,41 @@ commands =
--basetemp={envtmpdir} \
--junit-xml=xunit-{envname}.xml \
--cov=mopidy_musicbox_webclient --cov-report=term-missing \
- {posargs}
+ {posargs:tests/}
[testenv:flake8]
deps =
flake8
flake8-import-order
skip_install = true
-commands = flake8
+commands = flake8 {posargs:mopidy_musicbox_webclient}
+
+[testenv:eslint]
+whitelist_externals =
+ /bin/bash
+deps =
+ nodeenv
+skip_install = true
+commands =
+ - nodeenv --prebuilt {toxworkdir}/node_env
+ bash -c '. {toxworkdir}/node_env/bin/activate; npm install; npm run eslint'
+
+[testenv:csslint]
+whitelist_externals =
+ /bin/bash
+deps =
+ nodeenv
+skip_install = true
+commands =
+ - nodeenv --prebuilt {toxworkdir}/node_env
+ bash -c '. {toxworkdir}/node_env/bin/activate; npm install; npm run csslint'
+
+[testenv:tidy]
+whitelist_externals =
+ /bin/bash
+deps =
+ nodeenv
+skip_install = true
+commands =
+ - nodeenv --prebuilt {toxworkdir}/node_env
+ bash -c '. {toxworkdir}/node_env/bin/activate; npm install; npm run tidy'