zulip/static/js/giphy.js

144 lines
4.8 KiB
JavaScript

import {renderGrid} from "@giphy/js-components";
import {GiphyFetch} from "@giphy/js-fetch-api";
import $ from "jquery";
import _ from "lodash";
import render_giphy_picker from "../templates/giphy_picker.hbs";
import render_giphy_picker_mobile from "../templates/giphy_picker_mobile.hbs";
import * as compose_ui from "./compose_ui";
import {page_params} from "./page_params";
import * as ui_util from "./ui_util";
const giphy_fetch = new GiphyFetch(page_params.giphy_api_key);
let search_term = "";
function fetchGifs(offset) {
const config = {
offset,
limit: 25,
// Default rating to 'g' until we can make this configurable.
rating: "g",
// We don't pass random_id here, for privacy reasons.
};
if (search_term === "") {
// Get the trending gifs by default.
return giphy_fetch.trending(config);
}
return giphy_fetch.search(search_term, config);
}
function renderGIPHYGrid(targetEl) {
const render = () =>
// See https://github.com/Giphy/giphy-js/blob/master/packages/components/README.md#grid
// for detailed documentation.
renderGrid(
{
width: 300,
fetchGifs,
columns: 3,
gutter: 6,
noLink: true,
// Hide the creator attribution that appears over a
// GIF; nice in principle but too distracting.
hideAttribution: true,
onGifClick: (props) => {
$("#compose_box_giphy_grid").popover("hide");
compose_ui.insert_syntax_and_focus(`[](${props.images.downsized_medium.url})`);
},
onGifVisible: (gif, e) => {
// Set tabindex for all the GIFs that
// are visible to the user. This allows
// user to navigate the GIFs using tab.
// TODO: Remove this after https://github.com/Giphy/giphy-js/issues/174
// is closed.
e.target.tabIndex = 0;
},
},
targetEl,
);
// Limit the rate at which we do queries to the GIPHY API to
// one per 300ms, in line with animation timing, basically to avoid
// content appearing while the user is typing.
const resizeRender = _.throttle(render, 300);
window.addEventListener("resize", resizeRender, false);
const remove = render();
return {
remove: () => {
remove();
window.removeEventListener("resize", resizeRender, false);
},
};
}
let template = render_giphy_picker();
if (window.innerWidth <= 768) {
// Show as modal in the center for small screens.
template = render_giphy_picker_mobile();
}
$("#compose_box_giphy_grid").popover({
animation: true,
placement: "top",
html: true,
trigger: "manual",
template,
});
function update_grid_with_search_term() {
const search_elem = $("#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;
return renderGIPHYGrid($("#giphy_grid_in_popover .popover-content")[0]);
}
// Return undefined to stop searching.
return undefined;
}
export function initialize() {
$("body").on("keydown", ".giphy-gif", ui_util.convert_enter_to_click);
$("body").on("keydown", "#compose_giphy_logo", ui_util.convert_enter_to_click);
$("#compose_giphy_logo").on("click", (e) => {
e.preventDefault();
e.stopPropagation();
if ($("#giphy_grid_in_popover").length) {
$("#compose_box_giphy_grid").popover("hide");
return;
}
$("#compose_box_giphy_grid").popover("show");
let gifs_grid = renderGIPHYGrid($("#giphy_grid_in_popover .popover-content")[0]);
$("body").on(
"keyup",
"#giphy-search-query",
// Use debounce to create a 300ms interval between
// every search. This makes the UX of searching pleasant
// by allowing user to finish typing before search
// is executed.
_.debounce(() => {
// GIPHY popover may have been hidden by the
// time this function is called.
if (gifs_grid) {
gifs_grid.remove();
gifs_grid = update_grid_with_search_term();
}
}, 300),
);
$(document).one("compose_canceled.zulip compose_finished.zulip", () => {
$("#compose_box_giphy_grid").popover("hide");
});
// Focus on search box by default.
// This is specially helpful for users
// navigating via keybaord.
$("#giphy-search-query").trigger("focus");
});
}