text: odoo.define('website.editor.menu', function (require) {
  'use strict';
  
  var Dialog = require('web.Dialog');
  var dom = require('web.dom');
  var Widget = require('web.Widget');
  var core = require('web.core');
  var Wysiwyg = require('web_editor.wysiwyg.root');
  
  var _t = core._t;
  
  var WysiwygMultizone = Wysiwyg.extend({
      assetLibs: Wysiwyg.prototype.assetLibs.concat(['website.compiled_assets_wysiwyg']),
      _getWysiwygContructor: function () {
          return odoo.__DEBUG__.services['web_editor.wysiwyg.multizone'];
      }
  });
  
  var EditorMenu = Widget.extend({
      template: 'website.editorbar',
      xmlDependencies: ['/website/static/src/xml/website.editor.xml'],
      events: {
          'click button[data-action=undo]': '_onUndoClick',
          'click button[data-action=redo]': '_onRedoClick',
          'click button[data-action=save]': '_onSaveClick',
          'click button[data-action=cancel]': '_onCancelClick',
      },
      custom_events: {
          request_save: '_onSnippetRequestSave',
          get_clean_html: '_onGetCleanHTML',
      },
  
      /**
       * @override
       */
      willStart: function () {
          var self = this;
          this.$el = null; // temporary null to avoid hidden error (@see start)
          return this._super()
              .then(function () {
                  var $wrapwrap = $('#wrapwrap');
                  $wrapwrap.removeClass('o_editable'); // clean the dom before edition
                  self.editable($wrapwrap).addClass('o_editable');
                  self.wysiwyg = self._wysiwygInstance();
              });
      },
      /**
       * @override
       */
      start: function () {
          var self = this;
          this.$el.css({width: '100%'});
          return this.wysiwyg.attachTo($('#wrapwrap')).then(function () {
              self.trigger_up('edit_mode');
              self.$el.css({width: ''});
          });
      },
      /**
       * @override
       */
      destroy: function () {
          this.trigger_up('readonly_mode');
          this._super.apply(this, arguments);
      },
  
      //--------------------------------------------------------------------------
      // Public
      //--------------------------------------------------------------------------
  
      /**
       * Asks the user if they really wants to discard their changes (if any),
       * then simply reloads the page if they want to.
       *
       * @param {boolean} [reload=true]
       *        true if the page has to be reloaded when the user answers yes
       *        (do nothing otherwise but add this to allow class extension)
       * @returns {Deferred}
       */
      cancel: function (reload) {
          var self = this;
          var def = new Promise(function (resolve, reject) {
              if (!self.wysiwyg.isDirty()) {
                  resolve();
              } else {
                  var confirm = Dialog.confirm(self, _t("If you discard the current edits, all unsaved changes will be lost. You can cancel to return to edit mode."), {
                      confirm_callback: resolve,
                  });
                  confirm.on('closed', self, reject);
              }
          });
  
          return def.then(function () {
              self.trigger_up('edition_will_stopped');
              var $wrapwrap = $('#wrapwrap');
              self.editable($wrapwrap).removeClass('o_editable');
              if (reload !== false) {
                  window.onbeforeunload = null;
                  self.wysiwyg.destroy();
                  return self._reload();
              } else {
                  self.wysiwyg.destroy();
                  self.trigger_up('readonly_mode');
                  self.trigger_up('edition_was_stopped');
                  self.destroy();
              }
          });
      },
      /**
       * Asks the snippets to clean themself, then saves the page, then reloads it
       * if asked to.
       *
       * @param {boolean} [reload=true]
       *        true if the page has to be reloaded after the save
       * @returns {Promise}
       */
      save: async function (reload) {
          if (this._saving) {
              return false;
          }
          var self = this;
          this._saving = true;
          this.trigger_up('edition_will_stopped');
          return this.wysiwyg.save(false).then(function (result) {
              var $wrapwrap = $('#wrapwrap');
              self.editable($wrapwrap).removeClass('o_editable');
              if (result.isDirty && reload !== false) {
                  // remove top padding because the connected bar is not visible
                  $('body').removeClass('o_connected_user');
                  return self._reload();
              } else {
                  self.wysiwyg.destroy();
                  self.trigger_up('edition_was_stopped');
                  self.destroy();
              }
              return true;
          }).guardedCatch(() => {
              this._saving = false;
          });
      },
      /**
       * Returns the editable areas on the page.
       *
       * @param {DOM} $wrapwrap
       * @returns {jQuery}
       */
      editable: function ($wrapwrap) {
          return $wrapwrap.find('[data-oe-model]')
              .not('.o_not_editable')
              .filter(function () {
                  var $parent = $(this).closest('.o_editable, .o_not_editable');
                  return !$parent.length || $parent.hasClass('o_editable');
              })
              .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')
              .not('hr, br, input, textarea')
              .add('.o_editable');
      },
  
      //--------------------------------------------------------------------------
      // Private
      //--------------------------------------------------------------------------
  
      /**
       * @private
       */
      _wysiwygInstance: function () {
          var context;
          this.trigger_up('context_get', {
              callback: function (ctx) {
                  context = ctx;
              },
          });
          return new WysiwygMultizone(this, {
              snippets: 'website.snippets',
              recordInfo: {
                  context: context,
                  data_res_model: 'website',
                  data_res_id: context.website_id,
              }
          });
      },
      /**
       * Reloads the page in non-editable mode, with the right scrolling.
       *
       * @private
       * @returns {Deferred} (never resolved, the page is reloading anyway)
       */
      _reload: function () {
          $('body').addClass('o_wait_reload');
          this.wysiwyg.destroy();
          this.$el.hide();
          window.location.hash = 'scrollTop=' + window.document.body.scrollTop;
          window.location.reload(true);
          return new Promise(function () {});
      },
  
      //--------------------------------------------------------------------------
      // Handlers
      //--------------------------------------------------------------------------
  
      /**
       * Called when the "Discard" button is clicked -> discards the changes.
       *
       * @private
       */
      _onCancelClick: function () {
          this.cancel(true);
      },
      /**
       * Get the cleaned value of the editable element.
       *
       * @private
       * @param {OdooEvent} ev
       */
      _onGetCleanHTML: function (ev) {
          ev.data.callback(this.wysiwyg.getValue({$layout: ev.data.$layout}));
      },
      /**
       * Snippet (menu_data) can request to save the document to leave the page
       *
       * @private
       * @param {OdooEvent} ev
       * @param {object} ev.data
       * @param {function} ev.data.onSuccess
       * @param {function} ev.data.onFailure
       */
      _onSnippetRequestSave: function (ev) {
          this.save(false).then(ev.data.onSuccess, ev.data.onFailure);
      },
      /**
       * Called when the "Save" button is clicked -> saves the changes.
       *
       * @private
       */
      _onSaveClick: function (ev) {
          const restore = dom.addButtonLoadingEffect(ev.currentTarget);
          this.save().then(restore).guardedCatch(restore);
      },
      /**
       * @private
       */
      _onUndoClick() {
          $('.note-history [data-event=undo]').first().click();
      },
      /**
       * @private
       */
      _onRedoClick() {
          $('.note-history [data-event=redo]').first().click();
      },
  });
  
  return EditorMenu;
  });
  