odoo.define('web_editor.backend', function (require) { 'use strict'; var AbstractField = require('web.AbstractField'); var basic_fields = require('web.basic_fields'); var config = require('web.config'); var core = require('web.core'); var session = require('web.session'); var field_registry = require('web.field_registry'); var SummernoteManager = require('web_editor.rte.summernote'); var transcoder = require('web_editor.transcoder'); var TranslatableFieldMixin = basic_fields.TranslatableFieldMixin; var QWeb = core.qweb; var _t = core._t; /** * FieldTextHtmlSimple Widget * Intended to display HTML content. This widget uses the summernote editor * improved by odoo. * */ var FieldTextHtmlSimple = basic_fields.DebouncedField.extend(TranslatableFieldMixin, { className: 'oe_form_field oe_form_field_html_text', supportedFieldTypes: ['html'], /** * @override */ start: function () { new SummernoteManager(this); return this._super.apply(this, arguments); }, //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- /** * Summernote doesn't notify for changes done in code mode. We override * commitChanges to manually switch back to normal mode before committing * changes, so that the widget is aware of the changes done in code mode. * * @override */ commitChanges: function () { // switch to WYSIWYG mode if currently in code mode to get all changes if (config.debug && this.mode === 'edit') { var layoutInfo = this.$textarea.data('layoutInfo'); $.summernote.pluginEvents.codeview(undefined, undefined, layoutInfo, false); } if (this._getValue() !== this.value) { this._isDirty = true; } this._super.apply(this, arguments); }, /** * @override */ isSet: function () { return this.value && this.value !== "


" && this.value.match(/\S/); }, /** * @override */ getFocusableElement: function () { return this.$content || this._super.apply(this, arguments); }, /** * Do not re-render this field if it was the origin of the onchange call. * * @override */ reset: function (record, event) { this._reset(record, event); if (!event || event.target !== this) { if (this.mode === 'edit') { this.$content.html(this._textToHtml(this.value)); } else { this._renderReadonly(); } } return $.when(); }, //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- /** * Returns the domain for attachments used in media dialog. * We look for attachments related to the current document. If there is a value for the model * field, it is used to search attachments, and the attachments from the current document are * filtered to display only user-created documents. * In the case of a wizard such as mail, we have the documents uploaded and those of the model * * @private * @returns {Array} "ir.attachment" odoo domain. */ _getAttachmentsDomain: function () { var domain = ['|', ['id', 'in', _.pluck(this.attachments, 'id')]]; var attachedDocumentDomain = [ '&', ['res_model', '=', this.model], ['res_id', '=', this.res_id|0] ]; // if the document is not yet created, do not see the documents of other users if (!this.res_id) { attachedDocumentDomain.unshift('&'); attachedDocumentDomain.push(['create_uid', '=', session.uid]); } if (this.recordData.res_model || this.recordData.model) { var relatedDomain = ['&', ['res_model', '=', this.recordData.res_model || this.recordData.model], ['res_id', '=', this.recordData.res_id|0]]; if (!this.recordData.res_id) { relatedDomain.unshift('&'); relatedDomain.push(['create_uid', '=', session.uid]); } domain = domain.concat(['|'], attachedDocumentDomain, relatedDomain); } else { domain = domain.concat(attachedDocumentDomain); } return domain; }, /** * @private * @returns {Object} the summernote configuration */ _getSummernoteConfig: function () { var summernoteConfig = { model: this.model, id: this.res_id, focus: false, height: 180, toolbar: [ ['style', ['style']], ['font', ['bold', 'italic', 'underline', 'clear']], ['fontsize', ['fontsize']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph']], ['table', ['table']], ['insert', this.nodeOptions['no-attachment'] ? ['link'] : ['link', 'picture']], ['history', ['undo', 'redo']] ], prettifyHtml: false, styleWithSpan: false, inlinemedia: ['p'], lang: "odoo", onChange: this._doDebouncedAction.bind(this), disableDragAndDrop: !!this.nodeOptions['no-attachment'], }; var fieldNameAttachment =_.chain(this.recordData) .pairs() .find(function (value) { return _.isObject(value[1]) && value[1].model === "ir.attachment"; }) .first() .value(); if (fieldNameAttachment) { this.fieldNameAttachment = fieldNameAttachment; this.attachments = []; summernoteConfig.onUpload = this._onUpload.bind(this); } summernoteConfig.getMediaDomain = this._getAttachmentsDomain.bind(this); if (config.debug) { summernoteConfig.toolbar.splice(7, 0, ['view', ['codeview']]); } return summernoteConfig; }, /** * @override * @private */ _getValue: function () { if (this.nodeOptions['style-inline']) { transcoder.attachmentThumbnailToLinkImg(this.$content); transcoder.fontToImg(this.$content); transcoder.classToStyle(this.$content); } return this.$content.html(); }, /** * trigger_up 'field_changed' add record into the "ir.attachment" field found in the view. * This method is called when an image is uploaded by the media dialog. * * For e.g. when sending email, this allows people to add attachments with the content * editor interface and that they appear in the attachment list. * The new documents being attached to the email, they will not be erased by the CRON * when closing the wizard. * * @private */ _onUpload: function (attachments) { var self = this; attachments = _.filter(attachments, function (attachment) { return !_.findWhere(self.attachments, {id: attachment.id}); }); if (!attachments.length) { return; } this.attachments = this.attachments.concat(attachments); this.trigger_up('field_changed', { dataPointID: this.dataPointID, changes: _.object([this.fieldNameAttachment], [{ operation: 'ADD_M2M', ids: attachments }]) }); }, /** * @override * @private */ _renderEdit: function () { this.$textarea = $('