mirror of https://github.com/zulip/zulip.git
giphy: Convert module to TypeScript.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
parent
c4ad9d8e09
commit
e82b7641c6
|
@ -98,6 +98,7 @@
|
||||||
"@babel/eslint-parser": "^7.11.3",
|
"@babel/eslint-parser": "^7.11.3",
|
||||||
"@babel/plugin-transform-modules-commonjs": "^7.19.6",
|
"@babel/plugin-transform-modules-commonjs": "^7.19.6",
|
||||||
"@formatjs/cli": "^6.0.0",
|
"@formatjs/cli": "^6.0.0",
|
||||||
|
"@giphy/js-types": "^5.1.0",
|
||||||
"@types/autosize": "^4.0.1",
|
"@types/autosize": "^4.0.1",
|
||||||
"@types/blueimp-md5": "^2.18.0",
|
"@types/blueimp-md5": "^2.18.0",
|
||||||
"@types/co-body": "^6.1.3",
|
"@types/co-body": "^6.1.3",
|
||||||
|
@ -116,6 +117,7 @@
|
||||||
"@types/sortablejs": "^1.15.1",
|
"@types/sortablejs": "^1.15.1",
|
||||||
"@types/spectrum": "^1.8.4",
|
"@types/spectrum": "^1.8.4",
|
||||||
"@types/textarea-caret": "^3.0.3",
|
"@types/textarea-caret": "^3.0.3",
|
||||||
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@types/tinycolor2": "^1.4.5",
|
"@types/tinycolor2": "^1.4.5",
|
||||||
"@types/turndown": "^5.0.1",
|
"@types/turndown": "^5.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.2.0",
|
"@typescript-eslint/eslint-plugin": "^8.2.0",
|
||||||
|
@ -141,6 +143,7 @@
|
||||||
"mockdate": "^3.0.2",
|
"mockdate": "^3.0.2",
|
||||||
"nyc": "^17.0.0",
|
"nyc": "^17.0.0",
|
||||||
"openapi-examples-validator": "^5.0.0",
|
"openapi-examples-validator": "^5.0.0",
|
||||||
|
"preact": "^10.24.3",
|
||||||
"prettier": "^3.0.0",
|
"prettier": "^3.0.0",
|
||||||
"puppeteer": "^23.5.0",
|
"puppeteer": "^23.5.0",
|
||||||
"source-map": "npm:source-map-js@^1.2.1",
|
"source-map": "npm:source-map-js@^1.2.1",
|
||||||
|
|
|
@ -305,6 +305,9 @@ importers:
|
||||||
'@formatjs/cli':
|
'@formatjs/cli':
|
||||||
specifier: ^6.0.0
|
specifier: ^6.0.0
|
||||||
version: 6.3.8
|
version: 6.3.8
|
||||||
|
'@giphy/js-types':
|
||||||
|
specifier: ^5.1.0
|
||||||
|
version: 5.1.0
|
||||||
'@types/autosize':
|
'@types/autosize':
|
||||||
specifier: ^4.0.1
|
specifier: ^4.0.1
|
||||||
version: 4.0.3
|
version: 4.0.3
|
||||||
|
@ -359,6 +362,9 @@ importers:
|
||||||
'@types/textarea-caret':
|
'@types/textarea-caret':
|
||||||
specifier: ^3.0.3
|
specifier: ^3.0.3
|
||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
|
'@types/throttle-debounce':
|
||||||
|
specifier: ^5.0.2
|
||||||
|
version: 5.0.2
|
||||||
'@types/tinycolor2':
|
'@types/tinycolor2':
|
||||||
specifier: ^1.4.5
|
specifier: ^1.4.5
|
||||||
version: 1.4.6
|
version: 1.4.6
|
||||||
|
@ -434,6 +440,9 @@ importers:
|
||||||
openapi-examples-validator:
|
openapi-examples-validator:
|
||||||
specifier: ^5.0.0
|
specifier: ^5.0.0
|
||||||
version: 5.0.0
|
version: 5.0.0
|
||||||
|
preact:
|
||||||
|
specifier: ^10.24.3
|
||||||
|
version: 10.24.3
|
||||||
prettier:
|
prettier:
|
||||||
specifier: ^3.0.0
|
specifier: ^3.0.0
|
||||||
version: 3.3.3
|
version: 3.3.3
|
||||||
|
@ -2481,6 +2490,9 @@ packages:
|
||||||
'@types/textarea-caret@3.0.3':
|
'@types/textarea-caret@3.0.3':
|
||||||
resolution: {integrity: sha512-bsA9GdXV1wQsXyDjS5+A+czz8IAR3haH5DU+KctIoXbzobRL2NOiwF/+EbB7pofAyudMytLj4ihPtbmbJT8FWw==}
|
resolution: {integrity: sha512-bsA9GdXV1wQsXyDjS5+A+czz8IAR3haH5DU+KctIoXbzobRL2NOiwF/+EbB7pofAyudMytLj4ihPtbmbJT8FWw==}
|
||||||
|
|
||||||
|
'@types/throttle-debounce@5.0.2':
|
||||||
|
resolution: {integrity: sha512-pDzSNulqooSKvSNcksnV72nk8p7gRqN8As71Sp28nov1IgmPKWbOEIwAWvBME5pPTtaXJAvG3O4oc76HlQ4kqQ==}
|
||||||
|
|
||||||
'@types/tinycolor2@1.4.6':
|
'@types/tinycolor2@1.4.6':
|
||||||
resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
|
resolution: {integrity: sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==}
|
||||||
|
|
||||||
|
@ -11322,6 +11334,8 @@ snapshots:
|
||||||
|
|
||||||
'@types/textarea-caret@3.0.3': {}
|
'@types/textarea-caret@3.0.3': {}
|
||||||
|
|
||||||
|
'@types/throttle-debounce@5.0.2': {}
|
||||||
|
|
||||||
'@types/tinycolor2@1.4.6': {}
|
'@types/tinycolor2@1.4.6': {}
|
||||||
|
|
||||||
'@types/triple-beam@1.3.5': {}
|
'@types/triple-beam@1.3.5': {}
|
||||||
|
|
|
@ -109,7 +109,7 @@ EXEMPT_FILES = make_set(
|
||||||
"web/src/fetch_status.ts",
|
"web/src/fetch_status.ts",
|
||||||
"web/src/flatpickr.ts",
|
"web/src/flatpickr.ts",
|
||||||
"web/src/gear_menu.js",
|
"web/src/gear_menu.js",
|
||||||
"web/src/giphy.js",
|
"web/src/giphy.ts",
|
||||||
"web/src/giphy_state.ts",
|
"web/src/giphy_state.ts",
|
||||||
"web/src/global.ts",
|
"web/src/global.ts",
|
||||||
"web/src/group_setting_pill.ts",
|
"web/src/group_setting_pill.ts",
|
||||||
|
|
|
@ -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
|
# historical commits sharing the same major version, in which case a
|
||||||
# minor version bump suffices.
|
# 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
|
||||||
|
|
|
@ -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 "jquery";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import assert from "minimalistic-assert";
|
||||||
|
import type * as tippy from "tippy.js";
|
||||||
|
|
||||||
import render_giphy_picker from "../templates/giphy_picker.hbs";
|
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 * as rows from "./rows.ts";
|
||||||
import {realm} from "./state_data.ts";
|
import {realm} from "./state_data.ts";
|
||||||
import * as ui_util from "./ui_util.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 search_term = "";
|
||||||
let gifs_grid;
|
let gifs_grid: {remove: () => void} | undefined;
|
||||||
let giphy_popover_instance = null;
|
let giphy_popover_instance: tippy.Instance | undefined;
|
||||||
|
|
||||||
// Only used if popover called from edit message, otherwise it is `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() {
|
export function is_popped_from_edit_message(): boolean {
|
||||||
return giphy_popover_instance && edit_message_id !== undefined;
|
return giphy_popover_instance !== undefined && edit_message_id !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function focus_current_edit_message() {
|
export function focus_current_edit_message(): void {
|
||||||
$(`#edit_form_${CSS.escape(edit_message_id)} .message_edit_content`).trigger("focus");
|
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 (
|
if (
|
||||||
realm.realm_giphy_rating === realm.giphy_rating_options.disabled.id ||
|
realm.realm_giphy_rating === realm.giphy_rating_options.disabled.id ||
|
||||||
realm.giphy_api_key === ""
|
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;
|
const options = realm.giphy_rating_options;
|
||||||
for (const rating in realm.giphy_rating_options) {
|
for (const rating of ["pg", "g", "y", "pg-13", "r"] as const) {
|
||||||
if (options[rating].id === realm.realm_giphy_rating) {
|
if (options[rating]?.id === realm.realm_giphy_rating) {
|
||||||
return rating;
|
return rating;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +57,7 @@ function get_rating() {
|
||||||
return "g";
|
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 {renderGrid} = await import(/* webpackChunkName: "giphy-sdk" */ "@giphy/js-components");
|
||||||
const {GiphyFetch} = await import(/* webpackChunkName: "giphy-sdk" */ "@giphy/js-fetch-api");
|
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);
|
giphy_fetch = new GiphyFetch(realm.giphy_api_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchGifs(offset) {
|
async function fetchGifs(offset: number): Promise<GifsResult> {
|
||||||
|
assert(giphy_fetch !== undefined);
|
||||||
const config = {
|
const config = {
|
||||||
offset,
|
offset,
|
||||||
limit: 25,
|
limit: 25,
|
||||||
|
@ -73,7 +80,7 @@ async function renderGIPHYGrid(targetEl) {
|
||||||
return giphy_fetch.search(search_term, config);
|
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
|
// See https://github.com/Giphy/giphy-js/blob/master/packages/components/README.md#grid
|
||||||
// for detailed documentation.
|
// for detailed documentation.
|
||||||
renderGrid(
|
renderGrid(
|
||||||
|
@ -86,11 +93,11 @@ async function renderGIPHYGrid(targetEl) {
|
||||||
// Hide the creator attribution that appears over a
|
// Hide the creator attribution that appears over a
|
||||||
// GIF; nice in principle but too distracting.
|
// GIF; nice in principle but too distracting.
|
||||||
hideAttribution: true,
|
hideAttribution: true,
|
||||||
onGifClick(props) {
|
onGifClick(props: IGif) {
|
||||||
let $textarea = $("textarea#compose-textarea");
|
let $textarea = $<HTMLTextAreaElement>("textarea#compose-textarea");
|
||||||
if (edit_message_id !== undefined) {
|
if (edit_message_id !== undefined) {
|
||||||
$textarea = $(
|
$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) {
|
if (!gifs_grid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const $search_elem = $("#giphy-search-query");
|
const $search_elem = $<HTMLInputElement>("input#giphy-search-query");
|
||||||
// GIPHY popover may have been hidden by the
|
// GIPHY popover may have been hidden by the
|
||||||
// time this function is called.
|
// time this function is called.
|
||||||
if ($search_elem.length) {
|
if ($search_elem.length) {
|
||||||
search_term = $search_elem[0].value;
|
search_term = the($search_elem).value;
|
||||||
gifs_grid.remove();
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +146,7 @@ async function update_grid_with_search_term() {
|
||||||
gifs_grid = undefined;
|
gifs_grid = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hide_giphy_popover() {
|
export function hide_giphy_popover(): boolean {
|
||||||
// Returns `true` if the popover was open.
|
// Returns `true` if the popover was open.
|
||||||
if (giphy_popover_instance) {
|
if (giphy_popover_instance) {
|
||||||
giphy_popover_instance.destroy();
|
giphy_popover_instance.destroy();
|
||||||
|
@ -151,7 +158,7 @@ export function hide_giphy_popover() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggle_giphy_popover(target) {
|
function toggle_giphy_popover(target: HTMLElement): void {
|
||||||
popover_menus.toggle_popover_menu(
|
popover_menus.toggle_popover_menu(
|
||||||
target,
|
target,
|
||||||
{
|
{
|
||||||
|
@ -161,10 +168,9 @@ function toggle_giphy_popover(target) {
|
||||||
instance.setContent(ui_util.parse_html(render_giphy_picker()));
|
instance.setContent(ui_util.parse_html(render_giphy_picker()));
|
||||||
$(instance.popper).addClass("giphy-popover");
|
$(instance.popper).addClass("giphy-popover");
|
||||||
},
|
},
|
||||||
async onShow(instance) {
|
onShow(instance) {
|
||||||
giphy_popover_instance = instance;
|
giphy_popover_instance = instance;
|
||||||
const $popper = $(giphy_popover_instance.popper).trigger("focus");
|
const $popper = $(giphy_popover_instance.popper).trigger("focus");
|
||||||
gifs_grid = await renderGIPHYGrid($popper.find(".giphy-content")[0]);
|
|
||||||
|
|
||||||
const $click_target = $(instance.reference);
|
const $click_target = $(instance.reference);
|
||||||
if ($click_target.parents(".message_edit_form").length === 1) {
|
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
|
// every search. This makes the UX of searching pleasant
|
||||||
// by allowing user to finish typing before search
|
// by allowing user to finish typing before search
|
||||||
// is executed.
|
// 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", ".giphy-gif", ui_util.convert_enter_to_click);
|
||||||
$popper.on("keydown", ".compose_gif_icon", 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();
|
e.stopPropagation();
|
||||||
$("#giphy-search-query").val("");
|
$("#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.
|
// Focus on search box by default.
|
||||||
// This is specially helpful for users
|
// This is specially helpful for users
|
||||||
// navigating via keyboard.
|
// navigating via keyboard.
|
||||||
$("#giphy-search-query").trigger("focus");
|
$("#giphy-search-query").trigger("focus");
|
||||||
|
})();
|
||||||
},
|
},
|
||||||
onHidden() {
|
onHidden() {
|
||||||
hide_giphy_popover();
|
hide_giphy_popover();
|
||||||
|
@ -214,12 +224,12 @@ function toggle_giphy_popover(target) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function register_click_handlers() {
|
function register_click_handlers(): void {
|
||||||
$("body").on("click", ".compose_control_button.compose_gif_icon", (e) => {
|
$("body").on("click", ".compose_control_button.compose_gif_icon", function (this: HTMLElement) {
|
||||||
toggle_giphy_popover(e.currentTarget);
|
toggle_giphy_popover(this);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initialize() {
|
export function initialize(): void {
|
||||||
register_click_handlers();
|
register_click_handlers();
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ import * as emoji from "./emoji.ts";
|
||||||
import * as emoji_picker from "./emoji_picker.ts";
|
import * as emoji_picker from "./emoji_picker.ts";
|
||||||
import * as feedback_widget from "./feedback_widget.ts";
|
import * as feedback_widget from "./feedback_widget.ts";
|
||||||
import * as gear_menu from "./gear_menu.js";
|
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 hash_util from "./hash_util.ts";
|
||||||
import * as hashchange from "./hashchange.js";
|
import * as hashchange from "./hashchange.js";
|
||||||
import * as inbox_ui from "./inbox_ui.ts";
|
import * as inbox_ui from "./inbox_ui.ts";
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {electron_bridge} from "./electron_bridge.ts";
|
||||||
import * as emoji from "./emoji.ts";
|
import * as emoji from "./emoji.ts";
|
||||||
import * as emoji_picker from "./emoji_picker.ts";
|
import * as emoji_picker from "./emoji_picker.ts";
|
||||||
import * as gear_menu from "./gear_menu.js";
|
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 information_density from "./information_density.ts";
|
||||||
import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area.ts";
|
import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area.ts";
|
||||||
import * as linkifiers from "./linkifiers.ts";
|
import * as linkifiers from "./linkifiers.ts";
|
||||||
|
|
|
@ -44,7 +44,7 @@ import * as emoji from "./emoji.ts";
|
||||||
import * as emoji_picker from "./emoji_picker.ts";
|
import * as emoji_picker from "./emoji_picker.ts";
|
||||||
import * as emojisets from "./emojisets.ts";
|
import * as emojisets from "./emojisets.ts";
|
||||||
import * as gear_menu from "./gear_menu.js";
|
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 giphy_state from "./giphy_state.ts";
|
||||||
import * as hashchange from "./hashchange.js";
|
import * as hashchange from "./hashchange.js";
|
||||||
import * as hotkey from "./hotkey.js";
|
import * as hotkey from "./hotkey.js";
|
||||||
|
|
Loading…
Reference in New Issue