diff --git a/pandora/0xdb.json b/pandora/0xdb.json index bb712806..4d25cd96 100644 --- a/pandora/0xdb.json +++ b/pandora/0xdb.json @@ -6,7 +6,7 @@ "canSeeFiles": {"guest": -1, "member": -1, "staff": 3, "admin": 4} }, "clipKeys": [ - {"id": "clip:value", "title": "Clip Text", "type": "string"}, + {"id": "clip:text", "title": "Clip Text", "type": "string"}, {"id": "clip:position", "title": "Clip Position", "type": "float"}, {"id": "clip:duration", "title": "Clip Duration", "type": "float"}, {"id": "clip:hue", "title": "Clip Hue", "type": "hue"}, @@ -432,7 +432,6 @@ "value": "capability" } ], - "fixme": "itemNames should be lowercase!", "itemName": { "singular": "Movie", "plural": "Movies" @@ -441,7 +440,7 @@ {"id": "info", "title": "Info"}, {"id": "statistics", "title": "Statistics"}, {"id": "clips", "title": "Clips"}, - {"id": "player", "title": "Player"}, + {"id": "video", "title": "Video"}, {"id": "timeline", "title": "Timeline"}, {"id": "map", "title": "Map"}, {"id": "calendar", "title": "Calendar"}, @@ -481,7 +480,7 @@ {"id": "maps", "title": "with Maps"}, {"id": "calendars", "title": "with Calendars"}, {"id": "clip", "title": "as Clips"}, - {"id": "player", "title": "as Player"}, + {"id": "video", "title": "as Video"}, {"id": "map", "title": "on Map"}, {"id": "calendar", "title": "on Calendar"} ], @@ -594,7 +593,7 @@ "videoScale": "fit", "videoMuted": false, "videoSize": "small", - "videoView": "player", + "videoView": "video", "videoVolume": 1 }, "username": "", diff --git a/static/js/pandora.js b/static/js/pandora.js index b8878156..1dc27b63 100644 --- a/static/js/pandora.js +++ b/static/js/pandora.js @@ -53,6 +53,11 @@ Ox.load({ }); Ox.extend(pandora.site, { + clipKeys: Ox.map(data.site.clipKeys, function(key) { + return Ox.extend(key, { + operator: pandora._getSortOperator(key.type) + }); + }), findKeys: Ox.map(data.site.itemKeys, function(key) { return key.find ? key : null; }), @@ -75,7 +80,9 @@ Ox.load({ ] }, sortKeys: Ox.map(data.site.itemKeys, function(key) { - return key.columnWidth ? key : null; + return key.columnWidth ? Ox.extend(key, { + operator: pandora._getSortOperator(key.type) + }) : null; }) }); Ox.extend(pandora.user, { @@ -97,6 +104,79 @@ Ox.load({ pandora.URL.update(); }; + // set up url controller + + var itemsName = pandora.site.itemName.plural.toLowerCase(), + sortKeys = {}, spanType = {}, views = {}; + views[itemsName] = { + list: Ox.merge( + // 'grid' is the default view + ['grid'], + Ox.map(pandora.site.listViews, function(view) { + return view.id == 'grid' ? null : view.id; + }) + ), + item: Ox.merge( + // 'info' is the default view, pandora.user.ui.videoView + // is the default view if there is a duration + ['info', pandora.user.ui.videoView], + pandora.site.itemViews.map(function(view) { + return [ + 'info', pandora.user.ui.videoView + ].indexOf(view.id) > -1 ? null : view.id; + }) + ) + }; + sortKeys[itemsName] = {list: {}, item: {}}; + views[itemsName].list.forEach(function(view) { + sortKeys[itemsName].list[view] = Ox.merge( + pandora.isClipView(view) ? Ox.clone(pandora.site.clipKeys) : [], + // 'director' is the default sort key + [Ox.getObjectById(pandora.site.sortKeys, 'director')], + Ox.map(pandora.site.sortKeys, function(key) { + return key.id == 'director' ? null : key; + }) + ); + }); + views[itemsName].item.forEach(function(view) { + if (pandora.isClipView(view, true)) { + sortKeys[itemsName].item[view] = Ox.merge( + // 'clip:position' is the default sort key + [Ox.getObjectById(pandora.site.clipKeys, 'clip:position')], + Ox.map(pandora.site.clipKeys, function(key) { + return key.id == 'clip:position' ? null : key; + }) + ); + } + }); + spanType[itemsName] = { + list: { + map: 'location', + calendar: 'date' + }, + item: { + video: 'duration', + timeline: 'duration', + map: 'location', + calendar: 'date' + } + }; + + pandora._URL = Ox.URL({ + findKeys: pandora.site.findKeys, + getItem: pandora.getItemByIdOrTitle, + getSpan: pandora.getMetadataByIdOrName, + pages: [ + 'about', 'contact', 'faq', 'help', 'home', 'news', + 'preferences', 'signin', 'signout', 'signup', + 'software', 'terms', 'tour' + ], + sortKeys: sortKeys, + spanType: spanType, + types: [pandora.site.itemName.plural.toLowerCase(), 'edits', 'texts'], + views: views + }); + pandora.URL.parse(function() { Ox.UI.hideLoadingScreen(); diff --git a/static/js/pandora/Query.js b/static/js/pandora/Query.js index 09549baa..77530ac2 100644 --- a/static/js/pandora/Query.js +++ b/static/js/pandora/Query.js @@ -17,6 +17,7 @@ pandora.Query = (function() { } function constructValue(value, operator) { + value = encodeURIComponent(value); operator = operator.replace('=', '^$'); if (operator.indexOf('$') > -1) { value = operator.substr(0, operator.length - 1) + value + '$'; @@ -176,7 +177,7 @@ pandora.Query = (function() { ) ? { index: indices[0], key: ret.query.conditions[indices[0]].key, - value: ret.query.conditions[indices[0]].value + value: decodeURIComponent(ret.query.conditions[indices[0]].value) } : {index: -1, key: 'advanced', value: ''} } } diff --git a/static/js/pandora/URL.js b/static/js/pandora/URL.js index 94123a7b..e237fe5f 100644 --- a/static/js/pandora/URL.js +++ b/static/js/pandora/URL.js @@ -1,5 +1,12 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript + +/* +FIXME: +we may want slashes in list names, and ampersands in queries + +*/ + pandora.URL = (function() { var previousURL = '', @@ -125,7 +132,7 @@ pandora.URL = (function() { section: 'items', item: item, itemView: view - }, ['player', 'timeline'].indexOf(view) > -1 ? { + }, ['video', 'timeline'].indexOf(view) > -1 ? { videoView: view } : {})); if (time) { @@ -259,13 +266,12 @@ pandora.URL = (function() { } pandora.$ui.contentPanel.replaceElement(1, pandora.ui.item()); } - // fixme: should be 'video', not 'player' if ( previousUI.item && - ['player', 'timeline'].indexOf(previousUI.itemView) > -1 + ['video', 'timeline'].indexOf(previousUI.itemView) > -1 ) { var $item = pandora.$ui[ - previousUI.itemView == 'player' ? 'player' : 'editor' + previousUI.itemView == 'video' ? 'player' : 'editor' ]; $item && pandora.UI.set( 'videoPoints|' + previousUI.item + '|position', diff --git a/static/js/pandora/pandora.js b/static/js/pandora/pandora.js index 0b25b509..029d9434 100644 --- a/static/js/pandora/pandora.js +++ b/static/js/pandora/pandora.js @@ -313,6 +313,43 @@ pandora.getInfoHeight = function() { ); } +pandora.getItemByIdOrTitle = function(str, callback) { + pandora.api.get({id: str, keys: ['id']}, function(result) { + if (result.status.code == 200) { + callback(result.data.id); + } else { + pandora.api.find({ + query: { + conditions: [{key: 'title', value: str, operator: ''}], // fixme: operator will be "=" + operator: '&' + }, + sort: [{key: 'votes', operator: ''}], // fixme: not all systems have "votes" + range: [0, 100], + keys: ['id', 'title', 'votes'] + }, function(result) { + var id = ''; + if (result.data.items.length) { + Ox.print('AAAAAA', result.data.items) + var items = Ox.map(result.data.items, function(item) { + // test if exact match or word match + var sort = new RegExp('^' + str + '$', 'i').test(item.title) ? 2000000 + : new RegExp('\\b' + str + '\\b', 'i').test(item.title) ? 1000000 : 0; + return sort ? {id: item.id, sort: sort + (parseInt(item.votes) || 0)} : null; + // fixme: remove the (...|| 0) check once the backend sends correct data + }); + if (items.length) { + Ox.print('BBBBBB', items) + id = items.sort(function(a, b) { + return b.sort - a.sort; + })[0].id; + } + } + callback(id); + }); + } + }); +} + pandora.getListData = function() { var data = {}, folder; if (pandora.user.ui.list) { @@ -360,6 +397,66 @@ pandora.getListMenu = function(lists) { ] }; }; +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, + // and returns the id (or none) and the view (or none) + // fixme: "subtitles:23" is still missing + Ox.print('getMetadataByIdOrName', item, view, str); + var isName = str[0] == '@', + canBeAnnotation = ( + !view || view == 'video' || view == 'timeline' + ) && item && !isName, + canBeEvent = !view || view == 'calendar', + canBePlace = !view || view == 'map'; + str = isName ? str.substr(1) : str; + getId(canBeAnnotation ? 'annotation' : '', function(id) { + if (id) { + Ox.print('id?', id) + callback(id, pandora.user.ui.videoView); + } else { + getId(canBePlace ? 'place' : '', function(id) { + if (id) { + callback(id, 'map'); + } else { + getId(canBeEvent ? 'event' : '', function(id) { + if (id) { + callback(id, 'calendar'); + } else if (canBePlace && isName) { + // set map query ... + pandora.user.ui.mapFind = str; + callback('@' + str, 'map'); + } else { + callback(); + } + }); + } + }); + } + }); + function getId(type, callback) { + if (type) { + pandora.api['find' + Ox.toTitleCase(type + 's')](Ox.extend({ + query: { + key: isName ? 'name' : 'id', + value: type == 'annotation' ? item + '/' + str : str, + operator: '=' + }, + keys: ['id'], + range: [0, 1] + }, item ? { + itemQuery: {key: 'id', value: item, operator: '='} + } : {}), function(result) { + // fixme: this has to be fixed on the backend! + if (result.data.events) { result.data.items = result.data.events; }; + callback(result.data.items.length ? result.data.items[0].id : ''); + }); + } else { + callback(); + } + } +}; + pandora.getSortMenu = function() { var list = pandora.user.ui.lists[pandora.user.ui.list], isClipView = pandora.isClipView(list.listView); @@ -410,7 +507,13 @@ pandora.getSortMenu = function() { ] }; }; -pandora.getSortOperator = function(key) { // fixme: make static +pandora._getSortOperator = function(type) { + return ['hue', 'string', 'text'].indexOf( + Ox.isArray(type) ? type[0] : type + ) > -1 ? '+' : '-'; +} + +pandora.getSortOperator = function(key) { // fixme: remove var type = Ox.getObjectById( /^clip:/.test(key) ? pandora.site.clipKeys : pandora.site.itemKeys, key @@ -444,9 +547,11 @@ pandora.getVideoPartsAndPoints = function(durations, points) { return ret; }; -pandora.isClipView = function(view) { +pandora.isClipView = function(view, item) { view = view || pandora.user.ui.lists[pandora.user.ui.list].listView; - return ['calendar', 'clip', 'map'].indexOf(view) > -1; + return ( + !item ? ['calendar', 'clip', 'map'] : ['calendar', 'clips', 'map'] + ).indexOf(view) > -1; }; pandora.signin = function(data) { diff --git a/static/js/pandora/ui/filter.js b/static/js/pandora/ui/filter.js index bcf4143b..377289b7 100644 --- a/static/js/pandora/ui/filter.js +++ b/static/js/pandora/ui/filter.js @@ -8,9 +8,9 @@ pandora.ui.filter = function(list) { format: key.format, id: key.id, title: key.title, - type: key.type == 'layer' ? Ox.getObjectById( - pandora.site.layers, key.id - ).type : key.type + type: key.type == 'layer' + ? Ox.getObjectById(pandora.site.layers, key.id).type + : key.type }; }), { id: 'list', @@ -34,9 +34,6 @@ pandora.ui.filter = function(list) { query: data.query }, function(result) { Ox.Request.clearCache(list.id); - pandora.$ui.groups.forEach(function($group) { - $group.reloadList(); - }); pandora.$ui.list .bindEventOnce({ init: function(data) { @@ -46,6 +43,10 @@ pandora.ui.filter = function(list) { } }) .reloadList(); + pandora.$ui.groups.forEach(function($group) { + $group.reloadList(); + }); + }); } else { pandora.user.ui.query = data.query; diff --git a/static/js/pandora/ui/foldersList.js b/static/js/pandora/ui/foldersList.js index 3fd2e68b..51402c2b 100644 --- a/static/js/pandora/ui/foldersList.js +++ b/static/js/pandora/ui/foldersList.js @@ -388,6 +388,7 @@ pandora.ui.folderList = function(id) { data_ = {id: data.id}; data_[data.key] = data.value; pandora.api.editList(data_, function(result) { + // fixme: we may want slashes in list names if (result.data.id != data.id) { pandora.$ui.folderList[id].value(data.id, 'name', result.data.name); pandora.$ui.folderList[id].value(data.id, 'id', result.data.id); diff --git a/static/js/pandora/ui/item.js b/static/js/pandora/ui/item.js index 2415af92..c7b0521d 100644 --- a/static/js/pandora/ui/item.js +++ b/static/js/pandora/ui/item.js @@ -26,7 +26,7 @@ pandora.ui.item = function() { }*/ if (!result.data.rendered && [ - 'clips', 'map', 'player', 'timeline' + 'clips', 'map', 'video', 'timeline' ].indexOf(pandora.user.ui.itemView)>-1) { pandora.$ui.contentPanel.replaceElement(1, Ox.Element() @@ -250,7 +250,7 @@ pandora.ui.item = function() { pandora.$ui.contentPanel.replaceElement(1, stats); - } else if (pandora.user.ui.itemView == 'player') { + } else if (pandora.user.ui.itemView == 'video') { // fixme: duplicated var layers = [], video = {}; diff --git a/static/js/pandora/ui/list.js b/static/js/pandora/ui/list.js index 177e6ea9..500935e1 100644 --- a/static/js/pandora/ui/list.js +++ b/static/js/pandora/ui/list.js @@ -647,8 +647,7 @@ pandora.ui.list = function() { // fixme: remove view argument }, select: function(data) { var $still, $timeline; - pandora.UI.set(['lists', pandora.user.ui.list, 'selected'].join('|'), data.ids); - //pandora.user.ui.lists[pandora.user.ui.list].selected = data.ids; + pandora.UI.set('lists|' + pandora.user.ui.list + '|selected', data.ids); if (data.ids.length) { pandora.$ui.mainMenu.enableItem('copy'); pandora.$ui.mainMenu.enableItem('openmovie'); diff --git a/static/js/pandora/ui/status.js b/static/js/pandora/ui/status.js index b7e83fb6..1fe9c61f 100644 --- a/static/js/pandora/ui/status.js +++ b/static/js/pandora/ui/status.js @@ -1,7 +1,7 @@ // vim: et:ts=4:sw=4:sts=4:ft=javascript pandora.ui.status = function(key, data) { var that = Ox.toTitleCase(key) + ': ' + [ - Ox.formatNumber(data.items) + ' '+ (data.items != 1 ? pandora.site.itemName.plural : pandora.site.itemName.sinular), + Ox.formatNumber(data.items) + ' '+ (data.items != 1 ? pandora.site.itemName.plural : pandora.site.itemName.singular), Ox.formatDuration(data.runtime, 'medium'), data.files + ' file' + (data.files != 1 ? 's' : ''), Ox.formatDuration(data.duration, 'short'),