/*jslint laxbreak:true */ /*jslint laxcomma:true */ /*jslint loopfunc:true */ /*jslint strict:true */ /*jslint browser:true */ /*jslint devel:true */ // Filename: app.js define([ "underscore" , "async" , "backbone" , "jquery" , "bootstrap" , "config" , "views/app" , "views/footer" , "views/sidebar" , "views/player" , "views/main" , "models/client" // , "models/dmap" , "collections/server" , "collections/playlist" , "views/client" , "views/list" , "text!../templates/app/modal-loading.html" , "text!../templates/app/modal-login.html" , "text!../templates/app/modal-about.html" ], function( _ , async , Backbone , $ , Bootstrap , Config , AppView , FooterView , SideBarView , PlayerView , MainView , ClientModel //, DMAPModel , ServerCollection , PlaylistCollection , ClientView , ListView , tmplModalLoading , tmplModalLogin , tmplModalAbout ) { "use strict"; var App = Backbone.Router.extend({ routes: { "about": "_routerActionAbout" , "playlist": "_routerActionPlaylist" , "servers/:server": "_routerActionClient" , "playlist/:item": "_routerActionPlaylistItem" , ":server/items/:item": "_routerActionServerItem" , "*actions": "_routerDefaultAction" // matches http://example.com/#anything-here } , historyStart: window.history.length , playlist: null , servers: null , initialize: function() { _.bindAll(this , "_serversInited" , "_routerActionAbout" , "_routerActionPlaylist" , "_routerActionClient" , "_routerActionItem" , "_routerActionServerItem" , "_routerDefaultAction" , "_serverInit" , "__showModalAbout" ); var that = this ; console.log("app.js::init()"); // Setup underscore templates with mustache styles _.templateSettings.interpolate = /\{\{(.+?)\}\}/g; this.servers = new ServerCollection(); this.playlist = new PlaylistCollection(); var serverLength = 0 , serverCbInit = function (server) { if (serverLength > 1) { --serverLength; } else { that._serversInited(); } }; async.waterfall([ function __asyncAppFetchServerCollection(callback) { that.servers.fetch({ success: function __fnApEventServersFetched(collection, modelsAttributes) { if (modelsAttributes.length === 0) { console.info("Adding default daap server"); collection.add(Config.daap); } callback(null, collection); } , error: callback }); } , function __asyncAppAttachStateEvents(servers, callback) { serverLength = servers.length; async.forEach(that.servers.models, function __fnAppCbServerInit(server) { that._serverInit(server, serverCbInit); }); that.servers.on("add", function __fnAppCbServerAdded(server) { server.save(); that._serverInit(server); }); callback(null, servers); } ] , function __asyncAppDependenciesReady(err, result) { that.Views = {}; that.Views.App = new AppView(); that.Views.SideBar = new SideBarView({ el: that.Views.App.Layout.panes.west , servers: that.servers }); that.Views.Player = new PlayerView({ el: that.Views.App.Layout.panes.north , servers: that.servers }); that.Views.Footer = new FooterView({ el: that.Views.App.Layout.panes.south }); that.Views.Main = new MainView({ el: that.Views.App.Layout.panes.center }); that.Views.Playlist = new ListView({ collection: that.playlist , type: "playlist" }); that.Views.Main.setView("playlist", that.Views.Playlist); that.Views.Main.on("action:item", function __fnAppEventMainViewActionItem (event) { }); that.Views.Main.on("action:playorder", function __fnAppEventMainViewActionItem (event) { that.Views.Player.setPlayIndex(event); }); that.Views.Footer.on("toggle:sidebar", function __fnAppEventTogglerSiderBar (event) { that.Views.App.toggleSideBar(); that.Views.Main.resizeView(); }); that.Views.Footer.on("toggle:random", function __fnAppEventTogglerRandom (event) { that.Views.Player.setRandomState(event); }); that.Views.Footer.on("toggle:repeat", function __fnAppEventTogglerRepeater (event) { that.Views.Player.setRepeatState(event); }); that.Views.Footer.on("show:about", that.__showModalAbout); that.Views.SideBar.on("add:playlist-item", function __fnAppEventPlaylistAddItem (event) { var listItem = that.servers.get(event.hostname).client.collections.databases[event.dbId].get("dmap_listing").get(event.item).attributes ; delete listItem._id; listItem.id = event.hostname + ":" + event.dbId + ":" + event.item; listItem = _.extend({}, listItem, { server: event.hostname , database: event.dbId , order: new Date().toString() }); that.playlist.on("add", function __fnAppSavePlaylistModel (model) { model.save(); }); that.playlist.add(listItem); }); that.Views.App.$el.delegate("div.modal", "hidden", function __fnAppEventRemoveModals (event) { $(event.target).remove(); }); Backbone.history.start({ pushState: true , root: Config.docRoot }); // For now let's reset the state when we start up //that.navigate("", false); App.__super__.initialize.apply(that, that.routes); }); return this; } , _serversInited: function () { var that = this ; console.debug("All Base Servers Inited!"); that.Views.Player.init(); that.Views.Player.playAtIndex(0);//Math.floor(Math.random() * that.Views.Player._playIndex.length)); } , _routerDefaultAction: function () { var that = this ; if (!that.servers || that.servers.length === 0) { Backbone.Router.prototype.navigate("about", true); } else { Backbone.Router.prototype.navigate("playlist", true); } } , _routerActionAbout: function () { var that = this ; that.__showModalAbout(); } , _routerActionPlaylist: function () { var that = this ; that.Views.SideBar.select("> ul > li:first"); that.Views.Main.showView("playlist"); } , _routerActionClient: function (hostname) { var that = this , server = this.servers.get(hostname) , client = server && server.client || undefined ; if (server && client) { that.Views.SideBar.select(server); // FIXME: This needs to take client states into account var __fnAppEventClientLoaded = function () { if (!that.Views.Main.getView(server.get("hostname"))) { that.Views.Main.setView(server.client.attributes.hostname, new ClientView({ /*el: that.Views.App.Layout.panes.center , */server: server , appendEl: that.Views.App.Layout.panes.center })); } that.Views.Main.showView(server.get("hostname")); } , __fnAppEventClientInitited = function () { client.fetchDatabases(function __fnAppCbFetchDatabases() { client.fetchDatabase(function __fnAppCbFetchDatabase() { client.fetchGenres(function __fnAppCbFetchGenres() { client.fetchArtists(function __fnAppCbFetchArtists() { client.fetchAlbums(function __fnAppCbFetchAlbums() { __fnAppEventClientLoaded(); }); }); }); }); }); }; if (client.state < 4) { client.on("inited", __fnAppEventClientInitited); if (client.state <= 0) { client.init(); } } else if (client.state === 4) { __fnAppEventClientInitited(); } else if (client.state > 4) { __fnAppEventClientLoaded(); } } } , _routerActionPlaylistItem: function (item) { var that = this ; that.Views.SideBar.select("> ul > li:first"); } , _routerActionServerItem: function (server, item) { var that = this ; that.Views.SideBar.select(server); that.Views.Main.showView(server.get("hostname")); } , _serverInit: function(server, cbInit) { var that = this ; that.loadingStates = 0; that.loadingModal = $(tmplModalLoading); that.loadingTimeout = null; server.client.off("all"); server.client.on("inited", function __fnAppEventClientInited(client) { cbInit(null, client); }); server.client.on("state", function __fnAppEventClientStateChange(client, state) { if (state === ClientModel.defaults._states.loading) { if (that.loadingStates === 0) { that.loadingTimeout = setTimeout(function __fnAppTimeoutLoadingStat() { that.loadingModal.modal(); that.loadingTimeout = null; }, 800); } that.loadingStates++; } else if (state === ClientModel.defaults._states.loaded) { that.loadingStates--; if (that.loadingStates === 0) { clearTimeout(that.loadingTimeout); if (that.loadingModal.modal) { that.loadingModal.modal("hide"); } } } }); server.client.on("unauthorized", function __fnAppEventClientUnauthorized(client, xhr) { var tmplHtml = _.template(tmplModalLogin)({ dmap_itemname: client.url() }) , serverModel = that.servers.get(client.attributes.hostname) ; that._modalLogin = $(tmplHtml); that._modalLogin.find("form").on("submit", function __fnAppEventModalLogin(event) { var username = $(event.target).find("input[type='text']").val() , password = $(event.target).find("input[type='password']").val() , saveCredentials = $(event.target).find("input[type='checkbox']").is(':checked') ; client.setAuth(username, password); if (saveCredentials) { var newModel = (_.clone({}, serverModel.attributes, {username: username, password: password})); serverModel.set("username", username, {silent: true}); serverModel.set("password", password, {silent: true}); serverModel.save(newModel, {silence: true}); } that._modalLogin.modal("hide"); setTimeout(client.init, 250); event.preventDefault(); }); that._modalLogin.delegate("input[type='checkbox']", "click", function __fnEventModalRemember(event) { if (event.target.checked === true) { if (!confirm("Using this feature will save the login and password locally in clear text, are you sure?")) { event.target.checked = false; event.preventDefault(); } } }); setTimeout(function __fnEventAppUnauthorizedDisplayModal() { that._modalLogin.modal(); }, 50); }); server.client.init(); } , __showModalAbout: function () { var that = this ; that._modalAbout = $(tmplModalAbout); that._modalAbout.on("hidden", function __fnEventAppModalAboutClosed(event) { // FIXME: Doesn't seem to work after 50 >_< if (window.history.length === 50) { window.history.length = 0; that.historyStart = 1; } console.log(window.history.length, that.historyStart); if (window.history.length === that.historyStart) { that.navigate("", false); } else { window.history.back(); } }); that._modalAbout.modal(); } }); return App; });