1(function($) 2{ 3 $.Redactor.prototype.table = function() 4 { 5 return { 6 langs: { 7 en: { 8 "table": "<span class='screen-reader'>Table</span> <i class='far fa-table'></i>", 9 "insert-table": "Insert table", 10 "insert-row-above": "Insert row above", 11 "insert-row-below": "Insert row below", 12 "insert-column-left": "Insert column left", 13 "insert-column-right": "Insert column right", 14 "add-head": "Add head", 15 "delete-head": "Delete head", 16 "delete-column": "Delete column", 17 "delete-row": "Delete row", 18 "delete-table": "Delete table" 19 } 20 }, 21 init: function() 22 { 23 var dropdown = {}; 24 25 dropdown.insert_table = { 26 title: this.lang.get('insert-table'), 27 func: this.table.insert, 28 observe: { 29 element: 'table', 30 in: { 31 attr: { 32 'class': 'redactor-dropdown-link-inactive', 33 'aria-disabled': true, 34 } 35 } 36 } 37 }; 38 39 dropdown.insert_row_above = { 40 title: this.lang.get('insert-row-above'), 41 func: this.table.addRowAbove, 42 observe: { 43 element: 'table', 44 out: { 45 attr: { 46 'class': 'redactor-dropdown-link-inactive', 47 'aria-disabled': true, 48 } 49 } 50 } 51 }; 52 53 dropdown.insert_row_below = { 54 title: this.lang.get('insert-row-below'), 55 func: this.table.addRowBelow, 56 observe: { 57 element: 'table', 58 out: { 59 attr: { 60 'class': 'redactor-dropdown-link-inactive', 61 'aria-disabled': true, 62 } 63 } 64 } 65 }; 66 67 dropdown.insert_column_left = { 68 title: this.lang.get('insert-column-left'), 69 func: this.table.addColumnLeft, 70 observe: { 71 element: 'table', 72 out: { 73 attr: { 74 'class': 'redactor-dropdown-link-inactive', 75 'aria-disabled': true, 76 } 77 } 78 } 79 }; 80 81 dropdown.insert_column_right = { 82 title: this.lang.get('insert-column-right'), 83 func: this.table.addColumnRight, 84 observe: { 85 element: 'table', 86 out: { 87 attr: { 88 'class': 'redactor-dropdown-link-inactive', 89 'aria-disabled': true, 90 } 91 } 92 } 93 }; 94 95 dropdown.add_head = { 96 title: this.lang.get('add-head'), 97 func: this.table.addHead, 98 observe: { 99 element: 'table', 100 out: { 101 attr: { 102 'class': 'redactor-dropdown-link-inactive', 103 'aria-disabled': true, 104 } 105 } 106 } 107 }; 108 109 dropdown.delete_head = { 110 title: this.lang.get('delete-head'), 111 func: this.table.deleteHead, 112 observe: { 113 element: 'table', 114 out: { 115 attr: { 116 'class': 'redactor-dropdown-link-inactive', 117 'aria-disabled': true, 118 } 119 } 120 } 121 }; 122 123 dropdown.delete_column = { 124 title: this.lang.get('delete-column'), 125 func: this.table.deleteColumn, 126 observe: { 127 element: 'table', 128 out: { 129 attr: { 130 'class': 'redactor-dropdown-link-inactive', 131 'aria-disabled': true, 132 } 133 } 134 } 135 }; 136 137 dropdown.delete_row = { 138 title: this.lang.get('delete-row'), 139 func: this.table.deleteRow, 140 observe: { 141 element: 'table', 142 out: { 143 attr: { 144 'class': 'redactor-dropdown-link-inactive', 145 'aria-disabled': true, 146 } 147 } 148 } 149 }; 150 151 dropdown.delete_table = { 152 title: this.lang.get('delete-table'), 153 func: this.table.deleteTable, 154 observe: { 155 element: 'table', 156 out: { 157 attr: { 158 'class': 'redactor-dropdown-link-inactive', 159 'aria-disabled': true, 160 } 161 } 162 } 163 }; 164 165 166 var button = this.button.addBefore('link', 'table', this.lang.get('table')); 167 button.attr('title', 'Table'); 168 this.button.addDropdown(button, dropdown); 169 }, 170 insert: function() 171 { 172 if (this.table.getTable()) 173 { 174 return; 175 } 176 177 this.placeholder.hide(); 178 179 var rows = 2; 180 var columns = 3; 181 var $tableBox = $('<div>'); 182 var $table = $('<table />'); 183 184 185 for (var i = 0; i < rows; i++) 186 { 187 var $row = $('<tr>'); 188 189 for (var z = 0; z < columns; z++) 190 { 191 var $column = $('<td>' + this.opts.invisibleSpace + '</td>'); 192 193 // set the focus to the first td 194 if (i === 0 && z === 0) 195 { 196 $column.append(this.marker.get()); 197 } 198 199 $($row).append($column); 200 } 201 202 $table.append($row); 203 } 204 205 $tableBox.append($table); 206 var html = $tableBox.html(); 207 208 this.buffer.set(); 209 210 var current = this.selection.current(); 211 if ($(current).closest('li').length !== 0) 212 { 213 $(current).closest('ul, ol').first().after(html); 214 } 215 else 216 { 217 this.air.collapsed(); 218 this.insert.html(html); 219 } 220
221 this.selection.restore(); 222 this.core.callback('insertedTable', $table); 223 }, 224 getTable: function() 225 { 226 var $table = $(this.selection.current()).closest('table'); 227 228 if (!this.utils.isRedactorParent($table)) 229 { 230 return false; 231 } 232 233 if ($table.size() === 0) 234 { 235 return false; 236 } 237 238 return $table; 239 }, 240 restoreAfterDelete: function($table) 241 { 242 this.selection.restore(); 243 $table.find('span.redactor-selection-marker').remove(); 244 245 }, 246 deleteTable: function() 247 { 248 var $table = this.table.getTable(); 249 if (!$table) 250 { 251 return; 252 } 253 254 this.buffer.set(); 255 256 257 var $next = $table.next(); 258 if (!this.opts.linebreaks && $next.length !== 0) 259 { 260 this.caret.start($next); 261 } 262 else 263 { 264 this.caret.after($table); 265 } 266 267 268 $table.remove(); 269 270 271 }, 272 deleteRow: function() 273 { 274 var $table = this.table.getTable(); 275 if (!$table) 276 { 277 return; 278 } 279 280 var $current = $(this.selection.current()); 281 282 this.buffer.set(); 283 284 var $current_tr = $current.closest('tr'); 285 var $focus_tr = $current_tr.prev().length ? $current_tr.prev() : $current_tr.next(); 286 if ($focus_tr.length) 287 { 288 var $focus_td = $focus_tr.children('td, th').first(); 289 if ($focus_td.length) 290 { 291 $focus_td.prepend(this.marker.get()); 292 } 293 } 294 295 $current_tr.remove(); 296 this.table.restoreAfterDelete($table); 297 }, 298 deleteColumn: function() 299 { 300 var $table = this.table.getTable(); 301 if (!$table) 302 { 303 return; 304 } 305 306 this.buffer.set(); 307 308 var $current = $(this.selection.current()); 309 var $current_td = $current.closest('td, th'); 310 var index = $current_td[0].cellIndex; 311 312 $table.find('tr').each($.proxy(function(i, elem) 313 { 314 var $elem = $(elem); 315 var focusIndex = index - 1 < 0 ? index + 1 : index - 1; 316 if (i === 0) 317 { 318 $elem.find('td, th').eq(focusIndex).prepend(this.marker.get()); 319 } 320 321 $elem.find('td, th').eq(index).remove(); 322 323 }, this)); 324 325 this.table.restoreAfterDelete($table); 326 }, 327 addHead: function() 328 { 329 var $table = this.table.getTable(); 330 if (!$table) 331 { 332 return; 333 } 334 335 this.buffer.set(); 336 337 if ($table.find('thead').size() !== 0) 338 { 339 this.table.deleteHead(); 340 return; 341 } 342 343 var tr = $table.find('tr').first().clone(); 344 tr.find('td').replaceWith($.proxy(function() 345 { 346 return $('<th>').html(this.opts.invisibleSpace); 347 }, this)); 348 349 $thead = $('<thead></thead>').append(tr); 350 $table.prepend($thead); 351 352 353 354 }, 355 deleteHead: function() 356 { 357 var $table = this.table.getTable(); 358 if (!$table) 359 { 360 return; 361 } 362 363 var $thead = $table.find('thead'); 364 if ($thead.size() === 0) 365 { 366 return; 367 } 368 369 this.buffer.set(); 370 371 $thead.remove(); 372 373 }, 374 addRowAbove: function() 375 { 376 this.table.addRow('before'); 377 }, 378 addRowBelow: function() 379 { 380 this.table.addRow('after'); 381 }, 382 addColumnLeft: function() 383 { 384 this.table.addColumn('before'); 385 }, 386 addColumnRight: function() 387 { 388 this.table.addColumn('after'); 389 }, 390 addRow: function(type) 391 { 392 var $table = this.table.getTable(); 393 if (!$table) 394 { 395 return; 396 } 397 398 this.buffer.set(); 399 400 var $current = $(this.selection.current()); 401 var $current_tr = $current.closest('tr'); 402 var new_tr = $current_tr.clone(); 403 404 new_tr.find('th').replaceWith(function() 405 { 406 var $td = $('<td>'); 407 $td[0].attributes = this.attributes; 408 409 return $td.append($(this).contents()); 410 }); 411 412 new_tr.find('td').html(this.opts.invisibleSpace); 413 414 if (type === 'after') 415 { 416 $current_tr.after(new_tr); 417 } 418 else 419 { 420 $current_tr.before(new_tr); 421 } 422 423 424 }, 425 addColumn: function (type) 426 { 427 var $table = this.table.getTable(); 428 if (!$table) 429 { 430 return; 431 } 432 433 var index = 0; 434 var current = $(this.selection.current()); 435 436 this.buffer.set(); 437 438 var $current_tr = current.closest('tr'); 439 var $current_td = current.closest('td, th'); 440 441 $current_tr.find('td, th').each($.proxy(function(i, elem) 442 { 443 if ($(elem)[0] === $current_td[0]) 444 { 445 index = i; 446 } 447 448 }, this)); 449 450 $table.find('tr').each($.proxy(function(i, elem) 451 { 452 var $current = $(elem).find('td, th').eq(index); 453 454 var td = $current.clone(); 455 td.html(this.opts.invisibleSpace); 456 457 if (type === 'after') 458 { 459 $current.after(td); 460 } 461 else 462 { 463 $current.before(td); 464 } 465 466 }, this)); 467 468 469 } 470 }; 471 }; 472})(jQuery);
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.