From 31c1ee7fba8630d9c0b4d06ea7e480596efb93ee Mon Sep 17 00:00:00 2001 From: rolux Date: Thu, 29 Sep 2011 17:25:04 +0000 Subject: [PATCH] various improvements for lists --- pandora/itemlist/models.py | 2 +- pandora/itemlist/views.py | 5 + static/favicon.ico | 1 + static/js/pandora.js | 1 - static/js/pandora/URL.js | 2 +- static/js/pandora/autovalidate.js | 4 +- static/js/pandora/ui/account.js | 2 +- static/js/pandora/ui/deleteListDialog.js | 54 +++ static/js/pandora/ui/folderList.js | 54 +-- static/js/pandora/ui/folders.js | 14 +- static/js/pandora/ui/info.js | 47 +- static/js/pandora/ui/listDialog.js | 484 +++++++++++++-------- static/js/pandora/ui/menu.js | 39 +- static/js/pandora/ui/videoPreview.js | 21 +- static/js/pandora/{pandora.js => utils.js} | 138 +++++- static/json/pandora.json | 85 ++-- static/png/list256.png | Bin 0 -> 270 bytes 17 files changed, 636 insertions(+), 317 deletions(-) create mode 120000 static/favicon.ico create mode 100644 static/js/pandora/ui/deleteListDialog.js rename static/js/pandora/{pandora.js => utils.js} (85%) create mode 100644 static/png/list256.png diff --git a/pandora/itemlist/models.py b/pandora/itemlist/models.py index da41abd7..adc5b628 100644 --- a/pandora/itemlist/models.py +++ b/pandora/itemlist/models.py @@ -35,7 +35,7 @@ class List(models.Model): upload_to=lambda i, x: i.path("icon.jpg")) view = models.TextField(default=settings.CONFIG['user']['ui']['listView']) - sort = TupleField(default=tuple(settings.CONFIG['user']['ui']['listSort']), editable=False) + sort = TupleField(default=settings.CONFIG['user']['ui']['listSort'], editable=False) poster_frames = TupleField(default=[], editable=False) diff --git a/pandora/itemlist/views.py b/pandora/itemlist/views.py index 1622001c..feed6026 100644 --- a/pandora/itemlist/views.py +++ b/pandora/itemlist/views.py @@ -238,6 +238,8 @@ def addList(request): list.view = data['view'] if 'sort' in data: list.sort= tuple(data['sort']) + if 'posterFrames' in data: + list.poster_frames = tuple(data['posterFrames']) list.save() @@ -245,6 +247,9 @@ def addList(request): for item in Item.objects.filter(itemId__in=data['items']): list.add(item) + if 'posterFrames' in data: + list.update_icon() + if list.status == 'featured': pos, created = models.Position.objects.get_or_create(list=list, user=request.user, section='featured') diff --git a/static/favicon.ico b/static/favicon.ico new file mode 120000 index 00000000..9fc257be --- /dev/null +++ b/static/favicon.ico @@ -0,0 +1 @@ +png/icon16.png \ No newline at end of file diff --git a/static/js/pandora.js b/static/js/pandora.js index 4e2b3ede..f822e0a9 100644 --- a/static/js/pandora.js +++ b/static/js/pandora.js @@ -137,7 +137,6 @@ Ox.load({ Ox.Theme(pandora.user.ui.theme); pandora.$ui.appPanel = pandora.ui.appPanel().display(); - Ox.Request.requests() && pandora.$ui.loadingIcon.start(); pandora.$ui.body.ajaxStart(pandora.$ui.loadingIcon.start); pandora.$ui.body.ajaxStop(pandora.$ui.loadingIcon.stop); diff --git a/static/js/pandora/URL.js b/static/js/pandora/URL.js index ee7f7f9d..7cd784f6 100644 --- a/static/js/pandora/URL.js +++ b/static/js/pandora/URL.js @@ -116,7 +116,7 @@ pandora.URL = (function() { pandora.$ui.helpDialog = pandora.ui.helpDialog().open(); } else if (['signup', 'signin'].indexOf(state.page) > -1) { if (pandora.user.level == 'guest') { - pandora.ui.accountDialog(state.page).open(); + pandora.$ui.accountDialog = pandora.ui.accountDialog(state.page).open(); } else { pandora.URL.replace('/'); } diff --git a/static/js/pandora/autovalidate.js b/static/js/pandora/autovalidate.js index a56718e2..b7c35bb6 100644 --- a/static/js/pandora/autovalidate.js +++ b/static/js/pandora/autovalidate.js @@ -1,14 +1,14 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript pandora.autovalidateCode = function(value, blur, callback) { value = value.toUpperCase().split('').map(function(v) { - return /[0-9A-Z]/(v) ? v : null; + return /[0-9A-Z]/.test(v) ? v : null; }).join(''); callback(value); }; pandora.autovalidateEmail = function(value, blur, callback) { value = value.toLowerCase().split('').map(function(v, i) { - return /[0-9a-z\.\+\-_@]/(v) ? v : null; + return /[0-9a-z\.\+\-_@]/.test(v) ? v : null; }).join(''); callback(value); }; diff --git a/static/js/pandora/ui/account.js b/static/js/pandora/ui/account.js index 020df2e6..39b01847 100644 --- a/static/js/pandora/ui/account.js +++ b/static/js/pandora/ui/account.js @@ -174,7 +174,7 @@ pandora.ui.accountForm = function(action, value) { }, validate: function(data) { - //Ox.print('FORM VALIDATE', data) + Ox.print('FORM VALIDATE', data, action, 'submit' + Ox.toTitleCase(action)); pandora.$ui.accountDialog[ (data.valid ? 'enable' : 'disable') + 'Button' ]('submit' + Ox.toTitleCase(action)); diff --git a/static/js/pandora/ui/deleteListDialog.js b/static/js/pandora/ui/deleteListDialog.js new file mode 100644 index 00000000..b6e5a125 --- /dev/null +++ b/static/js/pandora/ui/deleteListDialog.js @@ -0,0 +1,54 @@ +// vim: et:ts=4:sw=4:sts=4:ft=javascript + +pandora.ui.deleteListDialog = function() { + + var listData = pandora.getListData(), + $folderList = pandora.$ui.folderList[listData.folder], + that = Ox.Dialog({ + buttons: [ + Ox.Button({ + id: 'cancel', + title: 'Cancel' + }).bindEvent({ + click: function() { + that.close(); + } + }), + Ox.Button({ + id: 'delete', + title: 'Delete' + }).bindEvent({ + click: function() { + that.close(); + pandora.api.removeList({ + id: listData.id + }, function(result) { + Ox.Request.clearCache('findLists'); + Ox.Request.clearCache(listData.id); + $folderList + .options({selected: []}) + .bindEventOnce({ + load: function() { + pandora.UI.set('lists.' + listData.id, null); + pandora.UI.set({ + find: pandora.site.user.ui.find + }); + } + }) + .reloadList(); + }); + } + }) + ], + content: $('
') + .css({margin: '16px'}) + .html('Do you want to delete the list "' + listData.id + '"?'), + height: 128, + keys: {enter: 'delete', escape: 'cancel'}, + title: 'Delete List', + width: 304 + }); + + return that; + +} \ No newline at end of file diff --git a/static/js/pandora/ui/folderList.js b/static/js/pandora/ui/folderList.js index b87c7ce2..4e1918ea 100644 --- a/static/js/pandora/ui/folderList.js +++ b/static/js/pandora/ui/folderList.js @@ -11,13 +11,14 @@ pandora.ui.folderList = function(id) { clickable: function(data) { return data.user == pandora.user.username; }, - format: function() { + format: function(value, data) { return $('').attr({ - src: Ox.UI.getImageURL('symbolIcon') + src: '/list/' + data.id + '/icon16.jpg' }).css({ - width: '10px', - height: '10px', - padding: '3px' + width: '14px', + height: '14px', + borderRadius: '4px', + margin: '0 0 0 -3px' }); }, id: 'user', @@ -297,11 +298,11 @@ pandora.ui.folderList = function(id) { click: function(data) { //var $list = pandora.$ui.folderList[id]; if (data.key == 'user') { - pandora.$ui.filterDialog = pandora.ui.listDialog(that.value(data.id), 'icon').open(); + pandora.$ui.listDialog = pandora.ui.listDialog('icon').open(); } else if (data.key == 'type') { if (that.value(data.id, 'type') == 'smart') { - pandora.$ui.filterDialog = pandora.ui.listDialog(that.value(data.id), 'query').open(); + pandora.$ui.listDialog = pandora.ui.listDialog('query').open(); } } else if (data.key == 'status') { pandora.api.editList({ @@ -318,44 +319,7 @@ pandora.ui.folderList = function(id) { }, 'delete': function(data) { if (id == 'personal') { - var $dialog = Ox.Dialog({ - buttons: [ - Ox.Button({ - id: 'cancel', - title: 'Cancel' - }).bindEvent({ - click: function() { - $dialog.close(); - } - }), - Ox.Button({ - id: 'delete', - title: 'Delete' - }).bindEvent({ - click: function() { - $dialog.close(); - that.options({selected: []}); - pandora.api.removeList({ - id: data.ids[0] - }, function(result) { - pandora.UI.set('lists.' + data.ids[0], null); - pandora.UI.set({ - find: pandora.site.user.ui.find - }); - Ox.Request.clearCache(); // fixme: remove - that.reloadList(); - }); - } - }) - ], - content: $('
') - .css({margin: '16px'}) - .html('Do you want to delete the list ' + data.ids[0] + '?'), - height: 128, - keys: {enter: 'delete', escape: 'cancel'}, - title: 'Delete List', - width: 304 - }).open(); + pandora.ui.deleteListDialog().open(); } else if (id == 'favorite') { that.options({selected: []}); pandora.api.unsubscribeFromList({ diff --git a/static/js/pandora/ui/folders.js b/static/js/pandora/ui/folders.js index 2c85f2e0..277117b7 100644 --- a/static/js/pandora/ui/folders.js +++ b/static/js/pandora/ui/folders.js @@ -23,11 +23,11 @@ pandora.ui.folders = function() { } else { extras = [Ox.Select({ items: [ - { id: 'new', title: 'New List...' }, - { id: 'newfromselection', title: 'New List from Current Selection...', disabled: true }, + { id: 'newlist', title: 'New List...' }, + { id: 'newlistfromselection', title: 'New List from Current Selection...', disabled: true }, {}, - { id: 'newsmart', title: 'New Smart List...' }, - { id: 'newfromresults', title: 'New Smart List from Current Results...', disabled: true }, + { id: 'newsmartlist', title: 'New Smart List...' }, + { id: 'newsmartlistfromresults', title: 'New Smart List from Current Results...', disabled: true }, {}, { id: 'duplicate', title: 'Duplicate List' }, { id: 'copyselection', title: 'Copy Selection to List...' }, @@ -56,7 +56,7 @@ pandora.ui.folders = function() { operator: '&' } }); - Ox.Request.clearCache(); // fixme: remove + Ox.Request.clearCache('"findLists"'); $list.reloadList().bindEventOnce({ load: function(data) { $list.gainFocus() @@ -152,7 +152,9 @@ pandora.ui.folders = function() { pandora.$ui.folderList.favorite.options({selected: [listData.id]}); } else { // and nowhere else - pandora.URL.set(''); + pandora.UI.set({ + find: pandora.site.user.ui.find + }); } } pandora.$ui.folderBrowser.featured.replaceWith( diff --git a/static/js/pandora/ui/info.js b/static/js/pandora/ui/info.js index 8289dafb..57968a4a 100644 --- a/static/js/pandora/ui/info.js +++ b/static/js/pandora/ui/info.js @@ -30,12 +30,33 @@ pandora.ui.info = function() { if (result.data) { pandora.$ui.videoPreview && pandora.$ui.videoPreview.removeElement(); pandora.$ui.videoPreview = pandora.ui.videoPreview({ - duration: result.data.duration, - frameRatio: result.data.videoRatio, - height: pandora.getInfoHeight(), - id: id, - width: pandora.user.ui.sidebarSize - }).appendTo(pandora.$ui.info); + duration: result.data.duration, + frameRatio: result.data.videoRatio, + height: pandora.getInfoHeight(), + id: id, + width: pandora.user.ui.sidebarSize + }) + .bindEvent({ + click: function(data) { + pandora.UI.set( + 'videoPoints.' + id, + {'in': 0, out: 0, position: data.position} + ); + if (pandora.user.ui.item && ['video', 'timeline'].indexOf(pandora.user.ui.itemView) > -1) { + pandora.$ui[ + pandora.user.ui.itemView == 'video' ? 'player' : 'editor' + ].options({ + position: data.position + }); + } else { + pandora.UI.set({ + item: id, + itemView: pandora.user.ui.videoView + }); + } + } + }) + .appendTo(pandora.$ui.info); } }); } @@ -66,7 +87,7 @@ pandora.ui.info = function() { pandora.$ui.videoPreview.options({ height: pandora.getInfoHeight(), width: pandora.user.ui.sidebarSize - }) + }); } }; return that; @@ -75,14 +96,22 @@ pandora.ui.info = function() { pandora.ui.listInfo = function(data) { var that = $('
').css({padding: '16px', textAlign: 'center'}); var $icon = $('') - .attr({src: !pandora.user.ui._list ? '/static/png/icon256.png' : Ox.UI.getImageURL('symbolIcon')}) + .attr({ + src: !pandora.user.ui._list + ? '/static/png/icon256.png' + : '/list/' + pandora.user.ui._list + '/icon256.jpg?' + Ox.uid() + }) .css(getIconCSS()) .appendTo(that); $('
').css({padding: '16px 0 16px 0', fontWeight: 'bold'}).html(!pandora.user.ui._list ? 'All Movies' : pandora.user.ui._list.replace(':', ': ')).appendTo(that); $('
').css({textAlign: 'left'}).html(Ox.repeat('This is the list info text. ', 10)).appendTo(that); function getIconCSS() { var size = Math.round(pandora.user.ui.sidebarSize / 2); - return {width: size + 'px', height: size + 'px'}; + return { + width: size + 'px', + height: size + 'px', + borderRadius: Math.round(size / 4) + 'px' + }; } that.resizeIcon = function() { $icon.css(getIconCSS()); diff --git a/static/js/pandora/ui/listDialog.js b/static/js/pandora/ui/listDialog.js index f7f606bf..5cc7ce2f 100644 --- a/static/js/pandora/ui/listDialog.js +++ b/static/js/pandora/ui/listDialog.js @@ -1,43 +1,81 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript -pandora.ui.listDialog = function(list, section) { +pandora.ui.listDialog = function(section) { - var tabs = Ox.merge([ - {id: 'general', title: 'General'}, - {id: 'icon', title: 'Icon'} - ], list.type == 'smart' - ? {id: 'query', title: 'Query'} - : [] - ); + section = section || 'general'; + var width = getWidth(section); + var listData = pandora.getListData(), + tabs = Ox.merge([ + {id: 'general', title: 'General'}, + {id: 'icon', title: 'Icon'} + ], listData.type == 'smart' + ? [{id: 'query', title: 'Query'}] + : [] + ); Ox.getObjectById(tabs, section).selected = true; + var $tabPanel = Ox.TabPanel({ content: function(id) { if (id == 'general') { - return Ox.Element({}).css({padding: '16px'}).html('General'); + return pandora.ui.listGeneralPanel(listData); } else if (id == 'icon') { - return pandora.ui.listIconPanel(list); + return pandora.ui.listIconPanel(listData); } else if (id == 'query') { - return pandora.$ui.filter = pandora.ui.filter(list); + return pandora.$ui.filter = pandora.ui.filter(listData); } }, tabs: tabs }) .bindEvent({ change: function(data) { + var width = getWidth(data.selected); $dialog.options({ - title: 'Smart List - ' + list.name + ' - ' + maxWidth: width, + minWidth: width, + title: 'Smart List - ' + listData.name + ' - ' + Ox.getObjectById(tabs, data.selected).title }); - if (data.selected == 'icon') { - $dialog.options({ - maxWidth: 704 + Ox.UI.SCROLLBAR_SIZE, - minWidth: 704 + Ox.UI.SCROLLBAR_SIZE, - width: 704 + Ox.UI.SCROLLBAR_SIZE - }); - } + $dialog.setSize(width, 312); + $findElement[data.selected == 'icon' ? 'show' : 'hide'](); } }); + var $findElement = Ox.FormElementGroup({ + elements: [ + pandora.$ui.findIconItemSelect = Ox.Select({ + items: pandora.site.findKeys, + overlap: 'right', + type: 'image' + }) + .bindEvent({ + change: function(data) { + + } + }), + pandora.$ui.findIconItemInput = Ox.Input({ + changeOnKeypress: true, + clear: true, + placeholder: 'Find: Foo', + width: 120 + Ox.UI.SCROLLBAR_SIZE + }) + .bindEvent({ + change: function(data) { + + } + }) + ], + }) + .css({ + float: 'right', + margin: '4px', + align: 'right' + }); + if (section != 'icon') { + $findElement.hide(); + } + $findElement.appendTo($tabPanel.children('.OxBar')); + + var $dialog = Ox.Dialog({ buttons: [ Ox.Button({ @@ -49,196 +87,284 @@ pandora.ui.listDialog = function(list, section) { alert(JSON.stringify(pandora.$ui.filter.options('query'))); } }), - /* - Ox.Button({ - id: 'cancel', - title: 'Cancel' - }) - .bindEvent({ - click: function() { - pandora.$ui.filterDialog.close(); - } - }), - */ Ox.Button({ id: 'done', title: 'Done' }) .bindEvent({ click: function() { - pandora.$ui.filterDialog.close(); + $dialog.close(); } }) ], content: $tabPanel, - maxWidth: (section == 'icon' ? 704 : 648) + Ox.UI.SCROLLBAR_SIZE, + maxWidth: width, minHeight: 312, - minWidth: (section == 'icon' ? 704 : 648) + Ox.UI.SCROLLBAR_SIZE, + minWidth: width, height: 312, // keys: {enter: 'save', escape: 'cancel'}, - //title: list ? 'Smart List - ' + list.name : 'Advanced Find', - title: 'Smart List - ' + list.name + ' - ' - + Ox.getObjectById(tabs, section).title, - width: (section == 'icon' ? 704 : 648) + Ox.UI.SCROLLBAR_SIZE + title: 'Smart List - ' + listData.name, + width: width }); + function getWidth(section) { + return section == 'general' ? 496 + : (section == 'icon' ? 696 : 648) + Ox.UI.SCROLLBAR_SIZE; + } + return $dialog; }; -pandora.ui.listIconPanel = function(list) { +pandora.ui.listGeneralPanel = function(listData) { + var that = Ox.Element({}), + $icon = $('') + .attr({src: '/list/' + listData.id + '/icon256.jpg?' + Ox.uid()}) + .css({position: 'absolute', left: '16px', top: '16px', width: '128px', height: '128px', borderRadius: '32px'}) + .appendTo(that); + $nameInput = Ox.Input({ + label: 'Name', + labelWidth: 80, + value: listData.name, + width: 320 + }) + .css({position: 'absolute', left: '160px', top: '16px'}) + .appendTo(that); + $itemsInput = Ox.Input({ + disabled: true, + label: 'Items', + labelWidth: 80, + value: listData.items, + width: 320 + }) + .css({position: 'absolute', left: '160px', top: '40px'}) + .appendTo(that); + $statusSelect = Ox.Select({ + items: [ + {id: 'private', title: 'Private', selected: listData.status == 'private'}, + {id: 'public', title: 'Public', selected: listData.status == 'public'}, + {id: 'featured', title: 'Featured', selected: listData.status == 'featured'}, + ], + label: 'Status', + labelWidth: 80, + width: 320 + }) + .css({position: 'absolute', left: '160px', top: '64px'}) + .appendTo(that); + $subscribersInput = Ox.Input({ + disabled: true, + label: 'Subscribers', + labelWidth: 80, + value: 0, + width: 320 + }) + .css({position: 'absolute', left: '160px', top: '88px'}) + .appendTo(that); + return that; +}; - var quarter = 'top-left'; +pandora.ui.listIconPanel = function(listData) { - var $interface = Ox.Element({ - tooltip: function(e) { - return 'Edit ' + $(e.target).attr('id').replace('-', ' ') + ' image'; - } - }) - .css({position: 'absolute', width: '256px', height: '256px', margin: '16px', cursor: 'pointer'}) - .click(function(e) { - quarter = $(e.target).attr('id'); - renderQuarters(); + var quarter = 0, + quarters = ['top-left', 'top-right', 'bottom-left', 'bottom-right'], + + $iconPanel = Ox.Element(), + + $icon = $('') + .attr({src: '/list/' + listData.id + '/icon256.jpg?' + Ox.uid()}) + .css({position: 'absolute', borderRadius: '64px', margin: '16px'}) + .appendTo($iconPanel), + + $previewPanel = Ox.Element(), + + $preview, + + $list = Ox.Element(), + + that = Ox.SplitPanel({ + elements: [ + { + element: $iconPanel, + size: 280 + }, + { + element: $previewPanel + }, + { + element: $list, + size: 144 + Ox.UI.SCROLLBAR_SIZE + } + ], + orientation: 'horizontal' }); - var $list = Ox.IconList({ - borderRadius: 16, - item: function(data, sort) { - var size = 128; - return { - height: size, - id: data.id, - info: data[['title', 'director'].indexOf(sort[0].key) > -1 ? 'year' : sort[0].key], - title: data.title + (data.director.length ? ' (' + data.director.join(', ') + ')' : ''), - url: '/' + data.id + '/icon' + size + '.jpg', - width: size - }; + pandora.api.findLists({ + query: { + conditions: [{key: 'id', value: listData.id, operator: '=='}], + operator: '&' }, - items: function(data, callback) { - //Ox.print('data, pandora.Query.toObject', data, pandora.Query.toObject()) - pandora.api.find(Ox.extend(data, { - query: { - conditions: [{key: 'list', value: list.id, operator: '='}], - operator: '&' - } - }), callback); - }, - keys: ['director', 'duration', 'id', 'title', 'videoRatio', 'year'], - max: 1, - min: 1, - orientation: 'vertical', - size: 128, - sort: pandora.user.ui.listSort, - unique: 'id' - }) - .css({width: '144px'}) - .bindEvent({ - select: function(data) { - var value = $list.value(data.ids[0]); - //frameCSS['border-' + quarter + '-radius'] = '120px'; - Ox.print("$$$", value) - $preview.empty().append( - pandora.ui.videoPreview({ - duration: value.duration, - frameRatio: value.videoRatio, - height: 256, - id: value.id, - width: 240 - }) - .css({margin: '16px', overflow: 'hidden'}) - ); - } - }) - - var $preview = Ox.Element() - .css({width: '256px', height: '256px'}); + keys: ['posterFrames'] + }, function(result) { - renderQuarters(); + var posterFrames = result.data.items[0].posterFrames, + posterFrame = posterFrames[quarter], + + $interface = Ox.Element({ + tooltip: function(e) { + return 'Edit ' + $(e.target).attr('id').replace('-', ' ') + ' image'; + } + }) + .css({ + position: 'absolute', + width: '256px', + height: '256px', + marginLeft: '16px', + marginTop: '16px', + cursor: 'pointer' + }) + .bind({ + click: function(e) { + clickIcon(e); + }, + dblclick: function(e) { + clickIcon(e, true); + } + }) + .appendTo($iconPanel); + + renderQuarters(); + + $list = Ox.IconList({ + borderRadius: 16, + item: function(data, sort) { + var size = 128; + return { + height: size, + id: data.id, + info: data[['title', 'director'].indexOf(sort[0].key) > -1 ? 'year' : sort[0].key], + title: data.title + (data.director.length ? ' (' + data.director.join(', ') + ')' : ''), + url: '/' + data.id + '/icon' + size + '.jpg', + width: size + }; + }, + items: function(data, callback) { + //Ox.print('data, pandora.Query.toObject', data, pandora.Query.toObject()) + pandora.api.find(Ox.extend(data, { + query: { + conditions: [{key: 'list', value: listData.id, operator: '='}], + operator: '&' + } + }), callback); + }, + keys: ['director', 'duration', 'id', 'posterFrame', 'title', 'videoRatio', 'year'], + max: 1, + min: 1, + //orientation: 'vertical', + selected: posterFrame ? [posterFrame.item] : [], + size: 128, + sort: pandora.user.ui.listSort, + unique: 'id' + }) + //.css({width: '144px'}) + .bindEvent({ + open: function(data) { + setPosterFrame(data.ids[0], $list.value(data.ids[0], 'posterFrame')) + }, + select: function(data) { + renderPreview($list.value(data.ids[0])); + } + }) + .bindEventOnce({ + load: function() { + var itemData; + if (!posterFrame) { + itemData = $list.value(0); + $list.options({selected: [itemData.id]}); + } else { + itemData = $list.value(posterFrame.item); + } + renderPreview(itemData); + } + }) + .gainFocus(); + + that.replaceElement(2, $list); + + function clickIcon(e, isDoubleClick) { + quarter = quarters.indexOf($(e.target).attr('id')); + renderQuarters(); + if (isDoubleClick) { + var item = posterFrames[quarter].item; + $list.options({selected: [item]}); + renderPreview($list.value(item), posterFrames[quarter].position); + } + } + + function renderPreview(itemData, position) { + $preview = pandora.ui.videoPreview({ + duration: itemData.duration, + frameRatio: itemData.videoRatio, + height: 256, + id: itemData.id, + position: position, + width: 256 + }) + .css({marginLeft: '8px', marginTop: '16px', overflow: 'hidden'}) + .bindEvent({ + click: function(data) { + setPosterFrame(itemData.id, data.position); + } + }); + /* + // fixme: need canvas for this + $($preview.children('.OxFrame')[0]) + .css('border-' + quarter + '-radius', '128px'); + */ + $previewPanel.empty().append($preview); + } + + function renderQuarters() { + $interface.empty(); + quarters.forEach(function(q, i) { + $interface.append( + $('
') + .attr({id: q}) + .css({ + float: 'left', + width: '126px', + height: '126px', + border: '1px solid rgba(255, 255, 255, ' + (i == quarter ? 0.75 : 0) + ')', + background: 'rgba(0, 0, 0, ' + (i == quarter ? 0 : 0.75) + ')' + }) + .css('border-' + q + '-radius', '64px') + ); + }); + } + + function setPosterFrame(item, position) { + var posterFrame = {item: item, position: position}; + if (posterFrames.length) { + posterFrames[quarter] = posterFrame; + } else { + posterFrames = Ox.repeat([posterFrame], 4); + } + pandora.api.editList({ + id: listData.id, + posterFrames: posterFrames + }, function() { + $icon.attr({src: '/list/' + listData.id + '/icon256.jpg?' + Ox.uid()}); + }); + $preview.options({position: position}); + } + + }); function renderFrame() { $frame.css({borderRadius: 0}); - $frame.css('border-' + quarter + '-radius', '128px'); + $frame.css('border-' + quarters[quarter] + '-radius', '128px'); } - function renderQuarters() { - $interface.empty(); - ['top-left', 'top-right', 'bottom-left', 'bottom-right'].forEach(function(q) { - $interface.append( - $('
') - .attr({id: q}) - .css({ - float: 'left', - width: '126px', - height: '126px', - border: '1px solid rgba(255, 255, 255, ' + (q == quarter ? 0.75 : 0) + ')', - background: 'rgba(0, 0, 0, ' + (q == quarter ? 0 : 0.75) + ')' - }) - .css('border-' + q + '-radius', '64px') - ); - }); - } - - var that = Ox.SplitPanel({ - elements: [ - { - element: Ox.Element({}).append( - $('').css({position: 'absolute', margin: '16px'}).attr({src: '/static/png/icon256.png'}) - ).append( - $interface - ), - size: 288 - }, - { - element: Ox.SplitPanel({ - elements: [ - { - element: Ox.Bar({size: 24}).append( - Ox.FormElementGroup({ - elements: [ - pandora.$ui.findIconItemSelect = Ox.Select({ - items: pandora.site.findKeys, - overlap: 'right', - type: 'image' - }) - .bindEvent({ - change: function(data) { - } - }), - pandora.$ui.findIconItemInput = Ox.Input({ - changeOnKeypress: true, - clear: true, - placeholder: 'Find: Foo', - width: 120 - }) - .bindEvent({ - change: function(data) { - - } - }) - ], - }) - .css({ - float: 'right', - margin: '4px', - align: 'right' - }) - ), - size: 24 - }, - { - element: $list - } - ], - orientation: 'vertical' - }) - }, - { - element: $preview, - size: 272 - } - ], - orientation: 'horizontal' - }) return that; + } diff --git a/static/js/pandora/ui/menu.js b/static/js/pandora/ui/menu.js index 55a64299..7e801d0a 100644 --- a/static/js/pandora/ui/menu.js +++ b/static/js/pandora/ui/menu.js @@ -203,6 +203,16 @@ pandora.ui.mainMenu = function() { 'signup', 'signin', 'signout', 'preferences', 'help' ].indexOf(data.id) > -1) { pandora.URL.push('/' + data.id); + } else if ([ + 'newlist', 'newlistfromselection', 'newsmartlist', 'newsmartlistfromresults' + ].indexOf(data.id) > -1) { + pandora.addList(data.id.indexOf('smart') > -1, data.id.indexOf('from') > -1); + } else if (data.id == 'duplicatelist') { + pandora.addList(pandora.user.ui._list); + } else if (data.id == 'editlist') { + pandora.ui.listDialog().open(); + } else if (data.id == 'deletelist') { + pandora.ui.deleteListDialog().open(); } else if (data.id == 'stills') { var id = pandora.user.ui.item || pandora.user.ui.listItem; pandora.$ui.postersDialog = pandora.ui.framesDialog(id).open(); @@ -230,7 +240,19 @@ pandora.ui.mainMenu = function() { Ox.Request.clearCache(); } }, - pandora_listView: function(data) { + pandora_find: function() { + var action = ui._list + && pandora.getListData(ui._list).user == pandora.user.username + ? 'enableItem' : 'disableItem'; + that[action]('editlist'); + that[action]('duplicatelist'); + that[action]('deletelist'); + that[pandora.user.ui.listSelection.length ? 'enableItem' : 'disableItem']('newlistfromselection'); + }, + pandora_listselection: function(data) { + that[data.value.length ? 'enableItem' : 'disableItem']('newlistfromselection'); + }, + pandora_listview: function(data) { if (pandora.isClipView() != pandora.isClipView(data.previousValue)) { that.replaceMenu('sortMenu', getSortMenu()); } @@ -259,15 +281,14 @@ pandora.ui.mainMenu = function() { }), [ {}, - { id: 'newlist', title: 'New List...', keyboard: 'control n' }, - { id: 'newlistfromselection', title: 'New List from Selection...', disabled: true, keyboard: 'shift control n' }, - { id: 'newsmartlist', title: 'New Smart List...', keyboard: 'alt control n' }, - { id: 'newsmartlistfromresults', title: 'New Smart List from Results...', keyboard: 'shift alt control n' }, - { id: 'duplicatelist', title: 'Duplicate Selected List', keyboard: 'control d' }, + { id: 'newlist', title: 'New List', keyboard: 'control n' }, + { id: 'newlistfromselection', title: 'New List from Selection', disabled: ui.listSelection.length == 0, keyboard: 'shift control n' }, + { id: 'newsmartlist', title: 'New Smart List', keyboard: 'alt control n' }, + { id: 'newsmartlistfromresults', title: 'New Smart List from Results', keyboard: 'shift alt control n' }, {}, - { id: 'addmovietolist', title: ['Add Selected ' + pandora.site.itemName.singular + ' to List...', 'Add Selected ' + pandora.site.itemName.plural + ' to List...'], disabled: true }, - {}, - { id: 'setposterframe', title: 'Set Poster Frame', disabled: true } + { id: 'duplicatelist', title: 'Duplicate Selected List', disabled: !pandora.user.ui._list, keyboard: 'control d' }, + { id: 'editlist', title: 'Edit Selected List...', disabled: !pandora.user.ui._list, keyboard: 'control e' }, + { id: 'deletelist', title: 'Delete Selected List...', disabled: !pandora.user.ui._list, keyboard: 'delete' }, ] )}; }; diff --git a/static/js/pandora/ui/videoPreview.js b/static/js/pandora/ui/videoPreview.js index b3ca98cd..7f172a4c 100644 --- a/static/js/pandora/ui/videoPreview.js +++ b/static/js/pandora/ui/videoPreview.js @@ -14,29 +14,10 @@ pandora.ui.videoPreview = function(data) { frameCSS: data.frameCSS, frameRatio: data.frameRatio, height: data.height, + position: data.position, scaleToFill: true, timeline: '/' + data.id + '/timeline16p.png', width: data.width - }) - .bindEvent({ - click: function(event) { - pandora.UI.set( - 'videoPoints.' + data.id, - {'in': 0, out: 0, position: event.position} - ); - if (pandora.user.ui.item && ['video', 'timeline'].indexOf(pandora.user.ui.itemView) > -1) { - pandora.$ui[ - pandora.user.ui.itemView == 'video' ? 'player' : 'editor' - ].options({ - position: event.position - }); - } else { - pandora.UI.set({ - item: data.id, - itemView: pandora.user.ui.videoView - }); - } - } }); return that; }; diff --git a/static/js/pandora/pandora.js b/static/js/pandora/utils.js similarity index 85% rename from static/js/pandora/pandora.js rename to static/js/pandora/utils.js index e3a528ad..d766b812 100644 --- a/static/js/pandora/pandora.js +++ b/static/js/pandora/utils.js @@ -1,5 +1,139 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript +pandora.addList = function() { + // addList(isSmart, isFrom) or addList(list) [=duplicate] + var $folderList = pandora.$ui.folderList.personal, + isDuplicate = arguments.length == 1, + isSmart, isFrom, list, listData, data; + if (!isDuplicate) { + isSmart = arguments[0]; + isFrom = arguments[1]; + data = { + name: 'Untitled', + status: 'private', + type: !isSmart ? 'static' : 'smart' + }; + if (isFrom) { + if (!isSmart) { + data.items = pandora.user.ui.listSelection; + } else { + data.query = pandora.user.ui.find; + } + } + } else { + list = arguments[0]; + listData = pandora.getListData(); + data = { + name: listData.name, + status: listData.status, + type: listData.type + }; + if (data.type == 'smart') { + data.query = listData.query; + } + } + if (isDuplicate && listData.type == 'static') { + var query = { + conditions: [{key: 'list', value: list, operator: '=='}], + operator: '&' + }; + pandora.api.find({ + query: query + }, function(result) { + if (result.data.items) { + pandora.api.find({ + query: query, + keys: ['id'], + sort: [{key: 'id', operator: ''}] + }, function(result) { + var items = result.data.items.map(function(item) { + return item.id; + }); + addList(items); + }) + } else { + addList(); + } + }) + } else { + addList(); + } + function addList(items) { + pandora.api.addList(data, function(result) { + var newList = result.data.id; + if (items) { + pandora.api.addListItems({ + list: newList, + items: items + }, function() { + getPosterFrames(newList); + }) + } else { + getPosterFrames(newList); + } + }); + } + function getPosterFrames(newList) { + if (!isDuplicate) { + pandora.api.find({ + query: { + conditions: [{key: 'list', value: newList, operator: '=='}], + operator: '&' + }, + keys: ['id', 'posterFrame'], + sort: [{key: 'votes', operator: ''}], // fixme: may not always exist + range: [0, 4] + }, function(result) { + var posterFrames = result.data.items.map(function(item) { + return {item: item.id, position: item.posterFrame}; + }); + posterFrames = posterFrames.length == 1 + ? Ox.repeat([posterFrames[0]], 4) + : posterFrames.length == 2 + ? [posterFrames[0], posterFrames[1], posterFrames[1], posterFrames[0]] + : posterFrames.length == 3 + ? [posterFrames[0], posterFrames[1], posterFrames[2], posterFrames[0]] + : posterFrames; + setPosterFrames(newList, posterFrames); + }) + } else { + pandora.api.findLists({ + query: { + conditions: [{key: 'id', value: list, operator: '=='}], + operator: '&' + }, + keys: ['posterFrames'] + }, function(result) { + setPosterFrames(newList, result.data.items[0].posterFrames); + }); + } + } + function setPosterFrames(newList, posterFrames) { + pandora.api.editList({ + id: newList, + posterFrames: posterFrames + }, function() { + reloadFolder(newList); + }); + } + function reloadFolder(newList) { + Ox.Request.clearCache('findLists'); + $folderList.bindEventOnce({ + load: function(data) { + $folderList.gainFocus() + .options({selected: [list]}) + .editCell(newList, 'name'); + pandora.UI.set({ + find: { + conditions: [{key: 'list', value: newList, operator: '=='}], + operator: '&' + } + }); + } + }).reloadList(); + } +}; + pandora.enableDragAndDrop = function($list, canMove) { var $tooltip = Ox.Tooltip({ @@ -482,6 +616,7 @@ pandora.signin = function(data) { pandora.user = data.user; pandora.Query.updateGroups(); Ox.Theme(pandora.user.ui.theme); + pandora.UI.set({find: pandora.user.ui.find}) pandora.$ui.appPanel.reload(); }; @@ -489,6 +624,7 @@ pandora.signout = function(data) { pandora.user = data.user; pandora.Query.updateGroups(); Ox.Theme(pandora.site.user.ui.theme); + pandora.UI.set({find: pandora.user.ui.find}) pandora.$ui.appPanel.reload(); }; @@ -713,4 +849,4 @@ pandora.selectList = function() { return state; }; -}()); \ No newline at end of file +}()); diff --git a/static/json/pandora.json b/static/json/pandora.json index 86d017cd..349325ab 100644 --- a/static/json/pandora.json +++ b/static/json/pandora.json @@ -1,51 +1,52 @@ [ - "js/pandora/pandora.js", - "js/pandora/URL.js", "js/pandora/Query.js", - "js/pandora/autovalidate.js", "js/pandora/UI.js", - "js/pandora/ui/info.js", - "js/pandora/ui/rightPanel.js", - "js/pandora/ui/folderBrowserList.js", - "js/pandora/ui/homePage.js", - "js/pandora/ui/group.js", - "js/pandora/ui/toolbar.js", - "js/pandora/ui/statusbar.js", - "js/pandora/ui/sectionButtons.js", - "js/pandora/ui/item.js", - "js/pandora/ui/folderBrowser.js", - "js/pandora/ui/publicLists.js", - "js/pandora/ui/filter.js", - "js/pandora/ui/status.js", - "js/pandora/ui/sectionbar.js", - "js/pandora/ui/folders.js", - "js/pandora/ui/mainPanel.js", - "js/pandora/ui/viewSelect.js", - "js/pandora/ui/sortSelect.js", - "js/pandora/ui/orderButton.js", - "js/pandora/ui/menu.js", + "js/pandora/URL.js", + "js/pandora/autovalidate.js", + "js/pandora/utils.js", "js/pandora/ui/Ox.FilesView.js", - "js/pandora/ui/browser.js", - "js/pandora/ui/list.js", - "js/pandora/ui/folderList.js", - "js/pandora/ui/findElement.js", - "js/pandora/ui/filterDialog.js", "js/pandora/ui/account.js", - "js/pandora/ui/folderBrowserBar.js", - "js/pandora/ui/sectionSelect.js", - "js/pandora/ui/placesDialog.js", - "js/pandora/ui/contentPanel.js", - "js/pandora/ui/backButton.js", - "js/pandora/ui/leftPanel.js", "js/pandora/ui/appPanel.js", - "js/pandora/ui/videoPreview.js", + "js/pandora/ui/backButton.js", + "js/pandora/ui/browser.js", + "js/pandora/ui/contentPanel.js", + "js/pandora/ui/deleteListDialog.js", "js/pandora/ui/editor.js", - "js/pandora/ui/infoView.js", - "js/pandora/ui/mediaView.js", - "js/pandora/ui/home.js", - "js/pandora/ui/preferencesDialog.js", - "js/pandora/ui/listDialog.js", - "js/pandora/ui/siteDialog.js", "js/pandora/ui/eventsDialog.js", - "js/pandora/ui/usersDialog.js" + "js/pandora/ui/filter.js", + "js/pandora/ui/filterDialog.js", + "js/pandora/ui/findElement.js", + "js/pandora/ui/folderBrowser.js", + "js/pandora/ui/folderBrowserBar.js", + "js/pandora/ui/folderBrowserList.js", + "js/pandora/ui/folderList.js", + "js/pandora/ui/folders.js", + "js/pandora/ui/group.js", + "js/pandora/ui/home.js", + "js/pandora/ui/homePage.js", + "js/pandora/ui/info.js", + "js/pandora/ui/infoView.js", + "js/pandora/ui/item.js", + "js/pandora/ui/leftPanel.js", + "js/pandora/ui/list.js", + "js/pandora/ui/listDialog.js", + "js/pandora/ui/mainPanel.js", + "js/pandora/ui/mediaView.js", + "js/pandora/ui/menu.js", + "js/pandora/ui/orderButton.js", + "js/pandora/ui/placesDialog.js", + "js/pandora/ui/preferencesDialog.js", + "js/pandora/ui/publicLists.js", + "js/pandora/ui/rightPanel.js", + "js/pandora/ui/sectionButtons.js", + "js/pandora/ui/sectionSelect.js", + "js/pandora/ui/sectionbar.js", + "js/pandora/ui/siteDialog.js", + "js/pandora/ui/sortSelect.js", + "js/pandora/ui/status.js", + "js/pandora/ui/statusbar.js", + "js/pandora/ui/toolbar.js", + "js/pandora/ui/usersDialog.js", + "js/pandora/ui/videoPreview.js", + "js/pandora/ui/viewSelect.js" ] diff --git a/static/png/list256.png b/static/png/list256.png new file mode 100644 index 0000000000000000000000000000000000000000..21fffbf00917b4e9aabd34c6220248543355e909 GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K58911L)MWvCLm+k4)5S5QV$R!xh9J2^3%>fl gP32wyWDa4_AkC=Dz<6e<1v|(Sp00i_>zopr0LjD?Hvj+t literal 0 HcmV?d00001