giphy: Convert module to TypeScript.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2024-11-13 00:39:27 -08:00 committed by Tim Abbott
parent c4ad9d8e09
commit e82b7641c6
8 changed files with 69 additions and 42 deletions

View File

@ -98,6 +98,7 @@
"@babel/eslint-parser": "^7.11.3",
"@babel/plugin-transform-modules-commonjs": "^7.19.6",
"@formatjs/cli": "^6.0.0",
"@giphy/js-types": "^5.1.0",
"@types/autosize": "^4.0.1",
"@types/blueimp-md5": "^2.18.0",
"@types/co-body": "^6.1.3",
@ -116,6 +117,7 @@
"@types/sortablejs": "^1.15.1",
"@types/spectrum": "^1.8.4",
"@types/textarea-caret": "^3.0.3",
"@types/throttle-debounce": "^5.0.2",
"@types/tinycolor2": "^1.4.5",
"@types/turndown": "^5.0.1",
"@typescript-eslint/eslint-plugin": "^8.2.0",
@ -141,6 +143,7 @@
"mockdate": "^3.0.2",
"nyc": "^17.0.0",
"openapi-examples-validator": "^5.0.0",
"preact": "^10.24.3",
"prettier": "^3.0.0",
"puppeteer": "^23.5.0",
"source-map": "npm:source-map-js@^1.2.1",

View File

@ -305,6 +305,9 @@ importers:
'@formatjs/cli':
specifier: ^6.0.0
version: 6.3.8
'@giphy/js-types':
specifier: ^5.1.0
version: 5.1.0
'@types/autosize':
specifier: ^4.0.1
version: 4.0.3
@ -359,6 +362,9 @@ importers:
'@types/textarea-caret':
specifier: ^3.0.3
version: 3.0.3
'@types/throttle-debounce':
specifier: ^5.0.2
version: 5.0.2
'@types/tinycolor2':
specifier: ^1.4.5
version: 1.4.6
@ -434,6 +440,9 @@ importers:
openapi-examples-validator:
specifier: ^5.0.0
version: 5.0.0
preact:
specifier: ^10.24.3
version: 10.24.3
prettier:
specifier: ^3.0.0
version: 3.3.3
@ -2481,6 +2490,9 @@ packages:
'@types/textarea-caret@3.0.3':
resolution: {integrity: sha512-bsA9GdXV1wQsXyDjS5+A+czz8IAR3haH5DU+KctIoXbzobRL2NOiwF/+EbB7pofAyudMytLj4ihPtbmbJT8FWw==}
'@types/throttle-debounce@5.0.2':
resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==}
'@types/tinycolor2@1.4.6':
resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
@ -11322,6 +11334,8 @@ snapshots:
'@types/textarea-caret@3.0.3': {}
'@types/throttle-debounce@5.0.2': {}
'@types/tinycolor2@1.4.6': {}
'@types/triple-beam@1.3.5': {}

View File

@ -109,7 +109,7 @@ EXEMPT_FILES = make_set(
"web/src/fetch_status.ts",
"web/src/flatpickr.ts",
"web/src/gear_menu.js",
"web/src/giphy.js",
"web/src/giphy.ts",
"web/src/giphy_state.ts",
"web/src/global.ts",
"web/src/group_setting_pill.ts",

View File

@ -49,4 +49,4 @@ API_FEATURE_LEVEL = 319 # Last bumped for message-link class
# historical commits sharing the same major version, in which case a
# minor version bump suffices.
PROVISION_VERSION = (301, 2) # bumped 2024-11-12 to patch handlebars
PROVISION_VERSION = (301, 3) # bumped 2024-11-13 for @giphy/js-types

View File

@ -1,5 +1,9 @@
import type {GifsResult, GiphyFetch, Rating} from "@giphy/js-fetch-api";
import type {IGif} from "@giphy/js-types";
import $ from "jquery";
import _ from "lodash";
import assert from "minimalistic-assert";
import type * as tippy from "tippy.js";
import render_giphy_picker from "../templates/giphy_picker.hbs";
@ -9,24 +13,26 @@ import * as popover_menus from "./popover_menus.ts";
import * as rows from "./rows.ts";
import {realm} from "./state_data.ts";
import * as ui_util from "./ui_util.ts";
import {the} from "./util.ts";
let giphy_fetch;
let giphy_fetch: GiphyFetch | undefined;
let search_term = "";
let gifs_grid;
let giphy_popover_instance = null;
let gifs_grid: {remove: () => void} | undefined;
let giphy_popover_instance: tippy.Instance | undefined;
// Only used if popover called from edit message, otherwise it is `undefined`.
let edit_message_id;
let edit_message_id: number | undefined;
export function is_popped_from_edit_message() {
return giphy_popover_instance && edit_message_id !== undefined;
export function is_popped_from_edit_message(): boolean {
return giphy_popover_instance !== undefined && edit_message_id !== undefined;
}
export function focus_current_edit_message() {
$(`#edit_form_${CSS.escape(edit_message_id)} .message_edit_content`).trigger("focus");
export function focus_current_edit_message(): void {
assert(edit_message_id !== undefined);
$(`#edit_form_${CSS.escape(`${edit_message_id}`)} .message_edit_content`).trigger("focus");
}
export function update_giphy_rating() {
export function update_giphy_rating(): void {
if (
realm.realm_giphy_rating === realm.giphy_rating_options.disabled.id ||
realm.giphy_api_key === ""
@ -37,10 +43,10 @@ export function update_giphy_rating() {
}
}
function get_rating() {
function get_rating(): Rating {
const options = realm.giphy_rating_options;
for (const rating in realm.giphy_rating_options) {
if (options[rating].id === realm.realm_giphy_rating) {
for (const rating of ["pg", "g", "y", "pg-13", "r"] as const) {
if (options[rating]?.id === realm.realm_giphy_rating) {
return rating;
}
}
@ -51,7 +57,7 @@ function get_rating() {
return "g";
}
async function renderGIPHYGrid(targetEl) {
async function renderGIPHYGrid(targetEl: HTMLElement): Promise<{remove: () => void}> {
const {renderGrid} = await import(/* webpackChunkName: "giphy-sdk" */ "@giphy/js-components");
const {GiphyFetch} = await import(/* webpackChunkName: "giphy-sdk" */ "@giphy/js-fetch-api");
@ -59,7 +65,8 @@ async function renderGIPHYGrid(targetEl) {
giphy_fetch = new GiphyFetch(realm.giphy_api_key);
}
function fetchGifs(offset) {
async function fetchGifs(offset: number): Promise<GifsResult> {
assert(giphy_fetch !== undefined);
const config = {
offset,
limit: 25,
@ -73,7 +80,7 @@ async function renderGIPHYGrid(targetEl) {
return giphy_fetch.search(search_term, config);
}
const render = () =>
const render = (): (() => void) =>
// See https://github.com/Giphy/giphy-js/blob/master/packages/components/README.md#grid
// for detailed documentation.
renderGrid(
@ -86,11 +93,11 @@ async function renderGIPHYGrid(targetEl) {
// Hide the creator attribution that appears over a
// GIF; nice in principle but too distracting.
hideAttribution: true,
onGifClick(props) {
let $textarea = $("textarea#compose-textarea");
onGifClick(props: IGif) {
let $textarea = $<HTMLTextAreaElement>("textarea#compose-textarea");
if (edit_message_id !== undefined) {
$textarea = $(
`#edit_form_${CSS.escape(edit_message_id)} .message_edit_content`,
`#edit_form_${CSS.escape(`${edit_message_id}`)} .message_edit_content`,
);
}
@ -120,18 +127,18 @@ async function renderGIPHYGrid(targetEl) {
};
}
async function update_grid_with_search_term() {
async function update_grid_with_search_term(): Promise<void> {
if (!gifs_grid) {
return;
}
const $search_elem = $("#giphy-search-query");
const $search_elem = $<HTMLInputElement>("input#giphy-search-query");
// GIPHY popover may have been hidden by the
// time this function is called.
if ($search_elem.length) {
search_term = $search_elem[0].value;
search_term = the($search_elem).value;
gifs_grid.remove();
gifs_grid = await renderGIPHYGrid($("#giphy_grid_in_popover .giphy-content")[0]);
gifs_grid = await renderGIPHYGrid(the($("#giphy_grid_in_popover .giphy-content")));
return;
}
@ -139,7 +146,7 @@ async function update_grid_with_search_term() {
gifs_grid = undefined;
}
export function hide_giphy_popover() {
export function hide_giphy_popover(): boolean {
// Returns `true` if the popover was open.
if (giphy_popover_instance) {
giphy_popover_instance.destroy();
@ -151,7 +158,7 @@ export function hide_giphy_popover() {
return false;
}
function toggle_giphy_popover(target) {
function toggle_giphy_popover(target: HTMLElement): void {
popover_menus.toggle_popover_menu(
target,
{
@ -161,10 +168,9 @@ function toggle_giphy_popover(target) {
instance.setContent(ui_util.parse_html(render_giphy_picker()));
$(instance.popper).addClass("giphy-popover");
},
async onShow(instance) {
onShow(instance) {
giphy_popover_instance = instance;
const $popper = $(giphy_popover_instance.popper).trigger("focus");
gifs_grid = await renderGIPHYGrid($popper.find(".giphy-content")[0]);
const $click_target = $(instance.reference);
if ($click_target.parents(".message_edit_form").length === 1) {
@ -186,22 +192,26 @@ function toggle_giphy_popover(target) {
// every search. This makes the UX of searching pleasant
// by allowing user to finish typing before search
// is executed.
_.debounce(update_grid_with_search_term, 300),
_.debounce(() => void update_grid_with_search_term(), 300),
);
$popper.on("keydown", ".giphy-gif", ui_util.convert_enter_to_click);
$popper.on("keydown", ".compose_gif_icon", ui_util.convert_enter_to_click);
$popper.on("click", "#giphy_search_clear", async (e) => {
$popper.on("click", "#giphy_search_clear", (e) => {
e.stopPropagation();
$("#giphy-search-query").val("");
await update_grid_with_search_term();
void update_grid_with_search_term();
});
void (async () => {
gifs_grid = await renderGIPHYGrid(the($popper.find(".giphy-content")));
// Focus on search box by default.
// This is specially helpful for users
// navigating via keyboard.
$("#giphy-search-query").trigger("focus");
})();
},
onHidden() {
hide_giphy_popover();
@ -214,12 +224,12 @@ function toggle_giphy_popover(target) {
);
}
function register_click_handlers() {
$("body").on("click", ".compose_control_button.compose_gif_icon", (e) => {
toggle_giphy_popover(e.currentTarget);
function register_click_handlers(): void {
$("body").on("click", ".compose_control_button.compose_gif_icon", function (this: HTMLElement) {
toggle_giphy_popover(this);
});
}
export function initialize() {
export function initialize(): void {
register_click_handlers();
}

View File

@ -21,7 +21,7 @@ import * as emoji from "./emoji.ts";
import * as emoji_picker from "./emoji_picker.ts";
import * as feedback_widget from "./feedback_widget.ts";
import * as gear_menu from "./gear_menu.js";
import * as giphy from "./giphy.js";
import * as giphy from "./giphy.ts";
import * as hash_util from "./hash_util.ts";
import * as hashchange from "./hashchange.js";
import * as inbox_ui from "./inbox_ui.ts";

View File

@ -20,7 +20,7 @@ import {electron_bridge} from "./electron_bridge.ts";
import * as emoji from "./emoji.ts";
import * as emoji_picker from "./emoji_picker.ts";
import * as gear_menu from "./gear_menu.js";
import * as giphy from "./giphy.js";
import * as giphy from "./giphy.ts";
import * as information_density from "./information_density.ts";
import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area.ts";
import * as linkifiers from "./linkifiers.ts";

View File

@ -44,7 +44,7 @@ import * as emoji from "./emoji.ts";
import * as emoji_picker from "./emoji_picker.ts";
import * as emojisets from "./emojisets.ts";
import * as gear_menu from "./gear_menu.js";
import * as giphy from "./giphy.js";
import * as giphy from "./giphy.ts";
import * as giphy_state from "./giphy_state.ts";
import * as hashchange from "./hashchange.js";
import * as hotkey from "./hotkey.js";