1
0
Fork 0
mirror of https://github.com/TryGhost/Ghost-Admin.git synced 2023-12-14 02:33:04 +01:00

Form field icons load in default 'grey' state

ref #5652

- validations can be in default, success or error state
- adds check for 'hasValidated' if the validations haven't fired yet, the field is in the default state
- hasValidated is an Ember.Array which tracks the state for each field
This commit is contained in:
Hannah Wolfe 2015-08-27 21:28:41 +01:00
parent d7dda09f1d
commit f9e6bf9835
17 changed files with 71 additions and 39 deletions

View file

@ -13,10 +13,17 @@ export default Ember.Component.extend({
errors: null,
property: '',
hasValidated: Ember.A(),
errorClass: Ember.computed('errors.[]', 'property', function () {
errorClass: Ember.computed('errors.[]', 'property', 'hasValidated.[]', function () {
var property = this.get('property'),
errors = this.get('errors');
errors = this.get('errors'),
hasValidated = this.get('hasValidated');
// If we haven't yet validated this field, there is no validation class needed
if (!hasValidated || !hasValidated.contains(property)) {
return '';
}
if (errors) {
return errors.get(property) ? 'error' : 'success';

View file

@ -34,6 +34,7 @@ export default Ember.Controller.extend(ValidationEngine, {
var credentials = this.getProperties('newPassword', 'ne2Password', 'token'),
self = this;
this.set('flowErrors', '');
this.get('hasValidated').addObjects((['newPassword', 'ne2Password']));
this.validate().then(function () {
self.toggleProperty('submitting');
ajax({

View file

@ -79,8 +79,8 @@ export default Ember.Controller.extend(SettingsSaveMixin, {
},
actions: {
validate: function () {
this.get('model').validate(arguments);
validate: function (property) {
this.get('model').validate({property: property});
},
checkPostsPerPage: function () {

View file

@ -53,6 +53,7 @@ export default Ember.Controller.extend(PaginationMixin, SettingsMenuMixin, {
}
activeTag.set(propKey, newValue);
activeTag.get('hasValidated').addObject(propKey);
activeTag.save().catch(function (error) {
if (error) {

View file

@ -6,6 +6,7 @@ export default Ember.Controller.extend({
two: Ember.inject.controller('setup/two'),
errors: DS.Errors.create(),
hasValidated: Ember.A(),
users: '',
ownerEmail: Ember.computed.alias('two.email'),
submitting: false,
@ -63,17 +64,21 @@ export default Ember.Controller.extend({
validate: function () {
var errors = this.get('errors'),
validationResult = this.get('validationResult');
validationResult = this.get('validationResult'),
property = 'users';
errors.clear();
// If property isn't in the `hasValidated` array, add it to mark that this field can show a validation result
this.get('hasValidated').addObject(property);
if (validationResult === true) { return true; }
validationResult.forEach(function (error) {
// Only one error type here so far, but one day the errors might be more detailed
switch (error.error) {
case 'email':
errors.add('users', error.user + ' is not a valid email.');
errors.add(property, error.user + ' is not a valid email.');
}
});

View file

@ -50,10 +50,10 @@ export default Ember.Controller.extend(ValidationEngine, {
actions: {
preValidate: function (model) {
var self = this;
// Only triggers validation if a value has been entered, preventing empty errors on focusOut
if (this.get(model)) {
if (model === 'email') {
self.send('handleEmail');
this.send('handleEmail');
}
this.validate({property: model});
}
@ -61,7 +61,8 @@ export default Ember.Controller.extend(ValidationEngine, {
setup: function () {
var self = this,
data = self.getProperties('blogTitle', 'name', 'email', 'password', 'image'),
setupProperties = ['blogTitle', 'name', 'email', 'password', 'image'],
data = self.getProperties(setupProperties),
notifications = this.get('notifications'),
config = this.get('config'),
method = this.get('blogCreated') ? 'PUT' : 'POST';
@ -69,6 +70,7 @@ export default Ember.Controller.extend(ValidationEngine, {
this.toggleProperty('submitting');
this.set('flowErrors', '');
this.get('hasValidated').addObjects(setupProperties);
this.validate().then(function () {
ajax({
url: self.get('ghostPaths.url').api('authentication', 'setup'),

View file

@ -5,6 +5,7 @@ import {request as ajax} from 'ic-ajax';
export default Ember.Controller.extend(ValidationEngine, {
submitting: false,
loggingIn: false,
authProperties: ['identification', 'password'],
ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
@ -18,7 +19,7 @@ export default Ember.Controller.extend(ValidationEngine, {
var self = this,
model = this.get('model'),
authStrategy = 'ghost-authenticator:oauth2-password-grant',
data = model.getProperties('identification', 'password');
data = model.getProperties(this.authProperties);
this.get('session').authenticate(authStrategy, data).then(function () {
self.toggleProperty('loggingIn');
@ -28,7 +29,9 @@ export default Ember.Controller.extend(ValidationEngine, {
if (err.errors) {
self.set('flowErrors', err.errors[0].message.string);
if (err.errors[0].message.string.match(/no user with that email/)) {
// this catches both 'no user' and 'user inactive' errors
// long term, we probably need to introduce error codes from the server
if (err.errors[0].message.string.match(/user with that email/)) {
self.get('model.errors').add('identification', '');
}
@ -49,6 +52,8 @@ export default Ember.Controller.extend(ValidationEngine, {
// browsers and password managers that don't send proper events on autofill
$('#login').find('input').trigger('change');
// This is a bit dirty, but there's no other way to ensure the properties are set as well as 'signin'
this.get('hasValidated').addObjects(this.authProperties);
this.validate({property: 'signin'}).then(function () {
self.toggleProperty('loggingIn');
self.send('authenticate');
@ -67,6 +72,8 @@ export default Ember.Controller.extend(ValidationEngine, {
self = this;
this.set('flowErrors', '');
// This is a bit dirty, but there's no other way to ensure the properties are set as well as 'forgotPassword'
this.get('hasValidated').addObject('identification');
this.validate({property: 'forgotPassword'}).then(function () {
self.toggleProperty('submitting');

View file

@ -42,13 +42,15 @@ export default Ember.Controller.extend(ValidationEngine, {
signup: function () {
var self = this,
model = this.get('model'),
data = model.getProperties('name', 'email', 'password', 'token'),
setupProperties = ['name', 'email', 'password', 'token'],
data = model.getProperties(setupProperties),
image = this.get('image'),
notifications = this.get('notifications');
this.set('flowErrors', '');
this.get('hasValidated').addObjects(setupProperties);
this.validate().then(function () {
self.toggleProperty('submitting');
ajax({

View file

@ -42,6 +42,10 @@ export default Ember.Mixin.create({
// ember-data models because they essentially use the same thing
errors: DS.Errors.create(),
// Store whether a property has been validated yet, so that we know whether or not
// to show error / success validation for a field
hasValidated: Ember.A(),
/**
* Passes the model to the validator specified by validationType.
* Returns a promise that will resolve if validation succeeds, and reject if not.
@ -60,7 +64,8 @@ export default Ember.Mixin.create({
var model = this,
type,
validator;
validator,
hasValidated;
if (opts.model) {
model = opts.model;
@ -72,6 +77,7 @@ export default Ember.Mixin.create({
type = this.get('validationType') || model.get('validationType');
validator = this.get('validators.' + type) || model.get('validators.' + type);
hasValidated = this.get('hasValidated');
opts.validationType = type;
@ -83,6 +89,8 @@ export default Ember.Mixin.create({
}
if (opts.property) {
// If property isn't in `hasValidated`, add it to mark that this field can show a validation result
hasValidated.addObject(opts.property);
model.get('errors').remove(opts.property);
} else {
model.get('errors').clear();

View file

@ -2,10 +2,10 @@
<div class="gh-flow-content-wrap">
<section class="gh-flow-content fade-in">
<form id="reset" class="gh-signin" method="post" novalidate="novalidate" {{action "submit" on="submit"}}>
{{#gh-form-group errors=errors property="newPassword"}}
{{#gh-form-group errors=errors hasValidated=hasValidated property="newPassword"}}
{{gh-input type="password" name="newpassword" placeholder="Password" class="password" autocorrect="off" autofocus="autofocus" value=newPassword}}
{{/gh-form-group}}
{{#gh-form-group errors=errors property="ne2Password"}}
{{#gh-form-group errors=errors hasValidated=hasValidated property="ne2Password"}}
{{gh-input type="password" name="ne2password" placeholder="Confirm Password" class="password" autocorrect="off" autofocus="autofocus" value=ne2Password}}
{{/gh-form-group}}

View file

@ -10,14 +10,14 @@
<form id="settings-general" novalidate="novalidate">
<fieldset>
{{#gh-form-group errors=model.errors property="title"}}
{{#gh-form-group errors=model.errors hasValidated=model.hasValidated property="title"}}
<label for="blog-title">Blog Title</label>
{{gh-input id="blog-title" class="gh-input" name="general[title]" type="text" value=model.title focusOut=(action "validate" "title")}}
{{gh-error-message errors=model.errors property="title"}}
<p>The name of your blog</p>
{{/gh-form-group}}
{{#gh-form-group class="description-container" errors=model.errors property="description"}}
{{#gh-form-group errors=model.errors hasValidated=model.hasValidated property="description" class="description-container"}}
<label for="blog-description">Blog Description</label>
{{gh-textarea id="blog-description" class="gh-input" name="general[description]" value=model.description focusOut=(action "validate" "description")}}
{{gh-error-message errors=model.errors property="description"}}
@ -93,7 +93,7 @@
</div>
{{#if model.isPrivate}}
{{#gh-form-group errors=model.errors property="password"}}
{{#gh-form-group errors=model.errors hasValidated=model.hasValidated property="password"}}
{{gh-input name="general[password]" type="text" value=model.password focusOut=(action "validate" "password")}}
{{gh-error-message errors=model.errors property="password"}}
<p>This password will be needed to access your blog. All search engine optimization and social features are now disabled. This password is stored in plaintext.</p>

View file

@ -10,7 +10,7 @@
<div class="settings-menu-content">
{{gh-uploader uploaded="setCoverImage" canceled="clearCoverImage" description="Add tag image" image=activeTag.image initUploader="setUploaderReference" tagName="section"}}
<form>
{{#gh-form-group errors=activeTag.errors property="name"}}
{{#gh-form-group errors=activeTag.errors hasValidated=activeTag.hasValidated property="name"}}
<label for="tag-name">Name</label>
{{gh-input id="tag-name" name="name" type="text" value=activeTagNameScratch focus-out="saveActiveTagName"}}
{{gh-error-message errors=activeTag.errors property="name"}}
@ -55,14 +55,14 @@
<div class="settings-menu-content">
<form>
{{#gh-form-group errors=activeTag.errors property="meta_title"}}
{{#gh-form-group errors=activeTag.errors hasValidated=activeTag.hasValidated property="meta_title"}}
<label for="meta-title">Meta Title</label>
{{gh-input id="meta-title" name="meta_title" type="text" value=activeTagMetaTitleScratch focus-out="saveActiveTagMetaTitle"}}
{{gh-error-message errors=activeTag.errors property="meta_title"}}
<p>Recommended: <b>70</b> characters. Youve used {{gh-count-down-characters activeTagMetaTitleScratch 70}}</p>
{{/gh-form-group}}
{{#gh-form-group errors=activeTag.errors property="meta_description"}}
{{#gh-form-group errors=activeTag.errors hasValidated=activeTag.hasValidated property="meta_description"}}
<label for="meta-description">Meta Description</label>
{{gh-textarea id="meta-description" name="meta_description" value=activeTagMetaDescriptionScratch focus-out="saveActiveTagMetaDescription"}}
{{gh-error-message errors=activeTag.errors property="meta_description"}}

View file

@ -6,8 +6,8 @@
<img class="gh-flow-faces" src="{{gh-path 'admin' 'img/users.png'}}" alt="" />
<form class="gh-flow-invite">
{{#gh-form-group errors=errors property="users"}}
<label>Enter one email address per line, well handle the rest! <i class="icon-mail"></i></label>
{{#gh-form-group errors=errors hasValidated=hasValidated property="users"}}
<label for="users">Enter one email address per line, well handle the rest! <i class="icon-mail"></i></label>
{{gh-textarea name="users" value=users required="required" focusOut=(action "validate")}}
{{/gh-form-group}}

View file

@ -8,28 +8,28 @@
<input style="display:none;" type="password" name="fakepasswordremembered"/>
{{gh-profile-image fileStorage=config.fileStorage email=validEmail setImage="setImage"}}
{{#gh-form-group errors=errors property="email"}}
{{#gh-form-group errors=errors hasValidated=hasValidated property="email"}}
<label for="email-address">Email address</label>
<span class="input-icon icon-mail">
{{gh-trim-focus-input tabindex="1" type="email" name="email" placeholder="Eg. john@example.com" autocorrect="off" value=email focusOut=(action "preValidate" "email")}}
</span>
{{gh-error-message errors=errors property="email"}}
{{/gh-form-group}}
{{#gh-form-group errors=errors property="name"}}
{{#gh-form-group errors=errors hasValidated=hasValidated property="name"}}
<label for="full-name">Full name</label>
<span class="input-icon icon-user">
{{gh-input tabindex="2" type="text" name="name" placeholder="Eg. John H. Watson" autocorrect="off" value=name focusOut=(action "preValidate" "name")}}
</span>
{{gh-error-message errors=errors property="name"}}
{{/gh-form-group}}
{{#gh-form-group errors=errors property="password"}}
{{#gh-form-group errors=errors hasValidated=hasValidated property="password"}}
<label for="password">Password</label>
<span class="input-icon icon-lock">
{{gh-input tabindex="3" type="password" name="password" placeholder="At least 8 characters" autocorrect="off" value=password focusOut=(action "preValidate" "password")}}
</span>
{{gh-error-message errors=errors property="password"}}
{{/gh-form-group}}
{{#gh-form-group errors=errors property="blogTitle"}}
{{#gh-form-group errors=errors hasValidated=hasValidated property="blogTitle"}}
<label for="blog-title">Blog title</label>
<span class="input-icon icon-content">
{{gh-input tabindex="4" type="text" name="blog-title" placeholder="Eg. The Daily Awesome" autocorrect="off" value=blogTitle focusOut=(action "preValidate" "blogTitle")}}

View file

@ -2,12 +2,12 @@
<div class="gh-flow-content-wrap">
<section class="gh-flow-content">
<form id="login" class="gh-signin" method="post" novalidate="novalidate">
{{#gh-form-group errors=model.errors property="identification"}}
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="identification"}}
<span class="input-icon icon-mail">
{{gh-trim-focus-input class="gh-input email" type="email" placeholder="Email Address" name="identification" autocapitalize="off" autocorrect="off" tabindex="1" value=model.identification}}
</span>
{{/gh-form-group}}
{{#gh-form-group errors=model.errors property="password"}}
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="password"}}
<span class="input-icon icon-lock forgotten-wrap">
{{gh-input class="password" type="password" placeholder="Password" name="password" tabindex="2" value=model.password autocorrect="off"}}
{{#gh-spin-button class="forgotten-link btn btn-link" type="button" action="forgotten" tabindex="4" submitting=submitting autoWidth="true"}}Forgot?{{/gh-spin-button}}

View file

@ -12,21 +12,21 @@
<input style="display:none;" type="password" name="fakepasswordremembered"/>
{{gh-profile-image fileStorage=config.fileStorage email=validEmail setImage="setImage"}}
{{#gh-form-group errors=model.errors property="email"}}
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="email"}}
<label for="email-address">Email address</label>
<span class="input-icon icon-mail">
{{gh-input type="email" name="email" placeholder="Eg. john@example.com" enter=(action "signup") disabled="disabled" autocorrect="off" value=model.email focusOut=(action "handleEmail")}}
</span>
{{gh-error-message errors=model.errors property="email"}}
{{/gh-form-group}}
{{#gh-form-group errors=model.errors property="name"}}
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="name"}}
<label for="full-name">Full name</label>
<span class="input-icon icon-user">
{{gh-trim-focus-input tabindex="1" type="text" name="name" placeholder="Eg. John H. Watson" enter=(action "signup") autocorrect="off" value=model.name focusOut=(action "validate" "name")}}
</span>
{{gh-error-message errors=model.errors property="name"}}
{{/gh-form-group}}
{{#gh-form-group errors=model.errors property="password"}}
{{#gh-form-group errors=model.errors hasValidated=hasValidated property="password"}}
<label for="password">Password</label>
<span class="input-icon icon-lock">
{{gh-input tabindex="2" type="password" name="password" enter=(action "signup") autocorrect="off" value=model.password focusOut=(action "validate" "password")}}

View file

@ -53,7 +53,7 @@
<button type="button" {{action "openModal" "upload" user "image"}} class="edit-user-image js-modal-image">Edit Picture</button>
</figure>
{{#gh-form-group class="first-form-group" errors=user.errors property="name"}}
{{#gh-form-group errors=user.errors hasValidated=user.hasValidated property="name" class="first-form-group"}}
<label for="user-name">Full Name</label>
{{input value=user.name id="user-name" class="gh-input user-name" placeholder="Full Name" autocorrect="off" focusOut=(action "validate" "name")}}
{{#if user.errors.name}}
@ -67,14 +67,14 @@
<fieldset class="user-details-bottom">
{{#gh-form-group errors=user.errors property="slug"}}
{{#gh-form-group errors=user.errors hasValidated=user.hasValidated property="slug"}}
<label for="user-slug">Slug</label>
{{gh-input class="gh-input user-name" id="user-slug" value=slugValue name="user" focus-out="updateSlug" placeholder="Slug" selectOnClick="true" autocorrect="off"}}
<p>{{gh-blog-url}}/author/{{slugValue}}</p>
{{gh-error-message errors=user.errors property="slug"}}
{{/gh-form-group}}
{{#gh-form-group errors=user.errors property="email"}}
{{#gh-form-group errors=user.errors hasValidated=user.hasValidated property="email"}}
<label for="user-email">Email</label>
{{!-- Administrators only see text of Owner's email address but not input --}}
{{#unless isAdminUserOnOwnerProfile}}
@ -102,21 +102,21 @@
</div>
{{/if}}
{{#gh-form-group errors=user.errors property="location"}}
{{#gh-form-group errors=user.errors hasValidated=user.hasValidated property="location"}}
<label for="user-location">Location</label>
{{input type="text" value=user.location id="user-location" class="gh-input" focusOut=(action "validate" "location")}}
{{gh-error-message errors=user.errors property="location"}}
<p>Where in the world do you live?</p>
{{/gh-form-group}}
{{#gh-form-group errors=user.errors property="website"}}
{{#gh-form-group errors=user.errors hasValidated=user.hasValidated property="website"}}
<label for="user-website">Website</label>
{{input type="url" value=user.website id="user-website" class="gh-input" autocapitalize="off" autocorrect="off" autocomplete="off" focusOut=(action "validate" "website")}}
{{gh-error-message errors=user.errors property="website"}}
<p>Have a website or blog other than this one? Link it!</p>
{{/gh-form-group}}
{{#gh-form-group class="bio-container" errors=user.errors property="bio"}}
{{#gh-form-group errors=user.errors hasValidated=user.hasValidated property="bio" class="bio-container"}}
<label for="user-bio">Bio</label>
{{textarea id="user-bio" class="gh-input" value=user.bio focusOut=(action "validate" "bio")}}
{{gh-error-message errors=user.errors property="bio"}}
@ -155,6 +155,5 @@
</fieldset>
{{/unless}}
</form>
</div>
</section>