1(function($R) { 2 $R.add('plugin', 'table', { 3 translations: { 4 en: { 5 "table": "Table", 6 "insert-table": "Insert table", 7 "insert-row-above": "Insert row above", 8 "insert-row-below": "Insert row below", 9 "insert-column-left": "Insert column left", 10 "insert-column-right": "Insert column right", 11 "add-head": "Add head", 12 "delete-head": "Delete head", 13 "delete-column": "Delete column", 14 "delete-row": "Delete row", 15 "delete-table": "Delete table" 16 } 17 }, 18 init: function(app) { 19 this.app = app; 20 this.lang = app.lang; 21 this.opts = app.opts; 22 this.caret = app.caret; 23 this.editor = app.editor; 24 this.toolbar = app.toolbar; 25 this.component = app.component; 26 this.inspector = app.inspector; 27 this.insertion = app.insertion; 28 this.selection = app.selection; 29 }, 30 // messages 31 ondropdown: { 32 table: { 33 observe: function(dropdown) { 34 this._observeDropdown(dropdown); 35 } 36 } 37 }, 38 onbottomclick: function() { 39 this.insertion.insertToEnd(this.editor.getLastNode(), 'table'); 40 }, 41 42 // public 43 start: function() { 44 var dropdown = { 45 observe: 'table', 46 'insert-table': { 47 title: this.lang.get('insert-table'), 48 api: 'plugin.table.insert' 49 }, 50 'insert-row-above': { 51 title: this.lang.get('insert-row-above'), 52 classname: 'redactor-table-item-observable', 53 api: 'plugin.table.addRowAbove' 54 }, 55 'insert-row-below': { 56 title: this.lang.get('insert-row-below'), 57 classname: 'redactor-table-item-observable', 58 api: 'plugin.table.addRowBelow' 59 }, 60 'insert-column-left': { 61 title: this.lang.get('insert-column-left'), 62 classname: 'redactor-table-item-observable', 63 api: 'plugin.table.addColumnLeft' 64 }, 65 'insert-column-right': { 66 title: this.lang.get('insert-column-right'), 67 classname: 'redactor-table-item-observable', 68 api: 'plugin.table.addColumnRight' 69 }, 70 'add-head': { 71 title: this.lang.get('add-head'), 72 classname: 'redactor-table-item-observable', 73 api: 'plugin.table.addHead' 74 }, 75 'delete-head': { 76 title: this.lang.get('delete-head'), 77 classname: 'redactor-table-item-observable', 78 api: 'plugin.table.deleteHead' 79 }, 80 'delete-column': { 81 title: this.lang.get('delete-column'), 82 classname: 'redactor-table-item-observable', 83 api: 'plugin.table.deleteColumn' 84 }, 85 'delete-row': { 86 title: this.lang.get('delete-row'), 87 classname: 'redactor-table-item-observable', 88 api: 'plugin.table.deleteRow' 89 }, 90 'delete-table': { 91 title: this.lang.get('delete-table'), 92 classname: 'redactor-table-item-observable', 93 api: 'plugin.table.deleteTable' 94 } 95 }; 96 var obj = { 97 title: this.lang.get('table') 98 }; 99 100 var $button = this.toolbar.addButtonBefore('link', 'table', obj); 101 $button.setIcon('<i aria-hidden="true" class="re-icon-table"></i>'); 102 $button.setDropdown(dropdown); 103 }, 104 insert: function() { 105 var rows = 2; 106 var columns = 3; 107 var $component = this.component.create('table'); 108 109 for (var i = 0; i < rows; i++) { 110 $component.addRow(columns); 111 } 112 113 $component = this.insertion.insertHtml($component); 114 this.caret.setStart($component); 115 }, 116 addRowAbove: function() { 117 var $component = this._getComponent(); 118 if ($component) { 119 var current = this.selection.getCurrent(); 120 var $row = $component.addRowTo(current, 'before'); 121 122 this.caret.setStart($row); 123 } 124 }, 125 addRowBelow: function() { 126 var $component = this._getComponent(); 127 if ($component) { 128 var current = this.selection.getCurrent(); 129 var $row = $component.addRowTo(current, 'after'); 130 131 this.caret.setStart($row); 132 } 133 }, 134 addColumnLeft: function() { 135 var $component = this._getComponent(); 136 if ($component) { 137 var current = this.selection.getCurrent(); 138 139 this.selection.save(); 140 $component.addColumnTo(current, 'left');
141 this.selection.restore(); 142 } 143 }, 144 addColumnRight: function() { 145 var $component = this._getComponent(); 146 if ($component) { 147 var current = this.selection.getCurrent(); 148 149 this.selection.save(); 150 $component.addColumnTo(current, 'right'); 151 this.selection.restore(); 152 } 153 }, 154 addHead: function() { 155 var $component = this._getComponent(); 156 if ($component) { 157 this.selection.save(); 158 $component.addHead(); 159 this.selection.restore(); 160 } 161 }, 162 deleteHead: function() { 163 var $component = this._getComponent(); 164 if ($component) { 165 var current = this.selection.getCurrent(); 166 var $head = $R.dom(current).closest('thead'); 167 if ($head.length !== 0) { 168 $component.removeHead(); 169 this.caret.setStart($component); 170 } else { 171 this.selection.save(); 172 $component.removeHead(); 173 this.selection.restore(); 174 } 175 } 176 }, 177 deleteColumn: function() { 178 var $component = this._getComponent(); 179 if ($component) { 180 var current = this.selection.getCurrent(); 181 182 var $currentCell = $R.dom(current).closest('td, th'); 183 var nextCell = $currentCell.nextElement().get(); 184 var prevCell = $currentCell.prevElement().get(); 185 186 $component.removeColumn(current); 187 188 if (nextCell) this.caret.setStart(nextCell); 189 else if (prevCell) this.caret.setEnd(prevCell); 190 else this.deleteTable(); 191 } 192 }, 193 deleteRow: function() { 194 var $component = this._getComponent(); 195 if ($component) { 196 var current = this.selection.getCurrent(); 197 198 var $currentRow = $R.dom(current).closest('tr'); 199 var nextRow = $currentRow.nextElement().get(); 200 var prevRow = $currentRow.prevElement().get(); 201 202 $component.removeRow(current); 203 204 if (nextRow) this.caret.setStart(nextRow); 205 else if (prevRow) this.caret.setEnd(prevRow); 206 else this.deleteTable(); 207 } 208 }, 209 deleteTable: function() { 210 var table = this._getTable(); 211 if (table) { 212 this.component.remove(table); 213 } 214 }, 215 216 // private 217 _getTable: function() { 218 var current = this.selection.getCurrent(); 219 var data = this.inspector.parse(current); 220 if (data.isTable()) { 221 return data.getTable(); 222 } 223 }, 224 _getComponent: function() { 225 var current = this.selection.getCurrent(); 226 var data = this.inspector.parse(current); 227 if (data.isTable()) { 228 var table = data.getTable(); 229 230 return this.component.create('table', table); 231 } 232 }, 233 _observeDropdown: function(dropdown) { 234 var table = this._getTable(); 235 var items = dropdown.getItemsByClass('redactor-table-item-observable'); 236 var tableItem = dropdown.getItem('insert-table'); 237 if (table) { 238 this._observeItems(items, 'enable'); 239 tableItem.disable(); 240 } else { 241 this._observeItems(items, 'disable'); 242 tableItem.enable(); 243 } 244 }, 245 _observeItems: function(items, type) { 246 for (var i = 0; i < items.length; i++) { 247 items[i][type](); 248 } 249 } 250 }); 251})(Redactor); 252(function($R) { 253 $R.add('class', 'table.component', { 254 mixins: ['dom', 'component'], 255 init: function(app, el) { 256 this.app = app; 257 258 // init 259 return (el && el.cmnt !== undefined) ? el : this._init(el); 260 }, 261 262 // public 263 addHead: function() { 264 this.removeHead(); 265 266 var columns = this.$element.find('tr').first().children('td, th').length; 267 var $head = $R.dom('<thead>'); 268 var $row = this._buildRow(columns, '<th>'); 269 270 $head.append($row);
271 this.$element.prepend($head); 272 }, 273 addRow: function(columns) { 274 var $row = this._buildRow(columns); 275 this.$element.append($row); 276 277 return $row; 278 }, 279 addRowTo: function(current, type) { 280 return this._addRowTo(current, type); 281 }, 282 addColumnTo: function(current, type) { 283 var $current = $R.dom(current); 284 var $currentRow = $current.closest('tr'); 285 var $currentCell = $current.closest('td, th'); 286 287 var index = 0; 288 $currentRow.find('td, th').each(function(node, i) { 289 if (node === $currentCell.get()) index = i; 290 }); 291 292 this.$element.find('tr').each(function(node) { 293 var $node = $R.dom(node); 294 var origCell = $node.find('td, th').get(index); 295 var $origCell = $R.dom(origCell); 296 297 var $td = $origCell.clone(); 298 $td.html('<div data-redactor-tag="tbr"></div>'); 299 300 if (type === 'right') $origCell.after($td); 301 else $origCell.before($td); 302 }); 303 }, 304 removeHead: function() { 305 var $head = this.$element.find('thead'); 306 if ($head.length !== 0) $head.remove(); 307 }, 308 removeRow: function(current) { 309 var $current = $R.dom(current); 310 var $currentRow = $current.closest('tr'); 311 312 $currentRow.remove(); 313 }, 314 removeColumn: function(current) { 315 var $current = $R.dom(current); 316 var $currentRow = $current.closest('tr'); 317 var $currentCell = $current.closest('td, th'); 318 319 var index = 0; 320 $currentRow.find('td, th').each(function(node, i) { 321 if (node === $currentCell.get()) index = i; 322 }); 323 324 this.$element.find('tr').each(function(node) { 325 var $node = $R.dom(node); 326 var origCell = $node.find('td, th').get(index); 327 var $origCell = $R.dom(origCell); 328 329 $origCell.remove(); 330 }); 331 }, 332 333 // private 334 _init: function(el) { 335 var wrapper, element; 336 if (typeof el !== 'undefined') { 337 var $node = $R.dom(el); 338 var node = $node.get(); 339 var $figure = $node.closest('figure'); 340 if ($figure.length !== 0) { 341 wrapper = $figure; 342 element = $figure.find('table').get(); 343 } else if (node.tagName === 'TABLE') { 344 element = node; 345 } 346 } 347 348 this._buildWrapper(wrapper); 349 this._buildElement(element); 350 this._initWrapper(); 351 }, 352 _addRowTo: function(current, position) { 353 var $current = $R.dom(current); 354 var $currentRow = $current.closest('tr'); 355 if ($currentRow.length !== 0) { 356 var columns = $currentRow.children('td, th').length; 357 var $newRow = this._buildRow(columns); 358 359 $currentRow[position]($newRow); 360 361 return $newRow; 362 } 363 }, 364 _buildRow: function(columns, tag) { 365 tag = tag || '<td>'; 366 367 var $row = $R.dom('<tr>'); 368 for (var i = 0; i < columns; i++) { 369 var $cell = $R.dom(tag); 370 $cell.attr('contenteditable', true); 371 $cell.html('<div data-redactor-tag="tbr"></div>'); 372 373 $row.append($cell); 374 } 375 376 return $row; 377 }, 378 _buildElement: function(node) { 379 if (node) { 380 this.$element = $R.dom(node); 381 } else { 382 this.$element = $R.dom('<table>'); 383 this.append(this.$element); 384 } 385 }, 386 _buildWrapper: function(node) { 387 node = node || '<figure>'; 388 389 this.parse(node); 390 }, 391 _initWrapper: function() { 392 this.addClass('redactor-component'); 393 this.attr({ 394 'data-redactor-type': 'table', 395 'tabindex': '-1', 396 'contenteditable': false 397 }); 398 399 if (this.app.detector.isIe()) { 400 this.removeAttr('contenteditable'); 401 } 402 } 403 }); 404 405})(Redactor);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.