sharejs.js 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458
  1. import { generateSHA1Hash } from '../../shared/utils/sha1'
  2. import { debugging, debugConsole } from '@/utils/debugging'
  3. import getMeta from '@/utils/meta'
  4. import { postJSON } from '@/infrastructure/fetch-json'
  5. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  6. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  7. var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  8. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  9. /* eslint-disable
  10. camelcase,
  11. max-len,
  12. no-class-assign,
  13. no-return-assign,
  14. no-undef,
  15. no-unused-vars,
  16. no-use-before-define,
  17. standard/object-curly-even-spacing,
  18. */
  19. // TODO: This file was created by bulk-decaffeinate.
  20. // Fix any style issues and re-enable lint.
  21. /*
  22. * decaffeinate suggestions:
  23. * DS101: Remove unnecessary use of Array.from
  24. * DS102: Remove unnecessary code created because of implicit returns
  25. * DS205: Consider reworking code to avoid use of IIFEs
  26. * DS207: Consider shorter variations of null checks
  27. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  28. */
  29. export const { Doc } = (() => {
  30. var append = void 0,
  31. bootstrapTransform = void 0,
  32. exports = void 0,
  33. transformComponent = void 0;
  34. var WEB = true;
  35. window.sharejs = exports = {};
  36. var types = exports.types = {};
  37. // These methods let you build a transform function from a transformComponent function
  38. // for OT types like text and JSON in which operations are lists of components
  39. // and transforming them requires N^2 work.
  40. // Add transform and transformX functions for an OT type which has transformComponent defined.
  41. // transformComponent(destination array, component, other component, side)
  42. exports['_bt'] = bootstrapTransform = function bootstrapTransform(type, transformComponent, checkValidOp, append) {
  43. var _transformX = void 0;
  44. var transformComponentX = function transformComponentX(left, right, destLeft, destRight) {
  45. transformComponent(destLeft, left, right, 'left');
  46. return transformComponent(destRight, right, left, 'right');
  47. };
  48. // Transforms rightOp by leftOp. Returns ['rightOp', clientOp']
  49. type.transformX = type['transformX'] = _transformX = function transformX(leftOp, rightOp) {
  50. checkValidOp(leftOp);
  51. checkValidOp(rightOp);
  52. var newRightOp = [];
  53. var _iteratorNormalCompletion = true;
  54. var _didIteratorError = false;
  55. var _iteratorError = undefined;
  56. try {
  57. for (var _iterator = Array.from(rightOp)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
  58. var rightComponent = _step.value;
  59. // Generate newLeftOp by composing leftOp by rightComponent
  60. var newLeftOp = [];
  61. var k = 0;
  62. while (k < leftOp.length) {
  63. var l;
  64. var nextC = [];
  65. transformComponentX(leftOp[k], rightComponent, newLeftOp, nextC);
  66. k++;
  67. if (nextC.length === 1) {
  68. rightComponent = nextC[0];
  69. } else if (nextC.length === 0) {
  70. var _iteratorNormalCompletion2 = true;
  71. var _didIteratorError2 = false;
  72. var _iteratorError2 = undefined;
  73. try {
  74. for (var _iterator2 = Array.from(leftOp.slice(k))[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
  75. l = _step2.value;
  76. append(newLeftOp, l);
  77. }
  78. } catch (err) {
  79. _didIteratorError2 = true;
  80. _iteratorError2 = err;
  81. } finally {
  82. try {
  83. if (!_iteratorNormalCompletion2 && _iterator2.return) {
  84. _iterator2.return();
  85. }
  86. } finally {
  87. if (_didIteratorError2) {
  88. throw _iteratorError2;
  89. }
  90. }
  91. }
  92. rightComponent = null;
  93. break;
  94. } else {
  95. // Recurse.
  96. var _Array$from = Array.from(_transformX(leftOp.slice(k), nextC)),
  97. _Array$from2 = _slicedToArray(_Array$from, 2),
  98. l_ = _Array$from2[0],
  99. r_ = _Array$from2[1];
  100. var _iteratorNormalCompletion3 = true;
  101. var _didIteratorError3 = false;
  102. var _iteratorError3 = undefined;
  103. try {
  104. for (var _iterator3 = Array.from(l_)[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
  105. l = _step3.value;
  106. append(newLeftOp, l);
  107. }
  108. } catch (err) {
  109. _didIteratorError3 = true;
  110. _iteratorError3 = err;
  111. } finally {
  112. try {
  113. if (!_iteratorNormalCompletion3 && _iterator3.return) {
  114. _iterator3.return();
  115. }
  116. } finally {
  117. if (_didIteratorError3) {
  118. throw _iteratorError3;
  119. }
  120. }
  121. }
  122. var _iteratorNormalCompletion4 = true;
  123. var _didIteratorError4 = false;
  124. var _iteratorError4 = undefined;
  125. try {
  126. for (var _iterator4 = Array.from(r_)[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
  127. var r = _step4.value;
  128. append(newRightOp, r);
  129. }
  130. } catch (err) {
  131. _didIteratorError4 = true;
  132. _iteratorError4 = err;
  133. } finally {
  134. try {
  135. if (!_iteratorNormalCompletion4 && _iterator4.return) {
  136. _iterator4.return();
  137. }
  138. } finally {
  139. if (_didIteratorError4) {
  140. throw _iteratorError4;
  141. }
  142. }
  143. }
  144. rightComponent = null;
  145. break;
  146. }
  147. }
  148. if (rightComponent != null) {
  149. append(newRightOp, rightComponent);
  150. }
  151. leftOp = newLeftOp;
  152. }
  153. } catch (err) {
  154. _didIteratorError = true;
  155. _iteratorError = err;
  156. } finally {
  157. try {
  158. if (!_iteratorNormalCompletion && _iterator.return) {
  159. _iterator.return();
  160. }
  161. } finally {
  162. if (_didIteratorError) {
  163. throw _iteratorError;
  164. }
  165. }
  166. }
  167. return [leftOp, newRightOp];
  168. };
  169. // Transforms op with specified type ('left' or 'right') by otherOp.
  170. return type.transform = type['transform'] = function (op, otherOp, type) {
  171. var _ = void 0;
  172. if (type !== 'left' && type !== 'right') {
  173. throw new Error("type must be 'left' or 'right'");
  174. }
  175. if (otherOp.length === 0) {
  176. return op;
  177. }
  178. // TODO: Benchmark with and without this line. I _think_ it'll make a big difference...?
  179. if (op.length === 1 && otherOp.length === 1) {
  180. return transformComponent([], op[0], otherOp[0], type);
  181. }
  182. if (type === 'left') {
  183. var left = void 0;
  184. var _Array$from3 = Array.from(_transformX(op, otherOp));
  185. var _Array$from4 = _slicedToArray(_Array$from3, 2);
  186. left = _Array$from4[0];
  187. _ = _Array$from4[1];
  188. return left;
  189. } else {
  190. var right = void 0;
  191. var _Array$from5 = Array.from(_transformX(otherOp, op));
  192. var _Array$from6 = _slicedToArray(_Array$from5, 2);
  193. _ = _Array$from6[0];
  194. right = _Array$from6[1];
  195. return right;
  196. }
  197. };
  198. };
  199. // A simple text implementation
  200. //
  201. // Operations are lists of components.
  202. // Each component either inserts or deletes at a specified position in the document.
  203. //
  204. // Components are either:
  205. // {i:'str', p:100}: Insert 'str' at position 100 in the document
  206. // {d:'str', p:100}: Delete 'str' at position 100 in the document
  207. //
  208. // Components in an operation are executed sequentially, so the position of components
  209. // assumes previous components have already executed.
  210. //
  211. // Eg: This op:
  212. // [{i:'abc', p:0}]
  213. // is equivalent to this op:
  214. // [{i:'a', p:0}, {i:'b', p:1}, {i:'c', p:2}]
  215. // NOTE: The global scope here is shared with other sharejs files when built with closure.
  216. // Be careful what ends up in your namespace.
  217. var text = {};
  218. text.name = 'text';
  219. text.create = function () {
  220. return '';
  221. };
  222. var strInject = function strInject(s1, pos, s2) {
  223. return s1.slice(0, pos) + s2 + s1.slice(pos);
  224. };
  225. var checkValidComponent = function checkValidComponent(c) {
  226. if (typeof c.p !== 'number') {
  227. throw new Error('component missing position field');
  228. }
  229. var i_type = _typeof(c.i);
  230. var d_type = _typeof(c.d);
  231. var c_type = _typeof(c.c);
  232. if (!(i_type === 'string' ^ d_type === 'string' ^ c_type === 'string')) {
  233. throw new Error('component needs an i, d or c field');
  234. }
  235. if (!(c.p >= 0)) {
  236. throw new Error('position cannot be negative');
  237. }
  238. };
  239. var checkValidOp = function checkValidOp(op) {
  240. var _iteratorNormalCompletion5 = true;
  241. var _didIteratorError5 = false;
  242. var _iteratorError5 = undefined;
  243. try {
  244. for (var _iterator5 = Array.from(op)[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
  245. var c = _step5.value;
  246. checkValidComponent(c);
  247. }
  248. } catch (err) {
  249. _didIteratorError5 = true;
  250. _iteratorError5 = err;
  251. } finally {
  252. try {
  253. if (!_iteratorNormalCompletion5 && _iterator5.return) {
  254. _iterator5.return();
  255. }
  256. } finally {
  257. if (_didIteratorError5) {
  258. throw _iteratorError5;
  259. }
  260. }
  261. }
  262. return true;
  263. };
  264. text.apply = function (snapshot, op) {
  265. checkValidOp(op);
  266. var _iteratorNormalCompletion6 = true;
  267. var _didIteratorError6 = false;
  268. var _iteratorError6 = undefined;
  269. try {
  270. for (var _iterator6 = Array.from(op)[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
  271. var component = _step6.value;
  272. if (component.i != null) {
  273. snapshot = strInject(snapshot, component.p, component.i);
  274. } else if (component.d != null) {
  275. var deleted = snapshot.slice(component.p, component.p + component.d.length);
  276. if (component.d !== deleted) {
  277. throw new Error('Delete component \'' + component.d + '\' does not match deleted text \'' + deleted + '\'');
  278. }
  279. snapshot = snapshot.slice(0, component.p) + snapshot.slice(component.p + component.d.length);
  280. } else if (component.c != null) {
  281. var comment = snapshot.slice(component.p, component.p + component.c.length);
  282. if (component.c !== comment) {
  283. throw new Error('Comment component \'' + component.c + '\' does not match commented text \'' + comment + '\'');
  284. }
  285. } else {
  286. throw new Error('Unknown op type');
  287. }
  288. }
  289. } catch (err) {
  290. _didIteratorError6 = true;
  291. _iteratorError6 = err;
  292. } finally {
  293. try {
  294. if (!_iteratorNormalCompletion6 && _iterator6.return) {
  295. _iterator6.return();
  296. }
  297. } finally {
  298. if (_didIteratorError6) {
  299. throw _iteratorError6;
  300. }
  301. }
  302. }
  303. return snapshot;
  304. };
  305. var cloneAndModify = function cloneAndModify(op, modifications) {
  306. var v = void 0;
  307. var newOp = {};
  308. for (var k in op) {
  309. v = op[k];
  310. newOp[k] = v;
  311. }
  312. for (k in modifications) {
  313. v = modifications[k];
  314. newOp[k] = v;
  315. }
  316. return newOp;
  317. };
  318. // Exported for use by the random op generator.
  319. //
  320. // For simplicity, this version of append does not compress adjacent inserts and deletes of
  321. // the same text. It would be nice to change that at some stage.
  322. text._append = append = function append(newOp, c) {
  323. if (c.i === '' || c.d === '') {
  324. return;
  325. }
  326. if (newOp.length === 0) {
  327. return newOp.push(c);
  328. } else {
  329. var last = newOp[newOp.length - 1];
  330. // Compose the insert into the previous insert if possible
  331. if (last.i != null && c.i != null && last.p <= c.p && c.p <= last.p + last.i.length && last.u === c.u) {
  332. return newOp[newOp.length - 1] = cloneAndModify(last, { i: strInject(last.i, c.p - last.p, c.i) });
  333. } else if (last.d != null && c.d != null && c.p <= last.p && last.p <= c.p + c.d.length && last.u === c.u) {
  334. return newOp[newOp.length - 1] = cloneAndModify(last, { d: strInject(c.d, last.p - c.p, last.d), p: c.p });
  335. } else {
  336. return newOp.push(c);
  337. }
  338. }
  339. };
  340. text.compose = function (op1, op2) {
  341. checkValidOp(op1);
  342. checkValidOp(op2);
  343. var newOp = op1.slice();
  344. var _iteratorNormalCompletion7 = true;
  345. var _didIteratorError7 = false;
  346. var _iteratorError7 = undefined;
  347. try {
  348. for (var _iterator7 = Array.from(op2)[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
  349. var c = _step7.value;
  350. append(newOp, c);
  351. }
  352. } catch (err) {
  353. _didIteratorError7 = true;
  354. _iteratorError7 = err;
  355. } finally {
  356. try {
  357. if (!_iteratorNormalCompletion7 && _iterator7.return) {
  358. _iterator7.return();
  359. }
  360. } finally {
  361. if (_didIteratorError7) {
  362. throw _iteratorError7;
  363. }
  364. }
  365. }
  366. return newOp;
  367. };
  368. // Attempt to compress the op components together 'as much as possible'.
  369. // This implementation preserves order and preserves create/delete pairs.
  370. text.compress = function (op) {
  371. return text.compose([], op);
  372. };
  373. text.normalize = function (op) {
  374. var newOp = [];
  375. // Normalize should allow ops which are a single (unwrapped) component:
  376. // {i:'asdf', p:23}.
  377. // There's no good way to test if something is an array:
  378. // http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/
  379. // so this is probably the least bad solution.
  380. if (op.i != null || op.p != null) {
  381. op = [op];
  382. }
  383. var _iteratorNormalCompletion8 = true;
  384. var _didIteratorError8 = false;
  385. var _iteratorError8 = undefined;
  386. try {
  387. for (var _iterator8 = Array.from(op)[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
  388. var c = _step8.value;
  389. if (c.p == null) {
  390. c.p = 0;
  391. }
  392. append(newOp, c);
  393. }
  394. } catch (err) {
  395. _didIteratorError8 = true;
  396. _iteratorError8 = err;
  397. } finally {
  398. try {
  399. if (!_iteratorNormalCompletion8 && _iterator8.return) {
  400. _iterator8.return();
  401. }
  402. } finally {
  403. if (_didIteratorError8) {
  404. throw _iteratorError8;
  405. }
  406. }
  407. }
  408. return newOp;
  409. };
  410. // This helper method transforms a position by an op component.
  411. //
  412. // If c is an insert, insertAfter specifies whether the transform
  413. // is pushed after the insert (true) or before it (false).
  414. //
  415. // insertAfter is optional for deletes.
  416. var transformPosition = function transformPosition(pos, c, insertAfter) {
  417. if (c.i != null) {
  418. if (c.p < pos || c.p === pos && insertAfter) {
  419. return pos + c.i.length;
  420. } else {
  421. return pos;
  422. }
  423. } else if (c.d != null) {
  424. // I think this could also be written as: Math.min(c.p, Math.min(c.p - otherC.p, otherC.d.length))
  425. // but I think its harder to read that way, and it compiles using ternary operators anyway
  426. // so its no slower written like this.
  427. if (pos <= c.p) {
  428. return pos;
  429. } else if (pos <= c.p + c.d.length) {
  430. return c.p;
  431. } else {
  432. return pos - c.d.length;
  433. }
  434. } else if (c.c != null) {
  435. return pos;
  436. } else {
  437. throw new Error('unknown op type');
  438. }
  439. };
  440. // Helper method to transform a cursor position as a result of an op.
  441. //
  442. // Like transformPosition above, if c is an insert, insertAfter specifies whether the cursor position
  443. // is pushed after an insert (true) or before it (false).
  444. text.transformCursor = function (position, op, side) {
  445. var insertAfter = side === 'right';
  446. var _iteratorNormalCompletion9 = true;
  447. var _didIteratorError9 = false;
  448. var _iteratorError9 = undefined;
  449. try {
  450. for (var _iterator9 = Array.from(op)[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
  451. var c = _step9.value;
  452. position = transformPosition(position, c, insertAfter);
  453. }
  454. } catch (err) {
  455. _didIteratorError9 = true;
  456. _iteratorError9 = err;
  457. } finally {
  458. try {
  459. if (!_iteratorNormalCompletion9 && _iterator9.return) {
  460. _iterator9.return();
  461. }
  462. } finally {
  463. if (_didIteratorError9) {
  464. throw _iteratorError9;
  465. }
  466. }
  467. }
  468. return position;
  469. };
  470. // Transform an op component by another op component. Asymmetric.
  471. // The result will be appended to destination.
  472. //
  473. // exported for use in JSON type
  474. text._tc = transformComponent = function transformComponent(dest, c, otherC, side) {
  475. var cIntersect = void 0,
  476. intersectEnd = void 0,
  477. intersectStart = void 0,
  478. newC = void 0,
  479. otherIntersect = void 0;
  480. checkValidOp([c]);
  481. checkValidOp([otherC]);
  482. if (c.i != null) {
  483. append(dest, cloneAndModify(c, { p: transformPosition(c.p, otherC, side === 'right') }));
  484. } else if (c.d != null) {
  485. // Delete
  486. if (otherC.i != null) {
  487. // delete vs insert
  488. var s = c.d;
  489. if (c.p < otherC.p) {
  490. append(dest, cloneAndModify(c, { d: s.slice(0, otherC.p - c.p) }));
  491. s = s.slice(otherC.p - c.p);
  492. }
  493. if (s !== '') {
  494. append(dest, cloneAndModify(c, { d: s, p: c.p + otherC.i.length }));
  495. }
  496. } else if (otherC.d != null) {
  497. // Delete vs delete
  498. if (c.p >= otherC.p + otherC.d.length) {
  499. append(dest, cloneAndModify(c, { p: c.p - otherC.d.length }));
  500. } else if (c.p + c.d.length <= otherC.p) {
  501. append(dest, c);
  502. } else {
  503. // They overlap somewhere.
  504. newC = cloneAndModify(c, { d: '' });
  505. if (c.p < otherC.p) {
  506. newC.d = c.d.slice(0, otherC.p - c.p);
  507. }
  508. if (c.p + c.d.length > otherC.p + otherC.d.length) {
  509. newC.d += c.d.slice(otherC.p + otherC.d.length - c.p);
  510. }
  511. // This is entirely optional - just for a check that the deleted
  512. // text in the two ops matches
  513. intersectStart = Math.max(c.p, otherC.p);
  514. intersectEnd = Math.min(c.p + c.d.length, otherC.p + otherC.d.length);
  515. cIntersect = c.d.slice(intersectStart - c.p, intersectEnd - c.p);
  516. otherIntersect = otherC.d.slice(intersectStart - otherC.p, intersectEnd - otherC.p);
  517. if (cIntersect !== otherIntersect) {
  518. throw new Error('Delete ops delete different text in the same region of the document');
  519. }
  520. if (newC.d !== '') {
  521. // This could be rewritten similarly to insert v delete, above.
  522. newC.p = transformPosition(newC.p, otherC);
  523. append(dest, newC);
  524. }
  525. }
  526. } else if (otherC.c != null) {
  527. append(dest, c);
  528. } else {
  529. throw new Error('unknown op type');
  530. }
  531. } else if (c.c != null) {
  532. // Comment
  533. if (otherC.i != null) {
  534. if (c.p < otherC.p && otherC.p < c.p + c.c.length) {
  535. var offset = otherC.p - c.p;
  536. var new_c = c.c.slice(0, +(offset - 1) + 1 || undefined) + otherC.i + c.c.slice(offset);
  537. append(dest, cloneAndModify(c, { c: new_c }));
  538. } else {
  539. append(dest, cloneAndModify(c, { p: transformPosition(c.p, otherC, true) }));
  540. }
  541. } else if (otherC.d != null) {
  542. if (c.p >= otherC.p + otherC.d.length) {
  543. append(dest, cloneAndModify(c, { p: c.p - otherC.d.length }));
  544. } else if (c.p + c.c.length <= otherC.p) {
  545. append(dest, c);
  546. } else {
  547. // Delete overlaps comment
  548. // They overlap somewhere.
  549. newC = cloneAndModify(c, { c: '' });
  550. if (c.p < otherC.p) {
  551. newC.c = c.c.slice(0, otherC.p - c.p);
  552. }
  553. if (c.p + c.c.length > otherC.p + otherC.d.length) {
  554. newC.c += c.c.slice(otherC.p + otherC.d.length - c.p);
  555. }
  556. // This is entirely optional - just for a check that the deleted
  557. // text in the two ops matches
  558. intersectStart = Math.max(c.p, otherC.p);
  559. intersectEnd = Math.min(c.p + c.c.length, otherC.p + otherC.d.length);
  560. cIntersect = c.c.slice(intersectStart - c.p, intersectEnd - c.p);
  561. otherIntersect = otherC.d.slice(intersectStart - otherC.p, intersectEnd - otherC.p);
  562. if (cIntersect !== otherIntersect) {
  563. throw new Error('Delete ops delete different text in the same region of the document');
  564. }
  565. newC.p = transformPosition(newC.p, otherC);
  566. append(dest, newC);
  567. }
  568. } else if (otherC.c != null) {
  569. append(dest, c);
  570. } else {
  571. throw new Error('unknown op type');
  572. }
  573. }
  574. return dest;
  575. };
  576. var invertComponent = function invertComponent(c) {
  577. if (c.i != null) {
  578. return { d: c.i, p: c.p };
  579. } else {
  580. return { i: c.d, p: c.p };
  581. }
  582. };
  583. // No need to use append for invert, because the components won't be able to
  584. // cancel with one another.
  585. text.invert = function (op) {
  586. return Array.from(op.slice().reverse()).map(function (c) {
  587. return invertComponent(c);
  588. });
  589. };
  590. if (WEB != null) {
  591. if (!exports.types) {
  592. exports.types = {};
  593. }
  594. // This is kind of awful - come up with a better way to hook this helper code up.
  595. bootstrapTransform(text, transformComponent, checkValidOp, append);
  596. // [] is used to prevent closure from renaming types.text
  597. exports.types.text = text;
  598. }
  599. // Text document API for text
  600. text.api = {
  601. otType: "sharejs-text-ot",
  602. provides: { text: true },
  603. // The number of characters in the string
  604. getLength: function getLength() {
  605. return this.snapshot.length;
  606. },
  607. // Get the text contents of a document
  608. getText: function getText() {
  609. return this.snapshot;
  610. },
  611. insert: function insert(pos, text, fromUndo, callback) {
  612. var op = { p: pos, i: text };
  613. if (fromUndo) {
  614. op.u = true;
  615. }
  616. op = [op];
  617. this.submitOp(op, callback);
  618. return op;
  619. },
  620. del: function del(pos, length, fromUndo, callback) {
  621. var op = { p: pos, d: this.snapshot.slice(pos, pos + length) };
  622. if (fromUndo) {
  623. op.u = true;
  624. }
  625. op = [op];
  626. this.submitOp(op, callback);
  627. return op;
  628. },
  629. _register: function _register() {
  630. return this.on('remoteop', function (op) {
  631. var _this = this;
  632. return function () {
  633. var result = [];
  634. var _iteratorNormalCompletion10 = true;
  635. var _didIteratorError10 = false;
  636. var _iteratorError10 = undefined;
  637. try {
  638. for (var _iterator10 = Array.from(op)[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
  639. var component = _step10.value;
  640. if (component.i !== undefined) {
  641. result.push(_this.emit('insert', component.p, component.i));
  642. } else if (component.d !== undefined) {
  643. result.push(_this.emit('delete', component.p, component.d));
  644. } else {
  645. result.push(undefined);
  646. }
  647. }
  648. } catch (err) {
  649. _didIteratorError10 = true;
  650. _iteratorError10 = err;
  651. } finally {
  652. try {
  653. if (!_iteratorNormalCompletion10 && _iterator10.return) {
  654. _iterator10.return();
  655. }
  656. } finally {
  657. if (_didIteratorError10) {
  658. throw _iteratorError10;
  659. }
  660. }
  661. }
  662. return result;
  663. }();
  664. });
  665. }
  666. };
  667. // This is a simple port of microevent.js to Coffeescript. I've changed the
  668. // function names to be consistent with node.js EventEmitter.
  669. //
  670. // microevent.js is copyright Jerome Etienne, and licensed under the MIT license:
  671. // https://github.com/jeromeetienne/microevent.js
  672. var nextTick = WEB != null ? function (fn) {
  673. return setTimeout(fn, 0);
  674. } : process['nextTick'];
  675. var MicroEvent = function () {
  676. function MicroEvent() {
  677. _classCallCheck(this, MicroEvent);
  678. }
  679. _createClass(MicroEvent, [{
  680. key: 'on',
  681. value: function on(event, fct) {
  682. if (!this._events) {
  683. this._events = {};
  684. }
  685. if (!this._events[event]) {
  686. this._events[event] = [];
  687. }
  688. this._events[event].push(fct);
  689. return this;
  690. }
  691. }, {
  692. key: 'removeListener',
  693. value: function removeListener(event, fct) {
  694. var _this2 = this;
  695. if (!this._events) {
  696. this._events = {};
  697. }
  698. var listeners = this._events[event] || (this._events[event] = []);
  699. // Sadly, there's no IE8- support for indexOf.
  700. var i = 0;
  701. while (i < listeners.length) {
  702. if (listeners[i] === fct) {
  703. listeners[i] = undefined;
  704. }
  705. i++;
  706. }
  707. nextTick(function () {
  708. return _this2._events[event] = Array.from(_this2._events[event]).filter(function (x) {
  709. return x;
  710. });
  711. });
  712. return this;
  713. }
  714. }, {
  715. key: 'emit',
  716. value: function emit(event) {
  717. if (!(this._events != null ? this._events[event] : undefined)) {
  718. return this;
  719. }
  720. for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
  721. args[_key - 1] = arguments[_key];
  722. }
  723. var _iteratorNormalCompletion11 = true;
  724. var _didIteratorError11 = false;
  725. var _iteratorError11 = undefined;
  726. try {
  727. for (var _iterator11 = Array.from(this._events[event])[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) {
  728. var fn = _step11.value;
  729. if (fn) {
  730. fn.apply(this, args);
  731. }
  732. }
  733. } catch (err) {
  734. _didIteratorError11 = true;
  735. _iteratorError11 = err;
  736. } finally {
  737. try {
  738. if (!_iteratorNormalCompletion11 && _iterator11.return) {
  739. _iterator11.return();
  740. }
  741. } finally {
  742. if (_didIteratorError11) {
  743. throw _iteratorError11;
  744. }
  745. }
  746. }
  747. return this;
  748. }
  749. }]);
  750. return MicroEvent;
  751. }();
  752. // mixin will delegate all MicroEvent.js function in the destination object
  753. MicroEvent.mixin = function (obj) {
  754. var proto = obj.prototype || obj;
  755. // Damn closure compiler :/
  756. proto.on = MicroEvent.prototype.on;
  757. proto.removeListener = MicroEvent.prototype.removeListener;
  758. proto.emit = MicroEvent.prototype.emit;
  759. return obj;
  760. };
  761. if (WEB == null) {
  762. module.exports = MicroEvent;
  763. }
  764. if (WEB != null) {
  765. exports.extendDoc = function (name, fn) {
  766. return Doc.prototype[name] = fn;
  767. };
  768. }
  769. // A Doc is a client's view on a sharejs document.
  770. //
  771. // Documents are created by calling Connection.open().
  772. //
  773. // Documents are event emitters - use doc.on(eventname, fn) to subscribe.
  774. //
  775. // Documents get mixed in with their type's API methods. So, you can .insert('foo', 0) into
  776. // a text document and stuff like that.
  777. //
  778. // Events:
  779. // - remoteop (op)
  780. // - changed (op)
  781. // - acknowledge (op)
  782. // - error
  783. // - open, closing, closed. 'closing' is not guaranteed to fire before closed.
  784. var Doc = function () {
  785. // connection is a Connection object.
  786. // name is the documents' docName.
  787. // data can optionally contain known document data, and initial open() call arguments:
  788. // {v[erson], snapshot={...}, type, create=true/false/undefined}
  789. // callback will be called once the document is first opened.
  790. function Doc(connection, name, openData) {
  791. _classCallCheck(this, Doc);
  792. // Any of these can be null / undefined at this stage.
  793. this.flush = this.flush.bind(this);
  794. this.setFlushDelay = this.setFlushDelay.bind(this);
  795. this.shout = this.shout.bind(this);
  796. this.connection = connection;
  797. this.name = name;
  798. if (!openData) {
  799. openData = {};
  800. }
  801. this.version = openData.v;
  802. this.lastServerActivity = performance.now()
  803. this.snapshot = openData.snaphot;
  804. if (openData.type) {
  805. this._setType(openData.type);
  806. }
  807. this.state = 'closed';
  808. this.autoOpen = false;
  809. // Has the document already been created?
  810. this._create = openData.create;
  811. // The op that is currently roundtripping to the server, or null.
  812. //
  813. // When the connection reconnects, the inflight op is resubmitted.
  814. this.inflightOp = null;
  815. this.inflightCallbacks = [];
  816. // The auth ids which the client has previously used to attempt to send inflightOp. This is
  817. // usually empty.
  818. this.inflightSubmittedIds = [];
  819. // All ops that are waiting for the server to acknowledge @inflightOp
  820. this.pendingOp = null;
  821. this.pendingCallbacks = [];
  822. }
  823. // Transform a server op by a client op, and vice versa.
  824. _createClass(Doc, [{
  825. key: '_xf',
  826. value: function _xf(client, server) {
  827. if (this.type.transformX) {
  828. return this.type.transformX(client, server);
  829. } else {
  830. var client_ = this.type.transform(client, server, 'left');
  831. var server_ = this.type.transform(server, client, 'right');
  832. return [client_, server_];
  833. }
  834. }
  835. }, {
  836. key: '_otApply',
  837. value: function _otApply(docOp, isRemote, msg) {
  838. var oldSnapshot = this.snapshot;
  839. this.snapshot = this.type.apply(this.snapshot, docOp);
  840. // Its important that these event handlers are called with oldSnapshot.
  841. // The reason is that the OT type APIs might need to access the snapshots to
  842. // determine information about the received op.
  843. this.emit('change', docOp, oldSnapshot, msg, isRemote);
  844. if (isRemote) {
  845. return this.emit('remoteop', docOp, oldSnapshot, msg);
  846. }
  847. }
  848. }, {
  849. key: '_connectionStateChanged',
  850. value: function _connectionStateChanged(state, data) {
  851. switch (state) {
  852. case 'disconnected':
  853. this.state = 'closed';
  854. // This is used by the server to make sure that when an op is resubmitted it
  855. // doesn't end up getting applied twice.
  856. if (this.inflightOp) {
  857. this.inflightSubmittedIds.push(this.connection.id);
  858. }
  859. this.emit('closed');
  860. break;
  861. case 'ok':
  862. // Might be able to do this when we're connecting... that would save a roundtrip.
  863. if (this.autoOpen) {
  864. this.open();
  865. }
  866. break;
  867. case 'stopped':
  868. if (typeof this._openCallback === 'function') {
  869. this._openCallback(data);
  870. }
  871. break;
  872. }
  873. return this.emit(state, data);
  874. }
  875. }, {
  876. key: '_setType',
  877. value: function _setType(type) {
  878. if (typeof type === 'string') {
  879. type = types[type];
  880. }
  881. if (!type || !type.compose) {
  882. throw new Error('Support for types without compose() is not implemented');
  883. }
  884. this.type = type;
  885. if (type.api) {
  886. for (var k in type.api) {
  887. var v = type.api[k];this[k] = v;
  888. }
  889. return typeof this._register === 'function' ? this._register() : undefined;
  890. } else {
  891. return this.provides = {};
  892. }
  893. }
  894. }, {
  895. key: '_onMessage',
  896. value: function _onMessage(msg) {
  897. // debugConsole.warn('s->c', msg)
  898. if (msg.open === true) {
  899. // The document has been successfully opened.
  900. this.state = 'open';
  901. this._create = false; // Don't try and create the document again next time open() is called.
  902. if (this.created == null) {
  903. this.created = !!msg.create;
  904. }
  905. if (msg.type) {
  906. this._setType(msg.type);
  907. }
  908. if (msg.create) {
  909. this.created = true;
  910. this.snapshot = this.type.create();
  911. } else {
  912. if (this.created !== true) {
  913. this.created = false;
  914. }
  915. if (msg.snapshot !== undefined) {
  916. this.snapshot = msg.snapshot;
  917. }
  918. }
  919. if (msg.v != null) {
  920. this.version = msg.v;
  921. }
  922. // Resend any previously queued operation.
  923. if (this.inflightOp) {
  924. var response = {
  925. doc: this.name,
  926. op: this.inflightOp,
  927. v: this.version
  928. };
  929. if (this.inflightSubmittedIds.length) {
  930. response.dupIfSource = this.inflightSubmittedIds;
  931. }
  932. this.connection.send(response);
  933. } else {
  934. this.flush();
  935. }
  936. this.emit('open');
  937. return typeof this._openCallback === 'function' ? this._openCallback(null) : undefined;
  938. } else if (msg.open === false) {
  939. // The document has either been closed, or an open request has failed.
  940. if (msg.error) {
  941. // An error occurred opening the document.
  942. debugConsole.error('Could not open document: ' + msg.error);
  943. this.emit('error', msg.error);
  944. if (typeof this._openCallback === 'function') {
  945. this._openCallback(msg.error);
  946. }
  947. }
  948. this.state = 'closed';
  949. this.emit('closed');
  950. if (typeof this._closeCallback === 'function') {
  951. this._closeCallback();
  952. }
  953. return this._closeCallback = null;
  954. } else if (msg.op === null && error === 'Op already submitted') {
  955. // Overleaf: note that this branch is never reached, as `error` is always undefined
  956. // We've tried to resend an op to the server, which has already been received successfully. Do nothing.
  957. // The op will be confirmed normally when we get the op itself was echoed back from the server
  958. // (handled below).
  959. } else if (msg.op === undefined && msg.v !== undefined || msg.op && Array.from(this.inflightSubmittedIds).includes(msg.meta.source)) {
  960. // Overleaf: avoid clearing inflightOp on repeated acknowledgement of operations on the same version
  961. if (!msg.error) {
  962. if (msg.op === undefined && msg.v !== undefined) {
  963. if (msg.v < this.version) {
  964. postJSON('/error/client', {
  965. body: {
  966. error: {
  967. message: 'out-of-order-ack-ignored'
  968. },
  969. meta: { msg, version: this.version }
  970. }
  971. })
  972. return
  973. }
  974. } else {
  975. if (msg.v < this.version) {
  976. postJSON('/error/client', {
  977. body: {
  978. error: {
  979. message: 'out-of-order-self-op-ignored'
  980. },
  981. meta: { msg: { v: msg.v }, version: this.version }
  982. }
  983. })
  984. // return // TODO: enable this?
  985. }
  986. }
  987. }
  988. // Our inflight op has been acknowledged.
  989. var callback = void 0;
  990. var oldInflightOp = this.inflightOp;
  991. this.inflightOp = null;
  992. this.inflightSubmittedIds.length = 0;
  993. if (this.pendingOp === null) {
  994. // All ops are acked
  995. this.emit('saved');
  996. }
  997. var error = msg.error;
  998. if (error) {
  999. // The server has rejected an op from the client for some reason.
  1000. // We'll send the error message to the user and roll back the change.
  1001. //
  1002. // If the server isn't going to allow edits anyway, we should probably
  1003. // figure out some way to flag that (readonly:true in the open request?)
  1004. if (this.type.invert) {
  1005. var undo = this.type.invert(oldInflightOp);
  1006. // Now we have to transform the undo operation by any server ops & pending ops
  1007. if (this.pendingOp) {
  1008. var _Array$from7 = Array.from(this._xf(this.pendingOp, undo));
  1009. var _Array$from8 = _slicedToArray(_Array$from7, 2);
  1010. this.pendingOp = _Array$from8[0];
  1011. undo = _Array$from8[1];
  1012. }
  1013. // ... and apply it locally, reverting the changes.
  1014. //
  1015. // This call will also call @emit 'remoteop'. I'm still not 100% sure about this
  1016. // functionality, because its really a local op. Basically, the problem is that
  1017. // if the client's op is rejected by the server, the editor window should update
  1018. // to reflect the undo.
  1019. this._otApply(undo, true, msg);
  1020. } else {
  1021. this.emit('error', 'Op apply failed (' + error + ') and the op could not be reverted');
  1022. }
  1023. var _iteratorNormalCompletion12 = true;
  1024. var _didIteratorError12 = false;
  1025. var _iteratorError12 = undefined;
  1026. try {
  1027. for (var _iterator12 = Array.from(this.inflightCallbacks)[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) {
  1028. callback = _step12.value;
  1029. callback(error);
  1030. }
  1031. } catch (err) {
  1032. _didIteratorError12 = true;
  1033. _iteratorError12 = err;
  1034. } finally {
  1035. try {
  1036. if (!_iteratorNormalCompletion12 && _iterator12.return) {
  1037. _iterator12.return();
  1038. }
  1039. } finally {
  1040. if (_didIteratorError12) {
  1041. throw _iteratorError12;
  1042. }
  1043. }
  1044. }
  1045. } else {
  1046. // The op applied successfully.
  1047. // We may get multiple acks of the same message if we retried it,
  1048. // so its ok if we receive an ack for a version that we've already gone past.
  1049. // If so, just ignore it
  1050. if (msg.v < this.version) {
  1051. return;
  1052. }
  1053. if (msg.v !== this.version) {
  1054. throw new Error('Invalid version from server');
  1055. }
  1056. this.version++;
  1057. this.lastServerActivity = performance.now()
  1058. this.emit('acknowledge', oldInflightOp);
  1059. var _iteratorNormalCompletion13 = true;
  1060. var _didIteratorError13 = false;
  1061. var _iteratorError13 = undefined;
  1062. try {
  1063. for (var _iterator13 = Array.from(this.inflightCallbacks)[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) {
  1064. callback = _step13.value;
  1065. callback(null, oldInflightOp);
  1066. }
  1067. } catch (err) {
  1068. _didIteratorError13 = true;
  1069. _iteratorError13 = err;
  1070. } finally {
  1071. try {
  1072. if (!_iteratorNormalCompletion13 && _iterator13.return) {
  1073. _iterator13.return();
  1074. }
  1075. } finally {
  1076. if (_didIteratorError13) {
  1077. throw _iteratorError13;
  1078. }
  1079. }
  1080. }
  1081. }
  1082. // Send the next op.
  1083. return this.delayedFlush();
  1084. } else if (msg.op) {
  1085. // We got a new op from the server.
  1086. // msg is {doc:, op:, v:}
  1087. // There is a bug in socket.io (produced on firefox 3.6) which causes messages
  1088. // to be duplicated sometimes.
  1089. // We'll just silently drop subsequent messages.
  1090. if (msg.v < this.version) {
  1091. return;
  1092. }
  1093. if (msg.doc !== this.name) {
  1094. return this.emit('error', 'Expected docName \'' + this.name + '\' but got ' + msg.doc);
  1095. }
  1096. if (msg.v !== this.version) {
  1097. return this.emit('error', 'Expected version ' + this.version + ' but got ' + msg.v);
  1098. }
  1099. // p "if: #{i @inflightOp} pending: #{i @pendingOp} doc '#{@snapshot}' op: #{i msg.op}"
  1100. var docOp = msg.op;
  1101. if (this.inflightOp !== null) {
  1102. var _Array$from9 = Array.from(this._xf(this.inflightOp, docOp));
  1103. var _Array$from10 = _slicedToArray(_Array$from9, 2);
  1104. this.inflightOp = _Array$from10[0];
  1105. docOp = _Array$from10[1];
  1106. }
  1107. if (this.pendingOp !== null) {
  1108. var _Array$from11 = Array.from(this._xf(this.pendingOp, docOp));
  1109. var _Array$from12 = _slicedToArray(_Array$from11, 2);
  1110. this.pendingOp = _Array$from12[0];
  1111. docOp = _Array$from12[1];
  1112. }
  1113. this.version++;
  1114. this.lastServerActivity = performance.now()
  1115. // Finally, apply the op to @snapshot and trigger any event listeners
  1116. return this._otApply(docOp, true, msg);
  1117. } else if (msg.meta) {
  1118. var _msg$meta = msg.meta,
  1119. path = _msg$meta.path,
  1120. value = _msg$meta.value;
  1121. switch (path != null ? path[0] : undefined) {
  1122. case 'shout':
  1123. return this.emit('shout', value);
  1124. default:
  1125. return debugConsole.warn('Unhandled meta op:', msg);
  1126. }
  1127. } else {
  1128. return debugConsole.warn('Unhandled document message:', msg);
  1129. }
  1130. }
  1131. // Send ops to the server, if appropriate.
  1132. //
  1133. // Only one op can be in-flight at a time, so if an op is already on its way then
  1134. // this method does nothing.
  1135. }, {
  1136. key: 'flush',
  1137. value: function flush() {
  1138. this.flushTimeout = null;
  1139. // console.log "CALLED FLUSH"
  1140. if (this.connection.state !== 'ok' || this.inflightOp !== null || this.pendingOp === null) {
  1141. return;
  1142. }
  1143. // Rotate null -> pending -> inflight
  1144. this.inflightOp = this.pendingOp;
  1145. this.inflightCallbacks = this.pendingCallbacks;
  1146. this.pendingOp = null;
  1147. this.pendingCallbacks = [];
  1148. this.emit('flipped_pending_to_inflight');
  1149. if (getMeta('ol-useShareJsHash') || debugging) {
  1150. var now = Date.now()
  1151. var age = this.__lastSubmitTimestamp && (now - this.__lastSubmitTimestamp)
  1152. var RECOMPUTE_HASH_INTERVAL = 5000
  1153. // check the document hash regularly (but not if we have checked in the last 5 seconds)
  1154. var needToRecomputeHash = !this.__lastSubmitTimestamp || (age > RECOMPUTE_HASH_INTERVAL) || (age < 0)
  1155. if (needToRecomputeHash || debugging) {
  1156. // send git hash of current snapshot
  1157. const str = this.getText()
  1158. var sha1 = generateSHA1Hash("blob " + str.length + "\x00" + str)
  1159. this.__lastSubmitTimestamp = now;
  1160. }
  1161. }
  1162. // console.log "SENDING OP TO SERVER", @inflightOp, @version
  1163. var lastVersion = this.__lastVersion;
  1164. this.__lastVersion = this.version;
  1165. return this.connection.send({ doc: this.name, op: this.inflightOp, v: this.version, lastV: lastVersion, hash: sha1});
  1166. }
  1167. // Submit an op to the server. The op maybe held for a little while before being sent, as only one
  1168. // op can be inflight at any time.
  1169. }, {
  1170. key: 'submitOp',
  1171. value: function submitOp(op, callback) {
  1172. if (this.type.normalize != null) {
  1173. op = this.type.normalize(op);
  1174. }
  1175. var oldSnapshot = this.snapshot;
  1176. // If this throws an exception, no changes should have been made to the doc
  1177. this.snapshot = this.type.apply(this.snapshot, op);
  1178. if (this.pendingOp !== null) {
  1179. this.pendingOp = this.type.compose(this.pendingOp, op);
  1180. } else {
  1181. this.pendingOp = op;
  1182. }
  1183. if (callback) {
  1184. this.pendingCallbacks.push(callback);
  1185. }
  1186. this.emit('change', op, oldSnapshot);
  1187. return this.delayedFlush();
  1188. }
  1189. }, {
  1190. key: 'delayedFlush',
  1191. value: function delayedFlush() {
  1192. if (this.flushTimeout == null) {
  1193. return this.flushTimeout = setTimeout(this.flush, this._flushDelay || 0);
  1194. }
  1195. }
  1196. }, {
  1197. key: 'setFlushDelay',
  1198. value: function setFlushDelay(delay) {
  1199. return this._flushDelay = delay;
  1200. }
  1201. }, {
  1202. key: 'shout',
  1203. value: function shout(msg) {
  1204. // Meta ops don't have to queue, they can go direct. Good/bad idea?
  1205. return this.connection.send({ doc: this.name, meta: { path: ['shout'], value: msg } });
  1206. }
  1207. // Open a document. The document starts closed.
  1208. }, {
  1209. key: 'open',
  1210. value: function open(callback) {
  1211. var _this3 = this;
  1212. this.autoOpen = true;
  1213. if (this.state !== 'closed') {
  1214. return;
  1215. }
  1216. var message = {
  1217. doc: this.name,
  1218. open: true
  1219. };
  1220. if (this.snapshot === undefined) {
  1221. message.snapshot = null;
  1222. }
  1223. if (this.type) {
  1224. message.type = this.type.name;
  1225. }
  1226. if (this.version != null) {
  1227. message.v = this.version;
  1228. }
  1229. if (this._create) {
  1230. message.create = true;
  1231. }
  1232. this.connection.send(message);
  1233. this.state = 'opening';
  1234. return this._openCallback = function (error) {
  1235. _this3._openCallback = null;
  1236. return typeof callback === 'function' ? callback(error) : undefined;
  1237. };
  1238. }
  1239. // Close a document.
  1240. }, {
  1241. key: 'close',
  1242. value: function close(callback) {
  1243. this.autoOpen = false;
  1244. if (this.state === 'closed') {
  1245. return typeof callback === 'function' ? callback() : undefined;
  1246. }
  1247. this.connection.send({ doc: this.name, open: false });
  1248. // Should this happen immediately or when we get open:false back from the server?
  1249. this.state = 'closed';
  1250. this.emit('closing');
  1251. return this._closeCallback = callback;
  1252. }
  1253. }]);
  1254. return Doc;
  1255. }();
  1256. // Make documents event emitters
  1257. MicroEvent.mixin(Doc);
  1258. exports.Doc = Doc;
  1259. return exports;
  1260. })()
  1261. export default window.sharejs