Validation consistency

- introduced validation method in the post and user model
- moved signup validation onto model
- consistent use of validation & error messaging in the admin UI
- helper methods in base view moved to a utils object
This commit is contained in:
Hannah Wolfe 2013-08-20 19:52:44 +01:00
parent 163f88b83d
commit c75286ffb8
5 changed files with 54 additions and 56 deletions

View File

@ -73,7 +73,10 @@
this.removeSubviews();
}
return Backbone.View.prototype.remove.apply(this, arguments);
},
}
});
Ghost.Views.Utils = {
// Used in API request fail handlers to parse a standard api error
// response json for the message to display
@ -115,7 +118,7 @@
}
return vars;
}
});
};
/**
* This is the view to generate the markup for the individual

View File

@ -72,9 +72,9 @@
},
removeItem: function () {
var view = this;
var self = this;
$.when(this.$el.slideUp()).then(function () {
view.remove();
self.remove();
});
},

View File

@ -90,7 +90,7 @@
},
toggleStatus: function () {
var view = this,
var self = this,
keys = Object.keys(this.statusMap),
model = this.model,
prevStatus = this.model.get('status'),
@ -112,10 +112,10 @@
message: 'Your post: ' + model.get('title') + ' has been ' + keys[newIndex],
status: 'passive'
});
}, function (response) {
}, function (xhr) {
var status = keys[newIndex];
// Show a notification about the error
view.reportSaveError(response, model, status);
self.reportSaveError(xhr, model, status);
// Set the button text back to previous
model.set({ status: prevStatus });
});
@ -136,10 +136,9 @@
handleStatus: function (e) {
if (e) { e.preventDefault(); }
var view = this,
status = $(e.currentTarget).attr('data-set-status');
var status = $(e.currentTarget).attr('data-set-status');
view.setActiveStatus(status, this.statusMap[status]);
this.setActiveStatus(status, this.statusMap[status]);
// Dismiss the popup menu
$('body').find('.overlay:visible').fadeOut();
@ -147,8 +146,8 @@
updatePost: function (e) {
if (e) { e.preventDefault(); }
var view = this,
model = view.model,
var self = this,
model = this.model,
$currentTarget = $(e.currentTarget),
status = $currentTarget.attr('data-status'),
prevStatus = model.get('status');
@ -168,7 +167,7 @@
});
}
view.savePost({
this.savePost({
status: status
}).then(function () {
Ghost.notifications.addItem({
@ -176,15 +175,10 @@
message: ['Your post "', model.get('title'), '" has been ', status, '.'].join(''),
status: 'passive'
});
}, function (request) {
var message = view.getRequestErrorMessage(request) || model.validationError;
Ghost.notifications.addItem({
type: 'error',
message: message,
status: 'passive'
});
}, function (xhr) {
// Show a notification about the error
self.reportSaveError(xhr, model, status);
// Set the button text back to previous
model.set({ status: prevStatus });
});
},
@ -214,7 +208,7 @@
if (response) {
// Get message from response
message = this.getErrorMessageFromResponse(response);
message = Ghost.Views.Utils.getRequestErrorMessage(response);
} else if (model.validationError) {
// Grab a validation error
message += "; " + model.validationError;
@ -228,9 +222,7 @@
},
render: function () {
var status = this.model.get('status');
this.setActiveStatus(status, this.statusMap[status]);
this.$('.js-post-button').text(this.statusMap[this.model.get('status')]);
}
});
@ -337,19 +329,21 @@
// Currently gets called on every key press.
// Also trigger word count update
renderPreview: function () {
var view = this,
var self = this,
preview = document.getElementsByClassName('rendered-markdown')[0];
preview.innerHTML = this.converter.makeHtml(this.editor.getValue());
view.$('.js-drop-zone').upload({editor: true});
this.$('.js-drop-zone').upload({editor: true});
Countable.once(preview, function (counter) {
view.$('.entry-word-count').text($.pluralize(counter.words, 'word'));
view.$('.entry-character-count').text($.pluralize(counter.characters, 'character'));
view.$('.entry-paragraph-count').text($.pluralize(counter.paragraphs, 'paragraph'));
self.$('.entry-word-count').text($.pluralize(counter.words, 'word'));
self.$('.entry-character-count').text($.pluralize(counter.characters, 'character'));
self.$('.entry-paragraph-count').text($.pluralize(counter.paragraphs, 'paragraph'));
});
},
// Markdown converter & markdown shortcut initialization.
initMarkdown: function () {
var self = this;
this.converter = new Showdown.converter({extensions: ['ghostdown']});
this.editor = CodeMirror.fromTextArea(document.getElementById('entry-markdown'), {
mode: 'markdown',
@ -359,24 +353,22 @@
dragDrop: false
});
var view = this;
// Inject modal for HTML to be viewed in
shortcut.add("Ctrl+Alt+C", function () {
view.showHTML();
self.showHTML();
});
shortcut.add("Ctrl+Alt+C", function () {
view.showHTML();
self.showHTML();
});
_.each(MarkdownShortcuts, function (combo) {
shortcut.add(combo.key, function () {
return view.editor.addMarkdown({style: combo.style});
return self.editor.addMarkdown({style: combo.style});
});
});
this.editor.on('change', function () {
view.renderPreview();
self.renderPreview();
});
},

View File

@ -52,8 +52,7 @@
event.preventDefault();
var email = this.$el.find('.email').val(),
password = this.$el.find('.password').val(),
redirect = this.getUrlVariables().r,
self = this;
redirect = Ghost.Views.Utils.getUrlVariables().r;
$.ajax({
url: '/ghost/signin/',
@ -66,10 +65,10 @@
success: function (msg) {
window.location.href = msg.redirect;
},
error: function (obj, string, status) {
error: function (xhr) {
Ghost.notifications.addItem({
type: 'error',
message: self.getRequestErrorMessage(obj),
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
status: 'passive'
});
}
@ -88,8 +87,7 @@
submitHandler: function (event) {
event.preventDefault();
var email = this.$el.find('.email').val(),
password = this.$el.find('.password').val(),
self = this;
password = this.$el.find('.password').val();
$.ajax({
url: '/ghost/signup/',
@ -101,10 +99,10 @@
success: function (msg) {
window.location.href = msg.redirect;
},
error: function (obj, string, status) {
error: function (xhr) {
Ghost.notifications.addItem({
type: 'error',
message: self.getRequestErrorMessage(obj),
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
status: 'passive'
});
}

View File

@ -95,15 +95,22 @@
checkboxClass: 'icheckbox_ghost'
});
},
saveSuccess: function () {
saveSuccess: function (model, response, options) {
// TODO: better messaging here?
Ghost.notifications.addItem({
type: 'success',
message: 'Saved',
status: 'passive'
});
},
saveError: function (message) {
message = message || 'Something went wrong, not saved :(';
saveError: function (model, xhr) {
Ghost.notifications.addItem({
type: 'error',
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
status: 'passive'
});
},
validationError: function (message) {
Ghost.notifications.addItem({
type: 'error',
message: message,
@ -210,12 +217,12 @@
ne2Password = this.$('#user-new-password-verification').val();
if (newPassword !== ne2Password) {
this.saveError('The passwords do not match');
this.validationError('Your new passwords do not match');
return;
}
if (newPassword.length < 7) {
this.saveError('The password is not long enough. Have at least 7 characters');
if (newPassword.length < 8) {
this.validationError('Your password is not long enough. It must be at least 8 chars long.');
return;
}
@ -234,14 +241,12 @@
status: 'passive',
id: 'success-98'
});
self.$('#user-password-old').val('');
self.$('#user-password-new').val('');
self.$('#user-new-password-verification').val('');
self.$('#user-password-old, #user-password-new, #user-new-password-verification').val('');
},
error: function (obj, string, status) {
error: function (xhr) {
Ghost.notifications.addItem({
type: 'error',
message: 'Invalid username or password',
message: Ghost.Views.Utils.getRequestErrorMessage(xhr),
status: 'passive'
});
}