Reputation: 11
I am trying to use Quill as a WYSIWYG editor for creating a document with our own markdown syntax, which basically uses spans for everything but uses a data-type of the required element. It sounds complicated but it seems to be the only way we can insert liquid syntax around rows in a table.
I have managed to override the Block blot in Quill to achieve overriding the standard p
elements. However, it then treats the return key with the same and adds the <br>
inside a span
too.
I have a codepen here, reproducible with the code below, which outputs the html below the editor container:
<html lang="en">
<head>
<link href="https://cdn.jsdelivr.net/npm/quill@2/dist/quill.snow.css" rel="stylesheet" />
<style>
html, body {
font-family: arial;
font-size: 110%;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f0f0f0;
}
.container {
margin: auto;
padding: 20px;
position: relative;
width: 50%;
}
#editor-container {
width: 80%;
margin: 20px auto;
background-color: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
border-radius: 5px;
overflow: hidden;
}
#toolbar {
background-color: #f1f1f1;
padding: 10px;
border-bottom: 1px solid #ccc;
display: flex;
justify-content: space-around;
}
#toolbar button {
background-color: white;
border: 1px solid #ccc;
padding: 5px 10px;
cursor: pointer;
font-size: 16px;
}
#toolbar button:hover {
background-color: #e1e1e1;
}
#table-dropdown {
position: relative;
}
#table-picker {
display: none;
position: absolute;
top: 100%;
left: 0;
background-color: white;
border: 1px solid #ccc;
padding: 10px;
z-index: 1000;
}
#table-picker .cell {
width: 20px;
height: 20px;
border: 1px solid #ccc;
display: inline-block;
margin: 1px;
cursor: pointer;
}
#table-picker .cell.selected {
background-color: #007bff;
}
[contenteditable] {
font-size: 26px;
padding: .25em 0em;
margin: 1em 0;
transition: padding .3s ease-in-out;
}
[contenteditable]:hover,
[contenteditable]:focus {
padding: .25em;
}
[contenteditable]:hover {
background: #fafafa;
outline: 2px solid #eee;
}
[contenteditable]:focus {
background: #efefef;
outline: 2px solid blue;
}
#editor {
padding: 20px;
height: 300px; /* Set the desired height */
max-height: 300px; /* Set the maximum height */
overflow-y: auto; /* Make it scrollable if content exceeds the height */
outline: none;
font-size: 16px;
line-height: 1.5;
}
.btn {
background: #fff;
color: darkgreen;
border: 1px solid darkgreen;
box-shadow: inset 0 0 0 1px;
font-size: 1em;
padding: .75em;
margin-right: .5em;
}
.btn[disabled] {
color: #666;
border-color: #ddd;
opacity: .5;
}
.btn:not([disabled]):hover,
.btn:not([disabled]):focus {
outline: 3px solid;
outline-offset: 1px;
}
.btn:not([disabled]):active {
background: darkgreen;
color: #fff;
}
</style>
</head>
<body>
<div id="editor-container">
<div id="toolbar">
<button class="ql-bold">B</button>
<button class="ql-italic">I</button>
<button id="tool-save">Save</button>
<button class="ql-table">Table</button>
</div>
<div id="editor"></div>
</div>
<h3>Generated HTML:</h3>
<pre id="output" style="border: 1px solid #ddd; padding: 10px; min-height: 100px; white-space: pre-wrap; background: #f4f4f4;"></pre>
<script src="https://cdn.jsdelivr.net/npm/quill@2/dist/quill.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/parchment.min.js"></script>
<script>
// Import Quill modules correctly
const Block = Quill.import('blots/block');
const Inline = Quill.import('blots/inline');
// Custom Paragraph Blot (Replaces <p>)
class CustomParagraph extends Block {
static create() {
let node = super.create();
node.setAttribute('data-type', 'p'); // Replace <p> with <span data-type="p">
return node;
}
}
CustomParagraph.blotName = 'block';
CustomParagraph.tagName = 'span'; // Use <span> instead of <p>
Quill.register(CustomParagraph, true); // Overwrite default
// Custom Span Blot (Replaces inline text spans)
class CustomSpan extends Inline {
static create() {
let node = super.create();
node.setAttribute('data-type', 'span');
return node;
}
}
CustomSpan.blotName = 'custom-span';
CustomSpan.tagName = 'span';
Quill.register(CustomSpan, true); // Overwrite default
// Custom Table Blot (Replaces <table>)
class CustomTable extends Block {
static create() {
let node = super.create();
node.setAttribute('data-type', 'table');
return node;
}
}
CustomTable.blotName = 'custom-table';
CustomTable.tagName = 'span';
Quill.register(CustomTable, true); // Overwrite default
// Custom Table Row Blot (Replaces <tr>)
class CustomTableRow extends Block {
static create() {
let node = super.create();
node.setAttribute('data-type', 'tr');
return node;
}
}
CustomTableRow.blotName = 'custom-tr';
CustomTableRow.tagName = 'span';
Quill.register(CustomTableRow, true); // Overwrite default
// Initialize Quill with Overridden Defaults
const quill = new Quill('#editor', {
theme: 'snow',
modules: {
toolbar: [
[{ 'header': [1, 2, false] }],
['bold', 'italic', 'underline'],
['clean']
]
},
formats: ['custom-p', 'custom-span', 'custom-table', 'custom-tr']
});
// Override Quill's Clipboard Handling (Ensures pasting follows our custom format)
quill.clipboard.addMatcher(Node.ELEMENT_NODE, (node, delta) => {
delta.ops.forEach(op => {
if (op.insert && typeof op.insert === 'string') {
op.insert = { customSpan: op.insert };
}
});
return delta;
});
// Function to update HTML preview (display raw HTML)
function updateHtmlOutput() {
document.getElementById('output').textContent = quill.root.innerHTML;
}
// Listen for Quill changes and update output
quill.on('text-change', updateHtmlOutput);
</script>
</body>
</html>
I have tried overriding the block blot, which has helped me to change the default paragraph for typed text, but the above issue persists with the br
being wrapped in a span
too.
Ultimately I want to override all of the default blots with my own - so that when I am dealing with a table, it is a span with data-type="table"
etc etc.
Upvotes: 1
Views: 17