odoo.define('pad.pad', function (require) { "use strict"; var AbstractField = require('web.AbstractField'); var core = require('web.core'); var fieldRegistry = require('web.field_registry'); var _t = core._t; var FieldPad = AbstractField.extend({ template: 'FieldPad', content: "", events: { 'click .oe_pad_switch': '_onToggleFullScreen', }, /** * @override */ willStart: function () { if (this.isPadConfigured === undefined) { return this._rpc({ method: 'pad_is_configured', model: this.model, }).then(function (result) { // we write on the prototype to share the information between // all pad widgets instances, across all actions FieldPad.prototype.isPadConfigured = result; }); } return this._super.apply(this, arguments); }, /** * @override */ start: function () { if (!this.isPadConfigured) { this.$(".oe_unconfigured").removeClass('d-none'); this.$(".oe_configured").addClass('d-none'); return Promise.resolve(); } if (this.mode === 'edit' && typeof(this.value) === 'object') { this.value = this.value.toJSON(); } if (this.mode === 'edit' && _.str.startsWith(this.value, 'http')) { this.url = this.value; // please close your eyes and look elsewhere... // Since the pad value (the url) will not change during the edition // process, we have a problem: the description field will not be // properly updated. We need to explicitely write the value each // time someone edit the record in order to force the server to read // the updated value of the pad and put it in the description field. // // However, the basic model optimizes away the changes if they are // not really different from the current value. So, we need to // either add special configuration options to the basic model, or // to trick him into accepting the same value as being different... // Guess what we decided... var url = {}; url.toJSON = _.constant(this.url); this._setValue(url, {doNotSetDirty: true}); } return this._super.apply(this, arguments); }, //-------------------------------------------------------------------------- // Public //-------------------------------------------------------------------------- /** * If we had to generate an url, we wait for the generation to be completed, * so the current record will be associated with the correct pad url. * * @override */ commitChanges: function () { return this.urlDef; }, /** * @override */ isSet: function () { return true; }, //-------------------------------------------------------------------------- // Private //-------------------------------------------------------------------------- /** * Note that this method has some serious side effects: performing rpcs and * setting the value of this field. This is not conventional and should not * be copied in other code, unless really necessary. * * @override * @private */ _renderEdit: function () { if (this.url) { // here, we have a valid url, so we can simply display an iframe // with the correct src attribute var userName = encodeURIComponent(this.getSession().name); var url = this.url + '?showChat=false&userName=' + userName; var content = ''; this.$('.oe_pad_content').html(content); } else if (this.value) { // it looks like the field does not contain a valid url, so we just // display it (it cannot be edited in that case) this.$('.oe_pad_content').text(this.value); } else { // It is totally discouraged to have a render method that does // non-rendering work, especially since the work in question // involves doing RPCs and changing the value of the field. // However, this is kind of necessary in this case, because the // value of the field is actually only the url of the pad. The // actual content will be loaded in an iframe. We could do this // work in the basic model, but the basic model does not know that // this widget is in edit or readonly, and we really do not want to // create a pad url everytime a task without a pad is viewed. var self = this; this.urlDef = this._rpc({ method: 'pad_generate_url', model: this.model, context: { model: this.model, field_name: this.name, object_id: this.res_id, record: this.recordData, }, }, { shadow: true }).then(function (result) { // We need to write the url of the pad to trigger // the write function which updates the actual value // of the field to the value of the pad content self.url = result.url; self._setValue(result.url, {doNotSetDirty: true}); }); } }, /** * @override * @private */ _renderReadonly: function () { if (_.str.startsWith(this.value, 'http')) { var self = this; this.$('.oe_pad_content') .addClass('oe_pad_loading') .text(_t("Loading")); this._rpc({ method: 'pad_get_content', model: this.model, args: [this.value] }, { shadow: true }).then(function (data) { self.$('.oe_pad_content') .removeClass('oe_pad_loading') .html('
'); self.$('.oe_pad_readonly').html(data); }).guardedCatch(function () { self.$('.oe_pad_content').text(_t('Unable to load pad')); }); } else { this.$('.oe_pad_content') .addClass('oe_pad_loading') .show() .text(_t("This pad will be initialized on first edit")); } }, //-------------------------------------------------------------------------- // Handlers //-------------------------------------------------------------------------- /** * @override * @private */ _onToggleFullScreen: function () { this.$el.toggleClass('oe_pad_fullscreen mb0'); this.$('.oe_pad_switch').toggleClass('fa-expand fa-compress'); this.$el.parents('.o_touch_device').toggleClass('o_scroll_hidden'); }, }); fieldRegistry.add('pad', FieldPad); return FieldPad; });