tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

input-events-exec-command.html (12520B)


      1 <!DOCTYPE html>
      2 <meta charset="utf-8">
      3 <title>execCommand() should only trigger 'input'</title>
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <div id="txt" contenteditable></div>
      7 <script>
      8 (function() {
      9    let lastBeforeInputType = '';
     10    let lastBeforeInputData = '';
     11    let lastBeforeInputDataTransfer = undefined;
     12    let lastInputType = '';
     13    let lastInputData = '';
     14    let lastInputDataTransfer = undefined;
     15    const txt = document.getElementById('txt');
     16    txt.addEventListener('beforeinput', function(event) {
     17        assert_true(event instanceof InputEvent);
     18        assert_false(event.isComposing);
     19        lastBeforeInputType = event.inputType;
     20        lastBeforeInputData = event.data;
     21        lastBeforeInputDataTransfer = event.dataTransfer;
     22    });
     23    txt.addEventListener('input', function(event) {
     24        assert_true(event instanceof InputEvent);
     25        assert_false(event.isComposing);
     26        lastInputType = event.inputType;
     27        lastInputData = event.data;
     28        lastInputDataTransfer = event.dataTransfer;
     29    });
     30 
     31    const NO_INPUT_EVENT_FIRED = 'NO_INPUT_EVENT_FIRED';
     32    function testExecCommandInputType(command, args, inputType, data, dataTransfer) {
     33        const description = `Calling execCommand("${command}", false, ${args})`;
     34        lastBeforeInputType = NO_INPUT_EVENT_FIRED;
     35        lastBeforeInputData = NO_INPUT_EVENT_FIRED;
     36        lastBeforeInputDataTransfer = NO_INPUT_EVENT_FIRED;
     37        lastInputType = NO_INPUT_EVENT_FIRED;
     38        lastInputData = NO_INPUT_EVENT_FIRED;
     39        lastInputDataTransfer = NO_INPUT_EVENT_FIRED;
     40        test(function() {
     41            try {
     42                document.execCommand(command, false, args);
     43            } catch (e) {
     44                assert_true(false, `execCommand shouldn't cause any exception: ${e}`);
     45            }
     46        }, description + " (calling execCommand)");
     47        test(function() {
     48            assert_equals(lastBeforeInputType, NO_INPUT_EVENT_FIRED);
     49            assert_equals(lastBeforeInputData, NO_INPUT_EVENT_FIRED);
     50            assert_equals(lastBeforeInputDataTransfer, NO_INPUT_EVENT_FIRED);
     51        }, description + " (shouldn't fire beforeinput)");
     52        test(function() {
     53            assert_equals(lastInputType, inputType);
     54        }, description + " (inputType value)");
     55        if (lastInputType === NO_INPUT_EVENT_FIRED) {
     56            return;
     57        }
     58        test(function() {
     59            assert_equals(lastInputData, data);
     60        }, description + " (data value)");
     61        if (dataTransfer === null) {
     62            test(function() {
     63                assert_equals(lastInputDataTransfer, dataTransfer,
     64                              `${description} should produce dataTransfer: null`);
     65            }, description + " (dataTransfer value)");
     66        } else {
     67            for (let item of dataTransfer) {
     68                test(function() {
     69                    try {
     70                        assert_equals(lastInputDataTransfer.getData(item.type), item.data,
     71                                      `${description} should produce dataTransfer.getData(${item.type}): ${item.data}`);
     72                    } catch (e) {
     73                        assert_true(false, `calling dataTransfer.getData(${item.type}) caused exception: ${e}`);
     74                    }
     75                }, `${description} (dataTransfer value, ${item.type})`);
     76                test(function() {
     77                    try {
     78                        lastInputDataTransfer.clearData(item.type);
     79                    } catch (e) {
     80                        assert_true(false, `calling dataTransfer.clearData(${item.type}) caused exception: ${e}`);
     81                    }
     82                    assert_equals(lastInputDataTransfer.getData(item.type), item.data,
     83                                  `${description} dataTransfer.clearData(${item.type}) should do nothing`);
     84                }, `${description} (dataTransfer.clearData(${item.type}))`);
     85                test(function() {
     86                    try {
     87                        lastInputDataTransfer.setData(item.type, "foo");
     88                    } catch (e) {
     89                        assert_true(false, `calling dataTransfer.setData(${item.type}) caused exception: ${e}`);
     90                    }
     91                    assert_equals(lastInputDataTransfer.getData(item.type), item.data,
     92                                  `${description} dataTransfer.setData(${item.type}, "foo") should do nothing`);
     93                }, `${description} (dataTransfer.setData(${item.type}))`);
     94            }
     95        }
     96    }
     97 
     98    txt.focus();
     99    // InsertText
    100    testExecCommandInputType('insertText', 'a', 'insertText', 'a', null);
    101    testExecCommandInputType('insertText', 'bc', 'insertText', 'bc', null);
    102    test(function() {
    103        assert_equals(txt.innerHTML, 'abc');
    104    }, "execCommand(\"insertText\") should insert \"abc\" into the editor");
    105    testExecCommandInputType('insertOrderedList', null, 'insertOrderedList', null, null);
    106    test(function() {
    107        assert_equals(txt.innerHTML, '<ol><li>abc</li></ol>');
    108    }, "execCommand(\"insertOrderedList\") should make <ol> and wrap the text with it");
    109    testExecCommandInputType('insertUnorderedList', null, 'insertUnorderedList', null, null);
    110    test(function() {
    111        assert_equals(txt.innerHTML, '<ul><li>abc</li></ul>');
    112    }, "execCommand(\"insertUnorderedList\") should make <ul> and wrap the text with it");
    113    testExecCommandInputType('insertLineBreak', null, 'insertLineBreak', null, null);
    114    testExecCommandInputType('insertParagraph', null, 'insertParagraph', null, null);
    115    txt.innerHTML = '';
    116    testExecCommandInputType('insertHorizontalRule', null, 'insertHorizontalRule', null, null);
    117 
    118    // Styling
    119    txt.innerHTML = 'abc';
    120    var selection = window.getSelection();
    121    selection.collapse(txt, 0);
    122    selection.extend(txt, 1);
    123    testExecCommandInputType('bold', null, 'formatBold', null, null);
    124    test(function() {
    125        assert_equals(txt.innerHTML, '<b>abc</b>');
    126    }, "execCommand(\"bold\") should wrap selected text with <b> element");
    127    testExecCommandInputType('italic', null, 'formatItalic', null, null);
    128    test(function() {
    129        assert_equals(txt.innerHTML, '<b><i>abc</i></b>');
    130    }, "execCommand(\"italic\") should wrap selected text with <i> element");
    131    testExecCommandInputType('underline', null, 'formatUnderline', null, null);
    132    test(function() {
    133        assert_equals(txt.innerHTML, '<b><i><u>abc</u></i></b>');
    134    }, "execCommand(\"underline\") should wrap selected text with <u> element");
    135    testExecCommandInputType('strikeThrough', null, 'formatStrikeThrough', null, null);
    136    test(function() {
    137        assert_equals(txt.innerHTML, '<b><i><u><strike>abc</strike></u></i></b>');
    138    }, "execCommand(\"strikeThrough\") should wrap selected text with <strike> element");
    139    testExecCommandInputType('superscript', null, 'formatSuperscript', null, null);
    140    test(function() {
    141        assert_equals(txt.innerHTML, '<b><i><u><strike><sup>abc</sup></strike></u></i></b>');
    142    }, "execCommand(\"superscript\") should wrap selected text with <sup> element");
    143    testExecCommandInputType('subscript', null, 'formatSubscript', null, null);
    144    test(function() {
    145        assert_equals(txt.innerHTML, '<b><i><u><strike><sub>abc</sub></strike></u></i></b>');
    146    }, "execCommand(\"subscript\") should wrap selected text with <sub> element");
    147    txt.innerHTML = 'abc';
    148    selection.collapse(txt, 0);
    149    selection.extend(txt, 1);
    150    for (let test of [{command: 'backColor', inputType: 'formatBackColor'},
    151                      {command: 'foreColor', inputType: 'formatFontColor'},
    152                      {command: 'hiliteColor', inputType: 'formatBackColor'}]) {
    153      testExecCommandInputType(test.command, '#FF0000', test.inputType, 'rgb(255, 0, 0)', null);
    154      testExecCommandInputType(test.command, '#00FF00FF', test.inputType, 'rgb(0, 255, 0)', null);
    155      testExecCommandInputType(test.command, '#0000FF88', test.inputType, 'rgba(0, 0, 255, 0.533)', null);
    156      testExecCommandInputType(test.command, 'orange', test.inputType, 'rgb(255, 165, 0)', null);
    157      testExecCommandInputType(test.command, 'Inherit', test.inputType, 'inherit', null);
    158      testExecCommandInputType(test.command, 'Initial', test.inputType, 'initial', null);
    159      testExecCommandInputType(test.command, 'Reset', test.inputType, 'reset', null);
    160      testExecCommandInputType(test.command, 'transparent', test.inputType, 'rgba(0, 0, 0, 0)', null);
    161      testExecCommandInputType(test.command, 'CurrentColor', test.inputType, 'currentcolor', null);
    162      testExecCommandInputType(test.command, 'Invalid-Value', test.inputType, 'Invalid-Value', null);
    163    }
    164 
    165    testExecCommandInputType('fontName', 'monospace', 'formatFontName', 'monospace', null);
    166    testExecCommandInputType('fontName', ' monospace ', 'formatFontName', ' monospace ', null);
    167    testExecCommandInputType('fontName', '  monospace  ', 'formatFontName', '  monospace  ', null);
    168 
    169    // Formating
    170    txt.innerHTML = 'abc';
    171    testExecCommandInputType('justifyCenter', null, 'formatJustifyCenter', null, null);
    172    test(function() {
    173        assert_equals(txt.innerHTML, '<div style="text-align: center;">abc</div>');
    174    }, "execCommand(\"justifyCenter\") should wrap the text with <div> element whose text-align is center");
    175    testExecCommandInputType('justifyFull', null, 'formatJustifyFull', null, null);
    176    test(function() {
    177        assert_equals(txt.innerHTML, '<div style="text-align: justify;">abc</div>');
    178    }, "execCommand(\"justifyFull\") should wrap the text with <div> element whose text-align is justify");
    179    testExecCommandInputType('justifyRight', null, 'formatJustifyRight', null, null);
    180    test(function() {
    181        assert_equals(txt.innerHTML, '<div style="text-align: right;">abc</div>');
    182    }, "execCommand(\"justifyRight\") should wrap the text with <div> element whose text-align is right");
    183    testExecCommandInputType('justifyLeft', null, 'formatJustifyLeft', null, null);
    184    test(function() {
    185        assert_equals(txt.innerHTML, '<div style="text-align: left;">abc</div>');
    186    }, "execCommand(\"justifyLeft\") should wrap the text with <div> element whose text-align is left");
    187    selection.collapse(txt, 0);
    188    selection.extend(txt, 1);
    189    testExecCommandInputType('removeFormat', null, 'formatRemove', null, null);
    190    test(function() {
    191        assert_equals(txt.innerHTML, '<div style="">abc</div>');
    192    }, "execCommand(\"removeFormat\") should remove the style of current block");
    193    testExecCommandInputType('indent', null, 'formatIndent', null, null);
    194    testExecCommandInputType('outdent', null, 'formatOutdent', null, null);
    195    test(function() {
    196        assert_equals(txt.innerHTML, '<div style="">abc</div>');
    197    }, "Set of execCommand(\"indent\") and execCommand(\"outdent\") should keep same DOM tree");
    198 
    199    // Copy shouldn't fire 'input'.
    200    txt.innerHTML = 'ab<b>c</b>def';
    201    selection.collapse(txt.firstChild, 1);
    202    selection.extend(txt.firstChild.nextSibling.nextSibling, 1);
    203    testExecCommandInputType('copy', null, NO_INPUT_EVENT_FIRED, NO_INPUT_EVENT_FIRED, NO_INPUT_EVENT_FIRED);
    204    // Cut/Paste should fire 'input'.
    205    testExecCommandInputType('cut', null, 'deleteByCut', null, null);
    206    // XXX How can we test 'text/html' case? The detail of copied HTML fragment depends on browser.
    207    testExecCommandInputType('paste', null, 'insertFromPaste', null,  [{type: 'text/plain', data: 'bcd'}]);
    208 
    209    // Link and Unlink
    210    txt.innerHTML = 'abc';
    211    selection.collapse(txt.firstChild, 1);
    212    selection.extend(txt.firstChild, 2);
    213    testExecCommandInputType('createLink', 'https://example.com/', 'insertLink', 'https://example.com/', null);
    214    test(function() {
    215        assert_equals(txt.innerHTML, 'a<a href="https://example.com/">b</a>c');
    216    }, "execCommand(\"createLink\") should create a link with absolute URL");
    217    testExecCommandInputType('unlink', null, '', null, null);
    218    test(function() {
    219        assert_equals(txt.innerHTML, 'abc');
    220    }, "execCommand(\"createLink\") should remove the link");
    221 
    222    txt.innerHTML = 'abc';
    223    selection.collapse(txt.firstChild, 1);
    224    selection.extend(txt.firstChild, 2);
    225    testExecCommandInputType('createLink', 'foo.html', 'insertLink', 'foo.html', null);
    226    test(function() {
    227        assert_equals(txt.innerHTML, 'a<a href="foo.html">b</a>c');
    228    }, "execCommand(\"createLink\") should create a link with relative URL");
    229 })();
    230 </script>