This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/components/select-box.js.es6

299 lines
7.6 KiB
JavaScript

import { on, observes } from "ember-addons/ember-computed-decorators";
import { iconHTML } from 'discourse-common/lib/icon-library';
export default Ember.Component.extend({
layoutName: "components/select-box",
classNames: "select-box",
width: 220,
classNameBindings: ["expanded:is-expanded"],
expanded: false,
focused: false,
tabindex: 0,
caretUpIcon: "caret-up",
caretDownIcon: "caret-down",
headerText: null,
icon: null,
value: null,
selectedContent: null,
noContentText: I18n.t("select_box.no_content"),
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,
castInteger: false,
filterFunction: function() {
return (selectBox) => {
const filter = selectBox.get("filter").toLowerCase();
return _.filter(selectBox.get("content"), (content) => {
return content[selectBox.get("textKey")].toLowerCase().indexOf(filter) > -1;
});
};
},
selectBoxRowTemplate: function() {
return (rowComponent) => {
let template = "";
if (rowComponent.get("content.icon")) {
template += iconHTML(Handlebars.escapeExpression(rowComponent.get("content.icon")));
}
template += `<p class="text">${Handlebars.escapeExpression(rowComponent.get("text"))}</p>`;
return template;
};
}.property(),
init() {
this._super();
if (!this.get("content")) {
this.set("content", []);
}
this.setProperties({
componentId: this.elementId,
filteredContent: []
});
},
@observes("value")
_valueChanged: function() {
if (Ember.isNone(this.get("value"))) {
this.set("lastHoveredId", null);
}
this.set("filteredContent", this._remapContent(this.get("content")));
},
@observes("filter")
_filterChanged: function() {
if (Ember.isEmpty(this.get("filter"))) {
this.set("filteredContent", this._remapContent(this.get("content")));
} else {
const filtered = this.filterFunction()(this);
this.set("filteredContent", this._remapContent(filtered));
}
},
@observes("expanded")
_expandedChanged: function() {
if (this.get("expanded")) {
this.setProperties({ focused: false, renderBody: true });
if (Ember.isNone(this.get("lastHoveredId"))) {
this.set("lastHoveredId", this.get("value"));
}
};
},
@on("willDestroyElement")
_unbindEvents: function() {
$(document).off("click.select-box");
$(document).off("keydown.select-box");
this.$(".select-box-offscreen").off("focusin.select-box");
this.$(".select-box-offscreen").off("focusout.select-box");
this.$(".select-box-offscreen").off("keydown.select-box");
$(window).off("resize.select-box");
},
@on("didRender")
_configureSelectBoxDOM: function() {
this.$().css("width", this.get("width"));
this.$(".select-box-header").css("height", this.$().height());
this.$(".select-box-filter").css("height", this.$().height());
if (this.get("expanded")) {
this.$(".select-box-body").css('width', this.$().width());
this.$(".select-box-collection").css("max-height", this.get("maxCollectionHeight"));
this._bindTab();
Ember.run.schedule('afterRender', () => {
this.applyDirection();
this._positionSelectBoxWrapper();
});
} else {
$(document).off("keydown.select-box");
this.$(".select-box-wrapper").hide();
}
},
@observes("content.[]")
@on("didReceiveAttrs")
_contentChanged: function() {
if (!Ember.isNone(this.get("value"))) {
this.set("lastHoveredId", this.get("content")[this.get("idKey")]);
} else {
this.set("lastHoveredId", null);
}
this.set("filteredContent", this._remapContent(this.get("content")));
this._setSelectedContent(this.get("content"));
if (Ember.isNone(this.get("headerText"))) {
this.set("headerText", this.get("selectedContent.text"));
}
},
@on("didInsertElement")
_bindEvents: function() {
$(document).on("click.select-box", (event) => {
const clickOutside = $(event.target).parents(".select-box").attr("id") !== this.$().attr("id");
if (this.get("expanded") && clickOutside) {
this.setProperties({
expanded: false,
focused: false
});
}
});
this.$(".select-box-offscreen").on("focusin.select-box", () => {
this.set("focused", true);
});
this.$(".select-box-offscreen").on("keydown.select-box", (event) => {
const keyCode = event.keyCode || event.which;
if(keyCode === 13 || keyCode === 40) {
this.setProperties({expanded: true, focused: false});
return false;
}
if(keyCode === 27) {
this.$(".select-box-offscreen").blur();
return false;
}
});
this.$(".select-box-offscreen").on("focusout.select-box", () => {
this.set("focused", false);
});
$(window).on("resize.select-box", () => {
this.set("expanded", false);
});
},
actions: {
onToggle() {
this.toggleProperty("expanded");
},
onFilterChange(filter) {
this.set("filter", filter);
},
onSelectRow(id) {
if(this.get("castInteger") === true) {
id = parseInt(id, 10);
}
this.setProperties({
value: id,
expanded: false
});
},
onHoverRow(id) {
this.set("lastHoveredId", id);
}
},
_setSelectedContent(content) {
const selectedContent = content.find((c) => {
return c[this.get("idKey")] === this.get("value");
});
if (!Ember.isNone(selectedContent)) {
this.set("selectedContent", this._normalizeContent(selectedContent));
}
},
_remapContent(content) {
return content.map(c => this._normalizeContent(c));
},
_normalizeContent(content) {
let id = content[this.get("idKey")];
if(this.get("castInteger") === true) {
id = parseInt(id, 10);
}
return {
id,
text: content[this.get("textKey")],
icon: content[this.get("iconKey")]
};
},
_bindTab() {
$(document).on("keydown.select-box", (event) => {
const keyCode = event.keyCode || event.which;
if (keyCode === 9) {
this.set("expanded", false);
}
});
},
_positionSelectBoxWrapper() {
const headerHeight = this.$(".select-box-header").outerHeight();
this.$(".select-box-wrapper").css({
width: this.$().width(),
display: "block",
height: headerHeight + this.$(".select-box-body").outerHeight()
});
},
applyDirection() {
this.$().removeClass("is-reversed");
const offsetTop = this.$()[0].getBoundingClientRect().top;
const windowHeight = $(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: ""
});
}
},
});