From d679296c96314a8e7e3b06b2d1dc7c4cf83d3f3f Mon Sep 17 00:00:00 2001 From: SMLT Date: Fri, 4 Aug 2023 13:01:14 +0200 Subject: [PATCH 01/14] Add scpfoundation.net support through Crom --- js/branches-info-scp.js | 4 ++-- js/lookup/crom.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/js/branches-info-scp.js b/js/branches-info-scp.js index 9d77f8c..c680b70 100644 --- a/js/branches-info-scp.js +++ b/js/branches-info-scp.js @@ -79,8 +79,8 @@ export var scpBranches = { ru: { name: "Русский", head: "На других языках", - url: "http://scp-ru.wikidot.com/", - id: "169125", + url: "https://scpfoundation.net/", + id: "", category: "", }, es: { diff --git a/js/lookup/crom.js b/js/lookup/crom.js index ff35570..9ef2fa3 100644 --- a/js/lookup/crom.js +++ b/js/lookup/crom.js @@ -69,8 +69,8 @@ export function cromLookup(currentBranch, branches, fullname, addLink) { * @param {String} url */ function normaliseUrl(url) { - if (url.indexOf(".wikidot.com") === -1) { - throw new Error("Crom requires wikidot.com branch URLs (" + url + ")"); + if (url.indexOf(".wikidot.com") === -1 && url.indexOf("scpfoundation.net") === -1) { + throw new Error("Crom requires wikidot.com or scpfoundation.net branch URLs (" + url + ")"); } return url.replace(/^https:/, "http:"); } From bdf4defcc6e14694325200a460d10963975c7df7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D1=81=D0=BB=D0=B0=D0=B2=20?= =?UTF-8?q?=D0=93=D0=BE=D1=80=D1=81=D0=BA=D0=B8=D0=B9?= Date: Wed, 1 Nov 2023 15:31:35 +0300 Subject: [PATCH 02/14] Add russian WL branch --- js/branches-info-wl.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/js/branches-info-wl.js b/js/branches-info-wl.js index e00f0c5..852b60c 100644 --- a/js/branches-info-wl.js +++ b/js/branches-info-wl.js @@ -48,4 +48,11 @@ export var wlBranches = { id: "4593099", category: "", }, + ru: { + name: "Русский", + head: "На других языках", + url: "https://scpfoundation.net/", + id: "", + category: "wl:", + }, }; From 473f331dc1ad8fade2b97189eba947d07f68c29c Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 13:25:38 +0100 Subject: [PATCH 03/14] Limit preview to run on main repo only --- .github/workflows/preview.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 964da66..08b13f3 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -15,6 +15,7 @@ on: concurrency: preview-${{ github.ref }} jobs: deploy-preview: + if: github.repository == 'scpwiki/interwiki' runs-on: ubuntu-latest steps: - name: Checkout From dc915e789dfd9f463379054f88564a8305850d29 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 13:41:04 +0100 Subject: [PATCH 04/14] Output resize iframe script as separate file --- build.js | 10 ++++++++++ js/createResizeIframe.js | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/build.js b/build.js index 5f091e5..a53a31e 100644 --- a/build.js +++ b/build.js @@ -16,6 +16,16 @@ esbuild.buildSync({ target: dev ? "esnext" : "es5", }); +esbuild.buildSync({ + entryPoints: ["js/createResizeIframe.js"], + outdir: "dist", + bundle: true, + minify: !dev, + sourcemap: dev ? "inline" : true, + target: dev ? "esnext" : "es5", + globalName: "resizeIframe", +}); + ["interwikiFrame", "styleFrame", "index"].forEach(function (frame) { fs.copyFileSync("html/" + frame + ".html", "dist/" + frame + ".html"); }); diff --git a/js/createResizeIframe.js b/js/createResizeIframe.js index c7c4f1c..cabb130 100644 --- a/js/createResizeIframe.js +++ b/js/createResizeIframe.js @@ -50,7 +50,7 @@ export function createResizeIframe(site, frameId) { * @param {Number} wait - The number of milliseconds to wait after any call * to the debounced function before executing it. */ -function debounce(func, wait) { +export function debounce(func, wait) { var timeout = 0; return function () { clearTimeout(timeout); From a4e4a341dfe4d9fcb67f784270f15e8d4be0fa08 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 16:57:40 +0100 Subject: [PATCH 05/14] Get createResizeIframe from other script --- html/interwikiFrame.html | 1 + js/interwiki.js | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/html/interwikiFrame.html b/html/interwikiFrame.html index 020d159..3a2ad35 100644 --- a/html/interwikiFrame.html +++ b/html/interwikiFrame.html @@ -4,6 +4,7 @@ + diff --git a/js/interwiki.js b/js/interwiki.js index 86d3c95..ccf6018 100644 --- a/js/interwiki.js +++ b/js/interwiki.js @@ -1,11 +1,14 @@ -import { createResizeIframe } from "./createResizeIframe"; -import { addTranslations } from "./links"; import { addExternalStyle, createRequestStyleChange } from "./styles"; +import { ResizeObserver } from "@juggle/resize-observer"; +import { addTranslations } from "./links"; import { scpBranches } from "./branches-info-scp"; import { wlBranches } from "./branches-info-wl"; -import { ResizeObserver } from "@juggle/resize-observer"; +/** + * @type {import("./createResizeIframe").createResizeIframe} + */ +var createResizeIframe = window.createResizeIframe; addEventListener("DOMContentLoaded", function () { var community = getQueryString(location.search, "community"); From 006ac9318db8563d2362ef2a1f873716bba80d9f Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 17:03:30 +0100 Subject: [PATCH 06/14] Create resizer container if it doesn't exist --- js/createResizeIframe.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/createResizeIframe.js b/js/createResizeIframe.js index cabb130..41f959b 100644 --- a/js/createResizeIframe.js +++ b/js/createResizeIframe.js @@ -14,6 +14,11 @@ export var flags = { showInterwiki: false }; */ export function createResizeIframe(site, frameId) { var container = document.getElementById("resizer-container"); + if (container == null) { + container = document.createElement("div"); + container.id = "resizer-container"; + document.body.appendChild(container); + } var resizer = document.createElement("iframe"); resizer.style.display = "none"; container.appendChild(resizer); From 6eeedbf05b50ed32fab58cb55f66b5c928ea5a1f Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 17:04:54 +0100 Subject: [PATCH 07/14] Make debounce buffer configurable --- js/createResizeIframe.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/js/createResizeIframe.js b/js/createResizeIframe.js index 41f959b..9930ba5 100644 --- a/js/createResizeIframe.js +++ b/js/createResizeIframe.js @@ -5,14 +5,15 @@ export var flags = { showInterwiki: false }; /** - * Constructs and returns a function that, when called, resizes the current - * iframes to match its contents. The function is debounced. + * Constructs and returns a function that, when called, resizes the current iframes to match its contents. The function is debounced. * * @param {String} site - The base URL of the site. - * @param {String} frameId - The last segment of the URL of the interwiki - * iframe, used by Wikidot to identify it when resizing it. + * @param {String} frameId - The last segment of the URL of the interwiki iframe, used by Wikidot to identify it when resizing it. + * @param {Number=} [debounceTime] - Debounce delay to stagger repeated calls to the resizer. Defaults to 750 ms. */ -export function createResizeIframe(site, frameId) { +export function createResizeIframe(site, frameId, debounceTime) { + if (debounceTime == null) debounceTime = 750; + var container = document.getElementById("resizer-container"); if (container == null) { container = document.createElement("div"); @@ -43,7 +44,7 @@ export function createResizeIframe(site, frameId) { height + frameId; } - }, 750); + }, debounceTime); } /** From 831e33615b0d38bcdebf4a7b88feb8e76e7802b5 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 17:59:39 +0100 Subject: [PATCH 08/14] Move resize condition from resizer to interwiki Removes global-like flag variable that tracked whether to show the interwiki. Flag started off and switched on when a translation link was added. Resize attempts would no-op until this was the case. Moving this logic from the resize function to the main interwiki script means the resize functions are now logically independent of the interwiki. When the resize function is called, the iframe resizes. It is the interwiki's job to decide when to call the function. --- js/createResizeIframe.js | 42 ++++++++++++++++------------------------ js/interwiki.js | 5 ++++- js/links.js | 12 +----------- 3 files changed, 22 insertions(+), 37 deletions(-) diff --git a/js/createResizeIframe.js b/js/createResizeIframe.js index 9930ba5..91ee9eb 100644 --- a/js/createResizeIframe.js +++ b/js/createResizeIframe.js @@ -1,15 +1,10 @@ -/** - * Whether the interwiki should be visible. It should only be visible after - * data has been received from the API source. - */ -export var flags = { showInterwiki: false }; - /** * Constructs and returns a function that, when called, resizes the current iframes to match its contents. The function is debounced. * * @param {String} site - The base URL of the site. * @param {String} frameId - The last segment of the URL of the interwiki iframe, used by Wikidot to identify it when resizing it. * @param {Number=} [debounceTime] - Debounce delay to stagger repeated calls to the resizer. Defaults to 750 ms. + * @returns {(() => void)} Debounced function that resizes the iframe. */ export function createResizeIframe(site, frameId, debounceTime) { if (debounceTime == null) debounceTime = 750; @@ -24,26 +19,23 @@ export function createResizeIframe(site, frameId, debounceTime) { resizer.style.display = "none"; container.appendChild(resizer); - if (frameId[0] !== "/") frameId = "/" + frameId; + // Trim leading slashes from frame ID + frameId = frameId.replace(/^\/+/, ""); - return debounce(function (receivedData) { - if (receivedData) flags.showInterwiki = true; - if (flags.showInterwiki) { - // Measure from the top of the document to the iframe container to get - // the document height - this takes into account inner margins, unlike - // e.g. document.body.clientHeight - // The container must not have display:none for this to work, which is - // why the iframe has it instead - var height = container.getBoundingClientRect().top; - // Brute-force past any subpixel issues - if (height) height += 1; - resizer.src = - site + - "/common--javascript/resize-iframe.html?" + - "#" + - height + - frameId; - } + return debounce(function () { + // Measure from the top of the document to the iframe container to get the document height + // This takes into account inner margins, unlike e.g. document.body.clientHeight + // The container must not have display:none for this to work, which is why the iframe has it instead + var height = container.getBoundingClientRect().top; + // Brute-force past any subpixel issues + if (height) height += 1; + resizer.src = + site + + "/common--javascript/resize-iframe.html?" + + "#" + + height + + "/" + + frameId; }, debounceTime); } diff --git a/js/interwiki.js b/js/interwiki.js index ccf6018..b99d554 100644 --- a/js/interwiki.js +++ b/js/interwiki.js @@ -111,7 +111,10 @@ export function createInterwiki( var resize = createResizeIframe(site, frameId); // Resize frame when size changes are detected - var observer = new ResizeObserver(resize); + var observer = new ResizeObserver(function () { + // Only resize if there's at least one translation link + if (document.getElementsByClassName("menu-item").length) resize(); + }); observer.observe(document.documentElement); // Construct the function that will be called internally and by diff --git a/js/links.js b/js/links.js index ceb5490..c8e56ea 100644 --- a/js/links.js +++ b/js/links.js @@ -1,4 +1,3 @@ -import { flags } from "./createResizeIframe"; import { cromLookup } from "./lookup/crom"; // Configure which lookup method is currently active @@ -58,16 +57,7 @@ export function addTranslations(branches, currentBranchLang, pagename) { var header = document.querySelector(".heading p"); header.innerText = currentBranch.head; - lookupMethod( - currentBranch, - branches, - pagename, - function (pageUrl, branchName, branchLang, isOriginal) { - addTranslationLink(pageUrl, branchName, branchLang, isOriginal); - // Indicate that data has been received - flags.showInterwiki = true; - } - ); + lookupMethod(currentBranch, branches, pagename, addTranslationLink); } /** From 6aec1fcaa44f9a1e13eac544ef69368fe262af04 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 18:12:46 +0100 Subject: [PATCH 09/14] Add height parameter that overrides measurement --- js/createResizeIframe.js | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/js/createResizeIframe.js b/js/createResizeIframe.js index 91ee9eb..662a0c5 100644 --- a/js/createResizeIframe.js +++ b/js/createResizeIframe.js @@ -1,10 +1,10 @@ /** - * Constructs and returns a function that, when called, resizes the current iframes to match its contents. The function is debounced. + * Constructs and returns a function that, when called, resizes the current iframes to match its contents or the given height. The function is debounced. * * @param {String} site - The base URL of the site. * @param {String} frameId - The last segment of the URL of the interwiki iframe, used by Wikidot to identify it when resizing it. * @param {Number=} [debounceTime] - Debounce delay to stagger repeated calls to the resizer. Defaults to 750 ms. - * @returns {(() => void)} Debounced function that resizes the iframe. + * @returns {((height: Number=) => void)} Debounced function that resizes the iframe. Optional height parameter sets the height of the iframe; if not set, the height is calculated from the document. */ export function createResizeIframe(site, frameId, debounceTime) { if (debounceTime == null) debounceTime = 750; @@ -22,13 +22,15 @@ export function createResizeIframe(site, frameId, debounceTime) { // Trim leading slashes from frame ID frameId = frameId.replace(/^\/+/, ""); - return debounce(function () { - // Measure from the top of the document to the iframe container to get the document height - // This takes into account inner margins, unlike e.g. document.body.clientHeight - // The container must not have display:none for this to work, which is why the iframe has it instead - var height = container.getBoundingClientRect().top; - // Brute-force past any subpixel issues - if (height) height += 1; + var resize = function (height) { + if (height == null) { + // Measure from the top of the document to the iframe container to get the document height + // This takes into account inner margins, unlike e.g. document.body.clientHeight + // The container must not have display:none for this to work, which is why the iframe has it instead + height = container.getBoundingClientRect().top; + // Brute-force past any subpixel issues + if (height) height += 1; + } resizer.src = site + "/common--javascript/resize-iframe.html?" + @@ -36,17 +38,17 @@ export function createResizeIframe(site, frameId, debounceTime) { height + "/" + frameId; - }, debounceTime); + }; + + return debounce(resize, debounceTime); } /** - * Debounces a function, delaying its execution until a certain amount of - * time has passed since the last time it was called, and aggregating all - * calls made in that time into one. + * Debounces a function, delaying its execution until a certain amount of time has passed since the last time it was called, and aggregating all calls made in that time into one. * * @param {Function} func - The function to call. - * @param {Number} wait - The number of milliseconds to wait after any call - * to the debounced function before executing it. + * @param {Number} wait - The number of milliseconds to wait after any call to the debounced function before executing it. + * @returns {Function} The debounced function. */ export function debounce(func, wait) { var timeout = 0; From efd3eaa9d8970639553e434ceb95a7dd09edecf4 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 18:26:00 +0100 Subject: [PATCH 10/14] Rename resize script to match namespace --- build.js | 2 +- html/interwikiFrame.html | 2 +- js/interwiki.js | 4 ++-- js/{createResizeIframe.js => resizeIframe.js} | 0 4 files changed, 4 insertions(+), 4 deletions(-) rename js/{createResizeIframe.js => resizeIframe.js} (100%) diff --git a/build.js b/build.js index a53a31e..8448bb9 100644 --- a/build.js +++ b/build.js @@ -17,7 +17,7 @@ esbuild.buildSync({ }); esbuild.buildSync({ - entryPoints: ["js/createResizeIframe.js"], + entryPoints: ["js/resizeIframe.js"], outdir: "dist", bundle: true, minify: !dev, diff --git a/html/interwikiFrame.html b/html/interwikiFrame.html index 3a2ad35..e6d3f1d 100644 --- a/html/interwikiFrame.html +++ b/html/interwikiFrame.html @@ -4,7 +4,7 @@ - + diff --git a/js/interwiki.js b/js/interwiki.js index b99d554..148de1a 100644 --- a/js/interwiki.js +++ b/js/interwiki.js @@ -6,9 +6,9 @@ import { scpBranches } from "./branches-info-scp"; import { wlBranches } from "./branches-info-wl"; /** - * @type {import("./createResizeIframe").createResizeIframe} + * @type {import("./resizeIframe").createResizeIframe} */ -var createResizeIframe = window.createResizeIframe; +var createResizeIframe = window.resizeIframe.createResizeIframe; addEventListener("DOMContentLoaded", function () { var community = getQueryString(location.search, "community"); diff --git a/js/createResizeIframe.js b/js/resizeIframe.js similarity index 100% rename from js/createResizeIframe.js rename to js/resizeIframe.js From 112cb14343a432b1b92f4fcd94937aad922f2af5 Mon Sep 17 00:00:00 2001 From: Ross Williams Date: Wed, 22 May 2024 18:37:59 +0100 Subject: [PATCH 11/14] Pass arguments to debounced function As opposed to calling the debounced function with the Arguments object as the sole argument --- js/resizeIframe.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/resizeIframe.js b/js/resizeIframe.js index 662a0c5..a403f22 100644 --- a/js/resizeIframe.js +++ b/js/resizeIframe.js @@ -55,7 +55,7 @@ export function debounce(func, wait) { return function () { clearTimeout(timeout); timeout = setTimeout(function () { - func(arguments); + func.apply(null, arguments); }, wait); }; } From cf2f12d6ebe18cdb5a6e8d209d13ffa2643d2b91 Mon Sep 17 00:00:00 2001 From: SMLT Date: Tue, 5 Apr 2022 03:56:41 +0200 Subject: [PATCH 12/14] Make requests to Crom API over GET Currently, making POST requests [with a JSON content type](https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header) means that the browser needs to make a [preflight request](https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request) first, and that adds an additional request overhead. The preflight request itself doesn't add much load to the API server, and it probably doesn't add a _huge_ overhead to the client either, but with the server running out of a single geographic region, switching to a "CORS-safe" GET request would spare a good chunk of a second of latency for the end-user, depending on their location. In the long term, this would also open up the avenue for basic HTTP-layer caching. Implementation-wise, GraphQL doesn't exactly have an official spec for interfacing with HTTP, but the Crom API's custom implementation follows [the guidelines](https://graphql.org/learn/serving-over-http), which includes a recommendation for making requests over GET. The accept header is there so that the browser doesn't serve the playground HTML instead (which it would if the accept included text/html or \*/\*). Couldn't use URLSearchParams with the ES5 limitation, but the alternative isn't so bad. Also, I drafted this in the GitHub editor, so I haven't actually tested this change. --- js/lookup/crom.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/lookup/crom.js b/js/lookup/crom.js index 9ef2fa3..31849a4 100644 --- a/js/lookup/crom.js +++ b/js/lookup/crom.js @@ -137,8 +137,13 @@ function parseTranslations(response, currentBranch, branches, addLink) { */ function executeQuery(url, callback) { var request = new XMLHttpRequest(); - request.open("POST", "https://api.crom.avn.sh/graphql", true); - request.setRequestHeader("Content-Type", "application/json"); + var requestUrl = + "https://api.crom.avn.sh/graphql?query=" + + encodeURIComponent(query) + + "&variables=" + + encodeURIComponent(JSON.stringify({ url: url })); + request.open("GET", requestUrl, true); + request.setRequestHeader("Accept", "application/json"); request.addEventListener("readystatechange", function () { if (request.readyState === XMLHttpRequest.DONE) { try { @@ -157,5 +162,5 @@ function executeQuery(url, callback) { } } }); - request.send(JSON.stringify({ query: query, variables: { url: url } })); + request.send(); } From 5e8fb6dcc507e9bdf291913bd7fcf511201d3486 Mon Sep 17 00:00:00 2001 From: RTa <57354947+r74tech@users.noreply.github.com> Date: Mon, 27 May 2024 19:32:14 +0900 Subject: [PATCH 13/14] Update preview.yml --- .github/workflows/preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 08b13f3..ebef4bc 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -15,7 +15,7 @@ on: concurrency: preview-${{ github.ref }} jobs: deploy-preview: - if: github.repository == 'scpwiki/interwiki' + if: github.repository == 'SCP-JP/interwiki' runs-on: ubuntu-latest steps: - name: Checkout From f9e1d007b440ba4b6ba0818b900a155e0b08f9c0 Mon Sep 17 00:00:00 2001 From: RTa <57354947+r74tech@users.noreply.github.com> Date: Mon, 27 May 2024 19:34:00 +0900 Subject: [PATCH 14/14] Delete .github/workflows/preview.yml --- .github/workflows/preview.yml | 30 ------------------------------ 1 file changed, 30 deletions(-) delete mode 100644 .github/workflows/preview.yml diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml deleted file mode 100644 index ebef4bc..0000000 --- a/.github/workflows/preview.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: preview PR -on: - pull_request: - types: - - opened - - reopened - - synchronize - - closed - paths: - - css/** - - html/** - - js/** - - build.js - - .github/workflows/preview.yml -concurrency: preview-${{ github.ref }} -jobs: - deploy-preview: - if: github.repository == 'SCP-JP/interwiki' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Install - run: npm install - - name: Build - run: npm run build - - name: Deploy preview - uses: rossjrw/pr-preview-action@v1 - with: - source-dir: dist