/***
Pandora
***/
var app = new Ox.App({
apiURL: '/api/',
config: '/pandora.json',
init: 'hello',
}).launch(function(data) {
Ox.print('data', data)
app.config = data.config;
app.user = data.user;
if (app.user.group == 'guest') {
app.user = data.config.user;
$.browser.safari && Ox.theme('modern');
}
app.$body = $('body');
app.$document = $(document);
app.$window = $(window);
app.$ui = {};
app.requests = {};
app.ui = {
infoRatio: 4 / 3,
selectedMovies: []
};
app.Query.fromString(location.hash.substr(2));
app.$ui.mainMenu = app.constructMainMenu();
app.$ui.sections = app.constructSections();
app.$ui.lists = app.constructLists();
app.$ui.info = app.constructInfo();
app.$ui.toolbar = app.constructToolbar();
app.$ui.groups = app.constructGroups();
app.$ui.statusbar = app.constructStatusbar();
app.$ui.app = app.constructApp();
///*
app.$body.css({
opacity: 0
});
//*/
app.$ui.app.appendTo(app.$body);
///*
app.$body.animate({
opacity: 1
}, 2000);
//*/
Ox.Request.requests() && app.$ui.loadingIcon.start();
Ox.Event.bind('', 'requestStart', function() {
Ox.print('requestStart')
app.$ui.loadingIcon.start();
});
Ox.Event.bind('', 'requestStop', function() {
Ox.print('requestStop')
app.$ui.loadingIcon.stop();
});
$.each(app.afterLaunch, function(i, f) {f()});
});
// Objects
app.Query = (function() {
function constructFind(query) {
Ox.print('cF', query)
return /*encodeURI(*/$.map(query.conditions, function(v, i) {
if (!Ox.isUndefined(v.conditions)) {
return '[' + constructFind(v) + ']';
} else {
return v.value !== '' ? v.key + (v.key ? ':' : '') + constructValue(v.value, v.operator) : null;
}
}).join(query.operator)/*)*/;
}
function constructValue(value, operator) {
operator = operator.replace('=', '^$');
if (operator.indexOf('$') > -1) {
value = operator.substr(0, operator.length - 1) + value + '$'
} else {
value = operator + value;
}
return value;
}
function mergeFind() {
}
function parseFind(str) {
var find = {
conditions: [],
operator: ''
},
subconditions = str.match(/\[.*?\]/g) || [];
$.each(subconditions, function(i, v) {
subconditions[i] = v.substr(1, v.length - 2);
str = str.replace(v, '[' + i + ']');
});
if (str.indexOf(',') > -1) {
find.operator = '&';
} else if (str.indexOf('|') > -1) {
find.operator = '|';
}
Ox.print('pF', str, find.operator)
find.conditions = $.map(find.operator === '' ? [str] : str.split(find.operator == '&' ? ',' : '|'), function(v, i) {
Ox.print('v', v)
var ret, kv;
if (v[0] == '[') {
Ox.print('recursion', subconditions)
ret = parseFind(subconditions[parseInt(v.substr(1, v.length - 2))]);
} else {
kv = ((v.indexOf(':') > - 1 ? '' : ':') + v).split(':');
ret = $.extend({
key: kv[0]
}, parseValue(kv[1]));
}
return ret;
});
return find;
}
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),
sort = [];
if ('find' in query) {
app.user.ui.findQuery = parseFind(query.find);
Ox.print('user.ui.findQuery', app.user.ui.findQuery)
}
if ('sort' in query) {
sort = query.sort.split(',')
app.user.ui.sort = $.map(query.sort.split(','), function(v, i) {
var hasOperator = '+-'.indexOf(v[0]) > -1,
key = hasOperator ? query.sort.substr(1) : query.sort,
operator = hasOperator ? v[0].replace('+', '') : Ox.getObjectById(app.config.sortKeys, key).operator;
return {
key: key,
operator: operator
};
});
}
if ('view' in query) {
app.user.ui.listView = query.view;
}
},
toObject: function(groupId) {
Ox.print('tO', app.user.ui.findQuery.conditions)
// the inner $.merge() creates a clone
var conditions = $.merge($.merge([], app.user.ui.listQuery.conditions), app.user.ui.findQuery.conditions);
$.merge(conditions, app.ui.groups ? $.map(app.ui.groups, 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.print('>>', groupId, app.user.ui.find, conditions);
return {
conditions: conditions,
operator: operator
};
},
toString: function() {
Ox.print('tS', app.user.ui.find)
return '!' + Ox.serialize({
find: constructFind(app.Query.toObject()),
sort: app.user.ui.sort[0].operator + app.user.ui.sort[0].key,
view: app.user.ui.listView
});
}
};
})();
/*
// Menu
Ox.Event.bind('change_viewmovies', function(event, data) {
app.$ui.viewSelect.selectItem(data.id);
});
Ox.Event.bind('change_find', function(event, data) {
app.$ui.findInput.changeLabel(data.id);
});
Ox.Event.bind('click_query', function(event, data) {
var $dialog = new Ox.Dialog({
buttons: [
{
click: function() {
$dialog.close();
},
id: 'close',
title: 'Close',
value: 'Close'
}
],
id: 'query',
title: 'Query'
}).append(Query.toString() + '
' + JSON.stringify(Query.toObject())).open();
});
// Resize
Ox.Event.bind('click_show_query', function(event, data) {
var query = constructQuery(),
html = 'Conditions
' + $.map(query.conditions, function(v) {
return v.key + ' ' + v.operator + ' ' + v.value;
}).join('
') + '
Operator: ' + query.operator,
$dialog = new Ox.Dialog({
buttons: [
{
value: 'Close',
click: function() {
$dialog.close();
}
}
],
title: 'Show Query'
})
.append(html)
.open();
});
// Functions
*/
app.constructApp = function() {
/*
app
mainMenu
mainPanel
leftPanel
lists
info
rightPanel
toolbar
contentPanel
(browser)
(content)
statusbar
*/
return new Ox.SplitPanel({
elements: [
{
element: app.$ui.mainMenu,
size: 20
},
{
element: app.$ui.mainPanel = new Ox.SplitPanel({
elements: [
{
collapsible: true,
element: app.$ui.leftPanel = new Ox.SplitPanel({
elements: [
{
element: app.$ui.lists.options({
id: 'listsPanel'
})
},
{
collapsible: true,
element: app.$ui.info.options({
id: 'infoPanel'
}),
size: app.user.ui.listsSize / app.ui.infoRatio + 16
}
],
id: 'leftPanel',
orientation: 'vertical'
})
.bindEvent('resize', function(event, data) {
Ox.print('resize', data, data / app.ui.infoRatio + 16);
app.$ui.leftPanel.resize('infoPanel', Math.round(data / app.ui.infoRatio) + 16);
}),
resizable: true,
resize: [128, 192, 256],
size: app.user.ui.listsSize
},
{
element: app.$ui.rightPanel = new Ox.SplitPanel({
elements: [
{
element: app.$ui.toolbar.css({ zIndex: 2 }), // fixme: remove later
size: 24
},
{
element: app.$ui.contentPanel = new Ox.SplitPanel({
elements: [
{
collapsible: true,
element: app.$ui.groupsOuterPanel = new Ox.SplitPanel({
elements: [
{
element: app.$ui.groups[0],
size: app.ui.groups[0].size
},
{
element: app.$ui.groupsInnerPanel = new Ox.SplitPanel({
elements: [
{
element: app.$ui.groups[1],
size: app.ui.groups[1].size
},
{
element: app.$ui.groups[2],
},
{
element: app.$ui.groups[3],
size: app.ui.groups[3].size
}
],
orientation: 'horizontal'
})
},
{
element: app.$ui.groups[4],
size: app.ui.groups[4].size
},
],
id: 'browser',
orientation: 'horizontal'
})
.bindEvent('resize', function(event, data) {
Ox.print('resizing groups...')
$.each(app.$ui.groups, function(i, list) {
list.resize();
});
}),
resizable: true,
resize: [96, 112, 128, 144, 160, 176],
size: app.user.ui.groupsSize
},
{
element: app.$ui.list = app.constructList(app.user.ui.listView)
}
],
orientation: 'vertical'
})
},
{
element: app.$ui.statusbar,
size: 16
}
],
id: 'rightPanel',
orientation: 'vertical'
})
.bindEvent('resize', function(event, data) {
var widths = $.map(app.ui.groups, function(v, i) {
return app.getGroupWidth(i, data);
});
Ox.print('widths', widths);
app.$ui.groupsOuterPanel.resize(0, widths[0].list).resize(2, widths[4].list);
app.$ui.groupsInnerPanel.resize(0, widths[1].list).resize(2, widths[3].list);
$.each(app.$ui.groups, function(i, list) {
list.resizeColumn('name', widths[i].column);
});
app.$ui.list.resize();
})
}
],
orientation: 'horizontal'
})
}
],
orientation: 'vertical'
});
}
app.constructGroups = function() {
var $groups = [],
panelWidth = app.$document.width() - app.user.ui.listsSize - 1;
app.ui.groups = $.map(app.config.groups, function(id, i) {
var title = Ox.getObjectById(app.config.sortKeys, id).title,
width = app.getGroupWidth(i, panelWidth);
return {
id: id,
element: $groups[i] = new Ox.TextList({
columns: [
{
align: 'left',
id: 'name',
operator: id == 'year' ? '-' : '+',
title: title,
unique: true,
visible: true,
width: width.column
},
{
align: 'right',
id: 'items',
operator: '-',
title: '#',
visible: true,
width: 40
}
],
id: 'group_' + id,
request: function(data, callback) {
Ox.print('sending request', data)
delete data.keys;
return app.api.find($.extend(data, {
group: id,
query: app.Query.toObject()
}), callback);
},
sort: [
{
key: id == 'year' ? 'name' : 'items',
operator: '-'
}
]
})
.bindEvent('select', function(event, data) {
Ox.print('select', i)
var group = app.ui.groups[i],
query;
app.ui.groups[i].query.conditions = $.map(data.ids, function(v) {
return {
key: group.id,
value: v,
operator: '='
};
});
query = app.Query.toObject();
app.$ui.list.options({
request: function(data, callback) {
return app.api.find($.extend(data, {
query: query
}), callback);
}
});
$.each(app.ui.groups, function(i_, group_) {
if (i_ != i) {
Ox.print('setting groups request', i, i_)
app.$ui.groups[i_].options({
request: function(data, callback) {
delete data.keys;
return app.api.find($.extend(data, {
group: group_.id,
query: app.Query.toObject(group_.id)
}), callback);
}
});
}
});
location.hash = app.Query.toString(query);
}),
query: {
conditions: [],
operator: '|'
},
size: width.list,
title: title
};
Ox.print('--OK--');
});
return $groups;
}
app.constructInfo = function() {
return new Ox.Element()
.append(
app.$ui.infoStill = new Ox.Element('img')
.css({
position: 'absolute',
left: 0,
top: 0
})
)
.append(
app.$ui.infoTimeline = new Ox.Element('img')
.css({
position: 'absolute',
left: 0,
bottom: 0,
height: '16px',
})
);
}
app.constructItem = function(id, view) {
var $item;
//location.hash = '!' + id;
app.$ui.contentPanel.resize(0, 80);
app.$ui.groupsOuterPanel.empty();
if (view == 'timeline') {
app.api.getItem(id, function(result) {
item_debug = result.data.item;
var video = result.data.item.stream,
cuts = result.data.item.layers.cuts || {},
subtitles = result.data.item.layers.subtitles || [{
'in': 5,
'out': 10,
'text': 'This subtitle is just a test...'
}];
video.height = 96;
video.width = parseInt(video.height * video.aspectRatio / 2) * 2;
video.url = video.baseUrl + '/' + video.height + 'p.' + ($.support.video.webm ? 'webm' : 'mp4');
$item = new Ox.VideoEditor({
cuts: cuts,
duration: video.duration,
find: '',
frameURL: function(position) {
return '/' + id + '/frame/' + video.width.toString() + '/' + position.toString() + '.jpg'
},
id: 'editor',
largeTimeline: true,
matches: [],
points: [0, 0],
position: 0,
posterFrame: parseInt(video.duration / 2),
subtitles: subtitles,
videoHeight: video.height,
videoId: id,
videoWidth: video.width,
videoSize: 'small',
videoURL: video.url,
width: app.$document.width() - app.$ui.leftPanel.width() - 1 - 256 - 1
});
app.$ui.contentPanel.replace(1, $item);
app.$ui.rightPanel
/*.unbindEvent('resize')*/
.bindEvent('resize', function(event, data) {
Ox.print('seems to work', data)
$item.options({
width: data - 256 - 1
});
});
app.$window.resize(function() {
$item.options({
width: app.$document.width() - app.$ui.leftPanel.width() - 1 - 256 - 1
});
});
});
}
}
app.constructList = function(view) {
var $list,
keys = ['director', 'id', 'poster', 'title', 'year'];
Ox.print('constructList', view);
if (view == 'list' || view == 'calendar') {
$list = new Ox.TextList({
columns: $.map(app.config.sortKeys, function(key, i) {
return $.extend({
visible: $.inArray(key.id, app.user.ui.columns) > -1,
unique: key.id == 'id'
}, key);
}),
columnsMovable: true,
columnsRemovable: true,
id: 'list',
request: function(data, callback) {
Ox.print('data, Query.toObject', data, app.Query.toObject())
app.api.find($.extend(data, {
query: app.Query.toObject()
}), callback);
},
sort: app.user.ui.sort
})
.bindEvent({
resize: function(event, data) {
$list.resize();
}
});
} else if (view == 'icons') {
$list = new Ox.IconList({
id: 'list',
item: function(data, sort, size) {
var ratio = data.poster.width / data.poster.height;
size = size || 128;
return {
height: ratio <= 1 ? size : size / ratio,
id: data['id'],
info: data[['title', 'director'].indexOf(sort[0].key) > -1 ? 'year' : sort[0].key],
title: data.title + (data.director ? ' (' + data.director + ')' : ''),
url: data.poster.url.replace(/jpg/, size + '.jpg'),
width: ratio >= 1 ? size : size * ratio
};
},
keys: keys,
request: function(data, callback) {
Ox.print('data, Query.toObject', data, app.Query.toObject())
app.api.find($.extend(data, {
query: app.Query.toObject()
}), callback);
},
size: 128,
sort: app.user.ui.sort,
unique: 'id'
});
} else {
$list = new Ox.Element('