I added the ability for 1- moving the table, 2- styling the table.
See original GitHub issueI added the ability for:
- moving the table.
- styling the table.
Note: I tried to follow your way of making a tool as much as possible.
First: moving the table tool class:
class table_movingTool {
isDragging = false;
parent = null;
currentTarget = null;
// google: remove event listener from bind, to get why use these variables.
boundDrag = this.dragMoveToolHandler.bind(this);
boundMoving = this.movingTableHandler.bind(this);
boundDrop = this.dropMoveToolHandler.bind(this);
constructor(table, quill, options) {
if (!table) return null;
this.table = table;
this.quill = quill;
this.options = options;
this.domNode = null;
this.parent = this.quill.root.parentNode;
this.initMovingTool();
}
initMovingTool() {
this.domNode = document.createElement('div');
this.domNode.classList.add('qlbt-move-tool');
this.domNode.innerHTML =
`<svg style="width:22px;height:22px" viewBox="0 0 24 24"><path class="ql-custom-stroke-2" d="M20,2H4C2.89,2 2,2.89 2,4V20C2,21.11 2.89,22 4,22H20C21.11,22 22,21.11 22,20V4C22,2.89 21.11,2 20,2M20,20H4V4H20M13,8V10H11V8H9L12,5L15,8M16,15V13H14V11H16V9L19,12M10,13H8V15L5,12L8,9V11H10M15,16L12,19L9,16H11V14H13V16" /></svg>`;
this.domNode.addEventListener('mousedown', this.boundDrag);
this.parent.appendChild(this.domNode);
const tableRect = this.table.getBoundingClientRect();
const containerRect = this.quill.root.parentNode.getBoundingClientRect();
const tableViewRect = this.table.parentNode.getBoundingClientRect();
// css(this.domNode, {
// width: '22px',
// height: '22px',
// left: ''.concat(tableRect.x - 25, 'px'),
// top: ''.concat(tableViewRect.top - containerRect.top, 'px')
// });
new popper(this.table, this.domNode, {placement: 'bottom-start'}
);
}
locateMovingTool() {
this.quill.getModule('better-table').hideTableTools();
}
dragMoveToolHandler(e) {
this.isDragging = true;
this.table.style.opacity = '0.3';
document.addEventListener('mousemove', this.boundMoving);
document.addEventListener('mouseup', this.boundDrop);
}
dropMoveToolHandler(e) {
if (this.isDragging && e.target.nodeName === 'P') {
this.table.remove();
this.quill.root.insertBefore(this.table, e.target.nextSibling);
this.locateMovingTool();
}
this.isDragging = false;
this.table.style.opacity = '1';
if (this.currentTarget) this.currentTarget.classList.remove('current-position-table');
document.removeEventListener('mousemove', this.boundMoving);
document.removeEventListener('mouseup', this.boundDrop);
}
movingTableHandler(e) {
if (this.currentTarget) this.currentTarget.classList.remove('current-position-table');
e.preventDefault();
if (e.target.nodeName === 'P') {
this.currentTarget = e.target;
this.currentTarget.classList.add('current-position-table');
}
}
destroy() {
this.domNode.remove();
return null;
}
}
Second: stying the table tool class:
class table_styleTool {
backgroundColorBound = this.backgroundColorHandler.bind(this);
borderColorBound = this.borderColorHandler.bind(this);
borderWidthBound = this.borderWidthHandler.bind(this);
BorderStyleBound = this.borderStyleHandler.bind(this);
backgroundColorBtn;
borderColorBtn;
borderWidthBtn;
borderStyleBtn;
constructor(table, quill, options) {
if (!table) return null;
this.table = table;
this.quill = quill;
this.options = options;
this.domNode = null;
this.parent = this.quill.root.parentNode;
this.initStylingTool();
this.createStyingItems();
}
initStylingTool() {
this.domNode = document.createElement('div');
this.domNode.classList.add('qlbt-style-tool');
this.domNode.addEventListener('click', this.boundClick);
this.parent.appendChild(this.domNode);
const tableRect = this.table.getBoundingClientRect();
const containerRect = this.quill.root.parentNode.getBoundingClientRect();
const tableViewRect = this.table.parentNode.getBoundingClientRect();
// css(this.domNode, {
// width: '22px',
// height: '22px',
// left: ''.concat(tableRect.x - 25, 'px'),
// top: ''.concat(tableViewRect.top - containerRect.top + 22, 'px')
// });
new popper(this.table, this.domNode, {
placement: 'left-start',
modifiers: {
offset: {
enabled: true,
},
preventOverflow: {
enabled: true,
escapeWithReference: true,
}
}
}
);
}
createStyingItems() {
this.backgroundColorBtn = document.createElement('div');
this.backgroundColorBtn.id = 'backgroundColor';
this.backgroundColorBtn.innerHTML = `<svg style="width:22px;height:22px" viewBox="0 0 24 24">
<path class="ql-custom-stroke-2" d="M19,11.5C19,11.5 17,13.67 17,15A2,2 0 0,0 19,17A2,2 0 0,0 21,15C21,13.67 19,11.5 19,11.5M5.21,10L10,5.21L14.79,10M16.56,8.94L7.62,0L6.21,1.41L8.59,3.79L3.44,8.94C2.85,9.5 2.85,10.47 3.44,11.06L8.94,16.56C9.23,16.85 9.62,17 10,17C10.38,17 10.77,16.85 11.06,16.56L16.56,11.06C17.15,10.47 17.15,9.5 16.56,8.94Z" />
</svg>`;
this.borderColorBtn = document.createElement('div');
this.borderColorBtn.id = 'borderColorBtn';
this.borderColorBtn.innerHTML = `<svg style="width:22px;height:22px" viewBox="0 0 24 24">
<path class="ql-custom-stroke-2" d="M20.71,4.04C21.1,3.65 21.1,3 20.71,2.63L18.37,0.29C18,-0.1 17.35,-0.1 16.96,0.29L15,2.25L18.75,6M17.75,7L14,3.25L4,13.25V17H7.75L17.75,7Z" />
</svg>`;
this.borderWidthBtn = document.createElement('div');
this.borderWidthBtn.id = 'borderWidthBtn';
this.borderWidthBtn.innerHTML = `<svg style="width:22px;height:22px" viewBox="0 0 24 24">
<path class="ql-custom-stroke-2" d="M3,17H21V15H3V17M3,20H21V19H3V20M3,13H21V10H3V13M3,4V8H21V4H3Z" />
</svg>`;
this.borderStyleBtn = document.createElement('div');
this.borderStyleBtn.id = 'BorderStyleBtn';
this.borderStyleBtn.innerHTML = `<svg style="width:22px;height:22px" viewBox="0 0 24 24">
<path class="ql-custom-stroke-2" d="M3,16H8V14H3V16M9.5,16H14.5V14H9.5V16M16,16H21V14H16V16M3,20H5V18H3V20M7,20H9V18H7V20M11,20H13V18H11V20M15,20H17V18H15V20M19,20H21V18H19V20M3,12H11V10H3V12M13,12H21V10H13V12M3,4V8H21V4H3Z" />
</svg>`;
this.backgroundColorBtn.addEventListener('click', this.backgroundColorBound);
this.borderColorBtn.addEventListener('click', this.borderColorBound);
this.borderWidthBtn.addEventListener('click', this.borderWidthBound);
this.borderStyleBtn.addEventListener('click', this.BorderStyleBound);
this.domNode.appendChild(this.backgroundColorBtn);
this.domNode.appendChild(this.borderColorBtn);
this.domNode.appendChild(this.borderWidthBtn);
this.domNode.appendChild(this.borderStyleBtn);
}
backgroundColorHandler(e) {
const clickedElement = e.target;
if (clickedElement === this.backgroundColorBtn) {
this.destroyCurrentPicker();
this.createColorPicker(this.backgroundColorBtn);
} else if (clickedElement.className === 'qlbt-style-colors-item') {
const selectedCells = this.quill.getModule('better-table').getSelectedCells();
if (!selectedCells) return;
selectedCells.forEach(cell => cell.domNode.style.backgroundColor =
clickedElement.dataset.value);
}
}
borderColorHandler(e) {
const clickedElement = e.target;
if (clickedElement === this.borderColorBtn) {
this.destroyCurrentPicker();
this.createColorPicker(this.borderColorBtn);
} else if (clickedElement.className === 'qlbt-style-colors-item') {
const selectedCells = this.quill.getModule('better-table').getSelectedCells();
if (!selectedCells) return;
selectedCells.forEach(cell => cell.domNode.style.borderColor =
clickedElement.dataset.value);
}
}
borderWidthHandler(e) {
const clickedElement = e.target;
if (clickedElement === this.borderWidthBtn) {
this.destroyCurrentPicker();
this.createPicker(this.borderWidthBtn, [0, 1, 1.5, 1.75, 2.25, 3, 4.5,
6]);
} else if (clickedElement.className === 'qlbt-style-item') {
const selectedCells = this.quill.getModule('better-table').getSelectedCells();
if (!selectedCells) return;
selectedCells.forEach(cell => cell.domNode.style.borderWidth =
`${clickedElement.dataset.value}px`);
}
}
borderStyleHandler(e) {
const clickedElement = e.target;
if (clickedElement === this.borderStyleBtn) {
this.destroyCurrentPicker();
this.createPicker(this.borderStyleBtn, ['solid', 'dotted',
'dashed']);
} else if (clickedElement.className === 'qlbt-style-item') {
const selectedCells = this.quill.getModule('better-table').getSelectedCells();
if (!selectedCells) return;
selectedCells.forEach(cell => cell.domNode.style.borderStyle =
clickedElement.dataset.value);
}
}
destroy() {
this.domNode.remove();
return null;
}
createPicker(pickerParent, items) {
let pickerContainer = document.createElement('span');
pickerContainer.classList.add('qlbt-style-picker-options');
pickerParent.appendChild(pickerContainer);
items.forEach(item => {
let itemSpan = document.createElement('span');
itemSpan.className = 'qlbt-style-item';
itemSpan.dataset.value = item;
if (pickerParent === this.borderWidthBtn) itemSpan.innerText = item;
else {
const line = document.createElement('div');
line.id = item;
itemSpan.appendChild(line);
}
pickerContainer.appendChild(itemSpan);
});
}
createColorPicker(colorPickerParent) {
let colors = ['#000000', '#e60000', '#ff9900',
'#ffff00',
'#008a00', '#0066cc', '#9933ff', '#ffffff',
'#facccc', '#ffebcc', '#ffffcc', '#cce8cc',
'#cce0f5', '#ebd6ff', '#bbbbbb', '#f06666',
'#ffc266', '#ffff66', '#66b966', '#66a3e0',
'#c285ff', '#888888', '#a10000', '#b26b00',
'#b2b200', '#006100', '#0047b2', '#6b24b2',
'#444444', '#5c0000', '#663d00', '#666600',
'#003700', '#002966', '#3d1466'];
let colorPickerContainer = document.createElement('span');
colorPickerContainer.classList.add('qlbt-style-colors-picker-options');
colorPickerParent.appendChild(colorPickerContainer);
colors.forEach(color => {
let colorSpan = document.createElement('span');
colorSpan.className = 'qlbt-style-colors-item';
colorSpan.dataset.value = color;
colorSpan.style.backgroundColor = color;
colorPickerContainer.appendChild(colorSpan);
});
}
destroyCurrentPicker() {
if (this.backgroundColorBtn.querySelector('span'))
this.backgroundColorBtn.removeChild(this.backgroundColorBtn.querySelector('span'));
else if (this.borderColorBtn.querySelector('span'))
this.borderColorBtn.removeChild(this.borderColorBtn.querySelector('span'));
else if (this.borderWidthBtn.querySelector('span'))
this.borderWidthBtn.removeChild(this.borderWidthBtn.querySelector('span'));
else if (this.borderStyleBtn.querySelector('span'))
this.borderStyleBtn.removeChild(this.borderStyleBtn.querySelector('span'));
}
}
Also, I added new function the module which is getSelectedCells();
getSelectedCells() {
return this.tableSelection.selectedTds;
}
I also, added style for these tool, and modify the style for existed tools:
- for TableColumnTool, since changing the length of a column for upper tool is not convenient, I change it’s style so changing length of a column is like the way Google Docs does it which is above the columns directly, so, take it or leave it.
.quill-better-table-wrapper {
overflow-x: auto;
}
table {
table-layout: fixed;
border-collapse: collapse;
text-align: right;
}
table td {
border: 1px solid #000;
padding: 2px 5px;
}
.qlbt-operation-menu {
background-color: #fff;
font-size: 14px;
z-index: 100;
overflow: hidden;
display: grid;
grid-template-columns: repeat(12, 30px);
grid-template-rows: 35px;
align-items: center;
justify-items: center;
transition: opacity 0.5s;
box-shadow: 0 0 20px 4px rgba(154, 161, 177, .15), 0 4px 80px -8px rgba(36, 40, 47, .25), 0 4px 4px -2px rgba(91, 94, 105, .15);
border-radius: 0.4em;
}
.qlbt-operation-menu .qlbt-operation-menu-item {
background-color: #fff;
cursor: pointer;
color: #595959;
overflow: hidden;
text-overflow: ellipsis;
transition: .3s;
border: none;
}
.qlbt-col-tool, .qlbt-move-tool, .qlbt-style-tool {
position: absolute;
display: flex;
z-index: 99;
height: 16px;
}
.qlbt-col-tool {
margin-top: -15px;
margin-left: -3px;
opacity: 0;
}
.qlbt-move-tool, .qlbt-style-tool {
opacity: .35;
transition: .2s;
cursor: pointer;
}
.qlbt-style-tool .icon {
position: relative;
}
.qlbt-move-tool:hover,
.qlbt-move-tool:focus-within,
.qlbt-style-tool:focus-within,
.qlbt-style-tool:hover {
opacity: .8;
transition: .2s;
}
.qlbt-style-tool {
display: grid;
}
.qlbt-col-tool:hover .qlbt-col-tool-cell {
/*background-color: var(--light-primary);*/
transition: .2s;
}
.qlbt-col-tool .qlbt-col-tool-cell {
position: relative;
background-color: #fff;
/*border-top: 1px solid #000;*/
/*border-right: 2px solid #000;*/
/*border-bottom: 1px solid #000;*/
}
.qlbt-col-tool .qlbt-col-tool-cell:first-child {
/*border-left: 2px solid #000;*/
}
.qlbt-col-tool .qlbt-col-tool-cell-holder {
position: absolute;
right: 0;
top: 0;
bottom: 0;
z-index: 3;
width: 2px;
background-color: var(--primary);
cursor: ew-resize;
}
.qlbt-col-tool .qlbt-col-tool-cell-holder:hover {
background-color: #35a7ed;
}
.qlbt-col-tool .qlbt-col-tool-cell-holder::before {
content: "";
position: absolute;
top: 0;
left: -6px;
display: block;
width: 8px;
height: 100%;
}
.qlbt-col-tool .qlbt-col-tool-cell-holder::after {
content: "";
position: absolute;
top: 0;
right: -6px;
display: block;
width: 8px;
height: 100%;
}
button.ql-copy-format.ql-active {
cursor: url('data:image/svg+xml;utf8,<svg width="18"height="18" viewBox="0 0 22 22"><path class="ql-fill"d="M18,4V3A1,1 0 0,0 17,2H5A1,1 0 0,0 4,3V7A1,1 0 0,0 5,7H17A1,1 0 0,0 11,7V6H19V10H9V21A1,1 0 0,0 10,22H12A1,1 0 0,0 11,21V12H21V4H18Z"/></svg>'), auto;
}
#insertColumnLeft:hover path, #insertColumnRight:hover path, #insertRowUp:hover path,
#insertRowDown:hover {
fill: var(--success);
transition: .3s;
}
#deleteColumn:hover path, #deleteRow:hover path, #deleteTable:hover path {
fill: var(--danger);
transition: .3s;
}
#insertColumnLeft path, #insertColumnRight path, #insertRowUp path,
#insertRowDown, #deleteColumn path, #deleteRow path, #deleteTable path {
transition: .3s;
}
.qlbt-operation-menu *:not(hr):hover {
background-color: var(--light-primary);
}
.current-position-table {
border-radius: .3em;
border: 1px var(--dark-gray) dotted;
background-color: var(--white);
padding: 30px;
transition: .3s;
}
.qlbt-style-colors-picker-options {
background-color: #fff;
position: absolute;
top: 1px;
right: 40px;
padding: 3px 5px;
width: 152px;
}
.qlbt-style-picker-options {
background-color: #fff;
display: grid;
grid-template-rows: repeat(auto-fit, 1fr);
grid-gap: 5px;
position: absolute;
top: 1px;
right: 40px;
font-size: 16px;
font-weight: bold;
text-align: center;
color: var(--black);
box-shadow: 0 0 6px #00000035;
border-radius: .3em;
}
.qlbt-style-colors-item {
border: 1px solid transparent;
float: left;
height: 16px;
margin: 2px;
width: 16px;
z-index: 50;
transition: .2s;
}
.qlbt-style-item {
z-index: 50;
padding: 5px;
transition: .2s;
}
.qlbt-style-item:hover, .qlbt-style-colors-item:hover, .selected-item {
opacity: 1;
transition: .2s;
}
.qlbt-style-colors-item:hover, .selected-item {
border-color: var(--dark-gray);
transition: .2s;
}
.qlbt-style-item:hover, .selected-item {
background-color: var(--light-primary);
transition: .2s;
}
#solid {
width: 50px;
margin: 4px;
display: inline-block;
border-top: 2px solid rgb(0, 0, 0);
}
#dotted {
width: 50px;
margin-bottom: 4px;
display: inline-block;
border-top: 2px dotted rgb(0, 0, 0);
}
#dashed {
width: 50px;
margin-bottom: 4px;
display: inline-block;
border-top: 2px dashed rgb(0, 0, 0);
}
Note: I use popper.js for positioning the tools, you can remove it or consider using it.
feel free to take and modfiy my code as needed.
I’m sorry if issues page is not the place for these kind of posts.
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (2 by maintainers)
Top Results From Across the Web
Styling tables - Learn web development | MDN
This article provides a guide to making HTML tables look good, with some specific table styling techniques highlighted.
Read more >Format a table - Microsoft Support
Use Table Styles to format an entire table · Add or remove borders · Display or hide gridlines · Add a cell, row,...
Read more >Word 2010: Working with Tables - GCFGlobal
In this lesson, you will learn how to convert text to a table, apply table styles, format tables, and create blank tables.
Read more >Tables in HTML documents
<TABLE border="1" summary="This table gives some statistics about fruit ... of columns in a table), extra row cells are added to the right...
Read more >Word Table Move Column (2020) - YouTube
Word table, move column. That's what you will learn in this tutorial. I'll show you a trick to easily move the table columns...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Thanks for your awesome module!
I’m sorry, but I was working in production file which is this file https://github.com/soccerloway/quill-better-table/blob/master/dist/quill-better-table.js, since I did not expect to change alot, so showing it in CodePen is a pain. However, I’m planning to use the source file for the future (I will work for row-height changing tool, and an option to equalize the size of each cell, and others, don’t wait for me if you want to implement those 😃 )
About
styling the table
, these images my help:For background color
For border style
No image needed for the rest
Since you are here, please try to solve these two problems in column-width changing tool:
@KMLX28 could you please give further info on how to integrate your above changes with current quill-better-table master branch? Am interested in trying, but not sure where to include your changes