diff --git a/editor.js b/editor.js
index 082a3ba..abc8f98 100644
--- a/editor.js
+++ b/editor.js
@@ -146,6 +146,8 @@
kind === "footer" ?
"th" : "td");
+ cell.innerHTML = " ";
+
newRow.appendChild(cell);
}
@@ -260,6 +262,8 @@
rowKind === "header" ||
rowKind === "footer" ? "th" : "td"));
+ newCell.innerHTML = " ";
+
if (position === self.colIndex.length) {
row.appendChild(newCell);
} else {
diff --git a/index.html b/index.html
index 4c054cd..995ed07 100644
--- a/index.html
+++ b/index.html
@@ -12,53 +12,8 @@
body {
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
}
-
- table[tableedit] {
- border-spacing: 0px;
- border-bottom: solid 1px #999;
- border-right: solid 1px #999;
- margin: 2em;
- }
-
- [tableedit] td, [tableedit] th {
- border-top: solid 1px #999;
- border-left: solid 1px #999;
- min-height: 1.5em;
- line-height: 1.5em;
- min-width: 80px;
- padding-left: 0.2em;
- padding-right: 0.2em;
- }
-
- [tableedit] th {
- background-color: #EEE;
- }
-
- .tableedit-rowguide,
- .tableedit-colguide {
- border: solid #CCC 1px;
- border-top-color: #EEE;
- border-left-color: #DDD;
- border-right-color: #DDD;
- -webkit-border-radius: 3px;
- list-style-type: none;
- margin: 0px;
- padding: 0px;
- background-color: white;
-
- -webkit-box-shadow: rgba(0,0,0,0.1) 0px 1px 1px;
- }
-
- .tableedit-rowguide {
- margin-left: -2em;
- width: 1.8em;
- }
-
- .tableedit-colguide {
- margin-top: -2em;
- height: 1.8em;
- }
+
Table Editor
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..14c2d78
--- /dev/null
+++ b/style.css
@@ -0,0 +1,147 @@
+.tableedit-active,
+.tableedit-active *,
+.tableedit-rowguide,
+.tableedit-rowguide *,
+.tableedit-colguide,
+.tableedit-colguide * {
+ box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
+}
+
+.tableedit-active {
+ border-spacing: 0px;
+ border-bottom: solid 1px #999;
+ border-right: solid 1px #999;
+ margin: 2em;
+}
+
+.tableedit-active td,
+.tableedit-active th {
+ border-top: solid 1px #999;
+ border-left: solid 1px #999;
+ min-height: 1.5em;
+ line-height: 1.5em;
+ min-width: 80px;
+ padding-left: 0.2em;
+ padding-right: 0.2em;
+ min-height: 1.5em;
+}
+
+.tableedit-active th {
+ background-color: #EEE;
+}
+
+.tableedit-rowguide,
+.tableedit-colguide {
+ border: solid #CCC 1px;
+ border-top-color: #EEE;
+ border-left-color: #DDD;
+ border-right-color: #DDD;
+ -webkit-border-radius: 3px;
+ list-style-type: none;
+ margin: 0px;
+ padding: 0px;
+ background-color: white;
+ overflow: hidden;
+
+ -webkit-box-shadow: rgba(0,0,0,0.1) 0px 1px 1px;
+}
+
+.tableedit-rowguide {
+ margin-left: -2em;
+ width: 1.8em;
+}
+
+.tableedit-colguide {
+ margin-top: -2em;
+ height: 1.8em;
+}
+
+.tableedit-colguide > li {
+ position: absolute;
+ border-right: solid #EAEAEA 1px;
+ height: 100%;
+ line-height: 1.7em;
+}
+
+.tableedit-rowguide > li {
+ position: absolute;
+ border-bottom: solid #EAEAEA 1px;
+ width: 100%;
+ line-height: 1.7em;
+}
+
+.tableedit-colguide label,
+.tableedit-rowguide label {
+ width: 100%;
+ height: 100%;
+ text-align: center;
+ display: block;
+ font-size: 9pt;
+ color: #999;
+}
+
+.tableedit-rowguide > li ul,
+.tableedit-colguide > li ul {
+ display: none;
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ margin: 0px;
+ padding: 0px;
+ list-style-type: none;
+}
+
+.tableedit-rowguide > li ul {
+ margin-left: 100%;
+ padding-left: 0.4em;
+}
+
+.tableedit-rowguide > li ul:before {
+ position: absolute;
+ display: block;
+ content: ".";
+ color: transparent;
+ border: solid transparent 10px;
+ border-right-color: rgba(0,0,0,0.8);
+ width: 0px;
+ height: 0px;
+ margin-top: 0.3em;
+ left: -14px;
+}
+
+.tableedit-rowguide > li ul li,
+.tableedit-colguide > li ul li {
+ display: block;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ background-color: rgba(0,0,0,0.8);
+ min-width: 150px;
+ color: white;
+ font-size: 10pt;
+
+ cursor: pointer;
+}
+
+.tableedit-rowguide > li ul li:hover,
+.tableedit-colguide > li ul li:hover {
+ background-color: black;
+}
+
+.tableedit-rowguide > li ul li:first-child,
+.tableedit-colguide > li ul li:first-child {
+ -webkit-border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+}
+
+.tableedit-rowguide > li ul li:last-child,
+.tableedit-colguide > li ul li:last-child {
+ -webkit-border-bottom-left-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+}
+
+.tableedit-rowguide > li:hover ul,
+.tableedit-colguide > li:hover ul {
+ display: block;
+}
\ No newline at end of file
diff --git a/ui.js b/ui.js
new file mode 100644
index 0000000..266fbb4
--- /dev/null
+++ b/ui.js
@@ -0,0 +1,233 @@
+(function(glob) {
+
+ var TableEditUI = function(editor) {
+ var self = this;
+
+ if (!(editor instanceof TableEdit))
+ throw new Error("UI must be constructed with an instanceof TableEdit.");
+
+ self.editor = editor;
+ self.table = editor.table;
+ self.rowGuide = document.createElement("ul");
+ self.colGuide = document.createElement("ul");
+
+ // Assign some basic classes...
+ self.rowGuide.className = "tableedit-rowguide";
+ self.colGuide.className = "tableedit-colguide";
+ self.colGuide.style.position = self.rowGuide.style.position = "fixed";
+
+ // Assign a class to the table being edited...
+ self.table.className += " tableedit-active";
+
+ // Listen to table update events...
+ self.editor.on("update",self.update.bind(self));
+
+ // And to any document or interaction events we might need to keep our UI looking nice...
+ var posUpdate = self.updatePositioning.bind(self);
+ window.addEventListener("resize",posUpdate);
+ document.addEventListener("scroll",posUpdate);
+ self.table.addEventListener("keydown",posUpdate);
+ self.table.addEventListener("keyup",posUpdate);
+
+ for (var i = 0; i < 25; i++)
+ self.editor.addRow();
+
+ return self;
+ };
+
+ TableEditUI.prototype.getElementOffset = function(element) {
+ var offset = {x: 0, y: 0, width: 0, height: 0};
+
+ if (element instanceof HTMLElement) {
+
+ offset.width = element.offsetWidth;
+ offset.height = element.offsetHeight;
+
+ do {
+ offset.x += element.offsetLeft;
+ offset.y += element.offsetTop;
+
+ } while ((element = element.offsetParent));
+
+ return offset;
+
+ } else {
+ throw new Error("");
+ }
+ };
+
+ TableEditUI.prototype.update = function() {
+ var self = this;
+
+ self.rowGuide.innerHTML = "";
+ self.colGuide.innerHTML = "";
+
+ function menuItem(text,handler) {
+ var menuItem = document.createElement("li");
+ menuItem.innerHTML = text;
+
+ menuItem.addEventListener("click",handler);
+ return menuItem;
+ }
+
+ // Generate list items for rows and cols.
+ self.editor.rowIndex.forEach(function(row,index) {
+ var rowTab = document.createElement("li"),
+ rowTabLabel = document.createElement("label"),
+ rowTabMenu = document.createElement("ul");
+
+ rowTabLabel.innerHTML = index+1;
+ rowTab.appendChild(rowTabLabel);
+ rowTab.appendChild(rowTabMenu);
+ self.rowGuide.appendChild(rowTab);
+
+ rowTabMenu.appendChild(menuItem(
+ "Delete Row",
+ function() {
+ self.editor.removeRow(row);
+ }
+ ));
+
+ rowTabMenu.appendChild(menuItem(
+ "Insert Header Before",
+ function() {
+ self.editor.addRow("header",index);
+ }
+ ));
+
+ rowTabMenu.appendChild(menuItem(
+ "Insert Header After",
+ function() {
+ self.editor.addRow("header",index+1);
+ }
+ ));
+
+ rowTabMenu.appendChild(menuItem(
+ "Insert Row Before",
+ function() {
+ self.editor.addRow("normal",index);
+ }
+ ));
+
+ rowTabMenu.appendChild(menuItem(
+ "Insert Row After",
+ function() {
+ self.editor.addRow("normal",index+1);
+ }
+ ));
+ });
+
+ self.editor.colIndex.forEach(function(col,index) {
+ var colTab = document.createElement("li"),
+ colTabLabel = document.createElement("label"),
+ colTabMenu = document.createElement("ul");
+
+ var unitAlpha = index % 26,
+ globalAlpha = (index / 26) | 0,
+ alphaString = String.fromCharCode(unitAlpha+65);
+
+ if (globalAlpha > 0) alphaString = String.fromCharCode(globalAlpha+64) + alphaString;
+
+ colTabLabel.innerHTML = alphaString;
+ colTab.appendChild(colTabLabel);
+ colTab.appendChild(colTabMenu);
+ self.colGuide.appendChild(colTab);
+ });
+
+ self.updatePositioning();
+
+ return self;
+ };
+
+ TableEditUI.prototype.updatePositioning = function() {
+ var self = this;
+
+ // The UI centers around the table. So get the table offset...
+ var tableOffset = self.getElementOffset(self.table);
+
+ var scrollTop = document.body.scrollTop >= 0 ? document.body.scrollTop : 0,
+ scrollLeft = document.body.scrollLeft >= 0 ? document.body.scrollLeft : 0,
+ wheight = window.innerHeight,
+ wwidth = window.innerWidth,
+ top = (tableOffset.y - scrollTop),
+ left = (tableOffset.x - scrollLeft),
+ height = tableOffset.height,
+ width = tableOffset.width,
+ viewportBase = scrollTop + wheight,
+ viewportRight = scrollLeft + wwidth,
+ tableBase = tableOffset.height + tableOffset.y,
+ tableRight = tableOffset.width + tableOffset.x;
+
+ // Check to ensure our values are in bounds...
+ scrollTop = scrollTop + wheight > document.body.scrollHeight ?
+ document.body.scrollHeight - wheight : scrollTop;
+
+ scrollLeft = scrollLeft + wwidth > document.body.scrollWidth ?
+ document.body.scrollLeft - wwidth : scrollLeft;
+
+ var rowGuideScrollTop = top-40 <= 0 ? (top-40)*-1 : 0,
+ colGuideScrollLeft = left-40 <= 0 ? (left-40)*-1 : 0;
+
+ // And compute the final dimensions...
+ top = top <= 40 ? 40 : top;
+ left = left <= 40 ? 40 : left;
+ height = top + height > wheight - 3 ? wheight - top - 3: height;
+ width = left + width > wwidth - 3 ? wwidth - left - 3: width;
+ height = ((tableBase-scrollTop)-top) < height ? ((tableBase-scrollTop)-top) : height;
+ width = ((tableRight-scrollLeft)-left) < width ? ((tableRight-scrollLeft)-left) : width;
+
+ // First of all - position row and colguides...
+ self.rowGuide.style.height = height + "px";
+ self.rowGuide.style.top = top + "px";
+ self.rowGuide.style.left = left + "px";
+ self.rowGuide.scrollTop = rowGuideScrollTop;
+
+ self.colGuide.style.width = width + "px";
+ self.colGuide.style.top = top + "px";
+ self.colGuide.style.left = left + "px";
+ self.colGuide.scrollLeft = colGuideScrollLeft;
+
+ // Set the dimensions of children in the row and col guides
+ var cumulativeRowHeight = 0;
+ [].slice.call(self.rowGuide.childNodes)
+ .forEach(function(node,index) {
+ if (self.editor.rowIndex[index]) {
+ var rowDimensions =
+ self.getElementOffset(self.editor.rowIndex[index]);
+
+ node.style.height = rowDimensions.height + "px";
+ node.style.top = cumulativeRowHeight + "px";
+ cumulativeRowHeight += rowDimensions.height;
+ }
+ });
+
+ var cumulativeColWidth = 0;
+ [].slice.call(self.colGuide.childNodes)
+ .forEach(function(node,index) {
+ if (self.editor.colIndex[index]) {
+ var col = self.editor.colIndex[index][0],
+ colDimensions =
+ self.getElementOffset(col);
+
+ node.style.width = colDimensions.width + "px";
+ node.style.left = cumulativeColWidth + "px";
+ cumulativeColWidth += colDimensions.width;
+ }
+ });
+
+ return self;
+ };
+
+ TableEditUI.prototype.render = function() {
+ var self = this;
+
+ document.body.appendChild(self.rowGuide);
+ document.body.appendChild(self.colGuide);
+ self.update();
+
+ return self;
+ };
+
+ glob.TableEditUI = TableEditUI;
+
+})(this);
\ No newline at end of file