$(document).ready( function () { // Define global variables let isDragging = false; let saveDragPos; let rtime; let timeout = false; let delta = 200; let disableScrollEvent = false; let annotateLexical = false; let annotateSemantic = false; let annotateNovel = false; let annotateEntities = false; // Define functions function clamp(number, min, max) { return Math.max(min, Math.min(number, max)); } function hasScroll() { const el = $(".display .main-doc"); return el.prop("scrollHeight") > el.prop("clientHeight"); } function scrollBy(delta) { const proxyDoc = $(".display .proxy-doc"); const proxyScroll = proxyDoc.find(".proxy-scroll"); const currentTop = parseFloat(proxyScroll.css("top")); const newTop = clamp(currentTop + delta, 0, proxyDoc.innerHeight() - proxyScroll.innerHeight()); proxyScroll.css("top", newTop); const mainDoc = $(".display .main-doc"); const scaleY = mainDoc[0].scrollHeight / proxyDoc.innerHeight(); mainDoc.scrollTop(newTop * scaleY) } function getSpanId(el) { return getSpanIds(el)[0] } function getSpanIds(el) { return el.attr("class").split(/\s+/).filter(function (x) { return x.startsWith("span-") }); } function createProxy() { const mainDoc = $(".display .main-doc"); const proxyDoc = $(".display .proxy-doc"); const proxyHeight = proxyDoc.innerHeight(); const proxyWidth = proxyDoc.innerWidth(); const scaleX = 0.8 * proxyWidth / mainDoc.innerWidth(); const scaleY = proxyHeight / mainDoc[0].scrollHeight; const scrollTop = mainDoc.scrollTop(); const proxyScrollTop = scrollTop * scaleY; const proxyScrollBottom = (scrollTop + mainDoc.innerHeight()) * scaleY; const proxyScrollHeight = proxyScrollBottom - proxyScrollTop; proxyDoc.empty(); // Loop through underlines in doc view and create associated proxy element if (annotateLexical) { $(".display .main-doc .token-underline").each( function (index, value) { const el = $(value); const x = el.position().left; const y = mainDoc.scrollTop() + el.position().top - mainDoc.position().top; const newHeight = 3; const color = el.css("border-bottom-color"); const proxyPadding = proxyDoc.innerWidth() - proxyDoc.width(); const newX = x * scaleX + proxyPadding / 2; const newY = (y + el.height()) * scaleY - newHeight; const newWidth = Math.min( Math.max((el.width() * scaleX) + 1, 5), proxyDoc.width() + proxyPadding / 2 - newX ); let classes = "proxy-underline annotation-hidden " + getSpanIds(el).join(" "); const proxyEl = $('
', { "class": classes, "css": { "position": "absolute", "left": Math.round(newX), "top": Math.round(newY), "background-color": color, "width": newWidth, "height": newHeight, } }).appendTo(proxyDoc); proxyEl.data(el.data()); } ); } // Loop through all active highlights in doc view and create associated proxy element if (annotateSemantic) { $(".display .main-doc .highlight").each( function (index, value) { const el = $(value); const x = el.position().left; const y = mainDoc.scrollTop() + el.position().top - mainDoc.position().top; const newHeight = 5; const color = el.css("background-color"); const proxyPadding = proxyDoc.innerWidth() - proxyDoc.width() const newX = x * scaleX + proxyPadding / 2; const newY = (y + el.height()) * scaleY - newHeight; const newWidth = Math.min( Math.max((el.width() * scaleX) + 1, 5), proxyDoc.width() + proxyPadding / 2 - newX ); const proxyEl = $('', { "class": 'proxy-highlight annotation-hidden', "css": { "position": "absolute", "left": Math.round(newX), "top": Math.round(newY), "background-color": color, "width": newWidth, "height": newHeight, } }).appendTo(proxyDoc); // Copy data attributes proxyEl.data(el.data()); // Set classes for matching proxyEl.addClass(el.data("match-classes")) } ); } $('', { "class": 'proxy-scroll hidden', "css": { "top": proxyScrollTop, "height": proxyScrollHeight, } }).appendTo(proxyDoc); if (hasScroll()) { $(".display .proxy-scroll").removeClass("hidden") } $(".display .proxy-doc") .mousedown(function (event) { saveDragPos = parseFloat(event.pageY); isDragging = true; event.preventDefault(); }) .mousemove(function (event) { const dragPos = parseFloat(event.pageY); if (isDragging) { const distanceMoved = dragPos - saveDragPos; scrollBy(distanceMoved); saveDragPos = dragPos; event.preventDefault(); } }) .mouseup(function (event) { isDragging = false; }) .mouseenter(function () { disableScrollEvent = true; $(".display .proxy-scroll").addClass("hover") }) .mouseleave(function () { isDragging = false; disableScrollEvent = false; $(".display .proxy-scroll").removeClass("hover") }) .on('wheel', function (event) { scrollBy(event.originalEvent.deltaY / 4); event.preventDefault(); }); // TODO: Handle user clicking in scroll region $(".display .main-doc").scroll(function () { if (disableScrollEvent) return; $(".display .proxy-scroll") .css( "top", $(this).scrollTop() * scaleY ) }) } function resizeend() { if (new Date() - rtime < delta) { setTimeout(resizeend, delta); } else { timeout = false; updateAnnotations(); toggleScrollbar(); } } function toggleScrollbar() { if (hasScroll()) { $(".display .proxy-scroll").removeClass("hidden"); } else { $(".display .proxy-scroll").addClass("hidden"); } } function updateAnnotations() { annotateSemantic = $("#option-semantic").hasClass("selected"); annotateLexical = $("#option-lexical").hasClass("selected"); annotateEntities = $("#option-entity").hasClass("selected"); annotateNovel = $("#option-novel").hasClass("selected"); if (annotateSemantic || annotateLexical) { $(".summary-item").addClass("selectable") } else { $(".summary-item").removeClass("selectable") } if (annotateLexical) { $(".underline").removeClass("annotation-hidden"); $(".summary-item").addClass("annotate-lexical"); } else { $(".underline").addClass("annotation-hidden"); $(".summary-item").removeClass("annotate-lexical"); } if (annotateSemantic) { $(".highlight").removeClass("annotation-hidden"); } else { $(".highlight").addClass("annotation-hidden"); } if (annotateEntities) { $(".summary-item").addClass("annotate-entities") } else { $(".summary-item").removeClass("annotate-entities") } if (annotateNovel) { $(".summary-item").addClass("annotate-novel") } else { $(".summary-item").removeClass("annotate-novel") } createProxy(); if (annotateLexical) { $(".proxy-underline").removeClass("annotation-hidden"); } else { $(".proxy-underline").addClass("annotation-hidden"); } if (annotateSemantic) { $(".proxy-highlight").removeClass("annotation-hidden"); } else { $(".proxy-highlight").addClass("annotation-hidden"); } $(".summary-item .highlight").tooltip("disable"); if (annotateSemantic) { $(".summary-item.selected .highlight").tooltip("enable") } } function removeDocTooltips() { $("[data-tooltip-timestamp]").tooltip("dispose").removeAttr("data-tooltip-timestamp"); } function resetUnderlines() { $('.annotation-invisible').removeClass("annotation-invisible"); $('.annotation-inactive').removeClass("annotation-inactive"); $('.temp-underline-color') .each(function () { $(this).css("border-color", $(this).data("primary-color")); }) .removeClass("temp-underline-color") $('.temp-proxy-underline-color') .each(function () { $(this).css("background-color", $(this).data("primary-color")); }) .removeClass("temp-proxy-underline-color") } function showDocTooltip(el) { const topDocHighlightId = $(el).data("top-doc-highlight-id"); const topDocSim = $(el).data("top-doc-sim"); const topHighlight = $(`.display .main-doc .highlight[data-highlight-id=${topDocHighlightId}]`); if (!isViewable(topHighlight)) { return; } topHighlight.tooltip({title: `Most similar (${topDocSim})`, trigger: "manual", container: "body"}); topHighlight.tooltip("show"); const tooltipTimestamp = Date.now(); // Do not use .data() method to set data attributes as they are not searchable topHighlight.attr("data-tooltip-timestamp", tooltipTimestamp); setTimeout(function () { if (topHighlight.data("tooltip-timestamp") == tooltipTimestamp) { topHighlight.tooltip("dispose").removeAttr("data-tooltip-timestamp"); } }, 8000); } function highlightUnderlines() { const spanId = getSpanId($(this)); const color = $(this).css("border-bottom-color"); // TODO Consolidate into single statement $(`.summary-item.selected .underline.${spanId}`).removeClass("annotation-inactive"); $(`.doc .underline.${spanId}`) .removeClass("annotation-inactive") .each(function () { $(this).css("border-bottom-color", color); }) .addClass("temp-underline-color"); $(`.proxy-underline.${spanId}`) .removeClass("annotation-inactive") .each(function () { $(this).css("background-color", color); }) .addClass("temp-proxy-underline-color"); $(`.summary-item.selected .underline:not(.${spanId})`).addClass("annotation-inactive"); $(`.doc .underline:not(.${spanId})`).addClass("annotation-inactive"); $(`.proxy-underline:not(.${spanId})`).addClass("annotation-inactive"); $(".summary-item.selected .highlight:not(.annotation-hidden)").addClass("annotation-inactive"); } function resetHighlights() { removeDocTooltips(); $('.summary-item.selected .annotation-inactive').removeClass("annotation-inactive"); $('.summary-item.selected .annotation-invisible').removeClass("annotation-invisible"); $('.temp-highlight-color') .each(function () { $(this).css("background-color", $(this).data("primary-color")); }) .removeClass("temp-highlight-color"); $('.highlight.selected').removeClass("selected"); $('.proxy-highlight.selected').removeClass("selected"); $('.summary-item [title]').removeAttr("title"); } function highlightToken() { const highlightId = $(this).data("highlight-id"); $(`.summary-item.selected .highlight:not(.summary-highlight-${highlightId})`).addClass("annotation-inactive"); $('.highlight.selected').removeClass("selected") $('.proxy-highlight.selected').removeClass("selected") const matchedDocHighlight = `.display .main-doc .summary-highlight-${highlightId}`; const matchedProxyHighlight = `.proxy-doc .summary-highlight-${highlightId}`; $(matchedDocHighlight + ", " + matchedProxyHighlight) .each(function () { const newHighlightColor = $(this).data(`color-${highlightId}`); $(this).css("background-color", newHighlightColor); $(this).addClass("selected"); }) .addClass("temp-highlight-color"); $(".underline").addClass("annotation-inactive"); $(".proxy-underline").addClass("annotation-invisible") showDocTooltip(this); $(this).addClass("selected"); $(this).removeClass("annotation-inactive"); $('.summary-item [title]').removeAttr("title"); if (!isViewable($(matchedDocHighlight))) { $(this).attr("title", "Click to scroll to most similar word.") } } function isViewable(el) { const elTop = el.offset().top; const elBottom = elTop + el.outerHeight(); const scrollRegion = $(".display .main-doc"); const scrollTop = scrollRegion.offset().top; const scrollBottom = scrollTop + scrollRegion.outerHeight(); return elTop > scrollTop && elBottom < scrollBottom; } // Initialization $(function () { $('[data-toggle="tooltip"]').tooltip({ // 'boundary': '.summary-container' trigger: 'hover' }) }) updateAnnotations(); // Bind events $(window).resize(function () { rtime = new Date(); if (timeout === false) { timeout = true; setTimeout(resizeend, delta); } }); $(".summary-list").on( "click", ".summary-item.selectable:not(.selected)", function () { const summary_index = $(this).data("index"); // Update summary items $(".summary-item.selected").removeClass("selected") $(this).addClass("selected") // Update doc // Show the version of document aligned with selected summary index $(`.doc[data-index=${summary_index}]`).removeClass("nodisplay").addClass("display"); // Hide the version of document not aligned with selected summary index $(`.doc[data-index!=${summary_index}]`).removeClass("display").addClass("nodisplay"); updateAnnotations(); } ); $("#option-lexical").click(function () { $(this).toggleClass("selected") updateAnnotations() }); $("#option-semantic").click(function () { $(this).toggleClass("selected") updateAnnotations() }); $("#option-novel").click(function () { $(this).toggleClass("selected") updateAnnotations() }); $("#option-entity").click(function () { $(this).toggleClass("selected") updateAnnotations() }); const activeUnderlines = ".summary-item.selected .underline:not(.annotation-inactive):not(.annotation-hidden)"; $(".summary-list").on( "mouseenter", activeUnderlines, function () { highlightUnderlines.call(this); } ); $(".summary-list").on( "mouseleave", activeUnderlines, resetUnderlines ); $(".summary-list").on( "click", activeUnderlines, function () { // Find aligned underline in doc and scroll doc to that position highlightUnderlines.call(this); const mainDoc = $(".display .main-doc"); const spanId = getSpanId($(this)); const matchedUnderline = $(`.doc .underline.${spanId}`); mainDoc.animate({ scrollTop: mainDoc.scrollTop() + matchedUnderline.offset().top - mainDoc.offset().top - 60 }, 300 ) } ); const activeHighlights = ".summary-item.selected .highlight:not(.annotation-hidden):not(.matches-ngram), " + ".summary-item.selected:not(.annotate-lexical) .highlight:not(.annotation-hidden)"; $(".summary-list").on( "mouseenter", activeHighlights, function () { highlightToken.call(this); }) $(".summary-list").on( "mouseleave", activeHighlights, function () { resetHighlights(); resetUnderlines(); } ); $(".summary-list").on( "click", activeHighlights, function () { highlightToken.call(this); // Find corresponding highlight in doc representing max similarity and scroll doc to that position const topDocHighlightId = $(this).data("top-doc-highlight-id"); removeDocTooltips(topDocHighlightId); const topDocHighlight = $(`.display .main-doc .highlight[data-highlight-id=${topDocHighlightId}]`); const mainDoc = $(".display .main-doc"); const el = this; mainDoc.animate({ scrollTop: mainDoc.scrollTop() + topDocHighlight.offset().top - mainDoc.offset().top - 60 }, 300, function () { setTimeout( function () { // If no other tooltips have since been displayed if ($("[data-tooltip-timestamp]").length == 0) { showDocTooltip(el); } else { console.log("Not showing tooltip because one already exists") } }, 100 ) } ) } ); $(".summary-list").on( "mouseleave", ".summary-item.selected .content", function () { resetHighlights(); resetUnderlines(); }, ); } );