mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-23 22:11:09 +03:00
commit
c174dd27ce
@ -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 () {
|
||||
|
38
ghost/admin/app/components/gh-spin-button.js
Normal file
38
ghost/admin/app/components/gh-spin-button.js
Normal file
@ -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();
|
||||
}
|
||||
});
|
@ -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(),
|
||||
@ -28,6 +29,7 @@ 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);
|
||||
});
|
||||
},
|
||||
@ -35,6 +37,8 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
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');
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -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(),
|
||||
|
||||
@ -62,26 +63,26 @@ export default Ember.Controller.extend({
|
||||
}
|
||||
}),
|
||||
|
||||
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 model;
|
||||
}).catch(function (error) {
|
||||
if (error) {
|
||||
notifications.showAPIError(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
validate: function () {
|
||||
this.get('model').validate(arguments);
|
||||
},
|
||||
|
||||
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 model;
|
||||
}).catch(function (error) {
|
||||
if (error) {
|
||||
notifications.showAPIError(error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
checkPostsPerPage: function () {
|
||||
var postsPerPage = this.get('model.postsPerPage');
|
||||
|
||||
|
@ -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(),
|
||||
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Ember from 'ember';
|
||||
import SettingsSaveMixin from 'ghost/mixins/settings-save';
|
||||
|
||||
var NavItem = Ember.Object.extend({
|
||||
label: '',
|
||||
@ -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(),
|
||||
|
||||
@ -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'),
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -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;
|
||||
@ -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) {
|
||||
@ -123,6 +125,8 @@ export default Ember.Controller.extend({
|
||||
self.send('loadServerNotifications');
|
||||
self.transitionTo('posts.index');
|
||||
}
|
||||
|
||||
self.toggleProperty('submitting');
|
||||
});
|
||||
});
|
||||
} else if (users.length === 0) {
|
||||
|
@ -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(),
|
||||
@ -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({
|
||||
@ -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);
|
||||
});
|
||||
},
|
||||
|
@ -4,6 +4,7 @@ import {request as ajax} from 'ic-ajax';
|
||||
|
||||
export default Ember.Controller.extend(ValidationEngine, {
|
||||
submitting: false,
|
||||
loggingIn: false,
|
||||
|
||||
ghostPaths: Ember.inject.service('ghost-paths'),
|
||||
notifications: Ember.inject.service(),
|
||||
@ -19,12 +20,15 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
authStrategy = 'simple-auth-authenticator:oauth2-password-grant',
|
||||
data = model.getProperties('identification', 'password');
|
||||
|
||||
this.get('session').authenticate(authStrategy, data).catch(function (err) {
|
||||
this.get('session').authenticate(authStrategy, data).then(function () {
|
||||
self.toggleProperty('loggingIn');
|
||||
}).catch(function (err) {
|
||||
self.toggleProperty('loggingIn');
|
||||
|
||||
if (err.errors) {
|
||||
self.set('flowErrors', err.errors[0].message.string);
|
||||
}
|
||||
|
||||
// If authentication fails a rejected promise will be returned.
|
||||
// if authentication fails a rejected promise will be returned.
|
||||
// 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.
|
||||
});
|
||||
@ -39,6 +43,7 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
|
||||
this.validate().then(function () {
|
||||
self.get('notifications').closeNotifications();
|
||||
self.toggleProperty('loggingIn');
|
||||
self.send('authenticate');
|
||||
}).catch(function (error) {
|
||||
if (error) {
|
||||
@ -56,7 +61,7 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
|
||||
this.set('flowErrors', '');
|
||||
this.validate({property: 'identification'}).then(function () {
|
||||
self.set('submitting', true);
|
||||
self.toggleProperty('submitting');
|
||||
|
||||
ajax({
|
||||
url: self.get('ghostPaths.url').api('authentication', 'passwordreset'),
|
||||
@ -67,10 +72,10 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
}]
|
||||
}
|
||||
}).then(function () {
|
||||
self.set('submitting', false);
|
||||
self.toggleProperty('submitting');
|
||||
notifications.showAlert('Please check your email for instructions.', {type: 'info'});
|
||||
}).catch(function (resp) {
|
||||
self.set('submitting', false);
|
||||
self.toggleProperty('submitting');
|
||||
if (resp && resp.jqXHR && resp.jqXHR.responseJSON && resp.jqXHR.responseJSON.errors) {
|
||||
self.set('flowErrors', resp.jqXHR.responseJSON.errors[0].message);
|
||||
} else {
|
||||
|
@ -7,6 +7,7 @@ import ValidationEngine from 'ghost/mixins/validation-engine';
|
||||
export default Ember.Controller.extend(ValidationEngine, {
|
||||
// ValidationEngine settings
|
||||
validationType: 'user',
|
||||
submitting: false,
|
||||
|
||||
ghostPaths: Ember.inject.service('ghost-paths'),
|
||||
notifications: Ember.inject.service(),
|
||||
@ -103,6 +104,8 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
user.set('slug', slugValue);
|
||||
}
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
|
||||
promise = Ember.RSVP.resolve(afterUpdateSlug).then(function () {
|
||||
return user.save({format: false});
|
||||
}).then(function (model) {
|
||||
@ -121,11 +124,15 @@ export default Ember.Controller.extend(ValidationEngine, {
|
||||
window.history.replaceState({path: newPath}, '', newPath);
|
||||
}
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
|
||||
return model;
|
||||
}).catch(function (errors) {
|
||||
if (errors) {
|
||||
self.get('notifications').showErrors(errors);
|
||||
}
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
});
|
||||
|
||||
this.set('lastPromise', promise);
|
||||
|
@ -17,6 +17,7 @@ export default Ember.Mixin.create({
|
||||
autoSaveId: null,
|
||||
timedSaveId: null,
|
||||
editor: null,
|
||||
submitting: false,
|
||||
|
||||
notifications: Ember.inject.service(),
|
||||
|
||||
@ -247,6 +248,8 @@ export default Ember.Mixin.create({
|
||||
|
||||
options = options || {};
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
|
||||
if (options.backgroundSave) {
|
||||
// do not allow a post's status to be set to published by a background save
|
||||
status = 'draft';
|
||||
@ -294,6 +297,7 @@ export default Ember.Mixin.create({
|
||||
self.showSaveNotification(prevStatus, model.get('status'), isNew ? true : false);
|
||||
}
|
||||
|
||||
self.toggleProperty('submitting');
|
||||
return model;
|
||||
});
|
||||
}).catch(function (errors) {
|
||||
@ -303,6 +307,7 @@ export default Ember.Mixin.create({
|
||||
|
||||
self.set('model.status', prevStatus);
|
||||
|
||||
self.toggleProperty('submitting');
|
||||
return self.get('model');
|
||||
});
|
||||
|
||||
|
17
ghost/admin/app/mixins/settings-save.js
Normal file
17
ghost/admin/app/mixins/settings-save.js
Normal file
@ -0,0 +1,17 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Mixin.create({
|
||||
submitting: false,
|
||||
|
||||
actions: {
|
||||
save: function () {
|
||||
var self = this;
|
||||
|
||||
this.set('submitting', true);
|
||||
|
||||
this.save().then(function () {
|
||||
self.set('submitting', false);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -200,3 +200,27 @@ input[type="reset"].btn-block,
|
||||
input[type="button"].btn-block {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Spin Buttons!
|
||||
/* ---------------------------------------------------------- */
|
||||
.spinner {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
margin: -2px 0;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border: rgba(0,0,0,0.2) solid 4px;
|
||||
border-radius: 100px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.spinner:before {
|
||||
content: "";
|
||||
display: block;
|
||||
margin-top: 6px;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: rgba(0,0,0,0.6);
|
||||
border-radius: 100px;
|
||||
}
|
||||
|
@ -406,6 +406,15 @@ img {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.fade-in {
|
||||
animation: fade-in 0.2s;
|
||||
animation-fill-mode: forwards;
|
||||
|
@ -1,6 +1,4 @@
|
||||
<button type="button" {{action "save"}} class="btn btn-sm js-publish-button {{if isDangerous 'btn-red' 'btn-blue'}}">
|
||||
{{saveText}}
|
||||
</button>
|
||||
{{gh-spin-button type="button" classNameBindings=":btn :btn-sm :js-publish-button isDangerous:btn-red:btn-blue" action="save" buttonText=saveText submitting=submitting}}
|
||||
|
||||
{{#gh-dropdown-button dropdownName="post-save-menu" classNameBindings=":btn :btn-sm isDangerous:btn-red:btn-blue btnopen:active :dropdown-toggle :up"}}
|
||||
<i class="options icon-arrow2"></i>
|
||||
|
9
ghost/admin/app/templates/components/gh-spin-button.hbs
Normal file
9
ghost/admin/app/templates/components/gh-spin-button.hbs
Normal file
@ -0,0 +1,9 @@
|
||||
{{#unless submitting}}
|
||||
{{#if buttonText}}
|
||||
{{buttonText}}
|
||||
{{else}}
|
||||
{{{yield}}}
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="spinner"></span>
|
||||
{{/unless}}
|
@ -16,6 +16,7 @@
|
||||
save="save"
|
||||
setSaveType="setSaveType"
|
||||
delete="openDeleteModal"
|
||||
submitting=submitting
|
||||
}}
|
||||
</section>
|
||||
</header>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<div class="password-wrap">
|
||||
{{input class="gh-input password" type="password" placeholder="Password" name="password" value=password}}
|
||||
</div>
|
||||
<button class="btn btn-blue" type="submit" {{action "validateAndAuthenticate"}} disabled={{submitting}}>Log in</button>
|
||||
{{gh-spin-button class="btn btn-blue" type="submit" action="validateAndAuthenticate" submitting=submitting buttonText="Log in"}}
|
||||
</form>
|
||||
|
||||
{{/gh-modal-dialog}}
|
||||
|
@ -17,7 +17,7 @@
|
||||
{{input value=ne2Password class="gh-input password" type="password" placeholder="Confirm Password" name="ne2password" focusOut=(action "validate" "ne2Password")}}
|
||||
{{gh-error-message errors=errors property="ne2Password"}}
|
||||
{{/gh-form-group}}
|
||||
<button class="btn btn-blue btn-block" type="submit" disabled={{submitting}}>Reset Password</button>
|
||||
{{gh-spin-button class="btn btn-blue btn-block" type="submit" submitting=submitting buttonText="Reset Password" autoWidth=false}}
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<header class="view-header">
|
||||
{{#gh-view-title openMobileMenu="openMobileMenu"}}Code Injection{{/gh-view-title}}
|
||||
<section class="view-actions">
|
||||
<button type="button" class="btn btn-blue" {{action "save"}}>Save</button>
|
||||
{{gh-spin-button type="button" class="btn btn-blue" action="save" buttonText="Save" submitting=submitting}}
|
||||
</section>
|
||||
</header>
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<header class="view-header">
|
||||
{{#gh-view-title openMobileMenu="openMobileMenu"}}General{{/gh-view-title}}
|
||||
<section class="view-actions">
|
||||
<button type="button" class="btn btn-blue" {{action "save"}}>Save</button>
|
||||
{{gh-spin-button type="button" class="btn btn-blue" action="save" buttonText="Save" submitting=submitting}}
|
||||
</section>
|
||||
</header>
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
<fieldset>
|
||||
<div class="form-group">
|
||||
<label>Send a test email</label>
|
||||
<button type="button" id="sendtestmail" class="btn btn-blue" {{action "sendTestEmail"}}>Send</button>
|
||||
{{gh-spin-button type="button" id="sendtestemail" class="btn btn-blue" action="sendTestEmail" buttonText="Send" submitting=submitting}}
|
||||
<p>Sends a test email to your address.</p>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
@ -2,7 +2,7 @@
|
||||
<header class="view-header">
|
||||
{{#gh-view-title openMobileMenu="openMobileMenu"}}Navigation{{/gh-view-title}}
|
||||
<section class="view-actions">
|
||||
<button type="button" class="btn btn-blue" {{action "save"}}>Save</button>
|
||||
{{gh-spin-button type="button" class="btn btn-blue" action="save" buttonText="Save" submitting=submitting}}
|
||||
</section>
|
||||
</header>
|
||||
|
||||
|
@ -11,9 +11,8 @@
|
||||
{{gh-error-message errors=errors property="users"}}
|
||||
</form>
|
||||
|
||||
<button {{action 'invite'}} class="btn btn-default btn-lg btn-block {{buttonClass}}">
|
||||
{{buttonText}}
|
||||
</button>
|
||||
{{gh-spin-button type="button" classNameBindings=":btn :btn-default :btn-lg :btn-block buttonClass" action="invite" buttonText=buttonText submitting=submitting autoWidth=false}}
|
||||
|
||||
<button class="gh-flow-skip" {{action "skipInvite"}}>
|
||||
I'll do this later, take me to my blog!
|
||||
</button>
|
||||
|
@ -37,6 +37,7 @@
|
||||
{{gh-error-message errors=errors property="blogTitle"}}
|
||||
{{/gh-form-group}}
|
||||
</form>
|
||||
|
||||
<button type="submit" class="btn btn-green btn-lg btn-block" {{action "setup"}}>Last step: Invite your team <i class="icon-chevron"></i></button>
|
||||
{{#gh-spin-button type="button" class="btn btn-green btn-lg btn-block" action="setup" submitting=submitting autoWidth=false}}
|
||||
Last step: Invite your team <i class="icon-chevron"></i>
|
||||
{{/gh-spin-button}}
|
||||
<p class="main-error">{{#if showError}}{{invalidMessage}}{{/if}}</p>
|
||||
|
@ -15,7 +15,7 @@
|
||||
</span>
|
||||
{{gh-error-message errors=model.errors property="password"}}
|
||||
{{/gh-form-group}}
|
||||
<button id="login-button" class="login btn btn-blue btn-block" type="submit" tabindex="3" disabled={{submitting}}>Sign in</button>
|
||||
{{gh-spin-button class="login btn btn-blue btn-block" type="submit" tabindex="3" buttonText="Sign in" submitting=loggingIn autoWidth=false}}
|
||||
</form>
|
||||
|
||||
<p class="main-error">{{{flowErrors}}}</p>
|
||||
|
@ -48,7 +48,7 @@
|
||||
{{/gh-form-group}}
|
||||
</form>
|
||||
|
||||
<button type="submit" class="btn btn-green btn-lg btn-block" {{action "signup"}} disabled={{submitting}}>Create Account</button>
|
||||
{{gh-spin-button type="submit" class="btn btn-green btn-lg btn-block" action="signup" submitting=submitting autoWidth=false}}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
<button class="btn btn-blue" {{action "save"}}>Save</button>
|
||||
{{gh-spin-button class="btn btn-blue" action="save" buttonText="Save" submitting=submitting}}
|
||||
</section>
|
||||
</header>
|
||||
|
||||
|
@ -12,6 +12,7 @@ describeComponent(
|
||||
needs: [
|
||||
'component:gh-dropdown-button',
|
||||
'component:gh-dropdown',
|
||||
'component:gh-spin-button',
|
||||
'service:dropdown'
|
||||
]
|
||||
},
|
||||
|
27
ghost/admin/tests/unit/components/gh-spin-button-test.js
Normal file
27
ghost/admin/tests/unit/components/gh-spin-button-test.js
Normal file
@ -0,0 +1,27 @@
|
||||
/* jshint expr:true */
|
||||
import {expect} from 'chai';
|
||||
import {
|
||||
describeComponent,
|
||||
it
|
||||
} from 'ember-mocha';
|
||||
|
||||
describeComponent(
|
||||
'gh-spin-button',
|
||||
'GhSpinButtonComponent',
|
||||
{
|
||||
// specify the other units that are required for this test
|
||||
// needs: ['component:foo', 'helper:bar']
|
||||
},
|
||||
function () {
|
||||
it('renders', function () {
|
||||
// creates the component instance
|
||||
var component = this.subject();
|
||||
|
||||
expect(component._state).to.equal('preRender');
|
||||
|
||||
// renders the component on the page
|
||||
this.render();
|
||||
expect(component._state).to.equal('inDOM');
|
||||
});
|
||||
}
|
||||
);
|
Loading…
Reference in New Issue
Block a user