diff --git a/addons/website/static/src/js/website.snippets.animation.js b/addons/website/static/src/js/website.snippets.animation.js index 6a8a0257627..e4dd19e03db 100644 --- a/addons/website/static/src/js/website.snippets.animation.js +++ b/addons/website/static/src/js/website.snippets.animation.js @@ -314,52 +314,71 @@ animation.registry.slider = animation.Class.extend({ animation.registry.parallax = animation.Class.extend({ selector: ".parallax", - start: function () { - _.defer((function () { this.set_values(); }).bind(this)); - $(window).on("scroll.animation_parallax", _.throttle(this.on_scroll.bind(this), 10)) - .on("resize.animation_parallax", _.debounce(this.set_values.bind(this), 500)); - - return this._super.apply(this, arguments); + this._super.apply(this, arguments); + this._rebuild(); + $(window).on("resize.animation_parallax", _.debounce(this._rebuild.bind(this), 500)); }, stop: function () { + this._super.apply(this, arguments); $(window).off(".animation_parallax"); }, + _rebuild: function () { + // Add/find bg DOM element to hold the parallax bg (support old v10.0 parallax) + if (!this.$bg || !this.$bg.length) { + this.$bg = this.$("> .s_parallax_bg"); + if (!this.$bg.length) { + this.$bg = $("", {"class": "s_parallax_bg"}).prependTo(this.$target); + } + } + var urlTarget = this.$target.css("background-image"); + if (urlTarget !== "none") { + this.$bg.css("background-image", urlTarget); + } + this.$target.css("background-image", "none"); - set_values: function () { - var self = this; - this.speed = parseFloat(self.$target.attr("data-scroll-background-ratio") || 0); - this.offset = 0; + // Get parallax speed + this.speed = parseFloat(this.$target.attr("data-scroll-background-ratio") || 0); - if (this.speed === 1 || this.$target.css("background-image") === "none") { - this.$target.css("background-attachment", "fixed").css("background-position", "0px 0px"); + // Reset offset if parallax effect will not be performed and leave + this.$target.toggleClass("s_parallax_is_fixed", this.speed === 1); + if (this.speed === 0 || this.speed === 1) { + this.$bg.css({ + transform: "", + top: "", + bottom: "" + }); return; } - this.$target.css("background-attachment", "scroll"); + // Initialize parallax data according to snippet and viewport dimensions + this.viewport = document.body.clientHeight - $('#wrapwrap').position().top; + this.visible_area = [this.$target.offset().top]; + this.visible_area.push(this.visible_area[0] + this.$target.innerHeight() + this.viewport); + this.ratio = this.speed * (this.viewport / 10); - var img = new Image(); - img.onload = function () { - var offset = 0; - var padding = parseInt($(document.body).css("padding-top")); - if (self.speed > 1) { - var inner_offset = - self.$target.outerHeight() + this.height / this.width * document.body.clientWidth; - var outer_offset = self.$target.offset().top - (document.body.clientHeight - self.$target.outerHeight()) - padding; - offset = - outer_offset * self.speed + inner_offset; - } else { - offset = - self.$target.offset().top * self.speed; - } - self.offset = offset > 0 ? 0 : offset; - self.on_scroll(); - }; - img.src = this.$target.css("background-image").replace(/url\(['"]*|['"]*\)/g, ""); + // Provide a "safe-area" to limit parallax + this.$bg.css({ + top: -this.ratio, + bottom: -this.ratio + }); }, + on_scroll: function (scrollOffset) { + if (this.speed === 0 || this.speed === 1) return; - on_scroll: function () { - if (this.speed === 1) return; - var top = this.offset + window.scrollY * this.speed; - this.$target.css("background-position", "0px " + top + "px"); - }, + // Perform translate if the element is visible only + var vpEndOffset = scrollOffset + this.viewport; + if (vpEndOffset >= this.visible_area[0] && vpEndOffset <= this.visible_area[1]) { + this.$bg.css("transform", "translateY(" + _getNormalizedPosition.call(this, vpEndOffset) + "px)"); + } + + function _getNormalizedPosition(pos) { + // Normalize scroll in a 1 to 0 range + var r = (pos - this.visible_area[1]) / (this.visible_area[0] - this.visible_area[1]); + // Normalize accordingly to current options + return Math.round(this.ratio * (2 * r - 1)); + } + } }); animation.registry.share = animation.Class.extend({ diff --git a/addons/website/static/src/js/website.snippets.editor.js b/addons/website/static/src/js/website.snippets.editor.js index 4fbb79dd89e..94bb408b9ac 100644 --- a/addons/website/static/src/js/website.snippets.editor.js +++ b/addons/website/static/src/js/website.snippets.editor.js @@ -299,34 +299,34 @@ options.registry.parallax = options.Class.extend({ this.grid.size = 8; return this.grid; }, - on_resize: function () { - this._refresh(); - }, - _refresh: function () { - this.$target.data("snippet-view").set_values(); - }, start: function () { this._super.apply(this, arguments); if (!this.$target.data("snippet-view")) { this.$target.data("snippet-view", new animation.registry.parallax(this.$target)); } - this.scroll(); - this._refresh_callback = this._refresh.bind(this); - this.buildingBlock.$el.on("snippet-dropped snippet-activated", this._refresh_callback); - this.$target.on('snippet-option-change snippet-option-preview', this._refresh_callback); + this._toggle_refresh_callback(true); + }, + on_focus: function () { + this._super.apply(this, arguments); + this._update_target_to_bg(); + }, + on_resize: function () { + this._super.apply(this, arguments); + this._refresh(); }, scroll: function (type, value) { this.$target.attr("data-scroll-background-ratio", value); this._refresh(); }, set_active: function () { + this._super.apply(this, arguments); this.$el.find('[data-scroll]').removeClass("active") .filter('[data-scroll="' + (this.$target.attr('data-scroll-background-ratio') || 0) + '"]').addClass("active"); }, clean_for_save: function () { this._super.apply(this, arguments); - this.$target.css("background-position", '').css("background-attachment", ''); + this._toggle_refresh_callback(false); }, on_move: function () { this._super.apply(this, arguments); @@ -334,8 +334,23 @@ options.registry.parallax = options.Class.extend({ }, on_remove: function () { this._super.apply(this, arguments); - this.$target.off("snippet-option-change snippet-option-preview", this._refresh_callback); - this.buildingBlock.$el.off("snippet-dropped snippet-activated", this._refresh_callback); + this._toggle_refresh_callback(false); + }, + _update_target_to_bg: function () { + this.editor.styles.background.$target = this.$target.data("snippet-view").$bg; + this.editor.styles.background.set_active(); + this.editor.styles.background_position.$target = this.$target.data("snippet-view").$bg; + this.editor.styles.background_position.set_active(); + }, + _refresh: function () { + _.defer((function () { + this.$target.data("snippet-view")._rebuild(); + this._update_target_to_bg(); + }).bind(this)); + }, + _toggle_refresh_callback: function (on) { + this.$target[on ? "on" : "off"]("snippet-option-change snippet-option-preview", this._refresh_callback); + this.buildingBlock.$el[on ? "on" : "off"]("snippet-dropped snippet-activated", this._refresh_callback); }, }); diff --git a/addons/website/static/src/less/website.snippets.less b/addons/website/static/src/less/website.snippets.less index 7b941acda2f..1a290e65767 100644 --- a/addons/website/static/src/less/website.snippets.less +++ b/addons/website/static/src/less/website.snippets.less @@ -402,6 +402,17 @@ div.carousel { margin-bottom: 32px; } } + + > .s_parallax_bg { + .o-position-absolute(0, 0, 0, 0); + background-size: cover; + background-attachment: scroll; + pointer-events: none; + z-index: -1; + } + &.s_parallax_is_fixed > .s_parallax_bg { + background-attachment: fixed; + } } .s_parallax { diff --git a/addons/website/views/snippets.xml b/addons/website/views/snippets.xml index 82c308485e6..a1cbb1b4578 100644 --- a/addons/website/views/snippets.xml +++ b/addons/website/views/snippets.xml @@ -530,13 +530,13 @@ + data-scroll-background-ratio="1.6"> + data-scroll-background-ratio="1.6"> @@ -679,7 +679,7 @@ + data-selector="section, :not(.o_gallery > .container) > .carousel, .s_banner .carousel-content"> Background Image Sizing @@ -847,12 +847,14 @@ Scroll Speed - Static - Very Slow - Slow + No-scroll + Fixed - Fast - Very Fast + + Very Slow + Slow + Fast + Very Fast