From c9d053b950c86bd22250fbaf6575cad0e452ac73 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 19 Aug 2015 10:16:32 +0100 Subject: [PATCH] Replace the current tag input with a selectize based input issue #3800, closes #5648 - uses ember-cli-selectize addon for the tag editing functionality in the PSM --- core/client/app/components/gh-tags-input.js | 281 ------------ .../app/controllers/post-settings-menu.js | 46 ++ .../app/styles/components/dropdowns.css | 8 + .../templates/components/gh-tags-input.hbs | 6 - .../app/templates/post-settings-menu.hbs | 10 +- core/client/bower.json | 1 + core/client/package.json | 1 + .../unit/components/gh-tags-input-test.js | 405 ------------------ core/test/functional/client/psm_test.js | 119 ++--- 9 files changed, 100 insertions(+), 777 deletions(-) delete mode 100644 core/client/app/components/gh-tags-input.js delete mode 100644 core/client/app/templates/components/gh-tags-input.hbs delete mode 100644 core/client/tests/unit/components/gh-tags-input-test.js diff --git a/core/client/app/components/gh-tags-input.js b/core/client/app/components/gh-tags-input.js deleted file mode 100644 index 10351ee179..0000000000 --- a/core/client/app/components/gh-tags-input.js +++ /dev/null @@ -1,281 +0,0 @@ -/* global Bloodhound, key */ -import Ember from 'ember'; - -/** - * Ghost Tag Input Component - * - * Creates an input field that is used to input tags for a post. - * @param {Boolean} hasFocus Whether or not the input is focused - * @param {DS.Model} post The current post object to input tags for - */ -export default Ember.Component.extend({ - classNames: ['gh-input'], - classNameBindings: ['hasFocus:focus'], - - // Uses the Ember-Data store directly, as it needs to create and get tag records - store: Ember.inject.service(), - - hasFocus: false, - post: null, - highlightIndex: null, - - isDirty: false, - isReloading: false, - - unassignedTags: Ember.A(), // tags that AREN'T assigned to this post - currentTags: Ember.A(), // tags that ARE assigned to this post - - // Input field events - click: function () { - this.$('#tag-input').focus(); - }, - - focusIn: function () { - this.set('hasFocus', true); - key.setScope('tags'); - }, - - focusOut: function () { - this.set('hasFocus', false); - key.setScope('default'); - this.set('highlightIndex', null); - // if there is text in the input field, create a tag with it - if (this.$('#tag-input').val() !== '') { - this.send('addTag', this.$('#tag-input').val()); - } - this.saveTags(); - }, - - keyPress: function (event) { - var val = this.$('#tag-input').val(), - isComma = ','.localeCompare(String.fromCharCode(event.keyCode || event.charCode)) === 0; - - if (isComma && val !== '') { - event.preventDefault(); - this.send('addTag', val); - } - }, - - // Tag Loading functions - loadTagsOnInit: Ember.on('init', function () { - var self = this; - - if (this.get('post')) { - this.loadTags().then(function () { - Ember.run.schedule('afterRender', self, 'initTypeahead'); - }); - } - }), - - reloadTags: Ember.observer('post', function () { - var self = this; - - this.loadTags().then(function () { - self.reloadTypeahead(false); - }); - }), - - loadTags: function () { - var self = this, - post = this.get('post'); - - this.get('currentTags').clear(); - this.get('unassignedTags').clear(); - - return this.get('store').find('tag', {limit: 'all'}).then(function (tags) { - if (post.get('id')) { // if it's a new post, it won't have an id - self.get('currentTags').pushObjects(post.get('tags').toArray()); - } - - tags.forEach(function (tag) { - if (Ember.isEmpty(post.get('id')) || Ember.isEmpty(self.get('currentTags').findBy('id', tag.get('id')))) { - self.get('unassignedTags').pushObject(tag); - } - }); - - return Ember.RSVP.resolve(); - }); - }, - - // Key Binding functions - bindKeys: function () { - var self = this; - - key('enter, tab', 'tags', function (event) { - var val = self.$('#tag-input').val(); - - if (val !== '') { - event.preventDefault(); - self.send('addTag', val); - } - }); - - key('backspace', 'tags', function (event) { - if (self.$('#tag-input').val() === '') { - event.preventDefault(); - self.send('deleteTag'); - } - }); - - key('left', 'tags', function (event) { - self.updateHighlightIndex(-1, event); - }); - - key('right', 'tags', function (event) { - self.updateHighlightIndex(1, event); - }); - }, - - unbindKeys: function () { - key.unbind('enter, tab', 'tags'); - key.unbind('backspace', 'tags'); - key.unbind('left', 'tags'); - key.unbind('right', 'tags'); - }, - - didInsertElement: function () { - this.bindKeys(); - }, - - willDestroyElement: function () { - this.unbindKeys(); - this.destroyTypeahead(); - }, - - updateHighlightIndex: function (modifier, event) { - if (this.$('#tag-input').val() === '') { - var highlightIndex = this.get('highlightIndex'), - length = this.get('currentTags.length'), - newIndex; - - if (event) { - event.preventDefault(); - } - - if (highlightIndex === null) { - newIndex = (modifier > 0) ? 0 : length - 1; - } else { - newIndex = highlightIndex + modifier; - if (newIndex < 0 || newIndex >= length) { - newIndex = null; - } - } - this.set('highlightIndex', newIndex); - } - }, - - // Typeahead functions - initTypeahead: function () { - var tags = new Bloodhound({ - datumTokenizer: Bloodhound.tokenizers.whitespace, - queryTokenizer: Bloodhound.tokenizers.whitespace, - local: this.get('unassignedTags').map(function (tag) { - return tag.get('name'); - }) - }); - - this.$('#tag-input').typeahead({ - minLength: 1, - classNames: { - // TODO: Fix CSS for these - input: 'tag-input', - hint: 'tag-input', - menu: 'dropdown-menu', - suggestion: 'dropdown-item', - open: 'open' - } - }, { - name: 'tags', - source: tags - }).bind('typeahead:select', Ember.run.bind(this, 'typeaheadAdd')); - }, - - destroyTypeahead: function () { - this.$('#tag-input').typeahead('destroy'); - }, - - reloadTypeahead: function (refocus) { - refocus = (typeof refocus !== 'undefined') ? refocus : true; // set default refocus value - this.set('isReloading', true); - this.destroyTypeahead(); - this.initTypeahead(); - if (refocus) { - this.click(); - } - this.set('isReloading', false); - }, - - // Tag Saving / Tag Add/Delete Actions - saveTags: function () { - var post = this.get('post'); - - if (post && this.get('isDirty') && !this.get('isReloading')) { - post.get('tags').clear(); - post.get('tags').pushObjects(this.get('currentTags').toArray()); - this.set('isDirty', false); - } - }, - - // Used for typeahead selection - typeaheadAdd: function (event, datum) { - if (datum) { - // this is needed so two tags with the same name aren't added - this.$('#tag-input').typeahead('val', ''); - this.send('addTag', datum); - } - }, - - actions: { - addTag: function (tagName) { - var tagToAdd, checkTag; - - this.$('#tag-input').typeahead('val', ''); - - // Prevent multiple tags with the same name occuring - if (this.get('currentTags').findBy('name', tagName)) { - return; - } - - checkTag = this.get('unassignedTags').findBy('name', tagName); - - if (checkTag) { - tagToAdd = checkTag; - this.get('unassignedTags').removeObject(checkTag); - this.reloadTypeahead(); - } else { - tagToAdd = this.get('store').createRecord('tag', {name: tagName}); - } - - this.set('isDirty', true); - this.set('highlightIndex', null); - this.get('currentTags').pushObject(tagToAdd); - }, - - deleteTag: function (tag) { - var removedTag; - - if (tag) { - removedTag = this.get('currentTags').findBy('name', tag); - this.get('currentTags').removeObject(removedTag); - } else { - if (this.get('highlightIndex') !== null) { - removedTag = this.get('currentTags').objectAt(this.get('highlightIndex')); - this.get('currentTags').removeObject(removedTag); - this.set('highlightIndex', null); - } else { - this.set('highlightIndex', this.get('currentTags.length') - 1); - } - } - - if (removedTag) { - if (removedTag.get('isNew')) { // if tag is new, don't change isDirty, - removedTag.deleteRecord(); // and delete the new record - } else { - this.set('isDirty', true); - this.get('unassignedTags').pushObject(removedTag); - this.reloadTypeahead(); - } - } - } - } -}); diff --git a/core/client/app/controllers/post-settings-menu.js b/core/client/app/controllers/post-settings-menu.js index 58051e9210..50d3193fa8 100644 --- a/core/client/app/controllers/post-settings-menu.js +++ b/core/client/app/controllers/post-settings-menu.js @@ -188,6 +188,13 @@ export default Ember.Controller.extend(SettingsMenuMixin, { this.set('debounceId', debounceId); }, + // live-query of all tags for tag input autocomplete + availableTags: Ember.computed(function () { + return this.get('store').filter('tag', {limit: 'all'}, function () { + return true; + }); + }), + showErrors: function (errors) { errors = Ember.isArray(errors) ? errors : [errors]; this.get('notifications').showErrors(errors); @@ -460,6 +467,45 @@ export default Ember.Controller.extend(SettingsMenuMixin, { self.set('selectedAuthor', author); model.rollback(); }); + }, + + addTag: function (tagName) { + var self = this, + currentTags = this.get('model.tags'), + currentTagNames = currentTags.map(function (tag) { return tag.get('name').toLowerCase(); }), + availableTagNames = null, + tagToAdd = null; + + // abort if tag is already selected + if (currentTagNames.contains(tagName.toLowerCase())) { + return; + } + + this.get('availableTags').then(function (availableTags) { + availableTagNames = availableTags.map(function (tag) { return tag.get('name').toLowerCase(); }); + + // find existing tag or create new + if (availableTagNames.contains(tagName.toLowerCase())) { + tagToAdd = availableTags.find(function (tag) { + return tag.get('name').toLowerCase() === tagName.toLowerCase(); + }); + } else { + tagToAdd = self.get('store').createRecord('tag', { + name: tagName + }); + } + + // push tag onto post relationship + if (tagToAdd) { self.get('model.tags').pushObject(tagToAdd); } + }); + }, + + removeTag: function (tag) { + this.get('model.tags').removeObject(tag); + + if (tag.get('isNew')) { + tag.destroyRecord(); + } } } }); diff --git a/core/client/app/styles/components/dropdowns.css b/core/client/app/styles/components/dropdowns.css index 951f71e324..4ef7efa885 100644 --- a/core/client/app/styles/components/dropdowns.css +++ b/core/client/app/styles/components/dropdowns.css @@ -128,3 +128,11 @@ .closed > .dropdown-menu { display: none; } + + +/* Selectize +/* ---------------------------------------------------------- */ + +.selectize-dropdown { + z-index: 200; +} diff --git a/core/client/app/templates/components/gh-tags-input.hbs b/core/client/app/templates/components/gh-tags-input.hbs deleted file mode 100644 index 678214802d..0000000000 --- a/core/client/app/templates/components/gh-tags-input.hbs +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/core/client/app/templates/post-settings-menu.hbs b/core/client/app/templates/post-settings-menu.hbs index 2f9d9dd5ca..147552288d 100644 --- a/core/client/app/templates/post-settings-menu.hbs +++ b/core/client/app/templates/post-settings-menu.hbs @@ -35,7 +35,15 @@
- {{gh-tags-input post=model}} + {{ember-selectize + id="tag-input" + multiple=true + selection=model.tags + content=availableTags + optionValuePath="content.name" + optionLabelPath="content.name" + create-item="addTag" + remove-item="removeTag"}}
{{#unless session.user.isAuthor}} diff --git a/core/client/bower.json b/core/client/bower.json index 323d21cf72..2d732c7561 100644 --- a/core/client/bower.json +++ b/core/client/bower.json @@ -25,6 +25,7 @@ "normalize.css": "3.0.3", "password-generator": "git://github.com/bermi/password-generator#49accd7", "rangyinputs": "1.2.0", + "selectize": "~0.12.1", "showdown-ghost": "0.3.6", "sinonjs": "1.14.1", "typeahead.js": "0.11.1", diff --git a/core/client/package.json b/core/client/package.json index 0961a49fc2..c0e87a0d1e 100644 --- a/core/client/package.json +++ b/core/client/package.json @@ -31,6 +31,7 @@ "ember-cli-ic-ajax": "0.1.1", "ember-cli-inject-live-reload": "^1.3.0", "ember-cli-mocha": "^0.7.0", + "ember-cli-selectize": "0.4.0", "ember-cli-simple-auth": "0.8.0", "ember-cli-simple-auth-oauth2": "0.8.0", "ember-cli-uglify": "^1.0.1", diff --git a/core/client/tests/unit/components/gh-tags-input-test.js b/core/client/tests/unit/components/gh-tags-input-test.js deleted file mode 100644 index bb653d6e0c..0000000000 --- a/core/client/tests/unit/components/gh-tags-input-test.js +++ /dev/null @@ -1,405 +0,0 @@ -/* jshint expr:true */ -import Ember from 'ember'; -import { expect } from 'chai'; -import { - describeComponent, - it -} from 'ember-mocha'; - -describeComponent( - 'gh-tags-input', - 'GhTagsInputComponent', - { - needs: ['helper:is-equal'] - }, - function () { - var post = Ember.Object.create({ - id: 1, - tags: Ember.A() - }); - - beforeEach(function () { - var store = Ember.Object.create({ - tags: Ember.A(), - - find: function () { - return Ember.RSVP.resolve(this.get('tags')); - }, - - createRecord: function (name, opts) { - return Ember.Object.create({ - isNew: true, - isDeleted: false, - - name: opts.name, - - deleteRecord: function () { - this.set('isDeleted', true); - } - }); - } - }); - - store.get('tags').pushObject(Ember.Object.create({ - id: 1, - name: 'Test1' - })); - store.get('tags').pushObject(Ember.Object.create({ - id: 2, - name: 'Test2' - })); - - this.subject().set('store', store); - }); - - afterEach(function () { - post.get('tags').clear(); // reset tags - }); - - it('renders with null post', function () { - // creates the component instance - var component = this.subject(); - expect(component._state).to.equal('preRender'); - - // renders the component on the page - this.render(); - expect(component._state).to.equal('inDOM'); - }); - - it('correctly loads all tags', function () { - var component = this.subject(); - - this.render(); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(0); - }); - - it('correctly loads & filters tags when post has tags', function () { - var component = this.subject(); - - post.get('tags').pushObject(Ember.Object.create({ - id: 1, - name: 'Test1' - })); - - this.render(); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(1); - expect(component.get('currentTags.length')).to.equal(1); - expect(component.get('unassignedTags').findBy('id', 1)).to.not.exist; - expect(component.get('unassignedTags').findBy('id', 2)).to.exist; - }); - - it('correctly adds new tag to currentTags', function () { - var component = this.subject(); - - this.render(); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(0); - - Ember.run(function () { - component.send('addTag', 'Test3'); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(1); - expect(component.get('isDirty')).to.be.true; - expect(component.get('currentTags').findBy('name', 'Test3')).to.exist; - }); - - it('correctly adds existing tag to currentTags', function () { - var component = this.subject(); - - this.render(); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(0); - - Ember.run(function () { - component.send('addTag', 'Test2'); - }); - - expect(component.get('unassignedTags.length')).to.equal(1); - expect(component.get('currentTags.length')).to.equal(1); - expect(component.get('isDirty')).to.be.true; - expect(component.get('currentTags').findBy('name', 'Test2')).to.exist; - expect(component.get('unassignedTags').findBy('name', 'Test2')).to.not.exist; - }); - - it('doesn\'t allow duplicate tags to be added', function () { - var component = this.subject(); - - this.render(); - - post.get('tags').pushObject(Ember.Object.create({ - id: 1, - name: 'Test1' - })); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(1); - expect(component.get('currentTags.length')).to.equal(1); - - Ember.run(function () { - component.send('addTag', 'Test1'); - }); - - expect(component.get('unassignedTags.length')).to.equal(1); - expect(component.get('currentTags.length')).to.equal(1); - }); - - it('deletes new tag correctly', function () { - var component = this.subject(); - - this.render(); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(0); - - Ember.run(function () { - component.send('addTag', 'Test3'); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(1); - - Ember.run(function () { - component.send('deleteTag', 'Test3'); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(0); - expect(component.get('currentTags').findBy('name', 'Test3')).to.not.exist; - expect(component.get('unassignedTags').findBy('name', 'Test3')).to.not.exist; - }); - - it('deletes existing tag correctly', function () { - var component = this.subject(); - - this.render(); - - post.get('tags').pushObject(Ember.Object.create({ - id: 1, - name: 'Test1' - })); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(1); - expect(component.get('currentTags.length')).to.equal(1); - expect(component.get('unassignedTags').findBy('name', 'Test1')).to.not.exist; - - Ember.run(function () { - component.send('deleteTag', 'Test1'); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(0); - expect(component.get('unassignedTags').findBy('name', 'Test1')).to.exist; - }); - - it('creates tag with leftover text when component is de-focused', function () { - var component = this.subject(); - - this.render(); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(0); - - component.$('#tag-input').typeahead('val', 'Test3'); - component.focusOut(); // simluate de-focus - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(1); - }); - - it('sets highlight index to length-1 if it is null and modifier is negative', function () { - var component = this.subject(); - - this.render(); - - post.get('tags').pushObject(Ember.Object.create({ - id: 3, - name: 'Test3' - })); - - post.get('tags').pushObject(Ember.Object.create({ - id: 4, - name: 'Test4' - })); - - post.get('tags').pushObject(Ember.Object.create({ - id: 5, - name: 'Test5' - })); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(3); - - Ember.run(function () { - component.updateHighlightIndex(-1); - }); - - expect(component.get('highlightIndex')).to.equal(2); - }); - - it('sets highlight index to 0 if it is null and modifier is positive', function () { - var component = this.subject(); - - this.render(); - - post.get('tags').pushObject(Ember.Object.create({ - id: 3, - name: 'Test3' - })); - - post.get('tags').pushObject(Ember.Object.create({ - id: 4, - name: 'Test4' - })); - - post.get('tags').pushObject(Ember.Object.create({ - id: 5, - name: 'Test5' - })); - - Ember.run(function () { - component.set('post', post); - }); - - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(3); - - Ember.run(function () { - component.updateHighlightIndex(1); - }); - - expect(component.get('highlightIndex')).to.equal(0); - }); - - it('increments highlight index correctly (no reset)', function () { - var component = this.subject(); - - this.render(); - - post.get('tags').pushObject(Ember.Object.create({ - id: 3, - name: 'Test3' - })); - - post.get('tags').pushObject(Ember.Object.create({ - id: 4, - name: 'Test4' - })); - - post.get('tags').pushObject(Ember.Object.create({ - id: 5, - name: 'Test5' - })); - - Ember.run(function () { - component.set('post', post); - component.set('highlightIndex', 1); - }); - - expect(component.get('highlightIndex')).to.equal(1); - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(3); - - Ember.run(function () { - component.updateHighlightIndex(1); - }); - - expect(component.get('highlightIndex')).to.equal(2); - - Ember.run(function () { - component.updateHighlightIndex(-1); - }); - - expect(component.get('highlightIndex')).to.equal(1); - }); - - it('increments highlight index correctly (with reset)', function () { - var component = this.subject(); - - this.render(); - - post.get('tags').pushObject(Ember.Object.create({ - id: 3, - name: 'Test3' - })); - - post.get('tags').pushObject(Ember.Object.create({ - id: 4, - name: 'Test4' - })); - - post.get('tags').pushObject(Ember.Object.create({ - id: 5, - name: 'Test5' - })); - - Ember.run(function () { - component.set('post', post); - component.set('highlightIndex', 2); - }); - - expect(component.get('highlightIndex')).to.equal(2); - expect(component.get('unassignedTags.length')).to.equal(2); - expect(component.get('currentTags.length')).to.equal(3); - - Ember.run(function () { - component.updateHighlightIndex(1); - }); - - expect(component.get('highlightIndex')).to.be.null; - - Ember.run(function () { - component.set('highlightIndex', 0); - }); - - expect(component.get('highlightIndex')).to.equal(0); - - Ember.run(function () { - component.updateHighlightIndex(-1); - }); - - expect(component.get('highlightIndex')).to.be.null; - }); - } -); diff --git a/core/test/functional/client/psm_test.js b/core/test/functional/client/psm_test.js index 3607bb43b7..7ed2c40acb 100644 --- a/core/test/functional/client/psm_test.js +++ b/core/test/functional/client/psm_test.js @@ -181,9 +181,10 @@ CasperTest.begin('Post url input is reset from all whitespace back to original v }); }); -CasperTest.begin('Tag Editor', 18, function suite(test) { +CasperTest.begin('Tag Editor', 9, function suite(test) { var testTag = 'Test1', - createdTag = '.tags-input-list li.label-tag'; + createdTag = '#tag-input + .selectize-control .item', + tagInput = '#tag-input + .selectize-control input[type="text"]'; casper.thenOpenAndWaitForPageLoad('editor', function testTitleAndUrl() { test.assertTitle('Editor - Test Blog', 'Ghost admin has incorrect title'); @@ -191,118 +192,68 @@ CasperTest.begin('Tag Editor', 18, function suite(test) { }); casper.then(function () { - test.assertExists('.tags-input-list', 'should have tag list area'); - test.assertExists('#tag-input', 'should have tag input'); + test.assertExists('#tag-input + .selectize-control', 'should have tag list area'); }); - casper.thenClick('#tag-input'); + casper.thenClick(tagInput); casper.then(function () { - casper.sendKeys('#tag-input', testTag, {keepFocus: true}); + casper.sendKeys(tagInput, testTag, {keepFocus: true}); }); casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Enter, {keepFocus: true}); + casper.sendKeys(tagInput, casper.page.event.key.Enter, {keepFocus: true}); }); casper.waitForSelector(createdTag, function onSuccess() { test.assertSelectorHasText(createdTag, testTag, 'typing enter after tag name should create tag'); }); - casper.thenClick(createdTag); + casper.thenClick(createdTag + ' a.remove'); casper.waitWhileSelector(createdTag, function onSuccess() { - test.assert(true, 'clicking the tag should delete the tag'); + test.assert(true, 'clicking the tag remove button should delete the tag'); }); casper.then(function () { - casper.sendKeys('#tag-input', testTag, {keepFocus: true}); + casper.sendKeys(tagInput, testTag, {keepFocus: true}); }); casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Tab, {keepFocus: true}); + casper.sendKeys(tagInput, casper.page.event.key.Tab, {keepFocus: true}); }); - casper.waitForSelector(createdTag, function onSuccess() { test.assertSelectorHasText(createdTag, testTag, 'typing tab after tag name should create tag'); }); casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Backspace, {keepFocus: true}); + casper.sendKeys(tagInput, casper.page.event.key.Backspace, {keepFocus: true}); }); - - casper.waitForSelector(createdTag + '.highlight', function onSuccess() { - test.assert(true, 'hitting backspace should highlight the last tag'); + casper.waitWhileSelector(createdTag, function onSuccess() { + test.assert(true, 'hitting backspace should delete the last tag'); }); casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Backspace, {keepFocus: true}); + casper.sendKeys(tagInput, testTag, {keepFocus: true}); + }); + casper.then(function () { + casper.sendKeys(tagInput, casper.page.event.key.Enter, {keepFocus: true}); + }); + casper.thenClick(createdTag); + casper.waitForSelector(createdTag + '.active', function onSuccess() { + test.assert(true, 'clicking a tag should highlight it'); }); - casper.waitWhileSelector(createdTag + '.highlight', function onSuccess() { + casper.then(function () { + casper.sendKeys(createdTag + '.active', casper.page.event.key.Backspace); + }); + casper.waitWhileSelector(createdTag + '.active', function onSuccess() { test.assert(true, 'hitting backspace on a higlighted tag should delete it'); }); - casper.then(function () { - casper.sendKeys('#tag-input', testTag, {keepFocus: true}); - }); - casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Tab, {keepFocus: true}); - }); - - casper.waitForSelector(createdTag, function onSuccess() { - test.assertSelectorHasText(createdTag, testTag, 'typing tab after tag name should create tag'); - }); - - casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Left, {keepFocus: true}); - }); - - casper.waitForSelector(createdTag + '.highlight', function onSuccess() { - test.assert(true, 'hitting left should highlight the last tag'); - }); - - casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Left, {keepFocus: true}); - }); - - casper.waitWhileSelector(createdTag + '.highlight', function onSuccess() { - test.assert(true, 'hitting left on a higlighted tag should un-highlight it'); - }); - - casper.waitForSelector(createdTag, function onSuccess() { - test.assertSelectorHasText(createdTag, testTag, 'un-highlighting tag should not delete it'); - }); - - casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Right, {keepFocus: true}); - }); - - casper.waitForSelector(createdTag + '.highlight', function onSuccess() { - test.assert(true, 'hitting right should highlight the first tag'); - }); - - casper.then(function () { - casper.sendKeys('#tag-input', casper.page.event.key.Right, {keepFocus: true}); - }); - - casper.waitWhileSelector(createdTag + '.highlight', function onSuccess() { - test.assert(true, 'hitting right on a higlighted tag should un-highlight it'); - }); - - casper.waitForSelector(createdTag, function onSuccess() { - test.assertSelectorHasText(createdTag, testTag, 'un-highlighting tag should not delete it'); - }); - - casper.thenClick(createdTag); - casper.waitWhileSelector(createdTag, function onSuccess() { - test.assert(true, 'clicking the tag should delete the tag'); - }); - - casper.then(function () { - casper.sendKeys('#tag-input', testTag, {keepFocus: true}); - }); - - // Click in a different field - casper.thenClick('#post-setting-date'); - - casper.waitForSelector(createdTag, function onSuccess() { - test.assertSelectorHasText(createdTag, testTag, 'de-focusing from tag input should create tag with leftover text'); - }); + // TODO: add this back in if create-on-blur functionality is required + // casper.then(function () { + // casper.sendKeys(tagInput, testTag, {keepFocus: true}); + // }); + // // Click in a different field + // casper.thenClick('#post-setting-date'); + // casper.waitForSelector(createdTag, function onSuccess() { + // test.assertSelectorHasText(createdTag, testTag, 'de-focusing from tag input should create tag with leftover text'); + // }); });