diff --git a/.eslintrc b/.eslintrc
index 71e21b4381a..6f7c9f0ecdd 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -43,11 +43,11 @@
"asyncRender":true,
"selectDropdown":true,
"selectBox":true,
- "expandSelectBox":true,
- "collapseSelectBox":true,
- "selectBoxSelectRow":true,
- "selectBoxSelectNoneRow":true,
- "selectBoxFillInFilter":true,
+ "expandSelectBoxKit":true,
+ "collapseSelectBoxKit":true,
+ "selectBoxKitSelectRow":true,
+ "selectBoxKitSelectNoneRow":true,
+ "selectBoxKitFillInFilter":true,
"asyncTestDiscourse":true,
"fixture":true,
"find":true,
diff --git a/app/assets/javascripts/admin/components/admin-group-selector.js.es6 b/app/assets/javascripts/admin/components/admin-group-selector.js.es6
deleted file mode 100644
index fd487640d0e..00000000000
--- a/app/assets/javascripts/admin/components/admin-group-selector.js.es6
+++ /dev/null
@@ -1,43 +0,0 @@
-export default Ember.Component.extend({
- tagName: 'div',
-
- _init: function(){
- this.$("input").select2({
- multiple: true,
- width: '100%',
- query: function(opts) {
- opts.callback({
- results: this.get("available").filter(function(o) {
- return -1 !== o.name.toLowerCase().indexOf(opts.term.toLowerCase());
- }).map(this._format)
- });
- }.bind(this)
- }).on("change", function(evt) {
- if (evt.added){
- this.triggerAction({
- action: "groupAdded",
- actionContext: this.get("available").findBy("id", evt.added.id)
- });
- } else if (evt.removed) {
- this.triggerAction({
- action:"groupRemoved",
- actionContext: evt.removed.id
- });
- }
- }.bind(this));
-
- this._refreshOnReset();
- }.on("didInsertElement"),
-
- _format(item) {
- return {
- "text": item.name,
- "id": item.id,
- "locked": item.automatic
- };
- },
-
- _refreshOnReset: function() {
- this.$("input").select2("data", this.get("selected").map(this._format));
- }.observes("selected")
-});
diff --git a/app/assets/javascripts/admin/components/list-setting.js.es6 b/app/assets/javascripts/admin/components/list-setting.js.es6
deleted file mode 100644
index 9a1d865133d..00000000000
--- a/app/assets/javascripts/admin/components/list-setting.js.es6
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- Provide a nice GUI for a pipe-delimited list in the site settings.
-
- @param settingValue is a reference to SiteSetting.value.
- @param choices is a reference to SiteSetting.choices
-**/
-export default Ember.Component.extend({
-
- _select2FormatSelection: function(selectedObject, jqueryWrapper, htmlEscaper) {
- var text = selectedObject.text;
- if (text.length <= 6) {
- jqueryWrapper.closest('li.select2-search-choice').css({"border-bottom": '7px solid #'+text});
- }
- return htmlEscaper(text);
- },
-
- _initializeSelect2: function(){
- var options = {
- multiple: false,
- separator: "|",
- tokenSeparators: ["|"],
- tags : this.get("choices") || [],
- width: 'off',
- dropdownCss: this.get("choices") ? {} : {display: 'none'},
- selectOnBlur: this.get("choices") ? false : true
- };
-
- var settingName = this.get('settingName');
- if (typeof settingName === 'string' && settingName.indexOf('colors') > -1) {
- options.formatSelection = this._select2FormatSelection;
- }
-
- var self = this;
- this.$("input").select2(options).on("change", function(obj) {
- self.set("settingValue", obj.val.join("|"));
- self.refreshSortables();
- });
-
- this.refreshSortables();
- }.on('didInsertElement'),
-
- refreshOnReset: function() {
- this.$("input").select2("val", this.get("settingValue").split("|"));
- }.observes("settingValue"),
-
- refreshSortables: function() {
- var self = this;
- this.$("ul.select2-choices").sortable().on('sortupdate', function() {
- self.$("input").select2("onSortEnd");
- });
- }
-});
diff --git a/app/assets/javascripts/discourse/templates/components/admin-group-selector.hbs b/app/assets/javascripts/discourse/templates/components/admin-group-selector.hbs
deleted file mode 100644
index 4856de5179a..00000000000
--- a/app/assets/javascripts/discourse/templates/components/admin-group-selector.hbs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/app/assets/javascripts/discourse/templates/components/list-setting.hbs b/app/assets/javascripts/discourse/templates/components/list-setting.hbs
deleted file mode 100644
index 830982fc474..00000000000
--- a/app/assets/javascripts/discourse/templates/components/list-setting.hbs
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/app/assets/javascripts/select-box-kit/components/admin-group-selector.js.es6 b/app/assets/javascripts/select-box-kit/components/admin-group-selector.js.es6
new file mode 100644
index 00000000000..08248e72bda
--- /dev/null
+++ b/app/assets/javascripts/select-box-kit/components/admin-group-selector.js.es6
@@ -0,0 +1,45 @@
+import MultiComboBoxComponent from "select-box-kit/components/multi-combo-box";
+
+export default MultiComboBoxComponent.extend({
+ classNames: "admin-group-selector",
+ selected: null,
+ available: null,
+ allowAny: false,
+
+ didReceiveAttrs() {
+ this._super();
+
+ this.set("value", this.get("selected").map(s => this._valueForContent(s)));
+ this.set("content", this.get("available"));
+ },
+
+ formatRowContent(content) {
+ let formatedContent = this._super(content);
+ formatedContent.locked = content.automatic;
+ return formatedContent;
+ },
+
+ didUpdateAttrs() {
+ this._super();
+
+ this.set("highlightedValue", null);
+ Ember.run.schedule("afterRender", () => {
+ this.autoHighlightFunction();
+ });
+ },
+
+ selectValuesFunction(values) {
+ values.forEach(value => {
+ this.triggerAction({
+ action: "groupAdded",
+ actionContext: this.get("content").findBy("id", parseInt(value, 10))
+ });
+ });
+ },
+
+ deselectValuesFunction(values) {
+ values.forEach(value => {
+ this.triggerAction({ action: "groupRemoved", actionContext: value });
+ });
+ }
+});
diff --git a/app/assets/javascripts/select-box-kit/components/categories-admin-dropdown.js.es6 b/app/assets/javascripts/select-box-kit/components/categories-admin-dropdown.js.es6
index 61ffa1c2253..187a710b880 100644
--- a/app/assets/javascripts/select-box-kit/components/categories-admin-dropdown.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/categories-admin-dropdown.js.es6
@@ -8,10 +8,10 @@ export default DropdownSelectBoxComponent.extend({
@on("didReceiveAttrs")
_setComponentOptions() {
- this.set("headerComponentOptions", Ember.Object.create({
+ this.get("headerComponentOptions").setProperties({
shouldDisplaySelectedName: false,
icon: `${iconHTML('bars')}${iconHTML('caret-down')}`.htmlSafe(),
- }));
+ });
},
@computed
@@ -38,11 +38,8 @@ export default DropdownSelectBoxComponent.extend({
return items;
},
- actions: {
- onSelect(value) {
- value = this.defaultOnSelect(value);
- this.get(value)();
- this.set("value", null);
- }
+ selectValueFunction(value) {
+ this.get(value)();
+ this.set("value", null);
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/category-chooser.js.es6 b/app/assets/javascripts/select-box-kit/components/category-chooser.js.es6
index ee6e9b158ab..668f168b38c 100644
--- a/app/assets/javascripts/select-box-kit/components/category-chooser.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/category-chooser.js.es6
@@ -12,24 +12,24 @@ export default ComboBoxComponent.extend({
castInteger: true,
allowUncategorized: null,
- filterFunction(computedContent) {
- const _matchFunction = (filter, text) => {
- return text.toLowerCase().indexOf(filter) > -1;
- };
+ filteredContentFunction(computedContent, computedValue, filter) {
+ if (isEmpty(filter)) { return computedContent; }
- return (selectBox) => {
- const filter = selectBox.get("filter").toLowerCase();
- return _.filter(computedContent, c => {
- const category = Category.findById(get(c, "value"));
- const text = get(c, "name");
- if (category && category.get("parentCategory")) {
- const categoryName = category.get("parentCategory.name");
- return _matchFunction(filter, text) || _matchFunction(filter, categoryName);
- } else {
- return _matchFunction(filter, text);
- }
- });
+ const _matchFunction = (f, text) => {
+ return text.toLowerCase().indexOf(f) > -1;
};
+ const lowerFilter = filter.toLowerCase();
+
+ return computedContent.filter(c => {
+ const category = Category.findById(get(c, "value"));
+ const text = get(c, "name");
+ if (category && category.get("parentCategory")) {
+ const categoryName = category.get("parentCategory.name");
+ return _matchFunction(lowerFilter, text) || _matchFunction(lowerFilter, categoryName);
+ } else {
+ return _matchFunction(lowerFilter, text);
+ }
+ });
},
@computed("rootNone", "rootNoneLabel")
diff --git a/app/assets/javascripts/select-box-kit/components/category-notifications-button.js.es6 b/app/assets/javascripts/select-box-kit/components/category-notifications-button.js.es6
index d022c3c64cd..05908840069 100644
--- a/app/assets/javascripts/select-box-kit/components/category-notifications-button.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/category-notifications-button.js.es6
@@ -7,11 +7,7 @@ export default NotificationOptionsComponent.extend({
value: Ember.computed.alias("category.notification_level"),
headerComponent: "category-notifications-button/category-notifications-button-header",
- actions: {
- onSelect(value) {
- value = this.defaultOnSelect(value);
- this.get("category").setNotification(value);
- this.blur();
- }
+ selectValueFunction(value) {
+ this.get("category").setNotification(value);
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/combo-box.js.es6 b/app/assets/javascripts/select-box-kit/components/combo-box.js.es6
index f5ff7d03058..26779a38949 100644
--- a/app/assets/javascripts/select-box-kit/components/combo-box.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/combo-box.js.es6
@@ -12,10 +12,10 @@ export default SelectBoxKitComponent.extend({
@on("didReceiveAttrs")
_setComboBoxOptions() {
- this.set("headerComponentOptions", Ember.Object.create({
+ this.get("headerComponentOptions").setProperties({
caretUpIcon: this.get("caretUpIcon"),
caretDownIcon: this.get("caretDownIcon"),
clearable: this.get("clearable"),
- }));
+ });
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/dropdown-select-box.js.es6 b/app/assets/javascripts/select-box-kit/components/dropdown-select-box.js.es6
index 8e2789aa1db..252ff2dd646 100644
--- a/app/assets/javascripts/select-box-kit/components/dropdown-select-box.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/dropdown-select-box.js.es6
@@ -9,16 +9,11 @@ export default SelectBoxKitComponent.extend({
headerComponent: "dropdown-select-box/dropdown-select-box-header",
rowComponent: "dropdown-select-box/dropdown-select-box-row",
- clickOutside() {
- this.close();
- },
+ clickOutside() { this.close(); },
- actions: {
- onSelect(value) {
- value = this.defaultOnSelect(value);
- this.set("value", value);
+ didSelectValue() {
+ this._super();
- this.blur();
- }
+ this.blur();
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/group-notifications-button.js.es6 b/app/assets/javascripts/select-box-kit/components/group-notifications-button.js.es6
index 81477d2e476..e30b4ec62fc 100644
--- a/app/assets/javascripts/select-box-kit/components/group-notifications-button.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/group-notifications-button.js.es6
@@ -5,10 +5,7 @@ export default NotificationOptionsComponent.extend({
value: Ember.computed.alias("group.group_user.notification_level"),
i18nPrefix: "groups.notifications",
- actions: {
- onSelect(value) {
- value = this.defaultOnSelect(value);
- this.get("group").setNotification(value, this.get("user.id"));
- }
+ selectValueFunction(value) {
+ this.get("group").setNotification(value, this.get("user.id"));
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/list-setting.js.es6 b/app/assets/javascripts/select-box-kit/components/list-setting.js.es6
new file mode 100644
index 00000000000..94fa2fa66f2
--- /dev/null
+++ b/app/assets/javascripts/select-box-kit/components/list-setting.js.es6
@@ -0,0 +1,55 @@
+import MultiComboBoxComponent from "select-box-kit/components/multi-combo-box";
+import { observes } from 'ember-addons/ember-computed-decorators';
+
+export default MultiComboBoxComponent.extend({
+ classNames: "list-setting",
+ tokenSeparator: "|",
+ settingValue: "",
+ choices: null,
+ filterable: true,
+
+ init() {
+ const valuesFromString = this.get("settingValue").split(this.get("tokenSeparator"));
+ this.set("value", valuesFromString.reject(v => Ember.isEmpty(v)));
+
+ if (Ember.isNone(this.get("choices"))) {
+ this.set("content", valuesFromString);
+ } else {
+ this.set("content", this.get("choices"));
+ }
+
+ if (!Ember.isNone(this.get("settingName"))) {
+ this.set("nameProperty", this.get("settingName"));
+ }
+
+ if (Ember.isEmpty(this.get("content"))) {
+ this.set("rowComponent", null);
+ this.set("noContentLabel", null);
+ }
+
+ this._super();
+
+ if (this.get("nameProperty").indexOf("color") > -1) {
+ this.set("headerComponentOptions", Ember.Object.create({
+ selectedNameComponent: "multi-combo-box/selected-color"
+ }));
+ }
+ },
+
+ @observes("value.[]")
+ setSettingValue() {
+ this.set("settingValue", this.get("value").join(this.get("tokenSeparator")));
+ },
+
+ @observes("content.[]")
+ setChoices() { this.set("choices", this.get("content")); },
+
+ _handleTabOnKeyDown(event) {
+ if (this.$highlightedRow().length === 1) {
+ this._super(event);
+ } else {
+ this.close();
+ return false;
+ }
+ }
+});
diff --git a/app/assets/javascripts/select-box-kit/components/multi-combo-box.js.es6 b/app/assets/javascripts/select-box-kit/components/multi-combo-box.js.es6
index 6ce70b4e8e2..bf08d7da1f1 100644
--- a/app/assets/javascripts/select-box-kit/components/multi-combo-box.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/multi-combo-box.js.es6
@@ -1,20 +1,32 @@
-// Experimental
import SelectBoxKitComponent from "select-box-kit/components/select-box-kit";
import computed from "ember-addons/ember-computed-decorators";
-const { get, isNone } = Ember;
+const { get, isNone, isEmpty } = Ember;
export default SelectBoxKitComponent.extend({
- classNames: "multi-combobox",
+ classNames: "multi-combo-box",
headerComponent: "multi-combo-box/multi-combo-box-header",
filterComponent: null,
headerText: "select_box.default_header_text",
- value: [],
allowAny: true,
+ allowValueMutation: false,
+ autoSelectFirst: false,
+ autoFilterable: true,
+ selectedNameComponent: "multi-combo-box/selected-name",
+
+ init() {
+ this._super();
+
+ if (isNone(this.get("value"))) { this.set("value", []); }
+
+ this.set("headerComponentOptions", Ember.Object.create({
+ selectedNameComponent: this.get("selectedNameComponent")
+ }));
+ },
@computed("filter")
templateForCreateRow() {
return (rowComponent) => {
- return `Create: ${rowComponent.get("content.name")}`;
+ return I18n.t("select_box.create", { content: rowComponent.get("content.name")});
};
},
@@ -22,78 +34,207 @@ export default SelectBoxKitComponent.extend({
const keyCode = event.keyCode || event.which;
const $filterInput = this.$filterInput();
- if (keyCode === 8) {
- let $lastSelectedValue = $(this.$(".choices .selected-name").last());
+ if (this.get("isFocused") === true && this.get("isExpanded") === false && keyCode === this.keys.BACKSPACE) {
+ this.expand();
+ return;
+ }
- if ($lastSelectedValue.is(":focus") || $(document.activeElement).is($lastSelectedValue)) {
- this.send("onDeselect", $lastSelectedValue.data("value"));
+ // select all choices
+ if (event.metaKey === true && keyCode === 65 && isEmpty(this.get("filter"))) {
+ this.$(".choices .selected-name:not(.is-locked)").addClass("is-highlighted");
+ return;
+ }
+
+ // clear selection when multiple
+ if (Ember.isEmpty(this.get("filter")) && this.$(".selected-name.is-highlighted").length >= 1 && keyCode === this.keys.BACKSPACE) {
+ const highlightedValues = [];
+ $.each(this.$(".selected-name.is-highlighted"), (i, el) => {
+ highlightedValues.push($(el).attr("data-value"));
+ });
+
+ this.send("onDeselect", highlightedValues);
+ return;
+ }
+
+ // try to remove last item from the list
+ if (Ember.isEmpty(this.get("filter")) && keyCode === this.keys.BACKSPACE) {
+ let $lastSelectedValue = $(this.$(".choices .selected-name:not(.is-locked)").last());
+
+ if ($lastSelectedValue.length === 0) { return; }
+
+ if ($lastSelectedValue.hasClass("is-highlighted") || $(document.activeElement).is($lastSelectedValue)) {
+ this.send("onDeselect", this.get("selectedContent.lastObject.value"));
$filterInput.focus();
return;
}
+ if ($filterInput.not(":visible") && $lastSelectedValue.length > 0) {
+ $lastSelectedValue.click();
+ return false;
+ }
+
if ($filterInput.val() === "") {
if ($filterInput.is(":focus")) {
- if ($lastSelectedValue.length > 0) {
- $lastSelectedValue.focus();
- }
+ if ($lastSelectedValue.length > 0) { $lastSelectedValue.click(); }
} else {
if ($lastSelectedValue.length > 0) {
- $lastSelectedValue.focus();
+ $lastSelectedValue.click();
} else {
$filterInput.focus();
}
}
}
- } else {
- $filterInput.focus();
- this._super(event);
- }
- },
-
- @computed("none")
- computedNone(none) {
- if (!isNone(none)) {
- this.set("none", { name: I18n.t(none), value: "" });
}
},
@computed("value.[]")
- computedValue(value) {
- return value.map(v => this._castInteger(v));
- },
+ computedValue(value) { return value.map(v => this._castInteger(v)); },
- @computed("computedValue.[]", "computedContent.[]")
- selectedContent(computedValue, computedContent) {
+ @computed("value.[]", "computedContent.[]")
+ selectedContent(value, computedContent) {
const contents = [];
- computedValue.forEach(cv => {
- contents.push(computedContent.findBy("value", cv));
+ value.forEach(v => {
+ const content = computedContent.findBy("value", v);
+ if (!isNone(content)) { contents.push(content); }
});
return contents;
},
- filterFunction(content) {
- return (selectBox, computedValue) => {
- const filter = selectBox.get("filter").toLowerCase();
- return _.filter(content, c => {
- return !computedValue.includes(get(c, "value")) &&
- get(c, "name").toLowerCase().indexOf(filter) > -1;
- });
- };
+ filteredContentFunction(computedContent, computedValue, filter) {
+ computedContent = computedContent.filter(c => {
+ return !computedValue.includes(get(c, "value"));
+ });
+
+ if (isEmpty(filter)) { return computedContent; }
+
+ const lowerFilter = filter.toLowerCase();
+ return computedContent.filter(c => {
+ return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1;
+ });
+ },
+
+ willCreateContent() {
+ this.set("highlightedValue", null);
+ },
+
+ didCreateContent() {
+ this.clearFilter();
+ this.autoHighlightFunction();
+ },
+
+ createContentFunction(input) {
+ if (!this.get("content").includes(input)) {
+ this.get("content").pushObject(input);
+ this.get("value").pushObject(input);
+ }
+ },
+
+ deselectValuesFunction(values) {
+ const contents = this._computeRemovableContentsForValues(values);
+ this.get("value").removeObjects(values);
+ this.get("content").removeObjects(contents);
+ },
+
+ highlightValueFunction(value) {
+ this.set("highlightedValue", value);
+ },
+
+ selectValuesFunction(values) {
+ this.get("value").pushObjects(values);
+ },
+
+ willSelectValues() {
+ this.expand();
+ this.set("highlightedValue", null);
+ },
+
+ didSelectValues() {
+ this.focus();
+ this.clearFilter();
+ this.autoHighlightFunction();
+ },
+
+ willDeselectValues() {
+ this.set("highlightedValue", null);
+ },
+
+ didDeselectValues() {
+ this.autoHighlightFunction();
+ },
+
+ willHighlightValue() {},
+
+ didHighlightValue() {},
+
+ autoHighlightFunction() {
+ Ember.run.schedule("afterRender", () => {
+ if (this.get("isExpanded") === false) { return; }
+ if (this.get("renderedBodyOnce") === false) { return; }
+ if (!isNone(this.get("highlightedValue"))) { return; }
+
+ if (isEmpty(this.get("filteredContent"))) {
+ if (!isEmpty(this.get("filter"))) {
+ this.send("onHighlight", this.get("filter"));
+ } else if (this.get("none") && !isEmpty(this.get("selectedContent"))) {
+ this.send("onHighlight", this.noneValue);
+ }
+ } else {
+ this.send("onHighlight", this.get("filteredContent.firstObject.value"));
+ }
+ });
},
actions: {
onClearSelection() {
- this.send("onSelect", []);
+ const values = this.get("selectedContent").map(c => get(c, "value"));
+ this.send("onDeselect", values);
},
- onSelect(value) {
- this.setProperties({ filter: "", highlightedValue: null });
- this.get("value").pushObject(value);
+ onHighlight(value) {
+ value = this._originalValueForValue(value);
+ this.willHighlightValue(value);
+ this.set("highlightedValue", value);
+ this.highlightValueFunction(value);
+ this.didHighlightValue(value);
},
- onDeselect(value) {
- this.defaultOnDeselect(value);
- this.get("value").removeObject(value);
+ onCreateContent(input) {
+ this.willCreateContent(input);
+ this.createContentFunction(input);
+ this.didCreateContent(input);
+ },
+
+ onSelect(values) {
+ values = Ember.makeArray(values).map(v => this._originalValueForValue(v));
+ this.willSelectValues(values);
+ this.selectValuesFunction(values);
+ this.didSelectValues(values);
+ },
+
+ onDeselect(values) {
+ values = Ember.makeArray(this._computeRemovableValues(values));
+ this.willDeselectValues(values);
+ this.deselectValuesFunction(values);
+ this.didSelectValues(values);
}
+ },
+
+ _computeRemovableContentsForValues(values) {
+ const removableContents = [];
+ values.forEach(v => {
+ if (!this.get("_initialValues").includes(v)) {
+ const content = this._contentForValue(v);
+ if (!isNone(content)) { removableContents.push(content); }
+ }
+ });
+ return removableContents;
+ },
+
+ _computeRemovableValues(values) {
+ return Ember.makeArray(values)
+ .map(v => this._originalValueForValue(v))
+ .filter(v => {
+ return get(this._computedContentForValue(v), "locked") !== true;
+ });
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/multi-combo-box/multi-combo-box-header.js.es6 b/app/assets/javascripts/select-box-kit/components/multi-combo-box/multi-combo-box-header.js.es6
index 0b5f302e7b1..10e2d299ceb 100644
--- a/app/assets/javascripts/select-box-kit/components/multi-combo-box/multi-combo-box-header.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/multi-combo-box/multi-combo-box-header.js.es6
@@ -4,37 +4,27 @@ import SelectBoxKitHeaderComponent from "select-box-kit/components/select-box-ki
export default SelectBoxKitHeaderComponent.extend({
attributeBindings: ["names:data-name"],
- classNames: "multi-combobox-header",
+ classNames: "multi-combo-box-header",
layoutName: "select-box-kit/templates/components/multi-combo-box/multi-combo-box-header",
-
- @computed("filter", "selectedContent.[]", "isFocused", "selectBoxIsExpanded")
- shouldDisplayFilterPlaceholder(filter, selectedContent, isFocused) {
- if (Ember.isEmpty(selectedContent)) {
- if (filter.length > 0) { return false; }
- if (isFocused === true) { return false; }
- return true;
- }
-
- return false;
- },
+ selectedNameComponent: Ember.computed.alias("options.selectedNameComponent"),
@on("didRender")
_positionFilter() {
- this.$(".filter").width(0);
+ if (this.get("shouldDisplayFilter") === false) { return; }
+
+ const $filter = this.$(".filter");
+ $filter.width(0);
const leftHeaderOffset = this.$().offset().left;
- const leftFilterOffset = this.$(".filter").offset().left;
+ const leftFilterOffset = $filter.offset().left;
const offset = leftFilterOffset - leftHeaderOffset;
const width = this.$().outerWidth(false);
const availableSpace = width - offset;
-
- // TODO: avoid magic number 8
- // TODO: make sure the filter doesn’t end up being very small
- this.$(".filter").width(availableSpace - 8);
+ const $choices = $filter.parent(".choices");
+ const parentRightPadding = parseInt($choices.css("padding-right") , 10);
+ $filter.width(availableSpace - parentRightPadding * 4);
},
@computed("selectedContent.[]")
- names(selectedContent) {
- return selectedContent.map(sc => sc.name).join(",");
- }
+ names(selectedContent) { return selectedContent.map(sc => sc.name).join(","); }
});
diff --git a/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-color.js.es6 b/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-color.js.es6
new file mode 100644
index 00000000000..240c3570d9e
--- /dev/null
+++ b/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-color.js.es6
@@ -0,0 +1,8 @@
+import SelectedNameComponent from "select-box-kit/components/multi-combo-box/selected-name";
+
+export default SelectedNameComponent.extend({
+ didRender() {
+ const name = this.get("content.name");
+ this.$().css("border-bottom", Handlebars.Utils.escapeExpression(`7px solid #${name}`));
+ }
+});
diff --git a/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-name.js.es6 b/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-name.js.es6
new file mode 100644
index 00000000000..07c3ad0d64c
--- /dev/null
+++ b/app/assets/javascripts/select-box-kit/components/multi-combo-box/selected-name.js.es6
@@ -0,0 +1,19 @@
+export default Ember.Component.extend({
+ attributeBindings: ["tabindex","content.name:data-name", "content.value:data-value"],
+ classNames: "selected-name",
+ classNameBindings: ["isHighlighted", "isLocked"],
+ layoutName: "select-box-kit/templates/components/multi-combo-box/selected-name",
+ tagName: "li",
+ tabindex: -1,
+
+ isLocked: Ember.computed("content.locked", function() {
+ return this.getWithDefault("content.locked", false);
+ }),
+
+ click() {
+ if (this.get("isLocked") === true) { return false; }
+
+ this.toggleProperty("isHighlighted");
+ return false;
+ }
+});
diff --git a/app/assets/javascripts/select-box-kit/components/notifications-button.js.es6 b/app/assets/javascripts/select-box-kit/components/notifications-button.js.es6
index 88a1e71e982..d0515535001 100644
--- a/app/assets/javascripts/select-box-kit/components/notifications-button.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/notifications-button.js.es6
@@ -22,15 +22,15 @@ export default DropdownSelectBoxComponent.extend({
@on("didReceiveAttrs", "didUpdateAttrs")
_setComponentOptions() {
- this.set("headerComponentOptions", Ember.Object.create({
+ this.get("headerComponentOptions").setProperties({
i18nPrefix: this.get("i18nPrefix"),
showFullTitle: this.get("showFullTitle"),
- }));
+ });
- this.set("rowComponentOptions", Ember.Object.create({
+ this.get("rowComponentOptions").setProperties({
i18nPrefix: this.get("i18nPrefix"),
i18nPostfix: this.get("i18nPostfix")
- }));
+ });
},
@computed("computedValue")
diff --git a/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-header.js.es6 b/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-header.js.es6
index 96b15534928..268e8d7b311 100644
--- a/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-header.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/notifications-button/notifications-button-header.js.es6
@@ -11,7 +11,7 @@ export default DropdownSelectBoxHeaderComponent.extend({
@computed("_selectedDetails.icon", "_selectedDetails.key")
icon(icon, key) {
- return iconHTML(icon, {class: key}).htmlSafe();
+ return iconHTML(icon, { class: key }).htmlSafe();
},
@computed("_selectedDetails.key", "i18nPrefix")
@@ -20,5 +20,7 @@ export default DropdownSelectBoxHeaderComponent.extend({
},
@computed("selectedContent.firstObject.value")
- _selectedDetails(value) { return buttonDetails(value); }
+ _selectedDetails(value) {
+ return buttonDetails(value);
+ }
});
diff --git a/app/assets/javascripts/select-box-kit/components/pinned-options.js.es6 b/app/assets/javascripts/select-box-kit/components/pinned-options.js.es6
index c1be2e6ab38..3c96f2ee228 100644
--- a/app/assets/javascripts/select-box-kit/components/pinned-options.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/pinned-options.js.es6
@@ -48,17 +48,13 @@ export default DropdownSelectBoxComponent.extend({
];
},
- actions: {
- onSelect(value) {
- value = this.defaultOnSelect(value);
+ selectValueFunction(value) {
+ const topic = this.get("topic");
- const topic = this.get("topic");
-
- if (value === "unpinned") {
- topic.clearPin();
- } else {
- topic.rePin();
- }
+ if (value === "unpinned") {
+ topic.clearPin();
+ } else {
+ topic.rePin();
}
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit.js.es6
index 486b39bd701..ffb118eba88 100644
--- a/app/assets/javascripts/select-box-kit/components/select-box-kit.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/select-box-kit.js.es6
@@ -1,5 +1,5 @@
const { get, isNone, isEmpty, isPresent } = Ember;
-import { on, observes } from "ember-addons/ember-computed-decorators";
+import { on } from "ember-addons/ember-computed-decorators";
import computed from "ember-addons/ember-computed-decorators";
import UtilsMixin from "select-box-kit/mixins/utils";
import DomHelpersMixin from "select-box-kit/mixins/dom-helpers";
@@ -22,7 +22,8 @@ export default Ember.Component.extend(UtilsMixin, DomHelpersMixin, KeyboardMixin
isExpanded: false,
isFocused: false,
isHidden: false,
- renderBody: false,
+ renderedBodyOnce: false,
+ renderedFilterOnce: false,
tabindex: 0,
scrollableParentSelector: ".modal-body",
value: null,
@@ -37,10 +38,12 @@ export default Ember.Component.extend(UtilsMixin, DomHelpersMixin, KeyboardMixin
filterPlaceholder: "select_box.filter_placeholder",
filterIcon: "search",
rowComponent: "select-box-kit/select-box-kit-row",
+ rowComponentOptions: null,
noneRowComponent: "select-box-kit/select-box-kit-none-row",
createRowComponent: "select-box-kit/select-box-kit-create-row",
filterComponent: "select-box-kit/select-box-kit-filter",
headerComponent: "select-box-kit/select-box-kit-header",
+ headerComponentOptions: null,
collectionComponent: "select-box-kit/select-box-kit-collection",
collectionHeight: 200,
verticalOffset: 0,
@@ -50,126 +53,92 @@ export default Ember.Component.extend(UtilsMixin, DomHelpersMixin, KeyboardMixin
allowAny: false,
allowValueMutation: true,
autoSelectFirst: true,
+ content: null,
+ _initialValues: null,
init() {
this._super();
+ this.noneValue = "__none__";
+ this._previousScrollParentOverflow = "auto";
+ this._previousCSSContext = {};
+ this.set("headerComponentOptions", Ember.Object.create());
+ this.set("rowComponentOptions", Ember.Object.create());
+
if ($(window).outerWidth(false) <= 420) {
this.setProperties({ filterable: false, autoFilterable: false });
}
- this._previousScrollParentOverflow = "auto";
- this._previousCSSContext = {};
+ if (isNone(this.get("content"))) { this.set("content", []); }
+ this.set("value", this._castInteger(this.get("value")));
+
+ this.setInitialValues();
},
- click(event) {
- event.stopPropagation();
+ setInitialValues() {
+ this.set("_initialValues", this.getWithDefault("content", []).map((c) => {
+ return this._valueForContent(c);
+ }));
},
- close() {
- this.setProperties({ isExpanded: false, isFocused: false });
+ @computed("computedContent.[]", "computedValue.[]", "filter")
+ filteredContent(computedContent, computedValue, filter) {
+ return this.filteredContentFunction(computedContent, computedValue, filter);
},
- focus() {
- Ember.run.schedule("afterRender", () => this.$offscreenInput().select() );
+ filteredContentFunction(computedContent, computedValue, filter) {
+ if (isEmpty(filter)) { return computedContent; }
+
+ const lowerFilter = filter.toLowerCase();
+ return computedContent.filter(c => {
+ return get(c, "name").toLowerCase().indexOf(lowerFilter) > -1;
+ });
},
- blur() {
- Ember.run.schedule("afterRender", () => this.$offscreenInput().blur() );
- },
+ formatRowContent(content) {
+ let originalContent;
- clickOutside(event) {
- if ($(event.target).parents(".select-box-kit").length === 1) {
- this.close();
- return;
- }
-
- if (this.get("isExpanded") === true) {
- this.set("isExpanded", false);
- this.focus();
+ if (typeof content === "string" || typeof content === "number") {
+ originalContent = {};
+ originalContent[this.get("valueAttribute")] = content;
+ originalContent[this.get("nameProperty")] = content;
} else {
- this.close();
- }
- },
-
- createFunction(input) {
- return (selectedBox) => {
- const formatedContent = selectedBox.formatContent(input);
- formatedContent.meta.generated = true;
- return formatedContent;
- };
- },
-
- filterFunction(content) {
- return selectBox => {
- const filter = selectBox.get("filter").toLowerCase();
- return _.filter(content, c => {
- return get(c, "name").toLowerCase().indexOf(filter) > -1;
- });
- };
- },
-
- nameForContent(content) {
- if (isNone(content)) {
- return null;
+ originalContent = content;
}
- if (typeof content === "object") {
- return get(content, this.get("nameProperty"));
- }
-
- return content;
- },
-
- valueForContent(content) {
- switch (typeof content) {
- case "string":
- case "number":
- return this._castInteger(content);
- default:
- return this._castInteger(get(content, this.get("valueAttribute")));
- }
- },
-
- formatContent(content) {
return {
- value: this.valueForContent(content),
- name: this.nameForContent(content),
- originalContent: content,
- meta: { generated: false }
+ value: this._castInteger(this._valueForContent(content)),
+ name: this._nameForContent(content),
+ locked: false,
+ originalContent
};
},
formatContents(contents) {
- return contents.map(content => this.formatContent(content));
+ return contents.map(content => this.formatRowContent(content));
},
- @computed("filter", "filterable", "autoFilterable")
- computedFilterable(filter, filterable, autoFilterable) {
- if (filterable === true) {
- return true;
- }
-
- if (filter.length > 0 && autoFilterable === true) {
- return true;
- }
-
+ @computed("filter", "filterable", "autoFilterable", "renderedFilterOnce")
+ shouldDisplayFilter(filter, filterable, autoFilterable, renderedFilterOnce) {
+ if (renderedFilterOnce === true || filterable === true) { return true; }
+ if (filter.length > 0 && autoFilterable === true) { return true; }
return false;
},
- @computed("computedFilterable", "filter", "allowAny")
- shouldDisplayCreateRow(computedFilterable, filter, allow) {
- return computedFilterable === true && filter.length > 0 && allow === true;
+ @computed("filter")
+ shouldDisplayCreateRow(filter) {
+ if (this.get("allowAny") === true && filter.length > 0) { return true; }
+ return false;
},
- @computed("filter", "allowAny")
- createRowContent(filter, allow) {
- if (allow === true) {
+ @computed("filter", "shouldDisplayCreateRow")
+ createRowContent(filter, shouldDisplayCreateRow) {
+ if (shouldDisplayCreateRow === true && !this.get("value").includes(filter)) {
return Ember.Object.create({ value: filter, name: filter });
}
},
- @computed("content.[]")
+ @computed("content.[]", "value.[]")
computedContent(content) {
this._mutateValue();
return this.formatContents(content || []);
@@ -178,10 +147,10 @@ export default Ember.Component.extend(UtilsMixin, DomHelpersMixin, KeyboardMixin
@computed("value", "none", "computedContent.firstObject.value")
computedValue(value, none, firstContentValue) {
if (isNone(value) && isNone(none) && this.get("autoSelectFirst") === true) {
- return this._castInteger(firstContentValue);
+ return firstContentValue;
}
- return this._castInteger(value);
+ return value;
},
@computed
@@ -195,90 +164,51 @@ export default Ember.Component.extend(UtilsMixin, DomHelpersMixin, KeyboardMixin
@computed("none")
computedNone(none) {
- if (isNone(none)) {
- return null;
- }
+ if (isNone(none)) { return null; }
switch (typeof none) {
case "string":
- return Ember.Object.create({ name: I18n.t(none), value: "" });
+ return Ember.Object.create({ name: I18n.t(none), value: this.noneValue });
default:
- return this.formatContent(none);
+ return this.formatRowContent(none);
}
},
@computed("computedValue", "computedContent.[]")
selectedContent(computedValue, computedContent) {
- if (isNone(computedValue)) {
- return [];
- }
-
- return [ computedContent.findBy("value", this._castInteger(computedValue)) ];
- },
-
- @on("didRender")
- _configureSelectBoxDOM() {
- if (this.get("isExpanded") === true) {
- Ember.run.schedule("afterRender", () => {
- this.$collection().css("max-height", this.get("collectionHeight"));
- this._applyDirection();
- this._positionWrapper();
- });
- }
- },
-
- @on("willDestroyElement")
- _cleanHandlers() {
- $(window).off("resize.select-box-kit");
- this._removeFixedPosition();
+ if (isNone(computedValue)) { return []; }
+ return [ computedContent.findBy("value", computedValue) ];
},
@on("didInsertElement")
_setupResizeListener() {
- $(window).on("resize.select-box-kit", () => this.set("isExpanded", false) );
+ $(window).on("resize.select-box-kit", () => this.collapse() );
},
- @observes("filter", "filteredContent.[]", "shouldDisplayCreateRow")
- _setHighlightedValue() {
- const filteredContent = this.get("filteredContent");
- const display = this.get("shouldDisplayCreateRow");
- const none = this.get("computedNone");
- if (isNone(this.get("highlightedValue")) && !isEmpty(filteredContent)) {
- this.set("highlightedValue", get(filteredContent, "firstObject.value"));
- return;
- }
+ autoHighlightFunction() {
+ Ember.run.schedule("afterRender", () => {
+ if (!isNone(this.get("highlightedValue"))) { return; }
- if (display === true && isEmpty(filteredContent)) {
- this.set("highlightedValue", this.get("filter"));
- }
- else if (!isEmpty(filteredContent)) {
- this.set("highlightedValue", get(filteredContent, "firstObject.value"));
- }
- else if (isEmpty(filteredContent) && isPresent(none) && display === false) {
- this.set("highlightedValue", get(none, "value"));
- }
- },
+ const filteredContent = this.get("filteredContent");
+ const display = this.get("shouldDisplayCreateRow");
+ const none = this.get("computedNone");
- @observes("isExpanded")
- _isExpandedChanged() {
- if (this.get("isExpanded") === true) {
- this._applyFixedPosition();
+ if (isNone(this.get("highlightedValue")) && !isEmpty(filteredContent)) {
+ this.send("onHighlight", get(filteredContent, "firstObject.value"));
+ return;
+ }
- this.setProperties({
- highlightedValue: this.get("computedValue"),
- renderBody: true,
- isFocused: true
- });
- } else {
- this._removeFixedPosition();
- }
- },
-
- @computed("filter", "computedFilterable", "computedContent.[]", "computedValue.[]")
- filteredContent(filter, computedFilterable, computedContent, computedValue) {
- if (computedFilterable === false) { return computedContent; }
- return this.filterFunction(computedContent)(this, computedValue);
+ if (display === true && isEmpty(filteredContent)) {
+ this.send("onHighlight", this.get("filter"));
+ }
+ else if (!isEmpty(filteredContent)) {
+ this.send("onHighlight", get(filteredContent, "firstObject.value"));
+ }
+ else if (isEmpty(filteredContent) && isPresent(none) && display === false) {
+ this.send("onHighlight", get(none, "value"));
+ }
+ });
},
@computed("scrollableParentSelector")
@@ -286,191 +216,100 @@ export default Ember.Component.extend(UtilsMixin, DomHelpersMixin, KeyboardMixin
return this.$().parents(scrollableParentSelector).first();
},
+ willFilterContent() {
+ this.expand();
+ this.set("highlightedValue", null);
+ },
+ didFilterContent() {
+ this.set("renderedFilterOnce", true);
+ this.autoHighlightFunction();
+ },
+
+ willCreateContent() { },
+ createContentFunction(input) {
+ this.get("content").pushObject(input);
+ this.send("onSelect", input);
+ },
+ didCreateContent() {
+ this.clearFilter();
+ this.autoHighlightFunction();
+ },
+
+ willHighlightValue() {},
+ highlightValueFunction(value) {
+ this.set("highlightedValue", value);
+ },
+ didHighlightValue() {},
+
+ willSelectValue() {
+ this.clearFilter();
+ this.set("highlightedValue", null);
+ },
+ selectValueFunction(value) {
+ this.set("value", value);
+ },
+ didSelectValue() {
+ this.collapse();
+ this.focus();
+ },
+
+ willDeselectValue() {
+ this.set("highlightedValue", null);
+ },
+ unsetValueFunction() {
+ this.set("value", null);
+ },
+ didDeselectValue() {
+ this.focus();
+ },
+
actions: {
onToggle() {
- this.toggleProperty("isExpanded");
-
- if (this.get("isExpanded") === true) { this.focus(); }
- },
-
- onCreateContent(input) {
- const content = this.createFunction(input)(this);
- this.get("computedContent").pushObject(content);
- this.send("onSelect", content.value);
- },
-
- onFilterChange(filter) {
- this.set("filter", filter);
- },
-
- onHighlight(value) {
- this.set("highlightedValue", value);
+ this.get("isExpanded") === true ? this.collapse() : this.expand();
},
onClearSelection() {
- this.send("onSelect", null);
+ this.send("onDeselect", this.get("value"));
+ },
+
+ onHighlight(value) {
+ value = this._originalValueForValue(value);
+ this.willHighlightValue(value);
+ this.set("highlightedValue", value);
+ this.highlightValueFunction(value);
+ this.didHighlightValue(value);
+ },
+
+ onCreateContent(input) {
+ this.willCreateContent(input);
+ this.createContentFunction(input);
+ this.didCreateContent(input);
},
onSelect(value) {
- value = this.defaultOnSelect(value);
- this.set("value", value);
+ if (value === "") { value = null; }
+ this.willSelectValue(value);
+ this.selectValueFunction(value);
+ this.didSelectValue(value);
},
- onDeselect() {
- this.defaultOnDeselect();
- this.set("value", null);
- }
+ onDeselect(value) {
+ value = this._originalValueForValue(value);
+ this.willDeselectValue(value);
+ this.unsetValueFunction(value);
+ this.didSelectValue(value);
+ },
+
+ onFilterChange(_filter) {
+ this.willFilterContent(_filter);
+ this.set("filter", _filter);
+ this.didFilterContent(_filter);
+ },
},
- defaultOnSelect(value) {
- if (value === "") { value = null; }
-
- this.setProperties({
- highlightedValue: null,
- isExpanded: false,
- filter: ""
- });
-
- this.focus();
-
- return value;
- },
-
- defaultOnDeselect(value) {
- const content = this.get("computedContent").findBy("value", value);
- if (!isNone(content) && get(content, "meta.generated") === true) {
- this.get("computedContent").removeObject(content);
- }
- },
-
- _applyDirection() {
- let options = { left: "auto", bottom: "auto", top: "auto" };
-
- const dHeader = $(".d-header")[0];
- const dHeaderBounds = dHeader ? dHeader.getBoundingClientRect() : {top: 0, height: 0};
- const dHeaderHeight = dHeaderBounds.top + dHeaderBounds.height;
- const headerHeight = this.$header().outerHeight(false);
- const headerWidth = this.$header().outerWidth(false);
- const bodyHeight = this.$body().outerHeight(false);
- const windowWidth = $(window).width();
- const windowHeight = $(window).height();
- const boundingRect = this.get("element").getBoundingClientRect();
- const offsetTop = boundingRect.top;
- const offsetBottom = boundingRect.bottom;
-
- if (this.get("fullWidthOnMobile") && windowWidth <= 420) {
- const margin = 10;
- const relativeLeft = this.$().offset().left - $(window).scrollLeft();
- options.left = margin - relativeLeft;
- options.width = windowWidth - margin * 2;
- options.maxWidth = options.minWidth = "unset";
- } else {
- const bodyWidth = this.$body().outerWidth(false);
-
- if ($("html").css("direction") === "rtl") {
- const horizontalSpacing = boundingRect.right;
- const hasHorizontalSpace = horizontalSpacing - (this.get("horizontalOffset") + bodyWidth) > 0;
- if (hasHorizontalSpace) {
- this.setProperties({ isLeftAligned: true, isRightAligned: false });
- options.left = bodyWidth + this.get("horizontalOffset");
- } else {
- this.setProperties({ isLeftAligned: false, isRightAligned: true });
- options.right = - (bodyWidth - headerWidth + this.get("horizontalOffset"));
- }
- } else {
- const horizontalSpacing = boundingRect.left;
- const hasHorizontalSpace = (windowWidth - (this.get("horizontalOffset") + horizontalSpacing + bodyWidth) > 0);
- if (hasHorizontalSpace) {
- this.setProperties({ isLeftAligned: true, isRightAligned: false });
- options.left = this.get("horizontalOffset");
- } else {
- this.setProperties({ isLeftAligned: false, isRightAligned: true });
- options.right = this.get("horizontalOffset");
- }
- }
- }
-
- const componentHeight = this.get("verticalOffset") + bodyHeight + headerHeight;
- const hasBelowSpace = windowHeight - offsetBottom - componentHeight > 0;
- const hasAboveSpace = offsetTop - componentHeight - dHeaderHeight > 0;
- if (hasBelowSpace || (!hasBelowSpace && !hasAboveSpace)) {
- this.setProperties({ isBelow: true, isAbove: false });
- options.top = headerHeight + this.get("verticalOffset");
- } else {
- this.setProperties({ isBelow: false, isAbove: true });
- options.bottom = headerHeight + this.get("verticalOffset");
- }
-
- this.$body().css(options);
- },
-
- _applyFixedPosition() {
- const width = this.$().outerWidth(false);
- const height = this.$header().outerHeight(false);
-
- if (this.get("scrollableParent").length === 0) { return; }
-
- const $placeholder = $(``);
-
- this._previousScrollParentOverflow = this.get("scrollableParent").css("overflow");
- this.get("scrollableParent").css({ overflow: "hidden" });
-
- this._previousCSSContext = {
- minWidth: this.$().css("min-width"),
- maxWidth: this.$().css("max-width")
- };
-
- const componentStyles = {
- position: "fixed",
- "margin-top": -this.get("scrollableParent").scrollTop(),
- width,
- minWidth: "unset",
- maxWidth: "unset"
- };
-
- if ($("html").css("direction") === "rtl") {
- componentStyles.marginRight = -width;
- } else {
- componentStyles.marginLeft = -width;
- }
-
- $placeholder.css({ display: "inline-block", width, height, "vertical-align": "middle" });
-
- this.$().before($placeholder).css(componentStyles);
- },
-
- _removeFixedPosition() {
- if (this.get("scrollableParent").length === 0) {
- return;
- }
-
- $(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove();
-
- const css = _.extend(
- this._previousCSSContext,
- {
- top: "auto",
- left: "auto",
- "margin-left": "auto",
- "margin-right": "auto",
- "margin-top": "auto",
- position: "relative"
- }
- );
- this.$().css(css);
-
- this.get("scrollableParent").css({
- overflow: this._previousScrollParentOverflow
- });
- },
-
- _positionWrapper() {
- const headerHeight = this.$header().outerHeight(false);
-
- this.$(".select-box-kit-wrapper").css({
- width: this.$().width(),
- height: headerHeight + this.$body().outerHeight(false)
- });
+ clearFilter() {
+ this.$filterInput().val("");
+ this.setProperties({ filter: "" });
},
@on("didReceiveAttrs")
diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-filter.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-filter.js.es6
index 9717b59f78a..aafaa5e1363 100644
--- a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-filter.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-filter.js.es6
@@ -2,5 +2,5 @@ export default Ember.Component.extend({
layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-filter",
classNames: "select-box-kit-filter",
classNameBindings: ["isFocused", "isHidden"],
- isHidden: Ember.computed.not("filterable"),
+ isHidden: Ember.computed.not("shouldDisplayFilter")
});
diff --git a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-row.js.es6 b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-row.js.es6
index efdb299a564..0ef116bba9a 100644
--- a/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-row.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/select-box-kit/select-box-kit-row.js.es6
@@ -8,12 +8,15 @@ export default Ember.Component.extend(UtilsMixin, {
layoutName: "select-box-kit/templates/components/select-box-kit/select-box-kit-row",
classNames: "select-box-kit-row",
tagName: "li",
+ tabIndex: -1,
attributeBindings: [
+ "tabIndex",
"title",
"content.value:data-value",
"content.name:data-name"
],
classNameBindings: ["isHighlighted", "isSelected"],
+ clicked: false,
title: Ember.computed.alias("content.name"),
@@ -23,17 +26,15 @@ export default Ember.Component.extend(UtilsMixin, {
@on("didReceiveAttrs")
_setSelectionState() {
const contentValue = this.get("content.value");
+
this.set("isSelected", this.get("value") === contentValue);
- this.set("isHighlighted", this._castInteger(this.get("highlightedValue")) === this._castInteger(contentValue));
+ this.set("isHighlighted", this.get("highlightedValue") === contentValue);
},
@on("willDestroyElement")
_clearDebounce() {
const hoverDebounce = this.get("hoverDebounce");
-
- if (isPresent(hoverDebounce)) {
- run.cancel(hoverDebounce);
- }
+ if (isPresent(hoverDebounce)) { run.cancel(hoverDebounce); }
},
@computed("content.originalContent.icon", "content.originalContent.iconClass")
@@ -50,7 +51,14 @@ export default Ember.Component.extend(UtilsMixin, {
},
click() {
- this.sendAction("onSelect", this.get("content.value"));
+ this._sendOnSelectAction();
+ },
+
+ _sendOnSelectAction() {
+ if (this.get("clicked") === false) {
+ this.set("clicked", true);
+ this.sendAction("onSelect", this.get("content.value"));
+ }
},
_sendOnHighlightAction() {
diff --git a/app/assets/javascripts/select-box-kit/components/tag-notifications-button.js.es6 b/app/assets/javascripts/select-box-kit/components/tag-notifications-button.js.es6
index 2ab3ed375ba..bc2d95ac4d0 100644
--- a/app/assets/javascripts/select-box-kit/components/tag-notifications-button.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/tag-notifications-button.js.es6
@@ -6,11 +6,7 @@ export default NotificationOptionsComponent.extend({
showFullTitle: false,
headerComponent: "tag-notifications-button/tag-notifications-button-header",
- actions: {
- onSelect(value) {
- value = this.defaultOnSelect(value);
- this.sendAction("action", value);
- this.blur();
- }
+ selectValueFunction(value) {
+ this.sendAction("action", value);
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/topic-footer-mobile-dropdown.js.es6 b/app/assets/javascripts/select-box-kit/components/topic-footer-mobile-dropdown.js.es6
index 2fb8f3e3172..2222fbc8221 100644
--- a/app/assets/javascripts/select-box-kit/components/topic-footer-mobile-dropdown.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/topic-footer-mobile-dropdown.js.es6
@@ -39,38 +39,34 @@ export default ComboBoxComponent.extend({
return content;
},
- actions: {
- onSelect(value) {
- value = this.defaultOnSelect(value);
+ selectValueFunction(value) {
+ const topic = this.get("topic");
- const topic = this.get("topic");
+ // In case it"s not a valid topic
+ if (!topic.get("id")) {
+ return;
+ }
- // In case it"s not a valid topic
- if (!topic.get("id")) {
- return;
- }
+ this.set("value", value);
- this.set("value", value);
+ const refresh = () => this.send("onDeselect", value);
- const refresh = () => this.set("value", null);
-
- switch(value) {
- case "invite":
- this.attrs.showInvite();
- refresh();
- break;
- case "bookmark":
- topic.toggleBookmark().then(() => refresh() );
- break;
- case "share":
- this.appEvents.trigger("share:url", topic.get("shareUrl"), $("#topic-footer-buttons"));
- refresh();
- break;
- case "flag":
- this.attrs.showFlagTopic();
- refresh();
- break;
- }
+ switch(value) {
+ case "invite":
+ this.attrs.showInvite();
+ refresh();
+ break;
+ case "bookmark":
+ topic.toggleBookmark().then(() => refresh() );
+ break;
+ case "share":
+ this.appEvents.trigger("share:url", topic.get("shareUrl"), $("#topic-footer-buttons"));
+ refresh();
+ break;
+ case "flag":
+ this.attrs.showFlagTopic();
+ refresh();
+ break;
}
}
});
diff --git a/app/assets/javascripts/select-box-kit/components/topic-notifications-options.js.es6 b/app/assets/javascripts/select-box-kit/components/topic-notifications-options.js.es6
index d1da27684a0..34f63f4ea5a 100644
--- a/app/assets/javascripts/select-box-kit/components/topic-notifications-options.js.es6
+++ b/app/assets/javascripts/select-box-kit/components/topic-notifications-options.js.es6
@@ -24,17 +24,11 @@ export default NotificationOptionsComponent.extend({
this.appEvents.off("topic-notifications-button:changed");
},
- actions: {
- onSelect(value) {
- if (value !== this.get("computedValue")) {
- this.get("topic.details").updateNotifications(value);
- }
-
- this.set("value", value);
-
- this.defaultOnSelect(value);
-
- this.blur();
+ selectValueFunction(value) {
+ if (value !== this.get("value")) {
+ this.get("topic.details").updateNotifications(value);
}
+
+ this.set("value", value);
}
});
diff --git a/app/assets/javascripts/select-box-kit/mixins/dom-helpers.js.es6 b/app/assets/javascripts/select-box-kit/mixins/dom-helpers.js.es6
index d8caacb501e..ed70bcc59e8 100644
--- a/app/assets/javascripts/select-box-kit/mixins/dom-helpers.js.es6
+++ b/app/assets/javascripts/select-box-kit/mixins/dom-helpers.js.es6
@@ -1,3 +1,5 @@
+import { on } from "ember-addons/ember-computed-decorators";
+
export default Ember.Mixin.create({
init() {
this._super();
@@ -8,46 +10,237 @@ export default Ember.Mixin.create({
this.collectionSelector = ".select-box-kit-collection";
this.headerSelector = ".select-box-kit-header";
this.bodySelector = ".select-box-kit-body";
+ this.wrapperSelector = ".select-box-kit-wrapper";
},
- $findRowByValue(value) {
- return this.$(`${this.rowSelector}[data-value='${value}']`);
+ $findRowByValue(value) { return this.$(`${this.rowSelector}[data-value='${value}']`); },
+
+ $header() { return this.$(this.headerSelector); },
+
+ $body() { return this.$(this.bodySelector); },
+
+ $collection() { return this.$(this.collectionSelector); },
+
+ $rows(withHidden) {
+
+ if (withHidden === true) {
+ return this.$(`${this.rowSelector}:not(.no-content)`);
+ } else {
+ return this.$(`${this.rowSelector}:not(.no-content):not(.is-hidden)`);
+ }
},
- $header() {
- return this.$(this.headerSelector);
+ $highlightedRow() { return this.$rows().filter(".is-highlighted"); },
+
+ $selectedRow() { return this.$rows().filter(".is-selected"); },
+
+ $offscreenInput() { return this.$(this.offscreenInputSelector); },
+
+ $filterInput() { return this.$(this.filterInputSelector); },
+
+ @on("didRender")
+ _ajustPosition() {
+ $(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove();
+ this.$collection().css("max-height", this.get("collectionHeight"));
+ this._applyFixedPosition();
+ this._applyDirection();
+ this._positionWrapper();
},
- $body() {
- return this.$(this.bodySelector);
+ @on("willDestroyElement")
+ _clearState() {
+ $(window).off("resize.select-box-kit");
+ $(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove();
},
- $collection() {
- return this.$(this.collectionSelector);
+ // make sure we don’t propagate a click outside component
+ // to avoid closing a modal containing the component for example
+ click(event) { this._killEvent(event); },
+
+ // use to collapse and remove focus
+ close() {
+ this.collapse();
+ this.setProperties({ isFocused: false });
},
- $rows() {
- return this.$(this.rowSelector);
+ // force the component in a known default state
+ focus() {
+ Ember.run.schedule("afterRender", () => this.$offscreenInput().focus() );
},
- $highlightedRow() {
- return this.$rows().filter(".is-highlighted");
+ expand() {
+ if (this.get("isExpanded") === true) { return; }
+ this.setProperties({ isExpanded: true, renderedBodyOnce: true, isFocused: true });
+ this.focus();
+ this.autoHighlightFunction();
},
- $selectedRow() {
- return this.$rows().filter(".is-selected");
+ collapse() {
+ this.set("isExpanded", false);
+ Ember.run.schedule("afterRender", () => this._removeFixedPosition() );
},
- $offscreenInput() {
- return this.$(this.offscreenInputSelector);
+ // make sure we close/unfocus the component when clicked outside
+ clickOutside(event) {
+ if ($(event.target).parents(".select-box-kit").length === 1) {
+ this.close();
+ return false;
+ }
+
+ this.unfocus();
+ return;
},
- $filterInput() {
- return this.$(this.filterInputSelector);
+ // lose focus of the component in two steps
+ // first collapase and keep focus and then remove focus
+ unfocus() {
+ this.set("highlightedValue", null);
+
+ if (this.get("isExpanded") === true) {
+ this.collapse();
+ this.focus();
+ } else {
+ this.close();
+ }
+ },
+
+ blur() {
+ Ember.run.schedule("afterRender", () => this.$offscreenInput().blur() );
},
_killEvent(event) {
event.preventDefault();
event.stopPropagation();
- }
+ },
+
+ _applyDirection() {
+ let options = { left: "auto", bottom: "auto", top: "auto" };
+
+ const dHeader = $(".d-header")[0];
+ const dHeaderBounds = dHeader ? dHeader.getBoundingClientRect() : {top: 0, height: 0};
+ const dHeaderHeight = dHeaderBounds.top + dHeaderBounds.height;
+ const headerHeight = this.$header().outerHeight(false);
+ const headerWidth = this.$header().outerWidth(false);
+ const bodyHeight = this.$body().outerHeight(false);
+ const windowWidth = $(window).width();
+ const windowHeight = $(window).height();
+ const boundingRect = this.get("element").getBoundingClientRect();
+ const offsetTop = boundingRect.top;
+ const offsetBottom = boundingRect.bottom;
+
+ if (this.get("fullWidthOnMobile") && windowWidth <= 420) {
+ const margin = 10;
+ const relativeLeft = this.$().offset().left - $(window).scrollLeft();
+ options.left = margin - relativeLeft;
+ options.width = windowWidth - margin * 2;
+ options.maxWidth = options.minWidth = "unset";
+ } else {
+ const bodyWidth = this.$body().outerWidth(false);
+
+ if ($("html").css("direction") === "rtl") {
+ const horizontalSpacing = boundingRect.right;
+ const hasHorizontalSpace = horizontalSpacing - (this.get("horizontalOffset") + bodyWidth) > 0;
+ if (hasHorizontalSpace) {
+ this.setProperties({ isLeftAligned: true, isRightAligned: false });
+ options.left = bodyWidth + this.get("horizontalOffset");
+ } else {
+ this.setProperties({ isLeftAligned: false, isRightAligned: true });
+ options.right = - (bodyWidth - headerWidth + this.get("horizontalOffset"));
+ }
+ } else {
+ const horizontalSpacing = boundingRect.left;
+ const hasHorizontalSpace = (windowWidth - (this.get("horizontalOffset") + horizontalSpacing + bodyWidth) > 0);
+ if (hasHorizontalSpace) {
+ this.setProperties({ isLeftAligned: true, isRightAligned: false });
+ options.left = this.get("horizontalOffset");
+ } else {
+ this.setProperties({ isLeftAligned: false, isRightAligned: true });
+ options.right = this.get("horizontalOffset");
+ }
+ }
+ }
+
+ const componentHeight = this.get("verticalOffset") + bodyHeight + headerHeight;
+ const hasBelowSpace = windowHeight - offsetBottom - componentHeight > 0;
+ const hasAboveSpace = offsetTop - componentHeight - dHeaderHeight > 0;
+ if (hasBelowSpace || (!hasBelowSpace && !hasAboveSpace)) {
+ this.setProperties({ isBelow: true, isAbove: false });
+ options.top = headerHeight + this.get("verticalOffset");
+ } else {
+ this.setProperties({ isBelow: false, isAbove: true });
+ options.bottom = headerHeight + this.get("verticalOffset");
+ }
+
+ this.$body().css(options);
+ },
+
+ _applyFixedPosition() {
+ if (this.get("scrollableParent").length === 0) { return; }
+
+ const width = this.$().outerWidth(false);
+ const height = this.$().outerHeight(false);
+ const $placeholder = $(``);
+
+ this._previousScrollParentOverflow = this.get("scrollableParent").css("overflow");
+ this.get("scrollableParent").css({ overflow: "hidden" });
+
+ this._previousCSSContext = {
+ minWidth: this.$().css("min-width"),
+ maxWidth: this.$().css("max-width")
+ };
+
+ const componentStyles = {
+ position: "fixed",
+ "margin-top": -this.get("scrollableParent").scrollTop(),
+ width,
+ minWidth: "unset",
+ maxWidth: "unset"
+ };
+
+ if ($("html").css("direction") === "rtl") {
+ componentStyles.marginRight = -width;
+ } else {
+ componentStyles.marginLeft = -width;
+ }
+
+ $placeholder.css({ display: "inline-block", width, height, "vertical-align": "middle" });
+
+ this.$().before($placeholder).css(componentStyles);
+ },
+
+ _removeFixedPosition() {
+ $(`.select-box-kit-fixed-placeholder-${this.elementId}`).remove();
+
+ if (this.get("scrollableParent").length === 0) {
+ return;
+ }
+
+ if (!this.element || this.isDestroying || this.isDestroyed) { return; }
+
+ const css = jQuery.extend(
+ this._previousCSSContext,
+ {
+ top: "auto",
+ left: "auto",
+ "margin-left": "auto",
+ "margin-right": "auto",
+ "margin-top": "auto",
+ position: "relative"
+ }
+ );
+ this.$().css(css);
+
+ this.get("scrollableParent").css({
+ overflow: this._previousScrollParentOverflow
+ });
+ },
+
+ _positionWrapper() {
+ const headerHeight = this.$header().outerHeight(false);
+
+ this.$(this.wrapperSelector).css({
+ width: this.$().outerWidth(false),
+ height: headerHeight + this.$body().outerHeight(false)
+ });
+ },
});
diff --git a/app/assets/javascripts/select-box-kit/mixins/keyboard.js.es6 b/app/assets/javascripts/select-box-kit/mixins/keyboard.js.es6
index 0de89dbb2e7..e7973f5b0f8 100644
--- a/app/assets/javascripts/select-box-kit/mixins/keyboard.js.es6
+++ b/app/assets/javascripts/select-box-kit/mixins/keyboard.js.es6
@@ -1,5 +1,3 @@
-const { isEmpty } = Ember;
-
export default Ember.Mixin.create({
init() {
this._super();
@@ -35,9 +33,13 @@ export default Ember.Mixin.create({
.off("focus.select-box-kit")
.off("focusin.select-box-kit")
.off("blur.select-box-kit")
+ .off("keypress.select-box-kit")
.off("keydown.select-box-kit");
- this.$filterInput().off("keydown.select-box-kit");
+ this.$filterInput()
+ .off("change.select-box-kit")
+ .off("keypress.select-box-kit")
+ .off("keydown.select-box-kit");
},
didInsertElement() {
@@ -70,58 +72,67 @@ export default Ember.Mixin.create({
.on("keydown.select-box-kit", (event) => {
const keyCode = event.keyCode || event.which;
+ if (keyCode === this.keys.TAB) { this._handleTabOnKeyDown(event); }
+ if (keyCode === this.keys.ESC) { this._handleEscOnKeyDown(event); }
+ if (keyCode === this.keys.UP || keyCode === this.keys.DOWN) {
+ this._handleArrowKey(keyCode, event);
+ }
+ if (keyCode === this.keys.BACKSPACE) {
+ this.expand();
+
+ if (this.$filterInput().is(":visible")) {
+ this.$filterInput().focus().trigger(event).trigger("change");
+ }
+
+ return event;
+ }
+
+ return true;
+ })
+ .on("keypress.select-box-kit", (event) => {
+ const keyCode = event.keyCode || event.which;
+
switch (keyCode) {
- case this.keys.UP:
- case this.keys.DOWN:
- if (this.get("isExpanded") === false) {
- this.set("isExpanded", true);
- }
-
- Ember.run.schedule("actions", () => {
- this._handleArrowKey(keyCode);
- });
-
- this._killEvent(event);
-
- return;
case this.keys.ENTER:
if (this.get("isExpanded") === false) {
- this.set("isExpanded", true);
- } else {
- this.send("onSelect", this.$highlightedRow().data("value"));
+ this.expand();
+ } else if (this.$highlightedRow().length === 1) {
+ this.$highlightedRow().click();
}
-
- this._killEvent(event);
-
- return;
- case this.keys.TAB:
- if (this.get("isExpanded") === false) {
- return true;
- } else {
- this.send("onSelect", this.$highlightedRow().data("value"));
- return;
- }
- case this.keys.ESC:
- this.close();
- this._killEvent(event);
- return;
+ return false;
case this.keys.BACKSPACE:
- this._killEvent(event);
- return;
+ return event;
}
if (this._isSpecialKey(keyCode) === false && event.metaKey === false) {
- this.setProperties({
- isExpanded: true,
- filter: String.fromCharCode(keyCode)
- });
+ this.expand();
- Ember.run.schedule("afterRender", () => this.$filterInput().focus() );
+ if (this.get("filterable") === true || this.get("autoFilterable")) {
+ this.set("renderedFilterOnce", true);
+ }
+
+ Ember.run.schedule("afterRender", () => {
+ this.$filterInput()
+ .focus()
+ .val(this.$filterInput().val() + String.fromCharCode(keyCode));
+ });
}
});
this.$filterInput()
- .on(`keydown.select-box-kit`, (event) => {
+ .on("change.select-box-kit", (event) => {
+ this.send("onFilterChange", $(event.target).val());
+ })
+ .on("keydown.select-box-kit", (event) => {
+ const keyCode = event.keyCode || event.which;
+
+ if (keyCode === this.keys.TAB) { this._handleTabOnKeyDown(event); }
+ if (keyCode === this.keys.ESC) { this._handleEscOnKeyDown(event); }
+ if (keyCode === this.keys.UP || keyCode === this.keys.DOWN) {
+ this._handleArrowKey(keyCode, event);
+ }
+ })
+ .on("keypress.select-box-kit", (event) => {
const keyCode = event.keyCode || event.which;
if ([
@@ -133,67 +144,75 @@ export default Ember.Mixin.create({
return true;
}
+ if (keyCode === this.keys.TAB && this.get("isExpanded") === false) {
+ return true;
+ }
+
if (this._isSpecialKey(keyCode) === true) {
this.$offscreenInput().focus().trigger(event);
+ return false;
}
return true;
});
},
- _handleArrowKey(keyCode) {
- if (isEmpty(this.get("filteredContent"))) {
+ _handleEscOnKeyDown(event) {
+ this.unfocus();
+ this._killEvent(event);
+ },
+
+ _handleTabOnKeyDown(event) {
+ if (this.get("isExpanded") === false) {
+ this.unfocus();
+ return true;
+ } else if (this.$highlightedRow().length === 1) {
+ this._killEvent(event);
+ this.$highlightedRow().click();
+ this.focus();
+ } else {
+ this.unfocus();
+ return true;
+ }
+ return false;
+ },
+
+ _handleArrowKey(keyCode, event) {
+ if (this.get("isExpanded") === false) { this.expand(); }
+ this._killEvent(event);
+ const $rows = this.$rows();
+
+ if ($rows.length <= 0) { return; }
+ if ($rows.length === 1) {
+ this._rowSelection($rows, 0);
return;
}
- Ember.run.schedule("afterRender", () => {
- switch (keyCode) {
- case 38:
- Ember.run.throttle(this, this._handleUpArrow, 32);
- break;
- default:
- Ember.run.throttle(this, this._handleDownArrow, 32);
- }
- });
+ const direction = keyCode === 38 ? -1 : 1;
+
+ Ember.run.throttle(this, this._moveHighlight, direction, $rows, 32);
},
- _moveHighlight(direction) {
- const $rows = this.$rows();
+ _moveHighlight(direction, $rows) {
const currentIndex = $rows.index(this.$highlightedRow());
+ let nextIndex = currentIndex + direction;
- let nextIndex = 0;
-
- if (currentIndex < 0) {
+ if (nextIndex < 0) {
+ nextIndex = $rows.length - 1;
+ } else if (nextIndex >= $rows.length) {
nextIndex = 0;
- } else if (currentIndex + direction < $rows.length) {
- nextIndex = currentIndex + direction;
}
this._rowSelection($rows, nextIndex);
},
- _handleDownArrow() { this._moveHighlight(1); },
-
- _handleUpArrow() { this._moveHighlight(-1); },
-
_rowSelection($rows, nextIndex) {
- const highlightableValue = $rows.eq(nextIndex).data("value");
+ const highlightableValue = $rows.eq(nextIndex).attr("data-value");
const $highlightableRow = this.$findRowByValue(highlightableValue);
- this.send("onHighlight", highlightableValue);
Ember.run.schedule("afterRender", () => {
- const $collection = this.$collection();
- const currentOffset = $collection.offset().top +
- $collection.outerHeight(false);
- const nextBottom = $highlightableRow.offset().top +
- $highlightableRow.outerHeight(false);
- const nextOffset = $collection.scrollTop() + nextBottom - currentOffset;
-
- if (nextIndex === 0) {
- $collection.scrollTop(0);
- } else if (nextBottom > currentOffset) {
- $collection.scrollTop(nextOffset);
- }
+ $highlightableRow.trigger("mouseover").focus();
+ this.focus();
});
},
diff --git a/app/assets/javascripts/select-box-kit/mixins/utils.js.es6 b/app/assets/javascripts/select-box-kit/mixins/utils.js.es6
index 05d896a832b..3ece47cc3bf 100644
--- a/app/assets/javascripts/select-box-kit/mixins/utils.js.es6
+++ b/app/assets/javascripts/select-box-kit/mixins/utils.js.es6
@@ -1,9 +1,57 @@
+const { get, isNone } = Ember;
+
export default Ember.Mixin.create({
+ _nameForContent(content) {
+ if (isNone(content)) {
+ return null;
+ }
+
+ if (typeof content === "object") {
+ return get(content, this.get("nameProperty"));
+ }
+
+ return content;
+ },
+
_castInteger(value) {
if (this.get("castInteger") === true && Ember.isPresent(value)) {
return parseInt(value, 10);
}
- return Ember.isNone(value) ? value : value.toString();
- }
+ return value;
+ },
+
+ _valueForContent(content) {
+ switch (typeof content) {
+ case "string":
+ case "number":
+ return content;
+ default:
+ return get(content, this.get("valueAttribute"));
+ }
+ },
+
+ _contentForValue(value) {
+ return this.get("content").find(c => {
+ if (this._valueForContent(c) === value) { return true; }
+ });
+ },
+
+ _computedContentForValue(value) {
+ const searchedValue = value.toString();
+ return this.get("computedContent").find(c => {
+ if (c.value.toString() === searchedValue) { return true; }
+ });
+ },
+
+ _originalValueForValue(value) {
+ if (isNone(value)) { return null; }
+ if (value === this.noneValue) { return this.noneValue; }
+
+ const computedContent = this._computedContentForValue(value);
+
+ if (isNone(computedContent)) { return value; }
+
+ return get(computedContent.originalContent, this.get("valueAttribute"));
+ },
});
diff --git a/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/multi-combo-box-header.hbs b/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/multi-combo-box-header.hbs
index 13cf6c3f6d5..6245b4e8c7b 100644
--- a/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/multi-combo-box-header.hbs
+++ b/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/multi-combo-box-header.hbs
@@ -1,30 +1,13 @@
{{#each selectedContent as |selectedContent|}}
- -
-
- {{d-icon "times"}}
-
-
- {{selectedContent.name}}
-
-
- {{else}}
- {{#if shouldDisplayFilterPlaceholder}}
- -
- {{text}}
-
- {{/if}}
+ {{component selectedNameComponent onDeselect=onDeselect content=selectedContent}}
{{/each}}
-
-
- {{input
- class="select-box-kit-filter-input"
- key-up=onFilterChange
- autocomplete="off"
- autocorrect="off"
- autocapitalize="off"
- spellcheck=false
- value=filter
+ {{component "select-box-kit/select-box-kit-filter"
+ onFilterChange=onFilterChange
+ shouldDisplayFilter=shouldDisplayFilter
+ isFocused=isFocused
+ filter=filter
}}
diff --git a/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/selected-name.hbs b/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/selected-name.hbs
new file mode 100644
index 00000000000..54ef362ed31
--- /dev/null
+++ b/app/assets/javascripts/select-box-kit/templates/components/multi-combo-box/selected-name.hbs
@@ -0,0 +1,9 @@
+
+ {{#unless isLocked}}
+
+ {{d-icon "times"}}
+
+ {{/unless}}
+
+ {{content.name}}
+
diff --git a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit.hbs b/app/assets/javascripts/select-box-kit/templates/components/select-box-kit.hbs
index 6575daf8843..9c9e7188ad7 100644
--- a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit.hbs
+++ b/app/assets/javascripts/select-box-kit/templates/components/select-box-kit.hbs
@@ -19,6 +19,7 @@
onToggle=(action "onToggle")
onFilterChange=(action "onFilterChange")
onClearSelection=(action "onClearSelection")
+ shouldDisplayFilter=shouldDisplayFilter
options=headerComponentOptions
}}
@@ -26,16 +27,14 @@
{{component filterComponent
onFilterChange=(action "onFilterChange")
icon=filterIcon
- filter=filter
- filterable=computedFilterable
+ shouldDisplayFilter=shouldDisplayFilter
isFocused=isFocused
placeholder=(i18n filterPlaceholder)
- tabindex=tabindex
+ filter=filter
}}
- {{#if renderBody}}
+ {{#if renderedBodyOnce}}
{{component collectionComponent
- shouldDisplayCreateRow=shouldDisplayCreateRow
none=computedNone
createRowContent=createRowContent
selectedContent=selectedContent
@@ -43,13 +42,9 @@
rowComponent=rowComponent
noneRowComponent=noneRowComponent
createRowComponent=createRowComponent
- iconForRow=iconForRow
templateForRow=templateForRow
templateForNoneRow=templateForNoneRow
templateForCreateRow=templateForCreateRow
- shouldHighlightRow=shouldHighlightRow
- shouldSelectRow=shouldSelectRow
- titleForRow=titleForRow
onClearSelection=(action "onClearSelection")
onSelect=(action "onSelect")
onHighlight=(action "onHighlight")
diff --git a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-collection.hbs b/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-collection.hbs
index 73f80e2608a..bf7311049cb 100644
--- a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-collection.hbs
+++ b/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-collection.hbs
@@ -3,8 +3,6 @@
{{component noneRowComponent
content=none
templateForRow=templateForNoneRow
- titleForRow=titleForRow
- iconForRow=iconForRow
highlightedValue=highlightedValue
onClearSelection=onClearSelection
onHighlight=onHighlight
@@ -14,12 +12,11 @@
{{/if}}
{{/if}}
-{{#if shouldDisplayCreateRow}}
+{{#if createRowContent}}
{{component createRowComponent
content=createRowContent
templateForRow=templateForCreateRow
titleForRow=titleForRow
- iconForRow=iconForRow
highlightedValue=highlightedValue
onHighlight=onHighlight
onCreateContent=onCreateContent
@@ -33,7 +30,6 @@
content=content
templateForRow=templateForRow
titleForRow=titleForRow
- iconForRow=iconForRow
highlightedValue=highlightedValue
onSelect=onSelect
onHighlight=onHighlight
diff --git a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-filter.hbs b/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-filter.hbs
index 74d12880749..dc50d225040 100644
--- a/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-filter.hbs
+++ b/app/assets/javascripts/select-box-kit/templates/components/select-box-kit/select-box-kit-filter.hbs
@@ -1,8 +1,8 @@
{{input
- tabindex=tabindex
+ tabindex=-1
class="select-box-kit-filter-input"
placeholder=placeholder
- key-down=onFilterChange
+ key-up=onFilterChange
autocomplete="off"
autocorrect="off"
autocapitalize="off"
diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss
index 2f418ddad3f..eb8eb427d85 100644
--- a/app/assets/stylesheets/common/admin/admin_base.scss
+++ b/app/assets/stylesheets/common/admin/admin_base.scss
@@ -215,9 +215,8 @@ $mobile-breakpoint: 700px;
.select-box-kit {
width: 350px;
}
-
- .select-box-kit-header {
- height: 28px;
+ .select-box-kit.multi-combo-box {
+ width: 500px;
}
}
@@ -620,6 +619,10 @@ section.details {
text-align: left;
margin-left: 0;
}
+
+ .select-box-kit {
+ width: inherit;
+ }
}
.long-value {
width: 800px;
@@ -701,7 +704,7 @@ section.details {
.ace_editor {
pointer-events:none;
-
+
.ace_cursor {
visibility: hidden;
}
diff --git a/app/assets/stylesheets/common/select-box-kit/dropdown-select-box.scss b/app/assets/stylesheets/common/select-box-kit/dropdown-select-box.scss
index 363af0d7958..670a31e657c 100644
--- a/app/assets/stylesheets/common/select-box-kit/dropdown-select-box.scss
+++ b/app/assets/stylesheets/common/select-box-kit/dropdown-select-box.scss
@@ -89,14 +89,6 @@
white-space: normal;
}
}
-
- &.is-highlighted {
- background: $tertiary-low;
- }
-
- &:hover {
- background: $highlight-medium;
- }
}
.select-box-kit-collection {
diff --git a/app/assets/stylesheets/common/select-box-kit/list-setting.scss b/app/assets/stylesheets/common/select-box-kit/list-setting.scss
new file mode 100644
index 00000000000..eea89e6cb5a
--- /dev/null
+++ b/app/assets/stylesheets/common/select-box-kit/list-setting.scss
@@ -0,0 +1,13 @@
+.select-box-kit {
+ &.multi-combo-box {
+ &.list-setting {
+ .select-box-kit-row.create {
+ .square {
+ width: 12px;
+ height: 12px;
+ margin-left: 5px;
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/common/select-box-kit/multi-combo-box.scss b/app/assets/stylesheets/common/select-box-kit/multi-combo-box.scss
new file mode 100644
index 00000000000..501afde4e6e
--- /dev/null
+++ b/app/assets/stylesheets/common/select-box-kit/multi-combo-box.scss
@@ -0,0 +1,147 @@
+.select-box-kit {
+ &.multi-combo-box {
+ width: 300px;
+ background: $secondary;
+ border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
+ border-radius: 0;
+
+ .select-box-kit-body {
+ width: 100%;
+ }
+
+ .select-box-kit-row {
+ margin: 5px;
+ min-height: 1px;
+ padding: 5px;
+ border-radius: 0;
+ }
+
+ .select-box-kit-filter {
+ border: 0;
+ }
+
+ .multi-combo-box-header {
+ background: $secondary;
+ border: 0;
+ border-bottom: 1px solid transparent;
+
+ &.is-focused {
+ box-shadow: $tertiary 0px 0px 6px 0px;
+ border-radius: 0;
+ }
+ }
+
+ &.is-disabled {
+ .multi-combo-box-header {
+ background: #e9e9e9;
+ border-color: #ddd;
+ }
+ }
+
+ &.is-highlighted {
+ .multi-combo-box-header {
+ border-radius: 0;
+ border-bottom: 1px solid transparent;
+ box-shadow: $tertiary 0px 0px 6px 0px;
+ }
+ }
+
+ &.is-expanded {
+ .select-box-kit-wrapper {
+ display: block;
+ border: 1px solid $tertiary;
+ box-shadow: $tertiary 0px 0px 6px 0px;
+ border-radius: 0;
+ }
+
+ .multi-combo-box-header {
+ border-bottom: 1px solid $primary-low;
+ border-radius: 0;
+ box-shadow: none;
+ }
+
+ .select-box-kit-body {
+ border-radius: 0;
+ }
+ }
+
+ .choices {
+ list-style: none;
+ margin: 0;
+ padding: 5px;
+ flex: 1;
+ min-height: 36px;
+ box-sizing: border-box;
+
+ li {
+ display: inline-flex;
+ box-sizing: border-box;
+ padding: 0 5px;
+ margin-bottom: 4px;
+ border: 1px solid transparent;
+ }
+
+ .filter {
+ align-items: center;
+ justify-content: flex-start;
+ white-space: nowrap;
+ min-width: 50px;
+ padding: 0;
+
+ .select-box-kit-filter-input, .select-box-kit-filter-input:focus {
+ border: none;
+ background: none;
+ display: inline-block;
+ width: 100%;
+ outline: none;
+ min-width: auto;
+ padding: 0;
+ margin: 0;
+ outline: 0;
+ border: 0;
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ border-radius: 0;
+ }
+ }
+
+ .selected-name {
+ align-items: center;
+ justify-content: flex-start;
+ color: $primary;
+ cursor: default;
+ border: 1px solid $primary-medium;
+ border-radius: 3px;
+ box-shadow: 0 0 2px $secondary inset, 0 1px 0 rgba(0,0,0,0.05);
+ background-clip: padding-box;
+ -webkit-touch-callout: none;
+ user-select: none;
+ background-color: $primary-low;
+ cursor: pointer;
+ outline: none;
+ padding: 0;
+ line-height: normal;
+
+ .name {
+ padding: 0 5px;
+ line-height: 22px
+ }
+
+ &.is-highlighted {
+ border-color: $danger;
+ }
+
+ .d-icon {
+ margin-right: 5px;
+ color: $primary-medium;
+ cursor: pointer;
+ font-size: 12px;
+
+ &:hover {
+ color: $primary;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/common/select-box-kit/multi-combobox.scss b/app/assets/stylesheets/common/select-box-kit/multi-combobox.scss
deleted file mode 100644
index 87235fa8f3a..00000000000
--- a/app/assets/stylesheets/common/select-box-kit/multi-combobox.scss
+++ /dev/null
@@ -1,131 +0,0 @@
-.multi-combobox {
- width: 300px;
- background: $secondary;
- border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
-
- .select-box-kit-body {
- width: 100%;
- }
-
- .select-box-kit-row {
- margin: 5px;
- min-height: 1px;
- padding: 5px;
- }
-
- .select-box-kit-filter {
- border-top: 1px solid $primary-low;
- }
-
- .select-box-kit-header {
- background: $secondary;
- border-bottom: 1px solid transparent;
-
- &.is-focused {
- border-bottom: 1px solid $primary-low;
- box-shadow: $tertiary 0px 0px 6px 0px;
- }
- }
-
- &.is-disabled {
- .select-box-kit-header {
- background: #e9e9e9;
- border-color: #ddd;
- }
- }
-
- &.is-highlighted {
- .select-box-kit-header {
- border: 1px solid $tertiary;
- box-shadow: $tertiary 0px 0px 6px 0px;
- }
- }
-
- &.is-expanded {
- .select-box-kit-wrapper {
- display: block;
- border: 1px solid $tertiary;
- box-shadow: $tertiary 0px 0px 6px 0px;
- }
-
- .select-box-kit-header {
- border-radius: 3px 3px 0 0;
- }
-
- .select-box-kit-body {
- border-radius: 3px 3px 0 0;
- }
- }
-
- .choices {
- list-style: none;
- margin: 0;
- padding: 5px;
- }
-
- .choice-placeholder {
- padding: 0 5px;
- margin: 2px 0;
- border: 1px solid transparent;
- display: inline-flex;
- flex: 1;
- }
-
- .filter {
- display: inline-flex;
- align-items: center;
- justify-content: flex-start;
- margin: 0;
- padding: 0;
- white-space: nowrap;
- }
-
- .select-box-kit-filter-input, .select-box-kit-filter-input:focus {
- border: none;
- background: none;
- display: inline-block;
- width: 100%;
- outline: none;
- min-width: auto;
- padding: 0;
- margin: 0;
- outline: 0;
- border: 0;
- -webkit-box-shadow: none;
- box-shadow: none;
- border-radius: 0;
- }
-
- .selected-name {
- display: inline-flex;
- align-items: center;
- justify-content: flex-start;
- padding: 0 5px;
- margin: 2px 0;
- color: $primary;
- cursor: default;
- border: 1px solid $primary-medium;
- border-radius: 3px;
- box-shadow: 0 0 2px $secondary inset, 0 1px 0 rgba(0,0,0,0.05);
- background-clip: padding-box;
- -webkit-touch-callout: none;
- user-select: none;
- background-color: $primary-low;
-
- &:focus {
- border-color: $primary;
- outline: none;
- }
-
- .d-icon {
- margin-right: 5px;
- color: $primary-medium;
- cursor: pointer;
- font-size: 12px;
-
- &:hover {
- color: $primary;
- }
- }
- }
-}
diff --git a/app/assets/stylesheets/common/select-box-kit/select-box-kit.scss b/app/assets/stylesheets/common/select-box-kit/select-box-kit.scss
index 56ccf609ab8..05f7d620f58 100644
--- a/app/assets/stylesheets/common/select-box-kit/select-box-kit.scss
+++ b/app/assets/stylesheets/common/select-box-kit/select-box-kit.scss
@@ -3,6 +3,7 @@
}
.select-box-kit {
+ border: 1px solid transparent;
min-width: 220px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
@@ -65,6 +66,9 @@
}
.select-box-kit-header {
+ border: 1px solid transparent;
+ box-sizing: border-box;
+ overflow: hidden;
-webkit-transition: all .25s;
-o-transition: all .25s;
transition: all .25s;
@@ -138,10 +142,13 @@
.select-box-kit-row {
cursor: pointer;
+ line-height: normal;
outline: none;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
+ -webkit-box-sizing: border-box;
+ box-sizing: border-box;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
@@ -172,10 +179,6 @@
&.is-selected.is-highlighted {
background: $tertiary-low;
}
-
- &.none:not(.is-highlighted) {
- background: $primary-low;
- }
}
.select-box-kit-collection {
@@ -255,8 +258,8 @@
.select-box-kit-wrapper {
position: absolute;
- top: 0;
- left: 0;
+ top: -1px;
+ left: -1px;
background: none;
display: none;
-webkit-box-sizing: border-box;
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index ec4fc40a9fa..2b28082280a 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -1155,6 +1155,7 @@ en:
default_header_text: Select...
no_content: No matches found
filter_placeholder: Search...
+ create: "Create {{content}}"
emoji_picker:
filter_placeholder: Search for emoji
diff --git a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 b/test/javascripts/acceptance/admin-suspend-user-test.js.es6
index 4c3d43feeb3..bd1fb803563 100644
--- a/test/javascripts/acceptance/admin-suspend-user-test.js.es6
+++ b/test/javascripts/acceptance/admin-suspend-user-test.js.es6
@@ -44,8 +44,8 @@ QUnit.test("suspend, then unsuspend a user", assert => {
andThen(() => {
assert.equal(find('.perform-suspend[disabled]').length, 1, 'disabled by default');
- expandSelectBox('.suspend-until .combobox');
- selectBoxSelectRow('tomorrow', { selector: '.suspend-until .combobox'});
+ expandSelectBoxKit('.suspend-until .combobox');
+ selectBoxKitSelectRow('tomorrow', { selector: '.suspend-until .combobox'});
});
fillIn('.suspend-reason', "for breaking the rules");
diff --git a/test/javascripts/acceptance/category-chooser-test.js.es6 b/test/javascripts/acceptance/category-chooser-test.js.es6
index de39c870945..9f645bc6b00 100644
--- a/test/javascripts/acceptance/category-chooser-test.js.es6
+++ b/test/javascripts/acceptance/category-chooser-test.js.es6
@@ -11,7 +11,7 @@ QUnit.test("does not display uncategorized if not allowed", assert => {
visit("/");
click('#create-topic');
- expandSelectBox('.category-chooser');
+ ('.category-chooser');
andThen(() => {
assert.ok(selectBox('.category-chooser').rowByIndex(0).name() !== 'uncategorized');
diff --git a/test/javascripts/acceptance/category-edit-test.js.es6 b/test/javascripts/acceptance/category-edit-test.js.es6
index d3a99c3a35e..24d1eceef41 100644
--- a/test/javascripts/acceptance/category-edit-test.js.es6
+++ b/test/javascripts/acceptance/category-edit-test.js.es6
@@ -75,9 +75,9 @@ QUnit.test("Subcategory list settings", assert => {
click('.edit-category-general');
- expandSelectBox('.edit-category-tab-general .category-chooser');
+ expandSelectBoxKit('.edit-category-tab-general .category-chooser');
- selectBoxSelectRow(3, {selector: '.edit-category-tab-general .category-chooser'});
+ selectBoxKitSelectRow(3, {selector: '.edit-category-tab-general .category-chooser'});
click('.edit-category-settings');
andThen(() => {
diff --git a/test/javascripts/acceptance/search-full-test.js.es6 b/test/javascripts/acceptance/search-full-test.js.es6
index b64ca86dec4..24ad402b30b 100644
--- a/test/javascripts/acceptance/search-full-test.js.es6
+++ b/test/javascripts/acceptance/search-full-test.js.es6
@@ -257,8 +257,8 @@ QUnit.test("update in filter through advanced search ui", assert => {
fillIn('.search input.full-page-search', 'none');
click('.search-advanced-btn');
- expandSelectBox('.search-advanced-options .select-box-kit#in');
- selectBoxSelectRow('bookmarks', { selector: '.search-advanced-options .select-box-kit#in' });
+ expandSelectBoxKit('.search-advanced-options .select-box-kit#in');
+ selectBoxKitSelectRow('bookmarks', { selector: '.search-advanced-options .select-box-kit#in' });
fillIn('.search-advanced-options .select-box-kit#in', 'bookmarks');
andThen(() => {
@@ -271,8 +271,8 @@ QUnit.test("update status through advanced search ui", assert => {
visit("/search");
fillIn('.search input.full-page-search', 'none');
click('.search-advanced-btn');
- expandSelectBox('.search-advanced-options .select-box-kit#status');
- selectBoxSelectRow('closed', { selector: '.search-advanced-options .select-box-kit#status' });
+ expandSelectBoxKit('.search-advanced-options .select-box-kit#status');
+ selectBoxKitSelectRow('closed', { selector: '.search-advanced-options .select-box-kit#status' });
fillIn('.search-advanced-options .select-box-kit#status', 'closed');
andThen(() => {
@@ -286,8 +286,8 @@ QUnit.test("update post time through advanced search ui", assert => {
fillIn('.search input.full-page-search', 'none');
click('.search-advanced-btn');
fillIn('#search-post-date', '2016-10-05');
- expandSelectBox('.search-advanced-options .select-box-kit#postTime');
- selectBoxSelectRow('after', { selector: '.search-advanced-options .select-box-kit#postTime' });
+ expandSelectBoxKit('.search-advanced-options .select-box-kit#postTime');
+ selectBoxKitSelectRow('after', { selector: '.search-advanced-options .select-box-kit#postTime' });
fillIn('.search-advanced-options .select-box-kit#postTime', 'after');
andThen(() => {
diff --git a/test/javascripts/acceptance/search-test.js.es6 b/test/javascripts/acceptance/search-test.js.es6
index c449d17ccce..a5ce94669b3 100644
--- a/test/javascripts/acceptance/search-test.js.es6
+++ b/test/javascripts/acceptance/search-test.js.es6
@@ -89,7 +89,7 @@ QUnit.test("Search with context", assert => {
QUnit.test("Right filters are shown to anonymous users", assert => {
visit("/search?expanded=true");
- expandSelectBox(".select-box-kit#in");
+ expandSelectBoxKit(".select-box-kit#in");
andThen(() => {
assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=first]'));
@@ -115,7 +115,7 @@ QUnit.test("Right filters are shown to logged-in users", assert => {
Discourse.reset();
visit("/search?expanded=true");
- expandSelectBox(".select-box-kit#in");
+ expandSelectBoxKit(".select-box-kit#in");
andThen(() => {
assert.ok(exists('.select-box-kit#in .select-box-kit-row[data-value=first]'));
diff --git a/test/javascripts/acceptance/topic-notifications-button-test.js.es6 b/test/javascripts/acceptance/topic-notifications-button-test.js.es6
index 353ac651501..fa21ef4e96a 100644
--- a/test/javascripts/acceptance/topic-notifications-button-test.js.es6
+++ b/test/javascripts/acceptance/topic-notifications-button-test.js.es6
@@ -28,8 +28,8 @@ QUnit.test("Updating topic notification level", assert => {
);
});
- expandSelectBox(notificationOptions);
- selectBoxSelectRow("3", { selector: notificationOptions});
+ expandSelectBoxKit(notificationOptions);
+ selectBoxKitSelectRow("3", { selector: notificationOptions});
andThen(() => {
assert.equal(
diff --git a/test/javascripts/acceptance/topic-test.js.es6 b/test/javascripts/acceptance/topic-test.js.es6
index b1f7d80d6d5..72f8518070c 100644
--- a/test/javascripts/acceptance/topic-test.js.es6
+++ b/test/javascripts/acceptance/topic-test.js.es6
@@ -53,9 +53,9 @@ QUnit.test("Updating the topic title and category", assert => {
fillIn('#edit-title', 'this is the new title');
- expandSelectBox('.title-wrapper .category-chooser');
+ expandSelectBoxKit('.title-wrapper .category-chooser');
- selectBoxSelectRow(4, {selector: '.title-wrapper .category-chooser'});
+ selectBoxKitSelectRow(4, {selector: '.title-wrapper .category-chooser'});
click('#topic-title .submit-edit');
diff --git a/test/javascripts/components/categories-admin-dropdown-test.js.es6 b/test/javascripts/components/categories-admin-dropdown-test.js.es6
index 9816850677d..07593db3e62 100644
--- a/test/javascripts/components/categories-admin-dropdown-test.js.es6
+++ b/test/javascripts/components/categories-admin-dropdown-test.js.es6
@@ -10,7 +10,7 @@ componentTest('default', {
assert.equal($selectBox.el.find(".d-icon-bars").length, 1);
assert.equal($selectBox.el.find(".d-icon-caret-down").length, 1);
- expandSelectBox('.categories-admin-dropdown');
+ expandSelectBoxKit();
andThen(() => {
assert.equal($selectBox.rowByValue("create").name(), "New Category");
diff --git a/test/javascripts/components/category-chooser-test.js.es6 b/test/javascripts/components/category-chooser-test.js.es6
index f5ebfe2685c..d6fca21fd09 100644
--- a/test/javascripts/components/category-chooser-test.js.es6
+++ b/test/javascripts/components/category-chooser-test.js.es6
@@ -6,7 +6,7 @@ componentTest('with value', {
template: '{{category-chooser value=2}}',
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').header.name(), "feature");
@@ -18,7 +18,7 @@ componentTest('with excludeCategoryId', {
template: '{{category-chooser excludeCategoryId=2}}',
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').rowByValue(2).el.length, 0);
@@ -30,7 +30,7 @@ componentTest('with scopedCategoryId', {
template: '{{category-chooser scopedCategoryId=2}}',
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').rowByIndex(0).name(), "feature");
@@ -48,7 +48,7 @@ componentTest('with allowUncategorized=null', {
},
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').header.name(), "Select a category…");
@@ -64,7 +64,7 @@ componentTest('with allowUncategorized=null rootNone=true', {
},
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').header.name(), "Select a category…");
@@ -81,7 +81,7 @@ componentTest('with disallowed uncategorized, rootNone and rootNoneLabel', {
},
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').header.name(), "Select a category…");
@@ -97,7 +97,7 @@ componentTest('with allowed uncategorized', {
},
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').header.name(), "uncategorized");
@@ -113,7 +113,7 @@ componentTest('with allowed uncategorized and rootNone', {
},
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').header.name(), "(no category)");
@@ -130,7 +130,7 @@ componentTest('with allowed uncategorized rootNone and rootNoneLabel', {
},
test(assert) {
- expandSelectBox('.category-chooser');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.category-chooser').header.name(), "root none label");
diff --git a/test/javascripts/components/combo-box-test.js.es6 b/test/javascripts/components/combo-box-test.js.es6
index dcaccdfc1bb..c7f50b5da13 100644
--- a/test/javascripts/components/combo-box-test.js.es6
+++ b/test/javascripts/components/combo-box-test.js.es6
@@ -8,7 +8,7 @@ componentTest('default', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').header.name(), "hello");
@@ -25,7 +25,7 @@ componentTest('with valueAttribute', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').rowByValue(0).name(), "hello");
@@ -41,7 +41,7 @@ componentTest('with nameProperty', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').rowByValue(0).name(), "hello");
@@ -57,7 +57,7 @@ componentTest('with an array as content', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').rowByValue('evil').name(), "evil");
@@ -75,7 +75,7 @@ componentTest('with value and none as a string', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').noneRow.name(), 'none');
@@ -85,7 +85,7 @@ componentTest('with value and none as a string', {
assert.equal(this.get('value'), 'trout');
});
- selectBoxSelectRow('', {selector: '.combobox' });
+ selectBoxKitSelectRow('__none__', {selector: '.combobox' });
andThen(() => {
assert.equal(this.get('value'), null);
@@ -102,7 +102,7 @@ componentTest('with value and none as an object', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').noneRow.name(), 'none');
@@ -112,7 +112,7 @@ componentTest('with value and none as an object', {
assert.equal(this.get('value'), 'evil');
});
- selectBoxSelectNoneRow({ selector: '.combobox' });
+ selectBoxKitSelectNoneRow({ selector: '.combobox' });
andThen(() => {
assert.equal(this.get('value'), null);
@@ -130,7 +130,7 @@ componentTest('with no value and none as an object', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').header.name(), 'none');
@@ -148,7 +148,7 @@ componentTest('with no value and none string', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').header.name(), 'none');
@@ -164,7 +164,7 @@ componentTest('with no value and no none', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').header.name(), 'evil', 'it sets the first row as value');
@@ -180,15 +180,15 @@ componentTest('with no value and no none', {
// },
//
// test(assert) {
-// expandSelectBox();
+// ();
//
// andThen(() => assert.equal(find(".select-box-kit-filter-input").length, 1, "it has a search input"));
//
-// selectBoxFillInFilter("regis");
+// selectBoxKitFillInFilter("regis");
//
// andThen(() => assert.equal(selectBox().rows.length, 1, "it filters results"));
//
-// selectBoxFillInFilter("");
+// selectBoxKitFillInFilter("");
//
// andThen(() => {
// assert.equal(
@@ -207,17 +207,17 @@ componentTest('with no value and no none', {
// },
//
// test(assert) {
-// expandSelectBox();
+// ();
//
-// selectBoxFillInFilter("rob");
+// selectBoxKitFillInFilter("rob");
//
// andThen(() => assert.equal(selectBox().rows.length, 1) );
//
-// collapseSelectBox();
+// collapseSelectBoxKit();
//
// andThen(() => assert.notOk(selectBox().isExpanded) );
//
-// expandSelectBox();
+// ();
//
// andThen(() => assert.equal(selectBox().rows.length, 1) );
// }
@@ -232,7 +232,7 @@ componentTest('with empty string as value', {
},
test(assert) {
- expandSelectBox('.combobox');
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox('.combobox').header.name(), 'evil', 'it sets the first row as value');
diff --git a/test/javascripts/components/list-setting-test.js.es6 b/test/javascripts/components/list-setting-test.js.es6
new file mode 100644
index 00000000000..c3dd271fb1b
--- /dev/null
+++ b/test/javascripts/components/list-setting-test.js.es6
@@ -0,0 +1,74 @@
+import componentTest from 'helpers/component-test';
+
+moduleForComponent('list-setting', {integration: true});
+
+componentTest('default', {
+ template: '{{list-setting settingValue=settingValue choices=choices}}',
+
+ beforeEach() {
+ this.set('settingValue', 'bold|italic');
+ this.set('choices', ['bold', 'italic', 'underline']);
+ },
+
+ test(assert) {
+ expandSelectBoxKit();
+
+ andThen(() => {
+ assert.propEqual(selectBox().header.name(), 'bold,italic');
+ });
+ }
+});
+
+componentTest('with only setting value', {
+ template: '{{list-setting settingValue=settingValue}}',
+
+ beforeEach() {
+ this.set('settingValue', 'bold|italic');
+ },
+
+ test(assert) {
+ expandSelectBoxKit();
+
+ andThen(() => {
+ assert.propEqual(selectBox().header.name(), 'bold,italic');
+ });
+ }
+});
+
+componentTest('interactions', {
+ template: '{{list-setting settingValue=settingValue choices=choices}}',
+
+ beforeEach() {
+ this.set('settingValue', 'bold|italic');
+ this.set('choices', ['bold', 'italic', 'underline']);
+ },
+
+ test(assert) {
+ expandSelectBoxKit();
+
+ selectBoxKitSelectRow('underline');
+
+ andThen(() => {
+ assert.propEqual(selectBox().header.name(), 'bold,italic,underline');
+ });
+
+ selectBoxKitFillInFilter('strike');
+
+ andThen(() => {
+ assert.equal(selectBox().highlightedRow.name(), 'strike');
+ });
+
+ selectBox().keyboard.enter();
+
+ andThen(() => {
+ assert.propEqual(selectBox().header.name(), 'bold,italic,underline,strike');
+ });
+
+ selectBox().keyboard.backspace();
+ selectBox().keyboard.backspace();
+
+ andThen(() => {
+ assert.equal(this.get('choices').length, 3, 'it removes the created content from original list');
+ });
+ }
+});
diff --git a/test/javascripts/components/multi-combo-box-test.js.es6 b/test/javascripts/components/multi-combo-box-test.js.es6
index 9dbe3b5ffec..81f8b209e70 100644
--- a/test/javascripts/components/multi-combo-box-test.js.es6
+++ b/test/javascripts/components/multi-combo-box-test.js.es6
@@ -11,7 +11,99 @@ componentTest('with objects and values', {
test(assert) {
andThen(() => {
- assert.propEqual(selectBox(".multi-combobox").header.name(), 'hello,world');
+ assert.propEqual(selectBox().header.name(), 'hello,world');
+ });
+ }
+});
+
+componentTest('interactions', {
+ template: '{{multi-combo-box none=none content=items value=value}}',
+
+ beforeEach() {
+ I18n.translations[I18n.locale].js.test = {none: 'none'};
+ this.set('items', [{id: 1, name: 'regis'}, {id: 2, name: 'sam'}, {id: 3, name: 'robin'}]);
+ this.set('value', [1, 2]);
+ },
+
+ test(assert) {
+ expandSelectBoxKit();
+
+ andThen(() => {
+ assert.equal(selectBox().highlightedRow.name(), 'robin', 'it highlights the first content row');
+ });
+
+ this.set('none', 'test.none');
+
+ andThen(() => {
+ assert.equal(selectBox().noneRow.el.length, 1);
+ assert.equal(selectBox().highlightedRow.name(), 'robin', 'it highlights the first content row');
+ });
+
+ selectBoxKitSelectRow(3);
+
+ andThen(() => {
+ assert.equal(selectBox().highlightedRow.name(), 'none', 'it highlights none row if no content');
+ });
+
+ selectBoxKitFillInFilter('joffrey');
+
+ andThen(() => {
+ assert.equal(selectBox().highlightedRow.name(), 'joffrey', 'it highlights create row when filling filter');
+ });
+
+ selectBox().keyboard.enter();
+
+ andThen(() => {
+ assert.equal(selectBox().highlightedRow.name(), 'none', 'it highlights none row after creating content and no content left');
+ });
+
+ selectBox().keyboard.backspace();
+
+ andThen(() => {
+ const $lastSelectedName = selectBox().header.el.find('.selected-name').last();
+ assert.equal($lastSelectedName.attr('data-name'), 'joffrey');
+ assert.ok($lastSelectedName.hasClass('is-highlighted'), 'it highlights the last selected name when using backspace');
+ });
+
+ selectBox().keyboard.backspace();
+
+ andThen(() => {
+ const $lastSelectedName = selectBox().header.el.find('.selected-name').last();
+ assert.equal($lastSelectedName.attr('data-name'), 'robin', 'it removes the previous highlighted selected content');
+ assert.notOk(exists(selectBox().rowByValue('joffrey').el), 'generated content shouldn’t appear in content when removed');
+ });
+
+ selectBox().keyboard.selectAll();
+
+ andThen(() => {
+ const $highlightedSelectedNames = selectBox().header.el.find('.selected-name.is-highlighted');
+ assert.equal($highlightedSelectedNames.length, 3, 'it highlights each selected name');
+ });
+
+ selectBox().keyboard.backspace();
+
+ andThen(() => {
+ const $selectedNames = selectBox().header.el.find('.selected-name');
+ assert.equal($selectedNames.length, 0, 'it removed all selected content');
+ });
+
+ andThen(() => {
+ assert.ok(this.$(".select-box-kit").hasClass("is-focused"));
+ assert.ok(this.$(".select-box-kit").hasClass("is-expanded"));
+ });
+
+ selectBox().keyboard.escape();
+
+ andThen(() => {
+ assert.ok(this.$(".select-box-kit").hasClass("is-focused"));
+ assert.notOk(this.$(".select-box-kit").hasClass("is-expanded"));
+ });
+
+ selectBox().keyboard.escape();
+
+ andThen(() => {
+ assert.notOk(this.$(".select-box-kit").hasClass("is-focused"));
+ assert.notOk(this.$(".select-box-kit").hasClass("is-expanded"));
});
}
});
diff --git a/test/javascripts/components/pinned-button-test.js.es6 b/test/javascripts/components/pinned-button-test.js.es6
index eba26d40eb0..154d321a23c 100644
--- a/test/javascripts/components/pinned-button-test.js.es6
+++ b/test/javascripts/components/pinned-button-test.js.es6
@@ -23,7 +23,7 @@ componentTest('updating the content refreshes the list', {
test(assert) {
andThen(() => assert.notOk(selectBox().isHidden) );
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => assert.equal(selectBox().selectedRow.name(), "Pinned") );
diff --git a/test/javascripts/components/select-box-test.js.es6 b/test/javascripts/components/select-box-kit-test.js.es6
similarity index 90%
rename from test/javascripts/components/select-box-test.js.es6
rename to test/javascripts/components/select-box-kit-test.js.es6
index d5ce4660531..6e0f37a0485 100644
--- a/test/javascripts/components/select-box-test.js.es6
+++ b/test/javascripts/components/select-box-kit-test.js.es6
@@ -10,7 +10,7 @@ componentTest('updating the content refreshes the list', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox().rowByValue(1).name(), "robin");
@@ -29,7 +29,7 @@ componentTest('accepts a value by reference', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
assert.equal(
@@ -38,7 +38,7 @@ componentTest('accepts a value by reference', {
);
});
- selectBoxSelectRow(1);
+ selectBoxKitSelectRow(1);
andThen(() => {
assert.equal(this.get("value"), 1, "it mutates the value");
@@ -58,7 +58,7 @@ componentTest('default search icon', {
template: '{{select-box-kit filterable=true}}',
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
assert.ok(exists(selectBox().filter.icon), "it has a the correct icon");
@@ -70,7 +70,7 @@ componentTest('with no search icon', {
template: '{{select-box-kit filterable=true filterIcon=null}}',
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox().filter.icon().length, 0, "it has no icon");
@@ -82,7 +82,7 @@ componentTest('custom search icon', {
template: '{{select-box-kit filterable=true filterIcon="shower"}}',
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
assert.ok(selectBox().filter.icon().hasClass("d-icon-shower"), "it has a the correct icon");
@@ -93,11 +93,11 @@ componentTest('custom search icon', {
componentTest('select-box is expandable', {
template: '{{select-box-kit}}',
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => assert.ok(selectBox().isExpanded) );
- collapseSelectBox();
+ collapseSelectBoxKit();
andThen(() => assert.notOk(selectBox().isExpanded) );
}
@@ -112,7 +112,7 @@ componentTest('accepts custom value/name keys', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox().selectedRow.name(), "robin");
@@ -130,7 +130,7 @@ componentTest('doesn’t render collection content before first expand', {
test(assert) {
assert.notOk(exists(find(".select-box-kit-collection")));
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
assert.ok(exists(find(".select-box-kit-collection")));
@@ -146,7 +146,7 @@ componentTest('supports options to limit size', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
const height = find(".select-box-kit-collection").height();
@@ -163,11 +163,11 @@ componentTest('dynamic headerText', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => assert.equal(selectBox().header.name(), "robin") );
- selectBoxSelectRow(2);
+ selectBoxKitSelectRow(2);
andThen(() => {
assert.equal(selectBox().header.name(), "regis", "it changes header text");
@@ -186,7 +186,7 @@ componentTest('supports custom row template', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => assert.equal(selectBox().rowByValue(1).el.html().trim(), "robin") );
}
@@ -201,7 +201,7 @@ componentTest('supports converting select value to integer', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => assert.equal(selectBox().selectedRow.name(), "régis") );
@@ -224,7 +224,7 @@ componentTest('supports keyboard events', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
selectBox().keyboard.down();
@@ -251,7 +251,7 @@ componentTest('supports keyboard events', {
assert.notOk(selectBox().isExpanded, "it collapses the select box when selecting a row");
});
- expandSelectBox();
+ expandSelectBoxKit();
selectBox().keyboard.escape();
@@ -259,18 +259,13 @@ componentTest('supports keyboard events', {
assert.notOk(selectBox().isExpanded, "it collapses the select box");
});
- expandSelectBox();
+ expandSelectBoxKit();
- selectBoxFillInFilter("regis");
-
- // andThen(() => {
- // assert.equal(selectBox().highlightedRow.title(), "regis", "it highlights the first result");
- // });
+ selectBoxKitFillInFilter("regis");
selectBox().keyboard.tab();
andThen(() => {
- // assert.equal(selectBox().selectedRow.title(), "regis", "it selects the row when pressing tab");
assert.notOk(selectBox().isExpanded, "it collapses the select box when selecting a row");
});
}
diff --git a/test/javascripts/components/topic-footer-mobile-dropdown-test.js.es6 b/test/javascripts/components/topic-footer-mobile-dropdown-test.js.es6
index fbd31aeafcf..899bff4545a 100644
--- a/test/javascripts/components/topic-footer-mobile-dropdown-test.js.es6
+++ b/test/javascripts/components/topic-footer-mobile-dropdown-test.js.es6
@@ -17,7 +17,7 @@ componentTest('default', {
},
test(assert) {
- expandSelectBox();
+ expandSelectBoxKit();
andThen(() => {
assert.equal(selectBox().header.name(), "Topic Controls");
@@ -26,7 +26,7 @@ componentTest('default', {
assert.equal(selectBox().selectedRow.el.length, 0, "it doesn’t preselect first row");
});
- selectBoxSelectRow("share");
+ selectBoxKitSelectRow("share");
andThen(() => {
assert.equal(this.get("value"), null, "it resets the value");
diff --git a/test/javascripts/helpers/select-box-helper.js b/test/javascripts/helpers/select-box-kit-helper.js
similarity index 75%
rename from test/javascripts/helpers/select-box-helper.js
rename to test/javascripts/helpers/select-box-kit-helper.js
index 546148531ab..6388cff899d 100644
--- a/test/javascripts/helpers/select-box-helper.js
+++ b/test/javascripts/helpers/select-box-kit-helper.js
@@ -10,7 +10,7 @@ function checkSelectBoxIsNotCollapsed(selectBoxSelector) {
}
}
-Ember.Test.registerAsyncHelper('expandSelectBox', function(app, selectBoxSelector) {
+Ember.Test.registerAsyncHelper('expandSelectBoxKit', function(app, selectBoxSelector) {
selectBoxSelector = selectBoxSelector || '.select-box-kit';
checkSelectBoxIsNotExpanded(selectBoxSelector);
@@ -18,7 +18,7 @@ Ember.Test.registerAsyncHelper('expandSelectBox', function(app, selectBoxSelecto
click(selectBoxSelector + ' .select-box-kit-header');
});
-Ember.Test.registerAsyncHelper('collapseSelectBox', function(app, selectBoxSelector) {
+Ember.Test.registerAsyncHelper('collapseSelectBoxKit', function(app, selectBoxSelector) {
selectBoxSelector = selectBoxSelector || '.select-box-kit';
checkSelectBoxIsNotCollapsed(selectBoxSelector);
@@ -26,7 +26,7 @@ Ember.Test.registerAsyncHelper('collapseSelectBox', function(app, selectBoxSelec
click(selectBoxSelector + ' .select-box-kit-header');
});
-Ember.Test.registerAsyncHelper('selectBoxSelectRow', function(app, rowValue, options) {
+Ember.Test.registerAsyncHelper('selectBoxKitSelectRow', function(app, rowValue, options) {
options = options || {};
options.selector = options.selector || '.select-box-kit';
@@ -35,7 +35,7 @@ Ember.Test.registerAsyncHelper('selectBoxSelectRow', function(app, rowValue, opt
click(options.selector + " .select-box-kit-row[data-value='" + rowValue + "']");
});
-Ember.Test.registerAsyncHelper('selectBoxSelectNoneRow', function(app, options) {
+Ember.Test.registerAsyncHelper('selectBoxKitSelectNoneRow', function(app, options) {
options = options || {};
options.selector = options.selector || '.select-box-kit';
@@ -44,7 +44,7 @@ Ember.Test.registerAsyncHelper('selectBoxSelectNoneRow', function(app, options)
click(options.selector + " .select-box-kit-row.none");
});
-Ember.Test.registerAsyncHelper('selectBoxFillInFilter', function(app, filter, options) {
+Ember.Test.registerAsyncHelper('selectBoxKitFillInFilter', function(app, filter, options) {
options = options || {};
options.selector = options.selector || '.select-box-kit';
@@ -52,7 +52,6 @@ Ember.Test.registerAsyncHelper('selectBoxFillInFilter', function(app, filter, op
var filterQuerySelector = options.selector + ' .select-box-kit-filter-input';
fillIn(filterQuerySelector, filter);
- triggerEvent(filterQuerySelector, 'keyup');
});
function selectBox(selector) { // eslint-disable-line no-unused-vars
@@ -88,23 +87,26 @@ function selectBox(selector) { // eslint-disable-line no-unused-vars
}
function keyboardHelper() {
- function createEvent(target, keyCode) {
+ function createEvent(target, keyCode, options) {
target = target || ".select-box-kit-filter-input";
selector = find(selector).find(target);
andThen(function() {
- var event = jQuery.Event('keydown');
+ var event = jQuery.Event(options.type);
event.keyCode = keyCode;
+ if (options && options.metaKey === true) { event.metaKey = true; }
find(selector).trigger(event);
});
}
return {
- down: function(target) { createEvent(target, 40); },
- up: function(target) { createEvent(target, 38); },
- escape: function(target) { createEvent(target, 27); },
- enter: function(target) { createEvent(target, 13); },
- tab: function(target) { createEvent(target, 9); }
+ down: function(target) { createEvent(target, 40, {type: 'keydown'}); },
+ up: function(target) { createEvent(target, 38, {type: 'keydown'}); },
+ escape: function(target) { createEvent(target, 27, {type: 'keydown'}); },
+ enter: function(target) { createEvent(target, 13, {type: 'keypress'}); },
+ tab: function(target) { createEvent(target, 9, {type: 'keydown'}); },
+ backspace: function(target) { createEvent(target, 8, {type: 'keydown'}); },
+ selectAll: function(target) { createEvent(target, 65, {metaKey: true, type: 'keydown'}); },
};
}
diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js
index 97f759b0dc8..df242fa34ed 100644
--- a/test/javascripts/test_helper.js
+++ b/test/javascripts/test_helper.js
@@ -32,7 +32,7 @@
//= require sinon-qunit-1.0.0
//= require helpers/assertions
-//= require helpers/select-box-helper
+//= require helpers/select-box-kit-helper
//= require helpers/qunit-helpers
//= require_tree ./fixtures