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,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
|
-
|
|
17
|
+
toc.showPosition(args.rep);
|
|
9
18
|
}
|
|
10
19
|
|
|
11
20
|
if ($('#toc:visible').length > 0) {
|
|
12
|
-
|
|
21
|
+
toc.update();
|
|
13
22
|
}
|
|
14
23
|
};
|
package/static/js/postAceInit.js
CHANGED
|
@@ -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
|
-
|
|
28
|
+
toc.enable(); // enables line tocping
|
|
19
29
|
} else {
|
|
20
30
|
optionToc.prop('checked', false);
|
|
21
|
-
|
|
31
|
+
toc.disable(); // disables line tocping
|
|
22
32
|
}
|
|
23
33
|
});
|
|
24
34
|
if (optionToc.is(':checked')) {
|
|
25
|
-
|
|
35
|
+
toc.enable();
|
|
26
36
|
} else {
|
|
27
|
-
|
|
37
|
+
toc.disable();
|
|
28
38
|
}
|
|
29
39
|
|
|
30
|
-
const tocParam =
|
|
40
|
+
const tocParam = toc.getParam('toc');
|
|
31
41
|
if (tocParam === true) {
|
|
32
42
|
optionToc.prop('checked', true);
|
|
33
|
-
|
|
43
|
+
toc.enable();
|
|
34
44
|
} else if (tocParam === false) {
|
|
35
45
|
optionToc.prop('checked', false);
|
|
36
|
-
|
|
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
|
-
|
|
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
|
+
});
|