Opera 12.15 Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

documentedit.ot 66KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174
  1. /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
  2. group "DocumentEdit";
  3. require init;
  4. require DOCUMENT_EDIT_SUPPORT;
  5. include "modules/documentedit/OpDocumentEdit.h";
  6. include "modules/documentedit/OpDocumentEditUtils.h";
  7. include "modules/dochand/fdelm.h";
  8. include "modules/doc/frm_doc.h";
  9. include "modules/doc/html_doc.h";
  10. include "modules/logdoc/selection.h";
  11. include "modules/logdoc/selectionpoint.h";
  12. include "modules/doc/caret_painter.h";
  13. global
  14. {
  15. OpDocumentEdit* GetDocumentEdit()
  16. {
  17. if (FramesDocElm* ifrmroot = state.doc->GetIFrmRoot())
  18. if (ifrmroot->FirstChild())
  19. return ifrmroot->FirstChild()->GetCurrentDoc()->GetDocumentEdit();
  20. return NULL;
  21. }
  22. HTML_Element* GetSelectToCaretElement(OpDocumentEdit* edit)
  23. {
  24. HTML_Element* li_element = edit->FindElementAfterOfType(edit->GetBody(), HE_LI, FALSE);
  25. if (!li_element)
  26. return NULL;
  27. HTML_Element* candidate = li_element->FirstChild();
  28. if (candidate && candidate->GetIsListMarkerPseudoElement())
  29. candidate = candidate->Suc();
  30. return candidate;
  31. }
  32. }
  33. html
  34. {
  35. //! <script>
  36. //! function do_onload()
  37. //! {
  38. //! document.getElementById('edit').contentDocument.designMode = 'on';
  39. //! }
  40. //! </script>
  41. //! <body onload="do_onload()">
  42. //! <iframe id="edit" width="40" height="40"></iframe>
  43. //! </body>
  44. }
  45. test("ExecuteCommand_EmptyDoc") language ecmascript;
  46. {
  47. verify(document.getElementById('edit').contentDocument.designMode == 'on');
  48. verify(document.getElementById('edit').contentDocument.queryCommandEnabled('backcolor'));
  49. document.getElementById('edit').contentDocument.execCommand('backcolor', false, '#AA8855');
  50. }
  51. html
  52. {
  53. //! <script>
  54. //! function do_onload()
  55. //! {
  56. //! var doc = document.getElementById('edit').contentDocument;
  57. //! doc.open();
  58. //! doc.write("<HTML><BODY>Some <EM>italic</EM> and <B>bold</B> text!</BODY></HTML>");
  59. //! doc.close();
  60. //! doc = document.getElementById('edit').contentDocument;
  61. //! doc.designMode = 'on';
  62. //! }
  63. //! </script>
  64. //! <body onload="do_onload()">
  65. //! <iframe id="edit" width="40" height="40"></iframe>
  66. //! </body>
  67. }
  68. test("WriteTemplateDocument") language ecmascript;
  69. {
  70. var doc = document.getElementById('edit').contentDocument;
  71. verify(doc.designMode == 'on');
  72. verify(doc.body.innerHTML == "Some <em>italic</em> and <b>bold</b> text!");
  73. }
  74. test("EmptyDocument") language ecmascript;
  75. {
  76. var doc = document.getElementById('edit').contentDocument;
  77. doc.body.innerHTML = "";
  78. doc.execCommand('bold', false, null);
  79. verify(doc.body);
  80. }
  81. test("EditDocument1") language C++;
  82. {
  83. OpDocumentEdit* edit = GetDocumentEdit();
  84. verify(edit);
  85. edit->InsertText(UNI_L("test"), 4);
  86. }
  87. test("EditDocument2") language ecmascript;
  88. {
  89. var doc = document.getElementById('edit').contentDocument;
  90. verify(doc.body.innerHTML == "<strong>test</strong>");
  91. }
  92. subtest VerifyHtml(OpDocumentEdit* edit, const uni_char* text)
  93. {
  94. OpString tmp;
  95. edit->GetTextHTML(tmp);
  96. // Turn unicode nonbreaking space into &nbsp; since we can't (and don't want to) write teststrings with unicode character.
  97. while (1)
  98. {
  99. int pos = tmp.FindI(UNI_L("\xA0"));
  100. if (pos == KNotFound)
  101. break;
  102. tmp.Delete(pos, 1);
  103. tmp.Insert(pos, UNI_L("&nbsp;"));
  104. }
  105. if (tmp.CompareI(text))
  106. {
  107. output("Value: \"%s\" Expected value: \"%s\"\n", ST_down(tmp.CStr() ? tmp.CStr() : UNI_L("")), ST_down(text ? text : UNI_L("")));
  108. }
  109. verify(tmp.CompareI(text) == 0);
  110. }
  111. test("StyleStartEnd") language C++;
  112. {
  113. OpDocumentEdit* edit = GetDocumentEdit();
  114. verify(edit);
  115. edit->Clear();
  116. edit->InsertText(UNI_L("x"), 1);
  117. verify(VerifyHtml(edit, UNI_L("x")));
  118. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  119. edit->InsertText(UNI_L("x"), 1);
  120. verify(VerifyHtml(edit, UNI_L("x<STRONG>x</STRONG>")));
  121. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  122. verify(VerifyHtml(edit, UNI_L("x<STRONG>x</STRONG>")));
  123. edit->InsertText(UNI_L("x"), 1);
  124. verify(VerifyHtml(edit, UNI_L("x<STRONG>x</STRONG>x")));
  125. edit->Clear();
  126. edit->InsertText(UNI_L("x"), 1);
  127. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  128. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  129. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_ITALIC);
  130. edit->InsertText(UNI_L("x"), 1);
  131. verify(VerifyHtml(edit, UNI_L("x<EM>x</EM>")));
  132. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  133. edit->InsertText(UNI_L("x"), 1);
  134. verify(VerifyHtml(edit, UNI_L("x<EM>x<STRONG>x</STRONG></EM>")));
  135. /* edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  136. edit->InsertText(UNI_L("x"), 1);
  137. verify(VerifyHtml(edit, UNI_L("x<EM>x<STRONG>x</STRONG>x</EM>")));
  138. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_ITALIC);
  139. edit->InsertText(UNI_L("x"), 1);
  140. verify(VerifyHtml(edit, UNI_L("x<EM>x<STRONG>x</STRONG>x</EM>x")));*/
  141. }
  142. test("StyleAndWhitespace") language C++;
  143. {
  144. OpDocumentEdit* edit = GetDocumentEdit();
  145. verify(edit);
  146. edit->SetTextHTML(UNI_L("<STRONG>one two three</STRONG>"));
  147. // Select "two"
  148. HTML_Element* elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  149. verify(elm);
  150. edit->m_caret.Place(elm, 4);
  151. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 7);
  152. // Remove bold from selection
  153. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  154. verify(VerifyHtml(edit, UNI_L("<STRONG>one </STRONG>two<STRONG> three</STRONG>")));
  155. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  156. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_REMOVEFORMAT);
  157. verify(VerifyHtml(edit, UNI_L("one two three")));
  158. // Select "two"
  159. elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  160. verify(elm);
  161. edit->m_caret.Place(elm, 4, FALSE, FALSE);
  162. OpInputAction action(OpInputAction::ACTION_RANGE_NEXT_CHARACTER);
  163. edit->EditAction(&action);
  164. edit->EditAction(&action);
  165. edit->EditAction(&action);
  166. // Set bold and italic, and remove italic.
  167. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  168. verify(VerifyHtml(edit, UNI_L("one <STRONG>two</STRONG> three")));
  169. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_ITALIC);
  170. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_ITALIC);
  171. verify(VerifyHtml(edit, UNI_L("one <STRONG>two</STRONG> three")));
  172. }
  173. test("WhiteSpaceNBSP1") language C++;
  174. {
  175. OpDocumentEdit* edit = GetDocumentEdit();
  176. verify(edit);
  177. OpInputAction backspace(OpInputAction::ACTION_BACKSPACE);
  178. edit->SetTextHTML(UNI_L(""));
  179. // Adding space/text
  180. edit->InsertText(UNI_L(" "), 1);
  181. verify(VerifyHtml(edit, UNI_L("&nbsp;")));
  182. edit->InsertText(UNI_L("A"), 1);
  183. verify(VerifyHtml(edit, UNI_L("&nbsp;A")));
  184. edit->InsertText(UNI_L(" "), 1);
  185. verify(VerifyHtml(edit, UNI_L("&nbsp;A&nbsp;")));
  186. edit->InsertText(UNI_L("B"), 1);
  187. verify(VerifyHtml(edit, UNI_L("&nbsp;A B")));
  188. // Removing text
  189. edit->OnInputAction(&backspace);
  190. verify(VerifyHtml(edit, UNI_L("&nbsp;A&nbsp;")));
  191. }
  192. test("WhiteSpaceNBSP2") language C++;
  193. {
  194. OpDocumentEdit* edit = GetDocumentEdit();
  195. verify(edit);
  196. edit->SetTextHTML(UNI_L(""));
  197. // Adding lots of space
  198. edit->InsertText(UNI_L(" "), 1);
  199. edit->InsertText(UNI_L(" "), 1);
  200. verify(VerifyHtml(edit, UNI_L("&nbsp;&nbsp;")));
  201. edit->InsertText(UNI_L(" "), 1);
  202. verify(VerifyHtml(edit, UNI_L("&nbsp; &nbsp;")));
  203. }
  204. test("WhiteSpaceNBSP3") language C++;
  205. {
  206. OpDocumentEdit* edit = GetDocumentEdit();
  207. verify(edit);
  208. OpInputAction backspace(OpInputAction::ACTION_BACKSPACE);
  209. edit->SetTextHTML(UNI_L("AB"));
  210. edit->m_caret.Move(FALSE, FALSE);
  211. // Adding lots of space
  212. edit->InsertText(UNI_L(" "), 1);
  213. verify(VerifyHtml(edit, UNI_L("A B")));
  214. edit->InsertText(UNI_L(" "), 1);
  215. verify(VerifyHtml(edit, UNI_L("A &nbsp;B")));
  216. edit->InsertText(UNI_L(" "), 1);
  217. verify(VerifyHtml(edit, UNI_L("A &nbsp; B")));
  218. // Removing space
  219. edit->OnInputAction(&backspace);
  220. verify(VerifyHtml(edit, UNI_L("A &nbsp;B")));
  221. edit->OnInputAction(&backspace);
  222. verify(VerifyHtml(edit, UNI_L("A B")));
  223. }
  224. test("WhiteSpaceNBSP4") language C++;
  225. {
  226. OpDocumentEdit* edit = GetDocumentEdit();
  227. verify(edit);
  228. edit->SetTextHTML(UNI_L("<DIV>A</DIV>after"));
  229. HTML_Element* elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  230. verify(elm);
  231. edit->m_caret.Place(elm, 1);
  232. edit->InsertText(UNI_L(" "), 1);
  233. verify(VerifyHtml(edit, UNI_L("<DIV>A&nbsp;</DIV>after")));
  234. edit->SetTextHTML(UNI_L("<SPAN>A</SPAN>after"));
  235. elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  236. verify(elm);
  237. edit->m_caret.Place(elm, 1);
  238. edit->InsertText(UNI_L(" "), 1);
  239. verify(VerifyHtml(edit, UNI_L("<SPAN>A </SPAN>after")));
  240. }
  241. test("WhiteSpaceNBSP5") language C++;
  242. {
  243. OpDocumentEdit* edit = GetDocumentEdit();
  244. verify(edit);
  245. OpInputAction backspace(OpInputAction::ACTION_BACKSPACE);
  246. edit->SetTextHTML(UNI_L("<PRE>A</PRE>"));
  247. edit->InsertText(UNI_L(" "), 1);
  248. verify(VerifyHtml(edit, UNI_L("<PRE>A </PRE>")));
  249. edit->InsertText(UNI_L(" "), 1);
  250. verify(VerifyHtml(edit, UNI_L("<PRE>A </PRE>")));
  251. edit->OnInputAction(&backspace);
  252. verify(VerifyHtml(edit, UNI_L("<PRE>A </PRE>")));
  253. }
  254. test("WhiteSpaceNBSP6") language C++;
  255. {
  256. OpDocumentEdit* edit = GetDocumentEdit();
  257. verify(edit);
  258. OpInputAction backspace(OpInputAction::ACTION_BACKSPACE);
  259. edit->SetTextHTML(UNI_L("<BR>bb<BR>"));
  260. edit->m_caret.PlaceFirst();
  261. edit->InsertText(UNI_L(" "), 1);
  262. edit->InsertText(UNI_L(" "), 1);
  263. edit->InsertText(UNI_L(" "), 1);
  264. verify(VerifyHtml(edit, UNI_L("&nbsp; &nbsp;<BR>bb<BR>")));
  265. edit->OnInputAction(&backspace);
  266. verify(VerifyHtml(edit, UNI_L("&nbsp;&nbsp;<BR>bb<BR>")));
  267. edit->OnInputAction(&backspace);
  268. verify(VerifyHtml(edit, UNI_L("&nbsp;<BR>bb<BR>")));
  269. edit->OnInputAction(&backspace);
  270. verify(VerifyHtml(edit, UNI_L("<BR>bb<BR>")));
  271. }
  272. test("StyleWithDummy") language C++;
  273. {
  274. OpDocumentEdit* edit = GetDocumentEdit();
  275. verify(edit);
  276. edit->Clear();
  277. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_ITALIC);
  278. edit->InsertText(UNI_L("a"), 1);
  279. verify(VerifyHtml(edit, UNI_L("<EM>a</EM>")));
  280. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  281. edit->InsertText(UNI_L("b"), 1);
  282. verify(VerifyHtml(edit, UNI_L("<EM>a<STRONG>b</STRONG></EM>")));
  283. }
  284. test("InsertFontFaceInFont") language C++;
  285. {
  286. OpDocumentEdit* edit = GetDocumentEdit();
  287. verify(edit);
  288. edit->Clear();
  289. edit->SetTextHTML(UNI_L("<P><FONT FACE=\"serif\">ABC</FONT></P>"));
  290. HTML_Element* elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  291. verify(elm);
  292. edit->m_caret.Place(elm, 1);
  293. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 2);
  294. uni_char font_name[11]; /* ARRAY OK 2011-06-23 stighal */
  295. uni_strcpy(font_name, UNI_L("sans-serif"));
  296. // This will eventually call GetFirstFontNumber, which requires a non-const string as it changes it temporarily
  297. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FONTNAME, FALSE, font_name);
  298. verify(VerifyHtml(edit, UNI_L("<P><FONT FACE=\"serif\">A</FONT><FONT FACE=\"sans-serif\">B</FONT><FONT FACE=\"serif\">C</FONT></P>")));
  299. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  300. elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  301. verify(elm);
  302. edit->m_caret.Place(elm, 1);
  303. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 2);
  304. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FONTSIZE, FALSE, UNI_L("5"));
  305. verify(VerifyHtml(edit, UNI_L("<P><FONT FACE=\"serif\">A<FONT SIZE=\"5\">B</FONT>C</FONT></P>")));
  306. }
  307. test("ForegroundColor") language C++;
  308. {
  309. OpDocumentEdit* edit = GetDocumentEdit();
  310. verify(edit);
  311. edit->Clear();
  312. edit->SetTextHTML(UNI_L("12"));
  313. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORECOLOR, FALSE, UNI_L("#FF0000"));
  314. edit->InsertText(UNI_L("34"), 2);
  315. verify(VerifyHtml(edit, UNI_L("12<FONT color=\"#ff0000\">34</FONT>")));
  316. edit->InsertText(UNI_L("56"), 2);
  317. verify(VerifyHtml(edit, UNI_L("12<FONT color=\"#ff0000\">3456</FONT>")));
  318. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORECOLOR, FALSE, UNI_L("#000000"));
  319. edit->InsertText(UNI_L("78"), 2);
  320. verify(VerifyHtml(edit, UNI_L("12<FONT color=\"#ff0000\">3456</FONT>78")));
  321. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORECOLOR, FALSE, UNI_L("#FF0000"));
  322. edit->InsertText(UNI_L("90"), 2);
  323. verify(VerifyHtml(edit, UNI_L("12<FONT color=\"#ff0000\">3456</FONT>78<FONT color=\"#ff0000\">90</FONT>")));
  324. }
  325. test("ForegroundColorSelection") language C++;
  326. {
  327. OpDocumentEdit* edit = GetDocumentEdit();
  328. verify(edit);
  329. edit->Clear();
  330. edit->SetTextHTML(UNI_L("0123"));
  331. HTML_Element* elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  332. verify(elm);
  333. edit->m_caret.Place(elm, 0);
  334. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 2);
  335. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORECOLOR, FALSE, UNI_L("#FF0000"));
  336. verify(VerifyHtml(edit, UNI_L("<FONT color=\"#ff0000\">01</FONT>23")));
  337. elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  338. verify(elm);
  339. edit->m_caret.Place(elm, 0);
  340. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 2);
  341. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORECOLOR, FALSE, UNI_L("#000000"));
  342. verify(VerifyHtml(edit, UNI_L("0123")));
  343. }
  344. test("ReplaceInDivAndUndo") language C++;
  345. {
  346. OpDocumentEdit* edit = GetDocumentEdit();
  347. verify(edit);
  348. edit->SetTextHTML(UNI_L("<DIV>inside</DIV>after"));
  349. // Select "inside"
  350. HTML_Element* elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  351. verify(elm);
  352. edit->m_caret.Place(elm, 0);
  353. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 6);
  354. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  355. verify(VerifyHtml(edit, UNI_L("<DIV><BR></DIV>after")));
  356. edit->InsertText(UNI_L("newtextinside"), 13);
  357. verify(VerifyHtml(edit, UNI_L("<DIV>newtextinside</DIV>after")));
  358. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  359. verify(VerifyHtml(edit, UNI_L("<DIV><BR></DIV>after")));
  360. edit->InsertTextHTML(UNI_L("<P>newpinside</P>"), 17);
  361. verify(VerifyHtml(edit, UNI_L("<DIV><P>newpinside</P></DIV>after")));
  362. }
  363. test("ReplaceBeforeDivAndUndo") language C++;
  364. {
  365. OpDocumentEdit* edit = GetDocumentEdit();
  366. verify(edit);
  367. edit->SetTextHTML(UNI_L("before<DIV>inside</DIV>"));
  368. // Select "before"
  369. edit->m_caret.PlaceFirst();
  370. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 6);
  371. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  372. // Delete empty text at caret - and expect caret to jump inside the content of the now removed DIV
  373. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  374. edit->InsertText(UNI_L("newtext"), 7);
  375. verify(VerifyHtml(edit, UNI_L("newtextinside")));
  376. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  377. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  378. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  379. verify(VerifyHtml(edit, UNI_L("before<DIV>inside</DIV>")));
  380. // Let's try to redo...
  381. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_REDO);
  382. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_REDO);
  383. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_REDO);
  384. verify(VerifyHtml(edit, UNI_L("newtextinside")));
  385. // ...and undo again
  386. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  387. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  388. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  389. verify(VerifyHtml(edit, UNI_L("before<DIV>inside</DIV>")));
  390. edit->m_caret.PlaceFirst();
  391. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 6);
  392. edit->InsertText(UNI_L("newtextbefore"), 13);
  393. verify(VerifyHtml(edit, UNI_L("newtextbefore<DIV>inside</DIV>")));
  394. }
  395. test("DeleteIntoContainer") language C++;
  396. {
  397. OpDocumentEdit* edit = GetDocumentEdit();
  398. verify(edit);
  399. edit->SetTextHTML(UNI_L("<DIV>insideX</DIV>Xafter"));
  400. HTML_Element *helm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  401. edit->m_caret.Place(helm, 6);
  402. helm = edit->FindEditableElement(helm, TRUE, FALSE, FALSE);
  403. verify(helm);
  404. edit->m_selection.SelectToCaret(helm, 1);
  405. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  406. verify(VerifyHtml(edit, UNI_L("<DIV>insideafter</DIV>")));
  407. }
  408. test("GetTextHTMLFromNamedElement") language C++;
  409. {
  410. OpDocumentEdit* edit = GetDocumentEdit();
  411. verify(edit);
  412. edit->SetTextHTML(UNI_L("<DIV id=a>A</DIV><DIV id=b>B</DIV>after"));
  413. OpString text;
  414. edit->GetTextHTMLFromNamedElement(text, UNI_L("a"), FALSE);
  415. verify(text.Compare(UNI_L("A")) == 0);
  416. edit->GetTextHTMLFromNamedElement(text, UNI_L("a"), TRUE);
  417. verify(text.Compare(UNI_L("<div id=\"a\">A</div>")) == 0);
  418. }
  419. test("DeleteNamedElement") language C++;
  420. {
  421. OpDocumentEdit* edit = GetDocumentEdit();
  422. verify(edit);
  423. edit->SetTextHTML(UNI_L("<DIV id=a>A</DIV><DIV id=b>B</DIV>after"));
  424. edit->DeleteNamedElement(UNI_L("b"));
  425. verify(VerifyHtml(edit, UNI_L("<DIV id=\"a\">A</DIV>after")));
  426. }
  427. test("UndoGrouping") language C++;
  428. {
  429. OpDocumentEdit* edit = GetDocumentEdit();
  430. verify(edit);
  431. edit->Clear();
  432. edit->InsertText(UNI_L("a"), 1, TRUE);
  433. edit->InsertText(UNI_L("a"), 1, TRUE);
  434. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  435. edit->InsertText(UNI_L("b"), 1, TRUE);
  436. verify(VerifyHtml(edit, UNI_L("b")));
  437. edit->Clear();
  438. edit->InsertText(UNI_L("a"), 1, TRUE);
  439. edit->InsertText(UNI_L("a"), 1, TRUE);
  440. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  441. edit->InsertText(UNI_L("b"), 1, TRUE);
  442. verify(VerifyHtml(edit, UNI_L("b")));
  443. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  444. verify(VerifyHtml(edit, UNI_L("aa")));
  445. }
  446. test("DeleteDiv") language C++;
  447. {
  448. OpDocumentEdit* edit = GetDocumentEdit();
  449. verify(edit);
  450. edit->SetTextHTML(UNI_L("before<DIV>inside</DIV>"));
  451. // Select "before"
  452. HTML_Element* elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  453. verify(elm);
  454. edit->m_caret.Place(elm, 6);
  455. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  456. verify(VerifyHtml(edit, UNI_L("beforeinside")));
  457. }
  458. test("SplitLineCaretPosition") language C++;
  459. {
  460. OpDocumentEdit* edit = GetDocumentEdit();
  461. verify(edit);
  462. edit->SetTextHTML(UNI_L("<P>first</P><P>second</P><P><BR></P>"));
  463. // Set caret after "fi"
  464. HTML_Element* elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  465. verify(elm);
  466. edit->m_caret.Place(elm, 2);
  467. edit->InsertBreak(TRUE, TRUE);
  468. verify(VerifyHtml(edit, UNI_L("<P>fi</P><P>rst</P><P>second</P><P><BR></P>")));
  469. edit->InsertText(UNI_L("thi"), 3, TRUE);
  470. verify(VerifyHtml(edit, UNI_L("<P>fi</P><P>thirst</P><P>second</P><P><BR></P>")));
  471. }
  472. test("KeepWhenTidy") language C++;
  473. {
  474. OpDocumentEdit* edit = GetDocumentEdit();
  475. verify(edit);
  476. edit->SetTextHTML(UNI_L("before<TABLE><TR><TD>content</TD></TR></TABLE>after"));
  477. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  478. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  479. verify(VerifyHtml(edit, UNI_L("<BR>")));
  480. edit->SetTextHTML(UNI_L("before<TABLE><TR><TD>content</TD></TR></TABLE>after"));
  481. edit->m_caret.PlaceFirst();
  482. OpInputAction action(OpInputAction::ACTION_RANGE_NEXT_CHARACTER);
  483. for(int i = 0; i < 8; i++)
  484. edit->OnInputAction(&action);
  485. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  486. verify(VerifyHtml(edit, UNI_L("<TABLE><TBODY><TR><TD>ontent</TD></TR></TBODY></TABLE>after")));
  487. }
  488. test("KeepWhenTidyIfEmpty") language C++;
  489. {
  490. OpDocumentEdit* edit = GetDocumentEdit();
  491. verify(edit);
  492. edit->SetTextHTML(UNI_L("before<TEXTAREA>content</TEXTAREA>after"));
  493. verify(VerifyHtml(edit, UNI_L("before<TEXTAREA>content</TEXTAREA>after")));
  494. edit->SetTextHTML(UNI_L("before<TEXTAREA></TEXTAREA>after"));
  495. edit->m_caret.PlaceFirst();
  496. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  497. verify(VerifyHtml(edit, UNI_L("efore<TEXTAREA></TEXTAREA>after")));
  498. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  499. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  500. verify(VerifyHtml(edit, UNI_L("<BR>")));
  501. }
  502. test("InsertListItems") language C++;
  503. {
  504. OpDocumentEdit* edit = GetDocumentEdit();
  505. verify(edit);
  506. // New list
  507. edit->SetTextHTML(UNI_L("item1"));
  508. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTORDEREDLIST);
  509. verify(VerifyHtml(edit, UNI_L("<OL><LI>item1</LI></OL>")));
  510. // New listitem
  511. edit->InsertBreak();
  512. edit->InsertText(UNI_L("item2"), 5, TRUE);
  513. verify(VerifyHtml(edit, UNI_L("<OL><LI>item1</LI><LI>item2</LI></OL>")));
  514. // New listitem that splits current
  515. edit->InsertText(UNI_L("item3"), 5, TRUE);
  516. for(int i = 0; i < 5; i++)
  517. edit->m_caret.Move(FALSE, FALSE);
  518. edit->InsertBreak();
  519. verify(VerifyHtml(edit, UNI_L("<OL><LI>item1</LI><LI>item2</LI><LI>item3</LI></OL>")));
  520. // Break 2 times to split the list
  521. edit->InsertBreak();
  522. edit->InsertBreak();
  523. edit->InsertText(UNI_L("noitem"), 6, TRUE);
  524. verify(VerifyHtml(edit, UNI_L("<OL><LI>item1</LI><LI>item2</LI></OL><P>noitem</P><OL><LI>item3</LI></OL>")));
  525. }
  526. test("InsertListMultipleItems") language C++;
  527. {
  528. OpDocumentEdit* edit = GetDocumentEdit();
  529. verify(edit);
  530. edit->SetTextHTML(UNI_L("<P>item1<br></P><P>item2<br></P><P>item3<br></P>"));
  531. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  532. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTORDEREDLIST);
  533. verify(VerifyHtml(edit, UNI_L("<OL><LI>item1<BR></LI><LI>item2<BR></LI><LI>item3<BR></LI></OL>")));
  534. }
  535. test("RemoveList") language C++;
  536. {
  537. OpDocumentEdit* edit = GetDocumentEdit();
  538. verify(edit);
  539. edit->SetTextHTML(UNI_L("<OL><LI>item1</LI><LI>item2</LI><LI>item3</LI></OL>"));
  540. // Remove item 1
  541. edit->m_caret.PlaceFirst();
  542. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTORDEREDLIST);
  543. verify(VerifyHtml(edit, UNI_L("<P>item1</P><OL><LI>item2</LI><LI>item3</LI></OL>")));
  544. // Reverse and jump to item 2
  545. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  546. verify(VerifyHtml(edit, UNI_L("<OL><LI>item1</LI><LI>item2</LI><LI>item3</LI></OL>")));
  547. edit->m_caret.Place(OpWindowCommander::CARET_DOWN);
  548. // Remove item 2
  549. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTORDEREDLIST);
  550. verify(VerifyHtml(edit, UNI_L("<OL><LI>item1</LI></OL><P>item2</P><OL><LI>item3</LI></OL>")));
  551. // Reverse and select all
  552. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  553. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  554. // Remove entire list
  555. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTORDEREDLIST);
  556. verify(VerifyHtml(edit, UNI_L("<P>item1</P><P>item2</P><P>item3</P>")));
  557. }
  558. test("ToggleListOrderingInNestledList") language C++;
  559. {
  560. OpDocumentEdit* edit = GetDocumentEdit();
  561. verify(edit);
  562. edit->SetTextHTML(UNI_L("<OL><LI><OL><LI>item1</LI></OL></LI><LI><OL><LI>item2</LI></OL></LI></OL>"));
  563. // After this should one ordered list contain one un-ordered list with item1 and item2
  564. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  565. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTUNORDEREDLIST);
  566. verify(VerifyHtml(edit, UNI_L("<OL><LI><UL><LI>item1</LI><LI>item2</LI></UL></LI></OL>")));
  567. // After this should one ordered list contain one ordered list with item1 and item2
  568. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTORDEREDLIST);
  569. verify(VerifyHtml(edit, UNI_L("<OL><LI><OL><LI>item1</LI><LI>item2</LI></OL></LI></OL>")));
  570. // After this should one ordered list contain item1 and item2
  571. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTORDEREDLIST);
  572. verify(VerifyHtml(edit, UNI_L("<OL><LI>item1</LI><LI>item2</LI></OL>")));
  573. }
  574. test("IndentAndOutdent") language C++;
  575. {
  576. OpDocumentEdit* edit = GetDocumentEdit();
  577. verify(edit);
  578. edit->SetTextHTML(UNI_L("item1<OL><LI>item2</LI><LI>item3</LI></OL>"));
  579. edit->m_caret.PlaceFirst();
  580. HTML_Element *item2 = GetSelectToCaretElement(edit);
  581. verify(item2);
  582. edit->m_selection.SelectToCaret(item2, 1);
  583. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INDENT);
  584. verify(VerifyHtml(edit, UNI_L("<BLOCKQUOTE>item1</BLOCKQUOTE><OL><OL><LI>item2</LI></OL><LI>item3</LI></OL>")));
  585. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_OUTDENT);
  586. verify(VerifyHtml(edit, UNI_L("item1<OL><LI>item2</LI><LI>item3</LI></OL>")));
  587. }
  588. test("IndentAndOutdentCSS") language C++;
  589. {
  590. OpDocumentEdit* edit = GetDocumentEdit();
  591. verify(edit);
  592. edit->SetTextHTML(UNI_L("item1<OL><LI>item2</LI><LI>item3</LI></OL>"));
  593. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_STYLEWITHCSS, FALSE, UNI_L("true"));
  594. edit->m_caret.PlaceFirst();
  595. HTML_Element *item2 = GetSelectToCaretElement(edit);
  596. verify(item2);
  597. edit->m_selection.SelectToCaret(item2, 1);
  598. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INDENT);
  599. verify(VerifyHtml(edit, UNI_L("<DIV style=\"margin-left: 40px !important;\">item1</DIV><OL><OL><LI>item2</LI></OL><LI>item3</LI></OL>")));
  600. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_OUTDENT);
  601. verify(VerifyHtml(edit, UNI_L("<DIV style=\"margin-left: 0px !important;\">item1</DIV><OL><LI>item2</LI><LI>item3</LI></OL>")));
  602. }
  603. test("RemoveLeadingWhitespace") language C++;
  604. {
  605. OpDocumentEdit* edit = GetDocumentEdit();
  606. verify(edit);
  607. edit->SetTextHTML(UNI_L("<STRONG>A</STRONG> BCD"));
  608. edit->m_caret.PlaceFirst();
  609. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  610. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  611. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  612. verify(VerifyHtml(edit, UNI_L("CD")));
  613. }
  614. test("FormatBlock") language C++;
  615. {
  616. OpDocumentEdit* edit = GetDocumentEdit();
  617. verify(edit);
  618. edit->SetTextHTML(UNI_L("Row1 with <B>some</B> <IMG SRC=\"blah\"> inlines.<BR>Row2"));
  619. edit->m_caret.PlaceFirst();
  620. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORMATBLOCK, FALSE, UNI_L("H1"));
  621. verify(VerifyHtml(edit, UNI_L("<H1>Row1 with <B>some</B> <IMG SRC=\"blah\"> inlines.<BR></H1>Row2")));
  622. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  623. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORMATBLOCK, FALSE, UNI_L("H2"));
  624. verify(VerifyHtml(edit, UNI_L("<H2>Row1 with <B>some</B> <IMG SRC=\"blah\"> inlines.<BR></H2><H2>Row2</H2>")));
  625. }
  626. test("CreateLink") language C++;
  627. {
  628. OpDocumentEdit* edit = GetDocumentEdit();
  629. verify(edit);
  630. edit->SetTextHTML(UNI_L("link text"));
  631. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  632. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_CREATELINK, FALSE, UNI_L("HTTP://aaaa"));
  633. verify(VerifyHtml(edit, UNI_L("<A HREF=\"HTTP://aaaa\">link text</A>")));
  634. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_CREATELINK, FALSE, UNI_L("HTTP://bbbb"));
  635. verify(VerifyHtml(edit, UNI_L("<A HREF=\"HTTP://bbbb\">link text</A>")));
  636. }
  637. test("MoveCaretOverWhitespace") language C++;
  638. {
  639. OpDocumentEdit* edit = GetDocumentEdit();
  640. verify(edit);
  641. edit->SetTextHTML(UNI_L("Two words"));
  642. HTML_Element* elm = edit->FindEditableElement(edit->GetBody(), TRUE, FALSE, FALSE);
  643. verify(elm);
  644. edit->m_caret.Place(elm, 0);
  645. // Forward
  646. edit->m_caret.Move(TRUE, FALSE);
  647. edit->m_caret.Move(TRUE, FALSE);
  648. edit->m_caret.Move(TRUE, FALSE);
  649. verify(edit->m_caret.GetOffset() == 3);
  650. edit->m_caret.Move(TRUE, FALSE);
  651. verify(edit->m_caret.GetOffset() == 10);
  652. edit->m_caret.Move(TRUE, FALSE);
  653. verify(edit->m_caret.GetOffset() == 11);
  654. // Backward
  655. edit->m_caret.Move(FALSE, FALSE);
  656. verify(edit->m_caret.GetOffset() == 10);
  657. edit->m_caret.Move(FALSE, FALSE);
  658. verify(edit->m_caret.GetOffset() == 3);
  659. }
  660. test("TabInPre") language C++;
  661. {
  662. OpDocumentEdit* edit = GetDocumentEdit();
  663. verify(edit);
  664. edit->SetTextHTML(UNI_L(""));
  665. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORMATBLOCK, FALSE, UNI_L("PRE"));
  666. edit->InsertText(UNI_L("\t"), 1, TRUE);
  667. edit->InsertText(UNI_L("\t"), 1, TRUE);
  668. verify(VerifyHtml(edit, UNI_L("<pre>\t\t</pre>")));
  669. edit->m_caret.Move(FALSE, FALSE);
  670. edit->InsertText(UNI_L("A"), 1, TRUE);
  671. verify(VerifyHtml(edit, UNI_L("<pre>\tA\t</pre>")));
  672. }
  673. test("TabInP") language C++;
  674. {
  675. OpDocumentEdit* edit = GetDocumentEdit();
  676. verify(edit);
  677. edit->SetTextHTML(UNI_L(""));
  678. edit->InsertText(UNI_L("\t"), 1, TRUE);
  679. verify(VerifyHtml(edit, UNI_L("&nbsp; &nbsp;&nbsp;")));
  680. edit->InsertText(UNI_L("\t"), 1, TRUE);
  681. verify(VerifyHtml(edit, UNI_L("&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;")));
  682. }
  683. test("TabAndDeletion") language C++;
  684. {
  685. OpDocumentEdit* edit = GetDocumentEdit();
  686. verify(edit);
  687. edit->SetTextHTML(UNI_L(""));
  688. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_FORMATBLOCK, FALSE, UNI_L("PRE"));
  689. edit->InsertText(UNI_L("\tA\t\t"), 4, TRUE);
  690. verify(VerifyHtml(edit, UNI_L("<pre>\tA\t\t</pre>")));
  691. OpInputAction action(OpInputAction::ACTION_BACKSPACE);
  692. edit->OnInputAction(&action);
  693. VerifyHtml(edit, UNI_L("<pre>\tA\t</pre>"));
  694. edit->InsertText(UNI_L("A"), 1, TRUE);
  695. verify(VerifyHtml(edit, UNI_L("<pre>\tA\tA</pre>")));
  696. }
  697. test("GeneratedContent") language C++;
  698. {
  699. OpDocumentEdit* edit = GetDocumentEdit();
  700. verify(edit);
  701. edit->SetTextHTML(UNI_L("<q>Some quoted text</q>"));
  702. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  703. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_ITALIC);
  704. verify(VerifyHtml(edit, UNI_L("<q><EM>Some quoted text</EM></q>")));
  705. }
  706. test("InsertBreakBR") language C++;
  707. {
  708. OpDocumentEdit* edit = GetDocumentEdit();
  709. verify(edit);
  710. edit->SetTextHTML(UNI_L(""));
  711. edit->InsertBreak(FALSE, FALSE);
  712. verify(VerifyHtml(edit, UNI_L("<br><br>")));
  713. edit->SetTextHTML(UNI_L("text"));
  714. edit->m_caret.PlaceFirst();
  715. edit->InsertBreak(FALSE, FALSE);
  716. verify(VerifyHtml(edit, UNI_L("<br>text")));
  717. edit->SetTextHTML(UNI_L(""));
  718. edit->InsertText(UNI_L("text"), 6, TRUE);
  719. edit->InsertBreak(FALSE, FALSE);
  720. verify(VerifyHtml(edit, UNI_L("text<br><br>")));
  721. edit->InsertBreak(FALSE, FALSE);
  722. verify(VerifyHtml(edit, UNI_L("text<br><br><br>")));
  723. edit->InsertBreak(FALSE, FALSE);
  724. verify(VerifyHtml(edit, UNI_L("text<br><br><br><br>")));
  725. }
  726. test("RemoveBreakBR") language C++;
  727. {
  728. OpDocumentEdit* edit = GetDocumentEdit();
  729. verify(edit);
  730. OpInputAction action(OpInputAction::ACTION_BACKSPACE);
  731. edit->OnInputAction(&action);
  732. verify(VerifyHtml(edit, UNI_L("text<br><br><br>")));
  733. edit->OnInputAction(&action);
  734. verify(VerifyHtml(edit, UNI_L("text<br><br>")));
  735. }
  736. test("InsertBreakBR_first_last") language C++;
  737. {
  738. OpDocumentEdit* edit = GetDocumentEdit();
  739. verify(edit);
  740. // Insert break at end of H1 should insert *after* the H1
  741. edit->SetTextHTML(UNI_L("<h1>header</h1>"));
  742. edit->InsertBreak(FALSE, FALSE);
  743. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  744. verify(VerifyHtml(edit, UNI_L("<h1>header<br><br></h1>")));
  745. #else
  746. verify(VerifyHtml(edit, UNI_L("<h1>header</h1><br>")));
  747. #endif
  748. // Insert break first in a H1 should insert it *before* the H1
  749. edit->m_caret.PlaceFirst();
  750. edit->InsertBreak(FALSE, FALSE);
  751. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  752. verify(VerifyHtml(edit, UNI_L("<h1><br>header<br><br></h1>")));
  753. #else
  754. verify(VerifyHtml(edit, UNI_L("<br><h1>header</h1><br>")));
  755. #endif
  756. // Same test for links
  757. edit->SetTextHTML(UNI_L("<a href=\"#\">header</a>"));
  758. edit->InsertBreak(FALSE, FALSE);
  759. verify(VerifyHtml(edit, UNI_L("<a href=\"#\">header</a><br><br>")));
  760. edit->m_caret.PlaceFirst();
  761. edit->InsertBreak(FALSE, FALSE);
  762. verify(VerifyHtml(edit, UNI_L("<br><a href=\"#\">header</a><br><br>")));
  763. // FIX: Should we split header/links etc if inserting BR-break inside a header?
  764. }
  765. test("InsertBreak_first_last_in_block_with_child") language C++;
  766. {
  767. OpDocumentEdit* edit = GetDocumentEdit();
  768. verify(edit);
  769. edit->SetTextHTML(UNI_L("<div>first<div>inner</div></div>"));
  770. edit->m_caret.PlaceFirst();
  771. edit->m_caret.UpdatePos();
  772. edit->m_caret.Place(OpWindowCommander::CARET_LINE_END);
  773. edit->InsertBreak(TRUE, TRUE);
  774. verify(VerifyHtml(edit, UNI_L("<div>first</div><div><br></div><div><div>inner</div></div>")));
  775. }
  776. test("InsertBreakP_InPlainText") language C++;
  777. {
  778. OpDocumentEdit* edit = GetDocumentEdit();
  779. verify(edit);
  780. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  781. // == Break without any initial P-tag =========
  782. // empty
  783. edit->SetTextHTML(UNI_L(""));
  784. edit->InsertBreak(TRUE, TRUE);
  785. verify(VerifyHtml(edit, UNI_L("<P><BR></P><P><BR></P>")));
  786. edit->InsertText(UNI_L("A"), 1);
  787. verify(VerifyHtml(edit, UNI_L("<P><BR></P><P>A</P>")));
  788. // before
  789. edit->SetTextHTML(UNI_L("test"));
  790. edit->m_caret.Place(OpWindowCommander::CARET_LINE_HOME);
  791. edit->InsertBreak(TRUE, TRUE);
  792. verify(VerifyHtml(edit, UNI_L("<P><BR></P><P>test</P>")));
  793. edit->InsertText(UNI_L("A"), 1);
  794. verify(VerifyHtml(edit, UNI_L("<P><BR></P><P>Atest</P>")));
  795. // after
  796. edit->SetTextHTML(UNI_L("test"));
  797. edit->m_caret.Place(OpWindowCommander::CARET_LINE_END);
  798. edit->InsertBreak(TRUE, TRUE);
  799. verify(VerifyHtml(edit, UNI_L("<P>test</P><P><BR></P>")));
  800. edit->InsertText(UNI_L("A"), 1);
  801. verify(VerifyHtml(edit, UNI_L("<P>test</P><P>A</P>")));
  802. // split
  803. edit->SetTextHTML(UNI_L("test"));
  804. edit->m_caret.Place(OpWindowCommander::CARET_LINE_HOME);
  805. edit->m_caret.Move(TRUE, FALSE);
  806. edit->InsertBreak(TRUE, TRUE);
  807. verify(VerifyHtml(edit, UNI_L("<P>t</P><P>est</P>")));
  808. edit->InsertText(UNI_L("A"), 1);
  809. verify(VerifyHtml(edit, UNI_L("<P>t</P><P>Aest</P>")));
  810. #endif
  811. }
  812. test("InsertBreakP_InP") language C++;
  813. {
  814. OpDocumentEdit* edit = GetDocumentEdit();
  815. verify(edit);
  816. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  817. // == Break with a initial P-tag =========
  818. // before
  819. edit->SetTextHTML(UNI_L("<p>test</p>"));
  820. edit->m_caret.Place(OpWindowCommander::CARET_LINE_HOME);
  821. edit->InsertBreak(TRUE, TRUE);
  822. verify(VerifyHtml(edit, UNI_L("<P><BR></P><P>test</P>")));
  823. edit->InsertText(UNI_L("A"), 1);
  824. verify(VerifyHtml(edit, UNI_L("<P><BR></P><P>Atest</P>")));
  825. // after
  826. edit->SetTextHTML(UNI_L("<p>test</p>"));
  827. edit->m_caret.Place(OpWindowCommander::CARET_LINE_END);
  828. edit->InsertBreak(TRUE, TRUE);
  829. verify(VerifyHtml(edit, UNI_L("<P>test</P><P><BR></P>")));
  830. edit->InsertText(UNI_L("A"), 1);
  831. verify(VerifyHtml(edit, UNI_L("<P>test</P><P>A</P>")));
  832. // split
  833. edit->SetTextHTML(UNI_L("<p>test</p>"));
  834. edit->m_caret.Place(OpWindowCommander::CARET_LINE_HOME);
  835. edit->m_caret.Move(TRUE, FALSE);
  836. edit->InsertBreak(TRUE, TRUE);
  837. verify(VerifyHtml(edit, UNI_L("<P>t</P><P>est</P>")));
  838. edit->InsertText(UNI_L("A"), 1);
  839. verify(VerifyHtml(edit, UNI_L("<P>t</P><P>Aest</P>")));
  840. #endif
  841. }
  842. test("InsertBreakP_InH1") language C++;
  843. {
  844. OpDocumentEdit* edit = GetDocumentEdit();
  845. verify(edit);
  846. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  847. // == Break with a initial H1-tag =========
  848. // before
  849. edit->SetTextHTML(UNI_L("<h1>test</h1>"));
  850. edit->m_caret.Place(OpWindowCommander::CARET_LINE_HOME);
  851. edit->InsertBreak(TRUE, TRUE);
  852. // verify(VerifyHtml(edit, UNI_L("<P><BR></P><h1>test</h1>")));
  853. verify(VerifyHtml(edit, UNI_L("<h1><BR></h1><h1>test</h1>")));
  854. edit->InsertText(UNI_L("A"), 1);
  855. // verify(VerifyHtml(edit, UNI_L("<P><BR></P><h1>Atest</h1>")));
  856. verify(VerifyHtml(edit, UNI_L("<h1><BR></h1><h1>Atest</h1>")));
  857. // after - P should follow the h1
  858. edit->SetTextHTML(UNI_L("<h1>test</h1>"));
  859. edit->m_caret.Place(OpWindowCommander::CARET_LINE_END);
  860. edit->InsertBreak(TRUE, TRUE);
  861. verify(VerifyHtml(edit, UNI_L("<h1>test</h1><P><BR></P>")));
  862. edit->InsertText(UNI_L("A"), 1);
  863. verify(VerifyHtml(edit, UNI_L("<h1>test</h1><P>A</P>")));
  864. // after - P should follow the h1 (with some text after the header already)
  865. edit->SetTextHTML(UNI_L("<h1>test</h1>after"));
  866. edit->m_caret.Place(OpWindowCommander::CARET_DOCUMENT_HOME);
  867. edit->m_caret.Place(OpWindowCommander::CARET_LINE_END);
  868. edit->InsertBreak(TRUE, TRUE);
  869. verify(VerifyHtml(edit, UNI_L("<h1>test</h1><P><BR></P>after")));
  870. edit->InsertText(UNI_L("A"), 1);
  871. verify(VerifyHtml(edit, UNI_L("<h1>test</h1><P>A</P>after")));
  872. // split - new H1 should be created (instead of paragraph)
  873. edit->SetTextHTML(UNI_L("<h1>test</h1>"));
  874. edit->m_caret.Place(OpWindowCommander::CARET_LINE_HOME);
  875. edit->m_caret.Move(TRUE, FALSE);
  876. edit->InsertBreak(TRUE, TRUE);
  877. verify(VerifyHtml(edit, UNI_L("<h1>t</h1><h1>est</h1>")));
  878. edit->InsertText(UNI_L("A"), 1);
  879. verify(VerifyHtml(edit, UNI_L("<h1>t</h1><h1>Aest</h1>")));
  880. #endif
  881. }
  882. test("InsertBreakP_InPRE") language C++;
  883. {
  884. OpDocumentEdit* edit = GetDocumentEdit();
  885. verify(edit);
  886. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  887. // == Break with inside a PRE tag =========
  888. // before
  889. edit->SetTextHTML(UNI_L("<pre>test</pre>"));
  890. edit->m_caret.Place(OpWindowCommander::CARET_LINE_HOME);
  891. edit->InsertBreak(TRUE, TRUE);
  892. edit->InsertText(UNI_L("A"), 1);
  893. verify(VerifyHtml(edit, UNI_L("<pre><br>Atest</pre>")));
  894. // Might want to change to the following behaviour
  895. // verify(VerifyHtml(edit, UNI_L("<pre></pre><pre>Atest</pre>")));
  896. // after
  897. edit->SetTextHTML(UNI_L("<pre>test</pre>"));
  898. edit->m_caret.Place(OpWindowCommander::CARET_LINE_END);
  899. edit->InsertBreak(TRUE, TRUE);
  900. edit->InsertText(UNI_L("A"), 1);
  901. verify(VerifyHtml(edit, UNI_L("<pre>test<br>A<br></pre>")));
  902. // Might want to change to the following behaviour
  903. // verify(VerifyHtml(edit, UNI_L("<pre>test</pre><pre>A</pre>")));
  904. // split - new pre should be created (instead of br)
  905. edit->SetTextHTML(UNI_L("<pre>test</pre>"));
  906. edit->m_caret.Place(OpWindowCommander::CARET_LINE_HOME);
  907. edit->m_caret.Move(TRUE, FALSE);
  908. edit->InsertBreak(TRUE, TRUE);
  909. edit->InsertText(UNI_L("A"), 1);
  910. verify(VerifyHtml(edit, UNI_L("<pre>t<br>Aest</pre>")));
  911. // Might want to change to the following behaviour
  912. // verify(VerifyHtml(edit, UNI_L("<pre>t</pre><pre>Aest</pre>")));
  913. #endif
  914. }
  915. test("InsertBreakP_KeepStyleButNoId") language C++;
  916. {
  917. OpDocumentEdit* edit = GetDocumentEdit();
  918. verify(edit);
  919. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  920. // == Break a P-tag with inline style and id =========
  921. // The style should be set on the new P tag, but not the id.
  922. // after
  923. edit->SetTextHTML(UNI_L("<p id=\"unique\" style=\"color: red\">test</p>"));
  924. edit->m_caret.Place(OpWindowCommander::CARET_LINE_END);
  925. edit->InsertBreak(TRUE, TRUE);
  926. edit->InsertText(UNI_L("A"), 1);
  927. verify(VerifyHtml(edit, UNI_L("<p id=\"unique\" style=\"color: red\">test</p><p style=\"color: red\">A</p>")));
  928. #endif
  929. }
  930. test("RemoveContentNewAutomaticBR") language C++;
  931. {
  932. OpDocumentEdit* edit = GetDocumentEdit();
  933. verify(edit);
  934. #ifdef DOCUMENT_EDIT_USE_PARAGRAPH_BREAK
  935. edit->SetTextHTML(UNI_L("<p>test</p>"));
  936. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  937. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  938. verify(VerifyHtml(edit, UNI_L("<P><BR></P>")));
  939. edit->SetTextHTML(UNI_L("<h1>test</h1>"));
  940. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  941. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  942. verify(VerifyHtml(edit, UNI_L("<H1><BR></H1>")));
  943. edit->SetTextHTML(UNI_L("<p>test</p>"));
  944. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  945. edit->InsertText(UNI_L("A"), 1);
  946. verify(VerifyHtml(edit, UNI_L("<P>A</P>")));
  947. edit->SetTextHTML(UNI_L("<STRONG><U>k</U></STRONG>"));
  948. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  949. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  950. verify(VerifyHtml(edit, UNI_L("<STRONG><U><BR></U></STRONG>")));
  951. edit->InsertText(UNI_L("A"), 1);
  952. verify(VerifyHtml(edit, UNI_L("<STRONG><U>A</U></STRONG>")));
  953. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  954. edit->InsertText(UNI_L("B"), 1);
  955. verify(VerifyHtml(edit, UNI_L("<STRONG><U>B</U></STRONG>")));
  956. #endif
  957. }
  958. //Avoid this test temporary until selections on Containers with no VerticalLayout works (and doesn't cause asserts)
  959. html
  960. {
  961. //! <script>
  962. //! var win;
  963. //! var idoc;
  964. //! function do_onload()
  965. //! {
  966. //! win = document.getElementById('edit').contentWindow;
  967. //! idoc = document.getElementById('edit').contentDocument;
  968. //! idoc.designMode = 'on';
  969. //! idoc.body.innerHTML = '<p></p><p>_delete_this_when_fixed_</p>';
  970. //!
  971. //! var r = idoc.createRange();
  972. //! r.setStart(idoc.getElementsByTagName('p')[1], 0 );
  973. //! r.setEnd(idoc.getElementsByTagName('p')[1], 0 );
  974. //! win.getSelection().removeAllRanges();
  975. //! win.getSelection().addRange(r);
  976. //!
  977. //! }
  978. //! </script>
  979. //! <body onload="do_onload()">
  980. //! <iframe id="edit" width="40" height="40"></iframe>
  981. //! </body>
  982. }
  983. test("CaretPositionEmptyElement") language ecmascript;
  984. {
  985. verify(document.getElementById('edit').contentDocument.designMode == 'on');
  986. idoc.execCommand('inserthtml', false, 'A');
  987. verify(idoc.body.innerHTML == "<p></p><p>A_delete_this_when_fixed_</p>");
  988. }
  989. test("CaretPositionAfterLink") language C++;
  990. {
  991. OpDocumentEdit* edit = GetDocumentEdit();
  992. verify(edit);
  993. // The caret should always insert text right after a link instead of inside it (if the caret is at the last position in the link)
  994. edit->SetTextHTML(UNI_L("<STRONG><A href=\"http://test\">test</A></STRONG>"));
  995. edit->m_caret.Place(OpWindowCommander::CARET_LINE_END);
  996. edit->InsertText(UNI_L("after"), 5);
  997. verify(VerifyHtml(edit, UNI_L("<STRONG><A href=\"http://test\">test</A></STRONG>after")));
  998. }
  999. test("AlignRightAndLeft") language C++;
  1000. {
  1001. OpDocumentEdit* edit = GetDocumentEdit();
  1002. verify(edit);
  1003. edit->SetTextHTML(UNI_L("item1<p>item2</p><p align='left'>item3</p>item4"));
  1004. // Let's make everything right-aligned and verify that
  1005. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_SELECTALL);
  1006. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_JUSTIFYRIGHT);
  1007. verify(edit->queryCommandState(OP_DOCUMENT_EDIT_COMMAND_JUSTIFYRIGHT) == TRUE);
  1008. verify(edit->queryCommandState(OP_DOCUMENT_EDIT_COMMAND_JUSTIFYLEFT) == FALSE); // check so that queryCommandState works...
  1009. // And make it left-aligned and verify...
  1010. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_JUSTIFYLEFT);
  1011. verify(edit->queryCommandState(OP_DOCUMENT_EDIT_COMMAND_JUSTIFYRIGHT) == FALSE);
  1012. verify(edit->queryCommandState(OP_DOCUMENT_EDIT_COMMAND_JUSTIFYLEFT) == TRUE);
  1013. // Check so that everything really was selected
  1014. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  1015. verify(VerifyHtml(edit, UNI_L("<DIV align=\"left\"><BR></DIV>")));
  1016. }
  1017. test("InsertHrAtTopAndPlaceCaretBefore") language C++;
  1018. {
  1019. OpDocumentEdit* edit = GetDocumentEdit();
  1020. verify(edit);
  1021. edit->SetTextHTML(UNI_L(""));
  1022. // Create two HR at the top of the document and step before each of them and type text
  1023. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTHORIZONTALRULE);
  1024. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTHORIZONTALRULE);
  1025. verify(VerifyHtml(edit, UNI_L("<HR><HR>")));
  1026. edit->m_caret.Move(FALSE,FALSE);
  1027. edit->InsertText(UNI_L("b"), 1);
  1028. edit->m_caret.Move(FALSE,FALSE);
  1029. edit->m_caret.Move(FALSE,FALSE);
  1030. edit->InsertText(UNI_L("a"), 1);
  1031. verify(VerifyHtml(edit, UNI_L("a<HR>b<HR>")));
  1032. }
  1033. test("IME_accepted") language C++;
  1034. require WIDGETS_IME_SUPPORT;
  1035. {
  1036. OpDocumentEdit* edit = GetDocumentEdit();
  1037. verify(edit);
  1038. edit->SetTextHTML(UNI_L(""));
  1039. OpInputMethodString imstring;
  1040. imstring.Set(UNI_L("test1"), 5);
  1041. edit->OnStartComposing(&imstring, IM_COMPOSE_NEW);
  1042. verify(VerifyHtml(edit, UNI_L("<BR>")));
  1043. edit->OnCompose();
  1044. verify(VerifyHtml(edit, UNI_L("test1")));
  1045. imstring.Set(UNI_L("test2"), 5);
  1046. edit->OnCompose();
  1047. verify(VerifyHtml(edit, UNI_L("test2")));
  1048. edit->OnStopComposing(FALSE);
  1049. verify(VerifyHtml(edit, UNI_L("test2")));
  1050. }
  1051. test("IME_canceled") language C++;
  1052. require WIDGETS_IME_SUPPORT;
  1053. {
  1054. OpDocumentEdit* edit = GetDocumentEdit();
  1055. verify(edit);
  1056. edit->SetTextHTML(UNI_L(""));
  1057. OpInputMethodString imstring;
  1058. imstring.Set(UNI_L("test1"), 5);
  1059. edit->OnStartComposing(&imstring, IM_COMPOSE_NEW);
  1060. edit->OnCompose();
  1061. verify(VerifyHtml(edit, UNI_L("test1")));
  1062. edit->OnStopComposing(TRUE);
  1063. verify(VerifyHtml(edit, UNI_L("")));
  1064. }
  1065. test("IME_pending_styles") language C++;
  1066. require WIDGETS_IME_SUPPORT;
  1067. {
  1068. OpDocumentEdit* edit = GetDocumentEdit();
  1069. verify(edit);
  1070. edit->SetTextHTML(UNI_L(""));
  1071. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BOLD);
  1072. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_ITALIC);
  1073. OpInputMethodString imstring;
  1074. imstring.Set(UNI_L("test"), 4);
  1075. edit->OnStartComposing(&imstring, IM_COMPOSE_NEW);
  1076. edit->OnCompose();
  1077. verify(VerifyHtml(edit, UNI_L("<EM><STRONG>test</STRONG></EM>")));
  1078. edit->OnCompose();
  1079. verify(VerifyHtml(edit, UNI_L("<EM><STRONG>test</STRONG></EM>")));
  1080. edit->OnStopComposing(FALSE);
  1081. verify(VerifyHtml(edit, UNI_L("<EM><STRONG>test</STRONG></EM>")));
  1082. }
  1083. test("DefaultBlock div") language C++;
  1084. {
  1085. OpDocumentEdit* edit = GetDocumentEdit();
  1086. verify(edit);
  1087. OpInputAction enter(OpInputAction::ACTION_LOWLEVEL_KEY_PRESSED, OP_KEY_ENTER);
  1088. OpInputAction b(OpInputAction::ACTION_LOWLEVEL_KEY_PRESSED, OP_KEY_B);
  1089. verify_success(b.SetActionKeyValue("b", 1));
  1090. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DEFAULT_BLOCK, FALSE, UNI_L("div"));
  1091. edit->SetTextHTML(UNI_L("a"));
  1092. edit->m_caret.Place(OpWindowCommander::CARET_DOCUMENT_END);
  1093. edit->EditAction(&enter);
  1094. verify(VerifyHtml(edit, UNI_L("<div>a</div><div><br></div>")));
  1095. edit->EditAction(&b);
  1096. verify(VerifyHtml(edit, UNI_L("<div>a</div><div>b</div>")));
  1097. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DEFAULT_BLOCK, FALSE, UNI_L("p"));
  1098. }
  1099. test("DefaultBlock insert paragraph") language C++;
  1100. {
  1101. OpDocumentEdit* edit = GetDocumentEdit();
  1102. verify(edit);
  1103. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DEFAULT_BLOCK, FALSE, UNI_L("div"));
  1104. edit->SetTextHTML(UNI_L("a"));
  1105. edit->m_caret.Place(OpWindowCommander::CARET_DOCUMENT_END);
  1106. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTPARAGRAPH);
  1107. verify(VerifyHtml(edit, UNI_L("<div>a</div><div><br></div>")));
  1108. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DEFAULT_BLOCK, FALSE, UNI_L("p"));
  1109. }
  1110. test("DefaultBlock div with lists") language C++;
  1111. {
  1112. OpDocumentEdit* edit = GetDocumentEdit();
  1113. verify(edit);
  1114. OpInputAction enter(OpInputAction::ACTION_LOWLEVEL_KEY_PRESSED, OP_KEY_ENTER);
  1115. OpInputAction b(OpInputAction::ACTION_LOWLEVEL_KEY_PRESSED, OP_KEY_B);
  1116. OpInputAction backspace(OpInputAction::ACTION_BACKSPACE);
  1117. verify_success(b.SetActionKeyValue("b", 1));
  1118. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DEFAULT_BLOCK, FALSE, UNI_L("div"));
  1119. edit->SetTextHTML(UNI_L("a"));
  1120. edit->m_caret.Place(OpWindowCommander::CARET_DOCUMENT_END);
  1121. edit->EditAction(&enter);
  1122. verify(VerifyHtml(edit, UNI_L("<div>a</div><div><br></div>")));
  1123. edit->EditAction(&backspace);
  1124. verify(VerifyHtml(edit, UNI_L("<div>a</div>")));
  1125. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTUNORDEREDLIST);
  1126. verify(VerifyHtml(edit, UNI_L("<ul><li>a</li></ul>")));
  1127. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTUNORDEREDLIST);
  1128. verify(VerifyHtml(edit, UNI_L("<div>a</div>")));
  1129. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTUNORDEREDLIST);
  1130. verify(VerifyHtml(edit, UNI_L("<ul><li>a</li></ul>")));
  1131. edit->EditAction(&enter);
  1132. verify(VerifyHtml(edit, UNI_L("<ul><li>a</li><li></li></ul>")));
  1133. edit->EditAction(&enter);
  1134. verify(VerifyHtml(edit, UNI_L("<ul><li>a</li></ul><div></div>")));
  1135. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DEFAULT_BLOCK, FALSE, UNI_L("p"));
  1136. }
  1137. html
  1138. {
  1139. //! <body onload="document.getElementsByTagName('div')[0].focus();"><ul><li><div contenteditable="true"></div></ul></body>
  1140. }
  1141. test("ContentEditable within list item")
  1142. {
  1143. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1144. verify(edit);
  1145. // Document edit adds the <br> inside the div automatically.
  1146. // Also, newline is for some reason necessary at the end.
  1147. VerifyHtml(edit, UNI_L("<ul><li><div contenteditable=\"true\"><br></div></li></ul>\n"));
  1148. edit->InsertBreak();
  1149. VerifyHtml(edit, UNI_L("<ul><li><div contenteditable=\"true\"><br><br></div></li></ul>\n"));
  1150. }
  1151. html
  1152. {
  1153. //! <body>
  1154. //! <div contenteditable="TRUE"></div>
  1155. //! </body>
  1156. }
  1157. test("ContentEditable_Simple") language C++;
  1158. {
  1159. if (state.doc)
  1160. verify(state.doc->GetDocumentEdit());
  1161. }
  1162. html
  1163. {
  1164. //! <body>
  1165. //! <div id="one" contenteditable="TRUE"></div>
  1166. //! <script>
  1167. //! document.getElementById('one').focus();
  1168. //! document.execCommand("insertHTML", false, "PASS");
  1169. //! </script>
  1170. //! </body>
  1171. }
  1172. test("ContentEditable_ScriptAfter") language ecmascript;
  1173. {
  1174. /* This is not completely compatible with other browsers
  1175. since they seem to require that we wait until the
  1176. entire page is loaded before enabling designmode.
  1177. not sure how important or good it is to implement this */
  1178. var one = document.getElementById("one");
  1179. verify(one.firstChild.data=='PASS');
  1180. }
  1181. html
  1182. {
  1183. //! <body>PASS<div id="one" contenteditable="TRUE">PASS<script>
  1184. //! document.execCommand("insertHTML", false, "FAIL");
  1185. //! </script>
  1186. //! </div>
  1187. //! </body>
  1188. }
  1189. test("ContentEditable_ScriptInside") language ecmascript;
  1190. {
  1191. /* If we enable designmode as an emergency resort to handle
  1192. the execCommand, the added code end up as a child of body
  1193. instead of as a child of the documenteditable.
  1194. Generally the execCommand should not run at all before
  1195. the contenteditable is enabled. Related to DSK-153397. */
  1196. var one = document.getElementById("one");
  1197. verify(one.firstChild.data=='PASS');
  1198. var body = document.getElementsByTagName("body")[0];
  1199. verify(body.firstChild.data == 'PASS');
  1200. }
  1201. html
  1202. {
  1203. //! <body>PASS<div>dummy</div>
  1204. //! </body>
  1205. }
  1206. test("ContentEditable_ExecCommandNoEditable") language ecmascript;
  1207. {
  1208. /* execCommand on a non-editable document should not
  1209. throw an exception. And not insert anything. See also DSK-153397. */
  1210. try
  1211. {
  1212. document.execCommand("insertHTML", false, "FAIL");
  1213. }
  1214. catch (err)
  1215. {
  1216. verify(0);
  1217. }
  1218. var body = document.getElementsByTagName("body")[0];
  1219. verify(body.firstChild.data == 'PASS');
  1220. }
  1221. html
  1222. {
  1223. //! <!DOCTYPE html><html><head><title>appending contenteditable element</title>
  1224. //! </head><body></body></html>
  1225. }
  1226. test("Inserting contenteditable should only create br if needed")
  1227. language ecmascript;
  1228. {
  1229. var node1 = document.createElement('div');
  1230. node1.contentEditable = 'true';
  1231. node1.innerHTML = 'text';
  1232. node1.style.display = 'none';
  1233. document.body.appendChild(node1);
  1234. node1.style.display = 'block';
  1235. verify(node1.innerHTML=='text');
  1236. }
  1237. html
  1238. {
  1239. //! <!DOCTYPE html>
  1240. //! <title>Missing trailing linebreak</title>
  1241. //! <body contenteditable>
  1242. //! <pre>X<br></pre></body>
  1243. }
  1244. test("Pasting text with linebreak")
  1245. {
  1246. HTML_Element* pre = find_element("pre");
  1247. verify(pre);
  1248. // Caret between text node and <br>
  1249. SelectionBoundaryPoint start(pre, 1);
  1250. SelectionBoundaryPoint end(pre, 1);
  1251. state.doc->GetHtmlDocument()->SetSelection(&start, &end);
  1252. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1253. verify(edit);
  1254. const uni_char* clipboard_text = UNI_L("foo\n");
  1255. verify_success(edit->InsertText(clipboard_text, 4)); // The function used by OpDocumentEdit::OnPaste().
  1256. verify_success(edit->InsertText(clipboard_text, 4)); // The function used by OpDocumentEdit::OnPaste().
  1257. HTML_Element* pre_child = pre->FirstChildActual();
  1258. verify(pre_child && pre_child->Type() == HE_TEXT); // "X"
  1259. pre_child = pre_child->SucActual();
  1260. verify(pre_child && pre_child->Type() == HE_TEXT); // "foo"
  1261. pre_child = pre_child->SucActual();
  1262. verify(pre_child && pre_child->IsMatchingType(HE_BR, NS_HTML)); // <br>
  1263. pre_child = pre_child->SucActual();
  1264. verify(pre_child && pre_child->Type() == HE_TEXT); // "foo"
  1265. pre_child = pre_child->SucActual();
  1266. verify(pre_child && pre_child->IsMatchingType(HE_BR, NS_HTML)); // <br>
  1267. pre_child = pre_child->SucActual();
  1268. verify(pre_child && pre_child->IsMatchingType(HE_BR, NS_HTML)); // <br>
  1269. pre_child = pre_child->SucActual();
  1270. verify(!pre_child);
  1271. }
  1272. html
  1273. {
  1274. "<body><p></p><div contentEditable=true><input></div></body>"
  1275. }
  1276. test("Replace clicked input with text") language C++;
  1277. {
  1278. // Was a crasher (CORE-24156).
  1279. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1280. verify(edit);
  1281. // simulate a mouse click on the input
  1282. state.doc->HandleMouseEvent(ONMOUSEDOWN, NULL, find_element("input"), NULL, 127, 8, 138, 19, 0, 98304);
  1283. edit->InsertText(UNI_L("a"), 1); // shouldn't crash here
  1284. verify(VerifyHtml(edit, UNI_L("<P></P><DIV contenteditable=\"true\">a</DIV>")));
  1285. }
  1286. html
  1287. {
  1288. "<body><p></p><div contentEditable=true><input></div></body>"
  1289. }
  1290. test("Remove last input element from contentEditable element") language C++;
  1291. {
  1292. // When the input is removed the div shouldn't dissapear, a <br> placeholder should be inserted instead.
  1293. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1294. verify(edit);
  1295. // simulate a mouse click on the input
  1296. state.doc->HandleMouseEvent(ONMOUSEDOWN, NULL, find_element("input"), NULL, 127, 8, 138, 19, 0, 98304);
  1297. OpInputAction backspace(OpInputAction::ACTION_BACKSPACE);
  1298. edit->OnInputAction(&backspace);
  1299. verify(VerifyHtml(edit, UNI_L("<P></P><DIV contenteditable=\"true\"><BR></DIV>")));
  1300. }
  1301. setup
  1302. {
  1303. }
  1304. exit
  1305. {
  1306. }
  1307. // CORE-25307
  1308. html
  1309. {
  1310. //! <!DOCTYPE html>
  1311. //! <html>
  1312. //! <head>
  1313. //! <title>appendChild, queryCommandState and selection</title>
  1314. //! <style type="text/css"> body { margin: 0; } </style>
  1315. //! <script type="text/javascript">
  1316. //! // Code here comes from TinyMCE 3.
  1317. //! // (stripped down)
  1318. //! function getSelectedNode() {
  1319. //! var s = window.getSelection(), r = null, e = null;
  1320. //! if (s && s.rangeCount > 0) {
  1321. //! r = s.getRangeAt(0);
  1322. //! } else {
  1323. //! r = s && s.createRange ? s.createRange() : document.createRange();
  1324. //! }
  1325. //!
  1326. //! var e = r.commonAncestorContainer;
  1327. //!
  1328. //! if (!r.collapsed) {
  1329. //! if (r.startContainer == r.endContainer) {
  1330. //! if (r.startOffset - r.endOffset < 2) {
  1331. //! if (r.startContainer.hasChildNodes()) {
  1332. //! e = r.startContainer.childNodes[r.startOffset];
  1333. //! }
  1334. //! }
  1335. //! }
  1336. //! }
  1337. //!
  1338. //! if (e.nodeType !== Node.ELEMENT_NODE) {
  1339. //! e = e.parentNode;
  1340. //! }
  1341. //!
  1342. //! return e;
  1343. //! }
  1344. //!
  1345. //! function handler(ev) {
  1346. //! var results = document.getElementById('results');
  1347. //! results.innerHTML = 'IN PROGRESS';
  1348. //! document.queryCommandState('bold');
  1349. //! var node = getSelectedNode();
  1350. //! results.innerHTML = (node instanceof HTMLImageElement ? 'PASS' : 'FAIL');
  1351. //! }
  1352. //! </script>
  1353. //! </head>
  1354. //! <body>
  1355. //! <p contentEditable="true"><img src="http://t/resources/images/100x100-navy.png" id="test" onclick="handler()"></p>
  1356. //!
  1357. //! <p id="results">NOT TESTED</p>
  1358. //! </body>
  1359. //! </html>
  1360. }
  1361. test("selection after queryCommandState - setup1")
  1362. {
  1363. HTML_Element* img = find_element("img");
  1364. verify(img);
  1365. // simulate a mouse click on the image
  1366. state.doc->HandleMouseEvent(ONMOUSEDOWN, NULL, img, NULL, 35, 33, 35, 49, 0, 98304);
  1367. state.doc->HandleMouseEvent(ONMOUSEUP, NULL, img, NULL, 35, 33, 35, 49, 0, 98304);
  1368. }
  1369. test("selection after queryCommandState - setup2")
  1370. language ecmascript;
  1371. require success "selection after queryCommandState - setup1";
  1372. {
  1373. // nothing - just to make sure onclick script has run
  1374. }
  1375. test("selection after queryCommandState")
  1376. require success "selection after queryCommandState - setup2";
  1377. {
  1378. // find output element
  1379. HTML_Element* p = find_element("p", 2);
  1380. verify(p && p->Type() == HE_P);
  1381. // check contents - should be "PASS"
  1382. const int len = 4;
  1383. uni_char buf[len+1]; /* ARRAY OK 2010-06-07 markuso */
  1384. verify(p->GetTextContent(buf, len+1) == len);
  1385. verify(!uni_strcmp(buf, "PASS"));
  1386. }
  1387. html
  1388. {
  1389. //!<html>
  1390. //!<head>
  1391. //!<style>
  1392. //!body { height: 50px; }
  1393. //!</style>
  1394. //!</head>
  1395. //!<body contenteditable=true>
  1396. //!<div>a</div>
  1397. //!</body>
  1398. //!</html>
  1399. }
  1400. test("Caret place end")
  1401. {
  1402. verify(state.doc);
  1403. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1404. verify(edit);
  1405. edit->m_caret.Place(OpWindowCommander::CARET_DOCUMENT_HOME);
  1406. edit->m_caret.Place(OpWindowCommander::CARET_DOCUMENT_END);
  1407. edit->InsertText(UNI_L("b"), 1);
  1408. HTML_Element* div = find_element("div");
  1409. verify(div && div->Type() == HE_DIV);
  1410. verify(div->FirstChild() == edit->m_caret.GetElement());
  1411. verify(div->GetTextContentLength() == 2);
  1412. uni_char buf[3]; /* ARRAY OK 2010-06-07 markuso */
  1413. verify(div->GetTextContent(buf, 3));
  1414. verify(uni_strcmp(buf, UNI_L("ab")) == 0);
  1415. }
  1416. html
  1417. {
  1418. //!<html>
  1419. //!<head>
  1420. //!</head>
  1421. //!<body contenteditable=true>
  1422. //!</body>
  1423. //!</html>
  1424. }
  1425. test("Catching HTML_Element's Next() - NextActual() usage mismatch in UNDO/REDO stack #1") language C++;
  1426. {
  1427. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1428. verify(edit);
  1429. edit->SetTextHTML(UNI_L("<DIV STYLE=\"DISPLAY:TABLE-CELL\">DIV DISPLAYED AS TABLE CELL</DIV><P>Some text inside P element</P><DIV STYLE=\"DISPLAY:TABLE-CELL\">DIV DISPLAYED AS TABLE CELL</DIV>"));
  1430. HTML_Element *p = edit->GetBody()->FirstChild()->SucActual();
  1431. verify(p->Type() == HE_P);
  1432. HTML_Element* elm = edit->FindEditableElement(p, TRUE, TRUE, FALSE);
  1433. verify(elm);
  1434. edit->m_caret.Place(elm, 0);
  1435. edit->m_selection.SelectToCaret(edit->m_caret.GetElement(), 5);
  1436. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_DELETE);
  1437. verify(VerifyHtml(edit, UNI_L("<DIV STYLE=\"DISPLAY:TABLE-CELL\">DIV DISPLAYED AS TABLE CELL</DIV><P>text inside P element</P><DIV STYLE=\"DISPLAY:TABLE-CELL\">DIV DISPLAYED AS TABLE CELL</DIV>")));
  1438. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  1439. verify(VerifyHtml(edit, UNI_L("<DIV STYLE=\"DISPLAY:TABLE-CELL\">DIV DISPLAYED AS TABLE CELL</DIV><P>Some text inside P element</P><DIV STYLE=\"DISPLAY:TABLE-CELL\">DIV DISPLAYED AS TABLE CELL</DIV>")));
  1440. }
  1441. test("Catching HTML_Element's Next() - NextActual() usage mismatch in UNDO/REDO stack #2") language C++;
  1442. {
  1443. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1444. verify(edit);
  1445. edit->SetTextHTML(UNI_L("<div>A<div style=\"display:table-cell\"><div>B</div><div>C</div></div></div><div>D</div>"));
  1446. HTML_Element *div = edit->GetBody()->FirstChildActual();
  1447. verify(div->Type() == HE_DIV);
  1448. HTML_Element* elm = edit->FindEditableElement(div, TRUE, TRUE, FALSE);
  1449. verify(elm);
  1450. edit->m_caret.Place(elm, 0);
  1451. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_BACKCOLOR, FALSE, UNI_L("red"));
  1452. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  1453. verify(VerifyHtml(edit, UNI_L("<div>A<div style=\"display:table-cell\"><div>B</div><div>C</div></div></div><div>D</div>")));
  1454. }
  1455. html
  1456. {
  1457. //!<doctype html>
  1458. //!<html>
  1459. //!<head>
  1460. //!<style>
  1461. //!* { margin:0; padding:0; line-height:20px; }
  1462. //!</style>
  1463. //!</head>
  1464. //!<body contenteditable=true><b>abc<b><br><br></body>
  1465. //!</html>
  1466. }
  1467. test("Place caret after text row ending with br") language C++;
  1468. {
  1469. /* Verify that the caret is placed at the last content of the line when the mouse
  1470. is clicked to the right of that line. CORE-30815. */
  1471. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1472. verify(edit);
  1473. /* Simulate a mouse click to the right of the "abc<br>" line. */
  1474. state.doc->HandleMouseEvent(ONMOUSEDOWN, NULL, find_element("body"), NULL, 200, 10, 200, 10, 0, 98304);
  1475. state.doc->HandleMouseEvent(ONMOUSEUP, NULL, find_element("body"), NULL, 200, 10, 200, 10, 0, 98304);
  1476. HTML_Element* caret_elm = edit->m_caret.GetElement();
  1477. verify(caret_elm);
  1478. verify(caret_elm->IsText());
  1479. const uni_char* text = caret_elm->TextContent();
  1480. verify(uni_strncmp(text, UNI_L("abc"), 3) == 0);
  1481. }
  1482. html
  1483. {
  1484. //!<doctype html>
  1485. //!<html>
  1486. //!<head>
  1487. //!<style>
  1488. //!* { margin:0; padding:0; line-height:20px; }
  1489. //!</style>
  1490. //!</head>
  1491. //!<body contenteditable=true><b>abc<img src="data:image/png;base64,
  1492. //!iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP
  1493. //!C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA
  1494. //!AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J
  1495. //!REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq
  1496. //!ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0
  1497. //!vr4MkhoXe0rZigAAAABJRU5ErkJggg==">
  1498. //!<img src="data:image/png;base64,
  1499. //!iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP
  1500. //!C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA
  1501. //!AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J
  1502. //!REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq
  1503. //!ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0
  1504. //!vr4MkhoXe0rZigAAAABJRU5ErkJggg=="></b><br><br></body>
  1505. //!</html>
  1506. }
  1507. test("Place caret after image row ending with br") language C++;
  1508. {
  1509. /* Verify that the caret is placed at the last content of the line when the mouse
  1510. is clicked to the right of that line. CORE-30815. */
  1511. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1512. verify(edit);
  1513. /* Simulate a mouse click to the right of the line with content */
  1514. state.doc->HandleMouseEvent(ONMOUSEDOWN, NULL, find_element("body"), NULL, 200, 10, 200, 10, 0, 98304);
  1515. state.doc->HandleMouseEvent(ONMOUSEUP, NULL, find_element("body"), NULL, 200, 10, 200, 10, 0, 98304);
  1516. HTML_Element* caret_elm = edit->m_caret.GetElement();
  1517. verify(caret_elm);
  1518. verify(caret_elm->IsMatchingType(HE_IMG, NS_HTML));
  1519. verify(caret_elm->Pred());
  1520. verify(caret_elm->Pred()->IsText());
  1521. }
  1522. html
  1523. {
  1524. //! <html>
  1525. //! <head contenteditable="true">abc</head>
  1526. //! <body>
  1527. //! </body>
  1528. //! </html>
  1529. }
  1530. test("HEAD should not be editable")
  1531. {
  1532. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1533. verify(!edit || !edit->m_caret.GetElement());
  1534. state.doc->HandleMouseEvent(ONMOUSEDOWN, NULL, find_element("html"), NULL, 100, 100, 100, 100, 0, 98304);
  1535. state.doc->HandleMouseEvent(ONMOUSEUP, NULL, find_element("html"), NULL, 100, 100, 100, 100, 0, 98304);
  1536. edit = state.doc->GetDocumentEdit();
  1537. verify(!edit || !edit->m_caret.GetElement());
  1538. }
  1539. html
  1540. {
  1541. //! <html>
  1542. //! <body>
  1543. //! </body>
  1544. //! </html>
  1545. }
  1546. test("HELPER: set contentEditable on HTML and recreate body")
  1547. language ecmascript;
  1548. {
  1549. /* This is not an actual test, just part of a setup that
  1550. is easiest to be written in EcmaScript */
  1551. var html = document.documentElement
  1552. html.removeChild(document.querySelector('body'))
  1553. html.contentEditable = true
  1554. html.appendChild(document.createElement('body'))
  1555. }
  1556. test("Content editable on HTML element focuses <body>")
  1557. require success "HELPER: set contentEditable on HTML and recreate body";
  1558. {
  1559. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1560. verify(edit);
  1561. verify(!(edit->m_caret.GetElement()));
  1562. state.doc->HandleMouseEvent(ONMOUSEDOWN, NULL, find_element("html"), NULL, 100, 100, 100, 100, 0, 98304);
  1563. state.doc->HandleMouseEvent(ONMOUSEUP, NULL, find_element("html"), NULL, 100, 100, 100, 100, 0, 98304);
  1564. edit = state.doc->GetDocumentEdit();
  1565. verify(edit);
  1566. verify(edit->m_caret.GetElement());
  1567. HTML_Element* caret_element_parent = edit->m_caret.GetElement()->ParentActual();
  1568. verify(caret_element_parent);
  1569. verify(caret_element_parent->IsMatchingType(HE_BODY, NS_HTML));
  1570. }
  1571. html
  1572. {
  1573. //! <html>
  1574. //! <style>div { display: table-cell; }</style>
  1575. //! <body contentEditable="true"><div></div><p>PASS</p></body>
  1576. //! </html>
  1577. }
  1578. test("Generated content vs lists")
  1579. {
  1580. // We need to try and insert a list after some content inserted by layout
  1581. // The div with display: table-cell ensures layout will insert some table
  1582. // elements
  1583. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1584. verify(edit);
  1585. verify(VerifyHtml(edit, UNI_L("<div></div><p>PASS</p>\n\n")));
  1586. edit->m_caret.Place(edit->FindElementAfterOfType(edit->GetBody(), HE_P, FALSE), 4);
  1587. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTUNORDEREDLIST);
  1588. verify(VerifyHtml(edit, UNI_L("<div></div><ul><li>PASS</li></ul>\n\n")));
  1589. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_INSERTUNORDEREDLIST);
  1590. // document edit likes to add paragraphs but the important thing is
  1591. // that the list is created and removed and there is no crash.
  1592. verify(VerifyHtml(edit, UNI_L("<div></div><p>PASS</p>\n\n")));
  1593. }
  1594. html
  1595. {
  1596. //! <!DOCTYPE html>
  1597. //! <title>focus not updated when inserting newline</title>
  1598. //! <body contenteditable>
  1599. //! <pre>Click after the end of this line and press enter.<br/>A new line should be inserted with caret in that line.
  1600. //! (If the caret remains at the end of the first line it is a fail). </pre>
  1601. //! </body>
  1602. }
  1603. test("Pressing enter at the end of a line with br")
  1604. {
  1605. HTML_Element* pre = find_element("pre");
  1606. verify(pre);
  1607. // Caret between text node and <br>.
  1608. SelectionBoundaryPoint start(pre, 1);
  1609. SelectionBoundaryPoint end(pre, 1);
  1610. state.doc->GetHtmlDocument()->SetSelection(&start, &end);
  1611. verify(state.doc->GetCaretPainter());
  1612. int before_y = state.doc->GetCaretPainter()->GetY();
  1613. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1614. verify(edit);
  1615. edit->InsertBreak(TRUE, TRUE);
  1616. int after_y = state.doc->GetCaretPainter()->GetY();
  1617. verify(after_y > before_y || !"The caret didn't move to the next line");
  1618. }
  1619. html
  1620. {
  1621. "<html>"
  1622. "<body contentEditable=\"true\"><p id=\"foo\">FAIL: JavaScript not run</p></body>"
  1623. "</html>"
  1624. }
  1625. test("Caret moving through non-BMP characters: setup")
  1626. language ecmascript;
  1627. {
  1628. // Until html{} learns how to insert non-ASCII characters...
  1629. var p = document.getElementById("foo");
  1630. p.innerHTML = "Z\uD800\uDC00Z";
  1631. }
  1632. test("Caret moving through non-BMP characters")
  1633. require success "Caret moving through non-BMP characters: setup";
  1634. {
  1635. // We must not have the caret placed inside a surrogate pair
  1636. // (CORE-20881).
  1637. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1638. verify(edit);
  1639. verify(VerifyHtml(edit, UNI_L("<p id=\"foo\">Z\xD800\xDC00Z</p>")));
  1640. edit->m_caret.Place(edit->FindElementAfterOfType(edit->GetBody(), HE_P, FALSE), 0);
  1641. verify(edit->m_caret.GetOffset() == 0);
  1642. edit->m_caret.Move(TRUE, FALSE);
  1643. verify(edit->m_caret.GetOffset() == 1);
  1644. // Next move should skip past the entire non-BMP character
  1645. edit->m_caret.Move(TRUE, FALSE);
  1646. verify(edit->m_caret.GetOffset() == 3);
  1647. // Moving back should put us before the non-BMP character again
  1648. edit->m_caret.Move(FALSE, FALSE);
  1649. verify(edit->m_caret.GetOffset() == 1);
  1650. }
  1651. table converthextounicode
  1652. {
  1653. { "BMP", "20AC", UNI_L("<p>20AC</p>"), UNI_L("<p>\x20AC</p>") },
  1654. { "non-BMP", "1D616", UNI_L("<p>1D616</p>"), UNI_L("<p>\xD835\xDE16</p>") },
  1655. { "partial", "XXX58", UNI_L("<p>XXX58</p>"), UNI_L("<p>XXXX</p>") },
  1656. { "overlong", "200032", UNI_L("<p>200032</p>"), UNI_L("<p>202</p>") },
  1657. }
  1658. foreach (name, content, original, converted) from converthextounicode
  1659. {
  1660. html
  1661. {
  1662. "<html>"
  1663. "<body contentEditable=\"true\"><p>"
  1664. content
  1665. "</p></body>"
  1666. "</html>"
  1667. }
  1668. test("Convert hex to Unicode: " name)
  1669. {
  1670. OpDocumentEdit* edit = state.doc->GetDocumentEdit();
  1671. verify(edit);
  1672. verify(VerifyHtml(edit, original));
  1673. OpInputAction convert(OpInputAction::ACTION_CONVERT_HEX_TO_UNICODE);
  1674. edit->m_caret.Place(edit->FindElementAfterOfType(edit->GetBody(), HE_P, FALSE), op_strlen(content));
  1675. edit->EditAction(&convert);
  1676. verify(VerifyHtml(edit, converted));
  1677. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_UNDO);
  1678. verify(VerifyHtml(edit, original));
  1679. edit->execCommand(OP_DOCUMENT_EDIT_COMMAND_REDO);
  1680. verify(VerifyHtml(edit, converted));
  1681. }
  1682. }
  1683. html
  1684. {
  1685. //! <script>
  1686. //! var win;
  1687. //! var idoc;
  1688. //! function do_onload()
  1689. //! {
  1690. //! win = document.getElementById('edit').contentWindow;
  1691. //! idoc = document.getElementById('edit').contentDocument;
  1692. //! idoc.designMode = 'on';
  1693. //! idoc.body.innerHTML = '<div></div>';
  1694. //!
  1695. //! var r = idoc.createRange();
  1696. //! r.setStart(idoc.getElementsByTagName('div')[0], 0 );
  1697. //! r.setEnd(idoc.getElementsByTagName('div')[0], 0 );
  1698. //! win.getSelection().removeAllRanges();
  1699. //! win.getSelection().addRange(r);
  1700. //!
  1701. //! }
  1702. //! </script>
  1703. //! <body onload="do_onload()">
  1704. //! <iframe id="edit" width="40" height="40"></iframe>
  1705. //! </body>
  1706. }
  1707. test("Caret position set from DOM on non text element in text container") language ecmascript;
  1708. {
  1709. verify(document.getElementById('edit').contentDocument.designMode == 'on');
  1710. idoc.execCommand('inserthtml', false, 'ABC');
  1711. verify(idoc.body.innerHTML == "<div>ABC<br></div>");
  1712. }
  1713. html
  1714. {
  1715. //! <script>
  1716. //! var win;
  1717. //! var idoc;
  1718. //! function do_onload()
  1719. //! {
  1720. //! win = document.getElementById('edit').contentWindow;
  1721. //! idoc = document.getElementById('edit').contentDocument;
  1722. //! idoc.designMode = 'on';
  1723. //! idoc.body.innerHTML = '<p>ABC</p>';
  1724. //!
  1725. //! var r = idoc.createRange();
  1726. //! r.setStart(idoc.getElementsByTagName('p')[0].firstChild, 3 );
  1727. //! r.setEnd(idoc.getElementsByTagName('p')[0].firstChild, 3 );
  1728. //! win.getSelection().removeAllRanges();
  1729. //! win.getSelection().addRange(r);
  1730. //!
  1731. //! }
  1732. //! </script>
  1733. //! <body onload="do_onload()">
  1734. //! <iframe id="edit" width="40" height="40"></iframe>
  1735. //! </body>
  1736. }
  1737. test("Caret position set from DOM on text element") language ecmascript;
  1738. {
  1739. verify(document.getElementById('edit').contentDocument.designMode == 'on');
  1740. idoc.execCommand('inserthtml', false, 'DEF');
  1741. verify(idoc.body.innerHTML == "<p>ABCDEF</p>");
  1742. }
  1743. html
  1744. {
  1745. //! <script>
  1746. //! var win;
  1747. //! var idoc;
  1748. //! function do_onload()
  1749. //! {
  1750. //! win = document.getElementById('edit').contentWindow;
  1751. //! idoc = document.getElementById('edit').contentDocument;
  1752. //! idoc.designMode = 'on';
  1753. //! idoc.body.innerHTML = '<table><tbody><tr></tr></tbody></table>';
  1754. //!
  1755. //! var r = idoc.createRange();
  1756. //! r.setStart(idoc.getElementsByTagName('tr')[0], 0 );
  1757. //! r.setEnd(idoc.getElementsByTagName('tr')[0], 0 );
  1758. //! win.getSelection().removeAllRanges();
  1759. //! win.getSelection().addRange(r);
  1760. //!
  1761. //! }
  1762. //! </script>
  1763. //! <body onload="do_onload()">
  1764. //! <iframe id="edit" width="40" height="40"></iframe>
  1765. //! </body>
  1766. }
  1767. test("Caret position set from DOM on non text element in no text container") language ecmascript;
  1768. {
  1769. verify(document.getElementById('edit').contentDocument.designMode == 'on');
  1770. idoc.execCommand('inserthtml', false, 'ABC');
  1771. verify(idoc.body.innerHTML == "<table><tbody><tr>ABC<br></tr></tbody></table>");
  1772. }