diff --git a/examples/ui/audio_player/css/example.css b/examples/ui/audio_player/css/example.css index 0046c2e8..0bbcae98 100644 --- a/examples/ui/audio_player/css/example.css +++ b/examples/ui/audio_player/css/example.css @@ -1,3 +1,91 @@ +#artworkText { + padding-top: 1px; + text-align: center; +} +#findInput { + right: 4px; + top: 19px; + border-top-left-radius: 0; +} +#findInput > input { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +#findInput > .OxButton { + border-top-right-radius: 0; +} +#findLabel { + right: 20px; + top: 4px; + padding-top: 1px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + font-size: 9px; +} +#findSelect { + right: 4px; + top: 4px; + border-bottom-right-radius: 0; +} +#statusText { + padding-top: 3px; + font-size: 9px; + text-align: center; +} +#toolbar > * { + position: absolute; +} +#viewButtons > .OxButton:first-child { + border-top-left-radius: 0; +} +#viewButtons > .OxButton:last-child { + border-top-right-radius: 0; +} +#viewLabel { + right: 136px; + top: 4px; + padding: 1px 4px 0 4px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + font-size: 9px; +} + +.item { + height: 32px; +} +.item > * { + position: relative; +} +.itemIcon { + left: 2px; + top: 2px; + width: 28px; + height: 28px; +} +.itemTitle { + left: 34px; + top: -28px; + height: 14px; + font-size: 13px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + cursor: default; +} +.itemInfo { + left: 34px; + top: -28px; + height: 10px; + font-size: 9px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + cursor: default; +} + +.OxDialog > .OxContent { + padding: 24px; +} .OxTableList .OxItem .OxCell > img.image { width: 14px; height: 14px; diff --git a/examples/ui/audio_player/js/example.js b/examples/ui/audio_player/js/example.js index dbc2e90a..05fc7f40 100644 --- a/examples/ui/audio_player/js/example.js +++ b/examples/ui/audio_player/js/example.js @@ -6,249 +6,388 @@ Demo application using Ox.AudioPlayer. Ox.load('UI', function() { - var columns = [ - { - format: function(value) { - return value - ? Ox.Element('') + var app = { + $ui: {}, + data: {}, + site: { + listColumns: [ + { + format: function(value, data) { + return Ox.Element('') .addClass('symbol') .attr({src: Ox.UI.getImageURL( - paused ? 'symbolUnmute' : 'symbolMute' - )}) - : Ox.Element(); + 'symbol' + Ox.toTitleCase( + value || (data.query ? 'find ': 'click') + ) + )}); + }, + id: 'icon', + title: 'icon', + visible: true, + width: 16 }, - id: 'playing', - removable: false, - title: 'Playing', - titleImage: 'mute', - visible: true, - width: 16 - }, - { - format: function(value) { - return value - ? Ox.Element('') - .addClass('symbol') - .attr({src: Ox.UI.getImageURL( - 'symbolCheck' - )}) - : Ox.Element(); + { + id: 'title', + title: 'Title', + visible: true, + width: 136 }, - id: 'checked', - removable: false, - title: 'Checked', - titleImage: 'check', - visible: true, - width: 16 - }, - { - format: function(value) { - return value - ? Ox.Element('') - .addClass('image') - .attr({src: value}) - : Ox.Element() - }, - id: 'artwork', - operator: '+', - title: 'Artwork', - titleImage: 'icon', - visible: true, - width: 16 - }, - { - align: 'right', - id: 'disc', - operator: '+', - title: 'Disc', - titleImage: 'circle', - width: 32 - }, - { - align: 'right', - id: 'track', - operator: '+', - title: 'Track', - titleImage: 'square', - width: 32 - }, - { - id: 'title', - operator: '+', - removable: false, - title: 'Title', - visible: true, - width: 192 - }, - { - id: 'artist', - operator: '+', - removable: false, - title: 'Artist', - visible: true, - width: 192 - }, - { - id: 'album', - operator: '+', - removable: false, - title: 'Album', - visible: true, - width: 192 - }, - { - align: 'right', - id: 'year', - operator: '+', - title: 'Year', - visible: true, - width: 64 - }, - { - align: 'right', - format: function(value) { - return Ox.formatDuration(value).substr(4); - }, - id: 'duration', - operator: '-', - title: 'Time', - visible: true, - width: 64 - }, - { - align: 'right', - format: function(value) { - return Ox.formatValue(value, 'B'); - }, - id: 'size', - operator: '-', - title: 'Size', - visible: true, - width: 64 - }, - { - align: 'right', - format: function(value) { - return Math.round(value) + ' kbps' - }, - id: 'bitrate', - operator: '-', - title: 'Bitrate', - visible: true, - width: 64 - }, - { - id: 'genre', - operator: '+', - title: 'Genre', - visible: true, - width: 128 - } - ], - paused = true, - sidebarSize = 192, - sort = [ - {key: 'artist', operator: '+'}, - {key: 'year', operator: '+'}, - {key: 'disc', operator: '+'}, - {key: 'track', operator: '+'} - ], - track = 0, - tracklistSize = 256, - tracks = [ - { - album: 'The Grey Album', - artist: 'Danger Mouse', - artwork: 'mp3/Danger Mouse/2004 The Grey Album/artwork.png', - bitrate: 128, - checked: true, - disc: 1, - duration: 160.417, - file: 'mp3/Danger Mouse/2004 The Grey Album/03 Encore.mp3', - genre: 'Hip-Hop', - playing: false, - size: 2556502, - title: 'Encore', - track: 3, - year: '2004' - }, - { - album: 'No Love Deep Web', - artist: 'Death Grips', - artwork: 'mp3/Death Grips/2012 No Love Deep Web/artwork.png', - bitrate: 128, - checked: true, - disc: 1, - duration: 303.960, - file: 'mp3/Death Grips/2012 No Love Deep Web/03 No Love.mp3', - genre: 'Electronic', - playing: false, - size: 4863327, - title: 'No Love', - track: 3, - year: '2012' - }, - { - album: 'No Love Deep Web', - artist: 'Death Grips', - artwork: 'mp3/Death Grips/2012 No Love Deep Web/artwork.png', - bitrate: 128, - checked: true, - disc: 1, - duration: 138.370, - file: 'mp3/Death Grips/2012 No Love Deep Web/09 Deep Web.mp3', - genre: 'Electronic', - playing: false, - size: 2214303, - title: 'Deep Web', - track: 9, - year: '2012' - } - ], - artists = getArtists(tracks), - albums = getAlbums(artists), - view = 'tracks', - - $toolbar = Ox.Bar({size: 39}), - - $audioPlayer = Ox.AudioPlayer({ - audio: tracks, - paused: true, - width: window.innerWidth - 190 - }) - .css({left: '4px', top: '4px'}) - .bindEvent({ - paused: function(data) { - paused = data.paused; - $musicList.value(tracks[track].file, 'playing', false); - $musicList.value(tracks[track].file, 'playing', true); - }, - track: function(data) { - $musicList.value(tracks[track].file, 'playing', false); - track = data.track; - $musicList.value(tracks[track].file, 'playing', true); + { + align: 'right', + id: 'items', + title: 'Items', + visible: true, + width: 40 } - }) - .appendTo($toolbar) - .gainFocus(), + ], + lists: [ + {icon: 'audio', id: 'Music', index: 0, items: 3, title: 'Music'}, + {icon: 'playlist', id: 'Playing', index: 1, items: 0, title: 'Playing'} + ], + sort: [ + {key: 'artist', operator: '+'}, + {key: 'year', operator: '+'}, + {key: 'disc', operator: '+'}, + {key: 'track', operator: '+'} + ], + sums: ['duration', 'size'], + trackColumns: [ + { + format: function(value) { + return value + ? Ox.Element('') + .addClass('symbol') + .attr({src: Ox.UI.getImageURL( + app.user.ui.paused + ? 'symbolUnmute' : 'symbolMute' + )}) + : Ox.Element(); + }, + id: 'playing', + removable: false, + title: 'Playing', + titleImage: 'mute', + visible: true, + width: 16 + }, + { + format: function(value) { + return value + ? Ox.Element('') + .addClass('symbol') + .attr({src: Ox.UI.getImageURL( + 'symbolCheck' + )}) + : Ox.Element(); + }, + id: 'checked', + removable: false, + title: 'Checked', + titleImage: 'check', + visible: true, + width: 16 + }, + { + format: function(value) { + return value + ? Ox.Element('') + .addClass('image') + .attr({src: value}) + : Ox.Element() + }, + id: 'artwork', + operator: '+', + title: 'Artwork', + titleImage: 'icon', + visible: true, + width: 16 + }, + { + align: 'right', + id: 'disc', + operator: '+', + title: 'Disc', + titleImage: 'circle', + width: 32 + }, + { + align: 'right', + id: 'track', + operator: '+', + title: 'Track', + titleImage: 'square', + width: 32 + }, + { + id: 'title', + operator: '+', + removable: false, + title: 'Title', + visible: true, + width: 192 + }, + { + id: 'artist', + operator: '+', + removable: false, + title: 'Artist', + visible: true, + width: 192 + }, + { + id: 'album', + operator: '+', + removable: false, + title: 'Album', + visible: true, + width: 192 + }, + { + align: 'right', + id: 'year', + operator: '+', + title: 'Year', + visible: true, + width: 64 + }, + { + align: 'right', + format: function(value) { + return Ox.formatDuration(value).substr(4); + }, + id: 'duration', + operator: '-', + title: 'Time', + visible: true, + width: 64 + }, + { + align: 'right', + format: function(value) { + return Ox.formatValue(value, 'B'); + }, + id: 'size', + operator: '-', + title: 'Size', + visible: true, + width: 64 + }, + { + align: 'right', + format: function(value) { + return Math.round(value) + ' kbps' + }, + id: 'bitrate', + operator: '-', + title: 'Bitrate', + visible: true, + width: 64 + }, + { + id: 'genre', + operator: '+', + title: 'Genre', + visible: true, + width: 128 + } + ] + }, + ui: {}, + user: { + lists: [ + { + id: 'favorites', + index: 0, + items: 0, + title: 'Favorites', + type: 'static' + }, + { + id: 'hip-hop', + index: 1, + items: 1, + query: { + conditions: [ + {key: 'genre', operator: '==', value: 'Hip-Hop'} + ], + operator: '&' + }, + title: 'Hip-Hop' + } + ], + ui: { + artwork: 'selected', + coverSize: 64, + list: 'Music', + paused: true, + query: { + conditions: [], + operator: '&', + }, + selectedAlbum: [], + selectedArtist: [], + selectedTrack: [], + showSidebar: true, + sidebarSize: 192, + track: 0, + tracklistSize: 256, + view: 'tracks' + } + }, + utils: {} + }; - $viewLabel = Ox.Label({ + app.user.ui.sort = Ox.clone(app.site.sort, true); + + app.load = function() { + Ox.getJSON('json/music.json', function(data) { + app.data.tracks = data; + app.data.artists = app.utils.getArtists(); + app.data.albums = app.utils.getAlbums(); + app.$ui.appPanel = app.ui.appPanel().appendTo(Ox.$body); + Ox.$window.bind({resize: app.utils.resizeWindow}); + }); + }; + + app.UI = (function() { + var that = {}; + that.set = function() { + var args = Ox.makeObject(arguments), + keys = [], + previousUI = Ox.clone(app.user.ui, true); + Ox.forEach(args, function(value, key) { + if (!Ox.isEqual(value, previousUI[key])) { + app.user.ui[key] = value; + keys.push(key); + } + }); + keys.forEach(function(key) { + var data = { + previousValue: previousUI[key], + value: app.user.ui[key] + } + Ox.print('ui_' + key.toLowerCase(), JSON.stringify(app.user.ui[key])) + Ox.forEach(app.$ui, function($elements) { + Ox.makeArray($elements).forEach(function($element) { + $element.triggerEvent('ui_' + key.toLowerCase(), data); + }); + }); + }); + }; + return that; + }()); + + app.ui.appPanel = function() { + return Ox.SplitPanel({ + elements: [ + {element: app.$ui.mainMenu = app.ui.mainMenu(), size: 20}, + {element: app.$ui.mainPanel = app.ui.mainPanel()} + ], + orientation: 'vertical' + }); + }; + + app.ui.mainMenu = function() { + return Ox.MainMenu({ + menus: [ + { + id: '0xcd', + title: '0xCD', + items: [ + {id: 'about', title: 'About 0xCD'} + ] + } + ] + }) + .bindEvent({ + click: function(data) { + if (data.id == 'about') { + app.$ui.aboutDialog = ( + app.$ui.aboutDialog || app.ui.aboutDialog() + ).open(); + } + } + }); + }; + + app.ui.aboutDialog = function() { + var $element = Ox.Dialog({ + buttons: [ + Ox.Button({ + id: 'close', + title: 'Close' + }) + .bindEvent({ + click: function() { + $element.close(); + } + }) + ], + content: Ox.Element() + .html('Audio Player Example'), + height: 256, + keys: {enter: 'close', escape: 'close'}, + title: 'About 0xCD', + width: 512 + }); + return $element; + }; + + app.ui.mainPanel = function() { + return Ox.SplitPanel({ + elements: [ + {element: app.ui.$toolbar = app.ui.toolbar(), size: 39}, + {element: app.ui.$bothPanel = app.ui.bothPanel()} + ], + orientation: 'vertical' + }); + }; + + app.ui.toolbar = function() { + return Ox.Bar({size: 39}) + .attr({id: 'toolbar'}) + .append(app.$ui.audioPlayer = app.ui.audioPlayer()) + .append(app.$ui.viewLabel = app.ui.viewLabel()) + .append(app.$ui.viewButtons = app.ui.viewButtons()) + .append(app.$ui.findSelect = app.ui.findSelect()) + .append(app.$ui.findLabel = app.ui.findLabel()) + .append(app.$ui.findInput = app.ui.findInput()); + }; + + app.ui.audioPlayer = function() { + return Ox.AudioPlayer({ + audio: app.data.tracks, + paused: true, + width: window.innerWidth - 190 + }) + .css({left: '4px', top: '4px'}) + .bindEvent({ + paused: function(data) { + var id = app.data.tracks[app.user.ui.track].file + app.user.ui.paused = data.paused; + app.$ui.trackList.value(id, 'playing', false); + app.$ui.trackList.value(id, 'playing', true); + }, + track: function(data) { + var id = app.data.tracks[app.user.ui.track].file + app.$ui.trackList.value(id, 'playing', false); + app.user.ui.track = data.track; + $app.$ui.trackList.value(id, 'playing', true); + } + }); + }; + + app.ui.viewLabel = function() { + return Ox.Label({ textAlign: 'center', title: 'Tracks', width: 50 }) - .css({ - position: 'absolute', - right: '136px', - top: '4px', - padding: '1px 4px 0 4px', - borderBottomLeftRadius: 0, - borderBottomRightRadius: 0, - fontSize: '9px' - }) - .appendTo($toolbar), + .attr({id: 'viewLabel'}); + }; - $viewButtons = Ox.ButtonGroup({ + app.ui.viewButtons = function() { + return Ox.ButtonGroup({ buttons: [ {id: 'tracks', title: 'list', tooltip: 'View Tracks'}, {id: 'albums', title: 'grid', tooltip: 'View Albums'}, @@ -259,6 +398,7 @@ Ox.load('UI', function() { selectable: true, type: 'image' }) + .attr({id: 'viewButtons'}) .css({ position: 'absolute', right: '136px', @@ -266,223 +406,625 @@ Ox.load('UI', function() { }) .bindEvent({ change: function(data) { - view = data.value; - $viewLabel.options({title: Ox.toTitleCase(view)}); - $rightPanel.replaceElement(0, musicPanel(view)); + app.user.ui.view = data.value; + app.$ui.viewLabel.options({title: Ox.toTitleCase(app.user.ui.view)}); + app.$ui.rightPanel.replaceElement(0, app.$ui.musicPanel = app.ui.musicPanel()); } - }) - .appendTo($toolbar), + }); + }; - $findSelect = Ox.Select({ - items: [ - {id: 'all', title: 'Find: All'}, - {id: 'tracks', title: 'Find: Tracks'}, - {id: 'artists', title: 'Find: Artists'}, - {id: 'albums', title: 'Find: Albums'} - ], - overlap: 'left', - type: 'image' - }) - .css({ - position: 'absolute', - right: '4px', - top: '4px', - borderBottomRightRadius: 0 - }) - .bindEvent({ - change: function(data) { - $findLabel.options({title: data.title}); - } - }) - .appendTo($toolbar), - - $findLabel = Ox.Label({ + app.ui.findSelect = function() { + return Ox.Select({ + items: [ + {id: 'all', title: 'Find: All'}, + {id: 'tracks', title: 'Find: Tracks'}, + {id: 'artists', title: 'Find: Artists'}, + {id: 'albums', title: 'Find: Albums'} + ], + overlap: 'left', + type: 'image' + }) + .attr({id: 'findSelect'}) + .bindEvent({ + change: function(data) { + $findLabel.options({title: data.title}); + } + }); + }; + + app.ui.findLabel = function() { + return Ox.Label({ title: 'Find: All', width: 112 }) - .css({ - position: 'absolute', - right: '20px', - top: '4px', - paddingTop: '1px', - borderBottomLeftRadius: 0, - borderBottomRightRadius: 0, - fontSize: '9px' - }) - .appendTo($toolbar), + .attr({id: 'findLabel'}); + }; - $findInput = Ox.Input({ + app.ui.findInput = function() { + return Ox.Input({ clear: true, width: 128 }) - .css({ - position: 'absolute', - right: '4px', - top: '19px', - borderTopLeftRadius: 0 - }) - .appendTo($toolbar), + .attr({id: 'findInput'}); + }; - $listsList = Ox.TableList({ - columns: [ - { - format: function(value) { - return Ox.Element('') - .addClass('symbol') - .attr({src: Ox.UI.getImageURL( - 'symbol' + Ox.toTitleCase(value) - )}); - }, - id: 'icon', - title: 'icon', - visible: true, - width: 16 - }, - { - id: 'title', - title: 'Title', - visible: true, - width: 136 - }, - { - align: 'right', - id: 'items', - title: 'Items', - visible: true, - width: 40 - } - ], - items: [ - {icon: 'audio', index: '0', items: 3, title: 'Music'}, - {icon: 'playlist', index: '1', items: 0, title: 'Playing'}, - {icon: 'click', index: '1', items: 0, title: 'Favorites'}, - {icon: 'find', index: '1', items: 1, title: 'Hip-Hop'} - ], - max: 1, - selected: ['0'], - sort: [{key: 'index', operator: '+'}], - sortable: true, - unique: 'index' - }), + app.ui.bothPanel = function() { + return Ox.SplitPanel({ + elements: [ + { + collapsible: true, + element: app.$ui.leftPanel = app.ui.leftPanel(), + resizable: true, + resize: [128, 192, 256, 320, 384], + size: app.user.ui.sidebarSize + }, + { + element: app.$ui.rightPanel = app.ui.rightPanel() + } + ], + orientation: 'horizontal' + }); + } - $artworkbar = Ox.Bar({size: 16}), - - $artworkText = Ox.Element() - .css({ - paddingTop: '1px', - textAlign: 'center' - }) - .html('Selected Item') - .appendTo($artworkbar), - - $artwork = Ox.Element('') - .attr({src: tracks[0].artwork}) - .css({ - width: sidebarSize + 'px', - height: sidebarSize + 'px' - }), - - $artworkPanel = Ox.SplitPanel({ - elements: [ - {element: $artworkbar, size: 16}, - {element: $artwork} - ], - orientation: 'vertical' - }), - - $leftPanel = Ox.SplitPanel({ + app.ui.leftPanel = function() { + return Ox.SplitPanel({ elements: [ { - element: $listsList + element: app.$ui.listsPanel = app.ui.listsPanel() }, { collapsible: true, - element: $artworkPanel, - size: sidebarSize + 16 + element: app.$ui.artworkPanel = app.ui.artworkPanel(), + size: app.user.ui.sidebarSize + 16 } ], orientation: 'vertical' }) .bindEvent({ resize: function(data) { - sidebarSize = data.size; - $listsList.setColumnWidth('title', sidebarSize - 56); - $leftPanel.size(1, sidebarSize + 16); - $artwork.css({ - width: sidebarSize + 'px', - height: sidebarSize + 'px' + app.user.ui.sidebarSize = data.size; + [app.$ui.siteLists, app.$ui.userLists].forEach(function($list) { + $list.setColumnWidth('title', app.user.ui.sidebarSize - 56); + }); + app.$ui.listsList + app.$ui.leftPanel.size(1, app.user.ui.sidebarSize + 16); + app.$ui.artwork.css({ + width: app.user.ui.sidebarSize + 'px', + height: app.user.ui.sidebarSize + 'px' }); //$musicList.size(); } - }), - - $musicList, - - $musicPanel = musicPanel(view), - - $statusbar = Ox.Bar({size: 16}), - - $status = Ox.Element().css({ - paddingTop: '3px', - fontSize: '9px', - textAlign: 'center' }) - .html('Loading...') - .appendTo($statusbar), + }; - $rightPanel = Ox.SplitPanel({ - elements: [ - {element: $musicPanel}, - {element: $statusbar, size: 16} - ], - orientation: 'vertical' - }), + app.ui.listsPanel = function() { + return Ox.SplitPanel({ + elements: [ + { + element: app.$ui.siteLists = app.ui.siteLists(), + size: app.site.lists.length * 16 + }, + { + element: app.$ui.userLists = app.ui.userLists() + } + ], + orientation: 'vertical' + }); + }; - $mainPanel = Ox.SplitPanel({ - elements: [ - { - collapsible: true, - element: $leftPanel, - resizable: true, - resize: [128, 192, 256, 320, 384], - size: sidebarSize - }, - { - element: $rightPanel + app.ui.siteLists = function() { + var $element = Ox.TableList({ + columns: app.site.listColumns, + items: app.site.lists, + max: 1, + selected: [app.user.ui.list], + sort: [{key: 'index', operator: '+'}], + unique: 'id' + }) + .bindEvent({ + select: function(data) { + app.UI.set({list: data.ids[0] || app.site.lists[0].id}); + }, + selectafter: function() { + app.UI.set({list: app.user.lists[0].id}); + app.$ui.userLists.gainFocus(); + }, + ui_list: function(data) { + $element.options({ + selected: data.value[0] == data.value[0].toUpperCase() + ? [data.value] : [] + }); + } + }); + $element.update = function() { + return $element.setColumnWidth('title', app.user.ui.sidebarSize - 56); + }; + return $element.update(); + }; + + app.ui.userLists = function() { + var $element = Ox.TableList({ + columns: app.site.listColumns, + items: app.user.lists, + max: 1, + selected: [app.user.ui.list], + sort: [{key: 'index', operator: '+'}], + sortable: true, + unique: 'id' + }) + .bindEvent({ + move: function(data) { + Ox.print('MOVE:', data); + }, + select: function(data) { + app.UI.set({list: data.ids[0] || app.site.lists[0].id}); + }, + selectbefore: function() { + app.UI.set({list: Ox.last(app.site.lists).id}); + app.$ui.siteLists.gainFocus(); + }, + ui_list: function(data) { + $element.options({ + selected: data.value[0] == data.value[0].toLowerCase() + ? [data.value] : [] + }); + } + }); + $element.update = function() { + return $element.setColumnWidth('title', app.user.ui.sidebarSize - 56); + }; + return $element.update(); + }; + + app.ui.artworkPanel = function() { + return Ox.SplitPanel({ + elements: [ + {element: app.$ui.artworkbar = app.ui.artworkbar(), size: 16}, + {element: app.$ui.artwork = app.ui.artwork()} + ], + orientation: 'vertical' + }); + }; + + app.ui.artworkbar = function() { + return Ox.Bar({size: 16}) + .append(app.$ui.artworkText = app.ui.artworkText()) + .bindEvent({ + anyclick: function() { + app.UI.set({ + artwork: app.user.ui.artwork == 'playing' + ? 'selected' : 'playing' + }); + } + }); + }; + + app.ui.artworkText = function() { + var $element = Ox.Element() + .attr({id: 'artworkText'}) + .bindEvent({ + ui_artwork: function() { + $element.update(); + } + }); + $element.update = function() { + $element.html( + app.user.ui.artwork == 'playing' + ? 'Now Playing' : 'Selected Item' + ); + return $element; + }; + return $element.update(); + }; + + app.ui.artwork = function() { + var $element = Ox.Element('') + .attr({src: app.data.tracks[0].artwork}) + .bindEvent({ + ui_selectedalbum: function(data) { + if (app.user.ui.artwork == 'selected') { + $element.attr({ + src: data.value.length + ? Ox.getObjectById(app.data.albums, data.value[0]).artwork + : '' + }); } - ], - orientation: 'horizontal' - }), + }, + ui_selectedartist: function(data) { + if (app.user.ui.artwork == 'selected') { + $element.attr({ + src: data.value.length + ? Ox.getObjectById(app.data.artists, data.value[0]).artwork + : '' + }); + } + }, + ui_selectedtrack: function(data) { + if (app.user.ui.artwork == 'selected') { + $element.attr({ + src: data.value.length + ? Ox.getObjectById(app.data.tracks, data.value[0]).artwork + : '' + }); + } + } + }); + $element.update = function() { + $element.css({ + width: app.user.ui.sidebarSize + 'px', + height: app.user.ui.sidebarSize + 'px' + }); + return $element; + }; + return $element.update(); + }; - $appPanel = Ox.SplitPanel({ - elements: [ - {element: $toolbar, size: 39}, - {element: $mainPanel} - ], - orientation: 'vertical' + app.ui.rightPanel = function() { + return Ox.SplitPanel({ + elements: [ + {element: app.$ui.musicPanel = app.ui.musicPanel()}, + {element: app.$ui.statusbar = app.ui.statusbar(), size: 16} + ], + orientation: 'vertical' + }); + }; + + app.ui.musicPanel = function() { + return app.ui[app.user.ui.view + 'Panel'](); + }; + + app.ui.tracksPanel = function() { + return Ox.SplitPanel({ + elements: [ + { + collapsible: true, + element: app.$ui.albumBrowser = app.ui.albumBrowser(), + size: 112 + Ox.UI.SCROLLBAR_SIZE + }, + { + element: app.$ui.trackList = app.ui.trackList() + } + ], + orientation: 'vertical' + }); + }; + + app.ui.albumBrowser = function() { + var $element = Ox.IconList({ + fixedRatio: 1, + item: function(data, sort, size) { + return { + height: size, + id: data.id, + info: data.year, + title: [data.artist, data.title].join(' — '), + url: data.artwork, + width: size + }; + }, + items: app.data.albums, + max: 1, + orientation: 'horizontal', + pageLength: 100, + query: {conditions: [], operator: '&'}, + selected: [], + size: 64, + sort: [{key: 'index', operator: '+'}], + unique: 'id' }) - .appendTo(Ox.$body); + .bindEvent({ + ui_sort: function() { + $element.update(); + } + }); + $element.update = function() { + app.utils.getTrackAlbums(function(albums) { + Ox.print('ALBUMS::::', albums) + $element.options({items: albums}); + }); + return $element; + } + return $element; + }; - $($viewButtons.find('.OxButton')[0]).css({borderTopLeftRadius: 0}); - $($viewButtons.find('.OxButton')[2]).css({borderTopRightRadius: 0}); - $findInput.find('input').css({borderTopLeftRadius: 0, borderTopRightRadius: 0}); - $findInput.find('.OxButton').css({borderTopRightRadius: 0}); + app.ui.trackList = function() { + return Ox.TableList({ + columns: app.site.trackColumns, + columnsMovable: true, + columnsRemovable: true, + columnsResizable: true, + columnsVisible: true, + items: app.data.tracks, + scrollbarVisible: true, + sort: Ox.clone(app.user.ui.sort, true), + sums: app.site.sums, + unique: 'id' + }) + .bindEvent({ + init: function(data) { + app.$ui.statusText.update(data); + app.utils.getTrackAlbums(function(data) { + Ox.print('::::', data); + }); + }, + open: function(data) { + var file = data.ids[0], + id = app.data.tracks[app.user.ui.track].id, + index = Ox.getIndexById(app.data.tracks, id); + if (index == app.user.ui.track) { + app.$ui.trackList.value(id, 'playing', true); + app.$ui.audioPlayer.options({paused: false, position: 0}); + } else { + app.$ui.trackList.value(id, 'playing', false); + app.user.ui.track = index; + app.$ui.audioPlayer.options({paused: false, track: app.user.ui.track}); + app.$ui.trackList.value(id, 'playing', true); + } + }, + openpreview: function(data) { + app.user.ui.paused = !app.user.ui.paused; + app.$ui.audioPlayer.options({paused: app.user.ui.paused}); + app.$ui.trackList.closePreview(); + }, + select: function(data) { + app.UI.set({selectedTrack: data.ids}); + }, + sort: function(data) { + Ox.print('DDD', data); + app.UI.set({sort: [data]}); + } + }); + }; - // Ox.print('ARTISTS', artists, 'ALBUMS', albums); + app.ui.albumsPanel = function() { + return Ox.SplitPanel({ + elements: [ + { + element: app.$ui.albumList = app.ui.albumList() + }, + { + element: app.$ui.trackBrowser = app.ui.trackBrowser(), + resizable: true, + resize: [192, 256, 320], + size: app.user.ui.tracklistSize + } + ], + orientation: 'horizontal' + }); + }; - function getAlbums(artists) { + app.ui.albumList = function() { + return Ox.IconList({ + fixedRatio: 1, + item: function(data, sort, size) { + var key = Ox.contains(['artist', 'title'], sort[0].key) + ? 'year' : sort[0].key, + column = Ox.getObjectById(app.site.trackColumns, key), + info = (column.format || Ox.identity)(data[key]); + return { + height: size, + id: data.id, + info: info, + title: [data.artist, data.title].join(' — '), + url: data.artwork, + width: size + }; + }, + items: app.data.albums, + pageLength: 120, + query: {conditions: [], operator: '&'}, + selected: [], + size: 128, + sort: Ox.clone(app.user.ui.sort, true), + unique: 'id' + }) + .bindEvent({ + select: function(data) { + app.UI.set({selectedAlbum: data.ids}); + }, + openpreview: function() { + + } + }); + }; + + app.ui.trackBrowser = function() { + return Ox.TableList({ + columns: [ + Ox.getObjectById(app.site.trackColumns, 'playing'), + Ox.getObjectById(app.site.trackColumns, 'checked'), + Ox.getObjectById(app.site.trackColumns, 'artwork'), + Ox.extend( + Ox.getObjectById(app.site.trackColumns, 'track'), + {visible: true} + ), + Ox.extend( + Ox.getObjectById(app.site.trackColumns, 'title'), + {width: app.user.ui.tracklistSize - 144 - Ox.UI.SCROLLBAR_SIZE} + ), + Ox.getObjectById(app.site.trackColumns, 'duration') + ], + items: app.data.tracks, + query: {conditions: [], operator: '&'}, + scrollbarVisible: true, + selected: [], + sort: Ox.clone(app.site.sort, true), + unique: 'id' + }) + .bindEvent({ + resize: function(data) { + app.user.ui.tracklistSize = data.size; + app.$ui.trackBrowser.setColumnWidth( + 'title', app.user.ui.tracklistSize - 144 - Ox.UI.SCROLLBAR_SIZE + ); + }, + ui_selectedalbum: function(data) { + app.$ui.trackBrowser.options({ + items: data.value.length ? Ox.flatten( + data.value.map(function(id) { + return Ox.getObjectById(app.data.albums, id).items; + }) + ) : [] + }); + } + }); + }; + + app.ui.artistsPanel = function() { + return Ox.ColumnList({ + columns: [ + { + id: 'artists', + item: function(data, width) { + data.artwork = data.artwork || ''; + data.years = data.years || []; + var $item = $('
') + .addClass('item') + .css({width: width + 'px'}); + $('') + .addClass('itemIcon') + .attr({src: data.artwork}) + .appendTo($item); + $('
') + .addClass('itemTitle') + .css({width: width - 36 + 'px'}) + .html(data.name ? data.name : '') + .appendTo($item); + $('
') + .addClass('itemInfo OxLight') + .css({width: width - 36 + 'px'}) + .html( + [ + data.years.join('-'), + Ox.formatCount(data.albums, 'album'), + Ox.formatCount(data.tracks, 'track'), + Ox.formatDuration(data.duration), + Ox.formatValue(data.size, 'B') + ].join(' — ') + ) + .appendTo($item); + return $item; + }, + itemHeight: 32, + keys: ['albums', 'artwork', 'duration', 'name', 'size', 'tracks', 'years'] + }, + { + id: 'albums', + item: function(data, width) { + data.artwork = data.artwork || ''; + data.tracks = data.tracks || [{duration: 0}]; + data.year = data.year || '????'; + var $item = $('
') + .addClass('item') + .css({width: width + 'px'}); + $('') + .addClass('itemIcon') + .attr({src: data.artwork}) + .appendTo($item); + $('
') + .addClass('itemTitle') + .css({width: width - 36 + 'px'}) + .html(data.title ? data.title : '') + .appendTo($item); + $('
') + .addClass('itemInfo OxLight') + .css({width: width - 36 + 'px'}) + .html( + [ + data.year, + Ox.formatCount(data.tracks, 'track'), + Ox.formatDuration(data.duration), + Ox.formatValue(data.size, 'B') + ].join(' — ') + ) + .appendTo($item); + return $item; + }, + itemHeight: 32, + keys: ['artwork', 'duration', 'size', 'title', 'tracks', 'year'] + }, + { + id: 'tracks', + item: function(data, width) { + var $item = $('
') + .addClass('item') + .css({width: width + 'px'}); + $('') + .addClass('itemIcon') + .attr({src: data.artwork}) + .appendTo($item); + $('
') + .addClass('itemTitle') + .css({width: width - 36 + 'px'}) + .html(data.title ? data.title : '') + .appendTo($item); + $('
') + .addClass('itemInfo OxLight') + .css({width: width - 36 + 'px'}) + .html( + [ + Ox.formatDuration(data.duration), + Ox.formatValue(data.size, 'B'), + Math.round(data.bitrate) + ' kbps' + ].join(' — ') + ) + .appendTo($item); + return $item; + }, + itemHeight: 32, + keys: ['artwork', 'bitrate', 'checked', 'duration', 'playing', 'size', 'title'] + } + ], + items: app.data.artists, + list: 'custom', + width: window.innerWidth - app.user.ui.sidebarSize - 1 + }) + .bindEvent({ + resize: function(data) { + $panel.options({width: data.size}) + }, + select: function(data) { + Ox.print('SELECT::', data) + app.UI.set( + 'selected' + Ox.toTitleCase(data.id.slice(0, -1)), + data.ids + ); + } + }); + }; + + app.ui.statusbar = function() { + return Ox.Bar({size: 16}) + .append(app.$ui.statusText = app.ui.statusText()); + }; + + app.ui.statusText = function() { + var $element = Ox.Element().attr({id: 'statusText'}); + $element.update = function(data) { + return $element.html( + data ? [ + Ox.formatCount(data.items, 'track'), + Ox.formatDuration(data.duration), + Ox.formatValue(data.size, 'B') + ].join(' — ') : 'Loading...' + ); + }; + return $element.update(); + }; + + app.utils.getAlbums = function() { var albums = [] - artists.forEach(function(artist) { + app.data.artists.forEach(function(artist) { artist.items.forEach(function(album) { albums.push(Ox.extend(album, {artist: artist.name})); }); }); return albums; - } + }; - function getArtists(tracks) { + app.utils.getArtists = function() { var artists = [], tree = {}; - tracks.forEach(function(track, index) { + app.data.tracks.forEach(function(track, index) { var artist = track.artist, album = track.year + ' ' + track.album, title = Ox.pad(track.disc, 2) + '\n' + Ox.pad(track.track, 2) @@ -513,7 +1055,7 @@ Ox.load('UI', function() { duration: Ox.values(tracks).reduce(function(r, v, i) { return r + v.duration; }, 0), - id: [year, title].join('\n'), + id: [artist.id, year + ' ' + title].join('\n'), items: [], size: Ox.values(tracks).reduce(function(r, v, i) { return r + v.size; @@ -555,345 +1097,33 @@ Ox.load('UI', function() { artists.push(artist); }); return artists; - } + }; - function musicPanel(view) { - var $panel; - if (view == 'tracks') { - var $trackAlbumList = trackAlbumList(); - $musicList = Ox.TableList({ - columns: columns, - columnsMovable: true, - columnsRemovable: true, - columnsResizable: true, - columnsVisible: true, - items: tracks, - max: 1, - scrollbarVisible: true, - sort: Ox.clone(sort, true), - unique: 'file' - }) - .bindEvent({ - open: function(data) { - var file = data.ids[0], - index = Ox.indexOf(tracks, function(track) { - return track.file == file; - }); - if (index == track) { - $musicList.value(tracks[track].file, 'playing', true); - $audioPlayer.options({paused: false, position: 0}); - } else { - $musicList.value(tracks[track].file, 'playing', false); - track = index; - $audioPlayer.options({paused: false, track: track}); - $musicList.value(tracks[track].file, 'playing', true); - } - }, - openpreview: function(data) { - paused = !paused; - $audioPlayer.options({paused: paused}); - $musicList.closePreview(); - } - }); - $panel = Ox.SplitPanel({ - elements: [ - { - collapsible: true, - element: $trackAlbumList, - size: 112 + Ox.UI.SCROLLBAR_SIZE - }, - { - element: $musicList - } - ], - orientation: 'vertical' - }); - } else if (view == 'albums') { - $musicList = Ox.IconList({ - fixedRatio: 1, - item: function(data, sort, size) { - var key = Ox.contains(['artist', 'title'], sort[0].key) - ? 'year' : sort[0].key, - column = Ox.getObjectById(columns, key), - info = (column.format || Ox.identity)(data[key]); - return { - height: size, - id: data.id, - info: info, - title: [data.artist, data.title].join(' — '), - url: data.artwork, - width: size - } - }, - items: albums, - max: 1, - pageLength: 120, - query: {conditions: [], operator: '&'}, - selected: [], - size: 128, - sort: Ox.clone(sort, true), - unique: 'id' - }) - .bindEvent({ - - }); - var $albumTrackList = albumTrackList(); - $panel = Ox.SplitPanel({ - elements: [ - { - element: $musicList - }, - { - element: $albumTrackList, - resizable: true, - resize: [192, 256, 320], - size: tracklistSize - } - ], - orientation: 'horizontal' - }); - } else if (view == 'artists') { - $panel = Ox.ColumnList({ - columns: [ - { - id: 'artist', - item: function(data, width) { - data.artwork = data.artwork || ''; - data.years = data.years || []; - var $item = $('
') - .css({width: width + 'px', height: '32px'}); - $('') - .attr({src: data.artwork}) - .css({ - position: 'relative', - left: '2px', - top: '2px', - width: '28px', - height: '28px', - borderRadius: '7px' - }) - .appendTo($item); - $('
') - .css({ - position: 'relative', - left: '34px', - top: '-28px', - width: width - 36 + 'px', - fontSize: '13px', - textOverflow: 'ellipsis', - cursor: 'default', - overflow: 'hidden' - }) - .html(data.name ? data.name : '') - .appendTo($item); - $('
') - .addClass('OxLight') - .css({ - position: 'relative', - left: '34px', - top: '-28px', - width: width - 36 + 'px', - height: '10px', - fontSize: '9px', - textOverflow: 'ellipsis', - whiteSpace: 'nowrap', - cursor: 'default', - overflow: 'hidden' - }) - .html( - [ - data.years.join('-'), - Ox.formatCount(data.albums, 'album'), - Ox.formatCount(data.tracks, 'track'), - Ox.formatDuration(data.duration), - Ox.formatValue(data.size, 'B') - ].join(' — ') - ) - .appendTo($item); - return $item; - }, - itemHeight: 32, - keys: ['albums', 'artwork', 'duration', 'name', 'size', 'tracks', 'years'] - }, - { - id: 'album', - item: function(data, width) { - data.artwork = data.artwork || ''; - data.tracks = data.tracks || [{duration: 0}]; - data.year = data.year || '????'; - var $item = $('
') - .css({width: width + 'px', height: '32px'}); - $('') - .attr({src: data.artwork}) - .css({ - position: 'relative', - left: '2px', - top: '2px', - width: '28px', - height: '28px' - }) - .appendTo($item); - $('
') - .css({ - position: 'relative', - left: '34px', - top: '-28px', - width: width - 36 + 'px', - fontSize: '13px', - textOverflow: 'ellipsis', - cursor: 'default', - overflow: 'hidden' - }) - .html(data.title ? data.title : '') - .appendTo($item); - $('
') - .addClass('OxLight') - .css({ - position: 'relative', - left: '34px', - top: '-28px', - width: width - 36 + 'px', - fontSize: '9px', - textOverflow: 'ellipsis', - cursor: 'default', - overflow: 'hidden' - }) - .html( - [ - data.year, - Ox.formatCount(data.tracks, 'track'), - Ox.formatDuration(data.duration), - Ox.formatValue(data.size, 'B') - ].join(' — ') - ) - .appendTo($item); - return $item; - }, - itemHeight: 32, - keys: ['artwork', 'duration', 'size', 'title', 'tracks', 'year'] - }, - { - id: 'track', - item: function(data, width) { - var $item = $('
') - .css({width: width + 'px', height: '32px'}); - $('') - .attr({src: data.artwork}) - .css({ - position: 'relative', - left: '2px', - top: '2px', - width: '28px', - height: '28px' - }) - .appendTo($item); - $('
') - .css({ - position: 'relative', - left: '34px', - top: '-28px', - width: width - 36 + 'px', - fontSize: '13px', - textOverflow: 'ellipsis', - cursor: 'default', - overflow: 'hidden' - }) - .html(data.title ? data.title : '') - .appendTo($item); - $('
') - .addClass('OxLight') - .css({ - position: 'relative', - left: '34px', - top: '-28px', - width: width - 36 + 'px', - fontSize: '9px', - textOverflow: 'ellipsis', - cursor: 'default', - overflow: 'hidden' - }) - .html( - [ - data.duration, - Ox.formatValue(data.size, 'B'), - Math.round(data.bitrate) + ' kbps' - ].join(' — ') - ) - .appendTo($item); - return $item; - }, - itemHeight: 32, - keys: ['artwork', 'bitrate', 'checked', 'duration', 'playing', 'size', 'title'] - } - ], - items: artists, - list: 'custom', - width: window.innerWidth - sidebarSize - 1 - }) - .bindEvent({ - resize: function(data) { - $panel.options({width: data.size}) - } - }); - } - return $panel; - } - - function albumTrackList() { - var $list = Ox.TableList({ - columns: [ - Ox.getObjectById(columns, 'playing'), - Ox.getObjectById(columns, 'checked'), + app.utils.getTrackAlbums = function(callback) { + app.$ui.trackList.api({ + keys: ['id'], + query: app.user.ui.query, + sort: app.user.ui.sort + }, function(result) { + callback(result.data.items.reduce(function(r, v, i) { + var albumId = v.id.split('\n').slice(0, 2).join('\n'), + last = Ox.last(r); + return last && last.albumId == albumId ? r : r.concat( Ox.extend( - Ox.getObjectById(columns, 'title'), - {width: tracklistSize - 96 - Ox.UI.SCROLLBAR_SIZE} - ), - Ox.getObjectById(columns, 'duration') - ], - items: tracks, - max: 1, - query: {conditions: [], operator: '&'}, - scrollbarVisible: true, - selected: [], - sort: Ox.clone(sort, true), - unique: 'file' - }) - .bindEvent({ - resize: function(data) { - tracklistSize = data.size; - $list.setColumnWidth('title', tracklistSize - 96 - Ox.UI.SCROLLBAR_SIZE); - } - }); - return $list; - } - - function trackAlbumList() { - return Ox.IconList({ - fixedRatio: 1, - item: function(data, sort, size) { - var key = Ox.contains(['artist', 'title'], sort[0].key) - ? 'year' : sort[0].key, - column = Ox.getObjectById(columns, key), - info = (column.format || Ox.identity)(data[key]); - return { - height: size, - id: data.id, - info: info, - title: [data.artist, data.title].join(' — '), - url: data.artwork, - width: size - } - }, - items: albums, - max: 1, - orientation: 'horizontal', - pageLength: 100, - query: {conditions: [], operator: '&'}, - selected: [], - size: 64, - sort: Ox.clone(sort, true), - unique: 'id' + Ox.clone(Ox.getObjectById(app.data.albums, albumId)), + {albumId: albumId, id: v.id, index: r.length} + ) + ); + }, [])); }); - } + }; + + app.utils.resizeWindow = function() { + + }; + + app.load(); + + window.app = app; }); diff --git a/examples/ui/audio_player/mp3/Danger Mouse/2004 The Grey Album/03 Encore.mp3 b/examples/ui/audio_player/mp3/Danger Mouse/2004 The Grey Album/01-03 Encore.mp3 similarity index 100% rename from examples/ui/audio_player/mp3/Danger Mouse/2004 The Grey Album/03 Encore.mp3 rename to examples/ui/audio_player/mp3/Danger Mouse/2004 The Grey Album/01-03 Encore.mp3 diff --git a/examples/ui/audio_player/mp3/Danger Mouse/artwork.png b/examples/ui/audio_player/mp3/Danger Mouse/artwork.png new file mode 100644 index 00000000..61c12fa2 Binary files /dev/null and b/examples/ui/audio_player/mp3/Danger Mouse/artwork.png differ diff --git a/examples/ui/audio_player/mp3/Death Grips/2012 No Love Deep Web/03 No Love.mp3 b/examples/ui/audio_player/mp3/Death Grips/2012 No Love Deep Web/01-03 No Love.mp3 similarity index 100% rename from examples/ui/audio_player/mp3/Death Grips/2012 No Love Deep Web/03 No Love.mp3 rename to examples/ui/audio_player/mp3/Death Grips/2012 No Love Deep Web/01-03 No Love.mp3 diff --git a/examples/ui/audio_player/mp3/Death Grips/2012 No Love Deep Web/09 Deep Web.mp3 b/examples/ui/audio_player/mp3/Death Grips/2012 No Love Deep Web/01-09 Deep Web.mp3 similarity index 100% rename from examples/ui/audio_player/mp3/Death Grips/2012 No Love Deep Web/09 Deep Web.mp3 rename to examples/ui/audio_player/mp3/Death Grips/2012 No Love Deep Web/01-09 Deep Web.mp3 diff --git a/examples/ui/audio_player/mp3/Death Grips/artwork.png b/examples/ui/audio_player/mp3/Death Grips/artwork.png new file mode 100644 index 00000000..48e6d15a Binary files /dev/null and b/examples/ui/audio_player/mp3/Death Grips/artwork.png differ