mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 22:43:42 +00:00
We need fields like 'url_template' to do the code extraction. Those are absent if 'playground_info' is undefined, thus we should return immediately in those cases.
142 lines
5.1 KiB
TypeScript
142 lines
5.1 KiB
TypeScript
import $ from "jquery";
|
|
import type {Instance as PopoverInstance, ReferenceElement} from "tippy.js";
|
|
import url_template_lib from "url-template";
|
|
|
|
import render_playground_links_popover from "../templates/popovers/playground_links_popover.hbs";
|
|
|
|
import * as blueslip from "./blueslip";
|
|
import * as popover_menus from "./popover_menus";
|
|
import * as realm_playground from "./realm_playground";
|
|
import type {RealmPlayground} from "./realm_playground";
|
|
import * as ui_util from "./ui_util";
|
|
|
|
type RealmPlaygroundWithURL = RealmPlayground & {playground_url: string};
|
|
|
|
let playground_links_popover_instance: PopoverInstance;
|
|
|
|
// Playground_store contains all the data we need to generate a popover of
|
|
// playground links for each code block. The element is the target element
|
|
// to pop off of.
|
|
function toggle_playground_links_popover(
|
|
element: ReferenceElement,
|
|
playground_store: Map<number, RealmPlaygroundWithURL>,
|
|
): void {
|
|
if (is_open()) {
|
|
return;
|
|
}
|
|
|
|
popover_menus.toggle_popover_menu(element, {
|
|
placement: "bottom",
|
|
popperOptions: {
|
|
modifiers: [
|
|
{
|
|
name: "flip",
|
|
options: {
|
|
fallbackPlacements: ["top"],
|
|
},
|
|
},
|
|
],
|
|
},
|
|
onCreate(instance) {
|
|
// We extract all the values out of playground_store map into
|
|
// the playground_info array. Each element of the array is an
|
|
// object with all properties the template needs for rendering.
|
|
const playground_info = [...playground_store.values()];
|
|
playground_links_popover_instance = instance;
|
|
instance.setContent(
|
|
ui_util.parse_html(render_playground_links_popover({playground_info})),
|
|
);
|
|
},
|
|
onShow(instance) {
|
|
const $reference = $(instance.reference);
|
|
$reference.parent().addClass("active-playground-links-reference");
|
|
},
|
|
onHidden() {
|
|
hide();
|
|
},
|
|
});
|
|
}
|
|
|
|
export function is_open(): boolean {
|
|
return Boolean(playground_links_popover_instance);
|
|
}
|
|
|
|
export function hide(): void {
|
|
if (is_open()) {
|
|
$(playground_links_popover_instance.reference)
|
|
.parent()
|
|
.removeClass("active-playground-links-reference");
|
|
playground_links_popover_instance.destroy();
|
|
}
|
|
}
|
|
|
|
function get_playground_links_popover_items(): JQuery | undefined {
|
|
if (!is_open()) {
|
|
blueslip.error("Trying to get menu items when playground links popover is closed.");
|
|
return undefined;
|
|
}
|
|
|
|
const $popover = $(playground_links_popover_instance.popper);
|
|
if (!$popover) {
|
|
blueslip.error("Cannot find playground links popover data");
|
|
return undefined;
|
|
}
|
|
|
|
return $("li:not(.divider):visible a", $popover);
|
|
}
|
|
|
|
export function handle_keyboard(key: string): void {
|
|
const $items = get_playground_links_popover_items();
|
|
popover_menus.popover_items_handle_keyboard(key, $items);
|
|
}
|
|
|
|
function register_click_handlers(): void {
|
|
$("#main_div, #preview_content, #message-history").on(
|
|
"click",
|
|
".code_external_link",
|
|
function (e) {
|
|
const $view_in_playground_button = $(this);
|
|
const $codehilite_div = $(this).closest(".codehilite");
|
|
e.stopPropagation();
|
|
const playground_info = realm_playground.get_playground_info_for_languages(
|
|
$codehilite_div.data("code-language"),
|
|
);
|
|
if (playground_info === undefined) {
|
|
return;
|
|
}
|
|
// We do the code extraction here and set the target href expanding
|
|
// the url_template with the extracted code. Depending on whether
|
|
// the language has multiple playground links configured, a popover
|
|
// is shown.
|
|
const extracted_code = $codehilite_div.find("code").text();
|
|
if (playground_info.length === 1) {
|
|
const url_template = url_template_lib.parse(playground_info[0].url_template);
|
|
$view_in_playground_button.attr(
|
|
"href",
|
|
url_template.expand({code: extracted_code}),
|
|
);
|
|
} else {
|
|
const playground_store = new Map<number, RealmPlaygroundWithURL>();
|
|
for (const playground of playground_info) {
|
|
const url_template = url_template_lib.parse(playground.url_template);
|
|
const playground_url = url_template.expand({code: extracted_code});
|
|
playground_store.set(playground.id, {...playground, playground_url});
|
|
}
|
|
const popover_target = $view_in_playground_button.find(
|
|
".playground-links-popover-container",
|
|
)[0];
|
|
toggle_playground_links_popover(popover_target, playground_store);
|
|
}
|
|
},
|
|
);
|
|
|
|
$("body").on("click", ".popover_playground_link", (e) => {
|
|
hide();
|
|
e.stopPropagation();
|
|
});
|
|
}
|
|
|
|
export function initialize(): void {
|
|
register_click_handlers();
|
|
}
|