Pretty URLs for albums URLs as well

This commit is contained in:
Lucas Verney 2016-08-12 13:57:53 +02:00
parent e232ec8c16
commit 216f2e7348
13 changed files with 65 additions and 104 deletions

View File

@ -19,6 +19,7 @@ export default class Albums extends Component {
} }
// Set grid props // Set grid props
const artists = this.props.artists;
const grid = { const grid = {
isFetching: this.props.isFetching, isFetching: this.props.isFetching,
items: this.props.albums, items: this.props.albums,
@ -26,6 +27,14 @@ export default class Albums extends Component {
itemsLabel: "app.common.album", itemsLabel: "app.common.album",
subItemsType: "tracks", subItemsType: "tracks",
subItemsLabel: "app.common.track", subItemsLabel: "app.common.track",
buildLinkTo: (itemType, item) => {
let artist = encodeURIComponent(item.get("artist"));
if (artists && artists.size > 0) {
const id = item.get("artist");
artist = encodeURIComponent(id + "-" + artists.getIn([id, "name"]));
}
return "/artist/" + artist + "/album/" + item.get("id") + "-" + encodeURIComponent(item.get("name"));
},
}; };
return ( return (
@ -40,5 +49,6 @@ Albums.propTypes = {
error: PropTypes.string, error: PropTypes.string,
isFetching: PropTypes.bool.isRequired, isFetching: PropTypes.bool.isRequired,
albums: PropTypes.instanceOf(Immutable.List).isRequired, albums: PropTypes.instanceOf(Immutable.List).isRequired,
artists: PropTypes.instanceOf(Immutable.Map),
pagination: PropTypes.object.isRequired, pagination: PropTypes.object.isRequired,
}; };

View File

@ -27,7 +27,7 @@ export default class Artists extends Component {
subItemsType: "albums", subItemsType: "albums",
subItemsLabel: "app.common.album", subItemsLabel: "app.common.album",
buildLinkTo: (itemType, item) => { buildLinkTo: (itemType, item) => {
return "/" + itemType + "/" + item.get("id") + "-" + encodeURIComponent(item.get("name")); return "/artist/" + item.get("id") + "-" + encodeURIComponent(item.get("name"));
}, },
}; };

View File

@ -91,7 +91,11 @@ function _uglyFixes(jsonData) {
return songs.map(function (song) { return songs.map(function (song) {
// Fix for cdata left in artist and album // Fix for cdata left in artist and album
song.artist.name = song.artist.cdata; song.artist.name = song.artist.cdata;
delete(song.artist.cdata);
delete(song.artist.toString);
song.album.name = song.album.cdata; song.album.name = song.album.cdata;
delete(song.album.cdata);
delete(song.album.toString);
return song; return song;
}); });
}; };
@ -105,6 +109,11 @@ function _uglyFixes(jsonData) {
album.name = album.name + " [Disk " + album.disk + "]"; album.name = album.name + " [Disk " + album.disk + "]";
} }
// Fix for cdata left in artist
album.artist.name = album.artist.cdata;
delete(album.artist.cdata);
delete(album.artist.toString);
// Move songs one node top // Move songs one node top
if (album.tracks.song) { if (album.tracks.song) {
album.tracks = album.tracks.song; album.tracks = album.tracks.song;

View File

@ -10,7 +10,6 @@ import SimpleLayout from "./components/layouts/Simple";
import SidebarLayout from "./components/layouts/Sidebar"; import SidebarLayout from "./components/layouts/Sidebar";
import ArtistPage from "./views/ArtistPage"; import ArtistPage from "./views/ArtistPage";
import ArtistsPage from "./views/ArtistsPage"; import ArtistsPage from "./views/ArtistsPage";
import AlbumPage from "./views/AlbumPage";
import AlbumsPage from "./views/AlbumsPage"; import AlbumsPage from "./views/AlbumsPage";
import BrowsePage from "./views/BrowsePage"; import BrowsePage from "./views/BrowsePage";
import DiscoverPage from "./views/DiscoverPage"; import DiscoverPage from "./views/DiscoverPage";
@ -31,9 +30,9 @@ export default (
<Route path="discover" component={DiscoverPage} /> <Route path="discover" component={DiscoverPage} />
<Route path="browse" component={BrowsePage} /> <Route path="browse" component={BrowsePage} />
<Route path="artists" component={ArtistsPage} /> <Route path="artists" component={ArtistsPage} />
<Route path="artist/:id" component={ArtistPage} /> <Route path="artist/:artist" component={ArtistPage} />
<Route path="albums" component={AlbumsPage} /> <Route path="albums" component={AlbumsPage} />
<Route path="album/:id" component={AlbumPage} /> <Route path="artist/:artist/album/:album" component={ArtistPage} />
<Route path="songs" component={SongsPage} /> <Route path="songs" component={SongsPage} />
<Route path="playlist" component={PlaylistPage} /> <Route path="playlist" component={PlaylistPage} />
<IndexRoute component={HomePage} /> <IndexRoute component={HomePage} />

View File

@ -1,63 +0,0 @@
import React, { Component } from "react";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import Immutable from "immutable";
import * as actionCreators from "../actions";
import Album from "../components/Album";
// TODO: AlbumPage should be scrolled ArtistPage
export class AlbumPage extends Component {
componentWillMount() {
// Load the data
this.props.actions.loadAlbums({
pageNumber: 1,
filter: this.props.params.id,
include: ["songs"],
});
}
render() {
if (this.props.album) {
return (
<Album album={this.props.album} songs={this.props.songs} />
);
}
return (
<div></div>
); // TODO: Loading + error
}
}
const mapStateToProps = (state, ownProps) => {
const albums = state.api.entities.get("album");
let album = undefined;
let songs = new Immutable.List();
if (albums) {
// Get artist
album = albums.find(
item => item.get("id") == ownProps.params.id
);
// Get songs
const tracks = album.get("tracks");
if (Immutable.List.isList(tracks)) {
songs = new Immutable.List(
tracks.map(
id => state.api.entities.getIn(["track", id])
)
);
}
}
return {
album: album,
songs: songs,
};
};
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(actionCreators, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(AlbumPage);

View File

@ -56,7 +56,7 @@ class AlbumsPageIntl extends Component {
const error = handleErrorI18nObject(this.props.error, formatMessage, albumsMessages); const error = handleErrorI18nObject(this.props.error, formatMessage, albumsMessages);
return ( return (
<Albums isFetching={this.props.isFetching} error={error} albums={this.props.albumsList} pagination={pagination} /> <Albums isFetching={this.props.isFetching} error={error} albums={this.props.albumsList} artists={this.props.artistsList} pagination={pagination} />
); );
} }
} }
@ -67,15 +67,21 @@ AlbumsPageIntl.propTypes = {
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
let albumsList = new Immutable.List(); let albumsList = new Immutable.List();
let artistsList = new Immutable.Map();
if (state.paginated.type == "album" && state.paginated.result.size > 0) { if (state.paginated.type == "album" && state.paginated.result.size > 0) {
albumsList = state.paginated.result.map( albumsList = state.paginated.result.map(
id => state.entities.getIn(["entities", "album", id]) id => state.entities.getIn(["entities", "album", id])
); );
albumsList.forEach(function (album) {
const albumArtist = album.get("artist");
artistsList = artistsList.set(albumArtist, state.entities.getIn(["entities", "artist", albumArtist]));
});
} }
return { return {
isFetching: state.entities.isFetching, isFetching: state.entities.isFetching,
error: state.entities.error, error: state.entities.error,
albumsList: albumsList, albumsList: albumsList,
artistsList: artistsList,
currentPage: state.paginated.currentPage, currentPage: state.paginated.currentPage,
nPages: state.paginated.nPages, nPages: state.paginated.nPages,
}; };

View File

@ -26,7 +26,7 @@ const artistMessages = defineMessages(messagesMap(Array.concat([], APIMessages))
*/ */
class ArtistPageIntl extends Component { class ArtistPageIntl extends Component {
componentWillMount() { componentWillMount() {
const id = filterInt(this.props.params.id.split("-")[0]); const id = filterInt(this.props.params.artist.split("-")[0]);
if (isNaN(id)) { if (isNaN(id)) {
// Redirect to homepage // Redirect to homepage
this.context.router.replace({ this.context.router.replace({
@ -65,7 +65,7 @@ ArtistPageIntl.contextTypes = {
}; };
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
const id = ownProps.params.id.split("-")[0]; const id = ownProps.params.artist.split("-")[0];
// Get artist // Get artist
let artist = state.entities.getIn(["entities", "artist", id]); let artist = state.entities.getIn(["entities", "artist", id]);
let albums = new Immutable.List(); let albums = new Immutable.List();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
!function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="./",t(0)}({0:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(636);Object.keys(r).forEach(function(e){"default"!==e&&"__esModule"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return r[e]}})})},636:function(e,t){!function(t,n){function r(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x<style>"+t+"</style>",r.insertBefore(n.lastChild,r.firstChild)}function a(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,s(t)}function c(e){var t=E[e[v]];return t||(t={},y++,e[v]=y,E[y]=t),t}function i(e,t,r){if(t||(t=n),f)return t.createElement(e);r||(r=c(t));var a;return a=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!a.canHaveChildren||p.test(e)||a.tagUrn?a:r.frag.appendChild(a)}function l(e,t){if(e||(e=n),f)return e.createDocumentFragment();t=t||c(e);for(var r=t.frag.cloneNode(),o=0,i=a(),l=i.length;o<l;o++)r.createElement(i[o]);return r}function u(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+a().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function s(e){e||(e=n);var t=c(e);return!b.shivCSS||d||t.hasCSS||(t.hasCSS=!!r(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),f||u(e,t),e}var d,f,m="3.7.3-pre",h=t.html5||{},p=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",y=0,E={};!function(){try{var e=n.createElement("a");e.innerHTML="<xyz></xyz>",d="hidden"in e,f=1==e.childNodes.length||function(){n.createElement("a");var e=n.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(t){d=!0,f=!0}}();var b={elements:h.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:h.shivCSS!==!1,supportsUnknownElements:f,shivMethods:h.shivMethods!==!1,type:"default",shivDocument:s,createElement:i,createDocumentFragment:l,addElements:o};t.html5=b,s(n),"object"==typeof e&&e.exports&&(e.exports=b)}("undefined"!=typeof window?window:this,document)}}); !function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={exports:{},id:r,loaded:!1};return e[r].call(a.exports,a,a.exports,t),a.loaded=!0,a.exports}var n={};return t.m=e,t.c=n,t.p="./",t(0)}({0:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var r=n(635);Object.keys(r).forEach(function(e){"default"!==e&&"__esModule"!==e&&Object.defineProperty(t,e,{enumerable:!0,get:function(){return r[e]}})})},635:function(e,t){!function(t,n){function r(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;return n.innerHTML="x<style>"+t+"</style>",r.insertBefore(n.lastChild,r.firstChild)}function a(){var e=b.elements;return"string"==typeof e?e.split(" "):e}function o(e,t){var n=b.elements;"string"!=typeof n&&(n=n.join(" ")),"string"!=typeof e&&(e=e.join(" ")),b.elements=n+" "+e,s(t)}function c(e){var t=E[e[v]];return t||(t={},y++,e[v]=y,E[y]=t),t}function i(e,t,r){if(t||(t=n),f)return t.createElement(e);r||(r=c(t));var a;return a=r.cache[e]?r.cache[e].cloneNode():g.test(e)?(r.cache[e]=r.createElem(e)).cloneNode():r.createElem(e),!a.canHaveChildren||p.test(e)||a.tagUrn?a:r.frag.appendChild(a)}function l(e,t){if(e||(e=n),f)return e.createDocumentFragment();t=t||c(e);for(var r=t.frag.cloneNode(),o=0,i=a(),l=i.length;o<l;o++)r.createElement(i[o]);return r}function u(e,t){t.cache||(t.cache={},t.createElem=e.createElement,t.createFrag=e.createDocumentFragment,t.frag=t.createFrag()),e.createElement=function(n){return b.shivMethods?i(n,e,t):t.createElem(n)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+a().join().replace(/[\w\-:]+/g,function(e){return t.createElem(e),t.frag.createElement(e),'c("'+e+'")'})+");return n}")(b,t.frag)}function s(e){e||(e=n);var t=c(e);return!b.shivCSS||d||t.hasCSS||(t.hasCSS=!!r(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),f||u(e,t),e}var d,f,m="3.7.3-pre",h=t.html5||{},p=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,g=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",y=0,E={};!function(){try{var e=n.createElement("a");e.innerHTML="<xyz></xyz>",d="hidden"in e,f=1==e.childNodes.length||function(){n.createElement("a");var e=n.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(t){d=!0,f=!0}}();var b={elements:h.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:h.shivCSS!==!1,supportsUnknownElements:f,shivMethods:h.shivMethods!==!1,type:"default",shivDocument:s,createElement:i,createDocumentFragment:l,addElements:o};t.html5=b,s(n),"object"==typeof e&&e.exports&&(e.exports=b)}("undefined"!=typeof window?window:this,document)}});
//# sourceMappingURL=fix.ie9.js.map //# sourceMappingURL=fix.ie9.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long