/*** Pandora ***/ var pandora = new Ox.App({ apiURL: '/api/', config: '/site.json', init: 'hello', }).launch(function(data) { Ox.print('data', data); var app = { $ui: { body: $('body'), document: $(document), window: $(window) }, config: data.config, requests: {}, ui: { infoRatio: 4 / 3, sectionElement: 'buttons', selectedMovies: [] }, user: data.user }; if (app.user.group == 'guest') { app.user = data.config.user; $.browser.safari && Ox.theme('modern'); } // $.each(pandora.afterLaunch, function(i, f) { f(); }); function load() { $(function() { var $body = $('body'); Ox.Request.requests() && app.$ui.loadingIcon.start(); $body.bind('requestStart', function() { Ox.print('requestStart') app.$ui.loadingIcon.start(); }); $body.bind('requestStop', function() { Ox.print('requestStop') app.$ui.loadingIcon.stop(); }); }); //Query.fromString(location.hash.substr(1)); URL.parse(); window.onpopstate = function() { URL.update(); }; app.$ui.appPanel = ui.appPanel(); app.$ui.appPanel.display(); app.ui.sectionButtonsWidth = app.$ui.sectionButtons.width() + 8; app.$ui.window.resize(function() { if (app.user.ui.item == '') { app.$ui.list.size(); resizeGroups(app.$ui.rightPanel.width()); if (app.user.ui.listView == 'map') { app.$ui.map.triggerResize(); } } else { Ox.print('app.$ui.window.resize'); app.$ui.browser.scrollToSelection(); app.user.ui.itemView == 'timeline' && app.$ui.editor.options({ height: app.$ui.document.height() - 20 - 24 - app.$ui.contentPanel.size(0) - 1 - 16, width: app.$ui.document.width() - app.$ui.mainPanel.size(0) - app.$ui.item.size(1) - 2 }); } }); pandora.app = app; // remove later } function login(data) { app.user = data.user; //Ox.Event.unbindAll(); app.$ui.appPanel.reload(); } function logout(data) { app.user = data.user; //Ox.Event.unbindAll(); app.$ui.appPanel.reload(); } var ui = { accountDialog: function(action) { var that = new Ox.Dialog($.extend({ height: 256, id: 'accountDialog', minHeight: 256, minWidth: 384, width: 384 }, ui.accountDialogOptions(action))) .bindEvent({ resize: function(event, data) { var width = data.width - 32; app.$ui.accountForm.items.forEach(function(item) { item.options({width: width}); }); } }); return that; }, accountDialogOptions: function(action, value) { Ox.print('ACTION', action) app.$ui.accountForm && app.$ui.accountForm.remove(); var buttons = { login: ['register', 'reset'], register: ['login'], reset: ['login'], resetAndLogin: [] }, buttonTitle = { login: 'Login', register: 'Register', reset: 'Reset Password', resetAndLogin: 'Reset Password and Login' }, dialogText = { login: 'To login to your account, please enter your username and password.', register: 'To create a new account, please choose a username and password, and enter your e-mail address.', reset: 'To reset your password, please enter either your username or your e-mail address.', resetAndLogin: 'To login to your account, please choose a new password, and enter the code that we have just e-mailed to you.' }, dialogTitle = { login: 'Login', register: 'Register', reset: 'Reset Password', resetAndLogin: 'Reset Password' }; function button(type) { if (type == 'cancel') { return new Ox.Button({ id: 'cancel' + Ox.toTitleCase(action), title: 'Cancel' }).bindEvent('click', function() { app.$ui.accountDialog.close(); }); } else if (type == 'submit') { return new Ox.Button({ disabled: true, id: 'submit' + Ox.toTitleCase(action), title: buttonTitle[action] }).bindEvent('click', function() { app.$ui.accountForm.submit(); }); } else { return new Ox.Button({ id: type, title: buttonTitle[type] + '...' }).bindEvent('click', function() { Ox.print('CLICK EVENT', type) app.$ui.accountDialog.options(ui.accountDialogOptions(type)); }); } } return { buttons: [ $.map(buttons[action], function(type) { return button(type); }), [button('cancel'), button('submit')] ], content: new Ox.Element('div') .append( new Ox.Element('div') .addClass('OxText') .html(dialogText[action] + '

') ) .append( app.$ui.accountForm = ui.accountForm(action, value) ), keys: { enter: 'submit' + Ox.toTitleCase(action), escape: 'cancel' + Ox.toTitleCase(action) }, title: dialogTitle[action] }; }, accountForm: function(action, value) { if (app.$ui.accountForm) { app.$ui.accountForm.items.forEach(function(item) { if (item.options('id') == 'usernameOrEmail') { Ox.print('REMOVING') //Ox.Event.unbind('usernameOrEmailSelect') //Ox.Event.unbind('usernameOrEmailSelectMenu') //Ox.Event.unbind('usernameOrEmailInput') } Ox.print('REMOVING ITEM', item.options('id')); item.remove(); }); } var items = { 'login': ['username', 'password'], 'register': ['newUsername', 'password', 'email'], 'reset': ['usernameOrEmail'], 'resetAndLogin': ['oldUsername', 'newPassword', 'code'] }, $items = $.map(items[action], function(v) { return item(v, value); }), that = new Ox.Form({ id: 'accountForm' + Ox.toTitleCase(action), items: $items, submit: function(data, callback) { if (action == 'login') { pandora.api.signin(data, function(result) { if (!result.data.errors) { app.$ui.accountDialog.close(); login(result.data); } else { callback([{id: 'password', message: 'Incorrect password'}]); } }); } else if (action == 'register') { pandora.api.signup(data, function(result) { if (!result.data.errors) { app.$ui.accountDialog.close(); login(result.data); ui.accountWelcomeDialog().open(); } else { callback([{id: 'password', message: result.data.errors.toString()}]); // fixme } }); } else if (action == 'reset') { var usernameOrEmail = data.usernameOrEmail, key = usernameOrEmail[0].id; data = {}; data[key] = usernameOrEmail[1]; pandora.api.requestToken(data, function(result) { if (!result.data.errors) { app.$ui.accountDialog.options(ui.accountDialogOptions('resetAndLogin', result.data.username)); } else { callback([{id: 'usernameOrEmail', message: 'Unknown ' + (key == 'username' ? 'username' : 'e-mail address')}]) } }); } else if (action == 'resetAndLogin') { pandora.api.resetPassword(data, function(result) { if (!result.data.errors) { app.$ui.accountDialog.close(); login(result.data); } else { callback([{id: 'code', message: 'Incorrect code'}]); } }) } } }).bindEvent({ submit: function(event, data) { }, validate: function(event, data) { Ox.print('FORM VALIDATE', data) app.$ui.accountDialog[ (data.valid ? 'enable' : 'disable') + 'Button' ]('submit' + Ox.toTitleCase(action)); } }); that.items = $items; function item(type, value) { if (type == 'code') { return new Ox.Input({ autovalidate: autovalidateCode, id: 'code', label: 'Code', labelWidth: 120, validate: function(value, callback) { callback({ message: 'Missing code', valid: !!value.length }); }, width: 352 }); } else if (type == 'email') { return new Ox.Input({ autovalidate: autovalidateEmail, id: 'email', label: 'E-Mail Address', labelWidth: 120, type: 'email', validate: validateUser('email'), width: 352 }); } else if (type == 'newPassword') { return new Ox.Input({ autovalidate: /.+/, id: 'password', label: 'New Password', labelWidth: 120, type: 'password', validate: function(value, callback) { callback({ message: 'Missing password', valid: value.length > 0 }); }, width: 352 }); } else if (type == 'newUsername') { return new Ox.Input({ autovalidate: autovalidateUsername, id: 'username', label: 'Username', labelWidth: 120, validate: validateUser('username'), width: 352 }); } else if (type == 'oldUsername') { return new Ox.Input({ disabled: true, id: 'username', label: 'Username', labelWidth: 120, value: value, width: 352 }); } else if (type == 'password') { return new Ox.Input({ autovalidate: /.+/, id: 'password', label: 'Password', labelWidth: 120, type: 'password', validate: function(value, callback) { callback({ message: 'Missing Password', valid: value.length > 0 }); }, width: 352 }); } else if (type == 'username') { return new Ox.Input({ autovalidate: autovalidateUsername, id: 'username', label: 'Username', labelWidth: 120, validate: validateUser('username', true), width: 352 }); } else if (type == 'usernameOrEmail') { return new Ox.FormElementGroup({ id: 'usernameOrEmail', elements: [ app.$ui.usernameOrEmailSelect = new Ox.Select({ id: 'usernameOrEmailSelect', items: [ {id: 'username', title: 'Username'}, {id: 'email', title: 'E-Mail Address'}, ], overlap: 'right', width: 120 }) .bindEvent({ change: function(event, data) { var selected = data.selected[0].id; app.$ui.usernameOrEmailInput.options({ autovalidate: selected == 'username' ? autovalidateUsername : autovalidateEmail, validate: validateUser(selected, true), value: '' }).focus(); } }), app.$ui.usernameOrEmailInput = new Ox.Input({ autovalidate: autovalidateUsername, id: 'usernameOrEmailInput', validate: validateUser('username', true), width: 232 }) ], separators: [ {title: '', width: 0} ] }); } } return that; }, accountLogoutDialog: function() { var that = new Ox.Dialog({ buttons: [ new Ox.Button({ id: 'cancel', title: 'Cancel' }).bindEvent('click', function() { that.close(); app.$ui.mainMenu.getItem('loginlogout').toggleTitle(); }), new Ox.Button({ id: 'logout', title: 'Logout' }).bindEvent('click', function() { that.close(); pandora.api.signout({}, function(result) { logout(result.data); }); }) ], content: new Ox.Element('div').html('Are you sure you want to logout?'), height: 160, keys: {enter: 'logout', escape: 'cancel'}, title: 'Logout', width: 300 }); return that; }, accountWelcomeDialog: function() { var that = new Ox.Dialog({ buttons: [ [ new Ox.Button({ id: 'preferences', title: 'Preferences...' }).bindEvent('click', function() { that.close(); }) ], [ new Ox.Button({ id: 'close', title: 'Close' }).bindEvent('click', function() { that.close(); }) ] ], content: new Ox.Element('div').html('Welcome, ' + app.user.username + '!

Your account has been created.'), height: 160, keys: {enter: 'close', escape: 'close'}, title: 'Welcome to ' + app.config.site.name, width: 300 }); return that; }, annotations: function() { var that = new Ox.Element({ id: 'annotations' }) .bindEvent({ resize: function(event, data) { app.user.ui.annotationsSize = data; }, toggle: function(event, data) { app.user.ui.showAnnotations = !data.collapsed; } }), $bins = []; $.each(app.config.layers, function(i, layer) { var $bin = new Ox.CollapsePanel({ id: layer.id, size: 16, title: layer.title }); $bins.push($bin); $bin.$content.append( $('
').css({ height: '20px' }).append( $('
').css({ float: 'left', width: '16px', height: '16px', margin: '1px'}).append( $('').attr({ src: 'static/oxjs/build/png/ox.ui.modern/iconFind.png' }).css({ width: '16px', height: '16px', border: 0, background: 'rgb(64, 64, 64)', WebkitBorderRadius: '2px' }) ) ).append( $('
').css({ float: 'left', width: '122px', height: '14px', margin: '2px' }).html('Foo') ).append( $('
').css({ float: 'left', width: '40px', height: '14px', margin: '2px', textAlign: 'right' }).html('23') ) ); }); $.each($bins, function(i, bin) { that.append(bin); }); return that; }, appPanel: function() { var that = new Ox.SplitPanel({ elements: [ { element: app.$ui.mainMenu = ui.mainMenu(), size: 20 }, { element: app.$ui.mainPanel = ui.mainPanel() } ], orientation: 'vertical' }); that.display = function() { app.$ui.body.css({opacity: 0}); that.appendTo(app.$ui.body); app.$ui.body.animate({opacity: 1}, 1000); return that; } that.reload = function() { app.$ui.appPanel.remove(); app.$ui.appPanel = ui.appPanel().appendTo(app.$ui.body); return that; } return that; }, backButton: function() { var that = Ox.Button({ title: 'Back to Movies', width: 96 }).css({ float: 'left', margin: '4px' }) .bindEvent({ click: function(event, data) { URL.set(Query.toString()); } }); return that; }, browser: function() { var that; if (!app.user.ui.item) { app.$ui.groups = ui.groups(); that = new Ox.SplitPanel({ elements: [ { element: app.$ui.groups[0], size: app.ui.groups[0].size }, { element: app.$ui.groupsInnerPanel = ui.groupsInnerPanel() }, { element: app.$ui.groups[4], size: app.ui.groups[4].size }, ], id: 'browser', orientation: 'horizontal' }) .bindEvent({ resize: function(event, data) { app.user.ui.groupsSize = data; $.each(app.$ui.groups, function(i, list) { list.size(); }); }, toggle: function(event, data) { app.user.ui.showGroups = !data.collapsed; data.collapsed && app.$ui.list.gainFocus(); } }); } else { var that = new Ox.IconList({ centered: true, id: 'list', item: function(data, sort, size) { var ratio = data.poster.width / data.poster.height; size = size || 64; 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: ['director', 'id', 'poster', 'title', 'year'], max: 1, min: 1, orientation: 'horizontal', request: function(data, callback) { Ox.print('data, Query.toObject', data, Query.toObject()) pandora.api.find($.extend(data, { query: Query.toObject() }), callback); }, selected: [app.user.ui.item], size: 64, sort: app.user.ui.sort, unique: 'id' }) .bindEvent({ open: function(event, data) { that.scrollToSelection(); }, select: function(event, data) { URL.set(data.ids[0]); }, toggle: function(event, data) { app.user.ui.showMovies = !data.collapsed; if (data.collapsed) { if (app.user.ui.itemView == 'timeline') { app.$ui.editor.gainFocus(); } } } }); } that.update = function() { app.$ui.contentPanel.replace(0, app.$ui.browser = ui.browser()); } return that; }, contentPanel: function() { var that = new Ox.SplitPanel({ elements: app.user.ui.item == '' ? [ { collapsed: !app.user.ui.showGroups, collapsible: true, element: app.$ui.browser = ui.browser() .bindEvent('resize', function(event, data) { $.each(app.$ui.groups, function(i, list) { list.size(); }); }), resizable: true, resize: [96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256], size: app.user.ui.groupsSize }, { element: app.$ui.list = ui.list(app.user.ui.listView) } ] : [ { collapsed: !app.user.ui.showMovies, collapsible: true, element: app.$ui.browser = ui.browser(), size: 112 + ($.browser.mozilla ? 16 : 12) // fixme: should be app.ui.scrollbarSize }, { element: app.$ui.item = ui.item(app.user.ui.item, app.user.ui.itemView) } ], orientation: 'vertical' }) return that; }, findElement: function() { var that = new Ox.FormElementGroup({ elements: [ app.$ui.findSelect = new Ox.Select({ id: 'select', items: $.map(app.config.findKeys, function(key, i) { return { id: key.id, title: 'Find: ' + key.title }; }), overlap: 'right', width: 112 }) .bindEvent('change', function(event, data) { var key = data.selected[0].id; if (!app.user.ui.findQuery.conditions.length) { app.user.ui.findQuery.conditions = [{key: key, value: '', operator: ''}]; } else { app.user.ui.findQuery.conditions[0].key = key; } app.$ui.mainMenu.checkItem('findMenu_find_' + key); app.$ui.findInput.options({ autocomplete: autocompleteFunction() }).focus(); Ox.print(app.$ui.findInput.options('autocomplete').toString()) }), app.$ui.findInput = new Ox.Input({ autocomplete: autocompleteFunction(), autocompleteSelect: true, autocompleteSelectHighlight: true, autocompleteSelectSubmit: true, clear: true, id: 'input', width: 192 }) .bindEvent('submit', function(event, data) { var key = app.user.ui.findQuery.conditions.length ? app.user.ui.findQuery.conditions[0].key : '', query; Ox.print('key', key); app.user.ui.findQuery.conditions = [ { key: key == 'all' ? '' : key, value: data.value, operator: '' } ]; $.each(app.ui.groups, function(i, group) { group.query.conditions = []; app.$ui.groups[i].options({ request: function(data, callback) { delete data.keys; return pandora.api.find($.extend(data, { group: group.id, query: Query.toObject(group.id) }), callback); } }); }); app.$ui.list.options({ request: function(data, callback) { return pandora.api.find($.extend(data, { query: query = Query.toObject() }), callback); } }); history.pushState({}, '', '/#' + Query.toString(query)); }) ], id: 'findElement' }) .css({ float: 'right', margin: '4px' }); function autocompleteFunction() { return app.user.ui.findQuery.conditions.length ? function(value, callback) { var key = app.user.ui.findQuery.conditions[0].key, findKey = Ox.getObjectById(app.config.findKeys, key); Ox.print('autocomplete', key, value); value === '' && Ox.print('Warning: autocomplete function should never be called with empty value'); if ('autocomplete' in findKey && findKey.autocomplete) { pandora.api.autocomplete({ key: key, range: [0, 20], value: value }, function(result) { //alert(JSON.stringify(result)) callback(result.data.items); }); /* pandora.api.find({ keys: [key], query: { conditions: [ { key: key, value: value, operator: '' } ], operator: '' }, sort: [ { key: key, operator: '' } ], range: [0, 10] }, function(result) { callback($.map(result.data.items, function(v) { return v[key]; })); }); */ } else { callback(); } } : null; } return that; }, group: function(id, query) { Ox.print('group', id, query); /* query && query.conditions.length && alert($.map(query.conditions, function(v) { return v.value; })); */ //alert(id + ' ' + JSON.stringify(Query.toObject(id))) var i = app.user.ui.groups.indexOf(id), panelWidth = app.$ui.document.width() - (app.user.ui.showSidebar * app.user.ui.sidebarSize) - 1, title = Ox.getObjectById(app.config.groups, id).title, width = getGroupWidth(i, panelWidth), that = 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 } ], columnsVisible: true, id: 'group_' + id, request: function(data, callback) { Ox.print('sending request', data) delete data.keys; //alert(id + " Query.toObject " + JSON.stringify(Query.toObject(id)) + ' ' + JSON.stringify(data)) return pandora.api.find($.extend(data, { group: id, query: Query.toObject(id) }), callback); }, selected: query ? $.map(query.conditions, function(v) { return v.value; }) : [], sort: [ { key: id == 'year' ? 'name' : 'items', operator: '-' } ] }) .bindEvent('select', function(event, data) { var group = app.ui.groups[i], query; app.ui.groups[i].query.conditions = $.map(data.ids, function(v) { return { key: id, value: v, operator: '=' }; }); reloadGroups(i); }); new Ox.Select({ items: $.map(app.config.groups, function(v) { return { checked: v.id == id, id: v.id, title: v.title } }), max: 1, min: 1, type: 'image' }) .bindEvent('change', function(event, data) { var id_ = data.selected[0].id, i_ = app.user.ui.groups.indexOf(id_); if (i_ == -1) { // new group was not part of old group set if (app.ui.groups[i].query.conditions.length) { // if group with selection gets replaced, reload app.ui.groups[i].query.conditions = []; reloadGroups(i); } app.ui.groups[i] = getGroupObject(id_); app.user.ui.groups[i] = id_; replaceGroup(i, id_); } else { // swap two existing groups var group = $.extend({}, app.ui.groups[i]); app.ui.groups[i] = app.ui.groups[i_]; app.ui.groups[i_] = group; app.user.ui.groups[i] = id_; app.user.ui.groups[i_] = id; replaceGroup(i, id_, app.ui.groups[i].query); replaceGroup(i_, id, app.ui.groups[i_].query); } function replaceGroup(i, id, query) { // if query is passed, selected items will be derived from it var isOuter = i % 4 == 0; //foo = app.$ui.groups[i]; app.$ui[isOuter ? 'browser' : 'groupsInnerPanel'].replace( isOuter ? i / 2 : i - 1, app.$ui.groups[i] = ui.group(id, query) ); //foo.remove(); } }) .appendTo(that.$bar.$element); if (!query) { // if query is set, group object has already been taken care of app.ui.groups[i] = getGroupObject(id); } function getGroupObject(id) { var i = app.user.ui.groups.indexOf(id), title = Ox.getObjectById(app.config.groups, id).title, width = getGroupWidth(i, panelWidth); return { id: id, element: that, query: { conditions: [], operator: '|' }, size: width.list, title: title }; } return that; }, groups: function() { var $groups = []; app.ui.groups = []; app.user.ui.groups.forEach(function(id, i) { $groups[i] = ui.group(id); }); return $groups; }, groupsInnerPanel: function() { var that = 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' }); return that; }, info: function() { var that = 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', }) ); return that; }, item: function() { var that; if (app.user.ui.itemView == 'info') { that = new Ox.Element('div'); } else if (app.user.ui.itemView == 'timeline') { that = new Ox.SplitPanel({ elements: [ { element: new Ox.Element('div'), }, { collapsed: !app.user.ui.showAnnotations, collapsible: true, element: new Ox.Element('div'), resizable: true, resize: [256, 384], size: app.user.ui.annotationsSize } ] }) } getItem(); function getItem() { pandora.api.getItem(app.user.ui.item, function(result) { if (app.user.ui.itemView == 'info') { Ox.print('result.data.item', result.data.item) $.get('/static/html/itemInfo.html', {}, function(template) { Ox.print(template); app.$ui.contentPanel.replace(1, app.$ui.item = new Ox.Element('div') .append($.tmpl(template, result.data.item)) ); }); } else if (app.user.ui.itemView == 'timeline') { 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'); that.replace(0, app.$ui.editor = new Ox.VideoEditor({ cuts: cuts, duration: video.duration, find: '', frameURL: function(position) { return '/' + app.user.ui.item + '/frame/' + video.width.toString() + '/' + position.toString() + '.jpg' }, height: app.$ui.contentPanel.size(1), id: 'editor', largeTimeline: true, matches: [], points: [0, 0], position: 0, posterFrame: parseInt(video.duration / 2), subtitles: subtitles, videoHeight: video.height, videoId: app.user.ui.item, videoWidth: video.width, videoSize: 'small', videoURL: video.url, width: app.$ui.document.width() - app.$ui.mainPanel.size(0) - 1 - (app.user.ui.showAnnotations * app.user.ui.annotationsSize) - 1 }).bindEvent('resize', function(event, data) { Ox.print('resize editor', data) app.$ui.editor.options({ width: data }); Ox.print('resize done') })); that.replace(1, app.$ui.annotations = ui.annotations()); that.bindEvent('resize', function(event, data) { Ox.print('resize item', data) app.$ui.editor.options({ height: data }); }); /* app.$ui.rightPanel.bindEvent('resize', function(event, data) { Ox.print('... rightPanel resize', data, app.$ui.timelinePanel.size(1)) app.$ui.editor.options({ width: data - app.$ui.timelinePanel.size(1) - 1 }); }); */ } }); } that.display = function() { app.$ui.contentPanel.replaceElements([ { collapsible: true, element: app.$ui.browser = ui.browser(), resizable: false, size: 112 + ($.browser.mozilla ? 16 : 12) }, { element: new Ox.Element('div') } ]); getItem(); // fixme: can the asynchronicity be moved within the video editor? } return that; }, leftPanel: function() { var that = new Ox.SplitPanel({ elements: [ { element: app.$ui.sectionbar = ui.sectionbar('buttons'), size: 24 }, { element: app.$ui.sections = ui.sections().options({ id: 'listsPanel' }) }, { collapsible: true, element: app.$ui.info = ui.info().options({ id: 'infoPanel' }), size: app.user.ui.sidebarSize / app.ui.infoRatio + 16 } ], id: 'leftPanel', orientation: 'vertical' }) .bindEvent({ resize: function(event, data) { app.user.ui.sidebarSize = data; if (data < app.ui.sectionButtonsWidth && app.$ui.sectionButtons) { app.$ui.sectionButtons.remove(); delete app.$ui.sectionButtons; app.$ui.sectionbar.append(app.$ui.sectionSelect = ui.sectionSelect()); } else if (data >= app.ui.sectionButtonsWidth && app.$ui.sectionSelect) { app.$ui.sectionSelect.remove(); delete app.$ui.sectionSelect; app.$ui.sectionbar.append(app.$ui.sectionButtons = ui.sectionButtons()); } ///* app.$ui.leftPanel.find('.OxTextList').css({ width: data + 'px' }); app.$ui.leftPanel.find('.OxItem').css({ width: data + 'px' }); app.$ui.leftPanel.find('.OxCell.OxColumnTitle').css({ width: (data - 80) + 'px' }); //*/ Ox.print('resize', data, data / app.ui.infoRatio + 16); app.$ui.leftPanel.size('infoPanel', Math.round(data / app.ui.infoRatio) + 16); }, toggle: function(event, data) { app.user.ui.showSidebar = !data.collapsed; } }); return that; }, list: function(view) { var that, $map, keys = ['director', 'id', 'poster', 'title', 'year']; Ox.print('constructList', view); if (view == 'list') { that = new Ox.TextList({ columns: $.map(app.config.sortKeys, function(key, i) { return $.extend({ align: getAlignment(key.id), operator: getSortOperator(key.id), unique: key.id == 'id', visible: $.inArray(key.id, app.user.ui.columns) > -1 }, key); }), columnsMovable: true, columnsRemovable: true, columnsResizable: true, columnsVisible: true, id: 'list', request: function(data, callback) { Ox.print('data, Query.toObject', data, Query.toObject()) pandora.api.find($.extend(data, { query: Query.toObject() }), callback); }, sort: app.user.ui.sort }) .bindEvent({ resize: function(event, data) { that.size(); } }); } else if (view == 'icons') { that = 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, Query.toObject()) pandora.api.find($.extend(data, { query: Query.toObject() }), callback); }, size: 128, sort: app.user.ui.sort, unique: 'id' }); } else if (view == 'map') { that = new Ox.SplitPanel({ elements: [ { element: new Ox.SplitPanel({ elements: [ { element: new Ox.Toolbar({ orientation: 'horizontal', size: 24 }) .append( app.$ui.findMapInput = new Ox.Input({ clear: true, id: 'findMapInput', placeholder: 'Find on Map', width: 192 }) .css({ float: 'right', margin: '4px' }) .bindEvent({ submit: function(event, data) { app.$ui.map.find(data.value, function(data) { app.$ui.mapStatusbar.html(data.geoname + ' ' + JSON.stringify(data.points)) }); } }) ), size: 24 }, { element: app.$ui.map = new Ox.Map({ places: [ { geoname: 'Beirut, Lebanon', name: 'Beirut', points: { 'center': [33.8886284, 35.4954794], 'northeast': [33.8978909, 35.5114868], 'southwest': [33.8793659, 35.479472] } }, { geoname: 'Berlin, Germany', name: 'Berlin', points: { 'center': [52.506701, 13.4246065], 'northeast': [52.675323, 13.760909], 'southwest': [52.338079, 13.088304] } }, { geoname: 'Mumbai, Maharashtra, India', name: 'Bombay', points: { 'center': [19.07871865, 72.8778187], 'northeast': [19.2695223, 72.9806562], 'southwest': [18.887915, 72.7749812] } } ] }) .bindEvent({ select: function(event, data) { app.$ui.mapStatusbar.html(data.geoname + ' ' + JSON.stringify(data.points)) } }), id: 'map', size: 'auto' }, { element: app.$ui.mapStatusbar = new Ox.Toolbar({ orientation: 'horizontal', size: 16 }) .css({ fontSize: '9px', padding: '2px 4px 0 0', textAlign: 'right' }), size: 16 } ], orientation: 'vertical' }), }, { element: new Ox.Element(), id: 'place', size: 128 + 16 + 12 } ], orientation: 'horizontal' }) .bindEvent('resize', function() { app.$ui.map.triggerResize(); }); } else { $list = new Ox.Element('
') .css({ width: '100px', height: '100px', background: 'red' }); } ['list', 'icons'].indexOf(view) > -1 && that.bindEvent({ closepreview: function(event, data) { app.$ui.previewDialog.close(); delete app.$ui.previewDialog; }, load: function(event, data) { app.$ui.total.html(ui.status('total', data)); data = []; $.each(app.config.totals, function(i, v) { data[v.id] = 0; }); app.$ui.selected.html(ui.status('selected', data)); }, open: function(event, data) { var id = data.ids[0]; URL.set(id); }, openpreview: function(event, data) { app.requests.preview && pandora.api.cancel(app.requests.preview); app.requests.preview = pandora.api.find({ keys: ['director', 'id', 'poster', 'title'], query: { conditions: $.map(data.ids, function(id, i) { return { key: 'id', value: id, operator: '=' } }), operator: '|' } }, function(result) { var documentHeight = app.$ui.document.height(), item = result.data.items[0], title = item.title + (item.director ? ' (' + item.director + ')' : ''), dialogHeight = documentHeight - 100, dialogWidth; app.ui.previewRatio = item.poster.width / item.poster.height, dialogWidth = parseInt((dialogHeight - 48) * app.ui.previewRatio); if ('previewDialog' in app.$ui) { app.$ui.previewDialog.options({ title: title }); app.$ui.previewImage.animate({ opacity: 0 }, 100, function() { app.$ui.previewDialog.size(dialogWidth, dialogHeight, function() { app.$ui.previewImage .attr({ src: item.poster.url }) .one('load', function() { app.$ui.previewImage .css({ width: dialogWidth + 'px', height: (dialogHeight - 48 - 2) + 'px', // fixme: why -2 ? opacity: 0 }) .animate({ opacity: 1 }, 100); }); }); }); Ox.print(app.$ui.document.height(), dialogWidth, 'x', dialogHeight, dialogWidth / (dialogHeight - 48), item.poster.width, 'x', item.poster.height, item.poster.width / item.poster.height) } else { app.$ui.previewImage = $('') .attr({ src: item.poster.url }) .css({ position: 'absolute', width: dialogWidth + 'px', height: (dialogHeight - 48 - 2) + 'px', // fixme: why -2 ? left: 0, top: 0, right: 0, bottom: 0, margin: 'auto', }); app.$ui.previewDialog = new Ox.Dialog({ buttons: [ new Ox.Button({ title: 'Close', }).bindEvent({ click: function() { app.$ui.previewDialog.close(); delete app.$ui.previewDialog; app.$ui.list.closePreview(); } }) ], content: app.$ui.previewImage, height: dialogHeight, id: 'previewDialog', minHeight: app.ui.previewRatio >= 1 ? 128 / app.ui.previewRatio + 48 : 176, minWidth: app.ui.previewRatio >= 1 ? 128 : 176 * app.ui.previewRatio, padding: 0, title: title, width: dialogWidth }) .bindEvent('resize', function(event, data) { var dialogRatio = data.width / (data.height - 48), height, width; if (dialogRatio < app.ui.previewRatio) { width = data.width; height = width / app.ui.previewRatio; } else { height = (data.height - 48 - 2); width = height * app.ui.previewRatio; } app.$ui.previewImage.css({ width: width + 'px', height: height + 'px', // fixme: why -2 ? }) }) .open(); //app.$ui.previewImage = $image; //Ox.print(app.$document.height(), dialogWidth, 'x', dialogHeight, dialogWidth / (dialogHeight - 48), item.poster.width, 'x', item.poster.height, item.poster.width / item.poster.height) } }); }, select: function(event, data) { var $still, $timeline; app.ui.selectedMovies = data.ids; if (data.ids.length) { app.$ui.mainMenu.enableItem('copy'); app.$ui.mainMenu.enableItem('openmovie'); } else { app.$ui.mainMenu.disableItem('copy'); app.$ui.mainMenu.disableItem('openmovie'); } if (data.ids.length == 1) { $still = $('') .attr({ src: 'http://0xdb.org/' + data.ids[0] + '/still.jpg' }) .one('load', function() { if (data.ids[0] != app.ui.selectedMovies[0]) { Ox.print('cancel after load...') return; } var image = $still[0], imageWidth = image.width, imageHeight = image.height, width = app.$ui.info.width(), height = imageHeight * width / imageWidth; app.ui.infoRatio = width / height; app.$ui.leftPanel.size('infoPanel', height + 16); $still.css({ position: 'absolute', left: 0, top: 0, //width: width + 'px', //height: height + 'px', width: '100%', opacity: 0 }) .appendTo(app.$ui.info.$element) .animate({ opacity: 1 }); app.$ui.infoStill.animate({ opacity: 0 }, 250); app.$ui.info.animate({ height: (height + 16) + 'px' }, 250, function() { app.$ui.infoStill.remove(); app.$ui.infoStill = $still; }); }); /* $timeline = $('') .attr({ src: 'http://0xdb.org/' + data.ids[0] + '/timeline/timeline.png' }) .one('load', function() { $timeline.css({ position: 'absolute', left: 0, bottom: '16px', opacity: 0 }) .appendTo($ui.info.$element) .animate({ opacity: 1 }); $ui.infoTimeline.animate({ opacity: 0 }, 250, function() { $ui.infoTimeline.remove(); $ui.infoTimeline = $timeline; }); }); */ } pandora.api.find({ query: { conditions: $.map(data.ids, function(id, i) { return { key: 'id', value: id, operator: '=' } }), operator: '|' } }, function(result) { app.$ui.selected.html(ui.status('selected', result.data)); }); }, sort: function(event, data) { /* some magic has already set user.ui.sort Ox.print(':', user.ui.sort[0]) if (data.key != user.ui.sort[0].key) { app.$ui.mainMenu.checkItem('sort_sortmovies_' + data.key); } if (data.operator != user.ui.sort[0].operator) { app.$ui.mainMenu.checkItem('sort_ordermovies_' + data.operator === '' ? 'ascending' : 'descending'); } user.ui.sort[0] = data; */ app.$ui.mainMenu.checkItem('sortMenu_sortmovies_' + data.key); app.$ui.mainMenu.checkItem('sortMenu_ordermovies_' + (data.operator === '' ? 'ascending' : 'descending')); } }); that.display = function() { app.$ui.rightPanel.replace(1, app.$ui.contentPanel = ui.contentPanel()); }; return that; }, mainMenu: function() { var isGuest = app.user.group == 'guest', that = new Ox.MainMenu({ extras: [ app.$ui.loadingIcon = new Ox.LoadingIcon({ size: 'medium' }) ], id: 'mainMenu', menus: [ { id: app.config.site.id + 'Menu', title: app.config.site.name, items: [ { id: 'home', title: 'Home' }, {}, { id: 'about', title: 'About ' + app.config.site.name }, { id: 'news', title: app.config.site.name + ' News' }, { id: 'tour', title: 'Take a Tour' }, { id: 'faq', title: 'Frequently Asked Questions' }, { id: 'tos', title: 'Terms of Service' }, {}, { id: 'software', title: 'Software', items: [ { id: 'about', title: 'About' }, { id: 'download', title: 'Download' }, { id: 'report', title: 'Report a Bug' } ] }, {}, { id: 'contact', title: 'Contact ' + app.config.site.name } ] }, { id: 'userMenu', title: 'User', items: [ { id: 'username', title: 'User: ' + (isGuest ? 'not logged in' : app.user.username), disabled: true }, {}, { id: 'preferences', title: 'Preferences...', disabled: isGuest, keyboard: 'control ,' }, {}, { id: 'register', title: 'Register...', disabled: !isGuest }, { id: 'loginlogout', title: isGuest ? 'Login...' : 'Logout...' } ] }, { id: 'listMenu', title: 'List', items: [ { id: 'history', title: 'History', items: [ { id: 'allmovies', title: 'All Movies' } ] }, { id: 'lists', title: 'View List', items: [ { id: 'favorites', title: 'Favorites' } ] }, { id: 'features', title: 'View Feature', items: [ { id: 'situationistfilm', title: 'Situationist Film' }, { id: 'timelines', title: 'Timelines' } ] }, {}, { 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 Movie to List...', 'Add Selected Movies to List...'], disabled: true }, {}, { id: 'setposterframe', title: 'Set Poster Frame', disabled: true } ]}, { id: 'editMenu', title: 'Edit', items: [ { id: 'undo', title: 'Undo', disabled: true, keyboard: 'control z' }, { id: 'redo', title: 'Redo', disabled: true, keyboard: 'shift control z' }, {}, { id: 'cut', title: 'Cut', disabled: true, keyboard: 'control x' }, { id: 'copy', title: 'Copy', disabled: true, keyboard: 'control c' }, { id: 'paste', title: 'Paste', disabled: true, keyboard: 'control v' }, { id: 'delete', title: 'Delete', disabled: true, keyboard: 'delete' }, {}, { id: 'selectall', title: 'Select All', disabled: true, keyboard: 'control a' }, { id: 'selectnone', title: 'Select None', disabled: true, keyboard: 'shift control a' }, { id: 'invertselection', title: 'Invert Selection', disabled: true, keyboard: 'alt control a' } ] }, { id: 'viewMenu', title: 'View', items: [ { id: 'movies', title: 'View Movies', items: [ { group: 'viewmovies', min: 0, max: 1, items: $.map(app.config.listViews, function(view, i) { return $.extend({ checked: app.user.ui.listView == view.id, }, view); }) }, ]}, { id: 'icons', title: 'Icons', items: [ { id: 'poster', title: 'Poster' }, { id: 'still', title: 'Still' }, { id: 'timeline', title: 'Timeline' } ] }, { id: 'info', title: 'Info', items: [ { id: 'poster', title: 'Poster' }, { id: 'video', title: 'Video' } ] }, {}, { id: 'openmovie', title: ['Open Movie', 'Open Movies'], disabled: true, items: [ { group: 'movieview', min: 0, max: 1, items: $.map(app.config.itemViews, function(view, i) { return $.extend({ checked: app.user.ui.itemView == view.id, }, view); }) }, ]}, {}, { id: 'lists', title: 'Hide Lists', keyboard: 'shift l' }, { id: 'info', title: 'Hide Info', keyboard: 'shift i' }, { id: 'groups', title: 'Hide Groups', keyboard: 'shift g' }, { id: 'movies', title: 'Hide Movies', disabled: true, keyboard: 'shift m' } ]}, { id: 'sortMenu', title: 'Sort', items: [ { id: 'sortmovies', title: 'Sort Movies by', items: [ { group: 'sortmovies', min: 1, max: 1, items: $.map(app.config.sortKeys, function(key, i) { return $.extend({ checked: app.user.ui.sort[0].key == key.id, }, key); }) } ] }, { id: 'ordermovies', title: 'Order Movies', items: [ { group: 'ordermovies', min: 1, max: 1, items: [ { id: 'ascending', title: 'Ascending', checked: app.user.ui.sort[0].operator === '' }, { id: 'descending', title: 'Descending', checked: app.user.ui.sort[0].operator == '-' } ]} ] }, { id: 'advancedsort', title: 'Advanced Sort...', keyboard: 'shift control s' }, {}, { id: 'groupsstuff', title: 'Groups Stuff' } ] }, { id: 'findMenu', title: 'Find', items: [ { id: 'find', title: 'Find', items: [ { group: 'find', min: 1, max: 1, items: $.map(app.config.findKeys, function(key, i) { return $.extend({ checked: app.user.ui.findQuery.conditions.length && (app.user.ui.findQuery.conditions[0].key == key.id || (app.user.ui.findQuery.conditions[0].key === '' && key.id == 'all')), }, key) }) } ] }, { id: 'advancedfind', title: 'Advanced Find...', keyboard: 'shift control f' } ] }, { id: 'dataMenu', title: 'Data', items: [ { id: 'titles', title: 'Manage Titles...' }, { id: 'names', title: 'Manage Names...' }, {}, { id: 'posters', title: 'Manage Stills...' }, { id: 'posters', title: 'Manage Posters...' }, {}, { id: 'places', title: 'Manage Places...' }, { id: 'events', title: 'Manage Events...' }, {}, { id: 'users', title: 'Manage Users...' }, { id: 'lists', title: 'Manage Lists...' }, ] }, { id: 'codeMenu', title: 'Code', items: [ { id: 'download', title: 'Download' }, { id: 'contribute', title: 'Contribute' }, { id: 'report', title: 'Report a Bug' }, ] }, { id: 'helpMenu', title: 'Help', items: [ { id: 'help', title: app.config.site.name + ' Help', keyboard: 'shift ?' } ] }, { id: 'debugMenu', title: 'Debug', items: [ { id: 'query', title: 'Show Query' } ] }, { id: 'testMenu', title: 'Test', items: [ { group: 'foogroup', items: [ { id: 'item1', title: 'Item 1' }, { id: 'item2', title: 'Item 2' } ] } ] } ] }) .bindEvent({ change: function(event, data) { if (data.id == 'find') { var id = data.checked[0].id; app.$ui.findSelect.selectItem(id); } else if (data.id == 'movieview') { var view = data.checked[0].id; var id = document.location.pathname.split('/')[1]; if (view == 'info') url(id + '/info'); else url(id); } else if (data.id == 'ordermovies') { var id = data.checked[0].id; app.$ui.list.sortList(app.user.ui.sort[0].key, id == 'ascending' ? '' : '-'); } else if (data.id == 'sortmovies') { var id = data.checked[0].id, operator = getSortOperator(id); app.$ui.mainMenu.checkItem('sortMenu_ordermovies_' + (operator === '' ? 'ascending' : 'descending')); app.$ui.sortSelect.selectItem(id); //alert(id + ' ' + operator) app.$ui.list.sortList(id, operator); URL.set(Query.toString()); } else if (data.id == 'viewmovies') { var view = data.checked[0].id; url('#view=' + view); } }, click: function(event, data) { if (data.id == 'about') { var $dialog = new Ox.Dialog({ buttons: [ new Ox.Button({ id: 'close', title: 'Close' }).bindEvent({ click: function() { $dialog.close(); } }) ], id: 'about', title: 'About' }).open(); } else if (data.id == 'home') { var $dialog = new Ox.Dialog({ buttons: [ new Ox.Button({ id: 'close', title: 'Close' }).bindEvent({ click: function() { $dialog.close(); } }) ], height: 498, id: 'home', keys: {enter: 'close', escape: 'close'}, title: app.config.site.name, width: 800 }).open(); } else if (data.id == 'register') { app.$ui.accountDialog = ui.accountDialog('register').open(); } else if (data.id == 'loginlogout') { app.$ui.accountDialog = (app.user.group == 'guest' ? ui.accountDialog('login') : ui.accountLogoutDialog()).open(); } else if (data.id == 'places') { var $manage = new Ox.SplitPanel({ elements: [ { collapsible: true, element: new Ox.SplitPanel({ elements: [ { element: new Ox.Toolbar({ orientation: 'horizontal', size: 44 }).append( app.$ui.findPlacesElement = new Ox.FormElementGroup({ elements: [ app.$ui.findPlacesSelect = new 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(event, data) { app.$ui.findPlacesSelect.loseFocus(); app.$ui.findPlacesInput.options({ placeholder: data.selected[0].title }); } }), app.$ui.findPlacesInput = new Ox.Input({ clear: true, id: 'findPlacesInput', placeholder: 'Find: Name', width: 234 }) ], id: 'findPlacesElement' }) .css({ float: 'left', margin: '4px' }) ).append( app.$ui.sortPlacesSelect = new 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: new Ox.Element('div') }, { element: new Ox.Toolbar({ orientation: 'horizontal', size: 16 }), size: 16 } ], orientation: 'vertical' }), size: 256 }, { element: new Ox.SplitPanel({ elements: [ { element: new Ox.Toolbar({ orientation: 'horizontal', size: 24 }).append( app.$ui.labelsButton = new Ox.Button({ id: 'labelsButton', title: [ {id: 'show', title: 'Show Labels'}, {id: 'hide', title: 'Hide Labels'} ], width: 96 }) .css({ float: 'left', margin: '4px' }) ).append( app.$ui.findMapInput = new Ox.Input({ clear: true, id: 'findMapInput', placeholder: 'Find on Map', width: 192 }) .css({ float: 'right', margin: '4px' }) .bindEvent({ submit: function(event, data) { app.$ui.map.find(data.value, function(location) { /* app.$ui.placeNameInput.options({ disabled: false, value: location.name }); app.$ui.placeAliasesInput.options({ disabled: false }); app.$ui.placeGeonameLabel.options({ disabled: false, title: location.names.join(', ') }); app.$ui.removePlaceButton.options({ disabled: false }); app.$ui.addPlaceButton.options({ disabled: false }); */ }); } }) ), size: 24 }, { element: app.$ui.map = new 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) { app.$ui.placeNameInput.options({ disabled: false, value: location.name }); app.$ui.placeAliasesInput.options({ disabled: false }); app.$ui.placeGeonameLabel.options({ disabled: false, title: location.names.join(', ') }); app.$ui.removePlaceButton.options({ disabled: false }); app.$ui.addPlaceButton.options({ disabled: false }); } }) }, { element: app.$ui.bottomBar = new Ox.Toolbar({ orientation: 'horizontal', size: 24 }) .append( app.$ui.placeNameInput = new Ox.Input({ disabled: true, id: 'placeName', placeholder: 'Name', width: 128 }) .css({ float: 'left', margin: '4px 0 0 4px' }) ) .append( app.$ui.placeAliasesInput = new Ox.Input({ disabled: true, id: 'aliases', placeholder: 'Aliases', width: 128 }) .css({ float: 'left', margin: '4px 0 0 4px' }) ) .append( app.$ui.placeGeonameLabel = new Ox.Label({ disabled: true, id: 'placeGeoname', title: 'Geoname', width: parseInt(app.$ui.document.width() * 0.8) - 256 - 256 - 32 - 24 }) .css({ float: 'left', margin: '4px 0 0 4px' }) ) .append( app.$ui.addPlaceButton = new Ox.Button({ disabled: true, id: 'addPlaceButton', title: 'add', type: 'image' }) .css({ float: 'right', margin: '4px 4px 0 0' }) ) .append( app.$ui.removePlaceButton = new 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 = new Ox.Dialog({ buttons: [ { click: function() { $dialog.close(); }, id: 'close', title: 'Close', value: 'Close' } ], height: parseInt(app.$ui.document.height() * 0.8), id: 'places', minHeight: 400, minWidth: 600, padding: 0, title: 'Manage Places', width: parseInt(app.$ui.document.width() * 0.8) }).css({ overflow: 'hidden' }).append($manage).open(); } } }); return that; }, mainPanel: function() { var that = new Ox.SplitPanel({ elements: [ { collapsible: true, element: app.$ui.leftPanel = ui.leftPanel(), resizable: true, resize: [128, 256, 384, 512], size: app.user.ui.sidebarSize }, { element: app.$ui.rightPanel = ui.rightPanel() } ], orientation: 'horizontal' }) return that; }, rightPanel: function() { var that = new Ox.SplitPanel({ elements: [ { element: app.$ui.toolbar = ui.toolbar(), size: 24 }, { element: app.$ui.contentPanel = ui.contentPanel() }, { element: app.$ui.statusbar = ui.statusbar(), size: 16 } ], id: 'rightPanel', orientation: 'vertical' }) .bindEvent('resize', function(event, data) { Ox.print('???? resize rightPanel', event, data) if (!app.user.ui.item) { resizeGroups(data); app.$ui.list.size(); if (app.user.ui.listView == 'map') { app.$ui.map.triggerResize(); } } else { app.$ui.browser.scrollToSelection(); app.user.ui.itemView == 'timeline' && app.$ui.editor.options({ width: data - (app.user.ui.showAnnotations * app.user.ui.annotationsSize) - 1 }); } }); return that; }, sectionbar: function(mode) { var that = new Ox.Bar({ size: 24 }) .append( mode == 'buttons' ? app.$ui.sectionButtons = ui.sectionButtons() : app.$ui.sectionSelect = ui.sectionSelect() ); that.toggle = function() { }; return that; }, sectionButtons: function() { var that = new Ox.ButtonGroup({ buttons: [ {id: 'site', selected: app.user.ui.section == 'site', title: app.config.site.name}, {id: 'items', selected: app.user.ui.section == 'items', title: app.config.itemName.plural}, {id: 'texts', selected: app.user.ui.section == 'texts', title: 'Texts'}, {id: 'admin', selected: app.user.ui.section == 'admin', title: 'Admin'} ], id: 'sectionButtons', selectable: true }).css({ float: 'left', margin: '4px' }); return that; }, sections: function() { var that = new Ox.Element(); var $sections = []; app.$ui.sectionLists = []; $.each(app.user.ui.sections, function(i, id) { var menu = []; if (id == 'my') { menu = [ { id: 'new', title: 'New List...' }, { id: 'newfromselection', title: 'New List from Selection...' }, { id: 'newsmart', title: 'New Smart List...' }, { id: 'newfromresults', title: 'New Smart List from Results...' }, {}, { id: 'addselection', title: 'Add Selection to List...' } ]; } else if (id == 'public') { menu = [ { id: 'browse', title: 'More Public Lists...' }, ]; } var $section = new Ox.CollapsePanel({ id: id, menu: menu, size: 16, title: Ox.getObjectById(app.config.sections, id).title }); $sections.push($section); $section.$content.css({ height: app.user.lists[id].length * 16 + 'px' }); app.$ui.sectionLists[i] = new Ox.TextList({ columns: [ { align: 'left', id: 'title', operator: '+', unique: true, visible: true, width: 184 }, { align: 'right', id: 'items', operator: '-', visible: true, width: 40 }, { align: 'left', format: function(value) { return $('').attr({ src: 'static/oxjs/build/png/ox.ui.modern/symbol' + (value ? 'Find' : 'None') + '.png' }); }, id: 'query', operator: '+', visible: true, width: 16 }, { align: 'left', format: function(value) { return $('').attr({ src: 'static/oxjs/build/png/ox.ui.modern/symbol' + (value ? 'Publish' : 'None') + '.png' }); }, id: 'public', operator: '+', visible: true, width: 16 } ], max: 1, min: 0, request: function(data, callback) { if ($.isEmptyObject(data)) { callback({data: {items: app.user.lists[id].length}}); } else { callback({data: {items: $.map(app.user.lists[id], function(v, i) { return $.extend(v, { query: v.query, public: v.public, items: v.items ? v.items.length.toString() : (v.title == '1960s' || v.title == 'All Movies' ? '?' : '100') }); })}}); } }, sort: [ {key: 'title', operator: '+'} ] }) .css({ left: 0, top: 0, width: app.user.ui.sidebarSize + 'px', height: app.user.lists[id].length * 16 + 'px' }) .bindEvent('select', function(event, data) { app.$ui.sectionLists.forEach(function($list, i_) { if (i != i_) { $list.options('selected', []); } }); }) .appendTo($section.$content); }); $.each($sections, function(i, $section) { that.append($section); }); that.toggle = function() { } return that; }, sectionSelect: function() { var that = new Ox.Select({ id: 'sectionSelect', items: [ {checked: app.user.ui.section == 'site', id: 'site', title: app.config.site.name}, {checked: app.user.ui.section == 'items', id: 'items', title: app.config.itemName.plural}, {checked: app.user.ui.section == 'texts', id: 'texts', title: 'Texts'}, {checked: app.user.ui.section == 'admin', id: 'admin', title: 'Admin'} ] }).css({ float: 'left', margin: '4px' }); return that; }, sortSelect: function() { var that = new Ox.Select({ id: 'sortSelect', items: $.map(app.config.sortKeys, function(key) { Ox.print('????', app.user.ui.sort.key, key.id) return $.extend($.extend({}, key), { checked: app.user.ui.sort[0].key == key.id, title: 'Sort by ' + key.title }); }), width: 144 }) .css({ float: 'left', margin: '4px 0 0 4px' }) .bindEvent('change', function(event, data) { var id = data.selected[0].id, operator = getSortOperator(id); /* app.user.ui.sort[0] = { key: id, operator: operator }; */ app.$ui.mainMenu.checkItem('sortMenu_sortmovies_' + id); app.$ui.mainMenu.checkItem('sortMenu_ordermovies_' + (operator === '' ? 'ascending' : 'descending')); //alert(id + ' ' + operator) app.$ui.list.sortList(id, operator); URL.set(Query.toString()); }); return that; }, status: function(key, data) { var that = Ox.toTitleCase(key) + ': ' + [ Ox.formatNumber(data.items) + ' movie' + (data.items != 1 ? 's' : ''), Ox.formatDuration(data.runtime, 'medium'), data.files + ' file' + (data.files != 1 ? 's' : ''), Ox.formatDuration(data.duration, 'short'), Ox.formatValue(data.size, 'B'), Ox.formatValue(data.pixels, 'px') ].join(', '); return that; }, statusbar: function() { var that = new Ox.Bar({ size: 16 }) .css({ textAlign: 'center' }) .append( new Ox.Element() .css({ marginTop: '2px', fontSize: '9px' }) .append( app.$ui.total = new Ox.Element('span') ) .append( new Ox.Element('span').html(' — ') ) .append( app.$ui.selected = new Ox.Element('span') ) ); return that; }, toolbar: function() { var that = new Ox.Bar({ size: 24 }).css({ zIndex: 2 // fixme: remove later }); app.user.ui.item && that.append( app.$ui.backButton = ui.backButton() ); that.append( app.$ui.viewSelect = ui.viewSelect() ); !app.user.ui.item && that.append( app.$ui.sortSelect = ui.sortSelect() ); that.append( app.$ui.findElement = ui.findElement() ); that.display = function() { app.$ui.rightPanel.replace(0, app.$ui.toolbar = ui.toolbar()); // fixme: remove later } return that; }, viewSelect: function() { var that = new Ox.Select({ id: 'viewSelect', items: !app.user.ui.item ? $.map(app.config.listViews, function(view) { return $.extend($.extend({}, view), { checked: app.user.ui.listView == view.id, title: 'View ' + view.title }); }) : $.map(app.config.itemViews, function(view) { return $.extend($.extend({}, view), { checked: app.user.ui.itemView == view.id, title: view.title }); }), width: !app.user.ui.item ? 144 : 96 }) .css({ float: 'left', margin: '4px 0 0 4px' }) .bindEvent('change', !app.user.ui.item ? function(event, data) { var id = data.selected[0].id; app.user.ui.listView = id; app.$ui.mainMenu.checkItem('viewMenu_movies_' + id); app.$ui.contentPanel.replace(1, app.$ui.list = ui.list(id)); URL.set(Query.toString()); } : function(event, data) { var id = data.selected[0].id; app.user.ui.itemView = id; app.$ui.contentPanel.replace(1, app.$ui.item = ui.item()); }); return that; } } function autovalidateCode(value, blur, callback) { value = $.map(value.toUpperCase().split(''), function(v) { return /[0-9A-Z]/(v) ? v : null; }).join(''); callback(value); } function autovalidateEmail(value, blur, callback) { value = $.map(value.toLowerCase().split(''), function(v, i) { return /[0-9a-z\.\+\-_@]/(v) ? v : null; }).join(''); callback(value); } function autovalidateUsername(value, blur, callback) { var length = value.length; value = $.map(value.toLowerCase().split(''), function(v, i) { if (new RegExp('[0-9a-z' + ((i == 0 || (i == length - 1 && blur)) ? '' : '\-_') + ']')(v)) { return v } else { return null; } }).join(''); $.each(['--', '-_', '_-', '__'], function(i, v) { while (value.indexOf(v) > -1) { value = value.replace(new RegExp(v, 'g'), v[0]); } }) callback(value); } function getAlignment(key) { // fixme: make static return ['person', 'string', 'text', 'title'].indexOf( Ox.getObjectById(app.config.sortKeys, key).type ) > -1 ? 'left' : 'right'; } function getGroupWidth(pos, panelWidth) { var width = {}; width.list = Math.floor(panelWidth / 5) + (panelWidth % 5 > pos); width.column = width.list - 40 - ($.browser.mozilla ? 16 : 12); return width; } function getSortOperator(key) { // fixme: make static return ['person', 'string', 'text', 'title'].indexOf( Ox.getObjectById(app.config.sortKeys, key).type ) > -1 ? '' : '-'; } function reloadGroups(i) { var query = Query.toObject(); app.$ui.list.options({ request: function(data, callback) { return pandora.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; //alert(i_ + " Query.toObject " + JSON.stringify(Query.toObject(group_.id))) return pandora.api.find($.extend(data, { group: group_.id, query: Query.toObject(group_.id) }), callback); } }); } }); history.pushState({}, '', Query.toString(query)); } function resizeGroups(width) { var widths = $.map(app.ui.groups, function(v, i) { return getGroupWidth(i, width); }); Ox.print('widths', widths); app.$ui.browser.size(0, widths[0].list).size(2, widths[4].list); app.$ui.groupsInnerPanel.size(0, widths[1].list).size(2, widths[3].list); $.each(app.$ui.groups, function(i, list) { list.resizeColumn('name', widths[i].column); }); } function validateUser(key, existing) { existing = existing || false; var string = key == 'username' ? 'username' : 'e-mail address'; return function(value, callback) { var valid = key == 'username' ? !!value.length : Ox.isValidEmail(value); valid ? pandora.api.findUser({ key: key, value: value, operator: '=' }, function(result) { var valid = existing == !!result.data.users.length; Ox.print(existing, result.data.users) callback({ message: existing ? 'Unknown ' + string : string[0].toUpperCase() + string.substr(1) + ' already exists', valid: valid }); }) : callback({ message: (!value.length ? 'Missing' : 'Invalid') + ' ' + string, valid: false }); }; } var 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.substr(1)), 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('+', '') : getSortOperator(key); 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 ), operator; $.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(Query.toObject()), sort: app.user.ui.sort[0].operator + app.user.ui.sort[0].key, view: app.user.ui.listView }); } }; })(); var URL = (function() { var old = { user: { ui: {} } }, regexps = { '^\\?': function(url) { Query.fromString(url); app.user.ui.section = 'items'; app.user.ui.item = ''; }, '^(|about|faq|home|news|software|terms|tour)$': function(url) { app.user.ui.section = 'site'; app.user.ui.sitePage = url; }, '^(|find)$': function() { app.user.ui.section = 'items'; app.user.ui.item = ''; }, '^(calendar|calendars|clips|icons|flow|map|maps|timelines)$': function() { app.user.ui.section = 'items'; app.user.ui.item = ''; app.user.ui.listView = url; }, '^[0-9A-Z]': function() { var split = url.split('/'), item = split[0], view = new RegExp( '^(calendar|clips|files|info|map|player|statistics|timeline)$' )(split[1]) || app.user.ui.itemView; app.user.ui.section = 'items'; app.user.ui.item = item; app.user.ui.itemView = view; }, '^texts$': function() { app.user.ui.section = 'texts'; }, '^admin$': function() { app.user.ui.section = 'admin'; } }; return { set: function(url) { history.pushState({}, '', '/' + url); old.user.ui = $.extend({}, app.user.ui); // make a clone URL.update(); }, parse: function() { url = document.location.pathname.substr(1) + document.location.search + document.location.hash; $.each(regexps, function(re, fn) { Ox.print(url, 're', re) re = new RegExp(re); if (re(url)) { fn(url); return false; } }); }, update: function() { URL.parse(); if (app.user.ui.section == 'items') { if (!old.user.ui.item) { if (!app.user.ui.item) { } else { app.$ui.mainPanel.replace(1, app.$ui.rightPanel = ui.rightPanel()); //app.$ui.rightPanel.replace(0, app.$ui.toolbar = ui.toolbar()); //ui.item().display(); } } else { if (!app.user.ui.item) { app.$ui.mainPanel.replace(1, app.$ui.rightPanel = ui.rightPanel()); //ui.list(app.user.ui.listView).display(); } else { app.$ui.contentPanel.replace(1, ui.item()); } } } delete old.user.ui; } } }()); var url = function(url) { var currentURL = document.location.pathname.substr(1) + document.location.hash, match = false; regexps = { '^[0-9A-Z]': function() { var split = url.split('/'), id = split[0], view = split[1] || app.user.ui.itemView; ui.item(id, view); } }; if (!url) url = currentURL; else { if (url != currentURL) { var title = document.title + ' ' + url; history.pushState({}, title, url); } else { //FIXME: this is a workaround since open gets called twice // due to a bug with double click Ox.print('ignore double call of app.url, double click need to be fixed'); return; } } $.each(regexps, function(re, fn) { re = new RegExp(re); if (re(url)) { fn(); match = true; return false; } }); if (!match) { Query.fromString(location.hash.substr(1)); app.$ui.rightPanel.replace(1, ui.contentPanel()); } } load(); }); // Objects /* // 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.constructAnnotations = function() { var $annotations = new Ox.Element(); $.each(app.constructBins(), function(i, $bin) { $annotations.append($bin); }); return $annotations; } app.constructApp = function() { 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.sectionbar, size: 24 }, { 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.size('infoPanel', Math.round(data / app.ui.infoRatio) + 16); }), resizable: true, resize: [128, 256, 384, 512], 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.constructContentPanel() }, { 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.size(0, widths[0].list).size(2, widths[4].list); app.$ui.groupsInnerPanel.size(0, widths[1].list).size(2, widths[3].list); $.each(app.$ui.groups, function(i, list) { list.resizeColumn('name', widths[i].column); }); app.$ui.list.size(); }) } ], orientation: 'horizontal' }) } ], orientation: 'vertical' }); } app.constructBins = function() { var $bins = []; $.each(app.config.layers, function(i, layer) { var $bin = new Ox.CollapsePanel({ id: layer.id, size: 16, title: layer.title }); $bins.push($bin); $bin.$content.append( $('
').css({ height: '20px' }).append( $('
').css({ float: 'left', width: '16px', height: '16px', margin: '1px'}).append( $('').attr({ src: 'static/oxjs/build/png/ox.ui.modern/iconFind.png' }).css({ width: '16px', height: '16px', border: 0, background: 'rgb(64, 64, 64)', WebkitBorderRadius: '2px' }) ) ).append( $('
').css({ float: 'left', width: '122px', height: '14px', margin: '2px' }).html('Foo') ).append( $('
').css({ float: 'left', width: '40px', height: '14px', margin: '2px', textAlign: 'right' }).html('23') ) ); }); return $bins; } 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 pandora.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 pandora.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 pandora.api.find($.extend(data, { group: group_.id, query: app.Query.toObject(group_.id) }), callback); } }); } }); history.pushState({}, '', '/#' + 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.constructContentPanel = function(listView) { listView = listView || app.user.ui.listView; return 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.size(); }); }), resizable: true, resize: [96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256], size: app.user.ui.groupsSize }, { element: app.$ui.list = app.constructList(listView) } ], orientation: 'vertical' }); } app.constructItem = function(id, view) { } app.constructList = function(view) { } app.constructLists = function() { var $lists = new Ox.Element; $.each(app.$ui.sections, function(i, $section) { $lists.append($section); }); return $lists; } app.constructMainMenu = function() { return new Ox.MainMenu({ extras: [ app.$ui.loadingIcon = new Ox.LoadingIcon({ size: 'medium' }) ], id: 'mainMenu', menus: [ { id: app.config.site.id + 'Menu', title: app.config.site.name, items: [ { id: 'about', title: 'About' }, {}, { id: 'home', title: 'Home Screen' }, { id: 'faq', title: 'Frequently Asked Questions' }, { id: 'tos', title: 'Terms of Service' }, {}, { id: 'contact', title: 'Contact...' } ] }, { id: 'userMenu', title: 'User', items: [ { id: 'username', title: 'User: not logged in', disabled: true }, {}, { id: 'preferences', title: 'Preferences...', disabled: true, keyboard: 'control ,' }, {}, { id: 'register', title: 'Create an Account...' }, { id: 'loginlogout', title: ['Login...', 'Logout...'] } ] }, { id: 'listMenu', title: 'List', items: [ { id: 'history', title: 'History', items: [ { id: 'allmovies', title: 'All Movies' } ] }, { id: 'lists', title: 'View List', items: [ { id: 'favorites', title: 'Favorites' } ] }, { id: 'features', title: 'View Feature', items: [ { id: 'situationistfilm', title: 'Situationist Film' }, { id: 'timelines', title: 'Timelines' } ] }, {}, { 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 Movie to List...', 'Add Selected Movies to List...'], disabled: true }, {}, { id: 'setposterframe', title: 'Set Poster Frame', disabled: true } ]}, { id: 'editMenu', title: 'Edit', items: [ { id: 'undo', title: 'Undo', disabled: true, keyboard: 'control z' }, { id: 'redo', title: 'Redo', disabled: true, keyboard: 'shift control z' }, {}, { id: 'cut', title: 'Cut', disabled: true, keyboard: 'control x' }, { id: 'copy', title: 'Copy', disabled: true, keyboard: 'control c' }, { id: 'paste', title: 'Paste', disabled: true, keyboard: 'control v' }, { id: 'delete', title: 'Delete', disabled: true, keyboard: 'delete' }, {}, { id: 'selectall', title: 'Select All', disabled: true, keyboard: 'control a' }, { id: 'selectnone', title: 'Select None', disabled: true, keyboard: 'shift control a' }, { id: 'invertselection', title: 'Invert Selection', disabled: true, keyboard: 'alt control a' } ] }, { id: 'viewMenu', title: 'View', items: [ { id: 'movies', title: 'View Movies', items: [ { group: 'viewmovies', min: 0, max: 1, items: $.map(app.config.listViews, function(view, i) { return $.extend({ checked: app.user.ui.listView == view.id, }, view); }) }, ]}, { id: 'icons', title: 'Icons', items: [ { id: 'poster', title: 'Poster' }, { id: 'still', title: 'Still' }, { id: 'timeline', title: 'Timeline' } ] }, { id: 'info', title: 'Info', items: [ { id: 'poster', title: 'Poster' }, { id: 'video', title: 'Video' } ] }, {}, { id: 'openmovie', title: ['Open Movie', 'Open Movies'], disabled: true, items: [ { group: 'movieview', min: 0, max: 1, items: $.map(app.config.itemViews, function(view, i) { return $.extend({ checked: app.user.ui.itemView == view.id, }, view); }) }, ]}, {}, { id: 'lists', title: 'Hide Lists', keyboard: 'shift l' }, { id: 'info', title: 'Hide Info', keyboard: 'shift i' }, { id: 'groups', title: 'Hide Groups', keyboard: 'shift g' }, { id: 'movies', title: 'Hide Movies', disabled: true, keyboard: 'shift m' } ]}, { id: 'sortMenu', title: 'Sort', items: [ { id: 'sortmovies', title: 'Sort Movies by', items: [ { group: 'sortmovies', min: 1, max: 1, items: $.map(app.config.sortKeys, function(key, i) { return $.extend({ checked: app.user.ui.sort[0].key == key.id, }, key); }) } ] }, { id: 'ordermovies', title: 'Order Movies', items: [ { group: 'ordermovies', min: 1, max: 1, items: [ { id: 'ascending', title: 'Ascending', checked: app.user.ui.sort[0].operator === '' }, { id: 'descending', title: 'Descending', checked: app.user.ui.sort[0].operator == '-' } ]} ] }, { id: 'advancedsort', title: 'Advanced Sort...', keyboard: 'shift control s' }, {}, { id: 'groupsstuff', title: 'Groups Stuff' } ] }, { id: 'findMenu', title: 'Find', items: [ { id: 'find', title: 'Find', items: [ { group: 'find', min: 1, max: 1, items: $.map(app.config.findKeys, function(key, i) { return $.extend({ checked: app.user.ui.findQuery.conditions.length && (app.user.ui.findQuery.conditions[0].key == key.id || (app.user.ui.findQuery.conditions[0].key === '' && key.id == 'all')), }, key) }) } ] }, { id: 'advancedfind', title: 'Advanced Find...', keyboard: 'shift control f' } ] }, { id: 'dataMenu', title: 'Data', items: [ { id: 'titles', title: 'Manage Titles...' }, { id: 'names', title: 'Manage Names...' }, {}, { id: 'posters', title: 'Manage Stills...' }, { id: 'posters', title: 'Manage Posters...' }, {}, { id: 'places', title: 'Manage Places...' }, { id: 'events', title: 'Manage Events...' }, {}, { id: 'users', title: 'Manage Users...' }, { id: 'lists', title: 'Manage Lists...' }, ] }, { id: 'codeMenu', title: 'Code', items: [ { id: 'download', title: 'Download' }, { id: 'contribute', title: 'Contribute' }, { id: 'report', title: 'Report a Bug' }, ] }, { id: 'helpMenu', title: 'Help', items: [ { id: 'help', title: app.config.site.name + ' Help', keyboard: 'shift ?' } ] }, { id: 'debugMenu', title: 'Debug', items: [ { id: 'query', title: 'Show Query' } ] }, { id: 'testMenu', title: 'Test', items: [ { group: 'foogroup', items: [ { id: 'item1', title: 'Item 1' }, { id: 'item2', title: 'Item 2' } ] } ] } ] }) .bindEvent({ change: function(event, data) { if (data.id == 'find') { var id = data.checked[0].id; app.$ui.findSelect.selectItem(id); } else if (data.id == 'movieview') { var view = data.checked[0].id; var id = document.location.pathname.split('/')[1]; if (view == 'info') app.url('/'+id+'/info'); else app.url('/'+id); } else if (data.id == 'ordermovies') { var id = data.checked[0].id; app.$ui.list.sortList(user.ui.sort[0].key, id == 'ascending' ? '' : '-'); } else if (data.id == 'sortmovies') { var id = data.checked[0].id, operator = Ox.getObjectById(app.config.sortKeys, id).operator; app.$ui.mainMenu.checkItem('sortMenu_ordermovies_' + (operator === '' ? 'ascending' : 'descending')); app.$ui.list.sortList(id, operator); } else if (data.id == 'viewmovies') { var view = data.checked[0].id; app.url('/#view='+view); } }, click: function(event, data) { if (data.id == 'about') { var $dialog = new Ox.Dialog({ buttons: [ { click: function() { $dialog.close(); }, id: 'close', title: 'Close' } ], id: 'about', title: 'About' }).open(); } else if (data.id == 'home') { var $dialog = new Ox.Dialog({ buttons: [ { click: function() { $dialog.close(); }, id: 'close', title: 'Close' } ], height: 498, id: 'home', title: app.options('name'), width: 800 }).open(); } else if (data.id == 'loginlogout') { var $form = new Ox.Form({ error: 'Unknown username or wrong password', id: 'login', items: [ { element: new Ox.Input({ autovalidate: function(value, blur, callback) { var length = value.length; value = $.map(value.toLowerCase().split(''), function(v, i) { if (new RegExp('[a-z0-9' + ((i == 0 || (i == length - 1 && blur)) ? '' : '\- ') + ']')(v)) { return v } else { return null; } }).join(''); $.each(['--', '- ', ' -', '--'], function(i, v) { while (value.indexOf(v) > -1) { value = value.replace(new RegExp(v, 'g'), v[0]); } }) callback(value); }, id: 'username', label: 'Username', labelWidth: 120, validate: function(value, callback) { pandora.api.findUser({ key: 'username', value: value, operator: '=' }, function(result) { Ox.print('result', result) var valid = result.data.users.length == 1; callback({ message: 'Unknown Username', valid: valid }); }); }, width: 300 }) }, { element: new Ox.Input({ id: 'password', label: 'Password', labelWidth: 120, type: 'password', validate: /.+/, width: 300 }) } ], submit: function(data, callback) { pandora.api.login(data, function(result) { if (result.status.code == 200) { $dialog.close(); app.user = result.data.user; app.$ui.mainMenu.getItem('username').options({ title: 'User: ' + app.user.name }); app.$ui.mainMenu.getItem('preferences').options({ disabled: false }); app.$ui.mainMenu.getItem('register').options({ disabled: true }); } else { callback([{ id: 'password', message: 'Incorrect Password' }]); } }); } }) .bindEvent({ validate: function(event, data) { $dialog[(data.valid ? 'enable' : 'disable') + 'Button']('signin'); } }), $dialog = new Ox.Dialog({ buttons: [ [ { click: function() { }, id: 'signup', title: 'Sign up...' }, { click: function() { }, id: 'reset', title: 'Reset Password...' } ], [ { click: function() { $dialog.close(); app.$ui.mainMenu.getItem('loginlogout').toggleTitle(); }, id: 'cancel', title: 'Cancel' }, { click: $form.submit, disabled: true, id: 'signin', title: 'Sign in' } ] ], id: 'login', minWidth: 332, title: 'Sign in', width: 332 }).append($form).open(); } else if (data.id == 'places') { var $manage = new Ox.SplitPanel({ elements: [ { collapsible: true, element: new Ox.SplitPanel({ elements: [ { element: new Ox.Toolbar({ orientation: 'horizontal', size: 44 }).append( app.$ui.findPlacesElement = new Ox.FormElementGroup({ elements: [ app.$ui.findPlacesSelect = new 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(event, data) { app.$ui.findPlacesSelect.loseFocus(); app.$ui.findPlacesInput.options({ placeholder: data.selected[0].title }); } }), app.$ui.findPlacesInput = new Ox.Input({ clear: true, id: 'findPlacesInput', placeholder: 'Find: Name', width: 234 }) ], id: 'findPlacesElement' }) .css({ float: 'left', margin: '4px' }) ).append( app.$ui.sortPlacesSelect = new 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: new Ox.Element('div') }, { element: new Ox.Toolbar({ orientation: 'horizontal', size: 16 }), size: 16 } ], orientation: 'vertical' }), size: 256 }, { element: new Ox.SplitPanel({ elements: [ { element: new Ox.Toolbar({ orientation: 'horizontal', size: 24 }).append( app.$ui.labelsButton = new Ox.Button({ id: 'labelsButton', title: [ {id: 'show', title: 'Show Labels'}, {id: 'hide', title: 'Hide Labels'} ], width: 96 }) .css({ float: 'left', margin: '4px' }) ).append( app.$ui.findMapInput = new Ox.Input({ clear: true, id: 'findMapInput', placeholder: 'Find on Map', width: 192 }) .css({ float: 'right', margin: '4px' }) .bindEvent({ submit: function(event, data) { app.$ui.map.find(data.value, function(location) { app.$ui.placeNameInput.options({ disabled: false, value: location.name }); app.$ui.placeAliasesInput.options({ disabled: false }); app.$ui.placeGeonameLabel.options({ disabled: false, title: location.names.join(', ') }); app.$ui.removePlaceButton.options({ disabled: false }); app.$ui.addPlaceButton.options({ disabled: false }); }); } }) ), size: 24 }, { element: app.$ui.map = new 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) { app.$ui.placeNameInput.options({ disabled: false, value: location.name }); app.$ui.placeAliasesInput.options({ disabled: false }); app.$ui.placeGeonameLabel.options({ disabled: false, title: location.names.join(', ') }); app.$ui.removePlaceButton.options({ disabled: false }); app.$ui.addPlaceButton.options({ disabled: false }); } }) }, { element: app.$ui.bottomBar = new Ox.Toolbar({ orientation: 'horizontal', size: 24 }) .append( app.$ui.placeNameInput = new Ox.Input({ disabled: true, id: 'placeName', placeholder: 'Name', width: 128 }) .css({ float: 'left', margin: '4px 0 0 4px' }) ) .append( app.$ui.placeAliasesInput = new Ox.Input({ disabled: true, id: 'aliases', placeholder: 'Aliases', width: 128 }) .css({ float: 'left', margin: '4px 0 0 4px' }) ) .append( app.$ui.placeGeonameLabel = new Ox.Label({ disabled: true, id: 'placeGeoname', title: 'Geoname', width: parseInt(app.$document.width() * 0.8) - 256 - 256 - 32 - 24 }) .css({ float: 'left', margin: '4px 0 0 4px' }) ) .append( app.$ui.addPlaceButton = new Ox.Button({ disabled: true, id: 'addPlaceButton', title: 'add', type: 'image' }) .css({ float: 'right', margin: '4px 4px 0 0' }) ) .append( app.$ui.removePlaceButton = new 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 = new Ox.Dialog({ buttons: [ { click: function() { $dialog.close(); }, id: 'close', title: 'Close', value: 'Close' } ], height: parseInt(app.$document.height() * 0.8), id: 'places', minHeight: 400, minWidth: 600, padding: 0, title: 'Manage Places', width: parseInt(app.$document.width() * 0.8) }).css({ overflow: 'hidden' }).append($manage).open(); } } }); } app.constructSectionbar = function() { return new Ox.Bar({ size: 24 }) .append( app.$ui.sectionButtons = new Ox.ButtonGroup({ buttons: [ {id: 'site', title: app.config.site.name}, {id: 'items', title: app.config.itemName.plural}, {id: 'texts', title: 'Texts'}, {id: 'admin', title: 'Admin', type: 'image'} ], id: 'sectionButtons', selectable: true }) .css({ float: 'left', margin: '4px' }) ); } app.constructSections = function() { var $sections = []; $.each(app.user.ui.sections, function(i, id) { var $section = new Ox.CollapsePanel({ id: id, size: 16, title: Ox.getObjectById(app.config.sections, id).title }); $sections.push($section); $section.$content.append( $('
').css({ height: '20px' }).append( $('
').css({ float: 'left', width: '16px', height: '16px', margin: '1px'}).append( $('').attr({ src: 'static/oxjs/build/png/ox.ui.modern/iconFind.png' }).css({ width: '16px', height: '16px', border: 0, background: 'rgb(64, 64, 64)', WebkitBorderRadius: '2px' }) ) ).append( $('
').css({ float: 'left', width: '122px', height: '14px', margin: '2px' }).html('Foo') ).append( $('
').css({ float: 'left', width: '40px', height: '14px', margin: '2px', textAlign: 'right' }).html('23') ) ); }); return $sections; } app.constructStatusbar = function() { return new Ox.Bar({ size: 16 }) .css({ textAlign: 'center' }) .append( new Ox.Element() .css({ marginTop: '2px', fontSize: '9px' }) .append( app.$ui.total = new Ox.Element('span') ) .append( new Ox.Element('span').html(' — ') ) .append( app.$ui.selected = new Ox.Element('span') ) ); } app.constructStatus = function(key, data) { return Ox.toTitleCase(key) + ': ' + [ Ox.formatNumber(data.items) + ' movie' + (data.items != 1 ? 's' : ''), Ox.formatDuration(data.runtime, 'medium'), data.files + ' file' + (data.files != 1 ? 's' : ''), Ox.formatDuration(data.duration, 'short'), Ox.formatValue(data.size, 'B'), Ox.formatValue(data.pixels, 'px') ].join(', '); } app.constructToolbar = function() { return new Ox.Bar({ size: 24 }) .append( app.$ui.groupsButton = new Ox.Button({ id: 'groupsButton', title: [ {id: 'show', title: 'Show Groups'}, {id: 'hide', title: 'Hide Groups'} ], width: 96 }) .css({ float: 'left', margin: '4px' }) ) .append( app.$ui.viewSelect = new Ox.Select({ id: 'viewSelect', items: $.map(app.config.listViews, function(view, i) { view.title = 'View ' + view.title return $.extend({ checked: app.user.ui.listView == view.id, }, view); }), width: 144 }) .css({ float: 'left', margin: '4px' }) .bindEvent('change', function(event, data) { var id = data.selected[0].id; app.$ui.mainMenu.checkItem('viewMenu_movies_' + id); //$ui.list.$element.replaceWith(constructList(id)); Ox.print('change ... id', id, list = app.constructList(id), list.options(), list.options('id')) //$ui.contentPanel.replace('list', constructList(id)); app.$ui.contentPanel.replace(1, app.constructList(id)); }) ) .append( app.$ui.findElement = new Ox.FormElementGroup({ elements: [ app.$ui.findSelect = new Ox.Select({ id: 'select', items: $.map(app.config.findKeys, function(key, i) { return { id: key.id, title: 'Find: ' + key.title }; }), overlap: 'right', width: 112 }) .bindEvent('change', function(event, data) { var key = data.selected[0].id; app.user.ui.findQuery.conditions[0].key = key app.$ui.mainMenu.checkItem('findMenu_find_' + key); app.$ui.findInput.focus(); }), app.$ui.findInput = new Ox.Input({ autocomplete: function(value, callback) { var key = 'title'; var findKey = Ox.getObjectById(app.config.findKeys, key); Ox.print('autocomplete', key, value); value === '' && Ox.print('Warning: autocomplete function should never be called with empty value'); if ('autocomplete' in findKey && findKey.autocomplete) { pandora.api.find({ keys: [key], query: { conditions: [ { key: key, value: value, operator: '' } ], operator: '' }, sort: [ { key: key, operator: '' } ], range: [0, 10] }, function(result) { callback($.map(result.data.items, function(v) { return v.title; })); }); } else { callback(); } }, autocompleteSelect: true, autocompleteSelectHighlight: true, autocompleteSelectSubmit: true, clear: true, id: 'input', width: 192 }) .bindEvent('submit', function(event, data) { var key = app.user.ui.findQuery.conditions[0].key, query; Ox.print('key', key); app.user.ui.findQuery.conditions = [ { key: key == 'all' ? '' : key, value: data.value, operator: '' } ]; $.each(app.ui.groups, function(i, group) { group.query.conditions = []; app.$ui.groups[i].options({ request: function(data, callback) { delete data.keys; return pandora.api.find($.extend(data, { group: group.id, query: app.Query.toObject(group.id) }), callback); } }); }); app.$ui.list.options({ request: function(data, callback) { return pandora.api.find($.extend(data, { query: query = app.Query.toObject() }), callback); } }); history.pushState({}, '', '/#' + app.Query.toString(query)); }) ], id: 'findElement' }) .css({ float: 'right', margin: '4px' }) ); } */ /* //FIXME: how to properly overwrite functions without replacing them var super_launch = app.launch; app.launch = function() { app.request.send('hello', function(result) { app.user = result.data.user; if(app.user.group!='guest') { app.menu.getItem('status').options('title', 'User: ' + app.user.username); app.menu.getItem('login').options('title', 'Logout'); } }); super_launch(); }; var loadingIcon = new Ox.LoadingIcon({ size: 'medium' }) .css({ marginLeft: '4px' }); app.menu = new Ox.MainMenu({ extras: [ new Ox.Input({ autocomplete: function(option, value, callback) { var field = option.substring(6).toLowerCase(); if(typeof(callback) == 'undefined') { callback = value; value = null; } Ox.debug('app.menu.find.autocomplete: option: ', option, 'value: ', value, ', callback:',callback); Ox.debug('app.menu.find.autocomplete: field: ', field); if(field == 'all') { callback([]); } else if (value) { value = value.toLowerCase(); //var order = $.inArray(field, ['year', 'date'])?'-':''; app.request.send('find', { query: { conditions: [ { key: field, value: value, operator: '~' } ] }, list: 'all', sort: [{key:field, operator: ''}], keys: [field], range: [0, 10] }, function(result) { var items = $.map( result.data.items, function(item, i) { return item.title; } ); callback(items); }); } }, clear: true, highlight: false, id: 'find', label: [ { id: 'all', title: 'Find: All' }, { id: 'title', title: 'Find: Title' }, { id: 'director', title: 'Find: Director' }, { id: 'country', title: 'Find: Country' }, { id: 'year', title: 'Find: Year' }, { id: 'language', title: 'Find: Language' }, { id: 'writer', title: 'Find: Writer' }, { id: 'producer', title: 'Find: Producer' }, { id: 'cinematographer', title: 'Find: Cinematographer' }, { id: 'editor', title: 'Find: Editor' }, { id: 'actor', title: 'Find: Actor' }, { id: 'character', title: 'Find: Character' }, { id: 'name', title: 'Find: Name' }, { id: 'genre', title: 'Find: Genre' }, { id: 'keyword', title: 'Find: Keyword' }, { id: 'summary', title: 'Find: Summary' }, { id: 'dialog', title: 'Find: Dialog' } ], labelWidth: 96 }).width(320), loadingIcon ], menus: [ { id: 'pandoraMM', title: site.name, items: [ { id: 'about', title: 'About ' + site.name }, {}, { id: 'faq', title: 'Frequently Asked Questions'}, { id: 'tos', title: 'Terms of Service'}, { id: 'sas', title: 'Security Advisory System'}, {}, { id: 'contact', title: 'Contact'}, {}, { id: 'technology', title: 'Technology'}, { id: 'source', title: 'Source Code'}, { id: 'report', title: 'Report a Bug...'}, ] }, { id: 'user', id: 'user', title: 'User', items: [ { id: 'status', title: 'User: not logged in', disabled:true }, {}, { id: 'accunt', title: 'Account', disabled:true}, { id: 'preferences', title: 'Preferences', disabled:true}, {}, {id: 'login', title: 'Login'}, ] }, { id: 'file', title: 'File', items: [ { id: 'load', keyboard: 'control o', title: 'Open' }, { id: 'save', keyboard: 'control a', title: 'Save' }, { id: 'save_ad', keyboard: 'shift control s', title: 'Save As...'} ] }, { id: 'edit', title: 'Edit', items: [ { id: 'undo', keyboard: 'control z', title: 'Undo' }, { id: 'redo', keyboard: 'shift control z', title: 'Redo' }, {}, { id: 'cut', keyboard: 'control x', title: 'Cut' }, { id: 'copy', keyboard: 'control c', title: 'Copy' }, { id: 'paste', keyboard: 'control v', title: 'Paste'}, { id: 'delete', keyboard: 'delete', title: 'Delete'}, {}, { id: 'select_all', keyboard: 'control a', title: 'Select All' }, { id: 'select_none', keyboard: 'shift control a', title: 'Select None' }, { id: 'invert_selection', keyboard: 'alt control a', title: 'Invert Selection' }, ] }, { id: 'sort', title: 'Sort', items: [ { id: 'sort_movies', title: 'Sort Movies by', items: [ { checked: true, group: 'sort_movies', id: 'title', title: 'Title'}, { checked: false, group: 'sort_movies', id: 'director', title: 'Director' }, ] }, { id: 'order_movies', title: 'Order Movies', items: [ { checked: false, group: 'order_movies', id: 'ascending', title: 'Ascending'}, { checked: true, group: 'order_movies', id: 'descending', title: 'Descending' }, ] } ] }, { id: 'help', title: 'Help', items: [ { id: 'help', keyboard: 'control h', title: 'Help' } ] } ], size: 'large' }); function pageDialog(title, page) { //Ox.debug(title, page); var $dialog = new Ox.Dialog({ title: title, buttons: [ { title: 'Close', click: function() { $dialog.close(); } } ] }) .append(page) .open(); }; //this should be: mainMenu.bind('click_about', function(event) { app.menu.bindEvent('click_about', function() { pageDialog('About ' + site.name, site.pages.about); }); app.menu.bindEvent('click_faq', function() { pageDialog(app.menu.getItem('faq').options('title')[0], site.pages.faq); }); app.menu.bindEvent('click_tos', function() { pageDialog(app.menu.getItem('tos').options('title')[0], site.pages.tos); }); app.menu.bindEvent('click_sas', function() { pageDialog(app.menu.getItem('sas').options('title')[0], site.pages.sas); }); OxForm = function(options, self) { var self = self || {}, that = new Ox.Element({}, self) .defaults({ elements: [], }) .options(options || {}) .addClass('OxForm'), length = self.options.elements.length; $.each(self.options.elements, function(i, v) { that.append(Ox.Container().css({'margin': '5px'}).append(v)); }); that.values = function() { var values = {}; $.each(self.options.elements, function(i, v) { values[v.$input.attr('name')] = v.$input.val(); }); return values; } return that; }; app.menu.bindEvent('click_contact', function() { var labelWidth = 64; var inputWidth = 380; var u = new Ox.Input({ label: 'Your Email', labelWidth: labelWidth, name:'email', size: 'medium' }).width(inputWidth).addClass('margin'); if(app.user && app.user.preferences.email) { u.val(app.user.preferences.email); } var form = new OxForm({ elements: [ u, new Ox.Input({ label: 'Subject', labelWidth: labelWidth, name: 'subject', size: 'medium' }).width(inputWidth).addClass('margin'), new Ox.Input({ label: 'Message', labelWidth: labelWidth, type: 'textarea', size: 'medium', name: 'message' }).width(380).height(176).addClass('margin') ] }); var $dialog = new Ox.Dialog({ title: 'Contact', width: 424, height: 320, buttons: [ { value: 'Cancel', click: function() { $dialog.close(); } }, { value: 'Contact', click: function() { app.request.send('contact', form.values(), function(result) { if(result.status.code == 200) { $dialog.close(); } else { $dialog.append(result.status.text); } }); } } ] }) .append(form) .open(); }); app.menu.bindEvent('click_technology', function() { pageDialog(app.menu.getItem('technology').options('title')[0], site.pages.technology); }); app.menu.bindEvent('click_source', function() { pageDialog(app.menu.getItem('source').options('title')[0], site.pages.source); }); app.menu.bindEvent('click_report', function() { pageDialog(app.menu.getItem('report').options('title')[0], site.pages.report); }); app.logout = function () { this.request('logout'); this.user = {}; this.menu.getItem('logout').toggle(); this.menu.getItem('status').options('title', 'User: not logged in'); }; app.menu.bindEvent('click_logout', function(event, data) { app.logout(); }); app.menu.bindEvent('click_login', function(element) { var labelWidth = 64; var inputWidth = labelWidth+200; var loginForm = new OxForm({ elements: [ new Ox.Input({ label: 'Username', labelWidth: labelWidth, name:'username', size: 'medium' }).addClass('margin').width(inputWidth), new Ox.Input({ label: 'Password', labelWidth: labelWidth, name:'password', type: 'password', size: 'medium' }).addClass('margin').width(inputWidth) ] }).css({ 'padding-top': '48px', }); var submit = function() { app.request.send('login', loginForm.values(), function(result) { if(result.status.code == 200) { $dialog.close(); app.user = result.data.user; app.menu.getItem('status').options(title, 'User: ' + app.user.username); app.menu.getItem('login').toggle(); } else { $dialog.append('Login failed ' + result.status.text); } }); } var d = new Ox.Container(); var registerInfo = new Ox.Panel(); registerInfo.append(Ox.Element().css({'margin-left': '4px'}).append('
Forgot your password? Recover Password
Dont have an account? Register Now')); var panel = Ox.SplitPanel({ elements: [ { element: loginForm, }, { element: registerInfo, size: 80 } ], orientation: 'vertical' }).appendTo(d); var $dialog = new Ox.Dialog({ title: 'Login', width: inputWidth+24, height: 184, buttons: [ [],[ { value: 'Cancel', click: function() { $dialog.close(); } }, { value: 'Login', click: submit } ] ] }) .append(d) .open(); }); var bottomPanel = Ox.Toolbar({size: 'small'}) .css({ zIndex: 2, MozBoxShadow: '0 0 4px rgb(0, 0, 0)', WebkitBoxShadow: '0 0 4px rgb(0, 0, 0)' }) .append( $('
') .addClass('bottom') .html(site.url + ' - a rather unique kind of movie database.') ); var mainSplitPanel = Ox.SplitPanel({ elements: [ { element: app.menu, size: 24 }, { element: middleSplitPanel }, { element: bottomPanel, size: 24 } ], orientation: 'vertical' }).appendTo($body); var listPanel = new Ox.CollapsePanel({ title: 'Lists' }).appendTo(sidePanel); listPanel.$content.html('Nouvelle Vague
Hollywood 40\'s
Pirate Cinema Berlin') var historyPanel = new Ox.CollapsePanel({ title: 'Search History' }).appendTo(sidePanel); historyPanel.$content.html('Paris
Matirx
Godard') app.results = new Ox.TextList({ columns: [ { align: 'left', id: 'title', operator: '+', title: 'Title', visible: true, width: 160 }, { align: 'left', id: 'director', operator: '+', title: 'Director', visible: true, width: 160 }, { align: 'right', id: 'year', operator: '-', title: 'Year', visible: true, width: 80 } ], request: function(options) { app.request.send('find', $.extend(options, { query: { conditions: [], operator: ',' // fixme: should be & } }), options.callback); }, id: 'results', sort: [{ key: 'year', operator: '-' }] }).appendTo(content); app.menu.bindEvent('submit_find', function(event, data) { app.results.options({ request: function(options) { app.request.send('find', $.extend(options, { query: { key: data.option.substr(6).toLowerCase(), value: data.value, operator: '~' } }), options.callback); }, }); }); app.launch(); }); */