diff options
| author | Nicolas Lempereur <nle@odoo.com> | 2015-08-28 17:22:17 +0200 |
|---|---|---|
| committer | Nicolas Lempereur <nle@odoo.com> | 2015-09-25 08:29:16 +0200 |
| commit | 7747e0751f7a0409132d3171162d67d0885a70cb (patch) | |
| tree | 7da063ae03180622c1e2e1b193f7d2c5c0477318 /addons/web_editor/static/lib/summernote/src/js/EventHandler.js | |
| parent | 9798b57b12c5f943fc0f8ee7b82a9eb04434a635 (diff) | |
[IMP] web_editor: update summernote up to 2015-08-31
update summernote library up to revision:
https://github.com/summernote/summernote/commit/a0f26e300
see https://github.com/summernote/summernote/ for history
closes #8704
Diffstat (limited to 'addons/web_editor/static/lib/summernote/src/js/EventHandler.js')
| -rw-r--r-- | addons/web_editor/static/lib/summernote/src/js/EventHandler.js | 829 |
1 files changed, 311 insertions, 518 deletions
diff --git a/addons/web_editor/static/lib/summernote/src/js/EventHandler.js b/addons/web_editor/static/lib/summernote/src/js/EventHandler.js index 068ceff735f..09a7b00082a 100644 --- a/addons/web_editor/static/lib/summernote/src/js/EventHandler.js +++ b/addons/web_editor/static/lib/summernote/src/js/EventHandler.js @@ -1,92 +1,131 @@ define([ - 'summernote/core/agent', 'summernote/core/dom', 'summernote/core/async', 'summernote/core/key', 'summernote/core/list', 'summernote/core/range', - 'summernote/editing/Style', 'summernote/editing/Editor', 'summernote/editing/History', - 'summernote/module/Toolbar', 'summernote/module/Popover', 'summernote/module/Handle', 'summernote/module/Dialog' -], function (agent, dom, async, key, list, range, - Style, Editor, History, - Toolbar, Popover, Handle, Dialog) { - - var CodeMirror; - if (agent.hasCodeMirror) { - if (agent.isSupportAmd) { - require(['CodeMirror'], function (cm) { - CodeMirror = cm; - }); - } else { - CodeMirror = window.CodeMirror; - } - } + 'summernote/core/agent', + 'summernote/core/func', + 'summernote/core/dom', + 'summernote/core/async', + 'summernote/core/key', + 'summernote/core/list', + 'summernote/editing/History', + 'summernote/module/Editor', + 'summernote/module/Toolbar', + 'summernote/module/Statusbar', + 'summernote/module/Popover', + 'summernote/module/Handle', + 'summernote/module/Fullscreen', + 'summernote/module/Codeview', + 'summernote/module/DragAndDrop', + 'summernote/module/Clipboard', + 'summernote/module/LinkDialog', + 'summernote/module/ImageDialog', + 'summernote/module/HelpDialog' +], function (agent, func, dom, async, key, list, History, + Editor, Toolbar, Statusbar, Popover, Handle, Fullscreen, Codeview, + DragAndDrop, Clipboard, LinkDialog, ImageDialog, HelpDialog) { /** + * @class EventHandler + * * EventHandler + * - TODO: new instance per a editor */ var EventHandler = function () { - var $window = $(window); - var $document = $(document); - var $scrollbar = $('html, body'); - - var editor = new Editor(); - var toolbar = new Toolbar(), popover = new Popover(); - var handle = new Handle(), dialog = new Dialog(); + var self = this; - this.getEditor = function () { - return editor; + /** + * Modules + */ + var modules = this.modules = { + editor: new Editor(this), + toolbar: new Toolbar(this), + statusbar: new Statusbar(this), + popover: new Popover(this), + handle: new Handle(this), + fullscreen: new Fullscreen(this), + codeview: new Codeview(this), + dragAndDrop: new DragAndDrop(this), + clipboard: new Clipboard(this), + linkDialog: new LinkDialog(this), + imageDialog: new ImageDialog(this), + helpDialog: new HelpDialog(this) }; /** - * returns makeLayoutInfo from editor's descendant node. + * invoke module's method * - * @param {Node} descendant - * @returns {Object} + * @param {String} moduleAndMethod - ex) 'editor.redo' + * @param {...*} arguments - arguments of method + * @return {*} */ - var makeLayoutInfo = function (descendant) { - var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout'); + this.invoke = function () { + var moduleAndMethod = list.head(list.from(arguments)); + var args = list.tail(list.from(arguments)); - if (!$target.length) { return null; } + var splits = moduleAndMethod.split('.'); + var hasSeparator = splits.length > 1; + var moduleName = hasSeparator && list.head(splits); + var methodName = hasSeparator ? list.last(splits) : list.head(splits); - var $editor; - if ($target.is('.note-editor, .note-air-editor')) { - $editor = $target; - } else { - $editor = $('[data-note-id="' + list.last($target.attr('id').split('-')) + '"]'); - } + var module = this.getModule(moduleName); + var method = module[methodName]; + + return method && method.apply(module, args); + }; + + /** + * returns module + * + * @param {String} moduleName - name of module + * @return {Module} - defaults is editor + */ + this.getModule = function (moduleName) { + return this.modules[moduleName] || this.modules.editor; + }; - return dom.buildLayoutInfo($editor); + /** + * @param {jQuery} $holder + * @param {Object} callbacks + * @param {String} eventNamespace + * @returns {Function} + */ + var bindCustomEvent = this.bindCustomEvent = function ($holder, callbacks, eventNamespace) { + return function () { + var callback = callbacks[func.namespaceToCamel(eventNamespace, 'on')]; + if (callback) { + callback.apply($holder[0], arguments); + } + return $holder.trigger('summernote.' + eventNamespace, arguments); + }; }; /** * insert Images from file array. * + * @private * @param {Object} layoutInfo * @param {File[]} files */ - var insertImages = function (layoutInfo, files) { + this.insertImages = function (layoutInfo, files) { var $editor = layoutInfo.editor(), - $editable = layoutInfo.editable(); + $editable = layoutInfo.editable(), + $holder = layoutInfo.holder(); var callbacks = $editable.data('callbacks'); var options = $editor.data('options'); // If onImageUpload options setted if (callbacks.onImageUpload) { - callbacks.onImageUpload(files, editor, $editable); + bindCustomEvent($holder, callbacks, 'image.upload')(files); // else insert Image as dataURL } else { $.each(files, function (idx, file) { var filename = file.name; if (options.maximumImageFileSize && options.maximumImageFileSize < file.size) { - if (callbacks.onImageUploadError) { - callbacks.onImageUploadError(options.langInfo.image.maximumFileSizeError); - } else { - alert(options.langInfo.image.maximumFileSizeError); - } + bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError); } else { async.readFileAsDataURL(file).then(function (sDataURL) { - editor.insertImage($editable, sDataURL, filename); + modules.editor.insertImage($editable, sDataURL, filename); }).fail(function () { - if (callbacks.onImageUploadError) { - callbacks.onImageUploadError(); - } + bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError); }); } }); @@ -98,292 +137,90 @@ define([ * @param {Object} layoutInfo */ showLinkDialog: function (layoutInfo) { - var $editor = layoutInfo.editor(), - $dialog = layoutInfo.dialog(), - $editable = layoutInfo.editable(), - linkInfo = editor.getLinkInfo($editable); - - var options = $editor.data('options'); - - editor.saveRange($editable); - dialog.showLinkDialog($editable, $dialog, linkInfo).then(function (linkInfo) { - editor.restoreRange($editable); - editor.createLink($editable, linkInfo, options); - // hide popover after creating link - popover.hide(layoutInfo.popover()); - }).fail(function () { - editor.restoreRange($editable); - }); + modules.linkDialog.show(layoutInfo); }, /** * @param {Object} layoutInfo */ showImageDialog: function (layoutInfo) { - var $dialog = layoutInfo.dialog(), - $editable = layoutInfo.editable(); - - editor.saveRange($editable); - dialog.showImageDialog($editable, $dialog).then(function (data) { - editor.restoreRange($editable); - - if (typeof data === 'string') { - // image url - editor.insertImage($editable, data); - } else { - // array of files - insertImages(layoutInfo, data); - } - }).fail(function () { - editor.restoreRange($editable); - }); + modules.imageDialog.show(layoutInfo); }, /** * @param {Object} layoutInfo */ showHelpDialog: function (layoutInfo) { - var $dialog = layoutInfo.dialog(), - $editable = layoutInfo.editable(); - - editor.saveRange($editable, true); - dialog.showHelpDialog($editable, $dialog).then(function () { - editor.restoreRange($editable); - }); + modules.helpDialog.show(layoutInfo); }, + /** + * @param {Object} layoutInfo + */ fullscreen: function (layoutInfo) { - var $editor = layoutInfo.editor(), - $toolbar = layoutInfo.toolbar(), - $editable = layoutInfo.editable(), - $codable = layoutInfo.codable(); - - var resize = function (size) { - $editable.css('height', size.h); - $codable.css('height', size.h); - if ($codable.data('cmeditor')) { - $codable.data('cmeditor').setsize(null, size.h); - } - }; - - $editor.toggleClass('fullscreen'); - var isFullscreen = $editor.hasClass('fullscreen'); - if (isFullscreen) { - $editable.data('orgheight', $editable.css('height')); - - $window.on('resize', function () { - resize({ - h: $window.height() - $toolbar.outerHeight() - }); - }).trigger('resize'); - - $scrollbar.css('overflow', 'hidden'); - } else { - $window.off('resize'); - resize({ - h: $editable.data('orgheight') - }); - $scrollbar.css('overflow', 'visible'); - } - - toolbar.updateFullscreen($toolbar, isFullscreen); + modules.fullscreen.toggle(layoutInfo); }, + /** + * @param {Object} layoutInfo + */ codeview: function (layoutInfo) { - var $editor = layoutInfo.editor(), - $toolbar = layoutInfo.toolbar(), - $editable = layoutInfo.editable(), - $codable = layoutInfo.codable(), - $popover = layoutInfo.popover(), - $handle = layoutInfo.handle(); - - var options = $editor.data('options'); - - var cmEditor, server; - - $editor.toggleClass('codeview'); - - var isCodeview = $editor.hasClass('codeview'); - if (isCodeview) { - $codable.val(dom.html($editable, true)); - $codable.height($editable.height()); - toolbar.deactivate($toolbar); - popover.hide($popover); - handle.hide($handle); - $codable.focus(); - - // activate CodeMirror as codable - if (agent.hasCodeMirror) { - cmEditor = CodeMirror.fromTextArea($codable[0], options.codemirror); - - // CodeMirror TernServer - if (options.codemirror.tern) { - server = new CodeMirror.TernServer(options.codemirror.tern); - cmEditor.ternServer = server; - cmEditor.on('cursorActivity', function (cm) { - server.updateArgHints(cm); - }); - } - - // CodeMirror hasn't Padding. - cmEditor.setSize(null, $editable.outerHeight()); - $codable.data('cmEditor', cmEditor); - } - } else { - // deactivate CodeMirror as codable - if (agent.hasCodeMirror) { - cmEditor = $codable.data('cmEditor'); - $codable.val(cmEditor.getValue()); - cmEditor.toTextArea(); - } - - $editable.html(dom.value($codable) || dom.emptyPara); - $editable.height(options.height ? $codable.height() : 'auto'); - - toolbar.activate($toolbar); - $editable.focus(); - } - - toolbar.updateCodeview(layoutInfo.toolbar(), isCodeview); + modules.codeview.toggle(layoutInfo); } }; - this.commands = commands; // odoo change for overwrite - this.editor = editor; // odoo change for overwrite - this.toolbar = toolbar; // odoo change for overwrite - this.popover = popover; // odoo change for overwrite - this.handle = handle; // odoo change for overwrite - this.dialog = dialog; // odoo change for overwrite - var hMousedown = function (event) { //preventDefault Selection for FF, IE8+ if (dom.isImg(event.target)) { event.preventDefault(); - range.createFromNode(event.target).select(); } }; - var hToolbarAndPopoverUpdate = function (event) { - // delay for range after mouseup - setTimeout(function () { - var layoutInfo = makeLayoutInfo(event.target); - var $editable = layoutInfo.editable(); - editor.saveRange($editable); - var styleInfo = editor.currentStyle(); - if (!styleInfo) { return; } - - var isAirMode = layoutInfo.editor().data('options').airMode; - if (!isAirMode) { - toolbar.update(layoutInfo.toolbar(), styleInfo); - } - - popover.update(layoutInfo.popover(), styleInfo, isAirMode); - handle.update(layoutInfo.handle(), styleInfo, isAirMode); - }, 0); - }; - - var hScroll = function (event) { - var layoutInfo = makeLayoutInfo(event.currentTarget || event.target); - //hide popover and handle when scrolled - popover.hide(layoutInfo.popover()); - handle.hide(layoutInfo.handle()); + var hKeyupAndMouseup = function (event) { + var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target); + modules.editor.removeBogus(layoutInfo.editable()); + hToolbarAndPopoverUpdate(event); }; /** - * paste clipboard image - * - * @param {Event} event + * update sytle info + * @param {Object} styleInfo + * @param {Object} layoutInfo */ - var hPasteClipboardImage = function (event) { - var clipboardData = event.originalEvent.clipboardData; - var layoutInfo = makeLayoutInfo(event.currentTarget || event.target); - var $editable = layoutInfo.editable(); - - if (!clipboardData || !clipboardData.items || !clipboardData.items.length) { - var callbacks = $editable.data('callbacks'); - // only can run if it has onImageUpload method - if (!callbacks.onImageUpload) { - return; - } - - // save cursor - editor.saveNode($editable); - editor.saveRange($editable); - - $editable.html(''); - - setTimeout(function () { - var $img = $editable.find('img'); - var datauri = $img[0].src; - - var data = atob(datauri.split(',')[1]); - var array = new Uint8Array(data.length); - for (var i = 0; i < data.length; i++) { - array[i] = data.charCodeAt(i); - } - - var blob = new Blob([array], { type : 'image/png'}); - blob.name = 'clipboard.png'; - - editor.restoreNode($editable); - editor.restoreRange($editable); - insertImages(layoutInfo, [blob]); - - editor.afterCommand($editable); - }, 0); - + this.updateStyleInfo = function (styleInfo, layoutInfo) { + if (!styleInfo) { return; } - - var item = list.head(clipboardData.items); - var isClipboardImage = item.kind === 'file' && item.type.indexOf('image/') !== -1; - - if (isClipboardImage) { - insertImages(layoutInfo, [item.getAsFile()]); + var isAirMode = layoutInfo.editor().data('options').airMode; + if (!isAirMode) { + modules.toolbar.update(layoutInfo.toolbar(), styleInfo); } - editor.afterCommand($editable); + modules.popover.update(layoutInfo.popover(), styleInfo, isAirMode); + modules.handle.update(layoutInfo.handle(), styleInfo, isAirMode); }; - /** - * `mousedown` event handler on $handle - * - controlSizing: resize image - * - * @param {MouseEvent} event - */ - var hHandleMousedown = function (event) { - if (dom.isControlSizing(event.target)) { - event.preventDefault(); - event.stopPropagation(); - - var layoutInfo = makeLayoutInfo(event.target), - $handle = layoutInfo.handle(), $popover = layoutInfo.popover(), - $editable = layoutInfo.editable(), - $editor = layoutInfo.editor(); - - var target = $handle.find('.note-control-selection').data('target'), - $target = $(target), posStart = $target.offset(), - scrollTop = $document.scrollTop(); - - var isAirMode = $editor.data('options').airMode; - - $document.on('mousemove', function (event) { - editor.resizeTo({ - x: event.clientX - posStart.left, - y: event.clientY - (posStart.top - scrollTop) - }, $target, !event.shiftKey); - - handle.update($handle, {image: target}, isAirMode); - popover.update($popover, {image: target}, isAirMode); - }).one('mouseup', function () { - $document.off('mousemove'); - editor.afterCommand($editable); - }); - - if (!$target.data('ratio')) { // original ratio. - $target.data('ratio', $target.height() / $target.width()); + var hToolbarAndPopoverUpdate = function (event) { + var target = event.target; + // delay for range after mouseup + setTimeout(function () { + var layoutInfo = dom.makeLayoutInfo(target); + /* ODOO: (start_modification */ + var $editable = layoutInfo.editable(); + if (!event.isDefaultPrevented()) { + modules.editor.saveRange($editable); } - } + /* ODOO: end_modification) */ + var styleInfo = modules.editor.currentStyle(target); + self.updateStyleInfo(styleInfo, layoutInfo); + }, 0); + }; + + var hScroll = function (event) { + var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target); + //hide popover and handle when scrolled + modules.popover.hide(layoutInfo.popover()); + modules.handle.hide(layoutInfo.handle()); }; var hToolbarAndPopoverMousedown = function (event) { @@ -397,76 +234,49 @@ define([ var hToolbarAndPopoverClick = function (event) { var $btn = $(event.target).closest('[data-event]'); - if ($btn.length && !$btn.is(':disabled')) { - var eventName = $btn.attr('data-event'), - value = $btn.attr('data-value'), - hide = $btn.attr('data-hide'); - - var layoutInfo = makeLayoutInfo(event.target); - - var $editable = layoutInfo.editable(); - editor.restoreRange($editable); - - // before command: detect control selection element($target) - var $target; - if ($.inArray(eventName, ['resize', 'floatMe', 'removeMedia', 'imageShape']) !== -1) { - var $selection = layoutInfo.handle().find('.note-control-selection'); - $target = $($selection.data('target')); - } - - // If requested, hide the popover when the button is clicked. - // Useful for things like showHelpDialog. - if (hide) { - $btn.parents('.popover').hide(); - } + if (!$btn.length) { + return; + } - if ($.isFunction($.summernote.pluginEvents[eventName])) { - $.summernote.pluginEvents[eventName](event, editor, layoutInfo, value); - } else if (editor[eventName]) { // on command - $editable.trigger('focus'); - editor[eventName]($editable, value, $target); - event.preventDefault(); - } else if (commands[eventName]) { - commands[eventName].call(this, layoutInfo); - event.preventDefault(); - } + var eventName = $btn.attr('data-event'), + value = $btn.attr('data-value'), + hide = $btn.attr('data-hide'); - // after command - if ($.inArray(eventName, ['backColor', 'foreColor']) !== -1) { - var options = layoutInfo.editor().data('options', options); - var module = options.airMode ? popover : toolbar; - module.updateRecentColor(list.head($btn), eventName, value); - } + var layoutInfo = dom.makeLayoutInfo(event.target); - hToolbarAndPopoverUpdate(event); + // before command: detect control selection element($target) + var $target; + if ($.inArray(eventName, ['resize', 'floatMe', 'removeMedia', 'imageShape']) !== -1) { + var $selection = layoutInfo.handle().find('.note-control-selection'); + $target = $($selection.data('target')); } - }; - var EDITABLE_PADDING = 24; - /** - * `mousedown` event handler on statusbar - * - * @param {MouseEvent} event - */ - var hStatusbarMousedown = function (event) { - event.preventDefault(); - event.stopPropagation(); - - var layoutInfo = makeLayoutInfo(event.target); - var $editable = layoutInfo.editable(); - var nEditableTop = $editable.offset().top - $document.scrollTop(); - var options = layoutInfo.editor().data('options'); + // If requested, hide the popover when the button is clicked. + // Useful for things like showHelpDialog. + if (hide) { + $btn.parents('.popover').hide(); + } - $document.on('mousemove', function (event) { - var nHeight = event.clientY - (nEditableTop + EDITABLE_PADDING); + if ($.isFunction($.summernote.pluginEvents[eventName])) { + $.summernote.pluginEvents[eventName](event, modules.editor, layoutInfo, value); + } else if (modules.editor[eventName]) { // on command + var $editable = layoutInfo.editable(); + $editable.focus(); + modules.editor[eventName]($editable, value, $target); + event.preventDefault(); + } else if (commands[eventName]) { + commands[eventName].call(this, layoutInfo); + event.preventDefault(); + } - nHeight = (options.minHeight > 0) ? Math.max(nHeight, options.minHeight) : nHeight; - nHeight = (options.maxHeight > 0) ? Math.min(nHeight, options.maxHeight) : nHeight; + // after command + if ($.inArray(eventName, ['backColor', 'foreColor']) !== -1) { + var options = layoutInfo.editor().data('options', options); + var module = options.airMode ? modules.popover : modules.toolbar; + module.updateRecentColor(list.head($btn), eventName, value); + } - $editable.height(nHeight); - }).one('mouseup', function () { - $document.off('mousemove'); - }); + hToolbarAndPopoverUpdate(event); }; var PX_PER_EM = 18; @@ -510,81 +320,7 @@ define([ $dimensionDisplay.html(dim.c + ' x ' + dim.r); }; - - /** - * Drag and Drop Events - * - * @param {Object} layoutInfo - layout Informations - * @param {Object} options - */ - var handleDragAndDropEvent = function (layoutInfo, options) { - if (options.disableDragAndDrop) { - // prevent default drop event - $document.on('drop', function (e) { - e.preventDefault(); - }); - } else { - attachDragAndDropEvent(layoutInfo, options); - } - }; - - /** - * attach Drag and Drop Events - * - * @param {Object} layoutInfo - layout Informations - * @param {Object} options - */ - var attachDragAndDropEvent = function (layoutInfo, options) { - var collection = $(), - $dropzone = layoutInfo.dropzone, - $dropzoneMessage = layoutInfo.dropzone.find('.note-dropzone-message'); - - // show dropzone on dragenter when dragging a object to document. - $document.on('dragenter', function (e) { - var isCodeview = layoutInfo.editor.hasClass('codeview'); - if (!isCodeview && !collection.length) { - layoutInfo.editor.addClass('dragover'); - $dropzone.width(layoutInfo.editor.width()); - $dropzone.height(layoutInfo.editor.height()); - $dropzoneMessage.text(options.langInfo.image.dragImageHere); - } - collection = collection.add(e.target); - }).on('dragleave', function (e) { - collection = collection.not(e.target); - if (!collection.length) { - layoutInfo.editor.removeClass('dragover'); - } - }).on('drop', function () { - collection = $(); - layoutInfo.editor.removeClass('dragover'); - }); - - // change dropzone's message on hover. - $dropzone.on('dragenter', function () { - $dropzone.addClass('hover'); - $dropzoneMessage.text(options.langInfo.image.dropImage); - }).on('dragleave', function () { - $dropzone.removeClass('hover'); - $dropzoneMessage.text(options.langInfo.image.dragImageHere); - }); - - // attach dropImage - $dropzone.on('drop', function (event) { - event.preventDefault(); - - var dataTransfer = event.originalEvent.dataTransfer; - var text = dataTransfer.getData('text/plain'); - var layoutInfo = makeLayoutInfo(event.currentTarget || event.target); - layoutInfo.editable().focus(); - if (dataTransfer && dataTransfer.files && dataTransfer.files.length) { - insertImages(layoutInfo, dataTransfer.files); - } else if (text) { - editor.insertText(layoutInfo.editable(), text); - } - }).on('dragover', false); // prevent default dragover event - }; - - + /** * bind KeyMap on keydown * @@ -592,25 +328,28 @@ define([ * @param {Object} keyMap */ this.bindKeyMap = function (layoutInfo, keyMap) { - var $editor = layoutInfo.editor; - var $editable = layoutInfo.editable; - - layoutInfo = makeLayoutInfo($editable); + var $editor = layoutInfo.editor(); + var $editable = layoutInfo.editable(); $editable.on('keydown', function (event) { - var aKey = []; + var keys = []; // modifier - if (event.metaKey) { aKey.push('CMD'); } - if (event.ctrlKey && !event.altKey) { aKey.push('CTRL'); } - if (event.shiftKey) { aKey.push('SHIFT'); } + if (event.metaKey) { keys.push('CMD'); } + if (event.ctrlKey && !event.altKey) { keys.push('CTRL'); } + if (event.shiftKey) { keys.push('SHIFT'); } // keycode var keyName = key.nameFromCode[event.keyCode]; - if (keyName) { aKey.push(keyName); } + if (keyName) { + keys.push(keyName); + } - var eventName = keyMap[aKey.join('+')]; + var pluginEvent; + var keyString = keys.join('+'); + var eventName = keyMap[keyString]; + // ODOO: (start_modification // odoo change: add visible event to overwrite the browser comportment var keycode = event.keyCode; if (!eventName && @@ -623,27 +362,33 @@ define([ (keycode > 218 && keycode < 223))) { // [\]' (in order)) eventName = 'visible'; } else if (!keycode) { - editor.restoreRange($editable); + self.invoke('restoreRange', $editable); } + // ODOO: end_modification) if (eventName) { - if ($.summernote.pluginEvents[eventName]) { - var plugin = $.summernote.pluginEvents[eventName]; - if ($.isFunction(plugin)) { - plugin(event, editor, layoutInfo); + // FIXME Summernote doesn't support event pipeline yet. + // - Plugin -> Base Code + pluginEvent = $.summernote.pluginEvents[keyString]; + if ($.isFunction(pluginEvent)) { + if (pluginEvent(event, modules.editor, layoutInfo)) { + return false; } - } else if (editor[eventName]) { - editor[eventName]($editable, $editor.data('options')); + } + + pluginEvent = $.summernote.pluginEvents[eventName]; + + if ($.isFunction(pluginEvent)) { + pluginEvent(event, modules.editor, layoutInfo); + } else if (modules.editor[eventName]) { + modules.editor[eventName]($editable, $editor.data('options')); event.preventDefault(); } else if (commands[eventName]) { commands[eventName].call(this, layoutInfo); event.preventDefault(); } - if (keycode) { - editor.saveRange($editable); - } } else if (key.isEdit(event.keyCode)) { - editor.afterCommand($editable); + modules.editor.afterCommand($editable); } }); }; @@ -653,41 +398,40 @@ define([ * * @param {Object} layoutInfo - layout Informations * @param {Object} options - user options include custom event handlers - * @param {Function} options.enter - enter key handler */ this.attach = function (layoutInfo, options) { // handlers for editable if (options.shortcuts) { this.bindKeyMap(layoutInfo, options.keyMap[agent.isMac ? 'mac' : 'pc']); } - layoutInfo.editable.on('mousedown', hMousedown); - layoutInfo.editable.on('keyup mouseup', hToolbarAndPopoverUpdate); - layoutInfo.editable.on('scroll', hScroll); - layoutInfo.editable.on('paste', hPasteClipboardImage); + layoutInfo.editable().on('mousedown', hMousedown); + layoutInfo.editable().on('keyup mouseup', hKeyupAndMouseup); + layoutInfo.editable().on('scroll', hScroll); + + // handler for clipboard + modules.clipboard.attach(layoutInfo, options); // handler for handle and popover - layoutInfo.handle.on('mousedown', hHandleMousedown); - layoutInfo.popover.on('click', hToolbarAndPopoverClick); - layoutInfo.popover.on('mousedown', hToolbarAndPopoverMousedown); + modules.handle.attach(layoutInfo, options); + layoutInfo.popover().on('click', hToolbarAndPopoverClick); + layoutInfo.popover().on('mousedown', hToolbarAndPopoverMousedown); + + // handler for drag and drop + modules.dragAndDrop.attach(layoutInfo, options); // handlers for frame mode (toolbar, statusbar) if (!options.airMode) { - // handler for drag and drop - handleDragAndDropEvent(layoutInfo, options); - // handler for toolbar - layoutInfo.toolbar.on('click', hToolbarAndPopoverClick); - layoutInfo.toolbar.on('mousedown', hToolbarAndPopoverMousedown); + layoutInfo.toolbar().on('click', hToolbarAndPopoverClick); + layoutInfo.toolbar().on('mousedown', hToolbarAndPopoverMousedown); // handler for statusbar - if (!options.disableResizeEditor) { - layoutInfo.statusbar.on('mousedown', hStatusbarMousedown); - } + modules.statusbar.attach(layoutInfo, options); } // handler for table dimension - var $catcherContainer = options.airMode ? layoutInfo.popover : - layoutInfo.toolbar; + var $catcherContainer = options.airMode ? layoutInfo.popover() : + layoutInfo.toolbar(); var $catcher = $catcherContainer.find('.note-dimension-picker-mousecatcher'); $catcher.css({ width: options.insertTableMaxSize.col + 'em', @@ -697,72 +441,121 @@ define([ }); // save options on editor - layoutInfo.editor.data('options', options); + layoutInfo.editor().data('options', options); // ret styleWithCSS for backColor / foreColor clearing with 'inherit'. if (!agent.isMSIE) { - // protect FF Error: NS_ERROR_FAILURE: Failure + // [workaround] for Firefox + // - protect FF Error: NS_ERROR_FAILURE: Failure setTimeout(function () { document.execCommand('styleWithCSS', 0, options.styleWithSpan); }, 0); } // History - var history = new History(layoutInfo.editable); - layoutInfo.editable.data('NoteHistory', history); - - // basic event callbacks (lowercase) - // enter, focus, blur, keyup, keydown - if (options.onenter) { - layoutInfo.editable.keypress(function (event) { - if (event.keyCode === key.ENTER) { options.onenter(event); } - }); - } - - if (options.onfocus) { layoutInfo.editable.focus(options.onfocus); } - if (options.onblur) { layoutInfo.editable.blur(options.onblur); } - if (options.onkeyup) { layoutInfo.editable.keyup(options.onkeyup); } - if (options.onkeydown) { layoutInfo.editable.keydown(options.onkeydown); } - if (options.onpaste) { layoutInfo.editable.on('paste', options.onpaste); } - - // callbacks for advanced features (camel) - if (options.onToolbarClick) { layoutInfo.toolbar.click(options.onToolbarClick); } - if (options.onChange) { - var hChange = function () { - editor.triggerOnChange(layoutInfo.editable); - }; - - if (agent.isMSIE) { - var sDomEvents = 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted'; - layoutInfo.editable.on(sDomEvents, hChange); - } else { - layoutInfo.editable.on('input', hChange); - } - } + var history = new History(layoutInfo.editable()); + layoutInfo.editable().data('NoteHistory', history); // All editor status will be saved on editable with jquery's data // for support multiple editor with singleton object. - layoutInfo.editable.data('callbacks', { + layoutInfo.editable().data('callbacks', { + onInit: options.onInit, + onFocus: options.onFocus, + onBlur: options.onBlur, + onKeydown: options.onKeydown, + onKeyup: options.onKeyup, + onMousedown: options.onMousedown, + onEnter: options.onEnter, + onPaste: options.onPaste, + onBeforeCommand: options.onBeforeCommand, onChange: options.onChange, - onAutoSave: options.onAutoSave, onImageUpload: options.onImageUpload, onImageUploadError: options.onImageUploadError, - onFileUpload: options.onFileUpload, - onFileUploadError: options.onFileUpload + onMediaDelete: options.onMediaDelete, + onToolbarClick: options.onToolbarClick }); + + var styleInfo = modules.editor.styleFromNode(layoutInfo.editable()); + this.updateStyleInfo(styleInfo, layoutInfo); }; + /** + * attach jquery custom event + * + * @param {Object} layoutInfo - layout Informations + */ + this.attachCustomEvent = function (layoutInfo, options) { + var $holder = layoutInfo.holder(); + var $editable = layoutInfo.editable(); + var callbacks = $editable.data('callbacks'); + + $editable.focus(bindCustomEvent($holder, callbacks, 'focus')); + $editable.blur(bindCustomEvent($holder, callbacks, 'blur')); + + $editable.keydown(function (event) { + if (event.keyCode === key.code.ENTER) { + bindCustomEvent($holder, callbacks, 'enter').call(this, event); + } + bindCustomEvent($holder, callbacks, 'keydown').call(this, event); + }); + $editable.keyup(bindCustomEvent($holder, callbacks, 'keyup')); + + $editable.on('mousedown', bindCustomEvent($holder, callbacks, 'mousedown')); + $editable.on('mouseup', bindCustomEvent($holder, callbacks, 'mouseup')); + $editable.on('scroll', bindCustomEvent($holder, callbacks, 'scroll')); + + $editable.on('paste', bindCustomEvent($holder, callbacks, 'paste')); + + // [workaround] IE doesn't have input events for contentEditable + // - see: https://goo.gl/4bfIvA + var changeEventName = agent.isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input'; + $editable.on(changeEventName, function () { + bindCustomEvent($holder, callbacks, 'change')($editable.html(), $editable); + }); + + if (!options.airMode) { + layoutInfo.toolbar().click(bindCustomEvent($holder, callbacks, 'toolbar.click')); + layoutInfo.popover().click(bindCustomEvent($holder, callbacks, 'popover.click')); + } + + // Textarea: auto filling the code before form submit. + if (dom.isTextarea(list.head($holder))) { + $holder.closest('form').submit(function (e) { + layoutInfo.holder().val(layoutInfo.holder().code()); + bindCustomEvent($holder, callbacks, 'submit').call(this, e, $holder.code()); + }); + } + + // textarea auto sync + if (dom.isTextarea(list.head($holder)) && options.textareaAutoSync) { + $holder.on('summernote.change', function () { + layoutInfo.holder().val(layoutInfo.holder().code()); + }); + } + + // fire init event + bindCustomEvent($holder, callbacks, 'init')(layoutInfo); + + // fire plugin init event + for (var i = 0, len = $.summernote.plugins.length; i < len; i++) { + if ($.isFunction($.summernote.plugins[i].init)) { + $.summernote.plugins[i].init(layoutInfo); + } + } + }; + this.detach = function (layoutInfo, options) { - layoutInfo.editable.off(); + layoutInfo.holder().off(); + layoutInfo.editable().off(); - layoutInfo.popover.off(); - layoutInfo.handle.off(); - layoutInfo.dialog.off(); + layoutInfo.popover().off(); + layoutInfo.handle().off(); + layoutInfo.dialog().off(); if (!options.airMode) { - layoutInfo.dropzone.off(); - layoutInfo.toolbar.off(); - layoutInfo.statusbar.off(); + layoutInfo.dropzone().off(); + layoutInfo.toolbar().off(); + layoutInfo.statusbar().off(); } }; }; |
