attribute.js 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596
  1. import { Client, syncClients, expectClients, clearBuffer } from './utils.js';
  2. describe( 'transform', () => {
  3. let john, kate;
  4. beforeEach( () => {
  5. return Promise.all( [
  6. Client.get( 'john' ).then( client => ( john = client ) ),
  7. Client.get( 'kate' ).then( client => ( kate = client ) )
  8. ] );
  9. } );
  10. afterEach( () => {
  11. clearBuffer();
  12. return Promise.all( [ john.destroy(), kate.destroy() ] );
  13. } );
  14. describe( 'attribute', () => {
  15. describe( 'by attribute', () => {
  16. it( 'in text at same path', () => {
  17. john.setData( '<paragraph>[Foo] Bar</paragraph>' );
  18. kate.setData( '<paragraph>Foo [Bar]</paragraph>' );
  19. john.setAttribute( 'bold', true );
  20. kate.setAttribute( 'italic', true );
  21. syncClients();
  22. expectClients( '<paragraph><$text bold="true">Foo</$text> <$text italic="true">Bar</$text></paragraph>' );
  23. } );
  24. it( 'in text at same path, then undo', () => {
  25. john.setData( '<paragraph>[Foo] Bar</paragraph>' );
  26. kate.setData( '<paragraph>Foo [Bar]</paragraph>' );
  27. john.setAttribute( 'bold', true );
  28. kate.setAttribute( 'italic', true );
  29. syncClients();
  30. expectClients( '<paragraph><$text bold="true">Foo</$text> <$text italic="true">Bar</$text></paragraph>' );
  31. john.undo();
  32. syncClients();
  33. expectClients( '<paragraph>Foo <$text italic="true">Bar</$text></paragraph>' );
  34. } );
  35. it( 'in text in different path', () => {
  36. john.setData( '<paragraph>F[o]o</paragraph><paragraph>Bar</paragraph>' );
  37. kate.setData( '<paragraph>Foo</paragraph><paragraph>B[a]r</paragraph>' );
  38. john.setAttribute( 'bold', true );
  39. kate.setAttribute( 'italic', true );
  40. syncClients();
  41. expectClients(
  42. '<paragraph>F<$text bold="true">o</$text>o</paragraph>' +
  43. '<paragraph>B<$text italic="true">a</$text>r</paragraph>'
  44. );
  45. } );
  46. it( 'in text with selection inside other client\'s selection #1', () => {
  47. john.setData( '<paragraph>[Foo Bar]</paragraph>' );
  48. kate.setData( '<paragraph>Fo[o B]ar</paragraph>' );
  49. john.setAttribute( 'bold', true );
  50. kate.setAttribute( 'italic', true );
  51. syncClients();
  52. expectClients(
  53. '<paragraph>' +
  54. '<$text bold="true">Fo</$text><$text bold="true" italic="true">o B</$text><$text bold="true">ar</$text>' +
  55. '</paragraph>'
  56. );
  57. } );
  58. it( 'in text with selection inside other client\'s selection #2', () => {
  59. john.setData( '<paragraph>F[oo Ba]r</paragraph>' );
  60. kate.setData( '<paragraph>Foo [Bar]</paragraph>' );
  61. john.setAttribute( 'bold', true );
  62. kate.setAttribute( 'italic', true );
  63. syncClients();
  64. expectClients(
  65. '<paragraph>' +
  66. 'F' +
  67. '<$text bold="true">oo </$text>' +
  68. '<$text bold="true" italic="true">Ba</$text>' +
  69. '<$text italic="true">r</$text>' +
  70. '</paragraph>'
  71. );
  72. } );
  73. it( 'in text with selection inside other client\'s selection #3', () => {
  74. john.setData( '<paragraph><$text bold="true">[Foo Bar]</$text></paragraph>' );
  75. kate.setData( '<paragraph><$text bold="true">Fo[o] Bar</$text></paragraph>' );
  76. john.setAttribute( 'italic', true );
  77. kate.setAttribute( 'underline', true );
  78. syncClients();
  79. expectClients(
  80. '<paragraph>' +
  81. '<$text bold="true" italic="true">Fo</$text>' +
  82. '<$text bold="true" italic="true" underline="true">o</$text>' +
  83. '<$text bold="true" italic="true"> Bar</$text>' +
  84. '</paragraph>'
  85. );
  86. } );
  87. it( 'in text at same position', () => {
  88. john.setData( '<paragraph>[Foo Bar]</paragraph>' );
  89. kate.setData( '<paragraph>[Foo Bar]</paragraph>' );
  90. john.setAttribute( 'bold', true );
  91. kate.setAttribute( 'italic', true );
  92. syncClients();
  93. expectClients( '<paragraph><$text bold="true" italic="true">Foo Bar</$text></paragraph>' );
  94. } );
  95. it( 'in element at same position', () => {
  96. john.setData( '[<paragraph>Foo Bar</paragraph>]' );
  97. kate.setData( '[<paragraph>Foo Bar</paragraph>]' );
  98. john.setAttribute( 'bold', true );
  99. kate.setAttribute( 'italic', true );
  100. syncClients();
  101. expectClients( '<paragraph bold="true" italic="true">Foo Bar</paragraph>' );
  102. } );
  103. it( 'in collapsed selection', () => {
  104. john.setData( '<paragraph>F[]oo Bar</paragraph>' );
  105. kate.setData( '<paragraph>F[]oo Bar</paragraph>' );
  106. john.setAttribute( 'bold', true );
  107. kate.setAttribute( 'italic', true );
  108. syncClients();
  109. expectClients( '<paragraph>Foo Bar</paragraph>' );
  110. } );
  111. it( 'in same range, then change attribute', () => {
  112. john.setData( '<paragraph>[Foo Bar]</paragraph>' );
  113. kate.setData( '<paragraph>[Foo Bar]</paragraph>' );
  114. john.setAttribute( 'attr', 'foo' );
  115. kate.setAttribute( 'attr', 'bar' );
  116. syncClients();
  117. expectClients( '<paragraph><$text attr="foo">Foo Bar</$text></paragraph>' );
  118. kate.setAttribute( 'attr', 'bar' );
  119. syncClients();
  120. expectClients( '<paragraph><$text attr="bar">Foo Bar</$text></paragraph>' );
  121. } );
  122. } );
  123. describe( 'by insert', () => {
  124. it( 'text in different path', () => {
  125. john.setData( '<paragraph>[Foo]</paragraph><paragraph>Bar</paragraph>' );
  126. kate.setData( '<paragraph>Foo</paragraph><paragraph>[]Bar</paragraph>' );
  127. john.setAttribute( 'bold', true );
  128. kate.type( 'Abc' );
  129. syncClients();
  130. expectClients( '<paragraph><$text bold="true">Foo</$text></paragraph><paragraph>AbcBar</paragraph>' );
  131. } );
  132. it( 'text in different path #2', () => {
  133. john.setData( '[<paragraph>Foo</paragraph>]<paragraph>Bar</paragraph>' );
  134. kate.setData( '<paragraph>Foo</paragraph><paragraph>[]Bar</paragraph>' );
  135. john.setAttribute( 'bold', true );
  136. kate.type( 'Abc' );
  137. syncClients();
  138. expectClients( '<paragraph bold="true">Foo</paragraph><paragraph>AbcBar</paragraph>' );
  139. } );
  140. it( 'text at same path', () => {
  141. john.setData( '<paragraph>[F]oo</paragraph>' );
  142. kate.setData( '<paragraph>Foo[]</paragraph>' );
  143. john.setAttribute( 'bold', true );
  144. kate.type( 'Abc' );
  145. syncClients();
  146. expectClients( '<paragraph><$text bold="true">F</$text>ooAbc</paragraph>' );
  147. } );
  148. it( 'text inside other client\'s selection', () => {
  149. john.setData( '<paragraph>[Foo]</paragraph>' );
  150. kate.setData( '<paragraph>Fo[]o</paragraph>' );
  151. john.setAttribute( 'bold', true );
  152. kate.type( 'Abc' );
  153. syncClients();
  154. expectClients( '<paragraph><$text bold="true">FoAbco</$text></paragraph>' );
  155. } );
  156. it( 'element between changed elements', () => {
  157. john.setData( '[<paragraph>Foo</paragraph><paragraph>Bar</paragraph>]' );
  158. kate.setData( '<paragraph>Foo</paragraph>[]<paragraph>Bar</paragraph>' );
  159. john.setAttribute( 'bold', true );
  160. kate.insert( '<paragraph>Abc</paragraph>' );
  161. syncClients();
  162. expectClients(
  163. '<paragraph bold="true">Foo</paragraph>' +
  164. '<paragraph>Abc</paragraph>' +
  165. '<paragraph bold="true">Bar</paragraph>'
  166. );
  167. } );
  168. it( 'text between changed nodes', () => {
  169. john.setData( '<paragraph>[Foo</paragraph><paragraph>Bar]</paragraph>' );
  170. kate.setData( '<paragraph>Foo</paragraph><paragraph>B[]ar</paragraph>' );
  171. john.setAttribute( 'bold', true );
  172. kate.type( 'Abc' );
  173. syncClients();
  174. expectClients(
  175. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  176. '<paragraph><$text bold="true">BAbcar</$text></paragraph>'
  177. );
  178. } );
  179. it( 'element in different path', () => {
  180. john.setData( '<paragraph>[Foo]</paragraph><paragraph>Bar</paragraph>' );
  181. kate.setData( '<paragraph>Foo</paragraph><paragraph>Bar</paragraph>[]' );
  182. john.setAttribute( 'bold', true );
  183. kate.insert( '<paragraph>Abc</paragraph>' );
  184. syncClients();
  185. expectClients(
  186. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  187. '<paragraph>Bar</paragraph>' +
  188. '<paragraph>Abc</paragraph>'
  189. );
  190. } );
  191. it( 'element in different path #2', () => {
  192. john.setData( '[<paragraph>Foo</paragraph>]<paragraph>Bar</paragraph>' );
  193. kate.setData( '<paragraph>Foo</paragraph><paragraph>Bar</paragraph>[]' );
  194. john.setAttribute( 'bold', true );
  195. kate.insert( '<paragraph>Abc</paragraph>' );
  196. syncClients();
  197. expectClients(
  198. '<paragraph bold="true">Foo</paragraph>' +
  199. '<paragraph>Bar</paragraph>' +
  200. '<paragraph>Abc</paragraph>'
  201. );
  202. } );
  203. it( 'remove attribute from element in different path', () => {
  204. john.setData( '<paragraph>[]Foo</paragraph><paragraph bold="true">Bar</paragraph>' );
  205. kate.setData( '<paragraph>Foo</paragraph>[<paragraph bold="true">Bar</paragraph>]' );
  206. john.type( 'Abc' );
  207. kate.removeAttribute( 'bold' );
  208. syncClients();
  209. expectClients( '<paragraph>AbcFoo</paragraph><paragraph>Bar</paragraph>' );
  210. } );
  211. it( 'remove attribute from text in different path', () => {
  212. john.setData( '<paragraph>[]Foo</paragraph><paragraph><$text bold="true">Bar</$text></paragraph>' );
  213. kate.setData( '<paragraph>Foo</paragraph><paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  214. john.type( 'Abc' );
  215. kate.removeAttribute( 'bold' );
  216. syncClients();
  217. expectClients( '<paragraph>AbcFoo</paragraph><paragraph>Bar</paragraph>' );
  218. } );
  219. it( 'remove attribute from text while typing in client\'s range', () => {
  220. john.setData( '<paragraph>F<$text bold="true">o[]o</$text></paragraph>' );
  221. kate.setData( '<paragraph>F<$text bold="true">[oo]</$text></paragraph>' );
  222. john.type( 'Bar' );
  223. kate.removeAttribute( 'bold' );
  224. syncClients();
  225. expectClients( '<paragraph>FoBaro</paragraph>' );
  226. } );
  227. it( 'remove attribute from element in same path', () => {
  228. john.setData( '<paragraph bold="true">[]Foo</paragraph>' );
  229. kate.setData( '[<paragraph bold="true">Foo</paragraph>]' );
  230. john.type( 'Bar' );
  231. kate.removeAttribute( 'bold' );
  232. syncClients();
  233. expectClients( '<paragraph>BarFoo</paragraph>' );
  234. } );
  235. it( 'remove attribute from text with 2 attributes while typing in client\'s range', () => {
  236. john.setData( '<paragraph>F<$text bold="true" italic="true">o[]o</$text></paragraph>' );
  237. kate.setData( '<paragraph>F<$text bold="true" italic="true">[oo]</$text></paragraph>' );
  238. john.type( 'Bar', john.document.selection.getAttributes() );
  239. kate.removeAttribute( 'bold' );
  240. syncClients();
  241. expectClients( '<paragraph>F<$text italic="true">oBaro</$text></paragraph>' );
  242. } );
  243. it( 'multiple typing', () => {
  244. john.setData( '<paragraph>[Foo]</paragraph>' );
  245. kate.setData( '<paragraph>Fo[]o</paragraph>' );
  246. john.setAttribute( 'bold', true );
  247. kate.setSelection( [ 0, 2 ] );
  248. kate.type( 'x' );
  249. kate.setSelection( [ 0, 3 ] );
  250. kate.type( 'x' );
  251. kate.setSelection( [ 0, 4 ] );
  252. kate.type( 'x' );
  253. syncClients();
  254. expectClients( '<paragraph><$text bold="true">Foxxxo</$text></paragraph>' );
  255. } );
  256. it( 'type inside element which attribute changes', () => {
  257. john.setData( '[<paragraph></paragraph>]' );
  258. kate.setData( '<paragraph>[]</paragraph>' );
  259. john.setAttribute( 'bold', true );
  260. kate.type( 'x' );
  261. syncClients();
  262. expectClients( '<paragraph bold="true">x</paragraph>' );
  263. } );
  264. } );
  265. describe( 'by move', () => {
  266. it( 'text in different path', () => {
  267. john.setData( '<paragraph>[Foo]</paragraph><paragraph>Bar</paragraph>' );
  268. kate.setData( '<paragraph>Foo</paragraph><paragraph>B[ar]</paragraph>' );
  269. john.setAttribute( 'bold', true );
  270. kate.move( [ 1, 0 ] );
  271. syncClients();
  272. expectClients(
  273. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  274. '<paragraph>arB</paragraph>'
  275. );
  276. } );
  277. it( 'text in different path #2', () => {
  278. john.setData( '[<paragraph>Foo</paragraph>]<paragraph>Bar</paragraph>' );
  279. kate.setData( '<paragraph>Foo</paragraph><paragraph>B[ar]</paragraph>' );
  280. john.setAttribute( 'bold', true );
  281. kate.move( [ 1, 0 ] );
  282. syncClients();
  283. expectClients(
  284. '<paragraph bold="true">Foo</paragraph>' +
  285. '<paragraph>arB</paragraph>'
  286. );
  287. } );
  288. it( 'text in same path', () => {
  289. john.setData( '<paragraph>[Foo] Bar</paragraph>' );
  290. kate.setData( '<paragraph>Foo B[ar]</paragraph>' );
  291. john.setAttribute( 'bold', true );
  292. kate.move( [ 0, 4 ] );
  293. syncClients();
  294. expectClients( '<paragraph><$text bold="true">Foo</$text> arB</paragraph>' );
  295. } );
  296. it( 'text to other client\'s selection', () => {
  297. john.setData( '<paragraph>[Foo] Bar</paragraph>' );
  298. kate.setData( '<paragraph>Foo [Bar]</paragraph>' );
  299. john.setAttribute( 'bold', true );
  300. kate.move( [ 0, 1 ] );
  301. syncClients();
  302. expectClients( '<paragraph><$text bold="true">F</$text>Bar<$text bold="true">oo</$text> </paragraph>' );
  303. } );
  304. it( 'text from other client\'s selection', () => {
  305. john.setData( '<paragraph>[Foo] Bar</paragraph>' );
  306. kate.setData( '<paragraph>F[oo] Bar</paragraph>' );
  307. john.setAttribute( 'bold', true );
  308. kate.move( [ 0, 7 ] );
  309. syncClients();
  310. expectClients( '<paragraph><$text bold="true">F</$text> Bar<$text bold="true">oo</$text></paragraph>' );
  311. } );
  312. it( 'text from other client\'s selection #2', () => {
  313. john.setData( '[<paragraph>Foo Bar</paragraph>]' );
  314. kate.setData( '<paragraph>F[oo] Bar</paragraph>' );
  315. john.setAttribute( 'bold', true );
  316. kate.move( [ 0, 7 ] );
  317. syncClients();
  318. expectClients( '<paragraph bold="true">F Baroo</paragraph>' );
  319. } );
  320. it( 'remove attribute from element in different path', () => {
  321. john.setData( '<paragraph>F[oo]</paragraph><paragraph bold="true">Bar</paragraph>' );
  322. kate.setData( '<paragraph>Foo</paragraph>[<paragraph bold="true">Bar</paragraph>]' );
  323. john.move( [ 1, 0 ] );
  324. kate.removeAttribute( 'bold' );
  325. syncClients();
  326. expectClients(
  327. '<paragraph>F</paragraph>' +
  328. '<paragraph>ooBar</paragraph>'
  329. );
  330. } );
  331. it( 'remove attribute from text in different path', () => {
  332. john.setData( '<paragraph>F[oo]</paragraph><paragraph><$text bold="true">Bar</$text></paragraph>' );
  333. kate.setData( '<paragraph>Foo</paragraph><paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  334. john.move( [ 1, 0 ] );
  335. kate.removeAttribute( 'bold' );
  336. syncClients();
  337. expectClients(
  338. '<paragraph>F</paragraph>' +
  339. '<paragraph>ooBar</paragraph>'
  340. );
  341. } );
  342. it( 'remove attribute from text in same path', () => {
  343. john.setData( '<paragraph>[Fo]<$text bold="true">o</$text></paragraph>' );
  344. kate.setData( '<paragraph>Fo<$text bold="true">[o]</$text></paragraph>' );
  345. john.move( [ 0, 3 ] );
  346. kate.removeAttribute( 'bold' );
  347. syncClients();
  348. expectClients( '<paragraph>oFo</paragraph>' );
  349. } );
  350. it( 'remove attribute from element in same path', () => {
  351. john.setData( '<paragraph bold="true">[Fo]o</paragraph>' );
  352. kate.setData( '[<paragraph bold="true">Foo</paragraph>]' );
  353. john.move( [ 0, 3 ] );
  354. kate.removeAttribute( 'bold' );
  355. syncClients();
  356. expectClients( '<paragraph>oFo</paragraph>' );
  357. } );
  358. it( 'remove attribute from text with 2 attributes in same path', () => {
  359. john.setData( '<paragraph>[Fo]<$text bold="true" italic="true">o</$text></paragraph>' );
  360. kate.setData( '<paragraph>Fo<$text bold="true" italic="true">[o]</$text></paragraph>' );
  361. john.move( [ 0, 3 ] );
  362. kate.removeAttribute( 'bold' );
  363. syncClients();
  364. expectClients( '<paragraph><$text italic="true">o</$text>Fo</paragraph>' );
  365. } );
  366. it( 'remove attribute from text in other user\'s selection', () => {
  367. john.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph><paragraph></paragraph>' );
  368. kate.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph><paragraph></paragraph>' );
  369. john.move( [ 1, 0 ] );
  370. kate.removeAttribute( 'bold' );
  371. syncClients();
  372. expectClients(
  373. '<paragraph></paragraph>' +
  374. '<paragraph>Foo</paragraph>'
  375. );
  376. } );
  377. } );
  378. describe( 'by wrap', () => {
  379. it( 'element into blockQuote in different path', () => {
  380. john.setData( '<paragraph>[Foo]</paragraph><paragraph>Bar</paragraph>' );
  381. kate.setData( '<paragraph>Foo</paragraph>[<paragraph>Bar</paragraph>]' );
  382. john.setAttribute( 'bold', true );
  383. kate.wrap( 'blockQuote' );
  384. syncClients();
  385. expectClients(
  386. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  387. '<blockQuote><paragraph>Bar</paragraph></blockQuote>'
  388. );
  389. } );
  390. it( 'element into blockQuote in different path #2', () => {
  391. john.setData( '[<paragraph>Foo</paragraph>]<paragraph>Bar</paragraph>' );
  392. kate.setData( '<paragraph>Foo</paragraph>[<paragraph>Bar</paragraph>]' );
  393. john.setAttribute( 'bold', true );
  394. kate.wrap( 'blockQuote' );
  395. syncClients();
  396. expectClients(
  397. '<paragraph bold="true">Foo</paragraph>' +
  398. '<blockQuote><paragraph>Bar</paragraph></blockQuote>'
  399. );
  400. } );
  401. it( 'element into blockQuote in same path #1', () => {
  402. john.setData( '<paragraph>[Foo]</paragraph>' );
  403. kate.setData( '[<paragraph>Foo</paragraph>]' );
  404. john.setAttribute( 'bold', true );
  405. kate.wrap( 'blockQuote' );
  406. syncClients();
  407. expectClients(
  408. '<blockQuote>' +
  409. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  410. '</blockQuote>'
  411. );
  412. } );
  413. it( 'element into blockQuote in same path #2', () => {
  414. john.setData( '[<paragraph>Foo</paragraph>]' );
  415. kate.setData( '[<paragraph>Foo</paragraph>]' );
  416. john.setAttribute( 'bold', true );
  417. kate.wrap( 'blockQuote' );
  418. syncClients();
  419. expectClients(
  420. '<blockQuote>' +
  421. '<paragraph bold="true">Foo</paragraph>' +
  422. '</blockQuote>'
  423. );
  424. } );
  425. it( 'remove attribute from element in different path', () => {
  426. john.setData( '[<paragraph>Foo</paragraph>]<paragraph bold="true">Bar</paragraph>' );
  427. kate.setData( '<paragraph>Foo</paragraph>[<paragraph bold="true">Bar</paragraph>]' );
  428. john.wrap( 'blockQuote' );
  429. kate.removeAttribute( 'bold' );
  430. syncClients();
  431. expectClients(
  432. '<blockQuote>' +
  433. '<paragraph>Foo</paragraph>' +
  434. '</blockQuote>' +
  435. '<paragraph>Bar</paragraph>'
  436. );
  437. } );
  438. it( 'remove attribute from text in different path', () => {
  439. john.setData( '[<paragraph>Foo</paragraph>]<paragraph><$text bold="true">Bar</$text></paragraph>' );
  440. kate.setData( '<paragraph>Foo</paragraph><paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  441. john.wrap( 'blockQuote' );
  442. kate.removeAttribute( 'bold' );
  443. syncClients();
  444. expectClients(
  445. '<blockQuote>' +
  446. '<paragraph>Foo</paragraph>' +
  447. '</blockQuote>' +
  448. '<paragraph>Bar</paragraph>'
  449. );
  450. } );
  451. it( 'remove attribute from text in same path', () => {
  452. john.setData( '[<paragraph>Fo<$text bold="true">o</$text></paragraph>]' );
  453. kate.setData( '<paragraph>Fo<$text bold="true">[o]</$text></paragraph>' );
  454. john.wrap( 'blockQuote' );
  455. kate.removeAttribute( 'bold' );
  456. syncClients();
  457. expectClients( '<blockQuote><paragraph>Foo</paragraph></blockQuote>' );
  458. } );
  459. it( 'remove attribute from element in same path', () => {
  460. john.setData( '[<paragraph bold="true">Foo</paragraph>]' );
  461. kate.setData( '[<paragraph bold="true">Foo</paragraph>]' );
  462. john.wrap( 'blockQuote' );
  463. kate.removeAttribute( 'bold' );
  464. syncClients();
  465. expectClients( '<blockQuote><paragraph>Foo</paragraph></blockQuote>' );
  466. } );
  467. it( 'remove attribute from text with 2 attributes in same path', () => {
  468. john.setData( '[<paragraph>Fo<$text bold="true" italic="true">o</$text></paragraph>]' );
  469. kate.setData( '<paragraph>Fo<$text bold="true" italic="true">[o]</$text></paragraph>' );
  470. john.wrap( 'blockQuote' );
  471. kate.removeAttribute( 'bold' );
  472. syncClients();
  473. expectClients(
  474. '<blockQuote>' +
  475. '<paragraph>Fo<$text italic="true">o</$text></paragraph>' +
  476. '</blockQuote>'
  477. );
  478. } );
  479. } );
  480. describe( 'by unwrap', () => {
  481. it( 'element in different path', () => {
  482. john.setData( '<paragraph>[Foo]</paragraph><blockQuote><paragraph>Bar</paragraph></blockQuote>' );
  483. kate.setData( '<paragraph>Foo</paragraph><blockQuote>[<paragraph>Bar</paragraph>]</blockQuote>' );
  484. john.setAttribute( 'bold', true );
  485. kate.unwrap();
  486. syncClients();
  487. expectClients(
  488. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  489. '<paragraph>Bar</paragraph>'
  490. );
  491. } );
  492. it( 'element in different path #2', () => {
  493. john.setData( '[<paragraph>Foo</paragraph>]<blockQuote><paragraph>Bar</paragraph></blockQuote>' );
  494. kate.setData( '<paragraph>Foo</paragraph><blockQuote>[<paragraph>Bar</paragraph>]</blockQuote>' );
  495. john.setAttribute( 'bold', true );
  496. kate.unwrap();
  497. syncClients();
  498. expectClients(
  499. '<paragraph bold="true">Foo</paragraph>' +
  500. '<paragraph>Bar</paragraph>'
  501. );
  502. } );
  503. it( 'text in different path', () => {
  504. john.setData( '<paragraph>[Foo]</paragraph><blockQuote><paragraph>Bar</paragraph></blockQuote>' );
  505. kate.setData( '<paragraph>Foo</paragraph><blockQuote><paragraph>[]Bar</paragraph></blockQuote>' );
  506. john.setAttribute( 'bold', true );
  507. kate.unwrap();
  508. syncClients();
  509. expectClients(
  510. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  511. '<blockQuote>Bar</blockQuote>'
  512. );
  513. } );
  514. it( 'element in same path #1', () => {
  515. john.setData( '<blockQuote><paragraph>[Foo]</paragraph></blockQuote>' );
  516. kate.setData( '<blockQuote>[<paragraph>Foo</paragraph>]</blockQuote>' );
  517. john.setAttribute( 'bold', true );
  518. kate.unwrap();
  519. syncClients();
  520. expectClients( '<paragraph><$text bold="true">Foo</$text></paragraph>' );
  521. } );
  522. it( 'element in same path #2', () => {
  523. john.setData( '<blockQuote>[<paragraph>Foo</paragraph>]</blockQuote>' );
  524. kate.setData( '<blockQuote>[<paragraph>Foo</paragraph>]</blockQuote>' );
  525. john.setAttribute( 'bold', true );
  526. kate.unwrap();
  527. syncClients();
  528. expectClients( '<paragraph bold="true">Foo</paragraph>' );
  529. } );
  530. it( 'text in same path', () => {
  531. john.setData( '<blockQuote><paragraph>[Foo]</paragraph></blockQuote>' );
  532. kate.setData( '<blockQuote><paragraph>[]Foo</paragraph></blockQuote>' );
  533. john.setAttribute( 'bold', true );
  534. kate.unwrap();
  535. syncClients();
  536. expectClients( '<blockQuote><$text bold="true">Foo</$text></blockQuote>' );
  537. } );
  538. it( 'remove attribute from element in different path', () => {
  539. john.setData(
  540. '<blockQuote>[<paragraph>Foo</paragraph>]</blockQuote>' +
  541. '<paragraph bold="true">Bar</paragraph>' );
  542. kate.setData(
  543. '<blockQuote><paragraph>Foo</paragraph></blockQuote>' +
  544. '[<paragraph bold="true">Bar</paragraph>]' );
  545. john.unwrap();
  546. kate.removeAttribute( 'bold' );
  547. syncClients();
  548. expectClients(
  549. '<paragraph>Foo</paragraph>' +
  550. '<paragraph>Bar</paragraph>'
  551. );
  552. } );
  553. it( 'remove attribute from text in different path', () => {
  554. john.setData(
  555. '<blockQuote><paragraph>[]Foo</paragraph></blockQuote>' +
  556. '<paragraph><$text bold="true">Bar</$text></paragraph>' );
  557. kate.setData(
  558. '<blockQuote><paragraph>Foo</paragraph></blockQuote>' +
  559. '<paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  560. john.unwrap();
  561. kate.removeAttribute( 'bold' );
  562. syncClients();
  563. expectClients(
  564. '<blockQuote>Foo</blockQuote>' +
  565. '<paragraph>Bar</paragraph>'
  566. );
  567. } );
  568. it( 'remove attribute from text in same path', () => {
  569. john.setData( '<blockQuote><paragraph>[]Fo<$text bold="true">o</$text></paragraph></blockQuote>' );
  570. kate.setData( '<blockQuote><paragraph>Fo<$text bold="true">[o]</$text></paragraph></blockQuote>' );
  571. john.unwrap();
  572. kate.removeAttribute( 'bold' );
  573. syncClients();
  574. expectClients( '<blockQuote>Foo</blockQuote>' );
  575. } );
  576. it( 'remove attribute from element in same path', () => {
  577. john.setData( '<blockQuote><paragraph bold="true">[]Foo</paragraph></blockQuote>' );
  578. kate.setData( '<blockQuote>[<paragraph bold="true">Foo</paragraph>]</blockQuote>' );
  579. john.unwrap();
  580. kate.removeAttribute( 'bold' );
  581. syncClients();
  582. expectClients( '<blockQuote>Foo</blockQuote>' );
  583. } );
  584. it( 'remove attribute from text with 2 attributes in same path', () => {
  585. john.setData( '<blockQuote><paragraph>[]Fo<$text bold="true" italic="true">o</$text></paragraph></blockQuote>' );
  586. kate.setData( '<blockQuote><paragraph>Fo<$text bold="true" italic="true">[o]</$text></paragraph></blockQuote>' );
  587. john.unwrap();
  588. kate.removeAttribute( 'bold' );
  589. syncClients();
  590. expectClients( '<blockQuote>Fo<$text italic="true">o</$text></blockQuote>' );
  591. } );
  592. } );
  593. describe( 'by split', () => {
  594. it( 'text in different path', () => {
  595. john.setData( '<paragraph>[Foo]</paragraph><paragraph>Bar</paragraph>' );
  596. kate.setData( '<paragraph>Foo</paragraph><paragraph>Ba[]r</paragraph>' );
  597. john.setAttribute( 'bold', true );
  598. kate.split();
  599. syncClients();
  600. expectClients(
  601. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  602. '<paragraph>Ba</paragraph>' +
  603. '<paragraph>r</paragraph>'
  604. );
  605. } );
  606. it( 'text in different path #2', () => {
  607. john.setData( '[<paragraph>Foo</paragraph>]<paragraph>Bar</paragraph>' );
  608. kate.setData( '<paragraph>Foo</paragraph><paragraph>Ba[]r</paragraph>' );
  609. john.setAttribute( 'bold', true );
  610. kate.split();
  611. syncClients();
  612. expectClients(
  613. '<paragraph bold="true">Foo</paragraph>' +
  614. '<paragraph>Ba</paragraph>' +
  615. '<paragraph>r</paragraph>'
  616. );
  617. } );
  618. it( 'text in same path #1', () => {
  619. john.setData( '<paragraph>[Foo] Bar</paragraph>' );
  620. kate.setData( '<paragraph>Foo B[]ar</paragraph>' );
  621. john.setAttribute( 'bold', true );
  622. kate.split();
  623. syncClients();
  624. expectClients(
  625. '<paragraph><$text bold="true">Foo</$text> B</paragraph>' +
  626. '<paragraph>ar</paragraph>'
  627. );
  628. } );
  629. it( 'text in other user\'s selection', () => {
  630. john.setData( '<paragraph>[Foo]</paragraph>' );
  631. kate.setData( '<paragraph>Fo[]o</paragraph>' );
  632. john.setAttribute( 'bold', true );
  633. kate.split();
  634. syncClients();
  635. expect(
  636. '<paragraph><$text bold="true">Fo</$text></paragraph>' +
  637. '<paragraph><$text bold="true">o</$text></paragraph>'
  638. );
  639. } );
  640. it( 'text in other user\'s selection #2', () => {
  641. john.setData( '[<paragraph>Foo Bar</paragraph>]' );
  642. kate.setData( '<paragraph>Foo B[]ar</paragraph>' );
  643. john.setAttribute( 'bold', true );
  644. kate.split();
  645. syncClients();
  646. expectClients(
  647. '<paragraph bold="true">Foo B</paragraph>' +
  648. '<paragraph bold="true">ar</paragraph>'
  649. );
  650. } );
  651. it( 'text while changing attribute', () => {
  652. john.setData( '<paragraph><$text attr="foo">Foo B[ar]</$text></paragraph>' );
  653. kate.setData( '<paragraph><$text attr="foo">Foo B[]ar</$text></paragraph>' );
  654. john.setAttribute( 'attr', 'bar' );
  655. kate.split();
  656. syncClients();
  657. expectClients(
  658. '<paragraph><$text attr="foo">Foo B</$text></paragraph>' +
  659. '<paragraph><$text attr="bar">ar</$text></paragraph>'
  660. );
  661. } );
  662. it( 'remove attribute from element in different path', () => {
  663. john.setData( '<paragraph>F[]oo</paragraph><paragraph bold="true">Bar</paragraph>' );
  664. kate.setData( '<paragraph>Foo</paragraph>[<paragraph bold="true">Bar</paragraph>]' );
  665. john.split();
  666. kate.removeAttribute( 'bold' );
  667. syncClients();
  668. expectClients(
  669. '<paragraph>F</paragraph>' +
  670. '<paragraph>oo</paragraph>' +
  671. '<paragraph>Bar</paragraph>'
  672. );
  673. } );
  674. it( 'remove attribute from text in different path', () => {
  675. john.setData( '<paragraph>F[]oo</paragraph><paragraph><$text bold="true">Bar</$text></paragraph>' );
  676. kate.setData( '<paragraph>Foo</paragraph><paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  677. john.split();
  678. kate.removeAttribute( 'bold' );
  679. syncClients();
  680. expectClients(
  681. '<paragraph>F</paragraph>' +
  682. '<paragraph>oo</paragraph>' +
  683. '<paragraph>Bar</paragraph>'
  684. );
  685. } );
  686. it( 'remove attribute from text in same path #1', () => {
  687. john.setData( '<paragraph>F[]o<$text bold="true">o</$text></paragraph>' );
  688. kate.setData( '<paragraph>Fo<$text bold="true">[o]</$text></paragraph>' );
  689. john.split();
  690. kate.removeAttribute( 'bold' );
  691. syncClients();
  692. expectClients(
  693. '<paragraph>F</paragraph>' +
  694. '<paragraph>oo</paragraph>' );
  695. } );
  696. it( 'remove attribute from text in same path #2', () => {
  697. john.setData( '<paragraph>F<$text bold="true">o[]o</$text></paragraph>' );
  698. kate.setData( '<paragraph>F<$text bold="true">[oo]</$text></paragraph>' );
  699. john.split();
  700. kate.removeAttribute( 'bold' );
  701. syncClients();
  702. expectClients(
  703. '<paragraph>Fo</paragraph>' +
  704. '<paragraph>o</paragraph>' );
  705. } );
  706. it( 'remove attribute from element in same path', () => {
  707. john.setData( '<paragraph bold="true">F[]oo</paragraph>' );
  708. kate.setData( '[<paragraph bold="true">Foo</paragraph>]' );
  709. john.split();
  710. kate.removeAttribute( 'bold' );
  711. syncClients();
  712. expectClients(
  713. '<paragraph>F</paragraph>' +
  714. '<paragraph>oo</paragraph>' );
  715. } );
  716. it( 'remove attribute from text with 2 attributes in same path', () => {
  717. john.setData( '<paragraph>F<$text bold="true" italic="true">o[]o</$text></paragraph>' );
  718. kate.setData( '<paragraph>F<$text bold="true" italic="true">[oo]</$text></paragraph>' );
  719. john.split();
  720. kate.removeAttribute( 'bold' );
  721. syncClients();
  722. expectClients(
  723. '<paragraph>F<$text italic="true">o</$text></paragraph>' +
  724. '<paragraph><$text italic="true">o</$text></paragraph>'
  725. );
  726. } );
  727. } );
  728. describe( 'by remove', () => {
  729. it( 'text in different path', () => {
  730. john.setData( '<paragraph>[Foo]</paragraph><paragraph>Bar</paragraph>' );
  731. kate.setData( '<paragraph>Foo</paragraph><paragraph>[Bar]</paragraph>' );
  732. john.setAttribute( 'bold', true );
  733. kate.remove();
  734. syncClients();
  735. expectClients(
  736. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  737. '<paragraph></paragraph>'
  738. );
  739. } );
  740. it( 'text in same path', () => {
  741. john.setData( '<paragraph>[Fo]o</paragraph>' );
  742. kate.setData( '<paragraph>Fo[o]</paragraph>' );
  743. john.setAttribute( 'bold', true );
  744. kate.remove();
  745. syncClients();
  746. expectClients( '<paragraph><$text bold="true">Fo</$text></paragraph>' );
  747. } );
  748. it( 'text in other user\'s selection', () => {
  749. john.setData( '<paragraph>[Foo]</paragraph>' );
  750. kate.setData( '<paragraph>F[oo]</paragraph>' );
  751. john.setAttribute( 'bold', true );
  752. kate.remove();
  753. syncClients();
  754. expectClients( '<paragraph><$text bold="true">F</$text></paragraph>' );
  755. } );
  756. it( 'remove attribute from element in different path', () => {
  757. john.setData( '<paragraph>F[oo]</paragraph><paragraph bold="true">Bar</paragraph>' );
  758. kate.setData( '<paragraph>Foo</paragraph>[<paragraph bold="true">Bar</paragraph>]' );
  759. john.remove();
  760. kate.removeAttribute( 'bold' );
  761. syncClients();
  762. expectClients(
  763. '<paragraph>F</paragraph>' +
  764. '<paragraph>Bar</paragraph>'
  765. );
  766. } );
  767. it( 'remove attribute from text in different path', () => {
  768. john.setData( '<paragraph>F[oo]</paragraph><paragraph><$text bold="true">Bar</$text></paragraph>' );
  769. kate.setData( '<paragraph>Foo</paragraph><paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  770. john.remove();
  771. kate.removeAttribute( 'bold' );
  772. syncClients();
  773. expectClients(
  774. '<paragraph>F</paragraph>' +
  775. '<paragraph>Bar</paragraph>'
  776. );
  777. } );
  778. it( 'remove attribute from text in same path #1', () => {
  779. john.setData( '<paragraph>[Fo]<$text bold="true">o</$text></paragraph>' );
  780. kate.setData( '<paragraph>Fo<$text bold="true">[o]</$text></paragraph>' );
  781. john.remove();
  782. kate.removeAttribute( 'bold' );
  783. syncClients();
  784. expectClients( '<paragraph>o</paragraph>' );
  785. } );
  786. it( 'remove attribute from text in same path #2', () => {
  787. john.setData( '<paragraph>F[o<$text bold="true">o]z</$text>Bar</paragraph>' );
  788. kate.setData( '<paragraph>Fo<$text bold="true">[oz]</$text>Bar</paragraph>' );
  789. john.remove();
  790. kate.removeAttribute( 'bold' );
  791. syncClients();
  792. expectClients(
  793. '<paragraph>FzBar</paragraph>'
  794. );
  795. } );
  796. it( 'remove attribute from element in same path', () => {
  797. john.setData( '<paragraph bold="true">[Fo]o</paragraph>' );
  798. kate.setData( '[<paragraph bold="true">Foo</paragraph>]' );
  799. john.remove();
  800. kate.removeAttribute( 'bold' );
  801. syncClients();
  802. expectClients( '<paragraph>o</paragraph>' );
  803. } );
  804. it( 'remove attribute from text with 2 attributes in same path #1', () => {
  805. john.setData( '<paragraph>[Fo]<$text bold="true" italic="true">o</$text></paragraph>' );
  806. kate.setData( '<paragraph>Fo<$text bold="true" italic="true">[o]</$text></paragraph>' );
  807. john.remove();
  808. kate.removeAttribute( 'bold' );
  809. syncClients();
  810. expectClients( '<paragraph><$text italic="true">o</$text></paragraph>' );
  811. } );
  812. it( 'remove attribute from text with 2 attributes in same path #2', () => {
  813. john.setData( '<paragraph>F[o<$text bold="true" italic="true">o]z</$text>Bar</paragraph>' );
  814. kate.setData( '<paragraph>Fo<$text bold="true" italic="true">[oz]</$text>Bar</paragraph>' );
  815. john.remove();
  816. kate.removeAttribute( 'bold' );
  817. syncClients();
  818. expectClients(
  819. '<paragraph>F<$text italic="true">z</$text>Bar</paragraph>'
  820. );
  821. } );
  822. it( 'remove attribute from text in other user\'s selection', () => {
  823. john.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph>' );
  824. kate.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph>' );
  825. john.remove();
  826. kate.removeAttribute( 'bold' );
  827. syncClients();
  828. expectClients( '<paragraph></paragraph>' );
  829. } );
  830. } );
  831. describe( 'by remove attribute', () => {
  832. it( 'from element in different path', () => {
  833. john.setData( '<paragraph>[Foo]</paragraph><paragraph bold="true">Bar</paragraph>' );
  834. kate.setData( '<paragraph>Foo</paragraph>[<paragraph bold="true">Bar</paragraph>]' );
  835. john.setAttribute( 'bold', true );
  836. kate.removeAttribute( 'bold' );
  837. syncClients();
  838. expectClients(
  839. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  840. '<paragraph>Bar</paragraph>'
  841. );
  842. } );
  843. it( 'from text in different path', () => {
  844. john.setData( '<paragraph>[Foo]</paragraph><paragraph><$text bold="true">Bar</$text></paragraph>' );
  845. kate.setData( '<paragraph>Foo</paragraph><paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  846. john.setAttribute( 'bold', true );
  847. kate.removeAttribute( 'bold' );
  848. syncClients();
  849. expectClients(
  850. '<paragraph><$text bold="true">Foo</$text></paragraph>' +
  851. '<paragraph>Bar</paragraph>'
  852. );
  853. } );
  854. it( 'from text in same path', () => {
  855. john.setData( '<paragraph>[Fo]<$text bold="true">o</$text></paragraph>' );
  856. kate.setData( '<paragraph>Fo<$text bold="true">[o]</$text></paragraph>' );
  857. john.setAttribute( 'bold', true );
  858. kate.removeAttribute( 'bold' );
  859. syncClients();
  860. expectClients( '<paragraph><$text bold="true">Fo</$text>o</paragraph>' );
  861. } );
  862. it( 'from element in same path', () => {
  863. john.setData( '<paragraph bold="true">[Fo]o</paragraph>' );
  864. kate.setData( '[<paragraph bold="true">Foo</paragraph>]' );
  865. john.setAttribute( 'italic', true );
  866. kate.removeAttribute( 'bold' );
  867. syncClients();
  868. expectClients( '<paragraph><$text italic="true">Fo</$text>o</paragraph>' );
  869. } );
  870. it( 'from text with 2 attributes in same path', () => {
  871. john.setData( '<paragraph>[Fo]<$text bold="true" italic="true">o</$text></paragraph>' );
  872. kate.setData( '<paragraph>Fo<$text bold="true" italic="true">[o]</$text></paragraph>' );
  873. john.setAttribute( 'bold', true );
  874. kate.removeAttribute( 'bold' );
  875. syncClients();
  876. expectClients( '<paragraph><$text bold="true">Fo</$text><$text italic="true">o</$text></paragraph>' );
  877. } );
  878. it( 'from text in other user\'s selection', () => {
  879. john.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph>' );
  880. kate.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph>' );
  881. john.setAttribute( 'italic', true );
  882. kate.removeAttribute( 'bold' );
  883. syncClients();
  884. expectClients( '<paragraph><$text italic="true">Foo</$text></paragraph>' );
  885. } );
  886. } );
  887. describe( 'by marker', () => {
  888. it( 'in text at same path', () => {
  889. john.setData( '<paragraph>[Foo] Bar</paragraph>' );
  890. kate.setData( '<paragraph>Foo [Bar]</paragraph>' );
  891. john.setAttribute( 'bold', true );
  892. kate.setMarker( 'm1' );
  893. syncClients();
  894. expectClients( '<paragraph><$text bold="true">Foo</$text> <m1:start></m1:start>Bar<m1:end></m1:end></paragraph>' );
  895. } );
  896. it( 'in text at same path #2', () => {
  897. john.setData( '[<paragraph>Foo Bar</paragraph>]' );
  898. kate.setData( '<paragraph>Foo [Bar]</paragraph>' );
  899. john.setAttribute( 'bold', true );
  900. kate.setMarker( 'm1' );
  901. syncClients();
  902. expectClients(
  903. '<paragraph bold="true">' +
  904. 'Foo <m1:start></m1:start>Bar<m1:end></m1:end>' +
  905. '</paragraph>'
  906. );
  907. } );
  908. it( 'in text in different path', () => {
  909. john.setData( '<paragraph>F[o]o</paragraph><paragraph>Bar</paragraph>' );
  910. kate.setData( '<paragraph>Foo</paragraph><paragraph>B[a]r</paragraph>' );
  911. john.setAttribute( 'bold', true );
  912. kate.setMarker( 'm1' );
  913. syncClients();
  914. expectClients(
  915. '<paragraph>F<$text bold="true">o</$text>o</paragraph>' +
  916. '<paragraph>B<m1:start></m1:start>a<m1:end></m1:end>r</paragraph>'
  917. );
  918. } );
  919. it( 'in text with selection inside other client\'s selection #1', () => {
  920. john.setData( '<paragraph>[Foo Bar]</paragraph>' );
  921. kate.setData( '<paragraph>Fo[o B]ar</paragraph>' );
  922. john.setAttribute( 'bold', true );
  923. kate.setMarker( 'm1' );
  924. syncClients();
  925. expectClients(
  926. '<paragraph>' +
  927. '<$text bold="true">Fo</$text><m1:start></m1:start>' +
  928. '<$text bold="true">o B</$text><m1:end></m1:end><$text bold="true">ar</$text>' +
  929. '</paragraph>'
  930. );
  931. } );
  932. it( 'in text with selection inside other client\'s selection #2', () => {
  933. john.setData( '<paragraph>F[oo Ba]r</paragraph>' );
  934. kate.setData( '<paragraph>Foo [Bar]</paragraph>' );
  935. john.setAttribute( 'bold', true );
  936. kate.setMarker( 'm1' );
  937. syncClients();
  938. expectClients(
  939. '<paragraph>' +
  940. 'F<$text bold="true">oo </$text><m1:start></m1:start><$text bold="true">Ba</$text>r<m1:end></m1:end>' +
  941. '</paragraph>'
  942. );
  943. } );
  944. it( 'in text at same position', () => {
  945. john.setData( '<paragraph>[Foo Bar]</paragraph>' );
  946. kate.setData( '<paragraph>[Foo Bar]</paragraph>' );
  947. john.setAttribute( 'bold', true );
  948. kate.setMarker( 'm1' );
  949. syncClients();
  950. expectClients( '<paragraph><m1:start></m1:start><$text bold="true">Foo Bar</$text><m1:end></m1:end></paragraph>' );
  951. } );
  952. it( 'remove attribute from element in different path', () => {
  953. john.setData( '<paragraph>[Foo]</paragraph><paragraph bold="true">Bar</paragraph>' );
  954. kate.setData( '<paragraph>Foo</paragraph>[<paragraph bold="true">Bar</paragraph>]' );
  955. john.setMarker( 'm1' );
  956. kate.removeAttribute( 'bold' );
  957. syncClients();
  958. expectClients(
  959. '<paragraph><m1:start></m1:start>Foo<m1:end></m1:end></paragraph>' +
  960. '<paragraph>Bar</paragraph>'
  961. );
  962. } );
  963. it( 'remove attribute from text in different path', () => {
  964. john.setData( '<paragraph>[Foo]</paragraph><paragraph><$text bold="true">Bar</$text></paragraph>' );
  965. kate.setData( '<paragraph>Foo</paragraph><paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  966. john.setMarker( 'm1' );
  967. kate.removeAttribute( 'bold' );
  968. syncClients();
  969. expectClients(
  970. '<paragraph><m1:start></m1:start>Foo<m1:end></m1:end></paragraph>' +
  971. '<paragraph>Bar</paragraph>'
  972. );
  973. } );
  974. it( 'remove attribute from text in same path', () => {
  975. john.setData( '<paragraph>[Fo]<$text bold="true">o</$text></paragraph>' );
  976. kate.setData( '<paragraph>Fo<$text bold="true">[o]</$text></paragraph>' );
  977. john.setMarker( 'm1' );
  978. kate.removeAttribute( 'bold' );
  979. syncClients();
  980. expectClients( '<paragraph><m1:start></m1:start>Fo<m1:end></m1:end>o</paragraph>' );
  981. } );
  982. it( 'remove attribute from text in same path, then undo', () => {
  983. john.setData( '<paragraph>[Fo]<$text bold="true">o</$text></paragraph>' );
  984. kate.setData( '<paragraph>Fo<$text bold="true">[o]</$text></paragraph>' );
  985. john.setMarker( 'm1' );
  986. kate.removeAttribute( 'bold' );
  987. syncClients();
  988. kate.undo();
  989. syncClients();
  990. expectClients( '<paragraph><m1:start></m1:start>Fo<m1:end></m1:end><$text bold="true">o</$text></paragraph>' );
  991. } );
  992. it( 'remove attribute from text with 2 attributes in same path', () => {
  993. john.setData( '<paragraph>[Fo]<$text bold="true" italic="true">o</$text></paragraph>' );
  994. kate.setData( '<paragraph>Fo<$text bold="true" italic="true">[o]</$text></paragraph>' );
  995. john.setMarker( 'm1' );
  996. kate.removeAttribute( 'bold' );
  997. syncClients();
  998. expectClients( '<paragraph><m1:start></m1:start>Fo<m1:end></m1:end><$text italic="true">o</$text></paragraph>' );
  999. } );
  1000. it( 'remove attribute from text in other user\'s selection', () => {
  1001. john.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph>' );
  1002. kate.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph>' );
  1003. john.setMarker( 'm1' );
  1004. kate.removeAttribute( 'bold' );
  1005. syncClients();
  1006. expectClients( '<paragraph><m1:start></m1:start>Foo<m1:end></m1:end></paragraph>' );
  1007. } );
  1008. } );
  1009. describe( 'by merge', () => {
  1010. it( 'element into paragraph #1', () => {
  1011. john.setData( '<paragraph>Foo</paragraph><paragraph>B[ar]</paragraph>' );
  1012. kate.setData( '<paragraph>Foo</paragraph>[]<paragraph>Bar</paragraph>' );
  1013. john.setAttribute( 'bold', 'true' );
  1014. kate.merge();
  1015. syncClients();
  1016. expectClients( '<paragraph>FooB<$text bold="true">ar</$text></paragraph>' );
  1017. } );
  1018. it( 'element into paragraph #2, then undo', () => {
  1019. john.setData( '<paragraph>Foo</paragraph>[<paragraph>Bar</paragraph>]' );
  1020. kate.setData( '<paragraph>Foo</paragraph>[]<paragraph>Bar</paragraph>' );
  1021. john.setAttribute( 'bold', 'true' );
  1022. kate.merge();
  1023. syncClients();
  1024. expectClients( '<paragraph>FooBar</paragraph>' );
  1025. kate.undo();
  1026. syncClients();
  1027. expectClients( '<paragraph>Foo</paragraph><paragraph bold="true">Bar</paragraph>' );
  1028. } );
  1029. it( 'element in same path', () => {
  1030. john.setData( '<paragraph>Foo</paragraph><paragraph>Bar</paragraph>[<paragraph>Baz</paragraph>]' );
  1031. kate.setData( '<paragraph>Foo</paragraph>[]<paragraph>Bar</paragraph><paragraph>Baz</paragraph>' );
  1032. john.setAttribute( 'bold', 'true' );
  1033. kate.merge();
  1034. syncClients();
  1035. expectClients( '<paragraph>FooBar</paragraph><paragraph bold="true">Baz</paragraph>' );
  1036. kate.undo();
  1037. john.undo();
  1038. syncClients();
  1039. expectClients( '<paragraph>Foo</paragraph><paragraph>Bar</paragraph><paragraph>Baz</paragraph>' );
  1040. } );
  1041. } );
  1042. } );
  1043. describe( 'by rename', () => {
  1044. it( 'element in different path', () => {
  1045. john.setData( '<paragraph>Foo</paragraph><paragraph>[Ba]r</paragraph>' );
  1046. kate.setData( '<paragraph>F[]oo</paragraph><paragraph>Bar</paragraph>' );
  1047. john.setAttribute( 'bold', true );
  1048. kate.rename( 'heading1' );
  1049. syncClients();
  1050. expectClients(
  1051. '<heading1>Foo</heading1>' +
  1052. '<paragraph><$text bold="true">Ba</$text>r</paragraph>'
  1053. );
  1054. } );
  1055. it( 'element in same path', () => {
  1056. john.setData( '<paragraph>[Foo Bar]</paragraph>' );
  1057. kate.setData( '<paragraph>[]Foo Bar</paragraph>' );
  1058. john.setAttribute( 'bold', true );
  1059. kate.rename( 'heading1' );
  1060. syncClients();
  1061. expectClients( '<heading1><$text bold="true">Foo Bar</$text></heading1>' );
  1062. } );
  1063. it( 'element in user\'s selection', () => {
  1064. john.setData( '<paragraph>[Foo]</paragraph>' );
  1065. kate.setData( '<paragraph>[Foo]</paragraph>' );
  1066. john.setAttribute( 'bold', true );
  1067. kate.rename( 'heading1' );
  1068. syncClients();
  1069. expectClients( '<heading1><$text bold="true">Foo</$text></heading1>' );
  1070. } );
  1071. it( 'element in user\'s selection, then undo', () => {
  1072. john.setData( '<paragraph>[Foo]</paragraph>' );
  1073. kate.setData( '<paragraph>[Foo]</paragraph>' );
  1074. john.setAttribute( 'bold', true );
  1075. kate.rename( 'heading1' );
  1076. syncClients();
  1077. john.undo();
  1078. kate.undo();
  1079. syncClients();
  1080. expectClients( '<paragraph>Foo</paragraph>' );
  1081. } );
  1082. it( 'remove attribute from element in different path', () => {
  1083. john.setData( '<paragraph>F[]oo</paragraph><paragraph bold="true">Bar</paragraph>' );
  1084. kate.setData( '<paragraph>Foo</paragraph>[<paragraph bold="true">Bar</paragraph>]' );
  1085. john.rename( 'heading1' );
  1086. kate.removeAttribute( 'bold' );
  1087. syncClients();
  1088. expectClients(
  1089. '<heading1>Foo</heading1>' +
  1090. '<paragraph>Bar</paragraph>'
  1091. );
  1092. } );
  1093. it( 'remove attribute from text in different path', () => {
  1094. john.setData( '<paragraph>F[]oo</paragraph><paragraph><$text bold="true">Bar</$text></paragraph>' );
  1095. kate.setData( '<paragraph>Foo</paragraph><paragraph><$text bold="true">[Bar]</$text></paragraph>' );
  1096. john.rename( 'heading1' );
  1097. kate.removeAttribute( 'bold' );
  1098. syncClients();
  1099. expectClients(
  1100. '<heading1>Foo</heading1>' +
  1101. '<paragraph>Bar</paragraph>'
  1102. );
  1103. } );
  1104. it( 'remove attribute from text in same path', () => {
  1105. john.setData( '<paragraph>F[]o<$text bold="true">o</$text></paragraph>' );
  1106. kate.setData( '<paragraph>Fo<$text bold="true">[o]</$text></paragraph>' );
  1107. john.rename( 'heading1' );
  1108. kate.removeAttribute( 'bold' );
  1109. syncClients();
  1110. expectClients( '<heading1>Foo</heading1>' );
  1111. } );
  1112. it( 'remove attribute from element in same path', () => {
  1113. john.setData( '<paragraph bold="true">F[]oo</paragraph>' );
  1114. kate.setData( '[<paragraph bold="true">Foo</paragraph>]' );
  1115. john.rename( 'heading1' );
  1116. kate.removeAttribute( 'bold' );
  1117. syncClients();
  1118. expectClients( '<heading1>Foo</heading1>' );
  1119. } );
  1120. it( 'remove attribute from text with 2 attributes in same path', () => {
  1121. john.setData( '<paragraph>F[o]<$text bold="true" italic="true">o</$text></paragraph>' );
  1122. kate.setData( '<paragraph>Fo<$text bold="true" italic="true">[o]</$text></paragraph>' );
  1123. john.rename( 'heading1' );
  1124. kate.removeAttribute( 'bold' );
  1125. syncClients();
  1126. expectClients( '<heading1>Fo<$text italic="true">o</$text></heading1>' );
  1127. } );
  1128. it( 'remove attribute from text in other user\'s selection', () => {
  1129. john.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph>' );
  1130. kate.setData( '<paragraph><$text bold="true">[Foo]</$text></paragraph>' );
  1131. john.rename( 'heading1' );
  1132. kate.removeAttribute( 'bold' );
  1133. syncClients();
  1134. expectClients( '<heading1>Foo</heading1>' );
  1135. } );
  1136. } );
  1137. } );