summernote.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. define([
  2. 'summernote/core/agent',
  3. 'summernote/core/list',
  4. 'summernote/core/dom',
  5. 'summernote/core/range',
  6. 'summernote/defaults',
  7. 'summernote/EventHandler',
  8. 'summernote/Renderer'
  9. ], function (agent, list, dom, range,
  10. defaults, EventHandler, Renderer) {
  11. // jQuery namespace for summernote
  12. /**
  13. * @class $.summernote
  14. *
  15. * summernote attribute
  16. *
  17. * @mixin defaults
  18. * @singleton
  19. *
  20. */
  21. $.summernote = $.summernote || {};
  22. // extends default settings
  23. // - $.summernote.version
  24. // - $.summernote.options
  25. // - $.summernote.lang
  26. $.extend($.summernote, defaults);
  27. var renderer = new Renderer();
  28. var eventHandler = new EventHandler();
  29. $.extend($.summernote, {
  30. /** @property {Renderer} */
  31. renderer: renderer,
  32. /** @property {EventHandler} */
  33. eventHandler: eventHandler,
  34. /**
  35. * @property {Object} core
  36. * @property {core.agent} core.agent
  37. * @property {core.dom} core.dom
  38. * @property {core.range} core.range
  39. */
  40. core: {
  41. agent: agent,
  42. list : list,
  43. dom: dom,
  44. range: range
  45. },
  46. /**
  47. * @property {Object}
  48. * pluginEvents event list for plugins
  49. * event has name and callback function.
  50. *
  51. * ```
  52. * $.summernote.addPlugin({
  53. * events : {
  54. * 'hello' : function(layoutInfo, value, $target) {
  55. * console.log('event name is hello, value is ' + value );
  56. * }
  57. * }
  58. * })
  59. * ```
  60. *
  61. * * event name is data-event property.
  62. * * layoutInfo is a summernote layout information.
  63. * * value is data-value property.
  64. */
  65. pluginEvents: {},
  66. plugins : []
  67. });
  68. /**
  69. * @method addPlugin
  70. *
  71. * add Plugin in Summernote
  72. *
  73. * Summernote can make a own plugin.
  74. *
  75. * ### Define plugin
  76. * ```
  77. * // get template function
  78. * var tmpl = $.summernote.renderer.getTemplate();
  79. *
  80. * // add a button
  81. * $.summernote.addPlugin({
  82. * buttons : {
  83. * // "hello" is button's namespace.
  84. * "hello" : function(lang, options) {
  85. * // make icon button by template function
  86. * return tmpl.iconButton(options.iconPrefix + 'header', {
  87. * // callback function name when button clicked
  88. * event : 'hello',
  89. * // set data-value property
  90. * value : 'hello',
  91. * hide : true
  92. * });
  93. * }
  94. *
  95. * },
  96. *
  97. * events : {
  98. * "hello" : function(layoutInfo, value) {
  99. * // here is event code
  100. * }
  101. * }
  102. * });
  103. * ```
  104. * ### Use a plugin in toolbar
  105. *
  106. * ```
  107. * $("#editor").summernote({
  108. * ...
  109. * toolbar : [
  110. * // display hello plugin in toolbar
  111. * ['group', [ 'hello' ]]
  112. * ]
  113. * ...
  114. * });
  115. * ```
  116. *
  117. *
  118. * @param {Object} plugin
  119. * @param {Object} [plugin.buttons] define plugin button. for detail, see to Renderer.addButtonInfo
  120. * @param {Object} [plugin.dialogs] define plugin dialog. for detail, see to Renderer.addDialogInfo
  121. * @param {Object} [plugin.events] add event in $.summernote.pluginEvents
  122. * @param {Object} [plugin.langs] update $.summernote.lang
  123. * @param {Object} [plugin.options] update $.summernote.options
  124. */
  125. $.summernote.addPlugin = function (plugin) {
  126. // save plugin list
  127. $.summernote.plugins.push(plugin);
  128. if (plugin.buttons) {
  129. $.each(plugin.buttons, function (name, button) {
  130. renderer.addButtonInfo(name, button);
  131. });
  132. }
  133. if (plugin.dialogs) {
  134. $.each(plugin.dialogs, function (name, dialog) {
  135. renderer.addDialogInfo(name, dialog);
  136. });
  137. }
  138. if (plugin.events) {
  139. $.each(plugin.events, function (name, event) {
  140. $.summernote.pluginEvents[name] = event;
  141. });
  142. }
  143. if (plugin.langs) {
  144. $.each(plugin.langs, function (locale, lang) {
  145. if ($.summernote.lang[locale]) {
  146. $.extend($.summernote.lang[locale], lang);
  147. }
  148. });
  149. }
  150. if (plugin.options) {
  151. $.extend($.summernote.options, plugin.options);
  152. }
  153. };
  154. /*
  155. * extend $.fn
  156. */
  157. $.fn.extend({
  158. /**
  159. * @method
  160. * Initialize summernote
  161. * - create editor layout and attach Mouse and keyboard events.
  162. *
  163. * ```
  164. * $("#summernote").summernote( { options ..} );
  165. * ```
  166. *
  167. * @member $.fn
  168. * @param {Object|String} options reference to $.summernote.options
  169. * @return {this}
  170. */
  171. summernote: function () {
  172. // check first argument's type
  173. // - {String}: External API call {{module}}.{{method}}
  174. // - {Object}: init options
  175. var type = $.type(list.head(arguments));
  176. var isExternalAPICalled = type === 'string';
  177. var hasInitOptions = type === 'object';
  178. // extend default options with custom user options
  179. var options = hasInitOptions ? list.head(arguments) : {};
  180. options = $.extend({}, $.summernote.options, options);
  181. options.icons = $.extend({}, $.summernote.options.icons, options.icons);
  182. // Include langInfo in options for later use, e.g. for image drag-n-drop
  183. // Setup language info with en-US as default
  184. options.langInfo = $.extend(true, {}, $.summernote.lang['en-US'], $.summernote.lang[options.lang]);
  185. // override plugin options
  186. if (!isExternalAPICalled && hasInitOptions) {
  187. for (var i = 0, len = $.summernote.plugins.length; i < len; i++) {
  188. var plugin = $.summernote.plugins[i];
  189. if (options.plugin[plugin.name]) {
  190. $.summernote.plugins[i] = $.extend(true, plugin, options.plugin[plugin.name]);
  191. }
  192. }
  193. }
  194. this.each(function (idx, holder) {
  195. var $holder = $(holder);
  196. // if layout isn't created yet, createLayout and attach events
  197. if (!renderer.hasNoteEditor($holder)) {
  198. renderer.createLayout($holder, options);
  199. var layoutInfo = renderer.layoutInfoFromHolder($holder);
  200. $holder.data('layoutInfo', layoutInfo);
  201. eventHandler.attach(layoutInfo, options);
  202. eventHandler.attachCustomEvent(layoutInfo, options);
  203. }
  204. });
  205. var $first = this.first();
  206. if ($first.length) {
  207. var layoutInfo = renderer.layoutInfoFromHolder($first);
  208. // external API
  209. if (isExternalAPICalled) {
  210. var moduleAndMethod = list.head(list.from(arguments));
  211. var args = list.tail(list.from(arguments));
  212. // TODO now external API only works for editor
  213. var params = [moduleAndMethod, layoutInfo.editable()].concat(args);
  214. return eventHandler.invoke.apply(eventHandler, params);
  215. } else if (options.focus) {
  216. // focus on first editable element for initialize editor
  217. layoutInfo.editable().focus();
  218. }
  219. }
  220. return this;
  221. },
  222. /**
  223. * @method
  224. *
  225. * get the HTML contents of note or set the HTML contents of note.
  226. *
  227. * * get contents
  228. * ```
  229. * var content = $("#summernote").code();
  230. * ```
  231. * * set contents
  232. *
  233. * ```
  234. * $("#summernote").code(html);
  235. * ```
  236. *
  237. * @member $.fn
  238. * @param {String} [html] - HTML contents(optional, set)
  239. * @return {this|String} - context(set) or HTML contents of note(get).
  240. */
  241. code: function (html) {
  242. // get the HTML contents of note
  243. if (html === undefined) {
  244. var $holder = this.first();
  245. if (!$holder.length) {
  246. return;
  247. }
  248. var layoutInfo = renderer.layoutInfoFromHolder($holder);
  249. var $editable = layoutInfo && layoutInfo.editable();
  250. if ($editable && $editable.length) {
  251. var isCodeview = eventHandler.invoke('codeview.isActivated', layoutInfo);
  252. eventHandler.invoke('codeview.sync', layoutInfo);
  253. return isCodeview ? layoutInfo.codable().val() :
  254. layoutInfo.editable().html();
  255. }
  256. return dom.value($holder);
  257. }
  258. // set the HTML contents of note
  259. this.each(function (i, holder) {
  260. var layoutInfo = renderer.layoutInfoFromHolder($(holder));
  261. var $editable = layoutInfo && layoutInfo.editable();
  262. if ($editable) {
  263. $editable.html(html);
  264. }
  265. });
  266. return this;
  267. },
  268. /**
  269. * @method
  270. *
  271. * destroy Editor Layout and detach Key and Mouse Event
  272. *
  273. * @member $.fn
  274. * @return {this}
  275. */
  276. destroy: function () {
  277. this.each(function (idx, holder) {
  278. var $holder = $(holder);
  279. if (!renderer.hasNoteEditor($holder)) {
  280. return;
  281. }
  282. var info = renderer.layoutInfoFromHolder($holder);
  283. var options = info.editor().data('options');
  284. eventHandler.detach(info, options);
  285. renderer.removeLayout($holder, info, options);
  286. });
  287. return this;
  288. }
  289. });
  290. });