You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

578 lines
16 KiB

/**
* 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();
});