odoo.define('web_editor.wysiwyg_tests', function (require) { "use strict"; var testUtils = require('web.test_utils'); var weTestUtils = require('web_editor.test_utils'); var Wysiwyg = require('web_editor.wysiwyg'); var AltDialog = require('wysiwyg.widgets.AltDialog'); var CropDialog = require('wysiwyg.widgets.CropImageDialog'); var testName = ""; var carretTestSuffix = " (carret position)"; QUnit.module('web_editor', { afterEach: function () { $('body').removeClass('modal-open'); $('.note-popover, .modal, .modal-backdrop').remove(); }, }, function () { QUnit.module('wysiwyg', {}, function () { QUnit.module('toolbar', {}, function () { QUnit.test('Magic wand', async function (assert) { assert.expect(8); var wysiwyg = await weTestUtils.createWysiwyg({ debug: false, wysiwygOptions: { }, }); var $editable = wysiwyg.$('.note-editable'); var $dropdownStyle = wysiwyg.$('.note-style .dropdown-toggle'); var $btnsStyle = wysiwyg.$('.note-style .dropdown-menu .dropdown-item'); var wandTests = [{ name: "Click H1: p -> h1", content: '
dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownStyle, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsStyle.find('h1'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom not to edit
dom not to edit
dom to edit', start: 'pre:contents()[0]->0', end: 'pre:contents()[0]->11', }, }, { name: "Click NORMAL: pre -> p", content: '
dom not to edit
dom to edit', start: 'pre:contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownStyle, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsStyle.find('p'), ['mousedown', 'click']); }, test: { content: '
dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->0', end: 'p:eq(1):contents()[0]->11', }, }, { name: "Click H1 in empty p: empty p -> empty h1", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->0', end: 'b:contents()[0]->4', }, }, { name: "Click BOLD then 'a': normal -> bold (empty p)", content: 'a
', start: 'b:contents()[0]->1', }, }, { name: "Click BOLD: normal -> bold (across paragraphs)", content: 'dom to edit
dom to edit
', start: 'p:contents()[0]->1', end: 'p:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'dom to edit
dom to edit
', start: 'b:contents()[0]->0', end: 'b:eq(1):contents()[0]->5', }, }, { name: "Click BOLD then 'a': normal -> bold (no selection)", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->4', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); weTestUtils.keydown('a', $editable); }, test: { content: 'dom not to edit
dom ato edit
', start: 'b:contents()[0]->1', }, }, { name: "Click BOLD: bold -> normal", content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->0', end: 'b:contents()[0]->11', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->0', end: 'p:eq(1):contents()[0]->11', }, }, { name: "Click BOLD: bold -> normal (partial selection)", content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->4', end: 'b:contents()[0]->6', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[1]->0', end: 'p:eq(1):contents()[1]->2', }, }, { name: "Click BOLD: bold -> normal (no selection)", content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->4', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom \u200Bto edit
', start: 'p:eq(1):contents()[1]->1', }, }, { name: "Click BOLD: bold + normal -> normal", content: 'dom to edit
', start: 'b:contents()[0]->1', end: 'p:contents()[1]->4', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'dom to edit
', start: 'b:contents()[0]->1', end: 'b:contents()[0]->8', }, }, { name: "Click BOLD: normal -> bold (with fontawesome)", content: 'aaabbb
', start: 'p:contents()[0]->1', end: 'p:contents()[2]->2', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'aaabbb
', start: 'b:contents()[0]->0', end: 'b:contents()[2]->2', }, }, { name: "Click BOLD + click BOLD: normal -> bold -> normal (with fontawesome)", content: 'aaabbb
', start: 'p:contents()[0]->1', end: 'p:contents()[2]->2', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'aaabbb
', start: 'p:contents()[0]->1', end: 'p:contents()[2]->2', }, }, { name: "Click BOLD: bold -> normal (with fontawesome)", content: 'aaabbb
', start: 'b:contents()[0]->1', end: 'b:contents()[2]->2', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'aaabbb
', start: 'p:contents()[1]->0', end: 'p:contents()[3]->2', }, }, { name: "Click BOLD: bold -> normal (at start of dom)", content: 'abc
', start: 'b:contents()[0]->0', do: function () { $btnBold.mousedown().click(); }, test: { content: '\u200Babc
', start: 'p:contents()[0]->1', end: 'p:contents()[0]->1', }, }, /* ITALIC */ { name: "Click ITALIC: bold -> bold + italic", content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->1', end: 'b:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnItalic, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'i:contents()[0]->0', end: 'i:contents()[0]->4', }, }, { name: "Click ITALIC: bold & normal -> italic & bold + italic (across paragraphs)", content: 'dom to edit
dom to edit
', start: 'p:contents()[0]->1', end: 'b:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnItalic, ['mousedown', 'click']); }, test: { content: 'dom to edit
dom to edit
', start: 'i:contents()[0]->0', end: 'i:eq(1):contents()[0]->5', }, }, /* UNDERLINE */ { name: "Click UNDERLINE: bold -> bold + underlined", content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->1', end: 'b:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnUnderline, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'u:contents()[0]->0', end: 'u:contents()[0]->4', }, }, { name: "Click UNDERLINE: bold & normal -> underlined & bold + underlined (across paragraphs)", content: 'dom to edit
dom to edit
', start: 'p:contents()[0]->1', end: 'b:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnUnderline, ['mousedown', 'click']); }, test: { content: 'dom to edit
dom to edit
', start: 'u:contents()[0]->0', end: 'u:eq(1):contents()[0]->5', }, }, /* strikethrough */ { name: "Click strikethrough: bold -> bold + strikethrough", content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->1', end: 'b:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($strikethrough, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom to edit
dom to edit
', start: 'p:contents()[0]->1', end: 'b:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($strikethrough, ['mousedown', 'click']); }, test: { content: 'dom to edit
dom to edit
dom not to edit
dom to edit
', start: 'b:contents()[0]->1', end: 'b:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($superscript, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'sup:contents()[0]->0', end: 'sup:contents()[0]->4', }, }, { name: "Click superscript: bold & normal -> superscript & bold + superscript (across paragraphs)", content: 'dom to edit
dom to edit
', start: 'p:contents()[0]->1', end: 'b:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($superscript, ['mousedown', 'click']); }, test: { content: 'dom to edit
dom to edit
', start: 'sup:contents()[0]->0', end: 'sup:eq(1):contents()[0]->5', }, }, /* subscript */ { name: "Click subscript: bold -> bold + subscript", content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->1', end: 'b:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($subscript, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'sub:contents()[0]->0', end: 'sub:contents()[0]->4', }, }, { name: "Click subscript: bold & normal -> subscript & bold + subscript (across paragraphs)", content: 'dom to edit
dom to edit
', start: 'p:contents()[0]->1', end: 'b:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($subscript, ['mousedown', 'click']); }, test: { content: 'dom to edit
dom to edit
', start: 'sub:contents()[0]->0', end: 'sub:eq(1):contents()[0]->5', }, }, /* REMOVE FONT STYLE */ { name: "Click REMOVE FONT STYLE: bold -> normal", content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->1', end: 'b:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnRemoveStyles, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[1]->0', end: 'p:eq(1):contents()[1]->4', }, }, { name: "Click REMOVE FONT STYLE: bold, italic, underlined & normal -> normal (across paragraphs)", content: 'dom to edit
dom to edit
', start: 'p:contents()[0]->1', end: 'u:eq(1):contents()[0]->3', do: async function () { await testUtils.dom.triggerEvents($btnRemoveStyles, ['mousedown', 'click']); }, test: { content: 'dom to edit
dom to edit
', start: 'p:contents()[0]->1', end: 'p:eq(1):contents()[0]->3', }, }, { name: "Click REMOVE FONT STYLE: complex -> normal", content: 'aaabbb
ccc
', start: 'p:contents()[0]->1', end: 'font:eq(1):contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($btnRemoveStyles, ['mousedown', 'click']); }, test: { content: 'aaabbb
ccc
', start: 'p:contents()[0]->1', end: 'p:eq(1):contents()[0]->1', }, }, { name: "Click REMOVE FONT STYLE: complex -> normal (with icon)", content: 'aaabbb
', start: 'p:contents()[0]->0', end: 'i:contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($btnRemoveStyles, ['mousedown', 'click']); }, test: { content: 'aaabbb
', start: 'p:contents()[0]->0', end: 'p:contents()[2]->2', }, }, /* COMPLEX */ { name: "COMPLEX Click BOLD: italic -> italic bold (partial selection)", content: 'dom not to edit
dom to edit
', start: 'i:contents()[0]->1', end: 'i:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'b:contents()[0]->0', end: 'b:contents()[0]->4', }, }, { name: "COMPLEX Click BOLD then 'a': italic bold -> italic (across paragraphs)", content: 'dom to edit
dom to edit
', start: 'i:contents()[0]->1', end: 'b:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); weTestUtils.keydown('a', $editable, { firstDeselect: true, }); }, test: { content: 'dom to edit
dom tao edit
', }, }, { name: "COMPLEX Click BOLD then 'a': bold italic -> italic (no selection)", content: 'dom to edit
', start: 'i:contents()[0]->4', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); weTestUtils.keydown('a', $editable, { firstDeselect: true, }); }, test: { content: 'dom ato edit
', }, }, { name: "COMPLEX Click BOLD then 'a': underlined italic -> underlined italic bold (across paragraphs)", content: 'dom to edit
dom to edit
', start: 'i:contents()[0]->1', end: 'u:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); weTestUtils.keydown('a', $editable, { firstDeselect: true, }); }, test: { content: 'dom to edit
dom tao edit
', }, }, { name: "COMPLEX Click BOLD then 'a': underlined italic -> underlined italic bold (no selection)", content: 'dom to edit
', start: 'i:contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($btnBold, ['mousedown', 'click']); weTestUtils.keydown('a', $editable, { firstDeselect: true, }); }, test: { content: 'daom to edit
', }, }, ]; var def = Promise.resolve(); _.each(styleTests, function (test) { def = def.then(async function() { testName = test.name; wysiwyg.setValue(test.content); test.end = test.end || test.start; var range = weTestUtils.select(test.start, test.end, $editable); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await test.do(); assert.deepEqual(wysiwyg.getValue(), test.test.content, testName); $editable[0].normalize(); if (test.test.start) { test.test.end = test.test.end || test.test.start; assert.deepEqual(Wysiwyg.getRange($editable[0]), weTestUtils.select(test.test.start, test.test.end, $editable), testName + carretTestSuffix); } }); }); return def.then(function() { wysiwyg.destroy(); }); }); }); QUnit.test('Font size', function (assert) { assert.expect(10); return weTestUtils.createWysiwyg({ debug: false, wysiwygOptions: { }, }).then(function (wysiwyg) { var $editable = wysiwyg.$('.note-editable'); var $dropdownFontSize = wysiwyg.$('.note-fontsize .dropdown-toggle'); var $linksFontSize = wysiwyg.$('.note-fontsize .dropdown-menu .dropdown-item'); var sizeTests = [{ name: "Click 18: default -> 18px", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownFontSize, ['mousedown', 'click']); await testUtils.dom.triggerEvents($linksFontSize.filter(':contains("18")'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->4', }, }, { name: "Click DEFAULT: 18px -> default", content: 'dom not to edit
dom to edit
', start: 'font:contents()[0]->1', end: 'font:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownFontSize, ['mousedown', 'click']); await testUtils.dom.triggerEvents($linksFontSize.filter(':contains("Default")'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[1]->0', end: 'p:eq(1):contents()[1]->4', }, }, { name: "Click 18: 26px -> 18px", content: 'dom to edit
', start: 'font:contents()[0]->1', end: 'font:contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownFontSize, ['mousedown', 'click']); await testUtils.dom.triggerEvents($linksFontSize.filter(':contains("18")'), ['mousedown', 'click']); }, test: { content: '' + 'd' + 'om t' + 'o edit
', start: 'font:eq(1):contents()[0]->0', end: 'font:eq(1):contents()[0]->4', }, }, { name: "Click 18 then 'a' (no selection): default -> 18px", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownFontSize, ['mousedown', 'click']); await testUtils.dom.triggerEvents($linksFontSize.filter(':contains("18")'), ['mousedown', 'click']); weTestUtils.keydown('a', $editable, { firstDeselect: true, }); }, test: { content: 'dom not to edit
daom to edit
', start: 'font:contents()[0]->1', }, }, { name: "Click 18 then 'a' (no selection): 26px -> 18px", content: 'dom to edit
', start: 'font:contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownFontSize, ['mousedown', 'click']); await testUtils.dom.triggerEvents($linksFontSize.filter(':contains("18")'), ['mousedown', 'click']); weTestUtils.keydown('a', $editable, { firstDeselect: true, }); }, test: { content: '' + 'd' + 'a' + 'om to edit
', start: 'font:eq(1):contents()[0]->1', }, }, ]; var def = Promise.resolve(); _.each(sizeTests, function (test) { def = def.then(async function() { testName = test.name; wysiwyg.setValue(test.content); var range = weTestUtils.select(test.start, test.end, $editable); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await test.do(); assert.deepEqual(wysiwyg.getValue(), test.test.content, testName); assert.deepEqual(Wysiwyg.getRange($editable[0]), weTestUtils.select(test.test.start, test.test.end, $editable), testName + carretTestSuffix); }); }); return def.then(function() { wysiwyg.destroy(); }); }); }); QUnit.test('Text forecolor', function (assert) { assert.expect(40); return weTestUtils.createWysiwyg({ debug: false, wysiwygOptions: { }, }).then(function (wysiwyg) { var $editable = wysiwyg.$('.note-editable'); var $dropdownForeColor = wysiwyg.$('.note-color .note-fore-color .dropdown-toggle'); var $btnsForeColor = wysiwyg.$('.note-color .note-fore-color .dropdown-menu .note-palette .note-color-btn'); var forecolorTests = [{ name: "Click THEME COLORS - ALPHA: default -> alpha theme color", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsForeColor.filter('.bg-alpha'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->4', }, }, { name: "Click THEME COLORS - BLACK 25: alpha theme color & default -> black 25", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'font:contents()[0]->3', do: async function () { await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsForeColor.filter('.bg-black-25'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->4', }, }, { name: "Click COMMON COLORS - BLUE #0000FF: black 25 & default -> blue #0000FF", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'font:contents()[0]->3', do: async function () { await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsForeColor.filter('[style="background-color:#0000FF"]'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->4', }, }, { name: "Click RESET TO DEFAULT: black 25 & default -> default", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'font:contents()[0]->3', do: async function () { await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsForeColor.filter('.note-color-reset'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', }, }, { name: "Click CUSTOM COLORS then CUSTOM COLOR: blue #0000FF & default -> #875A7B", async: true, content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'font:contents()[0]->3', do: async function () { var self = this; await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color'), ['mousedown', 'click']); $('.modal-dialog .o_hex_input').val('#875A7B').change(); await testUtils.dom.triggerEvents($('.o_technical_modal .modal-footer .btn-primary:contains("Choose")'), ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color-btn:last'), ['mousedown', 'click']); assert.deepEqual(wysiwyg.getValue(), 'dom not to edit
dom to edit
', self.name); var range = weTestUtils.select('font:contents()[0]->0', 'font:contents()[0]->4', $editable); assert.deepEqual(Wysiwyg.getRange($editable[0]), range, self.name + carretTestSuffix); }, }, { name: "Click CUSTOM COLORS then CUSTOM COLOR: change blue input", content: 'dom to edit
', start: 'p:contents()[0]->1', end: 'p:contents()[0]->6', do: async function () { var self = this; await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color'), ['mousedown', 'click']); $('.modal-dialog .o_blue_input').val('100').change(); assert.deepEqual($('.modal-dialog .o_hex_input').val(), '#ff0064', self.name + ' (hex)'); assert.deepEqual($('.modal-dialog .o_hue_input').val(), '337', self.name + ' (hue)'); await testUtils.dom.triggerEvents($('.o_technical_modal .modal-footer .btn-primary:contains("Choose")'), ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color-btn:last'), ['mousedown', 'click']); }, test: { content: 'dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->5', }, }, { name: "CUSTOM COLOR: change hue, saturation and lightness inputs", content: 'dom to edit
', start: 'p:contents()[0]->1', end: 'p:contents()[0]->6', do: async function () { var self = this; await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color'), ['mousedown', 'click']); $('.modal-dialog .o_hue_input').val('337').change(); $('.modal-dialog .o_saturation_input').val('50').change(); $('.modal-dialog .o_lightness_input').val('40').change(); assert.deepEqual($('.modal-dialog .o_hex_input').val(), '#99335a', self.name + ' (hex)'); assert.deepEqual($('.modal-dialog .o_green_input').val(), '51', self.name + ' (green)'); await testUtils.dom.triggerEvents($('.o_technical_modal .modal-footer .btn-primary:contains("Choose")'), ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color-btn:last'), ['mousedown', 'click']); }, test: { content: 'dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->5', }, }, { name: "CUSTOM COLOR: mousedown on area", content: 'dom to edit
', start: 'p:contents()[0]->1', end: 'p:contents()[0]->6', do: async function () { var self = this; await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color'), ['mousedown', 'click']); var $area = $('.modal-dialog .o_color_pick_area'); var pos = $area.offset(); $area.trigger($.Event("mousedown", { which: 1, pageX: pos.left + 50, pageY: pos.top + 50 })); $area.trigger('mouseup'); assert.deepEqual($('.modal-dialog .o_hex_input').val(), '#cfafaf', self.name + ' (hex)'); assert.deepEqual($('.modal-dialog .o_red_input').val(), '207', self.name + ' (red)'); assert.deepEqual($('.modal-dialog .o_green_input').val(), '175', self.name + ' (green)'); assert.deepEqual($('.modal-dialog .o_blue_input').val(), '175', self.name + ' (blue)'); assert.deepEqual($('.modal-dialog .o_hue_input').val(), '0', self.name + ' (hue)'); assert.deepEqual($('.modal-dialog .o_saturation_input').val(), '25', self.name + ' (saturation)'); assert.deepEqual($('.modal-dialog .o_lightness_input').val(), '75', self.name + ' (lightness)'); await testUtils.dom.triggerEvents($('.o_technical_modal .modal-footer .btn-primary:contains("Choose")'), ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color-btn:last'), ['mousedown', 'click']); }, test: { content: 'dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->5', }, }, { name: "CUSTOM COLOR: mousedow on sliders", content: 'dom to edit
', start: 'p:contents()[0]->1', end: 'p:contents()[0]->6', do: async function () { var self = this; await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color'), ['mousedown', 'click']); var $slider1 = $('.modal-dialog .o_slider_pointer'); var pos1 = $slider1.offset(); $slider1.trigger($.Event("mousedown", { which: 1, pageX: pos1.left, pageY: pos1.top + 50 })); $slider1.trigger('mouseup'); assert.deepEqual($('.modal-dialog .o_hex_input').val(), '#83ff00', self.name + ' (hex)'); var $slider2 = $('.modal-dialog .o_opacity_slider'); var pos2 = $slider2.offset(); $slider2.trigger($.Event("mousedown", { which: 1, pageX: pos2.left, pageY: pos2.top + 80 })); $slider2.trigger('mouseup'); assert.deepEqual($('.modal-dialog .o_hue_input').val(), '89', self.name + ' (hue)'); assert.deepEqual($('.modal-dialog .o_opacity_input').val(), '60', self.name + ' (opacity)'); await testUtils.dom.triggerEvents($('.o_technical_modal .modal-footer .btn-primary:contains("Choose")'), ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-fore-color .note-custom-color-btn:last'), ['mousedown', 'click']); }, test: { content: 'dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->5', }, }, { name: "Apply a color on a fontawesome", content: 'dom not to edit
', start: 'i->0', do: async function () { await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsForeColor.filter('[style="background-color:#0000FF"]'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
', start: 'p->2', }, }, { name: "Apply a color on a font with text", content: 'dom not to edit
', start: 'p:contents()[0]->1', end: 'p:contents()[2]->6', do: async function () { await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsForeColor.filter('[style="background-color:#0000FF"]'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
', start: 'font:eq(0):contents()[0]->0', end: 'font:eq(1):contents()[0]->6', }, }, { name: "Apply color, then 'a' (no selection)", content: 'dom not to edit
', start: 'p:contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownForeColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsForeColor.filter('[style="background-color:#0000FF"]'), ['mousedown', 'click']); weTestUtils.keydown('a', $editable, { firstDeselect: true, }); }, test: { content: 'daom not to edit
', start: 'font:contents()[0]->1', }, }, { name: "Apply color on two ranges with the same color", content: 'do
m not to edit
do
m not to edit
dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownBgColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsBgColor.filter('.bg-alpha'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->4', }, }, { name: "Click THEME COLORS - BLACK 25: alpha theme color & default -> black 25", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'font:contents()[0]->3', do: async function () { await testUtils.dom.triggerEvents($dropdownBgColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsBgColor.filter('.bg-black-25'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->4', }, }, { name: "Click COMMON COLORS - BLUE #0000FF: black 25 & default -> blue #0000FF", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'font:contents()[0]->3', do: async function () { await testUtils.dom.triggerEvents($dropdownBgColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsBgColor.filter('[style="background-color:#0000FF"]'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'font:contents()[0]->0', end: 'font:contents()[0]->4', }, }, { name: "Click RESET TO DEFAULT: black 25 & default -> default", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'font:contents()[0]->3', do: async function () { await testUtils.dom.triggerEvents($dropdownBgColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnsBgColor.filter('.note-color-reset'), ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', }, }, { name: "Click CUSTOM COLORS then CUSTOM COLOR: blue #0000FF & default -> #875A7B", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'font:contents()[0]->3', async: true, do: async function () { testName = "Click CUSTOM COLORS then CUSTOM COLOR: blue #0000FF & default -> #875A7B"; await testUtils.dom.triggerEvents($dropdownBgColor, ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-bg-color .note-custom-color'), ['mousedown', 'click']); await testUtils.fields.editAndTrigger($('.modal-dialog .o_hex_input'), '#875A7B', 'change'); await testUtils.dom.triggerEvents($('.o_technical_modal .modal-footer .btn-primary:contains("Choose")'), ['mousedown', 'click']); await testUtils.dom.triggerEvents(wysiwyg.$('.note-color .note-bg-color .note-custom-color-btn:last'), ['mousedown', 'click']); assert.deepEqual(wysiwyg.getValue(), 'dom not to edit
dom to edit
', testName); var range = weTestUtils.select('font:contents()[0]->0', 'font:contents()[0]->4', $editable); assert.deepEqual(Wysiwyg.getRange($editable[0]), range, testName + carretTestSuffix); }, }, ]; var def = Promise.resolve(); _.each(bgcolorTests, function (test) { def = def.then(async function () { testName = test.name; wysiwyg.setValue(test.content); var range = weTestUtils.select(test.start, test.end, $editable); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await test.do(); if (!test.async) { assert.deepEqual(wysiwyg.getValue(), test.test.content, testName); assert.deepEqual(Wysiwyg.getRange($editable[0]), weTestUtils.select(test.test.start, test.test.end, $editable), testName + carretTestSuffix); } }); }); return def.then(function () { wysiwyg.destroy(); }); }); }); QUnit.test('Unordered list', function (assert) { assert.expect(34); return weTestUtils.createWysiwyg({ debug: false, wysiwygOptions: { }, }).then(function (wysiwyg) { var $editable = wysiwyg.$('.note-editable'); var $btnUL = wysiwyg.$('.note-para .note-icon-unorderedlist'); var ulTests = [{ name: "Click UL: p -> ul", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnUL, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnUL, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', }, }, { name: "Click UL: p -> ul (across li's)", content: 'dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', }, }, { name: "Click UL: ul -> p (from second li)", content: 'dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
', start: 'p:eq(2):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', }, }, // Conversion from OL { name: "Click UL: ol -> ul", content: 'dom not to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit 1
dom to edit 2
dom not to edit
xxx
dom to edit 1
dom to edit 2
dom not to edit
xxx
dom not to edit
dom to edit
dom not to edit
dom not to edit
xxx
dom not to edit
dom to edit
dom not to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit 1
dom to edit 2
dom not to edit
xxx
dom to edit 1
dom to edit 2
dom not to edit
xxx
dom not to edit
dom to edit
dom not to edit
dom not to edit
xxx
dom not to edit
dom to edit
dom not to edit
dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnOL, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($btnOL, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(1):contents()[0]->5', }, }, { name: "Click OL: p -> ol (across li's)", content: 'dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', }, }, { name: "Click OL: ol -> p (from second li) (2)", content: 'dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
a
' + 'b
c
d
e
a
' + 'b
c
d
e
a
' + 'a
' + 'a
' + 'a
' + 'a
' + 'a
' + 'a
' + '| aaa | ' + '||
a
' + '
| ' +
'||
a
' + '![]() | ' +
'||
a
' + 'x
' + 'aaa
bbb
ccc
ddd
y
', start: 'p:eq(2):contents(0)->1', end: 'p:eq(3):contents(0)->1', do: async function () { await testUtils.dom.triggerEvents($btnOL, ['mousedown', 'click']); }, test: { content: 'x
' + 'aaa
bbb
' + 'ccc
' + 'ddd
y
', start: 'p:eq(2):contents(0)->1', end: 'p:eq(3):contents(0)->1', }, }, { name: "Click OL with selected LI in UL", content: 'x
' + 'aaa
bbb
ccc
ddd
y
', start: 'p:eq(2):contents(0)->1', end: 'p:eq(3):contents(0)->1', do: async function () { await testUtils.dom.triggerEvents($btnOL, ['mousedown', 'click']); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
y
', start: 'p:eq(2):contents(0)->1', end: 'p:eq(3):contents(0)->1', }, }, { name: "Click OL after ENTER in p > b", content: "dom to edit
", start: 'b:contents(0)->11', do: async function () { weTestUtils.keydown(13, $editable); // ENTER await testUtils.dom.triggerEvents($btnOL, ['mousedown', 'click']); weTestUtils.keydown('a', $editable); // ENTER }, test: { content: "dom to edit
a
dom not to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit 1
dom to edit 2
dom not to edit
xxx
dom to edit 1
dom to edit 2
dom not to edit
xxx
dom not to edit
dom to edit
dom not to edit
dom not to edit
xxx
dom not to edit
dom to edit
dom not to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
dom to edit
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit
dom not to edit
xxx
dom to edit 1
dom to edit 2
dom not to edit
xxx
dom to edit 1
dom to edit 2
dom not to edit
xxx
dom not to edit
dom to edit
dom not to edit
dom not to edit
xxx
dom not to edit
dom to edit
dom not to edit
dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnAlignLeft, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', }, }, { name: "Click ALIGN LEFT: p (parent align right) -> p align left (does nothing)", content: 'dom not to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnAlignRight, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', }, }, /* ALIGN CENTER */ { name: "Click ALIGN CENTER: p -> p align center", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnAlignCenter, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', }, }, { name: "Click ALIGN CENTER: p align left & default -> p align center (across paragraphs)", content: 'dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnAlignCenter, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', }, }, /* ALIGN RIGHT */ { name: "Click ALIGN RIGHT: p align center -> p align right", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnAlignRight, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', }, }, { name: "Click ALIGN RIGHT: p align center & default -> p align right (across paragraphs)", content: 'dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnAlignRight, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', }, }, /* ALIGN JUSTIFY */ { name: "Click ALIGN JUSTIFY: p align right -> p align justify", content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnAlignJustify, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', }, }, { name: "Click ALIGN JUSTIFY: p align right & default -> p align justify (across paragraphs)", content: 'dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnAlignJustify, ['mousedown', 'click']); }, test: { content: 'dom not to edit
dom to edit
dom to edit
', start: 'p:eq(1):contents()[0]->1', end: 'p:eq(2):contents()[0]->5', }, }, ]; var def = Promise.resolve(); _.each(alignTests, function (test) { def = def.then(async function() { testName = test.name; wysiwyg.setValue(test.content); var range = weTestUtils.select(test.start, test.end, $editable); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await test.do(); assert.deepEqual(wysiwyg.getValue(), test.test.content, testName); assert.deepEqual(Wysiwyg.getRange($editable[0]), weTestUtils.select(test.test.start, test.test.end, $editable), testName + carretTestSuffix); }); }); return def.then(function() { wysiwyg.destroy(); }); }); }); QUnit.test('Indent/outdent', function (assert) { assert.expect(20); return weTestUtils.createWysiwyg({ debug: false, wysiwygOptions: { }, }).then(function (wysiwyg) { var $editable = wysiwyg.$('.note-editable'); var $dropdownPara = wysiwyg.$('.note-para .dropdown-toggle'); var $btnIndent = wysiwyg.$('.note-list .note-btn:eq(1)'); var $btnOutdent = wysiwyg.$('.note-list .note-btn:first'); var indentTests = [ /* INDENT */ { name: "Click INDENT: p -> indented p", content: 'dom to edit
', start: 'p:contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnIndent, ['mousedown', 'click']); }, test: { content: 'dom to edit
', start: 'p:contents()[0]->1', }, }, { name: "Click INDENT: li -> indented li", content: 'dom
to edit
dom
to edit
aaa
bbb
ccc
ddd
', start: 'p:eq(1):contents()[0]->0', end: 'p:eq(3):contents()[0]->3', do: function () { $dropdownPara.mousedown().click(); $btnIndent.mousedown().click(); }, test: { content: 'aaa
bbb
ccc
ddd
', start: 'p:eq(1):contents()[0]->0', end: 'p:eq(3):contents()[0]->3', }, }, /* OUTDENT */ { name: "Click OUTDENT: indented p -> p", content: 'dom to edit
', start: 'p:contents()[0]->1', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnOutdent, ['mousedown', 'click']); }, test: { content: 'dom to edit
', start: 'p:contents()[0]->1', }, }, { name: "Click OUTDENT: indented li -> li", content: 'dom
to edit
dom
to edit
dom
to edit
dom
to edit
x
' + 'aaa
bbb
ccc
ddd
eee
y
', start: 'ol ol p:eq(1):contents(0)->1', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnOutdent, ['mousedown', 'click']); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', start: 'ol:first > li:eq(2) p:contents(0)->1', }, }, { name: "Click OUTDENT on LI in OL in OL (2)", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', start: 'ol ol p:eq(1):contents(0)->1', do: async function () { await testUtils.dom.triggerEvents($dropdownPara, ['mousedown', 'click']); await testUtils.dom.triggerEvents($btnOutdent, ['mousedown', 'click']); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', start: 'li:eq(2) p:contents(0)->1', }, }, { name: "Click OUTDENT on LI in OL", content: 'aaa
bbb
ccc
aaa
bbb
' + 'ccc
dom
' + 'dom
' + 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('li:first'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "check checkbox in checklist with children (2)", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('li:first'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "uncheck checkbox in checklist with children", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('li:first'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "uncheck checkbox in checklist with children (2)", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('li:first'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "uncheck checkbox in checklist in checklist", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('ul ul li:eq(1)'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "uncheck checkbox in checklist in checklist (2)", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('ul ul li:eq(1)'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "check checkbox in checklist in checklist", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('ul ul li:eq(1)'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "check checkbox in checklist in checklist (2)", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('ul ul li:eq(1)'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "check checkbox in checklist in checklist (full)", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('ul ul li:eq(1)'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "check checkbox in checklist in checklist (full) (2)", content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', do: async function () { var $li = $editable.find('ul ul li:eq(1)'); $li.trigger($.Event('mousedown', { offsetX: -10, })); }, test: { content: 'x
' + 'aaa
bbb
ccc
ddd
eee
y
', }, }, { name: "convert 2 ul li ul li into two ul li ul.o_checklist li", content: '1
' + '2
' + '3
' + '4
' + '5
' + '1
' + '2
' + '3
' + '4
' + '5
' + 'dom to edit
', start: "p:contents()[0]->1", end: "p:contents()[0]->5", do: async function () { assert.strictEqual($('.modal-dialog:visible #o_link_dialog_label_input').val(), 'om t', testName + ' (label)'); await testUtils.fields.editInput($('.modal-dialog:visible #o_link_dialog_url_input'),'#'); }, test: { content: 'dom to edit
', start: 'a:contents()[0]->0', end: 'a:contents()[0]->4', }, }, { name: "Click LINK: p -> a in p (w/ URL) (no selection)", async: true, content: 'do edit
', start: 'p:contents()[0]->1', do: async function () { await testUtils.fields.editInput($('.modal-dialog:visible #o_link_dialog_label_input'),'om t'); await testUtils.fields.editInput($('.modal-dialog:visible #o_link_dialog_url_input'),'#'); }, test: { content: 'dom to edit
', start: 'p->2', // link not selected, the user can continue to write end: 'p->2', }, }, { name: "Click LINK: a.btn in div -> a.btn.btn-outline-alpha in div (edit) (no selection)", content: '', start: 'a:contents()[0]->5', do: async function () { assert.strictEqual($('.modal-dialog:visible #o_link_dialog_label_input').val(), 'dom to edit', testName + ' (label)'); await testUtils.fields.editInput($('.modal-dialog:visible #o_link_dialog_url_input'),'#newlink'); }, test: { content: '', start: 'a->0', end: 'a->1', }, }, { name: "Click LINK: p -> a in p (w/ Email)", async: true, content: 'dom to edit
', start: 'p:contents()[0]->1', end: 'p:contents()[0]->5', do: async function () { await testUtils.fields.editInput($('.modal-dialog:visible #o_link_dialog_url_input'),'john.coltrane@example.com'); }, test: { content: 'dom to edit
', start: 'a:contents()[0]->0', end: 'a:contents()[0]->4', }, }, { name: "Click LINK: p -> a in p (w/ URL & Size Large)", async: true, content: 'dom to edit
', start: 'p:contents()[0]->1', end: 'p:contents()[0]->5', do: async function () { await testUtils.fields.editInput($('.modal-dialog:visible #o_link_dialog_url_input'),'#'); await testUtils.fields.editInput($('.modal-dialog:visible [name="link_style_size"]'),"lg"); }, test: { content: 'dom to edit
', start: 'a:contents()[0]->0', end: 'a:contents()[0]->4', }, }, { name: "Click LINK: a in p -> a.btn-outline-alpha in p with alpha color and target=\"_blank\"", async: true, content: '', start: 'a:contents()[0]->1', do: async function () { await testUtils.fields.editInput( $('.modal-dialog:visible #o_link_dialog_url_input'), '#'); await testUtils.fields.editInput($('.modal-dialog:visible [name="link_style_shape"]'), "outline"); await testUtils.dom.triggerEvents($('.modal-dialog:visible .o_link_dialog_color .o_link_dialog_color_item.btn-alpha'), ['mousedown', 'click']); await testUtils.dom.triggerEvents($('.modal-dialog:visible .o_switch [name="is_new_window"]'), ['mousedown', 'click']); }, test: { content: '', start: 'a->0', end: 'a->1', }, }, // POPOVER { name: "Click LINK in popover after adding link in p", async: true, content: 'dom to edit
', start: "p:contents()[0]->1", end: "p:contents()[0]->5", do: async function () { $('.modal-dialog:visible #o_link_dialog_url_input').val('/link'); }, test: { check: async function () { await testUtils.dom.triggerEvents($('.note-link-popover .note-btn .note-icon-link'), ['mousedown', 'click']); assert.strictEqual($('.modal-dialog:visible #o_link_dialog_label_input').val(), 'om t', testName + ' (label)'); assert.strictEqual($('.modal-dialog:visible #o_link_dialog_url_input').val(), '/link', testName + ' (url)'); await testUtils.fields.editInput($('.modal-dialog:visible #o_link_dialog_url_input'), '/newlink'); await testUtils.dom.triggerEvents($('.modal-dialog:visible .modal-footer .btn.btn-primary:contains("Save")'), ['mousedown', 'click']); assert.deepEqual(wysiwyg.getValue(), 'dom to edit
', testName); }, }, }, { name: "Click UNLINK in popover after adding link in p", async: true, content: 'dom to edit
', start: "p:contents()[0]->1", end: "p:contents()[0]->5", do: async function () { $('.modal-dialog:visible #o_link_dialog_url_input').val('/link'); }, test: { content: 'dom to edit
', check: async function () { await testUtils.dom.triggerEvents($('.note-link-popover .note-btn .note-icon-chain-broken'), ['mousedown', 'click']); var range = weTestUtils.select('p:contents()[0]->1', 'p:contents()[0]->5', $editable); assert.deepEqual(Wysiwyg.getRange($editable[0]), range, testName + carretTestSuffix); }, }, }, ]; var def = Promise.resolve(); _.each(linkTests, function (test) { def = def.then(async function () { testName = test.name; wysiwyg.setValue(test.content); var range = weTestUtils.select(test.start, test.end, $editable); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await _clickLink(test.do, test.test); }); }); return def.then(function () { wysiwyg.destroy(); }); }); }); QUnit.test('Table', function (assert) { assert.expect(13); async function createTable(wysiwyg) { await testUtils.dom.triggerEvents(wysiwyg.$('.note-table button:first'), ['mousedown', 'click']); var $grid = wysiwyg.$('.note-table .note-dimension-picker-mousecatcher'); var pos = $grid.offset(); $grid.trigger($.Event('mousemove', { pageX: pos.left + 40, pageY: pos.top + 40, })); await testUtils.dom.triggerEvents($grid, ['mousedown', 'click']); } return weTestUtils.createWysiwyg({ debug: false, wysiwygOptions: {}, }).then(async function (wysiwyg) { var $editable = wysiwyg.getEditable(); // create a table in an empty dom wysiwyg.setValue('dom to edit
'); range = weTestUtils.select('p:contents()[0]->0', 'p:contents()[0]->0', $editable); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await createTable(wysiwyg); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom to edit
', "should create a table at start of single p with content"); // create a table at end of p with content wysiwyg.setValue('dom to edit
'); range = weTestUtils.select('p:contents()[0]->11', 'p:contents()[0]->11', $editable); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await createTable(wysiwyg); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom to edit
' + 'dom to edit
'); range = weTestUtils.select('p:contents()[0]->5', 'p:contents()[0]->5', $editable); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await createTable(wysiwyg); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + 'o edit
', "should create a table"); // remove a table range = weTestUtils.select('td:first->0', 'td:first->0', $editable); $(range.sc).mousedown(); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); var $trash = $('.note-table-popover:visible button:has(.note-icon-trash)'); await testUtils.dom.triggerEvents($trash, ['mousedown', 'click']); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom to edit
', "should remove the table"); // re create a table and table in table await createTable(wysiwyg); await createTable(wysiwyg); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + 'o edit
', "should create a table inside the table"); // remove inner table range = weTestUtils.select('td td:eq(1)->0', 'td td:eq(1)->0', $editable); $(range.sc).mousedown(); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); $trash = $('.note-table-popover:visible button:has(.note-icon-trash)'); await testUtils.dom.triggerEvents($trash, ['mousedown', 'click']); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + 'o edit
', "should remove the inner table"); // use popover to change row and line wysiwyg.setValue('dom t
' + '0-0 | 0-1 | 0-2 |
1-0 | 1-1 | 1-2 |
2-0 | 2-1 | 2-2 |
o edit
'); // remove a row range = weTestUtils.select('td:eq(1)->0', 'td:eq(1)->0', $editable); $(range.sc).mousedown(); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await testUtils.dom.triggerEvents($('.note-table-popover:visible button:has(.note-icon-col-remove)'), ['mousedown', 'click']); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + '0-0 | 0-2 |
1-0 | 1-2 |
2-0 | 2-2 |
o edit
', "should remove a row"); // remove a line range = weTestUtils.select('tr:eq(1) td:eq(1)->0', 'tr:eq(1) td:eq(1)->0', $editable); $(range.sc).mousedown(); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await testUtils.dom.triggerEvents($('.note-table-popover:visible button:has(.note-icon-row-remove)'), ['mousedown', 'click']); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + '0-0 | 0-2 |
2-0 | 2-2 |
o edit
', "should remove a line"); // add a row after range = weTestUtils.select('tr:eq(1) td:first->0', 'tr:eq(1) td:first->0', $editable); $(range.sc).mousedown(); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); await testUtils.dom.triggerEvents($('.note-table-popover:visible button:has(.note-icon-col-after)'), ['mousedown', 'click']); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + '0-0 | 0-2 | |
2-0 | 2-2 |
o edit
', "should add a row after"); // add a row before $(range.sc).mousedown(); await testUtils.dom.triggerEvents($('.note-table-popover:visible button:has(.note-icon-col-before)'), ['mousedown', 'click']); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + '0-0 | 0-2 | ||
2-0 | 2-2 |
o edit
', "should add a row before"); // add a line after $(range.sc).mousedown(); await testUtils.dom.triggerEvents($('.note-table-popover:visible button:has(.note-icon-row-below)'), ['mousedown', 'click']); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + '0-0 | 0-2 | ||
2-0 | 2-2 | ||
o edit
', "should add a line after"); // add a line before $(range.sc).mousedown(); await testUtils.dom.triggerEvents($('.note-table-popover:visible button:has(.note-icon-row-above)'), ['mousedown', 'click']); assert.strictEqual($editable.html().replace(/\s+/g, ' '), 'dom t
' + '0-0 | 0-2 | ||
2-0 | 2-2 | ||
o edit
', "should add a line before"); wysiwyg.destroy(); }); }); QUnit.test('CodeView', async function (assert) { assert.expect(8); var wysiwyg = await weTestUtils.createWysiwyg({ debug: false, wysiwygOptions: { codeview: true, }, }); wysiwyg.setValue('dom to edit 
dom to edit a 
\u200B
\u200B
| ' + ' aaa' + ' | ' + '' + ' bbb' + ' | ' + '' + ' ccc' + ' | ' + '
| ' + ' aaa' + ' | ' + '' +
' bb b' +
' | ' +
' ' + ' ccc' + ' | ' + '
| ' +
' ' + ' | ' +
' ' +
' ' + ' | ' +
' ' +
' ' + ' | ' +
'
| ' +
' ' + ' | ' +
' ' +
' ![]() ' + ' | ' +
' ' +
' ' + ' | ' +
'
\u200B
\u200B
\u200B
\u200B
\u200B
\u200B
\u200B
\u200B
\u200B
\u200B
\u200B\u200B
', check: async function () { assert.strictEqual($('.note-icon-popover').css('display'), 'block', testName + ' (popover)'); }, }, }, // Remove font { name: "Click REMOVE in popover after adding font in empty p", async: true, content: '\u200B\u200B
', check: async function () { await testUtils.dom.triggerEvents($('.note-icon-popover .note-faSize .dropdown-toggle'), ['mousedown', 'click']); await testUtils.dom.triggerEvents($('.note-icon-popover .note-faSize .dropdown-item:contains("5x")'), ['mousedown', 'click']); assert.ok($('.note-icon-popover .note-faSize .dropdown-item:contains("5x")').hasClass('active'), testName + ' (popover)'); }, }, }, // Spin { name: "Click SPIN in popover after adding pictogram in empty p", async: true, content: '\u200B\u200B
', check: async function () { await testUtils.dom.triggerEvents($('.note-icon-popover .note-faSpin .note-btn'), ['mousedown', 'click']); }, }, }, // Replace pictogram { name: "Add PICTOGRAM in empty p then replace it", async: true, content: '\u200B\u200B
', }); }, }, }, { name: "Replace PICTOGRAM (i.fa => span.fa)", async: true, content: 'tata yoyo
tata
yoyo

\u200B\u200B
', testName); }, }, }, { name: "replace video by pictogram (2)", async: true, content: 'aaa
bbb
', start: "div->0", do: async function () { await _insertPictogram('fa-glass'); }, test: { check: async function () { assert.deepEqual(wysiwyg.getValue(), 'aaabbb
', testName); }, }, }, ]; var def = Promise.resolve(); _.each(mediaTests, function (test) { def = def.then(async function () { testName = test.name; wysiwyg.setValue(test.content); var range = weTestUtils.select(test.start, test.end, $editable); await testUtils.dom.triggerEvents($(range.sc), ['mousedown', 'click']); Wysiwyg.setRange(range.sc, range.so, range.ec, range.eo); return _clickMedia(wysiwyg, assert, test.do, test.test); }); }); return def.then(function () { wysiwyg.destroy(); }); }); }); }); }); }); });