Files
zulip/static/js/components.js
Priyank Patel 6ab66ea17a keydown_util: Use Event.key instead of deprecated properties.
The Event.which and Event.keyCode are deprecated as pointed out by
TypeScript intellisense based on the jQuery types. We use Event.key
instead which behaves similarly to Event.which & Event.keyCode for
our use case.

The only difference in functionality by this change is that the vim
keys won't work when Caps Lock is on. This is because, in this case,
the key property will be "J" instead of 'j'. We can fix this by
adding a mapping for this, however, I think we don't want to handle
this case so I left this change out. Tested by trying out the
everywhere keydown_util is used.

Finally, we also turn off the new-cap rule for tests since I think
it fine to only enforce it on real code and exempting test code is
fine.
2021-05-27 23:33:17 -07:00

166 lines
4.4 KiB
JavaScript

import $ from "jquery";
import * as keydown_util from "./keydown_util";
/* USAGE:
Toggle x = components.toggle({
selected: Integer selected_index,
values: Array<Object> [
{label: $t({defaultMessage: "String title"})}
],
callback: function () {
// .. on value change.
},
}).get();
*/
export function toggle(opts) {
const component = $("<div class='tab-switcher'></div>");
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 = $("<div>", {
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);
}
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;
}
meta.$ind_tab.on("click", function () {
const idx = $(this).data("tab-id");
select_tab(idx);
});
keydown_util.handle({
elem: meta.$ind_tab,
handlers: {
ArrowLeft: maybe_go_left,
ArrowRight: 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;
}