[FIX] web_editor: restoreRange on invalid node

In a web editor, add some text, select the text, add a link and
immediately discard the link modal. Traceback.

The traceback is a execute `setEnd` on `Range`, that error is thrown
because editable DIV doesn't save old range

Odoo wrap code does some text node split in order to attach the link
just on the selected text. If it correctly re-set the underlying
structure, it does not update the $(editable) structure used to restore
ranges.

After this commit, editable div will use newly created range for the element

for ex:
-> content: test
-> selected content "test"

when click on link dialog:
ec: test , eo: 4, sc: test, so: 0
selected content  ->  start 0, end 4 -> "test" like this

after clicking on discard:
ec: null text element, eo: 4, sc: null text element, so: 0
selected content  ->  ec and sc both are null, so it will throw an error
while setting cursor position

after applying fix when click on discard:
ec: test, eo: 4, sc: test, so: 0
selected content -> start 0,  end 4 -> "test"

task - 1955863

closes odoo/odoo#33692

Signed-off-by: Nicolas Lempereur (nle) <nle@odoo.com>
This commit is contained in:
Priyanka Kakadiya
2019-06-03 05:36:08 +00:00
committed by Mohammed Shekha
parent 37ab5a7009
commit 0799742d05
2 changed files with 62 additions and 0 deletions
@@ -1189,6 +1189,7 @@ var LinkDialog = Dialog.extend({
}
this.data.range = range.create(sc, so, ec, eo);
$(editable).data("range", this.data.range);
this.data.range.select();
} else {
nodes = dom.ancestor(sc, dom.isAnchor).childNodes;
@@ -5,6 +5,7 @@ var FormView = require('web.FormView');
var testUtils = require('web.test_utils');
var core = require('web.core');
var web_editor = require('web_editor.editor');
var LinkDialog = require('web_editor.widget').LinkDialog;
var _t = core._t;
@@ -324,4 +325,64 @@ QUnit.test('html_frame saving in edit mode (editor and content fully loaded)', f
});
QUnit.test('discard on link dialog should select content of link in web_editor', function (assert) {
var done = assert.async();
assert.expect(5);
var form = testUtils.createView({
View: FormView,
model: 'mass.mailing',
data: this.data,
arch: '<form string="Partners">' +
'<field name="body"/>' +
'</form>',
res_id: 1,
});
form.$buttons.find('.o_form_button_edit').click();
assert.strictEqual(form.$('.note-editable').html(), '<div class="field_body">yep</div>',
"should have rendered the field correctly in edit");
var $fieldEdit = form.$('.oe_form_field[name="body"]');
var $editable = $fieldEdit.find('.field_body');
// create range, default startoffset:0, endOffset:length of element
var range = document.createRange();
var selection = window.getSelection();
range.selectNodeContents($editable[0].childNodes[0]);
selection.removeAllRanges();
selection.addRange(range);
var content = selection.getRangeAt(range);
assert.strictEqual(content.startOffset, 0, "selection starts at index 0");
assert.strictEqual(content.endOffset, 3, "selection ends at index 3");
var defLinkDialog = $.Deferred();
testUtils.patch(LinkDialog, {
init: function () {
this._super.apply(this, arguments);
this.opened(defLinkDialog.resolve.bind(defLinkDialog));
}
});
// click on 'link' button
$fieldEdit.find('.note-toolbar button[data-event="showLinkDialog"]').click();
defLinkDialog.then(function () {
$('.modal .modal-footer .btn-default').click(); // click on 'discard'
var content = selection.getRangeAt(range);
assert.strictEqual(content.startOffset, 0,
"selection should remain same after discarding modal, starts at index 0");
assert.strictEqual(content.endOffset, 3,
"selection should remain same after discarding modal, ends at index 3");
testUtils.unpatch(LinkDialog);
form.destroy();
done();
});
});
});