In this example, editor is created inside Shadow Root.
https://codepen.io/artemiusgreat/pen/XWMPdWG
The main concern so far is that inline formatting doesn't work when initiated from Toolbar module by clicking Bold or Italic buttons on the panel.
The reason is that window.getSelection always returns empty selection inside the Shadow Root.
The good thing is that it somehow works when inline formatting is initiated from Keyboard module by pressing CTRL+B or CTRL+I.
I'm digging into the code, but if somebody already resolved this I would appreciate some guidance.
Done.
This fix doesn't cover missing shadow.getSelection in Safari but all other browsers should work. In my case, I needed only Chrome.
var quill = new Quill(editorControl, {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block']
]
},
placeholder: 'Compose an epic...',
theme: 'snow'
});
const normalizeNative = (nativeRange) => {
// document.getSelection model has properties startContainer and endContainer
// shadow.getSelection model has baseNode and focusNode
// Unify formats to always look like document.getSelection
if (nativeRange) {
const range = nativeRange;
if (range.baseNode) {
range.startContainer = nativeRange.baseNode;
range.endContainer = nativeRange.focusNode;
range.startOffset = nativeRange.baseOffset;
range.endOffset = nativeRange.focusOffset;
if (range.endOffset < range.startOffset) {
range.startContainer = nativeRange.focusNode;
range.endContainer = nativeRange.baseNode;
range.startOffset = nativeRange.focusOffset;
range.endOffset = nativeRange.baseOffset;
}
}
if (range.startContainer) {
return {
start: { node: range.startContainer, offset: range.startOffset },
end: { node: range.endContainer, offset: range.endOffset },
native: range
};
}
}
return null
};
// Hack Quill and replace document.getSelection with shadow.getSelection
quill.selection.getNativeRange = () => {
const dom = quill.root.getRootNode();
const selection = dom.getSelection();
const range = normalizeNative(selection);
return range;
};
// Subscribe to selection change separately,
// because emitter in Quill doesn't catch this event in Shadow DOM
document.addEventListener("selectionchange", (...args) => {
// Update selection and some other properties
quill.selection.update()
});
Full HTML file
<html>
<head>
<meta charset="utf-8">
<title>CKEditor</title>
<script type="text/javascript" src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
</head>
<body>
<div class="container" name="NewEditor"></div>
<script>
let container = document.querySelector(".container");
let shadow = container.attachShadow({ mode: 'open' });
const ele = document.createElement('div');
console.log(shadow.getRootNode())
shadow.innerHTML = `<link href="https://cdn.quilljs.com/1.0.0/quill.snow.css" rel="stylesheet" />
<link rel="stylesheet" type="text/css" href="https://cdn.quilljs.com/1.3.6/quill.bubble.css">
`;
shadow.appendChild(ele);
var quill = new Quill(ele, {
"modules": {
"toolbar": [
[
"bold",
"italic",
"underline",
"strike",
"blockquote",
"code-block",
{
"list": "ordered"
},
{
"list": "bullet"
},
{
"script": "sub"
},
{
"script": "super"
},
{
"indent": -1
},
{
"indent": "+1"
},
{
"direction": "rtl"
},
{
"size": [
"small",
false,
"large",
"huge"
]
},
{
"color": []
},
{
"background": []
},
{
"font": []
},
{
"align": []
},
"clean",
"link",
"image",
"video"
]
]
},
"placeholder": "",
"readOnly": false,
"theme": "snow",
"value": {
"ops": [
{
"attributes": {
"bold": true
},
"insert": "Bold"
}
]
}
});
const normalizeNative = (nativeRange) => {
if (nativeRange) {
const range = nativeRange;
if (range.baseNode) {
range.startContainer = nativeRange.baseNode;
range.endContainer = nativeRange.focusNode;
range.startOffset = nativeRange.baseOffset;
range.endOffset = nativeRange.focusOffset;
if (range.endOffset < range.startOffset) {
range.startContainer = nativeRange.focusNode;
range.endContainer = nativeRange.baseNode;
range.startOffset = nativeRange.focusOffset;
range.endOffset = nativeRange.baseOffset;
}
}
if (range.startContainer) {
return {
start: { node: range.startContainer, offset: range.startOffset },
end: { node: range.endContainer, offset: range.endOffset },
native: range
};
}
}
return null
};
quill.selection.getNativeRange = () => {
const dom = quill.root.getRootNode();
const selection = dom.getSelection();
const range = normalizeNative(selection);
// if(selection.focusOffset !== selection.baseOffset){
// range.length = 0;
// document.activeElement.shadowRoot.querySelector('.ql-editor').focus();
// }
return range;
};
document.addEventListener("selectionchange", (...args) => {
quill.selection.update()
});
</script>
</body>
</html>
But still 'bubble' theme not working properly. Getting document.activeElement problem
Error Line in this iamge
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With