refactoring

This commit is contained in:
rolux 2011-09-27 14:14:40 +00:00
parent dee49e3a46
commit 164961e562
16 changed files with 349 additions and 637 deletions

View file

@ -564,7 +564,6 @@
"item": "", "item": "",
"itemSort": [{"key": "clip:position", "operator": ""}], "itemSort": [{"key": "clip:position", "operator": ""}],
"itemView": "info", "itemView": "info",
"list": "",
"listColumns": ["title", "director", "country", "year", "language", "runtime", "genre"], "listColumns": ["title", "director", "country", "year", "language", "runtime", "genre"],
"listColumnWidth": {}, "listColumnWidth": {},
"listSelection": [], "listSelection": [],

View file

@ -3,9 +3,25 @@
Pandora 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: never set pandora.ui.videoPosition to 0 ... set to null a.k.a. delete
// fixme: sort=-director doesn't work // fixme: sort=-director doesn't work
// fixme: don't reload full right panel on sortSelect
// fixme: clear items cache after login/logout // fixme: clear items cache after login/logout
Ox.load({ Ox.load({
@ -112,7 +128,7 @@ Ox.load({
} }
window.onpopstate = function(event) { window.onpopstate = function(event) {
pandora.URL.update(); //pandora.URL.update();
}; };
// set up url controller // set up url controller

View file

@ -1,55 +1,36 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript // vim: et:ts=4:sw=4:sts=4:ft=javascript
pandora.UI = (function() { pandora.UI = (function() {
var self = {}, that = {}; var self = {}, that = {};
self.previousUI = {}; self.previousUI = {};
that.bind = function() { that.bind = function() {
Ox.Event.bind.apply(null, arguments); Ox.Event.bind.apply(null, arguments);
}; };
that.encode = function(val) { that.encode = function(val) {
return val.replace(/\./g, '\\.'); return val.replace(/\./g, '\\.');
}; };
that.getPrevious = function(key) { that.getPrevious = function(key) {
return !key ? self.previousUI : self.previousUI[key]; return !key ? self.previousUI : self.previousUI[key];
}; };
// sets pandora.user.ui.key to val // sets pandora.user.ui.key to val
// key foo.bar.baz sets pandora.user.ui.foo.bar.baz // key foo.bar.baz sets pandora.user.ui.foo.bar.baz
// val null removes a key // val null removes a key
that.set = function(/*{key: val} or key, val*/) { that.set = function(/*{key: val} or key, val*/) {
var obj = Ox.makeObject(arguments), var obj = Ox.makeObject(arguments),
set = {}; set = {},
trigger = {};
self.previousUI = Ox.clone(pandora.user.ui, true); self.previousUI = Ox.clone(pandora.user.ui, true);
Ox.forEach(obj, function(val, key) { 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) { Ox.forEach(obj, function(val, key) {
var i = 0, var i = 0,
keys = key.split('.'), keys = key.split('.'),
listSettings = pandora.site.listSettings,
ui = pandora.user.ui; ui = pandora.user.ui;
while (i < keys.length - 1) { while (i < keys.length - 1) {
ui = ui[keys[i]]; ui = ui[keys[i]];
@ -62,20 +43,62 @@ pandora.UI = (function() {
ui[keys[i]] = val; ui[keys[i]] = val;
} }
if (key[0] != '_') { if (key[0] != '_') {
// don't send private keys // don't save or trigger events for private keys
// set[key] = val; // set[key] = val;
// fixme: remove later set[key] = val;
set[key.replace(/\./g, '|')] = 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};
} }
} }
}); });
if (Ox.len(set)) { Ox.forEach(trigger, function(val, key) {
Ox.forEach(set, function(val, key) {
Ox.Event.trigger(key, val); Ox.Event.trigger(key, val);
}); });
pandora.api.setUI(set); // 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;
});
pandora.api.setUI(set_);
} }
}; };
return that; return that;
}()); }());

View file

@ -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() { function getState() {
return { 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) { function setState(state) {
Ox.print('STATE:', state) Ox.print('STATE:', state)
var previousUI = pandora.UI.getPrevious(); var previousUI = pandora.UI.getPrevious();
@ -240,8 +115,8 @@ pandora.URL = (function() {
$('video').each(function() { $('video').each(function() {
$(this).trigger('stop'); $(this).trigger('stop');
}); });
pandora.user.ui._groupsState = getGroupsState(pandora.user.ui.find); pandora.user.ui._groupsState = pandora.getGroupsState();
pandora.user.ui._findState = getFindState(pandora.user.ui.find, pandora.user.ui.list, pandora.user.ui._groupsState); pandora.user.ui._findState = pandora.getFindState();
if (Ox.isEmpty(state)) { if (Ox.isEmpty(state)) {
if (pandora.user.ui.showHome) { if (pandora.user.ui.showHome) {
pandora.$ui.home = pandora.ui.home().showScreen(); pandora.$ui.home = pandora.ui.home().showScreen();
@ -292,21 +167,21 @@ pandora.URL = (function() {
state.find && pandora.UI.set({ state.find && pandora.UI.set({
find: state.find, find: state.find,
list: getListsState(state.find) list: pandora.getListsState(state.find)
}); });
if (state.view) { if (state.view) {
pandora.UI.set( pandora.UI.set(
!pandora.user.ui.item !pandora.user.ui.item
? 'lists.' + pandora.user.ui.list + '.view' ? 'listView'
: 'itemView', : 'itemView',
state.view state.view
); );
} }
pandora.user.ui._groupsState = getGroupsState(pandora.user.ui.find); pandora.user.ui._groupsState = pandora.getGroupsState();
Ox.print('_groupsState =', pandora.user.ui._groupsState); 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 (['video', 'timeline'].indexOf(pandora.user.ui.itemView) > -1) {
if (state.span) { if (state.span) {
@ -331,6 +206,7 @@ pandora.URL = (function() {
state.sort state.sort
); );
/*
if (!pandora.$ui.appPanel) { if (!pandora.$ui.appPanel) {
return; return;
} }
@ -403,6 +279,7 @@ pandora.URL = (function() {
$item.options('position') $item.options('position')
); );
} }
*/
} }
pandora.user.ui.showHome = false; pandora.user.ui.showHome = false;
@ -555,7 +432,7 @@ pandora.URL = (function() {
views: views 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() { pandora.UI.bind(event, function() {
that.push(); that.push();
}); });

View file

@ -368,32 +368,6 @@ pandora.getListData = function() {
return data; 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) { pandora.getMetadataByIdOrName = function(item, view, str, callback) {
// For a given item (or none) and a given view (or any), this takes a string // 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, // 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) { pandora._getSortOperator = function(type) {
return ['hue', 'string', 'text'].indexOf( return ['hue', 'string', 'text'].indexOf(
Ox.isArray(type) ? type[0] : type Ox.isArray(type) ? type[0] : type
@ -568,59 +492,6 @@ pandora.signout = function(data) {
pandora.$ui.appPanel.reload(); 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() { pandora.reloadList = function() {
Ox.print('reloadList') Ox.print('reloadList')
var listData = pandora.getListData(); var listData = pandora.getListData();
@ -628,7 +499,8 @@ pandora.reloadList = function() {
pandora.$ui.groups.forEach(function($group) { pandora.$ui.groups.forEach(function($group) {
$group.reloadList(); $group.reloadList();
}); });
pandora.$ui.list.bindEvent({ pandora.$ui.list
.bindEvent({
init: function(data) { init: function(data) {
// fixme: this will not work for lists in the favorites folder // fixme: this will not work for lists in the favorites folder
// (but then it's also unlikely they'll have to be reloaded) // (but then it's also unlikely they'll have to be reloaded)
@ -647,7 +519,6 @@ pandora.reloadList = function() {
pandora.resizeGroups = function(width) { pandora.resizeGroups = function(width) {
pandora.user.ui.groupsSizes = pandora.getGroupsSizes(); 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 pandora.$ui.browser
.size(0, pandora.user.ui.groupsSizes[0]) .size(0, pandora.user.ui.groupsSizes[0])
.size(2, pandora.user.ui.groupsSizes[4]); .size(2, pandora.user.ui.groupsSizes[4]);
@ -666,14 +537,12 @@ pandora.resizeFolders = function() {
columnWidth = {user: parseInt((width - 96) * 0.4)}; columnWidth = {user: parseInt((width - 96) * 0.4)};
columnWidth.name = (width - 96) - columnWidth.user; columnWidth.name = (width - 96) - columnWidth.user;
} }
//Ox.print('sectionsWidth', width)
Ox.forEach(pandora.$ui.folderList, function($list, id) { Ox.forEach(pandora.$ui.folderList, function($list, id) {
var i = Ox.getPositionById(pandora.site.sectionFolders[pandora.user.ui.section], id); var pos = Ox.getPositionById(pandora.site.sectionFolders[pandora.user.ui.section], id);
pandora.$ui.folder[i].css({width: width + 'px'}); pandora.$ui.folder[pos].css({width: width + 'px'});
$list.css({width: width + 'px'}); $list.css({width: width + 'px'});
if (pandora.user.ui.section == 'items') { if (pandora.user.ui.section == 'items') {
if (pandora.site.sectionFolders[pandora.user.ui.section][i].showBrowser) { if (pandora.site.sectionFolders[pandora.user.ui.section][pos].showBrowser) {
Ox.print('ID', id)
pandora.$ui.findListInput[id].options({ pandora.$ui.findListInput[id].options({
width: width - 24 width: width - 24
}); });
@ -684,12 +553,13 @@ pandora.resizeFolders = function() {
} }
} }
if (!pandora.user.ui.showFolder[pandora.user.ui.section][id]) { if (!pandora.user.ui.showFolder[pandora.user.ui.section][id]) {
pandora.$ui.folder[i].update(); pandora.$ui.folder[pos].update();
} }
}); });
}; };
pandora.selectList = function() { pandora.selectList = function() {
// fixme: can this be removed?
if (pandora.user.ui.list) { if (pandora.user.ui.list) {
pandora.api.findLists({ pandora.api.findLists({
keys: ['status', 'user'], keys: ['status', 'user'],
@ -710,10 +580,143 @@ pandora.selectList = function() {
.gainFocus(); .gainFocus();
} else { } else {
pandora.user.ui.list = ''; 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;
};
}());

View file

@ -102,13 +102,10 @@ pandora.ui.browser = function() {
}).reloadList(true); }).reloadList(true);
}, },
showSitePoster: function() { 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; return that;
}; };

View file

@ -32,8 +32,8 @@ pandora.ui.contentPanel = function() {
listView: function() { listView: function() {
that.replaceElement(1, pandora.$ui.list = pandora.ui.list()); that.replaceElement(1, pandora.$ui.list = pandora.ui.list());
}, },
item: function() { item: function(value) {
that.replaceElement(1, pandora.$ui.item = pandora.ui.item()); value && that.replaceElement(1, pandora.$ui.item = pandora.ui.item());
}, },
itemView: function() { itemView: function() {
that.replaceElement(1, pandora.$ui.item = pandora.ui.item()); that.replaceElement(1, pandora.$ui.item = pandora.ui.item());

View file

@ -105,7 +105,6 @@ pandora.ui.findElement = function() {
operator: '' operator: ''
}); });
} }
pandora.URL.push();
} }
}) })
]), ]),
@ -120,12 +119,15 @@ pandora.ui.findElement = function() {
var elementValue = that.value(), var elementValue = that.value(),
key = elementValue[pandora.user.ui.list ? 1 : 0], key = elementValue[pandora.user.ui.list ? 1 : 0],
findKey = Ox.getObjectById(pandora.site.findKeys, key); 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'); 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({ pandora.api.autocomplete({
key: key, 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], range: [0, 20],
sort: [{ sort: [{
key: 'votes', key: 'votes',

View file

@ -1,4 +1,5 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript // vim: et:ts=4:sw=4:sts=4:ft=javascript
pandora.ui.folderList = function(id) { pandora.ui.folderList = function(id) {
var i = Ox.getPositionById(pandora.site.sectionFolders[pandora.user.ui.section], id), var i = Ox.getPositionById(pandora.site.sectionFolders[pandora.user.ui.section], id),
that; that;
@ -372,30 +373,20 @@ pandora.ui.folderList = function(id) {
pandora.$ui.list.triggerEvent('paste', data); pandora.$ui.list.triggerEvent('paste', data);
}, },
select: function(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_) { Ox.forEach(pandora.$ui.folderList, function($list, id_) {
id != id_ && $list.options('selected', []); id != id_ && $list.options('selected', []);
}); });
} }
// pandora.URL.push(data.ids.length ? '/list==' + data.ids[0] : '')
/*
pandora.UI.set({ 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: { find: {
conditions: data.ids.length ? [ conditions: list ? [
{key: 'list', value: data.ids[0], operator: '=='} {key: 'list', value: data.ids[0], operator: '=='}
] : [], ] : [],
operator: '&' operator: '&'
} }
}) });
pandora.URL.push();
}, },
submit: function(data) { submit: function(data) {
data_ = {id: data.id}; data_ = {id: data.id};

View file

@ -29,6 +29,7 @@ pandora.ui.folders = function() {
{ id: 'newsmart', title: 'New Smart List...' }, { id: 'newsmart', title: 'New Smart List...' },
{ id: 'newfromresults', title: 'New Smart List from Current Results...', disabled: true }, { id: 'newfromresults', title: 'New Smart List from Current Results...', disabled: true },
{}, {},
{ id: 'duplicate', title: 'Duplicate List' },
{ id: 'copyselection', title: 'Copy Selection to List...' }, { id: 'copyselection', title: 'Copy Selection to List...' },
{ id: 'moveselection', title: 'Move Selection to List...' } { id: 'moveselection', title: 'Move Selection to List...' }
], ],

View file

@ -132,7 +132,7 @@ pandora.ui.group = function(id) {
pandora.reloadGroups(i); pandora.reloadGroups(i);
*/ */
pandora.UI.set('find', find); pandora.UI.set('find', find);
pandora.URL.push(); //pandora.URL.push();
}, },
sort: function(data) { sort: function(data) {
Ox.print('SORT', data) Ox.print('SORT', data)

View file

@ -517,7 +517,9 @@ pandora.ui.infoView = function(data) {
pandora.UI.bind({ pandora.UI.bind({
icons: that.reload, icons: that.reload,
showSitePoster: that.reload showSitePoster: function() {
pandora.user.ui.icons == 'poster' && that.reload();
}
}); });
return that; return that;

View file

@ -689,7 +689,7 @@ pandora.ui.list = function() {
}).reloadList(true); }).reloadList(true);
}, },
showSitePoster: function() { showSitePoster: function() {
that.reloadList(true); pandora.user.ui.icons == 'poster' && that.reloadList(true);
} }
}); });
} }

View file

@ -1,5 +1,6 @@
// vim: et:ts=4:sw=4:sts=4:ft=javascript // vim: et:ts=4:sw=4:sts=4:ft=javascript
pandora.ui.mainMenu = function() { pandora.ui.mainMenu = function() {
var isGuest = pandora.user.level == 'guest', var isGuest = pandora.user.level == 'guest',
ui = pandora.user.ui, ui = pandora.user.ui,
that = Ox.MainMenu({ that = Ox.MainMenu({
@ -33,7 +34,7 @@ pandora.ui.mainMenu = function() {
isGuest ? { id: 'signin', title: 'Sign In...' } isGuest ? { id: 'signin', title: 'Sign In...' }
: { id: 'signout', title: 'Sign Out...'} : { id: 'signout', title: 'Sign Out...'}
] }, ] },
pandora.getListMenu(), getListMenu(),
{ id: 'editMenu', title: 'Edit', items: [ { id: 'editMenu', title: 'Edit', items: [
{ id: 'undo', title: 'Undo', disabled: true, keyboard: 'control z' }, { id: 'undo', title: 'Undo', disabled: true, keyboard: 'control z' },
{ id: 'redo', title: 'Redo', disabled: true, keyboard: 'shift 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: 'findMenu', title: 'Find', items: [
{ id: 'find', title: 'Find', items: [ { id: 'find', title: 'Find', items: [
{ group: 'find', min: 1, max: 1, items: pandora.site.findKeys.map(function(key, i) { { 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(); pandora.$ui.postersDialog = pandora.ui.postersDialog(id).open();
} else if (data.id == 'places') { } else if (data.id == 'places') {
pandora.$ui.placesDialog = pandora.ui.placesDialog().open(); 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') { } else if (data.id == 'events') {
pandora.$ui.eventsDialog = pandora.ui.eventsDialog().open(); pandora.$ui.eventsDialog = pandora.ui.eventsDialog().open();
} else if (data.id == 'users') { } else if (data.id == 'users') {
pandora.$ui.eventsDialog = pandora.ui.usersDialog().open(); pandora.$ui.eventsDialog = pandora.ui.usersDialog().open();
} else if (data.id == 'lists') { } else if (data.id == 'lists') {
pandora.$ui.eventsDialog = pandora.ui.listsDialog().open(); 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('<br/><br/>')),
height: 192,
keys: {enter: 'close', escape: 'close'},
title: 'Query',
width: 384
}).open();
} else if (data.id == 'resetgroups') { } else if (data.id == 'resetgroups') {
pandora.UI.set({ pandora.UI.set({
groups: pandora.site.user.ui.groups 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. // fixme: the sidebar makes the same requests.
// is it ok to make them twice, or should the sidebar trigger the menu replace? // 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; lists[folder] = result.data.items;
if (++counter == 3) { if (++counter == 3) {
Ox.print('--------------------------------------------', lists) Ox.print('--------------------------------------------', lists)
pandora.$ui.mainMenu.replaceMenu('listMenu', pandora.getListMenu(lists)); pandora.$ui.mainMenu.replaceMenu('listMenu', getListMenu(lists));
} }
}); });
}); });

View file

@ -58,8 +58,21 @@ pandora.ui.rightPanel = function() {
}); });
} }
pandora.UI.bind({ pandora.UI.bind({
list: function() { 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()); that.replaceElement(1, pandora.$ui.contentPanel = pandora.ui.contentPanel());
}
}, },
itemView: function(value) { itemView: function(value) {
if (pandora.isClipView() != pandora.isClipView(pandora.UI.getPrevious('itemView'))) { if (pandora.isClipView() != pandora.isClipView(pandora.UI.getPrevious('itemView'))) {

View file

@ -38,7 +38,7 @@ pandora.ui.sortSelect = function() {
listSort: function(value) { listSort: function(value) {
that.selectItem(value[0].key); that.selectItem(value[0].key);
}, },
item: function(valye) { item: function(value) {
}, },
itemSort: function(value) { itemSort: function(value) {