Skip to content

Commit

Permalink
animation
Browse files Browse the repository at this point in the history
  • Loading branch information
Goaman committed Jan 15, 2025
1 parent bf5b49c commit df903f7
Show file tree
Hide file tree
Showing 5 changed files with 327 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Component, xml } from "@odoo/owl";
import {
basicContainerBuilderComponentProps,
BuilderComponent,
useBuilderComponent,
} from "./utils";

export class BuilderContext extends Component {
static template = xml`
<BuilderComponent dependencies="props.dependencies">
<t t-slot="default"/>
</BuilderComponent>
`;
static props = {
...basicContainerBuilderComponentProps,
slots: { type: Object },
};
static components = {
BuilderComponent,
};

setup() {
useBuilderComponent();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, useRef } from "@odoo/owl";
import { Component, onMounted, useRef } from "@odoo/owl";
import {
clickableBuilderComponentProps,
defaultBuilderComponentProps,
Expand All @@ -22,9 +22,16 @@ export class BuilderSelectItem extends Component {
throw new Error("BuilderSelectItem must be used inside a BuilderSelect component.");
}
const item = useRef("item");
let label = "";
const getLabel = () => {
label = item.el?.innerHTML || label || "";
return label;
};

onMounted(getLabel);

const { state, operation } = useSelectableItemComponent(this.props.id, {
getLabel: () => item.el?.innerHTML || "",
getLabel,
});
this.state = state;
this.onClick = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import { BuilderColorPicker } from "./builder_colorpicker";
import { BuilderTextInput } from "./builder_text_input";
import { BuilderCheckbox } from "./builder_checkbox";
import { BuilderRange } from "./builder_range";
import { BuilderContext } from "./builder_context";

export const defaultBuilderComponents = {
BuilderContext,
BuilderRow,
Dropdown,
DropdownItem,
Expand Down
195 changes: 194 additions & 1 deletion addons/html_builder/static/src/builder/options/animate_option.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Plugin } from "@html_editor/plugin";
import { Component } from "@odoo/owl";
import { Component, onWillDestroy, useEnv } from "@odoo/owl";
import { registry } from "@web/core/registry";
import { defaultBuilderComponents } from "../builder_components/default_builder_components";
import { withSequence } from "@html_editor/utils/resource";
import { useDomState } from "../builder_components/utils";
import { getScrollingElement } from "@web/core/utils/scrolling";

class AnimateOptionPlugin extends Plugin {
static id = "AnimateOption";
Expand All @@ -19,21 +21,212 @@ class AnimateOptionPlugin extends Plugin {
],
builder_actions: this.getActions(),
};

setup() {
this.scrollingElement = getScrollingElement(this.document);
}

getActions() {
const effectWithFadein = ["onAppearance", "onScroll"];
return {
setAnimationMode: {
// todo: to remove after having the commit of louis
isApplied: () => true,
clean: ({ editingElement, value: effectName, dependencyManager, nextAction }) => {
this.scrollingElement.classList.remove("o_wanim_overflow_xy_hidden");
editingElement.classList.remove(
"o_animating",
"o_animate_both_scroll",
"o_visible",
"o_animated",
"o_animate_out"
);
editingElement.style.animationDelay = "";
editingElement.style.animationPlayState = "";
editingElement.style.animationName = "";
editingElement.style.visibility = "";

if (effectName === "onScroll") {
delete editingElement.dataset.scrollZoneStart;
delete editingElement.dataset.scrollZoneEnd;
}
if (effectName === "onHover") {
// todo: to implement
// this.trigger_up("option_update", {
// optionName: "ImageTools",
// name: "disable_hover_effect",
// });
}

const isNextEffectFadein = effectWithFadein.includes(nextAction.value);
if (!isNextEffectFadein) {
this.removeEffectAndDirectionClasses(
dependencyManager,
editingElement.classList
);
editingElement.style.setProperty("--wanim-intensity", "");
editingElement.style.animationDuration = "";
this.setImagesLazyLoading(editingElement, true);
}
},
apply: ({ editingElement, value: effectName }) => {
if (effectWithFadein.includes(effectName)) {
editingElement.classList.add("o_anim_fade_in");
this.setImagesLazyLoading(editingElement, false);
}
if (effectName === "onScroll") {
editingElement.dataset.scrollZoneStart = 0;
editingElement.dataset.scrollZoneEnd = 100;
}
if (effectName === "onHover") {
// todo: to implement
// Pause the history until the hover effect is applied in
// "setImgShapeHoverEffect". This prevents saving the intermediate
// steps done (in a tricky way) up to that point.
// this.options.wysiwyg.odooEditor.historyPauseSteps();
// this.trigger_up("option_update", {
// optionName: "ImageTools",
// name: "enable_hover_effect",
// });
}
},
},
setAnimateIntensity: {
getValue: ({ editingElement }) => {
const intensity = parseInt(
window
.getComputedStyle(editingElement)
.getPropertyValue("--wanim-intensity")
);
return intensity;
},
apply: ({ editingElement, value }) => {},
},
forceAnimation: {
// todo: to remove after having the commit of louis
isActive: () => true,
apply: () => {
console.warn("todo");
},
},
};
}

removeEffectAndDirectionClasses(dependencyManager, targetClassList) {
const classes = getSelectableClasses(dependencyManager, "animation_effect_opt").concat(
getSelectableClasses(dependencyManager, "animation_direction_opt")
);
const classesToRemove = intersect(classes, [...targetClassList]);
for (const className of classesToRemove) {
targetClassList.remove(className);
}
}

/**
* Removes or adds the lazy loading on images because animated images can
* appear before or after their parents and cause bugs in the animations.
* To put "lazy" back on the "loading" attribute, we simply remove the
* attribute as it is automatically added on page load.
*
* @private
* @param {Boolean} isLazy
*/
setImagesLazyLoading(editingElement, isLazy) {
const imgEls = editingElement.matches("img")
? [editingElement]
: editingElement.querySelectorAll("img");
for (const imgEl of imgEls) {
if (isLazy) {
// Let the automatic system add the loading attribute
imgEl.removeAttribute("loading");
} else {
imgEl.loading = "eager";
}
}
}
}
registry.category("website-plugins").add(AnimateOptionPlugin.id, AnimateOptionPlugin);

class AnimateOption extends Component {
static template = "html_builder.AnimateOption";
static components = { ...defaultBuilderComponents };
static props = {};

setup() {
const env = useEnv();

// Animations for which the "On Scroll" and "Direction" options are not
// available.
this.limitedAnimations = [
"o_anim_flash",
"o_anim_pulse",
"o_anim_shake",
"o_anim_tada",
"o_anim_flip_in_x",
"o_anim_flip_in_y",
];
const dependencyManager = env.dependencyManager;

this.state = useDomState((editingElement) => {
const hasAnimateClass = editingElement.classList.contains("o_animate");
return {
hasAnimateClass: hasAnimateClass,
canHover: editingElement.tagName === "IMG",
isLimitedAnimation: this.limitedAnimations.some((className) =>
editingElement.classList.contains(className)
),
showIntensity: this.shouldShowIntensity(
editingElement,
dependencyManager,
hasAnimateClass
),
};
});
}

shouldShowIntensity(editingElement, dependencyManager, hasAnimateClass) {
if (!hasAnimateClass) {
return false;
}
if (!editingElement.classList.contains("o_anim_fade_in")) {
return true;
}

const possibleDirections = getSelectableClasses(
dependencyManager,
"animation_direction_opt"
).filter(Boolean);
const hasDirection = possibleDirections.some((direction) =>
editingElement.classList.contains(direction)
);

return hasDirection;
}
}

/**
* Returns the selectable classes for the given dependency.
*
* @returns {Array<string>}
*/
function getSelectableClasses(dependencyManager, dependency) {
return Array.from(
new Set(
dependencyManager
.get(dependency)
?.getSelectableItems()
.map((item) =>
item
.getActions()
.map((a) => a.actionId === "classAction" && a.actionParam.split(/\s+/))
.filter(Boolean)
.flat()
)
.flat() || []
)
);
}

function intersect(a, b) {
return a.filter((value) => b.includes(value));
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,105 @@
id="'animation_on_scroll_opt'">On Scroll</BuilderSelectItem>
<BuilderSelectItem action="'setAnimationMode'" actionValue="'onHover'"
classAction="'o_animate_on_hover'"
id="'animation_on_hover_opt'">On Hover</BuilderSelectItem>
id="'animation_on_hover_opt'"
t-if="state.canHover">On Hover</BuilderSelectItem>
</BuilderSelect>
</BuilderRow>
<BuilderRow label.translate="Effect">
<BuilderSelect t-if="this.state.hasAnimateClass" dependencies="'!animation_on_hover_opt'" id="'animation_effect_opt'">
<!-- Default value -->
<!-- <div class="d-none"><BuilderSelectItem classAction="''">None</BuilderSelectItem></div> -->
<BuilderSelectItem classAction="'o_anim_fade_in'"
inheritedActions="'animation_direction_in_place_opt'">Fade</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_slide_in'"
id="'o_anim_slide_in_opt'"
inheritedActions="'animation_direction_from_right_opt'">Slide</BuilderSelectItem>
<BuilderContext inheritedActions="'animation_direction_in_place_opt'">
<BuilderSelectItem classAction="'o_anim_bounce_in'">Bounce</BuilderSelectItem>
<BuilderSelectItem id="'o_anim_rotate_opt'"
classAction="'o_anim_rotate_in'">Rotate</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_zoom_out'">Zoom Out</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_zoom_in'">Zoom In</BuilderSelectItem>
<BuilderContext dependencies="'animation_on_appearance_opt'">
<BuilderSelectItem classAction="'o_anim_flash'">Flash</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_pulse'">Pulse</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_shake'">Shake</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_tada'">Tada</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_flip_in_x'">Flip-In-X</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_flip_in_y'">Flip-In-Y</BuilderSelectItem>
</BuilderContext>
</BuilderContext>
</BuilderSelect>
<!-- <div id="o_hover_effects_options" t-elif="state.canHover">
<BuilderSelect string="Effect" class="o_we_sublevel_1" data-attribute-name="hoverEffect"
data-set-img-shape-hover-effect="true">
<we-button data-select-data-attribute="" data-name="hover_effect_none_opt">None</we-button>
<we-button data-select-data-attribute="overlay" data-name="hover_effect_overlay_opt">Overlay</we-button>
<we-button data-select-data-attribute="image_zoom_in" data-name="hover_effect_zoom_in_opt">Zoom In</we-button>
<we-button data-select-data-attribute="image_zoom_out" data-name="hover_effect_zoom_out_opt">Zoom Out</we-button>
<we-button data-select-data-attribute="dolly_zoom" data-name="hover_effect_dolly_zoom_opt">Dolly Zoom</we-button>
<we-button data-select-data-attribute="outline" data-name="hover_effect_outline_opt">Outline</we-button>
<we-button data-select-data-attribute="image_mirror_blur" data-name="hover_effect_mirror_blur_opt">Mirror Blur</we-button>
</BuilderSelect>
<we-range string="Intensity" class="o_we_sublevel_2" data-select-data-attribute="" data-attribute-name="hoverEffectIntensity"
data-dependencies="hover_effect_zoom_in_opt, hover_effect_zoom_out_opt, hover_effect_mirror_blur_opt, hover_effect_dolly_zoom_opt"
data-min="1" data-max="100" data-step="1" data-display-range-value="true" data-no-preview="true"/>
<we-colorpicker string="Color" class="o_we_sublevel_2" data-set-hover-effect-color="true" data-excluded="theme, common"
data-dependencies="hover_effect_dolly_zoom_opt, hover_effect_overlay_opt, hover_effect_zoom_in_opt, hover_effect_zoom_out_opt, hover_effect_outline_opt"
data-no-preview="true" data-name="hover_effect_color_opt"/>
<we-input string="Stroke Width" class="o_we_sublevel_2" data-select-data-attribute="" data-attribute-name="hoverEffectStrokeWidth"
data-step="1" data-min="1" data-unit="px" data-dependencies="hover_effect_outline_opt" data-no-preview="true"/>
</div> -->
</BuilderRow>
<BuilderRow label.translate="Direction" t-if="state.hasAnimateClass and !state.isLimitedAnimation">
<BuilderSelect id="'animation_direction_opt'" action="'forceAnimation'">
<BuilderSelectItem classAction="''"
id="'animation_direction_in_place_opt'"
dependencies="'!o_anim_slide_in_opt'">In Place</BuilderSelectItem>

<BuilderContext dependencies="'!o_anim_rotate_opt'">
<BuilderSelectItem id="'animation_direction_from_right_opt'"
classAction="'o_anim_from_right'">From Right</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_from_left'">From Left</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_from_bottom'">From Bottom</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_from_top'">From Top</BuilderSelectItem>
</BuilderContext>

<BuilderContext dependencies="'o_anim_rotate_opt'">
<BuilderSelectItem classAction="'o_anim_from_top_right'">From Top Right</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_from_top_left'">From Top Left</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_from_bottom_right'">From Bottom Right</BuilderSelectItem>
<BuilderSelectItem classAction="'o_anim_from_bottom_left'">From Bottom Left</BuilderSelectItem>
</BuilderContext>
</BuilderSelect>
</BuilderRow>
<!-- Trigger -->
<BuilderRow label.translate="Trigger">
<BuilderSelect dependencies="'animation_on_appearance_opt'" id="'animation_trigger_opt'">
<BuilderSelectItem classAction="''">First Time Only</BuilderSelectItem>
<BuilderSelectItem classAction="'o_animate_both_scroll'">Every Time</BuilderSelectItem>
</BuilderSelect>
</BuilderRow>
<!-- Intensity -->
<BuilderRow label.translate="Intensity" t-if="state.showIntensity">
<BuilderRange id="'animation_intensity_opt'"
action="'setAnimateIntensity'"
preview="false"
min="1"
max="100"
step="1"
displayRangeValue="true"/>
</BuilderRow>
<BuilderContext dependencies="'animation_on_appearance_opt'">
<!-- Start After -->
<BuilderRow label.translate="Start After">
<BuilderNumberInput styleAction="'animation-delay'" default="0" unit="'s'" />
</BuilderRow>
<!-- Duration -->
<BuilderRow label.translate="Duration">
<BuilderNumberInput styleAction="'animation-duration'" default="0.4" unit="'s'" />
</BuilderRow>
</BuilderContext>
</t>


Expand Down

0 comments on commit df903f7

Please sign in to comment.