pandora/static/js/URL.js

561 lines
20 KiB
JavaScript
Raw Normal View History

2011-07-29 18:37:11 +00:00
// vim: et:ts=4:sw=4:sts=4:ft=javascript
2011-06-20 18:34:23 +00:00
2011-11-05 17:04:10 +00:00
'use strict';
pandora.URL = (function() {
var self = {}, that = {};
// translates UI settings to URL state
2011-11-09 22:32:54 +00:00
function getState() {
2011-11-05 13:27:17 +00:00
Ox.Log('URL', 'getState:, UI', pandora.user.ui)
2011-11-09 22:32:54 +00:00
2013-02-18 12:01:36 +00:00
var state = {};
2011-11-09 22:32:54 +00:00
if (pandora.user.ui.page) {
2011-11-05 13:27:17 +00:00
2013-02-18 12:01:36 +00:00
state.page = pandora.user.ui.page;
2013-07-11 18:11:07 +00:00
if (Ox.contains(Object.keys(pandora.site.user.ui.part), state.page)) {
state.part = pandora.user.ui.part[state.page];
}
2011-11-05 13:27:17 +00:00
2013-02-18 12:01:36 +00:00
} else {
2013-02-16 01:20:40 +00:00
2013-03-06 13:28:44 +00:00
state.type = pandora.user.ui.section == 'items'
? pandora.site.itemsSection : pandora.user.ui.section;
2013-02-18 12:01:36 +00:00
state.item = pandora.user.ui[pandora.user.ui.section.slice(0, -1)];
if (pandora.user.ui.section == 'items') {
if (!pandora.user.ui.item) {
state.view = pandora.user.ui.listView;
state.sort = pandora.user.ui.listSort;
state.find = pandora.user.ui.find;
} else {
state.view = pandora.user.ui.itemView;
state.sort = pandora.user.ui.itemSort;
}
if (state.view == 'map') {
state.span = pandora.user.ui.mapFind
? '@' + pandora.user.ui.mapFind
: pandora.user.ui.mapSelection
? '@' + pandora.user.ui.mapSelection
: '';
} else if (state.view == 'calendar') {
// ...
} else if (['timeline', 'player', 'editor'].indexOf(state.view) > -1) {
var videoPoints = pandora.user.ui.videoPoints[state.item] || {};
state.span = videoPoints.annotation || [].concat(
videoPoints.position
? videoPoints.position
: [],
videoPoints['in'] || videoPoints.out
? [videoPoints['in'], videoPoints.out]
: []
);
}
2013-07-14 14:30:51 +00:00
} else if (pandora.user.ui.section == 'edits') {
var editPoints = pandora.user.ui.edits[state.item] || {};
2014-02-08 19:16:31 +00:00
if (state.item) {
state.view = pandora.user.ui.editView;
state.sort = pandora.user.ui.editSort;
}
2013-07-14 14:30:51 +00:00
state.span = editPoints.clip || [].concat(
editPoints.position
? editPoints.position
: [],
editPoints['in'] || editPoints.out
? [editPoints['in'], editPoints.out]
: []
);
} else if (pandora.user.ui.section == 'texts') {
2013-11-09 15:39:07 +00:00
var textState = pandora.user.ui.texts[state.item] || {},
2013-11-08 18:57:24 +00:00
position = textState.position || 0;
if (textState.name) {
state.span = textState.name;
} else if (position) {
state.span = [position];
}
2013-02-18 12:01:36 +00:00
}
2011-10-08 13:09:16 +00:00
}
2011-11-05 13:27:17 +00:00
2013-07-12 11:39:45 +00:00
if (
pandora.user.ui._hash && (
2013-07-20 07:42:18 +00:00
pandora.user.ui._hash.anchor
|| !Ox.isEmpty(pandora.user.ui._hash.query)
2013-07-12 11:39:45 +00:00
)
) {
state.hash = {};
if (pandora.user.ui._hash.anchor) {
state.hash.anchor = pandora.user.ui._hash.anchor;
}
if (!Ox.isEmpty(pandora.user.ui._hash.query)) {
state.hash.query = pandora.user.ui._hash.query;
}
}
2013-03-04 10:09:42 +00:00
Ox.Log('URL', 'GOT STATE ...', state)
2011-11-05 13:27:17 +00:00
2011-09-28 17:32:03 +00:00
return state;
2011-11-05 13:27:17 +00:00
}
// translates URL state to UI settings
2011-09-28 17:32:03 +00:00
function setState(state, callback) {
2013-02-18 12:35:29 +00:00
var set = {};
2012-01-09 09:55:52 +00:00
Ox.Log('URL', 'setState:', state);
2011-11-06 08:28:10 +00:00
pandora.user.ui._list = pandora.getListState(pandora.user.ui.find);
pandora.user.ui._filterState = pandora.getFilterState(pandora.user.ui.find);
2011-09-27 22:12:37 +00:00
pandora.user.ui._findState = pandora.getFindState(pandora.user.ui.find);
2011-09-28 17:32:03 +00:00
if (Ox.isEmpty(state)) {
2011-09-28 17:32:03 +00:00
callback && callback();
} else {
2011-10-29 17:46:46 +00:00
2013-07-12 11:39:45 +00:00
pandora.user.ui._hash = state.hash;
2013-07-12 10:32:45 +00:00
if (
state.hash
&& !Ox.contains(['embed', 'print'], state.hash.anchor)
&& state.hash.query
) {
state.hash.query.forEach(function(kv) {
set[kv.key] = kv.value;
});
}
2013-02-18 12:35:29 +00:00
if (state.page) {
set.page = state.page;
2013-07-11 18:11:07 +00:00
if (Ox.contains(Object.keys(pandora.site.user.ui.part), state.page) && state.part) {
set['part.' + state.page] = state.part;
2013-03-06 13:28:44 +00:00
}
2013-02-18 12:35:29 +00:00
pandora.UI.set(set);
callback && callback();
} else {
set.page = '';
if (state.type) {
set.section = state.type == pandora.site.itemsSection ? 'items' : state.type
set[set.section.slice(0, -1)] = state.item;
}
if (set.section == 'items') {
2013-03-04 11:20:55 +00:00
2013-02-18 12:35:29 +00:00
if (state.view) {
set[!state.item ? 'listView' : 'itemView'] = state.view;
}
if (state.span) {
if (['timeline', 'player', 'editor'].indexOf(state.view) > -1) {
if (Ox.isArray(state.span)) {
set['videoPoints.' + state.item] = {
annotation: '',
'in': state.span[state.span.length - 2] || 0,
out: state.span.length == 1 ? 0 : Math.max(
state.span[state.span.length - 2],
state.span[state.span.length - 1]
),
position: state.span[0]
};
} else {
set['videoPoints.' + state.item + '.annotation'] = state.span;
}
} else if (state.view == 'map') {
// fixme: this doesn't handle map coordinates
if (state.span[0] != '@') {
2013-03-06 14:09:18 +00:00
set.mapSelection = state.span;
set.mapFind = '';
2013-02-18 12:35:29 +00:00
} else {
2013-03-06 14:09:18 +00:00
set.mapFind = state.span.slice(1);
set.mapSelection = '';
2013-02-18 12:35:29 +00:00
}
} else if (state.view == 'calendar') {
2013-03-06 14:09:18 +00:00
// fixme: this is still very much unclear
if (state.span.length == 1 && /^\d/.test(state.span)) {
set.calendarFind = state.span[0];
} else if (state.span.length == 2) {
set.calendarFind = state.span[0];
}
2013-02-18 12:35:29 +00:00
}
}
if (state.sort) {
set[!state.item ? 'listSort' : 'itemSort'] = state.sort;
}
if (!state.item) {
if (state.find) {
set.find = state.find;
} else if (!pandora.$ui.appPanel) {
// when loading results without find, clear find, so that
// removing a query and reloading works as expected
set.find = pandora.site.user.ui.find;
}
2011-09-28 17:32:03 +00:00
}
2013-07-14 14:30:51 +00:00
} else if (state.type == 'edits') {
2014-02-08 19:16:31 +00:00
if (state.view) {
set.editView = state.view;
}
if (state.sort) {
set.editSort = state.sort;
}
2013-07-14 14:30:51 +00:00
if (state.span) {
var key = 'edits.' + pandora.UI.encode(state.item);
set[key] = {};
2013-07-14 14:30:51 +00:00
if (Ox.isArray(state.span)) {
set[key + '.clip'] = '';
set[key + '.in'] = state.span[state.span.length - 2] || 0;
set[key + '.out'] = state.span.length == 1 ? 0 : Math.max(
state.span[state.span.length - 2],
state.span[state.span.length - 1]
);
set[key + '.position'] = state.span[0];
2013-07-14 14:30:51 +00:00
} else {
set[key + '.clip'] = state.span;
2013-07-14 14:30:51 +00:00
}
}
} else if (state.type == 'texts') {
2013-07-14 14:30:51 +00:00
if (state.span) {
2013-11-08 18:57:24 +00:00
set['texts.' + pandora.UI.encode(state.item)] = {
position: Ox.isArray(state.span) ? state.span[0] : 0,
name: Ox.isArray(state.span) ? '' : state.span
};
}
2013-07-14 14:30:51 +00:00
2013-02-18 12:35:29 +00:00
}
Ox.Request.cancel();
$('video').each(function() {
$(this).trigger('stop');
});
Ox.Log('URL', 'UI.set', set)
if (!pandora.$ui.appPanel && state.item && pandora.user.ui.find) {
// on page load, if item is set and there was a query,
// we have to check if the item actually matches the query,
// and otherwise reset find
pandora.api.find({
query: pandora.user.ui.find,
positions: [state.item],
sort: [{key: 'id', operator: ''}]
}, function(result) {
if (Ox.isUndefined(result.data.positions[state.item])) {
set.find = pandora.site.user.ui.find
}
pandora.UI.set(set);
callback && callback();
});
} else {
2011-09-28 17:32:03 +00:00
pandora.UI.set(set);
callback && callback();
2013-02-18 12:35:29 +00:00
}
2011-05-25 19:42:45 +00:00
}
2011-09-28 17:32:03 +00:00
}
2011-09-28 17:32:03 +00:00
2011-09-17 07:07:59 +00:00
}
function getOptions () {
2014-02-08 19:16:31 +00:00
var itemsSection = pandora.site.itemsSection,
sortKeys = {}, views = {};
views[itemsSection] = {
2012-05-24 08:22:56 +00:00
// listView is the default view
list: [pandora.user.ui.listView].concat(
2012-05-22 15:07:34 +00:00
pandora.site.listViews.filter(function(view) {
return view.id != pandora.user.ui.listView
2012-05-22 15:07:34 +00:00
}).map(function(view) {
return view.id;
})
),
2012-05-24 08:22:56 +00:00
// itemView is the default view,
// videoView is the default view if there is a duration
item: [pandora.user.ui.itemView, pandora.user.ui.videoView].concat(
2012-05-22 15:07:34 +00:00
pandora.site.itemViews.filter(function(view) {
return [
pandora.user.ui.itemView, pandora.user.ui.videoView
2012-05-30 00:19:33 +00:00
].indexOf(view.id) == -1;
2012-05-22 15:07:34 +00:00
}).map(function(view) {
return view.id;
})
)
};
sortKeys[itemsSection] = {list: {}, item: {}};
views[itemsSection].list.forEach(function(view) {
2012-05-24 08:22:56 +00:00
sortKeys[itemsSection].list[view] = [].concat(
// listSort[0].key is the default sort key
2011-09-27 22:12:37 +00:00
Ox.getObjectById(pandora.site.sortKeys, pandora.user.ui.listSort[0].key)
|| pandora.isClipView(view)
&& Ox.getObjectById(pandora.site.clipKeys, pandora.user.ui.listSort[0].key)
|| [],
2012-05-22 15:07:34 +00:00
pandora.isClipView(view) ? pandora.site.clipKeys.filter(function(key) {
return key.id != pandora.user.ui.listSort[0].key;
2011-09-27 22:12:37 +00:00
}) : [],
2012-05-22 15:07:34 +00:00
pandora.site.sortKeys.filter(function(key) {
return key.id != pandora.user.ui.listSort[0].key;
})
);
});
views[itemsSection].item.forEach(function(view) {
if (pandora.isClipView(view, true)) {
2012-05-24 08:22:56 +00:00
// itemSort[0].key is the default sort key
sortKeys[itemsSection].item[view] = [
Ox.getObjectById(
pandora.site.clipKeys,
pandora.user.ui.itemSort[0].key
)
].concat(
2012-05-22 15:07:34 +00:00
pandora.site.clipKeys.filter(function(key) {
return key.id != pandora.user.ui.itemSort[0].key;
})
);
}
});
// Edits
views['edits'] = {
list: [],
2014-02-08 19:16:31 +00:00
item: ['list', 'grid', 'annotations']
};
sortKeys['edits'] = {
list: {},
item: {}
};
2014-02-08 19:16:31 +00:00
views['edits'].item.forEach(function(view) {
sortKeys['edits'].item[view] = [
{id: 'index', operator: '+'}
]
.concat(pandora.site.clipKeys)
.concat(pandora.site.itemKeys);
});
// Texts
views['texts'] = {
list: [],
item: ['text']
};
sortKeys['texts'] = {
list: {},
item: {}
};
return {
views: views,
sortKeys: sortKeys
};
2014-02-08 19:16:31 +00:00
}
that.init = function() {
var itemsSection = pandora.site.itemsSection,
findKeys, spanType = {};
spanType[itemsSection] = {
list: {
map: 'location',
calendar: 'date'
},
item: {
2012-04-17 08:03:11 +00:00
timeline: 'duration',
player: 'duration',
editor: 'duration',
map: 'location',
calendar: 'date'
}
};
2013-07-14 14:30:51 +00:00
spanType['edits'] = {
2013-11-08 17:29:10 +00:00
list: {},
2014-02-08 19:16:31 +00:00
item: {
list: 'duration',
grid: 'duration',
annotations: 'duration'
}
2013-03-04 11:20:55 +00:00
};
2013-07-14 14:30:51 +00:00
spanType['texts'] = {
2013-11-08 17:29:10 +00:00
list: {},
item: {text: 'string'}
};
2012-05-24 08:22:56 +00:00
findKeys = [{id: 'list', type: 'string'}].concat(pandora.site.itemKeys);
self.URL = Ox.URL(Ox.extend({
findKeys: findKeys,
2013-03-04 10:09:42 +00:00
getHash: pandora.getHash,
getItem: pandora.getItem,
2013-07-11 18:11:07 +00:00
getPart: pandora.getPart,
2013-03-04 10:09:42 +00:00
getSpan: pandora.getSpan,
2012-05-24 08:22:56 +00:00
pages: [].concat(
2014-01-17 13:49:11 +00:00
['home', 'software', 'api', 'help', 'tv', 'documents'],
2012-02-18 15:39:53 +00:00
pandora.site.sitePages.map(function(page) {
return page.id;
}),
['preferences', 'signup', 'signin', 'signout']
),
spanType: spanType,
types: [pandora.site.itemName.plural.toLowerCase(), 'edits', 'texts'],
}, getOptions()));
2013-03-02 10:55:13 +00:00
window.addEventListener('hashchange', function() {
Ox.Request.cancel();
2011-09-28 17:32:03 +00:00
that.parse();
2013-03-02 10:55:13 +00:00
});
2013-02-18 10:17:40 +00:00
2013-03-02 10:55:13 +00:00
window.addEventListener('popstate', function(e) {
Ox.Request.cancel();
2011-09-28 17:32:03 +00:00
self.isPopState = true;
$('.OxDialog:visible').each(function() {
Ox.UI.elements[$(this).data('oxid')].close();
});
2011-11-09 22:32:54 +00:00
if (pandora.$ui.home) {
pandora.UI.set({page: ''});
pandora.$ui.home.fadeOutScreen();
2011-12-23 05:06:06 +00:00
} else if (pandora.$ui.tv) {
pandora.UI.set({page: ''});
2012-02-19 12:58:49 +00:00
pandora.$ui.tv.fadeOutScreen();
2011-11-09 22:32:54 +00:00
}
2011-11-02 20:53:21 +00:00
if (
pandora.user.ui.item
&& pandora.user.ui.itemView == 'video'
&& pandora.$ui.player
2011-11-02 20:53:21 +00:00
&& pandora.$ui.player.options('fullscreen')
) {
pandora.$ui.player.remove();
2011-11-02 20:53:21 +00:00
}
2011-11-09 22:32:54 +00:00
if (e.state && !Ox.isEmpty(e.state)) {
Ox.Log('URL', 'E.STATE', e.state)
2013-05-31 22:17:39 +00:00
document.title = Ox.decodeHTMLEntities(e.state.title);
2011-09-28 17:32:03 +00:00
setState(e.state);
} else if (window.location.pathname == '/') {
pandora.$ui.home = pandora.ui.home().fadeInScreen();
2011-09-28 17:32:03 +00:00
} else {
that.parse();
}
2013-03-02 10:55:13 +00:00
});
2011-09-28 17:32:03 +00:00
return that;
};
// on page load, this sets the state from the URL
2013-02-21 13:20:59 +00:00
// can also be used to parse a URL
that.parse = function(url, callback) {
2013-03-04 15:24:20 +00:00
if (arguments.length == 2) {
self.URL.parse(url, callback);
} else {
callback = arguments[0];
2013-02-21 13:20:59 +00:00
url = null;
if (document.location.pathname.slice(0, 4) == 'url=') {
2013-08-14 18:54:06 +00:00
document.location.href = Ox.decodeURI(document.location.pathname.slice(4));
2013-02-21 13:20:59 +00:00
} else {
self.URL.parse(function(state) {
// setState -> UI.set -> URL.update
2013-02-21 13:22:47 +00:00
setState(state, callback);
2013-02-21 13:20:59 +00:00
});
}
}
return that;
};
// sets the URL to the previous URL
that.pop = function() {
2011-11-09 22:32:54 +00:00
self.URL.pop() || that.update();
};
// pushes a new URL (as string or from state)
that.push = function(stateOrURL, expandURL) {
2011-11-09 22:32:54 +00:00
var state,
title = pandora.getPageTitle(stateOrURL)
|| pandora.getDocumentTitle(),
url;
pandora.replaceURL = expandURL;
if (Ox.isObject(stateOrURL)) {
state = stateOrURL;
} else {
url = stateOrURL;
}
self.URL.push(state, title, url, setState);
return that;
};
// replaces the current URL (as string or from state)
2011-11-09 22:32:54 +00:00
that.replace = function(stateOrURL, title) {
var state,
title = pandora.getPageTitle(stateOrURL)
|| pandora.getDocumentTitle(),
url;
if (Ox.isObject(stateOrURL)) {
state = stateOrURL;
} else {
url = stateOrURL;
}
self.URL.replace(state, title, url, setState);
return that;
};
2011-09-28 17:32:03 +00:00
that.update = function(keys) {
2013-02-18 12:01:36 +00:00
Ox.Log('URL', 'update.........', keys)
2011-10-01 13:51:18 +00:00
// this gets called from pandora.UI
2011-11-05 13:27:17 +00:00
var action, state;
2011-10-08 13:09:16 +00:00
if (!keys) {
// may get called from home screen too
keys = !pandora.user.ui.item
? ['listView', 'listSort', 'find']
: ['item', 'itemView', 'itemSort'];
} else {
if (keys.some(function(key) {
return Ox.contains(['itemSort', 'itemView', 'listSort', 'listView'], key);
})) {
self.URL.options(getOptions());
}
2011-10-08 13:09:16 +00:00
}
2011-09-28 17:32:03 +00:00
if (self.isPopState) {
self.isPopState = false;
} else {
if (
!pandora.$ui.appPanel
|| pandora.replaceURL
2011-09-28 17:32:03 +00:00
|| keys.every(function(key) {
2011-10-08 17:22:56 +00:00
return [
'listColumnWidth', 'listColumns', 'listSelection',
'mapFind', 'mapSelection'
].indexOf(key) > -1
|| /^videoPoints/.test(key)
|| /^edits/.test(key)
|| /^texts/.test(key);
2011-09-28 17:32:03 +00:00
})
) {
action = 'replace';
2011-09-28 17:32:03 +00:00
} else {
action = 'push';
}
2011-11-05 13:27:17 +00:00
state = getState();
2011-11-09 22:32:54 +00:00
self.URL[action](
state,
pandora.getPageTitle(state) || pandora.getDocumentTitle()
);
pandora.replaceURL = false;
}
2011-09-28 17:32:03 +00:00
};
2011-05-25 19:42:45 +00:00
2011-09-28 17:32:03 +00:00
return that;
2011-05-25 19:42:45 +00:00
}());