[IMP] website, web_editor: improve startup time of website editor

By starting the get_switchable_related_views request when the
WysiwygAdapter is started, and awaiting it only when we need to know,
we can improve the initial loading time of the editor.

See merge commit for more information.

task-2687506
This commit is contained in:
Arthur Detroux (ard)
2022-06-24 10:28:07 +02:00
committed by qsm-odoo
parent ac4c61bd87
commit 69af7dcfeb
7 changed files with 107 additions and 52 deletions
@@ -821,7 +821,7 @@ var SnippetEditor = Widget.extend({
this.$el.find('[data-toggle="dropdown"]').dropdown();
return Promise.all(defs).then(() => {
return Promise.all(defs).then(async () => {
const options = _.sortBy(this.styles, '__order');
const firstOptions = [];
options.forEach(option => {
@@ -2988,18 +2988,7 @@ var SnippetsMenu = Widget.extend({
if (!ev.currentTarget.classList.contains('active')) {
this._activateSnippet(false);
this._mutex.exec(() => {
let $pageOptionsTarget = $();
let i = 0;
const pageOptions = this.templateOptions.filter(template => template.data.pageOptions);
while (!$pageOptionsTarget.length && i < pageOptions.length) {
$pageOptionsTarget = pageOptions[i].selector.all();
i++;
}
if ($pageOptionsTarget.length) {
this._activateSnippet($pageOptionsTarget);
} else {
this._activateEmptyOptionsTab();
}
this._activateEmptyOptionsTab();
});
}
},
@@ -49,6 +49,13 @@ export class WysiwygAdapterComponent extends ComponentAdapter {
this.pageOptions[optionName] = new PageOption(pageOptionEl, this.websiteService.pageDocument, optionName);
}
this.editableElements(this.$editable).addClass('o_editable');
let switchableRelatedViews = [];
const viewKey = this.websiteService.pageDocument.documentElement.dataset.viewXmlid;
if (this.websiteService.isDesigner && viewKey) {
switchableRelatedViews = this.rpc('/website/get_switchable_related_views', {key: viewKey});
}
this.switchableRelatedViews = Promise.resolve(switchableRelatedViews);
});
useEffect(() => {
@@ -667,6 +674,18 @@ export class WysiwygAdapterComponent extends ComponentAdapter {
_onMobilePreviewRequest() {
this.websiteService.context.isMobile = !this.websiteService.context.isMobile;
}
/**
* Called when a child needs to know about the views that can
* be toggled on or off on a specific view related to the editable.
*
* @param event
* @returns {Promise<void>}
* @private
*/
async _onGetSwitchableRelatedViews(event) {
const views = await this.switchableRelatedViews;
event.data.onSuccess(views);
}
}
WysiwygAdapterComponent.prototype.events = {
'widgets_start_request': '_onRootEventRequest',
@@ -684,4 +703,5 @@ WysiwygAdapterComponent.prototype.events = {
'menu_dialog': '_onMenuDialogRequest',
'update_color_previews': '_onColorPreviewsUpdate',
'request_mobile_preview': '_onMobilePreviewRequest',
'get_switchable_related_views': '_onGetSwitchableRelatedViews',
};
@@ -54,43 +54,6 @@ const wSnippetMenu = weSnippetEditor.SnippetsMenu.extend({
this.$body[0].classList.remove('o_animated_text_highlighted');
},
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
/**
* Adds the "customize_show" templates to the options page of the editor
* panel.
*
* @override
*/
async loadSnippets() {
const viewName = $(this.options.wysiwyg.odooEditor.document.documentElement).data('view-xmlid');
const snippets = await this._super(...arguments);
if (!viewName) {
return snippets;
}
const $snippets = $(snippets);
return this._rpc({
route: '/website/get_switchable_related_views',
params: {
key: viewName,
},
}).then(function (result) {
_.each(result, view => {
$snippets.siblings('#snippet_options').append($(`
<div data-selector="#wrapwrap > main" data-page-options="true" data-no-check="true">
<we-checkbox string="${view.name}"
data-customize-website-views="${view.key}"
data-no-preview="true"
data-reload="/"/>
</div>
`));
});
return $('<div>').append($snippets).html();
});
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -356,6 +319,40 @@ const wSnippetMenu = weSnippetEditor.SnippetsMenu.extend({
throw e;
}
},
/**
* @override
*/
_onOptionsTabClick(ev) {
if (!ev.currentTarget.classList.contains('active')) {
this._activateSnippet(false);
this._mutex.exec(async () => {
const switchableViews = await new Promise((resolve, reject) => {
this.trigger_up('get_switchable_related_views', {
onSuccess: resolve,
onFailure: reject,
});
});
if (switchableViews.length) {
// These do not need to be awaited as we're in teh context
// of the mutex.
this._activateSnippet(this.$body.find('#wrapwrap > main'));
return;
}
let $pageOptionsTarget = $();
let i = 0;
const pageOptions = this.templateOptions.filter(template => template.data.pageOptions);
while (!$pageOptionsTarget.length && i < pageOptions.length) {
$pageOptionsTarget = pageOptions[i].selector.all();
i++;
}
if ($pageOptionsTarget.length) {
this._activateSnippet($pageOptionsTarget);
} else {
this._activateEmptyOptionsTab();
}
});
}
},
/**
* @private
*/
@@ -3235,6 +3235,47 @@ options.registry.sizing.include({
}
});
options.registry.SwitchableViews = options.Class.extend({
/**
* @override
*/
async willStart() {
const _super = this._super.bind(this);
this.switchableRelatedViews = await new Promise((resolve, reject) => {
this.trigger_up('get_switchable_related_views', {
onSuccess: resolve,
onFailure: reject,
});
});
return _super(...arguments);
},
/**
* @override
*/
_renderCustomXML(uiFragment) {
for (const view of this.switchableRelatedViews) {
const weCheckboxEl = document.createElement('we-checkbox');
weCheckboxEl.setAttribute('string', view.name);
weCheckboxEl.setAttribute('data-customize-website-views', view.key);
weCheckboxEl.setAttribute('data-no-preview', 'true');
weCheckboxEl.setAttribute('data-reload', '/');
uiFragment.appendChild(weCheckboxEl);
}
},
/***
* @override
*/
_computeVisibility() {
return !!this.switchableRelatedViews.length;
},
/**
* @override
*/
_checkIfWidgetsUpdateNeedReload() {
return true;
}
});
return {
UrlPickerUserValueWidget: UrlPickerUserValueWidget,
FontFamilyPickerUserValueWidget: FontFamilyPickerUserValueWidget,
@@ -35,6 +35,7 @@ export const websiteService = {
let websiteRootInstance;
let Wysiwyg;
let isPublisher;
let isDesigner;
let hasMultiWebsites;
const context = reactive({
showNewContentModal: false,
@@ -125,6 +126,9 @@ export const websiteService = {
get isPublisher() {
return isPublisher === true;
},
get isDesigner() {
return isDesigner === true;
},
get hasMultiWebsites() {
return hasMultiWebsites === true;
},
@@ -146,8 +150,9 @@ export const websiteService = {
},
async fetchWebsites() {
// Fetch user groups, before fetching the websites.
[isPublisher, hasMultiWebsites] = await Promise.all([
[isPublisher, isDesigner, hasMultiWebsites] = await Promise.all([
user.hasGroup('website.group_website_publisher'),
user.hasGroup('website.group_website_designer'),
user.hasGroup('website.group_multi_website'),
]);
@@ -22,7 +22,7 @@ wTourUtils.registerEditionTour('snippet_popup_add_remove', {
}, {
content: `Remove the s_popup snippet`,
in_modal: false,
trigger: '.o_we_customize_panel we-customizeblock-options we-button.oe_snippet_remove:first',
trigger: '.o_we_customize_panel we-customizeblock-options:contains("Popup") we-button.oe_snippet_remove:first',
}, {
content: 'Check the s_popup was removed',
in_modal: false,
@@ -1463,5 +1463,8 @@
data-no-preview="true"
data-reload="/"/>
</div>
<div data-selector="#wrapwrap > main" data-no-check="true" data-js="SwitchableViews">
<!-- Options will be populated by JS -->
</div>
</template>
</odoo>