DriveFile.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. /**
  2. * Copyright (c) 2006-2017, JGraph Ltd
  3. * Copyright (c) 2006-2017, Gaudenz Alder
  4. */
  5. DriveFile = function(ui, data, desc)
  6. {
  7. DrawioFile.call(this, ui, data);
  8. this.desc = desc;
  9. };
  10. //Extends mxEventSource
  11. mxUtils.extend(DriveFile, DrawioFile);
  12. /**
  13. * Delay for last save in ms.
  14. */
  15. DriveFile.prototype.saveDelay = 0;
  16. /**
  17. * Delay for last save in ms.
  18. */
  19. DriveFile.prototype.allChangesSavedKey = 'allChangesSavedInDrive';
  20. /**
  21. * Specifies if notify events should be ignored.
  22. */
  23. DriveFile.prototype.getSize = function()
  24. {
  25. return this.desc.fileSize;
  26. };
  27. /**
  28. * Returns true if copy, export and print are not allowed for this file.
  29. */
  30. DriveFile.prototype.isRestricted = function()
  31. {
  32. return DrawioFile.RESTRICT_EXPORT || (this.desc.userPermission != null && this.desc.labels != null &&
  33. this.desc.userPermission.role == 'reader' && this.desc.labels.restricted);
  34. };
  35. /**
  36. * Adds the listener for automatically saving the diagram for local changes.
  37. */
  38. DriveFile.prototype.isConflict = function(err)
  39. {
  40. return err != null && err.error != null && err.error.code == 412;
  41. };
  42. /**
  43. * Returns the current etag.
  44. */
  45. DriveFile.prototype.getCurrentUser = function()
  46. {
  47. return (this.ui.drive != null) ? this.ui.drive.user : null;
  48. };
  49. /**
  50. * Translates this point by the given vector.
  51. *
  52. * @param {number} dx X-coordinate of the translation.
  53. * @param {number} dy Y-coordinate of the translation.
  54. */
  55. DriveFile.prototype.getMode = function()
  56. {
  57. return App.MODE_GOOGLE;
  58. };
  59. /**
  60. * Returns true if copy, export and print are not allowed for this file.
  61. */
  62. DriveFile.prototype.getFileUrl = function()
  63. {
  64. return 'https://drive.google.com/open?authuser=0&id=' + this.getId();
  65. };
  66. /**
  67. * Returns true if copy, export and print are not allowed for this file.
  68. */
  69. DriveFile.prototype.getFolderUrl = function()
  70. {
  71. if (this.desc.labels != null && this.desc.labels.trashed)
  72. {
  73. return 'https://drive.google.com/drive/trash';
  74. }
  75. else
  76. {
  77. return (this.desc.parents != null && this.desc.parents.length > 0) ?
  78. 'https://drive.google.com/drive/folders/' +
  79. this.desc.parents[0].id : null;
  80. }
  81. };
  82. /**
  83. * Returns true if copy, export and print are not allowed for this file.
  84. */
  85. DriveFile.prototype.getPublicUrl = function(fn)
  86. {
  87. this.ui.drive.executeRequest({
  88. url: '/files/' + this.desc.id + '/permissions?supportsAllDrives=true'
  89. },
  90. mxUtils.bind(this, function(resp)
  91. {
  92. if (resp != null && resp.items != null)
  93. {
  94. for (var i = 0; i < resp.items.length; i++)
  95. {
  96. if (resp.items[i].id === 'anyoneWithLink' ||
  97. resp.items[i].id === 'anyone')
  98. {
  99. fn(this.desc.webContentLink);
  100. return;
  101. }
  102. }
  103. }
  104. fn(null);
  105. }), mxUtils.bind(this, function()
  106. {
  107. fn(null)
  108. }));
  109. };
  110. /**
  111. * Overridden to enable the autosave option in the document properties dialog
  112. * if realtime is not used.
  113. */
  114. DriveFile.prototype.isAutosaveOptional = function()
  115. {
  116. return true;
  117. };
  118. /**
  119. * Translates this point by the given vector.
  120. *
  121. * @param {number} dx X-coordinate of the translation.
  122. * @param {number} dy Y-coordinate of the translation.
  123. */
  124. DriveFile.prototype.isRenamable = function()
  125. {
  126. return this.isEditable() && DrawioFile.prototype.isEditable.apply(this, arguments);
  127. };
  128. /**
  129. * Translates this point by the given vector.
  130. *
  131. * @param {number} dx X-coordinate of the translation.
  132. * @param {number} dy Y-coordinate of the translation.
  133. */
  134. DriveFile.prototype.isMovable = function()
  135. {
  136. return this.isEditable();
  137. };
  138. /**
  139. * Translates this point by the given vector.
  140. *
  141. * @param {number} dx X-coordinate of the translation.
  142. * @param {number} dy Y-coordinate of the translation.
  143. */
  144. DriveFile.prototype.isTrashed = function()
  145. {
  146. return this.desc.labels.trashed;
  147. };
  148. /**
  149. * Translates this point by the given vector.
  150. *
  151. * @param {number} dx X-coordinate of the translation.
  152. * @param {number} dy Y-coordinate of the translation.
  153. */
  154. DriveFile.prototype.save = function(revision, success, error, unloading, overwrite)
  155. {
  156. DrawioFile.prototype.save.apply(this, [revision, mxUtils.bind(this, function()
  157. {
  158. this.saveFile(null, revision, success, error, unloading, overwrite);
  159. }), error, unloading, overwrite]);
  160. };
  161. /**
  162. * Translates this point by the given vector.
  163. *
  164. * @param {number} dx X-coordinate of the translation.
  165. * @param {number} dy Y-coordinate of the translation.
  166. */
  167. DriveFile.prototype.saveFile = function(title, revision, success, error, unloading, overwrite)
  168. {
  169. try
  170. {
  171. if (!this.isEditable())
  172. {
  173. if (success != null)
  174. {
  175. success();
  176. }
  177. }
  178. else if (!this.savingFile)
  179. {
  180. // Sets shadow modified state during save
  181. this.savingFileTime = new Date();
  182. this.setShadowModified(false);
  183. this.savingFile = true;
  184. this.createSecret(mxUtils.bind(this, function(secret, token)
  185. {
  186. var doSave = mxUtils.bind(this, function(realOverwrite, realRevision)
  187. {
  188. try
  189. {
  190. var lastDesc = this.desc;
  191. if (this.sync != null)
  192. {
  193. this.sync.fileSaving();
  194. }
  195. this.ui.drive.saveFile(this, realRevision, mxUtils.bind(this, function(resp, savedData, pages, checksum)
  196. {
  197. try
  198. {
  199. this.savingFile = false;
  200. // Handles special case where resp is false eg
  201. // if the old file was converted to realtime
  202. if (resp != false)
  203. {
  204. // Checks for changes during save
  205. this.setModified(this.getShadowModified());
  206. if (revision)
  207. {
  208. this.lastAutosaveRevision = new Date().getTime();
  209. }
  210. // Adaptive autosave delay
  211. this.autosaveDelay = Math.round(Math.min(10000,
  212. Math.max(DriveFile.prototype.autosaveDelay,
  213. this.saveDelay)));
  214. this.desc = resp;
  215. this.fileSaved(savedData, lastDesc, mxUtils.bind(this, function()
  216. {
  217. this.contentChanged();
  218. if (success != null)
  219. {
  220. success(resp);
  221. }
  222. }), error, token, pages, checksum);
  223. }
  224. else if (error != null)
  225. {
  226. error(resp);
  227. }
  228. }
  229. catch (e)
  230. {
  231. this.savingFile = false;
  232. if (error != null)
  233. {
  234. error(e);
  235. }
  236. else
  237. {
  238. throw e;
  239. }
  240. }
  241. }), mxUtils.bind(this, function(err, desc)
  242. {
  243. try
  244. {
  245. this.savingFile = false;
  246. if (this.isConflict(err))
  247. {
  248. this.inConflictState = true;
  249. if (this.sync != null)
  250. {
  251. this.savingFile = true;
  252. this.sync.fileConflict(desc, mxUtils.bind(this, function()
  253. {
  254. // Adds random cool-off
  255. window.setTimeout(mxUtils.bind(this, function()
  256. {
  257. this.updateFileData();
  258. this.setShadowModified(false);
  259. doSave(realOverwrite, true);
  260. }), 100 + Math.random() * 500);
  261. }), mxUtils.bind(this, function()
  262. {
  263. this.savingFile = false;
  264. if (error != null)
  265. {
  266. error();
  267. }
  268. }));
  269. }
  270. else if (error != null)
  271. {
  272. error();
  273. }
  274. }
  275. else if (error != null)
  276. {
  277. error(err);
  278. }
  279. }
  280. catch (e)
  281. {
  282. this.savingFile = false;
  283. if (error != null)
  284. {
  285. error(e);
  286. }
  287. else
  288. {
  289. throw e;
  290. }
  291. }
  292. }), unloading, unloading, realOverwrite, null, secret);
  293. }
  294. catch (e)
  295. {
  296. this.savingFile = false;
  297. if (error != null)
  298. {
  299. error(e);
  300. }
  301. else
  302. {
  303. throw e;
  304. }
  305. }
  306. });
  307. doSave(overwrite, revision);
  308. }));
  309. }
  310. }
  311. catch (e)
  312. {
  313. if (error != null)
  314. {
  315. error(e);
  316. }
  317. else
  318. {
  319. throw e;
  320. }
  321. }
  322. };
  323. /**
  324. * Shows a conflict dialog to the user.
  325. */
  326. DriveFile.prototype.copyFile = function(success, error)
  327. {
  328. if (!this.isRestricted())
  329. {
  330. this.makeCopy(mxUtils.bind(this, function()
  331. {
  332. if (this.ui.spinner.spin(document.body, mxResources.get('saving')))
  333. {
  334. try
  335. {
  336. this.save(true, success, error)
  337. }
  338. catch (e)
  339. {
  340. error(e);
  341. }
  342. }
  343. }), error, true);
  344. }
  345. else
  346. {
  347. DrawioFile.prototype.copyFile.apply(this, arguments);
  348. }
  349. };
  350. /**
  351. * Shows a conflict dialog to the user.
  352. */
  353. DriveFile.prototype.makeCopy = function(success, error, timestamp)
  354. {
  355. if (this.ui.spinner.spin(document.body, mxResources.get('saving')))
  356. {
  357. // Uses copyFile internally which is a remote REST call with the advantage of keeping
  358. // the parents of the file in-place, but copies the remote file contents so needs to
  359. // be updated as soon as we have the ID.
  360. this.saveAs(this.ui.getCopyFilename(this, timestamp), mxUtils.bind(this, function(resp)
  361. {
  362. this.desc = resp;
  363. this.ui.spinner.stop();
  364. this.setModified(false);
  365. this.invalidChecksum = false;
  366. this.inConflictState = false;
  367. this.descriptorChanged();
  368. success();
  369. }), mxUtils.bind(this, function()
  370. {
  371. this.ui.spinner.stop();
  372. if (error != null)
  373. {
  374. error();
  375. }
  376. }));
  377. }
  378. };
  379. /**
  380. * Translates this point by the given vector.
  381. *
  382. * @param {number} dx X-coordinate of the translation.
  383. * @param {number} dy Y-coordinate of the translation.
  384. */
  385. DriveFile.prototype.saveAs = function(filename, success, error)
  386. {
  387. this.ui.drive.copyFile(this.getId(), filename, success, error);
  388. };
  389. /**
  390. * Translates this point by the given vector.
  391. *
  392. * @param {number} dx X-coordinate of the translation.
  393. * @param {number} dy Y-coordinate of the translation.
  394. */
  395. DriveFile.prototype.rename = function(title, success, error)
  396. {
  397. var rev = this.getCurrentRevisionId();
  398. this.ui.drive.renameFile(this.getId(), title, mxUtils.bind(this, function(desc)
  399. {
  400. if (!this.hasSameExtension(title, this.getTitle()))
  401. {
  402. this.desc = desc;
  403. if (this.sync != null)
  404. {
  405. this.sync.descriptorChanged(rev);
  406. }
  407. this.save(true, success, error);
  408. }
  409. else
  410. {
  411. this.desc = desc;
  412. this.descriptorChanged();
  413. if (this.sync != null)
  414. {
  415. this.sync.descriptorChanged(rev);
  416. }
  417. if (success != null)
  418. {
  419. success(desc);
  420. }
  421. }
  422. }), error);
  423. };
  424. /**
  425. * Translates this point by the given vector.
  426. *
  427. * @param {number} dx X-coordinate of the translation.
  428. * @param {number} dy Y-coordinate of the translation.
  429. */
  430. DriveFile.prototype.move = function(folderId, success, error)
  431. {
  432. this.ui.drive.moveFile(this.getId(), folderId, mxUtils.bind(this, function(resp)
  433. {
  434. this.desc = resp;
  435. this.descriptorChanged();
  436. if (success != null)
  437. {
  438. success(resp);
  439. }
  440. }), error);
  441. };
  442. /**
  443. * Translates this point by the given vector.
  444. *
  445. * @param {number} dx X-coordinate of the translation.
  446. * @param {number} dy Y-coordinate of the translation.
  447. */
  448. DriveFile.prototype.share = function()
  449. {
  450. this.ui.drive.showPermissions(this.getId(), this);
  451. };
  452. /**
  453. * Translates this point by the given vector.
  454. *
  455. * @param {number} dx X-coordinate of the translation.
  456. * @param {number} dy Y-coordinate of the translation.
  457. */
  458. DriveFile.prototype.getTitle = function()
  459. {
  460. return this.desc.title;
  461. };
  462. /**
  463. * Translates this point by the given vector.
  464. *
  465. * @param {number} dx X-coordinate of the translation.
  466. * @param {number} dy Y-coordinate of the translation.
  467. */
  468. DriveFile.prototype.getHash = function()
  469. {
  470. return 'G' + this.getId();
  471. };
  472. /**
  473. * Translates this point by the given vector.
  474. *
  475. * @param {number} dx X-coordinate of the translation.
  476. * @param {number} dy Y-coordinate of the translation.
  477. */
  478. DriveFile.prototype.getId = function()
  479. {
  480. return this.desc.id;
  481. };
  482. /**
  483. * Translates this point by the given vector.
  484. *
  485. * @param {number} dx X-coordinate of the translation.
  486. * @param {number} dy Y-coordinate of the translation.
  487. */
  488. DriveFile.prototype.isEditable = function()
  489. {
  490. return DrawioFile.prototype.isEditable.apply(this, arguments) &&
  491. this.desc.editable;
  492. };
  493. /**
  494. * Hook for subclassers.
  495. */
  496. DriveFile.prototype.isSyncSupported = function()
  497. {
  498. return true;
  499. };
  500. /**
  501. * Hook for subclassers.
  502. */
  503. DriveFile.prototype.isRealtimeSupported = function()
  504. {
  505. return true;
  506. };
  507. /**
  508. * Returns true if all changes should be sent out immediately.
  509. */
  510. DriveFile.prototype.isRealtimeOptional = function()
  511. {
  512. return this.sync != null && this.sync.isConnected();
  513. };
  514. /**
  515. * Returns true if all changes should be sent out immediately.
  516. */
  517. DriveFile.prototype.setRealtimeEnabled = function(value, success, error)
  518. {
  519. if (this.sync != null)
  520. {
  521. this.ui.drive.executeRequest({
  522. 'url': '/files/' + this.getId() + '/properties?alt=json&supportsAllDrives=true',
  523. 'method': 'POST',
  524. 'contentType': 'application/json; charset=UTF-8',
  525. 'params': {
  526. 'key': 'collaboration',
  527. 'value': (value) ? 'enabled' :
  528. ((urlParams['fast-sync'] != '0') ?
  529. 'disabled' : '')
  530. }
  531. }, mxUtils.bind(this, function()
  532. {
  533. this.loadDescriptor(mxUtils.bind(this, function(desc)
  534. {
  535. if (desc != null)
  536. {
  537. this.sync.descriptorChanged(this.getCurrentEtag());
  538. this.sync.updateDescriptor(desc);
  539. success();
  540. }
  541. else
  542. {
  543. error();
  544. }
  545. }), error);
  546. }), error);
  547. }
  548. else
  549. {
  550. error();
  551. }
  552. };
  553. /**
  554. * Returns true if all changes should be sent out immediately.
  555. */
  556. DriveFile.prototype.isRealtimeEnabled = function()
  557. {
  558. var collab = this.ui.drive.getCustomProperty(this.desc, 'collaboration');
  559. return (DrawioFile.prototype.isRealtimeEnabled.apply(this, arguments) &&
  560. collab != 'disabled') || (Editor.enableRealtime && collab == 'enabled');
  561. };
  562. /**
  563. * Hook for subclassers.
  564. */
  565. DriveFile.prototype.isRevisionHistorySupported = function()
  566. {
  567. return true;
  568. };
  569. /**
  570. * Hook for subclassers.
  571. */
  572. DriveFile.prototype.getRevisions = function(success, error)
  573. {
  574. this.ui.drive.executeRequest(
  575. {
  576. url: '/files/' + this.getId() + '/revisions'
  577. },
  578. mxUtils.bind(this, function(resp)
  579. {
  580. for (var i = 0; i < resp.items.length; i++)
  581. {
  582. (mxUtils.bind(this, function(item)
  583. {
  584. // Redirects title to originalFilename to
  585. // match expected descriptor interface
  586. item.title = item.originalFilename;
  587. item.getXml = mxUtils.bind(this, function(itemSuccess, itemError)
  588. {
  589. this.ui.drive.getXmlFile(item, mxUtils.bind(this, function(file)
  590. {
  591. itemSuccess(file.getData());
  592. }), itemError);
  593. });
  594. item.getUrl = mxUtils.bind(this, function(page)
  595. {
  596. return this.ui.getUrl(window.location.pathname + '?rev=' + item.id +
  597. '&chrome=0&nav=1&layers=1&edit=_blank' + ((page != null) ?
  598. '&page=' + page : '')) + window.location.hash;
  599. });
  600. }))(resp.items[i]);
  601. }
  602. success(resp.items);
  603. }), error);
  604. };
  605. /**
  606. * Adds the listener for automatically saving the diagram for local changes.
  607. */
  608. DriveFile.prototype.getLatestVersion = function(success, error)
  609. {
  610. this.ui.drive.getFile(this.getId(), success, error, true);
  611. };
  612. /**
  613. * Adds all listeners.
  614. */
  615. DriveFile.prototype.getChannelId = function()
  616. {
  617. var chan = this.ui.drive.getCustomProperty(this.desc, 'channel');
  618. if (chan != null)
  619. {
  620. chan = 'G-' + this.getId() + '.' + chan;
  621. }
  622. return chan;
  623. };
  624. /**
  625. * Gets the channel ID from the given descriptor.
  626. */
  627. DriveFile.prototype.getChannelKey = function()
  628. {
  629. return this.ui.drive.getCustomProperty(this.desc, 'key');
  630. };
  631. /**
  632. * Adds all listeners.
  633. */
  634. DriveFile.prototype.getLastModifiedDate = function()
  635. {
  636. return new Date(this.desc.modifiedDate);
  637. };
  638. /**
  639. * Adds all listeners.
  640. */
  641. DriveFile.prototype.getDescriptor = function()
  642. {
  643. return this.desc;
  644. };
  645. /**
  646. * Updates the descriptor of this file with the one from the given file.
  647. */
  648. DriveFile.prototype.setDescriptor = function(desc)
  649. {
  650. this.desc = desc;
  651. };
  652. /**
  653. * Returns the checksum from the given descriptor.
  654. */
  655. DriveFile.prototype.getDescriptorChecksum = function(desc)
  656. {
  657. var value = this.ui.drive.getCustomProperty(desc, 'checksum');
  658. var secret = this.getDescriptorSecret(desc);
  659. var result = null;
  660. if (value != null && secret != null)
  661. {
  662. tokens = value.split(':');
  663. // Checks if checksum matches current secret
  664. if (tokens.length == 2 && tokens[0] == secret)
  665. {
  666. result = tokens[1];
  667. }
  668. }
  669. return result;
  670. };
  671. /**
  672. * Returns the secret from the given descriptor.
  673. */
  674. DriveFile.prototype.getDescriptorSecret = function(desc)
  675. {
  676. return this.ui.drive.getCustomProperty(desc, 'secret');
  677. };
  678. /**
  679. * Updates the revision ID on the given descriptor.
  680. */
  681. DriveFile.prototype.setDescriptorRevisionId = function(desc, id)
  682. {
  683. desc.headRevisionId = id;
  684. };
  685. /**
  686. * Returns the revision ID from the given descriptor.
  687. */
  688. DriveFile.prototype.getDescriptorRevisionId = function(desc)
  689. {
  690. return desc.headRevisionId;
  691. };
  692. /**
  693. * Adds all listeners.
  694. */
  695. DriveFile.prototype.getDescriptorEtag = function(desc)
  696. {
  697. return desc.etag;
  698. };
  699. /**
  700. * Adds the listener for automatically saving the diagram for local changes.
  701. */
  702. DriveFile.prototype.setDescriptorEtag = function(desc, etag)
  703. {
  704. desc.etag = etag;
  705. };
  706. /**
  707. * Adds the listener for automatically saving the diagram for local changes.
  708. */
  709. DriveFile.prototype.loadPatchDescriptor = function(success, error)
  710. {
  711. this.ui.drive.executeRequest(
  712. {
  713. url: '/files/' + this.getId() + '?supportsAllDrives=true&fields=' + this.ui.drive.catchupFields
  714. },
  715. mxUtils.bind(this, function(desc)
  716. {
  717. success(desc);
  718. }), error);
  719. };
  720. /**
  721. * Adds the listener for automatically saving the diagram for local changes.
  722. */
  723. DriveFile.prototype.patchDescriptor = function(desc, patch)
  724. {
  725. desc.headRevisionId = patch.headRevisionId;
  726. desc.modifiedDate = patch.modifiedDate;
  727. DrawioFile.prototype.patchDescriptor.apply(this, arguments);
  728. };
  729. /**
  730. * Adds the listener for automatically saving the diagram for local changes.
  731. */
  732. DriveFile.prototype.loadDescriptor = function(success, error)
  733. {
  734. this.ui.drive.loadDescriptor(this.getId(), success, error);
  735. };
  736. /**
  737. * Are comments supported
  738. */
  739. DriveFile.prototype.commentsSupported = function()
  740. {
  741. return true;
  742. };
  743. /**
  744. * Get comments of the file
  745. */
  746. DriveFile.prototype.getComments = function(success, error)
  747. {
  748. var currentUser = this.ui.getCurrentUser();
  749. function driveCommentToDrawio(file, gComment, pCommentId)
  750. {
  751. if (gComment.deleted) return null; //skip deleted comments
  752. var comment = new DriveComment(file, gComment.commentId || gComment.replyId, gComment.content,
  753. gComment.modifiedDate, gComment.createdDate, gComment.status == 'resolved',
  754. gComment.author.isAuthenticatedUser? currentUser :
  755. new DrawioUser(gComment.author.permissionId, gComment.author.emailAddress,
  756. gComment.author.displayName, gComment.author.picture.url), pCommentId);
  757. for (var i = 0; gComment.replies != null && i < gComment.replies.length; i++)
  758. {
  759. comment.addReplyDirect(driveCommentToDrawio(file, gComment.replies[i], gComment.commentId));
  760. }
  761. return comment;
  762. };
  763. this.ui.drive.executeRequest(
  764. {
  765. url: '/files/' + this.getId() + '/comments'
  766. },
  767. mxUtils.bind(this, function(resp)
  768. {
  769. var comments = [];
  770. for (var i = 0; i < resp.items.length; i++)
  771. {
  772. var comment = driveCommentToDrawio(this, resp.items[i]);
  773. if (comment != null) comments.push(comment);
  774. }
  775. success(comments);
  776. }), error);
  777. };
  778. /**
  779. * Add a comment to the file
  780. */
  781. DriveFile.prototype.addComment = function(comment, success, error)
  782. {
  783. var body = {'content': comment.content};
  784. this.ui.drive.executeRequest(
  785. {
  786. url: '/files/' + this.getId() + '/comments',
  787. method: 'POST',
  788. params: body
  789. },
  790. mxUtils.bind(this, function(resp)
  791. {
  792. success(resp.commentId); //pass comment id
  793. }), error);
  794. };
  795. /**
  796. * Can add a reply to a reply
  797. */
  798. DriveFile.prototype.canReplyToReplies = function()
  799. {
  800. return false;
  801. };
  802. /**
  803. * Can add comments (The permission to comment to this file)
  804. */
  805. DriveFile.prototype.canComment = function()
  806. {
  807. return this.desc.canComment;
  808. };
  809. /**
  810. * Get a new comment object
  811. */
  812. DriveFile.prototype.newComment = function(content, user)
  813. {
  814. return new DriveComment(this, null, content, Date.now(), Date.now(), false, user);
  815. };