LocalFile.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. // $Id = LocalFile.js,v 1.12 2010-01-02 09 =45 =14 gaudenz Exp $
  2. // Copyright (c) 2006-2014, JGraph Ltd
  3. /**
  4. * Constructs a new point for the optional x and y coordinates. If no
  5. * coordinates are given, then the default values for <x> and <y> are used.
  6. * @constructor
  7. * @class Implements a basic 2D point. Known subclassers = {@link mxRectangle}.
  8. * @param {number} x X-coordinate of the point.
  9. * @param {number} y Y-coordinate of the point.
  10. */
  11. LocalFile = function(ui, data, title, temp, fileHandle, desc, editable)
  12. {
  13. DrawioFile.call(this, ui, data);
  14. this.title = title;
  15. this.mode = (temp) ? null : App.MODE_DEVICE;
  16. this.fileHandle = fileHandle;
  17. this.desc = desc;
  18. this.editable = editable;
  19. };
  20. //Extends mxEventSource
  21. mxUtils.extend(LocalFile, DrawioFile);
  22. /**
  23. * Translates this point by the given vector.
  24. *
  25. * @param {number} dx X-coordinate of the translation.
  26. * @param {number} dy Y-coordinate of the translation.
  27. */
  28. LocalFile.prototype.isAutosave = function()
  29. {
  30. return this.fileHandle != null && !this.invalidFileHandle && DrawioFile.prototype.isAutosave.apply(this, arguments);
  31. };
  32. /**
  33. * Specifies if the autosave checkbox should be shown in the document
  34. * properties dialog. Default is false.
  35. */
  36. LocalFile.prototype.isAutosaveOptional = function()
  37. {
  38. return this.fileHandle != null;
  39. };
  40. /**
  41. * Translates this point by the given vector.
  42. *
  43. * @param {number} dx X-coordinate of the translation.
  44. * @param {number} dy Y-coordinate of the translation.
  45. */
  46. LocalFile.prototype.getMode = function()
  47. {
  48. return this.mode;
  49. };
  50. /**
  51. * Translates this point by the given vector.
  52. *
  53. * @param {number} dx X-coordinate of the translation.
  54. * @param {number} dy Y-coordinate of the translation.
  55. */
  56. LocalFile.prototype.getTitle = function()
  57. {
  58. return this.title;
  59. };
  60. /**
  61. * Translates this point by the given vector.
  62. *
  63. * @param {number} dx X-coordinate of the translation.
  64. * @param {number} dy Y-coordinate of the translation.
  65. */
  66. LocalFile.prototype.isRenamable = function()
  67. {
  68. return true;
  69. };
  70. /**
  71. * Translates this point by the given vector.
  72. *
  73. * @param {number} dx X-coordinate of the translation.
  74. * @param {number} dy Y-coordinate of the translation.
  75. */
  76. LocalFile.prototype.isEditable = function()
  77. {
  78. return DrawioFile.prototype.isEditable.apply(this, arguments) &&
  79. (this.editable == null || this.editable);
  80. };
  81. /**
  82. * Translates this point by the given vector.
  83. *
  84. * @param {number} dx X-coordinate of the translation.
  85. * @param {number} dy Y-coordinate of the translation.
  86. */
  87. LocalFile.prototype.setEditable = function(editable)
  88. {
  89. this.editable = editable;
  90. this.descriptorChanged();
  91. };
  92. /**
  93. * Translates this point by the given vector.
  94. *
  95. * @param {number} dx X-coordinate of the translation.
  96. * @param {number} dy Y-coordinate of the translation.
  97. */
  98. LocalFile.prototype.save = function(revision, success, error, unloading, overwrite)
  99. {
  100. this.saveAs(this.title, success, error, unloading, overwrite);
  101. };
  102. /**
  103. * Translates this point by the given vector.
  104. *
  105. * @param {number} dx X-coordinate of the translation.
  106. * @param {number} dy Y-coordinate of the translation.
  107. */
  108. LocalFile.prototype.saveAs = function(title, success, error, unloading, overwrite)
  109. {
  110. this.saveFile(title, false, success, error, null, unloading, overwrite);
  111. };
  112. /**
  113. * Adds all listeners.
  114. */
  115. LocalFile.prototype.getDescriptor = function()
  116. {
  117. return this.desc;
  118. };
  119. /**
  120. * Updates the descriptor of this file with the one from the given file.
  121. */
  122. LocalFile.prototype.setDescriptor = function(desc)
  123. {
  124. this.desc = desc;
  125. };
  126. /**
  127. * Translates this point by the given vector.
  128. *
  129. * @param {number} dx X-coordinate of the translation.
  130. * @param {number} dy Y-coordinate of the translation.
  131. */
  132. LocalFile.prototype.getLatestVersion = function(success, error)
  133. {
  134. if (this.fileHandle == null)
  135. {
  136. if (error != null)
  137. {
  138. error({message: mxResources.get('cannotOpenFile')});
  139. }
  140. }
  141. else
  142. {
  143. this.ui.loadFileSystemEntry(this.fileHandle, success, error);
  144. }
  145. };
  146. /**
  147. * Translates this point by the given vector.
  148. *
  149. * @param {number} dx X-coordinate of the translation.
  150. * @param {number} dy Y-coordinate of the translation.
  151. */
  152. LocalFile.prototype.saveFile = function(title, revision, success, error, useCurrentData, unloading, overwrite)
  153. {
  154. if (title != this.title)
  155. {
  156. this.fileHandle = null;
  157. this.desc = null;
  158. this.editable = null;
  159. }
  160. this.title = title;
  161. // Updates data after changing file name
  162. if (!useCurrentData)
  163. {
  164. this.updateFileData();
  165. }
  166. var binary = this.ui.useCanvasForExport && /(\.png)$/i.test(this.getTitle());
  167. this.setShadowModified(false);
  168. var savedData = this.getData();
  169. var done = mxUtils.bind(this, function()
  170. {
  171. this.setModified(this.getShadowModified());
  172. this.contentChanged();
  173. if (success != null)
  174. {
  175. success();
  176. }
  177. });
  178. var doSave = mxUtils.bind(this, function(data)
  179. {
  180. if (this.fileHandle != null)
  181. {
  182. // Sets shadow modified state during save
  183. if (!this.savingFile)
  184. {
  185. this.savingFileTime = new Date();
  186. this.savingFile = true;
  187. var errorWrapper = mxUtils.bind(this, function(e)
  188. {
  189. this.savingFile = false;
  190. if (error != null)
  191. {
  192. // Wraps error object to offer save status option
  193. error({error: e});
  194. }
  195. });
  196. // Saves a copy as a draft while saving
  197. this.saveDraft(savedData);
  198. this.fileHandle.createWritable().then(mxUtils.bind(this, function(writable)
  199. {
  200. this.fileHandle.getFile().then(mxUtils.bind(this, function(newDesc)
  201. {
  202. this.invalidFileHandle = null;
  203. EditorUi.debug('LocalFile.saveFile', [this],
  204. 'desc', [this.desc], 'newDesc', [newDesc],
  205. 'conflict', this.desc.lastModified !=
  206. newDesc.lastModified);
  207. if (overwrite || this.desc.lastModified == newDesc.lastModified)
  208. {
  209. writable.write((binary) ? this.ui.base64ToBlob(data, 'image/png') : data).then(mxUtils.bind(this, function()
  210. {
  211. writable.close().then(mxUtils.bind(this, function()
  212. {
  213. this.fileHandle.getFile().then(mxUtils.bind(this, function(desc)
  214. {
  215. try
  216. {
  217. var lastDesc = this.desc;
  218. this.savingFile = false;
  219. this.desc = desc;
  220. this.fileSaved(savedData, lastDesc, done, errorWrapper);
  221. // Deletes draft after saving
  222. this.removeDraft();
  223. }
  224. catch (e)
  225. {
  226. errorWrapper(e);
  227. }
  228. }), errorWrapper);
  229. }), errorWrapper);
  230. }), errorWrapper);
  231. }
  232. else
  233. {
  234. this.inConflictState = true;
  235. errorWrapper();
  236. }
  237. }), mxUtils.bind(this, function(e)
  238. {
  239. this.invalidFileHandle = true;
  240. errorWrapper(e);
  241. }));
  242. }), errorWrapper);
  243. }
  244. }
  245. else
  246. {
  247. if (this.ui.isOfflineApp() || this.ui.isLocalFileSave())
  248. {
  249. this.ui.doSaveLocalFile(data, title, (binary) ?
  250. 'image/png' : 'text/xml', binary);
  251. }
  252. else
  253. {
  254. if (data.length < MAX_REQUEST_SIZE)
  255. {
  256. var dot = title.lastIndexOf('.');
  257. var format = (dot > 0) ? title.substring(dot + 1) : 'xml';
  258. // Do not update modified flag
  259. new mxXmlRequest(SAVE_URL, 'format=' + format +
  260. '&xml=' + encodeURIComponent(data) +
  261. '&filename=' + encodeURIComponent(title) +
  262. ((binary) ? '&binary=1' : '')).
  263. simulate(document, '_blank');
  264. }
  265. else
  266. {
  267. this.ui.handleError({message: mxResources.get('drawingTooLarge')}, mxResources.get('error'), mxUtils.bind(this, function()
  268. {
  269. mxUtils.popup(data);
  270. }));
  271. }
  272. }
  273. done();
  274. }
  275. });
  276. if (binary)
  277. {
  278. var p = this.ui.getPngFileProperties(this.ui.fileNode);
  279. this.ui.getEmbeddedPng(mxUtils.bind(this, function(imageData)
  280. {
  281. doSave(imageData);
  282. }), error, (this.ui.getCurrentFile() != this) ?
  283. savedData : null, p.scale, p.border);
  284. }
  285. else
  286. {
  287. doSave(savedData);
  288. }
  289. };
  290. /**
  291. * Translates this point by the given vector.
  292. *
  293. * @param {number} dx X-coordinate of the translation.
  294. * @param {number} dy Y-coordinate of the translation.
  295. */
  296. LocalFile.prototype.rename = function(title, success, error)
  297. {
  298. this.title = title;
  299. this.descriptorChanged();
  300. if (success != null)
  301. {
  302. success();
  303. }
  304. };