diff --git a/static/js/pandora.js b/static/js/pandora.js
index f02f541a..da73f41b 100755
--- a/static/js/pandora.js
+++ b/static/js/pandora.js
@@ -40,15 +40,18 @@ var pandora = new Ox.App({
function load() {
- Ox.Request.requests() && app.$ui.loadingIcon.start();
- Ox.Event.bind('', 'requestStart', function() {
- Ox.print('requestStart')
- app.$ui.loadingIcon.start();
- });
- Ox.Event.bind('', 'requestStop', function() {
- Ox.print('requestStop')
- app.$ui.loadingIcon.stop();
- });
+ $(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));
@@ -86,180 +89,308 @@ var pandora = new Ox.App({
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 = {
- accountCodeInput: function() {
- return new Ox.Input({
- id: 'code',
- label: 'Code',
- labelWidth: 100,
- validate: function(value, callback) {
- callback({
- message: 'Missing Code',
- valid: value.length > 0
- });
- },
- width: 368
- });
- },
accountDialog: function(action) {
- var buttonTitle = {
- login: 'Login',
- register: 'Register',
- reset: 'Reset Password',
- resetlogin: 'Reset Password and Login'
- },
- buttons = {
- login: ['register', 'reset'],
- register: ['login'],
- reset: ['login'],
- resetlogin: ['login']
- },
- text = {
- login: '',
- register: '',
- reset: 'To reset your password, please enter your username or e-mail address.',
- resetlogin: 'To login to your account, please choose a new password, and enter the code that we have e-mailed you.'
- },
- title = {
- login: 'Login',
- register: 'Register',
- reset: 'Reset Password',
- resetlogin: 'Reset Password'
- };
- var that = new Ox.Dialog({
- buttons: [
- $.map(buttons[action], function(v) {
- return button(v);
- }),
- [button('cancel'), button('submit')]
- ],
- content: app.$ui.accountForm = ui.accountForm(action),
- height: 200,
+ var that = new Ox.Dialog($.extend({
+ height: 256,
id: 'accountDialog',
- minHeight: 200,
- minWidth: 400,
- title: title[action],
- width: 400
- })
+ 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})
+ item.options({width: width});
});
}
});
- function button(type) {
- if (type == 'cancel') {
+ 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',
+ id: 'cancel' + Ox.toTitleCase(action),
title: 'Cancel'
}).bindEvent('click', function() {
- that.close();
- })
+ app.$ui.accountDialog.close();
+ });
} else if (type == 'submit') {
return new Ox.Button({
disabled: true,
- id: 'submit',
+ id: 'submit' + Ox.toTitleCase(action),
title: buttonTitle[action]
}).bindEvent('click', function() {
- app.$ui.accountForm.submit()
- })
+ app.$ui.accountForm.submit();
+ });
} else {
return new Ox.Button({
id: type,
- title: title[type] + '...'
+ title: buttonTitle[type] + '...'
}).bindEvent('click', function() {
- action = type;
- that.options({
- buttons: [
- $.map(buttons[type], function(v) {
- return button(v);
- }),
- [button('cancel'), button('submit')]
- ],
- content: app.$ui.accountForm = ui.accountForm(type),
- title: title[type]
- });
+ Ox.print('CLICK EVENT', type)
+ app.$ui.accountDialog.options(ui.accountDialogOptions(type));
});
}
- }
- return that;
- },
- accountEmailInput: function() {
- return new Ox.Input({
- id: 'email',
- label: 'E-Mail Address',
- labelWidth: 100,
- type: 'email',
- validate: function(value, callback) {
- callback({
- message: 'Missing E-Mail Address',
- valid: value.length > 0
- });
- },
- width: 368
- });
- },
- accountForm: function(action) {
- app.$ui.codeInput = ui.accountEmailInput();
- app.$ui.emailInput = ui.accountEmailInput();
- app.$ui.passwordInput = ui.accountPasswordInput();
- app.$ui.usernameInput = ui.accountUsernameInput();
- app.$ui.usernameOrEmailInput = ui.accountUsernameOrEmailInput();
- var items = {
- 'login': [
- app.$ui.usernameInput,
- app.$ui.passwordInput
- ],
- 'register': [
- app.$ui.usernameInput,
- app.$ui.passwordInput,
- app.$ui.emailInput
- ],
- 'reset': [
- app.$ui.usernameOrEmailInput
- ],
- 'resetlogin': [
- app.$ui.usernameInput,
- app.$ui.passwordInput,
- app.$ui.codeInput
- ]
- },
- that = new Ox.Form({
- error: 'Unknown username or wrong password',
- id: 'accountForm',
- items: $.map(items[action], function(v, i) {
- return {element: v};
+ }
+ 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) {
- pandora.api.login(data, function(result) {
- if (!result.data.errors) {
- app.$ui.accountDialog.close();
- login(result.data);
- } else {
- callback([{id: 'password', message: 'Incorrect Password'}]);
- }
- });
+ if (action == 'login') {
+ pandora.api.login(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.register(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;
+ data = {};
+ data[usernameOrEmail[0].id] = 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: result.data.errors.username_or_email}])
+ }
+ });
+ } 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({
+ }).bindEvent({
submit: function(event, data) {
},
validate: function(event, data) {
- app.$ui.accountDialog[(data.valid ? 'enable' : 'disable') + 'Button']('submit');
+ Ox.print('FORM VALIDATE', data)
+ app.$ui.accountDialog[
+ (data.valid ? 'enable' : 'disable') + 'Button'
+ ]('submit' + Ox.toTitleCase(action));
}
});
- that.items = items[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() {
@@ -273,7 +404,7 @@ var pandora = new Ox.App({
app.$ui.mainMenu.getItem('loginlogout').toggleTitle();
}),
new Ox.Button({
- id: 'submit',
+ id: 'logout',
title: 'Logout'
}).bindEvent('click', function() {
that.close();
@@ -282,86 +413,41 @@ var pandora = new Ox.App({
});
})
],
+ content: new Ox.Element('div').html('Are you sure you want to logout?'),
height: 160,
+ keys: {enter: 'logout', escape: 'cancel'},
title: 'Logout',
width: 300
- })
- .append(
- new Ox.Element('div')
- .html('Are you sure you want to logout?')
- )
+ });
return that;
},
- accountPasswordInput: function() {
- return new Ox.Input({
- autovalidate: /.+/,
- id: 'password',
- label: 'Password',
- labelWidth: 100,
- type: 'password',
- validate: function(value, callback) {
- callback({
- message: 'Missing Password',
- valid: value.length > 0
- });
- },
- width: 368
- });
- },
- accountUsernameInput: function() {
- return 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: 100,
- validate: function(value, callback) {
- !value.length ? callback({
- message: 'Missing Username',
- valid: false
- }) : 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: 368
- });
- },
- accountUsernameOrEmailInput: function() {
- return new Ox.Input({
- id: 'email',
- label: 'Username or E-Mail Address',
- labelWidth: 184,
- validate: function(value, callback) {
- callback({
- message: 'Missing Username or E-Mail Address',
- valid: value.length > 0
- });
- },
- width: 368
- });
+ 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(),
@@ -410,9 +496,7 @@ var pandora = new Ox.App({
return that;
}
that.reload = function() {
- $.each($elements, function(i, $element) {
- $element.remove();
- });
+ app.$ui.appPanel.remove();
app.$ui.appPanel = ui.appPanel().appendTo(app.$ui.body);
return that;
}
@@ -498,7 +582,11 @@ var pandora = new Ox.App({
})
.bindEvent('change', function(event, data) {
var key = data.selected[0].id;
- app.user.ui.findQuery.conditions[0].key = key
+ 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.focus();
}),
@@ -1201,15 +1289,17 @@ var pandora = new Ox.App({
});
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,
@@ -1218,7 +1308,6 @@ var pandora = new Ox.App({
title: title,
width: dialogWidth
})
- .append(app.$ui.previewImage)
.bindEvent('resize', function(event, data) {
var dialogRatio = data.width / (data.height - 48),
height, width;
@@ -1541,13 +1630,14 @@ var pandora = new Ox.App({
if (data.id == 'about') {
var $dialog = new Ox.Dialog({
buttons: [
- {
+ new Ox.Button({
+ id: 'closeAbout',
+ title: 'Close'
+ }).bindEvent({
click: function() {
$dialog.close();
- },
- id: 'close',
- title: 'Close'
- }
+ }
+ })
],
id: 'about',
title: 'About'
@@ -1555,13 +1645,14 @@ var pandora = new Ox.App({
} else if (data.id == 'home') {
var $dialog = new Ox.Dialog({
buttons: [
- {
+ new Ox.Button({
+ id: 'closeHome',
+ title: 'Close'
+ }).bindEvent({
click: function() {
$dialog.close();
- },
- id: 'close',
- title: 'Close'
- }
+ }
+ })
],
height: 498,
id: 'home',
@@ -2070,6 +2161,37 @@ var pandora = new Ox.App({
}
}
+ 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 getGroupWidth(pos, panelWidth) {
var width = {};
width.list = Math.floor(panelWidth / 5) + (panelWidth % 5 > pos);
@@ -2089,6 +2211,31 @@ var pandora = new Ox.App({
});
}
+ 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) {