diff options
| author | fja-odoo <fja@odoo.com> | 2019-11-15 16:13:17 +0000 |
|---|---|---|
| committer | qsm-odoo <qsm@odoo.com> | 2020-01-16 14:29:04 +0000 |
| commit | 218e1cad6152999a0f41f073b5efa3c9428da48d (patch) | |
| tree | 76ebfa75fcb86195fd4b4c14af7b87b8ad3920c8 /addons/web_editor/static/src | |
| parent | 4946739c17488d32d3e61b1258ab48b5aec701a4 (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.png | bin | 0 -> 977 bytes | |||
| -rw-r--r-- | addons/web_editor/static/src/js/editor/snippets.editor.js | 105 | ||||
| -rw-r--r-- | addons/web_editor/static/src/js/editor/snippets.options.js | 55 | ||||
| -rw-r--r-- | addons/web_editor/static/src/scss/wysiwyg_snippets.scss | 27 | ||||
| -rw-r--r-- | addons/web_editor/static/src/xml/editor.xml | 14 |
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 Binary files differnew file mode 100644 index 00000000000..76ffb0905fb --- /dev/null +++ b/addons/web_editor/static/src/img/snippets_thumbs/s_custom_snippet.png 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> |
