diff --git a/ghost/admin/.template-lintrc.js b/ghost/admin/.template-lintrc.js index 6fdd9bc177..d4646221a0 100644 --- a/ghost/admin/.template-lintrc.js +++ b/ghost/admin/.template-lintrc.js @@ -3,7 +3,7 @@ module.exports = { rules: { 'no-forbidden-elements': ['meta', 'html', 'script'], - 'no-implicit-this': {allow: ['noop', 'now', 'site-icon-style', 'accent-color-background']}, + 'no-implicit-this': {allow: ['noop', 'now', 'site-icon-style']}, 'no-inline-styles': false, 'no-duplicate-landmark-elements': false, 'no-pointer-down-event-binding': false, diff --git a/ghost/admin/app/components/editor/modals/re-authenticate.hbs b/ghost/admin/app/components/editor/modals/re-authenticate.hbs index 1da8ce1031..6024aca235 100644 --- a/ghost/admin/app/components/editor/modals/re-authenticate.hbs +++ b/ghost/admin/app/components/editor/modals/re-authenticate.hbs @@ -27,7 +27,7 @@ @showSuccess={{false}} @task={{this.reauthenticateTask}} @class="login gh-btn gh-btn-login gh-btn-block gh-btn-icon" - style={{accent-color-background}} + @useAccentColor={{true}} /> {{#if this.authenticationError}} diff --git a/ghost/admin/app/components/gh-task-button.js b/ghost/admin/app/components/gh-task-button.js index 873c360366..a08ef711b9 100644 --- a/ghost/admin/app/components/gh-task-button.js +++ b/ghost/admin/app/components/gh-task-button.js @@ -1,6 +1,8 @@ import Component from '@ember/component'; import config from 'ghost-admin/config/environment'; import {action, computed} from '@ember/object'; +import {htmlSafe} from '@ember/template'; +import {inject} from 'ghost-admin/decorators/inject'; import {isBlank} from '@ember/utils'; import {reads} from '@ember/object/computed'; import {task, timeout} from 'ember-concurrency'; @@ -25,7 +27,7 @@ const GhTaskButton = Component.extend({ 'isSuccessClass', 'isFailureClass' ], - attributeBindings: ['disabled', 'form', 'type', 'tabindex', 'data-test-button'], + attributeBindings: ['disabled', 'form', 'type', 'tabindex', 'data-test-button', 'style'], task: null, taskArgs: undefined, @@ -49,6 +51,8 @@ const GhTaskButton = Component.extend({ // Allowed actions action: () => {}, + config: inject(), + runningText: reads('buttonText'), // hasRun is needed so that a newly rendered button does not show the last @@ -113,6 +117,13 @@ const GhTaskButton = Component.extend({ return !this.isRunning && !this.isSuccess && !this.isFailure; }), + style: computed('useAccentColor', 'isFailure', function () { + if (this.useAccentColor && !this.isFailure) { + return htmlSafe(`background-color: ${this.config.accent_color}`); + } + return null; + }), + init() { this._super(...arguments); this._initialPerformCount = this.get('task.performCount'); diff --git a/ghost/admin/app/helpers/accent-color-background.js b/ghost/admin/app/helpers/accent-color-background.js deleted file mode 100644 index 3590ddf9ec..0000000000 --- a/ghost/admin/app/helpers/accent-color-background.js +++ /dev/null @@ -1,12 +0,0 @@ -import Helper from '@ember/component/helper'; -import {htmlSafe} from '@ember/template'; -import {inject} from 'ghost-admin/decorators/inject'; - -export default class AccentColorBackgroundHelper extends Helper { - @inject config; - - compute() { - const color = this.config.accent_color; - return htmlSafe(`background: ${color};`); - } -} diff --git a/ghost/admin/app/templates/signin.hbs b/ghost/admin/app/templates/signin.hbs index 2a3d5e2741..6e4b1f0371 100644 --- a/ghost/admin/app/templates/signin.hbs +++ b/ghost/admin/app/templates/signin.hbs @@ -69,7 +69,7 @@ @showSuccess={{false}} @class="login gh-btn gh-btn-login gh-btn-block gh-btn-icon" @type="submit" - style={{accent-color-background}} + @useAccentColor={{true}} data-test-button="sign-in" /> diff --git a/ghost/admin/app/templates/signup.hbs b/ghost/admin/app/templates/signup.hbs index c6996c8922..7d7797bfac 100644 --- a/ghost/admin/app/templates/signup.hbs +++ b/ghost/admin/app/templates/signup.hbs @@ -75,10 +75,10 @@ @task={{this.signupTask}} @defaultClick={{true}} @showSuccess={{false}} + @useAccentColor={{true}} type="submit" form="signup" class="gh-btn gh-btn-signup gh-btn-block gh-btn-icon" - style={{accent-color-background}} data-test-button="signup" /> diff --git a/ghost/admin/tests/integration/components/gh-task-button-test.js b/ghost/admin/tests/integration/components/gh-task-button-test.js index b967e9006e..0687a4c0ef 100644 --- a/ghost/admin/tests/integration/components/gh-task-button-test.js +++ b/ghost/admin/tests/integration/components/gh-task-button-test.js @@ -3,13 +3,17 @@ import {click, find, render, settled, waitFor} from '@ember/test-helpers'; import {defineProperty} from '@ember/object'; import {describe, it} from 'mocha'; import {expect} from 'chai'; -import {run} from '@ember/runloop'; import {setupRenderingTest} from 'ember-mocha'; import {task, timeout} from 'ember-concurrency'; describe('Integration: Component: gh-task-button', function () { setupRenderingTest(); + beforeEach(function () { + const config = this.owner.lookup('config:main'); + config.accent_color = '#123456'; + }); + it('renders', async function () { // sets button text using positional param await render(hbs``); @@ -47,7 +51,6 @@ describe('Integration: Component: gh-task-button', function () { this.myTask.perform(); await waitFor('button svg', {timeout: 50}); - await settled(); }); it('shows running text when passed whilst running', async function () { @@ -61,8 +64,6 @@ describe('Integration: Component: gh-task-button', function () { await waitFor('button svg', {timeout: 50}); expect(find('button')).to.contain.text('Running'); - - await settled(); }); it('appears disabled whilst running', async function () { @@ -83,7 +84,7 @@ describe('Integration: Component: gh-task-button', function () { it('shows success on success', async function () { defineProperty(this, 'myTask', task(function* () { - yield timeout(50); + yield timeout(1); return true; })); @@ -97,7 +98,7 @@ describe('Integration: Component: gh-task-button', function () { it('assigns specified success class on success', async function () { defineProperty(this, 'myTask', task(function* () { - yield timeout(50); + yield timeout(1); return true; })); @@ -113,7 +114,7 @@ describe('Integration: Component: gh-task-button', function () { it('shows failure when task errors', async function () { defineProperty(this, 'myTask', task(function* () { try { - yield timeout(50); + yield timeout(1); throw new ReferenceError('test error'); } catch (error) { // noop, prevent mocha triggering unhandled error assert @@ -126,13 +127,11 @@ describe('Integration: Component: gh-task-button', function () { await waitFor('button.is-failed'); expect(find('button')).to.contain.text('Retry'); - - await settled(); }); it('shows failure on falsy response', async function () { defineProperty(this, 'myTask', task(function* () { - yield timeout(50); + yield timeout(1); return false; })); @@ -142,13 +141,11 @@ describe('Integration: Component: gh-task-button', function () { await waitFor('button.gh-btn-red', {timeout: 50}); expect(find('button')).to.contain.text('Retry'); - - await settled(); }); it('shows idle on canceled response', async function () { defineProperty(this, 'myTask', task(function* () { - yield timeout(50); + yield timeout(1); return 'canceled'; })); @@ -156,13 +153,11 @@ describe('Integration: Component: gh-task-button', function () { this.myTask.perform(); await waitFor('[data-test-task-button-state="idle"]', {timeout: 50}); - - await settled(); }); it('assigns specified failure class on failure', async function () { defineProperty(this, 'myTask', task(function* () { - yield timeout(50); + yield timeout(1); return false; })); @@ -174,15 +169,13 @@ describe('Integration: Component: gh-task-button', function () { expect(find('button')).to.not.have.class('gh-btn-red'); expect(find('button')).to.contain.text('Retry'); - - await settled(); }); it('performs task on click', async function () { let taskCount = 0; defineProperty(this, 'myTask', task(function* () { - yield timeout(50); + yield timeout(1); taskCount = taskCount + 1; })); @@ -192,33 +185,37 @@ describe('Integration: Component: gh-task-button', function () { expect(taskCount, 'taskCount').to.equal(1); }); - it.skip('keeps button size when showing spinner', async function () { + it('@useAccentColor=true adds style attr', async function () { defineProperty(this, 'myTask', task(function* () { - yield timeout(50); + yield timeout(1); })); - await render(hbs``); - let width = find('button').clientWidth; - let height = find('button').clientHeight; - expect(find('button')).to.not.have.attr('style'); + await render(hbs``); - this.myTask.perform(); + expect(find('button')).to.have.attr('style', 'background-color: #123456'); + }); - run.later(this, function () { - // we can't test exact width/height because Chrome/Firefox use different rounding methods - // expect(find('button')).to.have.attr('style', `width: ${width}px; height: ${height}px;`); + it('@useAccentColor=true removes style attr when in failure state', async function () { + defineProperty(this, 'myTask', task(function* () { + yield timeout(1); + return false; + })); - let [widthInt] = width.toString().split('.'); - let [heightInt] = height.toString().split('.'); + await render(hbs``); + await click('button'); + await waitFor('button.gh-btn-red', {timeout: 50}); - expect(find('button')).to.have.attr('style', `width: ${widthInt}`); - expect(find('button')).to.have.attr('style', `height: ${heightInt}`); - }, 20); + expect(find('button')).to.contain.text('Retry'); + expect(find('button')).not.to.have.attr('style'); + }); - run.later(this, function () { - expect(find('button').getAttribute('style')).to.be.empty; - }, 100); + it('@useAccentColor=false does not add style attr', async function () { + defineProperty(this, 'myTask', task(function* () { + yield timeout(1); + })); - await settled(); + await render(hbs``); + + expect(find('button')).not.to.have.attr('style'); }); });