Handle automatic timezone override

refs https://github.com/TryGhost/Ghost/pull/7142, https://github.com/TryGhost/Ghost/pull/7143
- moves timezone selection template and logic into a component
- detect if the current `activeTimezone` is not in our pre-defined list of timezones, if it isn't:
  - add a line indicating that there has been an override with the current `activeTimezone` value
  - add a blank option to the timezone select list
This commit is contained in:
Kevin Ansfield 2016-07-26 11:24:37 +01:00
parent 7fc02c1007
commit 96f2d4088f
5 changed files with 159 additions and 31 deletions

View File

@ -0,0 +1,61 @@
import Component from 'ember-component';
import computed, {mapBy} from 'ember-computed';
import injectService from 'ember-service/inject';
import {invokeAction} from 'ember-invoke-action';
export default Component.extend({
classNames: ['form-group', 'for-select'],
activeTimezone: null,
availableTimezones: null,
clock: injectService(),
availableTimezoneNames: mapBy('availableTimezones', 'name'),
hasTimezoneOverride: computed('activeTimezone', 'availableTimezoneNames', function () {
let activeTimezone = this.get('activeTimezone');
let availableTimezoneNames = this.get('availableTimezoneNames');
return !availableTimezoneNames.contains(activeTimezone);
}),
selectedTimezone: computed('activeTimezone', 'availableTimezones', 'hasTimezoneOverride', function () {
let hasTimezoneOverride = this.get('hasTimezoneOverride');
let activeTimezone = this.get('activeTimezone');
let availableTimezones = this.get('availableTimezones');
if (hasTimezoneOverride) {
return {name: '', label: ''};
}
return availableTimezones
.filterBy('name', activeTimezone)
.get('firstObject');
}),
selectableTimezones: computed('availableTimezones', 'hasTimezoneOverride', function () {
let hasTimezoneOverride = this.get('hasTimezoneOverride');
let availableTimezones = this.get('availableTimezones');
if (hasTimezoneOverride) {
return [{name: '', label: ''}, ...availableTimezones];
}
return availableTimezones;
}),
localTime: computed('hasTimezoneOverride', 'activeTimezone', 'selectedTimezone', 'clock.second', function () {
let hasTimezoneOverride = this.get('hasTimezoneOverride');
let timezone = hasTimezoneOverride ? this.get('activeTimezone') : this.get('selectedTimezone.name');
this.get('clock.second');
return timezone ? moment().tz(timezone).format('HH:mm:ss') : moment().utc().format('HH:mm:ss');
}),
actions: {
setTimezone(timezone) {
invokeAction(this, 'update', timezone);
}
}
});

View File

@ -17,7 +17,6 @@ export default Controller.extend(SettingsSaveMixin, {
config: injectService(),
_scratchFacebook: null,
_scratchTwitter: null,
clock: injectService(),
selectedTheme: computed('model.activeTheme', 'themes', function () {
let activeTheme = this.get('model.activeTheme');
@ -33,15 +32,6 @@ export default Controller.extend(SettingsSaveMixin, {
return selectedTheme;
}),
selectedTimezone: computed('model.activeTimezone', 'availableTimezones', function () {
let activeTimezone = this.get('model.activeTimezone');
let availableTimezones = this.get('availableTimezones');
return availableTimezones
.filterBy('name', activeTimezone)
.get('firstObject');
}),
logoImageSource: computed('model.logo', function () {
return this.get('model.logo') || '';
}),
@ -50,12 +40,6 @@ export default Controller.extend(SettingsSaveMixin, {
return this.get('model.cover') || '';
}),
localTime: computed('selectedTimezone', 'clock.second', function () {
let timezone = this.get('selectedTimezone.name');
this.get('clock.second');
return timezone ? moment().tz(timezone).format('HH:mm:ss') : moment().utc().format('HH:mm:ss');
}),
isDatedPermalinks: computed('model.permalinks', {
set(key, value) {
this.set('model.permalinks', value ? '/:year/:month/:day/:slug/' : '/:slug/');

View File

@ -0,0 +1,16 @@
<label for="activeTimezone">Timezone</label>
<span class="gh-select" data-select-text="{{selectedTimezone.label}}" tabindex="0">
{{gh-select-native
id="activeTimezone"
name="general[activeTimezone]"
content=selectableTimezones
optionValuePath="name"
optionLabelPath="label"
selection=selectedTimezone
action="setTimezone"
}}
</span>
{{#if hasTimezoneOverride}}
<p>Your timezone has been automatically set to {{activeTimezone}}.</p>
{{/if}}
<p>The local time here is currently {{localTime}}</p>

View File

@ -113,21 +113,10 @@
{{/gh-form-group}}
</div>
<div class="form-group for-select">
<label for="activeTimezone">Timezone</label>
<span class="gh-select" data-select-text="{{selectedTimezone.label}}" tabindex="0">
{{gh-select-native
id="activeTimezone"
name="general[activeTimezone]"
content=availableTimezones
optionValuePath="name"
optionLabelPath="label"
selection=selectedTimezone
action="setTimezone"
}}
</span>
<p>The local time here is currently {{localTime}}</p>
</div>
{{gh-timezone-select
activeTimezone=model.activeTimezone
availableTimezones=availableTimezones
update=(action "setTimezone")}}
<div class="form-group for-checkbox">
<label for="isPrivate">Make this blog private</label>

View File

@ -0,0 +1,78 @@
/* jshint expr:true */
import { expect } from 'chai';
import {
describeComponent,
it
} from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile';
import run from 'ember-runloop';
import wait from 'ember-test-helpers/wait';
import sinon from 'sinon';
describeComponent(
'gh-timezone-select',
'Integration: Component: gh-timezone-select',
{
integration: true
},
function() {
beforeEach(function () {
this.set('availableTimezones', [
{name: 'Pacific/Pago_Pago', label: '(GMT -11:00) Midway Island, Samoa'},
{name: 'Etc/UTC', label: '(GMT) UTC'},
{name: 'Pacific/Kwajalein', label: '(GMT +12:00) International Date Line West'}
]);
this.set('activeTimezone', 'Etc/UTC');
});
it('renders', function () {
this.render(hbs`{{gh-timezone-select
availableTimezones=availableTimezones
activeTimezone=activeTimezone}}`);
expect(this.$(), 'top-level elements').to.have.length(1);
expect(this.$('option'), 'number of options').to.have.length(3);
expect(this.$('select').val(), 'selected option value').to.equal('Etc/UTC');
});
it('handles an unknown timezone', function () {
this.set('activeTimezone', 'Europe/London');
this.render(hbs`{{gh-timezone-select
availableTimezones=availableTimezones
activeTimezone=activeTimezone}}`);
// we have an additional blank option at the top
expect(this.$('option'), 'number of options').to.have.length(4);
// blank option is selected
expect(this.$('select').val(), 'selected option value').to.equal('');
// we indicate the manual override
expect(this.$('p').text()).to.match(/Your timezone has been automatically set to Europe\/London/);
});
it('triggers update action on change', function (done) {
let update = sinon.spy();
this.set('update', update);
this.render(hbs`{{gh-timezone-select
availableTimezones=availableTimezones
activeTimezone=activeTimezone
update=(action update)}}`);
run(() => {
this.$('select').val('Pacific/Pago_Pago').change();
});
wait().then(() => {
expect(update.calledOnce, 'update was called once').to.be.true;
expect(update.firstCall.args[0].name, 'update was passed new timezone')
.to.equal('Pacific/Pago_Pago');
done();
});
});
// TODO: mock clock service, fake the time, test we have the correct
// local time and it changes alongside selection changes
it('renders local time');
}
);