Commit graph

8 commits

Author SHA1 Message Date
SamTV12345
4e6d073213 refactor(node/utils): finish CJS->ESM (Settings, Minify, ExportEtherpad, ImportEtherpad, ExportHtml, toolbar)
All 26 files in node/utils/ now ESM. Settings.ts CJS shim removed (dead code
under "type": module); plugins doing require() get .default-wrapped namespace
via Node interop, the createRequire bridge in pluginfw will preserve sync
loading once that lands. toolbar.ts's module.exports.availableButtons
self-reference replaced by a module-private toolbar const.

ts-check: 526 -> 539 errors. The +13 is from default-imports landing on
modules that still live in db/ as CJS; resolves once db/ is flipped.
2026-04-26 13:06:08 +02:00
John McLear
67e542d2b9
fix(editor): preserve U+00A0 non-breaking space (#3037) (#7585)
* fix(editor): preserve U+00A0 non-breaking space (#3037)

Non-breaking spaces were silently normalized to regular spaces at every
ingestion point, so typed/pasted/imported nbsps never reached the
changeset and users could not glue words against line-wrap in French or
other languages that require nbsp typography.

Removed the four strip sites that replaced U+00A0 with U+0020:
  - src/node/db/Pad.ts cleanText
  - src/static/js/contentcollector.ts textify
  - src/static/js/ace2_inner.ts textify
  - src/static/js/ace2_inner.ts importText raw-text guard

Updated both processSpaces functions (domline and ExportHtml) to tokenize
U+00A0 as a separate unit, emit it verbatim as  , and treat it as
content (not whitespace) for the run-collapse bookkeeping so adjacent
regular-space runs aren't miscounted.

Added backend round-trip tests for spliceText and setText, and extended
the cleanText case table. Updated the existing contentcollector and
importexport specs whose expectations encoded the previous buggy
behavior; they now assert genuine nbsp preservation.

Verified manually in Firefox: clipboard U+00A0 → paste → pad → getText
returns c2 a0; getHTML emits `100 km`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(contentcollector): collapse display-artifact nbsp runs on DOM read-back

processSpaces is a lossy one-way display transform: leading/trailing
spaces and all-but-the-last of a run get rendered as &nbsp; so HTML
doesn't collapse them. When incorporateUserChanges reads text back from
the DOM, those display-artifact nbsps were being stored in the changeset
model instead of being normalized back to plain spaces.

This broke handleReturnIndentation, whose /^ *(?:)/ regex only matches
ASCII spaces: auto-indent after `foo:\n` produced 4 spaces instead of
the expected prev-indent (2) + THE_TAB (4) = 6, because the previous
line's model had nbsps where it used to have spaces.

Fix: in contentcollector.textify, collapse any [  ]+ run back to
plain spaces UNLESS the run is pure U+00A0 AND strictly interior to
word chars. That preserves user-intended typographic nbsps like
"100 km" while undoing the one-way display transform.

Updated 7 contentcollector tests and 7 importexport tests whose
assertions needed to reflect the new rule (boundary/mixed runs collapse;
pure-interior nbsp runs preserve).

Fixes the Playwright regression in indentation.spec.ts:117 that the
previous commit introduced.

* fix(contentcollector): canonicalize nbsp runs at line assembly, not per text node

Addresses Qodo code review feedback on PR #7585.

## Bug fix — nbsp lost at DOM text-node boundary

The previous approach ran the "collapse display-artifact nbsp" rule inside
textify(), which is called per individual DOM TEXT_NODE. A user-intended
nbsp sitting at a text-node boundary (e.g., <span>100</span><span>&nbsp;km
</span>) was incorrectly seen as non-interior (before === '' for the second
text node) and normalized back to a regular space.

Fix: move the canonicalization out of textify() and run it on each
fully assembled line string inside cc.finish(). The rule remains:

    [  ]+ run  ->  plain spaces
                   UNLESS pure U+00A0 AND strictly interior to non-ws chars

It is length-preserving, so attribute offsets and line lengths are
unaffected.

Added a regression test (contentcollector.spec.ts) for the cross-span
case.

## Docs concern

Reverted the type-only addition of spliceText to PadType. spliceText
is an existing Pad runtime method; the backend test now uses a cast
(`(pad as any).spliceText`) so the PR does not expand the declared
public type surface, avoiding a separate documentation requirement.

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 08:57:30 +01:00
John McLear
7ec581afca
feat!: replace Abiword with LibreOffice and add DOCX export (#7539)
* feat!: replace Abiword with LibreOffice and add DOCX export (#4805)

The Abiword converter is dropped. Abiword's DOCX export is weak and the
project is niche on modern platforms; LibreOffice (soffice) is the
common deployment path and now serves as the sole converter backend.

DOCX is added as an export format and becomes the new target for the
"Microsoft Word" UI button. The /export/doc URL still works for legacy
API consumers.

BREAKING CHANGE: The 'abiword' setting, the INSTALL_ABIWORD Dockerfile
build arg, the abiwordAvailable clientVar, and the
#importmessageabiword UI element (with locale key
pad.importExport.abiword.innerHTML) are removed. Deployments relying on
Abiword must configure 'soffice' instead.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: add docxExport feature flag and abiword deprecation WARN

- Add `docxExport: true` setting to opt out of DOCX (use legacy DOC)
- Pass `docxExport` to client via clientVars
- Use `docxExport` flag in pad_impexp.ts for Word button format
- Emit a specific WARN when deprecated `abiword` config is detected
- Update settings.json.template and settings.json.docker with docxExport
- Add docxExport to ClientVarPayload type in SocketIOMessage.ts

Agent-Logs-Url: https://github.com/ether/etherpad/sessions/9afc5291-73b2-4b66-b028-feed39e7056f

Co-authored-by: JohnMcLear <220864+JohnMcLear@users.noreply.github.com>

* refactor: extract wordFormat variable and improve docxExport comment

Agent-Logs-Url: https://github.com/ether/etherpad/sessions/9afc5291-73b2-4b66-b028-feed39e7056f

Co-authored-by: JohnMcLear <220864+JohnMcLear@users.noreply.github.com>

* fix: restore import-limitation message when no converter is configured

The abiword removal dropped both the #importmessageabiword DOM element
and its locale key, but Copilot's refactor still expected the show()
call to surface a message when exportAvailable === 'no'. Result: users
with no soffice binary got silent failure instead of an explanation.

Add #importmessagenoconverter back with updated, LibreOffice-focused
copy (new locale key pad.importExport.noConverter.innerHTML) and flip
the hidden prop when the client knows no converter is available.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* i18n: inline English fallback for noConverter import message

The original abiword message existed in ~70 locale files and was
removed from all of them by this PR. The replacement key was only
added to en.json, so non-English users had an empty div until
translators localize. Follow the project's usual pad.html pattern
(e.g. line 146's "Font type:") and include the English text inside
the div as the fallback content; html10n replaces it when a
translation is available.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Revert "i18n: inline English fallback for noConverter import message"

This reverts commit f336f24d. Follow the project convention: add the
new locale key to en.json only and let translations catch up via the
translation system, rather than putting inline fallback in the template.

* i18n: leave non-English locale files untouched

The PR had removed pad.importExport.abiword.innerHTML from ~82 locale
files alongside its removal from en.json. The replacement message uses
a new key (pad.importExport.noConverter.innerHTML) in en.json only, so
churning every localisation file for a key that is no longer referenced
produces useless translation diffs. Restore every non-en locale file to
its pre-PR state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: JohnMcLear <220864+JohnMcLear@users.noreply.github.com>
2026-04-19 09:08:22 +01:00
John McLear
ac118cfde7
fix: preserve ordered list numbering across bullet interruptions in export (#7470)
* fix: preserve ordered list numbering across unordered list interruptions in export

When ordered lists were interrupted by unordered lists, each new <ol>
segment started at 1 instead of continuing the previous numbering.
Track running counts per indent level and emit start attributes.

Fixes #6471

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: respect explicit start attributes and reset counters per level

- line.start takes priority over counter-based continuation when present
- Counter is seeded from line.start to keep subsequent continuations aligned
- Counters for closed indent levels are cleared when list depth decreases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 11:24:01 +01:00
John McLear
f0b84cc1d0
fix: list bugs — indent export, renumber performance, and batching (#7449)
* fix: list bugs — indent export, renumber performance, and batching

Addresses four list-related bugs:

#4426: Indented text exports as bulleted lists. Added list-style-type:none
to indent-type <ul> elements in ExportHtml.ts so exported indented content
doesn't show bullet markers.

#3504 / #5546: List operations (indent, outdent, toggle) on large lists
are O(n²) because renumberList() runs after each individual line change.
Added _skipRenumber batching flag to setLineListType() — bulk operations
in doInsertList() and doIndentOutdent() now set all line types first,
then renumber once at the end.

#6471: Ordered list numbering in exports — the start attribute is already
read from the pad's atext during export. The client-side renumberList()
correctly sets start attributes which are persisted. Added export test
to verify numbering is preserved across bullet interruptions.

Fixes #4426, #3504, #5546
Related: #6471

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address Qodo review — exception safety, batch removal, renumber scope

- Wrap _skipRenumber in try/finally to prevent permanent disabling on error
- Move list removal (togglingOff) into the batched mods array instead of
  calling setLineListType directly (fixes O(n²) for list removal)
- Use firstLine instead of mods[0][0] for renumbering since the first
  mod may be an indent/removal that renumberList skips
- Rewrite indent export test to actually create indent lines via setHTML
  and unconditionally assert list-style-type:none is present

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: rewrite export tests to use importHtml/exportHtml directly

The HTTP API approach (setHTML via supertest) was hanging when tests
ran standalone because the API endpoint waited for something in the
request pipeline. Using importHtml.setPadHTML and exportHtml.getPadHTML
directly is faster and more reliable.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update importexport test to expect list-style-type on indent ul

The indent export fix adds style="list-style-type: none;" to indent
<ul> elements, which broke the golden test string comparison.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 01:58:27 +01:00
SamTV12345
28e04bdf71
Feat/changeset ts (#6594)
* Migrated changeset

* Added more tests.

* Fixed test scopes
2024-08-18 12:14:24 +02:00
SamTV12345
7e3ad03e2f
Moved to ts (#6593)
* Moved to ts

* Fixed type check

* Removed js suffixes

* Migrated to ts

* Fixed ts.

* Fixed type check

* Installed missing d ts
2024-08-17 20:14:36 +02:00
SamTV12345
4bd27a1c79
Moved more classes to ts. (#6179) 2024-02-22 11:36:43 +01:00
Renamed from src/node/utils/ExportHtml.js (Browse further)