FEATURE: initial implementation of an ember native select
This commit is contained in:
parent
7213e02dee
commit
482924b161
|
@ -36,11 +36,10 @@
|
|||
|
||||
<h3>{{i18n "admin.customize.theme.color_scheme"}}</h3>
|
||||
<p>{{i18n "admin.customize.theme.color_scheme_select"}}</p>
|
||||
<p>{{combo-box content=colorSchemes
|
||||
nameProperty="name"
|
||||
value=colorSchemeId
|
||||
selectionIcon="paint-brush"
|
||||
valueAttribute="id"}}
|
||||
<p>{{d-select-box data=colorSchemes
|
||||
textKey="name"
|
||||
value=colorSchemeId
|
||||
icon="paint-brush"}}
|
||||
{{#if colorSchemeChanged}}
|
||||
{{d-button action="changeScheme" class="btn-primary btn-small submit-edit" icon="check"}}
|
||||
{{d-button action="cancelChangeScheme" class="btn-small cancel-edit" icon="times"}}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import SelectBoxComponent from "discourse/components/select-box";
|
||||
|
||||
export default SelectBoxComponent.extend({
|
||||
layoutName: "components/select-box",
|
||||
|
||||
classNames: "discourse"
|
||||
});
|
|
@ -0,0 +1,211 @@
|
|||
import { observes } from "ember-addons/ember-computed-decorators";
|
||||
|
||||
export default Ember.Component.extend({
|
||||
classNames: "select-box",
|
||||
|
||||
classNameBindings: ["expanded:is-expanded"],
|
||||
|
||||
attributeBindings: ['componentStyle:style'],
|
||||
componentStyle: function() {
|
||||
return Ember.String.htmlSafe(`width: ${this.get("maxWidth")}px`);
|
||||
}.property("maxWidth"),
|
||||
|
||||
expanded: false,
|
||||
focused: false,
|
||||
|
||||
caretUpIcon: "caret-up",
|
||||
caretDownIcon: "caret-down",
|
||||
icon: null,
|
||||
|
||||
value: null,
|
||||
noDataText: I18n.t("select_box.no_data"),
|
||||
lastHoveredId: null,
|
||||
|
||||
idKey: "id",
|
||||
textKey: "text",
|
||||
iconKey: "icon",
|
||||
|
||||
filterable: false,
|
||||
filter: "",
|
||||
filterPlaceholder: I18n.t("select_box.filter_placeholder"),
|
||||
filterIcon: "search",
|
||||
|
||||
selectBoxRowComponent: "select-box/select-box-row",
|
||||
selectBoxFilterComponent: "select-box/select-box-filter",
|
||||
selectBoxHeaderComponent: "select-box/select-box-header",
|
||||
selectBoxCollectionComponent: "select-box/select-box-collection",
|
||||
|
||||
maxCollectionHeight: 200,
|
||||
maxWidth: 200,
|
||||
verticalOffset: 0,
|
||||
horizontalOffset: 0,
|
||||
|
||||
_renderBody: false,
|
||||
|
||||
init() {
|
||||
this._super();
|
||||
|
||||
if(!this.get("data")) {
|
||||
this.set("data", []);
|
||||
}
|
||||
|
||||
this.setProperties({
|
||||
componentId: this.elementId,
|
||||
filteredData: [],
|
||||
selectedData: {}
|
||||
});
|
||||
},
|
||||
|
||||
@observes("filter")
|
||||
_filter: function() {
|
||||
if(_.isEmpty(this.get("filter"))) {
|
||||
this.set("filteredData", this._remapData(this.get("data")));
|
||||
} else {
|
||||
const filtered = _.filter(this.get("data"), (data)=> {
|
||||
return data[this.get("textKey")].toLowerCase().indexOf(this.get("filter")) > -1;
|
||||
});
|
||||
this.set("filteredData", this._remapData(filtered));
|
||||
}
|
||||
},
|
||||
|
||||
@observes("expanded", "filteredData")
|
||||
_expand: function() {
|
||||
if(this.get("expanded")) {
|
||||
this.setProperties({focused: false, _renderBody: true});
|
||||
|
||||
Ember.$(document).on("keydown.select-box", (event) => {
|
||||
const keyCode = event.keyCode || event.which;
|
||||
if (keyCode === 9) {
|
||||
this.set("expanded", false);
|
||||
}
|
||||
});
|
||||
|
||||
if(_.isUndefined(this.get("lastHoveredId"))) {
|
||||
this.set("lastHoveredId", this.get("value"));
|
||||
}
|
||||
|
||||
Ember.run.scheduleOnce("afterRender", this, () => {
|
||||
this.$(".select-box-filter .filter-query").focus();
|
||||
this.$(".select-box-collection").css("max-height", this.get("maxCollectionHeight"));
|
||||
this.$().removeClass("is-reversed");
|
||||
|
||||
const offsetTop = this.$()[0].getBoundingClientRect().top;
|
||||
const windowHeight = Ember.$(window).height();
|
||||
const headerHeight = this.$(".select-box-header").outerHeight();
|
||||
const filterHeight = this.$(".select-box-filter").outerHeight();
|
||||
|
||||
if(windowHeight - (offsetTop + this.get("maxCollectionHeight") + filterHeight + headerHeight) < 0) {
|
||||
this.$().addClass("is-reversed");
|
||||
this.$(".select-box-body").css({
|
||||
left: this.get("horizontalOffset"),
|
||||
top: "",
|
||||
bottom: headerHeight + this.get("verticalOffset")
|
||||
});
|
||||
} else {
|
||||
this.$(".select-box-body").css({
|
||||
left: this.get("horizontalOffset"),
|
||||
top: headerHeight + this.get("verticalOffset"),
|
||||
bottom: ""
|
||||
});
|
||||
}
|
||||
|
||||
this.$(".select-box-wrapper").css({
|
||||
width: this.get("maxWidth"),
|
||||
display: "block",
|
||||
height: headerHeight + this.$(".select-box-body").outerHeight()
|
||||
});
|
||||
});
|
||||
} else {
|
||||
Ember.$(document).off("keydown.select-box");
|
||||
this.$(".select-box-wrapper").hide();
|
||||
};
|
||||
},
|
||||
|
||||
willDestroyElement() {
|
||||
this._super();
|
||||
|
||||
Ember.$(document).off("click.select-box");
|
||||
Ember.$(document).off("keydown.select-box");
|
||||
this.$(".select-box-offscreen").off("focusin.select-box");
|
||||
this.$(".select-box-offscreen").off("focusout.select-box");
|
||||
},
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super();
|
||||
|
||||
this.set("lastHoveredId", this.get("data")[this.get("idKey")]);
|
||||
this.set("filteredData", this._remapData(this.get("data")));
|
||||
this._setSelectedData(this.get("data"));
|
||||
},
|
||||
|
||||
didRender() {
|
||||
this._super();
|
||||
|
||||
this.$(".select-box-body").css('width', this.get("maxWidth"));
|
||||
this._expand();
|
||||
},
|
||||
|
||||
didInsertElement() {
|
||||
this._super();
|
||||
|
||||
Ember.$(document).on("click.select-box", (event) => {
|
||||
if(this.get("expanded") && $(event.target).parents(".select-box").attr("id") !== this.$().attr("id")) {
|
||||
this.setProperties({
|
||||
expanded: false,
|
||||
focused: false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.$(".select-box-offscreen").on("focusin.select-box", () => {
|
||||
this.set("focused", true);
|
||||
});
|
||||
|
||||
this.$(".select-box-offscreen").on("focusout.select-box", () => {
|
||||
this.set("focused", false);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
onToggle() {
|
||||
this.toggleProperty("expanded");
|
||||
},
|
||||
|
||||
onFilterChange(filter) {
|
||||
this.set("filter", filter);
|
||||
},
|
||||
|
||||
onSelectRow(id) {
|
||||
this.setProperties({
|
||||
value: id,
|
||||
expanded: false
|
||||
});
|
||||
},
|
||||
|
||||
onHoverRow(id) {
|
||||
this.set("lastHoveredId", id);
|
||||
}
|
||||
},
|
||||
|
||||
_setSelectedData(data) {
|
||||
const selectedData = _.find(data, (d)=> {
|
||||
return d[this.get("idKey")] === this.get("value");
|
||||
});
|
||||
|
||||
if(!_.isUndefined(selectedData)) {
|
||||
this.set("selectedData", this._normalizeData(selectedData));
|
||||
}
|
||||
},
|
||||
|
||||
_remapData(data) {
|
||||
return data.map(d => this._normalizeData(d));
|
||||
},
|
||||
|
||||
_normalizeData(data) {
|
||||
return {
|
||||
id: data[this.get("idKey")],
|
||||
text: data[this.get("textKey")],
|
||||
icon: data[this.get("iconKey")]
|
||||
};
|
||||
},
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
export default Ember.Component.extend({
|
||||
classNames: "select-box-collection"
|
||||
});
|
|
@ -0,0 +1,3 @@
|
|||
export default Ember.Component.extend({
|
||||
classNames: "select-box-filter"
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
export default Ember.Component.extend({
|
||||
classNames: "select-box-header",
|
||||
|
||||
classNameBindings: ["focused:is-focused"],
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super();
|
||||
|
||||
this._setCaretIcon();
|
||||
},
|
||||
|
||||
click() {
|
||||
this.sendAction("onToggle");
|
||||
},
|
||||
|
||||
_setCaretIcon() {
|
||||
if(this.get("expanded")) {
|
||||
this.set("caretIcon", this.get("caretUpIcon"));
|
||||
} else {
|
||||
this.set("caretIcon", this.get("caretDownIcon"));
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,34 @@
|
|||
export default Ember.Component.extend({
|
||||
classNames: "select-box-row",
|
||||
|
||||
tagName: "li",
|
||||
|
||||
classNameBindings: ["isHighlighted"],
|
||||
|
||||
attributeBindings: ["text:title"],
|
||||
|
||||
lastHoveredId: null,
|
||||
|
||||
mouseEnter() {
|
||||
this.sendAction("onHover", this.get("data.id"));
|
||||
},
|
||||
|
||||
click() {
|
||||
this.sendAction("onSelect", this.get("data.id"));
|
||||
},
|
||||
|
||||
didReceiveAttrs() {
|
||||
this._super();
|
||||
|
||||
this.set("isHighlighted", this._isHighlighted());
|
||||
this.set("text", this.get("data.text"));
|
||||
},
|
||||
|
||||
_isHighlighted() {
|
||||
if(_.isUndefined(this.get("lastHoveredId"))) {
|
||||
return this.get("data.id") === this.get("selectedId");
|
||||
} else {
|
||||
return this.get("data.id") === this.get("lastHoveredId");
|
||||
}
|
||||
},
|
||||
});
|
|
@ -0,0 +1,41 @@
|
|||
<input
|
||||
class="select-box-offscreen"
|
||||
type="text"
|
||||
aria-haspopup="true"
|
||||
role="button"
|
||||
aria-labelledby="select-box-input-{{componentId}}"
|
||||
/>
|
||||
|
||||
{{component selectBoxHeaderComponent
|
||||
data=selectedData
|
||||
focused=focused
|
||||
caretUpIcon=caretUpIcon
|
||||
caretDownIcon=caretDownIcon
|
||||
onToggle=(action "onToggle")
|
||||
icon=icon
|
||||
expanded=expanded
|
||||
}}
|
||||
|
||||
<div class="select-box-body">
|
||||
{{#if _renderBody}}
|
||||
{{#if filterable}}
|
||||
{{component selectBoxFilterComponent
|
||||
onFilterChange=(action "onFilterChange")
|
||||
filterIcon=filterIcon
|
||||
filterPlaceholder=filterPlaceholder
|
||||
}}
|
||||
{{/if}}
|
||||
|
||||
{{component selectBoxCollectionComponent
|
||||
filteredData=filteredData
|
||||
selectBoxRowComponent=selectBoxRowComponent
|
||||
lastHoveredId=lastHoveredId
|
||||
onSelectRow=(action "onSelectRow")
|
||||
onHoverRow=(action "onHoverRow")
|
||||
noDataText=noDataText
|
||||
selectedId=value
|
||||
}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="select-box-wrapper"></div>
|
|
@ -0,0 +1,17 @@
|
|||
<ul class="collection">
|
||||
{{#each filteredData as |data|}}
|
||||
{{component selectBoxRowComponent
|
||||
data=data
|
||||
lastHoveredId=lastHoveredId
|
||||
onSelect=onSelectRow
|
||||
onHover=onHoverRow
|
||||
selectedId=selectedId
|
||||
}}
|
||||
{{else}}
|
||||
{{#if noDataText}}
|
||||
<li class="select-box-row no-data">
|
||||
{{noDataText}}
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/each}}
|
||||
</ul>
|
|
@ -0,0 +1,14 @@
|
|||
<div class="wrapper">
|
||||
{{input
|
||||
tabindex="-1"
|
||||
class="filter-query"
|
||||
placeholder=filterPlaceholder
|
||||
key-up=onFilterChange
|
||||
}}
|
||||
|
||||
{{#if filterIcon}}
|
||||
<div class="filter-icon">
|
||||
{{d-icon filterIcon}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
|
@ -0,0 +1,15 @@
|
|||
<div class="wrapper">
|
||||
{{#if icon}}
|
||||
<div class="icon">
|
||||
{{d-icon icon}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<span class="current-selection">
|
||||
{{data.text}}
|
||||
</span>
|
||||
|
||||
<div class="caret-icon">
|
||||
{{d-icon caretIcon}}
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
{{#if data.icon}}
|
||||
{{d-icon data.icon}}
|
||||
{{/if}}
|
||||
|
||||
<p class="text">
|
||||
{{data.text}}
|
||||
</p>
|
|
@ -0,0 +1,246 @@
|
|||
.select-box {
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
z-index: 998;
|
||||
|
||||
&.is-expanded {
|
||||
z-index: 999;
|
||||
|
||||
.select-box-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
left: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-reversed {
|
||||
.select-box-body {
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
}
|
||||
|
||||
.select-box-wrapper {
|
||||
bottom: 0;
|
||||
top: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.d-icon {
|
||||
color: dark-light-choose(scale-color($header_primary, $lightness: 50%), $header_primary);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.select-box-header {
|
||||
background: $secondary;
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
height: 32px;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.select-box-body {
|
||||
display: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.select-box-row {
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
padding: 5px;
|
||||
height: 28px;
|
||||
min-height: 28px;
|
||||
line-height: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.select-box-collection {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
background: $secondary;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
border-radius: 0 0 3px 3px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.select-box-filter {
|
||||
border-bottom: 1px solid $primary-low;
|
||||
background: $secondary;
|
||||
}
|
||||
|
||||
.select-box-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: none;
|
||||
display: none;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-header {
|
||||
.wrapper {
|
||||
height: inherit;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.current-selection {
|
||||
text-align: left;
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.caret-icon {
|
||||
margin-left: 5px;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-row {
|
||||
&.is-highlighted {
|
||||
background: $highlight-medium;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-collection {
|
||||
flex: 0 1 auto;
|
||||
|
||||
.collection {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
-webkit-appearance: none;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
cursor: pointer;
|
||||
border-radius: 5px;
|
||||
background: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
|
||||
-webkit-transition: color .2s ease;
|
||||
transition: color .2s ease;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-row {
|
||||
.d-icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.text {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.is-selected {
|
||||
a {
|
||||
background: $highlight-medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-filter {
|
||||
.wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 5px 10px;
|
||||
}
|
||||
|
||||
input, input:focus {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
outline: none;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
width: 100%;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box .select-box-offscreen, .select-box .select-box-offscreen:focus {
|
||||
clip: rect(0 0 0 0);
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
outline: 0;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.select-box.discourse {
|
||||
.select-box-header {
|
||||
border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
|
||||
border-radius: 3px;
|
||||
|
||||
&.is-focused {
|
||||
border: 1px solid $tertiary;
|
||||
border-radius: 3px;
|
||||
box-shadow: $tertiary 0px 0px 6px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-expanded {
|
||||
.select-box-header {
|
||||
border-radius: 3px 3px 0 0;
|
||||
}
|
||||
|
||||
.select-box-body, .collection, {
|
||||
border-radius: 0 0 3px 3px;
|
||||
}
|
||||
|
||||
.select-box-wrapper {
|
||||
border: 1px solid $tertiary;
|
||||
border-radius: 3px;
|
||||
box-shadow: $tertiary 0px 0px 6px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-box-row {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
&.is-highlighted .select-box-header {
|
||||
border: 1px solid $tertiary;
|
||||
box-shadow: $tertiary 0px 0px 6px 0px;
|
||||
}
|
||||
}
|
|
@ -1143,6 +1143,10 @@ en:
|
|||
ctrl: 'Ctrl'
|
||||
alt: 'Alt'
|
||||
|
||||
select_box:
|
||||
no_data: No data
|
||||
filter_placeholder: Search...
|
||||
|
||||
emoji_picker:
|
||||
filter_placeholder: Search for emoji
|
||||
people: People
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
import componentTest from 'helpers/component-test';
|
||||
|
||||
moduleForComponent('select-box', {integration: true});
|
||||
|
||||
componentTest('updating the data refreshes the list', {
|
||||
template: '{{select-box value=1 data=data}}',
|
||||
|
||||
beforeEach() {
|
||||
this.set("data", [{id:1, text:"robin"}]);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-row .text").html().trim(), "robin");
|
||||
|
||||
andThen(() => this.set("data", [{id:1, text:"regis"}]));
|
||||
andThen(() => assert.equal(this.$(".select-box-row .text").html().trim(), "regis"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('accepts a value by reference', {
|
||||
template: '{{select-box value=value data=data}}',
|
||||
|
||||
beforeEach() {
|
||||
this.set("value", 1);
|
||||
this.set("data", [{id:1, text:"robin"}, {id: 2, text:"regis"}]);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-row.is-highlighted .text").html().trim(), "robin", "it highlights the row corresponding to the value");
|
||||
|
||||
click(this.$(".select-box-row[title='robin']"));
|
||||
andThen(() => assert.equal(this.get("value"), 1, "it mutates the value"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('select-box can be filtered', {
|
||||
template: '{{select-box filterable=true value=1 data=data}}',
|
||||
|
||||
beforeEach() {
|
||||
this.set("data", [{id:1, text:"robin"}, {id: 2, text:"regis"}]);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
andThen(() => assert.equal(this.$(".filter-query").length, 1, "it has a search input"));
|
||||
|
||||
andThen(() => {
|
||||
this.$(".filter-query").val("regis");
|
||||
this.$(".filter-query").trigger("keyup");
|
||||
});
|
||||
andThen(() => assert.equal(this.$(".select-box-row").length, 1, "it filters results"));
|
||||
|
||||
andThen(() => {
|
||||
this.$(".filter-query").val("");
|
||||
this.$(".filter-query").trigger("keyup");
|
||||
});
|
||||
andThen(() => assert.equal(this.$(".select-box-row").length, 2, "it returns to original data when filter is empty"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('no default icon', {
|
||||
template: '{{select-box}}',
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.$(".select-box-header .icon").length, 0, "it doesn’t have an icon if not specified");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('customisable icon', {
|
||||
template: '{{select-box icon="shower"}}',
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.$(".select-box-header .icon").html().trim(), "<i class=\"fa fa-shower d-icon d-icon-shower\"></i>", "it has a the correct icon");
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('default search icon', {
|
||||
template: '{{select-box filterable=true}}',
|
||||
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-filter .filter-icon").html().trim(), "<i class=\"fa fa-search d-icon d-icon-search\"></i>", "it has a the correct icon");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('with no search icon', {
|
||||
template: '{{select-box filterable=true searchIcon=null}}',
|
||||
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".search-icon").length, 0, "it has no icon");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('custom search icon', {
|
||||
template: '{{select-box filterable=true filterIcon="shower"}}',
|
||||
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-filter .filter-icon").html().trim(), "<i class=\"fa fa-shower d-icon d-icon-shower\"></i>", "it has a the correct icon");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('not filterable by default', {
|
||||
template: '{{select-box}}',
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-filter").length, 0);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
componentTest('select-box is expandable', {
|
||||
template: '{{select-box}}',
|
||||
test(assert) {
|
||||
|
||||
click(".select-box-header");
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box").hasClass("is-expanded"), true);
|
||||
});
|
||||
|
||||
click(".select-box-header");
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box").hasClass("is-expanded"), false);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('accepts custom id/text keys', {
|
||||
template: '{{select-box value=value data=data idKey="identifier" textKey="name"}}',
|
||||
|
||||
beforeEach() {
|
||||
this.set("value", 1);
|
||||
this.set("data", [{identifier:1, name:"robin"}]);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-row.is-highlighted .text").html().trim(), "robin");
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('doesn’t render collection content before first expand', {
|
||||
template: '{{select-box value=1 data=data idKey="identifier" textKey="name"}}',
|
||||
|
||||
beforeEach() {
|
||||
this.set("data", [{identifier:1, name:"robin"}]);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.$(".select-box-body .collection").length, 0);
|
||||
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-body .collection").length, 1);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
componentTest('persists filter state when expandind/collapsing', {
|
||||
template: '{{select-box value=1 data=data filterable=true}}',
|
||||
|
||||
beforeEach() {
|
||||
this.set("data", [{id:1, text:"robin"}, {id:2, text:"régis"}]);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
this.$(".filter-query").val("rob");
|
||||
this.$(".filter-query").trigger("keyup");
|
||||
});
|
||||
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-row").length, 1);
|
||||
});
|
||||
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$().hasClass("is-expanded"), false);
|
||||
});
|
||||
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-row").length, 1);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
componentTest('supports options to limit size', {
|
||||
template: '{{select-box maxWidth=100 maxCollectionHeight=20 data=data}}',
|
||||
|
||||
beforeEach() {
|
||||
this.set("data", [{id:1, text:"robin"}]);
|
||||
},
|
||||
|
||||
test(assert) {
|
||||
assert.equal(this.$(".select-box-header").outerWidth(), 100, "it limits the width");
|
||||
|
||||
click(this.$(".select-box-header"));
|
||||
andThen(() => {
|
||||
assert.equal(this.$(".select-box-body").height(), 20, "it limits the height");
|
||||
});
|
||||
}
|
||||
});
|
Loading…
Reference in New Issue