DropboxClient.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920
  1. /**
  2. * Copyright (c) 2006-2017, JGraph Ltd
  3. * Copyright (c) 2006-2017, Gaudenz Alder
  4. */
  5. DropboxClient = function(editorUi)
  6. {
  7. DrawioClient.call(this, editorUi, 'dbauth');
  8. this.client = new Dropbox({clientId: App.DROPBOX_APPKEY});
  9. this.client.setAccessToken(this.token);
  10. };
  11. // Extends DrawioClient
  12. mxUtils.extend(DropboxClient, DrawioClient);
  13. /**
  14. * FIXME: How to find name of app folder for current user. The Apps part of the
  15. * name is internationalized so this hardcoded check does not work everywhere.
  16. */
  17. DropboxClient.prototype.appPath = '/drawio/';
  18. /**
  19. * Executes the first step for connecting to Google Drive.
  20. */
  21. DropboxClient.prototype.extension = '.html';
  22. /**
  23. * Executes the first step for connecting to Google Drive.
  24. */
  25. DropboxClient.prototype.writingFile = false;
  26. /**
  27. * Executes the first step for connecting to Google Drive.
  28. */
  29. DropboxClient.prototype.maxRetries = 4;
  30. /**
  31. * Authorizes the client, gets the userId and calls <open>.
  32. */
  33. DropboxClient.prototype.logout = function()
  34. {
  35. this.clearPersistentToken();
  36. this.setUser(null);
  37. this.token = null;
  38. this.client.authTokenRevoke().then(mxUtils.bind(this, function()
  39. {
  40. this.client.setAccessToken(null);
  41. }));
  42. };
  43. /**
  44. * Checks if the client is authorized and calls the next step.
  45. */
  46. DropboxClient.prototype.updateUser = function(success, error, failOnAuth)
  47. {
  48. var acceptResponse = true;
  49. var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  50. {
  51. acceptResponse = false;
  52. error({code: App.ERROR_TIMEOUT});
  53. }), this.ui.timeout);
  54. var promise = this.client.usersGetCurrentAccount();
  55. promise.then(mxUtils.bind(this, function(response)
  56. {
  57. window.clearTimeout(timeoutThread);
  58. if (acceptResponse)
  59. {
  60. this.setUser(new DrawioUser(response.account_id,
  61. response.email, response.name.display_name));
  62. success();
  63. }
  64. }));
  65. // Workaround for IE8/9 support with catch function
  66. promise['catch'](mxUtils.bind(this, function(err)
  67. {
  68. window.clearTimeout(timeoutThread);
  69. if (acceptResponse)
  70. {
  71. if (err != null && err.status === 401 && !failOnAuth)
  72. {
  73. this.setUser(null);
  74. this.client.setAccessToken(null);
  75. this.authenticate(mxUtils.bind(this, function()
  76. {
  77. this.updateUser(success, error, true);
  78. }), error);
  79. }
  80. else
  81. {
  82. error({message: mxResources.get('accessDenied')});
  83. }
  84. }
  85. }));
  86. };
  87. /**
  88. * Authorizes the client, gets the userId and calls <open>.
  89. */
  90. DropboxClient.prototype.authenticate = function(success, error)
  91. {
  92. if (window.onDropboxCallback == null)
  93. {
  94. var auth = mxUtils.bind(this, function()
  95. {
  96. var acceptAuthResponse = true;
  97. this.ui.showAuthDialog(this, true, mxUtils.bind(this, function(remember, authSuccess)
  98. {
  99. var win = window.open(this.client.getAuthenticationUrl('https://' +
  100. window.location.host + '/dropbox.html'), 'dbauth');
  101. if (win != null)
  102. {
  103. window.onDropboxCallback = mxUtils.bind(this, function(token, authWindow)
  104. {
  105. if (acceptAuthResponse)
  106. {
  107. window.onDropboxCallback = null;
  108. acceptAuthResponse = false;
  109. try
  110. {
  111. if (token == null)
  112. {
  113. error({message: mxResources.get('accessDenied'), retry: auth});
  114. }
  115. else
  116. {
  117. if (authSuccess != null)
  118. {
  119. authSuccess();
  120. }
  121. this.client.setAccessToken(token);
  122. this.setUser(null);
  123. if (remember)
  124. {
  125. this.setPersistentToken(token);
  126. }
  127. success();
  128. }
  129. }
  130. catch (e)
  131. {
  132. error(e);
  133. }
  134. finally
  135. {
  136. if (authWindow != null)
  137. {
  138. authWindow.close();
  139. }
  140. }
  141. }
  142. else if (authWindow != null)
  143. {
  144. authWindow.close();
  145. }
  146. });
  147. }
  148. else
  149. {
  150. error({message: mxResources.get('serviceUnavailableOrBlocked'), retry: auth});
  151. }
  152. }), mxUtils.bind(this, function()
  153. {
  154. if (acceptAuthResponse)
  155. {
  156. window.onDropboxCallback = null;
  157. acceptAuthResponse = false;
  158. error({message: mxResources.get('accessDenied'), retry: auth});
  159. }
  160. }));
  161. });
  162. auth();
  163. }
  164. else
  165. {
  166. error({code: App.ERROR_BUSY});
  167. }
  168. };
  169. /**
  170. * Authorizes the client, gets the userId and calls <open>.
  171. */
  172. DropboxClient.prototype.executePromise = function(promise, success, error)
  173. {
  174. var doExecute = mxUtils.bind(this, function(failOnAuth)
  175. {
  176. var acceptResponse = true;
  177. var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  178. {
  179. acceptResponse = false;
  180. error({code: App.ERROR_TIMEOUT, retry: fn});
  181. }), this.ui.timeout);
  182. promise.then(mxUtils.bind(this, function(response)
  183. {
  184. window.clearTimeout(timeoutThread);
  185. if (acceptResponse && success != null)
  186. {
  187. success(response);
  188. }
  189. }));
  190. // Workaround for IE8/9 support with catch function
  191. promise['catch'](mxUtils.bind(this, function(err)
  192. {
  193. window.clearTimeout(timeoutThread);
  194. if (acceptResponse)
  195. {
  196. if (err != null && (err.status == 500 || err.status == 400 ||
  197. err.status == 401))
  198. {
  199. this.setUser(null);
  200. this.client.setAccessToken(null);
  201. if (!failOnAuth)
  202. {
  203. this.authenticate(function()
  204. {
  205. doExecute(true);
  206. }, error);
  207. }
  208. else
  209. {
  210. error({message: mxResources.get('accessDenied'), retry: mxUtils.bind(this, function()
  211. {
  212. this.authenticate(function()
  213. {
  214. fn(true);
  215. }, error);
  216. })});
  217. }
  218. }
  219. else
  220. {
  221. error({message: mxResources.get('error') + ' ' + err.status});
  222. }
  223. }
  224. }));
  225. });
  226. var fn = mxUtils.bind(this, function(failOnAuth)
  227. {
  228. if (this.user == null)
  229. {
  230. this.updateUser(function()
  231. {
  232. fn(true);
  233. }, error, failOnAuth);
  234. }
  235. else
  236. {
  237. doExecute(failOnAuth);
  238. }
  239. });
  240. if (this.client.getAccessToken() === null)
  241. {
  242. this.authenticate(function()
  243. {
  244. fn(true);
  245. }, error);
  246. }
  247. else
  248. {
  249. fn(false);
  250. }
  251. };
  252. /**
  253. * Checks if the client is authorized and calls the next step.
  254. */
  255. DropboxClient.prototype.getLibrary = function(path, success, error)
  256. {
  257. this.getFile(path, success, error, true);
  258. };
  259. /**
  260. * DenyConvert is ignored in this client, just added for API compatibility.
  261. */
  262. DropboxClient.prototype.getFile = function(path, success, error, asLibrary)
  263. {
  264. asLibrary = (asLibrary != null) ? asLibrary : false;
  265. var binary = /\.png$/i.test(path);
  266. if (/^https:\/\//i.test(path) || /\.vsdx$/i.test(path) || /\.gliffy$/i.test(path) ||
  267. (!this.ui.useCanvasForExport && binary))
  268. {
  269. // Should never be null
  270. if (this.token != null)
  271. {
  272. var tokens = path.split('/');
  273. var name = (tokens.length > 0) ? tokens[tokens.length - 1] : path;
  274. this.ui.convertFile(path, name, null, this.extension, success, error);
  275. }
  276. else
  277. {
  278. error({message: mxResources.get('accessDenied')});
  279. }
  280. }
  281. else
  282. {
  283. var arg = {path: '/' + path};
  284. if (urlParams['rev'] != null)
  285. {
  286. arg.rev = urlParams['rev'];
  287. }
  288. this.readFile(arg, mxUtils.bind(this, function(data, response)
  289. {
  290. var index = (binary) ? data.lastIndexOf(',') : -1;
  291. var file = null;
  292. if (index > 0)
  293. {
  294. var xml = this.ui.extractGraphModelFromPng(data.substring(index + 1));
  295. if (xml != null && xml.length > 0)
  296. {
  297. data = xml;
  298. }
  299. else
  300. {
  301. // Imports as PNG image
  302. file = new LocalFile(this, data, path, true);
  303. }
  304. }
  305. success((file != null) ? file :
  306. ((asLibrary) ? new DropboxLibrary(this.ui, data, response) :
  307. new DropboxFile(this.ui, data, response)));
  308. }), error, binary);
  309. }
  310. };
  311. /**
  312. * Translates this point by the given vector.
  313. *
  314. * @param {number} dx X-coordinate of the translation.
  315. * @param {number} dy Y-coordinate of the translation.
  316. */
  317. DropboxClient.prototype.readFile = function(arg, success, error, binary)
  318. {
  319. var doExecute = mxUtils.bind(this, function(failOnAuth)
  320. {
  321. var acceptResponse = true;
  322. var timeoutThread = window.setTimeout(mxUtils.bind(this, function()
  323. {
  324. acceptResponse = false;
  325. error({code: App.ERROR_TIMEOUT});
  326. }), this.ui.timeout);
  327. // Workaround for Uncaught DOMException in filesDownload is to
  328. // get the metadata to handle the file not found case
  329. var checkPromise = this.client.filesGetMetadata({path: '/' + arg.path.substring(1), include_deleted: false});
  330. checkPromise.then(mxUtils.bind(this, function(response)
  331. {
  332. // ignore
  333. }));
  334. // Workaround for IE8/9 support with catch function
  335. checkPromise['catch'](function(err)
  336. {
  337. window.clearTimeout(timeoutThread);
  338. if (acceptResponse && err != null && err.status == 409)
  339. {
  340. acceptResponse = false;
  341. error({message: mxResources.get('fileNotFound')});
  342. }
  343. });
  344. // Download file in parallel
  345. // LATER: Report Uncaught DOMException with path/not_found in filesDownload
  346. var promise = this.client.filesDownload(arg);
  347. promise.then(mxUtils.bind(this, function(response)
  348. {
  349. window.clearTimeout(timeoutThread);
  350. if (acceptResponse)
  351. {
  352. acceptResponse = false;
  353. try
  354. {
  355. var reader = new FileReader();
  356. reader.onload = mxUtils.bind(this, function(event)
  357. {
  358. success(reader.result, response);
  359. });
  360. if (binary)
  361. {
  362. reader.readAsDataURL(response.fileBlob);
  363. }
  364. else
  365. {
  366. reader.readAsText(response.fileBlob);
  367. }
  368. }
  369. catch (e)
  370. {
  371. error(e);
  372. }
  373. }
  374. }));
  375. // Workaround for IE8/9 support with catch function
  376. promise['catch'](mxUtils.bind(this, function(err)
  377. {
  378. window.clearTimeout(timeoutThread);
  379. if (acceptResponse)
  380. {
  381. acceptResponse = false;
  382. if (err != null && (err.status == 500 || err.status == 400 ||
  383. err.status == 401))
  384. {
  385. this.client.setAccessToken(null);
  386. this.setUser(null);
  387. if (!failOnAuth)
  388. {
  389. this.authenticate(function()
  390. {
  391. doExecute(true);
  392. }, error);
  393. }
  394. else
  395. {
  396. error({message: mxResources.get('accessDenied'), retry: mxUtils.bind(this, function()
  397. {
  398. this.authenticate(function()
  399. {
  400. fn(true);
  401. }, error);
  402. })});
  403. }
  404. }
  405. else
  406. {
  407. error({message: mxResources.get('error') + ' ' + err.status});
  408. }
  409. }
  410. }));
  411. });
  412. var fn = mxUtils.bind(this, function(failOnAuth)
  413. {
  414. if (this.user == null)
  415. {
  416. this.updateUser(function()
  417. {
  418. fn(true);
  419. }, error, failOnAuth);
  420. }
  421. else
  422. {
  423. doExecute(failOnAuth);
  424. }
  425. });
  426. if (this.client.getAccessToken() === null)
  427. {
  428. this.authenticate(function()
  429. {
  430. fn(true);
  431. }, error);
  432. }
  433. else
  434. {
  435. fn(false);
  436. }
  437. };
  438. /**
  439. * Translates this point by the given vector.
  440. *
  441. * @param {number} dx X-coordinate of the translation.
  442. * @param {number} dy Y-coordinate of the translation.
  443. */
  444. DropboxClient.prototype.checkExists = function(filename, fn, noConfirm)
  445. {
  446. var promise = this.client.filesGetMetadata({path: '/' + filename.toLowerCase(), include_deleted: false});
  447. this.executePromise(promise, mxUtils.bind(this, function(response)
  448. {
  449. if (noConfirm)
  450. {
  451. fn(false, true, response);
  452. }
  453. else
  454. {
  455. this.ui.confirm(mxResources.get('replaceIt', [filename]), function()
  456. {
  457. fn(true, true, response);
  458. }, function()
  459. {
  460. fn(false, true, response);
  461. });
  462. }
  463. }), function(err)
  464. {
  465. fn(true, false);
  466. });
  467. };
  468. /**
  469. * Translates this point by the given vector.
  470. *
  471. * @param {number} dx X-coordinate of the translation.
  472. * @param {number} dy Y-coordinate of the translation.
  473. */
  474. DropboxClient.prototype.renameFile = function(file, filename, success, error)
  475. {
  476. if (/[\\\/:\?\*"\|]/.test(filename))
  477. {
  478. error({message: mxResources.get('dropboxCharsNotAllowed')});
  479. }
  480. else
  481. {
  482. // Appends working directory of source file
  483. if (file != null && filename != null)
  484. {
  485. var path = file.stat.path_display.substring(1);
  486. var idx = path.lastIndexOf('/');
  487. if (idx > 0)
  488. {
  489. filename = path.substring(0, idx + 1) + filename;
  490. }
  491. }
  492. if (file != null && filename != null && file.stat.path_lower.substring(1) !== filename.toLowerCase())
  493. {
  494. // Checks if file exists
  495. this.checkExists(filename, mxUtils.bind(this, function(checked, exists, response)
  496. {
  497. if (checked)
  498. {
  499. var thenHandler = mxUtils.bind(this, function(deleteResponse)
  500. {
  501. var move = this.client.filesMove({from_path: file.stat.path_display, to_path: '/' +
  502. filename, autorename: false});
  503. this.executePromise(move, success, error);
  504. });
  505. // API fails on same name with different upper-/lowercase
  506. if (!exists || response.path_lower.substring(1) === filename.toLowerCase())
  507. {
  508. thenHandler();
  509. }
  510. else
  511. {
  512. // Deletes file first to avoid conflict in filesMove (non-atomic)
  513. var promise = this.client.filesDelete({path: '/' + filename.toLowerCase()});
  514. this.executePromise(promise, thenHandler, error);
  515. }
  516. }
  517. else
  518. {
  519. error();
  520. }
  521. }));
  522. }
  523. else
  524. {
  525. // Same name with different upper-/lowercase not supported by Dropbox API
  526. error({message: mxResources.get('invalidName')});
  527. }
  528. }
  529. };
  530. /**
  531. * Translates this point by the given vector.
  532. *
  533. * @param {number} dx X-coordinate of the translation.
  534. * @param {number} dy Y-coordinate of the translation.
  535. */
  536. DropboxClient.prototype.insertLibrary = function(filename, data, success, error)
  537. {
  538. this.insertFile(filename, data, success, error, true);
  539. };
  540. /**
  541. * Translates this point by the given vector.
  542. *
  543. * @param {number} dx X-coordinate of the translation.
  544. * @param {number} dy Y-coordinate of the translation.
  545. */
  546. DropboxClient.prototype.insertFile = function(filename, data, success, error, asLibrary)
  547. {
  548. asLibrary = (asLibrary != null) ? asLibrary : false;
  549. this.checkExists(filename, mxUtils.bind(this, function(checked)
  550. {
  551. if (checked)
  552. {
  553. this.saveFile(filename, data, mxUtils.bind(this, function(stat)
  554. {
  555. if (asLibrary)
  556. {
  557. success(new DropboxLibrary(this.ui, data, stat));
  558. }
  559. else
  560. {
  561. success(new DropboxFile(this.ui, data, stat));
  562. }
  563. }), error);
  564. }
  565. else
  566. {
  567. error();
  568. }
  569. }));
  570. };
  571. /**
  572. * Translates this point by the given vector.
  573. *
  574. * @param {number} dx X-coordinate of the translation.
  575. * @param {number} dy Y-coordinate of the translation.
  576. */
  577. DropboxClient.prototype.saveFile = function(filename, data, success, error, folder)
  578. {
  579. if (/[\\\/:\?\*"\|]/.test(filename))
  580. {
  581. error({message: mxResources.get('dropboxCharsNotAllowed')});
  582. }
  583. else if (data.length >= 150000000 /*150MB*/)
  584. {
  585. error({message: mxResources.get('drawingTooLarge') + ' (' +
  586. this.ui.formatFileSize(data.length) + ' / 150 MB)'});
  587. }
  588. else
  589. {
  590. folder = (folder != null) ? folder : '';
  591. // Mute switch is ignored
  592. var promise = this.client.filesUpload({path: '/' + folder + filename,
  593. mode: {'.tag': 'overwrite'}, mute: true,
  594. contents: new Blob([data], {type: 'text/plain'})});
  595. this.executePromise(promise, success, error);
  596. }
  597. };
  598. /**
  599. * Translates this point by the given vector.
  600. *
  601. * @param {number} dx X-coordinate of the translation.
  602. * @param {number} dy Y-coordinate of the translation.
  603. */
  604. DropboxClient.prototype.pickLibrary = function(fn)
  605. {
  606. // Authentication will be carried out on open to make sure the
  607. // autosave does not show an auth dialog. Showing it here will
  608. // block the second dialog (the file picker) so it's too early.
  609. Dropbox.choose(
  610. {
  611. linkType : 'direct',
  612. cancel: mxUtils.bind(this, function()
  613. {
  614. // do nothing
  615. }),
  616. success : mxUtils.bind(this, function(files)
  617. {
  618. if (this.ui.spinner.spin(document.body, mxResources.get('loading')))
  619. {
  620. var error = mxUtils.bind(this, function(e)
  621. {
  622. this.ui.spinner.stop();
  623. this.ui.handleError(e);
  624. });
  625. var tmp = files[0].link.indexOf(this.appPath);
  626. if (tmp > 0)
  627. {
  628. // Checks if file is in app folder by loading file from there and comparing the ID
  629. var rel = decodeURIComponent(files[0].link.substring(tmp + this.appPath.length - 1));
  630. this.readFile({path: rel}, mxUtils.bind(this, function(data, stat)
  631. {
  632. if (stat != null && stat.id == files[0].id)
  633. {
  634. // No need to load file a second time
  635. try
  636. {
  637. this.ui.spinner.stop();
  638. fn(rel.substring(1), new DropboxLibrary(this.ui, data, stat));
  639. }
  640. catch (e)
  641. {
  642. this.ui.handleError(e);
  643. }
  644. }
  645. else
  646. {
  647. this.createLibrary(files[0], fn, error);
  648. }
  649. }), error);
  650. }
  651. else
  652. {
  653. this.createLibrary(files[0], fn, error);
  654. }
  655. }
  656. })
  657. });
  658. };
  659. /**
  660. * Translates this point by the given vector.
  661. *
  662. * @param {number} dx X-coordinate of the translation.
  663. * @param {number} dy Y-coordinate of the translation.
  664. */
  665. DropboxClient.prototype.createLibrary = function(file, success, error)
  666. {
  667. this.ui.confirm(mxResources.get('note') + ': ' + mxResources.get('fileWillBeSavedInAppFolder',
  668. [file.name]), mxUtils.bind(this, function()
  669. {
  670. this.ui.loadUrl(file.link, mxUtils.bind(this, function(data)
  671. {
  672. this.insertFile(file.name, data, mxUtils.bind(this, function(newFile)
  673. {
  674. try
  675. {
  676. this.ui.spinner.stop();
  677. success(newFile.getHash().substring(1), newFile);
  678. }
  679. catch (e)
  680. {
  681. error(e);
  682. }
  683. }), error, true);
  684. }), error);
  685. }), mxUtils.bind(this, function()
  686. {
  687. this.ui.spinner.stop();
  688. }));
  689. };
  690. /**
  691. * Translates this point by the given vector.
  692. *
  693. * @param {number} dx X-coordinate of the translation.
  694. * @param {number} dy Y-coordinate of the translation.
  695. */
  696. DropboxClient.prototype.pickFile = function(fn, readOnly)
  697. {
  698. if (Dropbox.choose != null)
  699. {
  700. fn = (fn != null) ? fn : mxUtils.bind(this, function(path, file)
  701. {
  702. this.ui.loadFile((path != null) ? 'D' + encodeURIComponent(path) : file.getHash(), null, file);
  703. });
  704. // Authentication will be carried out on open to make sure the
  705. // autosave does not show an auth dialog. Showing it here will
  706. // block the second dialog (the file picker) so it's too early.
  707. Dropbox.choose(
  708. {
  709. linkType : 'direct',
  710. cancel: mxUtils.bind(this, function()
  711. {
  712. // do nothing
  713. }),
  714. success : mxUtils.bind(this, function(files)
  715. {
  716. if (this.ui.spinner.spin(document.body, mxResources.get('loading')))
  717. {
  718. // File used for read-only
  719. if (readOnly)
  720. {
  721. this.ui.spinner.stop();
  722. fn(files[0].link);
  723. }
  724. else
  725. {
  726. var error = mxUtils.bind(this, function(e)
  727. {
  728. this.ui.spinner.stop();
  729. this.ui.handleError(e);
  730. });
  731. var success = mxUtils.bind(this, function(path, file)
  732. {
  733. this.ui.spinner.stop();
  734. fn(path, file);
  735. });
  736. var binary = /\.png$/i.test(files[0].name);
  737. if (/\.vsdx$/i.test(files[0].name) || /\.gliffy$/i.test(files[0].name) ||
  738. (!this.ui.useCanvasForExport && binary))
  739. {
  740. success(files[0].link);
  741. }
  742. else
  743. {
  744. var tmp = files[0].link.indexOf(this.appPath);
  745. if (tmp > 0)
  746. {
  747. // Checks if file is in app folder by loading file from there and comparing the ID
  748. var rel = decodeURIComponent(files[0].link.substring(tmp + this.appPath.length - 1));
  749. this.readFile({path: rel}, mxUtils.bind(this, function(data, stat)
  750. {
  751. if (stat != null && stat.id == files[0].id)
  752. {
  753. var index = (binary) ? data.lastIndexOf(',') : -1;
  754. this.ui.spinner.stop();
  755. var file = null;
  756. if (index > 0)
  757. {
  758. var xml = this.ui.extractGraphModelFromPng(data.substring(index + 1));
  759. if (xml != null && xml.length > 0)
  760. {
  761. data = xml;
  762. }
  763. else
  764. {
  765. // Imports as PNG image
  766. file = new LocalFile(this, data, rel, true);
  767. }
  768. }
  769. // No need to load file a second time
  770. fn(rel.substring(1), (file != null) ? file : new DropboxFile(this.ui, data, stat));
  771. }
  772. else
  773. {
  774. this.createFile(files[0], success, error);
  775. }
  776. }), error, binary);
  777. }
  778. else
  779. {
  780. this.createFile(files[0], success, error);
  781. }
  782. }
  783. }
  784. }
  785. })
  786. });
  787. }
  788. else
  789. {
  790. this.ui.handleError({message: mxResources.get('serviceUnavailableOrBlocked')});
  791. }
  792. };
  793. /**
  794. * Translates this point by the given vector.
  795. *
  796. * @param {number} dx X-coordinate of the translation.
  797. * @param {number} dy Y-coordinate of the translation.
  798. */
  799. DropboxClient.prototype.createFile = function(file, success, error)
  800. {
  801. var binary = /(\.png)$/i.test(file.name);
  802. this.ui.loadUrl(file.link, mxUtils.bind(this, function(data)
  803. {
  804. if (data != null && data.length > 0)
  805. {
  806. this.ui.confirm(mxResources.get('note') + ': ' + mxResources.get('fileWillBeSavedInAppFolder', [file.name]), mxUtils.bind(this, function()
  807. {
  808. var index = (binary) ? data.lastIndexOf(',') : -1;
  809. if (index > 0)
  810. {
  811. var xml = this.ui.extractGraphModelFromPng(data.substring(index + 1));
  812. if (xml != null && xml.length > 0)
  813. {
  814. data = xml;
  815. }
  816. }
  817. this.insertFile(file.name, data, mxUtils.bind(this, function(newFile)
  818. {
  819. success(file.name, newFile);
  820. }), error);
  821. }), mxUtils.bind(this, function()
  822. {
  823. this.ui.spinner.stop();
  824. }));
  825. }
  826. else
  827. {
  828. this.ui.spinner.stop();
  829. error({message: mxResources.get('errorLoadingFile')});
  830. }
  831. }), error, binary);
  832. };