summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/lib/summernote/src/js/module
diff options
context:
space:
mode:
authorNicolas Lempereur <nle@odoo.com>2015-08-28 17:22:17 +0200
committerNicolas Lempereur <nle@odoo.com>2015-09-25 08:29:16 +0200
commit7747e0751f7a0409132d3171162d67d0885a70cb (patch)
tree7da063ae03180622c1e2e1b193f7d2c5c0477318 /addons/web_editor/static/lib/summernote/src/js/module
parent9798b57b12c5f943fc0f8ee7b82a9eb04434a635 (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/module')
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Button.js40
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js90
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Codeview.js137
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Dialog.js159
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/DragAndDrop.js98
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Fullscreen.js51
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Handle.js61
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/HelpDialog.js35
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/ImageDialog.js110
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/LinkDialog.js129
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Popover.js37
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Statusbar.js44
-rw-r--r--addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js47
13 files changed, 855 insertions, 183 deletions
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Button.js b/addons/web_editor/static/lib/summernote/src/js/module/Button.js
index 512822aeba8..b7a1614d4db 100644
--- a/addons/web_editor/static/lib/summernote/src/js/module/Button.js
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Button.js
@@ -1,7 +1,10 @@
define([
- 'summernote/core/list'
-], function (list) {
+ 'summernote/core/list',
+ 'summernote/core/agent'
+], function (list, agent) {
/**
+ * @class module.Button
+ *
* Button
*/
var Button = function () {
@@ -28,6 +31,7 @@ define([
/**
* update button state(active or not).
*
+ * @private
* @param {String} selector
* @param {Function} pred
*/
@@ -40,30 +44,30 @@ define([
var $img = $(styleInfo.image);
btnState('button[data-event="imageShape"][data-value="img-rounded"]', function () {
- return $img.hasClass("img-rounded");
+ return $img.hasClass('img-rounded');
});
btnState('button[data-event="imageShape"][data-value="img-circle"]', function () {
- return $img.hasClass("img-circle");
+ return $img.hasClass('img-circle');
});
btnState('button[data-event="imageShape"][data-value="img-thumbnail"]', function () {
- return $img.hasClass("img-thumbnail");
+ return $img.hasClass('img-thumbnail');
});
btnState('button[data-event="imageShape"]:not([data-value])', function () {
- return !$img.is(".img-rounded, .img-circle, .img-thumbnail");
+ return !$img.is('.img-rounded, .img-circle, .img-thumbnail');
});
- var imgFloat = $img.css("float");
+ var imgFloat = $img.css('float');
btnState('button[data-event="floatMe"][data-value="left"]', function () {
- return imgFloat === "left";
+ return imgFloat === 'left';
});
btnState('button[data-event="floatMe"][data-value="right"]', function () {
- return imgFloat === "right";
+ return imgFloat === 'right';
});
btnState('button[data-event="floatMe"][data-value="none"]', function () {
- return imgFloat !== "left" && imgFloat !== "right";
+ return imgFloat !== 'left' && imgFloat !== 'right';
});
- var style = $img.attr("style");
+ var style = $img.attr('style');
btnState('button[data-event="resize"][data-value="1"]', function () {
return !!/(^|\s)(max-)?width\s*:\s*100%/.test(style);
});
@@ -81,10 +85,18 @@ define([
if ($fontname.length) {
var selectedFont = styleInfo['font-family'];
if (!!selectedFont) {
- selectedFont = list.head(selectedFont.split(','));
- selectedFont = selectedFont.replace(/\'/g, '');
+
+ var list = selectedFont.split(',');
+ for (var i = 0, len = list.length; i < len; i++) {
+ selectedFont = list[i].replace(/[\'\"]/g, '').replace(/\s+$/, '').replace(/^\s+/, '');
+ if (agent.isFontInstalled(selectedFont)) {
+ break;
+ }
+ }
+
$fontname.find('.note-current-fontname').text(selectedFont);
checkDropdownMenu($fontname, selectedFont);
+
}
}
@@ -140,7 +152,7 @@ define([
*
* @param {Node} button
* @param {String} eventName
- * @param {value} value
+ * @param {Mixed} value
*/
this.updateRecentColor = function (button, eventName, value) {
var $color = $(button).closest('.note-color');
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js b/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js
new file mode 100644
index 00000000000..e2d234c9dbb
--- /dev/null
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js
@@ -0,0 +1,90 @@
+define([
+ 'summernote/core/list',
+ 'summernote/core/dom',
+ 'summernote/core/key',
+ 'summernote/core/agent'
+], function (list, dom, key, agent) {
+ var Clipboard = function (handler) {
+ var $paste;
+
+ this.attach = function (layoutInfo) {
+ // [workaround] getting image from clipboard
+ // - IE11 and Firefox: CTRL+v hook
+ // - Webkit: event.clipboardData
+ if ((agent.isMSIE && agent.browserVersion > 10) || agent.isFF) {
+ $paste = $('<div />').attr('contenteditable', true).css({
+ position : 'absolute',
+ left : -100000,
+ opacity : 0
+ });
+
+ layoutInfo.editable().on('keydown', function (e) {
+ if (e.ctrlKey && e.keyCode === key.code.V) {
+ handler.invoke('saveRange', layoutInfo.editable());
+ $paste.focus();
+
+ setTimeout(function () {
+ pasteByHook(layoutInfo);
+ }, 0);
+ }
+ });
+
+ layoutInfo.editable().before($paste);
+ } else {
+ layoutInfo.editable().on('paste', pasteByEvent);
+ }
+ };
+
+ var pasteByHook = function (layoutInfo) {
+ var $editable = layoutInfo.editable();
+ var node = $paste[0].firstChild;
+
+ if (dom.isImg(node)) {
+ var dataURI = node.src;
+ var decodedData = atob(dataURI.split(',')[1]);
+ var array = new Uint8Array(decodedData.length);
+ for (var i = 0; i < decodedData.length; i++) {
+ array[i] = decodedData.charCodeAt(i);
+ }
+
+ var blob = new Blob([array], { type : 'image/png' });
+ blob.name = 'clipboard.png';
+
+ handler.invoke('restoreRange', $editable);
+ handler.invoke('focus', $editable);
+ handler.insertImages(layoutInfo, [blob]);
+ } else {
+ var pasteContent = $('<div />').html($paste.html()).html();
+ handler.invoke('restoreRange', $editable);
+ handler.invoke('focus', $editable);
+
+ if (pasteContent) {
+ handler.invoke('pasteHTML', $editable, pasteContent);
+ }
+ }
+
+ $paste.empty();
+ };
+
+ /**
+ * paste by clipboard event
+ *
+ * @param {Event} event
+ */
+ var pasteByEvent = function (event) {
+ var clipboardData = event.originalEvent.clipboardData;
+ var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
+ var $editable = layoutInfo.editable();
+
+ if (clipboardData && clipboardData.items && clipboardData.items.length) {
+ var item = list.head(clipboardData.items);
+ if (item.kind === 'file' && item.type.indexOf('image/') !== -1) {
+ handler.insertImages(layoutInfo, [item.getAsFile()]);
+ }
+ handler.invoke('editor.afterCommand', $editable);
+ }
+ };
+ };
+
+ return Clipboard;
+});
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Codeview.js b/addons/web_editor/static/lib/summernote/src/js/module/Codeview.js
new file mode 100644
index 00000000000..46f3d96ab12
--- /dev/null
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Codeview.js
@@ -0,0 +1,137 @@
+define([
+ 'summernote/core/agent',
+ 'summernote/core/dom'
+], function (agent, dom) {
+
+ var CodeMirror;
+ if (agent.hasCodeMirror) {
+ if (agent.isSupportAmd) {
+ require(['CodeMirror'], function (cm) {
+ CodeMirror = cm;
+ });
+ } else {
+ CodeMirror = window.CodeMirror;
+ }
+ }
+
+ /**
+ * @class Codeview
+ */
+ var Codeview = function (handler) {
+
+ this.sync = function (layoutInfo) {
+ var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);
+ if (isCodeview && agent.hasCodeMirror) {
+ layoutInfo.codable().data('cmEditor').save();
+ }
+ };
+
+ /**
+ * @param {Object} layoutInfo
+ * @return {Boolean}
+ */
+ this.isActivated = function (layoutInfo) {
+ var $editor = layoutInfo.editor();
+ return $editor.hasClass('codeview');
+ };
+
+ /**
+ * toggle codeview
+ *
+ * @param {Object} layoutInfo
+ */
+ this.toggle = function (layoutInfo) {
+ if (this.isActivated(layoutInfo)) {
+ this.deactivate(layoutInfo);
+ } else {
+ this.activate(layoutInfo);
+ }
+ };
+
+ /**
+ * activate code view
+ *
+ * @param {Object} layoutInfo
+ */
+ this.activate = 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');
+
+ $codable.val(dom.html($editable, options.prettifyHtml));
+ $codable.height($editable.height());
+
+ handler.invoke('toolbar.updateCodeview', $toolbar, true);
+ handler.invoke('popover.hide', $popover);
+ handler.invoke('handle.hide', $handle);
+
+ $editor.addClass('codeview');
+
+ $codable.focus();
+
+ // activate CodeMirror as codable
+ if (agent.hasCodeMirror) {
+ var cmEditor = CodeMirror.fromTextArea($codable[0], options.codemirror);
+
+ // CodeMirror TernServer
+ if (options.codemirror.tern) {
+ var 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);
+ }
+ };
+
+ /**
+ * deactivate code view
+ *
+ * @param {Object} layoutInfo
+ */
+ this.deactivate = function (layoutInfo) {
+ var $holder = layoutInfo.holder(),
+ $editor = layoutInfo.editor(),
+ $toolbar = layoutInfo.toolbar(),
+ $editable = layoutInfo.editable(),
+ $codable = layoutInfo.codable();
+
+ var options = $editor.data('options');
+
+ // deactivate CodeMirror as codable
+ if (agent.hasCodeMirror) {
+ var cmEditor = $codable.data('cmEditor');
+ $codable.val(cmEditor.getValue());
+ cmEditor.toTextArea();
+ }
+
+ var value = dom.value($codable, options.prettifyHtml) || dom.emptyPara;
+ var isChange = $editable.html() !== value;
+
+ $editable.html(value);
+ $editable.height(options.height ? $codable.height() : 'auto');
+ $editor.removeClass('codeview');
+
+ if (isChange) {
+ handler.bindCustomEvent(
+ $holder, $editable.data('callbacks'), 'change'
+ )($editable.html(), $editable);
+ }
+
+ $editable.focus();
+
+ handler.invoke('toolbar.updateCodeview', $toolbar, false);
+ };
+ };
+
+ return Codeview;
+});
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Dialog.js b/addons/web_editor/static/lib/summernote/src/js/module/Dialog.js
index 8e7cf07b323..d4f4d700218 100644
--- a/addons/web_editor/static/lib/summernote/src/js/module/Dialog.js
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Dialog.js
@@ -1,158 +1 @@
-define('summernote/module/Dialog', function () {
- /**
- * Dialog
- *
- * @class
- */
- var Dialog = function () {
-
- /**
- * toggle button status
- *
- * @param {jQuery} $btn
- * @param {Boolean} isEnable
- */
- var toggleBtn = function ($btn, isEnable) {
- $btn.toggleClass('disabled', !isEnable);
- $btn.attr('disabled', !isEnable);
- };
-
- /**
- * show image dialog
- *
- * @param {jQuery} $editable
- * @param {jQuery} $dialog
- * @return {Promise}
- */
- this.showImageDialog = function ($editable, $dialog) {
- return $.Deferred(function (deferred) {
- var $imageDialog = $dialog.find('.note-image-dialog');
-
- var $imageInput = $dialog.find('.note-image-input'),
- $imageUrl = $dialog.find('.note-image-url'),
- $imageBtn = $dialog.find('.note-image-btn');
-
- $imageDialog.one('shown.bs.modal', function () {
- // Cloning imageInput to clear element.
- $imageInput.replaceWith($imageInput.clone()
- .on('change', function () {
- deferred.resolve(this.files || this.value);
- $imageDialog.modal('hide');
- })
- .val('')
- );
-
- $imageBtn.click(function (event) {
- event.preventDefault();
-
- deferred.resolve($imageUrl.val());
- $imageDialog.modal('hide');
- });
-
- $imageUrl.on('keyup paste', function (event) {
- var url;
-
- if (event.type === 'paste') {
- url = event.originalEvent.clipboardData.getData('text');
- } else {
- url = $imageUrl.val();
- }
-
- toggleBtn($imageBtn, url);
- }).val('').trigger('focus');
- }).one('hidden.bs.modal', function () {
- $imageInput.off('change');
- $imageUrl.off('keyup paste');
- $imageBtn.off('click');
-
- if (deferred.state() === 'pending') {
- deferred.reject();
- }
- }).modal('show');
- });
- };
-
- /**
- * Show link dialog and set event handlers on dialog controls.
- *
- * @param {jQuery} $dialog
- * @param {Object} linkInfo
- * @return {Promise}
- */
- this.showLinkDialog = function ($editable, $dialog, linkInfo) {
- return $.Deferred(function (deferred) {
- var $linkDialog = $dialog.find('.note-link-dialog');
-
- var $linkText = $linkDialog.find('.note-link-text'),
- $linkUrl = $linkDialog.find('.note-link-url'),
- $linkBtn = $linkDialog.find('.note-link-btn'),
- $openInNewWindow = $linkDialog.find('input[type=checkbox]');
-
- $linkDialog.one('shown.bs.modal', function () {
- $linkText.val(linkInfo.text);
-
- $linkText.on('input', function () {
- // if linktext was modified by keyup,
- // stop cloning text from linkUrl
- linkInfo.text = $linkText.val();
- });
-
- // if no url was given, copy text to url
- if (!linkInfo.url) {
- linkInfo.url = linkInfo.text;
- toggleBtn($linkBtn, linkInfo.text);
- }
-
- $linkUrl.on('input', function () {
- toggleBtn($linkBtn, $linkUrl.val());
- // display same link on `Text to display` input
- // when create a new link
- if (!linkInfo.text) {
- $linkText.val($linkUrl.val());
- }
- }).val(linkInfo.url).trigger('focus').trigger('select');
-
- $openInNewWindow.prop('checked', linkInfo.newWindow);
-
- $linkBtn.one('click', function (event) {
- event.preventDefault();
-
- deferred.resolve({
- range: linkInfo.range,
- url: $linkUrl.val(),
- text: $linkText.val(),
- newWindow: $openInNewWindow.is(':checked')
- });
- $linkDialog.modal('hide');
- });
- }).one('hidden.bs.modal', function () {
- // detach events
- $linkText.off('input');
- $linkUrl.off('input');
- $linkBtn.off('click');
-
- if (deferred.state() === 'pending') {
- deferred.reject();
- }
- }).modal('show');
- }).promise();
- };
-
- /**
- * show help dialog
- *
- * @param {jQuery} $dialog
- */
- this.showHelpDialog = function ($editable, $dialog) {
- return $.Deferred(function (deferred) {
- var $helpDialog = $dialog.find('.note-help-dialog');
-
- $helpDialog.one('hidden.bs.modal', function () {
- deferred.resolve();
- }).modal('show');
- }).promise();
- };
- };
-
- return Dialog;
-});
+/** TODO master: drop this file (splitted in several files) */
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/DragAndDrop.js b/addons/web_editor/static/lib/summernote/src/js/module/DragAndDrop.js
new file mode 100644
index 00000000000..b8871599c6f
--- /dev/null
+++ b/addons/web_editor/static/lib/summernote/src/js/module/DragAndDrop.js
@@ -0,0 +1,98 @@
+define([
+ 'summernote/core/dom'
+], function (dom) {
+ var DragAndDrop = function (handler) {
+ var $document = $(document);
+
+ /**
+ * attach Drag and Drop Events
+ *
+ * @param {Object} layoutInfo - layout Informations
+ * @param {Object} options
+ */
+ this.attach = function (layoutInfo, options) {
+ if (options.airMode || options.disableDragAndDrop) {
+ // prevent default drop event
+ $document.on('drop', function (e) {
+ e.preventDefault();
+ });
+ } else {
+ this.attachDragAndDropEvent(layoutInfo, options);
+ }
+ };
+
+ /**
+ * attach Drag and Drop Events
+ *
+ * @param {Object} layoutInfo - layout Informations
+ * @param {Object} options
+ */
+ this.attachDragAndDropEvent = function (layoutInfo, options) {
+ var collection = $(),
+ $editor = layoutInfo.editor(),
+ $dropzone = layoutInfo.dropzone(),
+ $dropzoneMessage = $dropzone.find('.note-dropzone-message');
+
+ // show dropzone on dragenter when dragging a object to document
+ // -but only if the editor is visible, i.e. has a positive width and height
+ $document.on('dragenter', function (e) {
+ var isCodeview = handler.invoke('codeview.isActivated', layoutInfo);
+ var hasEditorSize = $editor.width() > 0 && $editor.height() > 0;
+ if (!isCodeview && !collection.length && hasEditorSize) {
+ $editor.addClass('dragover');
+ $dropzone.width($editor.width());
+ $dropzone.height($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) {
+ $editor.removeClass('dragover');
+ }
+ }).on('drop', function () {
+ collection = $();
+ $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) {
+
+ var dataTransfer = event.originalEvent.dataTransfer;
+ var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
+
+ if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
+ event.preventDefault();
+ layoutInfo.editable().focus();
+ handler.insertImages(layoutInfo, dataTransfer.files);
+ } else {
+ var insertNodefunc = function () {
+ layoutInfo.holder().summernote('insertNode', this);
+ };
+
+ for (var i = 0, len = dataTransfer.types.length; i < len; i++) {
+ var type = dataTransfer.types[i];
+ var content = dataTransfer.getData(type);
+
+ if (type.toLowerCase().indexOf('text') > -1) {
+ layoutInfo.holder().summernote('pasteHTML', content);
+ } else {
+ $(content).each(insertNodefunc);
+ }
+ }
+ }
+ }).on('dragover', false); // prevent default dragover event
+ };
+ };
+
+ return DragAndDrop;
+});
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Fullscreen.js b/addons/web_editor/static/lib/summernote/src/js/module/Fullscreen.js
new file mode 100644
index 00000000000..fd837483b3b
--- /dev/null
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Fullscreen.js
@@ -0,0 +1,51 @@
+define([], function () { // ODOO: remove error from Odoo define
+ var Fullscreen = function (handler) {
+ var $window = $(window);
+ var $scrollbar = $('html, body');
+
+ /**
+ * toggle fullscreen
+ *
+ * @param {Object} layoutInfo
+ */
+ this.toggle = 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');
+ }
+
+ handler.invoke('toolbar.updateFullscreen', $toolbar, isFullscreen);
+ };
+ };
+
+ return Fullscreen;
+});
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Handle.js b/addons/web_editor/static/lib/summernote/src/js/module/Handle.js
index 375428faa32..3b62304d706 100644
--- a/addons/web_editor/static/lib/summernote/src/js/module/Handle.js
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Handle.js
@@ -1,8 +1,60 @@
-define('summernote/module/Handle', function () {
+define([
+ 'summernote/core/dom'
+], function (dom) {
/**
+ * @class module.Handle
+ *
* Handle
*/
- var Handle = function () {
+ var Handle = function (handler) {
+ var $document = $(document);
+
+ /**
+ * `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 = dom.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) {
+ handler.invoke('editor.resizeTo', {
+ x: event.clientX - posStart.left,
+ y: event.clientY - (posStart.top - scrollTop)
+ }, $target, !event.shiftKey);
+
+ handler.invoke('handle.update', $handle, {image: target}, isAirMode);
+ handler.invoke('popover.update', $popover, {image: target}, isAirMode);
+ }).one('mouseup', function () {
+ $document.off('mousemove');
+ handler.invoke('editor.afterCommand', $editable);
+ });
+
+ if (!$target.data('ratio')) { // original ratio.
+ $target.data('ratio', $target.height() / $target.width());
+ }
+ }
+ };
+
+ this.attach = function (layoutInfo) {
+ layoutInfo.handle().on('mousedown', hHandleMousedown);
+ };
+
/**
* update handle
* @param {jQuery} $handle
@@ -35,6 +87,11 @@ define('summernote/module/Handle', function () {
}
};
+ /**
+ * hide
+ *
+ * @param {jQuery} $handle
+ */
this.hide = function ($handle) {
$handle.children().hide();
};
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/HelpDialog.js b/addons/web_editor/static/lib/summernote/src/js/module/HelpDialog.js
new file mode 100644
index 00000000000..e4ff7b775ed
--- /dev/null
+++ b/addons/web_editor/static/lib/summernote/src/js/module/HelpDialog.js
@@ -0,0 +1,35 @@
+define([], function () { // ODOO: remove error from Odoo define
+ var HelpDialog = function (handler) {
+ /**
+ * show help dialog
+ *
+ * @param {jQuery} $editable
+ * @param {jQuery} $dialog
+ * @return {Promise}
+ */
+ this.showHelpDialog = function ($editable, $dialog) {
+ return $.Deferred(function (deferred) {
+ var $helpDialog = $dialog.find('.note-help-dialog');
+
+ $helpDialog.one('hidden.bs.modal', function () {
+ deferred.resolve();
+ }).modal('show');
+ }).promise();
+ };
+
+ /**
+ * @param {Object} layoutInfo
+ */
+ this.show = function (layoutInfo) {
+ var $dialog = layoutInfo.dialog(),
+ $editable = layoutInfo.editable();
+
+ handler.invoke('editor.saveRange', $editable, true);
+ this.showHelpDialog($editable, $dialog).then(function () {
+ handler.invoke('editor.restoreRange', $editable);
+ });
+ };
+ };
+
+ return HelpDialog;
+});
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/ImageDialog.js b/addons/web_editor/static/lib/summernote/src/js/module/ImageDialog.js
new file mode 100644
index 00000000000..042921183cc
--- /dev/null
+++ b/addons/web_editor/static/lib/summernote/src/js/module/ImageDialog.js
@@ -0,0 +1,110 @@
+define([
+ 'summernote/core/key'
+], function (key) {
+ var ImageDialog = function (handler) {
+ /**
+ * toggle button status
+ *
+ * @private
+ * @param {jQuery} $btn
+ * @param {Boolean} isEnable
+ */
+ var toggleBtn = function ($btn, isEnable) {
+ $btn.toggleClass('disabled', !isEnable);
+ $btn.attr('disabled', !isEnable);
+ };
+
+ /**
+ * bind enter key
+ *
+ * @private
+ * @param {jQuery} $input
+ * @param {jQuery} $btn
+ */
+ var bindEnterKey = function ($input, $btn) {
+ $input.on('keypress', function (event) {
+ if (event.keyCode === key.code.ENTER) {
+ $btn.trigger('click');
+ }
+ });
+ };
+
+ this.show = function (layoutInfo) {
+ var $dialog = layoutInfo.dialog(),
+ $editable = layoutInfo.editable();
+
+ handler.invoke('editor.saveRange', $editable);
+ this.showImageDialog($editable, $dialog).then(function (data) {
+ handler.invoke('editor.restoreRange', $editable);
+
+ if (typeof data === 'string') {
+ // image url
+ handler.invoke('editor.insertImage', $editable, data);
+ } else {
+ // array of files
+ handler.insertImages(layoutInfo, data);
+ }
+ }).fail(function () {
+ handler.invoke('editor.restoreRange', $editable);
+ });
+ };
+
+ /**
+ * show image dialog
+ *
+ * @param {jQuery} $editable
+ * @param {jQuery} $dialog
+ * @return {Promise}
+ */
+ this.showImageDialog = function ($editable, $dialog) {
+ return $.Deferred(function (deferred) {
+ var $imageDialog = $dialog.find('.note-image-dialog');
+
+ var $imageInput = $dialog.find('.note-image-input'),
+ $imageUrl = $dialog.find('.note-image-url'),
+ $imageBtn = $dialog.find('.note-image-btn');
+
+ $imageDialog.one('shown.bs.modal', function () {
+ // Cloning imageInput to clear element.
+ $imageInput.replaceWith($imageInput.clone()
+ .on('change', function () {
+ deferred.resolve(this.files || this.value);
+ $imageDialog.modal('hide');
+ })
+ .val('')
+ );
+
+ $imageBtn.click(function (event) {
+ event.preventDefault();
+
+ deferred.resolve($imageUrl.val());
+ $imageDialog.modal('hide');
+ });
+
+ $imageUrl.on('keyup paste', function (event) {
+ var url;
+
+ if (event.type === 'paste') {
+ url = event.originalEvent.clipboardData.getData('text');
+ } else {
+ url = $imageUrl.val();
+ }
+
+ toggleBtn($imageBtn, url);
+ }).val('').trigger('focus');
+ bindEnterKey($imageUrl, $imageBtn);
+ }).one('hidden.bs.modal', function () {
+ $imageInput.off('change');
+ $imageUrl.off('keyup paste keypress');
+ $imageBtn.off('click');
+
+ if (deferred.state() === 'pending') {
+ deferred.reject();
+ }
+ }).modal('show');
+ });
+ };
+ };
+
+ return ImageDialog;
+});
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/LinkDialog.js b/addons/web_editor/static/lib/summernote/src/js/module/LinkDialog.js
new file mode 100644
index 00000000000..045119ee68a
--- /dev/null
+++ b/addons/web_editor/static/lib/summernote/src/js/module/LinkDialog.js
@@ -0,0 +1,129 @@
+define([
+ 'summernote/core/key'
+], function (key) {
+ var LinkDialog = function (handler) {
+
+ /**
+ * toggle button status
+ *
+ * @private
+ * @param {jQuery} $btn
+ * @param {Boolean} isEnable
+ */
+ var toggleBtn = function ($btn, isEnable) {
+ $btn.toggleClass('disabled', !isEnable);
+ $btn.attr('disabled', !isEnable);
+ };
+
+ /**
+ * bind enter key
+ *
+ * @private
+ * @param {jQuery} $input
+ * @param {jQuery} $btn
+ */
+ var bindEnterKey = function ($input, $btn) {
+ $input.on('keypress', function (event) {
+ if (event.keyCode === key.code.ENTER) {
+ $btn.trigger('click');
+ }
+ });
+ };
+
+ /**
+ * Show link dialog and set event handlers on dialog controls.
+ *
+ * @param {jQuery} $editable
+ * @param {jQuery} $dialog
+ * @param {Object} linkInfo
+ * @return {Promise}
+ */
+ this.showLinkDialog = function ($editable, $dialog, linkInfo) {
+ return $.Deferred(function (deferred) {
+ var $linkDialog = $dialog.find('.note-link-dialog');
+
+ var $linkText = $linkDialog.find('.note-link-text'),
+ $linkUrl = $linkDialog.find('.note-link-url'),
+ $linkBtn = $linkDialog.find('.note-link-btn'),
+ $openInNewWindow = $linkDialog.find('input[type=checkbox]');
+
+ $linkDialog.one('shown.bs.modal', function () {
+ $linkText.val(linkInfo.text);
+
+ $linkText.on('input', function () {
+ toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());
+ // if linktext was modified by keyup,
+ // stop cloning text from linkUrl
+ linkInfo.text = $linkText.val();
+ });
+
+ // if no url was given, copy text to url
+ if (!linkInfo.url) {
+ linkInfo.url = linkInfo.text || 'http://';
+ toggleBtn($linkBtn, linkInfo.text);
+ }
+
+ $linkUrl.on('input', function () {
+ toggleBtn($linkBtn, $linkText.val() && $linkUrl.val());
+ // display same link on `Text to display` input
+ // when create a new link
+ if (!linkInfo.text) {
+ $linkText.val($linkUrl.val());
+ }
+ }).val(linkInfo.url).trigger('focus').trigger('select');
+
+ bindEnterKey($linkUrl, $linkBtn);
+ bindEnterKey($linkText, $linkBtn);
+
+ $openInNewWindow.prop('checked', linkInfo.isNewWindow);
+
+ $linkBtn.one('click', function (event) {
+ event.preventDefault();
+
+ deferred.resolve({
+ range: linkInfo.range,
+ url: $linkUrl.val(),
+ text: $linkText.val(),
+ isNewWindow: $openInNewWindow.is(':checked')
+ });
+ $linkDialog.modal('hide');
+ });
+ }).one('hidden.bs.modal', function () {
+ // detach events
+ $linkText.off('input keypress');
+ $linkUrl.off('input keypress');
+ $linkBtn.off('click');
+
+ if (deferred.state() === 'pending') {
+ deferred.reject();
+ }
+ }).modal('show');
+ }).promise();
+ };
+
+ /**
+ * @param {Object} layoutInfo
+ */
+ this.show = function (layoutInfo) {
+ var $editor = layoutInfo.editor(),
+ $dialog = layoutInfo.dialog(),
+ $editable = layoutInfo.editable(),
+ $popover = layoutInfo.popover(),
+ linkInfo = handler.invoke('editor.getLinkInfo', $editable);
+
+ var options = $editor.data('options');
+
+ handler.invoke('editor.saveRange', $editable);
+ this.showLinkDialog($editable, $dialog, linkInfo).then(function (linkInfo) {
+ handler.invoke('editor.restoreRange', $editable);
+ handler.invoke('editor.createLink', $editable, linkInfo, options);
+ // hide popover after creating link
+ handler.invoke('popover.hide', $popover);
+ }).fail(function () {
+ handler.invoke('editor.restoreRange', $editable);
+ });
+ };
+ };
+
+ return LinkDialog;
+});
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Popover.js b/addons/web_editor/static/lib/summernote/src/js/module/Popover.js
index e0531f06c45..f669569f6ba 100644
--- a/addons/web_editor/static/lib/summernote/src/js/module/Popover.js
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Popover.js
@@ -4,22 +4,32 @@ define([
'summernote/module/Button'
], function (func, list, Button) {
/**
+ * @class module.Popover
+ *
* Popover (http://getbootstrap.com/javascript/#popovers)
+ *
*/
var Popover = function () {
var button = new Button();
- this.button = button; // odoo change for overwrite
+ this.button = button; // ODOO: allow access for override
/**
* returns position from placeholder
+ *
+ * @private
* @param {Node} placeholder
- * @param {Boolean} isAirMode
+ * @param {Object} options
+ * @param {Boolean} options.isAirMode
+ * @return {Position}
*/
- var posFromPlaceholder = function (placeholder, isAirMode) {
+ var posFromPlaceholder = function (placeholder, options) {
+ var isAirMode = options && options.isAirMode;
+ var isLeftTop = options && options.isLeftTop;
+
var $placeholder = $(placeholder);
var pos = isAirMode ? $placeholder.offset() : $placeholder.position();
- var height = $placeholder.outerHeight(true); // include margin
+ var height = isLeftTop ? 0 : $placeholder.outerHeight(true); // include margin
// popover below placeholder.
return {
@@ -30,6 +40,8 @@ define([
/**
* show popover
+ *
+ * @private
* @param {jQuery} popover
* @param {Position} pos
*/
@@ -56,21 +68,32 @@ define([
if (styleInfo.anchor) {
var $anchor = $linkPopover.find('a');
var href = $(styleInfo.anchor).attr('href');
+ var target = $(styleInfo.anchor).attr('target');
$anchor.attr('href', href).html(href);
- showPopover($linkPopover, posFromPlaceholder(styleInfo.anchor, isAirMode));
+ if (!target) {
+ $anchor.removeAttr('target');
+ } else {
+ $anchor.attr('target', '_blank');
+ }
+ showPopover($linkPopover, posFromPlaceholder(styleInfo.anchor, {
+ isAirMode: isAirMode
+ }));
} else {
$linkPopover.hide();
}
var $imagePopover = $popover.find('.note-image-popover');
if (styleInfo.image) {
- showPopover($imagePopover, posFromPlaceholder(styleInfo.image, isAirMode));
+ showPopover($imagePopover, posFromPlaceholder(styleInfo.image, {
+ isAirMode: isAirMode,
+ isLeftTop: true
+ }));
} else {
$imagePopover.hide();
}
var $airPopover = $popover.find('.note-air-popover');
- if (isAirMode && !styleInfo.range.isCollapsed()) {
+ if (isAirMode && styleInfo.range && !styleInfo.range.isCollapsed()) {
var rect = list.last(styleInfo.range.getClientRects());
if (rect) {
var bnd = func.rect2bnd(rect);
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Statusbar.js b/addons/web_editor/static/lib/summernote/src/js/module/Statusbar.js
new file mode 100644
index 00000000000..b50fce458eb
--- /dev/null
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Statusbar.js
@@ -0,0 +1,44 @@
+define([
+ 'summernote/core/dom'
+], function (dom) {
+ var EDITABLE_PADDING = 24;
+
+ var Statusbar = function () {
+ var $document = $(document);
+
+ this.attach = function (layoutInfo, options) {
+ if (!options.disableResizeEditor) {
+ layoutInfo.statusbar().on('mousedown', hStatusbarMousedown);
+ }
+ };
+
+ /**
+ * `mousedown` event handler on statusbar
+ *
+ * @param {MouseEvent} event
+ */
+ var hStatusbarMousedown = function (event) {
+ event.preventDefault();
+ event.stopPropagation();
+
+ var $editable = dom.makeLayoutInfo(event.target).editable();
+ var editableTop = $editable.offset().top - $document.scrollTop();
+
+ var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
+ var options = layoutInfo.editor().data('options');
+
+ $document.on('mousemove', function (event) {
+ var nHeight = event.clientY - (editableTop + EDITABLE_PADDING);
+
+ nHeight = (options.minHeight > 0) ? Math.max(nHeight, options.minHeight) : nHeight;
+ nHeight = (options.maxHeight > 0) ? Math.min(nHeight, options.maxHeight) : nHeight;
+
+ $editable.height(nHeight);
+ }).one('mouseup', function () {
+ $document.off('mousemove');
+ });
+ };
+ };
+
+ return Statusbar;
+});
diff --git a/addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js b/addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js
index 832b7c4c561..5e5e5721b63 100644
--- a/addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js
+++ b/addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js
@@ -1,14 +1,17 @@
define([
'summernote/core/list',
+ 'summernote/core/dom',
'summernote/module/Button'
-], function (list, Button) {
+], function (list, dom, Button) {
/**
+ * @class module.Toolbar
+ *
* Toolbar
*/
var Toolbar = function () {
var button = new Button();
- this.button = button; // odoo change for overwrite
+ this.button = button; // ODOO: allow access for override
this.update = function ($toolbar, styleInfo) {
button.update($toolbar, styleInfo);
@@ -43,14 +46,54 @@ define([
.addClass('disabled');
};
+ /**
+ * @param {jQuery} $container
+ * @param {Boolean} [bFullscreen=false]
+ */
this.updateFullscreen = function ($container, bFullscreen) {
var $btn = $container.find('button[data-event="fullscreen"]');
$btn.toggleClass('active', bFullscreen);
};
+ /**
+ * @param {jQuery} $container
+ * @param {Boolean} [isCodeview=false]
+ */
this.updateCodeview = function ($container, isCodeview) {
var $btn = $container.find('button[data-event="codeview"]');
$btn.toggleClass('active', isCodeview);
+
+ if (isCodeview) {
+ this.deactivate($container);
+ } else {
+ this.activate($container);
+ }
+ };
+
+ /**
+ * get button in toolbar
+ *
+ * @param {jQuery} $editable
+ * @param {String} name
+ * @return {jQuery}
+ */
+ this.get = function ($editable, name) {
+ var $toolbar = dom.makeLayoutInfo($editable).toolbar();
+
+ return $toolbar.find('[data-name=' + name + ']');
+ };
+
+ /**
+ * set button state
+ * @param {jQuery} $editable
+ * @param {String} name
+ * @param {Boolean} [isActive=true]
+ */
+ this.setButtonState = function ($editable, name, isActive) {
+ isActive = (isActive === false) ? false : true;
+
+ var $button = this.get($editable, name);
+ $button.toggleClass('active', isActive);
};
};