Skip to content

Commit

Permalink
add spin-button component & implement it
Browse files Browse the repository at this point in the history
closes #3928
- adds spin-button component & styles
- implements spin-button in places where buttons trigger async tasks
  • Loading branch information
acburdine committed Aug 10, 2015
1 parent 026e3de commit 748895c
Show file tree
Hide file tree
Showing 32 changed files with 286 additions and 123 deletions.
1 change: 1 addition & 0 deletions core/client/app/components/gh-editor-save-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default Ember.Component.extend({
isPublished: null,
willPublish: null,
postOrPage: null,
submitting: false,

// Tracks whether we're going to change the state of the post on save
isDangerous: Ember.computed('isPublished', 'willPublish', function () {
Expand Down
38 changes: 38 additions & 0 deletions core/client/app/components/gh-spin-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Ember from 'ember';

export default Ember.Component.extend({
tagName: 'button',
buttonText: '',
submitting: false,
autoWidth: true,

// Disable Button when isLoading equals true
attributeBindings: ['disabled'],

// Must be set on the controller
disabled: Ember.computed.equal('submitting', true),

click: function () {
if (this.get('action')) {
this.sendAction('action');
return false;
}
return true;
},

setSize: function () {
if (!this.get('submitting') && this.get('autoWidth')) {
// this exists so that the spinner doesn't change the size of the button
this.$().width(this.$().width()); // sets width of button
this.$().height(this.$().height()); // sets height of button
}
},

width: Ember.observer('buttonText', 'autoWidth', function () {
this.setSize();
}),

didInsertElement: function () {
this.setSize();
}
});
4 changes: 4 additions & 0 deletions core/client/app/controllers/modals/signin.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ValidationEngine from 'ghost/mixins/validation-engine';

export default Ember.Controller.extend(ValidationEngine, {
validationType: 'signin',
submitting: false,

application: Ember.inject.controller(),
notifications: Ember.inject.service(),
Expand All @@ -28,13 +29,16 @@ export default Ember.Controller.extend(ValidationEngine, {
// it needs to be caught so it doesn't generate an exception in the console,
// but it's actually "handled" by the sessionAuthenticationFailed action handler.
}).finally(function () {
self.toggleProperty('submitting');
appController.set('skipAuthSuccessHandler', undefined);
});
},

validateAndAuthenticate: function () {
var self = this;

this.toggleProperty('submitting');

// Manually trigger events for input fields, ensuring legacy compatibility with
// browsers and password managers that don't send proper events on autofill
$('#login').find('input').trigger('change');
Expand Down
17 changes: 7 additions & 10 deletions core/client/app/controllers/settings/code-injection.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import Ember from 'ember';
import SettingsSaveMixin from 'ghost/mixins/settings-save';

export default Ember.Controller.extend({
export default Ember.Controller.extend(SettingsSaveMixin, {
notifications: Ember.inject.service(),

actions: {
save: function () {
var notifications = this.get('notifications');
save: function () {
var notifications = this.get('notifications');

return this.get('model').save().then(function (model) {
return model;
}).catch(function (error) {
notifications.showAPIError(error);
});
}
return this.get('model').save().catch(function (error) {
notifications.showAPIError(error);
});
}
});
33 changes: 17 additions & 16 deletions core/client/app/controllers/settings/general.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Ember from 'ember';
import SettingsSaveMixin from 'ghost/mixins/settings-save';
import randomPassword from 'ghost/utils/random-password';

export default Ember.Controller.extend({
export default Ember.Controller.extend(SettingsSaveMixin, {
notifications: Ember.inject.service(),
config: Ember.inject.service(),

Expand Down Expand Up @@ -62,24 +63,24 @@ export default Ember.Controller.extend({
}
}),

actions: {
validate: function () {
this.get('model').validate(arguments);
},
save: function () {
var notifications = this.get('notifications'),
config = this.get('config');

save: function () {
var notifications = this.get('notifications'),
config = this.get('config');
return this.get('model').save().then(function (model) {
config.set('blogTitle', model.get('title'));

return this.get('model').save().then(function (model) {
config.set('blogTitle', model.get('title'));
return model;
}).catch(function (error) {
if (error) {
notifications.showAPIError(error);
}
});
},

return model;
}).catch(function (error) {
if (error) {
notifications.showAPIError(error);
}
});
actions: {
validate: function () {
this.get('model').validate(arguments);
},

checkPostsPerPage: function () {
Expand Down
8 changes: 7 additions & 1 deletion core/client/app/controllers/settings/labs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {request as ajax} from 'ic-ajax';
export default Ember.Controller.extend({
uploadButtonText: 'Import',
importErrors: '',
submitting: false,

ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
Expand Down Expand Up @@ -78,18 +79,23 @@ export default Ember.Controller.extend({
},

sendTestEmail: function () {
var notifications = this.get('notifications');
var notifications = this.get('notifications'),
self = this;

this.toggleProperty('submitting');

ajax(this.get('ghostPaths.url').api('mail', 'test'), {
type: 'POST'
}).then(function () {
notifications.showAlert('Check your email for the test message.', {type: 'info'});
self.toggleProperty('submitting');
}).catch(function (error) {
if (typeof error.jqXHR !== 'undefined') {
notifications.showAPIError(error);
} else {
notifications.showErrors(error);
}
self.toggleProperty('submitting');
});
}
}
Expand Down
121 changes: 61 additions & 60 deletions core/client/app/controllers/settings/navigation.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Ember from 'ember';
import SettingsSaveMixin from 'ghost/mixins/settings-save';

var NavItem = Ember.Object.extend({
label: '',
Expand All @@ -10,7 +11,7 @@ var NavItem = Ember.Object.extend({
})
});

export default Ember.Controller.extend({
export default Ember.Controller.extend(SettingsSaveMixin, {
config: Ember.inject.service(),
notifications: Ember.inject.service(),

Expand Down Expand Up @@ -54,6 +55,65 @@ export default Ember.Controller.extend({
});
}),

save: function () {
var navSetting,
blogUrl = this.get('config').blogUrl,
blogUrlRegex = new RegExp('^' + blogUrl + '(.*)', 'i'),
navItems = this.get('navigationItems'),
message = 'One of your navigation items has an empty label. ' +
'<br /> Please enter a new label or delete the item before saving.',
match,
notifications = this.get('notifications');

// Don't save if there's a blank label.
if (navItems.find(function (item) {return !item.get('isComplete') && !item.get('last');})) {
notifications.showAlert(message.htmlSafe(), {type: 'error'});
return;
}

navSetting = navItems.map(function (item) {
var label,
url;

if (!item || !item.get('isComplete')) {
return;
}

label = item.get('label').trim();
url = item.get('url').trim();

// is this an internal URL?
match = url.match(blogUrlRegex);

if (match) {
url = match[1];

// if the last char is not a slash, then add one,
// as long as there is no # or . in the URL (anchor or file extension)
// this also handles the empty case for the homepage
if (url[url.length - 1] !== '/' && url.indexOf('#') === -1 && url.indexOf('.') === -1) {
url += '/';
}
} else if (!validator.isURL(url) && url !== '' && url[0] !== '/' && url.indexOf('mailto:') !== 0) {
url = '/' + url;
}

return {label: label, url: url};
}).compact();

this.set('model.navigation', JSON.stringify(navSetting));

// trigger change event because even if the final JSON is unchanged
// we need to have navigationItems recomputed.
this.get('model').notifyPropertyChange('navigation');

notifications.closeNotifications();

return this.get('model').save().catch(function (err) {
notifications.showErrors(err);
});
},

actions: {
addItem: function () {
var navItems = this.get('navigationItems'),
Expand Down Expand Up @@ -94,65 +154,6 @@ export default Ember.Controller.extend({
}

navItem.set('url', url);
},

save: function () {
var navSetting,
blogUrl = this.get('config').blogUrl,
blogUrlRegex = new RegExp('^' + blogUrl + '(.*)', 'i'),
navItems = this.get('navigationItems'),
message = 'One of your navigation items has an empty label. ' +
'<br /> Please enter a new label or delete the item before saving.',
match,
notifications = this.get('notifications');

// Don't save if there's a blank label.
if (navItems.find(function (item) {return !item.get('isComplete') && !item.get('last');})) {
notifications.showAlert(message.htmlSafe(), {type: 'error'});
return;
}

navSetting = navItems.map(function (item) {
var label,
url;

if (!item || !item.get('isComplete')) {
return;
}

label = item.get('label').trim();
url = item.get('url').trim();

// is this an internal URL?
match = url.match(blogUrlRegex);

if (match) {
url = match[1];

// if the last char is not a slash, then add one,
// as long as there is no # or . in the URL (anchor or file extension)
// this also handles the empty case for the homepage
if (url[url.length - 1] !== '/' && url.indexOf('#') === -1 && url.indexOf('.') === -1) {
url += '/';
}
} else if (!validator.isURL(url) && url !== '' && url[0] !== '/' && url.indexOf('mailto:') !== 0) {
url = '/' + url;
}

return {label: label, url: url};
}).compact();

this.set('model.navigation', JSON.stringify(navSetting));

// trigger change event because even if the final JSON is unchanged
// we need to have navigationItems recomputed.
this.get('model').notifyPropertyChange('navigation');

notifications.closeNotifications();

this.get('model').save().catch(function (err) {
notifications.showErrors(err);
});
}
}
});
4 changes: 4 additions & 0 deletions core/client/app/controllers/setup/three.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default Ember.Controller.extend({
users: '',

ownerEmail: Ember.computed.alias('two.email'),
submitting: false,
usersArray: Ember.computed('users', function () {
var users = this.get('users').split('\n').filter(function (email) {
return email.trim().length > 0;
Expand Down Expand Up @@ -75,6 +76,7 @@ export default Ember.Controller.extend({
this.get('errors').clear();

if (validationErrors === true && users.length > 0) {
this.toggleProperty('submitting');
this.get('authorRole').then(function (authorRole) {
Ember.RSVP.Promise.all(
users.map(function (user) {
Expand Down Expand Up @@ -123,6 +125,8 @@ export default Ember.Controller.extend({
self.send('loadServerNotifications');
self.transitionTo('posts.index');
}

self.toggleProperty('submitting');
});
});
} else if (users.length === 0) {
Expand Down
8 changes: 8 additions & 0 deletions core/client/app/controllers/setup/two.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default Ember.Controller.extend(ValidationEngine, {
password: null,
image: null,
blogCreated: false,
submitting: false,

ghostPaths: Ember.inject.service('ghost-paths'),
notifications: Ember.inject.service(),
Expand Down Expand Up @@ -54,6 +55,8 @@ export default Ember.Controller.extend(ValidationEngine, {
config = this.get('config'),
method = this.get('blogCreated') ? 'PUT' : 'POST';

this.toggleProperty('submitting');

this.validate().then(function () {
self.set('showError', false);
ajax({
Expand All @@ -80,18 +83,23 @@ export default Ember.Controller.extend(ValidationEngine, {
if (data.image) {
self.sendImage(result.users[0])
.then(function () {
self.toggleProperty('submitting');
self.transitionToRoute('setup.three');
}).catch(function (resp) {
self.toggleProperty('submitting');
notifications.showAPIError(resp);
});
} else {
self.toggleProperty('submitting');
self.transitionToRoute('setup.three');
}
});
}).catch(function (resp) {
self.toggleProperty('submitting');
notifications.showAPIError(resp);
});
}).catch(function () {
self.toggleProperty('submitting');
self.set('showError', true);
});
},
Expand Down
Loading

0 comments on commit 748895c

Please sign in to comment.