mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 14:03:48 +03:00
Use a custom transform to simplify navigation settings
no issue - moves the `NavItem` object from the navigation controller to an explicit `NavigationItem` model file - adds a custom transform `navigation-settings` that transforms the navigation settings JSON string to/from an array of `NavigationItem` objects - simplifies the `settings/navigation` controller as it no longer has to export it's own internal model and handle serialization and deserialization This pattern should also help simplify the apps/slack integration code if implemented there.
This commit is contained in:
parent
983c708ece
commit
0e2f4ea33e
@ -1,43 +1,13 @@
|
|||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import DS from 'ember-data';
|
|
||||||
import SettingsSaveMixin from 'ghost/mixins/settings-save';
|
import SettingsSaveMixin from 'ghost/mixins/settings-save';
|
||||||
import ValidationEngine from 'ghost/mixins/validation-engine';
|
import NavigationItem from 'ghost/models/navigation-item';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
Controller,
|
Controller,
|
||||||
RSVP,
|
RSVP,
|
||||||
computed,
|
computed,
|
||||||
inject: {service},
|
inject: {service}
|
||||||
isBlank
|
|
||||||
} = Ember;
|
} = Ember;
|
||||||
const {Errors} = DS;
|
|
||||||
const emberA = Ember.A;
|
|
||||||
|
|
||||||
export const NavItem = Ember.Object.extend(ValidationEngine, {
|
|
||||||
label: '',
|
|
||||||
url: '',
|
|
||||||
isNew: false,
|
|
||||||
|
|
||||||
validationType: 'navItem',
|
|
||||||
|
|
||||||
isComplete: computed('label', 'url', function () {
|
|
||||||
let {label, url} = this.getProperties('label', 'url');
|
|
||||||
|
|
||||||
return !isBlank(label) && !isBlank(url);
|
|
||||||
}),
|
|
||||||
|
|
||||||
isBlank: computed('label', 'url', function () {
|
|
||||||
let {label, url} = this.getProperties('label', 'url');
|
|
||||||
|
|
||||||
return isBlank(label) && isBlank(url);
|
|
||||||
}),
|
|
||||||
|
|
||||||
init() {
|
|
||||||
this._super(...arguments);
|
|
||||||
this.set('errors', Errors.create());
|
|
||||||
this.set('hasValidated', emberA());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Controller.extend(SettingsSaveMixin, {
|
export default Controller.extend(SettingsSaveMixin, {
|
||||||
config: service(),
|
config: service(),
|
||||||
@ -51,33 +21,16 @@ export default Controller.extend(SettingsSaveMixin, {
|
|||||||
return url.slice(-1) !== '/' ? `${url}/` : url;
|
return url.slice(-1) !== '/' ? `${url}/` : url;
|
||||||
}),
|
}),
|
||||||
|
|
||||||
navigationItems: computed('model.navigation', function () {
|
|
||||||
let navItems;
|
|
||||||
|
|
||||||
try {
|
|
||||||
navItems = JSON.parse(this.get('model.navigation') || [{}]);
|
|
||||||
} catch (e) {
|
|
||||||
navItems = [{}];
|
|
||||||
}
|
|
||||||
|
|
||||||
navItems = navItems.map((item) => {
|
|
||||||
return NavItem.create(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
return navItems;
|
|
||||||
}),
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.set('newNavItem', NavItem.create({isNew: true}));
|
this.set('newNavItem', NavigationItem.create({isNew: true}));
|
||||||
},
|
},
|
||||||
|
|
||||||
save() {
|
save() {
|
||||||
let navItems = this.get('navigationItems');
|
let navItems = this.get('model.navigation');
|
||||||
let newNavItem = this.get('newNavItem');
|
let newNavItem = this.get('newNavItem');
|
||||||
let notifications = this.get('notifications');
|
let notifications = this.get('notifications');
|
||||||
let validationPromises = [];
|
let validationPromises = [];
|
||||||
let navSetting;
|
|
||||||
|
|
||||||
if (!newNavItem.get('isBlank')) {
|
if (!newNavItem.get('isBlank')) {
|
||||||
validationPromises.pushObject(this.send('addItem'));
|
validationPromises.pushObject(this.send('addItem'));
|
||||||
@ -88,19 +41,6 @@ export default Controller.extend(SettingsSaveMixin, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return RSVP.all(validationPromises).then(() => {
|
return RSVP.all(validationPromises).then(() => {
|
||||||
navSetting = navItems.map((item) => {
|
|
||||||
let label = item.get('label').trim();
|
|
||||||
let url = item.get('url').trim();
|
|
||||||
|
|
||||||
return {label, 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');
|
|
||||||
|
|
||||||
return this.get('model').save().catch((err) => {
|
return this.get('model').save().catch((err) => {
|
||||||
notifications.showErrors(err);
|
notifications.showErrors(err);
|
||||||
});
|
});
|
||||||
@ -110,12 +50,12 @@ export default Controller.extend(SettingsSaveMixin, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
addNewNavItem() {
|
addNewNavItem() {
|
||||||
let navItems = this.get('navigationItems');
|
let navItems = this.get('model.navigation');
|
||||||
let newNavItem = this.get('newNavItem');
|
let newNavItem = this.get('newNavItem');
|
||||||
|
|
||||||
newNavItem.set('isNew', false);
|
newNavItem.set('isNew', false);
|
||||||
navItems.pushObject(newNavItem);
|
navItems.pushObject(newNavItem);
|
||||||
this.set('newNavItem', NavItem.create({isNew: true}));
|
this.set('newNavItem', NavigationItem.create({isNew: true}));
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
@ -137,13 +77,13 @@ export default Controller.extend(SettingsSaveMixin, {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let navItems = this.get('navigationItems');
|
let navItems = this.get('model.navigation');
|
||||||
|
|
||||||
navItems.removeObject(item);
|
navItems.removeObject(item);
|
||||||
},
|
},
|
||||||
|
|
||||||
reorderItems(navItems) {
|
reorderItems(navItems) {
|
||||||
this.set('navigationItems', navItems);
|
this.set('model.navigation', navItems);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateUrl(url, navItem) {
|
updateUrl(url, navItem) {
|
||||||
@ -155,7 +95,7 @@ export default Controller.extend(SettingsSaveMixin, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
this.set('newNavItem', NavItem.create({isNew: true}));
|
this.set('newNavItem', NavigationItem.create({isNew: true}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
27
ghost/admin/app/models/navigation-item.js
Normal file
27
ghost/admin/app/models/navigation-item.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import Ember from 'ember';
|
||||||
|
import ValidationEngine from 'ghost/mixins/validation-engine';
|
||||||
|
|
||||||
|
const {
|
||||||
|
computed,
|
||||||
|
isBlank
|
||||||
|
} = Ember;
|
||||||
|
|
||||||
|
export default Ember.Object.extend(ValidationEngine, {
|
||||||
|
label: '',
|
||||||
|
url: '',
|
||||||
|
isNew: false,
|
||||||
|
|
||||||
|
validationType: 'navItem',
|
||||||
|
|
||||||
|
isComplete: computed('label', 'url', function () {
|
||||||
|
let {label, url} = this.getProperties('label', 'url');
|
||||||
|
|
||||||
|
return !isBlank(label) && !isBlank(url);
|
||||||
|
}),
|
||||||
|
|
||||||
|
isBlank: computed('label', 'url', function () {
|
||||||
|
let {label, url} = this.getProperties('label', 'url');
|
||||||
|
|
||||||
|
return isBlank(label) && isBlank(url);
|
||||||
|
})
|
||||||
|
});
|
@ -19,7 +19,7 @@ export default Model.extend(ValidationEngine, {
|
|||||||
ghost_head: attr('string'),
|
ghost_head: attr('string'),
|
||||||
ghost_foot: attr('string'),
|
ghost_foot: attr('string'),
|
||||||
labs: attr('string'),
|
labs: attr('string'),
|
||||||
navigation: attr('string'),
|
navigation: attr('navigation-settings'),
|
||||||
isPrivate: attr('boolean'),
|
isPrivate: attr('boolean'),
|
||||||
password: attr('string')
|
password: attr('string')
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<section class="view-container">
|
<section class="view-container">
|
||||||
<form id="settings-navigation" class="gh-blognav" novalidate="novalidate">
|
<form id="settings-navigation" class="gh-blognav" novalidate="novalidate">
|
||||||
{{#sortable-group onChange=(action 'reorderItems') as |group|}}
|
{{#sortable-group onChange=(action 'reorderItems') as |group|}}
|
||||||
{{#each navigationItems as |navItem|}}
|
{{#each model.navigation as |navItem|}}
|
||||||
{{gh-navitem navItem=navItem baseUrl=blogUrl addItem="addItem" deleteItem="deleteItem" updateUrl="updateUrl" group=group}}
|
{{gh-navitem navItem=navItem baseUrl=blogUrl addItem="addItem" deleteItem="deleteItem" updateUrl="updateUrl" group=group}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{/sortable-group}}
|
{{/sortable-group}}
|
||||||
|
41
ghost/admin/app/transforms/navigation-settings.js
Normal file
41
ghost/admin/app/transforms/navigation-settings.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import Ember from 'ember';
|
||||||
|
import Transform from 'ember-data/transform';
|
||||||
|
import NavigationItem from 'ghost/models/navigation-item';
|
||||||
|
|
||||||
|
const {isArray} = Ember;
|
||||||
|
const emberA = Ember.A;
|
||||||
|
|
||||||
|
export default Transform.extend({
|
||||||
|
deserialize(serialized) {
|
||||||
|
let navItems, settingsArray;
|
||||||
|
|
||||||
|
try {
|
||||||
|
settingsArray = JSON.parse(serialized) || [];
|
||||||
|
} catch (e) {
|
||||||
|
settingsArray = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
navItems = settingsArray.map((itemDetails) => {
|
||||||
|
return NavigationItem.create(itemDetails);
|
||||||
|
});
|
||||||
|
|
||||||
|
return emberA(navItems);
|
||||||
|
},
|
||||||
|
|
||||||
|
serialize(deserialized) {
|
||||||
|
let settingsArray;
|
||||||
|
|
||||||
|
if (isArray(deserialized)) {
|
||||||
|
settingsArray = deserialized.map((item) => {
|
||||||
|
let label = item.get('label').trim();
|
||||||
|
let url = item.get('url').trim();
|
||||||
|
|
||||||
|
return {label, url};
|
||||||
|
}).compact();
|
||||||
|
} else {
|
||||||
|
settingsArray = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify(settingsArray);
|
||||||
|
}
|
||||||
|
});
|
@ -3,7 +3,7 @@ import { expect } from 'chai';
|
|||||||
import { describeComponent, it } from 'ember-mocha';
|
import { describeComponent, it } from 'ember-mocha';
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import { NavItem } from 'ghost/controllers/settings/navigation';
|
import NavItem from 'ghost/models/navigation-item';
|
||||||
|
|
||||||
const {run} = Ember;
|
const {run} = Ember;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { expect } from 'chai';
|
|||||||
import { describeComponent, it } from 'ember-mocha';
|
import { describeComponent, it } from 'ember-mocha';
|
||||||
import hbs from 'htmlbars-inline-precompile';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import { NavItem } from 'ghost/controllers/settings/navigation';
|
import NavItem from 'ghost/models/navigation-item';
|
||||||
|
|
||||||
const {run} = Ember;
|
const {run} = Ember;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { expect, assert } from 'chai';
|
import { expect, assert } from 'chai';
|
||||||
import { describeModule, it } from 'ember-mocha';
|
import { describeModule, it } from 'ember-mocha';
|
||||||
import Ember from 'ember';
|
import Ember from 'ember';
|
||||||
import { NavItem } from 'ghost/controllers/settings/navigation';
|
import NavItem from 'ghost/models/navigation-item';
|
||||||
|
|
||||||
const {run} = Ember;
|
const {run} = Ember;
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ describeModule(
|
|||||||
'Unit: Controller: settings/navigation',
|
'Unit: Controller: settings/navigation',
|
||||||
{
|
{
|
||||||
// Specify the other units that are required for this test.
|
// Specify the other units that are required for this test.
|
||||||
needs: ['service:config', 'service:notifications']
|
needs: ['service:config', 'service:notifications', 'model:navigation-item']
|
||||||
},
|
},
|
||||||
function () {
|
function () {
|
||||||
it('blogUrl: captures config and ensures trailing slash', function () {
|
it('blogUrl: captures config and ensures trailing slash', function () {
|
||||||
@ -46,35 +46,23 @@ describeModule(
|
|||||||
expect(ctrl.get('blogUrl')).to.equal('http://localhost:2368/blog/');
|
expect(ctrl.get('blogUrl')).to.equal('http://localhost:2368/blog/');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('navigationItems: generates list of NavItems', function () {
|
|
||||||
let ctrl = this.subject();
|
|
||||||
|
|
||||||
run(() => {
|
|
||||||
ctrl.set('model', Ember.Object.create({navigation: navSettingJSON}));
|
|
||||||
expect(ctrl.get('navigationItems.length')).to.equal(8);
|
|
||||||
expect(ctrl.get('navigationItems.firstObject.label')).to.equal('Home');
|
|
||||||
expect(ctrl.get('navigationItems.firstObject.url')).to.equal('/');
|
|
||||||
expect(ctrl.get('navigationItems.firstObject.isNew')).to.be.false;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('save: validates nav items', function (done) {
|
it('save: validates nav items', function (done) {
|
||||||
let ctrl = this.subject();
|
let ctrl = this.subject();
|
||||||
|
|
||||||
run(() => {
|
run(() => {
|
||||||
ctrl.set('model', Ember.Object.create({navigation: `[
|
ctrl.set('model', Ember.Object.create({navigation: [
|
||||||
{"label":"First", "url":"/"},
|
NavItem.create({label: 'First', url: '/'}),
|
||||||
{"label":"", "url":"/second"},
|
NavItem.create({label: '', url: '/second'}),
|
||||||
{"label":"Third", "url":""}
|
NavItem.create({label: 'Third', url: ''})
|
||||||
]`}));
|
]}));
|
||||||
// blank item won't get added because the last item is incomplete
|
// blank item won't get added because the last item is incomplete
|
||||||
expect(ctrl.get('navigationItems.length')).to.equal(3);
|
expect(ctrl.get('model.navigation.length')).to.equal(3);
|
||||||
|
|
||||||
ctrl.save().then(function passedValidation() {
|
ctrl.save().then(function passedValidation() {
|
||||||
assert(false, 'navigationItems weren\'t validated on save');
|
assert(false, 'navigationItems weren\'t validated on save');
|
||||||
done();
|
done();
|
||||||
}).catch(function failedValidation() {
|
}).catch(function failedValidation() {
|
||||||
let navItems = ctrl.get('navigationItems');
|
let navItems = ctrl.get('model.navigation');
|
||||||
expect(navItems[0].get('errors').toArray()).to.be.empty;
|
expect(navItems[0].get('errors').toArray()).to.be.empty;
|
||||||
expect(navItems[1].get('errors.firstObject.attribute')).to.equal('label');
|
expect(navItems[1].get('errors.firstObject.attribute')).to.equal('label');
|
||||||
expect(navItems[2].get('errors.firstObject.attribute')).to.equal('url');
|
expect(navItems[2].get('errors.firstObject.attribute')).to.equal('url');
|
||||||
@ -87,61 +75,34 @@ describeModule(
|
|||||||
let ctrl = this.subject();
|
let ctrl = this.subject();
|
||||||
|
|
||||||
run(() => {
|
run(() => {
|
||||||
ctrl.set('model', Ember.Object.create({navigation: `[
|
ctrl.set('model', Ember.Object.create({navigation: [
|
||||||
{"label":"First", "url":"/"},
|
NavItem.create({label: 'First', url: '/'}),
|
||||||
{"label":"", "url":""}
|
NavItem.create({label: '', url: ''})
|
||||||
]`}));
|
]}));
|
||||||
|
|
||||||
expect(ctrl.get('navigationItems.length')).to.equal(2);
|
expect(ctrl.get('model.navigation.length')).to.equal(2);
|
||||||
|
|
||||||
ctrl.save().then(function passedValidation() {
|
ctrl.save().then(function passedValidation() {
|
||||||
assert(false, 'navigationItems weren\'t validated on save');
|
assert(false, 'navigationItems weren\'t validated on save');
|
||||||
done();
|
done();
|
||||||
}).catch(function failedValidation() {
|
}).catch(function failedValidation() {
|
||||||
let navItems = ctrl.get('navigationItems');
|
let navItems = ctrl.get('model.navigation');
|
||||||
expect(navItems[0].get('errors').toArray()).to.be.empty;
|
expect(navItems[0].get('errors').toArray()).to.be.empty;
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('save: generates new navigation JSON', function (done) {
|
|
||||||
let ctrl = this.subject();
|
|
||||||
let model = Ember.Object.create({navigation: {}});
|
|
||||||
let expectedJSON = `[{"label":"New","url":"/new"}]`;
|
|
||||||
|
|
||||||
model.save = function () {
|
|
||||||
return new Ember.RSVP.Promise((resolve, reject) => {
|
|
||||||
return resolve(this);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
run(() => {
|
|
||||||
ctrl.set('model', model);
|
|
||||||
|
|
||||||
// remove inserted blank item so validation works
|
|
||||||
ctrl.get('navigationItems').removeObject(ctrl.get('navigationItems.firstObject'));
|
|
||||||
// add new object
|
|
||||||
ctrl.get('navigationItems').addObject(NavItem.create({label: 'New', url: '/new'}));
|
|
||||||
|
|
||||||
ctrl.save().then(function success() {
|
|
||||||
expect(ctrl.get('model.navigation')).to.equal(expectedJSON);
|
|
||||||
done();
|
|
||||||
}, function failure() {
|
|
||||||
assert(false, 'save failed with valid data');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('action - addItem: adds item to navigationItems', function () {
|
it('action - addItem: adds item to navigationItems', function () {
|
||||||
let ctrl = this.subject();
|
let ctrl = this.subject();
|
||||||
|
|
||||||
run(() => {
|
run(() => {
|
||||||
ctrl.set('navigationItems', [NavItem.create({label: 'First', url: '/first', last: true})]);
|
ctrl.set('model', Ember.Object.create({navigation: [
|
||||||
|
NavItem.create({label: 'First', url: '/first', last: true})
|
||||||
|
]}));
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(ctrl.get('navigationItems.length')).to.equal(1);
|
expect(ctrl.get('model.navigation.length')).to.equal(1);
|
||||||
|
|
||||||
ctrl.set('newNavItem.label', 'New');
|
ctrl.set('newNavItem.label', 'New');
|
||||||
ctrl.set('newNavItem.url', '/new');
|
ctrl.set('newNavItem.url', '/new');
|
||||||
@ -150,10 +111,10 @@ describeModule(
|
|||||||
ctrl.send('addItem');
|
ctrl.send('addItem');
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(ctrl.get('navigationItems.length')).to.equal(2);
|
expect(ctrl.get('model.navigation.length')).to.equal(2);
|
||||||
expect(ctrl.get('navigationItems.lastObject.label')).to.equal('New');
|
expect(ctrl.get('model.navigation.lastObject.label')).to.equal('New');
|
||||||
expect(ctrl.get('navigationItems.lastObject.url')).to.equal('/new');
|
expect(ctrl.get('model.navigation.lastObject.url')).to.equal('/new');
|
||||||
expect(ctrl.get('navigationItems.lastObject.isNew')).to.be.false;
|
expect(ctrl.get('model.navigation.lastObject.isNew')).to.be.false;
|
||||||
expect(ctrl.get('newNavItem.label')).to.be.blank;
|
expect(ctrl.get('newNavItem.label')).to.be.blank;
|
||||||
expect(ctrl.get('newNavItem.url')).to.be.blank;
|
expect(ctrl.get('newNavItem.url')).to.be.blank;
|
||||||
expect(ctrl.get('newNavItem.isNew')).to.be.true;
|
expect(ctrl.get('newNavItem.isNew')).to.be.true;
|
||||||
@ -163,10 +124,12 @@ describeModule(
|
|||||||
let ctrl = this.subject();
|
let ctrl = this.subject();
|
||||||
|
|
||||||
run(() => {
|
run(() => {
|
||||||
ctrl.set('navigationItems', [NavItem.create({label: '', url: '', last: true})]);
|
ctrl.set('model', Ember.Object.create({navigation: [
|
||||||
expect(ctrl.get('navigationItems.length')).to.equal(1);
|
NavItem.create({label: '', url: '', last: true})
|
||||||
|
]}));
|
||||||
|
expect(ctrl.get('model.navigation.length')).to.equal(1);
|
||||||
ctrl.send('addItem');
|
ctrl.send('addItem');
|
||||||
expect(ctrl.get('navigationItems.length')).to.equal(1);
|
expect(ctrl.get('model.navigation.length')).to.equal(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -178,10 +141,10 @@ describeModule(
|
|||||||
];
|
];
|
||||||
|
|
||||||
run(() => {
|
run(() => {
|
||||||
ctrl.set('navigationItems', navItems);
|
ctrl.set('model', Ember.Object.create({navigation: navItems}));
|
||||||
expect(ctrl.get('navigationItems').mapBy('label')).to.deep.equal(['First', 'Second']);
|
expect(ctrl.get('model.navigation').mapBy('label')).to.deep.equal(['First', 'Second']);
|
||||||
ctrl.send('deleteItem', ctrl.get('navigationItems.firstObject'));
|
ctrl.send('deleteItem', ctrl.get('model.navigation.firstObject'));
|
||||||
expect(ctrl.get('navigationItems').mapBy('label')).to.deep.equal(['Second']);
|
expect(ctrl.get('model.navigation').mapBy('label')).to.deep.equal(['Second']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -193,10 +156,10 @@ describeModule(
|
|||||||
];
|
];
|
||||||
|
|
||||||
run(() => {
|
run(() => {
|
||||||
ctrl.set('navigationItems', navItems);
|
ctrl.set('model', Ember.Object.create({navigation: navItems}));
|
||||||
expect(ctrl.get('navigationItems').mapBy('label')).to.deep.equal(['First', 'Second']);
|
expect(ctrl.get('model.navigation').mapBy('label')).to.deep.equal(['First', 'Second']);
|
||||||
ctrl.send('reorderItems', navItems.reverseObjects());
|
ctrl.send('reorderItems', navItems.reverseObjects());
|
||||||
expect(ctrl.get('navigationItems').mapBy('label')).to.deep.equal(['Second', 'First']);
|
expect(ctrl.get('model.navigation').mapBy('label')).to.deep.equal(['Second', 'First']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -208,10 +171,10 @@ describeModule(
|
|||||||
];
|
];
|
||||||
|
|
||||||
run(() => {
|
run(() => {
|
||||||
ctrl.set('navigationItems', navItems);
|
ctrl.set('model', Ember.Object.create({navigation: navItems}));
|
||||||
expect(ctrl.get('navigationItems').mapBy('url')).to.deep.equal(['/first', '/second']);
|
expect(ctrl.get('model.navigation').mapBy('url')).to.deep.equal(['/first', '/second']);
|
||||||
ctrl.send('updateUrl', '/new', ctrl.get('navigationItems.firstObject'));
|
ctrl.send('updateUrl', '/new', ctrl.get('model.navigation.firstObject'));
|
||||||
expect(ctrl.get('navigationItems').mapBy('url')).to.deep.equal(['/new', '/second']);
|
expect(ctrl.get('model.navigation').mapBy('url')).to.deep.equal(['/new', '/second']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
67
ghost/admin/tests/unit/models/navigation-item-test.js
Normal file
67
ghost/admin/tests/unit/models/navigation-item-test.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* jshint expr:true */
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { describeModule, it } from 'ember-mocha';
|
||||||
|
|
||||||
|
describeModule(
|
||||||
|
'model:navigation-item',
|
||||||
|
'Unit: Model: navigation-item',
|
||||||
|
{
|
||||||
|
// Specify the other units that are required for this test.
|
||||||
|
needs: []
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
it('isComplete is true when label and url are filled', function () {
|
||||||
|
let model = this.subject();
|
||||||
|
|
||||||
|
model.set('label', 'test');
|
||||||
|
model.set('url', 'test');
|
||||||
|
|
||||||
|
expect(model.get('isComplete')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isComplete is false when label is blank', function () {
|
||||||
|
let model = this.subject();
|
||||||
|
|
||||||
|
model.set('label', '');
|
||||||
|
model.set('url', 'test');
|
||||||
|
|
||||||
|
expect(model.get('isComplete')).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isComplete is false when url is blank', function () {
|
||||||
|
let model = this.subject();
|
||||||
|
|
||||||
|
model.set('label', 'test');
|
||||||
|
model.set('url', '');
|
||||||
|
|
||||||
|
expect(model.get('isComplete')).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isBlank is true when label and url are blank', function () {
|
||||||
|
let model = this.subject();
|
||||||
|
|
||||||
|
model.set('label', '');
|
||||||
|
model.set('url', '');
|
||||||
|
|
||||||
|
expect(model.get('isBlank')).to.be.true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isBlank is false when label is present', function () {
|
||||||
|
let model = this.subject();
|
||||||
|
|
||||||
|
model.set('label', 'test');
|
||||||
|
model.set('url', '');
|
||||||
|
|
||||||
|
expect(model.get('isBlank')).to.be.false;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('isBlank is false when url is present', function () {
|
||||||
|
let model = this.subject();
|
||||||
|
|
||||||
|
model.set('label', '');
|
||||||
|
model.set('url', 'test');
|
||||||
|
|
||||||
|
expect(model.get('isBlank')).to.be.false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -0,0 +1,42 @@
|
|||||||
|
/* jshint expr:true */
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { describeModule, it } from 'ember-mocha';
|
||||||
|
import Ember from 'ember';
|
||||||
|
import NavigationItem from 'ghost/models/navigation-item';
|
||||||
|
|
||||||
|
const emberA = Ember.A;
|
||||||
|
|
||||||
|
describeModule(
|
||||||
|
'transform:navigation-settings',
|
||||||
|
'Unit: Transform: navigation-settings',
|
||||||
|
{
|
||||||
|
// Specify the other units that are required for this test.
|
||||||
|
// needs: ['transform:foo']
|
||||||
|
},
|
||||||
|
function() {
|
||||||
|
it('deserializes navigation json', function () {
|
||||||
|
let transform = this.subject();
|
||||||
|
let serialized = '[{"label":"One","url":"/one"},{"label":"Two","url":"/two"}]';
|
||||||
|
let result = transform.deserialize(serialized);
|
||||||
|
|
||||||
|
expect(result.length).to.equal(2);
|
||||||
|
expect(result[0]).to.be.instanceof(NavigationItem);
|
||||||
|
expect(result[0].get('label')).to.equal('One');
|
||||||
|
expect(result[0].get('url')).to.equal('/one');
|
||||||
|
expect(result[1]).to.be.instanceof(NavigationItem);
|
||||||
|
expect(result[1].get('label')).to.equal('Two');
|
||||||
|
expect(result[1].get('url')).to.equal('/two');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('serializes array of NavigationItems', function () {
|
||||||
|
let transform = this.subject();
|
||||||
|
let deserialized = emberA([
|
||||||
|
NavigationItem.create({label: 'One', url: '/one'}),
|
||||||
|
NavigationItem.create({label: 'Two', url: '/two'})
|
||||||
|
]);
|
||||||
|
let result = transform.serialize(deserialized);
|
||||||
|
|
||||||
|
expect(result).to.equal('[{"label":"One","url":"/one"},{"label":"Two","url":"/two"}]');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
@ -5,7 +5,7 @@ import {
|
|||||||
it
|
it
|
||||||
} from 'mocha';
|
} from 'mocha';
|
||||||
import validator from 'ghost/validators/nav-item';
|
import validator from 'ghost/validators/nav-item';
|
||||||
import { NavItem } from 'ghost/controllers/settings/navigation';
|
import NavItem from 'ghost/models/navigation-item';
|
||||||
|
|
||||||
const testInvalidUrl = function (url) {
|
const testInvalidUrl = function (url) {
|
||||||
let navItem = NavItem.create({url});
|
let navItem = NavItem.create({url});
|
||||||
|
Loading…
Reference in New Issue
Block a user