Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ The release run heads these entries with the version and opens a fresh

## Unreleased

### Text documents and presentations

- The browser text editor attaches to a page with an addressed paragraph and
no run, as a new odt or docx renders. Typing there went nowhere and said
nothing.

## v7.5.1 - 2026-10-10

### Spreadsheets
Expand Down
7 changes: 4 additions & 3 deletions src/odr/internal/html/frontend/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

var odr = (window.odr = window.odr || {});

// A view whose runs carry no address is not this editor's: a sheet's editing
// is an overlay, and its cells state no id.
if (document.querySelector("x-s[data-odr-id]") === null) {
// A view with no addressed paragraph or run is not this editor's: a sheet's
// editing is an overlay, and its cells state no id. A new document has one
// empty paragraph and no run.
if (document.querySelector("x-p[data-odr-id], x-s[data-odr-id]") === null) {
return;
}

Expand Down
5 changes: 5 additions & 0 deletions test/browser/text/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ so these checks run by hand and not in `odr_test`.
```bash
test/browser/text/serve # serves on :8734
open http://localhost:8734/tests.html
open http://localhost:8734/empty.html
```

`serve` serves `document.css`, `editing.js`, `document.js` and `search.js` out
Expand All @@ -14,6 +15,10 @@ so the checks run the file the library embeds. `editing.js` goes first, as the
library writes it. `error-codes.js` is built from `src/odr/error_code.{hpp,cpp}`
by `test/browser/serve.py`.

`empty.html` is a new document: one addressed paragraph and no run. The
editor decides on load whether a page is its own, so that shape needs a page
of its own.

`tests.html` holds the shapes the editor handles: two runs beside each other,
a run under a link, a run under a style-only wrapper, a paragraph with a
picture and no run, and the `<wbr>` / `<br>` line box the renderer ends every
Expand Down
83 changes: 83 additions & 0 deletions test/browser/text/empty.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>text editing checks: an empty document</title>
<link rel="stylesheet" href="document.css" />
</head>
<body
class="odr-body"
data-odr-editable="true"
data-odr-keyboard="navigation shortcuts"
>
<!-- A new document as `create_document` makes one and `translate` writes
it: one paragraph with an address, no run, and the `<br>` line box of
an empty paragraph. The editor decides on load whether the page is
its own, so this needs a page of its own. -->
<div class="odr-text-flow" id="flow">
<x-p data-odr-id="2" style="display:block"><br></x-p>
</div>

<div id="out" contenteditable="false"><div id="report"></div></div>
<script src="error-codes.js"></script>
<script src="editing.js"></script>
<script src="document.js"></script>
<script src="checks.js"></script>
<script>
var refusals = [];
odr.onEditRefused = function (event) {
refusals.push(event.reason + " " + event.code);
};

var paragraph = document.querySelector('x-p[data-odr-id="2"]');
function ops() {
return JSON.parse(odr.editing.getOperations()).ops;
}
function input(type, data) {
var before = refusals.length;
var event = new InputEvent("beforeinput", {
inputType: type,
data: data,
bubbles: true,
cancelable: true,
});
document.body.dispatchEvent(event);
return refusals.length > before ? "refused" : "taken";
}

note("an empty document");
check("the mode turns on", odr.editing.enable() === true);
check(
"the text editor attached",
document.body.getAttribute("contenteditable") === "true"
);

var range = document.createRange();
range.setStart(paragraph, 0);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
check("typing is taken", input("insertText", "Hello") === "taken", refusals);
check("the paragraph holds it", paragraph.textContent === "Hello");
check(
"in a run of its own",
paragraph.querySelector("x-s[data-odr-id]") !== null &&
paragraph.querySelector("x-s[data-odr-id]").textContent === "Hello"
);
check(
"which the log states by its parent",
ops().length === 1 &&
ops()[0].op === "insertText" &&
ops()[0].parent === 2 &&
ops()[0].text === "Hello",
ops()
);
check(
"the line box is a wbr now",
paragraph.lastChild.nodeName === "WBR",
paragraph.lastChild.nodeName
);
odr.editing.undo();
check("undo empties it again", paragraph.textContent === "" && ops().length === 0);
</script>
</body>
</html>
2 changes: 1 addition & 1 deletion test/browser/text/serve
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ sys.path.insert(0, str(HERE.parent))

from serve import serve # noqa: E402

serve(8734, HERE, ("tests.html",))
serve(8734, HERE, ("tests.html", "empty.html"))
Loading