Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 95 additions & 21 deletions addons/html_builder/static/src/builder/builder_helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,30 @@ export function useClickableWeWidget() {
useWeComponent();
const comp = useComponent();
const getAction = comp.env.editor.shared.builderActions.getAction;
const call = comp.env.editor.shared.history.makePreviewableOperation(callActions);
const applyOperation = comp.env.editor.shared.history.makePreviewableOperation(callApply);

const operation = {
commit: () => {
callOperation(applyOperation.commit);
},
preview: () => {
callOperation(applyOperation.preview, {
cancellable: true,
cancelPrevious: () => applyOperation.revert(),
});
},
revert: () => {
// The `next` will cancel the previous operation, which will revert
// the operation in case of a preview.
comp.env.editor.shared.operation.next();
},
};

if (
comp.props.preview === false ||
(comp.env.weContext.preview === false && comp.props.preview !== true)
) {
call.preview = () => {};
operation.preview = () => {};
}

const state = useDomState(() => ({
Expand All @@ -150,7 +168,7 @@ export function useClickableWeWidget() {

if (comp.env.actionBus) {
useBus(comp.env.actionBus, "BEFORE_CALL_ACTIONS", () => {
for (const [actionId, actionParam, actionValue] of getActions()) {
for (const { actionId, actionParam, actionValue } of getAllActions()) {
for (const editingElement of comp.env.getEditingElements()) {
getAction(actionId).clean?.({
editingElement,
Expand All @@ -162,38 +180,93 @@ export function useClickableWeWidget() {
});
}

function callActions() {
comp.env.actionBus?.trigger("BEFORE_CALL_ACTIONS");
for (const [actionId, actionParam, actionValue] of getActions()) {
function callOperation(fn, operationParams) {
const actionsSpecs = getActionsSpecs(getAllActions());
comp.env.editor.shared.operation.next(
() => {
fn(actionsSpecs);
},
{
load: async () => {
return Promise.all(
actionsSpecs.map(async (applySpec) => {
if (!applySpec.load) {
return;
}
const result = await applySpec.load({
editingElement: applySpec.editingElement,
param: applySpec.actionParam,
value: applySpec.actionValue,
});
result.loadResult = result;
})
);
},
...operationParams,
}
);
}
function getActionsSpecs(actions) {
const specs = [];
for (const { actionId, actionParam, actionValue } of actions) {
const action = getAction(actionId);
for (const editingElement of comp.env.getEditingElements()) {
getAction(actionId).apply({
specs.push({
editingElement,
param: actionParam,
value: actionValue,
actionId,
actionParam,
actionValue,
apply: action.apply,
load: action.load,
});
}
}
return specs;
}
function callApply(applySpecs) {
comp.env.actionBus?.trigger("BEFORE_CALL_ACTIONS");
for (const applySpec of applySpecs) {
applySpec.apply({
editingElement: applySpec.editingElement,
param: applySpec.actionParam,
value: applySpec.actionValue,
loadResult: applySpec.loadResult,
});
}
}
function getActions() {
const actions = [];

function getShorthandActions() {
const actions = [];
const shorthands = [
["classAction", "classActionValue"],
["attributeAction", "attributeActionValue"],
["dataAttributeAction", "dataAttributeActionValue"],
["styleAction", "styleActionValue"],
];
for (const [actionName, actionValue] of shorthands) {
const value = comp.env.weContext[actionName] || comp.props[actionName];
if (value) {
actions.push([actionName, value, comp.props[actionValue]]);
for (const [actionId, actionValue] of shorthands) {
const actionParam = comp.env.weContext[actionId] || comp.props[actionId];
if (actionParam) {
actions.push({ actionId, actionParam, actionValue: comp.props[actionValue] });
}
}
return actions;
}
function getCustomAction() {
const action = {
actionId: comp.env.weContext.action || comp.props.action,
actionParam: comp.env.weContext.actionParam || comp.props.actionParam,
actionValue: comp.props.actionValue,
};
if (action.actionId) {
return action;
}
}
function getAllActions() {
const actions = getShorthandActions();

const action = comp.env.weContext.action || comp.props.action;
const actionParam = comp.env.weContext.actionParam || comp.props.actionParam;
if (action) {
actions.push([action, actionParam, comp.props.actionValue]);
const { actionId, actionParam, actionValue } = getCustomAction() || {};
if (actionId) {
actions.push({ actionId, actionParam, actionValue });
}
return actions;
}
Expand All @@ -202,7 +275,8 @@ export function useClickableWeWidget() {
if (!editingElements.length) {
return;
}
return getActions().every(([actionId, actionParam, actionValue]) => {
return getAllActions().every((o) => {
const { actionId, actionParam, actionValue } = o;
// TODO isActive === first editing el or all ?
const editingElement = editingElements[0];
return getAction(actionId).isActive?.({
Expand All @@ -215,7 +289,7 @@ export function useClickableWeWidget() {

return {
state,
call,
operation,
isActive,
};
}
Expand Down
8 changes: 4 additions & 4 deletions addons/html_builder/static/src/builder/components/WeButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ export class WeButton extends Component {
};

setup() {
const { state, call, isActive } = useClickableWeWidget();
const { state, operation, isActive } = useClickableWeWidget();
if (this.props.id) {
useDependecyDefinition({ id: this.props.id, isActive });
}
this.state = state;
this.onClick = call.commit;
this.onMouseenter = call.preview;
this.onMouseleave = call.revert;
this.onClick = operation.commit;
this.onMouseenter = operation.preview;
this.onMouseleave = operation.revert;
}

get className() {
Expand Down
15 changes: 10 additions & 5 deletions addons/html_builder/static/src/builder/components/WeSelectItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class WeSelectItem extends Component {

setup() {
const item = useRef("item");
const { state, call, isActive } = useClickableWeWidget();
const { state, operation, isActive } = useClickableWeWidget();
if (this.props.id) {
useDependecyDefinition({ id: this.props.id, isActive });
}
Expand All @@ -29,16 +29,21 @@ export class WeSelectItem extends Component {
this.env.weSetSelectLabel?.(item.el.innerHTML);
}
};
useBus(this.env.editorBus, "STEP_ADDED", setSelectLabel);
useBus(this.env.editorBus, "STEP_ADDED", (ev) => {
if (ev.detail.isPreviewing) {
return;
}
return setSelectLabel();
});
onMounted(setSelectLabel);

this.state = state;
this.onClick = () => {
call.commit();
operation.commit();
setSelectLabel();
this.env.weSelectBus?.trigger("select-item");
};
this.onMouseenter = call.preview;
this.onMouseleave = call.revert;
this.onMouseenter = operation.preview;
this.onMouseleave = operation.revert;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,20 @@ const actions = {
},
styleAction: {
getValue: ({ editingElement, param: styleName }) => {
return styleMap[styleName]?.getValue(editingElement);
const customStyle = styleMap[styleName];
if (customStyle) {
return customStyle.getValue(editingElement);
} else {
return getComputedStyle(editingElement).getPropertyValue(styleName);
}
},
apply: ({ editingElement, param: styleName, value }) => {
styleMap[styleName]?.apply(editingElement, value);
const customStyle = styleMap[styleName];
if (customStyle) {
customStyle?.apply(editingElement, value);
} else {
editingElement.style.setProperty(styleName, value);
}
},
},
attributeAction: {
Expand Down
44 changes: 33 additions & 11 deletions addons/html_builder/static/src/builder/options/image_tool_option.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { cropperAspectRatios, processImageCrop } from "@html_editor/main/media/image_crop";
import { activateCropper, loadImage } from "@html_editor/utils/image_processing";
import {
activateCropper,
applyModifications,
loadImage,
} from "@html_editor/utils/image_processing";
import { Component } from "@odoo/owl";
import { loadBundle } from "@web/core/assets";
import { registry } from "@web/core/registry";
Expand Down Expand Up @@ -29,7 +33,7 @@ class ImageToolOptionPlugin extends Plugin {
},
},
resetCrop: {
apply: async ({ editingElement }) => {
load: async ({ editingElement }) => {
// todo: This seems quite heavy for a simple reset. Retrieve some
// metadata, to load the image crop, to call processImageCrop, just to
// reset the crop. We might want to simplify this.
Expand All @@ -45,15 +49,11 @@ class ImageToolOptionPlugin extends Plugin {
const mimetime = getImageMimetype(croppedImage);
await loadImage(croppedImage.dataset.originalSrc, originalImage);
let aspectRatio = croppedImage.dataset.aspectRatio || "0/0";
let readyResolve;
const readyPromise = new Promise((resolve) => (readyResolve = resolve));
const cropper = await activateCropper(
originalImage,
cropperAspectRatios[aspectRatio].value,
croppedImage.dataset,
{ ready: readyResolve }
croppedImage.dataset
);
await readyPromise;
cropper.reset();
if (aspectRatio !== "0/0") {
aspectRatio = "0/0";
Expand All @@ -67,9 +67,12 @@ class ImageToolOptionPlugin extends Plugin {
);
container.remove();
cropper.destroy();
croppedImage.setAttribute("src", newSrc);
return newSrc;
},
apply: ({ editingElement, editor, loadResult: newSrc }) => {
editingElement.setAttribute("src", newSrc);
// todo: Should re-apply a shape if it was applied before.
this.dependencies.history.addStep();
editor.shared.history.addStep();
},
},
transformImage: {
Expand All @@ -92,6 +95,27 @@ class ImageToolOptionPlugin extends Plugin {
this.dependencies.history.addStep();
},
},
glFilter: {
isActive: ({ editingElement, param: glFilterName }) => {
if (glFilterName) {
return editingElement.dataset.glFilter === glFilterName;
} else {
return !editingElement.dataset.glFilter;
}
},
load: async ({ editingElement, param: glFilterName }) => {
await loadBundle("html_editor.assets_image_cropper");
editingElement.dataset.glFilter = glFilterName;
const newSrc = await applyModifications(editingElement, {
mimetype: getImageMimetype(editingElement),
});
return newSrc;
},
apply: ({ editingElement, editor, loadResult: newSrc }) => {
editingElement.setAttribute("src", newSrc);
editor.shared.history.addStep();
},
},
};
}
}
Expand All @@ -103,8 +127,6 @@ class ImageToolOption extends Component {
static props = {};
}

// const getActions = (plugin) => ();

/**
* @private
* @param {HTMLImageElement} img
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,31 @@
<WeButton title.translate="Transform the picture" action="'transformImage'" icon="'fa-object-ungroup'" id="'transformImage'" />
<WeButton title.translate="Reset transformation" action="'resetTransformImage'" dependencies="'transformImage'">Reset</WeButton>
</WeRow>
<WeRow label.translate="Filter">
<WeSelect>
<WeSelectItem action="'glFilter'" actionParam="''">None</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'blur'">Blur</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'1977'">1977</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'aden'">Aden</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'brannan'">Brannan</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'earlybird'">EarlyBird</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'inkwell'">Inkwell</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'maven'">Maven</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'toaster'">Toaster</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'walden'">Walden</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'valencia'">Valencia</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'xpro'">Xpro</WeSelectItem>
<WeSelectItem action="'glFilter'" actionParam="'custom'" id="custom_glfilter_opt">Custom</WeSelectItem>
</WeSelect>
</WeRow>
<WeRow label.translate="Size">
<WeButtonGroup string="Size" styleAction="'width'">
<WeButton styleActionValue="''" title.translate="Resize Default">Default</WeButton>
<WeButton styleActionValue="'25%'" title.translate="Resize Quarter">25%</WeButton>
<WeButton styleActionValue="'50%'" title.translate="Resize Half">50%</WeButton>
<WeButton styleActionValue="'100%'" title.translate="Resize Full">100%</WeButton>
</WeButtonGroup>
</WeRow>
</t>

</templates>
Loading