diff --git a/addons/web_editor/__manifest__.py b/addons/web_editor/__manifest__.py
index da793f5ea9f..df13365c6a2 100644
--- a/addons/web_editor/__manifest__.py
+++ b/addons/web_editor/__manifest__.py
@@ -26,7 +26,6 @@ Odoo Web Editor widget.
'web_editor/static/src/xml/*.xml',
],
'web_editor.assets_wysiwyg': [
- ('include', 'web_editor.assets_summernote'),
# lib
'web_editor/static/lib/cropperjs/cropper.css',
@@ -50,8 +49,6 @@ Odoo Web Editor widget.
'web_editor/static/src/js/wysiwyg/fonts.js',
'web_editor/static/src/js/base.js',
'web_editor/static/src/js/editor/editor.js',
- 'web_editor/static/src/js/editor/rte.js',
- 'web_editor/static/src/js/editor/rte.summernote.js',
'web_editor/static/src/js/editor/image_processing.js',
# widgets & plugins
@@ -64,43 +61,6 @@ Odoo Web Editor widget.
'web_editor/static/src/js/wysiwyg/wysiwyg_snippets.js',
'web_editor/static/src/js/wysiwyg/wysiwyg_iframe.js',
],
- 'web_editor.assets_summernote': [
- 'web_editor/static/src/js/editor/summernote_import_start.js',
-
- 'web_editor/static/lib/summernote/src/css/**/*',
- 'web_editor/static/lib/summernote/src/js/core/async.js',
- 'web_editor/static/lib/summernote/src/js/core/func.js',
- 'web_editor/static/lib/summernote/src/js/core/agent.js',
- 'web_editor/static/lib/summernote/src/js/core/list.js',
- 'web_editor/static/lib/summernote/src/js/core/dom.js',
- 'web_editor/static/lib/summernote/src/js/core/key.js',
- 'web_editor/static/lib/summernote/src/js/core/range.js',
- 'web_editor/static/lib/summernote/src/js/editing/Bullet.js',
- 'web_editor/static/lib/summernote/src/js/editing/History.js',
- 'web_editor/static/lib/summernote/src/js/editing/Style.js',
- 'web_editor/static/lib/summernote/src/js/editing/Table.js',
- 'web_editor/static/lib/summernote/src/js/editing/Typing.js',
- 'web_editor/static/lib/summernote/src/js/module/Editor.js',
- 'web_editor/static/lib/summernote/src/js/module/Button.js',
- 'web_editor/static/lib/summernote/src/js/module/Clipboard.js',
- 'web_editor/static/lib/summernote/src/js/module/Codeview.js',
- 'web_editor/static/lib/summernote/src/js/module/DragAndDrop.js',
- 'web_editor/static/lib/summernote/src/js/module/Fullscreen.js',
- 'web_editor/static/lib/summernote/src/js/module/Handle.js',
- 'web_editor/static/lib/summernote/src/js/module/HelpDialog.js',
- 'web_editor/static/lib/summernote/src/js/module/ImageDialog.js',
- 'web_editor/static/lib/summernote/src/js/module/LinkDialog.js',
- 'web_editor/static/lib/summernote/src/js/module/Popover.js',
- 'web_editor/static/lib/summernote/src/js/module/Statusbar.js',
- 'web_editor/static/lib/summernote/src/js/module/Toolbar.js',
- 'web_editor/static/lib/summernote/src/js/Renderer.js',
- 'web_editor/static/lib/summernote/src/js/EventHandler.js',
- 'web_editor/static/lib/summernote/src/js/defaults.js',
- 'web_editor/static/lib/summernote/src/js/summernote.js',
-
- 'web_editor/static/src/js/editor/summernote_import_end.js',
- 'web_editor/static/src/js/editor/summernote.js',
- ],
'web.assets_common': [
'web_editor/static/lib/vkbeautify/**/*',
'web_editor/static/src/js/common/**/*',
@@ -145,8 +105,6 @@ Odoo Web Editor widget.
# ----------------------------------------------------------------------
'web.qunit_suite_tests': [
- 'web_editor/static/src/js/wysiwyg/test_root.js',
-
('include', 'web_editor.assets_wysiwyg'),
'web_editor/static/tests/**/*',
diff --git a/addons/web_editor/static/lib/summernote/src/css/summernote.css b/addons/web_editor/static/lib/summernote/src/css/summernote.css
deleted file mode 100644
index 7604c9272de..00000000000
--- a/addons/web_editor/static/lib/summernote/src/css/summernote.css
+++ /dev/null
@@ -1,447 +0,0 @@
-/* Theme Variables
- ------------------------------------------*/
-/* Frame Mode Layout
- ------------------------------------------*/
-.note-editor {
- border: 1px solid #a9a9a9;
- position: relative;
- /* overflow: hidden; ODOO: removed for embedded editor */
- /* dropzone */
- /* codeview mode */
- /* fullscreen mode */
- /* statusbar */
-}
-.note-editor .note-dropzone {
- position: absolute;
- display: none;
- z-index: 100;
- color: lightskyblue;
- background-color: white;
- opacity: 0.95;
- pointer-event: none;
-}
-.note-editor .note-dropzone .note-dropzone-message {
- display: table-cell;
- vertical-align: middle;
- text-align: center;
- font-size: 28px;
- font-weight: bold;
-}
-.note-editor .note-dropzone.hover {
- color: #098ddf;
-}
-.note-editor.dragover .note-dropzone {
- display: table;
-}
-.note-editor.codeview .note-editing-area .note-editable {
- display: none;
-}
-.note-editor.codeview .note-editing-area .note-codable {
- display: block;
-}
-.note-editor.fullscreen {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- z-index: 1050;
- /* bs3 modal-backdrop: 1030, bs2: 1040 */
-}
-.note-editor.fullscreen .note-editable {
- background-color: white;
-}
-.note-editor.fullscreen .note-resizebar {
- display: none;
-}
-.note-editor .note-editing-area {
- position: relative;
- overflow: hidden;
- /* editable */
- /* codeable */
-}
-.note-editor .note-editing-area .note-editable {
- background-color: #fff;
- color: #000;
- padding: 10px;
- overflow: auto;
- outline: none;
-}
-.note-editor .note-editing-area .note-editable[contenteditable=true]:empty:not(:focus):before {
- content: attr(data-placeholder);
-}
-.note-editor .note-editing-area .note-editable[contenteditable="false"] {
- background-color: #e5e5e5;
-}
-.note-editor .note-editing-area .note-codable {
- display: none;
- width: 100%;
- padding: 10px;
- border: none;
- box-shadow: none;
- font-family: Menlo, Monaco, monospace, sans-serif;
- font-size: 14px;
- color: #ccc;
- background-color: #222;
- resize: none;
- /* override BS2 default style */
- box-sizing: border-box;
- border-radius: 0;
- margin-bottom: 0;
-}
-.note-editor .note-statusbar {
- background-color: #f5f5f5;
-}
-.note-editor .note-statusbar .note-resizebar {
- padding-top: 1px;
- height: 8px;
- width: 100%;
- cursor: ns-resize;
-}
-.note-editor .note-statusbar .note-resizebar .note-icon-bar {
- width: 20px;
- margin: 1px auto;
- border-top: 1px solid #a9a9a9;
-}
-/* Air Mode Layout
-------------------------------------------*/
-.note-air-editor {
- outline: none;
-}
-/* Popover
-------------------------------------------*/
-.note-popover .popover {
- max-width: none;
-}
-.note-popover .popover .popover-body a {
- display: inline-block;
- max-width: 200px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- /* for FF */
- vertical-align: middle;
- /* for FF */
-}
-.note-popover .popover .arrow {
- left: 20px;
-}
-/* Popover and Toolbar (Button container)
-------------------------------------------*/
-.note-popover .popover .popover-body,
-.panel-heading.note-toolbar {
- margin: 0;
- padding: 0 0 5px 5px;
- /* dropdown-menu for toolbar and popover */
- /* color palette for toolbar and popover */
-}
-.note-popover .popover .popover-body > .btn-group,
-.panel-heading.note-toolbar > .btn-group {
- margin-top: 5px;
- margin-left: 0;
- margin-right: 5px;
-}
-.note-popover .popover .popover-body .btn-group .note-table,
-.panel-heading.note-toolbar .btn-group .note-table {
- min-width: 0;
- padding: 5px;
-}
-.note-popover .popover .popover-body .btn-group .note-table .note-dimension-picker,
-.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker {
- font-size: 18px;
-}
-.note-popover .popover .popover-body .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher,
-.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-mousecatcher {
- position: absolute !important;
- z-index: 3;
- width: 10em;
- height: 10em;
- cursor: pointer;
-}
-.note-popover .popover .popover-body .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted,
-.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-unhighlighted {
- position: relative !important;
- z-index: 1;
- width: 5em;
- height: 5em;
- background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat;
-}
-.note-popover .popover .popover-body .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted,
-.panel-heading.note-toolbar .btn-group .note-table .note-dimension-picker .note-dimension-picker-highlighted {
- position: absolute !important;
- z-index: 2;
- width: 1em;
- height: 1em;
- background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat;
-}
-.note-popover .popover .popover-body .note-style h1,
-.panel-heading.note-toolbar .note-style h1,
-.note-popover .popover .popover-body .note-style h2,
-.panel-heading.note-toolbar .note-style h2,
-.note-popover .popover .popover-body .note-style h3,
-.panel-heading.note-toolbar .note-style h3,
-.note-popover .popover .popover-body .note-style h4,
-.panel-heading.note-toolbar .note-style h4,
-.note-popover .popover .popover-body .note-style h5,
-.panel-heading.note-toolbar .note-style h5,
-.note-popover .popover .popover-body .note-style h6,
-.panel-heading.note-toolbar .note-style h6,
-.note-popover .popover .popover-body .note-style blockquote,
-.panel-heading.note-toolbar .note-style blockquote {
- margin: 0;
-}
-.note-popover .popover .popover-body .note-color .dropdown-toggle,
-.panel-heading.note-toolbar .note-color .dropdown-toggle {
- width: 20px;
- padding-left: 5px;
-}
-.note-popover .popover .popover-body .note-color .dropdown-menu,
-.panel-heading.note-toolbar .note-color .dropdown-menu {
- min-width: 340px;
-}
-.note-popover .popover .popover-body .note-color .dropdown-menu .btn-group,
-.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group {
- margin: 0;
-}
-.note-popover .popover .popover-body .note-color .dropdown-menu .btn-group:first-child,
-.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group:first-child {
- margin: 0 5px;
-}
-.note-popover .popover .popover-body .note-color .dropdown-menu .btn-group .note-palette-title,
-.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title {
- font-size: 12px;
- margin: 2px 7px;
- text-align: center;
- border-bottom: 1px solid #eee;
-}
-.note-popover .popover .popover-body .note-color .dropdown-menu .btn-group .note-color-reset,
-.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset {
- font-size: 11px;
- margin: 3px;
- padding: 0 3px;
- cursor: pointer;
- border-radius: 5px;
-}
-.note-popover .popover .popover-body .note-color .dropdown-menu .btn-group .note-color-row,
-.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-row {
- height: 20px;
-}
-.note-popover .popover .popover-body .note-color .dropdown-menu .btn-group .note-color-reset:hover,
-.panel-heading.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover {
- background: #eee;
-}
-.note-popover .popover .popover-body .note-para .dropdown-menu,
-.panel-heading.note-toolbar .note-para .dropdown-menu {
- min-width: 216px;
- padding: 5px;
-}
-.note-popover .popover .popover-body .note-para .dropdown-menu > div:first-child,
-.panel-heading.note-toolbar .note-para .dropdown-menu > div:first-child {
- margin-right: 5px;
-}
-.note-popover .popover .popover-body .dropdown-menu,
-.panel-heading.note-toolbar .dropdown-menu {
- min-width: 90px;
- /* dropdown-menu right position */
- /* http://forrst.com/posts/Bootstrap_right_positioned_dropdown-2KB */
- /* dropdown-menu for selectbox */
-}
-.note-popover .popover .popover-body .dropdown-menu.right,
-.panel-heading.note-toolbar .dropdown-menu.right {
- right: 0;
- left: auto;
-}
-.note-popover .popover .popover-body .dropdown-menu.right::before,
-.panel-heading.note-toolbar .dropdown-menu.right::before {
- right: 9px;
- left: auto !important;
-}
-.note-popover .popover .popover-body .dropdown-menu.right::after,
-.panel-heading.note-toolbar .dropdown-menu.right::after {
- right: 10px;
- left: auto !important;
-}
-.note-popover .popover .popover-body .dropdown-menu.note-check li a i,
-.panel-heading.note-toolbar .dropdown-menu.note-check li a i {
- color: deepskyblue;
- visibility: hidden;
-}
-.note-popover .popover .popover-body .dropdown-menu.note-check li a.checked i,
-.panel-heading.note-toolbar .dropdown-menu.note-check li a.checked i {
- visibility: visible;
-}
-.note-popover .popover .popover-body .note-fontsize-10,
-.panel-heading.note-toolbar .note-fontsize-10 {
- font-size: 10px;
-}
-.note-popover .popover .popover-body .note-color-palette,
-.panel-heading.note-toolbar .note-color-palette {
- line-height: 1;
-}
-.note-popover .popover .popover-body .note-color-palette div .note-color-btn,
-.panel-heading.note-toolbar .note-color-palette div .note-color-btn {
- width: 20px;
- height: 20px;
- padding: 0;
- margin: 0;
- border: 1px solid #fff;
-}
-.note-popover .popover .popover-body .note-color-palette div .note-color-btn:hover,
-.panel-heading.note-toolbar .note-color-palette div .note-color-btn:hover {
- border: 1px solid #000;
-}
-/* Dialog
-------------------------------------------*/
-.note-dialog > div {
- display: none;
- /* BS2's hide pacth. */
-}
-.note-dialog .form-group {
- /* overwrite BS's form-horizontal minus margins */
- margin-left: 0;
- margin-right: 0;
-}
-.note-dialog .note-modal-form {
- margin: 0;
- /* overwrite BS2's form margin bottom */
-}
-.note-dialog .note-image-dialog .note-dropzone {
- min-height: 100px;
- font-size: 30px;
- line-height: 4;
- /* vertical-align */
- color: lightgray;
- text-align: center;
- border: 4px dashed lightgray;
- margin-bottom: 10px;
-}
-.note-dialog .note-help-dialog {
- font-size: 12px;
- color: #ccc;
- background-color: #222 !important;
- opacity: 0.9;
- /* BS2's background pacth. */
- background: transparent;
- border: none;
-}
-.note-dialog .note-help-dialog .modal-content {
- background: transparent;
- border: 1px solid white;
- box-shadow: none;
- border-radius: 5px;
-}
-.note-dialog .note-help-dialog a {
- font-size: 12px;
- color: white;
-}
-.note-dialog .note-help-dialog .title {
- color: white;
- font-size: 14px;
- font-weight: bold;
- padding-bottom: 5px;
- margin-bottom: 10px;
- border-bottom: white 1px solid;
-}
-.note-dialog .note-help-dialog .modal-close {
- font-size: 14px;
- color: #dd0;
- cursor: pointer;
-}
-.note-dialog .note-help-dialog .text-center {
- margin: 10px 0 0;
-}
-.note-dialog .note-help-dialog .note-shortcut {
- padding-top: 8px;
- padding-bottom: 8px;
-}
-.note-dialog .note-help-dialog .note-shortcut-row {
- margin-right: -5px;
- margin-left: -5px;
-}
-.note-dialog .note-help-dialog .note-shortcut-col {
- padding-right: 5px;
- padding-left: 5px;
-}
-.note-dialog .note-help-dialog .note-shortcut-title {
- font-size: 13px;
- font-weight: bold;
- color: #dd0;
-}
-.note-dialog .note-help-dialog .note-shortcut-key {
- font-family: "Courier New";
- color: #dd0;
- text-align: right;
-}
-/* Handle
-------------------------------------------*/
-.note-handle {
- /* control selection */
-}
-.note-handle .note-control-selection {
- position: absolute;
- display: none;
- border: 1px solid black;
-}
-.note-handle .note-control-selection > div {
- position: absolute;
-}
-.note-handle .note-control-selection .note-control-selection-bg {
- width: 100%;
- height: 100%;
- background-color: black;
- opacity: 0.3;
-}
-.note-handle .note-control-selection .note-control-handle {
- width: 7px;
- height: 7px;
- border: 1px solid black;
-}
-.note-handle .note-control-selection .note-control-holder {
- width: 7px;
- height: 7px;
- border: 1px solid black;
-}
-.note-handle .note-control-selection .note-control-sizing {
- width: 7px;
- height: 7px;
- border: 1px solid black;
- background-color: white;
-}
-.note-handle .note-control-selection .note-control-nw {
- top: -5px;
- left: -5px;
- border-right: none;
- border-bottom: none;
-}
-.note-handle .note-control-selection .note-control-ne {
- top: -5px;
- right: -5px;
- border-bottom: none;
- border-left: none;
-}
-.note-handle .note-control-selection .note-control-sw {
- bottom: -5px;
- left: -5px;
- border-top: none;
- border-right: none;
-}
-.note-handle .note-control-selection .note-control-se {
- right: -5px;
- bottom: -5px;
- cursor: se-resize;
-}
-.note-handle .note-control-selection .note-control-se.note-control-holder {
- cursor: default;
- border-top: none;
- border-left: none;
-}
-.note-handle .note-control-selection .note-control-selection-info {
- right: 0;
- bottom: 0;
- padding: 5px;
- margin: 5px;
- color: white;
- background-color: black;
- font-size: 12px;
- border-radius: 5px;
- opacity: 0.7;
-}
diff --git a/addons/web_editor/static/lib/summernote/src/js/EventHandler.js b/addons/web_editor/static/lib/summernote/src/js/EventHandler.js
deleted file mode 100644
index a1243c6f30d..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/EventHandler.js
+++ /dev/null
@@ -1,572 +0,0 @@
-define([
- '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 self = this;
-
- /**
- * 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)
- };
-
- /**
- * invoke module's method
- *
- * @param {String} moduleAndMethod - ex) 'editor.redo'
- * @param {...*} arguments - arguments of method
- * @return {*}
- */
- this.invoke = function () {
- var moduleAndMethod = list.head(list.from(arguments));
- var args = list.tail(list.from(arguments));
-
- 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 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;
- };
-
- /**
- * @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
- */
- this.insertImages = function (layoutInfo, files) {
- var $editor = layoutInfo.editor(),
- $editable = layoutInfo.editable(),
- $holder = layoutInfo.holder();
-
- var callbacks = $editable.data('callbacks');
- var options = $editor.data('options');
-
- // If onImageUpload options setted
- if (callbacks.onImageUpload) {
- 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) {
- bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);
- } else {
- async.readFileAsDataURL(file).then(function (sDataURL) {
- modules.editor.insertImage($editable, sDataURL, filename);
- }).fail(function () {
- bindCustomEvent($holder, callbacks, 'image.upload.error')(options.langInfo.image.maximumFileSizeError);
- });
- }
- });
- }
- };
-
- var commands = {
- /**
- * @param {Object} layoutInfo
- */
- showLinkDialog: function (layoutInfo) {
- modules.linkDialog.show(layoutInfo);
- },
-
- /**
- * @param {Object} layoutInfo
- */
- showImageDialog: function (layoutInfo) {
- modules.imageDialog.show(layoutInfo);
- },
-
- /**
- * @param {Object} layoutInfo
- */
- showHelpDialog: function (layoutInfo) {
- modules.helpDialog.show(layoutInfo);
- },
-
- /**
- * @param {Object} layoutInfo
- */
- fullscreen: function (layoutInfo) {
- modules.fullscreen.toggle(layoutInfo);
- },
-
- /**
- * @param {Object} layoutInfo
- */
- codeview: function (layoutInfo) {
- modules.codeview.toggle(layoutInfo);
- }
- };
-
- var hMousedown = function (event) {
- //preventDefault Selection for FF, IE8+
- if (dom.isImg(event.target)) {
- event.preventDefault();
- }
- };
-
- var hKeyupAndMouseup = function (event) {
- var layoutInfo = dom.makeLayoutInfo(event.currentTarget || event.target);
- modules.editor.removeBogus(layoutInfo.editable());
- hToolbarAndPopoverUpdate(event);
- };
-
- /**
- * update sytle info
- * @param {Object} styleInfo
- * @param {Object} layoutInfo
- */
- this.updateStyleInfo = function (styleInfo, layoutInfo) {
- if (!styleInfo) {
- return;
- }
- var isAirMode = (layoutInfo.editor().data('options') || {}).airMode;
- if (!isAirMode) {
- modules.toolbar.update(layoutInfo.toolbar(), styleInfo);
- }
-
- modules.popover.update(layoutInfo.popover(), styleInfo, isAirMode);
- modules.handle.update(layoutInfo.handle(), styleInfo, isAirMode);
- };
-
- var hToolbarAndPopoverUpdate = function (event) {
- var target = event.target;
- // delay for range after mouseup
- setTimeout(function () {
- var layoutInfo = dom.makeLayoutInfo(target);
- /* ODOO: (start_modification */
- if (!layoutInfo) {
- return;
- }
- var $editable = layoutInfo.editable();
- if (event.setStyleInfoFromEditable) {
- var styleInfo = modules.editor.styleFromNode($editable);
- } else {
- if (!event.isDefaultPrevented()) {
- modules.editor.saveRange($editable);
- }
- var styleInfo = modules.editor.currentStyle(target);
- }
- /* ODOO: end_modification) */
- 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) {
- // prevent default event when insertTable (FF, Webkit)
- var $btn = $(event.target).closest('[data-event]');
- if ($btn.length) {
- event.preventDefault();
- }
- };
-
- var hToolbarAndPopoverClick = function (event) {
- var $btn = $(event.target).closest('[data-event]');
-
- if (!$btn.length) {
- return;
- }
-
- var eventName = $btn.attr('data-event'),
- value = $btn.attr('data-value'),
- hide = $btn.attr('data-hide');
-
- var layoutInfo = dom.makeLayoutInfo(event.target);
-
- // 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 ($.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();
- }
-
- // 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);
- }
-
- hToolbarAndPopoverUpdate(event);
- };
-
- var PX_PER_EM = 18;
- var hDimensionPickerMove = function (event, options) {
- var $picker = $(event.target.parentNode); // target is mousecatcher
- var $dimensionDisplay = $picker.next();
- var $catcher = $picker.find('.note-dimension-picker-mousecatcher');
- var $highlighted = $picker.find('.note-dimension-picker-highlighted');
- var $unhighlighted = $picker.find('.note-dimension-picker-unhighlighted');
-
- var posOffset;
- // HTML5 with jQuery - e.offsetX is undefined in Firefox
- if (event.offsetX === undefined) {
- var posCatcher = $(event.target).offset();
- posOffset = {
- x: event.pageX - posCatcher.left,
- y: event.pageY - posCatcher.top
- };
- } else {
- posOffset = {
- x: event.offsetX,
- y: event.offsetY
- };
- }
-
- var dim = {
- c: Math.ceil(posOffset.x / PX_PER_EM) || 1,
- r: Math.ceil(posOffset.y / PX_PER_EM) || 1
- };
-
- $highlighted.css({ width: dim.c + 'em', height: dim.r + 'em' });
- $catcher.attr('data-value', dim.c + 'x' + dim.r);
-
- if (3 < dim.c && dim.c < options.insertTableMaxSize.col) {
- $unhighlighted.css({ width: dim.c + 1 + 'em'});
- }
-
- if (3 < dim.r && dim.r < options.insertTableMaxSize.row) {
- $unhighlighted.css({ height: dim.r + 1 + 'em'});
- }
-
- $dimensionDisplay.html(dim.c + ' x ' + dim.r);
- };
-
- /**
- * bind KeyMap on keydown
- *
- * @param {Object} layoutInfo
- * @param {Object} keyMap
- */
- this.bindKeyMap = function (layoutInfo, keyMap) {
- var $editor = layoutInfo.editor();
- var $editable = layoutInfo.editable();
-
- $editable.on('keydown', function (event) {
- var keys = [];
-
- // modifier
- 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) {
- keys.push(keyName);
- }
-
- 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 &&
- !event.ctrlKey && !event.metaKey && ( // special code/command
- (keycode > 47 && keycode < 58) || // number keys
- keycode == 32 || keycode == 13 || // spacebar & return
- (keycode > 64 && keycode < 91) || // letter keys
- (keycode > 95 && keycode < 112) || // numpad keys
- (keycode > 185 && keycode < 193) || // ;=,-./` (in order)
- (keycode > 218 && keycode < 223))) { // [\]' (in order))
- eventName = 'visible';
- } else if (!keycode && event.key !== 'Dead') {
- self.invoke('restoreRange', $editable);
- }
- // ODOO: end_modification)
-
- if (eventName) {
- // 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;
- }
- }
-
- 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();
- }
- } else if (key.isEdit(event.keyCode)) {
- modules.editor.afterCommand($editable);
- }
- });
- };
-
- /**
- * attach eventhandler
- *
- * @param {Object} layoutInfo - layout Informations
- * @param {Object} options - user options include custom event handlers
- */
- 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', hKeyupAndMouseup);
- layoutInfo.editable().on('scroll', hScroll);
-
- // handler for clipboard
- modules.clipboard.attach(layoutInfo, options);
-
- // handler for handle and popover
- 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 toolbar
- layoutInfo.toolbar().on('click', hToolbarAndPopoverClick);
- layoutInfo.toolbar().on('mousedown', hToolbarAndPopoverMousedown);
-
- // handler for statusbar
- modules.statusbar.attach(layoutInfo, options);
- }
-
- // handler for table dimension
- var $catcherContainer = options.airMode ? layoutInfo.popover() :
- layoutInfo.toolbar();
- var $catcher = $catcherContainer.find('.note-dimension-picker-mousecatcher');
- $catcher.css({
- width: options.insertTableMaxSize.col + 'em',
- height: options.insertTableMaxSize.row + 'em'
- }).on('mousemove', function (event) {
- hDimensionPickerMove(event, options);
- });
-
- // save options on editor
- layoutInfo.editor().data('options', options);
-
- // ret styleWithCSS for backColor / foreColor clearing with 'inherit'.
- if (!agent.isMSIE) {
- // [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);
-
- // All editor status will be saved on editable with jquery's data
- // for support multiple editor with singleton object.
- 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,
- onImageUpload: options.onImageUpload,
- onImageUploadError: options.onImageUploadError,
- onMediaDelete: options.onMediaDelete,
- onToolbarClick: options.onToolbarClick,
- onUpload: options.onUpload,
- });
-
- 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.holder().off();
- layoutInfo.editable().off();
-
- layoutInfo.popover().off();
- layoutInfo.handle().off();
- layoutInfo.dialog().off();
-
- if (!options.airMode) {
- layoutInfo.dropzone().off();
- layoutInfo.toolbar().off();
- layoutInfo.statusbar().off();
- }
- };
- };
-
- return EventHandler;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/Renderer.js b/addons/web_editor/static/lib/summernote/src/js/Renderer.js
deleted file mode 100644
index a57dab67573..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/Renderer.js
+++ /dev/null
@@ -1,1026 +0,0 @@
-define([
- 'summernote/core/agent',
- 'summernote/core/dom',
- 'summernote/core/func',
- 'summernote/core/list'
-], function (agent, dom, func, list) {
- /**
- * @class Renderer
- *
- * renderer
- *
- * rendering toolbar and editable
- */
- var Renderer = function () {
-
- /**
- * bootstrap button template
- * @private
- * @param {String} label button name
- * @param {Object} [options] button options
- * @param {String} [options.event] data-event
- * @param {String} [options.className] button's class name
- * @param {String} [options.value] data-value
- * @param {String} [options.title] button's title for popup
- * @param {String} [options.dropdown] dropdown html
- * @param {String} [options.hide] data-hide
- */
- var tplButton = function (label, options) {
- var event = options.event;
- var value = options.value;
- var title = options.title;
- var className = options.className;
- var dropdown = options.dropdown;
- var hide = options.hide;
-
- return (dropdown ? '
' : '') +
- '' +
- label +
- (dropdown ? ' ' : '') +
- ' ' +
- (dropdown || '') +
- (dropdown ? '
' : '');
- };
-
- /**
- * bootstrap icon button template
- * @private
- * @param {String} iconClassName
- * @param {Object} [options]
- * @param {String} [options.event]
- * @param {String} [options.value]
- * @param {String} [options.title]
- * @param {String} [options.dropdown]
- */
- var tplIconButton = function (iconClassName, options) {
- var label = ' ';
- return tplButton(label, options);
- };
-
- /**
- * bootstrap popover template
- * @private
- * @param {String} className
- * @param {String} content
- */
- var tplPopover = function (className, content) {
- var $popover = $('' +
- '
' +
- '
' +
- '
' +
- '
');
-
- $popover.find('.popover-body').append(content);
- return $popover;
- };
-
- /**
- * bootstrap dialog template
- *
- * @param {String} className
- * @param {String} [title='']
- * @param {String} body
- * @param {String} [footer='']
- */
- var tplDialog = function (className, title, body, footer) {
- return '' +
- '
' +
- '
' +
- (title ?
- '' : ''
- ) +
- '' + body + ' ' +
- (footer ?
- '' : ''
- ) +
- '
' +
- '
' +
- '
';
- };
-
- /**
- * bootstrap dropdown template
- *
- * @param {String|String[]} contents
- * @param {String} [className='']
- * @param {String} [nodeName='']
- */
- var tplDropdown = function (contents, className, nodeName) {
- var classes = 'dropdown-menu' + (className ? ' ' + className : '');
- nodeName = nodeName || 'ul';
- if (contents instanceof Array) {
- contents = contents.join('');
- }
-
- return '<' + nodeName + ' class="' + classes + '">' + contents + '' + nodeName + '>';
- };
-
- var tplButtonInfo = {
- picture: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.image.image, {
- event: 'showImageDialog',
- title: lang.image.image,
- hide: true
- });
- },
- link: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.link.link, {
- event: 'showLinkDialog',
- title: lang.link.link,
- hide: true
- });
- },
- table: function (lang, options) {
- var dropdown = [
- '',
- ' 1 x 1
'
- ];
-
- return tplIconButton(options.iconPrefix + options.icons.table.table, {
- title: lang.table.table,
- dropdown: tplDropdown(dropdown, 'note-table')
- });
- },
- style: function (lang, options) {
- var items = options.styleTags.reduce(function (memo, v) {
- var label = lang.style[v === 'p' ? 'normal' : v];
- return memo + '' +
- (
- (v === 'p' || v === 'pre') ? label :
- '<' + v + '>' + label + '' + v + '>'
- ) +
- ' ';
- }, '');
-
- return tplIconButton(options.iconPrefix + options.icons.style.style, {
- title: lang.style.style,
- dropdown: tplDropdown(items)
- });
- },
- fontname: function (lang, options) {
- var realFontList = [];
- var items = options.fontNames.reduce(function (memo, v) {
- if (!agent.isFontInstalled(v) && !list.contains(options.fontNamesIgnoreCheck, v)) {
- return memo;
- }
- realFontList.push(v);
- return memo + '' +
- ' ' + v +
- ' ';
- }, '');
-
- var hasDefaultFont = agent.isFontInstalled(options.defaultFontName);
- var defaultFontName = (hasDefaultFont) ? options.defaultFontName : realFontList[0];
-
- var label = '' +
- defaultFontName +
- ' ';
- return tplButton(label, {
- title: lang.font.name,
- className: 'note-fontname',
- dropdown: tplDropdown(items, 'note-check')
- });
- },
- fontsize: function (lang, options) {
- var items = options.fontSizes.reduce(function (memo, v) {
- return memo + '' +
- ' ' + v +
- ' ';
- }, '');
-
- var label = '11 ';
- return tplButton(label, {
- title: lang.font.size,
- className: 'note-fontsize',
- dropdown: tplDropdown(items, 'note-check')
- });
- },
- color: function (lang, options) {
- var colorButtonLabel = ' ';
- var colorButton = tplButton(colorButtonLabel, {
- className: 'note-recent-color',
- title: lang.color.recent,
- event: 'color',
- value: '{"backColor":"#B35E9B"}'
- });
-
- var items = [
- '',
- '
' + lang.color.background + '
',
- '
' + lang.color.setTransparent + '
',
- '
',
- '
',
- '
' + lang.color.foreground + '
',
- '
',
- lang.color.resetToDefault,
- '
',
- '
',
- '
'
- ];
-
- var moreButton = tplButton('', {
- title: lang.color.more,
- dropdown: tplDropdown(items)
- });
-
- return colorButton + moreButton;
- },
- bold: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.bold, {
- event: 'bold',
- title: lang.font.bold
- });
- },
- italic: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.italic, {
- event: 'italic',
- title: lang.font.italic
- });
- },
- underline: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.underline, {
- event: 'underline',
- title: lang.font.underline
- });
- },
- strikethrough: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.strikethrough, {
- event: 'strikethrough',
- title: lang.font.strikethrough
- });
- },
- superscript: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.superscript, {
- event: 'superscript',
- title: lang.font.superscript
- });
- },
- subscript: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.subscript, {
- event: 'subscript',
- title: lang.font.subscript
- });
- },
- clear: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.font.clear, {
- event: 'removeFormat',
- title: lang.font.clear
- });
- },
- ul: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.lists.unordered, {
- event: 'insertUnorderedList',
- title: lang.lists.unordered
- });
- },
- ol: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.lists.ordered, {
- event: 'insertOrderedList',
- title: lang.lists.ordered
- });
- },
- paragraph: function (lang, options) {
- var leftButton = tplIconButton(options.iconPrefix + options.icons.paragraph.left, {
- title: lang.paragraph.left,
- event: 'justifyLeft'
- });
- var centerButton = tplIconButton(options.iconPrefix + options.icons.paragraph.center, {
- title: lang.paragraph.center,
- event: 'justifyCenter'
- });
- var rightButton = tplIconButton(options.iconPrefix + options.icons.paragraph.right, {
- title: lang.paragraph.right,
- event: 'justifyRight'
- });
- var justifyButton = tplIconButton(options.iconPrefix + options.icons.paragraph.justify, {
- title: lang.paragraph.justify,
- event: 'justifyFull'
- });
-
- var outdentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.outdent, {
- title: lang.paragraph.outdent,
- event: 'outdent'
- });
- var indentButton = tplIconButton(options.iconPrefix + options.icons.paragraph.indent, {
- title: lang.paragraph.indent,
- event: 'indent'
- });
-
- var dropdown = [
- '',
- leftButton + centerButton + rightButton + justifyButton,
- '
',
- indentButton + outdentButton,
- '
'
- ];
-
- return tplIconButton(options.iconPrefix + options.icons.paragraph.paragraph, {
- title: lang.paragraph.paragraph,
- dropdown: tplDropdown(dropdown, '', 'div')
- });
- },
- height: function (lang, options) {
- var items = options.lineHeights.reduce(function (memo, v) {
- return memo + '' +
- ' ' + v +
- ' ';
- }, '');
-
- return tplIconButton(options.iconPrefix + options.icons.font.height, {
- title: lang.font.height,
- dropdown: tplDropdown(items, 'note-check')
- });
-
- },
- help: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.options.help, {
- event: 'showHelpDialog',
- title: lang.options.help,
- hide: true
- });
- },
- fullscreen: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.options.fullscreen, {
- event: 'fullscreen',
- title: lang.options.fullscreen
- });
- },
- codeview: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.options.codeview, {
- event: 'codeview',
- title: lang.options.codeview
- });
- },
- undo: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.history.undo, {
- event: 'undo',
- title: lang.history.undo
- });
- },
- redo: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.history.redo, {
- event: 'redo',
- title: lang.history.redo
- });
- },
- hr: function (lang, options) {
- return tplIconButton(options.iconPrefix + options.icons.hr.insert, {
- event: 'insertHorizontalRule',
- title: lang.hr.insert
- });
- }
- };
-
- var tplPopovers = function (lang, options) {
- var tplLinkPopover = function () {
- var linkButton = tplIconButton(options.iconPrefix + options.icons.link.edit, {
- title: lang.link.edit,
- event: 'showLinkDialog',
- hide: true
- });
- var unlinkButton = tplIconButton(options.iconPrefix + options.icons.link.unlink, {
- title: lang.link.unlink,
- event: 'unlink'
- });
- var content = 'www.google.com ' +
- '' +
- linkButton + unlinkButton +
- '
';
- return tplPopover('note-link-popover', content);
- };
-
- var tplImagePopover = function () {
- var autoButton = tplButton('Auto ', {
- event: 'resize',
- value: 'auto'
- });
- var fullButton = tplButton('100% ', {
- title: lang.image.resizeFull,
- event: 'resize',
- value: '1'
- });
- var halfButton = tplButton('50% ', {
- title: lang.image.resizeHalf,
- event: 'resize',
- value: '0.5'
- });
- var quarterButton = tplButton('25% ', {
- title: lang.image.resizeQuarter,
- event: 'resize',
- value: '0.25'
- });
-
- var leftButton = tplIconButton(options.iconPrefix + options.icons.image.floatLeft, {
- title: lang.image.floatLeft,
- event: 'floatMe',
- value: 'left'
- });
- var rightButton = tplIconButton(options.iconPrefix + options.icons.image.floatRight, {
- title: lang.image.floatRight,
- event: 'floatMe',
- value: 'right'
- });
- var justifyButton = tplIconButton(options.iconPrefix + options.icons.image.floatNone, {
- title: lang.image.floatNone,
- event: 'floatMe',
- value: 'none'
- });
-
- var roundedButton = tplIconButton(options.iconPrefix + options.icons.image.shapeRounded, {
- title: lang.image.shapeRounded,
- event: 'imageShape',
- value: 'rounded'
- });
- var circleButton = tplIconButton(options.iconPrefix + options.icons.image.shapeCircle, {
- title: lang.image.shapeCircle,
- event: 'imageShape',
- value: 'rounded-circle'
- });
- var thumbnailButton = tplIconButton(options.iconPrefix + options.icons.image.shapeThumbnail, {
- title: lang.image.shapeThumbnail,
- event: 'imageShape',
- value: 'img-thumbnail'
- });
- var noneButton = tplIconButton(options.iconPrefix + options.icons.image.shapeNone, {
- title: lang.image.shapeNone,
- event: 'imageShape',
- value: ''
- });
-
- var removeButton = tplIconButton(options.iconPrefix + options.icons.image.remove, {
- title: lang.image.remove,
- event: 'removeMedia',
- value: 'none'
- });
-
- var content = (options.disableResizeImage ? '' : '' + autoButton + fullButton + halfButton + quarterButton + '
') +
- '' + leftButton + rightButton + justifyButton + '
' +
- '' + roundedButton + circleButton + thumbnailButton + noneButton + '
' +
- '' + removeButton + '
';
- return tplPopover('note-image-popover', content);
- };
-
- var tplAirPopover = function () {
- var $content = $('
');
- for (var idx = 0, len = options.airPopover.length; idx < len; idx ++) {
- var group = options.airPopover[idx];
-
- var $group = $('');
- for (var i = 0, lenGroup = group[1].length; i < lenGroup; i++) {
- var $button = $(tplButtonInfo[group[1][i]](lang, options));
-
- $button.attr('data-name', group[1][i]);
-
- $group.append($button);
- }
- $content.append($group);
- }
-
- return tplPopover('note-air-popover', $content.children());
- };
-
- var $notePopover = $('
');
-
- $notePopover.append(tplLinkPopover());
- $notePopover.append(tplImagePopover());
-
- if (options.airMode) {
- $notePopover.append(tplAirPopover());
- }
-
- return $notePopover;
- };
-
- this.tplButtonInfo = tplButtonInfo; // ODOO: allow access for override
- this.tplPopovers = tplPopovers; // ODOO: allow access for override
-
- var tplHandles = function (options) {
- return '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- '
' +
- (options.disableResizeImage ? '' : '
') +
- '
' +
- '
';
- };
-
- /**
- * shortcut table template
- * @param {String} title
- * @param {String} body
- */
- var tplShortcut = function (title, keys) {
- var keyClass = 'note-shortcut-col col-6 note-shortcut-';
- var body = [];
-
- for (var i in keys) {
- if (keys.hasOwnProperty(i)) {
- body.push(
- '
' + keys[i].kbd + '
' +
- '
' + keys[i].text + '
'
- );
- }
- }
-
- return '
' +
- '
' + body.join('
') + '
';
- };
-
- var tplShortcutText = function (lang) {
- var keys = [
- { kbd: '⌘ + B', text: lang.font.bold },
- { kbd: '⌘ + I', text: lang.font.italic },
- { kbd: '⌘ + U', text: lang.font.underline },
- { kbd: '⌘ + \\', text: lang.font.clear }
- ];
-
- return tplShortcut(lang.shortcut.textFormatting, keys);
- };
-
- var tplShortcutAction = function (lang) {
- var keys = [
- { kbd: '⌘ + Z', text: lang.history.undo },
- { kbd: '⌘ + ⇧ + Z', text: lang.history.redo },
- { kbd: '⌘ + ]', text: lang.paragraph.indent },
- { kbd: '⌘ + [', text: lang.paragraph.outdent },
- { kbd: '⌘ + ENTER', text: lang.hr.insert }
- ];
-
- return tplShortcut(lang.shortcut.action, keys);
- };
-
- var tplShortcutPara = function (lang) {
- var keys = [
- { kbd: '⌘ + ⇧ + L', text: lang.paragraph.left },
- { kbd: '⌘ + ⇧ + E', text: lang.paragraph.center },
- { kbd: '⌘ + ⇧ + R', text: lang.paragraph.right },
- { kbd: '⌘ + ⇧ + J', text: lang.paragraph.justify },
- { kbd: '⌘ + ⇧ + NUM7', text: lang.lists.ordered },
- { kbd: '⌘ + ⇧ + NUM8', text: lang.lists.unordered }
- ];
-
- return tplShortcut(lang.shortcut.paragraphFormatting, keys);
- };
-
- var tplShortcutStyle = function (lang) {
- var keys = [
- { kbd: '⌘ + NUM0', text: lang.style.normal },
- { kbd: '⌘ + NUM1', text: lang.style.h1 },
- { kbd: '⌘ + NUM2', text: lang.style.h2 },
- { kbd: '⌘ + NUM3', text: lang.style.h3 },
- { kbd: '⌘ + NUM4', text: lang.style.h4 },
- { kbd: '⌘ + NUM5', text: lang.style.h5 },
- { kbd: '⌘ + NUM6', text: lang.style.h6 }
- ];
-
- return tplShortcut(lang.shortcut.documentStyle, keys);
- };
-
- var tplExtraShortcuts = function (lang, options) {
- var extraKeys = options.extraKeys;
- var keys = [];
-
- for (var key in extraKeys) {
- if (extraKeys.hasOwnProperty(key)) {
- keys.push({ kbd: key, text: extraKeys[key] });
- }
- }
-
- return tplShortcut(lang.shortcut.extraKeys, keys);
- };
-
- var tplShortcutTable = function (lang, options) {
- var colClass = 'class="note-shortcut note-shortcut-col col-md-6 col-12"';
- var template = [
- '
' + tplShortcutAction(lang, options) + '
' +
- '
' + tplShortcutText(lang, options) + '
',
- '
' + tplShortcutStyle(lang, options) + '
' +
- '
' + tplShortcutPara(lang, options) + '
'
- ];
-
- if (options.extraKeys) {
- template.push('
' + tplExtraShortcuts(lang, options) + '
');
- }
-
- return '
' +
- template.join('
') +
- '
';
- };
-
- var replaceMacKeys = function (sHtml) {
- return sHtml.replace(/⌘/g, 'Ctrl').replace(/⇧/g, 'Shift');
- };
-
- var tplDialogInfo = {
- image: function (lang, options) {
- var imageLimitation = '';
- if (options.maximumImageFileSize) {
- var unit = Math.floor(Math.log(options.maximumImageFileSize) / Math.log(1024));
- var readableSize = (options.maximumImageFileSize / Math.pow(1024, unit)).toFixed(2) * 1 +
- ' ' + ' KMGTP'[unit] + 'B';
- imageLimitation = '
' + lang.image.maximumFileSize + ' : ' + readableSize + ' ';
- }
-
- var body = '
' +
- '' + lang.image.selectFromFiles + ' ' +
- ' ' +
- imageLimitation +
- '
' +
- '
' +
- '' + lang.image.url + ' ' +
- ' ' +
- '
';
- var footer = '
' + lang.image.insert + ' ';
- return tplDialog('note-image-dialog', lang.image.insert, body, footer);
- },
-
- link: function (lang, options) {
- var body = '
' +
- '' + lang.link.textToDisplay + ' ' +
- ' ' +
- '
' +
- '
' +
- '' + lang.link.url + ' ' +
- ' ' +
- '
' +
- (!options.disableLinkTarget ?
- '
' +
- '' + ' ' +
- lang.link.openInNewWindow +
- ' ' +
- '
' : ''
- );
- var footer = '
' + lang.link.insert + ' ';
- return tplDialog('note-link-dialog', lang.link.insert, body, footer);
- },
-
- help: function (lang, options) {
- var body = '
' + lang.shortcut.close + ' ' +
- '
' + lang.shortcut.shortcuts + '
' +
- (agent.isMac ? tplShortcutTable(lang, options) : replaceMacKeys(tplShortcutTable(lang, options))) +
- '
' +
- 'Summernote @VERSION · ' +
- 'Project · ' +
- 'Issues ' +
- '
';
- return tplDialog('note-help-dialog', '', body, '');
- }
- };
-
- var tplDialogs = function (lang, options) {
- var dialogs = '';
-
- $.each(tplDialogInfo, function (idx, tplDialog) {
- dialogs += tplDialog(lang, options);
- });
-
- return '
' + dialogs + '
';
- };
-
- var tplStatusbar = function () {
- return '
' +
- '
' +
- '
' +
- '
' +
- '
';
- };
-
- var representShortcut = function (str) {
- if (agent.isMac) {
- str = str.replace('CMD', '⌘').replace('SHIFT', '⇧');
- }
-
- return str.replace('BACKSLASH', '\\')
- .replace('SLASH', '/')
- .replace('LEFTBRACKET', '[')
- .replace('RIGHTBRACKET', ']');
- };
-
- /**
- * createTooltip
- *
- * @param {jQuery} $container
- * @param {Object} keyMap
- * @param {String} [sPlacement]
- */
- var createTooltip = function ($container, keyMap, sPlacement) {
- var invertedKeyMap = func.invertObject(keyMap);
- var $buttons = $container.find('button');
-
- $buttons.each(function (i, elBtn) {
- var $btn = $(elBtn);
- var sShortcut = invertedKeyMap[$btn.data('event')];
- if (sShortcut) {
- $btn.attr('title', function (i, v) {
- return v + ' (' + representShortcut(sShortcut) + ')';
- });
- }
- // bootstrap tooltip on btn-group bug
- // https://github.com/twbs/bootstrap/issues/5687
- }).tooltip({
- container: 'body',
- trigger: 'hover',
- placement: sPlacement || 'top'
- }).on('click', function () {
- $(this).tooltip('hide');
- });
- };
-
- // createPalette
- var createPalette = function ($container, options) {
- var colorInfo = options.colors;
- $container.find('.note-color-palette').each(function () {
- var $palette = $(this), eventName = $palette.attr('data-target-event');
- var paletteContents = [];
- for (var row = 0, lenRow = colorInfo.length; row < lenRow; row++) {
- var colors = colorInfo[row];
- var buttons = [];
- for (var col = 0, lenCol = colors.length; col < lenCol; col++) {
- var color = colors[col];
- buttons.push(['
'].join(''));
- }
- paletteContents.push('
' + buttons.join('') + '
');
- }
- $palette.html(paletteContents.join(''));
- });
- };
-
- this.createPalette = createPalette; // ODOO: allow access for override
-
- /**
- * create summernote layout (air mode)
- *
- * @param {jQuery} $holder
- * @param {Object} options
- */
- this.createLayoutByAirMode = function ($holder, options) {
- var langInfo = options.langInfo;
- var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];
- var id = func.uniqueId();
-
- $holder.addClass('note-air-editor note-editable'); // ODOO: removing panel-body class to remove unwanted style
- $holder.attr({
- 'data-note-id': id, // ODOO: we use [data-note-id="{id}"] instead of [id="{id}"]
- // 'id': 'note-editor-' + id,
- 'contentEditable': true
- });
-
- var body = document.body;
- var $container = $('#web_editor-toolbars')
-
- // create Popover
- var $popover = $(this.tplPopovers(langInfo, options)); // ODOO: user (maybe) overrided method
- $popover.addClass('note-air-layout');
- $popover.attr('id', 'note-popover-' + id);
- $popover.appendTo($container);
- createTooltip($popover, keyMap);
- this.createPalette($popover, options); // ODOO: use (maybe) overrided method
-
- // create Handle
- var $handle = $(tplHandles(options));
- $handle.addClass('note-air-layout');
- $handle.attr('id', 'note-handle-' + id);
- $handle.appendTo($container);
-
- // create Dialog
- var $dialog = $(tplDialogs(langInfo, options));
- $dialog.addClass('note-air-layout');
- $dialog.attr('id', 'note-dialog-' + id);
- $dialog.find('button.close, a.modal-close').click(function () {
- $(this).closest('.modal').modal('hide');
- });
- $dialog.appendTo($container);
- };
-
- /**
- * create summernote layout (normal mode)
- *
- * @param {jQuery} $holder
- * @param {Object} options
- */
- this.createLayoutByFrame = function ($holder, options) {
- var langInfo = options.langInfo;
-
- //01. create Editor
- var $editor = $('
');
- if (options.width) {
- $editor.width(options.width);
- }
-
- //02. statusbar (resizebar)
- if (options.height > 0) {
- $('
' + (options.disableResizeEditor ? '' : tplStatusbar()) + '
').prependTo($editor);
- }
-
- //03 editing area
- var $editingArea = $('
');
- //03. create editable
- var isContentEditable = !$holder.is(':disabled');
- var $editable = $('
').prependTo($editingArea);
-
- if (options.height) {
- $editable.height(options.height);
- }
- if (options.direction) {
- $editable.attr('dir', options.direction);
- }
- var placeholder = $holder.attr('placeholder') || options.placeholder;
- if (placeholder) {
- $editable.attr('data-placeholder', placeholder);
- }
-
- $editable.html(dom.html($holder) || dom.emptyPara);
-
- //031. create codable
- $('
').prependTo($editingArea);
-
- //04. create Popover
- var $popover = $(this.tplPopovers(langInfo, options)).prependTo($editingArea); // ODOO: use (maybe) overrided method
- this.createPalette($popover, options); // ODOO: use (maybe) overrided method
- createTooltip($popover, keyMap);
-
- //05. handle(control selection, ...)
- $(tplHandles(options)).prependTo($editingArea);
-
- $editingArea.prependTo($editor);
-
- //06. create Toolbar
- var $toolbar = $('
');
- for (var idx = 0, len = options.toolbar.length; idx < len; idx ++) {
- var groupName = options.toolbar[idx][0];
- var groupButtons = options.toolbar[idx][1];
-
- var $group = $('
');
- for (var i = 0, btnLength = groupButtons.length; i < btnLength; i++) {
- var buttonInfo = tplButtonInfo[groupButtons[i]];
- // continue creating toolbar even if a button doesn't exist
- if (!$.isFunction(buttonInfo)) { continue; }
-
- var $button = $(buttonInfo(langInfo, options));
- $button.attr('data-name', groupButtons[i]); // set button's alias, becuase to get button element from $toolbar
- $group.append($button);
- }
- $toolbar.append($group);
- }
-
- var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc'];
- this.createPalette($toolbar, options); // ODOO: use (maybe) overrided method
- createTooltip($toolbar, keyMap, 'bottom');
- $toolbar.prependTo($editor);
-
- //07. create Dropzone
- $('
').prependTo($editor);
-
- //08. create Dialog
- var $dialogContainer = options.dialogsInBody ? $(document.body) : $editor;
- var $dialog = $(tplDialogs(langInfo, options)).prependTo($dialogContainer);
- $dialog.find('button.close, a.modal-close').click(function () {
- $(this).closest('.modal').modal('hide');
- });
-
- //09. Editor/Holder switch
- $editor.insertAfter($holder);
- $holder.hide();
- };
-
- this.hasNoteEditor = function ($holder) {
- return this.noteEditorFromHolder($holder).length > 0;
- };
-
- this.noteEditorFromHolder = function ($holder) {
- if ($holder.hasClass('note-air-editor')) {
- return $holder;
- } else if ($holder.next().hasClass('note-editor')) {
- return $holder.next();
- } else {
- return $();
- }
- };
-
- /**
- * create summernote layout
- *
- * @param {jQuery} $holder
- * @param {Object} options
- */
- this.createLayout = function ($holder, options) {
- if (options.airMode) {
- this.createLayoutByAirMode($holder, options);
- } else {
- this.createLayoutByFrame($holder, options);
- }
- };
-
- /**
- * returns layoutInfo from holder
- *
- * @param {jQuery} $holder - placeholder
- * @return {Object}
- */
- this.layoutInfoFromHolder = function ($holder) {
- var $editor = this.noteEditorFromHolder($holder);
- if (!$editor.length) {
- return;
- }
-
- // connect $holder to $editor
- $editor.data('holder', $holder);
-
- return dom.buildLayoutInfo($editor);
- };
-
- /**
- * removeLayout
- *
- * @param {jQuery} $holder - placeholder
- * @param {Object} layoutInfo
- * @param {Object} options
- *
- */
- this.removeLayout = function ($holder, layoutInfo, options) {
- if (options.airMode) {
- $holder.removeClass('note-air-editor note-editable')
- .removeAttr('contentEditable'); // ODOO: removed id 'id contentEditable'
-
- layoutInfo.popover().remove();
- layoutInfo.handle().remove();
- layoutInfo.dialog().remove();
- } else {
- $holder.html(layoutInfo.editable().html());
-
- if (options.dialogsInBody) {
- layoutInfo.dialog().remove();
- }
- layoutInfo.editor().remove();
- $holder.show();
- }
- };
-
- /**
- *
- * @return {Object}
- * @return {function(label, options=):string} return.button {@link #tplButton function to make text button}
- * @return {function(iconClass, options=):string} return.iconButton {@link #tplIconButton function to make icon button}
- * @return {function(className, title=, body=, footer=):string} return.dialog {@link #tplDialog function to make dialog}
- */
- this.getTemplate = function () {
- return {
- button: tplButton,
- iconButton: tplIconButton,
- dialog: tplDialog,
- dropdown: tplDropdown // ODOO: suggest upstream
- };
- };
-
- /**
- * add button information
- *
- * @param {String} name button name
- * @param {Function} buttonInfo function to make button, reference to {@link #tplButton},{@link #tplIconButton}
- */
- this.addButtonInfo = function (name, buttonInfo) {
- tplButtonInfo[name] = buttonInfo;
- };
-
- /**
- *
- * @param {String} name
- * @param {Function} dialogInfo function to make dialog, reference to {@link #tplDialog}
- */
- this.addDialogInfo = function (name, dialogInfo) {
- tplDialogInfo[name] = dialogInfo;
- };
- };
-
- return Renderer;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/app.js b/addons/web_editor/static/lib/summernote/src/js/app.js
deleted file mode 100644
index fba17afd588..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/app.js
+++ /dev/null
@@ -1,42 +0,0 @@
-require.config({
- baseUrl: 'src/js',
- paths: {
- jquery: '//code.jquery.com/jquery-1.11.3',
- bootstrap: '//netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min',
- summernotevideo: '/../../plugin/summernote-ext-video',
- CodeMirror: '//cdnjs.cloudflare.com/ajax/libs/codemirror/3.20.0/codemirror',
- CodeMirrorXml: '//cdnjs.cloudflare.com/ajax/libs/codemirror/3.20.0/mode/xml/xml.min',
- CodeMirrorFormatting: '//cdnjs.cloudflare.com/ajax/libs/codemirror/2.36.0/formatting.min'
- },
- shim: {
- bootstrap: ['jquery'],
- CodeMirror: { exports: 'CodeMirror' },
- CodeMirrorXml: ['CodeMirror'],
- CodeMirrorFormatting: ['CodeMirror', 'CodeMirrorXml'],
- summernotevideo: ['summernote']
- },
- packages: [{
- name: 'summernote',
- location: './',
- main: 'summernote'
- }]
-});
-
-require([
- 'jquery', 'bootstrap', 'CodeMirrorFormatting',
- 'summernote', 'summernotevideo'
-], function ($) {
- // summernote
- $('.summernote').summernote({
- height: 300, // set editable area's height
- focus: true, // set focus editable area after summernote loaded
- tabsize: 2, // size of tab
- placeholder: 'Type your message here...', // set editable area's placeholder text
- codemirror: { // code mirror options
- mode: 'text/html',
- htmlMode: true,
- lineNumbers: true,
- theme: 'monokai'
- }
- });
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/core/agent.js b/addons/web_editor/static/lib/summernote/src/js/core/agent.js
deleted file mode 100644
index 21555a1191c..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/core/agent.js
+++ /dev/null
@@ -1,170 +0,0 @@
-define(['jquery'], function ($) {
- if (!Array.prototype.reduce) {
- /**
- * Array.prototype.reduce polyfill
- *
- * @param {Function} callback
- * @param {Value} [initialValue]
- * @return {Value}
- *
- * @see http://goo.gl/WNriQD
- */
- Array.prototype.reduce = function (callback) {
- var t = Object(this), len = t.length >>> 0, k = 0, value;
- if (arguments.length === 2) {
- value = arguments[1];
- } else {
- while (k < len && !(k in t)) {
- k++;
- }
- if (k >= len) {
- throw new TypeError('Reduce of empty array with no initial value');
- }
- value = t[k++];
- }
- for (; k < len; k++) {
- if (k in t) {
- value = callback(value, t[k], k, t);
- }
- }
- return value;
- };
- }
-
- if ('function' !== typeof Array.prototype.filter) {
- /**
- * Array.prototype.filter polyfill
- *
- * @param {Function} func
- * @return {Array}
- *
- * @see http://goo.gl/T1KFnq
- */
- Array.prototype.filter = function (func) {
- var t = Object(this), len = t.length >>> 0;
-
- var res = [];
- var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
- for (var i = 0; i < len; i++) {
- if (i in t) {
- var val = t[i];
- if (func.call(thisArg, val, i, t)) {
- res.push(val);
- }
- }
- }
-
- return res;
- };
- }
-
- if (!Array.prototype.map) {
- /**
- * Array.prototype.map polyfill
- *
- * @param {Function} callback
- * @return {Array}
- *
- * @see https://goo.gl/SMWaMK
- */
- Array.prototype.map = function (callback, thisArg) {
- var T, A, k;
- if (this === null) {
- throw new TypeError(' this is null or not defined');
- }
-
- var O = Object(this);
- var len = O.length >>> 0;
- if (typeof callback !== 'function') {
- throw new TypeError(callback + ' is not a function');
- }
-
- if (arguments.length > 1) {
- T = thisArg;
- }
-
- A = new Array(len);
- k = 0;
-
- while (k < len) {
- var kValue, mappedValue;
- if (k in O) {
- kValue = O[k];
- mappedValue = callback.call(T, kValue, k, O);
- A[k] = mappedValue;
- }
- k++;
- }
- return A;
- };
- }
-
- var isSupportAmd = typeof define === 'function' && define.amd;
-
- /**
- * returns whether font is installed or not.
- *
- * @param {String} fontName
- * @return {Boolean}
- */
- var isFontInstalled = function (fontName) {
- var testFontName = fontName === 'Comic Sans MS' ? 'Courier New' : 'Comic Sans MS';
- var $tester = $('
').css({
- position: 'absolute',
- left: '-9999px',
- top: '-9999px',
- fontSize: '200px'
- }).text('mmmmmmmmmwwwwwww').appendTo(document.body);
-
- var originalWidth = $tester.css('fontFamily', testFontName).width();
- var width = $tester.css('fontFamily', fontName + ',' + testFontName).width();
-
- $tester.remove();
-
- return originalWidth !== width;
- };
-
- var userAgent = navigator.userAgent;
- var isMSIE = /MSIE|Trident/i.test(userAgent);
- var browserVersion;
- if (isMSIE) {
- var matches = /MSIE (\d+[.]\d+)/.exec(userAgent);
- if (matches) {
- browserVersion = parseFloat(matches[1]);
- }
- matches = /Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(userAgent);
- if (matches) {
- browserVersion = parseFloat(matches[1]);
- }
- }
-
- /**
- * @class core.agent
- *
- * Object which check platform and agent
- *
- * @singleton
- * @alternateClassName agent
- */
- var agent = {
- /** @property {Boolean} [isMac=false] true if this agent is Mac */
- isMac: navigator.appVersion.indexOf('Mac') > -1,
- /** @property {Boolean} [isMSIE=false] true if this agent is a Internet Explorer */
- isMSIE: isMSIE,
- /** @property {Boolean} [isFF=false] true if this agent is a Firefox */
- isFF: /firefox/i.test(userAgent),
- isWebkit: /webkit/i.test(userAgent),
- /** @property {Boolean} [isSafari=false] true if this agent is a Safari */
- isSafari: /safari/i.test(userAgent),
- /** @property {Float} browserVersion current browser version */
- browserVersion: browserVersion,
- /** @property {String} jqueryVersion current jQuery version string */
- jqueryVersion: parseFloat($.fn.jquery),
- isSupportAmd: isSupportAmd,
- hasCodeMirror: isSupportAmd ? require.specified('CodeMirror') : !!window.CodeMirror,
- isFontInstalled: isFontInstalled,
- isW3CRangeSupport: !!document.createRange
- };
-
- return agent;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/core/async.js b/addons/web_editor/static/lib/summernote/src/js/core/async.js
deleted file mode 100644
index 7bc23586e86..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/core/async.js
+++ /dev/null
@@ -1,68 +0,0 @@
-define('summernote/core/async', function () {
- /**
- * @class core.async
- *
- * Async functions which returns `Promise`
- *
- * @singleton
- * @alternateClassName async
- */
- var async = (function () {
- /**
- * @method readFileAsDataURL
- *
- * read contents of file as representing URL
- *
- * @param {File} file
- * @return {Promise} - then: sDataUrl
- */
- var readFileAsDataURL = function (file) {
- return $.Deferred(function (deferred) {
- $.extend(new FileReader(), {
- onload: function (e) {
- var sDataURL = e.target.result;
- deferred.resolve(sDataURL);
- },
- onerror: function () {
- deferred.reject(this);
- }
- }).readAsDataURL(file);
- }).promise();
- };
-
- /**
- * @method createImage
- *
- * create `
` from url string
- *
- * @param {String} sUrl
- * @param {String} filename
- * @return {Promise} - then: $image
- */
- var createImage = function (sUrl, filename) {
- return $.Deferred(function (deferred) {
- var $img = $(' ');
-
- $img.one('load', function () {
- $img.off('error abort');
- deferred.resolve($img);
- }).one('error abort', function () {
- $img.off('load').detach();
- deferred.reject($img);
- }).css({
- display: 'none'
- }).appendTo(document.body).attr({
- 'src': sUrl,
- 'data-filename': filename
- });
- }).promise();
- };
-
- return {
- readFileAsDataURL: readFileAsDataURL,
- createImage: createImage
- };
- })();
-
- return async;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/core/dom.js b/addons/web_editor/static/lib/summernote/src/js/core/dom.js
deleted file mode 100644
index fdcf784a081..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/core/dom.js
+++ /dev/null
@@ -1,1120 +0,0 @@
-define([
- 'summernote/core/func',
- 'summernote/core/list',
- 'summernote/core/agent'
-], function (func, list, agent) {
-
- var NBSP_CHAR = String.fromCharCode(160);
- var ZERO_WIDTH_NBSP_CHAR = '\ufeff';
-
- /**
- * @class core.dom
- *
- * Dom functions
- *
- * @singleton
- * @alternateClassName dom
- */
- var dom = (function () {
- /**
- * @method isEditable
- *
- * returns whether node is `note-editable` or not.
- *
- * @param {Node} node
- * @return {Boolean}
- */
- var isEditable = function (node) {
- return node && $(node).hasClass('note-editable');
- };
-
- /**
- * @method isControlSizing
- *
- * returns whether node is `note-control-sizing` or not.
- *
- * @param {Node} node
- * @return {Boolean}
- */
- var isControlSizing = function (node) {
- return node && $(node).hasClass('note-control-sizing');
- };
-
- /**
- * @method buildLayoutInfo
- *
- * build layoutInfo from $editor(.note-editor)
- *
- * @param {jQuery} $editor
- * @return {Object}
- * @return {Function} return.editor
- * @return {Node} return.dropzone
- * @return {Node} return.toolbar
- * @return {Node} return.editable
- * @return {Node} return.codable
- * @return {Node} return.popover
- * @return {Node} return.handle
- * @return {Node} return.dialog
- */
- var buildLayoutInfo = function ($editor) {
- var makeFinder;
-
- // air mode
- if ($editor.hasClass('note-air-editor')) {
- // ODOO: editor on [data-note-id] attribute
- // var id = list.last($editor.attr('id').split('-'));
- var id = list.last($editor.attr('data-note-id').split('-'));
- makeFinder = function (sIdPrefix) {
- return function () { return $(sIdPrefix + id); };
- };
-
- return {
- editor: function () { return $editor; },
- holder : function () { return $editor.data('holder'); },
- editable: function () { return $editor; },
- popover: makeFinder('#note-popover-'),
- handle: makeFinder('#note-handle-'),
- dialog: makeFinder('#note-dialog-')
- };
-
- // frame mode
- } else {
- makeFinder = function (className, $base) {
- $base = $base || $editor;
- return function () { return $base.find(className); };
- };
-
- var options = $editor.data('options');
- var $dialogHolder = (options && options.dialogsInBody) ? $(document.body) : null;
-
- return {
- editor: function () { return $editor; },
- holder : function () { return $editor.data('holder'); },
- dropzone: makeFinder('.note-dropzone'),
- toolbar: makeFinder('.note-toolbar'),
- editable: makeFinder('.note-editable'),
- codable: makeFinder('.note-codable'),
- statusbar: makeFinder('.note-statusbar'),
- popover: makeFinder('.note-popover'),
- handle: makeFinder('.note-handle'),
- dialog: makeFinder('.note-dialog', $dialogHolder)
- };
- }
- };
-
- /**
- * returns makeLayoutInfo from editor's descendant node.
- *
- * @private
- * @param {Node} descendant
- * @return {Object}
- */
- var makeLayoutInfo = function (descendant) {
- var $target = $(descendant).closest('.note-editor, .note-air-editor, .note-air-layout');
-
- if (!$target.length) {
- return null;
- }
-
- var $editor;
- if ($target.is('.note-editor, .note-air-editor')) {
- $editor = $target;
- } else {
- // ODOO: editor on [data-note-id] attribute
- // $editor = $('#note-editor-' + list.last($target.attr('id').split('-')));
- $editor = $('[data-note-id="' + list.last($target.attr('id').split('-')) + '"]');
- }
-
- return buildLayoutInfo($editor);
- };
-
- /**
- * @method makePredByNodeName
- *
- * returns predicate which judge whether nodeName is same
- *
- * @param {String} nodeName
- * @return {Function}
- */
- var makePredByNodeName = function (nodeName) {
- nodeName = nodeName.toUpperCase();
- return function (node) {
- return node && node.nodeName.toUpperCase() === nodeName;
- };
- };
-
- /**
- * @method isText
- *
- *
- *
- * @param {Node} node
- * @return {Boolean} true if node's type is text(3)
- */
- var isText = function (node) {
- return node && node.nodeType === 3;
- };
-
- /**
- * ex) br, col, embed, hr, img, input, ...
- * @see http://www.w3.org/html/wg/drafts/html/master/syntax.html#void-elements
- */
- var isVoid = function (node) {
- return node && /^BR|^IMG|^HR|^IFRAME|^BUTTON/.test(node.nodeName.toUpperCase());
- };
-
- var isPara = function (node) {
- if (isEditable(node)) {
- return false;
- }
-
- // Chrome(v31.0), FF(v25.0.1) use DIV for paragraph
- return node && /^DIV|^P|^LI|^H[1-7]/.test(node.nodeName.toUpperCase());
- };
-
- var isLi = makePredByNodeName('LI');
-
- var isPurePara = function (node) {
- return isPara(node) && !isLi(node);
- };
-
- var isTable = makePredByNodeName('TABLE');
-
- var isInline = function (node) {
- return !isBodyContainer(node) &&
- !isList(node) &&
- !isHr(node) &&
- !isPara(node) &&
- !isTable(node) &&
- !isBlockquote(node);
- };
-
- var isList = function (node) {
- return node && /^UL|^OL/.test(node.nodeName.toUpperCase());
- };
-
- var isHr = makePredByNodeName('HR');
-
- var isCell = function (node) {
- return node && /^TD|^TH/.test(node.nodeName.toUpperCase());
- };
-
- var isBlockquote = makePredByNodeName('BLOCKQUOTE');
-
- var isBodyContainer = function (node) {
- return isCell(node) || isBlockquote(node) || isEditable(node);
- };
-
- var isAnchor = makePredByNodeName('A');
-
- var isParaInline = function (node) {
- return isInline(node) && !!ancestor(node, isPara);
- };
-
- var isBodyInline = function (node) {
- return isInline(node) && !ancestor(node, isPara);
- };
-
- var isBody = makePredByNodeName('BODY');
-
- /**
- * returns whether nodeB is closest sibling of nodeA
- *
- * @param {Node} nodeA
- * @param {Node} nodeB
- * @return {Boolean}
- */
- var isClosestSibling = function (nodeA, nodeB) {
- return nodeA.nextSibling === nodeB ||
- nodeA.previousSibling === nodeB;
- };
-
- /**
- * returns array of closest siblings with node
- *
- * @param {Node} node
- * @param {function} [pred] - predicate function
- * @return {Node[]}
- */
- var withClosestSiblings = function (node, pred) {
- pred = pred || func.ok;
-
- var siblings = [];
- if (node.previousSibling && pred(node.previousSibling)) {
- siblings.push(node.previousSibling);
- }
- siblings.push(node);
- if (node.nextSibling && pred(node.nextSibling)) {
- siblings.push(node.nextSibling);
- }
- return siblings;
- };
-
- /**
- * blank HTML for cursor position
- * - [workaround] old IE only works with
- * - [workaround] IE11 and other browser works with bogus br
- */
- var blankHTML = agent.isMSIE && agent.browserVersion < 11 ? ' ' : ' ';
-
- /**
- * @method nodeLength
- *
- * returns #text's text size or element's childNodes size
- *
- * @param {Node} node
- */
- var nodeLength = function (node) {
- if (isText(node)) {
- return node.nodeValue.length;
- }
-
- return node.childNodes.length;
- };
-
- /**
- * returns whether node is empty or not.
- *
- * @param {Node} node
- * @return {Boolean}
- */
- var isEmpty = function (node) {
- var len = nodeLength(node);
-
- if (len === 0) {
- return true;
- } else if (!isText(node) && len === 1 && blankHTML === node.innerHTML) {
- // ex)
,
- return true;
- } else if (list.all(node.childNodes, isText) && '' === node.innerHTML) {
- // ex)
,
- return true;
- }
-
- return false;
- };
-
- /**
- * padding blankHTML if node is empty (for cursor position)
- */
- var paddingBlankHTML = function (node) {
- if (!isVoid(node) && !nodeLength(node)) {
- $(node).html(blankHTML);
- }
- };
-
- /**
- * find nearest ancestor predicate hit
- *
- * @param {Node} node
- * @param {Function} pred - predicate function
- */
- var ancestor = function (node, pred) {
- while (node) {
- if (pred(node)) { return node; }
- if (isEditable(node)) { break; }
-
- node = node.parentNode;
- }
- return null;
- };
-
- /**
- * find nearest ancestor only single child blood line and predicate hit
- *
- * @param {Node} node
- * @param {Function} pred - predicate function
- */
- var singleChildAncestor = function (node, pred) {
- node = node.parentNode;
-
- while (node) {
- if (nodeLength(node) !== 1) { break; }
- if (pred(node)) { return node; }
- if (isEditable(node)) { break; }
-
- node = node.parentNode;
- }
- return null;
- };
-
- /**
- * returns new array of ancestor nodes (until predicate hit).
- *
- * @param {Node} node
- * @param {Function} [optional] pred - predicate function
- */
- var listAncestor = function (node, pred) {
- pred = pred || func.fail;
-
- var ancestors = [];
- ancestor(node, function (el) {
- if (!isEditable(el)) {
- ancestors.push(el);
- }
-
- return pred(el);
- });
- return ancestors;
- };
-
- /**
- * find farthest ancestor predicate hit
- */
- var lastAncestor = function (node, pred) {
- var ancestors = listAncestor(node);
- return list.last(ancestors.filter(pred));
- };
-
- /**
- * returns common ancestor node between two nodes.
- *
- * @param {Node} nodeA
- * @param {Node} nodeB
- */
- var commonAncestor = function (nodeA, nodeB) {
- var ancestors = listAncestor(nodeA);
- for (var n = nodeB; n; n = n.parentNode) {
- if ($.inArray(n, ancestors) > -1) { return n; }
- }
- return null; // difference document area
- };
-
- /**
- * listing all previous siblings (until predicate hit).
- *
- * @param {Node} node
- * @param {Function} [optional] pred - predicate function
- */
- var listPrev = function (node, pred) {
- pred = pred || func.fail;
-
- var nodes = [];
- while (node) {
- if (pred(node)) { break; }
- nodes.push(node);
- node = node.previousSibling;
- }
- return nodes;
- };
-
- /**
- * listing next siblings (until predicate hit).
- *
- * @param {Node} node
- * @param {Function} [pred] - predicate function
- */
- var listNext = function (node, pred) {
- pred = pred || func.fail;
-
- var nodes = [];
- while (node) {
- if (pred(node)) { break; }
- nodes.push(node);
- node = node.nextSibling;
- }
- return nodes;
- };
-
- /**
- * listing descendant nodes
- *
- * @param {Node} node
- * @param {Function} [pred] - predicate function
- */
- var listDescendant = function (node, pred) {
- var descendents = [];
- pred = pred || func.ok;
-
- // start DFS(depth first search) with node
- (function fnWalk(current) {
- if (node !== current && pred(current)) {
- descendents.push(current);
- }
- for (var idx = 0, len = current.childNodes.length; idx < len; idx++) {
- fnWalk(current.childNodes[idx]);
- }
- })(node);
-
- return descendents;
- };
-
- /**
- * wrap node with new tag.
- *
- * @param {Node} node
- * @param {Node} tagName of wrapper
- * @return {Node} - wrapper
- */
- var wrap = function (node, wrapperName) {
- var parent = node.parentNode;
- var wrapper = $('<' + wrapperName + '>')[0];
-
- parent.insertBefore(wrapper, node);
- wrapper.appendChild(node);
-
- return wrapper;
- };
-
- /**
- * insert node after preceding
- *
- * @param {Node} node
- * @param {Node} preceding - predicate function
- */
- var insertAfter = function (node, preceding) {
- var next = preceding.nextSibling, parent = preceding.parentNode;
- if (next) {
- parent.insertBefore(node, next);
- } else {
- parent.appendChild(node);
- }
- return node;
- };
-
- /**
- * append elements.
- *
- * @param {Node} node
- * @param {Collection} aChild
- */
- var appendChildNodes = function (node, aChild) {
- $.each(aChild, function (idx, child) {
- node.appendChild(child);
- });
- return node;
- };
-
- /**
- * returns whether boundaryPoint is left edge or not.
- *
- * @param {BoundaryPoint} point
- * @return {Boolean}
- */
- var isLeftEdgePoint = function (point) {
- return point.offset === 0;
- };
-
- /**
- * returns whether boundaryPoint is right edge or not.
- *
- * @param {BoundaryPoint} point
- * @return {Boolean}
- */
- var isRightEdgePoint = function (point) {
- return point.offset === nodeLength(point.node);
- };
-
- /**
- * returns whether boundaryPoint is edge or not.
- *
- * @param {BoundaryPoint} point
- * @return {Boolean}
- */
- var isEdgePoint = function (point) {
- return isLeftEdgePoint(point) || isRightEdgePoint(point);
- };
-
- /**
- * returns wheter node is left edge of ancestor or not.
- *
- * @param {Node} node
- * @param {Node} ancestor
- * @return {Boolean}
- */
- var isLeftEdgeOf = function (node, ancestor) {
- while (node && node !== ancestor) {
- if (position(node) !== 0) {
- return false;
- }
- node = node.parentNode;
- }
-
- return true;
- };
-
- /**
- * returns whether node is right edge of ancestor or not.
- *
- * @param {Node} node
- * @param {Node} ancestor
- * @return {Boolean}
- */
- var isRightEdgeOf = function (node, ancestor) {
- while (node && node !== ancestor) {
- if (position(node) !== nodeLength(node.parentNode) - 1) {
- return false;
- }
- node = node.parentNode;
- }
-
- return true;
- };
-
- /**
- * returns whether point is left edge of ancestor or not.
- * @param {BoundaryPoint} point
- * @param {Node} ancestor
- * @return {Boolean}
- */
- var isLeftEdgePointOf = function (point, ancestor) {
- return isLeftEdgePoint(point) && isLeftEdgeOf(point.node, ancestor);
- };
-
- /**
- * returns whether point is right edge of ancestor or not.
- * @param {BoundaryPoint} point
- * @param {Node} ancestor
- * @return {Boolean}
- */
- var isRightEdgePointOf = function (point, ancestor) {
- return isRightEdgePoint(point) && isRightEdgeOf(point.node, ancestor);
- };
-
- /**
- * returns offset from parent.
- *
- * @param {Node} node
- */
- var position = function (node) {
- var offset = 0;
- while ((node = node.previousSibling)) {
- offset += 1;
- }
- return offset;
- };
-
- var hasChildren = function (node) {
- return !!(node && node.childNodes && node.childNodes.length);
- };
-
- /**
- * returns previous boundaryPoint
- *
- * @param {BoundaryPoint} point
- * @param {Boolean} isSkipInnerOffset
- * @return {BoundaryPoint}
- */
- var prevPoint = function (point, isSkipInnerOffset) {
- var node, offset;
-
- if (point.offset === 0) {
- if (isEditable(point.node)) {
- return null;
- }
-
- node = point.node.parentNode;
- offset = position(point.node);
- } else if (hasChildren(point.node)) {
- node = point.node.childNodes[point.offset - 1];
- offset = nodeLength(node);
- } else {
- node = point.node;
- offset = isSkipInnerOffset ? 0 : point.offset - 1;
- }
-
- return {
- node: node,
- offset: offset
- };
- };
-
- /**
- * returns next boundaryPoint
- *
- * @param {BoundaryPoint} point
- * @param {Boolean} isSkipInnerOffset
- * @return {BoundaryPoint}
- */
- var nextPoint = function (point, isSkipInnerOffset) {
- var node, offset;
-
- if (nodeLength(point.node) === point.offset) {
- if (isEditable(point.node)) {
- return null;
- }
-
- node = point.node.parentNode;
- offset = position(point.node) + 1;
- } else if (hasChildren(point.node)) {
- node = point.node.childNodes[point.offset];
- offset = 0;
- } else {
- node = point.node;
- offset = isSkipInnerOffset ? nodeLength(point.node) : point.offset + 1;
- }
-
- return {
- node: node,
- offset: offset
- };
- };
-
- /**
- * returns whether pointA and pointB is same or not.
- *
- * @param {BoundaryPoint} pointA
- * @param {BoundaryPoint} pointB
- * @return {Boolean}
- */
- var isSamePoint = function (pointA, pointB) {
- return pointA.node === pointB.node && pointA.offset === pointB.offset;
- };
-
- /**
- * returns whether point is visible (can set cursor) or not.
- *
- * @param {BoundaryPoint} point
- * @return {Boolean}
- */
- var isVisiblePoint = function (point) {
- if (isText(point.node) || !hasChildren(point.node) || isEmpty(point.node)) {
- return true;
- }
-
- var leftNode = point.node.childNodes[point.offset - 1];
- var rightNode = point.node.childNodes[point.offset];
- if ((!leftNode || isVoid(leftNode)) && (!rightNode || isVoid(rightNode))) {
- return true;
- }
-
- return false;
- };
-
- /**
- * @method prevPointUtil
- *
- * @param {BoundaryPoint} point
- * @param {Function} pred
- * @return {BoundaryPoint}
- */
- var prevPointUntil = function (point, pred) {
- while (point) {
- if (pred(point)) {
- return point;
- }
-
- point = prevPoint(point);
- }
-
- return null;
- };
-
- /**
- * @method nextPointUntil
- *
- * @param {BoundaryPoint} point
- * @param {Function} pred
- * @return {BoundaryPoint}
- */
- var nextPointUntil = function (point, pred) {
- while (point) {
- if (pred(point)) {
- return point;
- }
-
- point = nextPoint(point);
- }
-
- return null;
- };
-
- /**
- * returns whether point has character or not.
- *
- * @param {Point} point
- * @return {Boolean}
- */
- var isCharPoint = function (point) {
- if (!isText(point.node)) {
- return false;
- }
-
- var ch = point.node.nodeValue.charAt(point.offset - 1);
- return ch && (ch !== ' ' && ch !== NBSP_CHAR);
- };
-
- /**
- * @method walkPoint
- *
- * @param {BoundaryPoint} startPoint
- * @param {BoundaryPoint} endPoint
- * @param {Function} handler
- * @param {Boolean} isSkipInnerOffset
- */
- var walkPoint = function (startPoint, endPoint, handler, isSkipInnerOffset) {
- var point = startPoint;
-
- while (point) {
- handler(point);
-
- if (isSamePoint(point, endPoint)) {
- break;
- }
-
- var isSkipOffset = isSkipInnerOffset &&
- startPoint.node !== point.node &&
- endPoint.node !== point.node;
- point = nextPoint(point, isSkipOffset);
- }
- };
-
- /**
- * @method makeOffsetPath
- *
- * return offsetPath(array of offset) from ancestor
- *
- * @param {Node} ancestor - ancestor node
- * @param {Node} node
- */
- var makeOffsetPath = function (ancestor, node) {
- var ancestors = listAncestor(node, func.eq(ancestor));
- return ancestors.map(position).reverse();
- };
-
- /**
- * @method fromOffsetPath
- *
- * return element from offsetPath(array of offset)
- *
- * @param {Node} ancestor - ancestor node
- * @param {array} offsets - offsetPath
- */
- var fromOffsetPath = function (ancestor, offsets) {
- var current = ancestor;
- for (var i = 0, len = offsets.length; i < len; i++) {
- if (current.childNodes.length <= offsets[i]) {
- current = current.childNodes[current.childNodes.length - 1];
- } else {
- current = current.childNodes[offsets[i]];
- }
- }
- return current;
- };
-
- /**
- * @method splitNode
- *
- * split element or #text
- *
- * @param {BoundaryPoint} point
- * @param {Object} [options]
- * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
- * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
- * @return {Node} right node of boundaryPoint
- */
- var splitNode = function (point, options) {
- var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;
- var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;
-
- // edge case
- if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {
- if (isLeftEdgePoint(point)) {
- return point.node;
- } else if (isRightEdgePoint(point)) {
- return point.node.nextSibling;
- }
- }
-
- // split #text
- if (isText(point.node)) {
- return point.node.splitText(point.offset);
- } else {
- var childNode = point.node.childNodes[point.offset];
- var clone = insertAfter(point.node.cloneNode(false), point.node);
- appendChildNodes(clone, listNext(childNode));
-
- if (!isSkipPaddingBlankHTML) {
- paddingBlankHTML(point.node);
- paddingBlankHTML(clone);
- }
-
- return clone;
- }
- };
-
- /**
- * @method splitTree
- *
- * split tree by point
- *
- * @param {Node} root - split root
- * @param {BoundaryPoint} point
- * @param {Object} [options]
- * @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
- * @param {Boolean} [options.isNotSplitEdgePoint] - default: false
- * @return {Node} right node of boundaryPoint
- */
- var splitTree = function (root, point, options) {
- // ex) [#text, , ]
- var ancestors = listAncestor(point.node, func.eq(root));
-
- if (!ancestors.length) {
- return null;
- } else if (ancestors.length === 1) {
- return splitNode(point, options);
- }
-
- return ancestors.reduce(function (node, parent) {
- if (node === point.node) {
- node = splitNode(point, options);
- }
-
- return splitNode({
- node: parent,
- offset: node ? dom.position(node) : nodeLength(parent)
- }, options);
- });
- };
-
- /**
- * split point
- *
- * @param {Point} point
- * @param {Boolean} isInline
- * @return {Object}
- */
- var splitPoint = function (point, isInline) {
- // find splitRoot, container
- // - inline: splitRoot is a child of paragraph
- // - block: splitRoot is a child of bodyContainer
- var pred = isInline ? isPara : isBodyContainer;
- var ancestors = listAncestor(point.node, pred);
- var topAncestor = list.last(ancestors) || point.node;
-
- var splitRoot, container;
- if (pred(topAncestor)) {
- splitRoot = ancestors[ancestors.length - 2];
- container = topAncestor;
- } else {
- splitRoot = topAncestor;
- container = splitRoot.parentNode;
- }
-
- // if splitRoot is exists, split with splitTree
- var pivot = splitRoot && splitTree(splitRoot, point, {
- isSkipPaddingBlankHTML: isInline,
- isNotSplitEdgePoint: isInline
- });
-
- // if container is point.node, find pivot with point.offset
- if (!pivot && container === point.node) {
- pivot = point.node.childNodes[point.offset];
- }
-
- return {
- rightNode: pivot,
- container: container
- };
- };
-
- var create = function (nodeName) {
- return document.createElement(nodeName);
- };
-
- var createText = function (text) {
- return document.createTextNode(text);
- };
-
- /**
- * @method remove
- *
- * remove node, (isRemoveChild: remove child or not)
- *
- * @param {Node} node
- * @param {Boolean} isRemoveChild
- */
- var remove = function (node, isRemoveChild) {
- if (!node || !node.parentNode) { return; }
- if (node.removeNode) { return node.removeNode(isRemoveChild); }
-
- var parent = node.parentNode;
- if (!isRemoveChild) {
- var nodes = [];
- var i, len;
- for (i = 0, len = node.childNodes.length; i < len; i++) {
- nodes.push(node.childNodes[i]);
- }
-
- for (i = 0, len = nodes.length; i < len; i++) {
- parent.insertBefore(nodes[i], node);
- }
- }
-
- parent.removeChild(node);
- };
-
- /**
- * @method removeWhile
- *
- * @param {Node} node
- * @param {Function} pred
- */
- var removeWhile = function (node, pred) {
- while (node) {
- if (isEditable(node) || !pred(node)) {
- break;
- }
-
- var parent = node.parentNode;
- remove(node);
- node = parent;
- }
- };
-
- /**
- * @method replace
- *
- * replace node with provided nodeName
- *
- * @param {Node} node
- * @param {String} nodeName
- * @return {Node} - new node
- */
- var replace = function (node, nodeName) {
- if (node.nodeName.toUpperCase() === nodeName.toUpperCase()) {
- return node;
- }
-
- var newNode = create(nodeName);
-
- if (node.style.cssText) {
- newNode.style.cssText = node.style.cssText;
- }
-
- appendChildNodes(newNode, list.from(node.childNodes));
- insertAfter(newNode, node);
- remove(node);
-
- return newNode;
- };
-
- var isTextarea = makePredByNodeName('TEXTAREA');
-
- /**
- * @param {jQuery} $node
- * @param {Boolean} [stripLinebreaks] - default: false
- */
- var value = function ($node, stripLinebreaks) {
- var val = isTextarea($node[0]) ? $node.val() : $node.html();
- if (stripLinebreaks) {
- return val.replace(/[\n\r]/g, '');
- }
- return val;
- };
-
- /**
- * @method html
- *
- * get the HTML contents of node
- *
- * @param {jQuery} $node
- * @param {Boolean} [isNewlineOnBlock]
- */
- var html = function ($node, isNewlineOnBlock) {
- var markup = value($node);
-
- if (isNewlineOnBlock) {
- var regexTag = /<(\/?)(\b(?!!)[^>\s]*)(.*?)(\s*\/?>)/g;
- markup = markup.replace(regexTag, function (match, endSlash, name) {
- name = name.toUpperCase();
- var isEndOfInlineContainer = /^DIV|^TD|^TH|^P|^LI|^H[1-7]/.test(name) &&
- !!endSlash;
- var isBlockNode = /^BLOCKQUOTE|^TABLE|^TBODY|^TR|^HR|^UL|^OL/.test(name);
-
- return match + ((isEndOfInlineContainer || isBlockNode) ? '\n' : '');
- });
- markup = $.trim(markup);
- }
-
- return markup;
- };
-
- return {
- /** @property {String} NBSP_CHAR */
- NBSP_CHAR: NBSP_CHAR,
- /** @property {String} ZERO_WIDTH_NBSP_CHAR */
- ZERO_WIDTH_NBSP_CHAR: ZERO_WIDTH_NBSP_CHAR,
- /** @property {String} blank */
- blank: blankHTML,
- /** @property {String} emptyPara */
- emptyPara: '
' + blankHTML + '
',
- makePredByNodeName: makePredByNodeName,
- isEditable: isEditable,
- isControlSizing: isControlSizing,
- buildLayoutInfo: buildLayoutInfo,
- makeLayoutInfo: makeLayoutInfo,
- isText: isText,
- isVoid: isVoid,
- isPara: isPara,
- isPurePara: isPurePara,
- isInline: isInline,
- isBlock: func.not(isInline),
- isBodyInline: isBodyInline,
- isBody: isBody,
- isParaInline: isParaInline,
- isList: isList,
- isTable: isTable,
- isCell: isCell,
- isBlockquote: isBlockquote,
- isBodyContainer: isBodyContainer,
- isAnchor: isAnchor,
- isDiv: makePredByNodeName('DIV'),
- isLi: isLi,
- isBR: makePredByNodeName('BR'),
- isSpan: makePredByNodeName('SPAN'),
- isB: makePredByNodeName('B'),
- isU: makePredByNodeName('U'),
- isS: makePredByNodeName('S'),
- isI: makePredByNodeName('I'),
- isImg: makePredByNodeName('IMG'),
- isTextarea: isTextarea,
- isEmpty: isEmpty,
- isEmptyAnchor: func.and(isAnchor, isEmpty),
- isClosestSibling: isClosestSibling,
- withClosestSiblings: withClosestSiblings,
- nodeLength: nodeLength,
- isLeftEdgePoint: isLeftEdgePoint,
- isRightEdgePoint: isRightEdgePoint,
- isEdgePoint: isEdgePoint,
- isLeftEdgeOf: isLeftEdgeOf,
- isRightEdgeOf: isRightEdgeOf,
- isLeftEdgePointOf: isLeftEdgePointOf,
- isRightEdgePointOf: isRightEdgePointOf,
- prevPoint: prevPoint,
- nextPoint: nextPoint,
- isSamePoint: isSamePoint,
- isVisiblePoint: isVisiblePoint,
- prevPointUntil: prevPointUntil,
- nextPointUntil: nextPointUntil,
- isCharPoint: isCharPoint,
- walkPoint: walkPoint,
- ancestor: ancestor,
- singleChildAncestor: singleChildAncestor,
- listAncestor: listAncestor,
- lastAncestor: lastAncestor,
- listNext: listNext,
- listPrev: listPrev,
- listDescendant: listDescendant,
- commonAncestor: commonAncestor,
- wrap: wrap,
- insertAfter: insertAfter,
- appendChildNodes: appendChildNodes,
- position: position,
- hasChildren: hasChildren,
- makeOffsetPath: makeOffsetPath,
- fromOffsetPath: fromOffsetPath,
- splitTree: splitTree,
- splitPoint: splitPoint,
- create: create,
- createText: createText,
- remove: remove,
- removeWhile: removeWhile,
- replace: replace,
- html: html,
- value: value
- };
- })();
-
- return dom;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/core/func.js b/addons/web_editor/static/lib/summernote/src/js/core/func.js
deleted file mode 100644
index 11bfdf546e0..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/core/func.js
+++ /dev/null
@@ -1,130 +0,0 @@
-define('summernote/core/func', function () {
- /**
- * @class core.func
- *
- * func utils (for high-order func's arg)
- *
- * @singleton
- * @alternateClassName func
- */
- var func = (function () {
- var eq = function (itemA) {
- return function (itemB) {
- return itemA === itemB;
- };
- };
-
- var eq2 = function (itemA, itemB) {
- return itemA === itemB;
- };
-
- var peq2 = function (propName) {
- return function (itemA, itemB) {
- return itemA[propName] === itemB[propName];
- };
- };
-
- var ok = function () {
- return true;
- };
-
- var fail = function () {
- return false;
- };
-
- var not = function (f) {
- return function () {
- return !f.apply(f, arguments);
- };
- };
-
- var and = function (fA, fB) {
- return function (item) {
- return fA(item) && fB(item);
- };
- };
-
- var self = function (a) {
- return a;
- };
-
- var idCounter = 0;
-
- /**
- * generate a globally-unique id
- *
- * @param {String} [prefix]
- */
- var uniqueId = function (prefix) {
- var id = ++idCounter + '';
- return prefix ? prefix + id : id;
- };
-
- /**
- * returns bnd (bounds) from rect
- *
- * - IE Compatability Issue: http://goo.gl/sRLOAo
- * - Scroll Issue: http://goo.gl/sNjUc
- *
- * @param {Rect} rect
- * @return {Object} bounds
- * @return {Number} bounds.top
- * @return {Number} bounds.left
- * @return {Number} bounds.width
- * @return {Number} bounds.height
- */
- var rect2bnd = function (rect) {
- var $document = $(document);
- return {
- top: rect.top + $document.scrollTop(),
- left: rect.left + $document.scrollLeft(),
- width: rect.right - rect.left,
- height: rect.bottom - rect.top
- };
- };
-
- /**
- * returns a copy of the object where the keys have become the values and the values the keys.
- * @param {Object} obj
- * @return {Object}
- */
- var invertObject = function (obj) {
- var inverted = {};
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) {
- inverted[obj[key]] = key;
- }
- }
- return inverted;
- };
-
- /**
- * @param {String} namespace
- * @param {String} [prefix]
- * @return {String}
- */
- var namespaceToCamel = function (namespace, prefix) {
- prefix = prefix || '';
- return prefix + namespace.split('.').map(function (name) {
- return name.substring(0, 1).toUpperCase() + name.substring(1);
- }).join('');
- };
-
- return {
- eq: eq,
- eq2: eq2,
- peq2: peq2,
- ok: ok,
- fail: fail,
- self: self,
- not: not,
- and: and,
- uniqueId: uniqueId,
- rect2bnd: rect2bnd,
- invertObject: invertObject,
- namespaceToCamel: namespaceToCamel
- };
- })();
-
- return func;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/core/key.js b/addons/web_editor/static/lib/summernote/src/js/core/key.js
deleted file mode 100644
index a17b2756328..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/core/key.js
+++ /dev/null
@@ -1,96 +0,0 @@
-define([
- 'summernote/core/list',
- 'summernote/core/func'
-], function (list, func) {
- /**
- * @class core.key
- *
- * Object for keycodes.
- *
- * @singleton
- * @alternateClassName key
- */
- var key = (function () {
- var keyMap = {
- 'BACKSPACE': 8,
- 'TAB': 9,
- 'ENTER': 13,
- 'SPACE': 32,
-
- // Arrow
- 'LEFT': 37,
- 'UP': 38,
- 'RIGHT': 39,
- 'DOWN': 40,
-
- // Number: 0-9
- 'NUM0': 48,
- 'NUM1': 49,
- 'NUM2': 50,
- 'NUM3': 51,
- 'NUM4': 52,
- 'NUM5': 53,
- 'NUM6': 54,
- 'NUM7': 55,
- 'NUM8': 56,
-
- // Alphabet: a-z
- 'B': 66,
- 'E': 69,
- 'I': 73,
- 'J': 74,
- 'K': 75,
- 'L': 76,
- 'R': 82,
- 'S': 83,
- 'U': 85,
- 'V': 86,
- 'Y': 89,
- 'Z': 90,
-
- 'SLASH': 191,
- 'LEFTBRACKET': 219,
- 'BACKSLASH': 220,
- 'RIGHTBRACKET': 221
- };
-
- return {
- /**
- * @method isEdit
- *
- * @param {Number} keyCode
- * @return {Boolean}
- */
- isEdit: function (keyCode) {
- return list.contains([
- keyMap.BACKSPACE,
- keyMap.TAB,
- keyMap.ENTER,
- keyMap.SPACe
- ], keyCode);
- },
- /**
- * @method isMove
- *
- * @param {Number} keyCode
- * @return {Boolean}
- */
- isMove: function (keyCode) {
- return list.contains([
- keyMap.LEFT,
- keyMap.UP,
- keyMap.RIGHT,
- keyMap.DOWN
- ], keyCode);
- },
- /**
- * @property {Object} nameFromCode
- * @property {String} nameFromCode.8 "BACKSPACE"
- */
- nameFromCode: func.invertObject(keyMap),
- code: keyMap
- };
- })();
-
- return key;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/core/list.js b/addons/web_editor/static/lib/summernote/src/js/core/list.js
deleted file mode 100644
index 2d6708838df..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/core/list.js
+++ /dev/null
@@ -1,191 +0,0 @@
-define(['summernote/core/func'], function (func) {
- /**
- * @class core.list
- *
- * list utils
- *
- * @singleton
- * @alternateClassName list
- */
- var list = (function () {
- /**
- * returns the first item of an array.
- *
- * @param {Array} array
- */
- var head = function (array) {
- return array[0];
- };
-
- /**
- * returns the last item of an array.
- *
- * @param {Array} array
- */
- var last = function (array) {
- return array[array.length - 1];
- };
-
- /**
- * returns everything but the last entry of the array.
- *
- * @param {Array} array
- */
- var initial = function (array) {
- return array.slice(0, array.length - 1);
- };
-
- /**
- * returns the rest of the items in an array.
- *
- * @param {Array} array
- */
- var tail = function (array) {
- return array.slice(1);
- };
-
- /**
- * returns item of array
- */
- var find = function (array, pred) {
- for (var idx = 0, len = array.length; idx < len; idx ++) {
- var item = array[idx];
- if (pred(item)) {
- return item;
- }
- }
- };
-
- /**
- * returns true if all of the values in the array pass the predicate truth test.
- */
- var all = function (array, pred) {
- for (var idx = 0, len = array.length; idx < len; idx ++) {
- if (!pred(array[idx])) {
- return false;
- }
- }
- return true;
- };
-
- /**
- * returns index of item
- */
- var indexOf = function (array, item) {
- return $.inArray(item, array);
- };
-
- /**
- * returns true if the value is present in the list.
- */
- var contains = function (array, item) {
- return indexOf(array, item) !== -1;
- };
-
- /**
- * get sum from a list
- *
- * @param {Array} array - array
- * @param {Function} fn - iterator
- */
- var sum = function (array, fn) {
- fn = fn || func.self;
- return array.reduce(function (memo, v) {
- return memo + fn(v);
- }, 0);
- };
-
- /**
- * returns a copy of the collection with array type.
- * @param {Collection} collection - collection eg) node.childNodes, ...
- */
- var from = function (collection) {
- var result = [], idx = -1, length = collection.length;
- while (++idx < length) {
- result[idx] = collection[idx];
- }
- return result;
- };
-
- /**
- * cluster elements by predicate function.
- *
- * @param {Array} array - array
- * @param {Function} fn - predicate function for cluster rule
- * @param {Array[]}
- */
- var clusterBy = function (array, fn) {
- if (!array.length) { return []; }
- var aTail = tail(array);
- return aTail.reduce(function (memo, v) {
- var aLast = last(memo);
- if (fn(last(aLast), v)) {
- aLast[aLast.length] = v;
- } else {
- memo[memo.length] = [v];
- }
- return memo;
- }, [[head(array)]]);
- };
-
- /**
- * returns a copy of the array with all falsy values removed
- *
- * @param {Array} array - array
- * @param {Function} fn - predicate function for cluster rule
- */
- var compact = function (array) {
- var aResult = [];
- for (var idx = 0, len = array.length; idx < len; idx ++) {
- if (array[idx]) { aResult.push(array[idx]); }
- }
- return aResult;
- };
-
- /**
- * produces a duplicate-free version of the array
- *
- * @param {Array} array
- */
- var unique = function (array) {
- var results = [];
-
- for (var idx = 0, len = array.length; idx < len; idx ++) {
- if (!contains(results, array[idx])) {
- results.push(array[idx]);
- }
- }
-
- return results;
- };
-
- /**
- * returns next item.
- * @param {Array} array
- */
- var next = function (array, item) {
- var idx = indexOf(array, item);
- if (idx === -1) { return null; }
-
- return array[idx + 1];
- };
-
- /**
- * returns prev item.
- * @param {Array} array
- */
- var prev = function (array, item) {
- var idx = indexOf(array, item);
- if (idx === -1) { return null; }
-
- return array[idx - 1];
- };
-
- return { head: head, last: last, initial: initial, tail: tail,
- prev: prev, next: next, find: find, contains: contains,
- all: all, sum: sum, from: from,
- clusterBy: clusterBy, compact: compact, unique: unique };
- })();
-
- return list;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/core/range.js b/addons/web_editor/static/lib/summernote/src/js/core/range.js
deleted file mode 100644
index c4a510eced3..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/core/range.js
+++ /dev/null
@@ -1,796 +0,0 @@
-define([
- 'summernote/core/agent',
- 'summernote/core/func',
- 'summernote/core/list',
- 'summernote/core/dom'
-], function (agent, func, list, dom) {
-
- var range = (function () {
-
- /**
- * return boundaryPoint from TextRange, inspired by Andy Na's HuskyRange.js
- *
- * @param {TextRange} textRange
- * @param {Boolean} isStart
- * @return {BoundaryPoint}
- *
- * @see http://msdn.microsoft.com/en-us/library/ie/ms535872(v=vs.85).aspx
- */
- var textRangeToPoint = function (textRange, isStart) {
- var container = textRange.parentElement(), offset;
-
- var tester = document.body.createTextRange(), prevContainer;
- var childNodes = list.from(container.childNodes);
- for (offset = 0; offset < childNodes.length; offset++) {
- if (dom.isText(childNodes[offset])) {
- continue;
- }
- tester.moveToElementText(childNodes[offset]);
- if (tester.compareEndPoints('StartToStart', textRange) >= 0) {
- break;
- }
- prevContainer = childNodes[offset];
- }
-
- if (offset !== 0 && dom.isText(childNodes[offset - 1])) {
- var textRangeStart = document.body.createTextRange(), curTextNode = null;
- textRangeStart.moveToElementText(prevContainer || container);
- textRangeStart.collapse(!prevContainer);
- curTextNode = prevContainer ? prevContainer.nextSibling : container.firstChild;
-
- var pointTester = textRange.duplicate();
- pointTester.setEndPoint('StartToStart', textRangeStart);
- var textCount = pointTester.text.replace(/[\r\n]/g, '').length;
-
- while (textCount > curTextNode.nodeValue.length && curTextNode.nextSibling) {
- textCount -= curTextNode.nodeValue.length;
- curTextNode = curTextNode.nextSibling;
- }
-
- /* jshint ignore:start */
- var dummy = curTextNode.nodeValue; // enforce IE to re-reference curTextNode, hack
- /* jshint ignore:end */
-
- if (isStart && curTextNode.nextSibling && dom.isText(curTextNode.nextSibling) &&
- textCount === curTextNode.nodeValue.length) {
- textCount -= curTextNode.nodeValue.length;
- curTextNode = curTextNode.nextSibling;
- }
-
- container = curTextNode;
- offset = textCount;
- }
-
- return {
- cont: container,
- offset: offset
- };
- };
-
- /**
- * return TextRange from boundary point (inspired by google closure-library)
- * @param {BoundaryPoint} point
- * @return {TextRange}
- */
- var pointToTextRange = function (point) {
- var textRangeInfo = function (container, offset) {
- var node, isCollapseToStart;
-
- if (dom.isText(container)) {
- var prevTextNodes = dom.listPrev(container, func.not(dom.isText));
- var prevContainer = list.last(prevTextNodes).previousSibling;
- node = prevContainer || container.parentNode;
- offset += list.sum(list.tail(prevTextNodes), dom.nodeLength);
- isCollapseToStart = !prevContainer;
- } else {
- node = container.childNodes[offset] || container;
- if (dom.isText(node)) {
- return textRangeInfo(node, 0);
- }
-
- offset = 0;
- isCollapseToStart = false;
- }
-
- return {
- node: node,
- collapseToStart: isCollapseToStart,
- offset: offset
- };
- };
-
- var textRange = document.body.createTextRange();
- var info = textRangeInfo(point.node, point.offset);
-
- textRange.moveToElementText(info.node);
- textRange.collapse(info.collapseToStart);
- textRange.moveStart('character', info.offset);
- return textRange;
- };
-
- /**
- * Wrapped Range
- *
- * @constructor
- * @param {Node} sc - start container
- * @param {Number} so - start offset
- * @param {Node} ec - end container
- * @param {Number} eo - end offset
- */
- var WrappedRange = function (sc, so, ec, eo) {
- this.sc = sc;
- this.so = so;
- this.ec = ec;
- this.eo = eo;
-
- // nativeRange: get nativeRange from sc, so, ec, eo
- var nativeRange = function () {
- if (agent.isW3CRangeSupport) {
- var w3cRange = document.createRange();
- w3cRange.setStart(sc, so);
- w3cRange.setEnd(ec, eo);
-
- return w3cRange;
- } else {
- var textRange = pointToTextRange({
- node: sc,
- offset: so
- });
-
- textRange.setEndPoint('EndToEnd', pointToTextRange({
- node: ec,
- offset: eo
- }));
-
- return textRange;
- }
- };
-
- this.getPoints = function () {
- return {
- sc: sc,
- so: so,
- ec: ec,
- eo: eo
- };
- };
-
- this.getStartPoint = function () {
- return {
- node: sc,
- offset: so
- };
- };
-
- this.getEndPoint = function () {
- return {
- node: ec,
- offset: eo
- };
- };
-
- /**
- * select update visible range
- */
- this.select = function () {
- var nativeRng = nativeRange();
- if (agent.isW3CRangeSupport) {
- var selection = document.getSelection();
- if (selection.rangeCount > 0) {
- selection.removeAllRanges();
- }
- selection.addRange(nativeRng);
- } else {
- nativeRng.select();
- }
-
- return this;
- };
-
- /**
- * @return {WrappedRange}
- */
- this.normalize = function () {
-
- /**
- * @param {BoundaryPoint} point
- * @param {Boolean} isLeftToRight
- * @return {BoundaryPoint}
- */
- var getVisiblePoint = function (point, isLeftToRight) {
- if ((dom.isVisiblePoint(point) && !dom.isEdgePoint(point)) ||
- (dom.isVisiblePoint(point) && dom.isRightEdgePoint(point) && !isLeftToRight) ||
- (dom.isVisiblePoint(point) && dom.isLeftEdgePoint(point) && isLeftToRight) ||
- (dom.isVisiblePoint(point) && dom.isBlock(point.node) && dom.isEmpty(point.node))) {
- return point;
- }
-
- // point on block's edge
- var block = dom.ancestor(point.node, dom.isBlock);
- if (((dom.isLeftEdgePointOf(point, block) || dom.isVoid(dom.prevPoint(point).node)) && !isLeftToRight) ||
- ((dom.isRightEdgePointOf(point, block) || dom.isVoid(dom.nextPoint(point).node)) && isLeftToRight)) {
-
- // returns point already on visible point
- if (dom.isVisiblePoint(point)) {
- return point;
- }
- // reverse direction
- isLeftToRight = !isLeftToRight;
- }
-
- var nextPoint = isLeftToRight ? dom.nextPointUntil(dom.nextPoint(point), dom.isVisiblePoint) :
- dom.prevPointUntil(dom.prevPoint(point), dom.isVisiblePoint);
- return nextPoint || point;
- };
-
- var endPoint = getVisiblePoint(this.getEndPoint(), false);
- var startPoint = this.isCollapsed() ? endPoint : getVisiblePoint(this.getStartPoint(), true);
-
- return new WrappedRange(
- startPoint.node,
- startPoint.offset,
- endPoint.node,
- endPoint.offset
- );
- };
-
- /**
- * returns matched nodes on range
- *
- * @param {Function} [pred] - predicate function
- * @param {Object} [options]
- * @param {Boolean} [options.includeAncestor]
- * @param {Boolean} [options.fullyContains]
- * @return {Node[]}
- */
- this.nodes = function (pred, options) {
- pred = pred || func.ok;
-
- var includeAncestor = options && options.includeAncestor;
- var fullyContains = options && options.fullyContains;
-
- // TODO compare points and sort
- var startPoint = this.getStartPoint();
- var endPoint = this.getEndPoint();
-
- var nodes = [];
- var leftEdgeNodes = [];
-
- dom.walkPoint(startPoint, endPoint, function (point) {
- if (dom.isEditable(point.node)) {
- return;
- }
-
- var node;
- if (fullyContains) {
- if (dom.isLeftEdgePoint(point)) {
- leftEdgeNodes.push(point.node);
- }
- if (dom.isRightEdgePoint(point) && list.contains(leftEdgeNodes, point.node)) {
- node = point.node;
- }
- } else if (includeAncestor) {
- node = dom.ancestor(point.node, pred);
- } else {
- node = point.node;
- }
-
- if (node && pred(node)) {
- nodes.push(node);
- }
- }, true);
-
- return list.unique(nodes);
- };
-
- /**
- * returns commonAncestor of range
- * @return {Element} - commonAncestor
- */
- this.commonAncestor = function () {
- return dom.commonAncestor(sc, ec);
- };
-
- /**
- * returns expanded range by pred
- *
- * @param {Function} pred - predicate function
- * @return {WrappedRange}
- */
- this.expand = function (pred) {
- var startAncestor = dom.ancestor(sc, pred);
- var endAncestor = dom.ancestor(ec, pred);
-
- if (!startAncestor && !endAncestor) {
- return new WrappedRange(sc, so, ec, eo);
- }
-
- var boundaryPoints = this.getPoints();
-
- if (startAncestor) {
- boundaryPoints.sc = startAncestor;
- boundaryPoints.so = 0;
- }
-
- if (endAncestor) {
- boundaryPoints.ec = endAncestor;
- boundaryPoints.eo = dom.nodeLength(endAncestor);
- }
-
- return new WrappedRange(
- boundaryPoints.sc,
- boundaryPoints.so,
- boundaryPoints.ec,
- boundaryPoints.eo
- );
- };
-
- /**
- * @param {Boolean} isCollapseToStart
- * @return {WrappedRange}
- */
- this.collapse = function (isCollapseToStart) {
- if (isCollapseToStart) {
- return new WrappedRange(sc, so, sc, so);
- } else {
- return new WrappedRange(ec, eo, ec, eo);
- }
- };
-
- /**
- * splitText on range
- */
- this.splitText = function () {
- var isSameContainer = sc === ec;
- var boundaryPoints = this.getPoints();
-
- if (dom.isText(ec) && !dom.isEdgePoint(this.getEndPoint())) {
- ec.splitText(eo);
- }
-
- if (dom.isText(sc) && !dom.isEdgePoint(this.getStartPoint())) {
- boundaryPoints.sc = sc.splitText(so);
- boundaryPoints.so = 0;
-
- if (isSameContainer) {
- boundaryPoints.ec = boundaryPoints.sc;
- boundaryPoints.eo = eo - so;
- }
- }
-
- return new WrappedRange(
- boundaryPoints.sc,
- boundaryPoints.so,
- boundaryPoints.ec,
- boundaryPoints.eo
- );
- };
-
- /**
- * delete contents on range
- * @return {WrappedRange}
- */
- if(_.isUndefined(this.deleteContents)) // ODOO: ability to override by prototype
- this.deleteContents = function () {
- if (this.isCollapsed()) {
- return this;
- }
-
- var rng = this.splitText();
- var nodes = rng.nodes(null, {
- fullyContains: true
- });
-
- // find new cursor point
- var point = dom.prevPointUntil(rng.getStartPoint(), function (point) {
- return !list.contains(nodes, point.node);
- });
-
- var emptyParents = [];
- $.each(nodes, function (idx, node) {
- // find empty parents
- var parent = node.parentNode;
- if (point.node !== parent && dom.nodeLength(parent) === 1) {
- emptyParents.push(parent);
- }
- dom.remove(node, false);
- });
-
- // remove empty parents
- $.each(emptyParents, function (idx, node) {
- dom.remove(node, false);
- });
-
- return new WrappedRange(
- point.node,
- point.offset,
- point.node,
- point.offset
- ).normalize();
- };
-
- /**
- * makeIsOn: return isOn(pred) function
- */
- var makeIsOn = function (pred) {
- return function () {
- var ancestor = dom.ancestor(sc, pred);
- return !!ancestor && (ancestor === dom.ancestor(ec, pred));
- };
- };
-
- // isOnEditable: judge whether range is on editable or not
- this.isOnEditable = makeIsOn(dom.isEditable);
- // isOnList: judge whether range is on list node or not
- this.isOnList = makeIsOn(dom.isList);
- // isOnAnchor: judge whether range is on anchor node or not
- this.isOnAnchor = makeIsOn(dom.isAnchor);
- // isOnAnchor: judge whether range is on cell node or not
- this.isOnCell = makeIsOn(dom.isCell);
-
- /**
- * @param {Function} pred
- * @return {Boolean}
- */
- this.isLeftEdgeOf = function (pred) {
- if (!dom.isLeftEdgePoint(this.getStartPoint())) {
- return false;
- }
-
- var node = dom.ancestor(this.sc, pred);
- return node && dom.isLeftEdgeOf(this.sc, node);
- };
-
- /**
- * returns whether range was collapsed or not
- */
- this.isCollapsed = function () {
- return sc === ec && so === eo;
- };
-
- /**
- * wrap inline nodes which children of body with paragraph
- *
- * @return {WrappedRange}
- */
- this.wrapBodyInlineWithPara = function () {
- if (dom.isBodyContainer(sc) && dom.isEmpty(sc)) {
- $(sc).html(dom.emptyPara);
- return new WrappedRange(sc.firstChild, 0, sc.firstChild, 0);
- }
-
- /**
- * [workaround] firefox often create range on not visible point. so normalize here.
- * - firefox: |text
|
- * - chrome: |text|
- */
- var rng = this.normalize();
- if (dom.isParaInline(sc) || dom.isPara(sc)) {
- return rng;
- }
-
- // ODOO: insert a p tag when try to insert a br with insertNode method, if the editor is inside a p, li, h1... (start_modification
- // if apply the editor to a P, LI... or inside a P, LI...
- if (dom.isText(sc)) {
- var node = sc;
- while (node.parentNode !== document) {
- node = node.parentNode;
- if (/^(P|LI|H[1-7]|BUTTON|A|SPAN)/.test(node.nodeName.toUpperCase())) {
- return this.normalize();
- }
- }
- }
- // ODOO: end_modification)
-
- // find inline top ancestor
- var topAncestor;
- if (dom.isInline(rng.sc)) {
- var ancestors = dom.listAncestor(rng.sc, func.not(dom.isInline));
- topAncestor = list.last(ancestors);
- if (!dom.isInline(topAncestor)) {
- topAncestor = ancestors[ancestors.length - 2] || rng.sc.childNodes[rng.so];
- }
- } else {
- topAncestor = rng.sc.childNodes[rng.so > 0 ? rng.so - 1 : 0];
- }
-
- // siblings not in paragraph
- var inlineSiblings = dom.listPrev(topAncestor, dom.isParaInline).reverse();
- inlineSiblings = inlineSiblings.concat(dom.listNext(topAncestor.nextSibling, dom.isParaInline));
-
- // wrap with paragraph
- if (inlineSiblings.length) {
- var para = dom.wrap(list.head(inlineSiblings), 'p');
- dom.appendChildNodes(para, list.tail(inlineSiblings));
- }
-
- return this.normalize();
- };
-
- /**
- * insert node at current cursor
- *
- * @param {Node} node
- * @return {Node}
- */
- this.insertNode = function (node) {
- var rng = this.wrapBodyInlineWithPara().deleteContents();
- // ODOO: override to not split world for inserting inline
- // original: var info = dom.splitPoint(rng.getStartPoint(), dom.isInline(node));
- var info = dom.splitPoint(rng.getStartPoint(), !dom.isBodyContainer(dom.ancestor(rng.sc, function(node) { return dom.isBodyContainer(node) || dom.isPara(node) })));
-
- if (info.rightNode) {
- info.rightNode.parentNode.insertBefore(node, info.rightNode);
- } else {
- info.container.appendChild(node);
- }
-
- return node;
- };
-
- /**
- * insert html at current cursor
- */
- this.pasteHTML = function (markup) {
- var contentsContainer = $('
').html(markup)[0];
- var childNodes = list.from(contentsContainer.childNodes);
-
- var rng = this.wrapBodyInlineWithPara().deleteContents();
-
- return childNodes.reverse().map(function (childNode) {
- return rng.insertNode(childNode);
- }).reverse();
- };
-
- /**
- * returns text in range
- *
- * @return {String}
- */
- this.toString = function () {
- var nativeRng = nativeRange();
- return agent.isW3CRangeSupport ? nativeRng.toString() : nativeRng.text;
- };
-
- /**
- * returns range for word before cursor
- *
- * @param {Boolean} [findAfter] - find after cursor, default: false
- * @return {WrappedRange}
- */
- this.getWordRange = function (findAfter) {
- var endPoint = this.getEndPoint();
-
- if (!dom.isCharPoint(endPoint)) {
- return this;
- }
-
- var startPoint = dom.prevPointUntil(endPoint, function (point) {
- return !dom.isCharPoint(point);
- });
-
- if (findAfter) {
- endPoint = dom.nextPointUntil(endPoint, function (point) {
- return !dom.isCharPoint(point);
- });
- }
-
- return new WrappedRange(
- startPoint.node,
- startPoint.offset,
- endPoint.node,
- endPoint.offset
- );
- };
-
- /**
- * create offsetPath bookmark
- *
- * @param {Node} editable
- */
- this.bookmark = function (editable) {
- return {
- s: {
- path: dom.makeOffsetPath(editable, sc),
- offset: so
- },
- e: {
- path: dom.makeOffsetPath(editable, ec),
- offset: eo
- }
- };
- };
-
- /**
- * create offsetPath bookmark base on paragraph
- *
- * @param {Node[]} paras
- */
- this.paraBookmark = function (paras) {
- return {
- s: {
- path: list.tail(dom.makeOffsetPath(list.head(paras), sc)),
- offset: so
- },
- e: {
- path: list.tail(dom.makeOffsetPath(list.last(paras), ec)),
- offset: eo
- }
- };
- };
-
- /**
- * getClientRects
- * @return {Rect[]}
- */
- this.getClientRects = function () {
- var nativeRng = nativeRange();
- return nativeRng.getClientRects();
- };
- };
-
- /**
- * @class core.range
- *
- * Data structure
- * * BoundaryPoint: a point of dom tree
- * * BoundaryPoints: two boundaryPoints corresponding to the start and the end of the Range
- *
- * See to http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Position
- *
- * @singleton
- * @alternateClassName range
- */
- return {
- WrappedRange: WrappedRange, // ODOO: give access to WrappedRange
- /**
- * @method
- *
- * create Range Object From arguments or Browser Selection
- *
- * @param {Node} sc - start container
- * @param {Number} so - start offset
- * @param {Node} ec - end container
- * @param {Number} eo - end offset
- * @return {WrappedRange}
- */
- create : function (sc, so, ec, eo) {
- if (!arguments.length) { // from Browser Selection
- if (agent.isW3CRangeSupport) {
- var selection = document.getSelection();
- if (!selection || selection.rangeCount === 0) {
- return null;
- } else {
- try {
- if (dom.isBody(selection.anchorNode)) {
- // Firefox: returns entire body as range on initialization. We won't never need it.
- return null;
- }
- } catch (e) {
- return null;
- }
- }
-
- var nativeRng = selection.getRangeAt(0);
- sc = nativeRng.startContainer;
- so = nativeRng.startOffset;
- ec = nativeRng.endContainer;
- eo = nativeRng.endOffset;
- } else { // IE8: TextRange
- var textRange = document.selection.createRange();
- var textRangeEnd = textRange.duplicate();
- textRangeEnd.collapse(false);
- var textRangeStart = textRange;
- textRangeStart.collapse(true);
-
- var startPoint = textRangeToPoint(textRangeStart, true),
- endPoint = textRangeToPoint(textRangeEnd, false);
-
- // same visible point case: range was collapsed.
- if (dom.isText(startPoint.node) && dom.isLeftEdgePoint(startPoint) &&
- dom.isTextNode(endPoint.node) && dom.isRightEdgePoint(endPoint) &&
- endPoint.node.nextSibling === startPoint.node) {
- startPoint = endPoint;
- }
-
- sc = startPoint.cont;
- so = startPoint.offset;
- ec = endPoint.cont;
- eo = endPoint.offset;
- }
- } else if (arguments.length === 2) { //collapsed
- ec = sc;
- eo = so;
- }
- return new WrappedRange(sc, so, ec, eo);
- },
-
- /**
- * @method
- *
- * create WrappedRange from node
- *
- * @param {Node} node
- * @return {WrappedRange}
- */
- createFromNode: function (node) {
- var sc = node;
- var so = 0;
- var ec = node;
- var eo = dom.nodeLength(ec);
-
- // browsers can't target a picture or void node
- if (dom.isVoid(sc)) {
- so = dom.listPrev(sc).length - 1;
- sc = sc.parentNode;
- }
- if (dom.isBR(ec)) {
- eo = dom.listPrev(ec).length - 1;
- ec = ec.parentNode;
- } else if (dom.isVoid(ec)) {
- eo = dom.listPrev(ec).length;
- ec = ec.parentNode;
- }
-
- return this.create(sc, so, ec, eo);
- },
-
- /**
- * create WrappedRange from node after position
- *
- * @param {Node} node
- * @return {WrappedRange}
- */
- createFromNodeBefore: function (node) {
- return this.createFromNode(node).collapse(true);
- },
-
- /**
- * create WrappedRange from node after position
- *
- * @param {Node} node
- * @return {WrappedRange}
- */
- createFromNodeAfter: function (node) {
- return this.createFromNode(node).collapse();
- },
-
- /**
- * @method
- *
- * create WrappedRange from bookmark
- *
- * @param {Node} editable
- * @param {Object} bookmark
- * @return {WrappedRange}
- */
- createFromBookmark : function (editable, bookmark) {
- var sc = dom.fromOffsetPath(editable, bookmark.s.path);
- var so = bookmark.s.offset;
- var ec = dom.fromOffsetPath(editable, bookmark.e.path);
- var eo = bookmark.e.offset;
- return new WrappedRange(sc, so, ec, eo);
- },
-
- /**
- * @method
- *
- * create WrappedRange from paraBookmark
- *
- * @param {Object} bookmark
- * @param {Node[]} paras
- * @return {WrappedRange}
- */
- createFromParaBookmark: function (bookmark, paras) {
- var so = bookmark.s.offset;
- var eo = bookmark.e.offset;
- var sc = dom.fromOffsetPath(list.head(paras), bookmark.s.path);
- var ec = dom.fromOffsetPath(list.last(paras), bookmark.e.path);
-
- return new WrappedRange(sc, so, ec, eo);
- }
- };
- })();
-
- return range;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/defaults.js b/addons/web_editor/static/lib/summernote/src/js/defaults.js
deleted file mode 100644
index 9d8e0bab661..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/defaults.js
+++ /dev/null
@@ -1,416 +0,0 @@
-define('summernote/defaults', function () {
- /**
- * @class defaults
- *
- * @singleton
- */
- var defaults = {
- /** @property */
- version: '@VERSION',
-
- /**
- *
- * for event options, reference to EventHandler.attach
- *
- * @property {Object} options
- * @property {String/Number} [options.width=null] set editor width
- * @property {String/Number} [options.height=null] set editor height, ex) 300
- * @property {String/Number} options.minHeight set minimum height of editor
- * @property {String/Number} options.maxHeight
- * @property {String/Number} options.focus
- * @property {Number} options.tabsize
- * @property {Boolean} options.styleWithSpan
- * @property {Object} options.codemirror
- * @property {Object} [options.codemirror.mode='text/html']
- * @property {Object} [options.codemirror.htmlMode=true]
- * @property {Object} [options.codemirror.lineNumbers=true]
- * @property {String} [options.lang=en-US] language 'en-US', 'ko-KR', ...
- * @property {String} [options.direction=null] text direction, ex) 'rtl'
- * @property {Array} [options.toolbar]
- * @property {Boolean} [options.airMode=false]
- * @property {Array} [options.airPopover]
- * @property {Fucntion} [options.onInit] initialize
- * @property {Fucntion} [options.onsubmit]
- */
- options: {
- width: null, // set editor width
- height: null, // set editor height, ex) 300
-
- minHeight: null, // set minimum height of editor
- maxHeight: null, // set maximum height of editor
-
- focus: false, // set focus to editable area after initializing summernote
-
- tabsize: 4, // size of tab ex) 2 or 4
- styleWithSpan: true, // style with span (Chrome and FF only)
-
- disableLinkTarget: false, // hide link Target Checkbox
- disableDragAndDrop: false, // disable drag and drop event
- disableResizeEditor: false, // disable resizing editor
- disableResizeImage: false, // disable resizing image
-
- shortcuts: true, // enable keyboard shortcuts
-
- textareaAutoSync: true, // enable textarea auto sync
-
- placeholder: false, // enable placeholder text
- prettifyHtml: true, // enable prettifying html while toggling codeview
-
- iconPrefix: 'fa fa-', // prefix for css icon classes
-
- icons: {
- font: {
- bold: 'bold',
- italic: 'italic',
- underline: 'underline',
- clear: 'eraser',
- height: 'text-height',
- strikethrough: 'strikethrough',
- superscript: 'superscript',
- subscript: 'subscript'
- },
- image: {
- image: 'picture-o',
- floatLeft: 'align-left',
- floatRight: 'align-right',
- floatNone: 'align-justify',
- shapeRounded: 'square',
- shapeCircle: 'circle-o',
- shapeThumbnail: 'picture-o',
- shapeNone: 'times',
- remove: 'trash-o'
- },
- link: {
- link: 'link',
- unlink: 'unlink',
- edit: 'edit'
- },
- table: {
- table: 'table'
- },
- hr: {
- insert: 'minus'
- },
- style: {
- style: 'magic'
- },
- lists: {
- unordered: 'list-ul',
- ordered: 'list-ol'
- },
- options: {
- help: 'question',
- fullscreen: 'arrows-alt',
- codeview: 'code'
- },
- paragraph: {
- paragraph: 'align-left',
- outdent: 'outdent',
- indent: 'indent',
- left: 'align-left',
- center: 'align-center',
- right: 'align-right',
- justify: 'align-justify'
- },
- color: {
- recent: 'font'
- },
- history: {
- undo: 'undo',
- redo: 'repeat'
- },
- misc: {
- check: 'check'
- }
- },
-
- dialogsInBody: false, // false will add dialogs into editor
-
- codemirror: { // codemirror options
- mode: 'text/html',
- htmlMode: true,
- lineNumbers: true
- },
-
- // language
- lang: 'en-US', // language 'en-US', 'ko-KR', ...
- direction: null, // text direction, ex) 'rtl'
-
- // toolbar
- toolbar: [
- ['style', ['style']],
- ['font', ['bold', 'italic', 'underline', 'clear']],
- // ['font', ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']],
- ['fontname', ['fontname']],
- ['fontsize', ['fontsize']],
- ['color', ['color']],
- ['para', ['ul', 'ol', 'paragraph']],
- ['height', ['height']],
- ['table', ['table']],
- ['insert', ['link', 'picture', 'hr']],
- ['view', ['fullscreen', 'codeview']],
- ['help', ['help']]
- ],
-
- plugin : { },
-
- // air mode: inline editor
- airMode: false,
- // airPopover: [
- // ['style', ['style']],
- // ['font', ['bold', 'italic', 'underline', 'clear']],
- // ['fontname', ['fontname']],
- // ['color', ['color']],
- // ['para', ['ul', 'ol', 'paragraph']],
- // ['height', ['height']],
- // ['table', ['table']],
- // ['insert', ['link', 'picture']],
- // ['help', ['help']]
- // ],
- airPopover: [
- ['color', ['color']],
- ['font', ['bold', 'underline', 'clear']],
- ['para', ['ul', 'paragraph']],
- ['table', ['table']],
- ['insert', ['link', 'picture']]
- ],
-
- // style tag
- styleTags: ['p', 'blockquote', 'pre', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
-
- // default fontName
- defaultFontName: 'Helvetica Neue',
-
- // fontName
- fontNames: [
- 'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New',
- 'Helvetica Neue', 'Helvetica', 'Impact', 'Lucida Grande',
- 'Tahoma', 'Times New Roman', 'Verdana'
- ],
- fontNamesIgnoreCheck: [],
-
- fontSizes: ['8', '9', '10', '11', '12', '14', '18', '24', '36'],
-
- // pallete colors(n x n)
- colors: [
- ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'],
- ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],
- ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],
- ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],
- ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],
- ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],
- ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],
- ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']
- ],
-
- // lineHeight
- lineHeights: ['1.0', '1.2', '1.4', '1.5', '1.6', '1.8', '2.0', '3.0'],
-
- // insertTable max size
- insertTableMaxSize: {
- col: 10,
- row: 10
- },
-
- // image
- maximumImageFileSize: null, // size in bytes, null = no limit
-
- // callbacks
- oninit: null, // initialize
- onfocus: null, // editable has focus
- onblur: null, // editable out of focus
- onenter: null, // enter key pressed
- onkeyup: null, // keyup
- onkeydown: null, // keydown
- onImageUpload: null, // imageUpload
- onImageUploadError: null, // imageUploadError
- onMediaDelete: null, // media delete
- onToolbarClick: null,
- onsubmit: null,
-
- /**
- * manipulate link address when user create link
- * @param {String} sLinkUrl
- * @return {String}
- */
- onCreateLink: function (sLinkUrl) {
- if (sLinkUrl.indexOf('@') !== -1 && sLinkUrl.indexOf(':') === -1) {
- sLinkUrl = 'mailto:' + sLinkUrl;
- }
-
- return sLinkUrl;
- },
-
- keyMap: {
- pc: {
- 'ENTER': 'insertParagraph',
- 'CTRL+Z': 'undo',
- 'CTRL+Y': 'redo',
- 'TAB': 'tab',
- 'SHIFT+TAB': 'untab',
- 'CTRL+B': 'bold',
- 'CTRL+I': 'italic',
- 'CTRL+U': 'underline',
- 'CTRL+SHIFT+S': 'strikethrough',
- 'CTRL+BACKSLASH': 'removeFormat',
- 'CTRL+SHIFT+L': 'justifyLeft',
- 'CTRL+SHIFT+E': 'justifyCenter',
- 'CTRL+SHIFT+R': 'justifyRight',
- 'CTRL+SHIFT+J': 'justifyFull',
- 'CTRL+SHIFT+NUM7': 'insertUnorderedList',
- 'CTRL+SHIFT+NUM8': 'insertOrderedList',
- 'CTRL+LEFTBRACKET': 'outdent',
- 'CTRL+RIGHTBRACKET': 'indent',
- 'CTRL+NUM0': 'formatPara',
- 'CTRL+NUM1': 'formatH1',
- 'CTRL+NUM2': 'formatH2',
- 'CTRL+NUM3': 'formatH3',
- 'CTRL+NUM4': 'formatH4',
- 'CTRL+NUM5': 'formatH5',
- 'CTRL+NUM6': 'formatH6',
- 'CTRL+ENTER': 'insertHorizontalRule',
- 'CTRL+K': 'showLinkDialog'
- },
-
- mac: {
- 'ENTER': 'insertParagraph',
- 'CMD+Z': 'undo',
- 'CMD+SHIFT+Z': 'redo',
- 'TAB': 'tab',
- 'SHIFT+TAB': 'untab',
- 'CMD+B': 'bold',
- 'CMD+I': 'italic',
- 'CMD+U': 'underline',
- 'CMD+SHIFT+S': 'strikethrough',
- 'CMD+BACKSLASH': 'removeFormat',
- 'CMD+SHIFT+L': 'justifyLeft',
- 'CMD+SHIFT+E': 'justifyCenter',
- 'CMD+SHIFT+R': 'justifyRight',
- 'CMD+SHIFT+J': 'justifyFull',
- 'CMD+SHIFT+NUM7': 'insertUnorderedList',
- 'CMD+SHIFT+NUM8': 'insertOrderedList',
- 'CMD+LEFTBRACKET': 'outdent',
- 'CMD+RIGHTBRACKET': 'indent',
- 'CMD+NUM0': 'formatPara',
- 'CMD+NUM1': 'formatH1',
- 'CMD+NUM2': 'formatH2',
- 'CMD+NUM3': 'formatH3',
- 'CMD+NUM4': 'formatH4',
- 'CMD+NUM5': 'formatH5',
- 'CMD+NUM6': 'formatH6',
- 'CMD+ENTER': 'insertHorizontalRule',
- 'CMD+K': 'showLinkDialog'
- }
- }
- },
-
- // default language: en-US
- lang: {
- 'en-US': {
- font: {
- bold: 'Bold',
- italic: 'Italic',
- underline: 'Underline',
- clear: 'Remove Font Style',
- height: 'Line Height',
- name: 'Font Family',
- strikethrough: 'Strikethrough',
- subscript: 'Subscript',
- superscript: 'Superscript',
- size: 'Font Size'
- },
- image: {
- image: 'Picture',
- insert: 'Insert Image',
- resizeFull: 'Resize Full',
- resizeHalf: 'Resize Half',
- resizeQuarter: 'Resize Quarter',
- floatLeft: 'Float Left',
- floatRight: 'Float Right',
- floatNone: 'Float None',
- shapeRounded: 'Shape: Rounded',
- shapeCircle: 'Shape: Circle',
- shapeThumbnail: 'Shape: Thumbnail',
- shapeNone: 'Shape: None',
- dragImageHere: 'Drag image or text here',
- dropImage: 'Drop image or Text',
- selectFromFiles: 'Select from files',
- maximumFileSize: 'Maximum file size',
- maximumFileSizeError: 'Maximum file size exceeded.',
- url: 'Image URL',
- remove: 'Remove Image'
- },
- link: {
- link: 'Link',
- insert: 'Insert Link',
- unlink: 'Unlink',
- edit: 'Edit',
- textToDisplay: 'Text to display',
- url: 'To what URL should this link go?',
- openInNewWindow: 'Open in new window'
- },
- table: {
- table: 'Table'
- },
- hr: {
- insert: 'Insert Horizontal Rule'
- },
- style: {
- style: 'Style',
- normal: 'Paragraph',
- blockquote: 'Quote',
- pre: 'Code',
- h1: 'Header 1',
- h2: 'Header 2',
- h3: 'Header 3',
- h4: 'Header 4',
- h5: 'Header 5',
- h6: 'Header 6'
- },
- lists: {
- unordered: 'Unordered list',
- ordered: 'Ordered list'
- },
- options: {
- help: 'Help',
- fullscreen: 'Full Screen',
- codeview: 'Code View'
- },
- paragraph: {
- paragraph: 'Paragraph',
- outdent: 'Outdent',
- indent: 'Indent',
- left: 'Align left',
- center: 'Align center',
- right: 'Align right',
- justify: 'Justify full'
- },
- color: {
- recent: 'Recent Color',
- more: 'More Color',
- background: 'Background Color',
- foreground: 'Foreground Color',
- transparent: 'Transparent',
- setTransparent: 'Set transparent',
- reset: 'Reset',
- resetToDefault: 'Reset to default'
- },
- shortcut: {
- shortcuts: 'Keyboard shortcuts',
- close: 'Close',
- textFormatting: 'Text formatting',
- action: 'Action',
- paragraphFormatting: 'Paragraph formatting',
- documentStyle: 'Document Style',
- extraKeys: 'Extra keys'
- },
- history: {
- undo: 'Undo',
- redo: 'Redo'
- }
- }
- }
- };
-
- return defaults;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/editing/Bullet.js b/addons/web_editor/static/lib/summernote/src/js/editing/Bullet.js
deleted file mode 100644
index 6a115edaa90..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/editing/Bullet.js
+++ /dev/null
@@ -1,235 +0,0 @@
-define([
- 'summernote/core/list',
- 'summernote/core/func',
- 'summernote/core/dom',
- 'summernote/core/range'
-], function (list, func, dom, range) {
-
- /**
- * @class editing.Bullet
- *
- * @alternateClassName Bullet
- */
- var Bullet = function () {
- /**
- * @method insertOrderedList
- *
- * toggle ordered list
- *
- * @type command
- */
- this.insertOrderedList = function () {
- this.toggleList('OL');
- };
-
- /**
- * @method insertUnorderedList
- *
- * toggle unordered list
- *
- * @type command
- */
- this.insertUnorderedList = function () {
- this.toggleList('UL');
- };
-
- /**
- * @method indent
- *
- * indent
- *
- * @type command
- */
- this.indent = function () {
- var self = this;
- var rng = range.create().wrapBodyInlineWithPara();
-
- var paras = rng.nodes(dom.isPara, { includeAncestor: true });
- var clustereds = list.clusterBy(paras, func.peq2('parentNode'));
-
- $.each(clustereds, function (idx, paras) {
- var head = list.head(paras);
- if (dom.isLi(head)) {
- self.wrapList(paras, head.parentNode.nodeName);
- } else {
- $.each(paras, function (idx, para) {
- $(para).css('marginLeft', function (idx, val) {
- return (parseInt(val, 10) || 0) + 25;
- });
- });
- }
- });
-
- rng.select();
- };
-
- /**
- * @method outdent
- *
- * outdent
- *
- * @type command
- */
- this.outdent = function () {
- var self = this;
- var rng = range.create().wrapBodyInlineWithPara();
-
- var paras = rng.nodes(dom.isPara, { includeAncestor: true });
- var clustereds = list.clusterBy(paras, func.peq2('parentNode'));
-
- $.each(clustereds, function (idx, paras) {
- var head = list.head(paras);
- if (dom.isLi(head)) {
- self.releaseList([paras]);
- } else {
- $.each(paras, function (idx, para) {
- $(para).css('marginLeft', function (idx, val) {
- val = (parseInt(val, 10) || 0);
- return val > 25 ? val - 25 : '';
- });
- });
- }
- });
-
- rng.select();
- };
-
- /**
- * @method toggleList
- *
- * toggle list
- *
- * @param {String} listName - OL or UL
- */
- this.toggleList = function (listName) {
- var self = this;
- var rng = range.create().wrapBodyInlineWithPara();
-
- var paras = rng.nodes(dom.isPara, { includeAncestor: true });
- var bookmark = rng.paraBookmark(paras);
- var clustereds = list.clusterBy(paras, func.peq2('parentNode'));
-
- // paragraph to list
- if (list.find(paras, dom.isPurePara)) {
- var wrappedParas = [];
- $.each(clustereds, function (idx, paras) {
- wrappedParas = wrappedParas.concat(self.wrapList(paras, listName));
- });
- paras = wrappedParas;
- // list to paragraph or change list style
- } else {
- var diffLists = rng.nodes(dom.isList, {
- includeAncestor: true
- }).filter(function (listNode) {
- return !$.nodeName(listNode, listName);
- });
-
- if (diffLists.length) {
- $.each(diffLists, function (idx, listNode) {
- dom.replace(listNode, listName);
- });
- } else {
- paras = this.releaseList(clustereds, true);
- }
- }
-
- range.createFromParaBookmark(bookmark, paras).select();
- };
-
- /**
- * @method wrapList
- *
- * @param {Node[]} paras
- * @param {String} listName
- * @return {Node[]}
- */
- this.wrapList = function (paras, listName) {
- var head = list.head(paras);
- var last = list.last(paras);
-
- var prevList = dom.isList(head.previousSibling) && head.previousSibling;
- var nextList = dom.isList(last.nextSibling) && last.nextSibling;
-
- var listNode = prevList || dom.insertAfter(dom.create(listName || 'UL'), last);
-
- // P to LI
- paras = paras.map(function (para) {
- return dom.isPurePara(para) ? dom.replace(para, 'LI') : para;
- });
-
- // append to list(, )
- dom.appendChildNodes(listNode, paras);
-
- if (nextList) {
- dom.appendChildNodes(listNode, list.from(nextList.childNodes));
- dom.remove(nextList);
- }
-
- return paras;
- };
-
- /**
- * @method releaseList
- *
- * @param {Array[]} clustereds
- * @param {Boolean} isEscapseToBody
- * @return {Node[]}
- */
- this.releaseList = function (clustereds, isEscapseToBody) {
- var releasedParas = [];
-
- $.each(clustereds, function (idx, paras) {
- var head = list.head(paras);
- var last = list.last(paras);
-
- var headList = isEscapseToBody ? dom.lastAncestor(head, dom.isList) :
- head.parentNode;
- var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {
- node: last.parentNode,
- offset: dom.position(last) + 1
- }, {
- isSkipPaddingBlankHTML: true
- }) : null;
-
- var middleList = dom.splitTree(headList, {
- node: head.parentNode,
- offset: dom.position(head)
- }, {
- isSkipPaddingBlankHTML: true
- });
-
- paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) :
- list.from(middleList.childNodes).filter(dom.isLi);
-
- // LI to P
- if (isEscapseToBody || !dom.isList(headList.parentNode)) {
- paras = paras.map(function (para) {
- return dom.replace(para, 'P');
- });
- }
-
- $.each(list.from(paras).reverse(), function (idx, para) {
- dom.insertAfter(para, headList);
- });
-
- // remove empty lists
- var rootLists = list.compact([headList, middleList, lastList]);
- $.each(rootLists, function (idx, rootList) {
- var listNodes = [rootList].concat(dom.listDescendant(rootList, dom.isList));
- $.each(listNodes.reverse(), function (idx, listNode) {
- if (!dom.nodeLength(listNode)) {
- dom.remove(listNode, true);
- }
- });
- });
-
- releasedParas = releasedParas.concat(paras);
- });
-
- return releasedParas;
- };
- };
-
- return Bullet;
-});
-
diff --git a/addons/web_editor/static/lib/summernote/src/js/editing/History.js b/addons/web_editor/static/lib/summernote/src/js/editing/History.js
deleted file mode 100644
index 2cc946488c2..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/editing/History.js
+++ /dev/null
@@ -1,118 +0,0 @@
-define(['summernote/core/range', 'summernote/core/dom'], function (range, dom) { // ODOO: suggest upstream
- /**
- * @class editing.History
- *
- * Editor History
- *
- */
- var History = function ($editable) {
- var stack = [], stackOffset = -1;
- var editable = $editable[0];
-
- var makeSnapshot = function () {
- var rng = range.create();
- var emptyBookmark = {s: {path: [], offset: 0}, e: {path: [], offset: 0}};
-
- return {
- contents: $editable.html(),
- bookmark: (rng && dom.ancestor(rng.sc, dom.isEditable) ? rng.bookmark(editable) : emptyBookmark)
- // ODOO: suggest upstream added " && dom.ancestor(rng.sc, dom.isEditable) "
- };
- };
-
- var applySnapshot = function (snapshot) {
- if (snapshot.contents !== null) {
- $editable.html(snapshot.contents);
- }
- if (snapshot.bookmark !== null) {
- range.createFromBookmark(editable, snapshot.bookmark).select();
- }
- };
-
- /**
- * undo
- */
- this.undo = function () {
- // Create snap shot if not yet recorded
- if ($editable.html() !== stack[stackOffset].contents) {
- this.recordUndo();
- }
-
- if (0 < stackOffset) {
- stackOffset--;
- applySnapshot(stack[stackOffset]);
- }
- };
-
- /* ODOO: to suggest upstream */
- this.hasUndo = function () {
- return 0 < stackOffset;
- };
-
- /**
- * redo
- */
- this.redo = function () {
- if (stack.length - 1 > stackOffset) {
- stackOffset++;
- applySnapshot(stack[stackOffset]);
- }
- };
-
- /* ODOO: to suggest upstream */
- this.hasRedo = function () {
- return stack.length - 1 > stackOffset;
- };
-
- var last; // ODOO: to suggest upstream (since we may have several editor)
- /**
- * recorded undo
- */
- this.recordUndo = function () {
- // ODOO: method totally rewritten
- // test event for firefox: remove stack of history because event doesn't exists
- var key = typeof event !== 'undefined' ? event : false;
- if (key && !event.metaKey && !event.ctrlKey && !event.altKey && event.type === "keydown") {
- key = event.type + "-";
- if (event.which === 8 || event.which === 46) key += 'delete';
- else if (event.which === 13) key += 'enter';
- else key += 'other';
- if (key === last) return;
- hasUndo = true;
- }
- last = key;
-
- // Wash out stack after stackOffset
- if (stack.length > stackOffset+1) {
- stack = stack.slice(0, stackOffset+1);
- }
-
- if (stack[stackOffset] && stack[stackOffset].contents === $editable.html()) {
- return;
- }
-
- stackOffset++;
-
- // Create new snapshot and push it to the end
- stack.push(makeSnapshot());
- };
-
- /* ODOO: to suggest upstream */
- this.splitNext = function () {
- last = false;
- };
-
- /* ODOO: to suggest upstream */
- this.reset = function () {
- last = false;
- stack = [];
- stackOffset = -1;
- this.recordUndo();
- };
-
- // Create first undo stack
- this.recordUndo();
- };
-
- return History;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/editing/Style.js b/addons/web_editor/static/lib/summernote/src/js/editing/Style.js
deleted file mode 100644
index bf749cd817b..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/editing/Style.js
+++ /dev/null
@@ -1,161 +0,0 @@
-define([
- 'summernote/core/agent',
- 'summernote/core/func',
- 'summernote/core/list',
- 'summernote/core/dom'
-], function (agent, func, list, dom) {
- /**
- * @class editing.Style
- *
- * Style
- *
- */
- var Style = function () {
- /**
- * @method jQueryCSS
- *
- * [workaround] for old jQuery
- * passing an array of style properties to .css()
- * will result in an object of property-value pairs.
- * (compability with version < 1.9)
- *
- * @private
- * @param {jQuery} $obj
- * @param {Array} propertyNames - An array of one or more CSS properties.
- * @return {Object}
- */
- var jQueryCSS = function ($obj, propertyNames) {
- if (agent.jqueryVersion < 1.9) {
- var result = {};
- $.each(propertyNames, function (idx, propertyName) {
- result[propertyName] = $obj.css(propertyName);
- });
- return result;
- }
- return $obj.css.call($obj, propertyNames);
- };
-
- /**
- * returns style object from node
- *
- * @param {jQuery} $node
- * @return {Object}
- */
- this.fromNode = function ($node) {
- var properties = ['font-family', 'font-size', 'text-align', 'list-style-type', 'line-height'];
- var styleInfo = jQueryCSS($node, properties) || {};
- styleInfo['font-size'] = parseInt(styleInfo['font-size'], 10);
- return styleInfo;
- };
-
- /**
- * paragraph level style
- *
- * @param {WrappedRange} rng
- * @param {Object} styleInfo
- */
- this.stylePara = function (rng, styleInfo) {
- $.each(rng.nodes(dom.isPara, {
- includeAncestor: true
- }), function (idx, para) {
- $(para).css(styleInfo);
- });
- };
-
- /**
- * insert and returns styleNodes on range.
- *
- * @param {WrappedRange} rng
- * @param {Object} [options] - options for styleNodes
- * @param {String} [options.nodeName] - default: `SPAN`
- * @param {Boolean} [options.expandClosestSibling] - default: `false`
- * @param {Boolean} [options.onlyPartialContains] - default: `false`
- * @return {Node[]}
- */
- this.styleNodes = function (rng, options) {
- rng = rng.splitText();
-
- var nodeName = options && options.nodeName || 'SPAN';
- var expandClosestSibling = !!(options && options.expandClosestSibling);
- var onlyPartialContains = !!(options && options.onlyPartialContains);
-
- if (rng.isCollapsed()) {
- return [rng.insertNode(dom.create(nodeName))];
- }
-
- var pred = dom.makePredByNodeName(nodeName);
- var nodes = rng.nodes(dom.isText, {
- fullyContains: true
- }).map(function (text) {
- return dom.singleChildAncestor(text, pred) || dom.wrap(text, nodeName);
- });
-
- if (expandClosestSibling) {
- if (onlyPartialContains) {
- var nodesInRange = rng.nodes();
- // compose with partial contains predication
- pred = func.and(pred, function (node) {
- return list.contains(nodesInRange, node);
- });
- }
-
- return nodes.map(function (node) {
- var siblings = dom.withClosestSiblings(node, pred);
- var head = list.head(siblings);
- var tails = list.tail(siblings);
- $.each(tails, function (idx, elem) {
- dom.appendChildNodes(head, elem.childNodes);
- dom.remove(elem);
- });
- return list.head(siblings);
- });
- } else {
- return nodes;
- }
- };
-
- /**
- * get current style on cursor
- *
- * @param {WrappedRange} rng
- * @return {Object} - object contains style properties.
- */
- this.current = function (rng) {
- var $cont = $(dom.isText(rng.sc) ? rng.sc.parentNode : rng.sc);
- var styleInfo = this.fromNode($cont);
-
- // document.queryCommandState for toggle state
- styleInfo['font-bold'] = document.queryCommandState('bold') ? 'bold' : 'normal';
- styleInfo['font-italic'] = document.queryCommandState('italic') ? 'italic' : 'normal';
- styleInfo['font-underline'] = document.queryCommandState('underline') ? 'underline' : 'normal';
- styleInfo['font-strikethrough'] = document.queryCommandState('strikeThrough') ? 'strikethrough' : 'normal';
- styleInfo['font-superscript'] = document.queryCommandState('superscript') ? 'superscript' : 'normal';
- styleInfo['font-subscript'] = document.queryCommandState('subscript') ? 'subscript' : 'normal';
-
- // list-style-type to list-style(unordered, ordered)
- if (!rng.isOnList()) {
- styleInfo['list-style'] = 'none';
- } else {
- var aOrderedType = ['circle', 'disc', 'disc-leading-zero', 'square'];
- var isUnordered = $.inArray(styleInfo['list-style-type'], aOrderedType) > -1;
- styleInfo['list-style'] = isUnordered ? 'unordered' : 'ordered';
- }
-
- var para = dom.ancestor(rng.sc, dom.isPara);
- if (para && para.style['line-height']) {
- styleInfo['line-height'] = para.style.lineHeight;
- } else {
- var lineHeight = parseInt(styleInfo['line-height'], 10) / parseInt(styleInfo['font-size'], 10);
- styleInfo['line-height'] = lineHeight.toFixed(1);
- }
-
- styleInfo.anchor = rng.isOnAnchor() && dom.ancestor(rng.sc, dom.isAnchor);
- styleInfo.ancestors = dom.listAncestor(rng.sc, dom.isEditable);
- styleInfo.range = rng;
-
- return styleInfo;
- };
- };
-
- return Style;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/editing/Table.js b/addons/web_editor/static/lib/summernote/src/js/editing/Table.js
deleted file mode 100644
index 634d5a79d7e..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/editing/Table.js
+++ /dev/null
@@ -1,52 +0,0 @@
-define([
- 'summernote/core/dom', 'summernote/core/range', 'summernote/core/list'
-], function (dom, range, list) {
- /**
- * @class editing.Table
- *
- * Table
- *
- */
- var Table = function () {
- /**
- * handle tab key
- *
- * @param {WrappedRange} rng
- * @param {Boolean} isShift
- */
- this.tab = function (rng, isShift) {
- var cell = dom.ancestor(rng.commonAncestor(), dom.isCell);
- var table = dom.ancestor(cell, dom.isTable);
- var cells = dom.listDescendant(table, dom.isCell);
-
- var nextCell = list[isShift ? 'prev' : 'next'](cells, cell);
- if (nextCell) {
- range.create(nextCell, 0).select();
- }
- };
-
- /**
- * create empty table element
- *
- * @param {Number} rowCount
- * @param {Number} colCount
- * @return {Node}
- */
- this.createTable = function (colCount, rowCount) {
- var tds = [], tdHTML;
- for (var idxCol = 0; idxCol < colCount; idxCol++) {
- tds.push('' + dom.blank + ' ');
- }
- tdHTML = tds.join('');
-
- var trs = [], trHTML;
- for (var idxRow = 0; idxRow < rowCount; idxRow++) {
- trs.push('' + tdHTML + ' ');
- }
- trHTML = trs.join('');
- return $('')[0];
- };
- };
- return Table;
-});
-
diff --git a/addons/web_editor/static/lib/summernote/src/js/editing/Typing.js b/addons/web_editor/static/lib/summernote/src/js/editing/Typing.js
deleted file mode 100644
index f95eba9e9f3..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/editing/Typing.js
+++ /dev/null
@@ -1,86 +0,0 @@
-define([
- 'summernote/core/dom',
- 'summernote/core/range',
- 'summernote/editing/Bullet'
-], function (dom, range, Bullet) {
-
- /**
- * @class editing.Typing
- *
- * Typing
- *
- */
- var Typing = function () {
-
- // a Bullet instance to toggle lists off
- var bullet = new Bullet();
-
- /**
- * insert tab
- *
- * @param {jQuery} $editable
- * @param {WrappedRange} rng
- * @param {Number} tabsize
- */
- this.insertTab = function ($editable, rng, tabsize) {
- var tab = dom.createText(new Array(tabsize + 1).join(dom.NBSP_CHAR));
- rng = rng.deleteContents();
- rng.insertNode(tab, true);
-
- rng = range.create(tab, tabsize);
- rng.select();
- };
-
- /**
- * insert paragraph
- */
- this.insertParagraph = function () {
- var rng = range.create();
-
- // deleteContents on range.
- rng = rng.deleteContents();
-
- // Wrap range if it needs to be wrapped by paragraph
- rng = rng.wrapBodyInlineWithPara();
-
- // finding paragraph
- var splitRoot = dom.ancestor(rng.sc, dom.isPara);
-
- var nextPara;
- // on paragraph: split paragraph
- if (splitRoot) {
- // if it is an empty line with li
- if (dom.isEmpty(splitRoot) && dom.isLi(splitRoot)) {
- // disable UL/OL and escape!
- bullet.toggleList(splitRoot.parentNode.nodeName);
- return;
- // if new line has content (not a line break)
- } else {
- nextPara = dom.splitTree(splitRoot, rng.getStartPoint());
-
- var emptyAnchors = dom.listDescendant(splitRoot, dom.isEmptyAnchor);
- emptyAnchors = emptyAnchors.concat(dom.listDescendant(nextPara, dom.isEmptyAnchor));
-
- $.each(emptyAnchors, function (idx, anchor) {
- dom.remove(anchor);
- });
- }
- // no paragraph: insert empty paragraph
- } else {
- var next = rng.sc.childNodes[rng.so];
- nextPara = $(dom.emptyPara)[0];
- if (next) {
- rng.sc.insertBefore(nextPara, next);
- } else {
- rng.sc.appendChild(nextPara);
- }
- }
-
- range.create(nextPara, 0).normalize().select();
-
- };
-
- };
-
- return Typing;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/intro.js b/addons/web_editor/static/lib/summernote/src/js/intro.js
deleted file mode 100644
index 357132eb110..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/intro.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Super simple wysiwyg editor on Bootstrap v@VERSION
- * http://summernote.org/
- *
- * summernote.js
- * Copyright 2013-2015 Alan Hong. and other contributors
- * summernote may be freely distributed under the MIT license./
- *
- * Date: @DATE
- */
-(function (factory) {
- /* global define */
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module.
- define(['jquery'], factory);
- } else {
- // Browser globals: jQuery
- factory(window.jQuery);
- }
-}(function ($) {
- 'use strict';
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
deleted file mode 100644
index c6d28494cd0..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Button.js
+++ /dev/null
@@ -1,169 +0,0 @@
-define([
- 'summernote/core/list',
- 'summernote/core/agent'
-], function (list, agent) {
- /**
- * @class module.Button
- *
- * Button
- */
- var Button = function () {
- /**
- * update button status
- *
- * @param {jQuery} $container
- * @param {Object} styleInfo
- */
- this.update = function ($container, styleInfo) {
- /**
- * handle dropdown's check mark (for fontname, fontsize, lineHeight).
- * @param {jQuery} $btn
- * @param {Number} value
- */
- var checkDropdownMenu = function ($btn, value) {
- $btn.find('.dropdown-menu .dropdown-item').each(function () {
- // always compare string to avoid creating another func.
- var isChecked = ($(this).data('value') + '') === (value + '');
- this.className = 'dropdown-item' + (isChecked ? ' checked' : '');
- });
- };
-
- /**
- * update button state(active or not).
- *
- * @private
- * @param {String} selector
- * @param {Function} pred
- */
- var btnState = function (selector, pred) {
- var $btn = $container.find(selector);
- $btn.toggleClass('active', pred());
- };
-
- if (styleInfo.image) {
- var $img = $(styleInfo.image);
-
- btnState('button[data-event="imageShape"][data-value="rounded"]', function () {
- return $img.hasClass('rounded');
- });
- btnState('button[data-event="imageShape"][data-value="rounded-circle"]', function () {
- return $img.hasClass('rounded-circle');
- });
- btnState('button[data-event="imageShape"][data-value="img-thumbnail"]', function () {
- return $img.hasClass('img-thumbnail');
- });
- btnState('button[data-event="imageShape"]:not([data-value])', function () {
- return !$img.is('.rounded, .rounded-circle, .img-thumbnail');
- });
-
- var imgFloat = $img.css('float');
- btnState('button[data-event="floatMe"][data-value="left"]', function () {
- return imgFloat === 'left';
- });
- btnState('button[data-event="floatMe"][data-value="right"]', function () {
- return imgFloat === 'right';
- });
- btnState('button[data-event="floatMe"][data-value="none"]', function () {
- return imgFloat !== 'left' && imgFloat !== 'right';
- });
-
- var style = $img.attr('style');
- btnState('button[data-event="resize"][data-value="1"]', function () {
- return !!/(^|\s)(max-)?width\s*:\s*100%/.test(style);
- });
- btnState('button[data-event="resize"][data-value="0.5"]', function () {
- return !!/(^|\s)(max-)?width\s*:\s*50%/.test(style);
- });
- btnState('button[data-event="resize"][data-value="0.25"]', function () {
- return !!/(^|\s)(max-)?width\s*:\s*25%/.test(style);
- });
- return;
- }
-
- // fontname
- var $fontname = $container.find('.note-fontname');
- if ($fontname.length) {
- var selectedFont = styleInfo['font-family'];
- if (!!selectedFont) {
-
- 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);
-
- }
- }
-
- // fontsize
- var $fontsize = $container.find('.note-fontsize');
- $fontsize.find('.note-current-fontsize').text(styleInfo['font-size']);
- checkDropdownMenu($fontsize, parseFloat(styleInfo['font-size']));
-
- // lineheight
- var $lineHeight = $container.find('.note-height');
- checkDropdownMenu($lineHeight, parseFloat(styleInfo['line-height']));
-
- btnState('button[data-event="bold"]', function () {
- return styleInfo['font-bold'] === 'bold';
- });
- btnState('button[data-event="italic"]', function () {
- return styleInfo['font-italic'] === 'italic';
- });
- btnState('button[data-event="underline"]', function () {
- return styleInfo['font-underline'] === 'underline';
- });
- btnState('button[data-event="strikethrough"]', function () {
- return styleInfo['font-strikethrough'] === 'strikethrough';
- });
- btnState('button[data-event="superscript"]', function () {
- return styleInfo['font-superscript'] === 'superscript';
- });
- btnState('button[data-event="subscript"]', function () {
- return styleInfo['font-subscript'] === 'subscript';
- });
- btnState('button[data-event="justifyLeft"]', function () {
- return styleInfo['text-align'] === 'left' || styleInfo['text-align'] === 'start';
- });
- btnState('button[data-event="justifyCenter"]', function () {
- return styleInfo['text-align'] === 'center';
- });
- btnState('button[data-event="justifyRight"]', function () {
- return styleInfo['text-align'] === 'right';
- });
- btnState('button[data-event="justifyFull"]', function () {
- return styleInfo['text-align'] === 'justify';
- });
- btnState('button[data-event="insertUnorderedList"]', function () {
- return styleInfo['list-style'] === 'unordered';
- });
- btnState('button[data-event="insertOrderedList"]', function () {
- return styleInfo['list-style'] === 'ordered';
- });
- };
-
- /**
- * update recent color
- *
- * @param {Node} button
- * @param {String} eventName
- * @param {Mixed} value
- */
- this.updateRecentColor = function (button, eventName, value) {
- var $color = $(button).closest('.note-color');
- var $recentColor = $color.find('.note-recent-color');
- var colorInfo = JSON.parse($recentColor.attr('data-value'));
- colorInfo[eventName] = value;
- $recentColor.attr('data-value', JSON.stringify(colorInfo));
- var sKey = eventName === 'backColor' ? 'background-color' : 'color';
- $recentColor.find('i').css(sKey, value);
- };
- };
-
- return Button;
-});
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
deleted file mode 100644
index 0e28726dd7f..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Clipboard.js
+++ /dev/null
@@ -1,42 +0,0 @@
-define([
- 'summernote/core/list',
- 'summernote/core/dom',
- 'summernote/core/key',
- 'summernote/core/agent',
- 'summernote/core/range'
-], function (list, dom, key, agent, range) {
- // ODOO override: use 0.8.10 version of this, adapted for the old summernote
- // version odoo is using
- var Clipboard = function (handler) {
- /**
- * paste by clipboard event
- *
- * @param {Event} event
- */
- var pasteByEvent = function (event) {
- if (["INPUT", "TEXTAREA"].indexOf(event.target.tagName) !== -1) {
- // ODOO override: from old summernote version
- return;
- }
-
- 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()]);
- event.preventDefault();
- }
- handler.invoke('editor.afterCommand', $editable);
- }
- };
-
- this.attach = function (layoutInfo) {
- layoutInfo.editable().on('paste', pasteByEvent);
- };
- };
-
- 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
deleted file mode 100644
index 46f3d96ab12..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Codeview.js
+++ /dev/null
@@ -1,137 +0,0 @@
-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/DragAndDrop.js b/addons/web_editor/static/lib/summernote/src/js/module/DragAndDrop.js
deleted file mode 100644
index 9e96dc329eb..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/DragAndDrop.js
+++ /dev/null
@@ -1,108 +0,0 @@
-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);
-
- /* ODOO: start_modification */
- event.preventDefault();
- /* ODOO: end_modification */
-
- 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);
-
- /* ODOO: start_modification */
- if (type.toLowerCase().indexOf('_moz_') > -1) {
- return;
- }
- /* ODOO: end_modification */
-
- 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/Editor.js b/addons/web_editor/static/lib/summernote/src/js/module/Editor.js
deleted file mode 100644
index 49d38187330..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Editor.js
+++ /dev/null
@@ -1,910 +0,0 @@
-define([
- 'summernote/core/agent',
- 'summernote/core/func',
- 'summernote/core/list',
- 'summernote/core/dom',
- 'summernote/core/range',
- 'summernote/core/async',
- 'summernote/editing/Style',
- 'summernote/editing/Typing',
- 'summernote/editing/Table',
- 'summernote/editing/Bullet'
-], function (agent, func, list, dom, range, async,
- Style, Typing, Table, Bullet) {
-
- var KEY_BOGUS = 'bogus';
-
- /**
- * @class editing.Editor
- *
- * Editor
- *
- */
- var Editor = function (handler) {
-
- var self = this;
- var style = new Style();
- var table = new Table();
- var typing = new Typing();
- var bullet = new Bullet();
-
- this.style = style; // ODOO: allow access for override
- this.table = table; // ODOO: allow access for override
- this.typing = typing; // ODOO: allow access for override
- this.bullet = bullet; // ODOO: allow access for override
-
- /**
- * @method createRange
- *
- * create range
- *
- * @param {jQuery} $editable
- * @return {WrappedRange}
- */
- this.createRange = function ($editable) {
- this.focus($editable);
- return range.create();
- };
-
- /**
- * @method saveRange
- *
- * save current range
- *
- * @param {jQuery} $editable
- * @param {Boolean} [thenCollapse=false]
- */
- this.saveRange = function ($editable, thenCollapse) {
- // ODOO: scroll to top when click on input in editable m (start_modification
- // this.focus($editable);
- var r = range.create();
- if (!r || ($editable[0] !== r.sc && !$.contains($editable[0], r.sc))) {
- $editable.focus();
- }
- // ODOO: end_modication)
- $editable.data('range', range.create());
- if (thenCollapse) {
- range.create().collapse().select();
- }
- };
-
- /**
- * @method saveRange
- *
- * save current node list to $editable.data('childNodes')
- *
- * @param {jQuery} $editable
- */
- this.saveNode = function ($editable) {
- // copy child node reference
- var copy = [];
- for (var key = 0, len = $editable[0].childNodes.length; key < len; key++) {
- copy.push($editable[0].childNodes[key]);
- }
- $editable.data('childNodes', copy);
- };
-
- /**
- * @method restoreRange
- *
- * restore lately range
- *
- * @param {jQuery} $editable
- */
- this.restoreRange = function ($editable) {
- var rng = $editable.data('range');
- if (rng) {
- rng.select();
- this.focus($editable);
- }
- };
-
- /**
- * @method restoreNode
- *
- * restore lately node list
- *
- * @param {jQuery} $editable
- */
- this.restoreNode = function ($editable) {
- $editable.html('');
- var child = $editable.data('childNodes');
- for (var index = 0, len = child.length; index < len; index++) {
- $editable[0].appendChild(child[index]);
- }
- };
-
- /**
- * @method currentStyle
- *
- * current style
- *
- * @param {Node} target
- * @return {Object|Boolean} unfocus
- */
- this.currentStyle = function (target) {
- var rng = range.create();
- var styleInfo = rng && rng.isOnEditable() ? style.current(rng.normalize()) : {};
- if (dom.isImg(target)) {
- styleInfo.image = target;
- }
- return styleInfo;
- };
-
- /**
- * style from node
- *
- * @param {jQuery} $node
- * @return {Object}
- */
- this.styleFromNode = function ($node) {
- return style.fromNode($node);
- };
-
- var triggerOnBeforeChange = function ($editable) {
- var $holder = dom.makeLayoutInfo($editable).holder();
- handler.bindCustomEvent(
- $holder, $editable.data('callbacks'), 'before.command'
- )($editable.html(), $editable);
- };
-
- var triggerOnChange = function ($editable) {
- var $holder = dom.makeLayoutInfo($editable).holder();
- handler.bindCustomEvent(
- $holder, $editable.data('callbacks'), 'change'
- )($editable.html(), $editable);
- };
-
- /**
- * @method undo
- * undo
- * @param {jQuery} $editable
- */
- this.undo = function ($editable) {
- triggerOnBeforeChange($editable);
- $editable.data('NoteHistory').undo();
- triggerOnChange($editable);
- };
-
- /**
- * @method redo
- * redo
- * @param {jQuery} $editable
- */
- this.redo = function ($editable) {
- triggerOnBeforeChange($editable);
- $editable.data('NoteHistory').redo();
- triggerOnChange($editable);
- };
-
- /**
- * @method beforeCommand
- * before command
- * @param {jQuery} $editable
- */
- var beforeCommand = this.beforeCommand = function ($editable) {
- triggerOnBeforeChange($editable);
- // keep focus on editable before command execution
- self.focus($editable);
- };
-
- /**
- * @method afterCommand
- * after command
- * @param {jQuery} $editable
- * @param {Boolean} isPreventTrigger
- */
- var afterCommand = this.afterCommand = function ($editable, isPreventTrigger) {
- $editable.data('NoteHistory').recordUndo();
- if (!isPreventTrigger) {
- triggerOnChange($editable);
- }
- };
-
- /**
- * @method bold
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method italic
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method underline
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method strikethrough
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method formatBlock
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method superscript
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method subscript
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method justifyLeft
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method justifyCenter
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method justifyRight
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method justifyFull
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method formatBlock
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method removeFormat
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method backColor
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method foreColor
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method insertHorizontalRule
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /**
- * @method fontName
- *
- * change font name
- *
- * @param {jQuery} $editable
- * @param {Mixed} value
- */
-
- /* jshint ignore:start */
- // native commands(with execCommand), generate function for execCommand
- var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript',
- 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull',
- 'formatBlock', 'removeFormat',
- 'backColor', 'foreColor', 'fontName'];
-
- for (var idx = 0, len = commands.length; idx < len; idx ++) {
- this[commands[idx]] = (function (sCmd) {
- return function ($editable, value) {
- beforeCommand($editable);
-
- document.execCommand(sCmd, false, value);
-
- afterCommand($editable, true);
- };
- })(commands[idx]);
- }
- /* jshint ignore:end */
-
- /**
- * @method tab
- *
- * handle tab key
- *
- * @param {jQuery} $editable
- * @param {Object} options
- */
- this.tab = function ($editable, options) {
- var rng = this.createRange($editable);
- if (rng.isCollapsed() && rng.isOnCell()) {
- table.tab(rng);
- } else {
- beforeCommand($editable);
- typing.insertTab($editable, rng, options.tabsize);
- afterCommand($editable);
- }
- };
-
- /**
- * @method untab
- *
- * handle shift+tab key
- *
- */
- this.untab = function ($editable) {
- var rng = this.createRange($editable);
- if (rng.isCollapsed() && rng.isOnCell()) {
- table.tab(rng, true);
- }
- };
-
- /**
- * @method insertParagraph
- *
- * insert paragraph
- *
- * @param {Node} $editable
- */
- this.insertParagraph = function ($editable) {
- beforeCommand($editable);
- typing.insertParagraph($editable);
- afterCommand($editable);
- };
-
- /**
- * @method insertOrderedList
- *
- * @param {jQuery} $editable
- */
- this.insertOrderedList = function ($editable) {
- beforeCommand($editable);
- bullet.insertOrderedList($editable);
- afterCommand($editable);
- };
-
- /**
- * @param {jQuery} $editable
- */
- this.insertUnorderedList = function ($editable) {
- beforeCommand($editable);
- bullet.insertUnorderedList($editable);
- afterCommand($editable);
- };
-
- /**
- * @param {jQuery} $editable
- */
- this.indent = function ($editable) {
- beforeCommand($editable);
- bullet.indent($editable);
- afterCommand($editable);
- };
-
- /**
- * @param {jQuery} $editable
- */
- this.outdent = function ($editable) {
- beforeCommand($editable);
- bullet.outdent($editable);
- afterCommand($editable);
- };
-
- /**
- * insert image
- *
- * @param {jQuery} $editable
- * @param {String} sUrl
- */
- this.insertImage = function ($editable, sUrl, filename) {
- async.createImage(sUrl, filename).then(function ($image) {
- beforeCommand($editable);
- $image.css({
- display: '',
- width: Math.min($editable.width(), $image.width())
- });
- range.create().insertNode($image[0]);
- range.createFromNodeAfter($image[0]).select();
- afterCommand($editable);
- }).fail(function () {
- var $holder = dom.makeLayoutInfo($editable).holder();
- handler.bindCustomEvent(
- $holder, $editable.data('callbacks'), 'image.upload.error'
- )();
- });
- };
-
- /**
- * @method insertNode
- * insert node
- * @param {Node} $editable
- * @param {Node} node
- */
- this.insertNode = function ($editable, node) {
- beforeCommand($editable);
- range.create().insertNode(node);
- range.createFromNodeAfter(node).select();
- afterCommand($editable);
- };
-
- /**
- * insert text
- * @param {Node} $editable
- * @param {String} text
- */
- this.insertText = function ($editable, text) {
- beforeCommand($editable);
- var textNode = range.create().insertNode(dom.createText(text));
- range.create(textNode, dom.nodeLength(textNode)).select();
- afterCommand($editable);
- };
-
- /**
- * paste HTML
- * @param {Node} $editable
- * @param {String} markup
- */
- this.pasteHTML = function ($editable, markup) {
- beforeCommand($editable);
- var contents = range.create().pasteHTML(markup);
- range.createFromNodeAfter(list.last(contents)).select();
- afterCommand($editable);
- };
-
- /**
- * formatBlock
- *
- * @param {jQuery} $editable
- * @param {String} tagName
- */
- this.formatBlock = function ($editable, tagName) {
- beforeCommand($editable);
- // [workaround] for MSIE, IE need `<`
- tagName = agent.isMSIE ? '<' + tagName + '>' : tagName;
- document.execCommand('FormatBlock', false, tagName);
- afterCommand($editable);
- };
-
- this.formatPara = function ($editable) {
- beforeCommand($editable);
- this.formatBlock($editable, 'P');
- afterCommand($editable);
- };
-
- /* jshint ignore:start */
- for (var idx = 1; idx <= 6; idx ++) {
- this['formatH' + idx] = function (idx) {
- return function ($editable) {
- this.formatBlock($editable, 'H' + idx);
- };
- }(idx);
- };
- /* jshint ignore:end */
-
- /**
- * fontSize
- *
- * @param {jQuery} $editable
- * @param {String} value - px
- */
- this.fontSize = function ($editable, value) {
- var rng = range.create();
-
- if (rng.isCollapsed()) {
- var spans = style.styleNodes(rng);
- var firstSpan = list.head(spans);
-
- $(spans).css({
- 'font-size': value + 'px'
- });
-
- // [workaround] added styled bogus span for style
- // - also bogus character needed for cursor position
- if (firstSpan && !dom.nodeLength(firstSpan)) {
- $(firstSpan).html(dom.ZERO_WIDTH_NBSP_CHAR);
- range.createFromNodeAfter(firstSpan.firstChild).select();
- $editable.data(KEY_BOGUS, firstSpan);
- }
- } else {
- beforeCommand($editable);
- $(style.styleNodes(rng)).css({
- 'font-size': value + 'px'
- });
- afterCommand($editable);
- }
- };
-
- /**
- * insert horizontal rule
- * @param {jQuery} $editable
- */
- this.insertHorizontalRule = function ($editable) {
- beforeCommand($editable);
-
- var rng = range.create();
- var hrNode = rng.insertNode($(' ')[0]);
- if (hrNode.nextSibling) {
- range.create(hrNode.nextSibling, 0).normalize().select();
- }
-
- afterCommand($editable);
- };
-
- /**
- * remove bogus node and character
- */
- this.removeBogus = function ($editable) {
- var bogusNode = $editable.data(KEY_BOGUS);
- if (!bogusNode) {
- return;
- }
-
- var textNode = list.find(list.from(bogusNode.childNodes), dom.isText);
-
- var bogusCharIdx = textNode.nodeValue.indexOf(dom.ZERO_WIDTH_NBSP_CHAR);
- if (bogusCharIdx !== -1) {
- textNode.deleteData(bogusCharIdx, 1);
- }
-
- if (dom.isEmpty(bogusNode)) {
- dom.remove(bogusNode);
- }
-
- $editable.removeData(KEY_BOGUS);
- };
-
- /**
- * lineHeight
- * @param {jQuery} $editable
- * @param {String} value
- */
- this.lineHeight = function ($editable, value) {
- beforeCommand($editable);
- style.stylePara(range.create(), {
- lineHeight: value
- });
- afterCommand($editable);
- };
-
- /**
- * unlink
- *
- * @type command
- *
- * @param {jQuery} $editable
- */
- this.unlink = function ($editable) {
- var rng = this.createRange($editable);
- if (rng.isOnAnchor()) {
- var anchor = dom.ancestor(rng.sc, dom.isAnchor);
- rng = range.createFromNode(anchor);
- rng.select();
-
- beforeCommand($editable);
- document.execCommand('unlink');
- afterCommand($editable);
- }
- };
-
- /**
- * create link (command)
- *
- * @param {jQuery} $editable
- * @param {Object} linkInfo
- * @param {Object} options
- */
- this.createLink = function ($editable, linkInfo, options) {
- var linkUrl = linkInfo.url;
- var linkText = linkInfo.text;
- var isNewWindow = linkInfo.isNewWindow;
- var rng = linkInfo.range || this.createRange($editable);
- var isTextChanged = rng.toString() !== linkText;
- // Hack : This method was updated to create buttons as well (using the same logic as anchor nodes).
- const nodeName = linkInfo.isButton ? 'BUTTON' : 'A';
- const pred = dom.makePredByNodeName(nodeName);
-
- options = options || dom.makeLayoutInfo($editable).editor().data('options');
-
- beforeCommand($editable);
-
- if (options.onCreateLink) {
- linkUrl = options.onCreateLink(linkUrl);
- }
-
- var anchors = [];
- // ODOO: adding this branch to modify existing anchor if it fully contains the range
- var ancestor_anchor = dom.ancestor(rng.sc, pred);
- if (ancestor_anchor && ancestor_anchor === dom.ancestor(rng.ec, pred)) {
- anchors.push($(ancestor_anchor).html(linkText).get(0));
- } else if (isTextChanged) {
- // Create a new element when text changed.
- var anchor = rng.insertNode($(`<${nodeName}>${linkText}${nodeName}>`)[0]);
- anchors.push(anchor);
- } else {
- anchors = style.styleNodes(rng, {
- nodeName: nodeName,
- expandClosestSibling: true,
- onlyPartialContains: true
- });
- }
-
- $.each(anchors, function (idx, anchor) {
- if (!linkInfo.isButton) {
- $(anchor).attr('href', linkUrl);
- }
- $(anchor).attr('class', linkInfo.className || null); // ODOO: addition
- $(anchor).css(linkInfo.style || {}); // ODOO: addition
- if (isNewWindow) {
- $(anchor).attr('target', '_blank');
- } else {
- $(anchor).removeAttr('target');
- }
- });
-
- var startRange = range.createFromNodeBefore(list.head(anchors));
- var startPoint = startRange.getStartPoint();
- var endRange = range.createFromNodeAfter(list.last(anchors));
- var endPoint = endRange.getEndPoint();
-
- range.create(
- startPoint.node,
- startPoint.offset,
- endPoint.node,
- endPoint.offset
- ).select();
-
- afterCommand($editable);
- };
-
- /**
- * returns link info
- * Hack : This method was updated to return a boolean attribute 'isButton' to allow
- * handling buttons in linkDialog.
- *
- * @return {Object}
- * @return {WrappedRange} return.range
- * @return {String} return.text
- * @return {Boolean} [return.isNewWindow=true]
- * @return {String} [return.url=""]
- */
- this.getLinkInfo = function ($editable) {
- // ODOO MODIFICATION START
- var selection;
- var currentSelection = null;
- if (document.getSelection) {
- selection = document.getSelection();
- if (selection.getRangeAt && selection.rangeCount) {
- currentSelection = selection.getRangeAt(0);
- }
- }
- // ODOO MODIFICATION END
-
- this.focus($editable);
-
- // ODOO MODIFICATION START
- if (currentSelection && document.getSelection) {
- selection = document.getSelection();
- selection.removeAllRanges();
- selection.addRange(currentSelection);
- }
- // ODOO MODIFICATION END
-
- var rng = range.create().expand(dom.isAnchor);
-
- // Get the first anchor on range(for edit).
- var anchor = list.head(rng.nodes(dom.isAnchor));
- const $anchor = $(anchor);
-
- if ($anchor.length && !rng.nodes()[0].isSameNode(anchor)) {
- rng = range.createFromNode(anchor);
- rng.select();
- }
-
- // Check if the target is a button element.
- let isButton = false;
- if (!$anchor.length) {
- const pred = dom.makePredByNodeName('BUTTON');
- const rngNew = range.create().expand(pred);
- const target = list.head(rngNew.nodes(pred));
- if (target && target.nodeName === 'BUTTON') {
- isButton = true;
- rng = rngNew;
- }
- }
-
- return {
- range: rng,
- text: rng.toString(),
- isNewWindow: $anchor.length ? $anchor.attr('target') === '_blank' : false,
- url: $anchor.length ? $anchor.attr('href') : '',
- isButton: isButton,
- };
- };
-
- /**
- * setting color
- *
- * @param {Node} $editable
- * @param {Object} sObjColor color code
- * @param {String} sObjColor.foreColor foreground color
- * @param {String} sObjColor.backColor background color
- */
- this.color = function ($editable, sObjColor) {
- var oColor = JSON.parse(sObjColor);
- var foreColor = oColor.foreColor, backColor = oColor.backColor;
-
- beforeCommand($editable);
-
- if (foreColor) { document.execCommand('foreColor', false, foreColor); }
- if (backColor) { document.execCommand('backColor', false, backColor); }
-
- afterCommand($editable);
- };
-
- /**
- * insert Table
- *
- * @param {Node} $editable
- * @param {String} sDim dimension of table (ex : "5x5")
- */
- this.insertTable = function ($editable, sDim) {
- var dimension = sDim.split('x');
- beforeCommand($editable);
-
- var rng = range.create().deleteContents();
- rng.insertNode(table.createTable(dimension[0], dimension[1]));
- afterCommand($editable);
- };
-
- /**
- * float me
- *
- * @param {jQuery} $editable
- * @param {String} value
- * @param {jQuery} $target
- */
- this.floatMe = function ($editable, value, $target) {
- beforeCommand($editable);
- // bootstrap
- $target.removeClass('float-left float-right');
- if (value && value !== 'none') {
- $target.addClass('pull-' + value);
- }
-
- // fallback for non-bootstrap
- $target.css('float', value);
- afterCommand($editable);
- };
-
- /**
- * change image shape
- *
- * @param {jQuery} $editable
- * @param {String} value css class
- * @param {Node} $target
- */
- this.imageShape = function ($editable, value, $target) {
- beforeCommand($editable);
-
- $target.removeClass('rounded rounded-circle img-thumbnail');
-
- if (value) {
- $target.addClass(value);
- }
-
- afterCommand($editable);
- };
-
- /**
- * resize overlay element
- * @param {jQuery} $editable
- * @param {String} value
- * @param {jQuery} $target - target element
- */
- this.resize = function ($editable, value, $target) {
- beforeCommand($editable);
-
- $target.css({
- width: value * 100 + '%',
- height: ''
- });
-
- afterCommand($editable);
- };
-
- /**
- * @param {Position} pos
- * @param {jQuery} $target - target element
- * @param {Boolean} [bKeepRatio] - keep ratio
- */
- this.resizeTo = function (pos, $target, bKeepRatio) {
- var imageSize;
- if (bKeepRatio) {
- var newRatio = pos.y / pos.x;
- var ratio = $target.data('ratio');
- imageSize = {
- width: ratio > newRatio ? pos.x : pos.y / ratio,
- height: ratio > newRatio ? pos.x * ratio : pos.y
- };
- } else {
- imageSize = {
- width: pos.x,
- height: pos.y
- };
- }
-
- $target.css(imageSize);
- };
-
- /**
- * remove media object
- *
- * @param {jQuery} $editable
- * @param {String} value - dummy argument (for keep interface)
- * @param {jQuery} $target - target element
- */
- this.removeMedia = function ($editable, value, $target) {
- beforeCommand($editable);
- $target.detach();
-
- handler.bindCustomEvent(
- $(), $editable.data('callbacks'), 'media.delete'
- )($target, $editable);
-
- afterCommand($editable);
- };
-
- /**
- * set focus
- *
- * @param $editable
- */
- this.focus = function ($editable) {
- $editable.focus();
-
- // [workaround] for firefox bug http://goo.gl/lVfAaI
- if (agent.isFF) {
- var rng = range.create();
- if (!rng || rng.isOnEditable()) {
- return;
- }
-
- range.createFromNode($editable[0])
- .normalize()
- .collapse()
- .select();
- }
- };
-
- /**
- * returns whether contents is empty or not.
- *
- * @param {jQuery} $editable
- * @return {Boolean}
- */
- this.isEmpty = function ($editable) {
- return dom.isEmpty($editable[0]) || dom.emptyPara === $editable.html();
- };
- };
-
- return Editor;
-});
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
deleted file mode 100644
index fd837483b3b..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Fullscreen.js
+++ /dev/null
@@ -1,51 +0,0 @@
-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
deleted file mode 100644
index 3b62304d706..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Handle.js
+++ /dev/null
@@ -1,101 +0,0 @@
-define([
- 'summernote/core/dom'
-], function (dom) {
- /**
- * @class module.Handle
- *
- * Handle
- */
- 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
- * @param {Object} styleInfo
- * @param {Boolean} isAirMode
- */
- this.update = function ($handle, styleInfo, isAirMode) {
- var $selection = $handle.find('.note-control-selection');
- if (styleInfo.image) {
- var $image = $(styleInfo.image);
- var pos = isAirMode ? $image.offset() : $image.position();
-
- // include margin
- var imageSize = {
- w: $image.outerWidth(true),
- h: $image.outerHeight(true)
- };
-
- $selection.css({
- display: 'block',
- left: pos.left,
- top: pos.top,
- width: imageSize.w,
- height: imageSize.h
- }).data('target', styleInfo.image); // save current image element.
- var sizingText = imageSize.w + 'x' + imageSize.h;
- $selection.find('.note-control-selection-info').text(sizingText);
- } else {
- $selection.hide();
- }
- };
-
- /**
- * hide
- *
- * @param {jQuery} $handle
- */
- this.hide = function ($handle) {
- $handle.children().hide();
- };
- };
-
- return Handle;
-});
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
deleted file mode 100644
index e4ff7b775ed..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/HelpDialog.js
+++ /dev/null
@@ -1,35 +0,0 @@
-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
deleted file mode 100644
index 042921183cc..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/ImageDialog.js
+++ /dev/null
@@ -1,110 +0,0 @@
-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
deleted file mode 100644
index 045119ee68a..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/LinkDialog.js
+++ /dev/null
@@ -1,129 +0,0 @@
-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
deleted file mode 100644
index 00061f39848..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Popover.js
+++ /dev/null
@@ -1,129 +0,0 @@
-define([
- 'summernote/core/func',
- 'summernote/core/list',
- '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: allow access for override
-
- /**
- * returns position from placeholder
- *
- * @private
- * @param {Node} placeholder
- * @param {Object} options
- * @param {Boolean} options.isAirMode
- * @return {Position}
- */
- 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 = isLeftTop ? 0 : $placeholder.outerHeight(true); // include margin
-
- // popover below placeholder.
- return {
- left: pos.left,
- top: pos.top + height
- };
- };
-
- /**
- * show popover
- *
- * @private
- * @param {jQuery} popover
- * @param {Position} pos
- */
- var showPopover = function ($popover, pos) {
- $popover.css({
- display: 'block',
- left: pos.left,
- top: pos.top
- });
- };
-
- var PX_POPOVER_ARROW_OFFSET_X = 20;
-
- /**
- * update current state
- * @param {jQuery} $popover - popover container
- * @param {Object} styleInfo - style object
- * @param {Boolean} isAirMode
- */
- this.update = function ($popover, styleInfo, isAirMode) {
- button.update($popover, styleInfo);
-
- var $linkPopover = $popover.find('.note-link-popover');
- if (styleInfo.anchor) {
- var $anchor = $linkPopover.find('a');
- var href = $(styleInfo.anchor).attr('href');
- var target = $(styleInfo.anchor).attr('target');
- $anchor.attr('href', href).text(href);
- 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: isAirMode,
- isLeftTop: true
- }));
- } else {
- $imagePopover.hide();
- }
-
- var $airPopover = $popover.find('.note-air-popover');
- if (isAirMode && styleInfo.range && !styleInfo.range.isCollapsed()) {
- var rect = list.last(styleInfo.range.getClientRects());
- if (rect) {
- var bnd = func.rect2bnd(rect);
- showPopover($airPopover, {
- left: Math.max(bnd.left + bnd.width / 2 - PX_POPOVER_ARROW_OFFSET_X, 0),
- top: bnd.top + bnd.height
- });
- }
- } else {
- $airPopover.hide();
- }
- };
-
- /**
- * @param {Node} button
- * @param {String} eventName
- * @param {String} value
- */
- this.updateRecentColor = function (button, eventName, value) {
- button.updateRecentColor(button, eventName, value);
- };
-
- /**
- * hide all popovers
- * @param {jQuery} $popover - popover container
- */
- this.hide = function ($popover) {
- $popover.children().hide();
- };
- };
-
- return Popover;
-});
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
deleted file mode 100644
index b50fce458eb..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Statusbar.js
+++ /dev/null
@@ -1,44 +0,0 @@
-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
deleted file mode 100644
index 5e5e5721b63..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/module/Toolbar.js
+++ /dev/null
@@ -1,101 +0,0 @@
-define([
- 'summernote/core/list',
- 'summernote/core/dom',
- 'summernote/module/Button'
-], function (list, dom, Button) {
- /**
- * @class module.Toolbar
- *
- * Toolbar
- */
- var Toolbar = function () {
- var button = new Button();
-
- this.button = button; // ODOO: allow access for override
-
- this.update = function ($toolbar, styleInfo) {
- button.update($toolbar, styleInfo);
- };
-
- /**
- * @param {Node} button
- * @param {String} eventName
- * @param {String} value
- */
- this.updateRecentColor = function (buttonNode, eventName, value) {
- button.updateRecentColor(buttonNode, eventName, value);
- };
-
- /**
- * activate buttons exclude codeview
- * @param {jQuery} $toolbar
- */
- this.activate = function ($toolbar) {
- $toolbar.find('button')
- .not('button[data-event="codeview"]')
- .removeClass('disabled');
- };
-
- /**
- * deactivate buttons exclude codeview
- * @param {jQuery} $toolbar
- */
- this.deactivate = function ($toolbar) {
- $toolbar.find('button')
- .not('button[data-event="codeview"]')
- .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);
- };
- };
-
- return Toolbar;
-});
diff --git a/addons/web_editor/static/lib/summernote/src/js/outro.js b/addons/web_editor/static/lib/summernote/src/js/outro.js
deleted file mode 100644
index be4600a5cb1..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/outro.js
+++ /dev/null
@@ -1 +0,0 @@
-}));
diff --git a/addons/web_editor/static/lib/summernote/src/js/summernote.js b/addons/web_editor/static/lib/summernote/src/js/summernote.js
deleted file mode 100644
index 329ba7fa126..00000000000
--- a/addons/web_editor/static/lib/summernote/src/js/summernote.js
+++ /dev/null
@@ -1,328 +0,0 @@
-define([
- 'summernote/core/agent',
- 'summernote/core/list',
- 'summernote/core/dom',
- 'summernote/core/range',
- 'summernote/defaults',
- 'summernote/EventHandler',
- 'summernote/Renderer',
- 'summernote/core/key' // ODOO: change for override
-], function (agent, list, dom, range,
- defaults, EventHandler, Renderer, key) {
-
- // jQuery namespace for summernote
- /**
- * @class $.summernote
- *
- * summernote attribute
- *
- * @mixin defaults
- * @singleton
- *
- */
- $.summernote = $.summernote || {};
-
- // extends default settings
- // - $.summernote.version
- // - $.summernote.options
- // - $.summernote.lang
- $.extend($.summernote, defaults);
-
- var renderer = new Renderer();
- var eventHandler = new EventHandler();
-
- $.extend($.summernote, {
- /** @property {Renderer} */
- renderer: renderer,
- /** @property {EventHandler} */
- eventHandler: eventHandler,
- /**
- * @property {Object} core
- * @property {core.agent} core.agent
- * @property {core.dom} core.dom
- * @property {core.range} core.range
- */
- core: {
- agent: agent,
- list : list,
- dom: dom,
- range: range,
- key: key // ODOO: change for override
- },
- /**
- * @property {Object}
- * pluginEvents event list for plugins
- * event has name and callback function.
- *
- * ```
- * $.summernote.addPlugin({
- * events : {
- * 'hello' : function(layoutInfo, value, $target) {
- * console.log('event name is hello, value is ' + value );
- * }
- * }
- * })
- * ```
- *
- * * event name is data-event property.
- * * layoutInfo is a summernote layout information.
- * * value is data-value property.
- */
- pluginEvents: {},
-
- plugins : []
- });
-
- /**
- * @method addPlugin
- *
- * add Plugin in Summernote
- *
- * Summernote can make a own plugin.
- *
- * ### Define plugin
- * ```
- * // get template function
- * var tmpl = $.summernote.renderer.getTemplate();
- *
- * // add a button
- * $.summernote.addPlugin({
- * buttons : {
- * // "hello" is button's namespace.
- * "hello" : function(lang, options) {
- * // make icon button by template function
- * return tmpl.iconButton(options.iconPrefix + 'header', {
- * // callback function name when button clicked
- * event : 'hello',
- * // set data-value property
- * value : 'hello',
- * hide : true
- * });
- * }
- *
- * },
- *
- * events : {
- * "hello" : function(layoutInfo, value) {
- * // here is event code
- * }
- * }
- * });
- * ```
- * ### Use a plugin in toolbar
- *
- * ```
- * $("#editor").summernote({
- * ...
- * toolbar : [
- * // display hello plugin in toolbar
- * ['group', [ 'hello' ]]
- * ]
- * ...
- * });
- * ```
- *
- *
- * @param {Object} plugin
- * @param {Object} [plugin.buttons] define plugin button. for detail, see to Renderer.addButtonInfo
- * @param {Object} [plugin.dialogs] define plugin dialog. for detail, see to Renderer.addDialogInfo
- * @param {Object} [plugin.events] add event in $.summernote.pluginEvents
- * @param {Object} [plugin.langs] update $.summernote.lang
- * @param {Object} [plugin.options] update $.summernote.options
- */
- $.summernote.addPlugin = function (plugin) {
-
- // save plugin list
- $.summernote.plugins.push(plugin);
-
- if (plugin.buttons) {
- $.each(plugin.buttons, function (name, button) {
- renderer.addButtonInfo(name, button);
- });
- }
-
- if (plugin.dialogs) {
- $.each(plugin.dialogs, function (name, dialog) {
- renderer.addDialogInfo(name, dialog);
- });
- }
-
- if (plugin.events) {
- $.each(plugin.events, function (name, event) {
- $.summernote.pluginEvents[name] = event;
- });
- }
-
- if (plugin.langs) {
- $.each(plugin.langs, function (locale, lang) {
- if ($.summernote.lang[locale]) {
- $.extend($.summernote.lang[locale], lang);
- }
- });
- }
-
- if (plugin.options) {
- $.extend($.summernote.options, plugin.options);
- }
- };
-
- /*
- * extend $.fn
- */
- $.fn.extend({
- /**
- * @method
- * Initialize summernote
- * - create editor layout and attach Mouse and keyboard events.
- *
- * ```
- * $("#summernote").summernote( { options ..} );
- * ```
- *
- * @member $.fn
- * @param {Object|String} options reference to $.summernote.options
- * @return {this}
- */
- summernote: function () {
- // check first argument's type
- // - {String}: External API call {{module}}.{{method}}
- // - {Object}: init options
- var type = $.type(list.head(arguments));
- var isExternalAPICalled = type === 'string';
- var hasInitOptions = type === 'object';
-
- // extend default options with custom user options
- var options = hasInitOptions ? list.head(arguments) : {};
-
- options = $.extend({}, $.summernote.options, options);
- options.icons = $.extend({}, $.summernote.options.icons, options.icons);
-
- // Include langInfo in options for later use, e.g. for image drag-n-drop
- // Setup language info with en-US as default
- options.langInfo = $.extend(true, {}, $.summernote.lang['en-US'], $.summernote.lang[options.lang]);
-
- // override plugin options
- if (!isExternalAPICalled && hasInitOptions) {
- for (var i = 0, len = $.summernote.plugins.length; i < len; i++) {
- var plugin = $.summernote.plugins[i];
-
- if (options.plugin[plugin.name]) {
- $.summernote.plugins[i] = $.extend(true, plugin, options.plugin[plugin.name]);
- }
- }
- }
-
- this.each(function (idx, holder) {
- var $holder = $(holder);
-
- // if layout isn't created yet, createLayout and attach events
- if (!renderer.hasNoteEditor($holder)) {
- renderer.createLayout($holder, options);
-
- var layoutInfo = renderer.layoutInfoFromHolder($holder);
- $holder.data('layoutInfo', layoutInfo);
-
- eventHandler.attach(layoutInfo, options);
- eventHandler.attachCustomEvent(layoutInfo, options);
- }
- });
-
- var $first = this.first();
- if ($first.length) {
- var layoutInfo = renderer.layoutInfoFromHolder($first);
-
- // external API
- if (isExternalAPICalled) {
- var moduleAndMethod = list.head(list.from(arguments));
- var args = list.tail(list.from(arguments));
-
- // TODO now external API only works for editor
- var params = [moduleAndMethod, layoutInfo.editable()].concat(args);
- return eventHandler.invoke.apply(eventHandler, params);
- } else if (options.focus) {
- // focus on first editable element for initialize editor
- layoutInfo.editable().focus();
- }
- }
-
- return this;
- },
-
- /**
- * @method
- *
- * get the HTML contents of note or set the HTML contents of note.
- *
- * * get contents
- * ```
- * var content = $("#summernote").code();
- * ```
- * * set contents
- *
- * ```
- * $("#summernote").code(html);
- * ```
- *
- * @member $.fn
- * @param {String} [html] - HTML contents(optional, set)
- * @return {this|String} - context(set) or HTML contents of note(get).
- */
- code: function (html) {
- // get the HTML contents of note
- if (html === undefined) {
- var $holder = this.first();
- if (!$holder.length) {
- return;
- }
-
- var layoutInfo = renderer.layoutInfoFromHolder($holder);
- var $editable = layoutInfo && layoutInfo.editable();
-
- if ($editable && $editable.length) {
- var isCodeview = eventHandler.invoke('codeview.isActivated', layoutInfo);
- eventHandler.invoke('codeview.sync', layoutInfo);
- return isCodeview ? layoutInfo.codable().val() :
- layoutInfo.editable().html();
- }
- return dom.value($holder);
- }
-
- // set the HTML contents of note
- this.each(function (i, holder) {
- var layoutInfo = renderer.layoutInfoFromHolder($(holder));
- var $editable = layoutInfo && layoutInfo.editable();
- if ($editable) {
- $editable.html(html);
- }
- });
-
- return this;
- },
-
- /**
- * @method
- *
- * destroy Editor Layout and detach Key and Mouse Event
- *
- * @member $.fn
- * @return {this}
- */
- destroy: function () {
- this.each(function (idx, holder) {
- var $holder = $(holder);
-
- if (!renderer.hasNoteEditor($holder)) {
- return;
- }
-
- var info = renderer.layoutInfoFromHolder($holder);
- var options = info.editor().data('options');
-
- eventHandler.detach(info, options);
- renderer.removeLayout($holder, info, options);
- });
-
- return this;
- }
- });
-});
diff --git a/addons/web_editor/static/lib/summernote/src/less/summernote.less b/addons/web_editor/static/lib/summernote/src/less/summernote.less
deleted file mode 100644
index dc8da25122d..00000000000
--- a/addons/web_editor/static/lib/summernote/src/less/summernote.less
+++ /dev/null
@@ -1,467 +0,0 @@
-/* Theme Variables
- ------------------------------------------*/
-@border-color: #a9a9a9;
-@background-color: #f5f5f5;
-
-/* Frame Mode Layout
- ------------------------------------------*/
-.note-editor {
- border: 1px solid @border-color;
- position: relative;
- /* overflow: hidden; ODOO: removed for embedded editor */
-
- /* dropzone */
- @dropzone-color: lightskyblue;
- @dropzone-active-color: darken(@dropzone-color, 30);
- .note-dropzone {
- position: absolute;
- display: none;
- z-index: 100;
- color: @dropzone-color;
- background-color: white;
- opacity: 0.95;
- pointer-event: none;
-
- .note-dropzone-message {
- display: table-cell;
- vertical-align: middle;
- text-align: center;
- font-size: 28px;
- font-weight: bold;
- }
-
- &.hover {
- color: @dropzone-active-color;
- }
- }
-
- &.dragover .note-dropzone {
- display: table;
- }
-
- /* codeview mode */
- &.codeview {
- .note-editing-area {
- .note-editable {
- display: none;
- }
- .note-codable {
- display: block;
- }
- }
- }
-
- /* fullscreen mode */
- &.fullscreen {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- z-index: 1050; /* bs3 modal-backdrop: 1030, bs2: 1040 */
- .note-editable {
- background-color: white;
- }
- .note-resizebar {
- display: none;
- }
- }
-
- .note-editing-area {
- position: relative;
- overflow: hidden;
-
- /* editable */
- .note-editable {
- background-color: #fff;
- color: #000;
- padding: 10px;
- overflow: auto;
- outline: none;
-
- &[contenteditable=true]:empty:not(:focus):before {
- content:attr(data-placeholder);
- }
- &[contenteditable="false"] {
- background-color: #e5e5e5;
- }
- }
-
- /* codeable */
- .note-codable {
- display: none;
- width: 100%;
- padding: 10px;
- border: none;
- box-shadow: none;
- font-family: Menlo, Monaco, monospace, sans-serif;
- font-size: 14px;
- color: #ccc;
- background-color: #222;
- resize: none;
-
- /* override BS2 default style */
- box-sizing: border-box;
- border-radius: 0;
- margin-bottom: 0;
- }
- }
-
- /* statusbar */
- .note-statusbar {
- background-color: @background-color;
- .note-resizebar {
- padding-top: 1px;
- height: 8px;
- width: 100%;
- cursor: ns-resize;
- .note-icon-bar {
- width: 20px;
- margin: 1px auto;
- border-top: 1px solid @border-color;
- }
- }
- }
-}
-
-/* Air Mode Layout
-------------------------------------------*/
-.note-air-editor {
- outline: none;
-}
-
-/* Popover
-------------------------------------------*/
-.note-popover .popover {
- max-width: none;
- .popover-body {
- a {
- display: inline-block;
- max-width: 200px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap; /* for FF */
- vertical-align: middle; /* for FF */
- }
- }
- & .arrow {
- left: 20px;
- }
-}
-
-/* Popover and Toolbar (Button container)
-------------------------------------------*/
-.note-popover .popover .popover-body, .panel-heading.note-toolbar {
- margin: 0;
- padding: 0 0 5px 5px;
-
- &>.btn-group {
- margin-top: 5px;
- margin-left: 0;
- margin-right: 5px;
- }
-
- .btn-group {
- .note-table {
- min-width: 0;
- padding: 5px;
- .note-dimension-picker {
- font-size: 18px;
- .note-dimension-picker-mousecatcher {
- position: absolute !important;
- z-index: 3;
- width: 10em;
- height: 10em;
- cursor: pointer;
- }
- .note-dimension-picker-unhighlighted {
- position: relative !important;
- z-index: 1;
- width: 5em;
- height: 5em;
- background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat;
- }
- .note-dimension-picker-highlighted {
- position: absolute !important;
- z-index: 2;
- width: 1em;
- height: 1em;
- background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC') repeat;
- }
- }
- }
- }
-
- .note-style {
- h1, h2, h3, h4, h5, h6, blockquote {
- margin: 0;
- }
- }
-
- .note-color {
- .dropdown-toggle {
- width: 20px;
- padding-left: 5px;
- }
- .dropdown-menu {
- min-width: 340px;
- .btn-group {
- margin: 0;
- &:first-child {
- margin: 0 5px;
- }
-
- .note-palette-title {
- font-size: 12px;
- margin: 2px 7px;
- text-align: center;
- border-bottom: 1px solid #eee;
- }
-
- .note-color-reset {
- font-size: 11px;
- margin: 3px;
- padding: 0 3px;
- cursor: pointer;
- border-radius: 5px;
- }
-
- .note-color-row {
- height: 20px;
- }
-
- .note-color-reset:hover {
- background: #eee;
- }
- }
- }
- }
-
- .note-para {
- .dropdown-menu {
- min-width: 216px;
- padding: 5px;
- &>div:first-child {
- margin-right: 5px;
- }
- }
- }
-
- /* dropdown-menu for toolbar and popover */
- .dropdown-menu {
- min-width: 90px;
-
- /* dropdown-menu right position */
- /* http://forrst.com/posts/Bootstrap_right_positioned_dropdown-2KB */
- &.right {
- right: 0;
- left: auto;
- &::before { right: 9px; left: auto !important; }
- &::after { right: 10px; left: auto !important; }
- }
- /* dropdown-menu for selectbox */
- &.note-check {
- li a i {
- color: deepskyblue;
- visibility: hidden;
- }
- li a.checked i {
- visibility: visible;
- }
- }
-
- }
-
- .note-fontsize-10 {
- font-size: 10px;
- }
-
- /* color palette for toolbar and popover */
- .note-color-palette {
- line-height: 1;
- div {
- .note-color-btn {
- width: 20px;
- height: 20px;
- padding: 0;
- margin: 0;
- border: 1px solid #fff;
- }
- .note-color-btn:hover {
- border: 1px solid #000;
- }
- }
- }
-}
-
-/* Dialog
-------------------------------------------*/
-.note-dialog {
- &>div {
- display: none; /* BS2's hide pacth. */
- }
- .form-group { /* overwrite BS's form-horizontal minus margins */
- margin-left: 0;
- margin-right: 0;
- }
- .note-modal-form {
- margin: 0; /* overwrite BS2's form margin bottom */
- }
- .note-image-dialog {
- .note-dropzone {
- min-height: 100px;
- font-size: 30px;
- line-height: 4; /* vertical-align */
- color: lightgray;
- text-align: center;
- border: 4px dashed lightgray;
- margin-bottom: 10px;
- }
- }
- .note-help-dialog {
- @note-shortcut-hl: #dd0;
- font-size: 12px;
- color: #ccc;
- background-color: #222 !important;
- opacity: 0.9;
- .modal-content {
- background: transparent;
- border: 1px solid white;
- box-shadow: none;
- border-radius: 5px;
- }
-
- /* BS2's background pacth. */
- background: transparent;
- border: none;
-
- a {
- font-size: 12px;
- color: white;
- }
-
- .title {
- color: white;
- font-size: 14px;
- font-weight: bold;
- padding-bottom: 5px;
- margin-bottom: 10px;
- border-bottom: white 1px solid;
- }
-
- .modal-close {
- font-size: 14px;
- color: @note-shortcut-hl;
- cursor: pointer;
- }
-
- .text-center {
- margin: 10px 0 0;
- }
-
- .note-shortcut {
- padding-top: 8px;
- padding-bottom: 8px;
-
- &-row {
- margin-right: -5px;
- margin-left: -5px;
- }
-
- &-col {
- padding-right: 5px;
- padding-left: 5px;
- }
-
- &-title {
- font-size: 13px;
- font-weight: bold;
- color: @note-shortcut-hl;
- }
-
- &-key {
- font-family: "Courier New";
- color: @note-shortcut-hl;
- text-align: right;
- }
- }
- }
-}
-
-/* Handle
-------------------------------------------*/
-.note-handle {
- /* control selection */
- .note-control-selection {
- position: absolute;
- display: none;
- border: 1px solid black;
- &>div { position: absolute; }
-
- .note-control-selection-bg {
- width: 100%;
- height: 100%;
- background-color: black;
- opacity: 0.3;
- }
-
- .note-control-handle {
- width: 7px;
- height: 7px;
- border: 1px solid black;
- }
-
- .note-control-holder {
- .note-control-handle;
- }
-
- .note-control-sizing {
- .note-control-handle;
- background-color: white;
- }
-
- .note-control-nw {
- top: -5px;
- left: -5px;
- border-right: none;
- border-bottom: none;
- }
-
- .note-control-ne {
- top: -5px;
- right: -5px;
- border-bottom: none;
- border-left: none;
- }
-
- .note-control-sw {
- bottom: -5px;
- left: -5px;
- border-top: none;
- border-right: none;
- }
-
- .note-control-se {
- right: -5px;
- bottom: -5px;
- cursor: se-resize;
- }
-
- .note-control-se.note-control-holder {
- cursor: default;
- border-top: none;
- border-left: none;
- }
-
- .note-control-selection-info {
- right: 0;
- bottom: 0;
- padding: 5px;
- margin: 5px;
- color: white;
- background-color: black;
- font-size: 12px;
- border-radius: 5px;
- opacity: 0.7;
- }
- }
-}
diff --git a/addons/web_editor/static/src/js/editor/rte.js b/addons/web_editor/static/src/js/editor/rte.js
deleted file mode 100644
index ae6293a35cc..00000000000
--- a/addons/web_editor/static/src/js/editor/rte.js
+++ /dev/null
@@ -1,835 +0,0 @@
-odoo.define('web_editor.rte', function (require) {
-'use strict';
-
-var fonts = require('wysiwyg.fonts');
-var concurrency = require('web.concurrency');
-var core = require('web.core');
-var Widget = require('web.Widget');
-var weContext = require('web_editor.context');
-const weWidgets = require('wysiwyg.widgets');
-var summernote = require('web_editor.summernote');
-var summernoteCustomColors = require('web_editor.rte.summernote_custom_colors');
-
-var _t = core._t;
-
-// Summernote Lib (neek change to make accessible: method and object)
-var dom = summernote.core.dom;
-var range = summernote.core.range;
-
-// Change History to have a global History for all summernote instances
-var History = function History($editable) {
- var aUndo = [];
- var pos = 0;
- var toSnap;
-
- this.makeSnap = function (event, rng) {
- rng = rng || range.create();
- var elEditable = $(rng && rng.sc).closest('.o_editable')[0];
- if (!elEditable) {
- return false;
- }
- return {
- event: event,
- editable: elEditable,
- contents: elEditable.innerHTML,
- bookmark: rng && rng.bookmark(elEditable),
- scrollTop: $(elEditable).scrollTop()
- };
- };
-
- this.applySnap = function (oSnap) {
- var $editable = $(oSnap.editable);
-
- if (document.documentMode) {
- $editable.removeAttr('contentEditable').removeProp('contentEditable');
- }
-
- $editable.trigger('content_will_be_destroyed');
- var $tempDiv = $('
', {html: oSnap.contents});
- _.each($tempDiv.find('.o_temp_auto_element'), function (el) {
- var $el = $(el);
- var originalContent = $el.attr('data-temp-auto-element-original-content');
- if (originalContent) {
- $el.after(originalContent);
- }
- $el.remove();
- });
- $editable.html($tempDiv.html()).scrollTop(oSnap.scrollTop);
- $editable.trigger('content_was_recreated');
-
- $('.oe_overlay').remove();
- $('.note-control-selection').hide();
-
- $editable.trigger('content_changed');
-
- try {
- var r = '' === oSnap.editable.innerHTML ? range.create(oSnap.editable, 0) : range.createFromBookmark(oSnap.editable, oSnap.bookmark);
- r.select();
- } catch (e) {
- console.error(e);
- return;
- }
-
- $(document).trigger('click');
- $('.o_editable *').filter(function () {
- var $el = $(this);
- if ($el.data('snippet-editor')) {
- $el.removeData();
- }
- });
-
-
- _.defer(function () {
- var target = dom.isBR(r.sc) ? r.sc.parentNode : dom.node(r.sc);
- if (!target) {
- return;
- }
-
- $editable.trigger('applySnap');
-
- var evt = document.createEvent('MouseEvents');
- evt.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, target);
- target.dispatchEvent(evt);
-
- $editable.trigger('keyup');
- });
- };
-
- this.undo = function () {
- if (!pos) { return; }
- var _toSnap = toSnap;
- if (_toSnap) {
- this.saveSnap();
- }
- if (!aUndo[pos] && (!aUndo[pos] || aUndo[pos].event !== 'undo')) {
- var temp = this.makeSnap('undo');
- if (temp && (!pos || temp.contents !== aUndo[pos-1].contents)) {
- aUndo[pos] = temp;
- } else {
- pos--;
- }
- } else if (_toSnap) {
- pos--;
- }
- this.applySnap(aUndo[Math.max(--pos,0)]);
- while (pos && (aUndo[pos].event === 'blur' || (aUndo[pos+1].editable === aUndo[pos].editable && aUndo[pos+1].contents === aUndo[pos].contents))) {
- this.applySnap(aUndo[--pos]);
- }
- };
-
- this.hasUndo = function () {
- return (toSnap && (toSnap.event !== 'blur' && toSnap.event !== 'activate' && toSnap.event !== 'undo')) ||
- !!_.find(aUndo.slice(0, pos+1), function (undo) {
- return undo.event !== 'blur' && undo.event !== 'activate' && undo.event !== 'undo';
- });
- };
-
- this.getEditableHasUndo = function () {
- var editable = [];
- if ((toSnap && (toSnap.event !== 'blur' && toSnap.event !== 'activate' && toSnap.event !== 'undo'))) {
- editable.push(toSnap.editable);
- }
- _.each(aUndo.slice(0, pos+1), function (undo) {
- if (undo.event !== 'blur' && undo.event !== 'activate' && undo.event !== 'undo') {
- editable.push(undo.editable);
- }
- });
- return _.uniq(editable);
- };
-
- this.redo = function () {
- if (!aUndo[pos+1]) { return; }
- this.applySnap(aUndo[++pos]);
- while (aUndo[pos+1] && aUndo[pos].event === 'active') {
- this.applySnap(aUndo[pos++]);
- }
- };
-
- this.hasRedo = function () {
- return aUndo.length > pos+1;
- };
-
- this.recordUndo = function ($editable, event, internal_history) {
- var self = this;
- if (!$editable) {
- var rng = range.create();
- if (!rng) return;
- $editable = $(rng.sc).closest('.o_editable');
- }
-
- if (aUndo[pos] && (event === 'applySnap' || event === 'activate')) {
- return;
- }
-
- if (!internal_history) {
- if (!event || !toSnap || !aUndo[pos-1] || toSnap.event === 'activate') { // don't trigger change for all keypress
- setTimeout(function () {
- $editable.trigger('content_changed');
- },0);
- }
- }
-
- if (aUndo[pos]) {
- pos = Math.min(pos, aUndo.length);
- aUndo.splice(pos, aUndo.length);
- }
-
- // => make a snap when the user change editable zone (because: don't make snap for each keydown)
- if (toSnap && (toSnap.split || !event || toSnap.event !== event || toSnap.editable !== $editable[0])) {
- this.saveSnap();
- }
-
- if (pos && aUndo[pos-1].editable !== $editable[0]) {
- var snap = this.makeSnap('blur', range.create(aUndo[pos-1].editable, 0));
- pos++;
- aUndo.push(snap);
- }
-
- if (range.create()) {
- toSnap = self.makeSnap(event);
- } else {
- toSnap = false;
- }
- };
-
- this.splitNext = function () {
- if (toSnap) {
- toSnap.split = true;
- }
- };
-
- this.saveSnap = function () {
- if (toSnap) {
- if (!aUndo[pos]) {
- pos++;
- }
- aUndo.push(toSnap);
- delete toSnap.split;
- toSnap = null;
- }
- };
-};
-var history = new History();
-
-// jQuery extensions
-$.extend($.expr[':'], {
- o_editable: function (node, i, m) {
- while (node) {
- if (node.className && _.isString(node.className)) {
- if (node.className.indexOf('o_not_editable')!==-1 ) {
- return false;
- }
- if (node.className.indexOf('o_editable')!==-1 ) {
- return true;
- }
- }
- node = node.parentNode;
- }
- return false;
- },
-});
-$.fn.extend({
- focusIn: function () {
- if (this.length) {
- range.create(dom.firstChild(this[0]), 0).select();
- }
- return this;
- },
- focusInEnd: function () {
- if (this.length) {
- var last = dom.lastChild(this[0]);
- range.create(last, dom.nodeLength(last)).select();
- }
- return this;
- },
- selectContent: function () {
- if (this.length) {
- var next = dom.lastChild(this[0]);
- range.create(dom.firstChild(this[0]), 0, next, next.textContent.length).select();
- }
- return this;
- },
-});
-
-// RTE
-var RTEWidget = Widget.extend({
- /**
- * @constructor
- */
- init: function (parent, params) {
- var self = this;
- this._super.apply(this, arguments);
-
- this.init_bootstrap_carousel = $.fn.carousel;
- this.edit_bootstrap_carousel = function () {
- var res = self.init_bootstrap_carousel.apply(this, arguments);
- // off bootstrap keydown event to remove event.preventDefault()
- // and allow to change cursor position
- $(this).off('keydown.bs.carousel');
- return res;
- };
-
- this._getConfig = params && params.getConfig || this._getDefaultConfig;
- this._saveElement = params && params.saveElement || this._saveElement;
-
- fonts.computeFonts();
- },
- /**
- * @override
- */
- start: function () {
- var self = this;
-
- this.saving_mutex = new concurrency.Mutex();
-
- $.fn.carousel = this.edit_bootstrap_carousel;
-
- $(document).on('click.rte keyup.rte', function () {
- var current_range = {};
- try {
- current_range = range.create() || {};
- } catch (e) {
- // if range is on Restricted element ignore error
- }
- var $popover = $(current_range.sc).closest('[contenteditable]');
- var popover_history = ($popover.data()||{}).NoteHistory;
- if (!popover_history || popover_history === history) return;
- var editor = $popover.parent('.note-editor');
- $('button[data-event="undo"]', editor).attr('disabled', !popover_history.hasUndo());
- $('button[data-event="redo"]', editor).attr('disabled', !popover_history.hasRedo());
- });
- $(document).on('mousedown.rte activate.rte', this, this._onMousedown.bind(this));
- $(document).on('mouseup.rte', this, this._onMouseup.bind(this));
-
- $('.o_not_editable').attr('contentEditable', false);
-
- var $editable = this.editable();
-
- // When a undo/redo is performed, the whole DOM is changed so we have
- // to prepare for it (website will restart animations for example)
- // TODO should be better handled
- $editable.on('content_will_be_destroyed', function (ev) {
- self.trigger_up('content_will_be_destroyed', {
- $target: $(ev.currentTarget),
- });
- });
- $editable.on('content_was_recreated', function (ev) {
- self.trigger_up('content_was_recreated', {
- $target: $(ev.currentTarget),
- });
- });
-
- $editable.addClass('o_editable')
- .data('rte', this)
- .each(function () {
- var $node = $(this);
-
- // fallback for firefox iframe display:none see https://github.com/odoo/odoo/pull/22610
- var computedStyles = window.getComputedStyle(this) || window.parent.getComputedStyle(this);
- // add class to display inline-block for empty t-field
- if (computedStyles.display === 'inline' && $node.data('oe-type') !== 'image') {
- $node.addClass('o_is_inline_editable');
- }
- });
-
- // start element observation
- $(document).on('content_changed', function (ev) {
- self.trigger_up('rte_change', {target: ev.target});
-
- // Add the dirty flag to the element that changed by either adding
- // it on the highest editable ancestor or, if there is no editable
- // ancestor, on the element itself (that element may not be editable
- // but if it received a content_changed event, it should be marked
- // as dirty to allow for custom savings).
- if (!ev.__isDirtyHandled) {
- ev.__isDirtyHandled = true;
-
- var el = ev.target;
- var dirty = el.closest('.o_editable') || el;
- dirty.classList.add('o_dirty');
- }
- });
-
- $('#wrapwrap, .o_editable').on('click.rte', '*', this, this._onClick.bind(this));
-
- $('body').addClass('editor_enable');
-
- $(document.body)
- .tooltip({
- selector: '[data-oe-readonly]',
- container: 'body',
- trigger: 'hover',
- delay: { 'show': 1000, 'hide': 100 },
- placement: 'bottom',
- title: _t("Readonly field")
- })
- .on('click', function () {
- $(this).tooltip('hide');
- });
-
- $(document).trigger('mousedown');
- this.trigger('rte:start');
-
- return this._super.apply(this, arguments);
- },
- /**
- * @override
- */
- destroy: function () {
- this.cancel();
- this._super.apply(this, arguments);
- },
-
- //--------------------------------------------------------------------------
- // Public
- //--------------------------------------------------------------------------
-
- /**
- * Stops the RTE.
- */
- cancel: function () {
- if (this.$last) {
- this.$last.destroy();
- this.$last = null;
- }
-
- $.fn.carousel = this.init_bootstrap_carousel;
-
- $(document).off('.rte');
- $('#wrapwrap, .o_editable').off('.rte');
-
- $('.o_not_editable').removeAttr('contentEditable');
-
- $(document).off('click.rte keyup.rte mousedown.rte activate.rte mouseup.rte');
- $(document).off('content_changed').removeClass('o_is_inline_editable').removeData('rte');
- $(document).tooltip('dispose');
- $('body').removeClass('editor_enable');
- this.trigger('rte:stop');
- },
- /**
- * Returns the editable areas on the page.
- *
- * @returns {jQuery}
- */
- editable: function () {
- return $('#wrapwrap [data-oe-model]')
- .not('.o_not_editable')
- .filter(function () {
- return !$(this).closest('.o_not_editable').length;
- })
- .not('link, script')
- .not('[data-oe-readonly]')
- .not('img[data-oe-field="arch"], br[data-oe-field="arch"], input[data-oe-field="arch"]')
- .not('.oe_snippet_editor')
- .add('.o_editable');
- },
- /**
- * Records the current state of the given $target to be able to undo future
- * changes.
- *
- * @see History.recordUndo
- * @param {jQuery} $target
- * @param {string} event
- * @param {boolean} internal_history
- */
- historyRecordUndo: function ($target, event, internal_history) {
- const initialActiveElement = document.activeElement;
- const initialSelectionStart = initialActiveElement && initialActiveElement.selectionStart;
- const initialSelectionEnd = initialActiveElement && initialActiveElement.selectionEnd;
-
- $target = $($target);
- var rng = range.create();
- var $editable = $(rng && rng.sc).closest('.o_editable');
- if (!rng || !$editable.length) {
- $editable = $target.closest('.o_editable');
- rng = range.create($target.closest('*')[0],0);
- } else {
- rng = $editable.data('range') || rng;
- }
- try {
- // TODO this line might break for unknown reasons. I suppose that
- // the created range is an invalid one. As it might be tricky to
- // adapt that line and that it is not a critical one, temporary fix
- // is to ignore the errors that this generates.
- rng.select();
- } catch (e) {
- console.log('error', e);
- }
- history.recordUndo($editable, event, internal_history);
-
- if (initialActiveElement && initialActiveElement !== document.activeElement) {
- initialActiveElement.focus();
- // Range inputs don't support selection
- if (initialActiveElement.matches('input[type=range]')) {
- return;
- }
- try {
- initialActiveElement.selectionStart = initialSelectionStart;
- initialActiveElement.selectionEnd = initialSelectionEnd;
- } catch (e) {
- // The active element might be of a type that
- // does not support selection.
- console.log('error', e);
- }
- }
- },
- /**
- * Searches all the dirty element on the page and saves them one by one. If
- * one cannot be saved, this notifies it to the user and restarts rte
- * edition.
- *
- * @param {Object} [context] - the context to use for saving rpc, default to
- * the editor context found on the page
- * @return {Promise} rejected if the save cannot be done
- */
- save: function (context) {
- var self = this;
-
- $('.o_editable')
- .destroy()
- .removeClass('o_editable o_is_inline_editable o_editable_date_field_linked o_editable_date_field_format_changed');
-
- var $dirty = $('.o_dirty');
- $dirty
- .removeAttr('contentEditable')
- .removeClass('o_dirty oe_carlos_danger o_is_inline_editable');
- var defs = _.map($dirty, function (el) {
- var $el = $(el);
-
- $el.find('[class]').filter(function () {
- if (!this.getAttribute('class').match(/\S/)) {
- this.removeAttribute('class');
- }
- });
-
- // TODO: Add a queue with concurrency limit in webclient
- // https://github.com/medikoo/deferred/blob/master/lib/ext/function/gate.js
- return self.saving_mutex.exec(function () {
- return self._saveElement($el, context || weContext.get())
- .then(function () {
- $el.removeClass('o_dirty');
- }).guardedCatch(function (response) {
- // because ckeditor regenerates all the dom, we can't just
- // setup the popover here as everything will be destroyed by
- // the DOM regeneration. Add markings instead, and returns a
- // new rejection with all relevant info
- var id = _.uniqueId('carlos_danger_');
- $el.addClass('o_dirty oe_carlos_danger ' + id);
- $('.o_editable.' + id)
- .removeClass(id)
- .popover({
- trigger: 'hover',
- content: response.message.data.message || '',
- placement: 'auto top',
- })
- .popover('show');
- });
- });
- });
-
- return Promise.all(defs).then(function () {
- window.onbeforeunload = null;
- }).guardedCatch(function (failed) {
- // If there were errors, re-enable edition
- self.cancel();
- self.start();
- });
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * When the users clicks on an editable element, this function allows to add
- * external behaviors.
- *
- * @private
- * @param {jQuery} $editable
- */
- _enableEditableArea: function ($editable) {
- if ($editable.data('oe-type') === "datetime" || $editable.data('oe-type') === "date") {
- var selector = '[data-oe-id="' + $editable.data('oe-id') + '"]';
- selector += '[data-oe-field="' + $editable.data('oe-field') + '"]';
- selector += '[data-oe-model="' + $editable.data('oe-model') + '"]';
- var $linkedFieldNodes = this.editable().find(selector).addBack(selector);
- $linkedFieldNodes.not($editable).addClass('o_editable_date_field_linked');
- if (!$editable.hasClass('o_editable_date_field_format_changed')) {
- $linkedFieldNodes.html($editable.data('oe-original-with-format'));
- $linkedFieldNodes.addClass('o_editable_date_field_format_changed');
- }
- }
- if ($editable.data('oe-type') === "monetary") {
- $editable.attr('contenteditable', false);
- $editable.find('.oe_currency_value').attr('contenteditable', true);
- }
- if ($editable.is('[data-oe-model]') && !$editable.is('[data-oe-model="ir.ui.view"]') && !$editable.is('[data-oe-type="html"]')) {
- $editable.data('layoutInfo').popover().find('.btn-group:not(.note-history)').remove();
- }
- },
- /**
- * When an element enters edition, summernote is initialized on it. This
- * function returns the default configuration for the summernote instance.
- *
- * @see _getConfig
- * @private
- * @param {jQuery} $editable
- * @returns {Object}
- */
- _getDefaultConfig: function ($editable) {
- return {
- 'airMode' : true,
- 'focus': false,
- 'airPopover': [
- ['style', ['style']],
- ['font', ['bold', 'italic', 'underline', 'clear']],
- ['fontsize', ['fontsize']],
- ['color', ['color']],
- ['para', ['ul', 'ol', 'paragraph']],
- ['table', ['table']],
- ['insert', ['link', 'picture']],
- ['history', ['undo', 'redo']],
- ],
- 'styleWithSpan': false,
- 'inlinemedia' : ['p'],
- 'lang': 'odoo',
- 'onChange': function (html, $editable) {
- $editable.trigger('content_changed');
- },
- 'colors': summernoteCustomColors,
- };
- },
- /**
- * Gets jQuery cloned element with internal text nodes escaped for XML
- * storage.
- *
- * @private
- * @param {jQuery} $el
- * @return {jQuery}
- */
- _getEscapedElement: function ($el) {
- var escaped_el = $el.clone();
- var to_escape = escaped_el.find('*').addBack();
- to_escape = to_escape.not(to_escape.filter('object,iframe,script,style,[data-oe-model][data-oe-model!="ir.ui.view"]').find('*').addBack());
- to_escape.contents().each(function () {
- if (this.nodeType === 3) {
- this.nodeValue = $('
').text(this.nodeValue).html();
- }
- });
- return escaped_el;
- },
- /**
- * Saves one (dirty) element of the page.
- *
- * @private
- * @param {jQuery} $el - the element to save
- * @param {Object} context - the context to use for the saving rpc
- * @param {boolean} [withLang=false]
- * false if the lang must be omitted in the context (saving "master"
- * page element)
- */
- _saveElement: function ($el, context, withLang) {
- var viewID = $el.data('oe-id');
- if (!viewID) {
- return Promise.resolve();
- }
-
- return this._rpc({
- model: 'ir.ui.view',
- method: 'save',
- args: [
- viewID,
- this._getEscapedElement($el).prop('outerHTML'),
- !$el.data('oe-expression') && $el.data('oe-xpath') || null, // Note: hacky way to get the oe-xpath only if not a t-field
- ],
- context: context,
- }, withLang ? undefined : {
- noContextKeys: 'lang',
- });
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * Called when any editable element is clicked -> Prevents default browser
- * action for the element.
- *
- * @private
- * @param {Event} e
- */
- _onClick: function (e) {
- e.preventDefault();
- },
- /**
- * Called when the mouse is pressed on the document -> activate element
- * edition.
- *
- * @private
- * @param {Event} ev
- */
- _onMousedown: function (ev) {
- var $target = $(ev.target);
- var $editable = $target.closest('.o_editable');
- var isLink = $target.is('a');
-
- if (this && this.$last && this.$last.length && this.$last[0] !== $target[0]) {
- $('.o_editable_date_field_linked').removeClass('o_editable_date_field_linked');
- }
- // Keep popover open if clicked inside it, but not on a button
- if (!($target.parents('.o_edit_menu_popover').length && !$target.parent('a').addBack('a').length)) {
- $('.o_edit_menu_popover').popover('hide');
- }
- if (!$editable.length || (!isLink && $.summernote.core.dom.isContentEditableFalse($target))) {
- return;
- }
-
- // Removes strange _moz_abspos attribute when it appears. Cannot
- // find another solution which works in all cases. A grabber still
- // appears at the same time which I did not manage to remove.
- // TODO find a complete and better solution
- _.defer(function () {
- $editable.find('[_moz_abspos]').removeAttr('_moz_abspos');
- });
-
- if (isLink) {
- if (!$target.data('popover-widget-initialized')) {
- weWidgets.LinkPopoverWidget.createFor(this, ev.target);
- $target.data('popover-widget-initialized', true);
- }
-
- /**
- * Remove content editable everywhere and add it on the link only so that characters can be added
- * and removed at the start and at the end of it.
- */
- let hasContentEditable = $target.attr('contenteditable');
- $target.attr('contenteditable', true);
- _.defer(function () {
- $editable.not($target).attr('contenteditable', false);
- $target.focus();
- });
-
- // Once clicked outside, remove contenteditable on link and reactive all
- $(document).on('mousedown.reactivate_contenteditable', function (e) {
- // Keep popover open if clicked inside it, but not on a button
- const $currTarget = $(e.target);
- if (!($currTarget.parents('.o_edit_menu_popover').length && !$currTarget.parent('a').addBack('a').length)) {
- $('.o_edit_menu_popover').popover('hide');
- } else {
- return;
- }
-
- if ($target.is(e.target)) {
- return;
- }
- if (!hasContentEditable) {
- $target.removeAttr('contenteditable');
- }
- $editable.attr('contenteditable', true);
- $(document).off('mousedown.reactivate_contenteditable');
- });
- }
-
- if (this && this.$last && (!$editable.length || this.$last[0] !== $editable[0])) {
- var $destroy = this.$last;
- history.splitNext();
- // In some special cases, we need to clear the timeout.
- var lastTimerId = _.delay(function () {
- var id = $destroy.data('note-id');
- $destroy.destroy().removeData('note-id').removeAttr('data-note-id');
- $('#note-popover-'+id+', #note-handle-'+id+', #note-dialog-'+id+'').remove();
- }, 150); // setTimeout to remove flickering when change to editable zone (re-create an editor)
- this.$last = null;
- // for modal dialogs (eg newsletter popup), when we close the dialog, the modal is
- // destroyed immediately and so after the delayed execution due to timeout, dialog will
- // not be available, leading to trace-back, so we need to clearTimeout for the dialogs.
- if ($destroy.hasClass('modal-body')) {
- clearTimeout(lastTimerId);
- }
- }
-
- if ($editable.length && (!this.$last || this.$last[0] !== $editable[0])) {
- $editable.summernote(this._getConfig($editable));
- if ($editable.is('[data-oe-many2one-id]')) {
- $editable.attr('contenteditable', false);
- }
-
- $editable.data('NoteHistory', history);
- this.$last = $editable;
-
- // firefox & IE fix
- try {
- document.execCommand('enableObjectResizing', false, false);
- document.execCommand('enableInlineTableEditing', false, false);
- document.execCommand('2D-position', false, false);
- } catch (e) { /* */ }
- document.body.addEventListener('resizestart', function (evt) {evt.preventDefault(); return false;});
- document.body.addEventListener('movestart', function (evt) {evt.preventDefault(); return false;});
- document.body.addEventListener('dragstart', function (evt) {evt.preventDefault(); return false;});
-
- if (!range.create()) {
- $editable.focusIn();
- }
-
- if (dom.isImg($target[0])) {
- $target.trigger('mousedown'); // for activate selection on picture
- }
-
- this._enableEditableArea($editable);
- }
- },
- /**
- * Called when the mouse is unpressed on the document.
- *
- * @private
- * @param {Event} ev
- */
- _onMouseup: function (ev) {
- var $target = $(ev.target);
- var $editable = $target.closest('.o_editable');
-
- if (!$editable.length) {
- return;
- }
-
- var self = this;
- _.defer(function () {
- self.historyRecordUndo($target, 'activate', true);
- });
-
- // Browsers select different content from one to another after a
- // triple click (especially: if triple-clicking on a paragraph on
- // Chrome, blank characters of the element following the paragraph are
- // selected too)
- //
- // The triple click behavior is reimplemented for all browsers here
- if (ev.originalEvent && ev.originalEvent.detail === 3) {
- // Select the whole content inside the deepest DOM element that was
- // triple-clicked
- range.create(ev.target, 0, ev.target, ev.target.childNodes.length).select();
- }
- },
-});
-
-return {
- Class: RTEWidget,
- history: history,
-};
-});
-
-odoo.define('web_editor.rte.summernote_custom_colors', function (require) {
-'use strict';
-
-// These colors are already normalized as per normalizeCSSColor in web.Colorpicker
-return [
- ['#000000', '#424242', '#636363', '#9C9C94', '#CEC6CE', '#EFEFEF', '#F7F7F7', '#FFFFFF'],
- ['#FF0000', '#FF9C00', '#FFFF00', '#00FF00', '#00FFFF', '#0000FF', '#9C00FF', '#FF00FF'],
- ['#F7C6CE', '#FFE7CE', '#FFEFC6', '#D6EFD6', '#CEDEE7', '#CEE7F7', '#D6D6E7', '#E7D6DE'],
- ['#E79C9C', '#FFC69C', '#FFE79C', '#B5D6A5', '#A5C6CE', '#9CC6EF', '#B5A5D6', '#D6A5BD'],
- ['#E76363', '#F7AD6B', '#FFD663', '#94BD7B', '#73A5AD', '#6BADDE', '#8C7BC6', '#C67BA5'],
- ['#CE0000', '#E79439', '#EFC631', '#6BA54A', '#4A7B8C', '#3984C6', '#634AA5', '#A54A7B'],
- ['#9C0000', '#B56308', '#BD9400', '#397B21', '#104A5A', '#085294', '#311873', '#731842'],
- ['#630000', '#7B3900', '#846300', '#295218', '#083139', '#003163', '#21104A', '#4A1031']
-];
-});
diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js
deleted file mode 100644
index ee0db26929d..00000000000
--- a/addons/web_editor/static/src/js/editor/rte.summernote.js
+++ /dev/null
@@ -1,1272 +0,0 @@
-odoo.define('web_editor.rte.summernote', function (require) {
-'use strict';
-
-var Class = require('web.Class');
-const concurrency = require('web.concurrency');
-var core = require('web.core');
-// Use the top window's core.bus for dialog events so that they take the whole window
-// instead of being confined to an iframe. This means that the event triggered on
-// the bus by summernote in an iframe will be caught by the wysiwyg's SummernoteManager
-// outside the iframe.
-const topBus = window.top.odoo.__DEBUG__.services['web.core'].bus;
-const {ColorpickerWidget} = require('web.Colorpicker');
-var ColorPaletteWidget = require('web_editor.ColorPalette').ColorPaletteWidget;
-var mixins = require('web.mixins');
-var fonts = require('wysiwyg.fonts');
-var rte = require('web_editor.rte');
-var ServicesMixin = require('web.ServicesMixin');
-var weWidgets = require('wysiwyg.widgets');
-require("summernote/summernote");
-
-var _t = core._t;
-
-// Summernote Lib (neek change to make accessible: method and object)
-var dom = $.summernote.core.dom;
-var range = $.summernote.core.range;
-var eventHandler = $.summernote.eventHandler;
-var renderer = $.summernote.renderer;
-
-// Summernote uses execCommand and, worth, obsolete queryCommandState function
-// to customize the edited content. Here we try to hack the function to solve
-// some problems by making the DOM and style easier to understand for the
-// base function for the duration of their executions. This won't obviously
-// solves all problems but this is an improvement while waiting for the new
-// Odoo editor coming in future versions.
-function protectCommand(callback) {
- return function () {
- var rng = range.create();
- var $sc = (rng && rng.sc) ? $(rng.sc).parents(':o_editable').last() : $();
- var $ec = (rng && rng.ec) ? $(rng.ec).parents(':o_editable').last() : $();
- $sc.addClass('o_we_command_protector');
- $ec.addClass('o_we_command_protector');
- var restore = function () {
- $sc.removeClass('o_we_command_protector');
- $ec.removeClass('o_we_command_protector');
- };
- var result;
- try {
- result = callback.apply(this, arguments);
- } catch (err) {
- restore();
- throw err;
- }
- restore();
- return result;
- };
-}
-document.execCommand = protectCommand(document.execCommand);
-document.queryCommandState = protectCommand(document.queryCommandState);
-
-var tplButton = renderer.getTemplate().button;
-var tplIconButton = renderer.getTemplate().iconButton;
-var tplDropdown = renderer.getTemplate().dropdown;
-
-const processAndApplyColor = function (target, eventName, color, preview) {
- if (!color) {
- color = 'inherit';
- } else if (!ColorpickerWidget.isCSSColor(color)) {
- color = (eventName === "foreColor" ? 'text-' : 'bg-') + color;
- }
- var layoutInfo = dom.makeLayoutInfo(target);
- $.summernote.pluginEvents[eventName](undefined, eventHandler.modules.editor, layoutInfo, color, preview);
-};
-// Update and change the popovers content, and add history button
-renderer.createPalette = function ($container, options) {
- const $dropdownContent = $container.find(".colorPalette");
- // The editor's root widget can be website or web's root widget and cannot be properly retrieved...
- const parent = odoo.__DEBUG__.services['root.widget'];
- _.each($dropdownContent, elem => {
- const eventName = elem.dataset.eventName;
- let colorpicker = null;
- const mutex = new concurrency.MutexedDropPrevious();
- const $dropdown = $(elem).closest('.btn-group, .dropdown');
- let manualOpening = false;
- // Prevent dropdown closing on colorpicker click
- $dropdown.on('hide.bs.dropdown', ev => {
- return !(ev.clickEvent && ev.clickEvent.originalEvent && ev.clickEvent.originalEvent.__isColorpickerClick);
- });
- $dropdown.on('show.bs.dropdown', () => {
- if (manualOpening) {
- return true;
- }
- mutex.exec(() => {
- const oldColorpicker = colorpicker;
- const hookEl = oldColorpicker ? oldColorpicker.el : elem;
-
- const r = range.create();
- const targetNode = r.sc;
- const targetElement = targetNode.nodeType === Node.ELEMENT_NODE ? targetNode : targetNode.parentNode;
- colorpicker = new ColorPaletteWidget(parent, {
- excluded: ['transparent_grayscale'],
- $editable: rte.Class.prototype.editable(), // Our parent is the root widget, we can't retrieve the editable section from it...
- selectedColor: $(targetElement).css(eventName === "foreColor" ? 'color' : 'backgroundColor'),
- });
- colorpicker.on('custom_color_picked color_picked', null, ev => {
- processAndApplyColor(ev.data.target, eventName, ev.data.color);
- });
- colorpicker.on('color_hover color_leave', null, ev => {
- processAndApplyColor(ev.data.target, eventName, ev.data.color, true);
- });
- colorpicker.on('enter_key_color_colorpicker', null, () => {
- $dropdown.children('.dropdown-toggle').dropdown('hide');
- });
- return colorpicker.replace(hookEl).then(() => {
- if (oldColorpicker) {
- oldColorpicker.destroy();
- }
- manualOpening = true;
- $dropdown.children('.dropdown-toggle').dropdown('show');
- manualOpening = false;
- });
- });
- return false;
- });
- });
-};
-
-var fn_tplPopovers = renderer.tplPopovers;
-renderer.tplPopovers = function (lang, options) {
- var $popover = $(fn_tplPopovers.call(this, lang, options));
-
- var $imagePopover = $popover.find('.note-image-popover');
- var $linkPopover = $popover.find('.note-link-popover');
- var $airPopover = $popover.find('.note-air-popover');
-
- //////////////// image popover
-
- // add center button for images
- $(tplIconButton('fa fa-align-center', {
- title: _t('Center'),
- event: 'floatMe',
- value: 'center'
- })).insertAfter($imagePopover.find('[data-event="floatMe"][data-value="left"]'));
- $imagePopover.find('button[data-event="removeMedia"]').parent().remove();
- $imagePopover.find('button[data-event="floatMe"][data-value="none"]').remove();
-
- // padding button
- var $padding = $('
');
- $padding.insertBefore($imagePopover.find('.btn-group:first'));
- var dropdown_content = [
- ''+_t('None')+' ',
- ''+_t('Small')+' ',
- ''+_t('Medium')+' ',
- ''+_t('Large')+' ',
- ''+_t('Xl')+' ',
- ];
- $(tplIconButton('fa fa-plus-square-o', {
- title: _t('Padding'),
- dropdown: tplDropdown(dropdown_content)
- })).appendTo($padding);
-
- // circle, boxed... options became toggled
- $imagePopover.find('[data-event="imageShape"]:not([data-value])').remove();
- var $button = $(tplIconButton('fa fa-sun-o', {
- title: _t('Shadow'),
- event: 'imageShape',
- value: 'shadow'
- })).insertAfter($imagePopover.find('[data-event="imageShape"][data-value="rounded-circle"]'));
-
- // add spin for fa
- var $spin = $('
').insertAfter($button.parent());
- $(tplIconButton('fa fa-refresh', {
- title: _t('Spin'),
- event: 'imageShape',
- value: 'fa-spin'
- })).appendTo($spin);
-
- // resize for fa
- var $resizefa = $('
')
- .insertAfter($imagePopover.find('.btn-group:has([data-event="resize"])'));
- for (var size=1; size<=5; size++) {
- $(tplButton(''+size+'x ', {
- title: size+"x",
- event: 'resizefa',
- value: size+''
- })).appendTo($resizefa);
- }
- var $colorfa = $airPopover.find('.note-color').clone();
- $colorfa.find(".dropdown-menu").css('min-width', '172px');
- $resizefa.after($colorfa);
-
- // show dialog box and delete
- var $imageprop = $('
');
- $imageprop.appendTo($imagePopover.find('.popover-body'));
- $(tplIconButton('fa fa-file-image-o', {
- title: _t('Edit'),
- event: 'showImageDialog'
- })).appendTo($imageprop);
- $(tplIconButton('fa fa-trash-o', {
- title: _t('Remove'),
- event: 'delete'
- })).appendTo($imageprop);
-
- $(tplIconButton('fa fa-crop', {
- title: _t('Crop Image'),
- event: 'cropImage',
- })).insertAfter($imagePopover.find('[data-event="imageShape"][data-value="img-thumbnail"]'));
-
- $imagePopover.find('.popover-body').append($airPopover.find(".note-history").clone());
-
- $imagePopover.find('[data-event="showImageDialog"]').before($airPopover.find('[data-event="showLinkDialog"]').clone());
-
- var $alt = $('
');
- $alt.appendTo($imagePopover.find('.popover-body'));
- $alt.append('' + _t('Description') + ': ');
-
- //////////////// link popover
-
- $linkPopover.find('.popover-body').append($airPopover.find(".note-history").clone());
-
- $linkPopover.find('button[data-event="showLinkDialog"] i').attr("class", "fa fa-link");
- $linkPopover.find('button[data-event="unlink"]').before($airPopover.find('button[data-event="showImageDialog"]').clone());
-
- //////////////// text/air popover
-
- //// highlight the text format
- $airPopover.find('.note-style .dropdown-toggle').on('mousedown', function () {
- var $format = $airPopover.find('[data-event="formatBlock"]');
- var node = range.create().sc;
- var formats = $format.map(function () { return $(this).data("value"); }).get();
- while (node && (!node.tagName || (!node.tagName || formats.indexOf(node.tagName.toLowerCase()) === -1))) {
- node = node.parentNode;
- }
- $format.removeClass('active');
- $format.filter('[data-value="'+(node ? node.tagName.toLowerCase() : "p")+'"]')
- .addClass("active");
- });
-
- //////////////// tooltip
-
- setTimeout(function () {
- $airPopover.add($linkPopover).add($imagePopover).find("button")
- .tooltip('dispose')
- .tooltip({
- container: 'body',
- trigger: 'hover',
- placement: 'bottom'
- }).on('click', function () {$(this).tooltip('hide');});
- });
-
- return $popover;
-};
-
-var fn_boutton_update = eventHandler.modules.popover.button.update;
-eventHandler.modules.popover.button.update = function ($container, oStyle) {
- // stop animation when edit content
- var previous = $(".note-control-selection").data('target');
- if (previous) {
- var $previous = $(previous);
- $previous.css({"-webkit-animation-play-state": "", "animation-play-state": "", "-webkit-transition": "", "transition": "", "-webkit-animation": "", "animation": ""});
- $previous.find('.o_we_selected_image').addBack('.o_we_selected_image').removeClass('o_we_selected_image');
- }
- // end
-
- fn_boutton_update.call(this, $container, oStyle);
-
- $container.find('.note-color').removeClass('d-none');
-
- if (oStyle.image) {
- $container.find('[data-event]').removeClass("active");
-
- $container.find('a[data-event="padding"][data-value="small"]').toggleClass("active", $(oStyle.image).hasClass("padding-small"));
- $container.find('a[data-event="padding"][data-value="medium"]').toggleClass("active", $(oStyle.image).hasClass("padding-medium"));
- $container.find('a[data-event="padding"][data-value="large"]').toggleClass("active", $(oStyle.image).hasClass("padding-large"));
- $container.find('a[data-event="padding"][data-value="xl"]').toggleClass("active", $(oStyle.image).hasClass("padding-xl"));
- $container.find('a[data-event="padding"][data-value=""]').toggleClass("active", !$container.find('li a.active[data-event="padding"]').length);
-
- $(oStyle.image).addClass('o_we_selected_image');
-
- if (dom.isImgFont(oStyle.image)) {
- $container.find('.note-fore-color-preview > button > .caret').css('border-bottom-color', $(oStyle.image).css('color'));
- $container.find('.note-back-color-preview > button > .caret').css('border-bottom-color', $(oStyle.image).css('background-color'));
-
- $container.find('.btn-group:not(.only_fa):has(button[data-event="resize"],button[data-value="img-thumbnail"])').addClass('d-none');
- $container.find('.only_fa').removeClass('d-none');
- $container.find('button[data-event="resizefa"][data-value="2"]').toggleClass("active", $(oStyle.image).hasClass("fa-2x"));
- $container.find('button[data-event="resizefa"][data-value="3"]').toggleClass("active", $(oStyle.image).hasClass("fa-3x"));
- $container.find('button[data-event="resizefa"][data-value="4"]').toggleClass("active", $(oStyle.image).hasClass("fa-4x"));
- $container.find('button[data-event="resizefa"][data-value="5"]').toggleClass("active", $(oStyle.image).hasClass("fa-5x"));
- $container.find('button[data-event="resizefa"][data-value="1"]').toggleClass("active", !$container.find('.active[data-event="resizefa"]').length);
-
- $container.find('button[data-event="imageShape"][data-value="fa-spin"]').toggleClass("active", $(oStyle.image).hasClass("fa-spin"));
- $container.find('button[data-event="imageShape"][data-value="shadow"]').toggleClass("active", $(oStyle.image).hasClass("shadow"));
- $container.find('.btn-group:has(button[data-event="imageShape"])').removeClass("d-none");
-
- } else {
- $container.find('.d-none:not(.only_fa, .note-recent-color)').removeClass('d-none');
- $container.find('.only_fa').addClass('d-none');
- var width = ($(oStyle.image).attr('style') || '').match(/(^|;|\s)width:\s*([0-9]+%)/);
- if (width) {
- width = width[2];
- }
- $container.find('button[data-event="resize"][data-value="auto"]').toggleClass("active", width !== "100%" && width !== "50%" && width !== "25%");
- $container.find('button[data-event="resize"][data-value="1"]').toggleClass("active", width === "100%");
- $container.find('button[data-event="resize"][data-value="0.5"]').toggleClass("active", width === "50%");
- $container.find('button[data-event="resize"][data-value="0.25"]').toggleClass("active", width === "25%");
-
- $container.find('button[data-event="imageShape"][data-value="shadow"]').toggleClass("active", $(oStyle.image).hasClass("shadow"));
-
- if (!$(oStyle.image).is("img")) {
- $container.find('.btn-group:has(button[data-event="imageShape"])').addClass('d-none');
- }
-
- $container.find('.note-color').addClass('d-none');
- }
-
- $container.find('button[data-event="floatMe"][data-value="left"]').toggleClass("active", $(oStyle.image).hasClass("float-left"));
- $container.find('button[data-event="floatMe"][data-value="center"]').toggleClass("active", $(oStyle.image).hasClass("d-block mx-auto"));
- $container.find('button[data-event="floatMe"][data-value="right"]').toggleClass("active", $(oStyle.image).hasClass("float-right"));
-
- $(oStyle.image).trigger('attributes_change');
- } else {
- $container.find('.note-fore-color-preview > button > .caret').css('border-bottom-color', oStyle.color);
- $container.find('.note-back-color-preview > button > .caret').css('border-bottom-color', oStyle['background-color']);
- }
-};
-
-var fn_toolbar_boutton_update = eventHandler.modules.toolbar.button.update;
-eventHandler.modules.toolbar.button.update = function ($container, oStyle) {
- fn_toolbar_boutton_update.call(this, $container, oStyle);
-
- $container.find('button[data-event="insertUnorderedList"]').toggleClass("active", $(oStyle.ancestors).is('ul:not(.o_checklist)'));
- $container.find('button[data-event="insertOrderedList"]').toggleClass("active", $(oStyle.ancestors).is('ol'));
- $container.find('button[data-event="insertCheckList"]').toggleClass("active", $(oStyle.ancestors).is('ul.o_checklist'));
-};
-
-var fn_popover_update = eventHandler.modules.popover.update;
-eventHandler.modules.popover.update = function ($popover, oStyle, isAirMode) {
- var $imagePopover = $popover.find('.note-image-popover');
- var $linkPopover = $popover.find('.note-link-popover');
- var $airPopover = $popover.find('.note-air-popover');
-
- fn_popover_update.call(this, $popover, oStyle, isAirMode);
-
- if (oStyle.image) {
- if (oStyle.image.parentNode.className.match(/(^|\s)media_iframe_video(\s|$)/i)) {
- oStyle.image = oStyle.image.parentNode;
- }
- var alt = $(oStyle.image).attr("alt");
-
- $imagePopover.find('.o_image_alt').text( (alt || "").replace(/"/g, '"') ).parent().toggle(oStyle.image.tagName === "IMG");
- $imagePopover.show();
-
- // for video tag (non-void) we select the range over the tag,
- // for other media types we get the first descendant leaf element
- var target_node = oStyle.image;
- if (!oStyle.image.className.match(/(^|\s)media_iframe_video(\s|$)/i)) {
- target_node = dom.firstChild(target_node);
- }
- range.createFromNode(target_node).select();
- // save range on the editor so it is not lost if restored
- eventHandler.modules.editor.saveRange(dom.makeLayoutInfo(target_node).editable());
- } else {
- $(".note-control-selection").hide();
- }
-
- if (oStyle.image || (oStyle.range && (!oStyle.range.isCollapsed() || (oStyle.range.sc.tagName && !dom.isAnchor(oStyle.range.sc)))) || (oStyle.image && !$(oStyle.image).closest('a').length)) {
- $linkPopover.hide();
- oStyle.anchor = false;
- }
-
- if (oStyle.image || oStyle.anchor || (oStyle.range && !$(oStyle.range.sc).closest('.note-editable').length)) {
- $airPopover.hide();
- } else {
- $airPopover.show();
- }
-
- const $externalHistoryButtons = $('.o_we_external_history_buttons');
- if ($externalHistoryButtons.length) {
- const $noteHistory = $('.note-history');
- $noteHistory.addClass('d-none');
- $externalHistoryButtons.find(':first-child').prop('disabled', $noteHistory.find('[data-event=undo]').prop('disabled'));
- $externalHistoryButtons.find(':last-child').prop('disabled', $noteHistory.find('[data-event=redo]').prop('disabled'));
- }
- $popover.trigger('summernote_popover_update_call');
-};
-
-var fn_handle_update = eventHandler.modules.handle.update;
-eventHandler.modules.handle.update = function ($handle, oStyle, isAirMode) {
- fn_handle_update.call(this, $handle, oStyle, isAirMode);
- if (oStyle.image) {
- $handle.find('.note-control-selection').hide();
- }
-};
-
-// Hack for image and link editor
-function getImgTarget($editable) {
- var $handle = $editable ? dom.makeLayoutInfo($editable).handle() : undefined;
- return $(".note-control-selection", $handle).data('target');
-}
-eventHandler.modules.editor.padding = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- var paddings = "small medium large xl".split(/\s+/);
- $editable.data('NoteHistory').recordUndo();
- if (sValue.length) {
- paddings.splice(paddings.indexOf(sValue),1);
- $target.toggleClass('padding-'+sValue);
- }
- $target.removeClass("padding-" + paddings.join(" padding-"));
-};
-eventHandler.modules.editor.resize = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- $editable.data('NoteHistory').recordUndo();
- var width = ($target.attr('style') || '').match(/(^|;|\s)width:\s*([0-9]+)%/);
- if (width) {
- width = width[2]/100;
- }
- $target.css('width', (width !== sValue && sValue !== "auto") ? (sValue * 100) + '%' : '');
-};
-eventHandler.modules.editor.resizefa = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- $editable.data('NoteHistory').recordUndo();
- $target.attr('class', $target.attr('class').replace(/\s*fa-[0-9]+x/g, ''));
- if (+sValue > 1) {
- $target.addClass('fa-'+sValue+'x');
- }
-};
-eventHandler.modules.editor.floatMe = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- $editable.data('NoteHistory').recordUndo();
- switch (sValue) {
- case 'center': $target.toggleClass('d-block mx-auto').removeClass('float-right float-left'); break;
- case 'left': $target.toggleClass('float-left').removeClass('float-right d-block mx-auto'); break;
- case 'right': $target.toggleClass('float-right').removeClass('float-left d-block mx-auto'); break;
- }
-};
-eventHandler.modules.editor.imageShape = function ($editable, sValue) {
- var $target = $(getImgTarget($editable));
- $editable.data('NoteHistory').recordUndo();
- $target.toggleClass(sValue);
-};
-
-eventHandler.modules.linkDialog.showLinkDialog = function ($editable, $dialog, linkInfo) {
- $editable.data('range').select();
- $editable.data('NoteHistory').recordUndo();
-
- var commonAncestor = linkInfo.range.commonAncestor();
- if (commonAncestor && commonAncestor.closest) {
- var link = commonAncestor.closest('a');
- linkInfo.className = link && link.className;
- }
-
- var def = new $.Deferred();
- topBus.trigger('link_dialog_demand', {
- options: eventHandler.modules.linkDialog.options,
- $editable: $editable,
- linkInfo: linkInfo,
- onSave: function (linkInfo) {
- linkInfo.range.select();
- $editable.data('range', linkInfo.range);
- def.resolve(linkInfo);
- $editable.trigger('keyup');
- $('.note-popover .note-link-popover').show();
- },
- onCancel: def.reject.bind(def),
- });
- return def;
-};
-var originalShowImageDialog = eventHandler.modules.imageDialog.showImageDialog;
-eventHandler.modules.imageDialog.showImageDialog = function ($editable) {
- var options = $editable.closest('.o_editable, .note-editor').data('options');
- if (options.disableFullMediaDialog) {
- return originalShowImageDialog.apply(this, arguments);
- }
- var r = $editable.data('range');
- if (r.sc.tagName && r.sc.childNodes.length) {
- r.sc = r.sc.childNodes[r.so];
- }
- var media = $(r.sc).parents().addBack().filter(function (i, el) {
- return dom.isImg(el);
- })[0];
- topBus.trigger('media_dialog_demand', {
- $editable: $editable,
- media: media,
- options: {
- onUpload: $editable.data('callbacks').onUpload,
- noVideos: options && options.noVideos,
- },
- onSave: function (newMedia) {
- if (!newMedia) {
- return;
- }
- if (media) {
- $(media).replaceWith(newMedia);
- } else {
- r.insertNode(newMedia);
- }
- },
- });
- return new $.Deferred().reject();
-};
-$.summernote.pluginEvents.alt = function (event, editor, layoutInfo, sorted) {
- var $editable = layoutInfo.editable();
- var $selection = layoutInfo.handle().find('.note-control-selection');
- topBus.trigger('alt_dialog_demand', {
- $editable: $editable,
- media: $selection.data('target'),
- });
-};
-$.summernote.pluginEvents.cropImage = function (event, editor, layoutInfo, sorted) {
- var $editable = layoutInfo.editable();
- var $selection = layoutInfo.handle().find('.note-control-selection');
- topBus.trigger('crop_image_demand', {
- $editable: $editable,
- media: $selection.data('target'),
- });
-};
-
-// Utils
-var fn_is_void = dom.isVoid || function () {};
-dom.isVoid = function (node) {
- return fn_is_void(node) || dom.isImgFont(node) || (node && node.className && node.className.match(/(^|\s)media_iframe_video(\s|$)/i));
-};
-var fn_is_img = dom.isImg || function () {};
-dom.isImg = function (node) {
- return fn_is_img(node) || dom.isImgFont(node) || (node && (node.nodeName === "IMG" || (node.className && node.className.match(/(^|\s)(media_iframe_video|o_image)(\s|$)/i)) ));
-};
-var fn_is_forbidden_node = dom.isForbiddenNode || function () {};
-dom.isForbiddenNode = function (node) {
- if (node.tagName === "BR") {
- return false;
- }
- return fn_is_forbidden_node(node) || $(node).is(".media_iframe_video");
-};
-var fn_is_img_font = dom.isImgFont || function () {};
-dom.isImgFont = function (node) {
- if (fn_is_img_font(node)) return true;
-
- var nodeName = node && node.nodeName.toUpperCase();
- var className = (node && node.className || "");
- if (node && (nodeName === "SPAN" || nodeName === "I") && className.length) {
- var classNames = className.split(/\s+/);
- for (var k=0; k ')[0];
- $node.append( p );
- range.createFromNode(p.firstChild).select();
- }
- return res;
-};
-
-function prettify_html(html) {
- html = html.trim();
- var result = '',
- level = 0,
- get_space = function (level) {
- var i = level, space = '';
- while (i--) space += ' ';
- return space;
- },
- reg = /^<\/?(a|span|font|u|em|i|strong|b)(\s|>)/i,
- inline_level = Infinity,
- tokens = _.compact(_.flatten(_.map(html.split(/), function (value) {
- value = value.replace(/\s+/g, ' ').split(/>/);
- value[0] = /\S/.test(value[0]) ? '<' + value[0] + '>' : '';
- return value;
- })));
-
- // reduce => merge inline style + text
-
- for (var i = 0, l = tokens.length; i < l; i++) {
- var token = tokens[i];
- var inline_tag = reg.test(token);
- var inline = inline_tag || inline_level <= level;
-
- if (token[0] === '<' && token[1] === '/') {
- if (inline_tag && inline_level === level) {
- inline_level = Infinity;
- }
- level--;
- }
-
- if (!inline && !/\S/.test(token)) {
- continue;
- }
- if (!inline || (token[1] !== '/' && inline_level > level)) {
- result += get_space(level);
- }
-
- if (token[0] === '<' && token[1] !== '/') {
- level++;
- if (inline_tag && inline_level > level) {
- inline_level = level;
- }
- }
-
- if (token.match(/^<(img|hr|br)/)) {
- level--;
- }
-
- // don't trim inline content (which could change appearance)
- if (!inline) {
- token = token.trim();
- }
-
- result += token.replace(/\s+/, ' ');
-
- if (inline_level > level) {
- result += '\n';
- }
- }
- return result;
-}
-
-/*
- * This override when clicking on the 'Code View' button has two aims:
- *
- * - have our own code view implementation for FieldTextHtml
- * - add an 'enable' paramater to call the function directly and allow us to
- * disable (false) or enable (true) the code view mode.
- */
-$.summernote.pluginEvents.codeview = function (event, editor, layoutInfo, enable) {
- if (!layoutInfo) {
- return;
- }
- if (layoutInfo.toolbar) {
- // if editor inline (FieldTextHtmlSimple)
- var is_activated = $.summernote.eventHandler.modules.codeview.isActivated(layoutInfo);
- if (is_activated === enable) {
- return;
- }
- return eventHandler.modules.codeview.toggle(layoutInfo);
- } else {
- // if editor iframe (FieldTextHtml)
- var $editor = layoutInfo.editor();
- var $textarea = $editor.prev('textarea');
- if ($textarea.is('textarea') === enable) {
- return;
- }
-
- if (!$textarea.length) {
- // init and create texarea
- var html = prettify_html($editor.prop("innerHTML"));
- $editor.parent().css({
- 'position': 'absolute',
- 'top': 0,
- 'bottom': 0,
- 'left': 0,
- 'right': 0
- });
- $textarea = $('').css({
- 'margin': '0 -4px',
- 'padding': '0 4px',
- 'border': 0,
- 'top': '51px',
- 'left': '620px',
- 'width': '100%',
- 'font-family': 'sans-serif',
- 'font-size': '13px',
- 'height': '98%',
- 'white-space': 'pre',
- 'word-wrap': 'normal'
- }).val(html).data('init', html);
- $editor.before($textarea);
- $editor.hide();
- } else {
- // save changes
- $editor.prop('innerHTML', $textarea.val().replace(/\s*\n\s*/g, '')).trigger('content_changed');
- $textarea.remove();
- $editor.show();
- }
- }
-};
-
-// Fix ie and re-range to don't break snippet
-var last_div;
-var last_div_change;
-var last_editable;
-var initial_data = {};
-function reRangeSelectKey(event) {
- initial_data.range = null;
- if (event.shiftKey && event.keyCode >= 37 && event.keyCode <= 40 && !$(event.target).is("input, textarea, select")) {
- var r = range.create();
- if (r) {
- var rng = r.reRange(event.keyCode <= 38);
- if (r !== rng) {
- rng.select();
- }
- }
- }
-}
-function reRangeSelect(event, dx, dy) {
- var r = range.create();
- if (!r || r.isCollapsed()) return;
-
- // check if the user move the caret on up or down
- var data = r.reRange(dy < 0 || (dy === 0 && dx < 0));
-
- if (data.sc !== r.sc || data.so !== r.so || data.ec !== r.ec || data.eo !== r.eo) {
- setTimeout(function () {
- data.select();
- $(data.sc.parentNode).closest('.note-popover');
- },0);
- }
-
- $(data.sc).closest('.o_editable').data('range', r);
- return r;
-}
-function summernote_mouseup(event) {
- if ($(event.target).closest("#web_editor-top-navbar, .note-popover").length) {
- return;
- }
- // don't rerange if simple click
- if (initial_data.event) {
- var dx = event.clientX - (event.shiftKey && initial_data.rect ? initial_data.rect.left : initial_data.event.clientX);
- var dy = event.clientY - (event.shiftKey && initial_data.rect ? initial_data.rect.top : initial_data.event.clientY);
- if (10 < Math.pow(dx, 2)+Math.pow(dy, 2)) {
- reRangeSelect(event, dx, dy);
- }
- }
-
- if (!$(event.target).closest(".o_editable").length) {
- return;
- }
- if (!initial_data.range || !event.shiftKey) {
- setTimeout(function () {
- initial_data.range = range.create();
- },0);
- }
-}
-var remember_selection;
-function summernote_mousedown(event) {
- rte.history.splitNext();
-
- var $editable = $(event.target).closest(".o_editable, .note-editor");
- var r;
-
- if (document.documentMode) {
- summernote_ie_fix(event, function (node) { return node.tagName === "DIV" || node.tagName === "IMG" || (node.dataset && node.dataset.oeModel); });
- } else if (last_div && event.target !== last_div) {
- if (last_div.tagName === "A") {
- summernote_ie_fix(event, function (node) { return node.dataset && node.dataset.oeModel; });
- } else if ($editable.length) {
- if (summernote_ie_fix(event, function (node) { return node.tagName === "A"; })) {
- r = range.create();
- r.select();
- }
- }
- }
-
- // restore range if range lost after clicking on non-editable area
- try {
- r = range.create();
- } catch (e) {
- // If this code is running inside an iframe-editor and that the range
- // is outside of this iframe, this will fail as the iframe does not have
- // the permission to check the outside content this way. In that case,
- // we simply ignore the exception as it is as if there was no range.
- return;
- }
- var editables = $(".o_editable[contenteditable], .note-editable[contenteditable]");
- var r_editable = editables.has((r||{}).sc).addBack(editables.filter((r||{}).sc));
- if (!r_editable.closest('.note-editor').is($editable) && !r_editable.filter('.o_editable').is(editables)) {
- var saved_editable = editables.has((remember_selection||{}).sc);
- if ($editable.length && !saved_editable.closest('.o_editable, .note-editor').is($editable)) {
- remember_selection = range.create(dom.firstChild($editable[0]), 0);
- } else if (!saved_editable.length) {
- remember_selection = undefined;
- }
- if (remember_selection) {
- try {
- remember_selection.select();
- } catch (e) {
- console.warn(e);
- }
- }
- } else if (r_editable.length) {
- remember_selection = r;
- }
-
- initial_data.event = event;
-
- // keep selection when click with shift
- if (event.shiftKey && $editable.length) {
- if (initial_data.range) {
- initial_data.range.select();
- }
- var rect = r && r.getClientRects();
- initial_data.rect = rect && rect.length ? rect[0] : { top: 0, left: 0 };
- }
-}
-
-function summernote_ie_fix(event, pred) {
- var editable;
- var div;
- var node = event.target;
- while (node.parentNode) {
- if (!div && pred(node)) {
- div = node;
- }
- if (last_div !== node && (node.getAttribute('contentEditable')==='false' || node.className && (node.className.indexOf('o_not_editable') !== -1))) {
- break;
- }
- if (node.className && node.className.indexOf('o_editable') !== -1) {
- if (!div) {
- div = node;
- }
- editable = node;
- break;
- }
- node = node.parentNode;
- }
-
- if (!editable) {
- $(last_div_change).removeAttr("contentEditable").removeProp("contentEditable");
- $(last_editable).attr("contentEditable", "true").prop("contentEditable", "true");
- last_div_change = null;
- last_editable = null;
- return;
- }
-
- if (div === last_div) {
- return;
- }
-
- last_div = div;
-
- $(last_div_change).removeAttr("contentEditable").removeProp("contentEditable");
-
- if (last_editable !== editable) {
- if ($(editable).is("[contentEditable='true']")) {
- $(editable).removeAttr("contentEditable").removeProp("contentEditable");
- last_editable = editable;
- } else {
- last_editable = null;
- }
- }
- if (!$(div).attr("contentEditable") && !$(div).is("[data-oe-type='many2one'], [data-oe-type='contact']")) {
- $(div).attr("contentEditable", "true").prop("contentEditable", "true");
- last_div_change = div;
- } else {
- last_div_change = null;
- }
- return editable !== div ? div : null;
-}
-
-var fn_attach = eventHandler.attach;
-eventHandler.attach = function (oLayoutInfo, options) {
- fn_attach.call(this, oLayoutInfo, options);
-
- oLayoutInfo.editor().on('dragstart', 'img', function (e) { e.preventDefault(); });
- $(document).on('mousedown', summernote_mousedown).on('mouseup', summernote_mouseup);
- oLayoutInfo.editor().off('click').on('click', function (e) {e.preventDefault();}); // if the content editable is a link
- oLayoutInfo.editor().find('.note-image-dialog').on('click', '.note-image-input', function (e) {
- e.stopPropagation(); // let browser default happen for image file input
- });
-
- /**
- * Open Media Dialog on double click on an image/video/icon.
- * Shows a tooltip on click to say to the user he can double click.
- */
- create_dblclick_feature("img, .media_iframe_video, i.fa, span.fa, a.o_image", function () {
- eventHandler.modules.imageDialog.show(oLayoutInfo);
- });
-
- oLayoutInfo.editable().on('mousedown', function (e) {
- if (dom.isImg(e.target) && dom.isContentEditable(e.target)) {
- range.createFromNode(e.target).select();
- }
- });
- $(document).on("keyup", reRangeSelectKey);
-
- var clone_data = false;
-
- if (options.model) {
- oLayoutInfo.editable().data({'oe-model': options.model, 'oe-id': options.id});
- }
- if (options.getMediaDomain) {
- oLayoutInfo.editable().data('oe-media-domain', options.getMediaDomain);
- }
-
- var $node = oLayoutInfo.editor();
- if ($node.data('oe-model') || $node.data('oe-translation-id')) {
- $node.on('content_changed', function () {
- var $nodes = $('[data-oe-model], [data-oe-translation-id]')
- .filter(function () { return this !== $node[0];});
-
- if ($node.data('oe-model')) {
- $nodes = $nodes.filter('[data-oe-model="'+$node.data('oe-model')+'"]')
- .filter('[data-oe-id="'+$node.data('oe-id')+'"]')
- .filter('[data-oe-field="'+$node.data('oe-field')+'"]');
- }
- if ($node.data('oe-translation-id')) $nodes = $nodes.filter('[data-oe-translation-id="'+$node.data('oe-translation-id')+'"]');
- if ($node.data('oe-type')) $nodes = $nodes.filter('[data-oe-type="'+$node.data('oe-type')+'"]');
- if ($node.data('oe-expression')) $nodes = $nodes.filter('[data-oe-expression="'+$node.data('oe-expression')+'"]');
- else if ($node.data('oe-xpath')) $nodes = $nodes.filter('[data-oe-xpath="'+$node.data('oe-xpath')+'"]');
- if ($node.data('oe-contact-options')) $nodes = $nodes.filter("[data-oe-contact-options='"+$node[0].dataset.oeContactOptions+"']");
-
- var nodes = $node.get();
-
- if ($node.data('oe-type') === "many2one") {
- $nodes = $nodes.add($('[data-oe-model]')
- .filter(function () { return this !== $node[0] && nodes.indexOf(this) === -1; })
- .filter('[data-oe-many2one-model="'+$node.data('oe-many2one-model')+'"]')
- .filter('[data-oe-many2one-id="'+$node.data('oe-many2one-id')+'"]')
- .filter('[data-oe-type="many2one"]'));
-
- $nodes = $nodes.add($('[data-oe-model]')
- .filter(function () { return this !== $node[0] && nodes.indexOf(this) === -1; })
- .filter('[data-oe-model="'+$node.data('oe-many2one-model')+'"]')
- .filter('[data-oe-id="'+$node.data('oe-many2one-id')+'"]')
- .filter('[data-oe-field="name"]'));
- }
-
- if (!clone_data) {
- clone_data = true;
- $nodes.html(this.innerHTML);
- clone_data = false;
- }
- });
- }
-
- var custom_toolbar = oLayoutInfo.toolbar ? oLayoutInfo.toolbar() : undefined;
- var $toolbar = $(oLayoutInfo.popover()).add(custom_toolbar);
- $('button[data-event="undo"], button[data-event="redo"]', $toolbar).attr('disabled', true);
-
- $(oLayoutInfo.editor())
- .add(oLayoutInfo.handle())
- .add(oLayoutInfo.popover())
- .add(custom_toolbar)
- .on('click content_changed', function () {
- $('button[data-event="undo"]', $toolbar).attr('disabled', !oLayoutInfo.editable().data('NoteHistory').hasUndo());
- $('button[data-event="redo"]', $toolbar).attr('disabled', !oLayoutInfo.editable().data('NoteHistory').hasRedo());
- });
-
- function create_dblclick_feature(selector, callback) {
- var show_tooltip = true;
-
- oLayoutInfo.editor().on("dblclick", selector, function (e) {
- var $target = $(e.target);
- if (!dom.isContentEditable($target)) {
- // Prevent edition of non editable parts
- return;
- }
-
- show_tooltip = false;
- callback();
- e.stopImmediatePropagation();
- });
-
- oLayoutInfo.editor().on("click", selector, function (e) {
- var $target = $(e.target);
- if (!dom.isContentEditable($target)) {
- // Prevent edition of non editable parts
- return;
- }
-
- show_tooltip = true;
- setTimeout(function () {
- // Do not show tooltip on double-click and if there is already one
- if (!show_tooltip || $target.attr('title') !== undefined) {
- return;
- }
- $target.tooltip({title: _t('Double-click to edit'), trigger: 'manuel', container: 'body'}).tooltip('show');
- setTimeout(function () {
- $target.tooltip('dispose');
- }, 800);
- }, 400);
- });
- }
-};
-var fn_detach = eventHandler.detach;
-eventHandler.detach = function (oLayoutInfo, options) {
- fn_detach.call(this, oLayoutInfo, options);
- oLayoutInfo.editable().off('mousedown');
- oLayoutInfo.editor().off("dragstart");
- oLayoutInfo.editor().off('click');
- $(document).off('mousedown', summernote_mousedown);
- $(document).off('mouseup', summernote_mouseup);
- oLayoutInfo.editor().off("dblclick");
- $(document).off("keyup", reRangeSelectKey);
-};
-
-// Translation for odoo
-$.summernote.lang.odoo = {
- font: {
- bold: _t('Bold'),
- italic: _t('Italic'),
- underline: _t('Underline'),
- strikethrough: _t('Strikethrough'),
- subscript: _t('Subscript'),
- superscript: _t('Superscript'),
- clear: _t('Remove Font Style'),
- height: _t('Line Height'),
- name: _t('Font Family'),
- size: _t('Font Size')
- },
- image: {
- image: _t('File / Image'),
- insert: _t('Insert Image'),
- resizeFull: _t('Resize Full'),
- resizeHalf: _t('Resize Half'),
- resizeQuarter: _t('Resize Quarter'),
- floatLeft: _t('Float Left'),
- floatRight: _t('Float Right'),
- floatNone: _t('Float None'),
- dragImageHere: _t('Drag an image here'),
- selectFromFiles: _t('Select from files'),
- url: _t('Image URL'),
- remove: _t('Remove Image')
- },
- link: {
- link: _t('Link'),
- insert: _t('Insert Link'),
- unlink: _t('Unlink'),
- edit: _t('Edit'),
- textToDisplay: _t('Text to display'),
- url: _t('To what URL should this link go?'),
- openInNewWindow: _t('Open in new window')
- },
- video: {
- video: _t('Video'),
- videoLink: _t('Video Link'),
- insert: _t('Insert Video'),
- url: _t('Video URL?'),
- providers: _t('(YouTube, Vimeo, Vine, Instagram, DailyMotion or Youku)')
- },
- table: {
- table: _t('Table')
- },
- hr: {
- insert: _t('Insert Horizontal Rule')
- },
- style: {
- style: _t('Style'),
- normal: _t('Normal'),
- blockquote: _t('Quote'),
- pre: _t('Code'),
- small: _t('Small'),
- h1: _t('Header 1'),
- h2: _t('Header 2'),
- h3: _t('Header 3'),
- h4: _t('Header 4'),
- h5: _t('Header 5'),
- h6: _t('Header 6')
- },
- lists: {
- unordered: _t('Unordered list'),
- ordered: _t('Ordered list')
- },
- options: {
- help: _t('Help'),
- fullscreen: _t('Full Screen'),
- codeview: _t('Code View')
- },
- paragraph: {
- paragraph: _t('Paragraph'),
- outdent: _t('Outdent'),
- indent: _t('Indent'),
- left: _t('Align left'),
- center: _t('Align center'),
- right: _t('Align right'),
- justify: _t('Justify full')
- },
- color: {
- custom: _t('Custom Color'),
- background: _t('Background Color'),
- foreground: _t('Font Color'),
- transparent: _t('Transparent'),
- setTransparent: _t('None'),
- },
- shortcut: {
- shortcuts: _t('Keyboard shortcuts'),
- close: _t('Close'),
- textFormatting: _t('Text formatting'),
- action: _t('Action'),
- paragraphFormatting: _t('Paragraph formatting'),
- documentStyle: _t('Document Style')
- },
- history: {
- undo: _t('Undo'),
- redo: _t('Redo')
- }
-};
-
-//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-/**
- * @todo get rid of this. This has been implemented as a fix to be able to
- * instantiate media, link and alt dialogs outside the main editor: in the
- * simple HTML fields and forum textarea.
- */
-var SummernoteManager = Class.extend(mixins.EventDispatcherMixin, ServicesMixin, {
- /**
- * @constructor
- */
- init: function (parent) {
- mixins.EventDispatcherMixin.init.call(this);
- this.setParent(parent);
-
- topBus.on('alt_dialog_demand', this, this._onAltDialogDemand);
- topBus.on('crop_image_demand', this, this._onCropImageDemand);
- topBus.on('link_dialog_demand', this, this._onLinkDialogDemand);
- topBus.on('media_dialog_demand', this, this._onMediaDialogDemand);
- },
- /**
- * @override
- */
- destroy: function () {
- mixins.EventDispatcherMixin.destroy.call(this);
-
- topBus.off('alt_dialog_demand', this, this._onAltDialogDemand);
- topBus.off('crop_image_demand', this, this._onCropImageDemand);
- topBus.off('link_dialog_demand', this, this._onLinkDialogDemand);
- topBus.off('media_dialog_demand', this, this._onMediaDialogDemand);
- },
-
- /**
- * Create modified image attachments.
- *
- * @param {jQuery} $editable
- * @returns {Promise}
- */
- saveModifiedImages: function ($editable) {
- const defs = _.map($editable, async editableEl => {
- const {oeModel: resModel, oeId: resId} = editableEl.dataset;
- const proms = [...editableEl.querySelectorAll('.o_modified_image_to_save')].map(async el => {
- const isBackground = !el.matches('img');
- el.classList.remove('o_modified_image_to_save');
- // Modifying an image always creates a copy of the original, even if
- // it was modified previously, as the other modified image may be used
- // elsewhere if the snippet was duplicated or was saved as a custom one.
- const newAttachmentSrc = await this._rpc({
- route: `/web_editor/modify_image/${el.dataset.originalId}`,
- params: {
- res_model: resModel,
- res_id: parseInt(resId),
- data: (isBackground ? el.dataset.bgSrc : el.getAttribute('src')).split(',')[1],
- },
- });
- if (isBackground) {
- $(el).css('background-image', `url('${newAttachmentSrc}')`);
- delete el.dataset.bgSrc;
- } else {
- el.setAttribute('src', newAttachmentSrc);
- }
- });
- return Promise.all(proms);
- });
- return Promise.all(defs);
- },
-
- //--------------------------------------------------------------------------
- // Handlers
- //--------------------------------------------------------------------------
-
- /**
- * Called when a demand to open a alt dialog is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onAltDialogDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
- var altDialog = new weWidgets.AltDialog(this,
- data.options || {},
- data.media
- );
- if (data.onSave) {
- altDialog.on('save', this, data.onSave);
- }
- if (data.onCancel) {
- altDialog.on('cancel', this, data.onCancel);
- }
- altDialog.open();
- },
- /**
- * Called when a demand to crop an image is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onCropImageDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
- new weWidgets.ImageCropWidget(this, data.media)
- .appendTo(data.$editable.parent());
- },
- /**
- * Called when a demand to open a link dialog is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onLinkDialogDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
- var linkDialog = new weWidgets.LinkDialog(this,
- data.options || {},
- data.$editable,
- data.linkInfo
- );
- if (data.onSave) {
- linkDialog.on('save', this, data.onSave);
- }
- if (data.onCancel) {
- linkDialog.on('cancel', this, data.onCancel);
- }
- linkDialog.open();
- },
- /**
- * Called when a demand to open a media dialog is received on the bus.
- *
- * @private
- * @param {Object} data
- */
- _onMediaDialogDemand: function (data) {
- if (data.__alreadyDone) {
- return;
- }
- data.__alreadyDone = true;
-
- const model = data.$editable.data('oe-model');
- const field = data.$editable.data('oe-field');
- const type = data.$editable.data('oe-type');
- var mediaDialog = new weWidgets.MediaDialog(this,
- _.extend({
- res_model: model,
- res_id: data.$editable.data('oe-id'),
- domain: data.$editable.data('oe-media-domain'),
- useMediaLibrary: field && (model === 'ir.ui.view' && field === 'arch' || type === 'html'),
- }, data.options),
- data.media
- );
- if (data.onSave) {
- mediaDialog.on('save', this, data.onSave);
- }
- if (data.onCancel) {
- mediaDialog.on('cancel', this, data.onCancel);
- }
- mediaDialog.open();
- },
-});
-return SummernoteManager;
-});
diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js
index e5862f6c9b6..6fa62bb9e6d 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -1661,7 +1661,7 @@ const DatetimePickerUserValueWidget = InputUserValueWidget.extend({
widgetParent: 'body',
// Open the datetimepicker on focus not on click. This allows to
- // take care of a bug which is due to the summernote editor:
+ // take care of a bug which is due to the wysiwyg editor:
// sometimes, the datetimepicker loses the focus then get it back
// in the same execution flow. This was making the datepicker close
// for no apparent reason. Now, it only closes then reopens directly
diff --git a/addons/web_editor/static/src/js/editor/summernote.js b/addons/web_editor/static/src/js/editor/summernote.js
deleted file mode 100644
index f99bae3030f..00000000000
--- a/addons/web_editor/static/src/js/editor/summernote.js
+++ /dev/null
@@ -1,2526 +0,0 @@
-odoo.define('web_editor.summernote', function (require) {
-'use strict';
-
-var core = require('web.core');
-require('summernote/summernote'); // wait that summernote is loaded
-var weDefaultOptions = require('web_editor.wysiwyg.default_options');
-
-var _t = core._t;
-
-// Summernote Lib (neek hack to make accessible: method and object)
-// var agent = $.summernote.core.agent;
-var dom = $.summernote.core.dom;
-var range = $.summernote.core.range;
-var list = $.summernote.core.list;
-var key = $.summernote.core.key;
-var eventHandler = $.summernote.eventHandler;
-var editor = eventHandler.modules.editor;
-var renderer = $.summernote.renderer;
-var options = $.summernote.options;
-
-// Browser-unify execCommand
-var oldJustify = {};
-_.each(['Left', 'Right', 'Full', 'Center'], function (align) {
- oldJustify[align] = editor['justify' + align];
- editor['justify' + align] = function ($editable, value) {
- // Before calling the standard function, check all elements which have
- // an 'align' attribute and mark them with their value
- var $align = $editable.find('[align]');
- _.each($align, function (el) {
- var $el = $(el);
- $el.data('__align', $el.attr('align'));
- });
-
- // Call the standard function
- oldJustify[align].apply(this, arguments);
-
- // Then:
-
- // Remove the text-align of elements which lost the 'align' attribute
- var $newAlign = $editable.find('[align]');
- $align.not($newAlign).css('text-align', '');
-
- // Transform the 'align' attribute into the 'text-align' css
- // property for elements which received the 'align' attribute or whose
- // 'align' attribute changed
- _.each($newAlign, function (el) {
- var $el = $(el);
-
- var oldAlignValue = $align.data('__align');
- var alignValue = $el.attr('align');
- if (oldAlignValue === alignValue) {
- // If the element already had an 'align' attribute and that it
- // did not changed, do nothing (compatibility)
- return;
- }
-
- $el.removeAttr('align');
- $el.css('text-align', alignValue);
-
- // Note the first step (removing the text-align of elemnts which
- // lost the 'align' attribute) is kinda the same as this one, but
- // this one handles the elements which have been edited with chrome
- // or with this new system
- $el.find('*').css('text-align', '');
- });
-
- // Unmark the elements
- $align.removeData('__align');
- };
-});
-
-
-// Add methods to summernote
-
-dom.hasContentAfter = function (node) {
- var next;
- if (dom.isEditable(node)) return;
- while (node.nextSibling) {
- next = node.nextSibling;
- if (next.tagName || dom.isVisibleText(next) || dom.isBR(next)) return next;
- node = next;
- }
-};
-dom.hasContentBefore = function (node) {
- var prev;
- if (dom.isEditable(node)) return;
- while (node.previousSibling) {
- prev = node.previousSibling;
- if (prev.tagName || dom.isVisibleText(prev) || dom.isBR(prev)) return prev;
- node = prev;
- }
-};
-dom.ancestorHaveNextSibling = function (node, pred) {
- pred = pred || dom.hasContentAfter;
- while (!dom.isEditable(node) && (!node.nextSibling || !pred(node))) { node = node.parentNode; }
- return node;
-};
-dom.ancestorHavePreviousSibling = function (node, pred) {
- pred = pred || dom.hasContentBefore;
- while (!dom.isEditable(node) && (!node.previousSibling || !pred(node))) { node = node.parentNode; }
- return node;
-};
-dom.nextElementSibling = function (node) {
- while (node) {
- node = node.nextSibling;
- if (node && node.tagName) {
- break;
- }
- }
- return node;
-};
-dom.previousElementSibling = function (node) {
- while (node) {
- node = node.previousSibling;
- if (node && node.tagName) {
- break;
- }
- }
- return node;
-};
-dom.lastChild = function (node) {
- while (node.lastChild) { node = node.lastChild; }
- return node;
-};
-dom.firstChild = function (node) {
- while (node.firstChild) { node = node.firstChild; }
- return node;
-};
-dom.lastElementChild = function (node, deep) {
- node = deep ? dom.lastChild(node) : node.lastChild;
- return !node || node.tagName ? node : dom.previousElementSibling(node);
-};
-dom.firstElementChild = function (node, deep) {
- node = deep ? dom.firstChild(node) : node.firstChild;
- return !node || node.tagName ? node : dom.nextElementSibling(node);
-};
-dom.isEqual = function (prev, cur) {
- if (prev.tagName !== cur.tagName) {
- return false;
- }
- if ((prev.attributes ? prev.attributes.length : 0) !== (cur.attributes ? cur.attributes.length : 0)) {
- return false;
- }
-
- function strip(text) {
- return text && text.replace(/^\s+|\s+$/g, '').replace(/\s+/g, ' ');
- }
- var att, att2;
- loop_prev:
- for (var a in prev.attributes) {
- att = prev.attributes[a];
- for (var b in cur.attributes) {
- att2 = cur.attributes[b];
- if (att.name === att2.name) {
- if (strip(att.value) !== strip(att2.value)) return false;
- continue loop_prev;
- }
- }
- return false;
- }
- return true;
-};
-dom.hasOnlyStyle = function (node) {
- for (var i = 0; i < node.attributes.length; i++) {
- var attr = node.attributes[i];
- if (attr.attributeName !== 'style') {
- return false;
- }
- }
- return true;
-};
-dom.hasProgrammaticStyle = function (node) {
- var styles = ["float", "display", "position", "top", "left", "right", "bottom"];
- for (var i = 0; i < node.style.length; i++) {
- var style = node.style[i];
- if (styles.indexOf(style) !== -1) {
- return true;
- }
- }
- return false;
-};
-dom.mergeFilter = function (prev, cur, parent) {
- // merge text nodes
- if (prev && (dom.isText(prev) || (['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'LI', 'P'].indexOf(prev.tagName) !== -1 && prev !== cur.parentNode)) && dom.isText(cur)) {
- return true;
- }
- if (prev && prev.tagName === "P" && dom.isText(cur)) {
- return true;
- }
- if (prev && dom.isText(cur) && !dom.isVisibleText(cur) && (dom.isText(prev) || dom.isVisibleText(prev))) {
- return true;
- }
- if (prev && !dom.isBR(prev) && dom.isEqual(prev, cur) &&
- ((prev.tagName && dom.getComputedStyle(prev).display === "inline" &&
- cur.tagName && dom.getComputedStyle(cur).display === "inline"))) {
- return true;
- }
- if (dom.isEqual(parent, cur) &&
- ((parent.tagName && dom.getComputedStyle(parent).display === "inline" &&
- cur.tagName && dom.getComputedStyle(cur).display === "inline"))) {
- return true;
- }
- if (parent && cur.tagName === "FONT" && (!cur.firstChild || (!cur.attributes.getNamedItem('style') && !cur.className.length))) {
- return true;
- }
- // On backspace, webkit browsers create a with a bunch of
- // inline styles "remembering" where they come from.
- // chances are we had e.g.
- // foo
- // bar
- // merged the lines getting this in webkit
- // foobar
- if (parent && cur.tagName === "SPAN" && dom.hasOnlyStyle(cur) && !dom.hasProgrammaticStyle(cur)) {
- return true;
- }
-};
-dom.doMerge = function (prev, cur) {
- if (prev.tagName) {
- if (prev.childNodes.length && !prev.textContent.match(/\S/) && dom.firstElementChild(prev) && dom.isBR(dom.firstElementChild(prev))) {
- prev.removeChild(dom.firstElementChild(prev));
- }
- if (cur.tagName) {
- while (cur.firstChild) {
- prev.appendChild(cur.firstChild);
- }
- cur.parentNode.removeChild(cur);
- } else {
- prev.appendChild(cur);
- }
- } else {
- if (cur.tagName) {
- var deep = cur;
- while (deep.tagName && deep.firstChild) {deep = deep.firstChild;}
- prev.appendData(deep.textContent);
- cur.parentNode.removeChild(cur);
- } else {
- prev.appendData(cur.textContent);
- cur.parentNode.removeChild(cur);
- }
- }
-};
-dom.merge = function (node, begin, so, end, eo, mergeFilter, all) {
- mergeFilter = mergeFilter || dom.mergeFilter;
- var _merged = false;
- var add = all || false;
-
- if (!begin) {
- begin = node;
- while (begin.firstChild) {begin = begin.firstChild;}
- so = 0;
- } else if (begin.tagName && begin.childNodes[so]) {
- begin = begin.childNodes[so];
- so = 0;
- }
- if (!end) {
- end = node;
- while (end.lastChild) {end = end.lastChild;}
- eo = end.textContent.length-1;
- } else if (end.tagName && end.childNodes[so]) {
- end = end.childNodes[so];
- so = 0;
- }
-
- begin = dom.firstChild(begin);
- if (dom.isText(begin) && so > begin.textContent.length) {
- so = 0;
- }
- end = dom.firstChild(end);
- if (dom.isText(end) && eo > end.textContent.length) {
- eo = 0;
- }
-
- function __merge(node) {
- var merged = false;
- var prev;
- for (var k=0; k 1 && dom.isText(cur) && !dom.isVisibleText(cur)) {
- removed = true;
- if (cur === begin) {
- t_begin = dom.hasContentBefore(dom.ancestorHavePreviousSibling(cur));
- if (t_begin) {
- so = 0;
- begin = dom.lastChild(t_begin);
- }
- }
- if (cur === end) {
- t_end = dom.hasContentAfter(dom.ancestorHaveNextSibling(cur));
- if (t_end) {
- eo = 1;
- end = dom.firstChild(t_end);
- if (dom.isText(end)) {
- eo = end.textContent.length;
- }
- }
- }
- cur.parentNode.removeChild(cur);
- begin = dom.lastChild(begin);
- end = dom.lastChild(end);
- k--;
- continue;
- }
-
- // convert HTML space
- if (dom.isText(cur)) {
- var text;
- var temp;
- var _temp;
- var exp1 = /[\t\n\r ]+/g;
- var exp2 = /(?!([ ]|\u00A0)|^)\u00A0(?!([ ]|\u00A0)|$)/g;
- if (cur === begin) {
- temp = cur.textContent.substr(0, so);
- _temp = temp.replace(exp1, ' ').replace(exp2, ' ');
- so -= temp.length - _temp.length;
- }
- if (cur === end) {
- temp = cur.textContent.substr(0, eo);
- _temp = temp.replace(exp1, ' ').replace(exp2, ' ');
- eo -= temp.length - _temp.length;
- }
- text = cur.textContent.replace(exp1, ' ').replace(exp2, ' ');
- removed = removed || cur.textContent.length !== text.length;
- cur.textContent = text;
- }
- }
- })(node);
-
- return {
- removed: removed,
- sc: begin,
- ec: end,
- so: !dom.isBR(begin) && so > 0 ? so : 0,
- eo: dom.isBR(end) ? 0 : eo
- };
-};
-dom.removeBetween = function (sc, so, ec, eo, towrite) {
- var text;
- if (ec.tagName) {
- if (ec.childNodes[eo]) {
- ec = ec.childNodes[eo];
- eo = 0;
- } else {
- ec = dom.lastChild(ec);
- eo = dom.nodeLength(ec);
- }
- }
- if (sc.tagName) {
- sc = sc.childNodes[so] || dom.firstChild(ec);
- so = 0;
- if (!dom.hasContentBefore(sc) && towrite) {
- sc.parentNode.insertBefore(document.createTextNode('\u00A0'), sc);
- }
- }
- if (!eo && sc !== ec) {
- ec = dom.lastChild(dom.hasContentBefore(dom.ancestorHavePreviousSibling(ec)) || ec);
- eo = ec.textContent.length;
- }
-
- var ancestor = dom.commonAncestor(sc.tagName ? sc.parentNode : sc, ec.tagName ? ec.parentNode : ec) || dom.ancestor(sc, dom.isEditable);
-
- if (!dom.isContentEditable(ancestor)) {
- return {
- sc: sc,
- so: so,
- ec: sc,
- eo: eo
- };
- }
-
- if (ancestor.tagName) {
- var ancestor_sc = sc;
- var ancestor_ec = ec;
- while (ancestor !== ancestor_sc && ancestor !== ancestor_sc.parentNode) { ancestor_sc = ancestor_sc.parentNode; }
- while (ancestor !== ancestor_ec && ancestor !== ancestor_ec.parentNode) { ancestor_ec = ancestor_ec.parentNode; }
-
-
- var node = dom.node(sc);
- if (!dom.isNotBreakable(node) && !dom.isVoid(sc)) {
- sc = dom.splitTree(ancestor_sc, {'node': sc, 'offset': so});
- }
- var before = dom.hasContentBefore(dom.ancestorHavePreviousSibling(sc));
-
- var after;
- if (ec.textContent.slice(eo, Infinity).match(/\S|\u00A0/)) {
- after = dom.splitTree(ancestor_ec, {'node': ec, 'offset': eo});
- } else {
- after = dom.hasContentAfter(dom.ancestorHaveNextSibling(ec));
- }
-
- var nodes = dom.listBetween(sc, ec);
-
- var ancestor_first_last = function (node) {
- return node === before || node === after;
- };
-
- for (var i=0; i")[0];
- node.appendChild(sc);
- sc = br;
- so = 0;
- } else if (!ancestor.children.length && !ancestor.textContent.match(/\S|\u00A0/)) {
- sc = $(" ")[0];
- so = 0;
- $(ancestor).prepend(sc);
- } else if (dom.isText(sc)) {
- text = sc.textContent.replace(/[ \t\n\r]+$/, '\u00A0');
- so = Math.min(so, text.length);
- sc.textContent = text;
- }
- } else {
- text = ancestor.textContent;
- ancestor.textContent = text.slice(0, so) + text.slice(eo, Infinity).replace(/^[ \t\n\r]+/, '\u00A0');
- }
-
- eo = so;
- if (!dom.isBR(sc) && !dom.isVisibleText(sc) && !dom.isText(dom.hasContentBefore(sc)) && !dom.isText(dom.hasContentAfter(sc))) {
- ancestor = dom.node(sc);
- text = document.createTextNode('\u00A0');
- $(sc).before(text);
- sc = text;
- so = 0;
- eo = 1;
- }
-
- var parentNode = sc && sc.parentNode;
- if (parentNode && sc.tagName === 'BR') {
- sc = parentNode;
- ec = parentNode;
- }
-
- return {
- sc: sc,
- so: so,
- ec: sc,
- eo: eo
- };
-};
-dom.indent = function (node) {
- var style = dom.isCell(node) ? 'paddingLeft' : 'marginLeft';
- var margin = parseFloat(node.style[style] || 0)+1.5;
- node.style[style] = margin + "em";
- return margin;
-};
-dom.outdent = function (node) {
- var style = dom.isCell(node) ? 'paddingLeft' : 'marginLeft';
- var margin = parseFloat(node.style[style] || 0)-1.5;
- node.style[style] = margin > 0 ? margin + "em" : "";
- return margin;
-};
-dom.scrollIntoViewIfNeeded = function (node) {
- node = dom.node(node);
-
- var $span;
- if (dom.isBR(node)) {
- $span = $(' ').text('\u00A0');
- $(node).after($span);
- node = $span[0];
- }
-
- if (node.scrollIntoViewIfNeeded) {
- node.scrollIntoViewIfNeeded(false);
- } else {
- var offsetParent = node.offsetParent;
- while (offsetParent) {
- var elY = 0;
- var elH = node.offsetHeight;
- var parent = node;
-
- while (offsetParent && parent) {
- elY += node.offsetTop;
-
- // get if a parent have a scrollbar
- parent = node.parentNode;
- while (parent !== offsetParent &&
- (parent.tagName === "BODY" || ["auto", "scroll"].indexOf(dom.getComputedStyle(parent).overflowY) === -1)) {
- parent = parent.parentNode;
- }
- node = parent;
-
- if (parent !== offsetParent) {
- elY -= parent.offsetTop;
- parent = null;
- }
-
- offsetParent = node.offsetParent;
- }
-
- if ((node.tagName === "BODY" || ["auto", "scroll"].indexOf(dom.getComputedStyle(node).overflowY) !== -1) &&
- (node.scrollTop + node.clientHeight) < (elY + elH)) {
- node.scrollTop = (elY + elH) - node.clientHeight;
- }
- }
- }
-
- if ($span) {
- $span.remove();
- }
-
- return;
-};
-dom.moveTo = function (node, target, before) {
- var nodes = [];
- while (node.firstChild) {
- nodes.push(node.firstChild);
- if (before) {
- target.insertBefore(node.firstChild, before);
- } else {
- target.appendChild(node.firstChild);
- }
- }
- node.parentNode.removeChild(node);
- return nodes;
-};
-dom.isMergable = function (node) {
- return node.tagName && "h1 h2 h3 h4 h5 h6 p b bold i u code sup strong small li a ul ol font".indexOf(node.tagName.toLowerCase()) !== -1;
-};
-dom.isSplitable = function (node) {
- return node.tagName && "h1 h2 h3 h4 h5 h6 p b bold i u code sup strong small li a font".indexOf(node.tagName.toLowerCase()) !== -1;
-};
-dom.isRemovableEmptyNode = function (node) {
- return "h1 h2 h3 h4 h5 h6 p b bold i u code sup strong small li a ul ol font span br".indexOf(node.tagName.toLowerCase()) !== -1;
-};
-dom.isForbiddenNode = function (node) {
- return node.tagName === "BR" || $(node).is(".fa, img");
-};
-/**
- * @todo 'so' and 'eo' were added as a bugfix and are not given everytime. They
- * however should be as the function may be wrong without them (for example,
- * when asking the list between an element and its parent, as there is no path
- * from the beginning of the former to the beginning of the later).
- */
-dom.listBetween = function (sc, ec, so, eo) {
- var nodes = [];
- var ancestor = dom.commonAncestor(sc, ec);
- dom.walkPoint({'node': sc, 'offset': so || 0}, {'node': ec, 'offset': eo || 0}, function (point) {
- if (ancestor !== point.node || ancestor === sc || ancestor === ec) {
- nodes.push(point.node);
- }
- });
- return list.unique(nodes);
-};
-dom.isNotBreakable = function (node) {
- // avoid triple click => crappy dom
- return !dom.isText(node) && !dom.isBR(dom.firstChild(node)) && dom.isVoid(dom.firstChild(node));
-};
-dom.isContentEditable = function (node) {
- return $(node).closest('[contenteditable]').prop('contenteditable') === 'true';
-};
-dom.isContentEditableFalse = function (node) {
- return $(node).closest('[contenteditable]').prop('contenteditable') === 'false';
-};
-dom.isFont = function (node) {
- var nodeName = node && node.nodeName.toUpperCase();
- return node && (nodeName === "FONT" ||
- (nodeName === "SPAN" && (
- node.className.match(/(^|\s)fa(\s|$)/i) ||
- node.className.match(/(^|\s)(text|bg)-/i) ||
- (node.attributes.style && node.attributes.style.value.match(/(^|\s)(color|background-color|font-size):/i)))) );
-};
-dom.isVisibleText = function (textNode) {
- return !!textNode.textContent.match(/\S|\u00A0/);
-};
-var old_isVisiblePoint = dom.isVisiblePoint;
-dom.isVisiblePoint = function (point) {
- return point.node.nodeType !== 8 && old_isVisiblePoint.apply(this, arguments);
-};
-dom.orderStyle = function (node) {
- var style = node.getAttribute('style');
- if (!style) return null;
- style = style.replace(/[\s\n\r]+/, ' ').replace(/^ ?;? ?| ?;? ?$/g, '').replace(/ ?; ?/g, ';');
- if (!style.length) {
- node.removeAttribute("style");
- return null;
- }
- style = style.split(";");
- style.sort();
- style = style.join("; ")+";";
- node.setAttribute('style', style);
- return style;
-};
-dom.orderClass = function (node) {
- var className = node.getAttribute && node.getAttribute('class');
- if (!className) return null;
- className = className.replace(/[\s\n\r]+/, ' ').replace(/^ | $/g, '').replace(/ +/g, ' ');
- if (!className.length) {
- node.removeAttribute("class");
- return null;
- }
- className = className.split(" ");
- className.sort();
- className = className.join(" ");
- node.setAttribute('class', className);
- return className;
-};
-dom.node = function (node) {
- return dom.isText(node) ? node.parentNode : node;
-};
-dom.moveContent = function (from, to) {
- if (from === to) {
- return;
- }
- if (from.parentNode === to) {
- while (from.lastChild) {
- dom.insertAfter(from.lastChild, from);
- }
- } else {
- while (from.firstChild && from.firstChild !== to) {
- to.appendChild(from.firstChild);
- }
- }
-};
-dom.getComputedStyle = function (node) {
- return node.nodeType === Node.COMMENT_NODE ? {} : window.getComputedStyle(node);
-};
-
-//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-range.WrappedRange.prototype.reRange = function (keep_end, isNotBreakable) {
- var sc = this.sc;
- var so = this.so;
- var ec = this.ec;
- var eo = this.eo;
- isNotBreakable = isNotBreakable || dom.isNotBreakable;
-
- // search the first snippet editable node
- var start = keep_end ? ec : sc;
- while (start) {
- if (isNotBreakable(start, sc, so, ec, eo)) {
- break;
- }
- start = start.parentNode;
- }
-
- // check if the end caret have the same node
- var lastFilterEnd;
- var end = keep_end ? sc : ec;
- while (end) {
- if (start === end) {
- break;
- }
- if (isNotBreakable(end, sc, so, ec, eo)) {
- lastFilterEnd = end;
- }
- end = end.parentNode;
- }
- if (lastFilterEnd) {
- end = lastFilterEnd;
- }
- if (!end) {
- end = document.getElementsByTagName('body')[0];
- }
-
- // if same node, keep range
- if (start === end || !start) {
- return this;
- }
-
- // reduce or extend the range to don't break a isNotBreakable area
- if ($.contains(start, end)) {
-
- if (keep_end) {
- sc = dom.lastChild(dom.hasContentBefore(dom.ancestorHavePreviousSibling(end)) || sc);
- so = sc.textContent.length;
- } else if (!eo) {
- ec = dom.lastChild(dom.hasContentBefore(dom.ancestorHavePreviousSibling(end)) || ec);
- eo = ec.textContent.length;
- } else {
- ec = dom.firstChild(dom.hasContentAfter(dom.ancestorHaveNextSibling(end)) || ec);
- eo = 0;
- }
- } else {
-
- if (keep_end) {
- sc = dom.firstChild(start);
- so = 0;
- } else {
- ec = dom.lastChild(start);
- eo = ec.textContent.length;
- }
- }
-
- return new range.WrappedRange(sc, so, ec, eo);
-};
-/**
- * Returns the image the range is in or matches (if any, false otherwise).
- *
- * @todo this implementation may not cover all corner cases but should do the
- * trick for all reproductible ones
- * @returns {DOMElement|boolean}
- */
-range.WrappedRange.prototype.isOnImg = function () {
- // If not a selection but a cursor position, just check if a point's
- // ancestor is an image or not
- if (this.sc === this.ec && this.so === this.eo) {
- return dom.ancestor(this.sc, dom.isImg);
- }
-
- var startPoint = {node: this.sc, offset: this.so};
- var endPoint = {node: this.ec, offset: this.eo};
-
- var nb = 0;
- var image;
- var textNode;
- dom.walkPoint(startPoint, endPoint, function (point) {
- // If the element has children (not a text node and not empty node),
- // the element cannot be considered as selected (these children will
- // be processed to determine that)
- if (dom.hasChildren(point.node)) {
- return;
- }
-
- // Check if an ancestor of the current point is an image
- var pointImg = dom.ancestor(point.node, dom.isImg);
- var isText = dom.isText(point.node);
-
- // Check if a visible element is selected, i.e.
- // - If an ancestor of the current is an image we did not see yet
- // - If the point is not in a br or a text (so a node with no children)
- // - If the point is in a non empty text node we already saw
- if (pointImg ?
- (image !== pointImg) :
- ((!dom.isBR(point.node) && !isText) || (textNode === point.node && point.node.textContent.match(/\S|\u00A0/)))) {
- nb++;
- }
-
- // If an ancestor of the current point is an image, then save it as the
- // image we are looking for
- if (pointImg) {
- image = pointImg;
- }
- // If the current point is a text node save it as the last text node
- // seen (if we see it again, this might mean it is selected)
- if (isText) {
- textNode = point.node;
- }
- });
-
- return nb === 1 && image;
-};
-range.WrappedRange.prototype.deleteContents = function (towrite) {
- if (this.sc === this.ec && this.so === this.eo) {
- return this;
- }
-
- var r;
- var image = this.isOnImg();
- if (image) {
- // If the range matches/is in an image, then the image is to be removed
- // and the cursor moved to its previous position
- var parentNode = image.parentNode;
- var index = _.indexOf(parentNode.childNodes, image);
- parentNode.removeChild(image);
- r = new range.WrappedRange(parentNode, index, parentNode, index);
- } else {
- r = dom.removeBetween(this.sc, this.so, this.ec, this.eo, towrite);
- }
-
- $(dom.node(r.sc)).trigger("click"); // trigger click to disable and reanable editor and image handler
- return new range.WrappedRange(r.sc, r.so, r.ec, r.eo);
-};
-range.WrappedRange.prototype.clean = function (mergeFilter, all) {
- var node = dom.node(this.sc === this.ec ? this.sc : this.commonAncestor());
- node = node || $(this.sc).closest('[contenteditable]')[0];
- if (node.childNodes.length <=1) {
- return this;
- }
-
- var merge = dom.merge(node, this.sc, this.so, this.ec, this.eo, mergeFilter, all);
- var rem = dom.removeSpace(node.parentNode, merge.sc, merge.so, merge.ec, merge.eo);
-
- if (merge.merged || rem.removed) {
- return range.create(rem.sc, rem.so, rem.ec, rem.eo);
- }
- return this;
-};
-range.WrappedRange.prototype.remove = function (mergeFilter) {
-};
-range.WrappedRange.prototype.isOnCellFirst = function () {
- var node = dom.ancestor(this.sc, function (node) {return ["LI", "DIV", "TD","TH"].indexOf(node.tagName) !== -1;});
- return node && ["TD","TH"].indexOf(node.tagName) !== -1;
-};
-range.WrappedRange.prototype.isContentEditable = function () {
- return dom.isContentEditable(this.sc) && (this.sc === this.ec || dom.isContentEditable(this.ec));
-};
-
-//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-renderer.tplButtonInfo.fontsize = function (lang, options) {
- var items = options.fontSizes.reduce(function (memo, v) {
- return memo + '' +
- ' ' + v +
- ' ';
- }, '');
-
- var sLabel = '11 ';
- return renderer.getTemplate().button(sLabel, {
- title: lang.font.size,
- dropdown: ''
- });
-};
-
-renderer.tplButtonInfo.color = function (lang, options) {
- var foreColorButtonLabel = ' ';
- var backColorButtonLabel = ' ';
- // TODO Remove recent color button if possible.
- // It is still put to avoid JS errors when clicking other buttons as the
- // editor still expects it to exist.
- var recentColorButton = renderer.getTemplate().button(foreColorButtonLabel, {
- className: 'note-recent-color d-none',
- title: lang.color.foreground,
- event: 'color',
- value: '{"backColor":"#B35E9B"}'
- });
- var foreColorButton = renderer.getTemplate().button(foreColorButtonLabel, {
- className: 'note-fore-color-preview',
- title: lang.color.foreground,
- dropdown: renderer.getTemplate().dropdown('
'),
- });
- var backColorButton = renderer.getTemplate().button(backColorButtonLabel, {
- className: 'note-back-color-preview',
- title: lang.color.background,
- dropdown: renderer.getTemplate().dropdown('
'),
- });
- return recentColorButton + foreColorButton + backColorButton;
-};
-
-renderer.tplButtonInfo.checklist = function (lang, options) {
- return ' ';
-};
-
-//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
-
-key.nameFromCode[46] = 'DELETE';
-key.nameFromCode[27] = 'ESCAPE';
-
-options.keyMap.pc['BACKSPACE'] = 'backspace';
-options.keyMap.pc['DELETE'] = 'delete';
-options.keyMap.pc['ENTER'] = 'enter';
-options.keyMap.pc['ESCAPE'] = 'cancel';
-options.keyMap.mac['SHIFT+TAB'] = 'untab';
-options.keyMap.pc['UP'] = 'up';
-options.keyMap.pc['DOWN'] = 'down';
-
-options.keyMap.mac['BACKSPACE'] = 'backspace';
-options.keyMap.mac['DELETE'] = 'delete';
-options.keyMap.mac['ENTER'] = 'enter';
-options.keyMap.mac['ESCAPE'] = 'cancel';
-options.keyMap.mac['UP'] = 'up';
-options.keyMap.mac['DOWN'] = 'down';
-
-options.styleTags = weDefaultOptions.styleTags;
-
-$.summernote.pluginEvents.insertTable = function (event, editor, layoutInfo, sDim) {
- var $editable = layoutInfo.editable();
- $editable.focus();
- var dimension = sDim.split('x');
- var r = range.create();
- if (!r) return;
- r = r.deleteContents(true);
-
- var table = editor.table.createTable(dimension[0], dimension[1]);
- var parent = r.sc;
- while (dom.isText(parent.parentNode) || dom.isRemovableEmptyNode(parent.parentNode)) {
- parent = parent.parentNode;
- }
- var node = dom.splitTree(parent, {'node': r.sc, 'offset': r.so}) || r.sc;
- node.parentNode.insertBefore(table, node);
-
- if ($(node).text() === '' || node.textContent === '\u00A0') {
- node.parentNode.removeChild(node);
- }
-
- editor.afterCommand($editable);
- event.preventDefault();
- return false;
-};
-$.summernote.pluginEvents.tab = function (event, editor, layoutInfo, outdent) {
- var $editable = layoutInfo.editable();
- $editable.data('NoteHistory').recordUndo($editable, 'tab');
- var r = range.create();
- outdent = outdent || false;
- event.preventDefault();
-
- if (r && (dom.ancestor(r.sc, dom.isCell) || dom.ancestor(r.ec, dom.isCell))) {
- if (r.isCollapsed() && r.isOnCell() && r.isOnCellFirst()) {
- var td = dom.ancestor(r.sc, dom.isCell);
- if (!outdent && !dom.nextElementSibling(td) && !dom.nextElementSibling(td.parentNode)) {
- var last = dom.lastChild(td);
- range.create(last, dom.nodeLength(last), last, dom.nodeLength(last)).select();
- $.summernote.pluginEvents.enter(event, editor, layoutInfo);
- } else if (outdent && !dom.previousElementSibling(td) && !$(td.parentNode).text().match(/\S/)) {
- $.summernote.pluginEvents.backspace(event, editor, layoutInfo);
- } else {
- editor.table.tab(r, outdent);
- }
- } else {
- $.summernote.pluginEvents.indent(event, editor, layoutInfo, outdent);
- }
- } else if (r && r.isCollapsed()) {
- if (!r.sc.textContent.slice(0,r.so).match(/\S/) && r.isOnList()) {
- if (outdent) {
- $.summernote.pluginEvents.outdent(event, editor, layoutInfo);
- } else {
- $.summernote.pluginEvents.indent(event, editor, layoutInfo);
- }
- } else {
- var next;
- if (!outdent) {
- if (dom.isText(r.sc)) {
- next = r.sc.splitText(r.so);
- } else {
- next = document.createTextNode('');
- $(r.sc.childNodes[r.so]).before(next);
- }
- editor.typing.insertTab($editable, r, options.tabsize);
- r = range.create(next, 0, next, 0);
- r = dom.merge(r.sc.parentNode, r.sc, r.so, r.ec, r.eo, null, true);
- range.create(r.sc, r.so, r.ec, r.eo).select();
- } else {
- r = dom.merge(r.sc.parentNode, r.sc, r.so, r.ec, r.eo, null, true);
- r = range.create(r.sc, r.so, r.ec, r.eo);
- if (r.sc.splitText) {
- next = r.sc.splitText(r.so);
- r.sc.textContent = r.sc.textContent.replace(/(\u00A0)+$/g, '');
- next.textContent = next.textContent.replace(/^(\u00A0)+/g, '');
- range.create(r.sc, r.sc.textContent.length, r.sc, r.sc.textContent.length).select();
- }
- }
- }
- }
- return false;
-};
-$.summernote.pluginEvents.untab = function (event, editor, layoutInfo) {
- return $.summernote.pluginEvents.tab(event, editor, layoutInfo, true);
-};
-$.summernote.pluginEvents.up = function (event, editor, layoutInfo) {
- var r = range.create();
- var node = dom.firstChild(r.sc.childNodes[r.so] || r.sc);
- if (!r.isOnCell()) {
- return;
- }
- // check if an ancestor between node and cell has content before
- var ancestor = dom.ancestor(node, function (ancestorNode) {
- return dom.hasContentBefore(ancestorNode) || dom.isCell(ancestorNode);
- });
- if (!dom.isCell(ancestor) && (!dom.isBR(dom.hasContentBefore(ancestor)) || !dom.isText(node) || dom.isVisibleText(node) || dom.hasContentBefore(dom.hasContentBefore(ancestor)))) {
- return;
- }
- event.preventDefault();
- var td = dom.ancestor(r.sc, dom.isCell);
- var tr = td.parentNode;
- var target = tr.previousElementSibling && tr.previousElementSibling.children[_.indexOf(tr.children, td)];
- if (!target) {
- target = (dom.ancestorHavePreviousSibling(tr) || tr).previousSibling;
- }
- if (target) {
- range.create(dom.lastChild(target), dom.lastChild(target).textContent.length).select();
- }
-};
-$.summernote.pluginEvents.down = function (event, editor, layoutInfo) {
- var r = range.create();
- var node = dom.firstChild(r.sc.childNodes[r.so] || r.sc);
- if (!r.isOnCell()) {
- return;
- }
- // check if an ancestor between node and cell has content after
- var ancestor = dom.ancestor(node, function (ancestorNode) {
- return dom.hasContentAfter(ancestorNode) || dom.isCell(ancestorNode);
- });
- if (!dom.isCell(ancestor) && (!dom.isBR(dom.hasContentAfter(ancestor)) || !dom.isText(node) || dom.isVisibleText(node) || dom.hasContentAfter(dom.hasContentAfter(ancestor)))) {
- return;
- }
- event.preventDefault();
- var td = dom.ancestor(r.sc, dom.isCell);
- var tr = td.parentNode;
- var target = tr.nextElementSibling && tr.nextElementSibling.children[_.indexOf(tr.children, td)];
- if (!target) {
- target = (dom.ancestorHaveNextSibling(tr) || tr).nextSibling;
- }
- if (target) {
- range.create(dom.firstChild(target), 0).select();
- }
-};
-$.summernote.pluginEvents.enter = function (event, editor, layoutInfo) {
- var $editable = layoutInfo.editable();
- $editable.data('NoteHistory').recordUndo($editable, 'enter');
-
- var r = range.create();
- if (!r.isContentEditable()) {
- event.preventDefault();
- return false;
- }
- if (!r.isCollapsed()) {
- r = r.deleteContents();
- r.select();
- }
-
- var br = $(" ")[0];
-
- // set selection outside of A if range is at beginning or end
- var elem = dom.isBR(elem) ? elem.parentNode : dom.node(r.sc);
- if (elem.tagName === "A") {
- if (r.so === 0 && dom.firstChild(elem) === r.sc) {
- r.ec = r.sc = dom.hasContentBefore(elem) || $(dom.createText('')).insertBefore(elem)[0];
- r.eo = r.so = dom.nodeLength(r.sc);
- r.select();
- } else if (dom.nodeLength(r.sc) === r.so && dom.lastChild(elem) === r.sc) {
- r.ec = r.sc = dom.hasContentAfter(elem) || dom.insertAfter(dom.createText(''), elem);
- r.eo = r.so = 0;
- r.select();
- }
- }
-
- var node;
- var $node;
- var $clone;
- var contentBefore = r.sc.textContent.slice(0,r.so).match(/\S|\u00A0/);
- if (!contentBefore && dom.isText(r.sc)) {
- node = r.sc.previousSibling;
- while (!contentBefore && node && dom.isText(node)) {
- contentBefore = dom.isVisibleText(node);
- node = node.previousSibling;
- }
- }
-
- node = dom.node(r.sc);
- var exist = r.sc.childNodes[r.so] || r.sc;
- exist = dom.isVisibleText(exist) || dom.isBR(exist) ? exist : dom.hasContentAfter(exist) || (dom.hasContentBefore(exist) || exist);
-
- // table: add a tr
- var td = dom.ancestor(node, dom.isCell);
- if (td && !dom.nextElementSibling(node) && !dom.nextElementSibling(td) && !dom.nextElementSibling(td.parentNode) && (!dom.isText(r.sc) || !r.sc.textContent.slice(r.so).match(/\S|\u00A0/))) {
- $node = $(td.parentNode);
- $clone = $node.clone();
- $clone.children().html(dom.blank);
- $node.after($clone);
- node = dom.firstElementChild($clone[0]) || $clone[0];
- range.create(node, 0, node, 0).select();
- dom.scrollIntoViewIfNeeded(br);
- event.preventDefault();
- return false;
- }
-
- var last = node;
- while (node && dom.isSplitable(node) && !dom.isList(node)) {
- last = node;
- node = node.parentNode;
- }
-
- if (last === node && !dom.isBR(node)) {
- node = r.insertNode(br, true);
- if (isFormatNode(last.firstChild) && $(last).closest(options.styleTags.join(',')).length) {
- dom.moveContent(last.firstChild, last);
- last.removeChild(last.firstChild);
- }
- do {
- node = dom.hasContentAfter(node);
- } while (node && dom.isBR(node));
-
- // create an other br because the user can't see the new line with only br in a block
- if (!node && (!br.nextElementSibling || !dom.isBR(br.nextElementSibling))) {
- $(br).before($(" ")[0]);
- }
- node = br.nextSibling || br;
- } else if (last === node && dom.isBR(node)) {
- $(node).after(br);
- node = br;
- } else if (!r.so && r.isOnList() && !r.sc.textContent.length && !dom.ancestor(r.sc, dom.isLi).nextElementSibling) {
- // double enter on the end of a list = new line out of the list
- $('
').append(br).insertAfter(dom.ancestor(r.sc, dom.isList));
- node = br;
- } else if (dom.isBR(exist) && $(r.sc).closest('blockquote, pre').length && !dom.hasContentAfter($(exist.parentNode).closest('blockquote *, pre *').length ? exist.parentNode : exist)) {
- // double enter on the end of a blockquote & pre = new line out of the list
- $('
').append(br).insertAfter($(r.sc).closest('blockquote, pre'));
- node = br;
- } else if (dom.isEditable(dom.node(r.sc))) {
- // if we are directly in an editable, only SHIFT + ENTER should add a newline
- node = null;
- } else if (last === r.sc) {
- if (dom.isBR(last)) {
- last = last.parentNode;
- }
- $node = $(last);
- $clone = $node.clone().text("");
- $node.after($clone);
- node = dom.node(dom.firstElementChild($clone[0]) || $clone[0]);
- $(node).html(br);
- node = br;
- } else {
- node = dom.splitTree(last, {'node': r.sc, 'offset': r.so}) || r.sc;
- if (!contentBefore) {
- // dom.node chooses the parent if node is text
- var cur = dom.node(dom.lastChild(node.previousSibling));
- if (!dom.isBR(cur)) {
- // We should concat what was before with a
- $(cur).html(cur.innerHTML + br.outerHTML);
- }
- }
- if (!dom.isVisibleText(node)) {
- node = dom.firstChild(node);
- $(dom.node( dom.isBR(node) ? node.parentNode : node )).html(br);
- node = br;
- }
- }
-
- if (node) {
- node = dom.firstChild(node);
- if (dom.isBR(node)) {
- range.createFromNode(node).select();
- } else {
- range.create(node,0).select();
- }
- dom.scrollIntoViewIfNeeded(node);
- }
- event.preventDefault();
- return false;
-};
-$.summernote.pluginEvents.visible = function (event, editor, layoutInfo) {
- var $editable = layoutInfo.editable();
- $editable.data('NoteHistory').recordUndo($editable, "visible");
-
- var r = range.create();
- if (!r) return;
-
- if (!r.isCollapsed()) {
- if ((dom.isCell(dom.node(r.sc)) || dom.isCell(dom.node(r.ec))) && dom.node(r.sc) !== dom.node(r.ec)) {
- remove_table_content(r);
- r = range.create(r.ec, 0);
- }
- r.select();
- }
-
- // don't write in forbidden tag (like span for font awsome)
- var node = dom.firstChild(r.sc.tagName && r.so ? r.sc.childNodes[r.so] || r.sc : r.sc);
- while (node.parentNode) {
- if (dom.isForbiddenNode(node)) {
- var text = node.previousSibling;
- if (text && dom.isText(text) && dom.isVisibleText(text)) {
- range.create(text, text.textContent.length, text, text.textContent.length).select();
- } else {
- text = node.parentNode.insertBefore(document.createTextNode( "." ), node);
- range.create(text, 1, text, 1).select();
- setTimeout(function () {
- var text = range.create().sc;
- text.textContent = text.textContent.replace(/^./, '');
- range.create(text, text.textContent.length, text, text.textContent.length).select();
- },0);
- }
- break;
- }
- node = node.parentNode;
- }
-
- return true;
-};
-
-function remove_table_content(r) {
- var nodes = dom.listBetween(r.sc, r.ec, r.so, r.eo);
- if (dom.isText(r.sc)) {
- r.sc.textContent = r.sc.textContent.slice(0, r.so);
- }
- if (dom.isText(r.ec)) {
- r.ec.textContent = r.ec.textContent.slice(r.eo);
- }
- for (var i in nodes) {
- var node = nodes[i];
- if (node === r.sc || node === r.ec || $.contains(node, r.sc) || $.contains(node, r.ec)) {
- continue;
- } else if (dom.isCell(node)) {
- $(node).html(" ");
- } else if (node.parentNode) {
- do {
- var parent = node.parentNode;
- parent.removeChild(node);
- node = parent;
- } while (!dom.isVisibleText(node) && !dom.firstElementChild(node) &&
- !dom.isCell(node) &&
- node.parentNode && !$(node.parentNode).hasClass('o_editable'));
- }
- }
- return false;
-}
-
-$.summernote.pluginEvents.delete = function (event, editor, layoutInfo) {
- var $editable = layoutInfo.editable();
- $editable.data('NoteHistory').recordUndo($editable, "delete");
-
- var r = range.create();
- if (!r) return;
- if (!r.isContentEditable()) {
- event.preventDefault();
- return false;
- }
- if (!r.isCollapsed()) {
- if (dom.isCell(dom.node(r.sc)) || dom.isCell(dom.node(r.ec))) {
- remove_table_content(r);
- range.create(r.ec, 0).select();
- } else {
- r = r.deleteContents();
- r.select();
- }
- event.preventDefault();
- return false;
- }
-
- var target = r.ec;
- var offset = r.eo;
- if (target.tagName && target.childNodes[offset]) {
- target = target.childNodes[offset];
- offset = 0;
- }
-
- var node = dom.node(target);
- var data = dom.merge(node, target, offset, target, offset, null, true);
- data = dom.removeSpace(node.parentNode, data.sc, data.so, data.ec, data.eo);
- r = range.create(data.sc, data.so);
- r.select();
- target = r.sc;
- offset = r.so;
-
- while (!dom.hasContentAfter(node) && !dom.hasContentBefore(node) && !dom.isImg(node)) {node = node.parentNode;}
-
- var contentAfter = target.textContent.slice(offset,Infinity).match(/\S|\u00A0/);
- var content = target.textContent.replace(/[ \t\r\n]+$/, '');
- var temp;
- var temp2;
- var next;
-
- // media
- if (dom.isImg(node) || (!contentAfter && dom.isImg(dom.hasContentAfter(node)))) {
- var parent;
- var index;
- if (!dom.isImg(node)) {
- node = dom.hasContentAfter(node);
- }
- while (dom.isImg(node)) {
- parent = node.parentNode;
- index = dom.position(node);
- if (index>0) {
- next = node.previousSibling;
- r = range.create(next, next.textContent.length);
- } else {
- r = range.create(parent, 0);
- }
- if (!dom.hasContentAfter(node) && !dom.hasContentBefore(node)) {
- parent.appendChild($(' ')[0]);
- }
- parent.removeChild(node);
- node = parent;
- r.select();
- }
- }
- // empty tag
- else if (!content.length && target.tagName && dom.isRemovableEmptyNode(dom.isBR(target) ? target.parentNode : target)) {
- if (node === $editable[0] || $.contains(node, $editable[0])) {
- event.preventDefault();
- return false;
- }
- var before = false;
- next = dom.hasContentAfter(dom.ancestorHaveNextSibling(node));
- if (!dom.isContentEditable(next)) {
- before = true;
- next = dom.hasContentBefore(dom.ancestorHavePreviousSibling(node));
- }
- dom.removeSpace(next.parentNode, next, 0, next, 0); // clean before jump for not select invisible space between 2 tag
- next = dom.firstChild(next);
- node.parentNode.removeChild(node);
- range.create(next, before ? next.textContent.length : 0).select();
- }
- // normal feature if same tag and not the end
- else if (contentAfter) {
- return true;
- }
- // merge with the next text node
- else if (dom.isText(target) && (temp = dom.hasContentAfter(target)) && dom.isText(temp)) {
- return true;
- }
- //merge with the next block
- else if ((temp = dom.ancestorHaveNextSibling(target)) &&
- !r.isOnCell() &&
- dom.isMergable(temp) &&
- dom.isMergable(temp2 = dom.hasContentAfter(temp)) &&
- temp.tagName === temp2.tagName &&
- (temp.tagName !== "LI" || !$('ul,ol', temp).length) && (temp2.tagName !== "LI" || !$('ul,ol', temp2).length) && // protect li
- !dom.isNotBreakable(temp) &&
- !dom.isNotBreakable(temp2)) {
- dom.autoMerge(target, false);
- next = dom.firstChild(dom.hasContentAfter(dom.ancestorHaveNextSibling(target)));
- if (dom.isBR(next)) {
- if (dom.position(next) === 0) {
- range.create(next.parentNode, 0).select();
- }
- else {
- range.create(next.previousSibling, next.previousSibling.textContent.length).select();
- }
- next.parentNode.removeChild(next);
- } else {
- range.create(next, 0).select();
- }
- }
- // jump to next node for delete
- else if ((temp = dom.ancestorHaveNextSibling(target)) && (temp2 = dom.hasContentAfter(temp)) && dom.isContentEditable(temp2)) {
-
- dom.removeSpace(temp2.parentNode, temp2, 0, temp, 0); // clean before jump for not select invisible space between 2 tag
- temp2 = dom.firstChild(temp2);
-
- r = range.create(temp2, 0);
- r.select();
-
- if ((dom.isText(temp) || dom.getComputedStyle(temp).display === "inline") && (dom.isText(temp2) || dom.getComputedStyle(temp2).display === "inline")) {
- if (dom.isText(temp2)) {
- temp2.textContent = temp2.textContent.replace(/^\s*\S/, '');
- } else {
- $.summernote.pluginEvents.delete(event, editor, layoutInfo);
- }
- }
- }
-
- $(dom.node(r.sc)).trigger("click"); // trigger click to disable and reanable editor and image handler
- event.preventDefault();
- return false;
-};
-$.summernote.pluginEvents.backspace = function (event, editor, layoutInfo) {
- var $editable = layoutInfo.editable();
- $editable.data('NoteHistory').recordUndo($editable, "backspace");
-
- var r = range.create();
- if (!r) return;
- if (!r.isContentEditable()) {
- event.preventDefault();
- return false;
- }
- if (!r.isCollapsed()) {
- if (dom.isCell(dom.node(r.sc)) || dom.isCell(dom.node(r.ec))) {
- remove_table_content(r);
- range.create(r.sc, dom.nodeLength(r.sc)).select();
- } else {
- r = r.deleteContents();
- r.select();
- }
- event.preventDefault();
- return false;
- }
-
- var target = r.sc;
- var offset = r.so;
- if (target.tagName && target.childNodes[offset]) {
- target = target.childNodes[offset];
- offset = 0;
- }
-
- var node = dom.node(target);
- var data = dom.merge(node, target, offset, target, offset, null, true);
- data = dom.removeSpace(node.parentNode, data.sc, data.so, data.ec, data.eo);
- r = dom.isVoid(data.sc) ? range.createFromNode(data.sc) : range.create(data.sc, data.so);
- r.select();
- target = r.sc;
- offset = r.so;
- if (target.tagName && target.childNodes[offset]) {
- target = target.childNodes[offset];
- offset = 0;
- node = dom.node(target);
- }
-
- while (node.parentNode && !dom.hasContentAfter(node) && !dom.hasContentBefore(node) && !dom.isImg(node)) {node = node.parentNode;}
-
- var contentBefore = target.textContent.slice(0,offset).match(/\S|\u00A0/);
- var content = target.textContent.replace(/[ \t\r\n]+$/, '');
- var temp;
- var temp2;
- var prev;
-
- // delete media
- if (dom.isImg(node) || (!contentBefore && dom.isImg(dom.hasContentBefore(node)))) {
- if (!dom.isImg(node)) {
- node = dom.hasContentBefore(node);
- }
- range.createFromNode(node).select();
- $.summernote.pluginEvents.delete(event, editor, layoutInfo);
- }
- // table tr td
- else if (r.isOnCell() && !offset && (target === (temp = dom.ancestor(target, dom.isCell)) || target === temp.firstChild || (dom.isText(temp.firstChild) && !dom.isVisibleText(temp.firstChild) && target === temp.firstChild.nextSibling))) {
- if (dom.previousElementSibling(temp)) {
- var td = dom.previousElementSibling(temp);
- node = td.lastChild || td;
- } else {
- var tr = temp.parentNode;
- var prevTr = dom.previousElementSibling(tr);
- if (!$(temp.parentNode).text().match(/\S|\u00A0/)) {
- if (prevTr) {
- node = dom.lastChild(dom.lastElementChild(prevTr));
- } else {
- node = dom.lastChild(dom.hasContentBefore(dom.ancestorHavePreviousSibling(tr)) || $editable.get(0));
- }
- $(tr).empty();
- if (!$(tr).closest('table').has('td, th').length) {
- $(tr).closest('table').remove();
- }
- $(tr).remove();
- range.create(node, node.textContent.length, node, node.textContent.length).select();
- } else {
- node = dom.lastElementChild(prevTr).lastChild || dom.lastElementChild(prevTr);
- }
- }
- if (dom.isBR(node)) {
- range.createFromNode(node).select();
- } else {
- range.create(node, dom.nodeLength(node)).select();
- }
- }
- // empty tag
- else if (!content.length && target.tagName && dom.isRemovableEmptyNode(target)) {
- if (node === $editable[0] || $.contains(node, $editable[0])) {
- event.preventDefault();
- return false;
- }
- var before = true;
- prev = dom.hasContentBefore(dom.ancestorHavePreviousSibling(node));
- if (!dom.isContentEditable(prev)) {
- before = false;
- prev = dom.hasContentAfter(dom.ancestorHaveNextSibling(node));
- }
- dom.removeSpace(prev.parentNode, prev, 0, prev, 0); // clean before jump for not select invisible space between 2 tag
- prev = dom.lastChild(prev);
- node.parentNode.removeChild(node);
- range.createFromNode(prev).select();
- range.create(prev, before ? prev.textContent.length : 0).select();
- }
- // normal feature if same tag and not the begin
- else if (contentBefore) {
- return true;
- }
- // merge with the previous text node
- else if (dom.isText(target) && (temp = dom.hasContentBefore(target)) && (dom.isText(temp) || dom.isBR(temp))) {
- return true;
- }
- //merge with the previous block
- else if ((temp = dom.ancestorHavePreviousSibling(target)) &&
- dom.isMergable(temp) &&
- dom.isMergable(temp2 = dom.hasContentBefore(temp)) &&
- temp.tagName === temp2.tagName &&
- (temp.tagName !== "LI" || !$('ul,ol', temp).length) && (temp2.tagName !== "LI" || !$('ul,ol', temp2).length) && // protect li
- !dom.isNotBreakable(temp) &&
- !dom.isNotBreakable(temp2)) {
- prev = dom.firstChild(target);
- dom.autoMerge(target, true);
- range.create(prev, 0).select();
- }
- // jump to previous node for delete
- else if ((temp = dom.ancestorHavePreviousSibling(target)) && (temp2 = dom.hasContentBefore(temp)) && dom.isContentEditable(temp2)) {
-
- dom.removeSpace(temp2.parentNode, temp2, 0, temp, 0); // clean before jump for not select invisible space between 2 tag
- temp2 = dom.lastChild(temp2);
-
- r = range.create(temp2, temp2.textContent.length, temp2, temp2.textContent.length);
- r.select();
-
- if ((dom.isText(temp) || dom.getComputedStyle(temp).display === "inline") && (dom.isText(temp2) || dom.getComputedStyle(temp2).display === "inline")) {
- if (dom.isText(temp2)) {
- temp2.textContent = temp2.textContent.replace(/\S\s*$/, '');
- } else {
- $.summernote.pluginEvents.backspace(event, editor, layoutInfo);
- }
- }
- }
-
- r = range.create();
- if (r) {
- $(dom.node(r.sc)).trigger("click"); // trigger click to disable and reanable editor and image handler
- dom.scrollIntoViewIfNeeded(r.sc.parentNode.previousElementSibling || r.sc);
- }
-
- event.preventDefault();
- return false;
-};
-
-function isFormatNode(node) {
- return node.tagName && options.styleTags.indexOf(node.tagName.toLowerCase()) !== -1;
-}
-
-$.summernote.pluginEvents.insertUnorderedList = function (event, editor, layoutInfo, type) {
- var $editable = layoutInfo.editable();
- $editable.focus();
- $editable.data('NoteHistory').recordUndo($editable);
-
- type = type || "UL";
- var sorted = type === "OL";
-
- var parent;
- var r = range.create();
- if (!r) return;
- var node = r.sc;
- while (node && node !== $editable[0]) {
-
- parent = node.parentNode;
- if (node.tagName === (sorted ? "UL" : "OL")) {
-
- var ul = document.createElement(sorted ? "ol" : "ul");
- ul.className = node.className;
- if (type !== 'checklist') {
- ul.classList.remove('o_checklist');
- } else {
- ul.classList.add('o_checklist');
- }
- parent.insertBefore(ul, node);
- while (node.firstChild) {
- ul.appendChild(node.firstChild);
- }
- parent.removeChild(node);
- r.select();
- return;
-
- } else if (node.tagName === (sorted ? "OL" : "UL")) {
-
- if (type === 'checklist' && !node.classList.contains('o_checklist')) {
- node.classList.add('o_checklist');
- return;
- } else if (type === 'UL' && node.classList.contains('o_checklist')) {
- node.classList.remove('o_checklist');
- return;
- }
-
- var lis = [];
- for (var i=0; i= r.eo) {
- r.ec = dom.lastChild(r.ec);
- r.eo = dom.nodeLength(r.ec);
- }
- r = range.create(r.sc, r.so, r.ec, r.eo);
- r.reRange().select();
-
- if (sTagName === "blockquote" || sTagName === "pre") {
- sTagName = $.summernote.core.agent.isMSIE ? '<' + sTagName + '>' : sTagName;
- document.execCommand('FormatBlock', false, sTagName);
- return;
- }
-
- // fix by odoo because if you select a style in a li with no p tag all the ul is wrapped by the style tag
- var nodes = dom.listBetween(r.sc, r.ec, r.so, r.eo);
- for (var i=0; i 0.05) {
- font.style.fontSize = size + "px";
- }
- }
- }
- }
-
- // remove empty values
- // we must remove the value in 2 steps (applay inherit then remove) because some
- // browser like chrome have some time an error for the rendering and/or keep inherit
- for (i=0; i ').appendTo('body');
- $del.data('td', this);
- $dels = $dels.add($del);
- $del.css({
- left: ((pos.left + $td.outerWidth()/2)-6) + "px",
- top: (pos.top-6) + "px"
- });
-
- var $add = $(' ').appendTo('body');
- $add.data('td', this);
- $adds = $adds.add($add);
- $add.css({
- left: (pos.left-6) + "px",
- top: (pos.top-6) + "px"
- });
- });
-
- var $last = $tds.last();
- var pos = $last.offset();
- var $add = $(' ').appendTo('body');
- $adds = $adds.add($add);
- $add.css({
- left: (pos.left+$last.outerWidth()-6) + "px",
- top: (pos.top-6) + "px"
- });
-
- var $table = $(table);
- $dels.data('table', table).on('mousedown', function (event) {
- var td = $(this).data('td');
- $editable.data('NoteHistory').recordUndo($editable);
-
- var newTd;
- if ($(td).siblings().length) {
- var eq = $(td).index();
- $table.find('tr').each(function () {
- $('> td:eq('+eq+')', this).remove();
- });
- newTd = $table.find('tr:first > td:eq('+eq+'), tr:first > td:last').first();
- } else {
- var prev = dom.lastChild(dom.hasContentBefore(dom.ancestorHavePreviousSibling($table[0])));
- $table.remove();
- $('.o_table_handler').remove();
- r = range.create(prev, prev.textContent.length);
- r.select();
- $(r.sc).trigger('mouseup');
- return;
- }
-
- $('.o_table_handler').remove();
- range.create(newTd[0], 0, newTd[0], 0).select();
- newTd.trigger('mouseup');
- });
- $adds.data('table', table).on('mousedown', function (event) {
- var td = $(this).data('td');
- $editable.data('NoteHistory').recordUndo($editable);
-
- var newTd;
- if (td) {
- var eq = $(td).index();
- $table.find('tr').each(function () {
- $('td:eq('+eq+')', this).before(''+dom.blank+' ');
- });
- newTd = $table.find('tr:first td:eq('+eq+')');
- } else {
- $table.find('tr').each(function () {
- $(this).append(''+dom.blank+' ');
- });
- newTd = $table.find('tr:first td:last');
- }
-
- $('.o_table_handler').remove();
- range.create(newTd[0], 0, newTd[0], 0).select();
- newTd.trigger('mouseup');
- });
-
- $dels.css({
- 'position': 'absolute',
- 'cursor': 'pointer',
- 'background-color': '#fff',
- 'color': '#ff0000'
- });
- $adds.css({
- 'position': 'absolute',
- 'cursor': 'pointer',
- 'background-color': '#fff',
- 'color': '#00ff00'
- });
-}
-var fn_popover_update = eventHandler.modules.popover.update;
-eventHandler.modules.popover.update = function ($popover, oStyle, isAirMode) {
- fn_popover_update.call(this, $popover, oStyle, isAirMode);
- if ((isAirMode ? $popover : $popover.parent()).find('.note-table').length) {
- summernote_table_update(oStyle);
- }
-};
-
-function mouseDownChecklist (e) {
- if (!dom.isLi(e.target) || !$(e.target).parent('ul.o_checklist').length || e.offsetX > 0) {
- return;
- }
- e.stopPropagation();
- e.preventDefault();
- var checked = $(e.target).hasClass('o_checked');
- $(e.target).toggleClass('o_checked', !checked);
- var $sublevel = $(e.target).next('ul.o_checklist, li:has(> ul.o_checklist)').find('> li, ul.o_checklist > li');
- var $parents = $(e.target).parents('ul.o_checklist').map(function () {
- return this.parentNode.tagName === 'LI' ? this.parentNode : this;
- });
- if (checked) {
- $sublevel.removeClass('o_checked');
- do {
- $parents = $parents.prev('ul.o_checklist li').removeClass('o_checked');
- } while ($parents.length);
- } else {
- $sublevel.addClass('o_checked');
- var $lis;
- do {
- $lis = $parents.not(':has(li[id^="checklist-id"]:not(.o_checked))').prev('ul.o_checklist li:not(.o_checked)');
- $lis.addClass('o_checked');
- } while ($lis.length);
- }
-}
-
-var fn_attach = eventHandler.attach;
-eventHandler.attach = function (oLayoutInfo, options) {
- var $editable = oLayoutInfo.editor().hasClass('note-editable') ? oLayoutInfo.editor() : oLayoutInfo.editor().find('.note-editable');
- fn_attach.call(this, oLayoutInfo, options);
- $editable.on("scroll", summernote_table_scroll);
- $editable.on("mousedown", mouseDownChecklist);
-};
-var fn_detach = eventHandler.detach;
-eventHandler.detach = function (oLayoutInfo, options) {
- var $editable = oLayoutInfo.editor().hasClass('note-editable') ? oLayoutInfo.editor() : oLayoutInfo.editor().find('.note-editable');
- fn_detach.call(this, oLayoutInfo, options);
- $editable.off("scroll", summernote_table_scroll);
- $editable.off("mousedown", mouseDownChecklist);
- $('.o_table_handler').remove();
-};
-
-options.icons.image.image = "file-image-o";
-$.summernote.lang['en-US'].image.image = "File / Image";
-
-return $.summernote;
-});
diff --git a/addons/web_editor/static/src/js/editor/summernote_import_end.js b/addons/web_editor/static/src/js/editor/summernote_import_end.js
deleted file mode 100644
index 5b3ac8b1ea7..00000000000
--- a/addons/web_editor/static/src/js/editor/summernote_import_end.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * @todo Remove when summernote is updated/removed.
- * @see summernote_import_start.js (setup script) for more information.
- */
-(function () {
- "use strict";
- window.define = odoo.__define__;
- delete odoo.__define__;
-})();
diff --git a/addons/web_editor/static/src/js/editor/summernote_import_start.js b/addons/web_editor/static/src/js/editor/summernote_import_start.js
deleted file mode 100644
index 8705caea5cd..00000000000
--- a/addons/web_editor/static/src/js/editor/summernote_import_start.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * This file allows the import of all summernote files.
- *
- * @todo The version we currently have is summernote v0.6.0 (source code
- * version). It is supposed to be used pre-compiled in one file or with its
- * correct dev dependencies. We use neither of those methods; instead we have
- * to call this setup file to declare the global `define` method and pipe the
- * results into our `odoo.define` architecture, and then to call the
- * dismantling function to clean the global scope. To properly import the files
- * we need to match the order of declared imports with the order in which the
- * files are loaded by the client, since they don't provide their own
- * file/module names in their declaration. This is obviously to remove as soon
- * as we remove/update summernote for a decent alternative.
- * @see summernote_import_end.js (dismantling script)
- */
-(function () {
- "use strict";
- odoo.define("jquery", () => $);
-
- const SUMMERNOTE_MODULES = [
- 'summernote/core/async',
- 'summernote/core/func',
- 'summernote/core/agent',
- 'summernote/core/list',
- 'summernote/core/dom',
- 'summernote/core/key',
- 'summernote/core/range',
- 'summernote/editing/Bullet',
- 'summernote/editing/History',
- 'summernote/editing/Style',
- 'summernote/editing/Table',
- 'summernote/editing/Typing',
- 'summernote/module/Editor',
- 'summernote/module/Button',
- 'summernote/module/Clipboard',
- 'summernote/module/Codeview',
- 'summernote/module/DragAndDrop',
- 'summernote/module/Fullscreen',
- 'summernote/module/Handle',
- 'summernote/module/HelpDialog',
- 'summernote/module/ImageDialog',
- 'summernote/module/LinkDialog',
- 'summernote/module/Popover',
- 'summernote/module/Statusbar',
- 'summernote/module/Toolbar',
- 'summernote/Renderer',
- 'summernote/EventHandler',
- 'summernote/defaults',
- 'summernote/summernote',
- ];
-
- odoo.__define__ = window.define;
-
- window.define = function (deps, factory) {
- const moduleId = SUMMERNOTE_MODULES.shift();
- if (Array.isArray(deps)) {
- const odooKey = `__summernote_module_${moduleId}`;
- const args = [];
- const reqs = [`f=odoo["${odooKey}"]`];
- for (let i = 0; i < deps.length; i++) {
- args.push(`m${i}`);
- reqs.push(`m${i}=require("${deps[i]}")`);
- }
- odoo[odooKey] = factory;
- factory = new Function(
- "require",
- `let ${reqs.join(",")};delete odoo["${odooKey}"];return f(${args.join(",")});`
- );
- }
- odoo.define(moduleId, factory);
- };
-})();
diff --git a/addons/web_editor/static/src/js/wysiwyg/test_root.js b/addons/web_editor/static/src/js/wysiwyg/test_root.js
deleted file mode 100644
index 0a116f79ed4..00000000000
--- a/addons/web_editor/static/src/js/wysiwyg/test_root.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/** @odoo-module alias=web_editor.wysiwyg.root.test */
-import * as WysiwygRoot from "web_editor.wysiwyg.root";
-
-WysiwygRoot.include({
- assetLibs: null // We need to add the asset because tests performed overwrites (Dialog, Unbreakable...)
-});
diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js b/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js
index f6e66dc7c69..ccd6be6b5f8 100644
--- a/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js
+++ b/addons/web_editor/static/src/js/wysiwyg/widgets/color_palette.js
@@ -6,7 +6,7 @@ const core = require('web.core');
const session = require('web.session');
const {ColorpickerWidget} = require('web.Colorpicker');
const Widget = require('web.Widget');
-const summernoteCustomColors = require('web_editor.rte.summernote_custom_colors');
+const customColors = require('web_editor.custom_colors');
const weUtils = require('web_editor.utils');
const qweb = core.qweb;
@@ -38,7 +38,6 @@ const ColorPaletteWidget = Widget.extend({
*/
init: function (parent, options) {
this._super.apply(this, arguments);
- this.summernoteCustomColorsArray = [].concat(...summernoteCustomColors);
this.style = window.getComputedStyle(document.documentElement);
this.options = _.extend({
selectedColor: false,
@@ -89,9 +88,9 @@ const ColorPaletteWidget = Widget.extend({
// Render common colors
if (!this.options.excluded.includes('common')) {
const $commonColorSection = this.$('[data-name="common"]');
- summernoteCustomColors.forEach((colorRow, i) => {
+ customColors.forEach((colorRow, i) => {
if (i === 0) {
- return; // Ignore the summernote gray palette and use ours
+ return; // Ignore the wysiwyg gray palette and use ours
}
const $div = $('
', {class: 'clearfix'}).appendTo($commonColorSection);
colorRow.forEach(color => {
@@ -176,7 +175,7 @@ const ColorPaletteWidget = Widget.extend({
return;
}
this.el.querySelectorAll('.o_custom_color').forEach(el => el.remove());
- const existingColors = new Set(this.summernoteCustomColorsArray.concat(
+ const existingColors = new Set(customColors.concat(
Object.keys(this.colorToColorNames)
));
this.trigger_up('get_custom_colors', {
@@ -384,7 +383,7 @@ ColorPaletteWidget.loadDependencies = async function (rpcCapableObj) {
const proms = [ajax.loadXML('/web_editor/static/src/xml/snippets.xml', qweb)];
// Public user using the editor may have a colorpalette but with
- // the default summernote ones.
+ // the default wysiwyg ones.
if (!session.is_website_user) {
// We can call the colorPalette multiple times but only need 1 rpc
if (!colorpickerTemplateProm && !colorpickerArch) {
diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/dialog.js
index 516aa4bee47..2f19f9fc8c9 100644
--- a/addons/web_editor/static/src/js/wysiwyg/widgets/dialog.js
+++ b/addons/web_editor/static/src/js/wysiwyg/widgets/dialog.js
@@ -10,7 +10,7 @@ var _t = core._t;
/**
* Extend Dialog class to handle save/cancel of edition components.
*/
-var SummernoteDialog = Dialog.extend({
+var WysiwygDialog = Dialog.extend({
/**
* @constructor
*/
@@ -77,5 +77,5 @@ var SummernoteDialog = Dialog.extend({
},
});
-return SummernoteDialog;
+return WysiwygDialog;
});
diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/link_dialog.js b/addons/web_editor/static/src/js/wysiwyg/widgets/link_dialog.js
index 60ff2c94e5d..0247cc256e3 100644
--- a/addons/web_editor/static/src/js/wysiwyg/widgets/link_dialog.js
+++ b/addons/web_editor/static/src/js/wysiwyg/widgets/link_dialog.js
@@ -5,9 +5,6 @@ var core = require('web.core');
var Dialog = require('wysiwyg.widgets.Dialog');
require("summernote/summernote");
-var dom = $.summernote.core.dom;
-var range = $.summernote.core.range;
-
var _t = core._t;
/**
diff --git a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js
index b0da7a8ce3b..d823a337b3e 100644
--- a/addons/web_editor/static/src/js/wysiwyg/widgets/media.js
+++ b/addons/web_editor/static/src/js/wysiwyg/widgets/media.js
@@ -1261,7 +1261,7 @@ var IconWidget = SearchableMediaWidget.extend({
});
/**
- * Let users choose a video, support all summernote video, and embed iframe.
+ * Let users choose a video, support embed iframe.
*/
var VideoWidget = MediaWidget.extend({
template: 'wysiwyg.widgets.video',
diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
index fe9666dea7a..790ca765def 100644
--- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
+++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
@@ -1,8 +1,6 @@
odoo.define('web_editor.wysiwyg', function (require) {
'use strict';
-var Widget = require('web.Widget');
-var SummernoteManager = require('web_editor.rte.summernote');
-var summernoteCustomColors = require('web_editor.rte.summernote_custom_colors');
+const customColors = require('web_editor.custom_colors');
var id = 0;
// core.bus
@@ -25,7 +23,7 @@ var Wysiwyg = Widget.extend({
'styleWithSpan': false,
'inlinemedia': ['p'],
'lang': 'odoo',
- 'colors': summernoteCustomColors,
+ 'colors': customColors,
recordInfo: {
context: {},
},
diff --git a/addons/web_editor/static/src/xml/wysiwyg.xml b/addons/web_editor/static/src/xml/wysiwyg.xml
index 92b0022645b..970b6d652bb 100644
--- a/addons/web_editor/static/src/xml/wysiwyg.xml
+++ b/addons/web_editor/static/src/xml/wysiwyg.xml
@@ -53,10 +53,6 @@
odoo.define('web_editor.wysiwyg.iniframe', function (require) {
'use strict';
var editor = require('web_editor.editor');
-
- window._summernoteSlave = $.summernote;
- window._summernoteSlave.iframe = true;
- window._summernoteSlave.lang = window.top.$.summernote.lang;
if (window.top. ) {
window.top. (editor.Class, );
}
diff --git a/addons/web_editor/static/tests/test_utils.js b/addons/web_editor/static/tests/test_utils.js
index cf2157495a8..11abf8cffbd 100644
--- a/addons/web_editor/static/tests/test_utils.js
+++ b/addons/web_editor/static/tests/test_utils.js
@@ -332,7 +332,6 @@ async function createWysiwyg(params) {
/**
* Char codes.
*/
-var dom = $.summernote.dom;
var keyboardMap = {
"8": "BACKSPACE",
"9": "TAB",
diff --git a/addons/website/static/src/js/editor/rte.summernote.js b/addons/website/static/src/js/editor/rte.summernote.js
deleted file mode 100644
index 36cadca7a8d..00000000000
--- a/addons/website/static/src/js/editor/rte.summernote.js
+++ /dev/null
@@ -1,59 +0,0 @@
-odoo.define('website.rte.summernote', function (require) {
-'use strict';
-
-var core = require('web.core');
-require('web_editor.rte.summernote');
-
-var eventHandler = $.summernote.eventHandler;
-var renderer = $.summernote.renderer;
-var tplIconButton = renderer.getTemplate().iconButton;
-var _t = core._t;
-
-var fn_tplPopovers = renderer.tplPopovers;
-renderer.tplPopovers = function (lang, options) {
- var $popover = $(fn_tplPopovers.call(this, lang, options));
- $popover.find('.note-image-popover .btn-group:has([data-value="img-thumbnail"])').append(
- tplIconButton('fa fa-object-ungroup', {
- title: _t('Transform the picture (click twice to reset transformation)'),
- event: 'transform',
- }));
- return $popover;
-};
-
-$.summernote.pluginEvents.transform = function (event, editor, layoutInfo, sorted) {
- var $selection = layoutInfo.handle().find('.note-control-selection');
- var $image = $($selection.data('target'));
-
- if ($image.data('transfo-destroy')) {
- $image.removeData('transfo-destroy');
- return;
- }
-
- $image.transfo();
-
- var mouseup = function (event) {
- $('.note-popover button[data-event="transform"]').toggleClass('active', $image.is('[style*="transform"]'));
- };
- $(document).on('mouseup', mouseup);
-
- var mousedown = function (event) {
- if (!$(event.target).closest('.transfo-container').length) {
- $image.transfo('destroy');
- $(document).off('mousedown', mousedown).off('mouseup', mouseup);
- }
- if ($(event.target).closest('.note-popover').length) {
- $image.data('transfo-destroy', true).attr('style', ($image.attr('style') || '').replace(/[^;]*transform[\w:]*;?/g, ''));
- }
- $image.trigger('content_changed');
- };
- $(document).on('mousedown', mousedown);
-};
-
-var fn_boutton_update = eventHandler.modules.popover.button.update;
-eventHandler.modules.popover.button.update = function ($container, oStyle) {
- fn_boutton_update.call(this, $container, oStyle);
- $container.find('button[data-event="transform"]')
- .toggleClass('active', $(oStyle.image).is('[style*="transform"]'))
- .toggleClass('d-none', !$(oStyle.image).is('img'));
-};
-});
diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml
index efa635cf114..40115cc7ebd 100644
--- a/addons/website_forum/views/website_forum.xml
+++ b/addons/website_forum/views/website_forum.xml
@@ -14,7 +14,7 @@
-
+
diff --git a/debian/copyright b/debian/copyright
index a5954463363..97fba38cd89 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -426,10 +426,6 @@ Files: addons/web_editor/static/lib/cropperjs/* addons/web_editor/static/lib/jqu
Copyright: 2015-present Chen Fengyuan
License: MIT
-Files: addons/web_editor/static/lib/summernote/src/js/intro.js
-Copyright: 2013-2015 Alan Hong and other contributors
-License: MIT
-
Files: addons/web_editor/static/lib/vkbeautify/vkbeautify.0.99.00.beta.js
Copyright: 2012 Vadim Kiryukhin
License: MIT
diff --git a/doc/_extensions/autojsdoc/__main__.py b/doc/_extensions/autojsdoc/__main__.py
index 2ac5f3a0cb3..689d8cd6606 100644
--- a/doc/_extensions/autojsdoc/__main__.py
+++ b/doc/_extensions/autojsdoc/__main__.py
@@ -72,11 +72,6 @@ ABSTRACT_MODULES = [
'doc': 'maybe tourmanager instance?',
}),
}),
- # OH FOR FUCK'S SAKE
- jsdoc.ModuleDoc({
- 'module': 'summernote/summernote',
- 'exports': jsdoc.NSDoc({'doc': "totally real summernote"}),
- })
]
@click.group(context_settings={'help_option_names': ['-h', '--help']})
diff --git a/doc/_extensions/autojsdoc/ext/extractor.py b/doc/_extensions/autojsdoc/ext/extractor.py
index 36211cfd3b3..70cc80dfe68 100644
--- a/doc/_extensions/autojsdoc/ext/extractor.py
+++ b/doc/_extensions/autojsdoc/ext/extractor.py
@@ -80,8 +80,4 @@ ABSTRACT_MODULES = [
'doc': u'maybe tourmanager instance?',
}),
}),
- jsdoc.ModuleDoc({
- 'module': u'summernote/summernote',
- 'exports': jsdoc.NSDoc({'doc': u"totally real summernote"}),
- })
]
diff --git a/odoo/addons/test_lint/tests/test_ecmascript.py b/odoo/addons/test_lint/tests/test_ecmascript.py
index 1a706175ebc..8d326fb5b20 100644
--- a/odoo/addons/test_lint/tests/test_ecmascript.py
+++ b/odoo/addons/test_lint/tests/test_ecmascript.py
@@ -29,8 +29,6 @@ class TestECMAScriptVersion(lint_case.LintCase):
def test_ecmascript_version(self):
""" Test that there is no unsupported ecmascript in javascript files """
- black_re = re.compile(r'summernote.+(intro\.js|outro.js)$')
-
files_to_check = [
p for p in self.iter_module_files('*.js')
if 'static/test' not in p
@@ -38,7 +36,6 @@ class TestECMAScriptVersion(lint_case.LintCase):
if 'static/lib/qweb/qweb.js' not in p # because this file is not bundled at all
if 'py.js/lib/py.js' not in p # because it is not "strict" compliant
if 'static/lib/epos-2.12.0.js' not in p # same
- if not black_re.search(p)
]
_logger.info('Testing %s js files', len(files_to_check))