lexxy 0.9.25 → 0.9.27
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.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/app/assets/javascript/lexxy.js +79 -6
- data/app/assets/javascript/lexxy.js.br +0 -0
- data/app/assets/javascript/lexxy.js.gz +0 -0
- data/app/assets/javascript/lexxy.js.map +1 -1
- data/app/assets/javascript/lexxy.min.js +1 -1
- data/app/assets/javascript/lexxy.min.js.br +0 -0
- data/app/assets/javascript/lexxy.min.js.gz +0 -0
- data/app/assets/stylesheets/lexxy-editor.css +10 -2
- data/lib/lexxy/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1ef504d8ff6c3ee45519815bb36ea8c2d21316f8032c87967602138c88f4457b
|
|
4
|
+
data.tar.gz: 95e79bbbccdffe031d6938acce662d7d466fc248c63b609d0b6a058e9f586da1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d600ab9f59fa036b56143d081ecadecde64c24f674639d64067add0bebb276ab4da142c0022802e6cfe5c656902f866ae4fecc80a37ba63e8385d567e3517caa
|
|
7
|
+
data.tar.gz: a0eb4b38a69a6f436a611f5023e078bfff26b37152603f2f3d923256c1e57672845c0bed337cec6c38989582e400be3a24ff7d9e803782d0c56dc94bb5f7995f
|
data/README.md
CHANGED
|
@@ -21,6 +21,7 @@ A modern rich text editor for Rails.
|
|
|
21
21
|
|
|
22
22
|
- Bug reports and pull requests are welcome on [GitHub Issues](https://github.com/basecamp/lexxy/issues). Help is especially welcome with [those tagged as "Help Wanted"](https://github.com/basecamp/lexxy/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22help%20wanted%22).
|
|
23
23
|
- For questions and general Lexxy discussion, please use the [Discussions section](https://github.com/basecamp/lexxy/discussions)
|
|
24
|
+
- To build with a development version of Lexical, use `bin/link-to-local-lexical`.
|
|
24
25
|
|
|
25
26
|
## License
|
|
26
27
|
|
|
@@ -11085,10 +11085,34 @@ class Selection {
|
|
|
11085
11085
|
|
|
11086
11086
|
this.editor.registerCommand(ie$4, () => {
|
|
11087
11087
|
this.#syncSelectedClasses();
|
|
11088
|
-
}, io)
|
|
11088
|
+
}, io),
|
|
11089
|
+
|
|
11090
|
+
this.editor.registerCommand(ie$4, () => {
|
|
11091
|
+
this.#preserveFocusOfOtherFields();
|
|
11092
|
+
return false
|
|
11093
|
+
}, lo)
|
|
11089
11094
|
);
|
|
11090
11095
|
}
|
|
11091
11096
|
|
|
11097
|
+
// Firefox (152+) keeps window.getSelection() anchored inside the editor after focus
|
|
11098
|
+
// moves to another field, and fires document selectionchange for every keystroke
|
|
11099
|
+
// typed there. Lexical reads that stale selection, reconciles, and pulls focus back
|
|
11100
|
+
// into the editor — stealing it mid-typing. When another text-entry field owns focus,
|
|
11101
|
+
// tag the update so Lexical leaves the DOM selection (and with it, focus) alone.
|
|
11102
|
+
#preserveFocusOfOtherFields() {
|
|
11103
|
+
if (this.#anotherFieldIsFocused) {
|
|
11104
|
+
Os(qn);
|
|
11105
|
+
}
|
|
11106
|
+
}
|
|
11107
|
+
|
|
11108
|
+
get #anotherFieldIsFocused() {
|
|
11109
|
+
const rootElement = this.editor.getRootElement();
|
|
11110
|
+
const activeElement = rootElement?.ownerDocument.activeElement;
|
|
11111
|
+
|
|
11112
|
+
return activeElement && !rootElement.contains(activeElement) &&
|
|
11113
|
+
(activeElement.tagName === "INPUT" || activeElement.tagName === "TEXTAREA" || activeElement.isContentEditable)
|
|
11114
|
+
}
|
|
11115
|
+
|
|
11092
11116
|
#listenForNodeSelections() {
|
|
11093
11117
|
this.#listeners.track(this.editor.registerCommand(se$5, ({ target }) => {
|
|
11094
11118
|
if (!qs(target)) return false
|
|
@@ -12485,6 +12509,7 @@ class PastedContentFormatter {
|
|
|
12485
12509
|
this.#stripStyleElements();
|
|
12486
12510
|
this.#unwrapPlaceholderAnchors();
|
|
12487
12511
|
this.#stripTableCellColorStyles();
|
|
12512
|
+
this.#unwrapWrappedListChildren();
|
|
12488
12513
|
this.#nestStrayListChildren();
|
|
12489
12514
|
this.#stripStrayListChildren();
|
|
12490
12515
|
return this.doc
|
|
@@ -12526,6 +12551,29 @@ class PastedContentFormatter {
|
|
|
12526
12551
|
}
|
|
12527
12552
|
}
|
|
12528
12553
|
|
|
12554
|
+
// Some sources wrap runs of <li>s in a stray element (e.g. a <div> directly
|
|
12555
|
+
// inside the list). Dissolve such wrappers so their items become direct
|
|
12556
|
+
// list children and any nested list they hide becomes visible to
|
|
12557
|
+
// #nestStrayListChildren below.
|
|
12558
|
+
#unwrapWrappedListChildren() {
|
|
12559
|
+
for (const list of this.doc.querySelectorAll("ol, ul")) {
|
|
12560
|
+
let wrapper = this.#wrappedListChild(list);
|
|
12561
|
+
while (wrapper) {
|
|
12562
|
+
wrapper.replaceWith(...wrapper.childNodes);
|
|
12563
|
+
wrapper = this.#wrappedListChild(list);
|
|
12564
|
+
}
|
|
12565
|
+
}
|
|
12566
|
+
}
|
|
12567
|
+
|
|
12568
|
+
#wrappedListChild(list) {
|
|
12569
|
+
for (const child of list.children) {
|
|
12570
|
+
if (child.tagName !== "LI" && !this.#isNestedList(child) && this.#containsListItems(child)) {
|
|
12571
|
+
return child
|
|
12572
|
+
}
|
|
12573
|
+
}
|
|
12574
|
+
return null
|
|
12575
|
+
}
|
|
12576
|
+
|
|
12529
12577
|
// Some sources (e.g. Gmail) nest a sublist as a direct child of the parent
|
|
12530
12578
|
// <ol>/<ul> instead of inside a <li>. Move each nested list into its
|
|
12531
12579
|
// preceding <li> so the import preserves the nesting instead of dropping it.
|
|
@@ -12542,16 +12590,41 @@ class PastedContentFormatter {
|
|
|
12542
12590
|
}
|
|
12543
12591
|
}
|
|
12544
12592
|
|
|
12545
|
-
// Only <li> is a valid child of a list
|
|
12546
|
-
//
|
|
12593
|
+
// Only <li> is a valid child of a list. Unwrap remaining stray children
|
|
12594
|
+
// that still hold list items (a nested list with no preceding <li> to nest
|
|
12595
|
+
// under) so the items survive, and drop stray <br>/whitespace so the import
|
|
12596
|
+
// doesn't wrap them into an empty leading item.
|
|
12547
12597
|
#stripStrayListChildren() {
|
|
12548
12598
|
for (const list of this.doc.querySelectorAll("ol, ul")) {
|
|
12549
|
-
|
|
12550
|
-
|
|
12551
|
-
|
|
12599
|
+
let stray = this.#firstStrayListChild(list);
|
|
12600
|
+
while (stray) {
|
|
12601
|
+
if (this.#containsListItems(stray)) {
|
|
12602
|
+
stray.replaceWith(...stray.childNodes);
|
|
12603
|
+
} else {
|
|
12604
|
+
stray.remove();
|
|
12605
|
+
}
|
|
12606
|
+
|
|
12607
|
+
stray = this.#firstStrayListChild(list);
|
|
12552
12608
|
}
|
|
12553
12609
|
}
|
|
12554
12610
|
}
|
|
12611
|
+
|
|
12612
|
+
#firstStrayListChild(list) {
|
|
12613
|
+
for (const child of list.childNodes) {
|
|
12614
|
+
if (child.nodeType !== Node.ELEMENT_NODE || child.tagName !== "LI") {
|
|
12615
|
+
return child
|
|
12616
|
+
}
|
|
12617
|
+
}
|
|
12618
|
+
return null
|
|
12619
|
+
}
|
|
12620
|
+
|
|
12621
|
+
#isNestedList(node) {
|
|
12622
|
+
return node.nodeType === Node.ELEMENT_NODE && (node.tagName === "OL" || node.tagName === "UL")
|
|
12623
|
+
}
|
|
12624
|
+
|
|
12625
|
+
#containsListItems(node) {
|
|
12626
|
+
return node.nodeType === Node.ELEMENT_NODE && node.querySelector("li") !== null
|
|
12627
|
+
}
|
|
12555
12628
|
}
|
|
12556
12629
|
|
|
12557
12630
|
class Contents {
|
|
Binary file
|
|
Binary file
|