164 lines
4.1 KiB
TypeScript
164 lines
4.1 KiB
TypeScript
import { parseQuote } from "../../lib/util";
|
|
import { clickAction } from "../click_action";
|
|
import { expand } from "../expand";
|
|
import { addYous } from "../yous";
|
|
import { clickQuote } from "./click_quote";
|
|
import $ from "jquery";
|
|
|
|
const hoverQuote = (quotes: JQuery<HTMLElement>) => {
|
|
const cache: { [key: string]: string } = {};
|
|
let hovering = false;
|
|
let previewW = 0;
|
|
let previewH = 0;
|
|
|
|
quotes.on("mouseover", function (event) {
|
|
toggleHover($(this), event);
|
|
});
|
|
|
|
quotes.on("mouseout", function (event) {
|
|
toggleHover($(this), event);
|
|
});
|
|
|
|
quotes.on("click", function (event) {
|
|
toggleHover($(this), event);
|
|
});
|
|
|
|
quotes.on("mousemove", movePreview);
|
|
|
|
const toggleHover = (
|
|
quote: JQuery<HTMLElement>,
|
|
event: JQuery.MouseEventBase,
|
|
) => {
|
|
hovering = event.type === "mouseover";
|
|
|
|
if ($("#preview").length > 0 && !hovering) {
|
|
removePreview();
|
|
return;
|
|
}
|
|
|
|
const board =
|
|
quote.closest(".post, .catalog-tile").attr("data-board") || null;
|
|
|
|
const id = parseQuote(board, quote.text());
|
|
const existingPost = $(`#${id}.post`); // Catalog tiles don't count
|
|
const url = quote.attr("href");
|
|
|
|
console.log(id, existingPost[0]);
|
|
|
|
if (existingPost.length > 0 && isInViewport(existingPost)) {
|
|
existingPost.toggleClass("highlighted", hovering);
|
|
return;
|
|
}
|
|
|
|
if (existingPost.length > 0 && hovering) {
|
|
createPreview(existingPost.clone(), event.clientX, event.clientY);
|
|
return;
|
|
}
|
|
|
|
const cachedPost = $(cache[id]);
|
|
|
|
if (cachedPost.length > 0) {
|
|
createPreview(cachedPost, event.clientX, event.clientY);
|
|
return;
|
|
}
|
|
|
|
quote.css("cursor", "wait");
|
|
|
|
$.ajax({
|
|
url,
|
|
success: function (html) {
|
|
const posts = $(html).find(".post");
|
|
|
|
posts.each(function () {
|
|
const board = $(this).attr("data-board");
|
|
const id = $(this).attr("data-id");
|
|
cache[`${board}-${id}`] = this.outerHTML;
|
|
});
|
|
|
|
const post = $(cache[id]);
|
|
createPreview(post, event.clientX, event.clientY);
|
|
quote.css("cursor", "");
|
|
},
|
|
error: function () {
|
|
quote.css("cursor", "");
|
|
},
|
|
});
|
|
};
|
|
|
|
function movePreview(event: JQuery.MouseEventBase) {
|
|
positionPreview($("#preview"), event.clientX, event.clientY);
|
|
}
|
|
|
|
function createPreview(preview: JQuery<HTMLElement>, x: number, y: number) {
|
|
if (!hovering) {
|
|
return;
|
|
}
|
|
|
|
preview.attr("id", "preview");
|
|
preview.addClass("reply");
|
|
preview.removeClass("highlighted");
|
|
preview.css("position", "fixed");
|
|
|
|
const existing = $("#preview");
|
|
|
|
if (existing.length > 0) {
|
|
existing.replaceWith(preview);
|
|
} else {
|
|
preview.appendTo("body");
|
|
}
|
|
|
|
previewW = preview.outerWidth() || 0;
|
|
previewH = preview.outerHeight() || 0;
|
|
|
|
positionPreview(preview, x, y);
|
|
|
|
// Set up events
|
|
clickQuote(preview.find(".quote-link"));
|
|
hoverQuote(preview.find(".quote"));
|
|
clickAction(preview.find(".post-checkbox"));
|
|
expand(preview.find(".thumb-link"));
|
|
addYous(preview);
|
|
}
|
|
|
|
function removePreview() {
|
|
$("#preview").remove();
|
|
}
|
|
|
|
function positionPreview(preview: JQuery<HTMLElement>, x: number, y: number) {
|
|
const ww = $(window).width() || 0;
|
|
const wh = $(window).height() || 0;
|
|
|
|
preview.css("left", `${Math.min(x + 4, ww - previewW)}px`);
|
|
|
|
if (previewH + y < wh) {
|
|
preview.css("top", `${y + 4}px`);
|
|
preview.css("bottom", "");
|
|
} else {
|
|
preview.css("bottom", `${wh - y + 4}px`);
|
|
preview.css("top", "");
|
|
}
|
|
}
|
|
};
|
|
|
|
const isInViewport = function (element: JQuery<HTMLElement>) {
|
|
const offset = element.offset();
|
|
const width = element.outerWidth();
|
|
const height = element.outerHeight();
|
|
const viewportTop = $(window).scrollTop();
|
|
const windowHeight = $(window).height();
|
|
|
|
if (!offset) return false;
|
|
if (!width) return false;
|
|
if (!height) return false;
|
|
if (!viewportTop) return false;
|
|
if (!windowHeight) return false;
|
|
|
|
const elementTop = offset.top;
|
|
const elementBottom = elementTop + height;
|
|
const viewportBottom = viewportTop + windowHeight;
|
|
|
|
return elementBottom > viewportTop && elementTop < viewportBottom;
|
|
};
|
|
|
|
export { hoverQuote };
|