Created
May 1, 2017 18:43
-
-
Save WinstonFassett/9752d3abaf0257b8a561a326b705223a to your computer and use it in GitHub Desktop.
JS Bin // source http://jsbin.com/defixum
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width"> | |
| <title>JS Bin</title> | |
| <link href="http://cdn.quilljs.com/1.2.4/quill.snow.css" rel="stylesheet"> | |
| <link href="http://cdn.quilljs.com/1.2.4/quill.bubble.css" rel="stylesheet"> | |
| <style id="jsbin-css"> | |
| .ql-editor table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| } | |
| .ql-editor table td { | |
| border: 1px solid black; | |
| padding: 5px; | |
| height: 25px; | |
| } | |
| button.ql-table::after { content: "TABLE"; } | |
| .ql-picker.ql-table .ql-picker-label::before { content: "TABLE"; } | |
| button.ql-contain::after { content: "WRAP"; } | |
| button.ql-table-insert-rows::after { content: "ROWS+"; } | |
| button.ql-table-insert-columns::after { content: "COLS+"; } | |
| .ql-table, | |
| .ql-contain { | |
| width: auto !important; | |
| margin-right: -15px; | |
| } | |
| .ql-picker.ql-table { | |
| margin-right: -15px; | |
| font-size: 11px; | |
| font-weight: normal; | |
| } | |
| .ql-picker.ql-table svg { | |
| display: none; | |
| } | |
| .ql-picker.ql-table .ql-picker-label { | |
| padding: 0px 3px; | |
| } | |
| .ql-picker.ql-table .ql-picker-options { | |
| width: 190px; | |
| } | |
| .ql-picker.ql-table .ql-picker-item { | |
| display: block; | |
| float: left; | |
| width: 30px; | |
| height: 30px; | |
| line-height: 30px; | |
| text-align: center; | |
| padding: 0px; | |
| margin: 1px; | |
| } | |
| .ql-picker.ql-table .ql-picker-item { | |
| background: lightgrey; | |
| } | |
| .ql-picker-item:nth-child(5):before { | |
| clear: both; | |
| display: block; | |
| content: ""; | |
| width: 100%; | |
| } | |
| .ql-picker-item[data-value=newtable_1_1]:before { content: "1x1"; } | |
| .ql-picker-item[data-value=newtable_1_2]:before { content: "1x2"; } | |
| .ql-picker-item[data-value=newtable_1_3]:before { content: "1x3"; } | |
| .ql-picker-item[data-value=newtable_1_4]:before { content: "1x4"; } | |
| .ql-picker-item[data-value=newtable_1_5]:before { content: "1x5"; } | |
| .ql-picker-item[data-value=newtable_2_1]:before { content: "2x1"; } | |
| .ql-picker-item[data-value=newtable_2_2]:before { content: "2x2"; } | |
| .ql-picker-item[data-value=newtable_2_3]:before { content: "2x3"; } | |
| .ql-picker-item[data-value=newtable_2_4]:before { content: "2x4"; } | |
| .ql-picker-item[data-value=newtable_2_5]:before { content: "2x5"; } | |
| .ql-picker-item[data-value=newtable_3_1]:before { content: "3x1"; } | |
| .ql-picker-item[data-value=newtable_3_2]:before { content: "3x2"; } | |
| .ql-picker-item[data-value=newtable_3_3]:before { content: "3x3"; } | |
| .ql-picker-item[data-value=newtable_3_4]:before { content: "3x4"; } | |
| .ql-picker-item[data-value=newtable_3_5]:before { content: "3x5"; } | |
| .ql-picker-item[data-value=newtable_4_1]:before { content: "4x1"; } | |
| .ql-picker-item[data-value=newtable_4_2]:before { content: "4x2"; } | |
| .ql-picker-item[data-value=newtable_4_3]:before { content: "4x3"; } | |
| .ql-picker-item[data-value=newtable_4_4]:before { content: "4x4"; } | |
| .ql-picker-item[data-value=newtable_4_5]:before { content: "4x5"; } | |
| .ql-picker-item[data-value=newtable_5_1]:before { content: "5x1"; } | |
| .ql-picker-item[data-value=newtable_5_2]:before { content: "5x2"; } | |
| .ql-picker-item[data-value=newtable_5_3]:before { content: "5x3"; } | |
| .ql-picker-item[data-value=newtable_5_4]:before { content: "5x4"; } | |
| .ql-picker-item[data-value=newtable_5_5]:before { content: "5x5"; } | |
| .ql-picker-item[data-value=newtable_6_1]:before { content: "6x1"; } | |
| .ql-picker-item[data-value=newtable_6_2]:before { content: "6x2"; } | |
| .ql-picker-item[data-value=newtable_6_3]:before { content: "6x3"; } | |
| .ql-picker-item[data-value=newtable_6_4]:before { content: "6x4"; } | |
| .ql-picker-item[data-value=newtable_6_5]:before { content: "6x5"; } | |
| .ql-picker-item[data-value=newtable_7_1]:before { content: "7x1"; } | |
| .ql-picker-item[data-value=newtable_7_2]:before { content: "7x2"; } | |
| .ql-picker-item[data-value=newtable_7_3]:before { content: "7x3"; } | |
| .ql-picker-item[data-value=newtable_7_4]:before { content: "7x4"; } | |
| .ql-picker-item[data-value=newtable_7_5]:before { content: "7x5"; } | |
| .ql-picker-item[data-value=newtable_8_1]:before { content: "8x1"; } | |
| .ql-picker-item[data-value=newtable_8_2]:before { content: "8x2"; } | |
| .ql-picker-item[data-value=newtable_8_3]:before { content: "8x3"; } | |
| .ql-picker-item[data-value=newtable_8_4]:before { content: "8x4"; } | |
| .ql-picker-item[data-value=newtable_8_5]:before { content: "8x5"; } | |
| .ql-picker-item[data-value=newtable_9_1]:before { content: "9x1"; } | |
| .ql-picker-item[data-value=newtable_9_2]:before { content: "9x2"; } | |
| .ql-picker-item[data-value=newtable_9_3]:before { content: "9x3"; } | |
| .ql-picker-item[data-value=newtable_9_4]:before { content: "9x4"; } | |
| .ql-picker-item[data-value=newtable_9_5]:before { content: "9x5"; } | |
| .ql-picker-item[data-value=newtable_10_1]:before { content: "10x1"; } | |
| .ql-picker-item[data-value=newtable_10_2]:before { content: "10x2"; } | |
| .ql-picker-item[data-value=newtable_10_3]:before { content: "10x3"; } | |
| .ql-picker-item[data-value=newtable_10_4]:before { content: "10x4"; } | |
| .ql-picker-item[data-value=newtable_10_5]:before { content: "10x5"; } | |
| .tdbr, .trbr { | |
| display: none | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>Quill Table Breaks</h1> | |
| <div id="editor-container"> | |
| </div> | |
| Output: | |
| <textarea id='output_delta' style='width:100%; height:200px; padding: 3px;'></textarea> | |
| Orig Delta: | |
| <textarea id='orig_delta' style='width:100%; height:200px; padding: 3px;'></textarea> | |
| Current HTML: | |
| <textarea id='output_html' style='width:100%; height:200px; padding: 3px;'></textarea> | |
| HTML: | |
| <div id="view_html"> | |
| </div> | |
| <script src="http://cdn.quilljs.com/1.2.4/quill.js"></script> | |
| <script id="jsbin-javascript"> | |
| // quill-table-breaks.js | |
| let Container = Quill.import('blots/container'); | |
| let Scroll = Quill.import('blots/scroll'); | |
| let Inline = Quill.import('blots/inline'); | |
| let Block = Quill.import('blots/block'); | |
| let Delta = Quill.import('delta'); | |
| let Parchment = Quill.import('parchment'); | |
| let BlockEmbed = Quill.import('blots/block/embed'); | |
| let TextBlot = Quill.import('blots/text'); | |
| class ContainBlot extends Container { | |
| static create(value) { | |
| let tagName = 'contain'; | |
| let node = super.create(tagName); | |
| return node; | |
| } | |
| insertBefore(blot, ref) { | |
| if (blot.statics.blotName == this.statics.blotName) { | |
| console.log('############################ Not sure this is clean:') | |
| console.log(blot) | |
| console.log(blot.children.head) | |
| super.insertBefore(blot.children.head, ref); | |
| } else { | |
| super.insertBefore(blot, ref); | |
| } | |
| } | |
| static formats(domNode) { | |
| return domNode.tagName; | |
| } | |
| formats() { | |
| // We don't inherit from FormatBlot | |
| return { [this.statics.blotName]: this.statics.formats(this.domNode) } | |
| } | |
| replace(target) { | |
| if (target.statics.blotName !== this.statics.blotName) { | |
| let item = Parchment.create(this.statics.defaultChild); | |
| target.moveChildren(item); | |
| this.appendChild(item); | |
| } | |
| if (target.parent == null) return; | |
| super.replace(target) | |
| } | |
| } | |
| ContainBlot.blotName = 'contain'; | |
| ContainBlot.tagName = 'contain'; | |
| ContainBlot.scope = Parchment.Scope.BLOCK_BLOT; | |
| ContainBlot.defaultChild = 'block'; | |
| ContainBlot.allowedChildren = [Block, BlockEmbed, Container]; | |
| Quill.register(ContainBlot); | |
| class TableRow extends Container { | |
| static create(value) { | |
| let tagName = 'tr'; | |
| let node = super.create(tagName); | |
| return node; | |
| } | |
| optimize() { | |
| super.optimize(); | |
| var parent = this.parent | |
| if (parent != null && parent.statics.blotName != 'table') { | |
| this.processTable() | |
| } | |
| } | |
| processTable () { | |
| var currentBlot = this | |
| var rows = [] | |
| while (currentBlot) { | |
| if (! (currentBlot instanceof TableRow)) { | |
| break | |
| } | |
| rows.push(currentBlot) | |
| currentBlot = currentBlot.next | |
| } | |
| let mark = Parchment.create('block'); | |
| this.parent.insertBefore(mark, this.next); | |
| let table = Parchment.create('table'); | |
| rows.forEach(function (row) { | |
| table.appendChild(row) | |
| }) | |
| table.replace(mark) | |
| } | |
| } | |
| TableRow.blotName = 'tr'; | |
| TableRow.tagName = 'tr'; | |
| TableRow.scope = Parchment.Scope.BLOCK_BLOT; | |
| TableRow.defaultChild = 'td'; | |
| Quill.register(TableRow); | |
| class Table extends Container { | |
| optimize() { | |
| super.optimize(); | |
| let next = this.next; | |
| if (next != null && next.prev === this && | |
| next.statics.blotName === this.statics.blotName && | |
| next.domNode.tagName === this.domNode.tagName | |
| ) { | |
| next.moveChildren(this); | |
| next.remove(); | |
| } | |
| } | |
| } | |
| Table.blotName = 'table'; | |
| Table.tagName = 'table'; | |
| Table.scope = Parchment.Scope.BLOCK_BLOT; | |
| Table.defaultChild = 'tr'; | |
| Table.allowedChildren = [TableRow]; | |
| Quill.register(Table); | |
| // | |
| // | |
| // CONTAINER TD | |
| // | |
| class TableCell extends ContainBlot { | |
| format() { | |
| return 'td' | |
| } | |
| optimize() { | |
| super.optimize(); | |
| let parent = this.parent; | |
| if (parent != null && parent.statics.blotName != 'tr') { | |
| this.processTR() | |
| } | |
| // merge same TD id | |
| let next = this.next; | |
| if (next != null && next.prev === this && | |
| next.statics.blotName === this.statics.blotName && | |
| next.domNode.tagName === this.domNode.tagName | |
| ) { | |
| next.moveChildren(this); | |
| next.remove(); | |
| } | |
| } | |
| processTR () { | |
| // find next row break | |
| var currentBlot = this | |
| var rowItems = [this] | |
| while (currentBlot) { | |
| if (currentBlot.statics.tagName !== 'TD') { | |
| break | |
| } | |
| rowItems.push(currentBlot) | |
| if (currentBlot instanceof RowBreak) { | |
| break | |
| } | |
| currentBlot = currentBlot.next | |
| } | |
| // create row, add row items as TDs | |
| var prevItem | |
| var cellItems = [] | |
| var cells = [] | |
| rowItems.forEach(function (rowItem) { | |
| cellItems.push(rowItem) | |
| if (rowItem instanceof TableCell) { | |
| prevItem = rowItem | |
| } else if (rowItem instanceof CellBreak) { | |
| cells.push(cellItems) | |
| cellItems = [] | |
| } | |
| }) | |
| if (cellItems.length > 0) { | |
| cells.push(cellItems) | |
| } | |
| let mark = Parchment.create('block'); | |
| this.parent.insertBefore(mark, this.next); | |
| // create row | |
| var row = Parchment.create('tr') | |
| cells.forEach(function (cell) { | |
| // add row elements | |
| cell.forEach(function (cellItem) { | |
| row.appendChild(cellItem) | |
| }) | |
| }) | |
| row.replace(mark) | |
| } | |
| } | |
| TableCell.blotName = 'td'; | |
| TableCell.tagName = 'td'; | |
| TableCell.scope = Parchment.Scope.BLOCK_BLOT; | |
| TableCell.defaultChild = 'block'; | |
| TableCell.allowedChildren = [Block, BlockEmbed, Container]; | |
| Quill.register(TableCell); | |
| Container.order = [ | |
| 'list', 'contain', // Must be lower | |
| 'td', 'tr', 'table' // Must be higher | |
| ]; | |
| class RowBreak extends BlockEmbed { | |
| formats() { | |
| return { trbr: true } | |
| } | |
| } | |
| RowBreak.blotName = 'trbr' | |
| RowBreak.tagName = 'td' | |
| RowBreak.className = 'trbr' | |
| Quill.register(RowBreak); | |
| class CellBreak extends BlockEmbed { | |
| formats() { | |
| return { tdbr: true } | |
| } | |
| } | |
| CellBreak.blotName = 'tdbr' | |
| CellBreak.tagName = 'td' | |
| CellBreak.className = 'tdbr' | |
| Quill.register(CellBreak); | |
| // END quill-table-breaks.js | |
| // Render UI | |
| var Keyboard = Quill.import('modules/keyboard') | |
| // set up toolbar options | |
| let maxRows = 10; | |
| let maxCols = 5; | |
| let tableOptions = []; | |
| for (let r = 1; r <= maxRows; r++) { | |
| for (let c = 1; c <= maxCols; c++) { | |
| tableOptions.push('newtable_' + r + '_' + c); | |
| } | |
| } | |
| Quill.debug('debug'); | |
| var quill = new Quill('#editor-container', { | |
| modules: { | |
| toolbar: { | |
| container: [ | |
| [{ 'table': tableOptions }], // new table (cursor needs to be out of table) | |
| ['table-insert-rows'], // cursor needs to be in the table | |
| ['table-insert-columns'], // cursor needs to be in the table | |
| ['bold', 'italic', 'underline', 'strike'], | |
| ['blockquote', 'code-block'], | |
| [{ 'header': 1 }, { 'header': 2 }], | |
| [{ 'list': 'ordered'}, { 'list': 'bullet' }], | |
| [{ 'script': 'sub'}, { 'script': 'super' }], | |
| [{ 'indent': '-1'}, { 'indent': '+1' }], | |
| [{ 'direction': 'rtl' }], | |
| [{ 'size': ['small', false, 'large', 'huge'] }], | |
| [{ 'header': [1, 2, 3, 4, 5, 6, false] }], | |
| [{ 'color': [] }, { 'background': [] }], | |
| [{ 'align': [] }], | |
| ['link', 'image', 'code-block'], | |
| ['clean'] | |
| ], | |
| handlers: { | |
| table: function (value) { | |
| if(value && value.includes('newtable_')) { | |
| let sizes = value.split('_'); | |
| let rows = Number.parseInt(sizes[1]) | |
| let columns = Number.parseInt(sizes[2]) | |
| let table = Parchment.create('table'); | |
| const range = this.quill.getSelection() | |
| if (!range) return | |
| const newLineIndex = getClosestNewLineIndex(this.quill.getContents(), range.index + range.length) | |
| let changeDelta = new Delta().retain(newLineIndex) | |
| changeDelta = changeDelta.insert('\n') | |
| for (let i = 0; i < rows; i++) { | |
| for (let j = 0; j < columns; j++) { | |
| changeDelta = changeDelta.insert('\n', { | |
| td: true | |
| }) | |
| if (j < columns - 1) { | |
| changeDelta = changeDelta.insert({ tdbr: true }) | |
| } | |
| } | |
| changeDelta = changeDelta.insert({ trbr: true }) | |
| } | |
| this.quill.updateContents(changeDelta, Quill.sources.USER) | |
| this.quill.setSelection(newLineIndex + 1) | |
| } else { | |
| // TODO | |
| } | |
| }, | |
| 'table-insert-rows': function() { | |
| let td = find_td('td') | |
| if(td) { | |
| let col_count = 0 | |
| td.parent.children.forEach(function (it) { | |
| if (it instanceof TableCell) { | |
| col_count++ | |
| } | |
| }) | |
| let table = td.parent.parent; | |
| let new_row = td.parent.clone() | |
| for (var i = col_count - 1; i >= 0; i--) { | |
| let td = Parchment.create('td'); | |
| new_row.appendChild(td); | |
| new_row.appendChild(Parchment.create('tdbr')) | |
| }; | |
| new_row.appendChild(Parchment.create('trbr')) | |
| table.appendChild(new_row); | |
| } | |
| }, | |
| 'table-insert-columns': function() { | |
| let td = find_td('td') | |
| if(td) { | |
| let table = td.parent.parent; | |
| td.parent.parent.children.forEach(function(tr) { | |
| let td = Parchment.create('td'); | |
| tr.appendChild(td); | |
| tr.appendChild(Parchment.create('tdbr')) | |
| }); | |
| } | |
| } | |
| } | |
| }, | |
| clipboard: { | |
| matchers: [ | |
| ['TD, TH', function (node, delta) { | |
| delta.insert("\n", { td: true }) | |
| delta.insert({ tdbr: true }) | |
| return delta | |
| }], | |
| ['TR', function (node, delta) { | |
| delta.insert({ trbr: true }) | |
| return delta | |
| }], | |
| ] | |
| }, | |
| keyboard: { | |
| bindings: { | |
| 'backspaceTable': { | |
| key: 8, | |
| format: ['td'], | |
| // offset: 0, | |
| handler: function handleTableBackspace (range, context) { | |
| var formats = quill.getFormat(range.index-1, 1) | |
| if (formats.tdbr || formats.trbr) { | |
| // prevent deletion of table break | |
| return false | |
| } | |
| return true | |
| } | |
| } | |
| } | |
| }, | |
| }, | |
| placeholder: 'Compose an epic...', | |
| theme: 'snow' // or 'bubble' | |
| }); | |
| // global for console debugging | |
| QuillInstance = quill | |
| quill.on('text-change', function(delta, source) { | |
| document.getElementById("output_delta").value=JSON.stringify(quill.editor.getDelta(), null, 2) | |
| document.getElementById("output_html").value=quill.root.innerHTML; | |
| document.getElementById("view_html").innerHTML=quill.root.innerHTML; | |
| }) | |
| // use sample delta | |
| var delta = getSampleDelta() | |
| document.getElementById("orig_delta").value=JSON.stringify(delta, null, 2) | |
| quill.setContents(delta); | |
| function getClosestNewLineIndex (contents, index) { | |
| return index + contents.map((op) => { | |
| return typeof op.insert === 'string' ? op.insert : ' ' | |
| }).join('') | |
| .slice(index) | |
| .indexOf('\n') | |
| } | |
| function find_td(what) { | |
| let leaf = quill.getLeaf(quill.getSelection()['index']); | |
| let blot = leaf[0]; | |
| for(;blot!=null && blot.statics.blotName!=what;) { | |
| blot=blot.parent; | |
| } | |
| return blot; // return TD or NULL | |
| } | |
| function getSampleDelta () { | |
| return { | |
| "ops": [ | |
| { | |
| "insert": "Test Tables" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 1 | |
| } | |
| }, | |
| { | |
| "insert": "Empty 3x3 table from toolbar" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\nPopulated 3x3 table (from toolbar)" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "Col 1" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Col 2" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Col 3" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "a" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": "b" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": "c" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "123" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "456" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "d" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "4" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "7" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\nPasted Table" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "Company" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Contact" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Country" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Alfreds Futterkiste" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Maria Anders" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Germany" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Centro comercial Moctezuma" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Francisco Chang" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Mexico" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Ernst Handel" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Roland Mendel" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Austria" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Island Trading" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Helen Bennett" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "UK" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Laughing Bacchus Winecellars" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Yoshi Tannamuri" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Canada" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Magazzini Alimentari Riuniti" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Giovanni Rovelli" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Italy" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n" | |
| } | |
| ] | |
| } | |
| } | |
| </script> | |
| <script id="jsbin-source-html" type="text/html"><!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width"> | |
| <title>JS Bin</title> | |
| <link href="//cdn.quilljs.com/1.2.4/quill.snow.css" rel="stylesheet"> | |
| <link href="//cdn.quilljs.com/1.2.4/quill.bubble.css" rel="stylesheet"> | |
| </head> | |
| <body> | |
| <h1>Quill Table Breaks</h1> | |
| <div id="editor-container"> | |
| </div> | |
| Output: | |
| <textarea id='output_delta' style='width:100%; height:200px; padding: 3px;'></textarea> | |
| Orig Delta: | |
| <textarea id='orig_delta' style='width:100%; height:200px; padding: 3px;'></textarea> | |
| Current HTML: | |
| <textarea id='output_html' style='width:100%; height:200px; padding: 3px;'></textarea> | |
| HTML: | |
| <div id="view_html"> | |
| </div> | |
| <script src="//cdn.quilljs.com/1.2.4/quill.js"><\/script> | |
| </body> | |
| </html></script> | |
| <script id="jsbin-source-css" type="text/css"> | |
| .ql-editor table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| } | |
| .ql-editor table td { | |
| border: 1px solid black; | |
| padding: 5px; | |
| height: 25px; | |
| } | |
| button.ql-table::after { content: "TABLE"; } | |
| .ql-picker.ql-table .ql-picker-label::before { content: "TABLE"; } | |
| button.ql-contain::after { content: "WRAP"; } | |
| button.ql-table-insert-rows::after { content: "ROWS+"; } | |
| button.ql-table-insert-columns::after { content: "COLS+"; } | |
| .ql-table, | |
| .ql-contain { | |
| width: auto !important; | |
| margin-right: -15px; | |
| } | |
| .ql-picker.ql-table { | |
| margin-right: -15px; | |
| font-size: 11px; | |
| font-weight: normal; | |
| } | |
| .ql-picker.ql-table svg { | |
| display: none; | |
| } | |
| .ql-picker.ql-table .ql-picker-label { | |
| padding: 0px 3px; | |
| } | |
| .ql-picker.ql-table .ql-picker-options { | |
| width: 190px; | |
| } | |
| .ql-picker.ql-table .ql-picker-item { | |
| display: block; | |
| float: left; | |
| width: 30px; | |
| height: 30px; | |
| line-height: 30px; | |
| text-align: center; | |
| padding: 0px; | |
| margin: 1px; | |
| } | |
| .ql-picker.ql-table .ql-picker-item { | |
| background: lightgrey; | |
| } | |
| .ql-picker-item:nth-child(5):before { | |
| clear: both; | |
| display: block; | |
| content: ""; | |
| width: 100%; | |
| } | |
| .ql-picker-item[data-value=newtable_1_1]:before { content: "1x1"; } | |
| .ql-picker-item[data-value=newtable_1_2]:before { content: "1x2"; } | |
| .ql-picker-item[data-value=newtable_1_3]:before { content: "1x3"; } | |
| .ql-picker-item[data-value=newtable_1_4]:before { content: "1x4"; } | |
| .ql-picker-item[data-value=newtable_1_5]:before { content: "1x5"; } | |
| .ql-picker-item[data-value=newtable_2_1]:before { content: "2x1"; } | |
| .ql-picker-item[data-value=newtable_2_2]:before { content: "2x2"; } | |
| .ql-picker-item[data-value=newtable_2_3]:before { content: "2x3"; } | |
| .ql-picker-item[data-value=newtable_2_4]:before { content: "2x4"; } | |
| .ql-picker-item[data-value=newtable_2_5]:before { content: "2x5"; } | |
| .ql-picker-item[data-value=newtable_3_1]:before { content: "3x1"; } | |
| .ql-picker-item[data-value=newtable_3_2]:before { content: "3x2"; } | |
| .ql-picker-item[data-value=newtable_3_3]:before { content: "3x3"; } | |
| .ql-picker-item[data-value=newtable_3_4]:before { content: "3x4"; } | |
| .ql-picker-item[data-value=newtable_3_5]:before { content: "3x5"; } | |
| .ql-picker-item[data-value=newtable_4_1]:before { content: "4x1"; } | |
| .ql-picker-item[data-value=newtable_4_2]:before { content: "4x2"; } | |
| .ql-picker-item[data-value=newtable_4_3]:before { content: "4x3"; } | |
| .ql-picker-item[data-value=newtable_4_4]:before { content: "4x4"; } | |
| .ql-picker-item[data-value=newtable_4_5]:before { content: "4x5"; } | |
| .ql-picker-item[data-value=newtable_5_1]:before { content: "5x1"; } | |
| .ql-picker-item[data-value=newtable_5_2]:before { content: "5x2"; } | |
| .ql-picker-item[data-value=newtable_5_3]:before { content: "5x3"; } | |
| .ql-picker-item[data-value=newtable_5_4]:before { content: "5x4"; } | |
| .ql-picker-item[data-value=newtable_5_5]:before { content: "5x5"; } | |
| .ql-picker-item[data-value=newtable_6_1]:before { content: "6x1"; } | |
| .ql-picker-item[data-value=newtable_6_2]:before { content: "6x2"; } | |
| .ql-picker-item[data-value=newtable_6_3]:before { content: "6x3"; } | |
| .ql-picker-item[data-value=newtable_6_4]:before { content: "6x4"; } | |
| .ql-picker-item[data-value=newtable_6_5]:before { content: "6x5"; } | |
| .ql-picker-item[data-value=newtable_7_1]:before { content: "7x1"; } | |
| .ql-picker-item[data-value=newtable_7_2]:before { content: "7x2"; } | |
| .ql-picker-item[data-value=newtable_7_3]:before { content: "7x3"; } | |
| .ql-picker-item[data-value=newtable_7_4]:before { content: "7x4"; } | |
| .ql-picker-item[data-value=newtable_7_5]:before { content: "7x5"; } | |
| .ql-picker-item[data-value=newtable_8_1]:before { content: "8x1"; } | |
| .ql-picker-item[data-value=newtable_8_2]:before { content: "8x2"; } | |
| .ql-picker-item[data-value=newtable_8_3]:before { content: "8x3"; } | |
| .ql-picker-item[data-value=newtable_8_4]:before { content: "8x4"; } | |
| .ql-picker-item[data-value=newtable_8_5]:before { content: "8x5"; } | |
| .ql-picker-item[data-value=newtable_9_1]:before { content: "9x1"; } | |
| .ql-picker-item[data-value=newtable_9_2]:before { content: "9x2"; } | |
| .ql-picker-item[data-value=newtable_9_3]:before { content: "9x3"; } | |
| .ql-picker-item[data-value=newtable_9_4]:before { content: "9x4"; } | |
| .ql-picker-item[data-value=newtable_9_5]:before { content: "9x5"; } | |
| .ql-picker-item[data-value=newtable_10_1]:before { content: "10x1"; } | |
| .ql-picker-item[data-value=newtable_10_2]:before { content: "10x2"; } | |
| .ql-picker-item[data-value=newtable_10_3]:before { content: "10x3"; } | |
| .ql-picker-item[data-value=newtable_10_4]:before { content: "10x4"; } | |
| .ql-picker-item[data-value=newtable_10_5]:before { content: "10x5"; } | |
| .tdbr, .trbr { | |
| display: none | |
| }</script> | |
| <script id="jsbin-source-javascript" type="text/javascript">// quill-table-breaks.js | |
| let Container = Quill.import('blots/container'); | |
| let Scroll = Quill.import('blots/scroll'); | |
| let Inline = Quill.import('blots/inline'); | |
| let Block = Quill.import('blots/block'); | |
| let Delta = Quill.import('delta'); | |
| let Parchment = Quill.import('parchment'); | |
| let BlockEmbed = Quill.import('blots/block/embed'); | |
| let TextBlot = Quill.import('blots/text'); | |
| class ContainBlot extends Container { | |
| static create(value) { | |
| let tagName = 'contain'; | |
| let node = super.create(tagName); | |
| return node; | |
| } | |
| insertBefore(blot, ref) { | |
| if (blot.statics.blotName == this.statics.blotName) { | |
| console.log('############################ Not sure this is clean:') | |
| console.log(blot) | |
| console.log(blot.children.head) | |
| super.insertBefore(blot.children.head, ref); | |
| } else { | |
| super.insertBefore(blot, ref); | |
| } | |
| } | |
| static formats(domNode) { | |
| return domNode.tagName; | |
| } | |
| formats() { | |
| // We don't inherit from FormatBlot | |
| return { [this.statics.blotName]: this.statics.formats(this.domNode) } | |
| } | |
| replace(target) { | |
| if (target.statics.blotName !== this.statics.blotName) { | |
| let item = Parchment.create(this.statics.defaultChild); | |
| target.moveChildren(item); | |
| this.appendChild(item); | |
| } | |
| if (target.parent == null) return; | |
| super.replace(target) | |
| } | |
| } | |
| ContainBlot.blotName = 'contain'; | |
| ContainBlot.tagName = 'contain'; | |
| ContainBlot.scope = Parchment.Scope.BLOCK_BLOT; | |
| ContainBlot.defaultChild = 'block'; | |
| ContainBlot.allowedChildren = [Block, BlockEmbed, Container]; | |
| Quill.register(ContainBlot); | |
| class TableRow extends Container { | |
| static create(value) { | |
| let tagName = 'tr'; | |
| let node = super.create(tagName); | |
| return node; | |
| } | |
| optimize() { | |
| super.optimize(); | |
| var parent = this.parent | |
| if (parent != null && parent.statics.blotName != 'table') { | |
| this.processTable() | |
| } | |
| } | |
| processTable () { | |
| var currentBlot = this | |
| var rows = [] | |
| while (currentBlot) { | |
| if (! (currentBlot instanceof TableRow)) { | |
| break | |
| } | |
| rows.push(currentBlot) | |
| currentBlot = currentBlot.next | |
| } | |
| let mark = Parchment.create('block'); | |
| this.parent.insertBefore(mark, this.next); | |
| let table = Parchment.create('table'); | |
| rows.forEach(function (row) { | |
| table.appendChild(row) | |
| }) | |
| table.replace(mark) | |
| } | |
| } | |
| TableRow.blotName = 'tr'; | |
| TableRow.tagName = 'tr'; | |
| TableRow.scope = Parchment.Scope.BLOCK_BLOT; | |
| TableRow.defaultChild = 'td'; | |
| Quill.register(TableRow); | |
| class Table extends Container { | |
| optimize() { | |
| super.optimize(); | |
| let next = this.next; | |
| if (next != null && next.prev === this && | |
| next.statics.blotName === this.statics.blotName && | |
| next.domNode.tagName === this.domNode.tagName | |
| ) { | |
| next.moveChildren(this); | |
| next.remove(); | |
| } | |
| } | |
| } | |
| Table.blotName = 'table'; | |
| Table.tagName = 'table'; | |
| Table.scope = Parchment.Scope.BLOCK_BLOT; | |
| Table.defaultChild = 'tr'; | |
| Table.allowedChildren = [TableRow]; | |
| Quill.register(Table); | |
| // | |
| // | |
| // CONTAINER TD | |
| // | |
| class TableCell extends ContainBlot { | |
| format() { | |
| return 'td' | |
| } | |
| optimize() { | |
| super.optimize(); | |
| let parent = this.parent; | |
| if (parent != null && parent.statics.blotName != 'tr') { | |
| this.processTR() | |
| } | |
| // merge same TD id | |
| let next = this.next; | |
| if (next != null && next.prev === this && | |
| next.statics.blotName === this.statics.blotName && | |
| next.domNode.tagName === this.domNode.tagName | |
| ) { | |
| next.moveChildren(this); | |
| next.remove(); | |
| } | |
| } | |
| processTR () { | |
| // find next row break | |
| var currentBlot = this | |
| var rowItems = [this] | |
| while (currentBlot) { | |
| if (currentBlot.statics.tagName !== 'TD') { | |
| break | |
| } | |
| rowItems.push(currentBlot) | |
| if (currentBlot instanceof RowBreak) { | |
| break | |
| } | |
| currentBlot = currentBlot.next | |
| } | |
| // create row, add row items as TDs | |
| var prevItem | |
| var cellItems = [] | |
| var cells = [] | |
| rowItems.forEach(function (rowItem) { | |
| cellItems.push(rowItem) | |
| if (rowItem instanceof TableCell) { | |
| prevItem = rowItem | |
| } else if (rowItem instanceof CellBreak) { | |
| cells.push(cellItems) | |
| cellItems = [] | |
| } | |
| }) | |
| if (cellItems.length > 0) { | |
| cells.push(cellItems) | |
| } | |
| let mark = Parchment.create('block'); | |
| this.parent.insertBefore(mark, this.next); | |
| // create row | |
| var row = Parchment.create('tr') | |
| cells.forEach(function (cell) { | |
| // add row elements | |
| cell.forEach(function (cellItem) { | |
| row.appendChild(cellItem) | |
| }) | |
| }) | |
| row.replace(mark) | |
| } | |
| } | |
| TableCell.blotName = 'td'; | |
| TableCell.tagName = 'td'; | |
| TableCell.scope = Parchment.Scope.BLOCK_BLOT; | |
| TableCell.defaultChild = 'block'; | |
| TableCell.allowedChildren = [Block, BlockEmbed, Container]; | |
| Quill.register(TableCell); | |
| Container.order = [ | |
| 'list', 'contain', // Must be lower | |
| 'td', 'tr', 'table' // Must be higher | |
| ]; | |
| class RowBreak extends BlockEmbed { | |
| formats() { | |
| return { trbr: true } | |
| } | |
| } | |
| RowBreak.blotName = 'trbr' | |
| RowBreak.tagName = 'td' | |
| RowBreak.className = 'trbr' | |
| Quill.register(RowBreak); | |
| class CellBreak extends BlockEmbed { | |
| formats() { | |
| return { tdbr: true } | |
| } | |
| } | |
| CellBreak.blotName = 'tdbr' | |
| CellBreak.tagName = 'td' | |
| CellBreak.className = 'tdbr' | |
| Quill.register(CellBreak); | |
| // END quill-table-breaks.js | |
| // Render UI | |
| var Keyboard = Quill.import('modules/keyboard') | |
| // set up toolbar options | |
| let maxRows = 10; | |
| let maxCols = 5; | |
| let tableOptions = []; | |
| for (let r = 1; r <= maxRows; r++) { | |
| for (let c = 1; c <= maxCols; c++) { | |
| tableOptions.push('newtable_' + r + '_' + c); | |
| } | |
| } | |
| Quill.debug('debug'); | |
| var quill = new Quill('#editor-container', { | |
| modules: { | |
| toolbar: { | |
| container: [ | |
| [{ 'table': tableOptions }], // new table (cursor needs to be out of table) | |
| ['table-insert-rows'], // cursor needs to be in the table | |
| ['table-insert-columns'], // cursor needs to be in the table | |
| ['bold', 'italic', 'underline', 'strike'], | |
| ['blockquote', 'code-block'], | |
| [{ 'header': 1 }, { 'header': 2 }], | |
| [{ 'list': 'ordered'}, { 'list': 'bullet' }], | |
| [{ 'script': 'sub'}, { 'script': 'super' }], | |
| [{ 'indent': '-1'}, { 'indent': '+1' }], | |
| [{ 'direction': 'rtl' }], | |
| [{ 'size': ['small', false, 'large', 'huge'] }], | |
| [{ 'header': [1, 2, 3, 4, 5, 6, false] }], | |
| [{ 'color': [] }, { 'background': [] }], | |
| [{ 'align': [] }], | |
| ['link', 'image', 'code-block'], | |
| ['clean'] | |
| ], | |
| handlers: { | |
| table: function (value) { | |
| if(value && value.includes('newtable_')) { | |
| let sizes = value.split('_'); | |
| let rows = Number.parseInt(sizes[1]) | |
| let columns = Number.parseInt(sizes[2]) | |
| let table = Parchment.create('table'); | |
| const range = this.quill.getSelection() | |
| if (!range) return | |
| const newLineIndex = getClosestNewLineIndex(this.quill.getContents(), range.index + range.length) | |
| let changeDelta = new Delta().retain(newLineIndex) | |
| changeDelta = changeDelta.insert('\n') | |
| for (let i = 0; i < rows; i++) { | |
| for (let j = 0; j < columns; j++) { | |
| changeDelta = changeDelta.insert('\n', { | |
| td: true | |
| }) | |
| if (j < columns - 1) { | |
| changeDelta = changeDelta.insert({ tdbr: true }) | |
| } | |
| } | |
| changeDelta = changeDelta.insert({ trbr: true }) | |
| } | |
| this.quill.updateContents(changeDelta, Quill.sources.USER) | |
| this.quill.setSelection(newLineIndex + 1) | |
| } else { | |
| // TODO | |
| } | |
| }, | |
| 'table-insert-rows': function() { | |
| let td = find_td('td') | |
| if(td) { | |
| let col_count = 0 | |
| td.parent.children.forEach(function (it) { | |
| if (it instanceof TableCell) { | |
| col_count++ | |
| } | |
| }) | |
| let table = td.parent.parent; | |
| let new_row = td.parent.clone() | |
| for (var i = col_count - 1; i >= 0; i--) { | |
| let td = Parchment.create('td'); | |
| new_row.appendChild(td); | |
| new_row.appendChild(Parchment.create('tdbr')) | |
| }; | |
| new_row.appendChild(Parchment.create('trbr')) | |
| table.appendChild(new_row); | |
| } | |
| }, | |
| 'table-insert-columns': function() { | |
| let td = find_td('td') | |
| if(td) { | |
| let table = td.parent.parent; | |
| td.parent.parent.children.forEach(function(tr) { | |
| let td = Parchment.create('td'); | |
| tr.appendChild(td); | |
| tr.appendChild(Parchment.create('tdbr')) | |
| }); | |
| } | |
| } | |
| } | |
| }, | |
| clipboard: { | |
| matchers: [ | |
| ['TD, TH', function (node, delta) { | |
| delta.insert("\n", { td: true }) | |
| delta.insert({ tdbr: true }) | |
| return delta | |
| }], | |
| ['TR', function (node, delta) { | |
| delta.insert({ trbr: true }) | |
| return delta | |
| }], | |
| ] | |
| }, | |
| keyboard: { | |
| bindings: { | |
| 'backspaceTable': { | |
| key: 8, | |
| format: ['td'], | |
| // offset: 0, | |
| handler: function handleTableBackspace (range, context) { | |
| var formats = quill.getFormat(range.index-1, 1) | |
| if (formats.tdbr || formats.trbr) { | |
| // prevent deletion of table break | |
| return false | |
| } | |
| return true | |
| } | |
| } | |
| } | |
| }, | |
| }, | |
| placeholder: 'Compose an epic...', | |
| theme: 'snow' // or 'bubble' | |
| }); | |
| // global for console debugging | |
| QuillInstance = quill | |
| quill.on('text-change', function(delta, source) { | |
| document.getElementById("output_delta").value=JSON.stringify(quill.editor.getDelta(), null, 2) | |
| document.getElementById("output_html").value=quill.root.innerHTML; | |
| document.getElementById("view_html").innerHTML=quill.root.innerHTML; | |
| }) | |
| // use sample delta | |
| var delta = getSampleDelta() | |
| document.getElementById("orig_delta").value=JSON.stringify(delta, null, 2) | |
| quill.setContents(delta); | |
| function getClosestNewLineIndex (contents, index) { | |
| return index + contents.map((op) => { | |
| return typeof op.insert === 'string' ? op.insert : ' ' | |
| }).join('') | |
| .slice(index) | |
| .indexOf('\n') | |
| } | |
| function find_td(what) { | |
| let leaf = quill.getLeaf(quill.getSelection()['index']); | |
| let blot = leaf[0]; | |
| for(;blot!=null && blot.statics.blotName!=what;) { | |
| blot=blot.parent; | |
| } | |
| return blot; // return TD or NULL | |
| } | |
| function getSampleDelta () { | |
| return { | |
| "ops": [ | |
| { | |
| "insert": "Test Tables" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 1 | |
| } | |
| }, | |
| { | |
| "insert": "Empty 3x3 table from toolbar" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\nPopulated 3x3 table (from toolbar)" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "Col 1" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Col 2" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Col 3" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "a" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": "b" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": "c" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "123" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "456" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "d" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "4" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "7" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\nPasted Table" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "Company" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Contact" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Country" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Alfreds Futterkiste" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Maria Anders" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Germany" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Centro comercial Moctezuma" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Francisco Chang" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Mexico" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Ernst Handel" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Roland Mendel" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Austria" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Island Trading" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Helen Bennett" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "UK" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Laughing Bacchus Winecellars" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Yoshi Tannamuri" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Canada" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Magazzini Alimentari Riuniti" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Giovanni Rovelli" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Italy" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n" | |
| } | |
| ] | |
| } | |
| } | |
| </script></body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| .ql-editor table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| } | |
| .ql-editor table td { | |
| border: 1px solid black; | |
| padding: 5px; | |
| height: 25px; | |
| } | |
| button.ql-table::after { content: "TABLE"; } | |
| .ql-picker.ql-table .ql-picker-label::before { content: "TABLE"; } | |
| button.ql-contain::after { content: "WRAP"; } | |
| button.ql-table-insert-rows::after { content: "ROWS+"; } | |
| button.ql-table-insert-columns::after { content: "COLS+"; } | |
| .ql-table, | |
| .ql-contain { | |
| width: auto !important; | |
| margin-right: -15px; | |
| } | |
| .ql-picker.ql-table { | |
| margin-right: -15px; | |
| font-size: 11px; | |
| font-weight: normal; | |
| } | |
| .ql-picker.ql-table svg { | |
| display: none; | |
| } | |
| .ql-picker.ql-table .ql-picker-label { | |
| padding: 0px 3px; | |
| } | |
| .ql-picker.ql-table .ql-picker-options { | |
| width: 190px; | |
| } | |
| .ql-picker.ql-table .ql-picker-item { | |
| display: block; | |
| float: left; | |
| width: 30px; | |
| height: 30px; | |
| line-height: 30px; | |
| text-align: center; | |
| padding: 0px; | |
| margin: 1px; | |
| } | |
| .ql-picker.ql-table .ql-picker-item { | |
| background: lightgrey; | |
| } | |
| .ql-picker-item:nth-child(5):before { | |
| clear: both; | |
| display: block; | |
| content: ""; | |
| width: 100%; | |
| } | |
| .ql-picker-item[data-value=newtable_1_1]:before { content: "1x1"; } | |
| .ql-picker-item[data-value=newtable_1_2]:before { content: "1x2"; } | |
| .ql-picker-item[data-value=newtable_1_3]:before { content: "1x3"; } | |
| .ql-picker-item[data-value=newtable_1_4]:before { content: "1x4"; } | |
| .ql-picker-item[data-value=newtable_1_5]:before { content: "1x5"; } | |
| .ql-picker-item[data-value=newtable_2_1]:before { content: "2x1"; } | |
| .ql-picker-item[data-value=newtable_2_2]:before { content: "2x2"; } | |
| .ql-picker-item[data-value=newtable_2_3]:before { content: "2x3"; } | |
| .ql-picker-item[data-value=newtable_2_4]:before { content: "2x4"; } | |
| .ql-picker-item[data-value=newtable_2_5]:before { content: "2x5"; } | |
| .ql-picker-item[data-value=newtable_3_1]:before { content: "3x1"; } | |
| .ql-picker-item[data-value=newtable_3_2]:before { content: "3x2"; } | |
| .ql-picker-item[data-value=newtable_3_3]:before { content: "3x3"; } | |
| .ql-picker-item[data-value=newtable_3_4]:before { content: "3x4"; } | |
| .ql-picker-item[data-value=newtable_3_5]:before { content: "3x5"; } | |
| .ql-picker-item[data-value=newtable_4_1]:before { content: "4x1"; } | |
| .ql-picker-item[data-value=newtable_4_2]:before { content: "4x2"; } | |
| .ql-picker-item[data-value=newtable_4_3]:before { content: "4x3"; } | |
| .ql-picker-item[data-value=newtable_4_4]:before { content: "4x4"; } | |
| .ql-picker-item[data-value=newtable_4_5]:before { content: "4x5"; } | |
| .ql-picker-item[data-value=newtable_5_1]:before { content: "5x1"; } | |
| .ql-picker-item[data-value=newtable_5_2]:before { content: "5x2"; } | |
| .ql-picker-item[data-value=newtable_5_3]:before { content: "5x3"; } | |
| .ql-picker-item[data-value=newtable_5_4]:before { content: "5x4"; } | |
| .ql-picker-item[data-value=newtable_5_5]:before { content: "5x5"; } | |
| .ql-picker-item[data-value=newtable_6_1]:before { content: "6x1"; } | |
| .ql-picker-item[data-value=newtable_6_2]:before { content: "6x2"; } | |
| .ql-picker-item[data-value=newtable_6_3]:before { content: "6x3"; } | |
| .ql-picker-item[data-value=newtable_6_4]:before { content: "6x4"; } | |
| .ql-picker-item[data-value=newtable_6_5]:before { content: "6x5"; } | |
| .ql-picker-item[data-value=newtable_7_1]:before { content: "7x1"; } | |
| .ql-picker-item[data-value=newtable_7_2]:before { content: "7x2"; } | |
| .ql-picker-item[data-value=newtable_7_3]:before { content: "7x3"; } | |
| .ql-picker-item[data-value=newtable_7_4]:before { content: "7x4"; } | |
| .ql-picker-item[data-value=newtable_7_5]:before { content: "7x5"; } | |
| .ql-picker-item[data-value=newtable_8_1]:before { content: "8x1"; } | |
| .ql-picker-item[data-value=newtable_8_2]:before { content: "8x2"; } | |
| .ql-picker-item[data-value=newtable_8_3]:before { content: "8x3"; } | |
| .ql-picker-item[data-value=newtable_8_4]:before { content: "8x4"; } | |
| .ql-picker-item[data-value=newtable_8_5]:before { content: "8x5"; } | |
| .ql-picker-item[data-value=newtable_9_1]:before { content: "9x1"; } | |
| .ql-picker-item[data-value=newtable_9_2]:before { content: "9x2"; } | |
| .ql-picker-item[data-value=newtable_9_3]:before { content: "9x3"; } | |
| .ql-picker-item[data-value=newtable_9_4]:before { content: "9x4"; } | |
| .ql-picker-item[data-value=newtable_9_5]:before { content: "9x5"; } | |
| .ql-picker-item[data-value=newtable_10_1]:before { content: "10x1"; } | |
| .ql-picker-item[data-value=newtable_10_2]:before { content: "10x2"; } | |
| .ql-picker-item[data-value=newtable_10_3]:before { content: "10x3"; } | |
| .ql-picker-item[data-value=newtable_10_4]:before { content: "10x4"; } | |
| .ql-picker-item[data-value=newtable_10_5]:before { content: "10x5"; } | |
| .tdbr, .trbr { | |
| display: none | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // quill-table-breaks.js | |
| let Container = Quill.import('blots/container'); | |
| let Scroll = Quill.import('blots/scroll'); | |
| let Inline = Quill.import('blots/inline'); | |
| let Block = Quill.import('blots/block'); | |
| let Delta = Quill.import('delta'); | |
| let Parchment = Quill.import('parchment'); | |
| let BlockEmbed = Quill.import('blots/block/embed'); | |
| let TextBlot = Quill.import('blots/text'); | |
| class ContainBlot extends Container { | |
| static create(value) { | |
| let tagName = 'contain'; | |
| let node = super.create(tagName); | |
| return node; | |
| } | |
| insertBefore(blot, ref) { | |
| if (blot.statics.blotName == this.statics.blotName) { | |
| console.log('############################ Not sure this is clean:') | |
| console.log(blot) | |
| console.log(blot.children.head) | |
| super.insertBefore(blot.children.head, ref); | |
| } else { | |
| super.insertBefore(blot, ref); | |
| } | |
| } | |
| static formats(domNode) { | |
| return domNode.tagName; | |
| } | |
| formats() { | |
| // We don't inherit from FormatBlot | |
| return { [this.statics.blotName]: this.statics.formats(this.domNode) } | |
| } | |
| replace(target) { | |
| if (target.statics.blotName !== this.statics.blotName) { | |
| let item = Parchment.create(this.statics.defaultChild); | |
| target.moveChildren(item); | |
| this.appendChild(item); | |
| } | |
| if (target.parent == null) return; | |
| super.replace(target) | |
| } | |
| } | |
| ContainBlot.blotName = 'contain'; | |
| ContainBlot.tagName = 'contain'; | |
| ContainBlot.scope = Parchment.Scope.BLOCK_BLOT; | |
| ContainBlot.defaultChild = 'block'; | |
| ContainBlot.allowedChildren = [Block, BlockEmbed, Container]; | |
| Quill.register(ContainBlot); | |
| class TableRow extends Container { | |
| static create(value) { | |
| let tagName = 'tr'; | |
| let node = super.create(tagName); | |
| return node; | |
| } | |
| optimize() { | |
| super.optimize(); | |
| var parent = this.parent | |
| if (parent != null && parent.statics.blotName != 'table') { | |
| this.processTable() | |
| } | |
| } | |
| processTable () { | |
| var currentBlot = this | |
| var rows = [] | |
| while (currentBlot) { | |
| if (! (currentBlot instanceof TableRow)) { | |
| break | |
| } | |
| rows.push(currentBlot) | |
| currentBlot = currentBlot.next | |
| } | |
| let mark = Parchment.create('block'); | |
| this.parent.insertBefore(mark, this.next); | |
| let table = Parchment.create('table'); | |
| rows.forEach(function (row) { | |
| table.appendChild(row) | |
| }) | |
| table.replace(mark) | |
| } | |
| } | |
| TableRow.blotName = 'tr'; | |
| TableRow.tagName = 'tr'; | |
| TableRow.scope = Parchment.Scope.BLOCK_BLOT; | |
| TableRow.defaultChild = 'td'; | |
| Quill.register(TableRow); | |
| class Table extends Container { | |
| optimize() { | |
| super.optimize(); | |
| let next = this.next; | |
| if (next != null && next.prev === this && | |
| next.statics.blotName === this.statics.blotName && | |
| next.domNode.tagName === this.domNode.tagName | |
| ) { | |
| next.moveChildren(this); | |
| next.remove(); | |
| } | |
| } | |
| } | |
| Table.blotName = 'table'; | |
| Table.tagName = 'table'; | |
| Table.scope = Parchment.Scope.BLOCK_BLOT; | |
| Table.defaultChild = 'tr'; | |
| Table.allowedChildren = [TableRow]; | |
| Quill.register(Table); | |
| // | |
| // | |
| // CONTAINER TD | |
| // | |
| class TableCell extends ContainBlot { | |
| format() { | |
| return 'td' | |
| } | |
| optimize() { | |
| super.optimize(); | |
| let parent = this.parent; | |
| if (parent != null && parent.statics.blotName != 'tr') { | |
| this.processTR() | |
| } | |
| // merge same TD id | |
| let next = this.next; | |
| if (next != null && next.prev === this && | |
| next.statics.blotName === this.statics.blotName && | |
| next.domNode.tagName === this.domNode.tagName | |
| ) { | |
| next.moveChildren(this); | |
| next.remove(); | |
| } | |
| } | |
| processTR () { | |
| // find next row break | |
| var currentBlot = this | |
| var rowItems = [this] | |
| while (currentBlot) { | |
| if (currentBlot.statics.tagName !== 'TD') { | |
| break | |
| } | |
| rowItems.push(currentBlot) | |
| if (currentBlot instanceof RowBreak) { | |
| break | |
| } | |
| currentBlot = currentBlot.next | |
| } | |
| // create row, add row items as TDs | |
| var prevItem | |
| var cellItems = [] | |
| var cells = [] | |
| rowItems.forEach(function (rowItem) { | |
| cellItems.push(rowItem) | |
| if (rowItem instanceof TableCell) { | |
| prevItem = rowItem | |
| } else if (rowItem instanceof CellBreak) { | |
| cells.push(cellItems) | |
| cellItems = [] | |
| } | |
| }) | |
| if (cellItems.length > 0) { | |
| cells.push(cellItems) | |
| } | |
| let mark = Parchment.create('block'); | |
| this.parent.insertBefore(mark, this.next); | |
| // create row | |
| var row = Parchment.create('tr') | |
| cells.forEach(function (cell) { | |
| // add row elements | |
| cell.forEach(function (cellItem) { | |
| row.appendChild(cellItem) | |
| }) | |
| }) | |
| row.replace(mark) | |
| } | |
| } | |
| TableCell.blotName = 'td'; | |
| TableCell.tagName = 'td'; | |
| TableCell.scope = Parchment.Scope.BLOCK_BLOT; | |
| TableCell.defaultChild = 'block'; | |
| TableCell.allowedChildren = [Block, BlockEmbed, Container]; | |
| Quill.register(TableCell); | |
| Container.order = [ | |
| 'list', 'contain', // Must be lower | |
| 'td', 'tr', 'table' // Must be higher | |
| ]; | |
| class RowBreak extends BlockEmbed { | |
| formats() { | |
| return { trbr: true } | |
| } | |
| } | |
| RowBreak.blotName = 'trbr' | |
| RowBreak.tagName = 'td' | |
| RowBreak.className = 'trbr' | |
| Quill.register(RowBreak); | |
| class CellBreak extends BlockEmbed { | |
| formats() { | |
| return { tdbr: true } | |
| } | |
| } | |
| CellBreak.blotName = 'tdbr' | |
| CellBreak.tagName = 'td' | |
| CellBreak.className = 'tdbr' | |
| Quill.register(CellBreak); | |
| // END quill-table-breaks.js | |
| // Render UI | |
| var Keyboard = Quill.import('modules/keyboard') | |
| // set up toolbar options | |
| let maxRows = 10; | |
| let maxCols = 5; | |
| let tableOptions = []; | |
| for (let r = 1; r <= maxRows; r++) { | |
| for (let c = 1; c <= maxCols; c++) { | |
| tableOptions.push('newtable_' + r + '_' + c); | |
| } | |
| } | |
| Quill.debug('debug'); | |
| var quill = new Quill('#editor-container', { | |
| modules: { | |
| toolbar: { | |
| container: [ | |
| [{ 'table': tableOptions }], // new table (cursor needs to be out of table) | |
| ['table-insert-rows'], // cursor needs to be in the table | |
| ['table-insert-columns'], // cursor needs to be in the table | |
| ['bold', 'italic', 'underline', 'strike'], | |
| ['blockquote', 'code-block'], | |
| [{ 'header': 1 }, { 'header': 2 }], | |
| [{ 'list': 'ordered'}, { 'list': 'bullet' }], | |
| [{ 'script': 'sub'}, { 'script': 'super' }], | |
| [{ 'indent': '-1'}, { 'indent': '+1' }], | |
| [{ 'direction': 'rtl' }], | |
| [{ 'size': ['small', false, 'large', 'huge'] }], | |
| [{ 'header': [1, 2, 3, 4, 5, 6, false] }], | |
| [{ 'color': [] }, { 'background': [] }], | |
| [{ 'align': [] }], | |
| ['link', 'image', 'code-block'], | |
| ['clean'] | |
| ], | |
| handlers: { | |
| table: function (value) { | |
| if(value && value.includes('newtable_')) { | |
| let sizes = value.split('_'); | |
| let rows = Number.parseInt(sizes[1]) | |
| let columns = Number.parseInt(sizes[2]) | |
| let table = Parchment.create('table'); | |
| const range = this.quill.getSelection() | |
| if (!range) return | |
| const newLineIndex = getClosestNewLineIndex(this.quill.getContents(), range.index + range.length) | |
| let changeDelta = new Delta().retain(newLineIndex) | |
| changeDelta = changeDelta.insert('\n') | |
| for (let i = 0; i < rows; i++) { | |
| for (let j = 0; j < columns; j++) { | |
| changeDelta = changeDelta.insert('\n', { | |
| td: true | |
| }) | |
| if (j < columns - 1) { | |
| changeDelta = changeDelta.insert({ tdbr: true }) | |
| } | |
| } | |
| changeDelta = changeDelta.insert({ trbr: true }) | |
| } | |
| this.quill.updateContents(changeDelta, Quill.sources.USER) | |
| this.quill.setSelection(newLineIndex + 1) | |
| } else { | |
| // TODO | |
| } | |
| }, | |
| 'table-insert-rows': function() { | |
| let td = find_td('td') | |
| if(td) { | |
| let col_count = 0 | |
| td.parent.children.forEach(function (it) { | |
| if (it instanceof TableCell) { | |
| col_count++ | |
| } | |
| }) | |
| let table = td.parent.parent; | |
| let new_row = td.parent.clone() | |
| for (var i = col_count - 1; i >= 0; i--) { | |
| let td = Parchment.create('td'); | |
| new_row.appendChild(td); | |
| new_row.appendChild(Parchment.create('tdbr')) | |
| }; | |
| new_row.appendChild(Parchment.create('trbr')) | |
| table.appendChild(new_row); | |
| } | |
| }, | |
| 'table-insert-columns': function() { | |
| let td = find_td('td') | |
| if(td) { | |
| let table = td.parent.parent; | |
| td.parent.parent.children.forEach(function(tr) { | |
| let td = Parchment.create('td'); | |
| tr.appendChild(td); | |
| tr.appendChild(Parchment.create('tdbr')) | |
| }); | |
| } | |
| } | |
| } | |
| }, | |
| clipboard: { | |
| matchers: [ | |
| ['TD, TH', function (node, delta) { | |
| delta.insert("\n", { td: true }) | |
| delta.insert({ tdbr: true }) | |
| return delta | |
| }], | |
| ['TR', function (node, delta) { | |
| delta.insert({ trbr: true }) | |
| return delta | |
| }], | |
| ] | |
| }, | |
| keyboard: { | |
| bindings: { | |
| 'backspaceTable': { | |
| key: 8, | |
| format: ['td'], | |
| // offset: 0, | |
| handler: function handleTableBackspace (range, context) { | |
| var formats = quill.getFormat(range.index-1, 1) | |
| if (formats.tdbr || formats.trbr) { | |
| // prevent deletion of table break | |
| return false | |
| } | |
| return true | |
| } | |
| } | |
| } | |
| }, | |
| }, | |
| placeholder: 'Compose an epic...', | |
| theme: 'snow' // or 'bubble' | |
| }); | |
| // global for console debugging | |
| QuillInstance = quill | |
| quill.on('text-change', function(delta, source) { | |
| document.getElementById("output_delta").value=JSON.stringify(quill.editor.getDelta(), null, 2) | |
| document.getElementById("output_html").value=quill.root.innerHTML; | |
| document.getElementById("view_html").innerHTML=quill.root.innerHTML; | |
| }) | |
| // use sample delta | |
| var delta = getSampleDelta() | |
| document.getElementById("orig_delta").value=JSON.stringify(delta, null, 2) | |
| quill.setContents(delta); | |
| function getClosestNewLineIndex (contents, index) { | |
| return index + contents.map((op) => { | |
| return typeof op.insert === 'string' ? op.insert : ' ' | |
| }).join('') | |
| .slice(index) | |
| .indexOf('\n') | |
| } | |
| function find_td(what) { | |
| let leaf = quill.getLeaf(quill.getSelection()['index']); | |
| let blot = leaf[0]; | |
| for(;blot!=null && blot.statics.blotName!=what;) { | |
| blot=blot.parent; | |
| } | |
| return blot; // return TD or NULL | |
| } | |
| function getSampleDelta () { | |
| return { | |
| "ops": [ | |
| { | |
| "insert": "Test Tables" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 1 | |
| } | |
| }, | |
| { | |
| "insert": "Empty 3x3 table from toolbar" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\nPopulated 3x3 table (from toolbar)" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "Col 1" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Col 2" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Col 3" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "a" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": "b" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": "c" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "123" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "456" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "d" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "4" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "7" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\nPasted Table" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "header": 2 | |
| } | |
| }, | |
| { | |
| "insert": "Company" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Contact" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Country" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Alfreds Futterkiste" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Maria Anders" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Germany" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Centro comercial Moctezuma" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Francisco Chang" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Mexico" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Ernst Handel" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Roland Mendel" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Austria" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Island Trading" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Helen Bennett" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "UK" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Laughing Bacchus Winecellars" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Yoshi Tannamuri" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Canada" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Magazzini Alimentari Riuniti" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Giovanni Rovelli" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": "Italy" | |
| }, | |
| { | |
| "insert": "\n", | |
| "attributes": { | |
| "td": "TD" | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "tdbr": true | |
| }, | |
| "attributes": { | |
| "tdbr": true | |
| } | |
| }, | |
| { | |
| "insert": { | |
| "trbr": true | |
| }, | |
| "attributes": { | |
| "trbr": true | |
| } | |
| }, | |
| { | |
| "insert": "\n" | |
| } | |
| ] | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment