1
0
Fork 0
mirror of https://github.com/TryGhost/Ghost-Admin.git synced 2023-12-14 02:33:04 +01:00

Replace jquery-ui.sortable with ember-sortable for nav items

refs #6458, closes #6457
- replaces jquery-ui.sortable with ember-sortable for drag-n-drop handling
- moves the "new/blank" nav item out of the nav items list
  - allows it to be excluded from the draggable list
  - cleans up handling of the `navigationItems` array as there's no longer a need to ignore/exclude this extra item
- clears validation errors when typing in the respective field
- adds acceptance test for adding/removing nav items
- improves acceptance test for saving nav items to cover more edge cases
This commit is contained in:
Kevin Ansfield 2016-02-09 17:16:18 +00:00
parent f96e9855f9
commit 8aaf2e1356
12 changed files with 280 additions and 162 deletions

View file

@ -26,8 +26,8 @@ export default TextField.extend({
return this.get('baseUrl') === this.get('value');
}),
fakePlaceholder: computed('isBaseUrl', 'hasFocus', function () {
return this.get('isBaseUrl') && this.get('last') && !this.get('hasFocus');
fakePlaceholder: computed('isBaseUrl', 'hasFocus', 'isNew', function () {
return this.get('isBaseUrl') && this.get('isNew') && !this.get('hasFocus');
}),
didReceiveAttrs() {
@ -72,9 +72,10 @@ export default TextField.extend({
},
keyPress(event) {
this.attrs.clearErrors();
// enter key
if (event.keyCode === 13) {
event.preventDefault();
this.notifyUrlChanged();
}

View file

@ -1,15 +1,18 @@
import Ember from 'ember';
import ValidationStateMixin from 'ghost/mixins/validation-state';
import ValidationState from 'ghost/mixins/validation-state';
import SortableItem from 'ember-sortable/mixins/sortable-item';
const {Component, computed} = Ember;
const {readOnly} = computed;
const {Component, computed, run} = Ember;
const {alias, readOnly} = computed;
export default Component.extend(ValidationStateMixin, {
export default Component.extend(ValidationState, SortableItem, {
classNames: 'gh-blognav-item',
classNameBindings: ['errorClass'],
classNameBindings: ['errorClass', 'navItem.isNew::gh-blognav-item--sortable'],
attributeBindings: ['order:data-order'],
order: readOnly('navItem.order'),
new: false,
handle: '.gh-blognav-grab',
model: alias('navItem'),
errors: readOnly('navItem.errors'),
errorClass: computed('hasError', function () {
@ -20,12 +23,12 @@ export default Component.extend(ValidationStateMixin, {
keyPress(event) {
// enter key
if (event.keyCode === 13) {
if (event.keyCode === 13 && this.get('navItem.isNew')) {
event.preventDefault();
this.send('addItem');
run.scheduleOnce('actions', this, function () {
this.send('addItem');
});
}
this.get('navItem.errors').clear();
},
actions: {
@ -39,6 +42,14 @@ export default Component.extend(ValidationStateMixin, {
updateUrl(value) {
this.sendAction('updateUrl', value, this.get('navItem'));
},
clearLabelErrors() {
this.get('navItem.errors').remove('label');
},
clearUrlErrors() {
this.get('navItem.errors').remove('url');
}
}
});

View file

@ -8,8 +8,7 @@ const {
RSVP,
computed,
inject: {service},
isBlank,
observer
isBlank
} = Ember;
const {Errors} = DS;
const emberA = Ember.A;
@ -17,7 +16,7 @@ const emberA = Ember.A;
export const NavItem = Ember.Object.extend(ValidationEngine, {
label: '',
url: '',
last: false,
isNew: false,
validationType: 'navItem',
@ -44,6 +43,8 @@ export default Controller.extend(SettingsSaveMixin, {
config: service(),
notifications: service(),
newNavItem: null,
blogUrl: computed('config.blogUrl', function () {
let url = this.get('config.blogUrl');
@ -51,8 +52,7 @@ export default Controller.extend(SettingsSaveMixin, {
}),
navigationItems: computed('model.navigation', function () {
let lastItem,
navItems;
let navItems;
try {
navItems = JSON.parse(this.get('model.navigation') || [{}]);
@ -64,38 +64,27 @@ export default Controller.extend(SettingsSaveMixin, {
return NavItem.create(item);
});
lastItem = navItems.get('lastObject');
if (!lastItem || lastItem.get('isComplete')) {
navItems.addObject(NavItem.create({last: true}));
}
return navItems;
}),
updateLastNavItem: observer('navigationItems.[]', function () {
let navItems = this.get('navigationItems');
navItems.forEach((item, index, items) => {
if (index === (items.length - 1)) {
item.set('last', true);
} else {
item.set('last', false);
}
});
}),
init() {
this._super(...arguments);
this.set('newNavItem', NavItem.create({isNew: true}));
},
save() {
let navItems = this.get('navigationItems');
let newNavItem = this.get('newNavItem');
let notifications = this.get('notifications');
let navSetting,
validationPromises;
let validationPromises = [];
let navSetting;
validationPromises = navItems.map((item) => {
if (item.get('last') && item.get('isBlank')) {
return;
}
if (!newNavItem.get('isBlank')) {
validationPromises.pushObject(this.send('addItem'));
}
return item.validate();
navItems.map((item) => {
validationPromises.pushObject(item.validate());
});
return RSVP.all(validationPromises).then(() => {
@ -103,10 +92,6 @@ export default Controller.extend(SettingsSaveMixin, {
let label = item.get('label').trim();
let url = item.get('url').trim();
if (item.get('last') && !item.get('isComplete')) {
return null;
}
return {label, url};
}).compact();
@ -124,17 +109,22 @@ export default Controller.extend(SettingsSaveMixin, {
});
},
addNewNavItem() {
let navItems = this.get('navigationItems');
let newNavItem = this.get('newNavItem');
newNavItem.set('isNew', false);
navItems.pushObject(newNavItem);
this.set('newNavItem', NavItem.create({isNew: true}));
},
actions: {
addItem() {
let navItems = this.get('navigationItems');
let lastItem = navItems.get('lastObject');
let newNavItem = this.get('newNavItem');
if (lastItem) {
lastItem.validate().then(() => {
// Add new blank navItem
navItems.addObject(NavItem.create({last: true}));
});
}
return newNavItem.validate().then(() => {
this.addNewNavItem();
});
},
deleteItem(item) {
@ -147,12 +137,8 @@ export default Controller.extend(SettingsSaveMixin, {
navItems.removeObject(item);
},
moveItem(index, newIndex) {
let navItems = this.get('navigationItems');
let item = navItems.objectAt(index);
navItems.removeAt(index);
navItems.insertAt(newIndex, item);
reorderItems(navItems) {
this.set('navigationItems', navItems);
},
updateUrl(url, navItem) {
@ -161,6 +147,10 @@ export default Controller.extend(SettingsSaveMixin, {
}
navItem.set('url', url);
},
reset() {
this.set('newNavItem', NavItem.create({isNew: true}));
}
}
});

View file

@ -159,7 +159,7 @@ export default function () {
});
this.put('/settings/', function (db, request) {
let newSettings = JSON.parse(request.requestBody);
let newSettings = JSON.parse(request.requestBody).settings;
db.settings.remove();
db.settings.insert(newSettings);

View file

@ -22,6 +22,11 @@ export default AuthenticatedRoute.extend(styleBody, CurrentUserSettings, {
});
},
setupController() {
this._super(...arguments);
this.get('controller').send('reset');
},
actions: {
save() {
// since shortcuts are run on the route, we have to signal to the components

View file

@ -83,15 +83,11 @@
background: color(var(--green) lightness(-10%));
}
.gh-blognav-item:last-child {
.gh-blognav-item:not(.gh-blognav-item--sortable) {
padding-left: calc(16px + 20px);
/* icon-grab + nav-item padding) */
}
.gh-blognav-item:last-child .gh-blognav-grab {
display: none;
}
/* Remove space between inputs on smaller screens */
@media (max-width: 800px) {
.gh-blognav-label {

View file

@ -1,4 +1,4 @@
{{#unless navItem.last}}
{{#unless navItem.isNew}}
<span class="gh-blognav-grab icon-grab">
<span class="sr-only">Reorder</span>
</span>
@ -6,16 +6,16 @@
<div class="gh-blognav-line">
{{#gh-validation-status-container tagName="span" class="gh-blognav-label" errors=navItem.errors property="label" hasValidated=navItem.hasValidated}}
{{gh-trim-focus-input focus=navItem.last placeholder="Label" value=navItem.label}}
{{gh-trim-focus-input focus=navItem.last placeholder="Label" value=navItem.label keyPress=(action "clearLabelErrors")}}
{{gh-error-message errors=navItem.errors property="label"}}
{{/gh-validation-status-container}}
{{#gh-validation-status-container tagName="span" class="gh-blognav-url" errors=navItem.errors property="url" hasValidated=navItem.hasValidated}}
{{gh-navitem-url-input baseUrl=baseUrl url=navItem.url last=navItem.last change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=navItem.url isNew=navItem.isNew change="updateUrl" clearErrors=(action "clearUrlErrors")}}
{{gh-error-message errors=navItem.errors property="url"}}
{{/gh-validation-status-container}}
</div>
{{#if navItem.last}}
{{#if navItem.isNew}}
<button type="button" class="gh-blognav-add" {{action "addItem"}}>
<i class="icon-add2"><span class="sr-only">Add</span></i>
</button>

View file

@ -1,4 +1,4 @@
{{#gh-navigation moveItem="moveItem"}}
<section class="gh-view">
<header class="view-header">
{{#gh-view-title openMobileMenu="openMobileMenu"}}<span>Navigation</span>{{/gh-view-title}}
<section class="view-actions">
@ -7,10 +7,13 @@
</header>
<section class="view-container">
<form id="settings-navigation" class="gh-blognav js-gh-blognav" novalidate="novalidate">
{{#each navigationItems as |navItem|}}
{{gh-navitem navItem=navItem baseUrl=blogUrl addItem="addItem" deleteItem="deleteItem" updateUrl="updateUrl"}}
{{/each}}
<form id="settings-navigation" class="gh-blognav" novalidate="novalidate">
{{#sortable-group onChange=(action 'reorderItems') as |group|}}
{{#each navigationItems as |navItem|}}
{{gh-navitem navItem=navItem baseUrl=blogUrl addItem="addItem" deleteItem="deleteItem" updateUrl="updateUrl" group=group}}
{{/each}}
{{/sortable-group}}
{{gh-navitem navItem=newNavItem baseUrl=blogUrl addItem="addItem" updateUrl="updateUrl"}}
</form>
</section>
{{/gh-navigation}}
</section>

View file

@ -60,12 +60,17 @@ describe('Acceptance: Settings - Navigation', function () {
andThen(function () {
expect(currentPath()).to.equal('settings.navigation');
// test has expected number of rows
expect($('.gh-blognav-item').length, 'navigation items count').to.equal(3);
// fixtures contain two nav items, check for three rows as we
// should have one extra that's blank
expect(
find('.gh-blognav-item').length,
'navigation items count'
).to.equal(3);
});
});
it('saves settings', function () {
it('saves navigation settings', function () {
visit('/settings/navigation');
fillIn('.gh-blognav-label:first input', 'Test');
fillIn('.gh-blognav-url:first input', '/test');
@ -74,14 +79,47 @@ describe('Acceptance: Settings - Navigation', function () {
click('.btn-blue');
andThen(function () {
// TODO: Test for successful save here once we have a visual
// indication. For now we know the save happened because
// Pretender doesn't complain about an unknown URL
let [navSetting] = server.db.settings.where({key: 'navigation'});
expect(navSetting.value).to.equal('[{"label":"Test","url":"/test/"},{"label":"About","url":"/about"}]');
// don't test against .error directly as it will pick up failed
// tests "pre.error" elements
expect($('span.error').length, 'error fields count').to.equal(0);
expect($('.gh-alert').length, 'alerts count').to.equal(0);
expect(find('span.error').length, 'error fields count').to.equal(0);
expect(find('.gh-alert').length, 'alerts count').to.equal(0);
expect(find('.response:visible').length, 'validation errors count')
.to.equal(0);
});
});
it('validates new item correctly on save', function () {
visit('/settings/navigation');
click('.btn-blue');
andThen(function () {
expect(
find('.gh-blognav-item').length,
'number of nav items after saving with blank new item'
).to.equal(3);
});
fillIn('.gh-blognav-label:last input', 'Test');
fillIn('.gh-blognav-url:last input', 'http://invalid domain/');
triggerEvent('.gh-blognav-url:last input', 'blur');
click('.btn-blue');
andThen(function () {
expect(
find('.gh-blognav-item').length,
'number of nav items after saving with invalid new item'
).to.equal(3);
expect(
find('.gh-blognav-item:last .response:visible').length,
'number of invalid fields in new item'
).to.equal(1);
});
});
@ -91,14 +129,105 @@ describe('Acceptance: Settings - Navigation', function () {
triggerEvent('.gh-blognav-label:first input', 'blur');
andThen(function () {
expect($('.gh-blognav-label:first input').val()).to.equal('Test');
expect(find('.gh-blognav-label:first input').val()).to.equal('Test');
});
visit('/settings/code-injection');
visit('/settings/navigation');
andThen(function () {
expect($('.gh-blognav-label:first input').val()).to.equal('Home');
expect(find('.gh-blognav-label:first input').val()).to.equal('Home');
});
});
it('can add and remove items', function (done) {
visit('/settings/navigation');
click('.gh-blognav-add');
andThen(function () {
expect(
find('.gh-blognav-label:last .response').is(':visible'),
'blank label has validation error'
).to.be.true;
expect(
find('.gh-blognav-url:last .response').is(':visible'),
'blank url has validation error'
).to.be.true;
});
fillIn('.gh-blognav-label:last input', 'New');
triggerEvent('.gh-blognav-label:last input', 'keypress', {});
andThen(function () {
expect(
find('.gh-blognav-label:last .response').is(':visible'),
'label validation is visible after typing'
).to.be.false;
expect(
find('.gh-blognav-url:last .response').is(':visible'),
'blank url still has validation error'
).to.be.true;
});
fillIn('.gh-blognav-url:last input', '/new');
triggerEvent('.gh-blognav-url:last input', 'keypress', {});
triggerEvent('.gh-blognav-url:last input', 'blur');
andThen(function () {
expect(
find('.gh-blognav-url:last .response').is(':visible'),
'url validation is visible after typing'
).to.be.false;
expect(
find('.gh-blognav-url:last input').val()
).to.equal(`${window.location.protocol}//${window.location.host}/new/`);
});
click('.gh-blognav-add');
andThen(function () {
expect(
find('.gh-blognav-item').length,
'number of nav items after successful add'
).to.equal(4);
expect(
find('.gh-blognav-label:last input').val(),
'new item label value after successful add'
).to.be.blank;
expect(
find('.gh-blognav-url:last input').val(),
'new item url value after successful add'
).to.equal(`${window.location.protocol}//${window.location.host}/`);
expect(
find('.gh-blognav-item .response:visible').length,
'number or validation errors shown after successful add'
).to.equal(0);
});
click('.gh-blognav-item:first .gh-blognav-delete');
andThen(function () {
expect(
find('.gh-blognav-item').length,
'number of nav items after successful remove'
).to.equal(3);
});
click('.btn-blue');
andThen(function () {
let [navSetting] = server.db.settings.where({key: 'navigation'});
expect(navSetting.value).to.equal('[{"label":"About","url":"/about"},{"label":"New","url":"/new/"}]');
done();
});
});
});

View file

@ -35,8 +35,8 @@ describeComponent(
expect($item.find('.response:visible').length).to.equal(0);
});
it('doesn\'t show drag handle for last item', function () {
this.set('navItem', NavItem.create({label: 'Test', url: '/url', last: true}));
it('doesn\'t show drag handle for new items', function () {
this.set('navItem', NavItem.create({label: 'Test', url: '/url', isNew: true}));
this.render(hbs`{{gh-navitem navItem=navItem baseUrl=baseUrl}}`);
let $item = this.$('.gh-blognav-item');
@ -44,8 +44,8 @@ describeComponent(
expect($item.find('.gh-blognav-grab').length).to.equal(0);
});
it('shows add button for last item', function () {
this.set('navItem', NavItem.create({label: 'Test', url: '/url', last: true}));
it('shows add button for new items', function () {
this.set('navItem', NavItem.create({label: 'Test', url: '/url', isNew: true}));
this.render(hbs`{{gh-navitem navItem=navItem baseUrl=baseUrl}}`);
let $item = this.$('.gh-blognav-item');
@ -70,7 +70,7 @@ describeComponent(
});
it('triggers add action', function () {
this.set('navItem', NavItem.create({label: 'Test', url: '/url', last: true}));
this.set('navItem', NavItem.create({label: 'Test', url: '/url', isNew: true}));
let addActionCallCount = 0;
this.on('add', () => {

View file

@ -23,12 +23,15 @@ describeComponent(
// set defaults
this.set('baseUrl', currentUrl);
this.set('url', '');
this.set('isLast', false);
this.set('isNew', false);
this.on('clearErrors', function () {
return null;
});
});
it('renders correctly with blank url', function () {
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -40,7 +43,7 @@ describeComponent(
it('renders correctly with relative urls', function () {
this.set('url', '/about');
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -53,7 +56,7 @@ describeComponent(
it('renders correctly with absolute urls', function () {
this.set('url', 'https://example.com:2368/#test');
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -74,7 +77,7 @@ describeComponent(
it('deletes base URL on backspace', function () {
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -90,7 +93,7 @@ describeComponent(
it('deletes base URL on delete', function () {
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -109,7 +112,7 @@ describeComponent(
return null;
});
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -128,7 +131,7 @@ describeComponent(
return null;
});
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -153,7 +156,7 @@ describeComponent(
return null;
});
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -175,7 +178,7 @@ describeComponent(
return null;
});
this.render(hbs`
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -187,9 +190,9 @@ describeComponent(
});
it('toggles .fake-placeholder on focus', function () {
this.set('isLast', true);
this.set('isNew', true);
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -208,7 +211,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -224,7 +227,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -245,7 +248,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -268,7 +271,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -301,7 +304,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -330,7 +333,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -349,7 +352,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -375,7 +378,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -403,7 +406,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -436,7 +439,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');
@ -463,7 +466,7 @@ describeComponent(
});
this.render(hbs `
{{gh-navitem-url-input baseUrl=baseUrl url=url last=isLast change="updateUrl"}}
{{gh-navitem-url-input baseUrl=baseUrl url=url isNew=isNew change="updateUrl" clearErrors=(action "clearErrors")}}
`);
let $input = this.$('input');

View file

@ -31,55 +31,30 @@ describeModule(
expect(ctrl.get('blogUrl')).to.equal('http://localhost:2368/blog/');
});
it('init: creates a new navigation item', function () {
let ctrl = this.subject();
run(() => {
expect(ctrl.get('newNavItem')).to.exist;
expect(ctrl.get('newNavItem.isNew')).to.be.true;
});
});
it('blogUrl: captures config and ensures trailing slash', function () {
let ctrl = this.subject();
ctrl.set('config.blogUrl', '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();
let lastItem;
run(() => {
ctrl.set('model', Ember.Object.create({navigation: navSettingJSON}));
expect(ctrl.get('navigationItems.length')).to.equal(9);
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.last')).to.be.false;
// adds a blank item as last one is complete
lastItem = ctrl.get('navigationItems.lastObject');
expect(lastItem.get('label')).to.equal('');
expect(lastItem.get('url')).to.equal('');
expect(lastItem.get('last')).to.be.true;
});
});
it('navigationItems: adds blank item if navigation setting is empty', function () {
let ctrl = this.subject();
let lastItem;
run(() => {
ctrl.set('model', Ember.Object.create({navigation: null}));
expect(ctrl.get('navigationItems.length')).to.equal(1);
lastItem = ctrl.get('navigationItems.lastObject');
expect(lastItem.get('label')).to.equal('');
expect(lastItem.get('url')).to.equal('');
});
});
it('updateLastNavItem: correctly sets "last" properties', function () {
let ctrl = this.subject();
let item1,
item2;
run(() => {
ctrl.set('model', Ember.Object.create({navigation: navSettingJSON}));
item1 = ctrl.get('navigationItems.lastObject');
expect(item1.get('last')).to.be.true;
ctrl.get('navigationItems').addObject(Ember.Object.create({label: 'Test', url: '/test'}));
item2 = ctrl.get('navigationItems.lastObject');
expect(item2.get('last')).to.be.true;
expect(item1.get('last')).to.be.false;
expect(ctrl.get('navigationItems.firstObject.isNew')).to.be.false;
});
});
@ -168,15 +143,20 @@ describeModule(
expect(ctrl.get('navigationItems.length')).to.equal(1);
ctrl.set('newNavItem.label', 'New');
ctrl.set('newNavItem.url', '/new');
run(() => {
ctrl.send('addItem');
});
expect(ctrl.get('navigationItems.length')).to.equal(2);
expect(ctrl.get('navigationItems.firstObject.last')).to.be.false;
expect(ctrl.get('navigationItems.lastObject.label')).to.equal('');
expect(ctrl.get('navigationItems.lastObject.url')).to.equal('');
expect(ctrl.get('navigationItems.lastObject.last')).to.be.true;
expect(ctrl.get('navigationItems.lastObject.label')).to.equal('New');
expect(ctrl.get('navigationItems.lastObject.url')).to.equal('/new');
expect(ctrl.get('navigationItems.lastObject.isNew')).to.be.false;
expect(ctrl.get('newNavItem.label')).to.be.blank;
expect(ctrl.get('newNavItem.url')).to.be.blank;
expect(ctrl.get('newNavItem.isNew')).to.be.true;
});
it('action - addItem: doesn\'t insert new item if last object is incomplete', function () {
@ -205,7 +185,7 @@ describeModule(
});
});
it('action - moveItem: updates navigationItems list', function () {
it('action - reorderItems: updates navigationItems list', function () {
let ctrl = this.subject();
let navItems = [
NavItem.create({label: 'First', url: '/first'}),
@ -215,7 +195,7 @@ describeModule(
run(() => {
ctrl.set('navigationItems', navItems);
expect(ctrl.get('navigationItems').mapBy('label')).to.deep.equal(['First', 'Second']);
ctrl.send('moveItem', 1, 0);
ctrl.send('reorderItems', navItems.reverseObjects());
expect(ctrl.get('navigationItems').mapBy('label')).to.deep.equal(['Second', 'First']);
});
});