[FIX] website_form, *: allow to update buttons using link dialog
*: web_editor, website_mass_mailing When we double click a link/button, a link dialog appears to update the target properties, and since the current link dialog can only handle anchor targets, using it on buttons leads to some inconsistencies : - visible href options for button & url required to save changes. - missing preview when button style changed. ... The goal of this commit is to add a fix (with minimum of code) on summernote linkdialog to handle button elements using the same logic as anchor nodes. Also, update website form test tour to test those new changes. Part of https://github.com/odoo/odoo/pull/62206 task-2381305 X-original-commit: 19fbbdc0327482b5d70bdbcf17c2a5a950327d63
This commit is contained in:
@@ -618,6 +618,9 @@ define([
|
||||
var isNewWindow = linkInfo.isNewWindow;
|
||||
var rng = linkInfo.range || this.createRange($editable);
|
||||
var isTextChanged = rng.toString() !== linkText;
|
||||
// Hack : This method was updated to create buttons as well (using the same logic as anchor nodes).
|
||||
const nodeName = linkInfo.isButton ? 'BUTTON' : 'A';
|
||||
const pred = dom.makePredByNodeName(nodeName);
|
||||
|
||||
options = options || dom.makeLayoutInfo($editable).editor().data('options');
|
||||
|
||||
@@ -629,23 +632,25 @@ define([
|
||||
|
||||
var anchors = [];
|
||||
// ODOO: adding this branch to modify existing anchor if it fully contains the range
|
||||
var ancestor_anchor = dom.ancestor(rng.sc, dom.isAnchor);
|
||||
if(ancestor_anchor && ancestor_anchor === dom.ancestor(rng.ec, dom.isAnchor)) {
|
||||
var ancestor_anchor = dom.ancestor(rng.sc, pred);
|
||||
if (ancestor_anchor && ancestor_anchor === dom.ancestor(rng.ec, pred)) {
|
||||
anchors.push($(ancestor_anchor).html(linkText).get(0));
|
||||
} else if (isTextChanged) {
|
||||
// Create a new link when text changed.
|
||||
var anchor = rng.insertNode($('<A>' + linkText + '</A>')[0]);
|
||||
// Create a new element when text changed.
|
||||
var anchor = rng.insertNode($(`<${nodeName}>${linkText}</${nodeName}>`)[0]);
|
||||
anchors.push(anchor);
|
||||
} else {
|
||||
anchors = style.styleNodes(rng, {
|
||||
nodeName: 'A',
|
||||
nodeName: nodeName,
|
||||
expandClosestSibling: true,
|
||||
onlyPartialContains: true
|
||||
});
|
||||
}
|
||||
|
||||
$.each(anchors, function (idx, anchor) {
|
||||
$(anchor).attr('href', linkUrl);
|
||||
if (!linkInfo.isButton) {
|
||||
$(anchor).attr('href', linkUrl);
|
||||
}
|
||||
$(anchor).attr('class', linkInfo.className || null); // ODOO: addition
|
||||
$(anchor).css(linkInfo.style || {}); // ODOO: addition
|
||||
if (isNewWindow) {
|
||||
@@ -672,6 +677,8 @@ define([
|
||||
|
||||
/**
|
||||
* returns link info
|
||||
* Hack : This method was updated to return a boolean attribute 'isButton' to allow
|
||||
* handling buttons in linkDialog.
|
||||
*
|
||||
* @return {Object}
|
||||
* @return {WrappedRange} return.range
|
||||
@@ -706,11 +713,24 @@ define([
|
||||
// Get the first anchor on range(for edit).
|
||||
var $anchor = $(list.head(rng.nodes(dom.isAnchor)));
|
||||
|
||||
// Check if the target is a button element.
|
||||
let isButton = false;
|
||||
if (!$anchor.length) {
|
||||
const pred = dom.makePredByNodeName('BUTTON');
|
||||
const rngNew = range.create().expand(pred);
|
||||
const target = list.head(rngNew.nodes(pred));
|
||||
if (target && target.nodeName === 'BUTTON') {
|
||||
isButton = true;
|
||||
rng = rngNew;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
range: rng,
|
||||
text: rng.toString(),
|
||||
isNewWindow: $anchor.length ? $anchor.attr('target') === '_blank' : false,
|
||||
url: $anchor.length ? $anchor.attr('href') : ''
|
||||
url: $anchor.length ? $anchor.attr('href') : '',
|
||||
isButton: isButton,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ var LinkDialog = Dialog.extend({
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {Boolean} linkInfo.isButton - whether if the target is a button element.
|
||||
*/
|
||||
init: function (parent, options, editable, linkInfo) {
|
||||
this.options = options || {};
|
||||
@@ -33,8 +34,11 @@ var LinkDialog = Dialog.extend({
|
||||
title: _t("Link to"),
|
||||
}, this.options));
|
||||
|
||||
this.data = linkInfo || {};
|
||||
this.isButton = this.data.isButton;
|
||||
// Using explicit type 'link' to preserve style when the target is <button class="...btn-link"/>.
|
||||
this.colorsData = [
|
||||
{type: '', label: _t("Link"), btnPreview: 'link'},
|
||||
{type: this.isButton ? 'link' : '', label: _t("Link"), btnPreview: 'link'},
|
||||
{type: 'primary', label: _t("Primary"), btnPreview: 'primary'},
|
||||
{type: 'secondary', label: _t("Secondary"), btnPreview: 'secondary'},
|
||||
// Note: by compatibility the dialog should be able to remove old
|
||||
@@ -44,8 +48,6 @@ var LinkDialog = Dialog.extend({
|
||||
];
|
||||
|
||||
this.editable = editable;
|
||||
this.data = linkInfo || {};
|
||||
|
||||
this.data.className = "";
|
||||
this.data.iniClassName = "";
|
||||
|
||||
@@ -53,10 +55,10 @@ var LinkDialog = Dialog.extend({
|
||||
this.needLabel = !r || (r.sc === r.ec && r.so === r.eo);
|
||||
|
||||
if (this.data.range) {
|
||||
const $link = $(this.data.range.sc).filter("a");
|
||||
this.data.iniClassName = $link.attr("class") || "";
|
||||
const $el = $(this.data.range.sc).filter(this.isButton ? "button" : "a");
|
||||
this.data.iniClassName = $el.attr("class") || "";
|
||||
this.colorCombinationClass = false;
|
||||
let $node = $link;
|
||||
let $node = $el;
|
||||
while ($node.length && !$node.is('body')) {
|
||||
const className = $node.attr('class') || '';
|
||||
const m = className.match(/\b(o_cc\d+)\b/g);
|
||||
@@ -149,6 +151,10 @@ var LinkDialog = Dialog.extend({
|
||||
this.data.className = this.data.iniClassName
|
||||
.replace(allBtnClassSuffixes, ' ')
|
||||
.replace(allBtnShapes, ' ');
|
||||
// 'o_submit' class will force anchor to be handled as a button in linkdialog.
|
||||
if (/(?:s_website_form_send|o_submit)/.test(this.data.className)) {
|
||||
this.isButton = true;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @override
|
||||
@@ -256,7 +262,7 @@ var LinkDialog = Dialog.extend({
|
||||
}
|
||||
}
|
||||
|
||||
if ($url.prop('required') && (!url || !$url[0].checkValidity())) {
|
||||
if (!this.isButton && $url.prop('required') && (!url || !$url[0].checkValidity())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -474,7 +474,7 @@
|
||||
<input type="text" name="label" class="form-control" id="o_link_dialog_label_input" required="required" t-att-value="widget.data.text"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row o_url_input">
|
||||
<div t-attf-class="form-group row o_url_input#{widget.isButton ? ' d-none' : ''}">
|
||||
<label class="col-form-label col-md-3" for="o_link_dialog_url_input">URL or Email</label>
|
||||
<div class="col-md-9">
|
||||
<input type="text" name="url" class="form-control" id="o_link_dialog_url_input" required="required"/>
|
||||
@@ -526,7 +526,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row" t-if="!widget.options.forceNewWindow">
|
||||
<div class="form-group row" t-if="!widget.isButton && !widget.options.forceNewWindow">
|
||||
<div class="offset-md-3 col-md-9">
|
||||
<label class="o_switch">
|
||||
<input type="checkbox" name="is_new_window" t-att-checked="widget.data.isNewWindow ? 'checked' : undefined"/>
|
||||
|
||||
@@ -226,6 +226,39 @@ odoo.define('website_form_editor.tour', function (require) {
|
||||
|
||||
...addExistingField('attachment_ids', 'file', 'Invoice Scan'),
|
||||
|
||||
// Edit the submit button using linkDialog.
|
||||
{
|
||||
content: "Double click submit button to edit it",
|
||||
trigger: '.s_website_form_send',
|
||||
run: 'dblclick',
|
||||
}, {
|
||||
content: "Check that no URL field is suggested",
|
||||
trigger: 'form:has(#o_link_dialog_label_input:hidden)',
|
||||
run: () => null,
|
||||
}, {
|
||||
content: "Check that preview element has the same style",
|
||||
trigger: '.o_link_dialog_preview:has(.s_website_form_send.btn.btn-lg.btn-primary)',
|
||||
run: () => null,
|
||||
}, {
|
||||
content: "Change button's style",
|
||||
trigger: 'label:has(input[name="link_style_color"][value="secondary"])',
|
||||
run: () => {
|
||||
$('input[name="link_style_color"][value="secondary"]').click();
|
||||
$('select[name="link_style_shape"]').val('rounded-circle').change();
|
||||
$('select[name="link_style_size"]').val('sm').change();
|
||||
},
|
||||
}, {
|
||||
content: "Check that preview is updated too",
|
||||
trigger: '.o_link_dialog_preview:has(.s_website_form_send.btn.btn-sm.btn-secondary.rounded-circle)',
|
||||
run: () => null,
|
||||
}, {
|
||||
content: "Save changes from linkDialog",
|
||||
trigger: '.modal-footer .btn-primary',
|
||||
}, {
|
||||
content: "Check the resulting button",
|
||||
trigger: '.s_website_form_send.btn.btn-sm.btn-secondary.rounded-circle',
|
||||
run: () => null,
|
||||
},
|
||||
// Save the page
|
||||
{
|
||||
trigger: 'body',
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
<div class="input-group">
|
||||
<input type="email" name="email" class="js_subscribe_email form-control" placeholder="your email..."/>
|
||||
<span class="input-group-append">
|
||||
<a role="button" href="#" class="btn btn-primary js_subscribe_btn">Subscribe</a>
|
||||
<a role="button" href="#" class="btn btn-success js_subscribed_btn d-none" disabled="disabled">Thanks</a>
|
||||
<a role="button" href="#" class="btn btn-primary js_subscribe_btn o_submit">Subscribe</a>
|
||||
<a role="button" href="#" class="btn btn-success js_subscribed_btn d-none o_submit" disabled="disabled">Thanks</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user