forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			556 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			556 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* Any copyright is dedicated to the Public Domain.
 | |
|  * http://creativecommons.org/publicdomain/zero/1.0/ */
 | |
| 
 | |
| function modifySelection(s) {
 | |
|   var g = window.getSelection();
 | |
|   var l = g.getRangeAt(0);
 | |
|   var d = document.createElement("p");
 | |
|   d.innerHTML = s;
 | |
|   d.appendChild(l.cloneContents());
 | |
| 
 | |
|   var e = document.createElement("div");
 | |
|   document.body.appendChild(e);
 | |
|   e.appendChild(d);
 | |
|   var a = document.createRange();
 | |
|   a.selectNode(d);
 | |
|   g.removeAllRanges();
 | |
|   g.addRange(a);
 | |
|   window.setTimeout(function() {
 | |
|     e.remove();
 | |
|     g.removeAllRanges();
 | |
|     g.addRange(l);
 | |
|   }, 0);
 | |
| }
 | |
| 
 | |
| function getLoadContext() {
 | |
|   var Ci = SpecialPowers.Ci;
 | |
|   return SpecialPowers.wrap(window).docShell.QueryInterface(Ci.nsILoadContext);
 | |
| }
 | |
| 
 | |
| async function testCopyPaste(isXHTML) {
 | |
|   var suppressUnicodeCheckIfHidden = !!isXHTML;
 | |
|   var suppressHTMLCheck = !!isXHTML;
 | |
| 
 | |
|   var docShell = SpecialPowers.wrap(window).docShell;
 | |
| 
 | |
|   var documentViewer = docShell.contentViewer.QueryInterface(
 | |
|     SpecialPowers.Ci.nsIContentViewerEdit
 | |
|   );
 | |
| 
 | |
|   var clipboard = SpecialPowers.Services.clipboard;
 | |
| 
 | |
|   var textarea = SpecialPowers.wrap(document.getElementById("input"));
 | |
| 
 | |
|   async function copySelectionToClipboard(suppressUnicodeCheck) {
 | |
|     await SimpleTest.promiseClipboardChange(
 | |
|       () => true,
 | |
|       () => {
 | |
|         documentViewer.copySelection();
 | |
|       }
 | |
|     );
 | |
|     if (!suppressUnicodeCheck) {
 | |
|       ok(
 | |
|         clipboard.hasDataMatchingFlavors(["text/unicode"], 1),
 | |
|         "check text/unicode"
 | |
|       );
 | |
|     }
 | |
|     if (!suppressHTMLCheck) {
 | |
|       ok(clipboard.hasDataMatchingFlavors(["text/html"], 1), "check text/html");
 | |
|     }
 | |
|   }
 | |
|   function clear(node, suppressUnicodeCheck) {
 | |
|     textarea.blur();
 | |
|     var sel = window.getSelection();
 | |
|     sel.removeAllRanges();
 | |
|   }
 | |
|   async function copyToClipboard(node, suppressUnicodeCheck) {
 | |
|     clear();
 | |
|     var r = document.createRange();
 | |
|     r.selectNode(node);
 | |
|     window.getSelection().addRange(r);
 | |
|     await copySelectionToClipboard(suppressUnicodeCheck);
 | |
|   }
 | |
|   function addRange(startNode, startIndex, endNode, endIndex) {
 | |
|     var sel = window.getSelection();
 | |
|     var r = document.createRange();
 | |
|     r.setStart(startNode, startIndex);
 | |
|     r.setEnd(endNode, endIndex);
 | |
|     sel.addRange(r);
 | |
|   }
 | |
|   async function copyRangeToClipboard(
 | |
|     startNode,
 | |
|     startIndex,
 | |
|     endNode,
 | |
|     endIndex,
 | |
|     suppressUnicodeCheck
 | |
|   ) {
 | |
|     clear();
 | |
|     addRange(startNode, startIndex, endNode, endIndex);
 | |
|     await copySelectionToClipboard(suppressUnicodeCheck);
 | |
|   }
 | |
|   async function copyChildrenToClipboard(id) {
 | |
|     clear();
 | |
|     window.getSelection().selectAllChildren(document.getElementById(id));
 | |
|     await copySelectionToClipboard();
 | |
|   }
 | |
|   function getClipboardData(mime) {
 | |
|     var transferable = SpecialPowers.Cc[
 | |
|       "@mozilla.org/widget/transferable;1"
 | |
|     ].createInstance(SpecialPowers.Ci.nsITransferable);
 | |
|     transferable.init(getLoadContext());
 | |
|     transferable.addDataFlavor(mime);
 | |
|     clipboard.getData(transferable, 1);
 | |
|     var data = SpecialPowers.createBlankObject();
 | |
|     transferable.getTransferData(mime, data);
 | |
|     return data;
 | |
|   }
 | |
|   function testHtmlClipboardValue(mime, expected) {
 | |
|     // For Windows, navigator.platform returns "Win32".
 | |
|     var expectedValue = expected;
 | |
|     if (navigator.platform.includes("Win")) {
 | |
|       // Windows has extra content.
 | |
|       var expectedValue =
 | |
|         kTextHtmlPrefixClipboardDataWindows +
 | |
|         expected.replace(/\n/g, "\n") +
 | |
|         kTextHtmlSuffixClipboardDataWindows;
 | |
|     }
 | |
|     testClipboardValue(mime, expectedValue);
 | |
|   }
 | |
|   function testClipboardValue(mime, expected) {
 | |
|     if (suppressHTMLCheck && mime == "text/html") {
 | |
|       return null;
 | |
|     }
 | |
|     var data = SpecialPowers.wrap(getClipboardData(mime));
 | |
|     is(
 | |
|       data.value == null
 | |
|         ? data.value
 | |
|         : data.value.QueryInterface(SpecialPowers.Ci.nsISupportsString).data,
 | |
|       expected,
 | |
|       mime + " value in the clipboard"
 | |
|     );
 | |
|     return data.value;
 | |
|   }
 | |
|   function testPasteText(expected) {
 | |
|     textarea.value = "";
 | |
|     textarea.focus();
 | |
|     textarea.editor.paste(1);
 | |
|     is(textarea.value, expected, "value of the textarea after the paste");
 | |
|   }
 | |
|   function testPasteHTML(id, expected) {
 | |
|     var contentEditable = $(id);
 | |
|     contentEditable.focus();
 | |
|     synthesizeKey("v", { accelKey: true });
 | |
|     is(contentEditable.innerHTML, expected, id + ".innerHtml after the paste");
 | |
|   }
 | |
|   function testSelectionToString(expected) {
 | |
|     is(
 | |
|       window
 | |
|         .getSelection()
 | |
|         .toString()
 | |
|         .replace(/\r\n/g, "\n"),
 | |
|       expected,
 | |
|       "Selection.toString"
 | |
|     );
 | |
|   }
 | |
|   function testInnerHTML(id, expected) {
 | |
|     var value = document.getElementById(id).innerHTML;
 | |
|     is(value, expected, id + ".innerHTML");
 | |
|   }
 | |
| 
 | |
|   await copyChildrenToClipboard("draggable");
 | |
|   testSelectionToString("This is a draggable bit of text.");
 | |
|   testClipboardValue("text/unicode", "This is a draggable bit of text.");
 | |
|   testHtmlClipboardValue(
 | |
|     "text/html",
 | |
|     '<div id="draggable" title="title to have a long HTML line">This is a <em>draggable</em> bit of text.</div>'
 | |
|   );
 | |
|   testPasteText("This is a draggable bit of text.");
 | |
| 
 | |
|   await copyChildrenToClipboard("alist");
 | |
|   testSelectionToString(" bla\n\n    foo\n    bar\n\n");
 | |
|   testClipboardValue("text/unicode", " bla\n\n    foo\n    bar\n\n");
 | |
|   testHtmlClipboardValue(
 | |
|     "text/html",
 | |
|     '<div id="alist">\n    bla\n    <ul>\n      <li>foo</li>\n      \n      <li>bar</li>\n    </ul>\n  </div>'
 | |
|   );
 | |
|   testPasteText(" bla\n\n    foo\n    bar\n\n");
 | |
| 
 | |
|   await copyChildrenToClipboard("blist");
 | |
|   testSelectionToString(" mozilla\n\n    foo\n    bar\n\n");
 | |
|   testClipboardValue("text/unicode", " mozilla\n\n    foo\n    bar\n\n");
 | |
|   testHtmlClipboardValue(
 | |
|     "text/html",
 | |
|     '<div id="blist">\n    mozilla\n    <ol>\n      <li>foo</li>\n      \n      <li>bar</li>\n    </ol>\n  </div>'
 | |
|   );
 | |
|   testPasteText(" mozilla\n\n    foo\n    bar\n\n");
 | |
| 
 | |
|   await copyChildrenToClipboard("clist");
 | |
|   testSelectionToString(" mzla\n\n    foo\n        bazzinga!\n    bar\n\n");
 | |
|   testClipboardValue(
 | |
|     "text/unicode",
 | |
|     " mzla\n\n    foo\n        bazzinga!\n    bar\n\n"
 | |
|   );
 | |
|   testHtmlClipboardValue(
 | |
|     "text/html",
 | |
|     '<div id="clist">\n    mzla\n    <ul>\n      <li>foo<ul>\n        <li>bazzinga!</li>\n      </ul></li>\n      \n      <li>bar</li>\n    </ul>\n  </div>'
 | |
|   );
 | |
|   testPasteText(" mzla\n\n    foo\n        bazzinga!\n    bar\n\n");
 | |
| 
 | |
|   await copyChildrenToClipboard("div4");
 | |
|   testSelectionToString(" Tt t t ");
 | |
|   testClipboardValue("text/unicode", " Tt t t ");
 | |
|   if (isXHTML) {
 | |
|     testHtmlClipboardValue(
 | |
|       "text/html",
 | |
|       '<div id="div4">\n  T<textarea xmlns="http://www.w3.org/1999/xhtml">t t t</textarea>\n</div>'
 | |
|     );
 | |
|     testInnerHTML(
 | |
|       "div4",
 | |
|       '\n  T<textarea xmlns="http://www.w3.org/1999/xhtml">t t t</textarea>\n'
 | |
|     );
 | |
|   } else {
 | |
|     testHtmlClipboardValue(
 | |
|       "text/html",
 | |
|       '<div id="div4">\n  T<textarea>t t t</textarea>\n</div>'
 | |
|     );
 | |
|     testInnerHTML("div4", "\n  T<textarea>t t t</textarea>\n");
 | |
|   }
 | |
|   testPasteText(" Tt t t ");
 | |
| 
 | |
|   await copyChildrenToClipboard("div5");
 | |
|   testSelectionToString(" T     ");
 | |
|   testClipboardValue("text/unicode", " T     ");
 | |
|   if (isXHTML) {
 | |
|     testHtmlClipboardValue(
 | |
|       "text/html",
 | |
|       '<div id="div5">\n  T<textarea xmlns="http://www.w3.org/1999/xhtml">     </textarea>\n</div>'
 | |
|     );
 | |
|     testInnerHTML(
 | |
|       "div5",
 | |
|       '\n  T<textarea xmlns="http://www.w3.org/1999/xhtml">     </textarea>\n'
 | |
|     );
 | |
|   } else {
 | |
|     testHtmlClipboardValue(
 | |
|       "text/html",
 | |
|       '<div id="div5">\n  T<textarea>     </textarea>\n</div>'
 | |
|     );
 | |
|     testInnerHTML("div5", "\n  T<textarea>     </textarea>\n");
 | |
|   }
 | |
|   testPasteText(" T     ");
 | |
| 
 | |
|   await copyRangeToClipboard(
 | |
|     $("div6").childNodes[0],
 | |
|     0,
 | |
|     $("div6").childNodes[1],
 | |
|     1,
 | |
|     suppressUnicodeCheckIfHidden
 | |
|   );
 | |
|   testSelectionToString("");
 | |
|   // START Disabled due to bug 564688
 | |
|   if (false) {
 | |
|     testClipboardValue("text/unicode", "");
 | |
|     testClipboardValue("text/html", "");
 | |
|   }
 | |
|   // END Disabled due to bug 564688
 | |
|   testInnerHTML("div6", "div6");
 | |
| 
 | |
|   await copyRangeToClipboard(
 | |
|     $("div7").childNodes[0],
 | |
|     0,
 | |
|     $("div7").childNodes[0],
 | |
|     4,
 | |
|     suppressUnicodeCheckIfHidden
 | |
|   );
 | |
|   testSelectionToString("");
 | |
|   // START Disabled due to bug 564688
 | |
|   if (false) {
 | |
|     testClipboardValue("text/unicode", "");
 | |
|     testClipboardValue("text/html", "");
 | |
|   }
 | |
|   // END Disabled due to bug 564688
 | |
|   testInnerHTML("div7", "div7");
 | |
| 
 | |
|   await copyRangeToClipboard(
 | |
|     $("div8").childNodes[0],
 | |
|     0,
 | |
|     $("div8").childNodes[0],
 | |
|     4,
 | |
|     suppressUnicodeCheckIfHidden
 | |
|   );
 | |
|   testSelectionToString("");
 | |
|   // START Disabled due to bug 564688
 | |
|   if (false) {
 | |
|     testClipboardValue("text/unicode", "");
 | |
|     testClipboardValue("text/html", "");
 | |
|   }
 | |
|   // END Disabled due to bug 564688
 | |
|   testInnerHTML("div8", "div8");
 | |
| 
 | |
|   await copyRangeToClipboard(
 | |
|     $("div9").childNodes[0],
 | |
|     0,
 | |
|     $("div9").childNodes[0],
 | |
|     4,
 | |
|     suppressUnicodeCheckIfHidden
 | |
|   );
 | |
|   testSelectionToString("div9");
 | |
|   testClipboardValue("text/unicode", "div9");
 | |
|   testHtmlClipboardValue("text/html", "div9");
 | |
|   testInnerHTML("div9", "div9");
 | |
| 
 | |
|   await copyToClipboard($("div10"), suppressUnicodeCheckIfHidden);
 | |
|   testSelectionToString("");
 | |
|   testInnerHTML("div10", "div10");
 | |
| 
 | |
|   await copyToClipboard($("div10").firstChild, suppressUnicodeCheckIfHidden);
 | |
|   testSelectionToString("");
 | |
| 
 | |
|   await copyRangeToClipboard(
 | |
|     $("div10").childNodes[0],
 | |
|     0,
 | |
|     $("div10").childNodes[0],
 | |
|     1,
 | |
|     suppressUnicodeCheckIfHidden
 | |
|   );
 | |
|   testSelectionToString("");
 | |
| 
 | |
|   await copyRangeToClipboard(
 | |
|     $("div10").childNodes[1],
 | |
|     0,
 | |
|     $("div10").childNodes[1],
 | |
|     1,
 | |
|     suppressUnicodeCheckIfHidden
 | |
|   );
 | |
|   testSelectionToString("");
 | |
| 
 | |
|   if (!isXHTML) {
 | |
|     // ============ copy/paste multi-range selection (bug 1123505)
 | |
|     // with text start node
 | |
|     var sel = window.getSelection();
 | |
|     sel.removeAllRanges();
 | |
|     var r = document.createRange();
 | |
|     var ul = $("ul1");
 | |
|     var parent = ul.parentNode;
 | |
|     r.setStart(parent, 0);
 | |
|     r.setEnd(parent.firstChild, 15); // the end of "Copy..."
 | |
|     sel.addRange(r);
 | |
| 
 | |
|     r = document.createRange();
 | |
|     r.setStart(ul, 1); // before the space inside the UL
 | |
|     r.setEnd(parent, 2); // after the UL
 | |
|     sel.addRange(r);
 | |
|     await copySelectionToClipboard(true);
 | |
|     testPasteHTML("contentEditable1", "Copy1then Paste");
 | |
| 
 | |
|     // with text end node
 | |
|     var sel = window.getSelection();
 | |
|     sel.removeAllRanges();
 | |
|     var r = document.createRange();
 | |
|     var ul = $("ul2");
 | |
|     var parent = ul.parentNode;
 | |
|     r.setStart(parent, 0);
 | |
|     r.setEnd(ul, 1); // after the space
 | |
|     sel.addRange(r);
 | |
| 
 | |
|     r = document.createRange();
 | |
|     r.setStart(parent.childNodes[1], 0); // the start of "Copy..."
 | |
|     r.setEnd(parent, 2);
 | |
|     sel.addRange(r);
 | |
|     await copySelectionToClipboard(true);
 | |
|     testPasteHTML("contentEditable2", "Copy2then Paste");
 | |
| 
 | |
|     // with text end node and non-empty start
 | |
|     var sel = window.getSelection();
 | |
|     sel.removeAllRanges();
 | |
|     var r = document.createRange();
 | |
|     var ul = $("ul3");
 | |
|     var parent = ul.parentNode;
 | |
|     r.setStart(parent, 0);
 | |
|     r.setEnd(ul, 1); // after the space
 | |
|     sel.addRange(r);
 | |
| 
 | |
|     r = document.createRange();
 | |
|     r.setStart(parent.childNodes[1], 0); // the start of "Copy..."
 | |
|     r.setEnd(parent, 2);
 | |
|     sel.addRange(r);
 | |
|     await copySelectionToClipboard(true);
 | |
|     testPasteHTML(
 | |
|       "contentEditable3",
 | |
|       '<ul id="ul3"><li>\n<br></li></ul>Copy3then Paste'
 | |
|     );
 | |
| 
 | |
|     // with elements of different depth
 | |
|     var sel = window.getSelection();
 | |
|     sel.removeAllRanges();
 | |
|     var r = document.createRange();
 | |
|     var div1 = $("div1s");
 | |
|     var parent = div1.parentNode;
 | |
|     r.setStart(parent, 0);
 | |
|     r.setEnd(document.getElementById("div1se1"), 1); // after the "inner" DIV
 | |
|     sel.addRange(r);
 | |
| 
 | |
|     r = document.createRange();
 | |
|     r.setStart(div1.childNodes[1], 0); // the start of "after"
 | |
|     r.setEnd(parent, 1);
 | |
|     sel.addRange(r);
 | |
|     await copySelectionToClipboard(true);
 | |
|     testPasteHTML(
 | |
|       "contentEditable4",
 | |
|       '<div id="div1s"><div id="div1se1">before</div></div><div id="div1s">after</div>'
 | |
|     );
 | |
| 
 | |
|     // with elements of different depth, and a text node at the end
 | |
|     var sel = window.getSelection();
 | |
|     sel.removeAllRanges();
 | |
|     var r = document.createRange();
 | |
|     var div1 = $("div2s");
 | |
|     var parent = div1.parentNode;
 | |
|     r.setStart(parent, 0);
 | |
|     r.setEnd(document.getElementById("div2se1"), 1); // after the "inner" DIV
 | |
|     sel.addRange(r);
 | |
| 
 | |
|     r = document.createRange();
 | |
|     r.setStart(div1.childNodes[1], 0); // the start of "after"
 | |
|     r.setEnd(parent, 1);
 | |
|     sel.addRange(r);
 | |
|     await copySelectionToClipboard(true);
 | |
|     testPasteHTML(
 | |
|       "contentEditable5",
 | |
|       '<div id="div2s"><div id="div2se1">before</div></div><div id="div2s">after</div>'
 | |
|     );
 | |
| 
 | |
|     // crash test for bug 1127835
 | |
|     var e1 = document.getElementById("1127835crash1");
 | |
|     var e2 = document.getElementById("1127835crash2");
 | |
|     var e3 = document.getElementById("1127835crash3");
 | |
|     var t1 = e1.childNodes[0];
 | |
|     var t3 = e3.childNodes[0];
 | |
| 
 | |
|     var sel = window.getSelection();
 | |
|     sel.removeAllRanges();
 | |
| 
 | |
|     var r = document.createRange();
 | |
|     r.setStart(t1, 1);
 | |
|     r.setEnd(e2, 0);
 | |
|     sel.addRange(r);
 | |
| 
 | |
|     r = document.createRange();
 | |
|     r.setStart(e2, 1);
 | |
|     r.setEnd(t3, 0);
 | |
|     sel.addRange(r);
 | |
|     await copySelectionToClipboard(true);
 | |
|     testPasteHTML(
 | |
|       "contentEditable6",
 | |
|       '<span id="1127835crash1"></span><div id="1127835crash2"><div>\n</div></div><br>'
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   // ============ copy/paste test from/to a textarea
 | |
| 
 | |
|   var val = "1\n 2\n  3";
 | |
|   textarea.value = val;
 | |
|   textarea.select();
 | |
|   await SimpleTest.promiseClipboardChange(textarea.value, () => {
 | |
|     textarea.editor.copy();
 | |
|   });
 | |
|   textarea.value = "";
 | |
|   textarea.editor.paste(1);
 | |
|   is(textarea.value, val);
 | |
|   textarea.value = "";
 | |
| 
 | |
|   // ============ NOSCRIPT should not be copied
 | |
| 
 | |
|   await copyChildrenToClipboard("div13");
 | |
|   testSelectionToString("__");
 | |
|   testClipboardValue("text/unicode", "__");
 | |
|   testHtmlClipboardValue("text/html", '<div id="div13">__</div>');
 | |
|   testPasteText("__");
 | |
| 
 | |
|   // ============ converting cell boundaries to tabs in tables
 | |
| 
 | |
|   await copyToClipboard($("tr1"));
 | |
|   testClipboardValue("text/unicode", "foo\tbar");
 | |
| 
 | |
|   if (!isXHTML) {
 | |
|     // ============ spanning multiple rows
 | |
| 
 | |
|     await copyRangeToClipboard($("tr2"), 0, $("tr3"), 0);
 | |
|     testClipboardValue("text/unicode", "1\t2\n3\t4\n");
 | |
|     testHtmlClipboardValue(
 | |
|       "text/html",
 | |
|       '<table><tbody><tr id="tr2"><tr id="tr2"><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr><tr id="tr3"></tr></tr></tbody></table>'
 | |
|     );
 | |
| 
 | |
|     // ============ spanning multiple rows in multi-range selection
 | |
| 
 | |
|     clear();
 | |
|     addRange($("tr2"), 0, $("tr2"), 2);
 | |
|     addRange($("tr3"), 0, $("tr3"), 2);
 | |
|     await copySelectionToClipboard();
 | |
|     testClipboardValue("text/unicode", "1\t2\n5\t6");
 | |
|     testHtmlClipboardValue(
 | |
|       "text/html",
 | |
|       '<table><tbody><tr id="tr2"><td>1</td><td>2</td></tr><tr id="tr3"><td>5</td><td>6</td></tr></tbody></table>'
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   // ============ manipulating Selection in oncopy
 | |
| 
 | |
|   await copyRangeToClipboard(
 | |
|     $("div11").childNodes[0],
 | |
|     0,
 | |
|     $("div11").childNodes[1],
 | |
|     2
 | |
|   );
 | |
|   testClipboardValue("text/unicode", "Xdiv11");
 | |
|   testHtmlClipboardValue("text/html", "<div><p>X<span>div</span>11</p></div>");
 | |
| 
 | |
|   await new Promise(resolve => {
 | |
|     setTimeout(resolve, 0);
 | |
|   });
 | |
|   testSelectionToString("div11");
 | |
| 
 | |
|   await new Promise(resolve => {
 | |
|     setTimeout(resolve, 0);
 | |
|   });
 | |
|   await copyRangeToClipboard(
 | |
|     $("div12").childNodes[0],
 | |
|     0,
 | |
|     $("div12").childNodes[1],
 | |
|     2
 | |
|   );
 | |
| 
 | |
|   testClipboardValue("text/unicode", "Xdiv12");
 | |
|   testHtmlClipboardValue("text/html", "<div><p>X<span>div</span>12</p></div>");
 | |
|   await new Promise(resolve => {
 | |
|     setTimeout(resolve, 0);
 | |
|   });
 | |
|   testSelectionToString("div12");
 | |
| 
 | |
|   await new Promise(resolve => {
 | |
|     setTimeout(resolve, 0);
 | |
|   });
 | |
| 
 | |
|   if (!isXHTML) {
 | |
|     // ============ copy from ruby
 | |
| 
 | |
|     const ruby1 = $("ruby1");
 | |
|     const ruby1Container = ruby1.parentNode;
 | |
| 
 | |
|     // Ruby annotation is included when selecting inside ruby.
 | |
|     await copyRangeToClipboard(ruby1, 0, ruby1, 6);
 | |
|     testClipboardValue("text/unicode", "aabb(AABB)");
 | |
| 
 | |
|     // Ruby annotation is ignored when selecting across ruby.
 | |
|     await copyRangeToClipboard(ruby1Container, 0, ruby1Container, 3);
 | |
|     testClipboardValue("text/unicode", "XaabbY");
 | |
| 
 | |
|     // ... unless converter.html2txt.always_include_ruby is set
 | |
|     await SpecialPowers.pushPrefEnv({
 | |
|       set: [["converter.html2txt.always_include_ruby", true]],
 | |
|     });
 | |
|     await copyRangeToClipboard(ruby1Container, 0, ruby1Container, 3);
 | |
|     testClipboardValue("text/unicode", "Xaabb(AABB)Y");
 | |
|     await SpecialPowers.popPrefEnv();
 | |
|   }
 | |
| }
 | 
