[ADD] theme saas-12.3

This commit is contained in:
Design
2021-05-20 10:57:04 +02:00
committed by Jeremy Kersten
commit b759230266
3024 changed files with 68920 additions and 0 deletions
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 997 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 977 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 921 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1022 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

@@ -0,0 +1,19 @@
odoo.define('theme_common.compatibility_editor', function (require) {
'use strict';
var sOptions = require('web_editor.snippets.options');
sOptions.registry.background.include({
/**
* @override
*/
background: function (previewMode, value, $opt) {
this._super.apply(this, arguments);
var customClass = this.$target.attr('class').match(/\b(bg-img-\d+)\b/);
if (customClass) {
this.$target.removeClass(customClass[1]);
}
},
});
});
@@ -0,0 +1,79 @@
odoo.define('theme_common.s_animated_boxes_editor', function (require) {
'use strict';
var s_options = require('web_editor.snippets.options');
s_options.registry.s_animated_boxes = s_options.Class.extend({
start: function () {
var self = this;
self.add_btn_edit_slide();
setTimeout(function () {
if (self.$target.find(".slide").length > 0) {
self.$overlay.find(".createSlide").addClass("hide");
self.$overlay.find(".deleteSlide").removeClass("hide");
self.$overlay.find(".btn-showSlide").removeClass("hide");
} else {
self.$overlay.find(".createSlide").removeClass("hide");
self.$overlay.find(".deleteSlide").addClass("hide");
self.$overlay.find(".btn-showSlide").addClass("hide");
}
}, 100);
},
add_btn_edit_slide: function () {
var self = this;
self.$overlay.find(".oe_options").after('<a href="#" class="btn btn-secondary btn-showSlide" title="Lock slide" style="width: auto; padding: 0 5px;"><i class="fa fa-toggle-off"></i> Edit Slide</a> ');
self.$overlay.on('click', '.btn-showSlide', _.bind(this.toggle_slide, this));
},
create_slide: function (previewMode, value, $li) {
var self = this,
slide = '<div class="slide editable bg-success animated text-center dur-200ms insetShadow" anim="o_anim_fade_in_down" del="0" dur="200"><div class="v-align"><h3>Your new slide</h3></div></div>';
self.$target.append(slide);
self.$overlay.find(".btn-showSlide").removeClass("hide");
self.$overlay.find(".createSlide").addClass("hide");
self.$overlay.find(".deleteSlide").removeClass("hide");
},
delete_slide: function (previewMode, value, $li) {
var self = this;
self.$target.find(".slide").remove();
self.$overlay.find(".btn-showSlide").addClass("hide");
self.$overlay.find(".createSlide").removeClass("hide");
self.$overlay.find(".deleteSlide").addClass("hide");
},
toggle_slide: function () {
var a = this.$overlay.find(".btn-showSlide"),
i = a.find("i"),
t = this.$target,
s = t.find(".slide");
if (!t.hasClass("showSlide")) {
t.addClass("showSlide"); i.addClass("fa-toggle-on").removeClass("fa-toggle-off"); i.css("color", "#FFF");
s.addClass("visible");
} else {
t.removeClass("showSlide"); i.removeClass("fa-toggle-on").addClass("fa-toggle-off"); i.css("color", "");
s.removeClass("visible");
}
},
onFocus: function () {
this._adapt_items_height();
},
onBlur: function () {
this._adapt_items_height();
},
cleanForSave: function() {
this.$target.removeClass("showSlide")
.find(".slide").removeClass("visible");
this._adapt_items_height();
},
_adapt_items_height: function () {
var $items = this.$target.closest(".s_animated_boxes").find(".item");
var min_height = _.reduce($items.find(".v-align"), function (memo, item) {
return Math.max(memo, $(item).outerHeight(true) + 40);
}, 200);
$items.css("height", min_height);
},
});
});
@@ -0,0 +1,15 @@
odoo.define('theme_common.s_animated_boxes_frontend', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
/**
* This is a fix for some apple devices.
* The slide of animated boxes widget is shown on hover or click on mobile
* devices, but iOS only activates :hover if the element targeted is
* clickable.
*/
publicWidget.registry._fixAnimatedBoxesAppleClick = publicWidget.registry._fixAppleCollapse.extend({
selector: '.s_animated_boxes .item',
});
});
@@ -0,0 +1,82 @@
odoo.define('theme_common.s_css_slider_editor', function (require) {
'use strict';
var s_options = require('web_editor.snippets.options');
s_options.registry.s_css_slider_slide = s_options.Class.extend({
newSlideUrl: "/web/image/theme_common.image_content_23",
start: function () {
var self = this;
self.reset();
this.trigger_up('widgets_start_request', {
editableMode: true,
$target: this.$target,
});
setTimeout(function () {
self.$overlay.find(".js_s_css_slider_addSlide").on('click', function () { self.addSlide(); });
self.$overlay.find(".js_s_css_slider_removeSlide").on('click', function () { self.removeSlide(); });
}, 100);
$(document.body).on("media-saved", function () {
self.resizeImgsEditor();
});
},
resizeImgsEditor: function () {
var self = this;
setTimeout(function () {
self.trigger_up('widgets_start_request', {
editableMode: true,
$target: self.$target,
});
});
},
reset: function () {
var self= this;
self.$target.find(".s_css_slider_pagination").remove().end()
.find("span").unbind("click.s_css");
},
addSlide: function () {
var self = this;
var $currentSlide = self.$target.find(".slider .slide.selected");
$currentSlide.clone().insertAfter($currentSlide).removeClass("selected");
_.defer(function () {
self.reset();
self.trigger_up('widgets_start_request', {
editableMode: true,
$target: self.$target,
});
});
},
removeSlide: function () {
var self = this;
var $currentSlide = self.$target.find(".slider .slide.selected");
$currentSlide.remove();
_.defer(function () {
self.reset();
self.trigger_up('widgets_start_request', {
editableMode: true,
$target: self.$target,
});
});
},
cleanForSave: function () {
var self = this;
self.$target
.find(".s_css_slider_pagination").remove().end()
.find(".navigation .prev").addClass("inactive").end()
.find(".navigation .next").removeClass("inactive").end()
.find(".slider .slide").removeClass("selected move-left").end()
.find(".slider .slide").first().addClass("selected");
},
});
});
@@ -0,0 +1,122 @@
odoo.define('theme_common.s_css_slider_frontend', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
publicWidget.registry.s_css_slider = publicWidget.Widget.extend({
selector: ".s_css_slider",
disabledInEditableMode: false,
start: function () {
var self = this;
var $container = self.$target;
$container.find(".s_css_slider_pagination").remove();
// create slider pagination
var sliderPagination = self.createSliderPagination($container);
self.bindEvents($container, sliderPagination);
$(window).on("resize", function () {
self.resizeImgs($container);
}).trigger("resize");
return this._super.apply(this, arguments);
},
bindEvents: function ($container, sliderPagination) {
var self = this,
$next_btn = $container.find('.next'),
$prev_btn = $container.find('.prev');
$next_btn.on('click.s_css', function (e) {
self.nextSlide($container, sliderPagination);
});
$prev_btn.on('click.s_css', function (e) {
self.prevSlide($container, sliderPagination);
});
if ($container.hasClass("autoplay") && this.editableMode !== true) {
var interval;
var autoplay = function () {
interval = setInterval(function () {
if (!$next_btn.hasClass("inactive")) {
self.nextSlide($container, sliderPagination);
} else {
self.prevSlide($container, sliderPagination, 0);
}
}, 3000);
};
autoplay();
$container.hover(function () { clearInterval(interval); });
$container.mouseleave(function () { autoplay(); });
}
sliderPagination.on('click.s_css', function () {
var selectedDot = $(this);
if (!selectedDot.hasClass('selected')) {
var selectedPosition = selectedDot.index(),
activePosition = $container.find('.slider .selected').index();
if ( activePosition < selectedPosition) {
self.nextSlide($container, sliderPagination, selectedPosition);
} else {
self.prevSlide($container, sliderPagination, selectedPosition);
}
}
});
},
resizeImgs: function ($container) {
var cont_h = $container.height(),
imgs = $container.find(".slide img");
imgs.each(function () {
var $img = $(this),
img_h = $img.height();
if (img_h > cont_h) {
$img.css("width", "100%");
$img.css("margin-top", (cont_h - img_h)/2);
}
});
},
createSliderPagination: function ($container) {
var wrapper = $('<ul class="s_css_slider_pagination"></ul>').insertAfter($container.find('.navigation'));
$container.find('.slider .slide').each(function (index) {
var dotWrapper = (index === 0) ? $('<li class="selected"></li>') : $('<li></li>'),
dot = $('<a href="#0"></a>').appendTo(dotWrapper);
dotWrapper.appendTo(wrapper);
dot.text(index+1);
});
return wrapper.children('li');
},
nextSlide: function ($container, $pagination, $n) {
var self = this,
visibleSlide = $container.find('.slider .selected'),
navigationDot = $container.find('.s_css_slider_pagination .selected');
if (typeof $n === 'undefined') $n = visibleSlide.index() + 1;
visibleSlide.removeClass('selected');
$container.find('.slider .slide').eq($n).addClass('selected').prevAll().addClass('move-left');
navigationDot.removeClass('selected');
$pagination.eq($n).addClass('selected');
self.updateNavigation($container, $container.find('.slider .slide').eq($n));
},
prevSlide: function ($container, $pagination, $n) {
var self = this,
visibleSlide = $container.find('.slider .selected'),
navigationDot = $container.find('.s_css_slider_pagination .selected');
if (typeof $n === 'undefined') $n = visibleSlide.index() - 1;
visibleSlide.removeClass('selected');
$container.find('.slider .slide').eq($n).addClass('selected').removeClass('move-left').nextAll().removeClass('move-left');
navigationDot.removeClass('selected');
$pagination.eq($n).addClass('selected');
self.updateNavigation($container, $container.find('.slider .slide').eq($n));
},
updateNavigation: function ($container, $active) {
$container.find('.prev').toggleClass('inactive', $active.is(':first-child'));
$container.find('.next').toggleClass('inactive', $active.is(':last-child'));
},
});
});
@@ -0,0 +1,149 @@
odoo.define('theme_common.s_google_map_editor', function (require) {
'use strict';
var Dialog = require('web_editor.widget').Dialog;
var core = require('web.core');
var sOptions = require('web_editor.snippets.options');
var googleScriptLoaded = require('theme_common.s_google_map_frontend').googleScriptLoaded;
var _t = core._t;
sOptions.registry.map = sOptions.Class.extend({
xmlDependencies: ['/theme_common/static/src/xml/s_google_map_modal.xml'],
defaultLocation: '(50.854975,4.3753899)',
/**
* @override
*/
onBuilt: function () {
this._super.apply(this, arguments);
this.map('click', null, null);
},
//--------------------------------------------------------------------------
// Options
//--------------------------------------------------------------------------
/**
* Opens the customization dialog.
*
* @see this.selectClass for parameters
*/
map: function (previewMode, value, $opt) {
var self = this;
this.dialog = new Dialog(this, {
size: 'medium',
title: _t("Customize your map"),
buttons: [
{text: _t("Save"), classes: 'btn-primary', close: true, click: function () {
if (!this.$('#placeBk').val()) {
this.$('#placeBk').val(self.defaultLocation);
}
self.$target.attr({
'data-map-gps': this.$('#placeBk').val(),
'data-pin-style': this.$('#pin_style').val(),
'data-pin-address': this.$('#pin_address').val(),
});
self.trigger_up('widgets_start_request', {
editableMode: true,
$target: self.$target,
});
}},
{text: _t("Cancel"), close: true}
],
$content: $(core.qweb.render('theme_common.s_google_map_modal'))
});
this.dialog.opened().then((function () {
this.$('#pin_address').val(self.$target.attr('data-pin-address'));
this.$('#pin_style').val(self.$target.attr('data-pin-style'));
this.$('#placeBk').val(self.$target.attr('data-map-gps'));
var autocomplete = new google.maps.places.Autocomplete(this.$('#pin_address').get(0), {types: ['geocode']});
google.maps.event.addListener(autocomplete, 'place_changed', function () {
var place = autocomplete.getPlace();
self.dialog.$('#placeBk').val(place.geometry ? place.geometry.location : self.defaultLocation);
});
}).bind(this.dialog));
googleScriptLoaded.then(function () {
self.dialog.open();
});
},
/**
* Adapts map's type.
*
* @see this.selectClass for parameters
*/
mapType: function (previewMode, value, $opt) {
this.$target.attr('data-map-type', value);
this.$target.attr('data-map-color', '');
this.trigger_up('widgets_start_request', {
editableMode: true,
$target: this.$target,
});
},
/**
* Adapts map's color.
*
* @see this.selectClass for parameters
*/
mapColor: function (previewMode, value, $opt) {
this.$target.attr('data-map-color', value);
this.trigger_up('widgets_start_request', {
editableMode: true,
$target: this.$target,
});
},
/**
* Adapts map's zoom.
*
* @see this.selectClass for parameters
*/
mapZoom: function (previewMode, value, $opt) {
this.$target.attr('data-map-zoom', value);
this.trigger_up('widgets_start_request', {
editableMode: true,
$target: this.$target,
});
},
/**
* Adapts map's location.
*
* @see this.selectClass for parameters
*/
mapGps: function (previewMode, value, $opt) {
this.$target.attr('data-map-gps', value);
this.trigger_up('widgets_start_request', {
editableMode: true,
$target: this.$target,
});
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
/**
* @override
*/
_setActive: function () {
this.$el.find('[data-map-type]')
.removeClass('active')
.filter('[data-map-type="' + this.$target.attr('data-map-type') + '"]')
.addClass('active');
this.$el.find('[data-map-color]')
.removeClass('active')
.filter('[data-map-color="' + this.$target.attr('data-map-color') + '"]')
.addClass('active');
this.$el.find('[data-map-zoom]')
.removeClass('active')
.filter('[data-map-zoom="' + this.$target.attr('data-map-zoom') + '"]')
.addClass('active');
this.$el.find('[data-map-gps]')
.removeClass('active')
.filter('[data-map-gps="' + this.$target.attr('data-map-gps') + '"]')
.addClass('active');
},
});
});
@@ -0,0 +1,146 @@
odoo.define('theme_common.s_google_map_frontend', function (require) {
'use strict';
var core = require('web.core');
var publicWidget = require('web.public.widget');
var googleScriptLoaded = $.Deferred();
var _t = core._t;
publicWidget.registry.s_google_map = publicWidget.Widget.extend({
selector: '.s_google_map',
disabledInEditableMode: false,
/**
* @override
*/
start: function () {
var self = this;
var defs = [this._super.apply(this, arguments)];
if (typeof google !== 'object' || typeof google.maps !== 'object') {
if (!publicWidget.registry.s_google_map.isScriptLoading) {
publicWidget.registry.s_google_map.isScriptLoading = true;
window.odoo_s_google_map_redraw_all = function odoo_s_google_map_redraw_all() {
self.trigger_up('widgets_start_request', {
editableMode: self.editableMode,
$target: $('section.s_google_map'),
});
publicWidget.registry.s_google_map.isScriptLoading = false;
googleScriptLoaded.resolve();
};
defs.push(this._rpc({
route: '/theme_common/google_maps_api_key',
}).then(function (data) {
var key_param = '';
var data_json = JSON.parse(data);
if (!data_json.google_maps_api_key) {
publicWidget.registry.s_google_map.isScriptLoading = false;
if (self.editableMode) {
self.$loadingWarning = $('<div/>', {
class: 'alert alert-warning alert-link',
}).append($('<a/>', {
href: "#",
text: _t("Cannot load google map, check your configuration !"),
})).click(function (e) {
window.location.href = "/web#action=website.action_website_configuration";
});
self.$('.map_container').append(self.$loadingWarning);
}
return;
}
key_param = '&key=' + data_json.google_maps_api_key;
$('head').append($('<script/>', {
type: "text/javascript",
src: "https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=places&callback=odoo_s_google_map_redraw_all" + key_param,
}));
}));
}
return $.when.apply($, defs);
}
// Define a default map's colors set
var std = [];
new google.maps.StyledMapType(std, {name: "Std Map"});
// Default options, will be overwritten by the user
var myOptions = {
zoom: 12,
center: new google.maps.LatLng(50.854975,4.3753899),
mapTypeId: google.maps.MapTypeId.ROADMAP,
panControl: false,
zoomControl: false,
mapTypeControl: false,
streetViewControl: false,
scrollwheel: false,
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, 'map_style']
}
};
// Render Map
var mapC = this.$target.find('.map_container');
var map = new google.maps.Map(mapC.get(0), myOptions);
// Update GPS position
var p = this.$target.attr('data-map-gps').substring(1).slice(0, -1).split(',');
var gps = new google.maps.LatLng(p[0], p[1]);
map.setCenter(gps);
// Update Map on screen resize
google.maps.event.addDomListener(window, 'resize', function () {
map.setCenter(gps);
});
// Create Marker & Infowindow
if (this.$target.attr('data-pin-style') === "flat") {
new google.maps.Marker({
map: map,
animation: google.maps.Animation.DROP,
position: new google.maps.LatLng(p[0],p[1]),
icon: "/theme_common/static/src/img/snippets/s_google_map_marker.png",
});
} else {
new google.maps.Marker({
map: map,
animation: google.maps.Animation.DROP,
position: new google.maps.LatLng(p[0], p[1])
});
}
map.setMapTypeId(google.maps.MapTypeId[this.$target.attr('data-map-type')]); // Update Map Type
map.setZoom(parseInt(this.$target.attr('data-map-zoom'))); // Update Map Zoom
// Update Map Color
if (this.$target.attr('data-map-color') !== "") {
var mapColor = eval("this." + this.$target.attr('data-map-color'));
var thisMap = new google.maps.StyledMapType(mapColor, {name: "Styled Map"});
map.mapTypes.set('map_style', thisMap);
map.setMapTypeId('map_style');
}
return $.when.apply($, defs);
},
/**
* @override
*/
destroy: function () {
this._super.apply(this, arguments);
if (this.$loadingWarning) {
this.$loadingWarning.remove();
}
},
});
// This allows to save if the google maps script is already loading or not.
// This script cannot be loaded 2 times, so if we have 2 snippets in the same
// page we don't want to load the script 2 times.
// And we cannot put the script in an asset because we don't want to load it
// on each page, but only on pages with a google maps snippet...
publicWidget.registry.s_google_map.prototype.isScriptLoading = false;
return {
googleScriptLoaded: googleScriptLoaded,
};
});
@@ -0,0 +1,106 @@
odoo.define('theme_common.s_media_block_editor', function (require) {
'use strict';
var core = require('web.core');
var s_options = require('web_editor.snippets.options');
require("theme_common.s_media_block_frontend");
var QWeb = core.qweb;
// MEDIABLOCK EDITOR
// Image background - Fix for mediablock
s_options.registry.background.include({
selectClass: function (previewMode, value, $li) {
var self = this;
this._super(previewMode, value, $li);
if (this.$target.hasClass("s_media_block")) {
var objs = self.$target.find(".videoBox, > iframe, .yt_video_container");
objs.stop(true,true)
.fadeOut(200)
.delay(300)
.fadeIn(2000);
}
},
}),
s_options.registry.s_media_block = s_options.Class.extend({
xmlDependencies: ['/theme_common/static/src/xml/s_media_block_modal.xml'],
videoOpt: function (previewMode, value, $opt) {
var self = this;
self.trigger_up('widgets_stop_request', {
editableMode: true,
$target: self.$target,
});
self.$modal = $(QWeb.render("theme_common.s_media_block_modal"));
self.$modal.appendTo('body').modal();
var $src = self.$modal.find('#media_block_src'),
$cancel = self.$modal.find("#cancel"),
$sub_data = self.$modal.find("#sub_data");
var field_names = ['src', 'muted', 'loop', 'controls', 'autoplay', 'opacity', 'background', 'iframefit'];
_.each(field_names, function (field_name) {
var value = self.$target.attr(field_name);
var $fields = self.$modal.find('[name="'+field_name+'"]');
$fields.each(function (i, field) {
var $field = $(field);
if ($field.is(':radio, :checkbox')) {
$field.prop('checked', $field.val() === value);
} else if (!_.isUndefined(value)) {
$field.val(value);
}
});
});
if (!$src.val()) {
// if custom code is empty,provide an example video
$src.val('<iframe src="//player.vimeo.com/video/105977011?title=0&amp;byline=0&amp;portrait=0&amp;color=24a8bf&amp;autoplay=1&amp;loop=1" width="500" height="264" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>');
self.$target.attr('src', $src.val());
}
$sub_data.on('click', function () {
_.each(field_names, function (field_name) {
var field = self.$modal.find('[name="'+field_name+'"]').filter(':checked, :not(:checkbox, :radio)');
self.$target.removeAttr(field_name).attr(field_name, field.val());
});
self.trigger_up('widgets_start_request', {
editableMode: true,
$target: self.$target,
});
});
$cancel.on('click', function () {
self.trigger_up('widgets_start_request', {
editableMode: true,
$target: self.$target,
});
});
var update_form = function () {
self.$target.attr('src', this.value);
self.trigger_up('widgets_start_request', {
editableMode: true,
$target: self.$target,
});
self.$modal.find('form').attr('data-video-type', self.$target.data('video-type'));
};
$src
.on('keyup', _.throttle(update_form, 700))
.on('change', function () {
update_form.call(this);
this.value = self.$target.attr('src');
})
.keyup();
this.$modal.on('hidden.bs.modal', function () {
self.trigger_up('widgets_start_request', {
editableMode: true,
$target: self.$target,
});
$(this).remove();
});
},
});
});
@@ -0,0 +1,280 @@
odoo.define('theme_common.s_media_block_frontend', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
// MEDIABLOCK EDITOR
publicWidget.registry.s_media_block = publicWidget.Widget.extend({
selector : "section.s_media_block",
start: function () {
this.start_video();
return this._super.apply(this, arguments);
},
destroy: function () {
this._super.apply(this, arguments);
this.stop_video();
},
update_video_type: function () {
var regex_url = '((?:https?:)?//([^\\s\'"<>\\\\/]+)/([^\\s\'"<>\\\\]+))';
var match = this.src.match(new RegExp('\\ssrc=[\'"]?' + regex_url));
match = match || this.src.match(new RegExp('^\\s*' + regex_url));
if (!match) {
this.video_type = "image";
this.src = "";
return;
}
var url = match[1];
var domain = match[2];
var path = match[3];
match = undefined;
var services_prefix = {
youtube: 'https://youtu.be/',
vimeo: 'https://vimeo.com/',
dailymotion: 'http://dai.ly/',
};
if (/\.youtube(-nocookie)?\./.test(domain)) {
this.video_type = 'youtube';
match = path.match(/^(?:embed\/|watch\?v=)?([^\/?&#]+)/i);
} else if (domain === "youtu.be") {
this.video_type = 'youtube';
match = path.match(/^([^\/?&#]+)/);
} else if (_.str.include(domain, "vimeo.")) {
this.video_type = 'vimeo';
match = path.match(/^(?:video\/)?([^?&#]+)/i);
} else if (_.str.include(domain, ".dailymotion.")) {
this.video_type = "dailymotion";
match = path.match(/(?:embed\/)?(?:video\/)?([^\/?&#_]+)/i);
} else if (domain === "dai.ly") {
this.video_type = "dailymotion";
match = path.match(/^([^\/?&#]+)/);
}
if (match) {
this.src = services_prefix[this.video_type] + match[1];
} else if (!/\ssrc=/.test(this.src)) {
this.src = url;
this.video_type = 'html5';
} else {
this.video_type = 'other';
}
this.$target.data('video-type', this.video_type);
},
start_video: function () {
var self = this;
var video_url;
// mobile phones are not supported, just show the background image.
if (jQuery.browser.mobile) { return; }
if (!self.video_type || self.src !== self.$target.attr('src')) {
self.src = self.$target.attr('src');
if (!self.src) {
return;
}
self.update_video_type();
}
var params = _.chain(['muted', 'loop', 'autoplay', 'controls']).map(function (attribute) {
var value = self.$target.attr(attribute);
return [attribute, value ? 1 : value];
}).object().value();
var video_id = self.src.split('/')[3];
switch (self.video_type) {
case 'html5':
video_url = self.src;
break;
case 'youtube':
video_url = "https://www.youtube.com/embed/" + video_id;
if ('muted' in params) params['mute'] = 1;
if ('loop' in params) params['playlist'] = video_id;
_.extend(params, {iv_load_policy: 3, rel: 0, showinfo: 0});
break;
case 'vimeo':
video_url = "https://player.vimeo.com/video/" + video_id;
_.extend(params, {color: 'fff', title: 0, byline: 0, portrait: 0, badge: 0});
break;
case 'dailymotion':
video_url = "https://www.dailymotion.com/embed/video/" + video_id;
if (!params["controls"]) params["chromeless"] = 1;
_.extend(params, {logo: 0, info: 0, related: 0, wmode: 'opaque'});
break;
}
var whenPlayerReady = (self['create_' + self.video_type + '_video'] || self['create_video']).call(self, self.$target, video_url, params);
whenPlayerReady.then(function ($player) {
$player.fadeTo(0, 0);
$player.addClass('o_player').parent().addClass('o_player_wrapper');
self.ratio = ($player.width() / $player.height());
if (self.$target.attr('iframefit') === 'fitCont') {
$player.parentsUntil(self.$target).css({width: '100%', height: 'auto'});
if ($player.is('iframe')) {
$player.css('width', '100%');
$player.height($player.width() / self.ratio);
} else {
$player.css({width: '100%', height: 'auto'});
}
} else if (self.$target.attr('iframefit') === 'fitIframe') {
$player.parentsUntil(self.$target).andSelf().css({width: '100%', height: '100%'});
}
$player.fadeTo("slow", 1);
$player.removeClass('o_media_loading');
$(window).trigger('resize');
});
},
stop_video: function () {
this.$target.find('.videoBox, iframe').remove();
$(window).unbind('resize.s_media_block');
},
create_video: function ($container, video_url, params) {
var def = $.Deferred();
var $iframe;
if (video_url) {
$iframe = $('<iframe/>', {
frameborder: "0",
allowfullscreen: "allowfullscreen",
src: video_url + '?' + $.param(params),
});
} else {
$iframe = $('<div/>').html(this.src).find('iframe:first').css({
height: "100%", width: "100%", top: 0, position: "absolute",
});
if ($iframe.length) {
$container.css('max-height', '');
} else {
return def.reject();
}
}
$iframe.addClass('o_media_loading o_temp_auto_element');
$iframe.on('load', function () {
def.resolve($iframe);
});
$container.append($iframe);
return def;
},
create_html5_video: function ($container, video_url, params) {
var def = $.Deferred();
var $video_content = $('<video/>', {'class': 'videoBox d-none d-md-block o_temp_auto_element', 'preload': 'metadata'}).attr(params).attr('src', video_url);
$video_content.addClass('o_media_loading');
$video_content.on('canplay', function () {
def.resolve($video_content);
});
$container.append($video_content);
$video_content.get(0).load();
if (params['autoplay']) {
$video_content.get(0).play();
}
return def;
},
// When the visitor is logged in YouTube, the console return "Failed to execute 'postMessage'";
// That is a known error from the side of the Youtube API.
// Fortunately it's not blocking but unfortunatly the fix should be done by the Google team.
YTPlayer_video: function ($container, video_url, _params) {
var video_id = this.src.split('/')[3];
var params = _.mapObject(_params, function (v) { return !!v; });
var opacity = this.$target.attr('opacity');
var background = this.$target.attr('background') || '';
var timeStamp = Date.now();
var $video_container = $('<div/>', {
'class': 'yt_video_container '+ background,
id: "s_media_block_" + timeStamp,
});
var playerParams = {
videoURL: video_id, containment: '#s_media_block_' + timeStamp, mute: params['muted'], loop: params['loop'],
stopMovieOnBlur: false, autoPlay: true, showYTLogo: false, opacity: opacity, showControls: false,
};
var $el = $('<div/>', {'class': 'player', 'data-property': JSON.stringify(playerParams)});
var $loader = $("<span class='yt-loader'><span/></span>");
$video_container.append($el).append($loader);
var interval = null;
if ($("#oe_main_menu_navbar").length > 0) { $loader.css("top", $("#oe_main_menu_navbar").outerHeight()+1); }
$loader.animate({width: "45%"}, 800, function () {
var el = $loader;
interval = setInterval(function () { timer(); }, 300);
function timer() { var w = el.width(); el.width(w + 5); }
});
if (!params['autoplay']) {
$el.one('YTPStart', function () {
$el.YTPPause();
});
}
var def = $.Deferred();
$el.on('YTPReady', function () {
clearInterval(interval);
$loader.css("width", "100%").fadeOut(500);
def.resolve($video_container.find('iframe'));
if (!params['controls'] && params['autoplay']) {
return;
}
var $controls = $("<span/>", {'class': 'controls'}).appendTo($video_container);
var $btnplay = $("<span/>", {'class': 'fa fa-fw'}).appendTo($controls);
var playing = params['autoplay'];
$btnplay.toggleClass("fa-pause", playing).toggleClass("fa-play", !playing);
$btnplay.on("click", play_callback);
if (!params['controls']) {
$btnplay.one('click', function () {
$controls.remove();
});
}
if (!params['muted'] && params['controls']) {
var $btnMute = $("<span/>", {'class': 'fa fa-fw fa-volume-up'}).appendTo($controls);
$btnMute.on("click", mute_callback);
}
function play_callback() {
if (playing) {
$el.YTPPause();
} else {
$el.YTPPlay();
}
playing = !playing;
$btnplay.toggleClass("fa-pause", playing).toggleClass("fa-play", !playing);
}
function mute_callback() {
$el.YTPToggleVolume();
$btnMute.toggleClass("fa-volume-up").toggleClass("fa-volume-off");
}
});
$container.append($video_container);
$el.YTPlayer();
return def;
},
});
});
@@ -0,0 +1,30 @@
odoo.define('theme_common.s_mini_nav_bar', function (require) {
'use strict';
var publicWidget = require('web.public.widget');
publicWidget.registry.miniNavbarScroll = publicWidget.Widget.extend({
selector: '.s_mini_nav_bar a[href*="#"]:not([href="#"])',
events: {
'click': '_onClick',
},
//----------------------------------------------------------------------
// Handlers
//----------------------------------------------------------------------
/**
* Called on click on the mini navbar link -> scroll to the section.
*
* @private
*/
_onClick: function (ev) {
var index = $(this).parent().index();
var target = $('.o_scroll_nav').get(index);
if (target) {
ev.preventDefault();
$('html,body').animate({ scrollTop: $(target).offset().top }, 1000);
}
},
});
});
@@ -0,0 +1,45 @@
odoo.define('theme_common.s_progress_bar', function (require) {
'use strict';
var s_options = require('web_editor.snippets.options');
s_options.registry.progress = s_options.Class.extend({
start: function () {
if (this.$overlay) {
this.bind_move_progress();
}
this._super();
},
bind_move_progress: function () {
var self = this;
var $e = this.$overlay.find(".o_handle.e").removeClass("readonly");
var $parent = this.$target.parent();
var pos = $parent.offset();
var width = $parent.width();
var time;
function move(event) {
clearTimeout(time);
time = setTimeout(function () {
var value = (event.clientX - pos.left)/width*100 | 0;
if (value > 100 ) value = 100;
if (value < 0 ) value = 0;
self.$target.text( self.$target.text().replace(/[0-9]+/, value) );
self.$target.attr("data-value", value);
if (value < 3 ) value = 3;
self.$target.css("width", value + "%");
},5);
}
$e.on("mousedown", function () {
self.$overlay.addClass('d-none');
$(document)
.on("mousemove", move)
.one("mouseup", function () {
self.$overlay.removeClass('d-none');
$(document).off("mousemove", move);
self.trigger_up('cover_update');
});
});
},
});
});
@@ -0,0 +1,40 @@
odoo.define('theme_common.s_showcase_editor.js', function (require) {
'use strict';
var s_options = require('web_editor.snippets.options');
s_options.registry.s_showcase = s_options.Class.extend({
onClone: function () {
this._reset_alignment();
},
onRemove: function () {
this._reset_alignment(this.$target);
},
_reset_alignment: function ($exclude) {
var $features = this.$target.closest(".s_showcase").find(".feature").not($exclude);
// Remove classes used in the previus implementation
$features.removeClass('offset-md-2');
// Wait until the $clone element is in place
setTimeout(function () {
$features.unwrap('.row');
_.each($features, function (feat, i) {
var even = (i % 2 === 0);
$(feat)
.toggleClass('text-right', even)
.toggleClass('text-left', !even)
.toggleClass('offset-lg-2', !even);
});
// Re-wrap in rows
for (var i = 0; i < $features.length; i+=2) {
$features.slice(i, i + 2).wrapAll("<div class='row'/>");
}
}, 100);
}
});
});
@@ -0,0 +1,43 @@
odoo.define('theme_common.s_showcase_slider_editor.js', function (require) {
'use strict';
var s_options = require('web_editor.snippets.options');
require("theme_common.s_showcase_slider_frontend");
s_options.registry.s_showcase_slider = s_options.Class.extend({
start: function () {
this._super.apply(this, arguments);
this.$target.on("transitionIsFinished", (function () {
this.trigger_up('cover_update');
}).bind(this));
_.delay((function () { // FIXME ...
this.$overlay.find(".js_s_ss_addSlide").on('click', this.addSlide.bind(this));
this.$overlay.find(".js_s_ss_removeSlide").on('click', this.removeSlide.bind(this));
}).bind(this), 100);
},
resetSlides: function (active) {
this.trigger_up('widgets_start_request', {
editableMode: true,
$target: this.$target,
});
this.$target.toggleClass("active", !!active);
},
addSlide: function () {
var $currentSlide = this.$target.find(".s_ss_slider > .selected");
$currentSlide.after("<li><img class=\"o_not-animable\" src=\"/web/image/theme_common.image_content_23\"/></li>");
this.resetSlides(true);
},
removeSlide: function () {
if (this.$target.find(".s_ss_slider").children().length <= 1) return;
var $currentSlide = this.$target.find(".s_ss_slider > .selected");
$currentSlide.remove();
this.resetSlides(true);
},
});
});
@@ -0,0 +1,130 @@
odoo.define("theme_common.s_showcase_slider_frontend", function (require) {
"use strict";
var publicWidget = require('web.public.widget');
publicWidget.registry.s_showcase_slider = publicWidget.Widget.extend({
selector: ".s_showcase_slider",
start: function () {
_.defer(this.bindEvents.bind(this)); // FIXME delayed to counter a web_editor bug which off all click event
this.createPagination();
return this._super.apply(this, arguments);
},
destroy: function () {
this._super.apply(this, arguments);
_.defer(this.unbindEvents.bind(this)); // FIXME delayed to counter a web_editor bug which off all click event
this.destroyPagination();
this.$target.removeClass("active");
},
bindEvents: function () {
// Enlarge image on click if not already enlarged
this.$target.on("click.s_showcase_slider", ".s_ss_slider", (function (e) {
if (this.$target.hasClass("active")) return;
this.$target
.addClass("active")
.one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend", (function () {
$("body, html").animate({
scrollTop: this.$target.offset().top - 70
}, 200);
this.$target.trigger("transitionIsFinished");
}).bind(this));
}).bind(this));
// Close the enlarged image on close icon click
this.$target.on("click.s_showcase_slider", ".s_ss_close", (function (e) {
this.$target.removeClass("active");
}).bind(this));
// Handle click navigation
this.$target.on("click.s_showcase_slider", ".s_ss_prev", this.prevSlide.bind(this));
this.$target.on("click.s_showcase_slider", ".s_ss_next", this.nextSlide.bind(this));
this.$target.on("click.s_showcase_slider", ".s_ss_slider_pagination > li > a", (function (e) {
e.preventDefault();
var $selectedDot = $(e.currentTarget).parent();
if ($selectedDot.hasClass("selected")) return;
this.changeSlide($selectedDot.index());
}).bind(this));
// Keyboard slider navigation
$(document).on("keyup.s_showcase_slider", (function (e) {
if (!this.$target.hasClass("active")) return;
switch (e.which) {
case $.ui.keyCode.LEFT:
this.prevSlide();
break;
case $.ui.keyCode.RIGHT:
this.nextSlide();
break;
case $.ui.keyCode.ESCAPE:
this.$target.removeClass("active");
break;
}
}).bind(this));
},
unbindEvents: function () {
this.$target.off(".s_showcase_slider");
$(document).off(".s_showcase_slider");
},
createPagination: function () { // FIXME pagination should be saved with editor but keep this for compatibility
this.$target.find(".s_ss_slider_pagination").remove(); // Remove saved-with-editor pagination
this.$pagination = $("<ul/>", {class: "s_ss_slider_pagination"});
this.$pagination.insertAfter(this.$target.find(".s_ss_slider_navigation"));
var nbSlides = this.$target.find(".s_ss_slider").children().length;
for (var i = 0 ; i < nbSlides ; i++) {
this.$pagination.append("<li><a href=\"#\"></a></li>");
}
this.$pagination.children().eq(this.getCurrentIndex()).addClass("selected");
},
destroyPagination: function () {
if (this.$pagination) {
this.$pagination.remove();
this.$pagination = null;
}
},
prevSlide: function () {
var nbSlides = this.$target.find(".s_ss_slider").children().length;
var currentIndex = this.getCurrentIndex();
this.changeSlide(currentIndex > 0 ? (currentIndex - 1) : (nbSlides - 1));
},
nextSlide: function () {
var nbSlides = this.$target.find(".s_ss_slider").children().length;
var currentIndex = this.getCurrentIndex();
this.changeSlide((currentIndex + 1) % nbSlides);
},
getCurrentIndex: function () {
return this.$target.find(".s_ss_slider > .selected").index();
},
changeSlide: function (n) {
var $slides = this.$target.find(".s_ss_slider > li").removeClass("selected");
this.$target.find(".s_ss_slider_pagination > li").removeClass("selected");
var $slide = $slides.eq(n).addClass("selected");
$slides.removeClass("move-left");
$slide.prevAll().addClass("move-left");
this.$pagination.children().eq(n).addClass("selected");
this.updateNavigation();
},
updateNavigation: function () {
var $active = this.$target.find(".s_ss_slider > .selected");
this.$target.find(".s_ss_prev").toggleClass("inactive", $active.is(":first-child"));
this.$target.find(".s_ss_next").toggleClass("inactive", $active.is(":last-child"));
},
});
});
@@ -0,0 +1,17 @@
// This file is for compatibility since saas-10 web_editor refactoring.
// As a fix to work properly in the editor, some classes have been renamed.
// To allow a smooth transition, old classes alias are created here.
@mixin bg-compatibility-mixin($bg, $color) {
background-color: $bg;
color: $color;
.text-muted {
color: rgba($color, 0.4);
}
}
.black { @include bg-compatibility-mixin($black, gray('600')); }
.darkgray { @include bg-compatibility-mixin(gray('800'), $white); }
.gray { @include bg-compatibility-mixin(gray('700'), $white); }
.lightgray { @include bg-compatibility-mixin(gray('200'), gray('700')); }
.white { @include bg-compatibility-mixin($white, gray('700')); }

Some files were not shown because too many files have changed in this diff Show More