table.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. (function($)
  2. {
  3. $.Redactor.prototype.table = function()
  4. {
  5. return {
  6. getTemplate: function()
  7. {
  8. return String()
  9. + '<section id="redactor-modal-table-insert">'
  10. + '<label>' + this.lang.get('rows') + '</label>'
  11. + '<input type="text" size="5" value="2" id="redactor-table-rows" />'
  12. + '<label>' + this.lang.get('columns') + '</label>'
  13. + '<input type="text" size="5" value="3" id="redactor-table-columns" />'
  14. + '</section>';
  15. },
  16. init: function()
  17. {
  18. var dropdown = {};
  19. dropdown.insert_table = {
  20. title: this.lang.get('insert_table'),
  21. func: this.table.show,
  22. observe: {
  23. element: 'table',
  24. in: {
  25. attr: {
  26. 'class': 'redactor-dropdown-link-inactive',
  27. 'aria-disabled': true,
  28. }
  29. }
  30. }
  31. };
  32. dropdown.insert_row_above = {
  33. title: this.lang.get('insert_row_above'),
  34. func: this.table.addRowAbove,
  35. observe: {
  36. element: 'table',
  37. out: {
  38. attr: {
  39. 'class': 'redactor-dropdown-link-inactive',
  40. 'aria-disabled': true,
  41. }
  42. }
  43. }
  44. };
  45. dropdown.insert_row_below = {
  46. title: this.lang.get('insert_row_below'),
  47. func: this.table.addRowBelow,
  48. observe: {
  49. element: 'table',
  50. out: {
  51. attr: {
  52. 'class': 'redactor-dropdown-link-inactive',
  53. 'aria-disabled': true,
  54. }
  55. }
  56. }
  57. };
  58. dropdown.insert_column_left = {
  59. title: this.lang.get('insert_column_left'),
  60. func: this.table.addColumnLeft,
  61. observe: {
  62. element: 'table',
  63. out: {
  64. attr: {
  65. 'class': 'redactor-dropdown-link-inactive',
  66. 'aria-disabled': true,
  67. }
  68. }
  69. }
  70. };
  71. dropdown.insert_column_right = {
  72. title: this.lang.get('insert_column_right'),
  73. func: this.table.addColumnRight,
  74. observe: {
  75. element: 'table',
  76. out: {
  77. attr: {
  78. 'class': 'redactor-dropdown-link-inactive',
  79. 'aria-disabled': true,
  80. }
  81. }
  82. }
  83. };
  84. dropdown.add_head = {
  85. title: this.lang.get('add_head'),
  86. func: this.table.addHead,
  87. observe: {
  88. element: 'table',
  89. out: {
  90. attr: {
  91. 'class': 'redactor-dropdown-link-inactive',
  92. 'aria-disabled': true,
  93. }
  94. }
  95. }
  96. };
  97. dropdown.delete_head = {
  98. title: this.lang.get('delete_head'),
  99. func: this.table.deleteHead,
  100. observe: {
  101. element: 'table',
  102. out: {
  103. attr: {
  104. 'class': 'redactor-dropdown-link-inactive',
  105. 'aria-disabled': true,
  106. }
  107. }
  108. }
  109. };
  110. dropdown.delete_column = {
  111. title: this.lang.get('delete_column'),
  112. func: this.table.deleteColumn,
  113. observe: {
  114. element: 'table',
  115. out: {
  116. attr: {
  117. 'class': 'redactor-dropdown-link-inactive',
  118. 'aria-disabled': true,
  119. }
  120. }
  121. }
  122. };
  123. dropdown.delete_row = {
  124. title: this.lang.get('delete_row'),
  125. func: this.table.deleteRow,
  126. observe: {
  127. element: 'table',
  128. out: {
  129. attr: {
  130. 'class': 'redactor-dropdown-link-inactive',
  131. 'aria-disabled': true,
  132. }
  133. }
  134. }
  135. };
  136. dropdown.delete_table = {
  137. title: this.lang.get('delete_table'),
  138. func: this.table.deleteTable,
  139. observe: {
  140. element: 'table',
  141. out: {
  142. attr: {
  143. 'class': 'redactor-dropdown-link-inactive',
  144. 'aria-disabled': true,
  145. }
  146. }
  147. }
  148. };
  149. this.observe.addButton('td', 'table');
  150. this.observe.addButton('th', 'table');
  151. var button = this.button.addBefore('link', 'table', this.lang.get('table'));
  152. this.button.addDropdown(button, dropdown);
  153. },
  154. show: function()
  155. {
  156. this.modal.addTemplate('table', this.table.getTemplate());
  157. this.modal.load('table', this.lang.get('insert_table'), 300);
  158. this.modal.createCancelButton();
  159. var button = this.modal.createActionButton(this.lang.get('insert'));
  160. button.on('click', this.table.insert);
  161. this.selection.save();
  162. this.modal.show();
  163. $('#redactor-table-rows').focus();
  164. },
  165. insert: function()
  166. {
  167. this.placeholder.remove();
  168. var rows = $('#redactor-table-rows').val(),
  169. columns = $('#redactor-table-columns').val(),
  170. $tableBox = $('<div>'),
  171. tableId = Math.floor(Math.random() * 99999),
  172. $table = $('<table id="table' + tableId + '"><tbody></tbody></table>'),
  173. i, $row, z, $column;
  174. for (i = 0; i < rows; i++)
  175. {
  176. $row = $('<tr>');
  177. for (z = 0; z < columns; z++)
  178. {
  179. $column = $('<td>' + this.opts.invisibleSpace + '</td>');
  180. // set the focus to the first td
  181. if (i === 0 && z === 0)
  182. {
  183. $column.append(this.selection.getMarker());
  184. }
  185. $($row).append($column);
  186. }
  187. $table.append($row);
  188. }
  189. $tableBox.append($table);
  190. var html = $tableBox.html();
  191. this.modal.close();
  192. this.selection.restore();
  193. if (this.table.getTable()) return;
  194. this.buffer.set();
  195. var current = this.selection.getBlock() || this.selection.getCurrent();
  196. if (current && current.tagName != 'BODY')
  197. {
  198. if (current.tagName == 'LI') current = $(current).closest('ul, ol');
  199. $(current).after(html);
  200. }
  201. else
  202. {
  203. this.insert.html(html, false);
  204. }
  205. this.selection.restore();
  206. var table = this.$editor.find('#table' + tableId);
  207. var p = table.prev("p");
  208. if (p.length > 0 && this.utils.isEmpty(p.html()))
  209. {
  210. p.remove();
  211. }
  212. if (!this.opts.linebreaks && (this.utils.browser('mozilla') || this.utils.browser('msie')))
  213. {
  214. var $next = table.next();
  215. if ($next.length === 0)
  216. {
  217. table.after(this.opts.emptyHtml);
  218. }
  219. }
  220. this.observe.buttons();
  221. table.find('span.redactor-selection-marker').remove();
  222. table.removeAttr('id');
  223. this.code.sync();
  224. this.core.setCallback('insertedTable', table);
  225. },
  226. getTable: function()
  227. {
  228. var $table = $(this.selection.getParent()).closest('table');
  229. if (!this.utils.isRedactorParent($table)) return false;
  230. if ($table.size() === 0) return false;
  231. return $table;
  232. },
  233. restoreAfterDelete: function($table)
  234. {
  235. this.selection.restore();
  236. $table.find('span.redactor-selection-marker').remove();
  237. this.code.sync();
  238. },
  239. deleteTable: function()
  240. {
  241. var $table = this.table.getTable();
  242. if (!$table) return;
  243. this.buffer.set();
  244. var $next = $table.next();
  245. if (!this.opts.linebreaks && $next.length !== 0)
  246. {
  247. this.caret.setStart($next);
  248. }
  249. else
  250. {
  251. this.caret.setAfter($table);
  252. }
  253. $table.remove();
  254. this.code.sync();
  255. },
  256. deleteRow: function()
  257. {
  258. var $table = this.table.getTable();
  259. if (!$table) return;
  260. var $current = $(this.selection.getCurrent());
  261. this.buffer.set();
  262. var $current_tr = $current.closest('tr');
  263. var $focus_tr = $current_tr.prev().length ? $current_tr.prev() : $current_tr.next();
  264. if ($focus_tr.length)
  265. {
  266. var $focus_td = $focus_tr.children('td, th').first();
  267. if ($focus_td.length) $focus_td.prepend(this.selection.getMarker());
  268. }
  269. $current_tr.remove();
  270. this.table.restoreAfterDelete($table);
  271. },
  272. deleteColumn: function()
  273. {
  274. var $table = this.table.getTable();
  275. if (!$table) return;
  276. this.buffer.set();
  277. var $current = $(this.selection.getCurrent());
  278. var $current_td = $current.closest('td, th');
  279. var index = $current_td[0].cellIndex;
  280. $table.find('tr').each($.proxy(function(i, elem)
  281. {
  282. var $elem = $(elem);
  283. var focusIndex = index - 1 < 0 ? index + 1 : index - 1;
  284. if (i === 0) $elem.find('td, th').eq(focusIndex).prepend(this.selection.getMarker());
  285. $elem.find('td, th').eq(index).remove();
  286. }, this));
  287. this.table.restoreAfterDelete($table);
  288. },
  289. addHead: function()
  290. {
  291. var $table = this.table.getTable();
  292. if (!$table) return;
  293. this.buffer.set();
  294. if ($table.find('thead').size() !== 0)
  295. {
  296. this.table.deleteHead();
  297. return;
  298. }
  299. var tr = $table.find('tr').first().clone();
  300. tr.find('td').replaceWith($.proxy(function()
  301. {
  302. return $('<th>').html(this.opts.invisibleSpace);
  303. }, this));
  304. $thead = $('<thead></thead>').append(tr);
  305. $table.prepend($thead);
  306. this.code.sync();
  307. },
  308. deleteHead: function()
  309. {
  310. var $table = this.table.getTable();
  311. if (!$table) return;
  312. var $thead = $table.find('thead');
  313. if ($thead.size() === 0) return;
  314. this.buffer.set();
  315. $thead.remove();
  316. this.code.sync();
  317. },
  318. addRowAbove: function()
  319. {
  320. this.table.addRow('before');
  321. },
  322. addRowBelow: function()
  323. {
  324. this.table.addRow('after');
  325. },
  326. addColumnLeft: function()
  327. {
  328. this.table.addColumn('before');
  329. },
  330. addColumnRight: function()
  331. {
  332. this.table.addColumn('after');
  333. },
  334. addRow: function(type)
  335. {
  336. var $table = this.table.getTable();
  337. if (!$table) return;
  338. this.buffer.set();
  339. var $current = $(this.selection.getCurrent());
  340. var $current_tr = $current.closest('tr');
  341. var new_tr = $current_tr.clone();
  342. new_tr.find('th').replaceWith(function()
  343. {
  344. var $td = $('<td>');
  345. $td[0].attributes = this.attributes;
  346. return $td.append($(this).contents());
  347. });
  348. new_tr.find('td').html(this.opts.invisibleSpace);
  349. if (type == 'after')
  350. {
  351. $current_tr.after(new_tr);
  352. }
  353. else
  354. {
  355. $current_tr.before(new_tr);
  356. }
  357. this.code.sync();
  358. },
  359. addColumn: function (type)
  360. {
  361. var $table = this.table.getTable();
  362. if (!$table) return;
  363. var index = 0;
  364. var current = $(this.selection.getCurrent());
  365. this.buffer.set();
  366. var $current_tr = current.closest('tr');
  367. var $current_td = current.closest('td, th');
  368. $current_tr.find('td, th').each($.proxy(function(i, elem)
  369. {
  370. if ($(elem)[0] === $current_td[0]) index = i;
  371. }, this));
  372. $table.find('tr').each($.proxy(function(i, elem)
  373. {
  374. var $current = $(elem).find('td, th').eq(index);
  375. var td = $current.clone();
  376. td.html(this.opts.invisibleSpace);
  377. if (type == 'after')
  378. {
  379. $current.after(td);
  380. }
  381. else
  382. {
  383. $current.before(td);
  384. }
  385. }, this));
  386. this.code.sync();
  387. }
  388. };
  389. };
  390. })(jQuery);