mirror of https://github.com/zulip/zulip.git
web: Use util.the for accessing element of single-item lists.
This commit is contained in:
parent
113de14547
commit
d9f25d01a1
|
@ -7,6 +7,7 @@ import * as browser_history from "./browser_history";
|
||||||
import {show_copied_confirmation} from "./copied_tooltip";
|
import {show_copied_confirmation} from "./copied_tooltip";
|
||||||
import * as overlays from "./overlays";
|
import * as overlays from "./overlays";
|
||||||
import {realm} from "./state_data";
|
import {realm} from "./state_data";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
export function launch(): void {
|
export function launch(): void {
|
||||||
overlays.open_overlay({
|
overlays.open_overlay({
|
||||||
|
@ -19,12 +20,12 @@ export function launch(): void {
|
||||||
|
|
||||||
const zulip_version_clipboard = new ClipboardJS("#about-zulip .fa-copy.zulip-version");
|
const zulip_version_clipboard = new ClipboardJS("#about-zulip .fa-copy.zulip-version");
|
||||||
zulip_version_clipboard.on("success", () => {
|
zulip_version_clipboard.on("success", () => {
|
||||||
show_copied_confirmation($("#about-zulip .fa-copy.zulip-version")[0]!);
|
show_copied_confirmation(util.the($("#about-zulip .fa-copy.zulip-version")));
|
||||||
});
|
});
|
||||||
|
|
||||||
const zulip_merge_base_clipboard = new ClipboardJS("#about-zulip .fa-copy.zulip-merge-base");
|
const zulip_merge_base_clipboard = new ClipboardJS("#about-zulip .fa-copy.zulip-merge-base");
|
||||||
zulip_merge_base_clipboard.on("success", () => {
|
zulip_merge_base_clipboard.on("success", () => {
|
||||||
show_copied_confirmation($("#about-zulip .fa-copy.zulip-merge-base")[0]!);
|
show_copied_confirmation(util.the($("#about-zulip .fa-copy.zulip-merge-base")));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
|
||||||
import {user_settings} from "./user_settings";
|
import {user_settings} from "./user_settings";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
export function initialize(): void {
|
export function initialize(): void {
|
||||||
update_notification_sound_source($("audio#user-notification-sound-audio"), user_settings);
|
update_notification_sound_source($("audio#user-notification-sound-audio"), user_settings);
|
||||||
|
@ -22,6 +23,6 @@ export function update_notification_sound_source(
|
||||||
if (notification_sound !== "none") {
|
if (notification_sound !== "none") {
|
||||||
// Load it so that it is ready to be played; without this the old sound
|
// Load it so that it is ready to be played; without this the old sound
|
||||||
// is played.
|
// is played.
|
||||||
$container_elem[0]!.load();
|
util.the($container_elem).load();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import $ from "jquery";
|
||||||
import {z} from "zod";
|
import {z} from "zod";
|
||||||
|
|
||||||
import * as loading from "../loading";
|
import * as loading from "../loading";
|
||||||
|
import * as util from "../util";
|
||||||
|
|
||||||
export type FormDataObject = Record<string, string>;
|
export type FormDataObject = Record<string, string>;
|
||||||
|
|
||||||
|
@ -162,7 +163,7 @@ export function update_discount_details(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function is_valid_input($elem: JQuery<HTMLFormElement>): boolean {
|
export function is_valid_input($elem: JQuery<HTMLFormElement>): boolean {
|
||||||
return $elem[0]!.checkValidity();
|
return util.the($elem).checkValidity();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function redirect_to_billing_with_successful_upgrade(billing_base_url: string): void {
|
export function redirect_to_billing_with_successful_upgrade(billing_base_url: string): void {
|
||||||
|
|
|
@ -171,7 +171,7 @@ import getCaretCoordinates from "textarea-caret";
|
||||||
import * as tippy from "tippy.js";
|
import * as tippy from "tippy.js";
|
||||||
|
|
||||||
import * as scroll_util from "./scroll_util";
|
import * as scroll_util from "./scroll_util";
|
||||||
import {get_string_diff} from "./util";
|
import {get_string_diff, the} from "./util";
|
||||||
|
|
||||||
function get_pseudo_keycode(
|
function get_pseudo_keycode(
|
||||||
event: JQuery.KeyDownEvent | JQuery.KeyUpEvent | JQuery.KeyPressEvent,
|
event: JQuery.KeyDownEvent | JQuery.KeyUpEvent | JQuery.KeyPressEvent,
|
||||||
|
@ -322,7 +322,7 @@ export class Typeahead<ItemType extends string | object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
select(e?: JQuery.ClickEvent | JQuery.KeyUpEvent | JQuery.KeyDownEvent): this {
|
select(e?: JQuery.ClickEvent | JQuery.KeyUpEvent | JQuery.KeyDownEvent): this {
|
||||||
const val = this.values.get(this.$menu.find(".active")[0]!);
|
const val = this.values.get(the(this.$menu.find(".active")));
|
||||||
// It's possible that we got here from pressing enter with nothing highlighted.
|
// It's possible that we got here from pressing enter with nothing highlighted.
|
||||||
if (!this.requireHighlight && val === undefined) {
|
if (!this.requireHighlight && val === undefined) {
|
||||||
return this.hide();
|
return this.hide();
|
||||||
|
@ -359,7 +359,7 @@ export class Typeahead<ItemType extends string | object> {
|
||||||
}
|
}
|
||||||
|
|
||||||
set_value(): void {
|
set_value(): void {
|
||||||
const val = this.values.get(this.$menu.find(".active")[0]!);
|
const val = this.values.get(the(this.$menu.find(".active")));
|
||||||
assert(typeof val === "string");
|
assert(typeof val === "string");
|
||||||
if (this.input_element.type === "contenteditable") {
|
if (this.input_element.type === "contenteditable") {
|
||||||
this.input_element.$element.text(val);
|
this.input_element.$element.text(val);
|
||||||
|
@ -392,7 +392,7 @@ export class Typeahead<ItemType extends string | object> {
|
||||||
|
|
||||||
const input_element = this.input_element;
|
const input_element = this.input_element;
|
||||||
if (!this.non_tippy_parent_element) {
|
if (!this.non_tippy_parent_element) {
|
||||||
this.instance = tippy.default(input_element.$element[0]!, {
|
this.instance = tippy.default(the(input_element.$element), {
|
||||||
// Lets typeahead take the width needed to fit the content
|
// Lets typeahead take the width needed to fit the content
|
||||||
// and wraps it if it overflows the visible container.
|
// and wraps it if it overflows the visible container.
|
||||||
maxWidth: "none",
|
maxWidth: "none",
|
||||||
|
@ -425,7 +425,7 @@ export class Typeahead<ItemType extends string | object> {
|
||||||
interactive: true,
|
interactive: true,
|
||||||
appendTo: () => document.body,
|
appendTo: () => document.body,
|
||||||
showOnCreate: true,
|
showOnCreate: true,
|
||||||
content: this.$container[0]!,
|
content: the(this.$container),
|
||||||
// We expect the typeahead creator to handle when to hide / show the typeahead.
|
// We expect the typeahead creator to handle when to hide / show the typeahead.
|
||||||
trigger: "manual",
|
trigger: "manual",
|
||||||
arrow: false,
|
arrow: false,
|
||||||
|
@ -435,8 +435,8 @@ export class Typeahead<ItemType extends string | object> {
|
||||||
|
|
||||||
if (input_element.type === "textarea") {
|
if (input_element.type === "textarea") {
|
||||||
const caret = getCaretCoordinates(
|
const caret = getCaretCoordinates(
|
||||||
input_element.$element[0]!,
|
the(input_element.$element),
|
||||||
input_element.$element[0]!.selectionStart,
|
the(input_element.$element).selectionStart,
|
||||||
);
|
);
|
||||||
// Used to consider the scroll height of textbox in the vertical offset.
|
// Used to consider the scroll height of textbox in the vertical offset.
|
||||||
const scrollTop = input_element.$element.scrollTop() ?? 0;
|
const scrollTop = input_element.$element.scrollTop() ?? 0;
|
||||||
|
@ -554,7 +554,7 @@ export class Typeahead<ItemType extends string | object> {
|
||||||
render(final_items: ItemType[], matching_items: ItemType[]): this {
|
render(final_items: ItemType[], matching_items: ItemType[]): this {
|
||||||
const $items: JQuery[] = final_items.map((item) => {
|
const $items: JQuery[] = final_items.map((item) => {
|
||||||
const $i = $(ITEM_HTML);
|
const $i = $(ITEM_HTML);
|
||||||
this.values.set($i[0]!, item);
|
this.values.set(the($i), item);
|
||||||
const item_html = this.highlighter_html(item, this.query) ?? "";
|
const item_html = this.highlighter_html(item, this.query) ?? "";
|
||||||
const $item_html = $i.find("a").html(item_html);
|
const $item_html = $i.find("a").html(item_html);
|
||||||
|
|
||||||
|
@ -743,12 +743,12 @@ export class Typeahead<ItemType extends string | object> {
|
||||||
|
|
||||||
this.select(e);
|
this.select(e);
|
||||||
|
|
||||||
if (this.input_element.$element[0]!.id === "stream_message_recipient_topic") {
|
if (the(this.input_element.$element).id === "stream_message_recipient_topic") {
|
||||||
assert(this.input_element.type === "input");
|
assert(this.input_element.type === "input");
|
||||||
// Move the cursor to the end of the topic
|
// Move the cursor to the end of the topic
|
||||||
const topic_length = this.input_element.$element.val()!.length;
|
const topic_length = this.input_element.$element.val()!.length;
|
||||||
this.input_element.$element[0]!.selectionStart = topic_length;
|
the(this.input_element.$element).selectionStart = topic_length;
|
||||||
this.input_element.$element[0]!.selectionEnd = topic_length;
|
the(this.input_element.$element).selectionEnd = topic_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -775,7 +775,7 @@ export class Typeahead<ItemType extends string | object> {
|
||||||
// when shift (keycode 16) + tabbing to the topic field
|
// when shift (keycode 16) + tabbing to the topic field
|
||||||
if (
|
if (
|
||||||
pseudo_keycode === 16 &&
|
pseudo_keycode === 16 &&
|
||||||
this.input_element.$element[0]!.id === "stream_message_recipient_topic"
|
the(this.input_element.$element).id === "stream_message_recipient_topic"
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import * as stream_data from "./stream_data";
|
||||||
import type {StreamSubscription} from "./sub_store";
|
import type {StreamSubscription} from "./sub_store";
|
||||||
import {INTERACTIVE_HOVER_DELAY} from "./tippyjs";
|
import {INTERACTIVE_HOVER_DELAY} from "./tippyjs";
|
||||||
import {user_settings} from "./user_settings";
|
import {user_settings} from "./user_settings";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
function get_formatted_sub_count(sub_count: number): string {
|
function get_formatted_sub_count(sub_count: number): string {
|
||||||
if (sub_count < 1000) {
|
if (sub_count < 1000) {
|
||||||
|
@ -172,7 +173,7 @@ export class BuddyList extends BuddyListConf {
|
||||||
// This will default to "bottom" placement for this tooltip.
|
// This will default to "bottom" placement for this tooltip.
|
||||||
placement = "auto";
|
placement = "auto";
|
||||||
}
|
}
|
||||||
tippy.default($elem[0]!, {
|
tippy.default(util.the($elem), {
|
||||||
// Because the buddy list subheadings are potential click targets
|
// Because the buddy list subheadings are potential click targets
|
||||||
// for purposes having nothing to do with the subscriber count
|
// for purposes having nothing to do with the subscriber count
|
||||||
// (collapsing/expanding), we delay showing the tooltip until the
|
// (collapsing/expanding), we delay showing the tooltip until the
|
||||||
|
@ -765,9 +766,7 @@ export class BuddyList extends BuddyListConf {
|
||||||
fill_screen_with_content(): void {
|
fill_screen_with_content(): void {
|
||||||
let height = this.height_to_fill();
|
let height = this.height_to_fill();
|
||||||
|
|
||||||
const elem = scroll_util
|
const elem = util.the(scroll_util.get_scroll_element($(this.scroll_container_selector)));
|
||||||
.get_scroll_element($(this.scroll_container_selector))
|
|
||||||
.expectOne()[0]!;
|
|
||||||
|
|
||||||
// Add a fudge factor.
|
// Add a fudge factor.
|
||||||
height += 10;
|
height += 10;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import $ from "jquery";
|
||||||
import * as tippy from "tippy.js";
|
import * as tippy from "tippy.js";
|
||||||
|
|
||||||
import {$t} from "./i18n";
|
import {$t} from "./i18n";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
export const status_classes = "alert-error alert-success alert-info alert-warning alert-loading";
|
export const status_classes = "alert-error alert-success alert-info alert-warning alert-loading";
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ function set_password_toggle_label(
|
||||||
): void {
|
): void {
|
||||||
$(password_selector).attr("aria-label", label);
|
$(password_selector).attr("aria-label", label);
|
||||||
if (tippy_tooltips) {
|
if (tippy_tooltips) {
|
||||||
const element: tippy.ReferenceElement = $(password_selector)[0]!;
|
const element: tippy.ReferenceElement = util.the($(password_selector));
|
||||||
const tippy_instance = element._tippy ?? tippy.default(element);
|
const tippy_instance = element._tippy ?? tippy.default(element);
|
||||||
tippy_instance.setContent(label);
|
tippy_instance.setContent(label);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -281,7 +281,7 @@ function on_hidden_callback(): void {
|
||||||
// Always move focus to the topic input even if it's not empty,
|
// Always move focus to the topic input even if it's not empty,
|
||||||
// since it's likely the user will want to update the topic
|
// since it's likely the user will want to update the topic
|
||||||
// after updating the stream.
|
// after updating the stream.
|
||||||
ui_util.place_caret_at_end($("input#stream_message_recipient_topic")[0]!);
|
ui_util.place_caret_at_end(util.the($("input#stream_message_recipient_topic")));
|
||||||
} else {
|
} else {
|
||||||
if (compose_state.private_message_recipient().length === 0) {
|
if (compose_state.private_message_recipient().length === 0) {
|
||||||
$("#private_message_recipient").trigger("focus").trigger("select");
|
$("#private_message_recipient").trigger("focus").trigger("select");
|
||||||
|
|
|
@ -123,9 +123,9 @@ export function insert_and_scroll_into_view(
|
||||||
// to support `undo`, we can use a faster method.
|
// to support `undo`, we can use a faster method.
|
||||||
$textarea.val(content);
|
$textarea.val(content);
|
||||||
} else if (replace_all) {
|
} else if (replace_all) {
|
||||||
setFieldText($textarea[0]!, content);
|
setFieldText(util.the($textarea), content);
|
||||||
} else {
|
} else {
|
||||||
insertTextIntoField($textarea[0]!, content);
|
insertTextIntoField(util.the($textarea), content);
|
||||||
}
|
}
|
||||||
// Blurring and refocusing ensures the cursor / selection is in view
|
// Blurring and refocusing ensures the cursor / selection is in view
|
||||||
// in chromium browsers.
|
// in chromium browsers.
|
||||||
|
@ -300,7 +300,7 @@ export function replace_syntax(
|
||||||
// for details.
|
// for details.
|
||||||
|
|
||||||
const old_text = $textarea.val();
|
const old_text = $textarea.val();
|
||||||
replaceFieldText($textarea[0]!, old_syntax, () => new_syntax, "after-replacement");
|
replaceFieldText(util.the($textarea), old_syntax, () => new_syntax, "after-replacement");
|
||||||
const new_text = $textarea.val();
|
const new_text = $textarea.val();
|
||||||
|
|
||||||
// When replacing content in a textarea, we need to move the cursor
|
// When replacing content in a textarea, we need to move the cursor
|
||||||
|
|
|
@ -41,6 +41,7 @@ import type {UserGroup} from "./user_groups";
|
||||||
import * as user_pill from "./user_pill";
|
import * as user_pill from "./user_pill";
|
||||||
import type {UserPillData} from "./user_pill";
|
import type {UserPillData} from "./user_pill";
|
||||||
import {user_settings} from "./user_settings";
|
import {user_settings} from "./user_settings";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
// **********************************
|
// **********************************
|
||||||
// AN IMPORTANT NOTE ABOUT TYPEAHEADS
|
// AN IMPORTANT NOTE ABOUT TYPEAHEADS
|
||||||
|
@ -250,7 +251,7 @@ function handle_bulleting_or_numbering(
|
||||||
if (bulleted_numbered_list_util.strip_bullet(previous_line) === "") {
|
if (bulleted_numbered_list_util.strip_bullet(previous_line) === "") {
|
||||||
// below we select and replace the last 2 characters in the textarea before
|
// below we select and replace the last 2 characters in the textarea before
|
||||||
// the cursor - the bullet syntax - with an empty string
|
// the cursor - the bullet syntax - with an empty string
|
||||||
$textarea[0]!.setSelectionRange($textarea.caret() - 2, $textarea.caret());
|
util.the($textarea).setSelectionRange($textarea.caret() - 2, $textarea.caret());
|
||||||
compose_ui.insert_and_scroll_into_view("", $textarea);
|
compose_ui.insert_and_scroll_into_view("", $textarea);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
|
@ -264,7 +265,7 @@ function handle_bulleting_or_numbering(
|
||||||
if (bulleted_numbered_list_util.strip_numbering(previous_line) === "") {
|
if (bulleted_numbered_list_util.strip_numbering(previous_line) === "") {
|
||||||
// below we select then replaces the last few characters in the textarea before
|
// below we select then replaces the last few characters in the textarea before
|
||||||
// the cursor - the numbering syntax - with an empty string
|
// the cursor - the numbering syntax - with an empty string
|
||||||
$textarea[0]!.setSelectionRange(
|
util.the($textarea).setSelectionRange(
|
||||||
$textarea.caret() - previous_number_string.length - 2,
|
$textarea.caret() - previous_number_string.length - 2,
|
||||||
$textarea.caret(),
|
$textarea.caret(),
|
||||||
);
|
);
|
||||||
|
@ -297,7 +298,7 @@ export function handle_enter($textarea: JQuery<HTMLTextAreaElement>, e: JQuery.K
|
||||||
|
|
||||||
// If the selectionStart and selectionEnd are not the same, that
|
// If the selectionStart and selectionEnd are not the same, that
|
||||||
// means that some text was selected.
|
// means that some text was selected.
|
||||||
if ($textarea[0]!.selectionStart !== $textarea[0]!.selectionEnd) {
|
if (util.the($textarea).selectionStart !== util.the($textarea).selectionEnd) {
|
||||||
// Replace it with the newline, remembering to resize the
|
// Replace it with the newline, remembering to resize the
|
||||||
// textarea if needed.
|
// textarea if needed.
|
||||||
compose_ui.insert_and_scroll_into_view("\n", $textarea);
|
compose_ui.insert_and_scroll_into_view("\n", $textarea);
|
||||||
|
@ -1175,7 +1176,11 @@ export function content_typeahead_selected(
|
||||||
$textbox.caret(beginning.length);
|
$textbox.caret(beginning.length);
|
||||||
compose_ui.autosize_textarea($textbox);
|
compose_ui.autosize_textarea($textbox);
|
||||||
};
|
};
|
||||||
flatpickr.show_flatpickr(input_element.$element[0]!, on_timestamp_selection, timestamp);
|
flatpickr.show_flatpickr(
|
||||||
|
util.the(input_element.$element),
|
||||||
|
on_timestamp_selection,
|
||||||
|
timestamp,
|
||||||
|
);
|
||||||
return beginning + rest;
|
return beginning + rest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import * as message_lists from "./message_lists";
|
||||||
import type {Message} from "./message_store";
|
import type {Message} from "./message_store";
|
||||||
import * as message_viewport from "./message_viewport";
|
import * as message_viewport from "./message_viewport";
|
||||||
import * as rows from "./rows";
|
import * as rows from "./rows";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This library implements two related, similar concepts:
|
This library implements two related, similar concepts:
|
||||||
|
@ -151,7 +152,7 @@ function get_message_height(elem: HTMLElement): number {
|
||||||
// This needs to be very fast. This function runs hundreds of times
|
// This needs to be very fast. This function runs hundreds of times
|
||||||
// when displaying a message feed view that has hundreds of message
|
// when displaying a message feed view that has hundreds of message
|
||||||
// history, which ideally should render in <100ms.
|
// history, which ideally should render in <100ms.
|
||||||
return $(elem).find(".message_content")[0]!.scrollHeight;
|
return util.the($(elem).find(".message_content")).scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hide_message_expander($row: JQuery): void {
|
export function hide_message_expander($row: JQuery): void {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import * as hash_util from "./hash_util";
|
||||||
import * as message_lists from "./message_lists";
|
import * as message_lists from "./message_lists";
|
||||||
import * as rows from "./rows";
|
import * as rows from "./rows";
|
||||||
import * as topic_link_util from "./topic_link_util";
|
import * as topic_link_util from "./topic_link_util";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||||
|
@ -135,7 +136,7 @@ function select_div($div: JQuery, selection: Selection): void {
|
||||||
background: "#FFF",
|
background: "#FFF",
|
||||||
}).attr("id", "copytempdiv");
|
}).attr("id", "copytempdiv");
|
||||||
$("body").append($div);
|
$("body").append($div);
|
||||||
selection.selectAllChildren($div[0]!);
|
selection.selectAllChildren(util.the($div));
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove_div(_div: JQuery, ranges: Range[]): void {
|
function remove_div(_div: JQuery, ranges: Range[]): void {
|
||||||
|
@ -629,7 +630,9 @@ function is_safe_url_paste_target($textarea: JQuery<HTMLTextAreaElement>): boole
|
||||||
|
|
||||||
export function cursor_at_markdown_link_marker($textarea: JQuery<HTMLTextAreaElement>): boolean {
|
export function cursor_at_markdown_link_marker($textarea: JQuery<HTMLTextAreaElement>): boolean {
|
||||||
const range = $textarea.range();
|
const range = $textarea.range();
|
||||||
const possible_markdown_link_markers = $textarea[0]!.value.slice(range.start - 2, range.start);
|
const possible_markdown_link_markers = util
|
||||||
|
.the($textarea)
|
||||||
|
.value.slice(range.start - 2, range.start);
|
||||||
return possible_markdown_link_markers === "](";
|
return possible_markdown_link_markers === "](";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -363,11 +363,13 @@ export function restore_message(draft: LocalStorageDraft): ComposeArguments {
|
||||||
|
|
||||||
function draft_notify(): void {
|
function draft_notify(): void {
|
||||||
// Display a tooltip to notify the user about the saved draft.
|
// Display a tooltip to notify the user about the saved draft.
|
||||||
const instance = tippy.default(".top_left_drafts .unread_count", {
|
const instance = util.the(
|
||||||
|
tippy.default(".top_left_drafts .unread_count", {
|
||||||
content: $t({defaultMessage: "Saved as draft"}),
|
content: $t({defaultMessage: "Saved as draft"}),
|
||||||
arrow: true,
|
arrow: true,
|
||||||
placement: "right",
|
placement: "right",
|
||||||
})[0]!;
|
}),
|
||||||
|
);
|
||||||
instance.show();
|
instance.show();
|
||||||
function remove_instance(): void {
|
function remove_instance(): void {
|
||||||
instance.destroy();
|
instance.destroy();
|
||||||
|
|
|
@ -592,7 +592,7 @@ function process_keypress(e: JQuery.KeyPressEvent | JQuery.KeyDownEvent): void {
|
||||||
|
|
||||||
export function emoji_select_tab($elt: JQuery): void {
|
export function emoji_select_tab($elt: JQuery): void {
|
||||||
const scrolltop = $elt.scrollTop()!;
|
const scrolltop = $elt.scrollTop()!;
|
||||||
const scrollheight = $elt[0]!.scrollHeight;
|
const scrollheight = util.the($elt).scrollHeight;
|
||||||
const elt_height = $elt.height()!;
|
const elt_height = $elt.height()!;
|
||||||
let currently_selected = "";
|
let currently_selected = "";
|
||||||
for (const o of section_head_offsets) {
|
for (const o of section_head_offsets) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import assert from "minimalistic-assert";
|
||||||
|
|
||||||
import {$t} from "./i18n";
|
import {$t} from "./i18n";
|
||||||
import {user_settings} from "./user_settings";
|
import {user_settings} from "./user_settings";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
export let flatpickr_instance: flatpickr.Instance;
|
export let flatpickr_instance: flatpickr.Instance;
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ export function show_flatpickr(
|
||||||
): flatpickr.Instance {
|
): flatpickr.Instance {
|
||||||
const $flatpickr_input = $<HTMLInputElement>("<input>").attr("id", "#timestamp_flatpickr");
|
const $flatpickr_input = $<HTMLInputElement>("<input>").attr("id", "#timestamp_flatpickr");
|
||||||
|
|
||||||
flatpickr_instance = flatpickr($flatpickr_input[0]!, {
|
flatpickr_instance = flatpickr(util.the($flatpickr_input), {
|
||||||
mode: "single",
|
mode: "single",
|
||||||
enableTime: true,
|
enableTime: true,
|
||||||
clickOpens: false,
|
clickOpens: false,
|
||||||
|
|
|
@ -1438,7 +1438,7 @@ function move_focus_to_visible_area(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
const INBOX_ROW_HEIGHT = 30;
|
const INBOX_ROW_HEIGHT = 30;
|
||||||
const position = $("#inbox-filters")[0]!.getBoundingClientRect();
|
const position = util.the($("#inbox-filters")).getBoundingClientRect();
|
||||||
const inbox_center_x = (position.left + position.right) / 2;
|
const inbox_center_x = (position.left + position.right) / 2;
|
||||||
// We are aiming to get the first row if it is completely visible or the second row.
|
// We are aiming to get the first row if it is completely visible or the second row.
|
||||||
const inbox_row_below_filters = position.bottom + INBOX_ROW_HEIGHT;
|
const inbox_row_below_filters = position.bottom + INBOX_ROW_HEIGHT;
|
||||||
|
|
|
@ -7,6 +7,7 @@ import render_input_pill from "../templates/input_pill.hbs";
|
||||||
|
|
||||||
import * as keydown_util from "./keydown_util";
|
import * as keydown_util from "./keydown_util";
|
||||||
import * as ui_util from "./ui_util";
|
import * as ui_util from "./ui_util";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
// See https://zulip.readthedocs.io/en/latest/subsystems/input-pills.html
|
// See https://zulip.readthedocs.io/en/latest/subsystems/input-pills.html
|
||||||
|
|
||||||
|
@ -194,9 +195,9 @@ export function create<ItemType extends {type: string}>(
|
||||||
|
|
||||||
if (idx !== -1) {
|
if (idx !== -1) {
|
||||||
store.pills[idx]!.$element.remove();
|
store.pills[idx]!.$element.remove();
|
||||||
const pill = store.pills.splice(idx, 1);
|
const pill = util.the(store.pills.splice(idx, 1));
|
||||||
if (store.onPillRemove !== undefined) {
|
if (store.onPillRemove !== undefined) {
|
||||||
store.onPillRemove(pill[0]!, trigger);
|
store.onPillRemove(pill, trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is needed to run the "change" event handler registered in
|
// This is needed to run the "change" event handler registered in
|
||||||
|
@ -231,8 +232,7 @@ export function create<ItemType extends {type: string}>(
|
||||||
while (store.pills.length > 0) {
|
while (store.pills.length > 0) {
|
||||||
this.removeLastPill(trigger, quiet);
|
this.removeLastPill(trigger, quiet);
|
||||||
}
|
}
|
||||||
|
this.clear(util.the(store.$input));
|
||||||
this.clear(store.$input[0]!);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
insertManyPills(pills: string | string[]) {
|
insertManyPills(pills: string | string[]) {
|
||||||
|
@ -253,7 +253,7 @@ export function create<ItemType extends {type: string}>(
|
||||||
// when using the `text` insertion feature with jQuery the caret is
|
// when using the `text` insertion feature with jQuery the caret is
|
||||||
// placed at the beginning of the input field, so this moves it to
|
// placed at the beginning of the input field, so this moves it to
|
||||||
// the end.
|
// the end.
|
||||||
ui_util.place_caret_at_end(store.$input[0]!);
|
ui_util.place_caret_at_end(util.the(store.$input));
|
||||||
|
|
||||||
// this sends a flag if the operation wasn't completely successful,
|
// this sends a flag if the operation wasn't completely successful,
|
||||||
// which in this case is defined as some of the pills not autofilling
|
// which in this case is defined as some of the pills not autofilling
|
||||||
|
@ -341,7 +341,7 @@ export function create<ItemType extends {type: string}>(
|
||||||
// if the pill is successful, it will create the pill and clear
|
// if the pill is successful, it will create the pill and clear
|
||||||
// the input.
|
// the input.
|
||||||
if (funcs.appendPill(store.$input.text().trim())) {
|
if (funcs.appendPill(store.$input.text().trim())) {
|
||||||
funcs.clear(store.$input[0]!);
|
funcs.clear(util.the(store.$input));
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ export function create<ItemType extends {type: string}>(
|
||||||
break;
|
break;
|
||||||
case "Backspace": {
|
case "Backspace": {
|
||||||
const $next = $pill.next();
|
const $next = $pill.next();
|
||||||
funcs.removePill($pill[0]!, "backspace");
|
funcs.removePill(util.the($pill), "backspace");
|
||||||
$next.trigger("focus");
|
$next.trigger("focus");
|
||||||
// the "Backspace" key in Firefox will go back a page if you do
|
// the "Backspace" key in Firefox will go back a page if you do
|
||||||
// not prevent it.
|
// not prevent it.
|
||||||
|
@ -416,8 +416,8 @@ export function create<ItemType extends {type: string}>(
|
||||||
store.$input.trigger("change");
|
store.$input.trigger("change");
|
||||||
} else {
|
} else {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
const $pill = $(this).closest(".pill");
|
const pill = util.the($(this).closest(".pill"));
|
||||||
funcs.removePill($pill[0]!, "close");
|
funcs.removePill(pill, "close");
|
||||||
}
|
}
|
||||||
// Since removing a pill moves the $input, typeahead needs to refresh
|
// Since removing a pill moves the $input, typeahead needs to refresh
|
||||||
// to appear at the correct position.
|
// to appear at the correct position.
|
||||||
|
|
|
@ -53,7 +53,7 @@ export function show_generate_integration_url_modal(api_key: string): void {
|
||||||
});
|
});
|
||||||
clipboard.on("success", () => {
|
clipboard.on("success", () => {
|
||||||
show_copied_confirmation(
|
show_copied_confirmation(
|
||||||
$("#generate-integration-url-modal .dialog_submit_button")[0]!,
|
util.the($("#generate-integration-url-modal .dialog_submit_button")),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ import * as stream_pill from "./stream_pill";
|
||||||
import * as timerender from "./timerender";
|
import * as timerender from "./timerender";
|
||||||
import type {HTMLSelectOneElement} from "./types";
|
import type {HTMLSelectOneElement} from "./types";
|
||||||
import * as ui_report from "./ui_report";
|
import * as ui_report from "./ui_report";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
let custom_expiration_time_input = 10;
|
let custom_expiration_time_input = 10;
|
||||||
let custom_expiration_time_unit = "days";
|
let custom_expiration_time_unit = "days";
|
||||||
|
@ -208,7 +209,7 @@ function submit_invitation_form(): void {
|
||||||
$("#invite-user-modal .dialog_submit_button").text($t({defaultMessage: "Invite"}));
|
$("#invite-user-modal .dialog_submit_button").text($t({defaultMessage: "Invite"}));
|
||||||
$("#invite-user-modal .dialog_submit_button").prop("disabled", false);
|
$("#invite-user-modal .dialog_submit_button").prop("disabled", false);
|
||||||
$("#invite-user-modal .dialog_exit_button").prop("disabled", false);
|
$("#invite-user-modal .dialog_exit_button").prop("disabled", false);
|
||||||
$invite_status[0]!.scrollIntoView();
|
util.the($invite_status).scrollIntoView();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -228,7 +229,7 @@ function generate_multiuse_invite(): void {
|
||||||
clipboard.on("success", () => {
|
clipboard.on("success", () => {
|
||||||
const tippy_timeout_in_ms = 800;
|
const tippy_timeout_in_ms = 800;
|
||||||
show_copied_confirmation(
|
show_copied_confirmation(
|
||||||
$("#copy_generated_invite_link")[0]!,
|
util.the($("#copy_generated_invite_link")),
|
||||||
() => {
|
() => {
|
||||||
// Do nothing on hide
|
// Do nothing on hide
|
||||||
},
|
},
|
||||||
|
@ -243,7 +244,7 @@ function generate_multiuse_invite(): void {
|
||||||
$("#invite-user-modal .dialog_submit_button").text($t({defaultMessage: "Create link"}));
|
$("#invite-user-modal .dialog_submit_button").text($t({defaultMessage: "Create link"}));
|
||||||
$("#invite-user-modal .dialog_submit_button").prop("disabled", false);
|
$("#invite-user-modal .dialog_submit_button").prop("disabled", false);
|
||||||
$("#invite-user-modal .dialog_exit_button").prop("disabled", false);
|
$("#invite-user-modal .dialog_exit_button").prop("disabled", false);
|
||||||
$invite_status[0]!.scrollIntoView();
|
util.the($invite_status).scrollIntoView();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -302,7 +303,7 @@ function set_streams_to_join_list_visibility(): void {
|
||||||
const realm_has_default_streams = stream_data.get_default_stream_ids().length !== 0;
|
const realm_has_default_streams = stream_data.get_default_stream_ids().length !== 0;
|
||||||
const hide_streams_list =
|
const hide_streams_list =
|
||||||
realm_has_default_streams &&
|
realm_has_default_streams &&
|
||||||
$<HTMLInputElement>("input#invite_select_default_streams")[0]!.checked;
|
util.the($<HTMLInputElement>("input#invite_select_default_streams")).checked;
|
||||||
if (hide_streams_list) {
|
if (hide_streams_list) {
|
||||||
$(".add_streams_container").hide();
|
$(".add_streams_container").hide();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -118,12 +118,12 @@ export class PanZoomControl {
|
||||||
// See https://github.com/anvaka/panzoom/issues/112 for upstream discussion.
|
// See https://github.com/anvaka/panzoom/issues/112 for upstream discussion.
|
||||||
|
|
||||||
const {scale, x, y} = e.getTransform();
|
const {scale, x, y} = e.getTransform();
|
||||||
const image_width = $(".zoom-element > img")[0]!.clientWidth * scale;
|
const image_width = util.the($(".zoom-element > img")).clientWidth * scale;
|
||||||
const image_height = $(".zoom-element > img")[0]!.clientHeight * scale;
|
const image_height = util.the($(".zoom-element > img")).clientHeight * scale;
|
||||||
const zoom_element_width = $(".zoom-element")[0]!.clientWidth * scale;
|
const zoom_element_width = util.the($(".zoom-element")).clientWidth * scale;
|
||||||
const zoom_element_height = $(".zoom-element")[0]!.clientHeight * scale;
|
const zoom_element_height = util.the($(".zoom-element")).clientHeight * scale;
|
||||||
const max_translate_x = $(".image-preview")[0]!.clientWidth;
|
const max_translate_x = util.the($(".image-preview")).clientWidth;
|
||||||
const max_translate_y = $(".image-preview")[0]!.clientHeight;
|
const max_translate_y = util.the($(".image-preview")).clientHeight;
|
||||||
|
|
||||||
// When the image is dragged out of the image-preview container
|
// When the image is dragged out of the image-preview container
|
||||||
// (max_translate) it will be "snapped" back so that the number
|
// (max_translate) it will be "snapped" back so that the number
|
||||||
|
@ -394,7 +394,7 @@ export function build_open_media_function(
|
||||||
return function ($media: JQuery<HTMLMediaElement | HTMLImageElement>): void {
|
return function ($media: JQuery<HTMLMediaElement | HTMLImageElement>): void {
|
||||||
// This is used both for clicking on media in the messagelist, as well as clicking on images
|
// This is used both for clicking on media in the messagelist, as well as clicking on images
|
||||||
// in the media list under the lightbox when it is open.
|
// in the media list under the lightbox when it is open.
|
||||||
const payload = parse_media_data($media[0]!);
|
const payload = parse_media_data(util.the($media));
|
||||||
|
|
||||||
assert(payload !== undefined);
|
assert(payload !== undefined);
|
||||||
if (payload.type.match("-video")) {
|
if (payload.type.match("-video")) {
|
||||||
|
@ -597,7 +597,7 @@ export function initialize(): void {
|
||||||
|
|
||||||
// Bind the pan/zoom control the newly created element.
|
// Bind the pan/zoom control the newly created element.
|
||||||
const pan_zoom_control = new PanZoomControl(
|
const pan_zoom_control = new PanZoomControl(
|
||||||
$("#lightbox_overlay .image-preview > .zoom-element")[0]!,
|
util.the($("#lightbox_overlay .image-preview > .zoom-element")),
|
||||||
);
|
);
|
||||||
|
|
||||||
const reset_lightbox_state = function (): void {
|
const reset_lightbox_state = function (): void {
|
||||||
|
|
|
@ -233,7 +233,7 @@ export class MessageListData {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const recipient_id = Number.parseInt(recipients[0]!, 10);
|
const recipient_id = Number.parseInt(util.the(recipients), 10);
|
||||||
return (
|
return (
|
||||||
!muted_users.is_user_muted(recipient_id) &&
|
!muted_users.is_user_muted(recipient_id) &&
|
||||||
!muted_users.is_user_muted(message.sender_id)
|
!muted_users.is_user_muted(message.sender_id)
|
||||||
|
|
|
@ -78,7 +78,7 @@ export function message_viewport_info(): MessageViewportInfo {
|
||||||
export function at_rendered_bottom(): boolean {
|
export function at_rendered_bottom(): boolean {
|
||||||
const bottom = scrollTop() + height();
|
const bottom = scrollTop() + height();
|
||||||
// This also includes bottom whitespace.
|
// This also includes bottom whitespace.
|
||||||
const full_height = $scroll_container[0]!.scrollHeight;
|
const full_height = util.the($scroll_container).scrollHeight;
|
||||||
|
|
||||||
// We only know within a pixel or two if we're
|
// We only know within a pixel or two if we're
|
||||||
// exactly at the bottom, due to browser quirkiness,
|
// exactly at the bottom, due to browser quirkiness,
|
||||||
|
@ -94,7 +94,7 @@ export function bottom_rendered_message_visible(): boolean {
|
||||||
const $last_row = rows.last_visible();
|
const $last_row = rows.last_visible();
|
||||||
if ($last_row[0] !== undefined) {
|
if ($last_row[0] !== undefined) {
|
||||||
const message_bottom = $last_row[0].getBoundingClientRect().bottom;
|
const message_bottom = $last_row[0].getBoundingClientRect().bottom;
|
||||||
const bottom_of_feed = $("#compose")[0]!.getBoundingClientRect().top;
|
const bottom_of_feed = util.the($("#compose")).getBoundingClientRect().top;
|
||||||
return bottom_of_feed > message_bottom;
|
return bottom_of_feed > message_bottom;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -214,7 +214,7 @@ const top_of_feed = new util.CachedValue({
|
||||||
|
|
||||||
const bottom_of_feed = new util.CachedValue({
|
const bottom_of_feed = new util.CachedValue({
|
||||||
compute_value() {
|
compute_value() {
|
||||||
return $("#compose")[0]!.getBoundingClientRect().top;
|
return util.the($("#compose")).getBoundingClientRect().top;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import assert from "minimalistic-assert";
|
import assert from "minimalistic-assert";
|
||||||
|
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
export type Context = {
|
export type Context = {
|
||||||
items_container_selector: string;
|
items_container_selector: string;
|
||||||
items_list_selector: string;
|
items_list_selector: string;
|
||||||
|
@ -73,11 +75,11 @@ export function modals_handle_events(event_key: string, context: Context): void
|
||||||
|
|
||||||
export function set_initial_element(element_id: string, context: Context): void {
|
export function set_initial_element(element_id: string, context: Context): void {
|
||||||
if (element_id) {
|
if (element_id) {
|
||||||
const $current_element = get_element_by_id(element_id, context);
|
const current_element = util.the(get_element_by_id(element_id, context));
|
||||||
const focus_element = $current_element[0]!.children[0];
|
const focus_element = current_element.children[0];
|
||||||
assert(focus_element instanceof HTMLElement);
|
assert(focus_element instanceof HTMLElement);
|
||||||
activate_element(focus_element, context);
|
activate_element(focus_element, context);
|
||||||
$(`.${CSS.escape(context.items_list_selector)}`)[0]!.scrollTop = 0;
|
util.the($(`.${CSS.escape(context.items_list_selector)}`)).scrollTop = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +134,7 @@ function initialize_focus(event_name: string, context: Context): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
const $element = get_element_by_id(id, context);
|
const $element = get_element_by_id(id, context);
|
||||||
const focus_element = $element[0]!.children[0];
|
const focus_element = util.the($element).children[0];
|
||||||
assert(focus_element instanceof HTMLElement);
|
assert(focus_element instanceof HTMLElement);
|
||||||
activate_element(focus_element, context);
|
activate_element(focus_element, context);
|
||||||
}
|
}
|
||||||
|
@ -152,28 +154,29 @@ function scroll_to_element($element: JQuery, context: Context): void {
|
||||||
const $box_item = $(`.${CSS.escape(context.box_item_selector)}`);
|
const $box_item = $(`.${CSS.escape(context.box_item_selector)}`);
|
||||||
|
|
||||||
// If focused element is first, scroll to the top.
|
// If focused element is first, scroll to the top.
|
||||||
if ($box_item.first()[0]!.parentElement === $element[0]) {
|
if (util.the($box_item.first()).parentElement === $element[0]) {
|
||||||
$items_list[0]!.scrollTop = 0;
|
util.the($items_list).scrollTop = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If focused element is last, scroll to the bottom.
|
// If focused element is last, scroll to the bottom.
|
||||||
if ($box_item.last()[0]!.parentElement === $element[0]) {
|
if (util.the($box_item.last()).parentElement === $element[0]) {
|
||||||
$items_list[0]!.scrollTop = $items_list[0]!.scrollHeight - ($items_list.height() ?? 0);
|
util.the($items_list).scrollTop =
|
||||||
|
util.the($items_list).scrollHeight - ($items_list.height() ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If focused element is cut off from the top, scroll up halfway in modal.
|
// If focused element is cut off from the top, scroll up halfway in modal.
|
||||||
if ($element.position().top < 55) {
|
if ($element.position().top < 55) {
|
||||||
// 55 is the minimum distance from the top that will require extra scrolling.
|
// 55 is the minimum distance from the top that will require extra scrolling.
|
||||||
$items_list[0]!.scrollTop -= $items_list[0]!.clientHeight / 2;
|
util.the($items_list).scrollTop -= util.the($items_list).clientHeight / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If focused element is cut off from the bottom, scroll down halfway in modal.
|
// If focused element is cut off from the bottom, scroll down halfway in modal.
|
||||||
const dist_from_top = $element.position().top;
|
const dist_from_top = $element.position().top;
|
||||||
const total_dist = dist_from_top + $element[0].clientHeight;
|
const total_dist = dist_from_top + $element[0].clientHeight;
|
||||||
const dist_from_bottom = $items_container[0]!.clientHeight - total_dist;
|
const dist_from_bottom = util.the($items_container).clientHeight - total_dist;
|
||||||
if (dist_from_bottom < -4) {
|
if (dist_from_bottom < -4) {
|
||||||
// -4 is the min dist from the bottom that will require extra scrolling.
|
// -4 is the min dist from the bottom that will require extra scrolling.
|
||||||
$items_list[0]!.scrollTop += $items_list[0]!.clientHeight / 2;
|
util.the($items_list).scrollTop += util.the($items_list).clientHeight / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import * as popover_menus from "./popover_menus";
|
||||||
import * as realm_playground from "./realm_playground";
|
import * as realm_playground from "./realm_playground";
|
||||||
import type {RealmPlayground} from "./realm_playground";
|
import type {RealmPlayground} from "./realm_playground";
|
||||||
import * as ui_util from "./ui_util";
|
import * as ui_util from "./ui_util";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
type RealmPlaygroundWithURL = RealmPlayground & {playground_url: string};
|
type RealmPlaygroundWithURL = RealmPlayground & {playground_url: string};
|
||||||
|
|
||||||
|
@ -132,9 +133,9 @@ function register_click_handlers(): void {
|
||||||
const playground_url = url_template.expand({code: extracted_code});
|
const playground_url = url_template.expand({code: extracted_code});
|
||||||
playground_store.set(playground.id, {...playground, playground_url});
|
playground_store.set(playground.id, {...playground, playground_url});
|
||||||
}
|
}
|
||||||
const popover_target = $view_in_playground_button.find(
|
const popover_target = util.the(
|
||||||
".playground-links-popover-container",
|
$view_in_playground_button.find(".playground-links-popover-container"),
|
||||||
)[0]!;
|
);
|
||||||
toggle_playground_links_popover(popover_target, playground_store);
|
toggle_playground_links_popover(popover_target, playground_store);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,8 @@ import SortableJS from "sortablejs";
|
||||||
|
|
||||||
import render_poll_modal_option from "../templates/poll_modal_option.hbs";
|
import render_poll_modal_option from "../templates/poll_modal_option.hbs";
|
||||||
|
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
function create_option_row($last_option_row_input: JQuery): void {
|
function create_option_row($last_option_row_input: JQuery): void {
|
||||||
const row_html = render_poll_modal_option();
|
const row_html = render_poll_modal_option();
|
||||||
const $row_container = $last_option_row_input.closest(".simplebar-content");
|
const $row_container = $last_option_row_input.closest(".simplebar-content");
|
||||||
|
@ -46,7 +48,7 @@ export function poll_options_setup(): void {
|
||||||
|
|
||||||
// setTimeout is needed to here to give time for simplebar to initialise
|
// setTimeout is needed to here to give time for simplebar to initialise
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
SortableJS.create($("#add-poll-form .poll-options-list .simplebar-content")[0]!, {
|
SortableJS.create(util.the($("#add-poll-form .poll-options-list .simplebar-content")), {
|
||||||
onUpdate() {
|
onUpdate() {
|
||||||
// Do nothing on drag; the order is only processed on submission.
|
// Do nothing on drag; the order is only processed on submission.
|
||||||
},
|
},
|
||||||
|
|
|
@ -194,7 +194,7 @@ export const default_popover_props: Partial<tippy.Props> = {
|
||||||
// $tippy_box[0].hasAttribute("data-reference-hidden"); is the real check
|
// $tippy_box[0].hasAttribute("data-reference-hidden"); is the real check
|
||||||
// but linter wants us to write it like this.
|
// but linter wants us to write it like this.
|
||||||
const is_reference_outside_window = Object.hasOwn(
|
const is_reference_outside_window = Object.hasOwn(
|
||||||
$tippy_box[0]!.dataset,
|
util.the($tippy_box).dataset,
|
||||||
"referenceHidden",
|
"referenceHidden",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ export const default_popover_props: Partial<tippy.Props> = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reference_rect = $reference[0]!.getBoundingClientRect();
|
const reference_rect = util.the($reference).getBoundingClientRect();
|
||||||
// This is the logic we want but since it is too expensive to run
|
// This is the logic we want but since it is too expensive to run
|
||||||
// on every scroll, we run a cheaper version of this to just check if
|
// on every scroll, we run a cheaper version of this to just check if
|
||||||
// compose, sticky header or navbar are not obscuring the reference
|
// compose, sticky header or navbar are not obscuring the reference
|
||||||
|
|
|
@ -5,6 +5,7 @@ import * as tippy from "tippy.js";
|
||||||
|
|
||||||
import copy_to_clipboard_svg from "../../templates/copy_to_clipboard_svg.hbs";
|
import copy_to_clipboard_svg from "../../templates/copy_to_clipboard_svg.hbs";
|
||||||
import * as common from "../common";
|
import * as common from "../common";
|
||||||
|
import * as util from "../util";
|
||||||
|
|
||||||
import {activate_correct_tab} from "./tabbed-instructions";
|
import {activate_correct_tab} from "./tabbed-instructions";
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ function add_copy_to_clipboard_element($codehilite: JQuery): void {
|
||||||
|
|
||||||
$($codehilite).append($copy_button);
|
$($codehilite).append($copy_button);
|
||||||
|
|
||||||
const clipboard = new ClipboardJS($copy_button[0]!, {
|
const clipboard = new ClipboardJS(util.the($copy_button), {
|
||||||
text(copy_element) {
|
text(copy_element) {
|
||||||
// trim to remove trailing whitespace introduced
|
// trim to remove trailing whitespace introduced
|
||||||
// by additional elements inside <pre>
|
// by additional elements inside <pre>
|
||||||
|
@ -46,14 +47,14 @@ function add_copy_to_clipboard_element($codehilite: JQuery): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show a tippy tooltip when the button is hovered
|
// Show a tippy tooltip when the button is hovered
|
||||||
const tooltip_copy = tippy.default($copy_button[0]!, {
|
const tooltip_copy = tippy.default(util.the($copy_button), {
|
||||||
content: "Copy code",
|
content: "Copy code",
|
||||||
trigger: "mouseenter",
|
trigger: "mouseenter",
|
||||||
placement: "top",
|
placement: "top",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show a tippy tooltip when the code is copied
|
// Show a tippy tooltip when the code is copied
|
||||||
const tooltip_copied = tippy.default($copy_button[0]!, {
|
const tooltip_copied = tippy.default(util.the($copy_button), {
|
||||||
content: "Copied!",
|
content: "Copied!",
|
||||||
trigger: "manual",
|
trigger: "manual",
|
||||||
placement: "top",
|
placement: "top",
|
||||||
|
@ -89,7 +90,7 @@ function render_tabbed_sections(): void {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
new SimpleBar($(".sidebar")[0]!, {tabIndex: -1});
|
new SimpleBar(util.the($(".sidebar")), {tabIndex: -1});
|
||||||
|
|
||||||
// Scroll to anchor link when clicked. Note that landing-page.js has a
|
// Scroll to anchor link when clicked. Note that landing-page.js has a
|
||||||
// similar function; this file and landing-page.js are never included
|
// similar function; this file and landing-page.js are never included
|
||||||
|
|
|
@ -3,6 +3,7 @@ import assert from "minimalistic-assert";
|
||||||
import {z} from "zod";
|
import {z} from "zod";
|
||||||
|
|
||||||
import * as channel from "../channel";
|
import * as channel from "../channel";
|
||||||
|
import * as util from "../util";
|
||||||
// Main JavaScript file for the integrations development panel at
|
// Main JavaScript file for the integrations development panel at
|
||||||
// /devtools/integrations.
|
// /devtools/integrations.
|
||||||
|
|
||||||
|
@ -73,13 +74,13 @@ const clear_handlers: ClearHandlers = {
|
||||||
$("#fixture_name").empty();
|
$("#fixture_name").empty();
|
||||||
},
|
},
|
||||||
fixture_body() {
|
fixture_body() {
|
||||||
$<HTMLTextAreaElement>("textarea#fixture_body")[0]!.value = "";
|
util.the($<HTMLTextAreaElement>("textarea#fixture_body")).value = "";
|
||||||
},
|
},
|
||||||
custom_http_headers() {
|
custom_http_headers() {
|
||||||
$<HTMLTextAreaElement>("textarea#custom_http_headers")[0]!.value = "{}";
|
util.the($<HTMLTextAreaElement>("textarea#custom_http_headers")).value = "{}";
|
||||||
},
|
},
|
||||||
results() {
|
results() {
|
||||||
$<HTMLTextAreaElement>("textarea#idp-results")[0]!.value = "";
|
util.the($<HTMLTextAreaElement>("textarea#idp-results")).value = "";
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,7 +154,7 @@ function set_results(response: ServerResponse): void {
|
||||||
}
|
}
|
||||||
data += "\nResponse: " + response.message + "\n\n";
|
data += "\nResponse: " + response.message + "\n\n";
|
||||||
}
|
}
|
||||||
$<HTMLTextAreaElement>("textarea#idp-results")[0]!.value = data;
|
util.the($<HTMLTextAreaElement>("textarea#idp-results")).value = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function load_fixture_body(fixture_name: string): void {
|
function load_fixture_body(fixture_name: string): void {
|
||||||
|
@ -173,8 +174,8 @@ function load_fixture_body(fixture_name: string): void {
|
||||||
fixture_body = JSON.stringify(fixture_body, null, 4);
|
fixture_body = JSON.stringify(fixture_body, null, 4);
|
||||||
}
|
}
|
||||||
assert(typeof fixture_body === "string");
|
assert(typeof fixture_body === "string");
|
||||||
$<HTMLTextAreaElement>("textarea#fixture_body")[0]!.value = fixture_body;
|
util.the($<HTMLTextAreaElement>("textarea#fixture_body")).value = fixture_body;
|
||||||
$<HTMLTextAreaElement>("textarea#custom_http_headers")[0]!.value = JSON.stringify(
|
util.the($<HTMLTextAreaElement>("textarea#custom_http_headers")).value = JSON.stringify(
|
||||||
headers,
|
headers,
|
||||||
null,
|
null,
|
||||||
4,
|
4,
|
||||||
|
@ -187,9 +188,9 @@ function load_fixture_options(integration_name: string): void {
|
||||||
/* Using the integration name and loaded_fixtures object to set
|
/* Using the integration name and loaded_fixtures object to set
|
||||||
the fixture options for the fixture_names dropdown and also set
|
the fixture options for the fixture_names dropdown and also set
|
||||||
the fixture body to the first fixture by default. */
|
the fixture body to the first fixture by default. */
|
||||||
const fixtures_options_dropdown = $<HTMLSelectOneElement>(
|
const fixtures_options_dropdown = util.the(
|
||||||
"select:not([multiple])#fixture_name",
|
$<HTMLSelectOneElement>("select:not([multiple])#fixture_name"),
|
||||||
)[0]!;
|
);
|
||||||
const fixtures = loaded_fixtures.get(integration_name);
|
const fixtures = loaded_fixtures.get(integration_name);
|
||||||
assert(fixtures !== undefined);
|
assert(fixtures !== undefined);
|
||||||
const fixtures_names = Object.keys(fixtures).sort();
|
const fixtures_names = Object.keys(fixtures).sort();
|
||||||
|
@ -396,10 +397,12 @@ $(() => {
|
||||||
"results",
|
"results",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$<HTMLInputElement>("input#stream_name")[0]!.value = "Denmark";
|
util.the($<HTMLInputElement>("input#stream_name")).value = "Denmark";
|
||||||
$<HTMLInputElement>("input#topic_name")[0]!.value = "Integrations testing";
|
util.the($<HTMLInputElement>("input#topic_name")).value = "Integrations testing";
|
||||||
|
|
||||||
const potential_default_bot = $<HTMLSelectOneElement>("select:not([multiple])#bot_name")[0]![1];
|
const potential_default_bot = util.the(
|
||||||
|
$<HTMLSelectOneElement>("select:not([multiple])#bot_name"),
|
||||||
|
)[1];
|
||||||
assert(potential_default_bot instanceof HTMLOptionElement);
|
assert(potential_default_bot instanceof HTMLOptionElement);
|
||||||
if (potential_default_bot !== undefined) {
|
if (potential_default_bot !== undefined) {
|
||||||
potential_default_bot.selected = true;
|
potential_default_bot.selected = true;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import assert from "minimalistic-assert";
|
||||||
import {z} from "zod";
|
import {z} from "zod";
|
||||||
|
|
||||||
import {page_params} from "../base_page_params";
|
import {page_params} from "../base_page_params";
|
||||||
|
import * as util from "../util";
|
||||||
|
|
||||||
import type {UserOS} from "./tabbed-instructions";
|
import type {UserOS} from "./tabbed-instructions";
|
||||||
import {detect_user_os} from "./tabbed-instructions";
|
import {detect_user_os} from "./tabbed-instructions";
|
||||||
|
@ -271,7 +272,7 @@ $(document).on("click", ".comparison-tab", function (this: HTMLElement) {
|
||||||
|
|
||||||
const tab_label = z
|
const tab_label = z
|
||||||
.enum(["tab-cloud", "tab-hosted", "tab-all"])
|
.enum(["tab-cloud", "tab-hosted", "tab-all"])
|
||||||
.parse($(this)[0]!.dataset.label);
|
.parse(util.the($(this)).dataset.label);
|
||||||
const plans_columns_count = plans_columns_counts[tab_label];
|
const plans_columns_count = plans_columns_counts[tab_label];
|
||||||
const visible_plans_id = `showing-${tab_label}`;
|
const visible_plans_id = `showing-${tab_label}`;
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import $ from "jquery";
|
||||||
|
|
||||||
import * as blueslip from "../blueslip";
|
import * as blueslip from "../blueslip";
|
||||||
import * as common from "../common";
|
import * as common from "../common";
|
||||||
|
import * as util from "../util";
|
||||||
|
|
||||||
export type UserOS = "android" | "ios" | "mac" | "windows" | "linux";
|
export type UserOS = "android" | "ios" | "mac" | "windows" | "linux";
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ export function activate_correct_tab($tabbed_section: JQuery): void {
|
||||||
const $active_list_items = $li.filter(".active");
|
const $active_list_items = $li.filter(".active");
|
||||||
if (!$active_list_items.length) {
|
if (!$active_list_items.length) {
|
||||||
$li.first().addClass("active");
|
$li.first().addClass("active");
|
||||||
const tab_key = $li.first()[0]!.dataset.tabKey;
|
const tab_key = util.the($li.first()).dataset.tabKey;
|
||||||
if (tab_key) {
|
if (tab_key) {
|
||||||
$blocks.filter("[data-tab-key=" + tab_key + "]").addClass("active");
|
$blocks.filter("[data-tab-key=" + tab_key + "]").addClass("active");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -13,6 +13,7 @@ import * as message_store from "./message_store";
|
||||||
import * as modals from "./modals";
|
import * as modals from "./modals";
|
||||||
import * as people from "./people";
|
import * as people from "./people";
|
||||||
import * as ui_report from "./ui_report";
|
import * as ui_report from "./ui_report";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
const read_receipts_api_response_schema = z.object({
|
const read_receipts_api_response_schema = z.object({
|
||||||
user_ids: z.array(z.number()),
|
user_ids: z.array(z.number()),
|
||||||
|
@ -89,7 +90,7 @@ export function show_user_list(message_id: number): void {
|
||||||
$("#read_receipts_modal .read_receipts_list").html(
|
$("#read_receipts_modal .read_receipts_list").html(
|
||||||
render_read_receipts(context),
|
render_read_receipts(context),
|
||||||
);
|
);
|
||||||
new SimpleBar($("#read_receipts_modal .modal__content")[0]!, {
|
new SimpleBar(util.the($("#read_receipts_modal .modal__content")), {
|
||||||
tabIndex: -1,
|
tabIndex: -1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ import * as unread from "./unread";
|
||||||
import {user_settings} from "./user_settings";
|
import {user_settings} from "./user_settings";
|
||||||
import * as user_status from "./user_status";
|
import * as user_status from "./user_status";
|
||||||
import * as user_topics from "./user_topics";
|
import * as user_topics from "./user_topics";
|
||||||
|
import * as util from "./util";
|
||||||
import * as views_util from "./views_util";
|
import * as views_util from "./views_util";
|
||||||
|
|
||||||
type Row = {
|
type Row = {
|
||||||
|
@ -327,7 +328,7 @@ function set_table_focus(row: number, col: number, using_keyboard = false): bool
|
||||||
$current_focus_elem = "table";
|
$current_focus_elem = "table";
|
||||||
|
|
||||||
if (using_keyboard) {
|
if (using_keyboard) {
|
||||||
const scroll_element = $("html")[0]!;
|
const scroll_element = util.the($("html"));
|
||||||
const half_height_of_visible_area = scroll_element.offsetHeight / 2;
|
const half_height_of_visible_area = scroll_element.offsetHeight / 2;
|
||||||
const topic_offset = topic_offset_to_visible_area($topic_row);
|
const topic_offset = topic_offset_to_visible_area($topic_row);
|
||||||
|
|
||||||
|
@ -1148,10 +1149,10 @@ function topic_offset_to_visible_area($topic_row: JQuery): string | undefined {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rows are only visible below thead bottom and above compose top.
|
// Rows are only visible below thead bottom and above compose top.
|
||||||
const thead_bottom = $("#recent-view-table-headers")[0]!.getBoundingClientRect().bottom;
|
const thead_bottom = util.the($("#recent-view-table-headers")).getBoundingClientRect().bottom;
|
||||||
const compose_top = window.innerHeight - $("#compose").outerHeight(true)!;
|
const compose_top = window.innerHeight - $("#compose").outerHeight(true)!;
|
||||||
|
|
||||||
const topic_props = $topic_row[0]!.getBoundingClientRect();
|
const topic_props = util.the($topic_row).getBoundingClientRect();
|
||||||
|
|
||||||
// Topic is above the visible scroll region.
|
// Topic is above the visible scroll region.
|
||||||
if (topic_props.top < thead_bottom) {
|
if (topic_props.top < thead_bottom) {
|
||||||
|
@ -1185,7 +1186,7 @@ function recenter_focus_if_off_screen(): void {
|
||||||
|
|
||||||
if (topic_offset !== "visible") {
|
if (topic_offset !== "visible") {
|
||||||
// Get the element at the center of the table.
|
// Get the element at the center of the table.
|
||||||
const thead_props = $("#recent-view-table-headers")[0]!.getBoundingClientRect();
|
const thead_props = util.the($("#recent-view-table-headers")).getBoundingClientRect();
|
||||||
const compose_top = window.innerHeight - $("#compose").outerHeight(true)!;
|
const compose_top = window.innerHeight - $("#compose").outerHeight(true)!;
|
||||||
const topic_center_x = (thead_props.left + thead_props.right) / 2;
|
const topic_center_x = (thead_props.left + thead_props.right) / 2;
|
||||||
const topic_center_y = (thead_props.bottom + compose_top) / 2;
|
const topic_center_y = (thead_props.bottom + compose_top) / 2;
|
||||||
|
@ -1477,7 +1478,7 @@ function down_arrow_navigation(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_page_up_down_delta(): number {
|
function get_page_up_down_delta(): number {
|
||||||
const thead_bottom = $("#recent-view-table-headers")[0]!.getBoundingClientRect().bottom;
|
const thead_bottom = util.the($("#recent-view-table-headers")).getBoundingClientRect().bottom;
|
||||||
const compose_box_top = window.innerHeight - $("#compose").outerHeight(true)!;
|
const compose_box_top = window.innerHeight - $("#compose").outerHeight(true)!;
|
||||||
// One usually wants PageDown to move what had been the bottom row
|
// One usually wants PageDown to move what had been the bottom row
|
||||||
// to now be at the top, so one can be confident one will see
|
// to now be at the top, so one can be confident one will see
|
||||||
|
|
|
@ -312,7 +312,7 @@ export const update_elements = ($content: JQuery): void => {
|
||||||
$view_in_playground_button.attr("aria-label", title);
|
$view_in_playground_button.attr("aria-label", title);
|
||||||
}
|
}
|
||||||
const $copy_button = $buttonContainer.find(".copy_codeblock");
|
const $copy_button = $buttonContainer.find(".copy_codeblock");
|
||||||
const clipboard = new ClipboardJS($copy_button[0]!, {
|
const clipboard = new ClipboardJS(util.the($copy_button), {
|
||||||
text(copy_element) {
|
text(copy_element) {
|
||||||
const $code = $(copy_element).parent().siblings("code");
|
const $code = $(copy_element).parent().siblings("code");
|
||||||
return $code.text();
|
return $code.text();
|
||||||
|
@ -320,7 +320,7 @@ export const update_elements = ($content: JQuery): void => {
|
||||||
});
|
});
|
||||||
|
|
||||||
clipboard.on("success", () => {
|
clipboard.on("success", () => {
|
||||||
show_copied_confirmation($copy_button[0]!);
|
show_copied_confirmation(util.the($copy_button));
|
||||||
});
|
});
|
||||||
$codehilite.addClass("zulip-code-block");
|
$codehilite.addClass("zulip-code-block");
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import SimpleBar from "simplebar";
|
import SimpleBar from "simplebar";
|
||||||
|
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
// This type is helpful for testing, where we may have a dummy object instead of an actual jquery object.
|
// This type is helpful for testing, where we may have a dummy object instead of an actual jquery object.
|
||||||
type JQueryOrZJQuery = {__zjquery?: true} & JQuery;
|
type JQueryOrZJQuery = {__zjquery?: true} & JQuery;
|
||||||
|
|
||||||
export function get_content_element($element: JQuery): JQuery {
|
export function get_content_element($element: JQuery): JQuery {
|
||||||
const element = $element.expectOne()[0]!;
|
const element = util.the($element);
|
||||||
const sb = SimpleBar.instances.get(element);
|
const sb = SimpleBar.instances.get(element);
|
||||||
if (sb) {
|
if (sb) {
|
||||||
return $(sb.getContentElement()!);
|
return $(sb.getContentElement()!);
|
||||||
|
@ -19,7 +21,7 @@ export function get_scroll_element($element: JQueryOrZJQuery): JQuery {
|
||||||
return $element;
|
return $element;
|
||||||
}
|
}
|
||||||
|
|
||||||
const element = $element.expectOne()[0]!;
|
const element = util.the($element);
|
||||||
const sb = SimpleBar.instances.get(element);
|
const sb = SimpleBar.instances.get(element);
|
||||||
if (sb) {
|
if (sb) {
|
||||||
return $(sb.getScrollElement()!);
|
return $(sb.getScrollElement()!);
|
||||||
|
@ -32,7 +34,7 @@ export function get_scroll_element($element: JQueryOrZJQuery): JQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function reset_scrollbar($element: JQuery): void {
|
export function reset_scrollbar($element: JQuery): void {
|
||||||
const element = $element.expectOne()[0]!;
|
const element = util.the($element);
|
||||||
const sb = SimpleBar.instances.get(element);
|
const sb = SimpleBar.instances.get(element);
|
||||||
if (sb) {
|
if (sb) {
|
||||||
sb.getScrollElement()!.scrollTop = 0;
|
sb.getScrollElement()!.scrollTop = 0;
|
||||||
|
|
|
@ -12,6 +12,7 @@ import type {User} from "./people";
|
||||||
import type {NarrowTerm} from "./state_data";
|
import type {NarrowTerm} from "./state_data";
|
||||||
import * as user_status from "./user_status";
|
import * as user_status from "./user_status";
|
||||||
import type {UserStatusEmojiInfo} from "./user_status";
|
import type {UserStatusEmojiInfo} from "./user_status";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
export type SearchUserPill = {
|
export type SearchUserPill = {
|
||||||
type: "search_user";
|
type: "search_user";
|
||||||
|
@ -40,9 +41,7 @@ type SearchPill =
|
||||||
export type SearchPillWidget = InputPillContainer<SearchPill>;
|
export type SearchPillWidget = InputPillContainer<SearchPill>;
|
||||||
|
|
||||||
export function create_item_from_search_string(search_string: string): SearchPill | undefined {
|
export function create_item_from_search_string(search_string: string): SearchPill | undefined {
|
||||||
const search_terms = Filter.parse(search_string);
|
const search_term = util.the(Filter.parse(search_string));
|
||||||
assert(search_terms.length === 1);
|
|
||||||
const search_term = search_terms[0]!;
|
|
||||||
if (!Filter.is_valid_search_term(search_term)) {
|
if (!Filter.is_valid_search_term(search_term)) {
|
||||||
// This will cause pill validation to fail and trigger a shake animation.
|
// This will cause pill validation to fail and trigger a shake animation.
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -73,7 +72,7 @@ function on_pill_exit(
|
||||||
if (!$user_pill_container.length) {
|
if (!$user_pill_container.length) {
|
||||||
// This is just a regular search pill, so we don't need to do fancy logic.
|
// This is just a regular search pill, so we don't need to do fancy logic.
|
||||||
const $clicked_pill = $(clicked_element).closest(".pill");
|
const $clicked_pill = $(clicked_element).closest(".pill");
|
||||||
remove_pill($clicked_pill[0]!);
|
remove_pill(util.the($clicked_pill));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The user-pill-container container class is used exclusively for
|
// The user-pill-container container class is used exclusively for
|
||||||
|
@ -92,8 +91,8 @@ function on_pill_exit(
|
||||||
|
|
||||||
// If there's only one user in this pill, delete the whole pill.
|
// If there's only one user in this pill, delete the whole pill.
|
||||||
if (user_container_pill.users.length === 1) {
|
if (user_container_pill.users.length === 1) {
|
||||||
assert(user_container_pill.users[0]!.user_id === user_id);
|
assert(util.the(user_container_pill.users).user_id === user_id);
|
||||||
remove_pill($user_pill_container[0]!);
|
remove_pill(util.the($user_pill_container));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -390,7 +390,7 @@ function read_select_field_data_from_form(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$profile_field_form.find("div.choice-row").each(function (this: HTMLElement) {
|
$profile_field_form.find("div.choice-row").each(function (this: HTMLElement) {
|
||||||
const text = $(this).find("input")[0]!.value;
|
const text = util.the($(this).find("input")).value;
|
||||||
if (text) {
|
if (text) {
|
||||||
let value = old_option_value_map.get(text);
|
let value = old_option_value_map.get(text);
|
||||||
if (value !== undefined) {
|
if (value !== undefined) {
|
||||||
|
@ -729,7 +729,7 @@ export function get_auth_method_list_data(): Record<string, boolean> {
|
||||||
for (const method_row of $auth_method_rows) {
|
for (const method_row of $auth_method_rows) {
|
||||||
const method = $(method_row).attr("data-method");
|
const method = $(method_row).attr("data-method");
|
||||||
assert(method !== undefined);
|
assert(method !== undefined);
|
||||||
new_auth_methods[method] = $(method_row).find<HTMLInputElement>("input")[0]!.checked;
|
new_auth_methods[method] = util.the($(method_row).find<HTMLInputElement>("input")).checked;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_auth_methods;
|
return new_auth_methods;
|
||||||
|
@ -1305,7 +1305,7 @@ function enable_or_disable_save_button($subsection_elem: JQuery): void {
|
||||||
const $button_wrapper = $subsection_elem.find<tippy.PopperElement>(
|
const $button_wrapper = $subsection_elem.find<tippy.PopperElement>(
|
||||||
".subsection-changes-save",
|
".subsection-changes-save",
|
||||||
);
|
);
|
||||||
const tippy_instance = $button_wrapper[0]!._tippy;
|
const tippy_instance = util.the($button_wrapper)._tippy;
|
||||||
if (disable_save_btn) {
|
if (disable_save_btn) {
|
||||||
// avoid duplication of tippy
|
// avoid duplication of tippy
|
||||||
if (!tippy_instance) {
|
if (!tippy_instance) {
|
||||||
|
@ -1343,5 +1343,5 @@ export function initialize_disable_btn_hint_popover(
|
||||||
if (hint_text !== undefined) {
|
if (hint_text !== undefined) {
|
||||||
tippy_opts.content = hint_text;
|
tippy_opts.content = hint_text;
|
||||||
}
|
}
|
||||||
tippy.default($btn_wrapper[0]!, tippy_opts);
|
tippy.default(util.the($btn_wrapper), tippy_opts);
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,7 +265,7 @@ function show_modal(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
const files = $<HTMLInputElement>("input#emoji_file_input")[0]!.files;
|
const files = util.the($<HTMLInputElement>("input#emoji_file_input")).files;
|
||||||
assert(files !== null);
|
assert(files !== null);
|
||||||
for (const [i, file] of [...files].entries()) {
|
for (const [i, file] of [...files].entries()) {
|
||||||
formData.append("file-" + i, file);
|
formData.append("file-" + i, file);
|
||||||
|
|
|
@ -17,6 +17,7 @@ import * as settings_ui from "./settings_ui";
|
||||||
import {current_user, realm} from "./state_data";
|
import {current_user, realm} from "./state_data";
|
||||||
import * as ui_report from "./ui_report";
|
import * as ui_report from "./ui_report";
|
||||||
import * as ui_util from "./ui_util";
|
import * as ui_util from "./ui_util";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
type RealmLinkifiers = typeof realm.realm_linkifiers;
|
type RealmLinkifiers = typeof realm.realm_linkifiers;
|
||||||
|
|
||||||
|
@ -108,7 +109,7 @@ function open_linkifier_edit_form(linkifier_id: number): void {
|
||||||
submit_linkifier_form(dialog_widget_id);
|
submit_linkifier_form(dialog_widget_id);
|
||||||
},
|
},
|
||||||
on_shown() {
|
on_shown() {
|
||||||
ui_util.place_caret_at_end($("#edit-linkifier-pattern")[0]!);
|
ui_util.place_caret_at_end(util.the($("#edit-linkifier-pattern")));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -197,7 +198,7 @@ export function populate_linkifiers(linkifiers_data: RealmLinkifiers): void {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (current_user.is_admin) {
|
if (current_user.is_admin) {
|
||||||
new SortableJS($linkifiers_table[0]!, {
|
new SortableJS(util.the($linkifiers_table), {
|
||||||
onUpdate: update_linkifiers_order,
|
onUpdate: update_linkifiers_order,
|
||||||
handle: ".move-handle",
|
handle: ".move-handle",
|
||||||
filter: "input",
|
filter: "input",
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {current_user, realm} from "./state_data";
|
||||||
import type {HTMLSelectOneElement} from "./types";
|
import type {HTMLSelectOneElement} from "./types";
|
||||||
import * as ui_report from "./ui_report";
|
import * as ui_report from "./ui_report";
|
||||||
import {place_caret_at_end} from "./ui_util";
|
import {place_caret_at_end} from "./ui_util";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
type FieldChoice = {
|
type FieldChoice = {
|
||||||
value: string;
|
value: string;
|
||||||
|
@ -424,7 +425,7 @@ function set_up_select_field_edit_form(
|
||||||
|
|
||||||
// Add blank choice at last
|
// Add blank choice at last
|
||||||
create_choice_row($choice_list);
|
create_choice_row($choice_list);
|
||||||
SortableJS.create($choice_list[0]!, {
|
SortableJS.create(util.the($choice_list), {
|
||||||
onUpdate() {
|
onUpdate() {
|
||||||
// Do nothing on drag. We process the order on submission
|
// Do nothing on drag. We process the order on submission
|
||||||
},
|
},
|
||||||
|
@ -577,7 +578,7 @@ function open_edit_form_modal(this: HTMLElement): void {
|
||||||
post_render: set_initial_values_of_profile_field,
|
post_render: set_initial_values_of_profile_field,
|
||||||
loading_spinner: true,
|
loading_spinner: true,
|
||||||
on_shown() {
|
on_shown() {
|
||||||
place_caret_at_end($("#id-custom-profile-field-name")[0]!);
|
place_caret_at_end(util.the($("#id-custom-profile-field-name")));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -709,7 +710,7 @@ export function do_populate_profile_fields(profile_fields_data: CustomProfileFie
|
||||||
display_in_profile_summary_fields_limit_reached = display_in_profile_summary_fields_count >= 2;
|
display_in_profile_summary_fields_limit_reached = display_in_profile_summary_fields_count >= 2;
|
||||||
|
|
||||||
if (current_user.is_admin) {
|
if (current_user.is_admin) {
|
||||||
const field_list = $("#admin_profile_fields_table")[0]!;
|
const field_list = util.the($("#admin_profile_fields_table"));
|
||||||
SortableJS.create(field_list, {
|
SortableJS.create(field_list, {
|
||||||
onUpdate: update_field_order,
|
onUpdate: update_field_order,
|
||||||
filter: "input",
|
filter: "input",
|
||||||
|
@ -727,7 +728,7 @@ function set_up_select_field(): void {
|
||||||
create_choice_row($("#profile_field_choices"));
|
create_choice_row($("#profile_field_choices"));
|
||||||
|
|
||||||
if (current_user.is_admin) {
|
if (current_user.is_admin) {
|
||||||
const choice_list = $("#profile_field_choices")[0]!;
|
const choice_list = util.the($("#profile_field_choices"));
|
||||||
SortableJS.create(choice_list, {
|
SortableJS.create(choice_list, {
|
||||||
onUpdate() {
|
onUpdate() {
|
||||||
// Do nothing on drag. We process the order on submission
|
// Do nothing on drag. We process the order on submission
|
||||||
|
|
|
@ -8,6 +8,7 @@ import * as dialog_widget from "./dialog_widget";
|
||||||
import {$t_html} from "./i18n";
|
import {$t_html} from "./i18n";
|
||||||
import {realm} from "./state_data";
|
import {realm} from "./state_data";
|
||||||
import * as ui_report from "./ui_report";
|
import * as ui_report from "./ui_report";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
type RealmDomain = {
|
type RealmDomain = {
|
||||||
domain: string;
|
domain: string;
|
||||||
|
@ -112,9 +113,9 @@ export function setup_realm_domains_modal_handlers(): void {
|
||||||
const $realm_domains_info = $(".realm_domains_info");
|
const $realm_domains_info = $(".realm_domains_info");
|
||||||
const $widget = $("#add-realm-domain-widget");
|
const $widget = $("#add-realm-domain-widget");
|
||||||
const domain = $widget.find(".new-realm-domain").val();
|
const domain = $widget.find(".new-realm-domain").val();
|
||||||
const allow_subdomains = $widget.find<HTMLInputElement>(
|
const allow_subdomains = util.the(
|
||||||
"input.new-realm-domain-allow-subdomains",
|
$widget.find<HTMLInputElement>("input.new-realm-domain-allow-subdomains"),
|
||||||
)[0]!.checked;
|
).checked;
|
||||||
const data = {
|
const data = {
|
||||||
domain,
|
domain,
|
||||||
allow_subdomains: JSON.stringify(allow_subdomains),
|
allow_subdomains: JSON.stringify(allow_subdomains),
|
||||||
|
|
|
@ -2,6 +2,7 @@ import $ from "jquery";
|
||||||
|
|
||||||
import * as blueslip from "./blueslip";
|
import * as blueslip from "./blueslip";
|
||||||
import * as loading from "./loading";
|
import * as loading from "./loading";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
export let page_load_time: number | undefined;
|
export let page_load_time: number | undefined;
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ $(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
$.fn.get_offset_to_window = function () {
|
$.fn.get_offset_to_window = function () {
|
||||||
return this[0]!.getBoundingClientRect();
|
return util.the(this).getBoundingClientRect();
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.expectOne = function () {
|
$.fn.expectOne = function () {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
function collapse_spoiler($spoiler: JQuery): void {
|
function collapse_spoiler($spoiler: JQuery): void {
|
||||||
const spoiler_height = $spoiler.height() ?? 0;
|
const spoiler_height = $spoiler.height() ?? 0;
|
||||||
|
|
||||||
|
@ -21,7 +23,7 @@ function expand_spoiler($spoiler: JQuery): void {
|
||||||
// of the content). CSS animations do not work with properties set to
|
// of the content). CSS animations do not work with properties set to
|
||||||
// `auto`, so we get the actual height of the content here and temporarily
|
// `auto`, so we get the actual height of the content here and temporarily
|
||||||
// put it explicitly on the element styling to allow the transition to work.
|
// put it explicitly on the element styling to allow the transition to work.
|
||||||
const spoiler_height = $spoiler[0]!.scrollHeight;
|
const spoiler_height = util.the($spoiler).scrollHeight;
|
||||||
$spoiler.height(`${spoiler_height}px`);
|
$spoiler.height(`${spoiler_height}px`);
|
||||||
// The `spoiler-content-open` class has CSS animations defined on it which
|
// The `spoiler-content-open` class has CSS animations defined on it which
|
||||||
// will trigger on the frame after this class change.
|
// will trigger on the frame after this class change.
|
||||||
|
|
|
@ -14,6 +14,7 @@ import * as settings_config from "./settings_config";
|
||||||
import * as stream_data from "./stream_data";
|
import * as stream_data from "./stream_data";
|
||||||
import * as ui_util from "./ui_util";
|
import * as ui_util from "./ui_util";
|
||||||
import {user_settings} from "./user_settings";
|
import {user_settings} from "./user_settings";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
// For tooltips without data-tippy-content, we use the HTML content of
|
// For tooltips without data-tippy-content, we use the HTML content of
|
||||||
// a <template> whose id is given by data-tooltip-template-id.
|
// a <template> whose id is given by data-tooltip-template-id.
|
||||||
|
@ -353,7 +354,7 @@ export function initialize(): void {
|
||||||
const second_line = $t({defaultMessage: "File name: {filename}"}, {filename});
|
const second_line = $t({defaultMessage: "File name: {filename}"}, {filename});
|
||||||
$markup.append($("<br>"), $("<span>").text(second_line));
|
$markup.append($("<br>"), $("<span>").text(second_line));
|
||||||
}
|
}
|
||||||
instance.setContent($markup[0]!);
|
instance.setContent(util.the($markup));
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
onHidden(instance) {
|
onHidden(instance) {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {$t} from "./i18n";
|
import {$t} from "./i18n";
|
||||||
|
import * as util from "./util";
|
||||||
|
|
||||||
export type UploadWidget = {
|
export type UploadWidget = {
|
||||||
clear: () => void;
|
clear: () => void;
|
||||||
|
@ -83,7 +84,7 @@ export function build_widget(
|
||||||
if (files === null || files === undefined || files.length === 0) {
|
if (files === null || files === undefined || files.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
get_file_input()[0]!.files = files;
|
util.the(get_file_input()).files = files;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
@ -171,7 +172,7 @@ export function build_direct_upload_widget(
|
||||||
if (files === null || files === undefined || files.length === 0) {
|
if (files === null || files === undefined || files.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
get_file_input()[0]!.files = files;
|
util.the(get_file_input()).files = files;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -745,9 +745,9 @@ export function show_edit_bot_info_modal(user_id: number, $container: JQuery): v
|
||||||
formData.append("config_data", JSON.stringify(config_data));
|
formData.append("config_data", JSON.stringify(config_data));
|
||||||
}
|
}
|
||||||
|
|
||||||
const files = $("#bot-edit-form").find<HTMLInputElement>(
|
const files = util.the(
|
||||||
"input.edit_bot_avatar_file_input",
|
$("#bot-edit-form").find<HTMLInputElement>("input.edit_bot_avatar_file_input"),
|
||||||
)[0]!.files;
|
).files;
|
||||||
assert(files !== null);
|
assert(files !== null);
|
||||||
for (const [i, file] of [...files].entries()) {
|
for (const [i, file] of [...files].entries()) {
|
||||||
formData.append("file-" + i, file);
|
formData.append("file-" + i, file);
|
||||||
|
|
|
@ -47,6 +47,7 @@ function make_textbox(s) {
|
||||||
const $widget = {};
|
const $widget = {};
|
||||||
|
|
||||||
$widget.s = s;
|
$widget.s = s;
|
||||||
|
$widget.length = 1;
|
||||||
$widget[0] = "textarea";
|
$widget[0] = "textarea";
|
||||||
$widget.focused = false;
|
$widget.focused = false;
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,7 @@ function set_up() {
|
||||||
const $pill_input = $.create("pill_input");
|
const $pill_input = $.create("pill_input");
|
||||||
|
|
||||||
$pill_input[0] = {};
|
$pill_input[0] = {};
|
||||||
|
$pill_input.length = 1;
|
||||||
$pill_input.before = noop;
|
$pill_input.before = noop;
|
||||||
|
|
||||||
const create_item_from_text = (text) => items[text];
|
const create_item_from_text = (text) => items[text];
|
||||||
|
@ -115,6 +116,7 @@ run_test("copy from pill", ({mock_template}) => {
|
||||||
mock_template("input_pill.hbs", true, (data, html) => {
|
mock_template("input_pill.hbs", true, (data, html) => {
|
||||||
assert.ok(["BLUE", "RED"].includes(data.display_value));
|
assert.ok(["BLUE", "RED"].includes(data.display_value));
|
||||||
$(html)[0] = `<pill-stub ${data.display_value}>`;
|
$(html)[0] = `<pill-stub ${data.display_value}>`;
|
||||||
|
$(html).length = 1;
|
||||||
return html;
|
return html;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -350,6 +352,7 @@ run_test("insert_remove", ({mock_template}) => {
|
||||||
mock_template("input_pill.hbs", true, (data, html) => {
|
mock_template("input_pill.hbs", true, (data, html) => {
|
||||||
assert.equal(typeof data.display_value, "string");
|
assert.equal(typeof data.display_value, "string");
|
||||||
assert.ok(html.startsWith, "<div class='pill'");
|
assert.ok(html.startsWith, "<div class='pill'");
|
||||||
|
$(html).length = 1;
|
||||||
$(html)[0] = `<pill-stub ${data.display_value}>`;
|
$(html)[0] = `<pill-stub ${data.display_value}>`;
|
||||||
return html;
|
return html;
|
||||||
});
|
});
|
||||||
|
@ -437,6 +440,7 @@ run_test("insert_remove", ({mock_template}) => {
|
||||||
const $focus_pill_stub = {
|
const $focus_pill_stub = {
|
||||||
next: () => $next_pill_stub,
|
next: () => $next_pill_stub,
|
||||||
[0]: "<pill-stub BLUE>",
|
[0]: "<pill-stub BLUE>",
|
||||||
|
length: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
$container.set_find_results(".pill:focus", $focus_pill_stub);
|
$container.set_find_results(".pill:focus", $focus_pill_stub);
|
||||||
|
@ -456,6 +460,7 @@ run_test("exit button on pill", ({mock_template}) => {
|
||||||
assert.equal(typeof data.display_value, "string");
|
assert.equal(typeof data.display_value, "string");
|
||||||
assert.ok(html.startsWith, "<div class='pill'");
|
assert.ok(html.startsWith, "<div class='pill'");
|
||||||
$(html)[0] = `<pill-stub ${data.display_value}>`;
|
$(html)[0] = `<pill-stub ${data.display_value}>`;
|
||||||
|
$(html).length = 1;
|
||||||
return html;
|
return html;
|
||||||
});
|
});
|
||||||
$(".narrow_to_compose_recipients").toggleClass = noop;
|
$(".narrow_to_compose_recipients").toggleClass = noop;
|
||||||
|
@ -477,6 +482,7 @@ run_test("exit button on pill", ({mock_template}) => {
|
||||||
|
|
||||||
const $curr_pill_stub = {
|
const $curr_pill_stub = {
|
||||||
[0]: "<pill-stub BLUE>",
|
[0]: "<pill-stub BLUE>",
|
||||||
|
length: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const exit_button_stub = {
|
const exit_button_stub = {
|
||||||
|
@ -559,6 +565,7 @@ run_test("appendValue/clear", ({mock_template}) => {
|
||||||
|
|
||||||
$pill_input.before = noop;
|
$pill_input.before = noop;
|
||||||
$pill_input[0] = {};
|
$pill_input[0] = {};
|
||||||
|
$pill_input.length = 1;
|
||||||
|
|
||||||
const widget = input_pill.create(config);
|
const widget = input_pill.create(config);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ function FakeElement(selector, opts) {
|
||||||
const event_store = make_event_store(selector);
|
const event_store = make_event_store(selector);
|
||||||
|
|
||||||
const $self = {
|
const $self = {
|
||||||
|
length: 1,
|
||||||
[0]: {textContent: text},
|
[0]: {textContent: text},
|
||||||
*[Symbol.iterator]() {
|
*[Symbol.iterator]() {
|
||||||
// eslint-disable-next-line unicorn/no-for-loop
|
// eslint-disable-next-line unicorn/no-for-loop
|
||||||
|
|
Loading…
Reference in New Issue