summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src
diff options
context:
space:
mode:
authorfja-odoo <fja@odoo.com>2019-11-15 16:13:17 +0000
committerqsm-odoo <qsm@odoo.com>2020-01-16 14:29:04 +0000
commit218e1cad6152999a0f41f073b5efa3c9428da48d (patch)
tree76ebfa75fcb86195fd4b4c14af7b87b8ad3920c8 /addons/web_editor/static/src
parent4946739c17488d32d3e61b1258ab48b5aec701a4 (diff)
[IMP] web_editor, *: allow saving of snippets
* website, mass_mailing, website_event, website_form, website_mass_mailing, website_sale Now the user can save snippets to use them on other pages. task-2120409 closes odoo/odoo#40408 Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com> Co-authored-by: qsm-odoo <qsm@odoo.com>
Diffstat (limited to 'addons/web_editor/static/src')
-rw-r--r--addons/web_editor/static/src/img/snippets_thumbs/s_custom_snippet.pngbin0 -> 977 bytes
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.editor.js105
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.options.js55
-rw-r--r--addons/web_editor/static/src/scss/wysiwyg_snippets.scss27
-rw-r--r--addons/web_editor/static/src/xml/editor.xml14
5 files changed, 179 insertions, 22 deletions
diff --git a/addons/web_editor/static/src/img/snippets_thumbs/s_custom_snippet.png b/addons/web_editor/static/src/img/snippets_thumbs/s_custom_snippet.png
new file mode 100644
index 00000000000..76ffb0905fb
--- /dev/null
+++ b/addons/web_editor/static/src/img/snippets_thumbs/s_custom_snippet.png
Binary files differ
diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js
index 1e510ba9414..57ab6c37b73 100644
--- a/addons/web_editor/static/src/js/editor/snippets.editor.js
+++ b/addons/web_editor/static/src/js/editor/snippets.editor.js
@@ -780,6 +780,7 @@ var SnippetsMenu = Widget.extend({
events: {
'click .o_install_btn': '_onInstallBtnClick',
'click .o_we_invisible_entry': '_onInvisibleEntryClick',
+ 'click #snippet_custom .o_delete_btn': '_onDeleteBtnClick',
},
custom_events: {
'activate_insertion_zones': '_onActivateInsertionZones',
@@ -801,6 +802,7 @@ var SnippetsMenu = Widget.extend({
'block_preview_overlays': '_onBlockPreviewOverlays',
'unblock_preview_overlays': '_onUnblockPreviewOverlays',
'user_value_widget_opening': '_onUserValueWidgetOpening',
+ 'reload_snippet_template': '_onReloadSnippetTemplate',
},
/**
@@ -857,26 +859,22 @@ var SnippetsMenu = Widget.extend({
this.window = this.ownerDocument.defaultView;
this.$window = $(this.window);
- // Fetch snippet templates and compute it
+ this.customizePanel = document.createElement('div');
+ this.customizePanel.classList.add('o_we_customize_panel', 'd-none');
- defs.push(this.loadSnippets().then(html => {
- return this._computeSnippetTemplates(html);
- }).then(() => {
- this.customizePanel = document.createElement('div');
- this.customizePanel.classList.add('o_we_customize_panel', 'd-none');
- this.$el.append(this.customizePanel);
-
- this.invisibleDOMPanelEl = document.createElement('div');
- this.invisibleDOMPanelEl.classList.add('o_we_invisible_el_panel');
- this.invisibleDOMPanelEl.appendChild(
- $('<div/>', {
- text: _t('Invisible Elements'),
- class: 'o_panel_header',
- }).prepend(
- $('<i/>', {class: 'fa fa-eye-slash'})
- )[0]
- );
- this.$el.append(this.invisibleDOMPanelEl);
+ this.invisibleDOMPanelEl = document.createElement('div');
+ this.invisibleDOMPanelEl.classList.add('o_we_invisible_el_panel');
+ this.invisibleDOMPanelEl.appendChild(
+ $('<div/>', {
+ text: _t('Invisible Elements'),
+ class: 'o_panel_header',
+ }).prepend(
+ $('<i/>', {class: 'fa fa-eye-slash'})
+ )[0]
+ );
+
+ // Fetch snippet templates and compute it
+ defs.push(this._loadSnippetsTemplates().then(() => {
return this._updateInvisibleDOM();
}));
@@ -998,9 +996,10 @@ var SnippetsMenu = Widget.extend({
},
/**
* Load snippets.
+ * @param {boolean} invalidateCache
*/
- loadSnippets: function () {
- if (this.cacheSnippetTemplate[this.options.snippets]) {
+ loadSnippets: function (invalidateCache) {
+ if (!invalidateCache && this.cacheSnippetTemplate[this.options.snippets]) {
this._defLoadSnippets = this.cacheSnippetTemplate[this.options.snippets];
return this._defLoadSnippets;
}
@@ -1287,6 +1286,17 @@ var SnippetsMenu = Widget.extend({
},
/**
* @private
+ * @param {boolean} invalidateCache
+ */
+ _loadSnippetsTemplates: async function (invalidateCache) {
+ return this._mutex.exec(async () => {
+ await this._destroyEditors();
+ const html = await this.loadSnippets(invalidateCache);
+ await this._computeSnippetTemplates(html);
+ });
+ },
+ /**
+ * @private
*/
_destroyEditors: async function () {
const proms = _.map(this.snippetEditors, async function (snippetEditor) {
@@ -1502,6 +1512,7 @@ var SnippetsMenu = Widget.extend({
var $snippet = $(this);
var name = $snippet.attr('name');
var $sbody = $snippet.children(':not(.oe_snippet_thumbnail)').addClass('oe_snippet_body');
+ const isCustomSnippet = !!$snippet.parents('#snippet_custom').length;
// Associate in-page snippets to their name
if ($sbody.length) {
@@ -1525,6 +1536,13 @@ var SnippetsMenu = Widget.extend({
$snippet.find('[data-oe-thumbnail]').data('oeThumbnail'),
name
));
+ if (isCustomSnippet) {
+ const btn = document.createElement('we-button');
+ btn.dataset.snippetId = $snippet.data('oeSnippetId');
+ btn.classList.add('o_delete_btn', 'fa', 'fa-trash');
+ $thumbnail.prepend(btn);
+ $thumbnail.prepend($('<div class="o_image_ribbon"/>'));
+ }
$snippet.prepend($thumbnail);
// Create the install button (t-install feature) if necessary
@@ -1563,6 +1581,8 @@ var SnippetsMenu = Widget.extend({
// Add the computed template and make elements draggable
this.$el.html($html);
+ this.$el.append(this.customizePanel);
+ this.$el.append(this.invisibleDOMPanelEl);
this._makeSnippetDraggable(this.$snippets);
this._disableUndroppableSnippets();
@@ -1677,7 +1697,11 @@ var SnippetsMenu = Widget.extend({
$snippets.draggable({
greedy: true,
- helper: 'clone',
+ helper: function () {
+ const dragSnip = this.cloneNode(true);
+ dragSnip.querySelectorAll('.o_delete_btn, .o_image_ribbon').forEach(el => el.remove());
+ return dragSnip;
+ },
appendTo: this.$body,
cursor: 'move',
handle: '.oe_snippet_thumbnail',
@@ -1974,6 +1998,43 @@ var SnippetsMenu = Widget.extend({
/**
* @private
*/
+ _onDeleteBtnClick: function (ev) {
+ const $snippet = $(ev.target).closest('.oe_snippet');
+ new Dialog(this, {
+ size: 'medium',
+ title: _t('Confirmation'),
+ $content: $('<div><p>' + _t(`Are you sure you want to delete the snippet: ${$snippet.attr('name')} ?`) + '</p></div>'),
+ buttons: [{
+ text: _t("Yes"),
+ close: true,
+ classes: 'btn-primary',
+ click: async () => {
+ await this._rpc({
+ model: 'ir.ui.view',
+ method: 'delete_snippet',
+ kwargs: {
+ 'view_id': parseInt(ev.currentTarget.dataset.snippetId),
+ 'template_key': this.options.snippets,
+ },
+ });
+ await this._loadSnippetsTemplates(true);
+ },
+ }, {
+ text: _t("No"),
+ close: true,
+ }],
+ }).open();
+ },
+ /**
+ * @private
+ */
+ _onReloadSnippetTemplate: async function (ev) {
+ await this._activateSnippet(false);
+ await this._loadSnippetsTemplates(true);
+ },
+ /**
+ * @private
+ */
_onBlockPreviewOverlays: function (ev) {
this._blockPreviewOverlays = true;
},
diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js
index 86a3f70ac2b..53a36008a56 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -3,6 +3,7 @@ odoo.define('web_editor.snippets.options', function (require) {
var core = require('web.core');
const ColorpickerDialog = require('web.ColorpickerDialog');
+const Dialog = require('web.Dialog');
const time = require('web.time');
var Widget = require('web.Widget');
var ColorPaletteWidget = require('web_editor.ColorPalette').ColorPaletteWidget;
@@ -2973,6 +2974,60 @@ registry.many2one = SnippetOptionWidget.extend({
}
});
+/**
+ * Handle the save of a snippet as a template that can be reused later
+ */
+registry.SnippetSave = SnippetOptionWidget.extend({
+ xmlDependencies: ['/web_editor/static/src/xml/editor.xml'],
+ isTopOption: true,
+
+ //--------------------------------------------------------------------------
+ // Options
+ //--------------------------------------------------------------------------
+
+ /**
+ * @see this.selectClass for parameters
+ */
+ saveSnippet: function (previewMode, widgetValue, params) {
+ return new Promise(resolve => {
+ const dialog = new Dialog(this, {
+ title: _t("Save Your Block"),
+ size: 'small',
+ $content: $(qweb.render('web_editor.dialog.save_snippet', {
+ currentSnippetName: _.str.sprintf(_t("Custom %s"), this.data.snippetName),
+ })),
+ buttons: [{
+ text: _t("Save"),
+ classes: 'btn-primary',
+ close: true,
+ click: async () => {
+ const snippetName = dialog.el.querySelector('.o_we_snippet_name_input').value;
+ const targetCopyEl = this.$target[0].cloneNode(true);
+ delete targetCopyEl.dataset.name;
+ await this._rpc({
+ model: 'ir.ui.view',
+ method: 'save_snippet',
+ kwargs: {
+ 'name': snippetName,
+ 'arch': targetCopyEl.outerHTML,
+ 'template_key': this.options.snippets,
+ 'snippet_class': [...this.$target[0].classList].filter(x => /\bs_./g.test(x))[0],
+ },
+ });
+ this.trigger_up('reload_snippet_template');
+ resolve();
+ },
+ }, {
+ text: _t("Discard"),
+ close: true,
+ click: () => resolve(),
+ }],
+ }).open();
+ });
+ },
+});
+
+
return {
SnippetOptionWidget: SnippetOptionWidget,
snippetOptionRegistry: registry,
diff --git a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss
index 3dcb6e872e9..b8e87ff69f5 100644
--- a/addons/web_editor/static/src/scss/wysiwyg_snippets.scss
+++ b/addons/web_editor/static/src/scss/wysiwyg_snippets.scss
@@ -171,6 +171,33 @@ body.editor_enable.editor_has_snippets {
}
}
}
+ #snippet_custom .oe_snippet .oe_snippet_thumbnail {
+ .o_delete_btn {
+ @include o-position-absolute(0, 0);
+ z-index: 1;
+ display: none;
+ width: 25px;
+ height: 25px;
+ background-color: rgba(255, 0, 0, 0.75);
+ justify-content: center;
+ align-items: center;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+ &:hover .o_delete_btn {
+ display: flex;
+ }
+ .o_image_ribbon {
+ position: absolute;
+ z-index: 1;
+ width: 0;
+ height: 0;
+ border-right: 20px solid transparent;
+ border-top: 20px solid $o-enterprise-color;
+ }
+ }
}
> .o_we_customize_panel {
diff --git a/addons/web_editor/static/src/xml/editor.xml b/addons/web_editor/static/src/xml/editor.xml
index b1d7128e2c1..bb4abe15f60 100644
--- a/addons/web_editor/static/src/xml/editor.xml
+++ b/addons/web_editor/static/src/xml/editor.xml
@@ -25,4 +25,18 @@
</div>
</div>
</t>
+ <!-- Save Snippet Name option dialog -->
+ <t t-name="web_editor.dialog.save_snippet">
+ <div>
+ <div class="form-group form-row">
+ <label class="col-form-label col-md-3" for="snippetName">Name</label>
+ <div class="col-md-9">
+ <input type="text"
+ class="form-control o_we_snippet_name_input"
+ id="snippetName"
+ t-att-value="currentSnippetName"/>
+ </div>
+ </div>
+ </div>
+ </t>
</templates>