| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- /**
- * Copyright (c) 2006-2017, JGraph Ltd
- * Copyright (c) 2006-2017, Gaudenz Alder
- */
- /**
- * Constructs a new point for the optional x and y coordinates. If no
- * coordinates are given, then the default values for <x> and <y> are used.
- * @constructor
- * @class Implements a basic 2D point. Known subclassers = {@link mxRectangle}.
- * @param {number} x X-coordinate of the point.
- * @param {number} y Y-coordinate of the point.
- */
- StorageFile = function(ui, data, title)
- {
- DrawioFile.call(this, ui, data);
-
- this.title = title;
- this.etag = this.getEtag(data);
- };
- //Extends mxEventSource
- mxUtils.extend(StorageFile, DrawioFile);
- /**
- * Updates the descriptor of this file with the one from the given file.
- */
- StorageFile.prototype.getEtag = function(data)
- {
- return this.ui.hashValue((data != null) ? data : '');};
- /**
- * Sets the delay for autosave in milliseconds. Default is 1000.
- */
- StorageFile.prototype.autosaveDelay = 500;
- /**
- * Sets the delay for autosave in milliseconds. Default is 20000.
- */
- StorageFile.prototype.maxAutosaveDelay = 20000;
- /**
- * Maximum number if attempts to automatically catchup on save.
- */
- StorageFile.prototype.maxRetries = 5;
- /**
- * A differentiator of the stored object type (file or lib)
- */
- StorageFile.prototype.type = 'F';
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.getMode = function()
- {
- return App.MODE_BROWSER;
- };
- /**
- * Overridden to enable the autosave option in the document properties dialog.
- */
- StorageFile.prototype.isSyncSupported = function()
- {
- return true
- };
- /**
- * Overridden to enable the autosave option in the document properties dialog.
- */
- StorageFile.prototype.isPolling = function()
- {
- return this.isSyncSupported();
- };
- /**
- * Overridden to enable the autosave option in the document properties dialog.
- */
- StorageFile.prototype.getPollingInterval = function()
- {
- return 10000;
- };
- /**
- * Hook for subclassers to get the latest descriptor of this file
- * and return it in the success handler.
- */
- StorageFile.prototype.loadDescriptor = function(success, error)
- {
- this.getLatestVersionId(success, error);
- };
- /**
- * Hook for subclassers to get the latest version ID of this file
- * and return it in the success handler.
- */
- StorageFile.prototype.getLatestVersionId = function(success, error)
- {
- StorageFile.getFileContent(this.ui, this.title, mxUtils.bind(this, function(data)
- {
- success(this.getEtag(data));
- }), error);
- };
- /**
- * Overridden to enable the autosave option in the document properties dialog.
- */
- StorageFile.prototype.isAutosaveOptional = function()
- {
- return true;
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.getHash = function()
- {
- return 'L' + encodeURIComponent(this.getTitle());
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.getTitle = function()
- {
- return this.title;
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.isRenamable = function()
- {
- return true;
- };
- /**
- * Adds all listeners.
- */
- StorageFile.prototype.getDescriptor = function()
- {
- return this.etag;
- };
- /**
- * Updates the descriptor of this file with the one from the given file.
- */
- StorageFile.prototype.setDescriptor = function(etag)
- {
- this.etag = etag;
- };
- /**
- * Returns the etag from the given descriptor.
- */
- StorageFile.prototype.getDescriptorEtag = function(desc)
- {
- return desc;
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.save = function(revision, success, error)
- {
- this.saveAs(this.getTitle(), success, error);
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.saveAs = function(title, success, error)
- {
- DrawioFile.prototype.save.apply(this, [false, mxUtils.bind(this, function()
- {
- this.saveFile(this.getTitle(), false, success, error);
- }), error]);
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.insertFile = function(ui, title, data, success, error, file)
- {
- StorageFile.doInsertFile((file != null) ? file :
- new StorageFile(ui, data, title), success, error);
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.doInsertFile = function(file, success, error)
- {
- var title = file.getTitle();
- var ui = file.getUi();
- var createStorageFile = mxUtils.bind(this, function(exists)
- {
- var fn = function()
- {
- file.writeFile(title, function()
- {
- success(file);
- }, error);
- };
- if (exists)
- {
- ui.confirm(mxResources.get('replaceIt', [title]), fn, error);
- }
- else
- {
- fn();
- }
- });
-
- StorageFile.getFileContent(ui, title, function(data)
- {
- createStorageFile(data != null);
- }, function()
- {
- createStorageFile(false);
- });
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.getFileContent = function(ui, title, success, error)
- {
- ui.getDatabaseItem(title, function(obj)
- {
- success(obj != null? obj.data : null);
- },
- mxUtils.bind(this, function()
- {
- if (ui.database == null) //fallback to localstorage
- {
- ui.getLocalData(title, success);
- }
- else if (error != null)
- {
- error();
- }
- }), 'files');
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.getFileInfo = function(ui, title, success, error)
- {
- ui.getDatabaseItem(title, function(obj)
- {
- success(obj);
- },
- mxUtils.bind(this, function()
- {
- if (ui.database == null) //fallback to localstorage
- {
- ui.getLocalData(title, function(data)
- {
- success(data != null? {title: title} : null);
- });
- }
- else if (error != null)
- {
- error();
- }
- }), 'filesInfo');
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.saveFile = function(title, revision, success, error, retry)
- {
- retry = (retry != null) ? retry : 0;
- if (!this.isEditable())
- {
- if (success != null)
- {
- success();
- }
- }
- else
- {
- var fn = mxUtils.bind(this, function()
- {
- this.writeFile(title, success, error);
- });
-
- // Checks for trailing dots
- if (this.isRenamable() && title.charAt(0) == '.' && error != null)
- {
- error({message: mxResources.get('invalidName')});
- }
- else if (this instanceof StorageLibrary)
- {
- fn(); // No need to check for conflicts with libraries
- }
- else
- {
- StorageFile.getFileInfo(this.ui, title, mxUtils.bind(this, function(data)
- {
- if (!this.isRenamable() || this.getTitle() == title || data == null)
- {
- this.getLatestVersion(mxUtils.bind(this, function(file)
- {
- if (file.getDescriptor() != this.getDescriptor())
- {
- EditorUi.debug('StorageFile.saveFile',
- [this], 'conflict', [file]);
- this.mergeFile(file, mxUtils.bind(this, function()
- {
- if (retry >= this.maxRetries ||
- this.invalidChecksum ||
- this.inConflictState)
- {
- this.inConflictState = true;
- if (error != null)
- {
- error();
- }
- }
- else
- {
- this.retrySave(mxUtils.bind(this, function()
- {
- this.updateFileData();
- this.saveFile(title, revision,
- success, error, retry + 1);
- }));
- }
- }), error);
- }
- else
- {
- fn();
- }
- }), error);
- }
- else
- {
- this.ui.confirm(mxResources.get('replaceIt', [title]), fn, error);
- }
- }), error);
- }
- }
- EditorUi.debug('StorageFile.saveFile', [this], 'title', title,
- 'revision', revision, 'retry', retry);
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.retrySave = function(fn)
- {
- var delay = 300 + Math.random() * 300;
- window.setTimeout(fn, delay);
-
- EditorUi.debug('StorageFile.retrySave', [this], 'delay', delay);
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.writeFile = function(title, success, error)
- {
- if (this.isRenamable())
- {
- this.title = title;
- }
-
- try
- {
- var desc = this.getDescriptor();
- var data = this.getData();
- var saveDone = mxUtils.bind(this, function()
- {
- this.setModified(this.getShadowModified());
- this.setDescriptor(this.getEtag(data));
- this.contentChanged();
- this.fileSaved(data, desc, success, error);
- });
-
- this.setShadowModified(false);
- this.ui.setDatabaseItem(null, [{
- title: this.title,
- size: data.length,
- lastModified: Date.now(),
- type: this.type
- }, {
- title: this.title,
- data: data
- }], saveDone, mxUtils.bind(this, function()
- {
- if (this.ui.database == null) //fallback to localstorage
- {
- try
- {
- this.ui.setLocalData(this.title, data, saveDone);
- }
- catch (e)
- {
- if (error != null)
- {
- error(e);
- }
- }
- }
- else if (error != null)
- {
- error();
- }
- }), ['filesInfo', 'files']);
- }
- catch (e)
- {
- if (error != null)
- {
- error(e);
- }
- }
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.prototype.rename = function(title, success, error)
- {
- var oldTitle = this.getTitle();
- if (oldTitle != title)
- {
- StorageFile.getFileInfo(this.ui, title, mxUtils.bind(this, function(data)
- {
- var fn = mxUtils.bind(this, function()
- {
- this.title = title;
-
- // Updates the data if the extension has changed
- if (!this.hasSameExtension(oldTitle, title))
- {
- this.setData(this.ui.getFileData());
- }
-
- this.saveFile(title, false, mxUtils.bind(this, function()
- {
- this.ui.removeLocalData(oldTitle, success);
- }), error);
- });
-
- if (data != null)
- {
- this.ui.confirm(mxResources.get('replaceIt', [title]), fn, error);
- }
- else
- {
- fn();
- }
- }), error);
- }
- else
- {
- success();
- }
- };
- /**
- * Adds the listener for automatically saving the diagram for local changes.
- */
- StorageFile.prototype.getLatestVersion = function(success, error)
- {
- StorageFile.getFileContent(this.ui, this.title, mxUtils.bind(this, function(data)
- {
- success(new StorageFile(this.ui, data, this.title));
- }), error);
- };
- /**
- * Stops any pending autosaves and removes all listeners.
- */
- StorageFile.prototype.destroy = function()
- {
- DrawioFile.prototype.destroy.apply(this, arguments);
-
- if (this.storageListener != null)
- {
- mxEvent.removeListener(window, 'storage', this.storageListener);
- this.storageListener = null;
- }
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.listLocalStorageFiles = function(type)
- {
- var filesInfo = [];
-
- for (var i = 0; i < localStorage.length; i++)
- {
- var key = localStorage.key(i);
- var value = localStorage.getItem(key);
-
- if (key.length > 0 && key.charAt(0) != '.' && value.length > 0)
- {
- var isFile = (type == null || type == 'F') && (value.substring(0, 8) === '<mxfile ' ||
- value.substring(0, 5) === '<?xml' || value.substring(0, 12) === '<!--[if IE]>');
- var isLib = (type == null || type == 'L') && (value.substring(0, 11) === '<mxlibrary>');
- if (isFile || isLib)
- {
- filesInfo.push({
- title: key,
- type: isFile? 'F' : 'L',
- size: value.length,
- lastModified: Date.now()
- });
- }
- }
- }
-
- return filesInfo;
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.migrate = function(db)
- {
- var lsFilesInfo = StorageFile.listLocalStorageFiles();
- lsFilesInfo.push({title: '.scratchpad', type: 'L'}); //Adding scratchpad also since it is a library (storage file)
- var tx = db.transaction(['files', 'filesInfo'], 'readwrite');
- var files = tx.objectStore('files');
- var filesInfo = tx.objectStore('filesInfo');
-
- for (var i = 0; i < lsFilesInfo.length; i++)
- {
- var lsFileInfo = lsFilesInfo[i];
- var data = localStorage.getItem(lsFileInfo.title);
- files.add({
- title: lsFileInfo.title,
- data: data
- });
- filesInfo.add(lsFileInfo);
- }
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.listFiles = function(ui, type, success, error)
- {
- ui.getDatabaseItems(function(filesInfo)
- {
- var files = [];
-
- if (filesInfo != null)
- {
- for (var i = 0; i < filesInfo.length; i++)
- {
- if (filesInfo[i].title.charAt(0) != '.' && (type == null || filesInfo[i].type == type))
- {
- files.push(filesInfo[i]);
- }
- }
- }
-
- success(files);
- }, function()
- {
- if (ui.database == null) //fallback to localstorage
- {
- success(StorageFile.listLocalStorageFiles(type));
- }
- else if (error != null)
- {
- error();
- }
- }, 'filesInfo');
- };
- /**
- * Translates this point by the given vector.
- *
- * @param {number} dx X-coordinate of the translation.
- * @param {number} dy Y-coordinate of the translation.
- */
- StorageFile.deleteFile = function(ui, title, success, error)
- {
- ui.removeDatabaseItem([title, title], success, function()
- {
- if (ui.database == null) //fallback to localstorage
- {
- localStorage.removeItem(title)
- success();
- }
- else if (error != null)
- {
- error();
- }
- }, ['files', 'filesInfo']);
- };
|