summaryrefslogtreecommitdiff
path: root/addons/website/static/src
diff options
context:
space:
mode:
authorBenjamin Vray <bvr@odoo.com>2020-01-07 14:38:28 +0000
committerqsm-odoo <qsm@odoo.com>2020-01-24 13:02:01 +0000
commit7572cc150d5469af92138533a024cffbd57d878e (patch)
treea035c7e97f34075a34e2e68ed3503e56c99e9ecb /addons/website/static/src
parentca5f9ce26d7369d0450c3d2c1b406b904e838210 (diff)
[IMP] website: review snippet tabs
Adding new options that are available through Bootstrap (Tabs or pills class for nav-item. Alignment, menu horizontal/vertical, etc). Adding a slide transition option. The snippet becomes also a drag&drop zone. Part of https://github.com/odoo/odoo/pull/42937 task-2088157 task-2152185
Diffstat (limited to 'addons/website/static/src')
-rw-r--r--addons/website/static/src/js/editor/snippets.options.js132
-rw-r--r--addons/website/static/src/scss/website.scss1
-rw-r--r--addons/website/static/src/snippets/s_tabs/001.scss25
-rw-r--r--addons/website/static/src/snippets/s_tabs/options.js167
4 files changed, 211 insertions, 114 deletions
diff --git a/addons/website/static/src/js/editor/snippets.options.js b/addons/website/static/src/js/editor/snippets.options.js
index 0dbe26b024f..9765bc57473 100644
--- a/addons/website/static/src/js/editor/snippets.options.js
+++ b/addons/website/static/src/js/editor/snippets.options.js
@@ -393,119 +393,6 @@ options.registry.CarouselItem = options.Class.extend({
},
});
-options.registry.navTabs = options.Class.extend({
- /**
- * @override
- */
- start: function () {
- this._findLinksAndPanes();
- return this._super.apply(this, arguments);
- },
- /**
- * @override
- */
- onBuilt: function () {
- this._generateUniqueIDs();
- },
- /**
- * @override
- */
- onClone: function () {
- this._generateUniqueIDs();
- },
-
- //--------------------------------------------------------------------------
- // Options
- //--------------------------------------------------------------------------
-
- /**
- * Creates a new tab and tab-pane.
- *
- * @see this.selectClass for parameters
- */
- addTab: function (previewMode, widgetValue, params) {
- var $activeItem = this.$navLinks.filter('.active').parent();
- var $activePane = this.$tabPanes.filter('.active');
-
- var $navItem = $activeItem.clone();
- var $navLink = $navItem.find('.nav-link').removeClass('active show');
- var $tabPane = $activePane.clone().removeClass('active show');
- $navItem.insertAfter($activeItem);
- $tabPane.insertAfter($activePane);
- this._findLinksAndPanes();
- this._generateUniqueIDs();
-
- $navLink.tab('show');
- },
- /**
- * Removes the current active tab and its content.
- *
- * @see this.selectClass for parameters
- */
- removeTab: function (previewMode, widgetValue, params) {
- var self = this;
-
- var $activeLink = this.$navLinks.filter('.active');
- var $activePane = this.$tabPanes.filter('.active');
-
- var $next = this.$navLinks.eq((this.$navLinks.index($activeLink) + 1) % this.$navLinks.length);
-
- return new Promise(resolve => {
- $next.one('shown.bs.tab', function () {
- $activeLink.parent().remove();
- $activePane.remove();
- self._findLinksAndPanes();
- resolve();
- });
- $next.tab('show');
- });
- },
-
- //--------------------------------------------------------------------------
- // Private
- //--------------------------------------------------------------------------
-
- /**
- * @override
- */
- _computeWidgetVisibility: async function (widgetName, params) {
- if (widgetName === 'remove_tab_opt') {
- return (this.$tabPanes.length > 2);
- }
- return this._super(...arguments);
- },
- /**
- * @private
- */
- _findLinksAndPanes: function () {
- this.$navLinks = this.$target.find('.nav-link');
- var $el = this.$target;
- do {
- $el = $el.parent();
- this.$tabPanes = $el.find('.tab-pane');
- } while (this.$tabPanes.length === 0 && !$el.is('body'));
- },
- /**
- * @private
- */
- _generateUniqueIDs: function () {
- for (var i = 0; i < this.$navLinks.length; i++) {
- var id = _.now() + '_' + _.uniqueId();
- var idLink = 'nav_tabs_link_' + id;
- var idContent = 'nav_tabs_content_' + id;
- this.$navLinks.eq(i).attr({
- 'id': idLink,
- 'href': '#' + idContent,
- 'aria-controls': idContent,
- });
- this.$tabPanes.eq(i).attr({
- 'id': idContent,
- 'aria-labelledby': idLink,
- });
- }
- },
-});
-
options.registry.sizing_x = options.registry.sizing.extend({
/**
* @override
@@ -1171,6 +1058,17 @@ options.registry.SnippetMove = options.Class.extend({
return this._super(...arguments);
},
+ /**
+ * @override
+ */
+ onFocus: function () {
+ // TODO improve this: hack to hide options section if snippet move is
+ // the only one.
+ const $allOptions = this.$el.parent();
+ if ($allOptions.find('we-customizeblock-option').length <= 1) {
+ $allOptions.addClass('d-none');
+ }
+ },
//--------------------------------------------------------------------------
// Options
@@ -1182,12 +1080,20 @@ options.registry.SnippetMove = options.Class.extend({
* @see this.selectClass for parameters
*/
moveSnippet: function (previewMode, widgetValue, params) {
+ const isNavItem = this.$target[0].classList.contains('nav-item');
+ const $tabPane = isNavItem ? $(this.$target.find('.nav-link')[0].hash) : null;
switch (widgetValue) {
case 'prev':
this.$target.prev().before(this.$target);
+ if (isNavItem) {
+ $tabPane.prev().before($tabPane);
+ }
break;
case 'next':
this.$target.next().after(this.$target);
+ if (isNavItem) {
+ $tabPane.next().after($tabPane);
+ }
break;
}
},
diff --git a/addons/website/static/src/scss/website.scss b/addons/website/static/src/scss/website.scss
index 68a79f41a13..3637f8d714b 100644
--- a/addons/website/static/src/scss/website.scss
+++ b/addons/website/static/src/scss/website.scss
@@ -631,7 +631,6 @@ table.table_desc tr td {
}
}
-
//
// Layout
//
diff --git a/addons/website/static/src/snippets/s_tabs/001.scss b/addons/website/static/src/snippets/s_tabs/001.scss
new file mode 100644
index 00000000000..6e132e91f31
--- /dev/null
+++ b/addons/website/static/src/snippets/s_tabs/001.scss
@@ -0,0 +1,25 @@
+// Tabs
+.s_tabs[data-vcss="001"] {
+ .s_tabs_content {
+ &.s_tabs_slide_up, &.s_tabs_slide_down, &.s_tabs_slide_left, &.s_tabs_slide_right {
+ > .tab-pane.fade {
+ transition: all 0.2s;
+ }
+ > .tab-pane.fade.show {
+ transform: translateX(0rem) translateY(0rem);
+ }
+ }
+ &.s_tabs_slide_up > .tab-pane.fade {
+ transform: translateY(-1rem);
+ }
+ &.s_tabs_slide_down > .tab-pane.fade {
+ transform: translateY(1rem);
+ }
+ &.s_tabs_slide_left > .tab-pane.fade {
+ transform: translateX(-1rem);
+ }
+ &.s_tabs_slide_right > .tab-pane.fade {
+ transform: translateX(1rem);
+ }
+ }
+}
diff --git a/addons/website/static/src/snippets/s_tabs/options.js b/addons/website/static/src/snippets/s_tabs/options.js
new file mode 100644
index 00000000000..b10a7619f85
--- /dev/null
+++ b/addons/website/static/src/snippets/s_tabs/options.js
@@ -0,0 +1,167 @@
+odoo.define('website.s_tabs_options', function (require) {
+'use strict';
+
+const options = require('web_editor.snippets.options');
+
+options.registry.NavTabs = options.Class.extend({
+ isTopOption: true,
+
+ /**
+ * @override
+ */
+ start: function () {
+ this._findLinksAndPanes();
+ return this._super.apply(this, arguments);
+ },
+ /**
+ * @override
+ */
+ onBuilt: function () {
+ this._generateUniqueIDs();
+ },
+ /**
+ * @override
+ */
+ onClone: function () {
+ this._generateUniqueIDs();
+ },
+
+ //--------------------------------------------------------------------------
+ // Options
+ //--------------------------------------------------------------------------
+
+ /**
+ * Creates a new tab and tab-pane.
+ *
+ * @see this.selectClass for parameters
+ */
+ addTab: function (previewMode, widgetValue, params) {
+ var $activeItem = this.$navLinks.filter('.active').parent();
+ var $activePane = this.$tabPanes.filter('.active');
+
+ var $navItem = $activeItem.clone();
+ var $navLink = $navItem.find('.nav-link').removeClass('active show');
+ var $tabPane = $activePane.clone().removeClass('active show');
+ $navItem.insertAfter($activeItem);
+ $tabPane.insertAfter($activePane);
+ this._findLinksAndPanes();
+ this._generateUniqueIDs();
+
+ $navLink.tab('show');
+ },
+ /**
+ * Removes the current active tab and its content.
+ *
+ * @see this.selectClass for parameters
+ */
+ removeTab: function (previewMode, widgetValue, params) {
+ var self = this;
+
+ var $activeLink = this.$navLinks.filter('.active');
+ var $activePane = this.$tabPanes.filter('.active');
+
+ var $next = this.$navLinks.eq((this.$navLinks.index($activeLink) + 1) % this.$navLinks.length);
+
+ return new Promise(resolve => {
+ $next.one('shown.bs.tab', function () {
+ $activeLink.parent().remove();
+ $activePane.remove();
+ self._findLinksAndPanes();
+ resolve();
+ });
+ $next.tab('show');
+ });
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ _computeWidgetVisibility: async function (widgetName, params) {
+ if (widgetName === 'remove_tab_opt') {
+ return (this.$tabPanes.length > 2);
+ }
+ return this._super(...arguments);
+ },
+ /**
+ * @private
+ */
+ _findLinksAndPanes: function () {
+ this.$navLinks = this.$target.find('.nav:first .nav-link');
+ this.$tabPanes = this.$target.find('.tab-content:first .tab-pane');
+ },
+ /**
+ * @private
+ */
+ _generateUniqueIDs: function () {
+ for (var i = 0; i < this.$navLinks.length; i++) {
+ var id = _.now() + '_' + _.uniqueId();
+ var idLink = 'nav_tabs_link_' + id;
+ var idContent = 'nav_tabs_content_' + id;
+ this.$navLinks.eq(i).attr({
+ 'id': idLink,
+ 'href': '#' + idContent,
+ 'aria-controls': idContent,
+ });
+ this.$tabPanes.eq(i).attr({
+ 'id': idContent,
+ 'aria-labelledby': idLink,
+ });
+ }
+ },
+});
+options.registry.NavTabsStyle = options.Class.extend({
+
+ //--------------------------------------------------------------------------
+ // Options
+ //--------------------------------------------------------------------------
+
+ /**
+ * Set the style of the tabs.
+ *
+ * @see this.selectClass for parameters
+ */
+ setStyle: function (previewMode, widgetValue, params) {
+ const $nav = this.$target.find('.s_tabs_nav:first .nav');
+ const isPills = widgetValue === 'pills';
+ $nav.toggleClass('nav-tabs card-header-tabs', !isPills);
+ $nav.toggleClass('nav-pills', isPills);
+ this.$target.find('.s_tabs_nav:first').toggleClass('card-header', !isPills).toggleClass('mb-3', isPills);
+ this.$target.toggleClass('card', !isPills);
+ this.$target.find('.s_tabs_content:first').toggleClass('card-body', !isPills);
+ },
+ /**
+ * Horizontal/vertical nav.
+ *
+ * @see this.selectClass for parameters
+ */
+ setDirection: function (previewMode, widgetValue, params) {
+ const isVertical = widgetValue === 'vertical';
+ this.$target.toggleClass('row s_col_no_resize s_col_no_bgcolor', isVertical);
+ this.$target.find('.s_tabs_nav:first .nav').toggleClass('flex-column', isVertical);
+ this.$target.find('.s_tabs_nav:first > .nav-link').toggleClass('py-2', isVertical);
+ this.$target.find('.s_tabs_nav:first').toggleClass('col-md-3', isVertical);
+ this.$target.find('.s_tabs_content:first').toggleClass('col-md-9', isVertical);
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * @override
+ */
+ _computeWidgetState: function (methodName, params) {
+ switch (methodName) {
+ case 'setStyle':
+ return this.$target.find('.s_tabs_nav:first .nav').hasClass('nav-pills') ? 'pills' : 'tabs';
+ case 'setDirection':
+ return this.$target.find('.s_tabs_nav:first .nav').hasClass('flex-column') ? 'vertical' : 'horizontal';
+ }
+ return this._super(...arguments);
+ },
+});
+});