import { HTMLWidget } from "@hpcc-js/common"; import { select as d3Select } from "d3-selection"; import "../src/Select.css"; export class Select extends HTMLWidget { _span; _prompt; _select; constructor() { super(); } selectData() { if (this.data().length === 0) return []; const view = this._db.rollupView([this.textColumn(), this.valueColumn()]); let retVal = []; retVal = retVal.concat(view.entries().map(function (row) { return { text: row.key, value: row.values.length ? row.values[0].key : "", origRow: row.values.length && row.values[0].value.length ? row.values[0].value[0] : [] }; }, this)); if (this.sort_exists()) { const descending = this.sort() === "descending"; retVal.sort(function (l, r) { if (l.text < r.text) return descending ? 1 : -1; if (l.text > r.text) return descending ? -1 : 1; return 0; }); } if (this.optional()) { retVal.unshift({ value: "", text: "" }); } return retVal; } enter(domNode, element) { super.enter(domNode, element); this._span = element.append("span"); this._prompt = this._span.append("label") .attr("for", this.id() + "_select") ; const context = this; this._select = this._span.append("select") .attr("id", this.id() + "_select") .on("change", function (d) { const options = []; const options_dom_node = context._select.node().options; for (let i = 0; i < options_dom_node.length; ++i) { const optionNode = options_dom_node[i]; if (optionNode.selected) { options.push((d3Select(optionNode).datum() as any).origRow); } } if (options.length) { context.click(context.rowToObj(options[0]), context.valueColumn(), true); // TODO: Multiselect not support in HIPIE } else { context.click([], context.valueColumn(), false); } }) ; } update(domNode, element) { super.update(domNode, element); this._prompt .text(this.label()) ; this._select .attr("multiple", this.multiple() ? this.multiple() : null) .attr("size", this.multiple() && this.selectSize() ? this.selectSize() : null) ; const option = this._select.selectAll(".dataRow").data(this.selectData()); const optionUpdate = option.enter().append("option") .attr("class", "dataRow") .merge(option) .attr("value", function (row) { return row.value; }) .text(function (row) { return row.text; }) ; option.exit().remove(); optionUpdate.order(); } exit(domNode, element) { this._span.remove(); super.exit(domNode, element); } click(row, column, selected) { console.log("Click: " + JSON.stringify(row) + ", " + column + ", " + selected); } label: { (): string; (_: string): Select }; label_exists: () => boolean; valueColumn: { (): string; (_: string): Select }; valueColumn_exists: () => boolean; textColumn: { (): string; (_: string): Select }; textColumn_exists: () => boolean; optional: { (): boolean; (_: boolean): Select }; optional_exists: () => boolean; sort: { (): string; (_: string): Select }; sort_exists: () => boolean; multiple: { (): boolean; (_: boolean): Select }; multiple_exists: () => boolean; selectSize: { (): number; (_: number): Select }; selectSize_exists: () => boolean; } Select.prototype._class += " other_Select"; Select.prototype.publish("label", null, "string", "Label for select"); Select.prototype.publish("valueColumn", null, "set", "Select display value", function () { return this.columns(); }, { optional: true }); Select.prototype.publish("textColumn", null, "set", "Select value(s)", function () { return this.columns(); }, { optional: true }); Select.prototype.publish("optional", true, "boolean", "Optional Select"); Select.prototype.publish("sort", null, "set", "Sort contents", ["", "ascending", "descending"], { optional: true }); Select.prototype.publish("multiple", false, "boolean", "Multiple selection"); Select.prototype.publish("selectSize", 5, "number", "Size of multiselect box", null, { disable: w => !w.multiple() });