1/**
2 * Copyright (c) 2006-2017, JGraph Ltd
3 * Copyright (c) 2006-2017, Gaudenz Alder
4 */
5DropboxFile = function(ui, data, stat)
6{
7	DrawioFile.call(this, ui, data);
8
9	this.stat = stat;
10};
11
12//Extends mxEventSource
13mxUtils.extend(DropboxFile, DrawioFile);
14
15/**
16 * Translates this point by the given vector.
17 *
18 * @param {number} dx X-coordinate of the translation.
19 * @param {number} dy Y-coordinate of the translation.
20 */
21DropboxFile.prototype.getId = function()
22{
23	return this.stat.path_display.substring(1);
24};
25
26/**
27 * Translates this point by the given vector.
28 *
29 * @param {number} dx X-coordinate of the translation.
30 * @param {number} dy Y-coordinate of the translation.
31 */
32DropboxFile.prototype.getHash = function()
33{
34	return 'D' + encodeURIComponent(this.getId());
35};
36
37/**
38 * Translates this point by the given vector.
39 *
40 * @param {number} dx X-coordinate of the translation.
41 * @param {number} dy Y-coordinate of the translation.
42 */
43DropboxFile.prototype.getMode = function()
44{
45	return App.MODE_DROPBOX;
46};
47
48/**
49 * Overridden to enable the autosave option in the document properties dialog.
50 */
51DropboxFile.prototype.isAutosaveOptional = function()
52{
53	return true;
54};
55
56/**
57 * Translates this point by the given vector.
58 *
59 * @param {number} dx X-coordinate of the translation.
60 * @param {number} dy Y-coordinate of the translation.
61 */
62DropboxFile.prototype.getTitle = function()
63{
64	return this.stat.name;
65};
66
67/**
68 * Translates this point by the given vector.
69 *
70 * @param {number} dx X-coordinate of the translation.
71 * @param {number} dy Y-coordinate of the translation.
72 */
73DropboxFile.prototype.isRenamable = function()
74{
75	return true;
76};
77
78/**
79 * Specifies if notify events should be ignored.
80 */
81DropboxFile.prototype.getSize = function()
82{
83	return this.stat.size;
84};
85
86/**
87 * Hook for subclassers.
88 */
89DropboxFile.prototype.isRevisionHistorySupported = function()
90{
91	return true;
92};
93
94/**
95 * Hook for subclassers.
96 */
97DropboxFile.prototype.getRevisions = function(success, error)
98{
99	var promise = this.ui.dropbox.client.filesListRevisions({path: this.stat.path_lower, limit: 100});
100
101	promise.then(mxUtils.bind(this, function(resp)
102	{
103		try
104		{
105			var revs = [];
106
107			for (var i = resp.entries.length - 1; i >= 0; i--)
108			{
109				(mxUtils.bind(this, function(stat)
110				{
111					revs.push({modifiedDate: stat.client_modified, fileSize: stat.size,
112						getXml: mxUtils.bind(this, function(itemSuccess, itemError)
113					{
114						this.ui.dropbox.readFile({path: this.stat.path_lower, rev: stat.rev},
115							itemSuccess, itemError);
116					}), getUrl: mxUtils.bind(this, function(page)
117					{
118						return this.ui.getUrl(window.location.pathname + '?rev=' +
119							stat.rev + '&chrome=0&nav=1&layers=1&edit=_blank' + ((page != null) ?
120							'&page=' + page : '')) + window.location.hash;
121					})});
122				}))(resp.entries[i]);
123			}
124
125			success(revs);
126		}
127		catch (e)
128		{
129			error(e);
130		}
131	}));
132
133	// Workaround for IE8/9 support with catch function
134	promise['catch'](function(err)
135	{
136		error(err);
137	});
138};
139
140/**
141 * Adds the listener for automatically saving the diagram for local changes.
142 */
143DropboxFile.prototype.getLatestVersion = function(success, error)
144{
145	this.ui.dropbox.getFile(this.getId(), success, error);
146};
147
148/**
149* Updates the descriptor of this file with the one from the given file.
150*/
151DropboxFile.prototype.updateDescriptor = function(newFile)
152{
153	this.stat = newFile.stat;
154};
155
156/**
157 * Translates this point by the given vector.
158 *
159 * @param {number} dx X-coordinate of the translation.
160 * @param {number} dy Y-coordinate of the translation.
161 */
162DropboxFile.prototype.save = function(revision, success, error, unloading, overwrite)
163{
164	this.doSave(this.getTitle(), revision, success, error, unloading, overwrite);
165};
166
167/**
168 * Translates this point by the given vector.
169 *
170 * @param {number} dx X-coordinate of the translation.
171 * @param {number} dy Y-coordinate of the translation.
172 */
173DropboxFile.prototype.saveAs = function(title, success, error)
174{
175	this.doSave(title, false, success, error);
176};
177
178/**
179 * Translates this point by the given vector.
180 *
181 * @param {number} dx X-coordinate of the translation.
182 * @param {number} dy Y-coordinate of the translation.
183 */
184DropboxFile.prototype.doSave = function(title, revision, success, error, unloading, overwrite)
185{
186	// Forces update of data for new extensions
187	var prev = this.stat.name;
188	this.stat.name = title;
189
190	DrawioFile.prototype.save.apply(this, [null, mxUtils.bind(this, function()
191	{
192		this.stat.name = prev;
193		this.saveFile(title, revision, success, error, unloading, overwrite);
194	}), error, unloading, overwrite]);
195};
196
197/**
198 * Translates this point by the given vector.
199 *
200 * @param {number} dx X-coordinate of the translation.
201 * @param {number} dy Y-coordinate of the translation.
202 */
203DropboxFile.prototype.saveFile = function(title, revision, success, error)
204{
205	if (!this.isEditable())
206	{
207		if (success != null)
208		{
209			success();
210		}
211	}
212	else if (!this.savingFile)
213	{
214		var fn = mxUtils.bind(this, function(checked)
215		{
216			if (checked)
217			{
218				try
219				{
220					// Sets shadow modified state during save
221					this.savingFileTime = new Date();
222					this.setShadowModified(false);
223					this.savingFile = true;
224
225					var doSave = mxUtils.bind(this, function(data)
226					{
227						var index = this.stat.path_display.lastIndexOf('/');
228						var folder = (index > 1) ? this.stat.path_display.substring(1, index + 1) : null;
229
230						this.ui.dropbox.saveFile(title, data, mxUtils.bind(this, function(stat)
231						{
232							// Checks for changes during save
233							this.setModified(this.getShadowModified());
234							this.savingFile = false;
235							this.stat = stat;
236							this.contentChanged();
237
238							if (success != null)
239							{
240								success();
241							}
242						}), mxUtils.bind(this, function(err)
243						{
244							this.savingFile = false;
245
246							if (error != null)
247							{
248								error(err);
249							}
250						}), folder);
251					});
252
253					if (this.ui.useCanvasForExport && /(\.png)$/i.test(this.getTitle()))
254					{
255						var p = this.ui.getPngFileProperties(this.ui.fileNode);
256
257						this.ui.getEmbeddedPng(mxUtils.bind(this, function(data)
258						{
259							doSave(this.ui.base64ToBlob(data, 'image/png'));
260						}), error, (this.ui.getCurrentFile() != this) ?
261							this.getData() : null, p.scale, p.border);
262					}
263					else
264					{
265						doSave(this.getData());
266					}
267				}
268				catch (e)
269				{
270					this.savingFile = false;
271
272					if (error != null)
273					{
274						error(e);
275					}
276					else
277					{
278						throw e;
279					}
280				}
281			}
282			else if (error != null)
283			{
284				error();
285			}
286		});
287
288		if (this.getTitle() == title)
289		{
290			fn(true);
291		}
292		else
293		{
294			this.ui.dropbox.checkExists(title, fn);
295		}
296	}
297	else if (error != null)
298	{
299		error({code: App.ERROR_BUSY});
300	}
301};
302
303/**
304 * Translates this point by the given vector.
305 *
306 * @param {number} dx X-coordinate of the translation.
307 * @param {number} dy Y-coordinate of the translation.
308 */
309DropboxFile.prototype.rename = function(title, success, error)
310{
311	this.ui.dropbox.renameFile(this, title, mxUtils.bind(this, function(stat)
312	{
313		if (!this.hasSameExtension(title, this.getTitle()))
314		{
315			this.stat = stat;
316			// Required in this case to update hash tag in page
317			// before saving so that the edit link is correct
318			this.descriptorChanged();
319			this.save(true, success, error);
320		}
321		else
322		{
323			this.stat = stat;
324			this.descriptorChanged();
325
326			if (success != null)
327			{
328				success();
329			}
330		}
331	}), error);
332};
333