diff --git a/pandora/user/models.py b/pandora/user/models.py index 4d3bf2ab..ef92e8b3 100644 --- a/pandora/user/models.py +++ b/pandora/user/models.py @@ -39,7 +39,7 @@ class UserProfile(models.Model): for key in new: if isinstance(new[key], dict) and key in ui: ui[key] = updateUI(ui[key], new[key]) - else: + elif isinstance(ui, dict): ui[key] = new[key] return ui ui = updateUI(ui, self.ui) diff --git a/pandora/user/views.py b/pandora/user/views.py index df86c127..77d8a985 100644 --- a/pandora/user/views.py +++ b/pandora/user/views.py @@ -566,7 +566,7 @@ def setUI(request): if request.user.is_authenticated(): profile = request.user.get_profile() for key in data: - keys = key.split('|') + keys = re.sub('([^\\\\])\.', '\\1\n', key).split('\n') value = data[key] p = profile.ui while len(keys)>1: diff --git a/static/js/pandora/UI.js b/static/js/pandora/UI.js index 2defb4da..8b8f8094 100644 --- a/static/js/pandora/UI.js +++ b/static/js/pandora/UI.js @@ -21,81 +21,92 @@ pandora.UI = (function() { // key foo.bar.baz sets pandora.user.ui.foo.bar.baz // val null removes a key that.set = function(/*{key: val} or key, val*/) { - var obj = Ox.makeObject(arguments), + var add = {}, + args = Ox.makeObject(arguments), + listSettings = pandora.site.listSettings, set = {}, trigger = {}; + Ox.print('UI SET', args) self.previousUI = Ox.clone(pandora.user.ui, true); - Ox.forEach(obj, function(val, key) { - }); - Ox.forEach(obj, function(val, key) { - var i = 0, - keys = key.split('.'), - listSettings = pandora.site.listSettings, - ui = pandora.user.ui; - while (i < keys.length - 1) { - ui = ui[keys[i]]; - i++; - } - if (!Ox.isEqual(ui[keys[i]], val)) { - if (val === null) { - delete ui[keys[i]] - } else { - ui[keys[i]] = val; - } - if (key[0] != '_') { - // don't save or trigger events for private keys - // set[key] = val; - set[key] = val; - trigger[key] = val; - } - if (key == 'find') { - // the challenge here is that find may change list, - // and list may then change listSort and listView, - // which we don't want to trigger, since find triggers - var list = pandora.getListsState() - pandora.user.ui._list = list; - pandora.user.ui._groupsState = pandora.getGroupsState(); - pandora.user.ui._findState = pandora.getFindState(); - if (list != self.previousUI.list) { - if (!pandora.user.ui.lists[list]) { - set['lists.' + that.encode(list)] = {}; - } - Ox.forEach(listSettings, function(listSetting, setting) { - if (!pandora.user.ui.lists[list]) { - // add default list settings and copy to settings - set['lists.' + that.encode(list)][listSetting] = pandora.site.user.ui[setting]; - set[setting] = pandora.site.user.ui[setting]; - } else { - // copy list settings to setting - set[setting] = pandora.user.ui.lists[list][listSetting]; - } - }); + Ox.forEach(args, function(val, key) { + if (key == 'find') { + // the challenge here is that find may change list, + // and list may then change listSort and listView, + // which we don't want to trigger, since find triggers + var list = pandora.getListsState(val); + add['item'] = ''; + pandora.user.ui._list = list; + pandora.user.ui._groupsState = pandora.getGroupsState(val); + pandora.user.ui._findState = pandora.getFindState(val); + if (list != self.previousUI._list) { + if (!pandora.user.ui.lists[list]) { + add['lists.' + list] = {}; } - } else if (Object.keys(listSettings).indexOf(key) > -1) { - // copy setting to list setting - set['lists.' + that.encode(pandora.user.ui.list) + '.' + listSettings[key]] = val; - } else if ( - key == 'itemView' - && ['video', 'timeline'].indexOf(val) > -1 - && !pandora.user.ui.videoPoints[pandora.user.ui.item] - ) { - // add default videoPoints - set['videoPoints.' + pandora.user.ui.item] = {'in': 0, out: 0, position: 0}; + Ox.forEach(listSettings, function(listSetting, setting) { + if (!pandora.user.ui.lists[list]) { + // add default list setting and copy to settings + add['lists.' + list][listSetting] = pandora.site.user.ui[setting]; + add[setting] = pandora.site.user.ui[setting]; + } else { + // copy lists setting to settings + add[setting] = pandora.user.ui.lists[list][listSetting] + } + }); } + } else if (Object.keys(listSettings).indexOf(key) > -1) { + // copy setting to list setting + add['lists.' + that.encode(pandora.user.ui._list || '') + '.' + listSettings[key]] = val; + } else if (key == 'item' && val) { + // when switching to an item, update list selection + add['listSelection'] = [val]; + add['lists.' + that.encode(pandora.user.ui._list || '') + '.selection'] = [val]; + } else if ( + key == 'itemView' + && ['video', 'timeline'].indexOf(val) > -1 + && !pandora.user.ui.videoPoints[pandora.user.ui.item] + ) { + // add default videoPoints + add['videoPoints.' + pandora.user.ui.item] = {'in': 0, out: 0, position: 0}; } }); + [args, add].forEach(function(obj, isAdd) { + Ox.forEach(obj, function(val, key) { + var keys = key.replace(/([^\\])\./g, '$1\n').split('\n'), + ui = pandora.user.ui; + while (keys.length > 1) { + ui = ui[keys.shift()]; + } + if (!Ox.isEqual(ui[keys[0]], val)) { + if (val === null) { + delete ui[keys[0]] + } else { + ui[keys[0]] = val; + } + // don't save or trigger events for private keys + //if (key[0] != '_') { + //} + set[key] = val; + if (!isAdd) { + trigger[key] = val; + } + } + }); + }); + Ox.len(set) && pandora.api.setUI(set); Ox.forEach(trigger, function(val, key) { + // fixme: send previousVal as second parameter Ox.Event.trigger(key, val); }); - // fixme: swap later, once the backend accepts dots - // Ox.len(set) && pandora.api.setUI(set); - if (Ox.len(set)) { - var set_ = {}; - Ox.forEach(set, function(val, key) { - set_[key.replace(/\./g, '|')] = val; + + Ox.forEach(trigger, function(val, key) { + Ox.forEach(pandora.$ui, function(element) { + // fixme: send previousVal as second parameter + element.ox && element.triggerEvent('pandora_' + key.toLowerCase(), { + value: val, + previousValue: self.previousUI[key] + }); }); - pandora.api.setUI(set_); - } + }); }; return that; diff --git a/static/js/pandora/URL.js b/static/js/pandora/URL.js index acb26afa..5c4f9850 100644 --- a/static/js/pandora/URL.js +++ b/static/js/pandora/URL.js @@ -115,8 +115,8 @@ pandora.URL = (function() { $('video').each(function() { $(this).trigger('stop'); }); - pandora.user.ui._groupsState = pandora.getGroupsState(); - pandora.user.ui._findState = pandora.getFindState(); + pandora.user.ui._groupsState = pandora.getGroupsState(pandora.user.ui.find); + pandora.user.ui._findState = pandora.getFindState(pandora.user.ui.find); if (Ox.isEmpty(state)) { if (pandora.user.ui.showHome) { pandora.$ui.home = pandora.ui.home().showScreen(); @@ -160,51 +160,50 @@ pandora.URL = (function() { document.location.href = '/api/'; } } else { - pandora.UI.set({ + + var set = { section: state.type == pandora.site.itemsSection ? 'items' : state.type, item: state.item, - }); - - state.find && pandora.UI.set({ - find: state.find, - list: pandora.getListsState(state.find) - }); + //find: state.find + }; if (state.view) { - pandora.UI.set( - !pandora.user.ui.item - ? 'listView' - : 'itemView', - state.view - ); + set[!pandora.user.ui.item ? 'listView' : 'itemView'] = state.view; } - pandora.user.ui._groupsState = pandora.getGroupsState(); - Ox.print('_groupsState =', pandora.user.ui._groupsState); - pandora.user.ui._findState = pandora.getFindState(); + if (state.sort) { + set[!pandora.user.ui.item ? 'listSort' : 'itemSort'] = state.sort; + } + + ///* + if (state.find) { + set.find = state.find; + } else { + var find = pandora.user.ui.find; + pandora.user.ui._list = pandora.getListsState(find) + pandora.user.ui._groupsState = pandora.getGroupsState(find); + pandora.user.ui._findState = pandora.getFindState(find); + } + //*/ if (['video', 'timeline'].indexOf(pandora.user.ui.itemView) > -1) { if (state.span) { - pandora.UI.set('videoPoints.' + pandora.user.ui.item, { + set['videoPoints.' + pandora.user.ui.item] = { position: state.span[0], 'in': state.span[1] || 0, out: state.span[2] || 0 - }); + } } else if (!pandora.user.ui.videoPoints[pandora.user.ui.item]) { - pandora.UI.set('videoPoints.' + pandora.user.ui.item, { + set['videoPoints.' + pandora.user.ui.item] = { position: 0, 'in': 0, out: 0 - }); + } } } - state.sort && pandora.UI.set( - !pandora.user.ui.item - ? 'lists.' + pandora.user.ui.list + '.sort' - : 'itemSort', - state.sort - ); + + pandora.UI.set(set); /* if (!pandora.$ui.appPanel) { @@ -382,9 +381,14 @@ pandora.URL = (function() { sortKeys[itemsSection] = {list: {}, item: {}}; views[itemsSection].list.forEach(function(view) { sortKeys[itemsSection].list[view] = Ox.merge( - pandora.isClipView(view) ? Ox.clone(pandora.site.clipKeys) : [], // listSort[0].key is the default sort key - [Ox.getObjectById(pandora.site.sortKeys, pandora.user.ui.listSort[0].key)], + Ox.getObjectById(pandora.site.sortKeys, pandora.user.ui.listSort[0].key) + || pandora.isClipView(view) + && Ox.getObjectById(pandora.site.clipKeys, pandora.user.ui.listSort[0].key) + || [], + pandora.isClipView(view) ? Ox.map(pandora.site.clipKeys, function(key) { + return key.id == pandora.user.ui.listSort[0].key ? null : key; + }) : [], Ox.map(pandora.site.sortKeys, function(key) { return key.id == pandora.user.ui.listSort[0].key ? null : key; }) diff --git a/static/js/pandora/pandora.js b/static/js/pandora/pandora.js index 9b9b52fd..37d2acd3 100644 --- a/static/js/pandora/pandora.js +++ b/static/js/pandora/pandora.js @@ -349,21 +349,16 @@ pandora.getItemByIdOrTitle = function(str, callback) { pandora.getListData = function() { var data = {}, folder; - if (pandora.user.ui.list) { + if (pandora.user.ui._list) { Ox.forEach(pandora.$ui.folderList, function(list, key) { if (list.options('selected').length) { folder = key; return false; } }); - // the one case where folder is undefinded is when on page load - // the folderLists call getListData to determine which list is selected - if (folder) { - //Ox.print('gLD f', folder) - data = pandora.$ui.folderList[folder].value(pandora.user.ui.list); - data.editable = data.user == pandora.user.username && data.type == 'static'; - data.folder = folder; - } + data = pandora.$ui.folderList[folder].value(pandora.user.ui._list); + data.editable = data.user == pandora.user.username && data.type == 'static'; + data.folder = folder; } return data; }; @@ -559,12 +554,11 @@ pandora.resizeFolders = function() { }; pandora.selectList = function() { - // fixme: can this be removed? - if (pandora.user.ui.list) { + if (pandora.user.ui._list) { pandora.api.findLists({ keys: ['status', 'user'], query: { - conditions: [{key: 'id', value: pandora.user.ui.list, operator: '='}], + conditions: [{key: 'id', value: pandora.user.ui._list, operator: '='}], operator: '' }, range: [0, 1] @@ -576,7 +570,7 @@ pandora.selectList = function() { list.user == pandora.user.username ? 'personal' : 'favorite' ); pandora.$ui.folderList[folder] - .options('selected', [pandora.user.ui.list]) + .options('selected', [pandora.user.ui._list]) .gainFocus(); } else { pandora.user.ui.list = ''; @@ -612,19 +606,16 @@ pandora.selectList = function() { return indices.length == 1 ? indices[0] : -1; } - pandora.getFindState = function() { + pandora.getFindState = function(find) { // The find element is populated if exactly one condition in an & query // has a findKey as key and "=" as operator (and all other conditions // are either list or groups), or if all conditions in an | query have // the same group id as key and "==" as operator - var conditions, - find = pandora.user.ui.find, - indices, - state = {index: -1, key: '*', value: ''}; + var conditions, indices, state = {index: -1, key: '*', value: ''}; if (find.operator == '&') { // number of conditions that are not list or groups conditions = find.conditions.length - - !!pandora.user.ui.list + - !!pandora.user.ui._list - pandora.user.ui._groupsState.filter(function(group) { return group.index > -1; }).length; @@ -658,10 +649,9 @@ pandora.selectList = function() { return state; } - pandora.getGroupsState = function() { + pandora.getGroupsState = function(find) { // A group is selected if exactly one condition in an & query or every // condition in an | query has the group id as key and "==" as operator - var find = pandora.user.ui.find; return pandora.user.ui.groups.map(function(group) { // FIXME: cant index be an empty array, instead of -1? var key = group.id, @@ -691,14 +681,15 @@ pandora.selectList = function() { } else { // one condition in an & query matches this group state.find.conditions.splice(state.index, 1); - if (state.find.conditions.length == 1) { - if (state.find.conditions[0].conditions) { - // unwrap single remaining bracketed query - state.find = { - conditions: state.find.conditions[0].conditions, - operator: state.find.conditions[0].operator - }; - } + if ( + state.find.conditions.length == 1 + && state.find.conditions[0].conditions + ) { + // unwrap single remaining bracketed query + state.find = { + conditions: state.find.conditions[0].conditions, + operator: state.find.conditions[0].operator + }; } } } @@ -706,10 +697,10 @@ pandora.selectList = function() { }); } - pandora.getListsState = function() { + pandora.getListsState = function(find) { // A list is selected if exactly one condition in an & query has "list" // as key and "==" as operator - var find = pandora.user.ui.find, index, state = ''; + var index, state = ''; if (find.operator == '&') { index = oneCondition(find.conditions, 'list', '=='); if (index > -1) { diff --git a/static/js/pandora/ui/backButton.js b/static/js/pandora/ui/backButton.js index 6820375d..77c54190 100644 --- a/static/js/pandora/ui/backButton.js +++ b/static/js/pandora/ui/backButton.js @@ -9,7 +9,7 @@ pandora.ui.backButton = function() { }) .bindEvent({ click: function() { - pandora.UI.set({item: null}); + pandora.UI.set({item: ''}); } }); return that; diff --git a/static/js/pandora/ui/browser.js b/static/js/pandora/ui/browser.js index db5229a4..324b327e 100644 --- a/static/js/pandora/ui/browser.js +++ b/static/js/pandora/ui/browser.js @@ -80,7 +80,6 @@ pandora.ui.browser = function() { }, select: function(data) { pandora.UI.set({ - 'listSelection': data.ids, 'item': data.ids[0] }); }, diff --git a/static/js/pandora/ui/contentPanel.js b/static/js/pandora/ui/contentPanel.js index 3625558f..aa8bae7d 100644 --- a/static/js/pandora/ui/contentPanel.js +++ b/static/js/pandora/ui/contentPanel.js @@ -33,7 +33,9 @@ pandora.ui.contentPanel = function() { that.replaceElement(1, pandora.$ui.list = pandora.ui.list()); }, item: function(value) { - value && that.replaceElement(1, pandora.$ui.item = pandora.ui.item()); + if (value && pandora.UI.getPrevious('item')) { + that.replaceElement(1, pandora.$ui.item = pandora.ui.item()); + } }, itemView: function() { that.replaceElement(1, pandora.$ui.item = pandora.ui.item()); diff --git a/static/js/pandora/ui/folderList.js b/static/js/pandora/ui/folderList.js index 7e87446a..a716f0f9 100644 --- a/static/js/pandora/ui/folderList.js +++ b/static/js/pandora/ui/folderList.js @@ -241,7 +241,7 @@ pandora.ui.folderList = function(id) { max: 1, min: 0, pageLength: 1000, - selected: pandora.getListData().folder == id ? [pandora.user.ui.list] : [], + //selected: pandora.getListData().folder == id ? [pandora.user.ui._list] : [], sort: [{key: 'position', operator: '+'}], sortable: id != 'featured' || pandora.user.level == 'admin' }) diff --git a/static/js/pandora/ui/group.js b/static/js/pandora/ui/group.js index 5b9c1254..d9e32ca8 100644 --- a/static/js/pandora/ui/group.js +++ b/static/js/pandora/ui/group.js @@ -113,17 +113,32 @@ pandora.ui.group = function(id) { // nothing selected find.conditions.splice(index, 1); if (find.conditions.length == 1) { - find.operator = '&'; + if (find.conditions[0].conditions) { + // unwrap single remaining bracketed query + find = { + conditions: find.conditions[0].conditions, + operator: '|' + }; + } else { + find.operator = '&'; + } } } else if (conditions.length == 1) { // one item selected find.conditions[index] = conditions[0]; } else { // multiple items selected - find.conditions[index].conditions = conditions; - find.conditions[index].operator = '|'; - delete find.conditions[index].key; - delete find.conditions[index].value; + if (pandora.user.ui.find.conditions.length == 1) { + find = { + conditions: conditions, + operator: '|' + }; + } else { + find.conditions[index] = { + conditions: conditions, + operator: '|' + }; + } } } /* diff --git a/static/js/pandora/ui/mainPanel.js b/static/js/pandora/ui/mainPanel.js index 17555a00..bd8934d5 100644 --- a/static/js/pandora/ui/mainPanel.js +++ b/static/js/pandora/ui/mainPanel.js @@ -18,6 +18,22 @@ pandora.ui.mainPanel = function() { orientation: 'horizontal' }); pandora.UI.bind({ + find: function() { + var previousUI = pandora.UI.getPrevious(); + if (pandora.user.ui._list == previousUI._list) { + pandora.$ui.list.reloadList(); + pandora.user.ui._groupsState.forEach(function(data, i) { + if (!Ox.isEqual(data.selected, previousUI._groupsState[i].selected)) { + pandora.$ui.groups[i].options({selected: data.selected}); + } + if (!Ox.isEqual(data.find, previousUI._groupsState[i].find)) { + pandora.$ui.groups[i].reloadList(); + } + }); + } else { + that.replaceElement(1, pandora.$ui.rightPanel = pandora.ui.rightPanel()); + } + }, item: function(value) { if (!value || !pandora.UI.getPrevious('item')) { that.replaceElement(1, pandora.$ui.rightPanel = pandora.ui.rightPanel()); diff --git a/static/js/pandora/ui/menu.js b/static/js/pandora/ui/menu.js index c2af1c8e..5f4eb71a 100644 --- a/static/js/pandora/ui/menu.js +++ b/static/js/pandora/ui/menu.js @@ -272,10 +272,11 @@ pandora.ui.mainMenu = function() { return { id: 'sortMenu', title: 'Sort', items: [ { id: 'sortmovies', title: 'Sort ' + (isClipView ? 'Clips' : pandora.site.itemName.plural) + ' by', items: [ { group: 'sortmovies', min: 1, max: 1, items: Ox.merge(isClipView ? Ox.merge(pandora.site.clipKeys.map(function(key) { - return Ox.extend({ - checked: ui.listSort[0].key == key.id - }, key); - }), {}) : [], pandora.site.sortKeys.map(function(key) { + return Ox.extend(Ox.clone(key), { + checked: ui.listSort[0].key == key.id, + title: 'Clip ' + key.title + }); + }), /*{}*/[]) : [], pandora.site.sortKeys.map(function(key) { return Ox.extend({ checked: ui.listSort[0].key == key.id }, key); @@ -349,6 +350,15 @@ pandora.ui.mainMenu = function() { }); }); + pandora.UI.bind({ + listView: function(value) { + if (pandora.isClipView() != pandora.isClipView(pandora.UI.getPrevious('listView'))) { + that.replaceMenu('sortMenu', getSortMenu()); + } + } + }); + return that; + }; diff --git a/static/js/pandora/ui/orderButton.js b/static/js/pandora/ui/orderButton.js index d1afaaff..451b3ba1 100644 --- a/static/js/pandora/ui/orderButton.js +++ b/static/js/pandora/ui/orderButton.js @@ -18,7 +18,7 @@ pandora.ui.orderButton = function() { key: pandora.user.ui.listSort[0].key, operator: pandora.user.ui.listSort[0].operator == '+' ? '-' : '+' }] - }) + }); that.options({title: getTitle()}); } }); diff --git a/static/js/pandora/ui/rightPanel.js b/static/js/pandora/ui/rightPanel.js index 87560932..e0e67b92 100644 --- a/static/js/pandora/ui/rightPanel.js +++ b/static/js/pandora/ui/rightPanel.js @@ -58,22 +58,6 @@ pandora.ui.rightPanel = function() { }); } pandora.UI.bind({ - find: function() { - var previousUI = pandora.UI.getPrevious(); - if (pandora.user.ui.list == previousUI.list) { - pandora.$ui.list.reloadList(); - pandora.user.ui._groupsState.forEach(function(data, i) { - if (!Ox.isEqual(data.selected, previousUI._groupsState[i].selected)) { - pandora.$ui.groups[i].options({selected: data.selected}); - } - if (!Ox.isEqual(data.find, previousUI._groupsState[i].find)) { - pandora.$ui.groups[i].reloadList(); - } - }); - } else { - that.replaceElement(1, pandora.$ui.contentPanel = pandora.ui.contentPanel()); - } - }, itemView: function(value) { if (pandora.isClipView() != pandora.isClipView(pandora.UI.getPrevious('itemView'))) { that.replaceElement(0, pandora.$ui.toolbar = pandora.ui.toolbar()); diff --git a/static/js/pandora/ui/sortSelect.js b/static/js/pandora/ui/sortSelect.js index d429fc6b..37b193b1 100644 --- a/static/js/pandora/ui/sortSelect.js +++ b/static/js/pandora/ui/sortSelect.js @@ -10,7 +10,7 @@ pandora.ui.sortSelect = function() { title: 'Sort by ' + (!pandora.user.ui.item ? 'Clip ' : '') + key.title }); }); - !pandora.user.ui.item && items.push({}); + //!pandora.user.ui.item && items.push({}); } if (!pandora.user.ui.item) { items = Ox.merge(items, pandora.site.sortKeys.map(function(key) { @@ -32,19 +32,15 @@ pandora.ui.sortSelect = function() { .bindEvent({ change: function(data) { pandora.UI.set(sortKey, [{key: data.selected[0].id, operator: ''}]); + }, + pandora_listsort: function(data) { + that.selectItem(data.value[0].key); + }, + pandora_itemsort: function(value) { + that.selectItem(data.value[0].key); } }); - pandora.UI.bind({ - listSort: function(value) { - that.selectItem(value[0].key); - }, - item: function(value) { - - }, - itemSort: function(value) { - that.selectItem(value[0].key); - } - }); + return that; }; diff --git a/static/js/pandora/ui/toolbar.js b/static/js/pandora/ui/toolbar.js index a0b55266..6f31e003 100644 --- a/static/js/pandora/ui/toolbar.js +++ b/static/js/pandora/ui/toolbar.js @@ -25,6 +25,15 @@ pandora.ui.toolbar = function() { that.append( pandora.$ui.findElement = pandora.ui.findElement() ); + pandora.UI.bind({ + listView: function(value) { + if (pandora.isClipView() != pandora.isClipView(pandora.UI.getPrevious('listView'))) { + pandora.$ui.sortSelect.replaceWith( + pandora.$ui.sortSelect = pandora.ui.sortSelect() + ); + } + } + }) return that; };