diff --git a/pandora/0xdb.jsonc b/pandora/0xdb.jsonc index 715da10f3..3b269e130 100644 --- a/pandora/0xdb.jsonc +++ b/pandora/0xdb.jsonc @@ -39,8 +39,8 @@ {"id": "lightness", "title": "Lightness", "type": "float"}, {"id": "volume", "title": "Volume", "type": "float"} ], - // fixme: either this, or group: true in itemKeys, but not both - "groups": [ + // fixme: either this, or filter: true in itemKeys, but not both + "filters": [ {"id": "director", "title": "Director", "type": "string"}, {"id": "country", "title": "Country", "type": "string"}, {"id": "year", "title": "Year", "type": "integer"}, @@ -65,9 +65,9 @@ columnRequired: If true, the column can't be removed columnWidth: Default column width in px find: If true, will appear as a find option + filter: if true, one can filter results by this key format: {type: "...", args: [...]}, for special formatting (Ox.formatType(args) will be called) - group: if true, one can group results by this key sort: special sort rule (title, person) sortOperator: sort operator (+, -), in case it differs from the default for the key's type (+ for strings, - for numbers) @@ -99,8 +99,8 @@ "autocomplete": true, "columnRequired": true, "columnWidth": 180, + "filter": true, "find": true, - "group": true, "sort": "person" }, { @@ -109,8 +109,8 @@ "type": ["string"], "autocomplete": true, "columnWidth": 120, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "year", @@ -118,8 +118,8 @@ "type": "year", // fixme: do we need this? "autocomplete": true, "columnWidth": 60, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "language", @@ -128,7 +128,7 @@ "autocomplete": true, "columnWidth": 120, "find": true, - "group": true + "filter": true }, { "id": "runtime", @@ -143,8 +143,8 @@ "type": ["string"], "autocomplete": true, "columnWidth": 180, + "filter": true, "find": true, - "group": true, "sort": "person" }, { @@ -153,8 +153,8 @@ "type": ["string"], "autocomplete": true, "columnWidth": 180, + "filter": true, "find": true, - "group": true, "sort": "person" }, { @@ -163,8 +163,8 @@ "type": ["string"], "autocomplete": true, "columnWidth": 180, + "filter": true, "find": true, - "group": true, "sort": "person" }, { @@ -173,8 +173,8 @@ "type": ["string"], "autocomplete": true, "columnWidth": 180, + "filter": true, "find": true, - "group": true, "sort": "person" }, { @@ -182,8 +182,8 @@ "title": "Actor", "type": ["string"], "autocomplete": true, + "filter": true, "find": true, - "group": true, "sort": "person" }, { @@ -214,16 +214,16 @@ "type": ["string"], "autocomplete": true, "columnWidth": 120, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "keyword", "title": "Keyword", "type": ["string"], "autocomplete": true, - "find": true, - "group": true + "filter": true, + "find": true }, { "id": "summary", @@ -589,15 +589,15 @@ "columnWidth": {} } }, - "find": {"conditions": [], "operator": "&"}, - "groups": [ + "filters": [ {"id": "director", "sort": [{"key": "items", "operator": "-"}]}, {"id": "country", "sort": [{"key": "items", "operator": "-"}]}, {"id": "year", "sort": [{"key": "name", "operator": "-"}]}, {"id": "language", "sort": [{"key": "items", "operator": "-"}]}, {"id": "genre", "sort": [{"key": "items", "operator": "-"}]} ], - "groupsSize": 176, + "filtersSize": 176, + "find": {"conditions": [], "operator": "&"}, "icons": "posters", "infoIconSize": 256, "item": "", @@ -616,8 +616,8 @@ "showAnnotations": true, "showBrowser": true, "showCalendarControls": true, // fixme: should be false + "showFilters": true, "showFlags": true, - "showGroups": true, "showHome": true, "showIconBrowser": false, "showInfo": true, diff --git a/static/js/pandora/Query.js b/static/js/pandora/Query.js deleted file mode 100644 index 1751ff3ec..000000000 --- a/static/js/pandora/Query.js +++ /dev/null @@ -1,306 +0,0 @@ -// vim: et:ts=4:sw=4:sts=4:ft=javascript - -'use strict'; - -// FIXME: remove this - -pandora.Query = (function() { - - function constructFind(query) { - return /*encodeURI(*/query.conditions.map(function(condition) { - var ret; - if (condition.conditions) { - ret = '[' + constructFind(condition) + ']'; - } else { - ret = condition.value !== '' - ? condition.key + (condition.key ? ':' : '') - + constructValue(condition.value, condition.operator) - : null; - } - return ret; - }).join(query.operator == '&' ? ',' : '|')/*)*/; - } - - function constructValue(value, operator) { - value = encodeURIComponent(value); - operator = operator.replace('=', '^$'); - if (operator.indexOf('$') > -1) { - value = operator.substr(0, operator.length - 1) + value + '$'; - } else { - value = operator + value; - } - return value; - } - - 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 getGroupsData(fullQuery) { - // 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) { - var index = -1, - key = group.id, - query = Ox.clone(fullQuery, true), - selected = []; - if (query.operator == '|') { - if (everyCondition(query.conditions, key, '=')) { - index = Ox.range(query.conditions.length); - selected = query.conditions.map(function(condition) { - return condition.value; - }); - } - } else { - index = oneCondition(query.conditions, key, '='); - if (index > -1) { - selected = query.conditions[index].conditions - ? query.conditions[index].conditions.map(function(condition) { - return condition.value; - }) - : [query.conditions[index].value]; - } - } - if (selected.length) { - if (Ox.isArray(index)) { - query = {conditions: [], operator: ''}; - } else { - query.conditions.splice(index, 1); - if (query.conditions.length == 1) { - if (query.conditions[0].conditions) { - // unwrap single remaining bracketed query - query = { - conditions: query.conditions[0].conditions, - operator: query.conditions[0].operator - } - } else { - query.operator = ''; - } - } - } - } - return { - index: index, - query: query, - selected: selected - }; - }); - } - - function parseFind(str) { - // takes a find query string, returns useful information about the application's state - // (selected lists, find input key/value (and index of the corresponding condition), query object) - var conditions, - index, indices, - ret = { - find: {index: -1, key: '', value: ''}, - groups: [], // {index, query, selected} - list: '', - query: {conditions: [], operator: '&'} - }, - subconditions = []; - if (str.length) { - // replace subconditions with placeholder, - // so we can later split by main operator - var counter = 0; - Ox.forEach(str, function(c, i) { - if (c == ']') { - counter--; - } - if (counter >= 1) { - subconditions[subconditions.length - 1] += c; - } - if (c == '[') { - (++counter == 1) && subconditions.push(''); - } - }); - subconditions.forEach(function(subcondition, i) { - str = str.replace(subcondition, i); - }); - if (str.indexOf(',') > -1) { - ret.query.operator = '&'; - } else if (str.indexOf('|') > -1) { - ret.query.operator = '|'; - } - ret.query.conditions = ( - ret.query.operator == '' ? [str] : str.split(ret.query.operator == '&' ? ',' : '|') - ).map(function(condition, i) { - var kv, ret; - if (condition[0] == '[') { - // re-insert subcondition - ret = parseFind(subconditions[parseInt(Ox.sub(condition, 1, -1))]).query; - } else { - kv = ((condition.indexOf(':') > -1 ? '' : ':') + condition).split(':'); - ret = Ox.extend({key: kv[0]}, parseValue(kv[1])); - } - return ret; - }); - // a list is selected if exactly one condition in an & query - // has "list" as key and "" as operator - if (ret.query.operator != '|') { - index = oneCondition(ret.query.conditions, 'list', ''); - if (index > -1 && !ret.query.conditions[index].conditions) { - ret.list = ret.query.conditions[index].value; - } - } - ret.groups = getGroupsData(ret.query); - // find 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 - if (ret.query.operator == '|') { - ret.find = {index: -1, key: 'advanced', value: ''}; - Ox.map(pandora.user.ui.groups, function(key) { - if (everyCondition(ret.query.conditions, key, '=')) { - ret.find.key = ''; - return false; - } - }); - } else { - // number of conditions that are not list or groups - conditions = ret.query.conditions.length - - (ret.list != '') - - ret.groups.filter(function(group) { - return group.index > -1; - }).length; - // indices of non-advanced find queries - indices = Ox.map(pandora.site.findKeys, function(findKey) { - var key = findKey.id == 'all' ? '' : findKey.id, - index = oneCondition(ret.query.conditions, key, ''); - return index > -1 ? index : null; - }); - if (conditions > 0 || indices.length > 0) { - ret.find = ( - conditions == 1 && indices.length == 1 - && !ret.query.conditions[indices[0]].conditions - ) ? { - index: indices[0], - key: ret.query.conditions[indices[0]].key, - value: decodeURIComponent(ret.query.conditions[indices[0]].value) - } : {index: -1, key: 'advanced', value: ''} - } - } - } - return ret; - } - - function oneCondition(conditions, key, operator) { - // if exactly one condition has the given key and operator - // (including conditions where all subconditions match) - // returns the corresponding index, otherwise returns -1 - var indices = Ox.map(conditions, function(condition, i) { - return ( - condition.conditions - ? everyCondition(condition.conditions, key, operator) - : condition.key == key && condition.operator == operator - ) ? i : null; - }); - return indices.length == 1 ? indices[0] : -1; - } - - function parseValue(str) { - var value = { - value: decodeURI(str), - operator: '' - }; - if (value.value[0] == '!') { - value.operator = '!'; - value.value = value.value.substr(1); - } - if ('^<>'.indexOf(value.value[0]) > -1) { - value.operator += value.value[0]; - value.value = value.value.substr(1); - } - if (value.value.substr(-1) == '$') { - value.operator += '$'; - value.value = value.value.substr(0, value.value.length - 1); - } - value.operator = value.operator.replace('^$', '='); - return value; - } - - return { - - fromString: function(str) { - var query = Ox.unserialize(str), - data = parseFind(query.find || ''); - Ox.Log('', Ox.repeat('-', 120)); - Ox.Log('', 'STATE', data); - Ox.Log('', Ox.repeat('-', 120)); - pandora.UI.set({list: data.list}); - !pandora.user.ui.lists[data.list] && pandora.UI.set( - 'lists|' + data.list, pandora.site.user.ui.lists[''] - ); - pandora.user.ui.find = data.find; - pandora.user.ui.groupsData = data.groups; - pandora.user.ui.query = data.query; - if ('sort' in query) { - pandora.UI.set('lists|' + pandora.user.ui.list + '|sort', query.sort.split(',').map(function(v) { - var hasOperator = '+-'.indexOf(v[0]) > -1, - key = hasOperator ? v.substr(1) : v, - operator = hasOperator ? v[0]/*.replace('+', '')*/ : pandora.getSortOperator(key); - return { - key: key, - operator: operator - }; - })); - } - /* - if ('view' in query) { - pandora.UI.set(['lists', pandora.user.ui.list, 'listView'].join('|'), query.view); - } - */ - }, - - /* - toObject: function(groupId) { - //Ox.Log('', 'tO', pandora.user.ui.findQuery.conditions) - // the inner $.merge() creates a clone - var conditions = $.merge( - $.merge([], pandora.user.ui.listQuery.conditions), - pandora.user.ui.findQuery.conditions - ), - operator; - $.merge(conditions, pandora.user.queryGroups ? $.map(pandora.user.queryGroups, function(v, i) { - if (v.id != groupId && v.query.conditions.length) { - return v.query.conditions.length == 1 ? - v.query.conditions : v.query; - } - }) : []); - operator = conditions.length < 2 ? '' : ','; // fixme: should be & - //Ox.Log('', '>>', groupId, pandora.user.ui.find, conditions); - return { - conditions: conditions, - operator: operator - }; - }, - */ - - toString: function() { - //Ox.Log('', 'tS', pandora.user.ui.find) - if (!pandora.user.ui.item) { - var sort = pandora.user.ui.lists[pandora.user.ui.list].sort[0], - key = sort.key, - operator = sort.operator; - return pandora.user.ui.lists[pandora.user.ui.list].listView + '/?' + Ox.serialize({ - find: constructFind(pandora.user.ui.query), - sort: (operator == pandora.getSortOperator(key) ? '' : operator) + key - }); - } else { - return pandora.user.ui.item + '/' + pandora.user.ui.itemView; - } - }, - - updateGroups: function() { - pandora.user.ui.groupsData = getGroupsData(pandora.user.ui.query); - } - - }; - -})(); diff --git a/static/js/pandora/UI.js b/static/js/pandora/UI.js index f3f53a552..2fb51a3d2 100644 --- a/static/js/pandora/UI.js +++ b/static/js/pandora/UI.js @@ -16,8 +16,8 @@ pandora.UI = (function() { that.reset = function() { pandora.user.ui = pandora.site.user.ui; - pandora.user.ui._list = pandora.getListsState(pandora.user.ui.find); - pandora.user.ui._groupsState = pandora.getGroupsState(pandora.user.ui.find); + pandora.user.ui._list = pandora.getListState(pandora.user.ui.find); + pandora.user.ui._filterState = pandora.getFilterState(pandora.user.ui.find); pandora.user.ui._findState = pandora.getFindState(pandora.user.ui.find); }; @@ -46,16 +46,16 @@ pandora.UI = (function() { Ox.Log('UI', 'SET', args) self.previousUI = Ox.clone(pandora.user.ui, true); - self.previousUI._list = pandora.getListsState(self.previousUI.find); + self.previousUI._list = pandora.getListState(self.previousUI.find); if ('find' in args) { // 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 // (values we put in add will be changed, but won't trigger) - list = pandora.getListsState(args.find); + list = pandora.getListState(args.find); pandora.user.ui._list = list; - pandora.user.ui._groupsState = pandora.getGroupsState(args.find); + pandora.user.ui._filterState = pandora.getFilterState(args.find); pandora.user.ui._findState = pandora.getFindState(args.find); if (pandora.$ui.appPanel) { // if we're not on page load, diff --git a/static/js/pandora/URL.js b/static/js/pandora/URL.js index 6f2ed3e21..b99552516 100644 --- a/static/js/pandora/URL.js +++ b/static/js/pandora/URL.js @@ -53,8 +53,8 @@ pandora.URL = (function() { function setState(state, callback) { - pandora.user.ui._list = pandora.getListsState(pandora.user.ui.find); - pandora.user.ui._groupsState = pandora.getGroupsState(pandora.user.ui.find); + pandora.user.ui._list = pandora.getListState(pandora.user.ui.find); + pandora.user.ui._filterState = pandora.getFilterState(pandora.user.ui.find); pandora.user.ui._findState = pandora.getFindState(pandora.user.ui.find); if (Ox.isEmpty(state)) { diff --git a/static/js/pandora/browser.js b/static/js/pandora/browser.js index de9628ec5..415b7c930 100644 --- a/static/js/pandora/browser.js +++ b/static/js/pandora/browser.js @@ -3,20 +3,20 @@ pandora.ui.browser = function() { var that; if (!pandora.user.ui.item) { - pandora.user.ui.groupsSizes = pandora.getGroupsSizes(); - pandora.$ui.groups = pandora.ui.groups(); + pandora.user.ui.filterSizes = pandora.getFilterSizes(); + pandora.$ui.filters = pandora.ui.filters(); that = Ox.SplitPanel({ elements: [ { - element: pandora.$ui.groups[0], - size: pandora.user.ui.groupsSizes[0] + element: pandora.$ui.filters[0], + size: pandora.user.ui.filterSizes[0] }, { - element: pandora.$ui.groupsInnerPanel = pandora.ui.groupsInnerPanel() + element: pandora.$ui.filtersInnerPanel = pandora.ui.filtersInnerPanel() }, { - element: pandora.$ui.groups[4], - size: pandora.user.ui.groupsSizes[4] + element: pandora.$ui.filters[4], + size: pandora.user.ui.filterSizes[4] }, ], id: 'browser', @@ -24,7 +24,7 @@ pandora.ui.browser = function() { }) .bindEvent({ resize: function(data) { - pandora.$ui.groups.forEach(function(list) { + pandora.$ui.filters.forEach(function(list) { list.size(); }); if (pandora.user.ui.listView == 'map') { @@ -34,11 +34,11 @@ pandora.ui.browser = function() { } }, resizeend: function(data) { - pandora.UI.set({groupsSize: data.size}); + pandora.UI.set({filtersSize: data.size}); }, toggle: function(data) { data.collapsed && pandora.$ui.list.gainFocus(); - pandora.UI.set({showGroups: !data.collapsed}); + pandora.UI.set({showFilters: !data.collapsed}); if (pandora.user.ui.listView == 'map') { pandora.$ui.map.resizeMap(); } else if (pandora.user.ui.listView == 'calendar') { diff --git a/static/js/pandora/contentPanel.js b/static/js/pandora/contentPanel.js index 56a8f7bcd..504dfee3a 100644 --- a/static/js/pandora/contentPanel.js +++ b/static/js/pandora/contentPanel.js @@ -4,13 +4,13 @@ pandora.ui.contentPanel = function() { var that = Ox.SplitPanel({ elements: !pandora.user.ui.item ? [ { - collapsed: !pandora.user.ui.showGroups, + collapsed: !pandora.user.ui.showFilters, collapsible: true, element: pandora.$ui.browser = pandora.ui.browser(), resizable: true, resize: [96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256], - size: pandora.user.ui.groupsSize, - tooltip: 'groups' + size: pandora.user.ui.filtersSize, + tooltip: 'filters' }, { element: pandora.$ui.list = pandora.ui.list() @@ -44,7 +44,7 @@ pandora.ui.contentPanel = function() { pandora_showbrowser: function(data) { data.value == that.options('elements')[0].collapsed && that.toggle(0); }, - pandora_showgroups: function(data) { + pandora_showfilters: function(data) { data.value == that.options('elements')[0].collapsed && that.toggle(0); } }); diff --git a/static/js/pandora/filter.js b/static/js/pandora/filter.js index d49751faf..95223dd66 100644 --- a/static/js/pandora/filter.js +++ b/static/js/pandora/filter.js @@ -1,61 +1,252 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript - 'use strict'; - -pandora.ui.filter = function(list) { - var that = Ox.Filter({ - findKeys: Ox.merge(Ox.map(pandora.site.itemKeys, function(key) { - return { - autocomplete: key.autocomplete, - autocompleteSortKey: key.autocompleteSortKey, - format: key.format, - id: key.id, - title: key.title, - type: key.type == 'layer' - ? Ox.getObjectById(pandora.site.layers, key.id).type - : key.type - }; - }), { - id: 'list', - title: 'List', - type: 'list' - }), - list: list ? null : { - sort: pandora.user.ui.listSort, - view: pandora.user.ui.listView - }, - query: list ? list.query : pandora.user.ui.find, - sortKeys: pandora.site.sortKeys, - viewKeys: pandora.site.listViews - }) - .css({padding: '16px'}) - .bindEvent({ - change: function(data) { - if (list) { - pandora.api.editList({ - id: list.id, - query: data.query - }, function(result) { - Ox.Request.clearCache(list.id); - pandora.$ui.list - .bindEventOnce({ - init: function(data) { - pandora.$ui.folderList[ - pandora.getListData().folder - ].value(list.id, 'items', data.items); - } - }) - .reloadList(); - pandora.$ui.groups.forEach(function($group) { - $group.reloadList(); - }); - }); - } else { - pandora.UI.set({find: data.query}); - //pandora.URL.replace(); +pandora.ui.filter = function(id) { + var i = Ox.getPositionById(pandora.user.ui.filters, id), + filter = Ox.getObjectById(pandora.site.filters, id), + panelWidth = pandora.$ui.document.width() - (pandora.user.ui.showSidebar * pandora.user.ui.sidebarSize) - 1, + title = Ox.getObjectById(pandora.site.filters, id).title, + //width = pandora.getFilterWidth(i, panelWidth), + that = Ox.TextList({ + columns: [ + { + align: 'left', + id: 'name', + format: function(value) { + return ['country', 'language'].indexOf(id) > -1 && pandora.user.ui.showFlags + ? $('