summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/web_editor/static/src/js/wysiwyg/wysiwyg.js')
-rw-r--r--addons/web_editor/static/src/js/wysiwyg/wysiwyg.js274
1 files changed, 274 insertions, 0 deletions
diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
new file mode 100644
index 00000000..6a1924e1
--- /dev/null
+++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
@@ -0,0 +1,274 @@
+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');
+var id = 0;
+
+// core.bus
+// media_dialog_demand
+var Wysiwyg = Widget.extend({
+ xmlDependencies: [
+ ],
+ defaultOptions: {
+ 'focus': false,
+ 'toolbar': [
+ ['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',
+ 'colors': summernoteCustomColors,
+ recordInfo: {
+ context: {},
+ },
+ },
+ /**
+ * @options {Object} options
+ * @options {Object} options.recordInfo
+ * @options {Object} options.recordInfo.context
+ * @options {String} [options.recordInfo.context]
+ * @options {integer} [options.recordInfo.res_id]
+ * @options {String} [options.recordInfo.data_res_model]
+ * @options {integer} [options.recordInfo.data_res_id]
+ * @see _onGetRecordInfo
+ * @see _getAttachmentsDomain in /wysiwyg/widgets/media.js
+ * @options {Object} options.attachments
+ * @see _onGetRecordInfo
+ * @see _getAttachmentsDomain in /wysiwyg/widgets/media.js (for attachmentIDs)
+ * @options {function} options.generateOptions
+ * called with the summernote configuration object used before sending to summernote
+ * @see _editorOptions
+ **/
+ init: function (parent, options) {
+ this._super.apply(this, arguments);
+ this.id = ++id;
+ this.options = options;
+ },
+ /**
+ * Load assets and color picker template then call summernote API
+ * and replace $el by the summernote editable node.
+ *
+ * @override
+ **/
+ willStart: function () {
+ this._summernoteManager = new SummernoteManager(this);
+ this.$target = this.$el;
+ return this._super();
+ },
+ /**
+ *
+ * @override
+ */
+ start: function () {
+ this.$target.wrap('<odoo-wysiwyg-container>');
+ this.$el = this.$target.parent();
+ var options = this._editorOptions();
+ this.$target.summernote(options);
+ this.$editor = this.$('.note-editable:first');
+ this.$editor.data('wysiwyg', this);
+ this.$editor.data('oe-model', options.recordInfo.res_model);
+ this.$editor.data('oe-id', options.recordInfo.res_id);
+ $(document).on('mousedown', this._blur);
+ this._value = this.$target.html() || this.$target.val();
+ return this._super.apply(this, arguments);
+ },
+ /**
+ * @override
+ */
+ destroy: function () {
+ $(document).off('mousedown', this._blur);
+ if (this.$target && this.$target.is('textarea') && this.$target.next('.note-editor').length) {
+ this.$target.summernote('destroy');
+ }
+ this._super();
+ },
+ //--------------------------------------------------------------------------
+ // Public
+ //--------------------------------------------------------------------------
+ /**
+ * Return the editable area.
+ *
+ * @returns {jQuery}
+ */
+ getEditable: function () {
+ return this.$editor;
+ },
+ /**
+ * Return true if the content has changed.
+ *
+ * @returns {Boolean}
+ */
+ isDirty: function () {
+ return this._value !== (this.$editor.html() || this.$editor.val());
+ },
+ /**
+ * Set the focus on the element.
+ */
+ focus: function () {
+ console.log('focus');
+ },
+ /**
+ * Get the value of the editable element.
+ *
+ * @param {object} [options]
+ * @param {jQueryElement} [options.$layout]
+ * @returns {String}
+ */
+ getValue: function (options) {
+ var $editable = options && options.$layout || this.$editor.clone();
+ $editable.find('[contenteditable]').removeAttr('contenteditable');
+ $editable.find('[class=""]').removeAttr('class');
+ $editable.find('[style=""]').removeAttr('style');
+ $editable.find('[title=""]').removeAttr('title');
+ $editable.find('[alt=""]').removeAttr('alt');
+ $editable.find('[data-original-title=""]').removeAttr('data-original-title');
+ if (!options || !options['style-inline']) {
+ $editable.find('a.o_image, span.fa, i.fa').html('');
+ }
+ $editable.find('[aria-describedby]').removeAttr('aria-describedby').removeAttr('data-original-title');
+ return $editable.html();
+ },
+ /**
+ * Save the content in the target
+ * - in init option beforeSave
+ * - receive editable jQuery DOM as attribute
+ * - called after deactivate codeview if needed
+ * @returns {Promise}
+ * - resolve with true if the content was dirty
+ */
+ save: function (options) {
+ var isDirty = this.isDirty();
+ var html = this.getValue(options);
+ if (this.$target.is('textarea')) {
+ this.$target.val(html);
+ } else {
+ this.$target.html(html);
+ }
+ return Promise.resolve({isDirty:isDirty, html:html});
+ },
+ /**
+ * Create/Update cropped attachments.
+ *
+ * @param {jQuery} $editable
+ * @returns {Promise}
+ */
+ saveModifiedImages: function ($editable) {
+ return this._summernoteManager.saveModifiedImages($editable);
+ },
+ /**
+ * @param {String} value
+ * @param {Object} options
+ * @param {Boolean} [options.notifyChange]
+ * @returns {String}
+ */
+ setValue: function (value, options) {
+ if (this.$editor.is('textarea')) {
+ this.$target.val(value);
+ } else {
+ this.$target.html(value);
+ }
+ this.$editor.html(value);
+ },
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+ _editorOptions: function () {
+ var self = this;
+ var options = Object.assign({}, $.summernote.options, this.defaultOptions, this.options);
+ if (this.options.generateOptions) {
+ options = this.options.generateOptions(options);
+ }
+ options.airPopover = options.toolbar;
+ options.onChange = function (html, $editable) {
+ $editable.trigger('content_changed');
+ self.trigger_up('wysiwyg_change');
+ };
+ options.onUpload = function (attachments) {
+ self.trigger_up('wysiwyg_attachment', attachments);
+ };
+ options.onFocus = function () {
+ self.trigger_up('wysiwyg_focus');
+ };
+ options.onBlur = function () {
+ self.trigger_up('wysiwyg_blur');
+ };
+ return options;
+ },
+});
+//--------------------------------------------------------------------------
+// Public helper
+//--------------------------------------------------------------------------
+/**
+ * @param {Node} node (editable or node inside)
+ * @returns {Object}
+ * @returns {Node} sc - start container
+ * @returns {Number} so - start offset
+ * @returns {Node} ec - end container
+ * @returns {Number} eo - end offset
+ */
+Wysiwyg.getRange = function (node) {
+ var range = $.summernote.core.range.create();
+ return range && {
+ sc: range.sc,
+ so: range.so,
+ ec: range.ec,
+ eo: range.eo,
+ };
+};
+/**
+ * @param {Node} startNode
+ * @param {Number} startOffset
+ * @param {Node} endNode
+ * @param {Number} endOffset
+ */
+Wysiwyg.setRange = function (startNode, startOffset, endNode, endOffset) {
+ $(startNode).focus();
+ if (endNode) {
+ $.summernote.core.range.create(startNode, startOffset, endNode, endOffset).select();
+ } else {
+ $.summernote.core.range.create(startNode, startOffset).select();
+ }
+ // trigger for Unbreakable
+ $(startNode.tagName ? startNode : startNode.parentNode).trigger('wysiwyg.range');
+};
+/**
+ * @param {Node} node - dom node
+ * @param {Object} [options]
+ * @param {Boolean} options.begin move the range to the beginning of the first node.
+ * @param {Boolean} options.end move the range to the end of the last node.
+ */
+Wysiwyg.setRangeFromNode = function (node, options) {
+ var last = node;
+ while (last.lastChild) {
+ last = last.lastChild;
+ }
+ var first = node;
+ while (first.firstChild) {
+ first = first.firstChild;
+ }
+ if (options && options.begin && !options.end) {
+ Wysiwyg.setRange(first, 0);
+ } else if (options && !options.begin && options.end) {
+ Wysiwyg.setRange(last, last.textContent.length);
+ } else {
+ Wysiwyg.setRange(first, 0, last, last.tagName ? last.childNodes.length : last.textContent.length);
+ }
+};
+return Wysiwyg;
+});
+odoo.define('web_editor.widget', function (require) {
+'use strict';
+ return {
+ Dialog: require('wysiwyg.widgets.Dialog'),
+ MediaDialog: require('wysiwyg.widgets.MediaDialog'),
+ LinkDialog: require('wysiwyg.widgets.LinkDialog'),
+ };
+});