| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- /**
- * Plugin for embed mode in Nextcloud
- */
- Draw.loadPlugin(function(ui)
- {
- var loadDescriptor = null;
- var ncUser = null;
-
- mxEvent.addListener(window, 'message', mxUtils.bind(this, function(evt)
- {
- var data = evt.data;
- try
- {
- data = JSON.parse(data);
-
- if (data.action == 'load')
- {
- if (data.desc != null)
- {
- loadDescriptor = data.desc;
- }
- if (data.disableAutoSave)
- {
- ui.editor.setAutosave(false);
- }
- }
- }
- catch (e)
- {
- // Ignore
- }
- }));
- ui.getCurrentUser = function()
- {
- if (ncUser == null)
- {
- ui.remoteInvoke('getCurrentUser', null, null, function(user)
- {
- ncUser = user == null? new DrawioUser(Date.now(), null, 'Anonymous')
- : new DrawioUser(user.uid, null, user.displayName);
- }, function()
- {
- //ignore such that next call we retry
- });
-
- //Return a dummy user until we have the actual user in order for UI to be populated
- return new DrawioUser(Date.now(), null, 'Anonymous');
- }
-
- return ncUser;
- };
- //======================== Revisions ========================
-
- ui.isRevisionHistoryEnabled = function()
- {
- var file = ui.getCurrentFile();
- return file && file.desc && (!file.desc.ver || file.desc.versionsEnabled);
- };
-
- ui.isRevisionHistorySupported = function()
- {
- return ui.isRevisionHistoryEnabled();
- };
- /**
- * Get revisions of current file
- */
- ui.getRevisions = function(success, error)
- {
- var desc = ui.getCurrentFile().desc;
- var id = desc.ver > 1? desc.id : desc.path;
- function getXml(success, error)
- {
- ui.remoteInvoke('loadFileVersion', [id, this.revId], null, success, error);
- };
-
- function restoreFn(xml)
- {
- if (ui.spinner.spin(document.body, mxResources.get('restoring')))
- {
- ui.tryAndHandle(function()
- {
- ui.replaceFileData(xml);
- ui.spinner.stop();
- ui.hideDialog();
- });
- }
- };
-
- ui.remoteInvoke('getFileRevisions', [id], null, function(revisions)
- {
- revisions.sort(function(a, b)
- {
- return a.timestamp - b.timestamp;
- });
- //convert to editor format and add getXml function
- var revs = [];
-
- for (var i = 0; i < revisions.length; i++)
- {
- var rev = revisions[i];
- rev.modifiedDate = rev.timestamp * 1000;
- rev.getXml = mxUtils.bind(rev, getXml);
- revs.push(rev);
- }
-
- success(revs, restoreFn);
- }, error);
- };
-
- //============= Embed File with real-time collab support =================
- // Use optimistic sync since we cannot save file properties/metadata so far
-
- /**
- * Shorter autosave delay for optimistic sync.
- */
- EmbedFile.prototype.autosaveDelay = 500;
- /**
- * Delay for last save in ms.
- */
- EmbedFile.prototype.saveDelay = 0;
-
- /**
- *
- */
- EmbedFile.prototype.isConflict = function(err)
- {
- return err != null && err.status == 409;
- };
- /**
- * Returns the current user.
- */
- EmbedFile.prototype.getCurrentUser = function()
- {
- return ui.getCurrentUser();
- };
- EmbedFile.prototype.isRealtimeSupported = function()
- {
- return true;
- };
-
- /**
- *
- */
- EmbedFile.prototype.save = function(revision, success, error, unloading, overwrite)
- {
- this.saveStarted = true;
-
- DrawioFile.prototype.save.apply(this, [revision, mxUtils.bind(this, function()
- {
- this.saveFile(null, revision, success, error, unloading, overwrite);
- this.saveStarted = false;
- }), error, unloading, overwrite]);
- };
- /**
- *
- */
- EmbedFile.prototype.setModified = function(value)
- {
- DrawioFile.prototype.setModified.apply(this, arguments);
-
- //Set editor modified also to prevent accidental closure or exiting without saving
- ui.editor.modified = value;
- };
-
- /**
- *
- */
- EmbedFile.prototype.saveFile = function(title, revision, success, error, unloading, overwrite)
- {
- EditorUi.debug('EmbedFile.saveFile', [this], 'saving', this.savingFile);
- try
- {
- if (!this.isEditable())
- {
- if (success != null)
- {
- success();
- }
- }
- else if (!this.savingFile)
- {
- // Sets shadow modified state during save
- this.savingFileTime = new Date();
- this.setShadowModified(false);
- this.savingFile = true;
- var doSave = mxUtils.bind(this, function()
- {
- try
- {
- var lastDesc = this.desc;
- var savedData = this.getData();
- var etag = this.getCurrentEtag();
-
- if (this.sync != null)
- {
- this.sync.fileSaving();
- }
- ui.remoteInvoke('saveFile', this.desc.ver > 1? [this.desc.id, this.desc.shareToken, savedData, etag] :
- [this.desc.path, savedData, etag], null, mxUtils.bind(this, function(resp)
- {
- try
- {
- // Checks for changes during save
- this.setModified(this.getShadowModified());
- this.savingFile = false;
- this.desc = Object.assign({}, this.desc); // Clone the object
- Object.assign(this.desc, resp); // Assign the new values
-
- this.fileSaved(savedData, lastDesc, mxUtils.bind(this, function()
- {
- this.contentChanged();
-
- if (success != null)
- {
- success();
- }
- }), error);
- }
- catch (e)
- {
- this.savingFile = false;
-
- if (error != null)
- {
- error(e);
- }
- else
- {
- throw e;
- }
- }
- }),
- mxUtils.bind(this, function(err)
- {
- try
- {
- this.savingFile = false;
-
- if (this.isConflict(err))
- {
- this.inConflictState = true;
-
- if (this.sync != null)
- {
- this.savingFile = true;
-
- this.sync.fileConflict(null, mxUtils.bind(this, function()
- {
- // Adds random cool-off
- var delay = 100 + Math.random() * 500;
- window.setTimeout(mxUtils.bind(this, function()
- {
- this.updateFileData();
- doSave();
- }), delay);
- EditorUi.debug('EmbedFile.saveFile.conflict',
- [this], 'err', err, 'delay', delay);
- }), mxUtils.bind(this, function()
- {
- this.savingFile = false;
-
- if (error != null)
- {
- error();
- }
- }));
- }
- else if (error != null)
- {
- error();
- }
- }
- else if (error != null)
- {
- error(err);
- }
- }
- catch (e)
- {
- this.savingFile = false;
-
- if (error != null)
- {
- error(e);
- }
- else
- {
- throw e;
- }
- }
- }));
- }
- catch (e)
- {
- this.savingFile = false;
-
- if (error != null)
- {
- error(e);
- }
- else
- {
- throw e;
- }
- }
- });
-
- doSave();
- }
- }
- catch (e)
- {
- if (error != null)
- {
- error(e);
- }
- else
- {
- throw e;
- }
- }
- };
- /**
- *
- */
- EmbedFile.prototype.getTitle = function()
- {
- return this.desc.name;
- };
- /**
- *
- */
- EmbedFile.prototype.getHash = function()
- {
- return 'E' + this.getId();
- };
- /**
- * Overridden to enable the autosave option in the document properties dialog.
- */
- EmbedFile.prototype.isAutosaveOptional = function()
- {
- return true;
- };
- /**
- *
- */
- EmbedFile.prototype.getId = function()
- {
- return this.desc.instanceId + '$$' + this.desc.id;
- };
- /**
- *
- */
- EmbedFile.prototype.isSyncSupported = function()
- {
- return this.desc != null && this.desc.id != null && this.desc.instanceId != null;
- };
- /**
- *
- */
- EmbedFile.prototype.isRevisionHistorySupported = function()
- {
- return true;
- };
- EmbedFile.prototype.isOptimisticSync = function()
- {
- return true;
- };
- EmbedFile.prototype.getSize = function()
- {
- return this.desc.size;
- };
- EmbedFile.prototype.isEditable = function()
- {
- return this.desc != null && this.desc.writeable;
- };
- /**
- *
- */
- EmbedFile.prototype.getLatestVersion = function(success, error)
- {
- ui.remoteInvoke('loadFile', this.desc.ver > 1? [this.desc.id, this.desc.shareToken] : [this.desc.path],
- null, mxUtils.bind(this, function(data)
- {
- var xml = data.xml;
- delete data.xml;
- success(new EmbedFile(ui, xml, data));
- }), error);
- };
- /**
- * Gets the channel ID from the given descriptor.
- */
- EmbedFile.prototype.getChannelId = function()
- {
- return 'C-' + DrawioFile.prototype.getChannelId.apply(this, arguments);
- };
- EmbedFile.prototype.getHash = function()
- {
- return 'C' + encodeURIComponent(this.getId());
- };
- /**
- * Using MD5 of create timestamp and user ID as crypto key.
- */
- EmbedFile.prototype.getChannelKey = function()
- {
- if (typeof CryptoJS !== 'undefined')
- {
- return CryptoJS.MD5(this.desc.instanceId + this.desc.id).toString();
- }
-
- return null;
- };
- /**
- *
- */
- EmbedFile.prototype.getLastModifiedDate = function()
- {
- return new Date(this.desc.mtime * 1000);
- };
- /**
- *
- */
- EmbedFile.prototype.getDescriptor = function()
- {
- return this.desc;
- };
- /**
- * Updates the descriptor of this file with the one from the given file.
- */
- EmbedFile.prototype.setDescriptor = function(desc)
- {
- this.desc = desc;
- };
- /**
- *
- */
- EmbedFile.prototype.getDescriptorEtag = function(desc)
- {
- return desc.etag;
- };
- /**
- *
- */
- EmbedFile.prototype.setDescriptorEtag = function(desc, etag)
- {
- desc.etag = etag;
- };
- /**
- *
- */
- EmbedFile.prototype.loadDescriptor = function(success, error)
- {
- ui.remoteInvoke('getFileInfo', this.desc.ver > 1? [this.desc.id, this.desc.shareToken] : [this.desc.path], null, success, error);
- };
-
- var allowAutoSave = true;
-
- EmbedFile.prototype.isAutosaveNow = function(success, error)
- {
- return allowAutoSave;
- };
-
- //Ensure saving is via the file
- ui.actions.get('save').funct = function(exit)
- {
- if (ui.editor.graph.isEditing())
- {
- ui.editor.graph.stopEditing();
- }
- var curFile = ui.getCurrentFile();
-
- if (exit)
- {
- allowAutoSave = false;
- }
- function doActions()
- {
- if (exit)
- {
- ui.actions.get('exit').funct();
- }
- };
-
- function doSave()
- {
- if (curFile.saveStarted || curFile.savingFile)
- {
- setTimeout(doSave, 100);
- return;
- }
-
- if (curFile.isModified())
- {
- ui.saveFile(null, doActions);
- }
- else
- {
- doActions();
- }
- };
-
- doSave();
- };
- //Add file opening here (or it should be for all in EditorUi?)
- var origInstallMessageHandler = ui.installMessageHandler;
-
- ui.installMessageHandler = function(callback)
- {
- origInstallMessageHandler.call(this, function(xml, evt)
- {
- try
- {
- // New empty files
- if (JSON.parse(evt.data).xml == ' ') return;
- }
- catch (e) {} // Ignore
- callback.apply(this, arguments);
-
- var file = ui.getCurrentFile();
- loadDescriptor = loadDescriptor || {};
- // New files call this twice, so we need to check if the file is loaded
- if (!loadDescriptor.isLoaded)
- {
- loadDescriptor.isLoaded = true;
- file.setDescriptor(loadDescriptor);
- ui.fileLoaded(file, true);
- }
- });
- }
-
- ui.editor.setModified = function()
- {
- //Cancel set modified of the editor and use the file's one
- };
- //Prefetch current user
- ui.getCurrentUser();
- });
|