mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
de-couple gh-task-button from gh-spin-button
This commit is contained in:
parent
a988938a78
commit
0e7d455351
3 changed files with 140 additions and 17 deletions
|
@ -1,9 +1,8 @@
|
||||||
|
import Component from 'ember-component';
|
||||||
|
import observer from 'ember-metal/observer';
|
||||||
import {reads} from 'ember-computed';
|
import {reads} from 'ember-computed';
|
||||||
import {invokeAction} from 'ember-invoke-action';
|
import {invokeAction} from 'ember-invoke-action';
|
||||||
|
|
||||||
import SpinButton from './gh-spin-button';
|
|
||||||
import layout from 'ghost-admin/templates/components/gh-spin-button';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task Button works exactly like Spin button, but with one major difference:
|
* Task Button works exactly like Spin button, but with one major difference:
|
||||||
*
|
*
|
||||||
|
@ -15,30 +14,45 @@ import layout from 'ghost-admin/templates/components/gh-spin-button';
|
||||||
* component, all running promises will automatically be cancelled when this
|
* component, all running promises will automatically be cancelled when this
|
||||||
* component is removed from the DOM
|
* component is removed from the DOM
|
||||||
*/
|
*/
|
||||||
export default SpinButton.extend({
|
export default Component.extend({
|
||||||
layout, // This is used to we don't have to re-implement the template
|
tagName: 'button',
|
||||||
|
classNameBindings: ['isRunning:appear-disabled'],
|
||||||
classNameBindings: ['showSpinner:appear-disabled'],
|
attributeBindings: ['disabled', 'type', 'tabindex'],
|
||||||
|
|
||||||
task: null,
|
task: null,
|
||||||
|
|
||||||
submitting: reads('task.last.isRunning'),
|
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
|
||||||
|
isRunning: reads('task.last.isRunning'),
|
||||||
|
|
||||||
click() {
|
click() {
|
||||||
|
// do nothing if disabled externally
|
||||||
|
if (this.get('disabled')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let task = this.get('task');
|
let task = this.get('task');
|
||||||
let taskName = this.get('task.name');
|
let taskName = this.get('task.name');
|
||||||
let lastTaskName = this.get('task.last.task.name');
|
let lastTaskName = this.get('task.last.task.name');
|
||||||
|
|
||||||
// task-buttons are never truly disabled so that clicks when a taskGroup
|
// task-buttons are never disabled whilst running so that clicks when a
|
||||||
// is running don't get dropped however that means we need to check here
|
// taskGroup is running don't get dropped BUT that means we need to check
|
||||||
// so we don't spam actions through multiple clicks
|
// here to avoid spamming actions from multiple clicks
|
||||||
if (this.get('showSpinner') && taskName === lastTaskName) {
|
if (this.get('isRunning') && taskName === lastTaskName) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
invokeAction(this, 'action');
|
invokeAction(this, 'action');
|
||||||
|
|
||||||
return task.perform();
|
return task.perform();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
setSize: observer('isRunning', function () {
|
||||||
|
if (this.get('isRunning')) {
|
||||||
|
this.$().width(this.$().width());
|
||||||
|
this.$().height(this.$().height());
|
||||||
|
} else {
|
||||||
|
this.$().width('');
|
||||||
|
this.$().height('');
|
||||||
|
}
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
9
ghost/admin/app/templates/components/gh-task-button.hbs
Normal file
9
ghost/admin/app/templates/components/gh-task-button.hbs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{{#if isRunning}}
|
||||||
|
<span class="spinner"></span>
|
||||||
|
{{else}}
|
||||||
|
{{#if buttonText}}
|
||||||
|
{{buttonText}}
|
||||||
|
{{else}}
|
||||||
|
{{{yield}}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
|
@ -3,6 +3,9 @@ import {expect} from 'chai';
|
||||||
import {describe, it} from 'mocha';
|
import {describe, it} from 'mocha';
|
||||||
import {setupComponentTest} from 'ember-mocha';
|
import {setupComponentTest} from 'ember-mocha';
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
import {task, timeout} from 'ember-concurrency';
|
||||||
|
import run from 'ember-runloop';
|
||||||
|
import wait from 'ember-test-helpers/wait';
|
||||||
|
|
||||||
describe('Integration: Component: gh-task-button', function() {
|
describe('Integration: Component: gh-task-button', function() {
|
||||||
setupComponentTest('gh-task-button', {
|
setupComponentTest('gh-task-button', {
|
||||||
|
@ -11,9 +14,106 @@ describe('Integration: Component: gh-task-button', function() {
|
||||||
|
|
||||||
it('renders', function () {
|
it('renders', function () {
|
||||||
this.render(hbs`{{#gh-task-button}}Test{{/gh-task-button}}`);
|
this.render(hbs`{{#gh-task-button}}Test{{/gh-task-button}}`);
|
||||||
expect(this.$()).to.have.length(1);
|
expect(this.$('button')).to.exist;
|
||||||
expect(this.$().text().trim()).to.equal('Test');
|
expect(this.$('button')).to.contain('Test');
|
||||||
|
expect(this.$('button')).to.have.prop('disabled', false);
|
||||||
|
|
||||||
|
this.render(hbs`{{#gh-task-button class="testing"}}Test{{/gh-task-button}}`);
|
||||||
|
expect(this.$('button')).to.have.class('testing');
|
||||||
|
|
||||||
|
this.render(hbs`{{#gh-task-button disabled=true}}Test{{/gh-task-button}}`);
|
||||||
|
expect(this.$('button')).to.have.prop('disabled', true);
|
||||||
|
|
||||||
|
this.render(hbs`{{#gh-task-button type="submit"}}Test{{/gh-task-button}}`);
|
||||||
|
expect(this.$('button')).to.have.attr('type', 'submit');
|
||||||
|
|
||||||
|
this.render(hbs`{{#gh-task-button tabindex="-1"}}Test{{/gh-task-button}}`);
|
||||||
|
expect(this.$('button')).to.have.attr('tabindex', '-1');
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: figure out how to test concurrency behavior
|
it('shows spinner whilst running', function (done) {
|
||||||
|
this.set('myTask', task(function* () {
|
||||||
|
yield timeout(50);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.render(hbs`{{#gh-task-button task=myTask}}Test{{/gh-task-button}}`);
|
||||||
|
|
||||||
|
this.get('myTask').perform();
|
||||||
|
|
||||||
|
run.later(this, function () {
|
||||||
|
expect(this.$('button')).to.have.descendants('span.spinner');
|
||||||
|
}, 20);
|
||||||
|
|
||||||
|
wait().then(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('appears disabled whilst running', function (done) {
|
||||||
|
this.set('myTask', task(function* () {
|
||||||
|
yield timeout(50);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.render(hbs`{{#gh-task-button task=myTask}}Test{{/gh-task-button}}`);
|
||||||
|
expect(this.$('button'), 'initial class').to.not.have.class('appear-disabled');
|
||||||
|
|
||||||
|
this.get('myTask').perform();
|
||||||
|
|
||||||
|
run.later(this, function () {
|
||||||
|
expect(this.$('button'), 'running class').to.have.class('appear-disabled');
|
||||||
|
}, 20);
|
||||||
|
|
||||||
|
run.later(this, function () {
|
||||||
|
expect(this.$('button'), 'ended class').to.not.have.class('appear-disabled');
|
||||||
|
}, 70);
|
||||||
|
|
||||||
|
wait().then(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('performs task on click', function (done) {
|
||||||
|
let taskCount = 0;
|
||||||
|
|
||||||
|
this.set('myTask', task(function* () {
|
||||||
|
yield timeout(50);
|
||||||
|
taskCount = taskCount + 1;
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.render(hbs`{{#gh-task-button task=myTask}}Test{{/gh-task-button}}`);
|
||||||
|
this.$('button').click();
|
||||||
|
|
||||||
|
wait().then(() => {
|
||||||
|
expect(taskCount, 'taskCount').to.equal(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps button size when showing spinner', function (done) {
|
||||||
|
this.set('myTask', task(function* () {
|
||||||
|
yield timeout(50);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.render(hbs`{{#gh-task-button task=myTask}}Test{{/gh-task-button}}`);
|
||||||
|
let width = this.$('button').width();
|
||||||
|
let height = this.$('button').height();
|
||||||
|
expect(this.$('button')).to.not.have.attr('style');
|
||||||
|
|
||||||
|
this.get('myTask').perform();
|
||||||
|
|
||||||
|
run.later(this, function () {
|
||||||
|
// we can't test exact width/height because Chrome/Firefox use different rounding methods
|
||||||
|
// expect(this.$('button')).to.have.attr('style', `width: ${width}px; height: ${height}px;`);
|
||||||
|
|
||||||
|
let [widthInt] = width.toString().split('.');
|
||||||
|
let [heightInt] = height.toString().split('.');
|
||||||
|
|
||||||
|
expect(this.$('button').attr('style')).to.have.string(`width: ${widthInt}`);
|
||||||
|
expect(this.$('button').attr('style')).to.have.string(`height: ${heightInt}`);
|
||||||
|
}, 20);
|
||||||
|
|
||||||
|
run.later(this, function () {
|
||||||
|
// chai-jquery test doesn't work because Firefox outputs blank string
|
||||||
|
// expect(this.$('button')).to.not.have.attr('style');
|
||||||
|
expect(this.$('button').attr('style')).to.be.blank;
|
||||||
|
}, 70);
|
||||||
|
|
||||||
|
wait().then(done);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue