import $ from "jquery"; import * as keydown_util from "./keydown_util"; /* USAGE: Toggle x = components.toggle({ selected: Integer selected_index, values: Array [ { label: i18n.t("String title") } ], callback: function () { // .. on value change. }, }).get(); */ export function toggle(opts) { const component = (function render_component(opts) { const _component = $("
"); if (opts.html_class) { // add a check inside passed arguments in case some extra // classes need to be added for correct alignment or other purposes _component.addClass(opts.html_class); } for (const [i, value] of opts.values.entries()) { // create a tab with a tab-id so they don't have to be referenced // by text value which can be inconsistent. const tab = $("
", { class: "ind-tab", "data-tab-key": value.key, "data-tab-id": i, tabindex: 0, }); /* istanbul ignore if */ if (value.label_html !== undefined) { const html = value.label_html; tab.html(html); } else { tab.text(value.label); } // add proper classes for styling in CSS. if (i === 0) { // this should be default selected unless otherwise specified. tab.addClass("first selected"); } else if (i === opts.values.length - 1) { tab.addClass("last"); } else { tab.addClass("middle"); } _component.append(tab); } return _component; })(opts); const meta = { $ind_tab: component.find(".ind-tab"), idx: -1, }; // Returns false if the requested tab is disabled. function select_tab(idx) { const elem = meta.$ind_tab.eq(idx); if (elem.hasClass("disabled")) { return false; } meta.$ind_tab.removeClass("selected"); elem.addClass("selected"); meta.idx = idx; if (opts.callback) { opts.callback(opts.values[idx].label, opts.values[idx].key); } if (!opts.child_wants_focus) { elem.trigger("focus"); } return true; } function maybe_go_left() { // Select the first non-disabled tab to the left, if any. let i = 1; while (meta.idx - i >= 0) { if (select_tab(meta.idx - i)) { return true; } i += 1; } return false; } function maybe_go_right() { // Select the first non-disabled tab to the right, if any. let i = 1; while (meta.idx + i <= opts.values.length - 1) { if (select_tab(meta.idx + i)) { return true; } i += 1; } return false; } (function () { meta.$ind_tab.on("click", function () { const idx = $(this).data("tab-id"); select_tab(idx); }); keydown_util.handle({ elem: meta.$ind_tab, handlers: { left_arrow: maybe_go_left, right_arrow: maybe_go_right, }, }); // We should arguably default opts.selected to 0. if (typeof opts.selected === "number") { select_tab(opts.selected); } })(); const prototype = { // Skip disabled tabs and go to the next one. maybe_go_left, maybe_go_right, disable_tab(name) { const value = opts.values.find((o) => o.key === name); const idx = opts.values.indexOf(value); meta.$ind_tab.eq(idx).addClass("disabled"); }, enable_tab(name) { const value = opts.values.find((o) => o.key === name); const idx = opts.values.indexOf(value); meta.$ind_tab.eq(idx).removeClass("disabled"); }, value() { if (meta.idx >= 0) { return opts.values[meta.idx].label; } /* istanbul ignore next */ return undefined; }, get() { return component; }, // go through the process of finding the correct tab for a given name, // and when found, select that one and provide the proper callback. goto(name) { const value = opts.values.find((o) => o.label === name || o.key === name); const idx = opts.values.indexOf(value); if (idx >= 0) { select_tab(idx); } }, }; return prototype; }