freshereditor.min.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. (function() {
  2. (function($) {
  3. var methods;
  4. methods = {
  5. edit: function(isEditing) {
  6. return this.each(function() {
  7. return $(this).attr("contentEditable", isEditing || false);
  8. });
  9. },
  10. save: function(callback) {
  11. return this.each(function() {
  12. return callback($(this).attr('id'), $(this).html());
  13. });
  14. },
  15. createlink: function() {
  16. var urlPrompt;
  17. urlPrompt = prompt("Enter URL:", "http://");
  18. return document.execCommand("createlink", false, urlPrompt);
  19. },
  20. insertimage: function() {
  21. var urlPrompt;
  22. urlPrompt = prompt("Enter Image URL:", "http://");
  23. return document.execCommand("insertimage", false, urlPrompt);
  24. },
  25. formatblock: function(block) {
  26. return document.execCommand("formatblock", null, block);
  27. },
  28. init: function(opts) {
  29. var $toolbar, button, command, commands, excludes, font, font_list, fontnames, fontsize, fontsizes, group, groups, options, shortcuts, size_list, _i, _j, _k, _l, _len, _len2, _len3, _len4;
  30. options = opts || {};
  31. groups = [
  32. [
  33. {
  34. name: 'bold',
  35. label: "<span style='font-weight:bold;'>B</span>",
  36. title: 'Bold (Ctrl+B)',
  37. classname: 'toolbar_bold'
  38. }, {
  39. name: 'italic',
  40. label: "<span style='font-style:italic;'>I</span>",
  41. title: 'Italic (Ctrl+I)',
  42. classname: 'toolbar_italic'
  43. }, {
  44. name: 'underline',
  45. label: "<span style='text-decoration:underline!important;'>U</span>",
  46. title: 'Underline (Ctrl+U)',
  47. classname: 'toolbar_underline'
  48. }, {
  49. name: 'strikethrough',
  50. label: "<span style='text-shadow:none;text-decoration:line-through;'>ABC</span>",
  51. title: 'Strikethrough',
  52. classname: 'toolbar_strikethrough'
  53. }, {
  54. name: 'removeFormat',
  55. label: "<i class='icon-minus'></i>",
  56. title: 'Remove Formating (Ctrl+M)',
  57. classname: 'toolbar_remove'
  58. }
  59. ], [
  60. {
  61. name: 'fontname',
  62. label: "F <span class='caret'></span>",
  63. title: 'Select font name',
  64. classname: 'toolbar_fontname dropdown-toggle',
  65. dropdown: true
  66. }
  67. ], [
  68. {
  69. name: 'FontSize',
  70. label: "<span style='font:bold 16px;'>A</span><span style='font-size:8px;'>A</span> <span class='caret'></span>",
  71. title: 'Select font size',
  72. classname: 'toolbar_fontsize dropdown-toggle',
  73. dropdown: true
  74. }
  75. ], [
  76. {
  77. name: 'forecolor',
  78. label: "<div style='color:#ff0000;'>A <span class='caret'></span></div>",
  79. title: 'Select font color',
  80. classname: 'toolbar_forecolor dropdown-toggle',
  81. dropdown: true
  82. }
  83. ], [
  84. {
  85. name: 'backcolor',
  86. label: "<div style='display:inline-block;margin:3px;width:15px;height:12px;background-color:#0000ff;'></div> <span class='caret'></span>",
  87. title: 'Select background color',
  88. classname: 'toolbar_bgcolor dropdown-toggle',
  89. dropdown: true
  90. }
  91. ], [
  92. {
  93. name: 'justifyleft',
  94. label: "<i class='icon-align-left' style='margin-top:2px;'></i>",
  95. title: 'Left justify',
  96. classname: 'toolbar_justifyleft'
  97. }, {
  98. name: 'justifycenter',
  99. label: "<i class='icon-align-center' style='margin-top:2px;'></i>",
  100. title: 'Center justify',
  101. classname: 'toolbar_justifycenter'
  102. }, {
  103. name: 'justifyright',
  104. label: "<i class='icon-align-right' style='margin-top:2px;'></i>",
  105. title: 'Right justify',
  106. classname: 'toolbar_justifyright'
  107. }, {
  108. name: 'justifyfull',
  109. label: "<i class='icon-align-justify' style='margin-top:2px;'></i>",
  110. title: 'Full justify',
  111. classname: 'toolbar_justifyfull'
  112. }
  113. ], [
  114. {
  115. name: 'createlink',
  116. label: '@',
  117. title: 'Link to a web page (Ctrl+L)',
  118. userinput: "yes",
  119. classname: 'toolbar_link'
  120. }, {
  121. name: 'insertimage',
  122. label: "<i style='margin-top:2px;' class='icon-picture'></i>",
  123. title: 'Insert an image (Ctrl+G)',
  124. userinput: "yes",
  125. classname: 'toolbar_image'
  126. }, {
  127. name: 'insertorderedlist',
  128. label: "<i class='icon-list-alt' style='margin-top:2px;'></i>",
  129. title: 'Insert ordered list',
  130. classname: 'toolbar_ol'
  131. }, {
  132. name: 'insertunorderedlist',
  133. label: "<i class='icon-list' style='margin-top:2px;'></i>",
  134. title: 'Insert unordered list',
  135. classname: 'toolbar_ul'
  136. }
  137. ], [
  138. {
  139. name: 'insertparagraph',
  140. label: 'P',
  141. title: 'Insert a paragraph (Ctrl+Alt+0)',
  142. classname: 'toolbar_p',
  143. block: 'p'
  144. }, {
  145. name: 'insertheading1',
  146. label: 'H1',
  147. title: "Heading 1 (Ctrl+Alt+1)",
  148. classname: 'toolbar_h1',
  149. block: 'h1'
  150. }, {
  151. name: 'insertheading2',
  152. label: 'H2',
  153. title: "Heading 2 (Ctrl+Alt+2)",
  154. classname: 'toolbar_h2',
  155. block: 'h2'
  156. }, {
  157. name: 'insertheading3',
  158. label: 'H3',
  159. title: "Heading 3 (Ctrl+Alt+3)",
  160. classname: 'toolbar_h3',
  161. block: 'h3'
  162. }, {
  163. name: 'insertheading4',
  164. label: 'H4',
  165. title: "Heading 4 (Ctrl+Alt+4)",
  166. classname: 'toolbar_h4',
  167. block: 'h4'
  168. }
  169. ], [
  170. {
  171. name: 'blockquote',
  172. label: "<i style='margin-top:2px;' class='icon-comment'></i>",
  173. title: 'Blockquote (Ctrl+Q)',
  174. classname: 'toolbar_blockquote',
  175. block: 'blockquote'
  176. }, {
  177. name: 'code',
  178. label: '{&nbsp;}',
  179. title: 'Code (Ctrl+Alt+K)',
  180. classname: 'toolbar_code',
  181. block: 'pre'
  182. }, {
  183. name: 'superscript',
  184. label: 'x<sup>2</sup>',
  185. title: 'Superscript',
  186. classname: 'toolbar_superscript'
  187. }, {
  188. name: 'subscript',
  189. label: 'x<sub>2</sub>',
  190. title: 'Subscript',
  191. classname: 'toolbar_subscript'
  192. }
  193. ]
  194. ];
  195. if (options.toolbar_selector != null) {
  196. $toolbar = $(options.toolbar_selector);
  197. } else {
  198. $(this).before("<div id='editor-toolbar'></div>");
  199. $toolbar = $('#editor-toolbar');
  200. }
  201. $toolbar.addClass('fresheditor-toolbar');
  202. $toolbar.append("<div class='btn-toolbar'></div>");
  203. excludes = options.excludes || [];
  204. for (_i = 0, _len = groups.length; _i < _len; _i++) {
  205. commands = groups[_i];
  206. group = '';
  207. for (_j = 0, _len2 = commands.length; _j < _len2; _j++) {
  208. command = commands[_j];
  209. if (jQuery.inArray(command.name, excludes) < 0) {
  210. button = "<a href='#' class='btn toolbar-btn toolbar-cmd " + command.classname + "' title='" + command.title + "' command='" + command.name + "'";
  211. if (command.userinput != null) {
  212. button += " userinput='" + command.userinput + "'";
  213. }
  214. if (command.block != null) {
  215. button += " block='" + command.block + "'";
  216. }
  217. if (command.dropdown) {
  218. button += " data-toggle='dropdown'";
  219. }
  220. button += ">" + command.label + "</a>";
  221. group += button;
  222. }
  223. }
  224. $('.btn-toolbar', $toolbar).append("<div class='btn-group'>" + group + "</div>");
  225. }
  226. $("[data-toggle='dropdown']").removeClass('toolbar-cmd');
  227. if (jQuery.inArray('fontname', excludes) < 0) {
  228. fontnames = ["Arial", "Arial Black", "Comic Sans MS", "Courier New", "Georgia", "Helvetica", "Sans Serif", "Tahoma", "Times New Roman", "Trebuchet MS", "Verdana"];
  229. font_list = '';
  230. for (_k = 0, _len3 = fontnames.length; _k < _len3; _k++) {
  231. font = fontnames[_k];
  232. font_list += "<li><a href='#' class='fontname-option' style='font-family:" + font + ";'>" + font + "</a></li>";
  233. }
  234. $('.toolbar_fontname').after("<ul class='dropdown-menu'>" + font_list + "</ul>");
  235. $('.fontname-option').on('click', function() {
  236. document.execCommand("fontname", false, $(this).text());
  237. $(this).closest('.btn-group').removeClass('open');
  238. return false;
  239. });
  240. }
  241. if (jQuery.inArray('FontSize', excludes) < 0) {
  242. fontsizes = [
  243. {
  244. size: 1,
  245. point: 8
  246. }, {
  247. size: 2,
  248. point: 10
  249. }, {
  250. size: 3,
  251. point: 12
  252. }, {
  253. size: 4,
  254. point: 14
  255. }, {
  256. size: 5,
  257. point: 18
  258. }, {
  259. size: 6,
  260. point: 24
  261. }, {
  262. size: 7,
  263. point: 36
  264. }
  265. ];
  266. size_list = '';
  267. for (_l = 0, _len4 = fontsizes.length; _l < _len4; _l++) {
  268. fontsize = fontsizes[_l];
  269. size_list += "<li><a href='#' class='font-option fontsize-option' style='font-size:" + fontsize.point + "px;' fontsize='" + fontsize.size + "'>" + fontsize.size + "(" + fontsize.point + "pt)</a></li>";
  270. }
  271. $('.toolbar_fontsize').after("<ul class='dropdown-menu'>" + size_list + "</ul>");
  272. $('a.fontsize-option').on('click', function() {
  273. console.log($(this).attr('fontsize'));
  274. document.execCommand("FontSize", false, $(this).attr('fontsize'));
  275. $(this).closest('.btn-group').removeClass('open');
  276. return false;
  277. });
  278. }
  279. if (jQuery.inArray('forecolor', excludes) < 0) {
  280. $('a.toolbar_forecolor').after("<ul class='dropdown-menu colorpanel'><input type='text' id='forecolor-input' value='#000000' /><div id='forecolor-picker'></div></ul>");
  281. $('#forecolor-picker').farbtastic(function(color) {
  282. $('#forecolor-input').val(color);
  283. document.execCommand("forecolor", false, color);
  284. $(this).closest('.btn-group').removeClass('open');
  285. $('.toolbar_forecolor div').css({
  286. "color": color
  287. });
  288. return false;
  289. });
  290. }
  291. if (jQuery.inArray('backcolor', excludes) < 0) {
  292. $('a.toolbar_bgcolor').after("<ul class='dropdown-menu colorpanel'><input type='text' id='bgcolor-input' value='#000000' /><div id='bgcolor-picker'></div></ul>");
  293. $('#bgcolor-picker').farbtastic(function(color) {
  294. $('#bgcolor-input').val(color);
  295. document.execCommand("backcolor", false, color);
  296. $(this).closest('.btn-group').removeClass('open');
  297. $('.toolbar_bgcolor div').css({
  298. "background-color": color
  299. });
  300. return false;
  301. });
  302. }
  303. $(this).on('focus', function() {
  304. var $this;
  305. $this = $(this);
  306. $this.data('before', $this.html());
  307. return $this;
  308. }).on('blur keyup paste', function() {
  309. var $this;
  310. $this = $(this);
  311. if ($this.data('before') !== $this.html()) {
  312. $this.data('before', $this.html());
  313. $this.trigger('change');
  314. }
  315. return $this;
  316. });
  317. $("a.toolbar-cmd").on('click', function() {
  318. var ceNode, cmd, dummy, range;
  319. cmd = $(this).attr('command');
  320. if ($(this).attr('userinput') === 'yes') {
  321. methods[cmd].apply(this);
  322. } else if ($(this).attr('block')) {
  323. methods['formatblock'].apply(this, ["<" + ($(this).attr('block')) + ">"]);
  324. } else {
  325. if ((cmd === 'justifyright') || (cmd === 'justifyleft') || (cmd === 'justifycenter') || (cmd === 'justifyfull')) {
  326. try {
  327. document.execCommand(cmd, false, null);
  328. } catch (e) {
  329. if (e && e.result === 2147500037) {
  330. range = window.getSelection().getRangeAt(0);
  331. dummy = document.createElement('br');
  332. ceNode = range.startContainer.parentNode;
  333. while ((ceNode != null) && ceNode.contentEditable !== 'true') {
  334. ceNode = ceNode.parentNode;
  335. }
  336. if (!ceNode) {
  337. throw 'Selected node is not editable!';
  338. }
  339. ceNode.insertBefore(dummy, ceNode.childNodes[0]);
  340. document.execCommand(cmd, false, null);
  341. dummy.parentNode.removeChild(dummy);
  342. } else if (console && console.log) {
  343. console.log(e);
  344. }
  345. }
  346. } else {
  347. document.execCommand(cmd, false, null);
  348. }
  349. }
  350. return false;
  351. });
  352. shortcuts = [
  353. {
  354. keys: 'Ctrl+l',
  355. method: function() {
  356. return methods.createlink.apply(this);
  357. }
  358. }, {
  359. keys: 'Ctrl+g',
  360. method: function() {
  361. return methods.insertimage.apply(this);
  362. }
  363. }, {
  364. keys: 'Ctrl+Alt+U',
  365. method: function() {
  366. return document.execCommand('insertunorderedlist', false, null);
  367. }
  368. }, {
  369. keys: 'Ctrl+Alt+O',
  370. method: function() {
  371. return document.execCommand('insertorderedlist', false, null);
  372. }
  373. }, {
  374. keys: 'Ctrl+q',
  375. method: function() {
  376. return methods.formatblock.apply(this, ["<blockquote>"]);
  377. }
  378. }, {
  379. keys: 'Ctrl+Alt+k',
  380. method: function() {
  381. return methods.formatblock.apply(this, ["<pre>"]);
  382. }
  383. }, {
  384. keys: 'Ctrl+.',
  385. method: function() {
  386. return document.execCommand('superscript', false, null);
  387. }
  388. }, {
  389. keys: 'Ctrl+Shift+.',
  390. method: function() {
  391. return document.execCommand('subscript', false, null);
  392. }
  393. }, {
  394. keys: 'Ctrl+Alt+0',
  395. method: function() {
  396. return methods.formatblock.apply(this, ["p"]);
  397. }
  398. }, {
  399. keys: 'Ctrl+b',
  400. method: function() {
  401. return document.execCommand('bold', false, null);
  402. }
  403. }, {
  404. keys: 'Ctrl+i',
  405. method: function() {
  406. return document.execCommand('italic', false, null);
  407. }
  408. }, {
  409. keys: 'Ctrl+Alt+1',
  410. method: function() {
  411. return methods.formatblock.apply(this, ["H1"]);
  412. }
  413. }, {
  414. keys: 'Ctrl+Alt+2',
  415. method: function() {
  416. return methods.formatblock.apply(this, ["H2"]);
  417. }
  418. }, {
  419. keys: 'Ctrl+Alt+3',
  420. method: function() {
  421. return methods.formatblock.apply(this, ["H3"]);
  422. }
  423. }, {
  424. keys: 'Ctrl+Alt+4',
  425. method: function() {
  426. return methods.formatblock.apply(this, ["H4"]);
  427. }
  428. }, {
  429. keys: 'Ctrl+m',
  430. method: function() {
  431. return document.execCommand("removeFormat", false, null);
  432. }
  433. }, {
  434. keys: 'Ctrl+u',
  435. method: function() {
  436. return document.execCommand('underline', false, null);
  437. }
  438. }, {
  439. keys: 'tab',
  440. method: function() {
  441. return document.execCommand('indent', false, null);
  442. }
  443. }, {
  444. keys: 'Ctrl+tab',
  445. method: function() {
  446. return document.execCommand('indent', false, null);
  447. }
  448. }, {
  449. keys: 'Shift+tab',
  450. method: function() {
  451. return document.execCommand('outdent', false, null);
  452. }
  453. }
  454. ];
  455. $.each(shortcuts, function(index, elem) {
  456. return shortcut.add(elem.keys, function() {
  457. elem.method();
  458. return false;
  459. }, {
  460. 'type': 'keydown',
  461. 'propagate': false
  462. });
  463. });
  464. return this.each(function() {
  465. var $this, data, tooltip;
  466. $this = $(this);
  467. data = $this.data('fresheditor');
  468. tooltip = $('<div/>', {
  469. text: $this.attr('title')
  470. });
  471. if (!data) {
  472. return $(this).data('fresheditor', {
  473. target: $this,
  474. tooltip: tooltip
  475. });
  476. }
  477. });
  478. }
  479. };
  480. return $.fn.freshereditor = function(method) {
  481. if (methods[method]) {
  482. methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  483. } else if (typeof method === 'object' || !method) {
  484. methods.init.apply(this, arguments);
  485. } else {
  486. $.error('Method ' + method + ' does not exist on jQuery.contentEditable');
  487. }
  488. };
  489. })(jQuery);
  490. }).call(this);