diff --git a/README.md b/README.md index 0406a63..6dba30f 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,21 @@ A theme component that adds a button to the composer tools to easily build tables in markdown. -## To Do List: +## To Do List - [X] Add table builder functionality - [ ] Possibly add the ability to edit tables -- [X] Add front-end tests \ No newline at end of file +- [X] Add front-end tests + +## Edit Table Functionality (WIP) + +Known Issues: + +- Clicking expand table button showing empty modal +- After viewing an edit table modal once, a reload is required for it to work again or with another table, otherwise the following error appears: + +```js + You need to pass a node argument to Importabular, like this : new Importabular({node: document.body}) +``` + +This is possibly due to not having a unique id? Perhaps moving functionality to a component will resolve this. diff --git a/about.json b/about.json index c1a8c50..af2ec3d 100644 --- a/about.json +++ b/about.json @@ -8,7 +8,9 @@ "theme_version": "0.0.1", "minimum_discourse_version": null, "maximum_discourse_version": null, - "assets": {}, + "assets": { + "importabular": "assets/importabular.js" + }, "modifiers": { "svg_icons": [ "align-left", diff --git a/assets/importabular.js b/assets/importabular.js new file mode 100644 index 0000000..acf237a --- /dev/null +++ b/assets/importabular.js @@ -0,0 +1,726 @@ +!(function (t, e) { + "object" == typeof exports && "object" == typeof module + ? (module.exports = e()) + : "function" == typeof define && define.amd + ? define([], e) + : "object" == typeof exports + ? (exports.Importabular = e()) + : (t.Importabular = e()); +})(self, function () { + return (() => { + "use strict"; + var t = { + 103: (t, e, i) => { + i.d(e, { default: () => l }); + class s { + constructor() { + var t, e; + (e = {}), + (t = "_data") in this + ? Object.defineProperty(this, t, { + value: e, + enumerable: !0, + configurable: !0, + writable: !0, + }) + : (this[t] = e); + } + _setVal(t, e, i) { + const s = this._data, + n = (function (t) { + return 0 === t ? "0" : t ? t.toString() : ""; + })(i); + var o; + n + ? (s[t] || (s[t] = {}), (s[t][e] = n)) + : s[t] && + s[t][e] && + (delete s[t][e], + (o = s[t]), + 0 === Object.keys(o).length && delete s[t]); + } + _clear() { + this._data = {}; + } + _getVal(t, e) { + const i = this._data; + return (i && i[t] && i[t][e]) || ""; + } + _toArr(t, e) { + const i = []; + for (let s = 0; s < e; s++) { + i.push([]); + for (let e = 0; e < t; e++) i[s].push(this._getVal(e, s)); + } + return i; + } + } + function n(t, e, i, s, n, o, r) { + if ((t += i) < s) { + if (n === 1 / 0) return { x: s, y: e }; + if (((t = n), --e < o)) { + if (r === 1 / 0) return { x: s, y: o }; + e = r; + } + } + return ( + t > n && ((t = s), ++e > r && ((e = o), (t = s))), { x: t, y: e } + ); + } + function o(t) { + return t.split('"').length - 1; + } + function r(t, e, i) { + return ( + e in t + ? Object.defineProperty(t, e, { + value: i, + enumerable: !0, + configurable: !0, + writable: !0, + }) + : (t[e] = i), + t + ); + } + const h = [ + "mousedown", + "mouseenter", + "mouseup", + "mouseleave", + "touchstart", + "touchend", + "touchmove", + "keydown", + "paste", + "cut", + "copy", + ]; + class l { + constructor(t) { + r(this, "_width", 1), + r(this, "_height", 1), + r(this, "_data", new s()), + r(this, "paste", (t) => { + if (this._editing) return; + t.preventDefault(); + const e = (function (t) { + var e, + i, + s, + n, + r, + h, + l, + a = [], + c = 0; + for ( + (s = t.split("\n")).length > 1 && + "" === s[s.length - 1] && + s.pop(), + e = 0, + i = s.length; + e < i; + e += 1 + ) { + for ( + s[e] = s[e].split("\t"), n = 0, r = s[e].length; + n < r; + n += 1 + ) + a[c] || (a[c] = []), + h && 0 === n + ? ((l = a[c].length - 1), + (a[c][l] = a[c][l] + "\n" + s[e][0]), + h && + 1 & o(s[e][0]) && + ((h = !1), + (a[c][l] = a[c][l] + .substring(0, a[c][l].length - 1) + .replace(/""/g, '"')))) + : n === r - 1 && + 0 === s[e][n].indexOf('"') && + 1 & o(s[e][n]) + ? (a[c].push( + s[e][n].substring(1).replace(/""/g, '"') + ), + (h = !0)) + : (a[c].push(s[e][n].replace(/""/g, '"')), + (h = !1)); + h || (c += 1); + } + return a; + })( + (t.clipboardData || window.clipboardData).getData( + "text/plain" + ) + ), + { rx: i, ry: s } = this._selection, + n = { x: i[0], y: s[0] }; + for (let t = 0; t < e.length; t++) + for (let i = 0; i < e[0].length; i++) + this._setVal(n.x + i, n.y + t, e[t][i]); + this._changeSelectedCellsStyle(() => { + (this._selectionStart = n), + (this._selectionEnd = { + x: n.x + e[0].length - 1, + y: n.y + e.length - 1, + }), + this._onDataChanged(); + }); + }), + r(this, "copy", (t) => { + if (this._editing) return; + const e = this._getSelectionAsArray(); + e && + (t.preventDefault(), + t.clipboardData.setData( + "text/plain", + (function (t) { + var e, + i, + s, + n, + o, + r = ""; + for (e = 0, i = t.length; e < i; e += 1) { + for (s = 0, n = t[e].length; s < n; s += 1) + s > 0 && (r += "\t"), + "string" == typeof (o = t[e][s]) + ? o.indexOf("\n") > -1 + ? (r += '"' + o.replace(/"/g, '""') + '"') + : (r += o) + : (r += null == o ? "" : o); + r += "\n"; + } + return r; + })(e) + )); + }), + r(this, "cut", (t) => { + this._editing || + (this.copy(t), this._setAllSelectedCellsTo("")); + }), + r(this, "keydown", (t) => { + t.ctrlKey || + (this._selectionStart && + ("Escape" === t.key && + this._editing && + (t.preventDefault(), + this._revertEdit(), + this._stopEditing()), + "Enter" === t.key && + (t.preventDefault(), + this._tabCursorInSelection(!1, t.shiftKey ? -1 : 1)), + "Tab" === t.key && + (t.preventDefault(), + this._tabCursorInSelection(!0, t.shiftKey ? -1 : 1)), + this._editing || + ("F2" === t.key && + (t.preventDefault(), this._startEditing(this._focus)), + ("Delete" !== t.key && "Backspace" !== t.key) || + (t.preventDefault(), this._setAllSelectedCellsTo("")), + "ArrowDown" === t.key && + (t.preventDefault(), + this._moveCursor({ y: 1 }, t.shiftKey)), + "ArrowUp" === t.key && + (t.preventDefault(), + this._moveCursor({ y: -1 }, t.shiftKey)), + "ArrowLeft" === t.key && + (t.preventDefault(), + this._moveCursor({ x: -1 }, t.shiftKey)), + "ArrowRight" === t.key && + (t.preventDefault(), + this._moveCursor({ x: 1 }, t.shiftKey))), + 1 !== t.key.length || + this._editing || + this._changeSelectedCellsStyle(() => { + const { x: t, y: e } = this._focus; + this._startEditing({ x: t, y: e }), + (this._getCell(t, e).firstChild.value = ""); + }))); + }), + r(this, "_selecting", !1), + r(this, "_selectionStart", null), + r(this, "_selectionEnd", null), + r(this, "_selection", { rx: [0, 0], ry: [0, 0] }), + r(this, "_editing", null), + r(this, "_focus", null), + r(this, "mousedown", (t) => { + if (!this.mobile) { + if ( + 3 === t.which && + !this._editing && + this._selectionSize() + ) { + let t = new Range(); + const { rx: e, ry: i } = this._selection; + return ( + t.setStart(this._getCell(e[0], i[0]), 0), + t.setEnd(this._getCell(e[0], i[0]), 1), + this.cwd.getSelection().removeAllRanges(), + void this.cwd.getSelection().addRange(t) + ); + } + this._changeSelectedCellsStyle(() => { + (this.tbody.style.userSelect = "none"), + (this._selectionEnd = + this._selectionStart = + this._focus = + this._getCoords(t)), + (this._selecting = !0); + }); + } + }), + r(this, "mouseenter", (t) => { + this.mobile || + (this._selecting && + this._changeSelectedCellsStyle(() => { + this._selectionEnd = this._getCoords(t); + })); + }), + r(this, "_lastMouseUp", null), + r(this, "_lastMouseUpTarget", null), + r(this, "mouseup", (t) => { + this.mobile || + (3 !== t.which && + this._selecting && + this._changeSelectedCellsStyle(() => { + (this._selectionEnd = this._getCoords(t)), + this._endSelection(), + this._lastMouseUp && + this._lastMouseUp > Date.now() - 300 && + this._lastMouseUpTarget.x === + this._selectionEnd.x && + this._lastMouseUpTarget.y === + this._selectionEnd.y && + this._startEditing(this._selectionEnd), + (this._lastMouseUp = Date.now()), + (this._lastMouseUpTarget = this._selectionEnd); + })); + }), + r(this, "mouseleave", (t) => { + t.target === this.tbody && + this._selecting && + this._endSelection(); + }), + r(this, "touchstart", (t) => { + this._editing || ((this.mobile = !0), (this.moved = !1)); + }), + r(this, "touchend", (t) => { + this.mobile && + (this._editing || + this.moved || + (this._changeSelectedCellsStyle(() => { + this._selectionEnd = + this._selectionStart = + this._focus = + this._getCoords(t); + }), + this._startEditing(this._focus))); + }), + r(this, "touchmove", (t) => { + this.mobile && (this.moved = !0); + }), + r(this, "_stopEditing", () => { + if (!this._editing) return; + const { x: t, y: e } = this._editing, + i = this._getCell(t, e); + (i.style.width = ""), (i.style.height = ""); + const s = i.firstChild; + s.removeEventListener("blur", this._stopEditing), + s.removeEventListener("keydown", this._blurIfEnter), + this._setVal(t, e, s.value), + this._onDataChanged(), + i.removeChild(s), + (this._editing = null), + this._renderTDContent(i, t, e); + }), + r(this, "_blurIfEnter", (t) => { + 13 === t.keyCode && (this._stopEditing(), t.preventDefault()); + }), + r(this, "_restyle", ({ x: t, y: e }) => { + const i = this._getCell(t, e); + i.className = this._classNames(t, e); + const s = a(this.checkResults.titles, t, e); + s ? i.setAttribute("title", s) : i.removeAttribute("title"); + }), + r(this, "_refreshDisplayedValue", ({ x: t, y: e }) => { + const i = this._getCell(t, e).firstChild; + "DIV" === i.tagName && + (i.textContent = this._divContent(t, e)), + this._restyle({ x: t, y: e }); + }), + this._saveConstructorOptions(t), + this._setupDom(), + this._replaceDataWithArray(t.data), + this._incrementToFit({ + x: this.columns.length - 1, + y: this._options.minRows - 1, + }), + this._fillScrollSpace(); + } + _runChecks(t) { + const { titles: e, classNames: i } = this.checks(t); + this.checkResults = { titles: e, classNames: i }; + } + _saveConstructorOptions({ + data: t = [], + node: e = null, + onChange: i = null, + minRows: s = 1, + maxRows: n = 1 / 0, + css: o = "", + width: r = "100%", + height: h = "80vh", + columns: l, + checks: a, + }) { + if ( + ((this.columns = l), + (this.checks = a || (() => ({}))), + this._runChecks(t), + !e) + ) + throw new Error( + "You need to pass a node argument to Importabular, like this : new Importabular({node: document.body})" + ); + (this._parent = e), + (this._options = { + onChange: i, + minRows: s, + maxRows: n, + css: + "\nhtml{\n -ms-overflow-style: none;\n scrollbar-width: none;\n}\n::-webkit-scrollbar {\n width: 0;\n height:0;\n}\n*{\n box-sizing: border-box;\n}\nbody{\n padding: 0; \n margin: 0;\n}\ntable{\n border-spacing: 0;\n background: white;\n border: 1px solid #ddd;\n border-width: 0 1px 1px 0;\n font-size: 16px;\n font-family: sans-serif;\n border-collapse: separate;\n min-width:100%;\n}\ntd, th{\n padding:0;\n border: 1px solid;\n border-color: #ddd transparent transparent #ddd; \n}\ntd.selected.multi:not(.editing){\n background:#d7f2f9;\n} \ntd.focus:not(.editing){\n border-color: black;\n} \ntd>*, th>*{\n border:none;\n padding:10px;\n min-width:100px;\n min-height: 40px;\n font:inherit;\n line-height: 20px;\n color:inherit;\n white-space: normal;\n}\ntd>div::selection {\n color: none;\n background: none;\n}\n\n.placeholder div{\n user-select:none;\n color:rgba(0,0,0,0.2);\n}\n*[title] div{cursor:help;}\nth{text-align:left;}\n" + + o, + }), + (this._iframeStyle = { + width: r, + height: h, + border: "none", + background: "transparent", + }); + } + _fitBounds({ x: t, y: e }) { + return ( + t >= 0 && + t < this.columns.length && + e >= 0 && + e < this._options.maxRows + ); + } + _fillScrollSpace() { + const t = Math.ceil(this.iframe.contentWindow.innerHeight / 40), + e = Math.ceil(this.iframe.contentWindow.innerWidth / 100); + this._incrementToFit({ x: e - 1, y: t - 1 }); + } + getData() { + return this._data._toArr(this._width, this._height); + } + _onDataChanged() { + const t = this.getData(); + this._options.onChange && this._options.onChange(t), + this._runChecks(t), + this._restyleAll(); + } + _renderTDContent(t, e, i) { + const s = document.createElement("div"); + t.setAttribute("x", e.toString()), + t.setAttribute("y", i.toString()); + const n = this._divContent(e, i); + n ? (s.textContent = n) : (s.innerHTML = " "), + t.appendChild(s), + this._restyle({ x: e, y: i }); + } + _divContent(t, e) { + return this._getVal(t, e) || this.columns[t].placeholder; + } + _setupDom() { + const t = document.createElement("iframe"); + (this.iframe = t), this._parent.appendChild(t); + const e = t.contentWindow.document; + (this.cwd = e), + e.open(), + e.write( + `
` + ), + e.close(), + Object.assign(t.style, this._iframeStyle); + const i = document.createElement("table"), + s = document.createElement("tbody"), + n = document.createElement("THEAD"), + o = document.createElement("TR"); + n.appendChild(o), + this.columns.forEach((t) => { + const e = document.createElement("TH"), + i = document.createElement("div"); + (i.innerHTML = t.label), + t.title && e.setAttribute("title", t.title), + e.appendChild(i), + o.appendChild(e); + }), + i.appendChild(n), + i.appendChild(s), + e.body.appendChild(i), + (this.tbody = s), + (this.table = i); + for (let t = 0; t < this._height; t++) { + const e = document.createElement("tr"); + s.appendChild(e); + for (let i = 0; i < this._width; i++) this._addCell(e, i, t); + } + h.forEach((t) => e.addEventListener(t, this[t], !0)); + } + destroy() { + this._destroyEditing(), + h.forEach((t) => this.cwd.removeEventListener(t, this[t], !0)), + this.iframe.parentElement.removeChild(this.iframe); + } + _addCell(t, e, i) { + const s = document.createElement("td"); + t.appendChild(s), this._renderTDContent(s, e, i); + } + _incrementHeight() { + if (!this._fitBounds({ x: 0, y: this._height })) return !1; + this._height++; + const t = this._height - 1, + e = document.createElement("tr"); + this.tbody.appendChild(e); + for (let i = 0; i < this._width; i++) this._addCell(e, i, t); + return !0; + } + _incrementWidth() { + if (!this._fitBounds({ x: this._width, y: 0 })) return !1; + this._width++; + const t = this._width - 1; + return ( + Array.prototype.forEach.call(this.tbody.children, (e, i) => { + this._addCell(e, t, i); + }), + !0 + ); + } + _incrementToFit({ x: t, y: e }) { + for (; t > this._width - 1 && this._incrementWidth(); ); + for (; e > this._height - 1 && this._incrementHeight(); ); + } + _getSelectionAsArray() { + const { rx: t, ry: e } = this._selection; + if (t[0] === t[1]) return null; + const i = t[1] - t[0], + s = e[1] - e[0], + n = []; + for (let o = 0; o < s; o++) { + n.push([]); + for (let s = 0; s < i; s++) + n[o].push(this._getVal(t[0] + s, e[0] + o)); + } + return n; + } + _setAllSelectedCellsTo(t) { + this._forSelectionCoord(this._selection, ({ x: e, y: i }) => + this._setVal(e, i, t) + ), + this._onDataChanged(), + this._forSelectionCoord( + this._selection, + this._refreshDisplayedValue + ); + } + _moveCursor({ x: t = 0, y: e = 0 }, i) { + const s = i ? this._selectionEnd : this._selectionStart, + n = { x: s.x + t, y: s.y + e }; + this._fitBounds(n) && + (this._stopEditing(), + this._incrementToFit(n), + this._changeSelectedCellsStyle(() => { + i + ? (this._selectionEnd = n) + : (this._selectionStart = + this._selectionEnd = + this._focus = + n); + }), + this._scrollIntoView(n)); + } + _tabCursorInSelection(t, e = 1) { + let { x: i, y: s } = this._focus || { x: 0, y: 0 }; + const o = this._selectionSize(), + { rx: r, ry: h } = + o > 1 + ? this._selection + : { + rx: [0, this.columns.length], + ry: [0, this._options.maxRows], + }; + let l; + if (t) l = n(i, s, e, r[0], r[1] - 1, h[0], h[1] - 1); + else { + const t = n(s, i, e, h[0], h[1] - 1, r[0], r[1] - 1); + l = { x: t.y, y: t.x }; + } + this._fitBounds(l) && + (this._stopEditing(), + this._incrementToFit(l), + this._changeSelectedCellsStyle(() => { + (this._focus = l), + o <= 1 && (this._selectionStart = this._selectionEnd = l); + }), + this._scrollIntoView(l)); + } + _scrollIntoView({ x: t, y: e }) { + this._getCell(t, e).scrollIntoView({ + behavior: "smooth", + block: "nearest", + }); + } + _endSelection() { + (this._selecting = !1), (this.tbody.style.userSelect = ""); + } + _startEditing({ x: t, y: e }) { + this._editing = { x: t, y: e }; + const i = this._getCell(t, e), + s = i.getBoundingClientRect(), + n = i.firstChild.getBoundingClientRect(); + i.removeChild(i.firstChild); + const o = document.createElement("input"); + (o.type = "text"), + (o.value = this._getVal(t, e)), + i.appendChild(o), + Object.assign(i.style, { + width: s.width - 2, + height: s.height, + }), + Object.assign(o.style, { + width: `${n.width}px`, + height: `${n.height}px`, + }), + o.focus(), + o.addEventListener("blur", this._stopEditing), + o.addEventListener("keydown", this._blurIfEnter); + } + _destroyEditing() { + if (this._editing) { + const { x: t, y: e } = this._editing, + i = this._getCell(t, e).firstChild; + i.removeEventListener("blur", this._stopEditing), + i.removeEventListener("keydown", this._blurIfEnter); + } + } + _revertEdit() { + if (!this._editing) return; + const { x: t, y: e } = this._editing; + this._getCell(t, e).firstChild.value = this._getVal(t, e); + } + _changeSelectedCellsStyle(t) { + const e = this._selection; + t(), + (this._selection = this._getSelectionCoords()), + this._forSelectionCoord(e, this._restyle), + this._forSelectionCoord(this._selection, this._restyle); + } + _getSelectionCoords() { + if (!this._selectionStart) return { rx: [0, 0], ry: [0, 0] }; + let t = [this._selectionStart.x, this._selectionEnd.x]; + t[0] > t[1] && t.reverse(); + let e = [this._selectionStart.y, this._selectionEnd.y]; + return ( + e[0] > e[1] && e.reverse(), + { rx: [t[0], t[1] + 1], ry: [e[0], e[1] + 1] } + ); + } + _forSelectionCoord({ rx: t, ry: e }, i) { + for (let s = t[0]; s < t[1]; s++) + for (let t = e[0]; t < e[1]; t++) + this._fitBounds({ x: s, y: t }) && i({ x: s, y: t }); + } + _restyleAll() { + for (var t = 0; t < this._width; t++) + for (var e = 0; e < this._height; e++) + this._restyle({ x: t, y: e }); + } + _selectionSize() { + const { rx: t, ry: e } = this._selection; + return (t[1] - t[0]) * (e[1] - e[0]); + } + _classNames(t, e) { + const { rx: i, ry: s } = this._selection; + let n = ""; + return ( + t >= i[0] && + t < i[1] && + e >= s[0] && + e < s[1] && + ((n += " selected"), + this._selectionSize() > 1 && (n += " multi")), + this._focus && + this._focus.x === t && + this._focus.y === e && + (n += " focus"), + this._editing && + t === this._editing.x && + e === this._editing.y && + (n += " editing"), + this._getVal(t, e) || (n += " placeholder"), + (n += " " + a(this.checkResults.classNames, t, e)), + n + ); + } + _getCoords(t) { + let e = t.target; + for (; !e.getAttribute("x") && e.parentElement; ) + e = e.parentElement; + return { + x: parseInt(e.getAttribute("x")) || 0, + y: parseInt(e.getAttribute("y")) || 0, + }; + } + setData(t) { + this._data._clear(), this._replaceDataWithArray(t); + for (let t = 0; t < this._width; t++) + for (let e = 0; e < this._height; e++) + this._refreshDisplayedValue({ x: t, y: e }); + } + _replaceDataWithArray(t = [[]]) { + t.forEach((t, e) => { + t.forEach((t, i) => { + this._setVal(i, e, t); + }); + }); + } + _setVal(t, e, i) { + this._fitBounds({ x: t, y: e }) && + (this._data._setVal(t, e, i), + this._incrementToFit({ x: t + 1, y: e + 1 }), + this._refreshDisplayedValue({ x: t, y: e })); + } + _getVal(t, e) { + return this._data._getVal(t, e); + } + _getCell(t, e) { + return this.tbody.children[e].children[t]; + } + } + function a(t, e, i) { + return (t && t[i] && t[i][e]) || ""; + } + }, + }, + e = {}; + function i(s) { + if (e[s]) return e[s].exports; + var n = (e[s] = { exports: {} }); + return t[s](n, n.exports, i), n.exports; + } + return ( + (i.d = (t, e) => { + for (var s in e) + i.o(e, s) && + !i.o(t, s) && + Object.defineProperty(t, s, { enumerable: !0, get: e[s] }); + }), + (i.o = (t, e) => Object.prototype.hasOwnProperty.call(t, e)), + i(103) + ); + })().default; +}); diff --git a/common/common.scss b/common/common.scss index 1f2bf64..339379c 100644 --- a/common/common.scss +++ b/common/common.scss @@ -77,6 +77,7 @@ } // EDIT BUTTON RELATED (TODO move to partials) -.quote-button { - flex-direction: row; +.open-popup-link { + display: inline; + margin-inline: 0.25em; } diff --git a/javascripts/discourse/api-initializers/table-editor.js b/javascripts/discourse/api-initializers/table-editor.js new file mode 100644 index 0000000..c494b57 --- /dev/null +++ b/javascripts/discourse/api-initializers/table-editor.js @@ -0,0 +1,86 @@ +import { apiInitializer } from "discourse/lib/api"; +import showModal from "discourse/lib/show-modal"; +import { schedule } from "@ember/runloop"; +import I18n from "I18n"; +import { iconNode } from "discourse-common/lib/icon-library"; +import { create } from "virtual-dom"; +import { ajax } from "discourse/lib/ajax"; +import { popupAjaxError } from "discourse/lib/ajax-error"; + +export default apiInitializer("0.11.1", (api) => { + const site = api.container.lookup("site:main"); + const currentUser = api.getCurrentUser(); + + function createButton() { + const openPopupBtn = document.createElement("button"); + openPopupBtn.classList.add( + "open-popup-link", + "btn-default", + "btn", + "btn-icon-text" + ); + const expandIcon = create( + iconNode("pencil-alt", { class: "edit-table-icon" }) + ); + const openPopupText = document.createTextNode( + I18n.t(themePrefix("discourse_table_builder.edit.btn_edit")) + ); + openPopupBtn.append(expandIcon, openPopupText); + return openPopupBtn; + } + + function generateModal(event) { + const table = event.target.nextElementSibling; + const tempTable = table.cloneNode(true); + const postId = this.id; + + return ajax(`/posts/${postId}`, { + type: "GET", + cache: false, + }) + .then((result) => { + const attrs = { + widget: this, + raw: result.raw, + }; + + showModal("table-editor-modal", { + model: attrs, + }).set("tableHtml", tempTable); + return result.raw; + }) + .catch(popupAjaxError); + } + + function generatePopups(tables, attrs) { + tables.forEach((table) => { + if (site.isMobileDevice) { + return; + } + + const popupBtn = createButton(); + table.parentNode.classList.add("fullscreen-table-wrapper"); + table.parentNode.insertBefore(popupBtn, table); + popupBtn.addEventListener("click", generateModal.bind(attrs), false); + }); + } + + api.decorateCookedElement( + (post, helper) => { + const postOwner = helper.widget.attrs.username; + + if (postOwner !== currentUser.username) { + return; + } + + schedule("afterRender", () => { + const tables = post.querySelectorAll("table"); + generatePopups(tables, helper.widget.attrs); + }); + }, + { + onlyStream: true, + id: "edit-table", + } + ); +}); diff --git a/javascripts/discourse/connectors/quote-button-after/edit-table-button.hbs b/javascripts/discourse/connectors/quote-button-after/edit-table-button.hbs deleted file mode 100644 index e50eafa..0000000 --- a/javascripts/discourse/connectors/quote-button-after/edit-table-button.hbs +++ /dev/null @@ -1,9 +0,0 @@ -{{#if context._canEditPost}} -