ep_markdown 11.0.20 → 12.0.2
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/.github/workflows/backend-tests.yml +1 -1
- package/.github/workflows/frontend-tests.yml +1 -1
- package/.github/workflows/npmpublish.yml +0 -1
- package/AGENTS.md +75 -0
- package/CONTRIBUTING.md +74 -2
- package/ep.json +5 -1
- package/index.ts +16 -12
- package/package.json +3 -2
- package/static/js/markdown.js +23 -13
- package/templates/markdown_entry.ejs +0 -4
package/AGENTS.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Agent Guide — ep_markdown
|
|
2
|
+
|
|
3
|
+
Edit and Export as Markdown in Etherpad.
|
|
4
|
+
|
|
5
|
+
## Tech stack
|
|
6
|
+
|
|
7
|
+
* Etherpad plugin framework (hooks declared in `ep.json`)
|
|
8
|
+
* EJS templates rendered server-side via `eejsBlock_*` hooks
|
|
9
|
+
* html10n for i18n (`locales/<lang>.json`, `data-l10n-id` in templates)
|
|
10
|
+
* `ep_plugin_helpers` for shared boilerplate
|
|
11
|
+
|
|
12
|
+
## Project structure
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
ep_markdown/
|
|
16
|
+
├── AGENTS.md
|
|
17
|
+
├── CONTRIBUTING.md
|
|
18
|
+
├── ep.json
|
|
19
|
+
├── exportMarkdown.ts
|
|
20
|
+
├── express.ts
|
|
21
|
+
├── index.ts
|
|
22
|
+
├── locales/
|
|
23
|
+
│ ├── ar.json
|
|
24
|
+
│ ├── bn.json
|
|
25
|
+
│ ├── ca.json
|
|
26
|
+
│ ├── cs.json
|
|
27
|
+
│ ├── de.json
|
|
28
|
+
│ ├── diq.json
|
|
29
|
+
│ └── ...
|
|
30
|
+
├── package.json
|
|
31
|
+
├── static/
|
|
32
|
+
│ ├── css/
|
|
33
|
+
│ ├── js/
|
|
34
|
+
│ ├── tests/
|
|
35
|
+
├── templates/
|
|
36
|
+
│ ├── exportcolumn.html
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Helpers used
|
|
40
|
+
|
|
41
|
+
* `pad-toggle` from `ep_plugin_helpers`
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
## Helpers NOT used
|
|
45
|
+
|
|
46
|
+
_To be audited in the helpers-adoption sweep (Phase 4)._
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
## Running tests locally
|
|
50
|
+
|
|
51
|
+
`ep_markdown` runs inside Etherpad's test harness. From an etherpad checkout that has installed this plugin via `pnpm run plugins i --path ../ep_markdown`:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# Backend (Mocha) — harness boots its own server
|
|
55
|
+
pnpm --filter ep_etherpad-lite run test
|
|
56
|
+
|
|
57
|
+
# Playwright — needs `pnpm run dev` in a second terminal
|
|
58
|
+
pnpm --filter ep_etherpad-lite run test-ui
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Standing rules for agent edits
|
|
62
|
+
|
|
63
|
+
* PRs target `main`. Linear commits, no merge commits.
|
|
64
|
+
* Every bug fix includes a regression test in the same commit.
|
|
65
|
+
* All user-facing strings in `locales/`. No hardcoded English in templates.
|
|
66
|
+
* No hardcoded `aria-label` on icon-only controls — etherpad's html10n auto-populates `aria-label` from the localized string when (a) the element has a `data-l10n-id` and (b) no author-supplied `aria-label` is present. Adding a hardcoded English `aria-label` blocks that and leaves it untranslated. (See `etherpad-lite/src/static/js/vendors/html10n.ts:665-678`.)
|
|
67
|
+
* No nested interactive elements (no `<button>` inside `<a>`).
|
|
68
|
+
* LLM/Agent contributions are explicitly welcomed by maintainers.
|
|
69
|
+
|
|
70
|
+
## Quick reference: hooks declared in `ep.json`
|
|
71
|
+
|
|
72
|
+
* Server: `expressCreateServer`, `loadSettings`, `clientVars`, `eejsBlock_exportColumn`, `eejsBlock_mySettings`, `eejsBlock_padSettings`, `import`
|
|
73
|
+
* Client: `aceEditorCSS`, `postAceInit`, `handleClientMessage_CLIENT_MESSAGE`
|
|
74
|
+
|
|
75
|
+
When adding a hook, register it in both `ep.json` *and* the matching `exports.<hook> = ...` in the JS file.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -1,2 +1,74 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# Contributing to ep_markdown
|
|
2
|
+
|
|
3
|
+
Thanks for helping improve `ep_markdown` — a plugin for [Etherpad](https://etherpad.org/). LLM/Agent contributions are explicitly welcome, provided they follow the rules below.
|
|
4
|
+
|
|
5
|
+
For shared rules that apply to all Etherpad code (linear commits, deprecation policy, feature flags, stability guarantees), please read [ether/etherpad's CONTRIBUTING.md](https://github.com/ether/etherpad/blob/develop/CONTRIBUTING.md). This document only covers what's specific to plugin work.
|
|
6
|
+
|
|
7
|
+
## Plugin-specific rules
|
|
8
|
+
|
|
9
|
+
* **Target branch:** PRs go to `main` on this repo. Plugin repos do not use git-flow's `develop` branch.
|
|
10
|
+
* **Linear commits, no merge commits.** Rebase if needed.
|
|
11
|
+
* **Every bug fix must include a regression test in the same commit.**
|
|
12
|
+
* **Internationalization (i18n):** every user-facing string lives in `locales/<lang>.json` and is referenced via `data-l10n-id` in templates or `html10n.get(key)` in code. No hardcoded English in markup.
|
|
13
|
+
* **Accessibility (a11y):** no nested interactive elements (no `<button>` inside `<a>`); every interactive control has an accessible name; keyboard focus order matches visual order. Note that on icon-only controls you should rely on Etherpad's html10n to populate `aria-label` from the `data-l10n-id` translation — adding a hardcoded English `aria-label` blocks that and leaves the control untranslated.
|
|
14
|
+
|
|
15
|
+
## Local development
|
|
16
|
+
|
|
17
|
+
`ep_markdown` is a plugin, so you develop it inside a checkout of [ether/etherpad](https://github.com/ether/etherpad).
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Once: clone etherpad alongside this repo
|
|
21
|
+
git clone https://github.com/ether/etherpad.git
|
|
22
|
+
cd etherpad
|
|
23
|
+
pnpm install
|
|
24
|
+
|
|
25
|
+
# Install ep_markdown from your local clone
|
|
26
|
+
pnpm run plugins i --path ../ep_markdown
|
|
27
|
+
|
|
28
|
+
# Start the dev server (port 9001)
|
|
29
|
+
pnpm --filter ep_etherpad-lite run dev
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Edits in `../ep_markdown/` are picked up after a server restart.
|
|
33
|
+
|
|
34
|
+
## Tests
|
|
35
|
+
|
|
36
|
+
Tests live inside this repo and are executed by Etherpad's test harness:
|
|
37
|
+
|
|
38
|
+
* Backend (Mocha): `static/tests/backend/specs/`
|
|
39
|
+
* Playwright (frontend E2E): `static/tests/frontend-new/specs/`
|
|
40
|
+
|
|
41
|
+
Run them from the etherpad checkout:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Backend (no separate server needed, harness boots one)
|
|
45
|
+
pnpm --filter ep_etherpad-lite run test
|
|
46
|
+
|
|
47
|
+
# Playwright (requires `pnpm run dev` in another terminal)
|
|
48
|
+
pnpm --filter ep_etherpad-lite run test-ui
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Lint locally before pushing:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pnpm run lint
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Coding style
|
|
58
|
+
|
|
59
|
+
* JS/CSS/HTML: 2 spaces, no tabs.
|
|
60
|
+
* `pnpm run lint` must pass (configured via `eslint-config-etherpad`).
|
|
61
|
+
* Avoid breaking changes to public hooks, the line-attribute storage shape, or HTML export output. The backend export spec enforces a stable shape.
|
|
62
|
+
|
|
63
|
+
## Bug reports
|
|
64
|
+
|
|
65
|
+
Please include:
|
|
66
|
+
|
|
67
|
+
* Etherpad version, ep_markdown version, browser + OS
|
|
68
|
+
* Steps to reproduce
|
|
69
|
+
* What you expected, what actually happened
|
|
70
|
+
* Server log excerpt (set `"loglevel": "DEBUG"` in `settings.json` for verbose output)
|
|
71
|
+
|
|
72
|
+
## AI agents
|
|
73
|
+
|
|
74
|
+
If you are an LLM/agent contributor, also read [`AGENTS.md`](AGENTS.md) — it documents the file layout, helper usage, and standing rules for autonomous edits.
|
package/ep.json
CHANGED
|
@@ -4,13 +4,17 @@
|
|
|
4
4
|
"name": "markdown",
|
|
5
5
|
"hooks":{
|
|
6
6
|
"expressCreateServer": "ep_markdown/express",
|
|
7
|
+
"loadSettings": "ep_markdown/index",
|
|
8
|
+
"clientVars": "ep_markdown/index",
|
|
7
9
|
"eejsBlock_exportColumn": "ep_markdown/index",
|
|
8
10
|
"eejsBlock_mySettings": "ep_markdown/index",
|
|
11
|
+
"eejsBlock_padSettings": "ep_markdown/index",
|
|
9
12
|
"import": "ep_markdown/index"
|
|
10
13
|
},
|
|
11
14
|
"client_hooks": {
|
|
12
15
|
"aceEditorCSS": "ep_markdown/static/js/markdown",
|
|
13
|
-
"postAceInit": "ep_markdown/static/js/markdown"
|
|
16
|
+
"postAceInit": "ep_markdown/static/js/markdown",
|
|
17
|
+
"handleClientMessage_CLIENT_MESSAGE": "ep_markdown/static/js/markdown:handleClientMessage_CLIENT_MESSAGE"
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
20
|
]
|
package/index.ts
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const eejs = require('ep_etherpad-lite/node/eejs');
|
|
4
|
-
|
|
4
|
+
const {padToggle} = require('ep_plugin_helpers/pad-toggle-server');
|
|
5
5
|
import {promises} from 'fs';
|
|
6
6
|
const fsp = promises
|
|
7
7
|
|
|
8
|
+
// Parallel User Settings + Pad Wide Settings checkboxes for "Show Markdown".
|
|
9
|
+
// Helper owns storage, broadcast, enforce, and i18n wiring.
|
|
10
|
+
const markdownToggle = padToggle({
|
|
11
|
+
pluginName: 'ep_markdown',
|
|
12
|
+
settingId: 'markdown',
|
|
13
|
+
l10nId: 'ep_markdown.showMarkdown',
|
|
14
|
+
defaultLabel: 'Show Markdown',
|
|
15
|
+
defaultEnabled: false,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
exports.loadSettings = markdownToggle.loadSettings;
|
|
19
|
+
exports.clientVars = markdownToggle.clientVars;
|
|
20
|
+
exports.eejsBlock_mySettings = markdownToggle.eejsBlock_mySettings;
|
|
21
|
+
exports.eejsBlock_padSettings = markdownToggle.eejsBlock_padSettings;
|
|
22
|
+
|
|
8
23
|
exports.eejsBlock_exportColumn = (hookName, context) => {
|
|
9
24
|
context.content += eejs.require('./templates/exportcolumn.html', {}, module);
|
|
10
25
|
};
|
|
@@ -13,17 +28,6 @@ exports.eejsBlock_styles = (hookName, context) => {
|
|
|
13
28
|
context.content += eejs.require('./templates/styles.html', {}, module);
|
|
14
29
|
};
|
|
15
30
|
|
|
16
|
-
exports.eejsBlock_mySettings = (hookName, context) => {
|
|
17
|
-
let checkedState = 'unchecked';
|
|
18
|
-
if (!settings.ep_markdown_default) {
|
|
19
|
-
checkedState = 'unchecked';
|
|
20
|
-
} else if (settings.ep_markdown_default === true) {
|
|
21
|
-
checkedState = 'checked';
|
|
22
|
-
}
|
|
23
|
-
context.content +=
|
|
24
|
-
eejs.require('./templates/markdown_entry.ejs', {checked: checkedState}, module);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
31
|
exports.import = async (hookName, {destFile, fileEnding, srcFile}) => {
|
|
28
32
|
if (fileEnding !== '.md') return;
|
|
29
33
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ep_markdown",
|
|
3
3
|
"description": "Edit and Export as Markdown in Etherpad",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "12.0.2",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "John McLear",
|
|
7
7
|
"email": "john@mclear.co.uk",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"url": "https://github.com/ether/ep_markdown.git"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
+
"ep_plugin_helpers": "^0.3.2",
|
|
15
16
|
"showdown": "^2.1.0"
|
|
16
17
|
},
|
|
17
18
|
"contributors": [],
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
},
|
|
23
24
|
"devDependencies": {
|
|
24
25
|
"@types/mocha": "^10.0.10",
|
|
25
|
-
"@types/node": "^25.6.
|
|
26
|
+
"@types/node": "^25.6.2",
|
|
26
27
|
"eslint": "^8.57.1",
|
|
27
28
|
"eslint-config-etherpad": "^4.0.5",
|
|
28
29
|
"typescript": "^6.0.3"
|
package/static/js/markdown.js
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// Sub-path import keeps the client bundle clean. Importing the top-level
|
|
4
|
+
// `ep_plugin_helpers` index pulls in every helper's getters; `settings` and
|
|
5
|
+
// `toggle` reach server-only modules (eejs, Settings) which esbuild can't
|
|
6
|
+
// resolve for the browser.
|
|
7
|
+
const {padToggle} = require('ep_plugin_helpers/pad-toggle');
|
|
8
|
+
|
|
9
|
+
// Same config as the server-side instance — must agree on pluginName,
|
|
10
|
+
// settingId, l10nId, and defaultLabel for the checkbox ids and clientVars
|
|
11
|
+
// lookup to line up.
|
|
12
|
+
const markdownToggle = padToggle({
|
|
13
|
+
pluginName: 'ep_markdown',
|
|
14
|
+
settingId: 'markdown',
|
|
15
|
+
l10nId: 'ep_markdown.showMarkdown',
|
|
16
|
+
defaultLabel: 'Show Markdown',
|
|
17
|
+
defaultEnabled: false,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Re-export so the helper sees pad-wide broadcasts and refreshes our state
|
|
21
|
+
// when another user toggles the pad-wide checkbox.
|
|
22
|
+
exports.handleClientMessage_CLIENT_MESSAGE = markdownToggle.handleClientMessage_CLIENT_MESSAGE;
|
|
23
|
+
|
|
3
24
|
exports.postAceInit = (hookName, context) => {
|
|
4
25
|
const padRootPath = new RegExp(/.*\/p\/[^/]+/)
|
|
5
26
|
.exec(document.location.pathname) || clientVars.padId;
|
|
@@ -20,19 +41,8 @@ exports.postAceInit = (hookName, context) => {
|
|
|
20
41
|
$('#strikethrough').removeAttr('style');
|
|
21
42
|
};
|
|
22
43
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
enable();
|
|
26
|
-
} else {
|
|
27
|
-
disable();
|
|
28
|
-
}
|
|
29
|
-
/* on click */
|
|
30
|
-
$('#options-markdown').on('click', () => {
|
|
31
|
-
if ($('#options-markdown').is(':checked')) {
|
|
32
|
-
enable();
|
|
33
|
-
} else {
|
|
34
|
-
disable();
|
|
35
|
-
}
|
|
44
|
+
markdownToggle.init({
|
|
45
|
+
onChange: (enabled) => { enabled ? enable() : disable(); },
|
|
36
46
|
});
|
|
37
47
|
};
|
|
38
48
|
|