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:
parent
f96e9855f9
commit
8aaf2e1356
12 changed files with 280 additions and 162 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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}));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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');
|
||||
|
||||
|
|
|
@ -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']);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue