Enable navigation with a basic router

This commit is contained in:
An Phan 2016-07-11 01:55:20 +08:00
parent d2a6e04bb0
commit 032b9bee7c
No known key found for this signature in database
GPG key ID: 05536BB4BCDC02A2
17 changed files with 162 additions and 82 deletions

View file

@ -38,6 +38,7 @@ import { event, showOverlay, hideOverlay, loadMainView, forceReloadWindow, url }
import { sharedStore, queueStore, songStore, userStore, preferenceStore as preferences } from './stores';
import { playback, ls } from './services';
import { focusDirective, clickawayDirective } from './directives';
import router from './router';
export default {
components: { siteHeader, siteFooter, mainWrapper, overlay, loginForm, editSongsForm },
@ -199,6 +200,8 @@ export default {
* Parse song ID from permalink and play.
*/
'koel:ready': () => {
router.init();
const songId = url.parseSongId();
if (!songId) return;
const song = songStore.byId(songId);
@ -211,6 +214,8 @@ export default {
} else {
playback.queueAndPlay(song);
}
},
});
},

View file

@ -13,7 +13,7 @@
<span class="meta" v-show="meta.songCount">
by
<a class="artist" v-if="isNormalArtist" @click.prevent="viewArtistDetails(album.artist)">{{ album.artist.name }}</a>
<a class="artist" v-if="isNormalArtist" :href="'/#!/artist/' + album.artist.id">{{ album.artist.name }}</a>
<span class="nope" v-else>{{ album.artist.name }}</span>
{{ meta.songCount | pluralize('song') }}
@ -67,13 +67,12 @@ import { pluralize, event, loadMainView } from '../../../utils';
import { albumStore, artistStore, sharedStore } from '../../../stores';
import { playback, download, albumInfo as albumInfoService } from '../../../services';
import hasSongList from '../../../mixins/has-song-list';
import artistAlbumDetails from '../../../mixins/artist-album-details';
import albumInfo from '../extra/album-info.vue';
import soundBar from '../../shared/sound-bar.vue';
export default {
name: 'main-wrapper--main-content--album',
mixins: [hasSongList, artistAlbumDetails],
mixins: [hasSongList],
components: { albumInfo, soundBar },
filters: { pluralize },

View file

@ -58,9 +58,10 @@
<script>
import isMobile from 'ismobilejs';
import { pluralize, event, loadMainView } from '../../../utils';
import { pluralize, event } from '../../../utils';
import { playlistStore, sharedStore } from '../../../stores';
import { playback, download } from '../../../services';
import router from '../../../router';
import hasSongList from '../../../mixins/has-song-list';
export default {
@ -109,8 +110,8 @@ export default {
// any property reference error.
this.playlist = playlistStore.stub;
// Switch back to Queue screen
loadMainView('queue');
// Switch back to Home screen
router.go('/#!/home');
});
},

View file

@ -26,6 +26,7 @@
<script>
import { settingStore } from '../../../stores';
import { parseValidationError, forceReloadWindow, event, showOverlay, hideOverlay } from '../../../utils';
import router from '../../../router';
export default {
data() {
@ -42,6 +43,8 @@ export default {
showOverlay();
settingStore.update().then(() => {
// Make sure we're back to home first.
router.go('/#!/home');
forceReloadWindow();
}).catch(r => {
let msg = 'Unknown error.';

View file

@ -5,28 +5,24 @@
<ul class="menu">
<li>
<a class="home" :class="[currentView == 'home' ? 'active' : '']"
@click.prevent="loadMainView('home')">Home</a>
<a class="home" :class="[currentView == 'home' ? 'active' : '']" href="/#!/home">Home</a>
</li>
<li>
<a class="queue"
:class="[currentView == 'queue' ? 'active' : '']"
@click.prevent="loadMainView('queue')"
href="/#!/queue"
@dragleave="removeDroppableState"
@dragover.prevent="allowDrop"
@drop.stop.prevent="handleDrop">Current Queue</a>
</li>
<li>
<a class="songs" :class="[currentView == 'songs' ? 'active' : '']"
@click.prevent="loadMainView('songs')">All Songs</a>
<a class="songs" :class="[currentView == 'songs' ? 'active' : '']" href="/#!/songs">All Songs</a>
</li>
<li>
<a class="albums" :class="[currentView == 'albums' ? 'active' : '']"
@click.prevent="loadMainView('albums')">Albums</a>
<a class="albums" :class="[currentView == 'albums' ? 'active' : '']" href="/#!/albums">Albums</a>
</li>
<li>
<a class="artists" :class="[currentView == 'artists' ? 'active' : '']"
@click.prevent="loadMainView('artists')">Artists</a>
<a class="artists" :class="[currentView == 'artists' ? 'active' : '']" href="/#!/artists">Artists</a>
</li>
</ul>
</section>
@ -38,12 +34,10 @@
<ul class="menu">
<li>
<a class="settings" :class="[currentView == 'settings' ? 'active' : '']"
@click.prevent="loadMainView('settings')">Settings</a>
</li>
<a class="settings" :class="[currentView == 'settings' ? 'active' : '']" href="/#!/settings">Settings</a>
</li>
<li>
<a class="users" :class="[currentView == 'users' ? 'active' : '']"
@click.prevent="loadMainView('users')">Users</a>
<a class="users" :class="[currentView == 'users' ? 'active' : '']" href="/#!/users">Users</a>
</li>
</ul>
</section>

View file

@ -1,6 +1,6 @@
<template>
<li @dblclick.prevent="edit" class="playlist" :class="[type, editing ? 'editing' : '']">
<a @click.prevent="load"
<a :href="isFavorites ? '/#!/favorites' : '/#!/playlist/' + playlist.id"
@dragleave="removeDroppableState"
@dragover.prevent="allowDrop"
@drop.stop.prevent="handleDrop"
@ -21,7 +21,7 @@
<script>
import $ from 'jquery';
import { event, loadPlaylistView, loadFavoritesView } from '../../../utils';
import { event } from '../../../utils';
import { songStore, playlistStore, favoriteStore } from '../../../stores';
export default {
@ -47,17 +47,6 @@ export default {
},
methods: {
/**
* Load songs in the current playlist.
*/
load() {
if (this.isFavorites) {
loadFavoritesView();
} else {
loadPlaylistView(this.playlist);
}
},
/**
* Show the form to edit the playlist.
*/

View file

@ -29,8 +29,8 @@
</template>
<script>
import { loadPlaylistView } from '../../../utils';
import { playlistStore, favoriteStore } from '../../../stores';
import router from '../../../router';
import playlistItem from './playlist-item.vue';
@ -58,7 +58,7 @@ export default {
playlistStore.store(this.newName).then(p => {
this.newName = '';
// Activate the new playlist right away
this.$nextTick(() => loadPlaylistView(p));
this.$nextTick(() => router.go(`/#!/playlist/${p.id}`));
});
},
},

View file

@ -28,8 +28,9 @@
<script>
import { assign } from 'lodash';
import { pluralize, event, loadPlaylistView } from '../../utils';
import { pluralize, event } from '../../utils';
import { playlistStore } from '../../stores';
import router from '../../router';
import songMenuMethods from '../../mixins/song-menu-methods';
export default {
@ -72,7 +73,7 @@ export default {
playlistStore.store(this.newPlaylistName, this.songs).then(p => {
this.newPlaylistName = '';
// Activate the new playlist right away
this.$nextTick(() => loadPlaylistView(p));
this.$nextTick(() => router.go(`/#!/playlist/${p.id}`));
});
this.close();

View file

@ -7,12 +7,9 @@
</span>
<footer>
<div class="info">
<a class="name" @click.prevent="viewAlbumDetails(album)">{{ album.name }}</a>
<a class="name" :href="'/#!/album/' + album.id">{{ album.name }}</a>
<span class="sep">by</span>
<a class="artist" v-if="isNormalArtist"
@click.prevent="viewArtistDetails(album.artist)">
{{ album.artist.name }}
</a>
<a class="artist" v-if="isNormalArtist" :href="'/#!/artist/' + album.artist.id">{{ album.artist.name }}</a>
<span class="artist nope" v-else>{{ album.artist.name }}</span>
</div>
<p class="meta">
@ -43,12 +40,10 @@ import $ from 'jquery';
import { pluralize } from '../../utils';
import { queueStore, artistStore, sharedStore } from '../../stores';
import { playback, download } from '../../services';
import artistAlbumDetails from '../../mixins/artist-album-details';
export default {
name: 'shared--album-item',
props: ['album'],
mixins: [artistAlbumDetails],
filters: { pluralize },
data() {

View file

@ -7,7 +7,7 @@
</span>
<footer>
<div class="info">
<a class="name" @click.prevent="viewArtistDetails(artist)">{{ artist.name }}</a>
<a class="name" :href="'/#!/artist/' + artist.id">{{ artist.name }}</a>
</div>
<p class="meta">
<span class="left">
@ -34,12 +34,10 @@ import $ from 'jquery';
import { pluralize } from '../../utils';
import { artistStore, queueStore, sharedStore } from '../../stores';
import { playback, download } from '../../services';
import artistAlbumDetails from '../../mixins/artist-album-details';
export default {
name: 'shared--artist-item',
props: ['artist'],
mixins: [artistAlbumDetails],
filters: { pluralize },
data() {

View file

@ -14,7 +14,7 @@
class="play-count"></span>
{{ song.title }}
<span class="by">
<a href="#" @click.prevent="viewArtistDetails(song.artist)">{{ song.artist.name }}</a> -
<a :href="'/#!/artist/' + song.artist.id">{{ song.artist.name }}</a> -
{{ song.playCount | pluralize('play') }}
</span>
</span>
@ -25,12 +25,10 @@
import { pluralize } from '../../utils';
import { queueStore } from '../../stores';
import { playback } from '../../services';
import artistAlbumDetails from '../../mixins/artist-album-details';
export default {
name: 'shared--home-song-item',
props: ['song', 'topPlayCount'],
mixins: [artistAlbumDetails],
filters: { pluralize },
methods: {

View file

@ -33,16 +33,16 @@
import $ from 'jquery';
import songMenuMethods from '../../mixins/song-menu-methods';
import artistAlbumDetails from '../../mixins/artist-album-details';
import { event, isClipboardSupported, copyText } from '../../utils';
import { sharedStore, songStore, queueStore, userStore, playlistStore } from '../../stores';
import { playback, download } from '../../services';
import router from '../../router';
export default {
name: 'song-menu',
props: ['songs'],
mixins: [songMenuMethods, artistAlbumDetails],
mixins: [songMenuMethods],
data() {
return {
@ -128,6 +128,22 @@ export default {
this.close();
},
/**
* Load the album details screen.
*/
viewAlbumDetails(album) {
router.go(`/#!/album/${album.id}`);
this.close();
},
/**
* Load the artist details screen.
*/
viewArtistDetails(artist) {
router.go(`/#!/artist/${artist.id}`);
this.close();
},
download() {
download.fromSongs(this.songs);
this.close();

View file

@ -50,8 +50,8 @@
<script>
import { clone, assign } from 'lodash';
import { loadMainView } from '../../utils';
import { userStore } from '../../stores';
import router from '../../router';
export default {
props: ['user'],
@ -82,7 +82,7 @@ export default {
*/
edit() {
if (this.isCurrentUser) {
loadMainView('profile');
router.go('/#!/profile');
return;
}

View file

@ -2,7 +2,6 @@ import Vue from 'vue';
import { event } from './utils';
import { http } from './services';
/**
* For Ancelot, the ancient cross of war
* for the holy town of Gods

View file

@ -1,23 +0,0 @@
/**
* Add necessary functionalities into a view that triggers artist or album details views.
*/
import { loadAlbumView, loadArtistView } from './../utils';
export default {
methods: {
/**
* Load the album details screen.
*/
viewAlbumDetails(album) {
loadAlbumView(album);
},
/**
* Load the artist details screen.
*/
viewArtistDetails(artist) {
loadArtistView(artist);
},
},
};

View file

@ -0,0 +1,103 @@
import { loadMainView } from './utils';
import { artistStore, albumStore, songStore, playlistStore } from './stores';
export default {
routes: {
'/home'() {
loadMainView('home');
},
'/queue'() {
loadMainView('queue');
},
'/songs'() {
loadMainView('songs');
},
'/albums'() {
loadMainView('albums');
},
'/album/(\\d+)'(id) {
const album = albumStore.byId(Number.parseInt(id, 10));
if (album) {
loadMainView('album', album);
}
},
'/artists'() {
loadMainView('artists');
},
'/artist/(\\d+)'(id) {
const artist = artistStore.byId(Number.parseInt(id, 10));
if (artist) {
loadMainView('artist', artist);
}
},
'/favorites'() {
loadMainView('favorites');
},
'/playlist/(\\d+)'(id) {
const playlist = playlistStore.byId(Number.parseInt(id, 10));
if (playlist) {
loadMainView('playlist', playlist);
}
},
'/settings'() {
loadMainView('settings');
},
'/users'() {
loadMainView('users');
},
'/profile'() {
loadMainView('profile');
},
'/login'() {
},
'/song/([a-z0-9]{32})'(id) {
console.log(id)
},
},
init() {
this.loadState();
window.addEventListener('popstate', () => this.loadState(), true);
},
loadState() {
if (!window.location.hash) {
return this.go('/#!/home');
}
Object.keys(this.routes).forEach(route => {
const matches = window.location.hash.match(new RegExp(`^#!${route}$`));
if (matches) {
const [, ...params] = matches;
this.routes[route](...params);
return false;
}
});
},
/**
* Navigate to a (relative) path.
*
* @param {String} path
*/
go(path) {
if (path[0] !== '/') {
path = `/${path}`;
}
document.location.href = `${document.location.origin}${path}`;
},
};

View file

@ -3,9 +3,10 @@ import $ from 'jquery';
import plyr from 'plyr';
import Vue from 'vue';
import { event, loadMainView } from '../utils';
import { event } from '../utils';
import { queueStore, sharedStore, userStore, songStore, artistStore, preferenceStore as preferences } from '../stores';
import config from '../config';
import router from '../router';
export const playback = {
player: null,
@ -347,11 +348,12 @@ export const playback = {
queueStore.queue(songs, true);
loadMainView('queue');
// Wrap this inside a nextTick() to wait for the DOM to complete updating
// and then play the first song in the queue.
Vue.nextTick(() => this.play(queueStore.first));
Vue.nextTick(() => {
router.go('/#!/queue');
this.play(queueStore.first);
});
},
/**