|
| 1 | +var PostTagsInputController = Ember.Controller.extend({ |
| 2 | + |
| 3 | + tags: Ember.computed.alias('parentController.tags'), |
| 4 | + |
| 5 | + suggestions: null, |
| 6 | + newTagText: null, |
| 7 | + |
| 8 | + actions: { |
| 9 | + // triggered when the view is inserted so that later store.all('tag') |
| 10 | + // queries hit a full store cache and we don't see empty or out-of-date |
| 11 | + // suggestion lists |
| 12 | + loadAllTags: function () { |
| 13 | + this.store.find('tag'); |
| 14 | + }, |
| 15 | + |
| 16 | + addNewTag: function () { |
| 17 | + var newTagText = this.get('newTagText'), |
| 18 | + searchTerm, |
| 19 | + existingTags, |
| 20 | + newTag; |
| 21 | + |
| 22 | + if (Ember.isEmpty(newTagText) || this.hasTag(newTagText)) { |
| 23 | + this.send('reset'); |
| 24 | + return; |
| 25 | + } |
| 26 | + |
| 27 | + searchTerm = newTagText.toLowerCase(); |
| 28 | + |
| 29 | + // add existing tag if we have a match |
| 30 | + existingTags = this.store.all('tag').filter(function (tag) { |
| 31 | + return tag.get('name').toLowerCase() === searchTerm; |
| 32 | + }); |
| 33 | + if (existingTags.get('length')) { |
| 34 | + this.send('addTag', existingTags.get('firstObject')); |
| 35 | + } else { |
| 36 | + // otherwise create a new one |
| 37 | + newTag = this.store.createRecord('tag'); |
| 38 | + newTag.set('name', newTagText); |
| 39 | + this.get('tags').pushObject(newTag); |
| 40 | + } |
| 41 | + |
| 42 | + this.send('reset'); |
| 43 | + }, |
| 44 | + |
| 45 | + addTag: function (tag) { |
| 46 | + if (!Ember.isEmpty(tag) && !this.hasTag(tag.get('name'))) { |
| 47 | + this.get('tags').pushObject(tag); |
| 48 | + } |
| 49 | + this.send('reset'); |
| 50 | + }, |
| 51 | + |
| 52 | + deleteTag: function (tag) { |
| 53 | + this.get('tags').removeObject(tag); |
| 54 | + }, |
| 55 | + |
| 56 | + deleteLastTag: function () { |
| 57 | + this.send('deleteTag', this.get('tags.lastObject')); |
| 58 | + }, |
| 59 | + |
| 60 | + selectSuggestion: function (suggestion) { |
| 61 | + if (!Ember.isEmpty(suggestion)) { |
| 62 | + this.get('suggestions').setEach('selected', false); |
| 63 | + suggestion.set('selected', true); |
| 64 | + } |
| 65 | + }, |
| 66 | + |
| 67 | + selectNextSuggestion: function () { |
| 68 | + var suggestions = this.get('suggestions'), |
| 69 | + selectedSuggestion = this.get('selectedSuggestion'), |
| 70 | + currentIndex, |
| 71 | + newSelection; |
| 72 | + |
| 73 | + if (!Ember.isEmpty(suggestions)) { |
| 74 | + currentIndex = suggestions.indexOf(selectedSuggestion); |
| 75 | + if (currentIndex + 1 < suggestions.get('length')) { |
| 76 | + newSelection = suggestions[currentIndex + 1]; |
| 77 | + this.send('selectSuggestion', newSelection); |
| 78 | + } else { |
| 79 | + suggestions.setEach('selected', false); |
| 80 | + } |
| 81 | + } |
| 82 | + }, |
| 83 | + |
| 84 | + selectPreviousSuggestion: function () { |
| 85 | + var suggestions = this.get('suggestions'), |
| 86 | + selectedSuggestion = this.get('selectedSuggestion'), |
| 87 | + currentIndex, |
| 88 | + lastIndex, |
| 89 | + newSelection; |
| 90 | + |
| 91 | + if (!Ember.isEmpty(suggestions)) { |
| 92 | + currentIndex = suggestions.indexOf(selectedSuggestion); |
| 93 | + if (currentIndex === -1) { |
| 94 | + lastIndex = suggestions.get('length') - 1; |
| 95 | + this.send('selectSuggestion', suggestions[lastIndex]); |
| 96 | + } else if (currentIndex - 1 >= 0) { |
| 97 | + newSelection = suggestions[currentIndex - 1]; |
| 98 | + this.send('selectSuggestion', newSelection); |
| 99 | + } else { |
| 100 | + suggestions.setEach('selected', false); |
| 101 | + } |
| 102 | + } |
| 103 | + }, |
| 104 | + |
| 105 | + addSelectedSuggestion: function () { |
| 106 | + var suggestion = this.get('selectedSuggestion'); |
| 107 | + if (Ember.isEmpty(suggestion)) { return; } |
| 108 | + |
| 109 | + this.send('addTag', suggestion.get('tag')); |
| 110 | + }, |
| 111 | + |
| 112 | + reset: function () { |
| 113 | + this.set('suggestions', null); |
| 114 | + this.set('newTagText', null); |
| 115 | + } |
| 116 | + }, |
| 117 | + |
| 118 | + |
| 119 | + selectedSuggestion: function () { |
| 120 | + var suggestions = this.get('suggestions'); |
| 121 | + if (suggestions && suggestions.get('length')) { |
| 122 | + return suggestions.filterBy('selected').get('firstObject'); |
| 123 | + } else { |
| 124 | + return null; |
| 125 | + } |
| 126 | + }.property('suggestions.@each.selected'), |
| 127 | + |
| 128 | + |
| 129 | + updateSuggestionsList: function () { |
| 130 | + var searchTerm = this.get('newTagText'), |
| 131 | + matchingTags, |
| 132 | + // Limit the suggestions number |
| 133 | + maxSuggestions = 5, |
| 134 | + suggestions = new Ember.A(); |
| 135 | + |
| 136 | + if (!searchTerm || Ember.isEmpty(searchTerm.trim())) { |
| 137 | + this.set('suggestions', null); |
| 138 | + return; |
| 139 | + } |
| 140 | + |
| 141 | + searchTerm = searchTerm.trim(); |
| 142 | + |
| 143 | + matchingTags = this.findMatchingTags(searchTerm); |
| 144 | + matchingTags = matchingTags.slice(0, maxSuggestions); |
| 145 | + matchingTags.forEach(function (matchingTag) { |
| 146 | + var suggestion = this.makeSuggestionObject(matchingTag, searchTerm); |
| 147 | + suggestions.pushObject(suggestion); |
| 148 | + }, this); |
| 149 | + |
| 150 | + this.set('suggestions', suggestions); |
| 151 | + }.observes('newTagText'), |
| 152 | + |
| 153 | + |
| 154 | + findMatchingTags: function (searchTerm) { |
| 155 | + var matchingTags, |
| 156 | + self = this, |
| 157 | + allTags = this.store.all('tag'); |
| 158 | + |
| 159 | + if (allTags.get('length') === 0) { |
| 160 | + return []; |
| 161 | + } |
| 162 | + |
| 163 | + searchTerm = searchTerm.toLowerCase(); |
| 164 | + |
| 165 | + matchingTags = allTags.filter(function (tag) { |
| 166 | + var tagNameMatches, |
| 167 | + hasAlreadyBeenAdded; |
| 168 | + |
| 169 | + tagNameMatches = tag.get('name').toLowerCase().indexOf(searchTerm) !== -1; |
| 170 | + hasAlreadyBeenAdded = self.hasTag(tag.get('name')); |
| 171 | + |
| 172 | + return tagNameMatches && !hasAlreadyBeenAdded; |
| 173 | + }); |
| 174 | + |
| 175 | + return matchingTags; |
| 176 | + }, |
| 177 | + |
| 178 | + hasTag: function (tagName) { |
| 179 | + return this.get('tags').mapBy('name').contains(tagName); |
| 180 | + }, |
| 181 | + |
| 182 | + makeSuggestionObject: function (matchingTag, _searchTerm) { |
| 183 | + var searchTerm = Ember.Handlebars.Utils.escapeExpression(_searchTerm), |
| 184 | + regexEscapedSearchTerm = searchTerm.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'), |
| 185 | + tagName = Ember.Handlebars.Utils.escapeExpression(matchingTag.get('name')), |
| 186 | + regex = new RegExp('(' + regexEscapedSearchTerm + ')', 'gi'), |
| 187 | + highlightedName, |
| 188 | + suggestion = new Ember.Object(); |
| 189 | + |
| 190 | + highlightedName = tagName.replace(regex, '<mark>$1</mark>'); |
| 191 | + highlightedName = new Ember.Handlebars.SafeString(highlightedName); |
| 192 | + |
| 193 | + suggestion.set('tag', matchingTag); |
| 194 | + suggestion.set('highlightedName', highlightedName); |
| 195 | + |
| 196 | + return suggestion; |
| 197 | + }, |
| 198 | + |
| 199 | +}); |
| 200 | + |
| 201 | +export default PostTagsInputController; |
0 commit comments