ep_table_of_contents 0.3.134 → 0.3.136

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ep_table_of_contents",
3
- "version": "0.3.134",
3
+ "version": "0.3.136",
4
4
  "description": "View a table of contents for your pad",
5
5
  "author": {
6
6
  "name": "John McLear",
@@ -1,14 +1,23 @@
1
- /* global tableOfContents */
2
1
  'use strict';
3
2
 
3
+ // aceEditEvent fires inside ACE's inner iframe, which has its own `globalThis`
4
+ // separate from the outer pad page where toc.js runs. Reach across the
5
+ // iframe boundary via `window.top` (the topmost frame, i.e. the outer pad
6
+ // page). If toc.js hasn't executed yet — e.g. during very early pad init —
7
+ // silently skip; it will be called again on the next edit event.
8
+ const getToc = () => (typeof globalThis !== 'undefined' && globalThis.tableOfContents) ||
9
+ (window.top && window.top.tableOfContents) || null;
10
+
4
11
  exports.aceEditEvent = (hookName, args) => {
5
12
  // dont do anything on idle work timer, wait for changes..
6
13
  if (args.callstack && args.callstack.type === 'idleWorkTimer') return false;
14
+ const toc = getToc();
15
+ if (!toc) return;
7
16
  if (args.rep) {
8
- tableOfContents.showPosition(args.rep);
17
+ toc.showPosition(args.rep);
9
18
  }
10
19
 
11
20
  if ($('#toc:visible').length > 0) {
12
- tableOfContents.update();
21
+ toc.update();
13
22
  }
14
23
  };
@@ -1,6 +1,14 @@
1
- /* global tableOfContents */
2
1
  'use strict';
3
2
 
3
+ // postAceInit is loaded as a CommonJS plugin hook module; its scope is not
4
+ // the same as the <script> tag that loads toc.js, so `tableOfContents` is
5
+ // not visible via the normal scope chain. Look it up explicitly on the
6
+ // topmost window (where toc.js runs) with a globalThis fallback for the
7
+ // case where both happen to share a realm.
8
+ const getToc = () => (typeof globalThis !== 'undefined' && globalThis.tableOfContents) ||
9
+ (window.top && window.top.tableOfContents) ||
10
+ window.tableOfContents || null;
11
+
4
12
  exports.postAceInit = () => {
5
13
  if (!$('#editorcontainerbox').hasClass('flex-layout')) {
6
14
  $.gritter.add({
@@ -11,28 +19,30 @@ exports.postAceInit = () => {
11
19
  class_name: 'error',
12
20
  });
13
21
  }
22
+ const toc = getToc();
23
+ if (!toc) return;
14
24
  const optionToc = $('#options-toc');
15
25
  /* on click */
16
26
  optionToc.on('click', () => {
17
27
  if (optionToc.is(':checked')) {
18
- tableOfContents.enable(); // enables line tocping
28
+ toc.enable(); // enables line tocping
19
29
  } else {
20
30
  optionToc.prop('checked', false);
21
- tableOfContents.disable(); // disables line tocping
31
+ toc.disable(); // disables line tocping
22
32
  }
23
33
  });
24
34
  if (optionToc.is(':checked')) {
25
- tableOfContents.enable();
35
+ toc.enable();
26
36
  } else {
27
- tableOfContents.disable();
37
+ toc.disable();
28
38
  }
29
39
 
30
- const tocParam = tableOfContents.getParam('toc');
40
+ const tocParam = toc.getParam('toc');
31
41
  if (tocParam === true) {
32
42
  optionToc.prop('checked', true);
33
- tableOfContents.enable();
43
+ toc.enable();
34
44
  } else if (tocParam === false) {
35
45
  optionToc.prop('checked', false);
36
- tableOfContents.disable();
46
+ toc.disable();
37
47
  }
38
48
  };
package/static/js/toc.js CHANGED
@@ -63,7 +63,14 @@ if (typeof $ !== 'undefined') {
63
63
  });
64
64
  }
65
65
 
66
- const tableOfContents = {
66
+ // Expose on globalThis so other plugin scripts (postAceInit.js,
67
+ // aceEditEvent.js) that run in their own CommonJS-style module scopes can
68
+ // still reach it. Top-level `const` in a <script> tag is script-scoped,
69
+ // not a global, so without this the bare `tableOfContents` identifier in
70
+ // those modules throws `ReferenceError: tableOfContents is not defined`
71
+ // on pad load. globalThis resolves to `window` in the browser and to
72
+ // `global` in Node.js, so the Node unit tests keep working too.
73
+ const tableOfContents = globalThis.tableOfContents = {
67
74
 
68
75
  enable() {
69
76
  $('#toc').show();
@@ -0,0 +1,27 @@
1
+ import {expect, test} from '@playwright/test';
2
+ import {goToNewPad} from 'ep_etherpad-lite/tests/frontend-new/helper/padHelper';
3
+
4
+ test.beforeEach(async ({page}) => {
5
+ await goToNewPad(page);
6
+ });
7
+
8
+ test.describe('ep_table_of_contents', () => {
9
+ test('plugin is loaded and exposes itself in clientVars', async ({page}) => {
10
+ const enabled = await page.evaluate(
11
+ () => (window as any).clientVars?.plugins?.plugins?.ep_table_of_contents != null);
12
+ expect(enabled).toBe(true);
13
+ });
14
+
15
+ test('TOC sidebar element is rendered into the pad', async ({page}) => {
16
+ // The eejsBlock_editorContainerBox hook injects templates/toc.ejs
17
+ // (the #toc + #tocItems container) into the pad's editor box.
18
+ await expect(page.locator('#toc')).toBeAttached();
19
+ await expect(page.locator('#tocItems')).toBeAttached();
20
+ });
21
+
22
+ test('toolbar TOC toggle button is present', async ({page}) => {
23
+ // The eejsBlock_editbarMenuRight hook injects templates/barButton.ejs
24
+ // — the toolbar entry that toggles the TOC sidebar visibility.
25
+ await expect(page.locator('#ep_table_of_contents-a')).toBeAttached();
26
+ });
27
+ });