aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/constants.mjs9
-rw-r--r--app/directory.mjs116
-rw-r--r--app/directory.ts210
-rw-r--r--app/index.ts (renamed from app/index.mjs)54
-rw-r--r--app/static/css/globalstyles.css100
-rw-r--r--app/static/scripts/purge.js15
-rw-r--r--app/static/scripts/rebuild.js14
-rw-r--r--app/views/error.ejs19
-rw-r--r--app/views/index.ejs18
-rw-r--r--app/views/page.ejs20
-rw-r--r--app/views/partials/header.ejs12
-rw-r--r--app/views/partials/navbar.ejs3
-rw-r--r--app/views/purge.ejs24
-rw-r--r--app/views/rebuild.ejs23
-rw-r--r--app/wikiparser.mjs7
15 files changed, 243 insertions, 401 deletions
diff --git a/app/constants.mjs b/app/constants.mjs
deleted file mode 100644
index ace7e2f..0000000
--- a/app/constants.mjs
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-export const SERVER_PORT = 3000;
-export const PARSER_MAX_RECURSION = 20;
-export const PURGE_COOLDOWN_MIN = -1;
-export const REBUILD_COOLDOWN_MIN = -1;
-export const PAGES_DIR = 'pages';
-export const TEMPLATE_DIR = 'pages/tempates';
-export const IMAGES_DIR = 'pages/images';
diff --git a/app/directory.mjs b/app/directory.mjs
deleted file mode 100644
index b470bc7..0000000
--- a/app/directory.mjs
+++ /dev/null
@@ -1,116 +0,0 @@
-'use strict';
-
-import { PAGES_DIR, PURGE_COOLDOWN_MIN, REBUILD_COOLDOWN_MIN } from './constants.mjs';
-import { parse } from './wikiparser.mjs';
-import { readFileSync, readdirSync } from 'fs';
-
-const pages = {};
-const metadata = {};
-
-export function pageFor(path) {
- path = path.replace(/[^a-z0-9]/gi, '_').toLowerCase();
- let page = pages[path];
- if (!page) {
- return undefined;
- }
-
- if (!page.html) {
- buildPage(path);
- return pages[path];
- }
-
- return page;
-}
-
-function buildPage(path) {
- let data;
- try {
- data = readFileSync(`${PAGES_DIR}/${path}.wiki`, 'utf-8');
- } catch {
- return false;
- }
- let result = parse(data);
- let title = result.metadata.displayTitle ?? 'Unnamed page';
- let content = `${result.metadata.notitle ? '' : `<h1>${title}</h1>`}${result.html}`;
-
- let page = {
- html: content,
- raw: data,
- buildTime: result.metadata.buildTime,
- primary: result.metadata.primary ?? false,
- sortOrder: result.metadata.sortOrder ?? -1,
- notitle: result.metadata.notitle ?? false,
- displayTitle: title
- };
- pages[path] = page;
- return true;
-}
-
-export function rebuild() {
- if (metadata.fileTreeBuildTime + REBUILD_COOLDOWN_MIN * 60 * 1000 > Date.now()) {
- return false;
- }
- for (var page in pages) {
- delete pages[page];
- }
-
- readdirSync(PAGES_DIR).forEach(file => {
- if (!file.endsWith('.wiki')) {
- return;
- }
- file = file.replace('.wiki', '');
- buildPage(file);
- });
-
- let primaryPages = [];
- for (const page of Object.keys(pages)) {
- if (pages[page].primary) {
- primaryPages.push(page);
- }
- }
- primaryPages.sort((a, b) => {
- return pages[a].sortOrder - pages[b].sortOrder;
- });
- metadata.navbar = primaryPages;
- metadata.fileTreeBuildTime = new Date();
- return true;
-}
-
-export function exists(path) {
- return !!pages[path];
-}
-
-export function rawDataFor(path) {
- return pages[path];
-}
-
-export function purge(path) {
- let page = pages[path];
- if (page) {
- if (page.buildTime.getTime() + PURGE_COOLDOWN_MIN * 60 * 1000 > Date.now()) {
- return false;
- } else {
- pages[path] = {};
- if (buildPage(path)) {
- return true;
- }
- delete pages[path];
- }
- }
- return false;
-}
-
-export function getPages() {
- return pages;
-}
-
-export function getNavbar(current = '') {
- if (!metadata.navbar) {
- return '';
- }
- let navbar = '';
- for (const page of metadata.navbar) {
- navbar = navbar + `<div class="navbar-element"><a href="/${page}"${current == page ? ' class="highlight"' : ''}>${pages[page].displayTitle}</a></div>`;
- }
- return navbar;
-}
diff --git a/app/directory.ts b/app/directory.ts
new file mode 100644
index 0000000..6449e8e
--- /dev/null
+++ b/app/directory.ts
@@ -0,0 +1,210 @@
+'use strict';
+
+import { parse } from './wikiparser.mjs';
+import { readFileSync, readdirSync, statSync } from 'fs';
+import glob from 'glob';
+
+export class PageDirectory {
+
+ pages: Record<string, Page>;
+ primaryPages: Page[];
+ pagePath: string;
+ lastBuild: number;
+
+ constructor(root: string) {
+ this.lastBuild = 0;
+ this.pages = {};
+ this.pagePath = root;
+
+ this.rebuild();
+ }
+
+ /**
+ * Build this page directory.
+ *
+ * @returns whether the directory was built
+ */
+ rebuild(): boolean {
+ if (this.lastBuild + parseInt(process.env.REBUILD_COOLDOWN_MIN, 10) * 60 * 1000 > Date.now()) {
+ return false;
+ }
+ for (var page in this.pages) {
+ delete this.pages[page];
+ }
+
+ let pages = glob.sync(`**/*.wiki`, { cwd: this.pagePath })
+
+ pages.forEach(page => {
+ page = page.replace('.wiki', '').replace('/', ':').replace(/[^a-z0-9:]/gi, '_').toLowerCase();
+ this.pages[page] = this.buildPage(page);
+ });
+
+ let primaryPages = [];
+ Object.entries(this.pages).forEach(([name, page]) => {
+ if (page.metadata.includeInNavbar) {
+ primaryPages.push(page);
+ }
+ });
+
+ primaryPages.sort((a, b) => {
+ return a.metadata.sortOrder - b.metadata.sortOrder;
+ });
+ this.primaryPages = primaryPages;
+ this.lastBuild = Date.now();
+ return true;
+ }
+
+ /**
+ * Get whether a page exists with this name.
+ *
+ * @param name standard name for page
+ * @returns whether the page exists
+ */
+ exists(name: string): boolean {
+ return !!this.pages[this.convertNameToStandard(name)];
+ }
+
+ /**
+ * Get a page.
+ *
+ * @param name standard name for page
+ * @returns page
+ */
+ get(name: string): Page {
+ name = this.convertNameToStandard(name);
+ let page = this.pages[name];
+ if (!page) {
+ return undefined;
+ }
+
+ if (!page.html) {
+ return this.buildPage(name)
+ }
+
+ return page;
+ }
+
+ /**
+ * Get the raw wikitext for a page.
+ *
+ * @param name standard name for page
+ * @returns raw wikitext
+ */
+ getRaw(name: string): string {
+ name = this.convertNameToStandard(name);
+ return this.pages[name]?.raw;
+ }
+
+ /**
+ * Purge (rebuild) a page.
+ *
+ * @param name standard name for page
+ * @returns whether the page was rebuilt
+ */
+ purge(name: string): boolean {
+ name = this.convertNameToStandard(name);
+ let page = this.pages[name];
+ if (page) {
+ if (page.buildTime + parseInt(process.env.PURGE_COOLDOWN_MIN, 10) * 60 * 1000 > Date.now()) {
+ return false;
+ } else {
+ delete this.pages[name];
+ if (this.buildPage(name)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get all pages.
+ *
+ * @returns all pages
+ */
+ getPages(): Record<string, Page> {
+ return this.pages;
+ }
+
+ /**
+ * Get primary pages.
+ *
+ * @param current
+ * @returns
+ */
+ getPrimaryPages(): Page[] {
+ return this.primaryPages;
+ }
+
+ /**
+ * Build a page.
+ *
+ * @param path standard name for page
+ * @returns newly built page, or undefined
+ */
+ private buildPage(name: string): Page {
+ name = this.convertNameToStandard(name);
+ let data: string;
+ try {
+ data = readFileSync(`${this.pagePath}/${this.convertStandardToFilePath(name)}`, 'utf-8');
+ } catch {
+ return undefined;
+ }
+ let result = parse(data);
+ let title = result.metadata.displayTitle ?? name;
+ let content = `${result.metadata.notitle ? '' : `<h1>${title}</h1>`}${result.html}`;
+
+ let page: Page = {
+ html: content,
+ raw: data,
+ standardName: name,
+ buildTime: Date.now(),
+ metadata: {
+ includeInNavbar: result.metadata.primary ?? false,
+ sortOrder: result.metadata.sortOrder ?? -1,
+ showTitle: !result.metadata.notitle ?? true,
+ displayTitle: title
+ }
+ };
+ this.pages[name] = page;
+ return page;
+ }
+
+ /**
+ * Convert a page name to a standard name.
+ * A standard name is the key used by the page directory.
+ *
+ * @param name non-standard name for a page
+ */
+ private convertNameToStandard(name: string): string {
+ return name.replace(/[^a-z0-9:]/gi, '_').toLowerCase();
+ }
+
+ /**
+ * Convert a standard name to a file path.
+ *
+ * @param name standard name for a page
+ */
+ private convertStandardToFilePath(name: string): string {
+ let [first, second] = name.split(':');
+ let [title, subpage] = ((second) ? second : first).split('.')
+ let namespace = (second) ? first : undefined
+
+ return `${namespace ? `${namespace}/` : ''}${title}${subpage ? `.${subpage}` : ''}.wiki`
+ }
+};
+
+export type Page = {
+ html: string;
+ raw: string;
+ standardName: string,
+ buildTime: number;
+ metadata: PageMetadata;
+};
+
+export type PageMetadata = {
+ displayTitle?: string;
+ sortOrder?: number;
+ showTitle?: boolean;
+ includeInNavbar?: boolean;
+};
diff --git a/app/index.mjs b/app/index.ts
index 0f14ccf..9b16ec5 100644
--- a/app/index.mjs
+++ b/app/index.ts
@@ -1,38 +1,44 @@
'use strict';
-import { SERVER_PORT } from './constants.mjs';
-import * as directory from './directory.mjs';
+import { PageDirectory, Page, PageMetadata } from './directory.js';
import express from 'express';
-import { fileURLToPath } from 'url';
-import { dirname } from 'path';
+import dotenv from 'dotenv';
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = dirname(__filename);
+dotenv.config()
const app = express();
+const directory = new PageDirectory(process.env.PAGES_DIR);
directory.rebuild();
-app.use(express.static(__dirname + '/static'));
+function navbar(current: string = ''): string {
+ let navbar = '';
+ directory.primaryPages.forEach(page => {
+ navbar += `<div class="navbar-element"><a href="/${page.standardName}"${current == page.standardName ? ' class="highlight"' : ''}>${page.metadata.displayTitle}</a></div>`;
+ })
+ return navbar
+}
+
+app.use(express.static('static'));
app.set('view engine', 'ejs');
-app.set('views', __dirname + '/views');
+app.set('views', 'views');
app.get('/:page.wiki', (req, res) => {
let path = req.params.page;
- let page = directory.pageFor(path);
+ let raw = directory.getRaw(path);
- if (!page) {
+ if (!raw) {
error(res, 404);
return;
}
res.type('text/plain');
- res.send(page.raw).end();
+ res.send(raw).end();
});
app.get('/:page?', (req, res) => {
let path = req.params.page ?? 'index';
- let page = directory.pageFor(path);
+ let page = directory.get(path);
if (!page) {
error(res, 404);
@@ -40,17 +46,17 @@ app.get('/:page?', (req, res) => {
}
res.render('page.ejs', {
- navbar: directory.getNavbar(path),
+ navbar: navbar(),
path: path,
content: page.html,
- title: page.displayTitle,
- buildTime: page.buildTime.toString()
+ title: page.metadata.displayTitle,
+ buildTime: new Date(page.buildTime)
});
});
app.get('/special/purge/:page?', (req, res) => {
let path = req.params.page ?? 'index';
- let page = directory.rawDataFor(path);
+ let page = directory.get(path);
if (!page) {
error(res, 404);
@@ -58,16 +64,16 @@ app.get('/special/purge/:page?', (req, res) => {
}
res.render('purge.ejs', {
- navbar: directory.getNavbar(),
+ navbar: navbar(),
page: path,
- buildTime: page.buildTime?.toString() ?? 'never',
- buildTimeRelative: Math.round((Date.now() - page.buildTime?.getTime()) / 1000 / 60)
+ buildTime: new Date(page.buildTime) ?? 'never',
+ buildTimeRelative: Math.round((Date.now() - page.buildTime) / 1000 / 60)
});
});
app.get('/special/purge/:page/confirm', (req, res) => {
let path = req.params.page;
- let page = directory.rawDataFor(path);
+ let page = directory.get(path);
if (!page) {
error(res, 404);
@@ -83,7 +89,7 @@ app.get('/special/purge/:page/confirm', (req, res) => {
app.get('/special/rebuild', (req, res) => {
res.render('rebuild.ejs', {
- navbar: directory.getNavbar()
+ navbar: navbar()
});
});
@@ -95,13 +101,13 @@ app.get('/special/rebuild/confirm', (req, res) => {
}
});
-app.listen(SERVER_PORT, () => {
- console.log(`App listening on ${SERVER_PORT}`);
+app.listen(process.env.PORT, () => {
+ console.log(`App listening on ${process.env.PORT}`);
});
function error(res, code) {
res.render('error.ejs', {
code: code,
- navbar: directory.getNavbar()
+ navbar: navbar()
});
}
diff --git a/app/static/css/globalstyles.css b/app/static/css/globalstyles.css
deleted file mode 100644
index 774c6ca..0000000
--- a/app/static/css/globalstyles.css
+++ /dev/null
@@ -1,100 +0,0 @@
-@import url('https://fonts.googleapis.com/css2?family=Cousine:ital,wght@0,400;0,700;1,400;1,700&display=swap');
-
-.website-name {
- font-size: 10px;
- font-weight: 700;
- line-height: 1.2;
- color: #ddd;
- text-shadow: 0px 1px 10px #9876aa;
-}
-
-html, body {
- border: 0;
- margin: 0;
- background-color: #111;
- color: #ddd;
- font-family: 'Cousine', monospace, sans-serif;
- line-height: 1.3;
-}
-
-h1, h2, h3, h4, h5, h6 {
- color: #cc7832
-}
-
-.code-block {
- background-color: #222;
- border: solid 1px #333;
- padding: 10px;
-}
-
-#navbar {
- background-color: #222;
- width: 100%;
- display: flex;
- flex-direction: row;
- justify-content: flex-start;
- align-items: stretch;
- gap: 10px;
-}
-
-.navbar-element {
- background-color: #222;
- display: flex;
- height: 30px;
- text-align: center;
- line-height: 30px;
- padding: 10px;
-}
-
-.navbar-element:hover {
- background-color: #888;
- transition: 0.2s;
- cursor: pointer;
-}
-
-.navbar-element > a {
- color: #fff;
- text-decoration: none;
-}
-
-.navbar-element > .highlight {
- color: #ffc66d;
-}
-
-#main-container {
- max-width: 1200px;
- margin: 0 auto;
-}
-
-#content-container {
- box-shadow: 0px 0px 15px 10px rgba(152,118,170,0.05);
-}
-
-#content {
- padding: 20px;
- max-width: 1200px;
- background-color: #2b2b2b;
- margin: 0 auto;
-}
-
-a {
- color: #9876aa;
- text-decoration: underline;
-}
-
-.highlight {
- color: #ffc66d;
-}
-
-.footer {
- font-size: 10px;
-}
-
-.redlink {
- color: #ff4136;
-}
-
-.box {
- border: solid 1px #fff;
- padding: 10px;
-}
diff --git a/app/static/scripts/purge.js b/app/static/scripts/purge.js
deleted file mode 100644
index 5ee34f0..0000000
--- a/app/static/scripts/purge.js
+++ /dev/null
@@ -1,15 +0,0 @@
-$(() => {
- $('#confirm').click(() => {
- let page = $('#confirm').data('page');
- $.ajax({
- type: 'GET',
- url: `/special/purge/${page}/confirm`,
- success: () => {
- $('#response').html('<div class=\'box\'>Successfully purged page.</div>');
- },
- error: () => {
- $('#response').html('<div class=\'box\'>Could not purge page. Try again later.</div>');
- }
- });
- });
-});
diff --git a/app/static/scripts/rebuild.js b/app/static/scripts/rebuild.js
deleted file mode 100644
index 8fd0e2e..0000000
--- a/app/static/scripts/rebuild.js
+++ /dev/null
@@ -1,14 +0,0 @@
-$(() => {
- $('#confirm').click(() => {
- $.ajax({
- type: 'GET',
- url: `/special/rebuild/confirm`,
- success: () => {
- $('#response').html('<div class=\'box\'>Successfully rebuilt page directory.</div>');
- },
- error: () => {
- $('#response').html('<div class=\'box\'>Could not rebuild page directory. Try again later.</div>');
- }
- });
- });
-});
diff --git a/app/views/error.ejs b/app/views/error.ejs
deleted file mode 100644
index 88e1a27..0000000
--- a/app/views/error.ejs
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Error: <%= code %></title>
- <link rel="stylesheet" href="/css/globalstyles.css">
-</head>
-<body>
- <div id="main-container">
- <%- include('partials/header') %>
- <div id="content-container">
- <%- include('partials/navbar') %>
- <div id="content">
- <h1>An error occurred (<%= code %>)</h1>
- <p>Go <a href="/">home</a>?</p>
- </div>
- </div>
- </div>
-</body>
-</html>
diff --git a/app/views/index.ejs b/app/views/index.ejs
deleted file mode 100644
index f47b830..0000000
--- a/app/views/index.ejs
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title><%= title %></title>
- <link rel="stylesheet" href="/css/globalstyles.css">
-</head>
-<body>
- <div id="main-container">
- <%- include('partials/header') %>
- <div id="content-container">
- <%- include('partials/navbar') %>
- <div id="content">
- <%- page %>
- </div>
- </div>
- </div>
-</body>
-</html>
diff --git a/app/views/page.ejs b/app/views/page.ejs
deleted file mode 100644
index 41ee1e2..0000000
--- a/app/views/page.ejs
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title><%= title %></title>
- <link rel="stylesheet" href="/css/globalstyles.css">
-</head>
-<body>
- <div id="main-container">
- <%- include('partials/header') %>
- <div id="content-container">
- <%- include('partials/navbar') %>
- <div id="content">
- <%- content %>
- <hr>
- <span class=footer><a href="https://github.com/LMBishop/website">GitHub</a> | <a href="/<%= path %>.wiki">View raw</a> | Page built: <%= buildTime %> | <a href="/special/purge/<%= path %>">Purge this page</a></span>
- </div>
- </div>
- </div>
-</body>
-</html>
diff --git a/app/views/partials/header.ejs b/app/views/partials/header.ejs
deleted file mode 100644
index bd11ce0..0000000
--- a/app/views/partials/header.ejs
+++ /dev/null
@@ -1,12 +0,0 @@
-<pre class="website-name">
-
-<!--
-██╗ ███╗ ███╗██████╗ ██╗███████╗██╗ ██╗ ██████╗ ██████╗
-██║ ████╗ ████║██╔══██╗██║██╔════╝██║ ██║██╔═══██╗██╔══██╗
-██║ ██╔████╔██║██████╔╝██║███████╗███████║██║ ██║██████╔╝
-██║ ██║╚██╔╝██║██╔══██╗██║╚════██║██╔══██║██║ ██║██╔═══╝
-███████╗██║ ╚═╝ ██║██████╔╝██║███████║██║ ██║╚██████╔╝██║
-╚══════╝╚═╝ ╚═╝╚═════╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝
-
- -->
-</pre>
diff --git a/app/views/partials/navbar.ejs b/app/views/partials/navbar.ejs
deleted file mode 100644
index ff0c84d..0000000
--- a/app/views/partials/navbar.ejs
+++ /dev/null
@@ -1,3 +0,0 @@
-<div id="navbar">
- <%- navbar %>
-</div>
diff --git a/app/views/purge.ejs b/app/views/purge.ejs
deleted file mode 100644
index 04bae61..0000000
--- a/app/views/purge.ejs
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Purge page</title>
- <link rel="stylesheet" href="/css/globalstyles.css">
- <script src="https://code.jquery.com/jquery-3.6.0.min.js" ntegrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
- <script src="/scripts/purge.js"></script>
-</head>
-<body>
- <div id="main-container">
- <%- include('partials/header') %>
- <div id="content-container">
- <%- include('partials/navbar') %>
- <div id="content">
- <h1>Purge page</h1>
- <span id="response"></span>
- <p>Are you sure you wish to purge the page <span class="highlight"><%= page %></span>?</p>
- <p>The last build time for this page was <span class="highlight"><%= buildTime %></span> (<span class="highlight"><%= buildTimeRelative %></span> minutes ago).</p>
- <button id="confirm" data-page="<%= page %>">Confirm</button>
- </div>
- </div>
- </div>
-</body>
-</html>
diff --git a/app/views/rebuild.ejs b/app/views/rebuild.ejs
deleted file mode 100644
index 9f9cfaa..0000000
--- a/app/views/rebuild.ejs
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Rebuild</title>
- <link rel="stylesheet" href="/css/globalstyles.css">
- <script src="https://code.jquery.com/jquery-3.6.0.min.js" ntegrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
- <script src="/scripts/rebuild.js"></script>
-</head>
-<body>
- <div id="main-container">
- <%- include('partials/header') %>
- <div id="content-container">
- <%- include('partials/navbar') %>
- <div id="content">
- <h1>Rebuild</h1>
- <span id="response"></span>
- <p>Are you sure you wish to rebuild the page directory?</p>
- <button id="confirm">Confirm</button>
- </div>
- </div>
- </div>
-</body>
-</html>
diff --git a/app/wikiparser.mjs b/app/wikiparser.mjs
index 512d985..e49a09c 100644
--- a/app/wikiparser.mjs
+++ b/app/wikiparser.mjs
@@ -18,7 +18,6 @@
// in an action of contract, negligence or other tortious action, arising out of or in
// connection with the use or performance of this software.
-import { PARSER_MAX_RECURSION, TEMPLATE_DIR, IMAGES_DIR } from './constants.mjs';
import dateFormat from 'dateformat';
import htmlEscape from 'escape-html';
import * as fs from 'fs';
@@ -40,7 +39,7 @@ export function parse(data) {
let outText = data;
- for (let l = 0, last = ''; l < PARSER_MAX_RECURSION; l++) {
+ for (let l = 0, last = ''; l < parseInt(process.env.PARSER_MAX_RECURSION, 10); l++) {
if (last === outText) break; last = outText;
outText = outText
@@ -117,7 +116,7 @@ export function parse(data) {
// Templates: {{template}}
.replace(re(r`{{ \s* ([^#}|]+?) (\|[^}]+)? }} (?!})`), (_, title, params = '') => {
if (/{{/.test(params)) return _;
- const page = TEMPLATE_DIR + '/' + title.trim().replace(/ /g, '_');
+ const page = 'Template:' + title.trim().replace(/ /g, '_');
// Retrieve template content
let content = '';
@@ -151,7 +150,7 @@ export function parse(data) {
// Images: [[File:Image.png|options|caption]]
.replace(re(r`\[\[ (?:File|Image): (.+?) (\|.+?)? \]\]`), (_, file, params) => {
if (/{{/.test(params)) return _;
- const path = IMAGES_DIR + '/' + file.trim().replace(/ /g, '_');
+ const path = 'File:' + file.trim().replace(/ /g, '_');
let caption = '';
let imageData = {};
let imageArgs = params.split('|').map((arg) => arg.replace(/"/g, '&quot;'));