diff options
| author | Christophe Simonis <chs@odoo.com> | 2019-09-20 17:33:22 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2019-09-20 17:34:45 +0200 |
| commit | 64e43808b79badb5869a8d73cc1cc3f3b3aa8e12 (patch) | |
| tree | 9a22d5f6c03073a4d10faedea8df23a5211e8b8f /addons/website/static/src | |
| parent | 944891ced081cda3b8b3db5faf3b7ac23b6b4ce8 (diff) | |
| parent | 58a83d12228fbbd4e9dde542e133d264204ee0f3 (diff) | |
[MERGE] forward port branch saas-12.5 up to 58a83d12228
Diffstat (limited to 'addons/website/static/src')
| -rw-r--r-- | addons/website/static/src/img/snippets_thumbs/s_products_recently_viewed.png | bin | 0 -> 833 bytes | |||
| -rw-r--r-- | addons/website/static/src/js/content/snippets.animation.js | 109 | ||||
| -rw-r--r-- | addons/website/static/src/js/editor/snippets.options.js | 113 | ||||
| -rw-r--r-- | addons/website/static/src/js/editor/wysiwyg_multizone.js | 27 | ||||
| -rw-r--r-- | addons/website/static/src/js/set_view_track.js | 89 | ||||
| -rw-r--r-- | addons/website/static/src/scss/website.editor.ui.scss | 2 | ||||
| -rw-r--r-- | addons/website/static/src/scss/website.scss | 22 | ||||
| -rw-r--r-- | addons/website/static/src/xml/track_page.xml | 15 | ||||
| -rw-r--r-- | addons/website/static/src/xml/website.background.video.xml | 16 |
9 files changed, 375 insertions, 18 deletions
diff --git a/addons/website/static/src/img/snippets_thumbs/s_products_recently_viewed.png b/addons/website/static/src/img/snippets_thumbs/s_products_recently_viewed.png Binary files differnew file mode 100644 index 00000000000..c55ad28b628 --- /dev/null +++ b/addons/website/static/src/img/snippets_thumbs/s_products_recently_viewed.png diff --git a/addons/website/static/src/js/content/snippets.animation.js b/addons/website/static/src/js/content/snippets.animation.js index 681f6719354..7acb36d284b 100644 --- a/addons/website/static/src/js/content/snippets.animation.js +++ b/addons/website/static/src/js/content/snippets.animation.js @@ -6,9 +6,9 @@ odoo.define('website.content.snippets.animation', function (require) { */ var Class = require('web.Class'); +var config = require('web.config'); var core = require('web.core'); var mixins = require('web.mixins'); -var utils = require('web.utils'); var publicWidget = require('web.public.widget'); var utils = require('web.utils'); @@ -681,6 +681,113 @@ registry.mediaVideo = publicWidget.Widget.extend({ }, }); +registry.backgroundVideo = publicWidget.Widget.extend({ + selector: '.o_background_video', + xmlDependencies: ['/website/static/src/xml/website.background.video.xml'], + disabledInEditableMode: false, + + /** + * @override + */ + start: function () { + var proms = [this._super(...arguments)]; + + this.videoSrc = this.el.dataset.bgVideoSrc; + this.iframeID = _.uniqueId('o_bg_video_iframe_'); + + this.isYoutubeVideo = this.videoSrc.indexOf('youtube') >= 0; + this.isMobileEnv = config.device.size_class <= config.device.SIZES.LG && config.device.touch; + if (this.isYoutubeVideo && this.isMobileEnv) { + this.videoSrc = this.videoSrc + "&enablejsapi=1"; + + if (!window.YT) { + proms.push(new Promise(resolve => { + window.onYouTubeIframeAPIReady = () => resolve(); + })); + $('<script/>', { + src: 'https://www.youtube.com/iframe_api', + }).appendTo('head'); + } + } + + $(window).on('resize.' + this.iframeID, _.throttle(() => this._adjustIframe(), 50)); + + return Promise.all(proms).then(() => this._appendBgVideo()); + }, + /** + * @override + */ + destroy: function () { + this._super.apply(this, arguments); + + $(window).off('resize.' + this.iframeID); + + if (this.$bgVideoContainer) { + this.$bgVideoContainer.remove(); + } + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * Adjusts iframe sizes and position so that it fills the container and so + * that it is centered in it. + * + * @private + */ + _adjustIframe: function () { + // Adjust the iframe + var wrapperWidth = this.$target.innerWidth(); + var wrapperHeight = this.$target.innerHeight(); + var relativeRatio = (wrapperWidth / wrapperHeight) / (16 / 9); + var style = {}; + if (relativeRatio >= 1.0) { + style['width'] = '100%'; + style['height'] = (relativeRatio * 100) + '%'; + style['left'] = '0'; + style['top'] = (-(relativeRatio - 1.0) / 2 * 100) + '%'; + } else { + style['width'] = ((1 / relativeRatio) * 100) + '%'; + style['height'] = '100%'; + style['left'] = (-((1 / relativeRatio) - 1.0) / 2 * 100) + '%'; + style['top'] = '0'; + } + this.$iframe.css(style); + }, + /** + * Append background video related elements to the target. + * + * @private + */ + _appendBgVideo: function () { + var $oldContainer = this.$bgVideoContainer || this.$('> .o_bg_video_container'); + this.$bgVideoContainer = $(qweb.render('website.background.video', { + videoSrc: this.videoSrc, + iframeID: this.iframeID, + })); + this.$iframe = this.$bgVideoContainer.find('.o_bg_video_iframe'); + this.$iframe.one('load', () => { + this.$bgVideoContainer.find('.o_bg_video_loading').remove(); + }); + this.$bgVideoContainer.prependTo(this.$target); + $oldContainer.remove(); + + this._adjustIframe(); + + // YouTube does not allow to auto-play video in mobile devices, so we + // have to play the video manually. + if (this.isMobileEnv && this.isYoutubeVideo) { + new window.YT.Player(this.iframeID, { + events: { + onReady: ev => ev.target.playVideo(), + } + }); + } + }, +}); + registry.ul = publicWidget.Widget.extend({ selector: 'ul.o_ul_folded, ol.o_ul_folded', events: { diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js index baa1d8c5a7c..7f60a976a35 100644 --- a/addons/website/static/src/js/editor/snippets.options.js +++ b/addons/website/static/src/js/editor/snippets.options.js @@ -29,6 +29,102 @@ options.Class.include({ }, }); +options.registry.background.include({ + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @override + */ + _getEditableMedia: function () { + if (!this._hasBgvideo()) { + return this._super(...arguments); + } + return this.$('.o_bg_video_iframe')[0]; + }, + /** + * @override + */ + _getMediaDialogOptions: function () { + return _.extend(this._super(...arguments), { + // For now, disable the possibility to have a parallax video bg + noVideos: this.$target.is('.parallax, .s_parallax_bg'), + isForBgVideo: true, + }); + }, + /** + * @override + */ + _setActive: function () { + this._super(...arguments); + if (this._hasBgvideo()) { + this.$el.find('[data-choose-image]').addClass('active'); + } + }, + /** + * Updates the background video used by the snippet. + * + * @private + * @see this.selectClass for parameters + */ + _setBgVideo: function (previewMode, value) { + this.$('> .o_bg_video_container').toggleClass('d-none', previewMode === true); + + if (previewMode !== false) { + return; + } + + var target = this.$target[0]; + target.classList.toggle('o_background_video', !!(value && value.length)); + if (value && value.length) { + target.dataset.bgVideoSrc = value; + } else { + delete target.dataset.bgVideoSrc; + } + this._refreshPublicWidgets(); + this._setActive(); + }, + /** + * Returns whether the current target has a background video or not. + * + * @private + * @returns {boolean} + */ + _hasBgvideo: function () { + return this.$target[0].classList.contains('o_background_video'); + }, + + //-------------------------------------------------------------------------- + // Handlers + //-------------------------------------------------------------------------- + + /** + * @override + */ + _onBackgroundColorUpdate: function (ev, previewMode) { + var ret = this._super(...arguments); + if (ret) { + this._setBgVideo(previewMode); + } + return ret; + }, + /** + * @override + */ + _onSaveMediaDialog: function (data) { + if (!data.bgVideoSrc) { + this._setBgVideo(false); + this._super(...arguments); + return; + } + // if the user chose a video, only add the video without removing the + // background + this._setBgVideo(false, data.bgVideoSrc); + }, +}); + options.registry.menu_data = options.Class.extend({ xmlDependencies: ['/website/static/src/xml/website.editor.xml'], @@ -1014,6 +1110,7 @@ options.registry.gallery = options.Class.extend({ } self._reset(); self.trigger_up('cover_update'); + this._setActive(); }); dialog.open(); }, @@ -1170,11 +1267,12 @@ options.registry.gallery = options.Class.extend({ var urls = _.map(this._getImages(), function (img) { return $(img).attr('src'); }); + var currentInterval = this.$target.find('.carousel:first').attr('data-interval'); var params = { srcs : urls, index: 0, title: "", - interval : this.$target.data('interval') || false, + interval : currentInterval || this.$target.data('interval') || 0, id: 'slideshow_' + new Date().getTime(), userStyle: imgStyle, }, @@ -1312,7 +1410,7 @@ options.registry.gallery = options.Class.extend({ .data('mode'); var carousel = this.$target[0].querySelector('.carousel'); - var activeInterval = carousel ? carousel.dataset.interval : undefined; + var activeInterval = carousel ? (carousel.dataset.interval || 0) : undefined; var $intervalOptions = this.$el.find('[data-interval]'); $intervalOptions.removeClass('active') .filter('[data-interval="' + activeInterval + '"]') @@ -1334,14 +1432,19 @@ options.registry.gallery = options.Class.extend({ var $stylingOptions = this.$el.find('[data-styling]'); $stylingOptions.removeClass('active'); var img = this.$target[0].querySelector('img'); + var activeStyleSelectors = []; if (img) { - var activeStyleSelectors = []; for (const className of img.classList) { activeStyleSelectors.push('[data-styling="' + className + '"]'); } - $stylingOptions.filter(activeStyleSelectors.join(', ')) - .addClass('active'); } + var $toEnable = activeStyleSelectors.length + ? $stylingOptions.filter(activeStyleSelectors.join(', ')) + : null; + if (!$toEnable || !$toEnable.length) { + $toEnable = $stylingOptions.first(); + } + $toEnable.addClass('active'); }, }); diff --git a/addons/website/static/src/js/editor/wysiwyg_multizone.js b/addons/website/static/src/js/editor/wysiwyg_multizone.js index 9ed31d3afe5..8c7fbfb2e0c 100644 --- a/addons/website/static/src/js/editor/wysiwyg_multizone.js +++ b/addons/website/static/src/js/editor/wysiwyg_multizone.js @@ -124,17 +124,23 @@ var WysiwygMultizone = Wysiwyg.extend({ */ _saveElement: function (outerHTML, recordInfo, editable) { var promises = []; + var $el = $(editable); - promises.push(this._rpc({ - model: 'ir.ui.view', - method: 'save', - args: [ - $el.data('oe-id'), - outerHTML, - $el.data('oe-xpath') || null, - ], - context: recordInfo.context, - })); + + var viewID = $el.data('oe-id'); + if (viewID) { + promises.push(this._rpc({ + model: 'ir.ui.view', + method: 'save', + args: [ + viewID, + outerHTML, + $el.data('oe-xpath') || null, + ], + context: recordInfo.context, + })); + } + if ($el.data('oe-field') === 'mega_menu_content') { // On top of saving the mega menu content like any other field // content, we must save the custom classes that were set on the @@ -153,6 +159,7 @@ var WysiwygMultizone = Wysiwyg.extend({ ], })); } + return Promise.all(promises); }, /** diff --git a/addons/website/static/src/js/set_view_track.js b/addons/website/static/src/js/set_view_track.js new file mode 100644 index 00000000000..d94fcddfffd --- /dev/null +++ b/addons/website/static/src/js/set_view_track.js @@ -0,0 +1,89 @@ +odoo.define('website.set_view_track', function (require) { +"use strict"; + +var CustomizeMenu = require('website.customizeMenu'); +var Widget = require('web.Widget'); + +var TrackPage = Widget.extend({ + template: 'website.track_page', + xmlDependencies: ['/website/static/src/xml/track_page.xml'], + events: { + 'change #switch-track-page': '_onTrackChange', + }, + + /** + * @override + */ + start: function () { + this.$input = this.$('#switch-track-page'); + this._isTracked().then((data) => { + if (data[0]['track']) { + this.track = true; + this.$input.attr('checked', 'checked'); + } else { + this.track = false; + } + }); + }, + + //-------------------------------------------------------------------------- + // Private + //-------------------------------------------------------------------------- + + /** + * @private + */ + _isTracked: function (val) { + var viewid = $('html').data('viewid'); + if (!viewid) { + return Promise.reject(); + } else { + return this._rpc({ + model: 'ir.ui.view', + method: 'read', + args: [[viewid], ['track']], + }); + } + }, + /** + * @private + */ + _onTrackChange: function (ev) { + var checkboxValue = this.$input.is(':checked'); + if (checkboxValue !== this.track) { + this.track = checkboxValue; + this._trackPage(checkboxValue); + } + }, + /** + * @private + */ + _trackPage: function (val) { + var viewid = $('html').data('viewid'); + if (!viewid) { + return Promise.reject(); + } else { + return this._rpc({ + model: 'ir.ui.view', + method: 'write', + args: [[viewid], {track: val}], + }); + } + }, +}); + +CustomizeMenu.include({ + _loadCustomizeOptions: function () { + var self = this; + var def = this._super.apply(this, arguments); + return def.then(function () { + if (!self.__trackpageLoaded) { + self.__trackpageLoaded = true; + self.trackPage = new TrackPage(self); + self.trackPage.appendTo(self.$el.children('.dropdown-menu')); + } + }); + }, +}); + +}); diff --git a/addons/website/static/src/scss/website.editor.ui.scss b/addons/website/static/src/scss/website.editor.ui.scss index 5071e2f8b90..1d1728714dc 100644 --- a/addons/website/static/src/scss/website.editor.ui.scss +++ b/addons/website/static/src/scss/website.editor.ui.scss @@ -1,6 +1,6 @@ @each $url in $o-theme-font-urls { @if $url { - @import url("https://fonts.googleapis.com/css?family=#{unquote($url)}"); + @import url("https://fonts.googleapis.com/css?family=#{unquote($url)}&display=swap"); } } diff --git a/addons/website/static/src/scss/website.scss b/addons/website/static/src/scss/website.scss index b5ce0126afb..e2866e56a89 100644 --- a/addons/website/static/src/scss/website.scss +++ b/addons/website/static/src/scss/website.scss @@ -14,7 +14,7 @@ $-font-numbers: ( $-seen: append($-seen, $-number); $-theme-font: nth($o-theme-font-urls, $-number); @if $-theme-font { - @import url("https://fonts.googleapis.com/css?family=#{unquote($-theme-font)}"); + @import url("https://fonts.googleapis.com/css?family=#{unquote($-theme-font)}&display=swap"); } } } @@ -257,6 +257,26 @@ font[class*='bg-'] { } } +// Background videos +.o_background_video { + position: relative; + + > * { + position: relative; + } +} +.o_bg_video_container { + @include o-position-absolute(0, 0 ,0 ,0); + overflow: hidden; +} +.o_bg_video_iframe { + position: relative; + pointer-events: none !important; +} +.o_bg_video_loading { + @include o-position-absolute(0, 0 ,0 ,0); +} + // Probably outdated // Lists .o_ul_toggle { diff --git a/addons/website/static/src/xml/track_page.xml b/addons/website/static/src/xml/track_page.xml new file mode 100644 index 00000000000..11311156ca7 --- /dev/null +++ b/addons/website/static/src/xml/track_page.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<templates id="template" xml:space="preserve"> + + <t t-name="website.track_page"> + <div role="separator" class="dropdown-divider"/> + <a href="#" name="switch-track-page" class="dropdown-item" role="menuitem"> + <label class="o_switch" for="switch-track-page"> + <input id="switch-track-page" type="checkbox"/> + <span/> + Track visitor + </label> + </a> + </t> + +</templates> diff --git a/addons/website/static/src/xml/website.background.video.xml b/addons/website/static/src/xml/website.background.video.xml new file mode 100644 index 00000000000..548ce2aabb2 --- /dev/null +++ b/addons/website/static/src/xml/website.background.video.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<templates xml:space="preserve"> + <t t-name="website.background.video"> + <div class="o_bg_video_container"> + <div class="o_bg_video_loading d-flex justify-content-center align-items-center text-primary"> + <div class="spinner-border" style="width: 4em; height: 4em;" role="status"> + <span class="sr-only">Loading...</span> + </div> + </div> + <iframe t-att-id="iframeID" + class="o_bg_video_iframe" + frameBorder="0" + t-att-src="videoSrc"/> + </div> + </t> +</templates> |
