merge dev

This commit is contained in:
j 2010-12-27 10:40:59 +05:30
commit a383b5fc77

View file

@ -40,15 +40,18 @@ var pandora = new Ox.App({
function load() { function load() {
Ox.Request.requests() && app.$ui.loadingIcon.start(); $(function() {
Ox.Event.bind('', 'requestStart', function() { var $body = $('body');
Ox.print('requestStart') Ox.Request.requests() && app.$ui.loadingIcon.start();
app.$ui.loadingIcon.start(); $body.bind('requestStart', function() {
}); Ox.print('requestStart')
Ox.Event.bind('', 'requestStop', function() { app.$ui.loadingIcon.start();
Ox.print('requestStop') });
app.$ui.loadingIcon.stop(); $body.bind('requestStop', function() {
}); Ox.print('requestStop')
app.$ui.loadingIcon.stop();
});
});
Query.fromString(location.hash.substr(1)); Query.fromString(location.hash.substr(1));
@ -86,180 +89,309 @@ var pandora = new Ox.App({
function login(data) { function login(data) {
app.user = data.user; app.user = data.user;
//Ox.Event.unbindAll();
app.$ui.appPanel.reload(); app.$ui.appPanel.reload();
} }
function logout(data) { function logout(data) {
app.user = data.user; app.user = data.user;
//Ox.Event.unbindAll();
app.$ui.appPanel.reload(); app.$ui.appPanel.reload();
} }
var ui = { 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) { accountDialog: function(action) {
var buttonTitle = { var that = new Ox.Dialog($.extend({
login: 'Login', height: 256,
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,
id: 'accountDialog', id: 'accountDialog',
minHeight: 200, minHeight: 256,
minWidth: 400, minWidth: 384,
title: title[action], width: 384
width: 400 }, ui.accountDialogOptions(action)))
})
.bindEvent({ .bindEvent({
resize: function(event, data) { resize: function(event, data) {
var width = data.width - 32; var width = data.width - 32;
app.$ui.accountForm.items.forEach(function(item) { app.$ui.accountForm.items.forEach(function(item) {
item.options({width: width}) item.options({width: width});
}); });
} }
}); });
function button(type) { return that;
if (type == 'cancel') { },
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({ return new Ox.Button({
id: 'cancel', id: 'cancel' + Ox.toTitleCase(action),
title: 'Cancel' title: 'Cancel'
}).bindEvent('click', function() { }).bindEvent('click', function() {
that.close(); app.$ui.accountDialog.close();
}) });
} else if (type == 'submit') { } else if (type == 'submit') {
return new Ox.Button({ return new Ox.Button({
disabled: true, disabled: true,
id: 'submit', id: 'submit' + Ox.toTitleCase(action),
title: buttonTitle[action] title: buttonTitle[action]
}).bindEvent('click', function() { }).bindEvent('click', function() {
app.$ui.accountForm.submit() app.$ui.accountForm.submit();
}) });
} else { } else {
return new Ox.Button({ return new Ox.Button({
id: type, id: type,
title: title[type] + '...' title: buttonTitle[type] + '...'
}).bindEvent('click', function() { }).bindEvent('click', function() {
action = type; Ox.print('CLICK EVENT', type)
that.options({ app.$ui.accountDialog.options(ui.accountDialogOptions(type));
buttons: [
$.map(buttons[type], function(v) {
return button(v);
}),
[button('cancel'), button('submit')]
],
content: app.$ui.accountForm = ui.accountForm(type),
title: title[type]
});
}); });
} }
} }
return that; return {
}, buttons: [
accountEmailInput: function() { $.map(buttons[action], function(type) {
return new Ox.Input({ return button(type);
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};
}), }),
[button('cancel'), button('submit')]
],
content: new Ox.Element('div')
.append(
new Ox.Element('div')
.addClass('OxText')
.html(dialogText[action] + '<br/><br/>')
)
.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) { submit: function(data, callback) {
pandora.api.login(data, function(result) { if (action == 'login') {
if (!result.data.errors) { pandora.api.login(data, function(result) {
app.$ui.accountDialog.close(); if (!result.data.errors) {
login(result.data); app.$ui.accountDialog.close();
} else { login(result.data);
callback([{id: 'password', message: 'Incorrect Password'}]); } 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,
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({
.bindEvent({
submit: function(event, data) { submit: function(event, data) {
}, },
validate: 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; return that;
}, },
accountLogoutDialog: function() { accountLogoutDialog: function() {
@ -273,7 +405,7 @@ var pandora = new Ox.App({
app.$ui.mainMenu.getItem('loginlogout').toggleTitle(); app.$ui.mainMenu.getItem('loginlogout').toggleTitle();
}), }),
new Ox.Button({ new Ox.Button({
id: 'submit', id: 'logout',
title: 'Logout' title: 'Logout'
}).bindEvent('click', function() { }).bindEvent('click', function() {
that.close(); that.close();
@ -282,86 +414,41 @@ var pandora = new Ox.App({
}); });
}) })
], ],
content: new Ox.Element('div').html('Are you sure you want to logout?'),
height: 160, height: 160,
keys: {enter: 'logout', escape: 'cancel'},
title: 'Logout', title: 'Logout',
width: 300 width: 300
}) });
.append(
new Ox.Element('div')
.html('Are you sure you want to logout?')
)
return that; return that;
}, },
accountPasswordInput: function() { accountWelcomeDialog: function() {
return new Ox.Input({ var that = new Ox.Dialog({
autovalidate: /.+/, buttons: [
id: 'password', [
label: 'Password', new Ox.Button({
labelWidth: 100, id: 'preferences',
type: 'password', title: 'Preferences...'
validate: function(value, callback) { }).bindEvent('click', function() {
callback({ that.close();
message: 'Missing Password', })
valid: value.length > 0 ],
}); [
}, new Ox.Button({
width: 368 id: 'close',
}); title: 'Close'
}, }).bindEvent('click', function() {
accountUsernameInput: function() { that.close();
return new Ox.Input({ })
autovalidate: function(value, blur, callback) { ]
var length = value.length; ],
value = $.map(value.toLowerCase().split(''), function(v, i) { content: new Ox.Element('div').html('Welcome, ' + app.user.username + '!<br/><br/>Your account has been created.'),
if (new RegExp('[a-z0-9' + ((i == 0 || (i == length - 1 && blur)) ? '' : '\-_') + ']')(v)) { height: 160,
return v keys: {enter: 'close', escape: 'close'},
} else { title: 'Welcome to ' + app.config.site.name,
return null; width: 300
} });
}).join(''); return that;
$.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
});
}, },
annotations: function() { annotations: function() {
var that = new Ox.Element(), var that = new Ox.Element(),
@ -410,9 +497,7 @@ var pandora = new Ox.App({
return that; return that;
} }
that.reload = function() { that.reload = function() {
$.each($elements, function(i, $element) { app.$ui.appPanel.remove();
$element.remove();
});
app.$ui.appPanel = ui.appPanel().appendTo(app.$ui.body); app.$ui.appPanel = ui.appPanel().appendTo(app.$ui.body);
return that; return that;
} }
@ -498,7 +583,11 @@ var pandora = new Ox.App({
}) })
.bindEvent('change', function(event, data) { .bindEvent('change', function(event, data) {
var key = data.selected[0].id; 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.mainMenu.checkItem('findMenu_find_' + key);
app.$ui.findInput.focus(); app.$ui.findInput.focus();
}), }),
@ -1201,15 +1290,17 @@ var pandora = new Ox.App({
}); });
app.$ui.previewDialog = new Ox.Dialog({ app.$ui.previewDialog = new Ox.Dialog({
buttons: [ buttons: [
{ new Ox.Button({
title: 'Close', title: 'Close',
}).bindEvent({
click: function() { click: function() {
app.$ui.previewDialog.close(); app.$ui.previewDialog.close();
delete app.$ui.previewDialog; delete app.$ui.previewDialog;
app.$ui.list.closePreview(); app.$ui.list.closePreview();
} }
} })
], ],
content: app.$ui.previewImage,
height: dialogHeight, height: dialogHeight,
id: 'previewDialog', id: 'previewDialog',
minHeight: app.ui.previewRatio >= 1 ? 128 / app.ui.previewRatio + 48 : 176, minHeight: app.ui.previewRatio >= 1 ? 128 / app.ui.previewRatio + 48 : 176,
@ -1218,7 +1309,6 @@ var pandora = new Ox.App({
title: title, title: title,
width: dialogWidth width: dialogWidth
}) })
.append(app.$ui.previewImage)
.bindEvent('resize', function(event, data) { .bindEvent('resize', function(event, data) {
var dialogRatio = data.width / (data.height - 48), var dialogRatio = data.width / (data.height - 48),
height, width; height, width;
@ -1531,6 +1621,7 @@ var pandora = new Ox.App({
var id = data.checked[0].id, var id = data.checked[0].id,
operator = Ox.getObjectById(app.config.sortKeys, id).operator; operator = Ox.getObjectById(app.config.sortKeys, id).operator;
app.$ui.mainMenu.checkItem('sortMenu_ordermovies_' + (operator === '' ? 'ascending' : 'descending')); app.$ui.mainMenu.checkItem('sortMenu_ordermovies_' + (operator === '' ? 'ascending' : 'descending'));
app.$ui.sortSelect.selectItem(id);
app.$ui.list.sortList(id, operator); app.$ui.list.sortList(id, operator);
} else if (data.id == 'viewmovies') { } else if (data.id == 'viewmovies') {
var view = data.checked[0].id; var view = data.checked[0].id;
@ -1541,13 +1632,14 @@ var pandora = new Ox.App({
if (data.id == 'about') { if (data.id == 'about') {
var $dialog = new Ox.Dialog({ var $dialog = new Ox.Dialog({
buttons: [ buttons: [
{ new Ox.Button({
click: function() {
$dialog.close();
},
id: 'close', id: 'close',
title: 'Close' title: 'Close'
} }).bindEvent({
click: function() {
$dialog.close();
}
})
], ],
id: 'about', id: 'about',
title: 'About' title: 'About'
@ -1555,16 +1647,18 @@ var pandora = new Ox.App({
} else if (data.id == 'home') { } else if (data.id == 'home') {
var $dialog = new Ox.Dialog({ var $dialog = new Ox.Dialog({
buttons: [ buttons: [
{ new Ox.Button({
click: function() {
$dialog.close();
},
id: 'close', id: 'close',
title: 'Close' title: 'Close'
} }).bindEvent({
click: function() {
$dialog.close();
}
})
], ],
height: 498, height: 498,
id: 'home', id: 'home',
keys: {enter: 'close', escape: 'close'},
title: app.config.site.name, title: app.config.site.name,
width: 800 width: 800
}).open(); }).open();
@ -1994,6 +2088,32 @@ var pandora = new Ox.App({
}); });
return that; 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 = Ox.getObjectById(app.config.sortKeys, id).operator;
app.user.ui.listView = id;
app.$ui.mainMenu.checkItem('sortMenu_sortmovies_' + id);
app.$ui.mainMenu.checkItem('sortMenu_ordermovies_' + (operator === '' ? 'ascending' : 'descending'));
app.$ui.list.sortList(id, operator);
});
return that;
},
status: function(key, data) { status: function(key, data) {
var that = Ox.toTitleCase(key) + ': ' + [ var that = Ox.toTitleCase(key) + ': ' + [
Ox.formatNumber(data.items) + ' movie' + (data.items != 1 ? 's' : ''), Ox.formatNumber(data.items) + ' movie' + (data.items != 1 ? 's' : ''),
@ -2037,6 +2157,9 @@ var pandora = new Ox.App({
.append( .append(
app.$ui.viewSelect = ui.viewSelect() app.$ui.viewSelect = ui.viewSelect()
) )
.append(
app.$ui.sortSelect = ui.sortSelect()
)
.append( .append(
app.$ui.findElement = ui.findElement() app.$ui.findElement = ui.findElement()
); );
@ -2048,7 +2171,7 @@ var pandora = new Ox.App({
viewSelect: function() { viewSelect: function() {
var that = new Ox.Select({ var that = new Ox.Select({
id: 'viewSelect', id: 'viewSelect',
items: $.map(app.config.listViews, function(view, i) { items: $.map(app.config.listViews, function(view) {
return $.extend($.extend({}, view), { return $.extend($.extend({}, view), {
checked: app.user.ui.listView == view.id, checked: app.user.ui.listView == view.id,
title: 'View ' + view.title title: 'View ' + view.title
@ -2058,7 +2181,7 @@ var pandora = new Ox.App({
}) })
.css({ .css({
float: 'left', float: 'left',
margin: '4px' margin: '4px 0 0 4px'
}) })
.bindEvent('change', function(event, data) { .bindEvent('change', function(event, data) {
var id = data.selected[0].id; var id = data.selected[0].id;
@ -2070,6 +2193,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) { function getGroupWidth(pos, panelWidth) {
var width = {}; var width = {};
width.list = Math.floor(panelWidth / 5) + (panelWidth % 5 > pos); width.list = Math.floor(panelWidth / 5) + (panelWidth % 5 > pos);
@ -2089,6 +2243,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() { var Query = (function() {
function constructFind(query) { function constructFind(query) {