From dd96fee0e01423d568449402cee85e690a61ea27 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 19 Oct 2021 21:23:08 +0800 Subject: [PATCH] DEV: refactor and add support for new tab previews (#2) --- common/common.scss | 9 +++ .../initialize-for-pdf-preview.js | 71 ++++++++++++++----- settings.yml | 8 +++ 3 files changed, 70 insertions(+), 18 deletions(-) create mode 100644 settings.yml diff --git a/common/common.scss b/common/common.scss index 0ba618d..14fa21e 100644 --- a/common/common.scss +++ b/common/common.scss @@ -3,3 +3,12 @@ background-color: $primary-high; border: 0; } + +.attachment.new-tab-pdf { + &:before { + display: none; + } + .new-tab-pdf-icon { + margin-right: 4px; + } +} diff --git a/javascripts/discourse/initializers/initialize-for-pdf-preview.js b/javascripts/discourse/initializers/initialize-for-pdf-preview.js index bb6f6ae..55cd31c 100644 --- a/javascripts/discourse/initializers/initialize-for-pdf-preview.js +++ b/javascripts/discourse/initializers/initialize-for-pdf-preview.js @@ -1,4 +1,5 @@ import { withPluginApi } from "discourse/lib/plugin-api"; +import { iconHTML } from "discourse-common/lib/icon-library"; import Mobile from "discourse/lib/mobile"; const PREVIEW_HEIGHT = 500; @@ -16,46 +17,80 @@ const createPreviewElem = () => { export default { name: "pdf-previews", initialize() { - withPluginApi("0.8.41", api => { + withPluginApi("0.8.41", (api) => { if (Mobile.mobileView) return; + const previewMode = settings.preview_mode; + const newTabIcon = () => { + const template = document.createElement("template"); + template.innerHTML = iconHTML("external-link-alt", { + class: "new-tab-pdf-icon", + }); + return template.content.firstChild; + }; + try { api.decorateCookedElement( - post => { + (post) => { const attachments = [...post.querySelectorAll(".attachment")]; - if (!attachments.length) return; - - const pdfs = attachments.filter(attachment => + const pdfs = attachments.filter((attachment) => attachment.href.match(/\.[pdf]+$/) ); - if (!pdfs.length) return; - - pdfs.forEach(pdf => { - const preview = createPreviewElem(); - pdf.append(preview); - - pdf.classList.add("pdf-attachment"); + pdfs.forEach((pdf) => { const fileSize = pdf.nextSibling; if (fileSize) { fileSize.nodeValue = ""; } + const startsWithWhitespace = /^\s+/; + const fileName = pdf.innerText; + + if (startsWithWhitespace.test(fileName)) { + pdf.innerText = pdf.innerText.trim(); + return; + } + const httpRequest = new XMLHttpRequest(); httpRequest.open("GET", pdf.href); - httpRequest.responseType = "blob"; + httpRequest.responseType = "arraybuffer"; httpRequest.onreadystatechange = () => { if (httpRequest.readyState !== XMLHttpRequest.DONE) return; if (httpRequest.status === 200) { + let src = null; const blob = new Blob([httpRequest.response], { - type: "application/pdf" + type: "application/pdf", }); - const src = URL.createObjectURL(blob); - preview.src = src; + // new tab previews + if (previewMode === "New Tab") { + pdf.classList.add("new-tab-pdf"); + pdf.prepend(newTabIcon()); + src = URL.createObjectURL(blob); + + pdf.addEventListener("click", (event) => { + event.preventDefault(); + window.open(src); + }); + + return; + } + + // inline preview + pdf.classList.add("pdf-attachment"); + const preview = createPreviewElem(); + pdf.append(preview); + + const reader = new FileReader(); + reader.onload = function (event) { + src = event.target.result; + preview.src = src; + }; + + reader.readAsDataURL(blob); } }; httpRequest.send(); @@ -63,7 +98,7 @@ export default { }, { id: "pdf-previews", - onlyStream: true + onlyStream: true, } ); } catch (error) { @@ -71,5 +106,5 @@ export default { console.error(error); } }); - } + }, }; diff --git a/settings.yml b/settings.yml new file mode 100644 index 0000000..19a7387 --- /dev/null +++ b/settings.yml @@ -0,0 +1,8 @@ +preview_mode: + type: enum + default: Inline + description: + en: "Inline: PDF attachments will be rendered inline within posts

New Tab: PDF attachment links will take the user to a new tab where the PDF will be rendered" + choices: + - Inline + - New Tab