From 164961e562fcc4f9f1761822570c9a960bf857a7 Mon Sep 17 00:00:00 2001 From: rolux Date: Tue, 27 Sep 2011 14:14:40 +0000 Subject: [PATCH] refactoring --- pandora/0xdb.json | 1 - static/js/pandora.js | 20 +- static/js/pandora/UI.js | 89 +++--- static/js/pandora/URL.js | 141 +--------- static/js/pandora/pandora.js | 281 +++++++++---------- static/js/pandora/ui/browser.js | 5 +- static/js/pandora/ui/contentPanel.js | 4 +- static/js/pandora/ui/findElement.js | 10 +- static/js/pandora/ui/folderList.js | 19 +- static/js/pandora/ui/folders.js | 1 + static/js/pandora/ui/group.js | 2 +- static/js/pandora/ui/infoView.js | 4 +- static/js/pandora/ui/list.js | 2 +- static/js/pandora/ui/menu.js | 388 ++++++--------------------- static/js/pandora/ui/rightPanel.js | 17 +- static/js/pandora/ui/sortSelect.js | 2 +- 16 files changed, 349 insertions(+), 637 deletions(-) diff --git a/pandora/0xdb.json b/pandora/0xdb.json index 4d2e6d601..769afced1 100644 --- a/pandora/0xdb.json +++ b/pandora/0xdb.json @@ -564,7 +564,6 @@ "item": "", "itemSort": [{"key": "clip:position", "operator": ""}], "itemView": "info", - "list": "", "listColumns": ["title", "director", "country", "year", "language", "runtime", "genre"], "listColumnWidth": {}, "listSelection": [], diff --git a/static/js/pandora.js b/static/js/pandora.js index acc128675..53a3ab192 100644 --- a/static/js/pandora.js +++ b/static/js/pandora.js @@ -3,9 +3,25 @@ Pandora ***/ +/* +---- UI Tree ---- +appPanel + mainMenu + mainPanel + leftPanel + sectionbar + folders + info + rightPanel + toolbar + contentPanel + browser <-- should be filters or browser + list or item + statusbar +*/ + // fixme: never set pandora.ui.videoPosition to 0 ... set to null a.k.a. delete // fixme: sort=-director doesn't work -// fixme: don't reload full right panel on sortSelect // fixme: clear items cache after login/logout Ox.load({ @@ -112,7 +128,7 @@ Ox.load({ } window.onpopstate = function(event) { - pandora.URL.update(); + //pandora.URL.update(); }; // set up url controller diff --git a/static/js/pandora/UI.js b/static/js/pandora/UI.js index 295428f7d..2defb4dae 100644 --- a/static/js/pandora/UI.js +++ b/static/js/pandora/UI.js @@ -1,55 +1,36 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript pandora.UI = (function() { + var self = {}, that = {}; + self.previousUI = {}; + that.bind = function() { Ox.Event.bind.apply(null, arguments); }; + that.encode = function(val) { return val.replace(/\./g, '\\.'); }; + that.getPrevious = function(key) { return !key ? self.previousUI : self.previousUI[key]; }; + // sets pandora.user.ui.key to val // 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), - set = {}; + set = {}, + trigger = {}; self.previousUI = Ox.clone(pandora.user.ui, true); Ox.forEach(obj, function(val, key) { - var listSettings = pandora.site.listSettings - if (key == 'list') { - if (!pandora.user.ui.lists[val]) { - obj['lists.' + that.encode(val)] = {}; - } - Ox.forEach(listSettings, function(listSetting, setting) { - if (!pandora.user.ui.lists[val]) { - // add default list settings and copy to settings - obj['lists.' + that.encode(val)][listSetting] = pandora.site.user.ui[setting]; - obj[setting] = pandora.site.user.ui[setting]; - } else { - // copy list settings to setting - obj[setting] = pandora.user.ui.lists[val][listSetting]; - } - }); - Ox.forEach() - } else if (Object.keys(listSettings).indexOf(key) > -1) { - // add list setting - obj['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 - obj['videoPoints.' + pandora.user.ui.item] = {'in': 0, out: 0, position: 0}; - } }); 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]]; @@ -62,20 +43,62 @@ pandora.UI = (function() { ui[keys[i]] = val; } if (key[0] != '_') { - // don't send private keys + // don't save or trigger events for private keys // set[key] = val; - // fixme: remove later - set[key.replace(/\./g, '|')] = 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]; + } + }); + } + } 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(trigger, function(val, key) { + 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) { - Ox.Event.trigger(key, val); + set_[key.replace(/\./g, '|')] = val; }); - pandora.api.setUI(set); + pandora.api.setUI(set_); } }; + return that; + }()); diff --git a/static/js/pandora/URL.js b/static/js/pandora/URL.js index 6be90b302..acb26afaa 100644 --- a/static/js/pandora/URL.js +++ b/static/js/pandora/URL.js @@ -87,117 +87,6 @@ pandora.URL = (function() { } */ - function everyCondition(conditions, key, operator) { - // If every condition has the given key and operator - // (excluding conditions where all subconditions match) - // returns true, otherwise false - return Ox.every(conditions, function(condition) { - return condition.key == key && condition.operator == operator; - }); - } - - function getFindState(find, listsState, groupsState) { - // 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, indices, state = {index: -1, key: '*', value: ''}; - if (find.operator == '&') { - // number of conditions that are not list or groups - conditions = find.conditions.length - - (listsState != '') - - groupsState.filter(function(group) { - return group.index > -1; - }).length; - // indices of non-advanced find queries - indices = Ox.map(pandora.site.findKeys, function(findKey) { - var index = oneCondition(find.conditions, findKey.id, '='); - return index > -1 ? index : null; - }); - state = conditions == 1 && indices.length == 1 ? { - index: indices[0], - key: find.conditions[indices[0]].key, - value: decodeURIComponent(find.conditions[indices[0]].value) - } : { - index: -1, - key: conditions == 0 && indices.length == 0 ? '*' : 'advanced', - value: '' - }; - } else { - state = { - index: -1, - key: 'advanced', - value: '' - }; - Ox.forEach(pandora.user.ui.groups, function(key) { - if (everyCondition(find.conditions, key, '==')) { - state.key = '*'; - return false; - } - }); - } - return state; - } - - function getGroupsState(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 - return pandora.user.ui.groups.map(function(group) { - // FIXME: cant index be an empty array, instead of -1? - var key = group.id, - state = {index: -1, find: Ox.clone(find, true), selected: []}; - if (find.operator == '&') { - // include conditions where all subconditions match - state.index = oneCondition(find.conditions, key, '==', true); - if (state.index > -1) { - state.selected = find.conditions[state.index].conditions - ? find.conditions[state.index].conditions.map(function(condition) { - return condition.value; - }) - : [find.conditions[state.index].value]; - } - } else { - if (everyCondition(find.conditions, key, '==')) { - state.index = Ox.range(find.conditions.length); - state.selected = find.conditions.map(function(condition) { - return condition.value; - }); - } - } - if (state.selected.length) { - if (Ox.isArray(state.index)) { - // every condition in an | query matches this group - state.find = {conditions: [], operator: ''}; - } 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 - }; - } - } - } - } - return state; - }); - } - - function getListsState(find) { - // A list is selected if exactly one condition in an & query has "list" - // as key and "==" as operator - var index, state = ''; - if (find.operator == '&') { - index = oneCondition(find.conditions, 'list', '=='); - if (index > -1) { - state = find.conditions[index].value; - } - } - return state; - } function getState() { return { @@ -218,20 +107,6 @@ pandora.URL = (function() { }; } - function oneCondition(conditions, key, operator, includeSubconditions) { - // If exactly one condition has the given key and operator - // (including or excluding conditions where all subconditions match) - // returns the corresponding index, otherwise returns -1 - var indices = Ox.map(conditions, function(condition, i) { - return ( - condition.conditions - ? includeSubconditions && everyCondition(condition.conditions, key, operator) - : condition.key == key && condition.operator == operator - ) ? i : null; - }); - return indices.length == 1 ? indices[0] : -1; - } - function setState(state) { Ox.print('STATE:', state) var previousUI = pandora.UI.getPrevious(); @@ -240,8 +115,8 @@ pandora.URL = (function() { $('video').each(function() { $(this).trigger('stop'); }); - pandora.user.ui._groupsState = getGroupsState(pandora.user.ui.find); - pandora.user.ui._findState = getFindState(pandora.user.ui.find, pandora.user.ui.list, pandora.user.ui._groupsState); + pandora.user.ui._groupsState = pandora.getGroupsState(); + pandora.user.ui._findState = pandora.getFindState(); if (Ox.isEmpty(state)) { if (pandora.user.ui.showHome) { pandora.$ui.home = pandora.ui.home().showScreen(); @@ -292,21 +167,21 @@ pandora.URL = (function() { state.find && pandora.UI.set({ find: state.find, - list: getListsState(state.find) + list: pandora.getListsState(state.find) }); if (state.view) { pandora.UI.set( !pandora.user.ui.item - ? 'lists.' + pandora.user.ui.list + '.view' + ? 'listView' : 'itemView', state.view ); } - pandora.user.ui._groupsState = getGroupsState(pandora.user.ui.find); + pandora.user.ui._groupsState = pandora.getGroupsState(); Ox.print('_groupsState =', pandora.user.ui._groupsState); - pandora.user.ui._findState = getFindState(pandora.user.ui.find, pandora.user.ui.list, pandora.user.ui._groupsState); + pandora.user.ui._findState = pandora.getFindState(); if (['video', 'timeline'].indexOf(pandora.user.ui.itemView) > -1) { if (state.span) { @@ -331,6 +206,7 @@ pandora.URL = (function() { state.sort ); + /* if (!pandora.$ui.appPanel) { return; } @@ -403,6 +279,7 @@ pandora.URL = (function() { $item.options('position') ); } + */ } pandora.user.ui.showHome = false; @@ -555,7 +432,7 @@ pandora.URL = (function() { views: views }); - ['item', 'itemSort', 'itemView', 'list', 'listSort', 'listView'].forEach(function(event) { + ['find', 'item', 'itemSort', 'itemView', 'list', 'listSort', 'listView'].forEach(function(event) { pandora.UI.bind(event, function() { that.push(); }); diff --git a/static/js/pandora/pandora.js b/static/js/pandora/pandora.js index e1e34f921..9b9b52fd0 100644 --- a/static/js/pandora/pandora.js +++ b/static/js/pandora/pandora.js @@ -368,32 +368,6 @@ pandora.getListData = function() { return data; }; -pandora.getListMenu = function(lists) { - return { id: 'listMenu', title: 'List', items: [ - { id: 'history', title: 'History', items: [ - { id: 'allmovies', title: 'All ' + pandora.site.itemName.plural } - ] }, - { id: 'viewlist', title: 'View List', items: lists ? ['personal', 'favorite', 'featured'].map(function(folder) { - return { id: folder + 'lists', title: Ox.toTitleCase(folder) + ' Lists', items: [ - { group: folder + 'lists', min: 0, max: 1, items: lists[folder].map(function(list) { - return { id: 'viewlist' + list.id, title: (folder == 'favorite' ? list.user + ': ' : '') + list.name, checked: list.id == pandora.user.ui.list }; - }) } - ] }; - }) : [ - { id: 'loading', title: 'Loading...', disabled: true } - ] }, - {}, - { 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: '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 } - ] }; -}; - pandora.getMetadataByIdOrName = function(item, view, str, callback) { // For a given item (or none) and a given view (or any), this takes a string // and checks if it's an annotation/event/place id or an event/place name, @@ -454,56 +428,6 @@ pandora.getMetadataByIdOrName = function(item, view, str, callback) { } }; -pandora.getSortMenu = function() { - var ui = pandora.user.ui, - isClipView = pandora.isClipView(ui.listView); - 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({ - checked: ui.listSort[0].key == key.id - }, key); - })) } - ] }, - { id: 'ordermovies', title: 'Order ' + (isClipView ? 'Clips' : pandora.site.itemName.plural), items: [ - { group: 'ordermovies', min: 1, max: 1, items: [ - { id: 'ascending', title: 'Ascending', checked: (ui.listSort[0].operator || pandora.getSortOperator(ui.listSort[0].key)) == '+' }, - { id: 'descending', title: 'Descending', checked: (ui.listSort[0].operator || pandora.getSortOperator(ui.listSort[0].key)) == '-' } - ]} - ] }, - { id: 'advancedsort', title: 'Advanced Sort...', keyboard: 'shift control s' }, - {}, - { id: 'sortgroups', title: 'Sort Groups', items: pandora.user.ui.groups.map(function(group) { - return { - id: 'sortgroup' + group.id, - title: 'Sort ' + Ox.getObjectById(pandora.site.groups, group.id).title + ' Group by', - items: [ - { group: 'sortgroup' + group.id, min: 1, max: 1, items: [ - { id: 'name', title: 'Name', checked: group.sort[0].key == 'name' }, - { id: 'items', title: 'Items', checked: group.sort[0].key == 'items' } - ] } - ] - } - }) }, - { id: 'ordergroups', title: 'Order Groups', items: pandora.user.ui.groups.map(function(group) { - return { - id: 'ordergroup' + group.id, - title: 'Order ' + Ox.getObjectById(pandora.site.groups, group.id).title + ' Group', - items: [ - { group: 'ordergroup' + group.id, min: 1, max: 1, items: [ - { id: 'ascending', title: 'Ascending', checked: group.sort[0].operator == '+' }, - { id: 'descending', title: 'Descending', checked: group.sort[0].operator == '-' } - ] } - ] - } - }) } - ] }; -}; - pandora._getSortOperator = function(type) { return ['hue', 'string', 'text'].indexOf( Ox.isArray(type) ? type[0] : type @@ -568,59 +492,6 @@ pandora.signout = function(data) { pandora.$ui.appPanel.reload(); }; -pandora.reloadGroups = function(i) { - // fixme: no longer needed - var query = pandora.user.ui.query, - view = pandora.user.ui.lists[pandora.user.ui.list].listView; - if (view == 'clip') { - pandora.$ui.list.options({ - items: function(data, callback) { - return pandora.api.findAnnotations(Ox.extend(data, { - itemQuery: query - }), callback); - } - }); - } else if (view == 'map') { - pandora.$ui.map.options({ - places: function(data, callback) { - return pandora.api.findPlaces(Ox.extend(data, { - itemQuery: query - }), callback); - } - }); - } else if (view == 'calendar') { - pandora.$ui.list.options({ - items: function(data, callback) { - return pandora.api.findEvents(Ox.extend(data, { - itemQuery: query - }), callback); - } - }); - } else { - pandora.$ui.list.options({ - items: function(data, callback) { - return pandora.api.find(Ox.extend(data, { - query: query - }), callback); - } - }); - } - Ox.forEach(pandora.user.ui.groups, function(group, i_) { - if (i_ != i) { - //Ox.print('setting groups request', i, i_) - pandora.$ui.groups[i_].options({ - items: function(data, callback) { - delete data.keys; - return pandora.api.find(Ox.extend(data, { - group: group.id, - query: pandora.user.ui.groupsData[i_].query - }), callback); - } - }); - } - }); -}; - pandora.reloadList = function() { Ox.print('reloadList') var listData = pandora.getListData(); @@ -628,7 +499,8 @@ pandora.reloadList = function() { pandora.$ui.groups.forEach(function($group) { $group.reloadList(); }); - pandora.$ui.list.bindEvent({ + pandora.$ui.list + .bindEvent({ init: function(data) { // fixme: this will not work for lists in the favorites folder // (but then it's also unlikely they'll have to be reloaded) @@ -647,7 +519,6 @@ pandora.reloadList = function() { pandora.resizeGroups = function(width) { pandora.user.ui.groupsSizes = pandora.getGroupsSizes(); - Ox.print('{}{}{}', window.innerWidth, window.innerWidth - pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize - 1, pandora.user.ui.groupsSizes) pandora.$ui.browser .size(0, pandora.user.ui.groupsSizes[0]) .size(2, pandora.user.ui.groupsSizes[4]); @@ -666,14 +537,12 @@ pandora.resizeFolders = function() { columnWidth = {user: parseInt((width - 96) * 0.4)}; columnWidth.name = (width - 96) - columnWidth.user; } - //Ox.print('sectionsWidth', width) Ox.forEach(pandora.$ui.folderList, function($list, id) { - var i = Ox.getPositionById(pandora.site.sectionFolders[pandora.user.ui.section], id); - pandora.$ui.folder[i].css({width: width + 'px'}); + var pos = Ox.getPositionById(pandora.site.sectionFolders[pandora.user.ui.section], id); + pandora.$ui.folder[pos].css({width: width + 'px'}); $list.css({width: width + 'px'}); if (pandora.user.ui.section == 'items') { - if (pandora.site.sectionFolders[pandora.user.ui.section][i].showBrowser) { - Ox.print('ID', id) + if (pandora.site.sectionFolders[pandora.user.ui.section][pos].showBrowser) { pandora.$ui.findListInput[id].options({ width: width - 24 }); @@ -684,12 +553,13 @@ pandora.resizeFolders = function() { } } if (!pandora.user.ui.showFolder[pandora.user.ui.section][id]) { - pandora.$ui.folder[i].update(); + pandora.$ui.folder[pos].update(); } }); }; pandora.selectList = function() { + // fixme: can this be removed? if (pandora.user.ui.list) { pandora.api.findLists({ keys: ['status', 'user'], @@ -710,10 +580,143 @@ pandora.selectList = function() { .gainFocus(); } else { pandora.user.ui.list = ''; - //pandora.user.ui.listQuery.conditions = []; // fixme: Query should read from pandora.ui.list, and not need pandora.ui.listQuery to be reset - //pandora.URL.set(pandora.Query.toString()); } }); } }; +(function() { + + // Note: getFindState has to run after getListState and getGroupsState + + function everyCondition(conditions, key, operator) { + // If every condition has the given key and operator + // (excluding conditions where all subconditions match) + // returns true, otherwise false + return Ox.every(conditions, function(condition) { + return condition.key == key && condition.operator == operator; + }); + } + + function oneCondition(conditions, key, operator, includeSubconditions) { + // If exactly one condition has the given key and operator + // (including or excluding conditions where all subconditions match) + // returns the corresponding index, otherwise returns -1 + var indices = Ox.map(conditions, function(condition, i) { + return ( + condition.conditions + ? includeSubconditions && everyCondition(condition.conditions, key, operator) + : condition.key == key && condition.operator == operator + ) ? i : null; + }); + return indices.length == 1 ? indices[0] : -1; + } + + pandora.getFindState = function() { + // 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: ''}; + if (find.operator == '&') { + // number of conditions that are not list or groups + conditions = find.conditions.length + - !!pandora.user.ui.list + - pandora.user.ui._groupsState.filter(function(group) { + return group.index > -1; + }).length; + // indices of non-advanced find queries + indices = Ox.map(pandora.site.findKeys, function(findKey) { + var index = oneCondition(find.conditions, findKey.id, '='); + return index > -1 ? index : null; + }); + state = conditions == 1 && indices.length == 1 ? { + index: indices[0], + key: find.conditions[indices[0]].key, + value: decodeURIComponent(find.conditions[indices[0]].value) + } : { + index: -1, + key: conditions == 0 && indices.length == 0 ? '*' : 'advanced', + value: '' + }; + } else { + state = { + index: -1, + key: 'advanced', + value: '' + }; + Ox.forEach(pandora.user.ui.groups, function(key) { + if (everyCondition(find.conditions, key, '==')) { + state.key = '*'; + return false; + } + }); + } + return state; + } + + pandora.getGroupsState = function() { + // 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, + state = {index: -1, find: Ox.clone(find, true), selected: []}; + if (find.operator == '&') { + // include conditions where all subconditions match + state.index = oneCondition(find.conditions, key, '==', true); + if (state.index > -1) { + state.selected = find.conditions[state.index].conditions + ? find.conditions[state.index].conditions.map(function(condition) { + return condition.value; + }) + : [find.conditions[state.index].value]; + } + } else { + if (everyCondition(find.conditions, key, '==')) { + state.index = Ox.range(find.conditions.length); + state.selected = find.conditions.map(function(condition) { + return condition.value; + }); + } + } + if (state.selected.length) { + if (Ox.isArray(state.index)) { + // every condition in an | query matches this group + state.find = {conditions: [], operator: ''}; + } 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 + }; + } + } + } + } + return state; + }); + } + + pandora.getListsState = function() { + // 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 = ''; + if (find.operator == '&') { + index = oneCondition(find.conditions, 'list', '=='); + if (index > -1) { + state = find.conditions[index].value; + } + } + return state; + }; + +}()); \ No newline at end of file diff --git a/static/js/pandora/ui/browser.js b/static/js/pandora/ui/browser.js index 1f1ff7fe2..db5229a44 100644 --- a/static/js/pandora/ui/browser.js +++ b/static/js/pandora/ui/browser.js @@ -102,13 +102,10 @@ pandora.ui.browser = function() { }).reloadList(true); }, showSitePoster: function() { - that.reloadList(true); + pandora.user.ui.icons == 'poster' && that.reloadList(true); } }); } - that.update = function() { - pandora.$ui.contentPanel.replaceElement(0, pandora.$ui.browser = pandora.ui.browser()); - } return that; }; diff --git a/static/js/pandora/ui/contentPanel.js b/static/js/pandora/ui/contentPanel.js index 843ae65b0..3625558f7 100644 --- a/static/js/pandora/ui/contentPanel.js +++ b/static/js/pandora/ui/contentPanel.js @@ -32,8 +32,8 @@ pandora.ui.contentPanel = function() { listView: function() { that.replaceElement(1, pandora.$ui.list = pandora.ui.list()); }, - item: function() { - that.replaceElement(1, pandora.$ui.item = pandora.ui.item()); + item: function(value) { + value && 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/findElement.js b/static/js/pandora/ui/findElement.js index 2a33e7eb6..209538a0f 100644 --- a/static/js/pandora/ui/findElement.js +++ b/static/js/pandora/ui/findElement.js @@ -105,7 +105,6 @@ pandora.ui.findElement = function() { operator: '' }); } - pandora.URL.push(); } }) ]), @@ -120,12 +119,15 @@ pandora.ui.findElement = function() { var elementValue = that.value(), key = elementValue[pandora.user.ui.list ? 1 : 0], findKey = Ox.getObjectById(pandora.site.findKeys, key); - Ox.print('!!!!', key, findKey, 'autocomplete' in findKey && findKey.autocomplete) value === '' && Ox.print('Warning: autocomplete function should never be called with empty value'); - if ('autocomplete' in findKey && findKey.autocomplete) { + if (findKey.autocomplete) { pandora.api.autocomplete({ key: key, - query: elementValue[0].id == 'list' ? pandora.user.ui.listQuery : {conditions: [], operator: ''}, + query: { + conditions: pandora.$ui.findListSelect.value() == 'list' + ? [{key: 'list', value: pandora.user.ui.list, operator: '=='}] : [], + operator: '&' + }, range: [0, 20], sort: [{ key: 'votes', diff --git a/static/js/pandora/ui/folderList.js b/static/js/pandora/ui/folderList.js index f196cc817..7e87446a7 100644 --- a/static/js/pandora/ui/folderList.js +++ b/static/js/pandora/ui/folderList.js @@ -1,4 +1,5 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript + pandora.ui.folderList = function(id) { var i = Ox.getPositionById(pandora.site.sectionFolders[pandora.user.ui.section], id), that; @@ -372,30 +373,20 @@ pandora.ui.folderList = function(id) { pandora.$ui.list.triggerEvent('paste', data); }, select: function(data) { - if (data.ids.length) { + var list = data.ids.length ? data.ids[0] : ''; + if (list) { Ox.forEach(pandora.$ui.folderList, function($list, id_) { id != id_ && $list.options('selected', []); }); } - // pandora.URL.push(data.ids.length ? '/list==' + data.ids[0] : '') - /* pandora.UI.set({ - item: '', - list: data.ids.length ? data.ids[0] : '' - }) - pandora.URL.push(); - */ - pandora.UI.set({ - item: '', - list: data.ids.length ? data.ids[0] : '', find: { - conditions: data.ids.length ? [ + conditions: list ? [ {key: 'list', value: data.ids[0], operator: '=='} ] : [], operator: '&' } - }) - pandora.URL.push(); + }); }, submit: function(data) { data_ = {id: data.id}; diff --git a/static/js/pandora/ui/folders.js b/static/js/pandora/ui/folders.js index 8d28216f4..cc5c88d47 100644 --- a/static/js/pandora/ui/folders.js +++ b/static/js/pandora/ui/folders.js @@ -29,6 +29,7 @@ pandora.ui.folders = function() { { id: 'newsmart', title: 'New Smart List...' }, { id: 'newfromresults', title: 'New Smart List from Current Results...', disabled: true }, {}, + { id: 'duplicate', title: 'Duplicate List' }, { id: 'copyselection', title: 'Copy Selection to List...' }, { id: 'moveselection', title: 'Move Selection to List...' } ], diff --git a/static/js/pandora/ui/group.js b/static/js/pandora/ui/group.js index 0c606016b..5b9c12548 100644 --- a/static/js/pandora/ui/group.js +++ b/static/js/pandora/ui/group.js @@ -132,7 +132,7 @@ pandora.ui.group = function(id) { pandora.reloadGroups(i); */ pandora.UI.set('find', find); - pandora.URL.push(); + //pandora.URL.push(); }, sort: function(data) { Ox.print('SORT', data) diff --git a/static/js/pandora/ui/infoView.js b/static/js/pandora/ui/infoView.js index 8f4915cf6..b0cb498ac 100644 --- a/static/js/pandora/ui/infoView.js +++ b/static/js/pandora/ui/infoView.js @@ -517,7 +517,9 @@ pandora.ui.infoView = function(data) { pandora.UI.bind({ icons: that.reload, - showSitePoster: that.reload + showSitePoster: function() { + pandora.user.ui.icons == 'poster' && that.reload(); + } }); return that; diff --git a/static/js/pandora/ui/list.js b/static/js/pandora/ui/list.js index 9f71f64d6..432464303 100644 --- a/static/js/pandora/ui/list.js +++ b/static/js/pandora/ui/list.js @@ -689,7 +689,7 @@ pandora.ui.list = function() { }).reloadList(true); }, showSitePoster: function() { - that.reloadList(true); + pandora.user.ui.icons == 'poster' && that.reloadList(true); } }); } diff --git a/static/js/pandora/ui/menu.js b/static/js/pandora/ui/menu.js index e280187e8..c2af1c8e4 100644 --- a/static/js/pandora/ui/menu.js +++ b/static/js/pandora/ui/menu.js @@ -1,5 +1,6 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript pandora.ui.mainMenu = function() { + var isGuest = pandora.user.level == 'guest', ui = pandora.user.ui, that = Ox.MainMenu({ @@ -33,7 +34,7 @@ pandora.ui.mainMenu = function() { isGuest ? { id: 'signin', title: 'Sign In...' } : { id: 'signout', title: 'Sign Out...'} ] }, - pandora.getListMenu(), + getListMenu(), { id: 'editMenu', title: 'Edit', items: [ { id: 'undo', title: 'Undo', disabled: true, keyboard: 'control z' }, { id: 'redo', title: 'Redo', disabled: true, keyboard: 'shift control z' }, @@ -104,7 +105,7 @@ pandora.ui.mainMenu = function() { ]} ] } ]}, - pandora.getSortMenu(), + getSortMenu(), { id: 'findMenu', title: 'Find', items: [ { id: 'find', title: 'Find', items: [ { group: 'find', min: 1, max: 1, items: pandora.site.findKeys.map(function(key, i) { @@ -210,309 +211,12 @@ pandora.ui.mainMenu = function() { pandora.$ui.postersDialog = pandora.ui.postersDialog(id).open(); } else if (data.id == 'places') { pandora.$ui.placesDialog = pandora.ui.placesDialog().open(); - /* - var $manage = Ox.SplitPanel({ - elements: [ - { - collapsible: true, - element: Ox.SplitPanel({ - elements: [ - { - element: Ox.Toolbar({ - orientation: 'horizontal', - size: 44 - }).append( - pandora.$ui.findPlacesElement = Ox.FormElementGroup({ - elements: [ - pandora.$ui.findPlacesSelect = Ox.Select({ - id: 'findPlacesSelect', - items: [ - { id: 'name', title: 'Find: Name' }, - { id: 'region', title: 'Find: Region' }, - { id: 'user', title: 'Find: User' } - ], - overlap: 'right', - type: 'image' - }) - .bindEvent({ - change: function(data) { - pandora.$ui.findPlacesSelect.loseFocus(); - pandora.$ui.findPlacesInput.options({ - placeholder: data.selected[0].title - }); - } - }), - pandora.$ui.findPlacesInput = Ox.Input({ - clear: true, - id: 'findPlacesInput', - placeholder: 'Find: Name', - width: 234 - }) - ], - id: 'findPlacesElement' - }) - .css({ - float: 'left', - margin: '4px' - }) - ).append( - pandora.$ui.sortPlacesSelect = Ox.Select({ - id: 'sortPlacesSelect', - items: [ - { id: 'name', title: 'Sort by Name', checked: true }, - { id: 'region', title: 'Sort by Region' }, - { id: 'size', title: 'Sort by Size' }, - { id: 'latitude', title: 'Sort by Latitude' }, - { id: 'longitude', title: 'Sort by Longitude' }, - { id: 'clips', title: 'Sort by Number of Clips' }, - { id: 'user', title: 'Sort by User' }, - { id: 'datecreated', title: 'Sort by Date Added' }, - { id: 'datemodified', title: 'Sort by Date Modified' } - ], - width: 246 - }) - .css({ - float: 'left', - margin: '0 4px 4px 4px' - }) - ), - size: 44 - }, - { - element: Ox.Element('div') - }, - { - element: Ox.Toolbar({ - orientation: 'horizontal', - size: 16 - }), - size: 16 - } - ], - orientation: 'vertical' - }), - size: 256 - }, - { - element: Ox.SplitPanel({ - elements: [ - { - element: Ox.Toolbar({ - orientation: 'horizontal', - size: 24 - }).append( - pandora.$ui.labelsButton = Ox.Button({ - id: 'labelsButton', - title: [ - {id: 'show', title: 'Show Labels'}, - {id: 'hide', title: 'Hide Labels'} - ], - width: 96 - }) - .css({ - float: 'left', - margin: '4px' - }) - ).append( - pandora.$ui.findMapInput = Ox.Input({ - clear: true, - id: 'findMapInput', - placeholder: 'Find on Map', - width: 192 - }) - .css({ - float: 'right', - margin: '4px' - }) - .bindEvent({ - submit: function(data) { - pandora.$ui.map.find(data.value, function(location) { - - pandora.$ui.placeNameInput.options({ - disabled: false, - value: location.name - }); - pandora.$ui.placeAliasesInput.options({ - disabled: false - }); - pandora.$ui.placeGeonameLabel.options({ - disabled: false, - title: location.names.join(', ') - }); - pandora.$ui.removePlaceButton.options({ - disabled: false - }); - pandora.$ui.addPlaceButton.options({ - disabled: false - }); - - }); - } - }) - ), - size: 24 - }, - { - element: pandora.$ui.map = Ox.Map({ - places: ['Boston', 'Brussels', 'Barcelona', 'Berlin', 'Beirut', 'Bombay', 'Bangalore', 'Beijing'] - }) - .css({ - left: 0, - top: 0, - right: 0, - bottom: 0 - }) - .bindEvent({ - select: function(event, location) { - pandora.$ui.placeNameInput.options({ - disabled: false, - value: location.name - }); - pandora.$ui.placeAliasesInput.options({ - disabled: false - }); - pandora.$ui.placeGeonameLabel.options({ - disabled: false, - title: location.names.join(', ') - }); - pandora.$ui.removePlaceButton.options({ - disabled: false - }); - pandora.$ui.addPlaceButton.options({ - disabled: false - }); - } - }) - }, - { - element: pandora.$ui.bottomBar = Ox.Toolbar({ - orientation: 'horizontal', - size: 24 - }) - .append( - pandora.$ui.placeNameInput = Ox.Input({ - disabled: true, - id: 'placeName', - placeholder: 'Name', - width: 128 - }) - .css({ - float: 'left', - margin: '4px 0 0 4px' - }) - ) - .append( - pandora.$ui.placeAliasesInput = Ox.Input({ - disabled: true, - id: 'aliases', - placeholder: 'Aliases', - width: 128 - }) - .css({ - float: 'left', - margin: '4px 0 0 4px' - }) - ) - .append( - pandora.$ui.placeGeonameLabel = Ox.Label({ - disabled: true, - id: 'placeGeoname', - title: 'Geoname', - width: parseInt(pandora.$ui.document.width() * 0.8) - 256 - 256 - 32 - 24 - }) - .css({ - float: 'left', - margin: '4px 0 0 4px' - }) - ) - .append( - pandora.$ui.addPlaceButton = Ox.Button({ - disabled: true, - id: 'addPlaceButton', - title: 'add', - type: 'image' - }) - .css({ - float: 'right', - margin: '4px 4px 0 0' - }) - ) - .append( - pandora.$ui.removePlaceButton = Ox.Button({ - disabled: true, - id: 'removePlaceButton', - title: 'remove', - type: 'image' - }) - .css({ - float: 'right', - margin: '4px 4px 0 0' - }) - ), - size: 24 - } - ], - orientation: 'vertical' - }) - } - ], - orientation: 'horizontal' - }).css({ - top: '24px', - bottom: '24px', - }), - $dialog = Ox.Dialog({ - buttons: [ - { - click: function() { - $dialog.close(); - }, - id: 'close', - title: 'Close', - value: 'Close' - } - ], - height: parseInt(pandora.$ui.document.height() * 0.8), - id: 'places', - minHeight: 400, - minWidth: 600, - padding: 0, - title: 'Manage Places', - width: parseInt(pandora.$ui.document.width() * 0.8) - }).css({ - overflow: 'hidden' - }).append($manage).open(); - */ } else if (data.id == 'events') { pandora.$ui.eventsDialog = pandora.ui.eventsDialog().open(); } else if (data.id == 'users') { pandora.$ui.eventsDialog = pandora.ui.usersDialog().open(); } else if (data.id == 'lists') { pandora.$ui.eventsDialog = pandora.ui.listsDialog().open(); - } else if (data.id == 'query') { - var $dialog = Ox.Dialog({ - buttons: [ - Ox.Button({ - id: 'close', - title: 'Close' - }).bindEvent({ - click: function() { - $dialog.close(); - } - }) - ], - content: Ox.Element() - .css({padding: '16px'}) - .html([ - 'Query: ' + JSON.stringify(pandora.Query.toObject()), - 'findQuery: ' + JSON.stringify(pandora.user.ui.findQuery), - 'listQuery: ' + JSON.stringify(pandora.user.ui.listQuery) - ].join('

')), - height: 192, - keys: {enter: 'close', escape: 'close'}, - title: 'Query', - width: 384 - }).open(); } else if (data.id == 'resetgroups') { pandora.UI.set({ groups: pandora.site.user.ui.groups @@ -528,6 +232,90 @@ pandora.ui.mainMenu = function() { } }); + function getListMenu(lists) { + return { id: 'listMenu', title: 'List', items: Ox.merge( + ['personal', 'favorite', 'featured'].map(function(folder) { + return { + id: folder + 'lists', + title: Ox.toTitleCase(folder) + ' Lists', + items: [{ + group: folder + 'lists', + min: 0, + max: 1, + items: lists ? lists[folder].map(function(list) { + return { + id: 'viewlist' + list.id, + title: (folder == 'favorite' ? list.user + ': ' : '') + list.name, + checked: list.id == pandora.user.ui.list + }; + }) : [{id: 'loading', title: 'Loading...', disabled: true}] + }] + }; + }), + [ + {}, + { 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: '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 } + ] + )}; + }; + + function getSortMenu() { + var ui = pandora.user.ui, + isClipView = pandora.isClipView(ui.listView); + 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({ + checked: ui.listSort[0].key == key.id + }, key); + })) } + ] }, + { id: 'ordermovies', title: 'Order ' + (isClipView ? 'Clips' : pandora.site.itemName.plural), items: [ + { group: 'ordermovies', min: 1, max: 1, items: [ + { id: 'ascending', title: 'Ascending', checked: (ui.listSort[0].operator || pandora.getSortOperator(ui.listSort[0].key)) == '+' }, + { id: 'descending', title: 'Descending', checked: (ui.listSort[0].operator || pandora.getSortOperator(ui.listSort[0].key)) == '-' } + ]} + ] }, + { id: 'advancedsort', title: 'Advanced Sort...', keyboard: 'shift control s' }, + {}, + { id: 'sortgroups', title: 'Sort Groups', items: pandora.user.ui.groups.map(function(group) { + return { + id: 'sortgroup' + group.id, + title: 'Sort ' + Ox.getObjectById(pandora.site.groups, group.id).title + ' Group by', + items: [ + { group: 'sortgroup' + group.id, min: 1, max: 1, items: [ + { id: 'name', title: 'Name', checked: group.sort[0].key == 'name' }, + { id: 'items', title: 'Items', checked: group.sort[0].key == 'items' } + ] } + ] + } + }) }, + { id: 'ordergroups', title: 'Order Groups', items: pandora.user.ui.groups.map(function(group) { + return { + id: 'ordergroup' + group.id, + title: 'Order ' + Ox.getObjectById(pandora.site.groups, group.id).title + ' Group', + items: [ + { group: 'ordergroup' + group.id, min: 1, max: 1, items: [ + { id: 'ascending', title: 'Ascending', checked: group.sort[0].operator == '+' }, + { id: 'descending', title: 'Descending', checked: group.sort[0].operator == '-' } + ] } + ] + } + }) } + ] }; + } + // fixme: the sidebar makes the same requests. // is it ok to make them twice, or should the sidebar trigger the menu replace? @@ -556,7 +344,7 @@ pandora.ui.mainMenu = function() { lists[folder] = result.data.items; if (++counter == 3) { Ox.print('--------------------------------------------', lists) - pandora.$ui.mainMenu.replaceMenu('listMenu', pandora.getListMenu(lists)); + pandora.$ui.mainMenu.replaceMenu('listMenu', getListMenu(lists)); } }); }); diff --git a/static/js/pandora/ui/rightPanel.js b/static/js/pandora/ui/rightPanel.js index 6a940b515..875609321 100644 --- a/static/js/pandora/ui/rightPanel.js +++ b/static/js/pandora/ui/rightPanel.js @@ -58,8 +58,21 @@ pandora.ui.rightPanel = function() { }); } pandora.UI.bind({ - list: function() { - that.replaceElement(1, pandora.$ui.contentPanel = pandora.ui.contentPanel()); + 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'))) { diff --git a/static/js/pandora/ui/sortSelect.js b/static/js/pandora/ui/sortSelect.js index 089a4ba25..d429fc6b9 100644 --- a/static/js/pandora/ui/sortSelect.js +++ b/static/js/pandora/ui/sortSelect.js @@ -38,7 +38,7 @@ pandora.ui.sortSelect = function() { listSort: function(value) { that.selectItem(value[0].key); }, - item: function(valye) { + item: function(value) { }, itemSort: function(value) {