Skip to content

fix tour test_link_to_document #4767

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
21 changes: 18 additions & 3 deletions addons/html_builder/static/src/core/core_builder_action_plugin.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { Plugin } from "@html_editor/plugin";
import { CSS_SHORTHANDS, applyNeededCss, areCssValuesEqual } from "@html_builder/utils/utils_css";
import {
CSS_SHORTHANDS,
applyNeededCss,
areCssValuesEqual,
normalizeColor,
} from "@html_builder/utils/utils_css";

export function withoutTransition(editingElement, callback) {
if (editingElement.classList.contains("o_we_force_no_transition")) {
@@ -263,17 +268,27 @@ const attributeAction = {
};

const dataAttributeAction = {
getValue: ({ editingElement, params: { mainParam: attributeName } = {} }) =>
editingElement.dataset[attributeName],
// if it's a color action, we have to normalize the value
getValue: ({ editingElement, params: { mainParam: attributeName } = {} }) => {
if (!/(^color|Color)($|(?=[A-Z]))/.test(attributeName)) {
return editingElement.dataset[attributeName];
}
const color = normalizeColor(editingElement.dataset[attributeName]);
return color;
},
isApplied: ({ editingElement, params: { mainParam: attributeName } = {}, value }) => {
if (value) {
const match = value.match(/^var\(--(.*)\)$/);
value = match ? match[1] : value;
return editingElement.dataset[attributeName] === value;
} else {
return !(attributeName in editingElement.dataset);
}
},
apply: ({ editingElement, params: { mainParam: attributeName } = {}, value }) => {
if (value) {
const match = value.match(/^var\(--(.*)\)$/);
value = match ? match[1] : value;
editingElement.dataset[attributeName] = value;
} else {
delete editingElement.dataset[attributeName];
3 changes: 2 additions & 1 deletion addons/html_builder/static/src/core/setup_editor_plugin.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { Plugin } from "@html_editor/plugin";
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { withSequence } from "@html_editor/utils/resource";

export class SetupEditorPlugin extends Plugin {
static id = "setup_editor_plugin";
static shared = ["getEditableAreas"];
resources = {
clean_for_save_handlers: this.cleanForSave.bind(this),
normalize_handlers: this.setContenteditable.bind(this),
normalize_handlers: withSequence(0, this.setContenteditable.bind(this)),
};

setup() {
7 changes: 5 additions & 2 deletions addons/html_builder/static/src/snippets/snippet_viewer.js
Original file line number Diff line number Diff line change
@@ -109,9 +109,12 @@ export class SnippetViewer extends Component {
}
if (this.props.state.search) {
const strMatches = (str) =>
str.toLowerCase().includes(this.props.state.search.toLowerCase());
str ? str.toLowerCase().includes(this.props.state.search.toLowerCase()) : false;
return snippetStructures.filter(
(snippet) => strMatches(snippet.title) || strMatches(snippet.keyWords || "")
(snippet) =>
strMatches(snippet.name) ||
strMatches(snippet.title) ||
strMatches(snippet.keyWords)
);
}

8 changes: 5 additions & 3 deletions addons/html_editor/static/src/main/font/color_plugin.js
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ import {
rgbaToHex,
COLOR_COMBINATION_CLASSES_REGEX,
} from "@web/core/utils/colors";
import { backgroundImageCssToParts } from "@html_editor/utils/image";
import { ColorSelector } from "./color_selector";

const RGBA_OPACITY = 0.6;
@@ -136,7 +137,8 @@ export class ColorPlugin extends Plugin {
getElementColors(el) {
const elStyle = getComputedStyle(el);
const backgroundImage = elStyle.backgroundImage;
const hasGradient = isColorGradient(backgroundImage);
const gradient = backgroundImageCssToParts(backgroundImage).gradient;
const hasGradient = isColorGradient(gradient);
const hasTextGradientClass = el.classList.contains("text-gradient");

let backgroundColor = elStyle.backgroundColor;
@@ -155,9 +157,9 @@ export class ColorPlugin extends Plugin {
}

return {
color: hasGradient && hasTextGradientClass ? backgroundImage : rgbaToHex(elStyle.color),
color: hasGradient && hasTextGradientClass ? gradient : rgbaToHex(elStyle.color),
backgroundColor:
hasGradient && !hasTextGradientClass ? backgroundImage : rgbaToHex(backgroundColor),
hasGradient && !hasTextGradientClass ? gradient : rgbaToHex(backgroundColor),
};
}

1 change: 0 additions & 1 deletion addons/html_editor/static/src/main/link/link_popover.js
Original file line number Diff line number Diff line change
@@ -215,7 +215,6 @@ export class LinkPopover extends Component {
this.state.url = deducedUrl
? this.correctLink(deducedUrl)
: this.correctLink(this.state.url);
this.loadAsyncLinkPreview();
}
onClickEdit() {
this.state.editing = true;
8 changes: 4 additions & 4 deletions addons/html_editor/static/src/main/media/image_crop_plugin.js
Original file line number Diff line number Diff line change
@@ -42,10 +42,10 @@ export class ImageCropPlugin extends Plugin {
onSave: async (newDataset) => {
// todo: should use the mutex if there is one?
const updateImageAttributes =
await this.dependencies.imagePostProcess.processImage(
selectedImg,
newDataset
);
await this.dependencies.imagePostProcess.processImage({
img: selectedImg,
newDataset,
});
updateImageAttributes();
this.dependencies.history.addStep();
},
Original file line number Diff line number Diff line change
@@ -24,14 +24,21 @@ export class ImagePostProcessPlugin extends Plugin {
*
* @param {HTMLImageElement} img the image to which modifications are applied
* @param {Object} newDataset an object containing the modifications to apply
* @param {Function} [onImageInfoLoaded] can be used to fill
* newDataset after having access to image info, return true to cancel call
* @returns {Function} callback that sets dataURL of the image with the
* applied modifications to `img` element
*/
async processImage(img, newDataset = {}) {
async processImage({ img, newDataset = {}, onImageInfoLoaded }) {
const processContext = {};
if (!newDataset.originalSrc || !newDataset.mimetypeBeforeConversion) {
Object.assign(newDataset, await loadImageInfo(img));
}
if (onImageInfoLoaded) {
if (await onImageInfoLoaded(newDataset)) {
return () => {};
}
}
for (const cb of this.getResource("process_image_warmup_handlers")) {
const addedContext = await cb(img, newDataset);
if (addedContext) {
Original file line number Diff line number Diff line change
@@ -94,7 +94,7 @@ export class ImageSelector extends FileSelector {

this.fileMimetypes = IMAGE_MIMETYPES.join(",");
this.isImageField =
!!this.props.media?.closest("[data-oe-type=image]") || !!this.env.addFieldImage;
!!this.props.media?.closest("[data-oe-type=image]") || !!this.props.addFieldImage;
}

get canLoadMore() {
Original file line number Diff line number Diff line change
@@ -133,6 +133,7 @@ export class MediaDialog extends Component {
this.addTab(TABS.IMAGES, {
useMediaLibrary: this.props.useMediaLibrary,
multiSelect: this.props.multiImages,
addFieldImage: this.props.addFieldImage,
});
}
if (!noIcons) {
22 changes: 16 additions & 6 deletions addons/html_editor/static/src/main/media/media_plugin.js
Original file line number Diff line number Diff line change
@@ -126,13 +126,12 @@ export class MediaPlugin extends Plugin {
}
}

onSaveMediaDialog(element, { node }) {
async onSaveMediaDialog(element, { node }) {
if (!element) {
// @todo @phoenix to remove
throw new Error("Element is required: onSaveMediaDialog");
// return;
}

if (node) {
const changedIcon = isIconElement(node) && isIconElement(element);
if (changedIcon) {
@@ -151,11 +150,25 @@ export class MediaPlugin extends Plugin {
// Collapse selection after the inserted/replaced element.
const [anchorNode, anchorOffset] = rightPos(element);
this.dependencies.selection.setSelection({ anchorNode, anchorOffset });
this.delegateTo("afer_save_media_dialog_handlers", element);
this.delegateTo("after_save_media_dialog_handlers", element);
this.dependencies.history.addStep();
}

openMediaDialog(params = {}, editableEl = null) {
const oldSave =
params.save || ((element) => this.onSaveMediaDialog(element, { node: params.node }));
params.save = async (...args) => {
const selection = args[0];
const elements = selection
? selection[Symbol.iterator]
? selection
: [selection]
: [];
for (const onMediaDialogSaved of this.getResource("on_media_dialog_saved_handlers")) {
await onMediaDialogSaved(elements, { node: params.node });
}
return oldSave(...args);
};
const { resModel, resId, field, type } = this.getRecordInfo(editableEl);
const mediaDialogClosedPromise = this.dependencies.dialog.addDialog(MediaDialog, {
resModel,
@@ -165,9 +178,6 @@ export class MediaPlugin extends Plugin {
((resModel === "ir.ui.view" && field === "arch") || type === "html")
), // @todo @phoenix: should be removed and moved to config.mediaModalParams
media: params.node,
save: (element) => {
this.onSaveMediaDialog(element, { node: params.node });
},
onAttachmentChange: this.config.onAttachmentChange || (() => {}),
noVideos: !this.config.allowMediaDialogVideo,
noImages: !this.config.allowImage,
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ export class CaptionPlugin extends Plugin {
clean_for_save_handlers: this.cleanForSave.bind(this),
mount_component_handlers: this.setupNewCaption.bind(this),
delete_image_handlers: this.handleDeleteImage.bind(this),
afer_save_media_dialog_handlers: this.onImageReplaced.bind(this),
after_save_media_dialog_handlers: this.onImageReplaced.bind(this),
hints: [{ selector: "FIGCAPTION", text: _t("Write a caption...") }],
unsplittable_node_predicates: [
(node) => ["FIGURE", "FIGCAPTION"].includes(node.nodeName), // avoid merge
12 changes: 6 additions & 6 deletions addons/test_website/static/tests/tours/image_upload_progress.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { insertSnippet, registerWebsitePreviewTour } from "@website/js/tours/tour_utils";

import { FileSelectorControlPanel } from "@web_editor/components/media_dialog/file_selector";
import { FileSelectorControlPanel } from "@html_editor/main/media/media_dialog/file_selector";
import { patch } from "@web/core/utils/patch";

let patchWithError = false;
@@ -72,7 +72,7 @@ registerWebsitePreviewTour('test_image_upload_progress', {
run: "click",
}, {
content: "click on add images to open image dialog (in multi mode)",
trigger: 'we-customizeblock-option [data-add-images]',
trigger: "button[data-action-id='addImage']",
run: "click",
}, {
content: "manually trigger input change",
@@ -123,7 +123,7 @@ registerWebsitePreviewTour('test_image_upload_progress', {
run: "click",
}, {
content: "click on replace media to open image dialog",
trigger: 'we-customizeblock-option [data-replace-media]',
trigger: "button[data-action-id='replaceMedia']",
run: "click",
}, {
content: "manually trigger input change",
@@ -162,7 +162,7 @@ registerWebsitePreviewTour('test_image_upload_progress', {
run: "click",
}, {
content: "click on replace media to open image dialog",
trigger: 'we-customizeblock-option [data-replace-media]',
trigger: "button[data-action-id='replaceMedia']",
run: "click",
}, {
content: "manually trigger input change",
@@ -206,7 +206,7 @@ registerWebsitePreviewTour('test_image_upload_progress_unsplash', {
run: "click",
}, {
content: "click on replace media to open image dialog",
trigger: 'we-customizeblock-option [data-replace-media]',
trigger: "button[data-action-id='replaceMedia']",
run: "click",
}, {
content: "search 'fox' images",
@@ -230,7 +230,7 @@ registerWebsitePreviewTour('test_image_upload_progress_unsplash', {
run: "click",
}, {
content: "unsplash image (mocked to logo) should have been used",
trigger: ":iframe #wrap .s_image_gallery .img[data-original-src^='/unsplash/HQqIOc8oYro/fox']",
trigger: ":iframe #wrap .s_image_gallery img[src^='/unsplash/HQqIOc8oYro/fox']",
run() {
unpatchMediaDialog();
},
3 changes: 2 additions & 1 deletion addons/test_website/static/tests/tours/reset_views.js
Original file line number Diff line number Diff line change
@@ -20,7 +20,8 @@ registerWebsitePreviewTour(
() => [
{
content: "Drag the Intro snippet group and drop it in #oe_structure_test_website_page.",
trigger: '#oe_snippets .oe_snippet[name="Intro"] .oe_snippet_thumbnail:not(.o_we_ongoing_insertion)',
trigger:
"#snippet_groups .o_snippet[name='Intro'] .o_snippet_thumbnail:not(.o_we_ongoing_insertion) .o_snippet_thumbnail_area",
// id starting by 'oe_structure..' will actually create an inherited view
run: "drag_and_drop :iframe #oe_structure_test_website_page",
},
3 changes: 0 additions & 3 deletions addons/test_website/tests/test_image_upload_progress.py
Original file line number Diff line number Diff line change
@@ -9,9 +9,6 @@
from odoo import http
import unittest


# TODO master-mysterious-egg fix error
@unittest.skip("prepare mysterious-egg for merging")
@odoo.tests.common.tagged('post_install', '-at_install')
class TestImageUploadProgress(odoo.tests.HttpCase):

2 changes: 0 additions & 2 deletions addons/test_website/tests/test_reset_views.py
Original file line number Diff line number Diff line change
@@ -93,8 +93,6 @@ def test_06_reset_specific_view_controller_inexisting_template(self):
self.assertEqual(total_views + 1, self.View.search_count([('type', '=', 'qweb')]), "Missing COW view (2)")
self.fix_it('/test_view')

# TODO master-mysterious-egg fix error
@unittest.skip("prepare mysterious-egg for merging")
@mute_logger('odoo.http')
def test_07_reset_page_view_complete_flow(self):
self.start_tour(self.env['website'].get_client_action_url('/test_page_view'), 'test_reset_page_view_complete_flow_part1', login="admin")
3 changes: 1 addition & 2 deletions addons/test_website/tests/test_settings.py
Original file line number Diff line number Diff line change
@@ -7,8 +7,7 @@

@odoo.tests.tagged('-at_install', 'post_install')
class TestWebsiteSettings(odoo.tests.HttpCase):
# TODO master-mysterious-egg fix error
@unittest.skip("prepare mysterious-egg for merging")

def test_01_multi_website_settings(self):
# If not enabled (like in demo data), landing on res.config will try
# to disable module_sale_quotation_builder and raise an issue
10 changes: 10 additions & 0 deletions addons/web/static/src/core/utils/colors.js
Original file line number Diff line number Diff line change
@@ -217,6 +217,16 @@ export function convertCSSColorToRgba(cssColor) {
}

// Otherwise, check if cssColor is an hexadecimal code color
// first check if it's in its compact form (e.g. #FFF)
if (/^#([0-9a-f]{3})$/i.test(cssColor)) {
return {
red: parseInt(cssColor[1] + cssColor[1], 16),
green: parseInt(cssColor[2] + cssColor[2], 16),
blue: parseInt(cssColor[3] + cssColor[3], 16),
opacity: 100,
};
}

if (/^#([0-9A-F]{6}|[0-9A-F]{8})$/i.test(cssColor)) {
return {
red: parseInt(cssColor.substr(1, 2), 16),
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ export class BackgroundImageOptionPlugin extends Plugin {
editingElement.querySelector(".o_we_bg_filter")?.remove();
this.applyReplaceBackgroundImage.bind(this)({
editingElement: editingElement,
loadResult: "",
loadResult: undefined,
params: { forceClean: true },
});
this.dispatchTo("on_bg_image_hide_handlers", editingElement);
@@ -134,31 +134,38 @@ export class BackgroundImageOptionPlugin extends Plugin {
newEditingEl.classList.toggle("o_modified_image_to_save", isModifiedImage);
}
}
loadReplaceBackgroundImage() {
loadReplaceBackgroundImage({ editingElement }) {
return new Promise((resolve) => {
const onClose = this.dependencies.media.openMediaDialog({
onlyImages: true,
save: (imageEl) => {
resolve(imageEl.getAttribute("src"));
node: editingElement,
save: async (imageEl) => {
resolve(imageEl);
},
});
onClose.then(resolve);
});
}
applyReplaceBackgroundImage({
editingElement,
loadResult: imageSrc,
loadResult: imageEl,
params: { forceClean = false },
}) {
if (!forceClean && !imageSrc) {
if (!forceClean && !imageEl) {
// Do nothing: no images has been selected on the media dialog
return;
}
this.setImageBackground(editingElement, imageSrc);
const src = imageEl?.src || "";
this.setImageBackground(editingElement, src);
for (const attr of removeOnImageChangeAttrs) {
delete editingElement.dataset[attr];
}
// TODO: call _autoOptimizeImage of the ImageHandlersOption
if (imageEl) {
if (src.startsWith("data:")) {
editingElement.classList.add("o_modified_image_to_save");
}
Object.assign(editingElement.dataset, imageEl.dataset);
}
}
/**
*
Loading