@the-starport/nodebb-plugin-mdx-page-renderer 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,8 +18,10 @@ const sitemapLib = require('./sitemap');
18
18
  const sources = require('./sources');
19
19
  const { resolveLocalPath } = sources;
20
20
  const staticExport = require('./static-export');
21
+ const {fixPrefixPath} = require("./utils");
21
22
 
22
23
  const user = require.main.require('./src/user');
24
+ const winston = require.main.require('winston');
23
25
 
24
26
  // Public controllers
25
27
 
@@ -35,22 +37,26 @@ const user = require.main.require('./src/user');
35
37
  * @returns {Promise<void>}
36
38
  */
37
39
  async function renderPage(req, res, next) {
38
- // Strip /api prefix if present. ajaxify fetches /api/{path} for SPA
39
- // navigation; the catch-all in library.js dispatches both forms here.
40
+ // Strip /api prefix if present. ajaxify fetches /api/{path} for SPA navigation
40
41
  const urlPath = (req.path.startsWith('/api/')
41
- ? req.path.slice(4)
42
- : req.path
43
- ).replace(/^\/+/, '');
42
+ ? req.path.slice(4)
43
+ : req.path
44
+ )
44
45
 
46
+ // Grab the possible sources this route matches
45
47
  const matchingSources = sources.getAll().filter(function (s) {
46
- return urlPath === s.urlPrefix || urlPath.startsWith(s.urlPrefix + '/');
48
+ const urlPrefix = fixPrefixPath(s.urlPrefix);
49
+ return urlPath.startsWith(urlPrefix);
47
50
  });
48
51
 
49
52
  // Longest prefix wins (e.g. "wiki/guide" over "wiki") when both match.
50
- matchingSources.sort(function (a, b) { return b.urlPrefix.length - a.urlPrefix.length; });
53
+ matchingSources.sort(function (a, b) { return fixPrefixPath(b.urlPrefix).length - fixPrefixPath(a.urlPrefix).length; });
51
54
 
52
- const prefix = matchingSources.length ? matchingSources[0].urlPrefix : '';
53
- const rawPath = urlPath.startsWith(prefix + '/') ? urlPath.slice(prefix.length + 1) : '';
55
+ let prefix = matchingSources.length ? matchingSources[0].urlPrefix : '';
56
+ const rawPath = req.params[0] ? req.params[0] : '';
57
+
58
+ winston.verbose('[mdx-page-renderer] Matching prefix: ' + prefix);
59
+ winston.verbose('[mdx-page-renderer] Matching route: ' + rawPath);
54
60
 
55
61
  // Treat a bare prefix URL as a request for index.mdx.
56
62
  const effectivePath = rawPath || 'index';
@@ -70,19 +76,33 @@ async function renderPage(req, res, next) {
70
76
  }
71
77
 
72
78
  if (!filePath) {
79
+ winston.verbose('[mdx-page-renderer] Unable to find file path: ' + resolvedEffectivePath);
80
+
73
81
  // No content found for this path. Prompt to admins visiting the bare prefix URL; everyone else gets a 404.
74
82
  if (!rawPath) {
75
83
  const isAdmin = req.uid && await user.isAdministrator(req.uid);
76
84
  if (isAdmin) {
77
85
  return res.render('mdx-page', {
78
86
  title: 'MDX Page',
79
- content: buildNoContentHtml(prefix),
87
+ content: buildNoContentHtml(fixPrefixPath(prefix)),
80
88
  });
81
89
  }
82
90
  }
91
+
83
92
  return next();
84
93
  }
85
94
 
95
+ // Due to needing to handle relative paths, we need to invert any fixing of the prefix path in the same way here
96
+ if (prefix) {
97
+ if (prefix.charAt(0) === '/') {
98
+ prefix = prefix.substring(1, prefix.length);
99
+ }
100
+
101
+ if (prefix.slice(-1) === '/') {
102
+ prefix = prefix.substring(0, prefix.length - 1);
103
+ }
104
+ }
105
+
86
106
  try {
87
107
  const sourceText = fs.readFileSync(filePath, 'utf8');
88
108
 
@@ -117,7 +137,7 @@ async function renderPage(req, res, next) {
117
137
 
118
138
  res.render('mdx-page', { title, content: html, breadcrumbs, showSidebarToc, tocHtml });
119
139
  } catch (err) {
120
- console.error('[mdx-page-renderer] Failed to render page ' + filePath + ':', err);
140
+ winston.error('[mdx-page-renderer] Failed to render page ' + filePath + ':', err);
121
141
  res.status(500).render('mdx-page', {
122
142
  title: 'Render error',
123
143
  content: '<p>Failed to render this page. Check the server logs for details.</p>' +
package/lib/sources.js CHANGED
@@ -10,6 +10,28 @@
10
10
  * flagged for admin review.
11
11
  */
12
12
 
13
+ /**
14
+ * @typedef {Object} SourceConfig
15
+ * @property {string} type
16
+ * @property {string} label
17
+ * @property {string} urlPrefix
18
+ * @property {string} url
19
+ */
20
+
21
+ /**
22
+ * @typedef {Object} SourceObject
23
+ * @property {string} id
24
+ * @property {string} type
25
+ * @property {string} label
26
+ * @property {string} url
27
+ * @property {string} urlPrefix
28
+ * @property {string} localPath
29
+ * @property {string} createdAt
30
+ * @property {boolean} showIndexToc
31
+ * @property {string | undefined} asset
32
+ * @property {string | undefined} tag
33
+ */
34
+
13
35
  const crypto = require('crypto');
14
36
  const fs = require('fs');
15
37
  const https = require('https');
@@ -28,7 +50,8 @@ const settings = require('./settings');
28
50
  /** Database key used to persist the list of configured sources. */
29
51
  const DB_KEY = 'mdx-page-renderer:sources';
30
52
 
31
- /** In-memory list of source objects. Populated by loadAll(). */
53
+ /** In-memory list of source objects. Populated by loadAll().
54
+ * @type {SourceObject[]} */
32
55
  let sourceList = [];
33
56
 
34
57
  // Public API
@@ -44,7 +67,7 @@ async function loadAll() {
44
67
 
45
68
  /**
46
69
  * getAll - returns a copy of the current source list.
47
- * @returns {object[]}
70
+ * @returns {SourceObject[]}
48
71
  */
49
72
  function getAll() {
50
73
  return [...sourceList];
@@ -62,7 +85,7 @@ function getById(id) {
62
85
  /**
63
86
  * add - validates, creates, and persists a new source.
64
87
  * Returns the created source object (with generated ID and localPath).
65
- * @param {{ type: string, label: string, url?: string, urlPrefix: string }} sourceConfig
88
+ * @param {SourceConfig} sourceConfig
66
89
  * @returns {Promise<object>} The created source object.
67
90
  */
68
91
  async function add(sourceConfig) {
package/lib/utils.js ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @param prefix {string} A url prefix
3
+ * @returns {string} The prefix with a forward slash added to the front, and removed from the end
4
+ */
5
+ const fixPrefixPath = (prefix) => {
6
+ if (prefix.charAt(0) !== '/') {
7
+ prefix = '/' + prefix;
8
+ }
9
+
10
+ // Remove dangling slashes
11
+ if (prefix.slice(-1) === '/') {
12
+ prefix = prefix.substring(0, prefix.length - 1);
13
+ }
14
+
15
+ return prefix;
16
+ }
17
+
18
+ module.exports = {
19
+ fixPrefixPath,
20
+ }
package/library.js CHANGED
@@ -6,9 +6,11 @@
6
6
  */
7
7
 
8
8
  const controllers = require('./lib/controllers');
9
- const sources = require('./lib/sources');
10
- const doxygen = require('./lib/doxygen');
11
- const settings = require('./lib/settings');
9
+ const sources = require('./lib/sources');
10
+ const doxygen = require('./lib/doxygen');
11
+ const settings = require('./lib/settings');
12
+ const {fixPrefixPath} = require("./lib/utils");
13
+ const winston = require.main.require('winston');
12
14
 
13
15
  // Provides setupAdminPageRoute which applies the admin middleware stack and
14
16
  // auto-registers a /api/ JSON mirror of the route.
@@ -16,12 +18,14 @@ const routeHelpers = require.main.require('./src/routes/helpers');
16
18
 
17
19
  const Plugin = module.exports;
18
20
 
21
+ const PLUGIN_NAME = 'mdx-page-renderer';
22
+
19
23
  /**
20
24
  * init - registered against the `static:app.load` hook.
21
25
  * @param {{ router: import('express').Router, middleware: object }} params
22
26
  * @returns {Promise<void>}
23
27
  */
24
- Plugin.init = async function ({ router, middleware }) {
28
+ Plugin.init = async function ({router, middleware}) {
25
29
  await settings.load();
26
30
 
27
31
  // Load content and Doxygen data from any previously-configured sources.
@@ -36,53 +40,48 @@ Plugin.init = async function ({ router, middleware }) {
36
40
  // --- Admin panel page ---
37
41
  routeHelpers.setupAdminPageRoute(router, '/admin/plugins/mdx-page-renderer', controllers.renderAdmin);
38
42
 
39
- // --- Admin mutation endpoints ---
40
- const base = '/admin/plugins/mdx-page-renderer';
41
- router.post(`${base}/save`, controllers.saveSettings);
42
- router.post(`${base}/source`, controllers.addSource);
43
- router.post(`${base}/source/update`, controllers.updateSource);
44
- router.post(`${base}/source/remove`, controllers.removeSource);
45
- router.post(`${base}/refresh`, controllers.refreshSource);
46
- router.post(`${base}/clear-cache`, controllers.clearRenderCache);
47
- router.post(`${base}/export`, controllers.exportStatic);
48
-
49
- // Inline source page editor endpoints
50
- router.get(`${base}/inline/pages`, controllers.listInlinePages);
51
- router.get(`${base}/inline/page`, controllers.getInlinePage);
52
- router.post(`${base}/inline/page`, controllers.saveInlinePage);
53
- router.delete(`${base}/inline/page`, controllers.deleteInlinePage);
54
-
55
- // --- Content page catch-all ---
56
- // One catch-all dispatches to the correct source at request time, so sources
57
- // added in the admin panel take effect without a restart. Registered last so
58
- // it does not shadow NodeBB's own routes.
59
- router.get('*', function routeToDocPage(req, res, next) {
60
- // ajaxify fetches /api/{path} for SPA navigation; strip it to get the real path.
61
- const isApi = req.path.startsWith('/api/');
62
- const urlPath = (isApi ? req.path.slice(4) : req.path).replace(/^\/+/, '');
63
-
64
- if (!urlPath) {
65
- return next();
43
+ const availableSources = sources.getAll();
44
+ // Sort the array so the most specific routes are setup first
45
+ availableSources.sort(function (a, b) { return b.urlPrefix.length - a.urlPrefix.length; })
46
+ for (const source of availableSources) {
47
+ let prefix = source.urlPrefix;
48
+ if (!prefix) {
49
+ continue;
66
50
  }
67
51
 
68
- // Match exact prefix or prefix followed by slash (supports multi-segment prefixes like "wiki/guide").
69
- const matched = sources.getAll().some(function (s) {
70
- return urlPath === s.urlPrefix || urlPath.startsWith(s.urlPrefix + '/');
71
- });
52
+ prefix = fixPrefixPath(prefix);
72
53
 
73
- if (!matched) {
74
- return next();
75
- }
54
+ winston.info(`[mdx-page-renderer] Registering source: ${prefix}`);
55
+ routeHelpers.setupPageRoute(router, `${prefix}/*`, controllers.renderPage)
56
+ routeHelpers.setupPageRoute(router, `${prefix}`, controllers.renderPage)
57
+ }
58
+ };
76
59
 
77
- if (isApi) {
78
- // API requests come from ajaxify - buildHeader would interfere with the JSON response.
79
- controllers.renderPage(req, res, next);
80
- } else {
81
- middleware.buildHeader(req, res, function (err) {
82
- if (err) return next(err);
83
- controllers.renderPage(req, res, next);
84
- });
85
- }
60
+ Plugin.addRoutes = async ({router, middleware, helpers}) => {
61
+ const controllers = require('./lib/controllers');
62
+ const middlewares = [
63
+ middleware.authenticateRequest,
64
+ middleware.logApiUsage,
65
+ middleware.ensureLoggedIn,
66
+ middleware.admin.checkPrivileges,
67
+ ];
68
+
69
+ routeHelpers.setupApiRoute(router, 'post', `/${PLUGIN_NAME}/save`, middlewares, controllers.saveSettings);
70
+ routeHelpers.setupApiRoute(router, 'post', `/${PLUGIN_NAME}/source`, middlewares, controllers.addSource);
71
+ routeHelpers.setupApiRoute(router, 'post', `/${PLUGIN_NAME}/source/update`, middlewares, controllers.updateSource);
72
+ routeHelpers.setupApiRoute(router, 'post', `/${PLUGIN_NAME}/source/remove`, middlewares, controllers.removeSource);
73
+ routeHelpers.setupApiRoute(router, 'post', `/${PLUGIN_NAME}/refresh`, middlewares, controllers.refreshSource);
74
+ routeHelpers.setupApiRoute(router, 'post', `/${PLUGIN_NAME}/clear-cache`, middlewares, controllers.clearRenderCache);
75
+ routeHelpers.setupApiRoute(router, 'post', `/${PLUGIN_NAME}/export`, middlewares, controllers.exportStatic);
76
+
77
+ // Inline source page editor endpoints
78
+ routeHelpers.setupApiRoute(router, 'get', `/${PLUGIN_NAME}/inline/pages`, middlewares, controllers.listInlinePages);
79
+ routeHelpers.setupApiRoute(router, 'get', `/${PLUGIN_NAME}/inline/page`, middlewares, controllers.getInlinePage);
80
+ routeHelpers.setupApiRoute(router, 'post', `/${PLUGIN_NAME}/inline/page`, middlewares, controllers.saveInlinePage);
81
+ routeHelpers.setupApiRoute(router, 'delete', `/${PLUGIN_NAME}/inline/page`, middlewares, controllers.deleteInlinePage);
82
+
83
+ routeHelpers.setupApiRoute(router, 'get', `/test`, (req, res) => {
84
+ helpers.formatApiResponse(200, res, {})
86
85
  });
87
86
  };
88
87
 
@@ -93,9 +92,9 @@ Plugin.init = async function ({ router, middleware }) {
93
92
  */
94
93
  Plugin.addAdminNavigation = function (header) {
95
94
  header.plugins.push({
96
- route: '/plugins/mdx-page-renderer',
97
- icon: 'fa-file-alt',
98
- name: 'MDX Page Renderer',
95
+ route: '/plugins/mdx-page-renderer',
96
+ icon: 'fa-file-alt',
97
+ name: 'MDX Page Renderer',
99
98
  });
100
99
 
101
100
  return header;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the-starport/nodebb-plugin-mdx-page-renderer",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Serves MDX-based documentation pages within NodeBB, with server-side rendering and Doxygen API reference components.",
5
5
  "main": "library.js",
6
6
  "repository": {
package/plugin.json CHANGED
@@ -2,15 +2,21 @@
2
2
  "id": "nodebb-plugin-mdx-page-renderer",
3
3
  "name": "MDX Page Renderer",
4
4
  "description": "Serves MDX-based documentation pages within NodeBB with server-side rendering, Doxygen API reference components, and an admin panel for managing content sources.",
5
- "version": "1.0.0",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://codeberg.org/TheStarport/nodebb-plugin-mdx-page-renderer"
9
- },
5
+ "version": "1.0.1",
10
6
  "library": "./library.js",
11
7
  "hooks": [
12
- { "hook": "static:app.load", "method": "init" },
13
- { "hook": "filter:admin.header.build", "method": "addAdminNavigation" }
8
+ {
9
+ "hook": "static:app.load",
10
+ "method": "init"
11
+ },
12
+ {
13
+ "hook": "filter:admin.header.build",
14
+ "method": "addAdminNavigation"
15
+ },
16
+ {
17
+ "hook": "static:api.routes",
18
+ "method": "addRoutes"
19
+ }
14
20
  ],
15
21
  "scss": [
16
22
  "mdx.scss"
package/public/admin.js CHANGED
@@ -5,11 +5,11 @@
5
5
  /**
6
6
  * Admin panel AMD module for the MDX Page Renderer plugin.
7
7
  * Initial data comes from ajaxify.data (set by renderAdmin via res.render).
8
- * Mutations POST to /admin/plugins/mdx-page-renderer/* with a CSRF token.
8
+ * Mutations POST to /api/v3/plugins/mdx-page-renderer/* with a CSRF token.
9
9
  */
10
10
  define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alerts, bootbox) {
11
- const BASE = '/admin/plugins/mdx-page-renderer';
12
- const API = `/api${BASE}`;
11
+ const API = config.relative_path + '/api/v3/plugins/mdx-page-renderer';
12
+ const NAV_API = config.relative_path + '/api/admin/plugins/mdx-page-renderer';
13
13
 
14
14
  // HTTP helpers
15
15
  function postJSON(url, body) {
@@ -22,11 +22,10 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
22
22
  });
23
23
  }
24
24
 
25
-
26
25
  // Data loading
27
26
  // Reload settings and sources from the /api/ mirror of the admin page route.
28
27
  function loadData() {
29
- $.get(API)
28
+ $.get(NAV_API)
30
29
  .then(function (data) {
31
30
  populateSettings(data.settings || {});
32
31
  renderSourceList(data.sources || []);
@@ -109,7 +108,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
109
108
 
110
109
  const pathsEl = document.getElementById('mdx-content-paths');
111
110
  if (pathsEl) {
112
- $.get(API)
111
+ $.get(NAV_API)
113
112
  .then(function (data) {
114
113
  const sources = data.sources || [];
115
114
  pathsEl.innerHTML = sources.map(function (s) {
@@ -189,7 +188,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
189
188
  var listEl = document.getElementById('mdx-inline-page-list');
190
189
  listEl.innerHTML = '<p class="text-muted">Loading...</p>';
191
190
 
192
- $.get(BASE + '/inline/pages', { id: inlineEditor.sourceId })
191
+ $.get(API + '/inline/pages', { id: inlineEditor.sourceId })
193
192
  .then(function (data) {
194
193
  var pages = data.pages || [];
195
194
  if (!pages.length) {
@@ -229,7 +228,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
229
228
  inlineEditor.pagePath = pagePath;
230
229
  document.getElementById('mdx-inline-path').value = pagePath;
231
230
 
232
- $.get(BASE + '/inline/page', { id: inlineEditor.sourceId, path: pagePath })
231
+ $.get(API + '/inline/page', { id: inlineEditor.sourceId, path: pagePath })
233
232
  .then(function (data) {
234
233
  document.getElementById('mdx-inline-textarea').value = data.content || '';
235
234
  inlineEditor.showEditPane();
@@ -260,7 +259,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
260
259
 
261
260
  resultEl.textContent = 'Saving...';
262
261
 
263
- postJSON(BASE + '/inline/page', { id: inlineEditor.sourceId, path: pagePath, content: content })
262
+ postJSON(API + '/inline/page', { id: inlineEditor.sourceId, path: pagePath, content: content })
264
263
  .then(function () {
265
264
  inlineEditor.pagePath = pagePath;
266
265
  document.getElementById('mdx-inline-path').value = pagePath;
@@ -276,7 +275,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
276
275
  if (!window.confirm('Delete ' + pagePath + '?')) return;
277
276
 
278
277
  $.ajax({
279
- url: BASE + '/inline/page',
278
+ url: API + '/inline/page',
280
279
  type: 'DELETE',
281
280
  contentType: 'application/json',
282
281
  data: JSON.stringify({ id: inlineEditor.sourceId, path: pagePath }),
@@ -385,7 +384,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
385
384
  submitBtn.disabled = true;
386
385
  submitBtn.textContent = 'Adding...';
387
386
 
388
- postJSON(`${BASE}/source`, {type, label, urlPrefix, url, asset, tag})
387
+ postJSON(`${API}/source`, {type, label, urlPrefix, url, asset, tag})
389
388
  .then(function (res) {
390
389
  const sourceId = res.source.id;
391
390
  const sourceLabel = res.source.label;
@@ -406,7 +405,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
406
405
  '</div>';
407
406
  submitBtn.textContent = 'Downloading...';
408
407
 
409
- postJSON(`${BASE}/refresh`, {id: sourceId})
408
+ postJSON(`${API}/refresh`, {id: sourceId})
410
409
  .then(function (refreshRes) {
411
410
  const r = refreshRes.report;
412
411
  hideAddForm();
@@ -433,7 +432,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
433
432
  // Source operations
434
433
  // Patch mutable source fields; reloads on failure to revert the UI.
435
434
  function updateSource(id, data) {
436
- postJSON(`${BASE}/source/update`, {id, ...data})
435
+ postJSON(`${API}/source/update`, {id, ...data})
437
436
  .catch(function (err) {
438
437
  const msg = (err.responseJSON && err.responseJSON.error) || err.statusText;
439
438
  alerts.error(`Failed to update source: ${msg}`);
@@ -446,7 +445,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
446
445
  const resultEl = document.querySelector(`.mdx-refresh-result[data-id="${id}"]`);
447
446
  if (resultEl) resultEl.textContent = 'Refreshing...';
448
447
 
449
- postJSON(`${BASE}/refresh`, {id})
448
+ postJSON(`${API}/refresh`, {id})
450
449
  .then(function (res) {
451
450
  const r = res.report;
452
451
  let summary = `Added: ${r.added.length}, Updated: ${r.updated.length}, Deleted: ${r.autoDeleted.length}`;
@@ -471,7 +470,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
471
470
  },
472
471
  callback: function (confirmed) {
473
472
  if (!confirmed) return;
474
- postJSON(`${BASE}/source/remove`, {id})
473
+ postJSON(`${API}/source/remove`, {id})
475
474
  .then(function () {
476
475
  loadData();
477
476
  })
@@ -493,7 +492,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
493
492
  data[el.name] = el.value;
494
493
  });
495
494
 
496
- postJSON(`${BASE}/save`, data)
495
+ postJSON(`${API}/save`, data)
497
496
  .then(function () {
498
497
  alerts.success('Settings saved.');
499
498
  })
@@ -507,7 +506,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
507
506
  const resultEl = document.getElementById('mdx-clear-cache-result');
508
507
  resultEl.textContent = 'Clearing...';
509
508
 
510
- postJSON(`${BASE}/clear-cache`, {})
509
+ postJSON(`${API}/clear-cache`, {})
511
510
  .then(function () {
512
511
  resultEl.textContent = 'Cache cleared. Next page load will recompile.';
513
512
  })
@@ -520,7 +519,7 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
520
519
  const resultEl = document.getElementById('mdx-export-result');
521
520
  resultEl.textContent = 'Building...';
522
521
 
523
- postJSON(`${BASE}/export`, {})
522
+ postJSON(`${API}/export`, {})
524
523
  .then(function (res) {
525
524
  const r = res.result;
526
525
  let msg = `Done. Built ${r.built} page(s).`;
@@ -569,8 +568,6 @@ define('admin/plugins/mdx-page-renderer', ['alerts', 'bootbox'], function (alert
569
568
  // Delegate Refresh/Remove button clicks via the source list container.
570
569
  document.getElementById('mdx-source-list').addEventListener('click', function (e) {
571
570
  const id = e.target.dataset.id;
572
- console.log(e.target);
573
- console.log(id);
574
571
  if (!id) {
575
572
  return;
576
573
  }