drawio-offline
Version:
diagrams.net desktop
1,661 lines (1,476 loc) • 208 kB
JavaScript
/**
* Copyright (c) 2006-2020, JGraph Ltd
* Copyright (c) 2006-2020, draw.io AG
*/
/**
* 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.
*/
App = function(editor, container, lightbox)
{
EditorUi.call(this, editor, container, (lightbox != null) ? lightbox :
(urlParams['lightbox'] == '1' || (uiTheme == 'min' &&
urlParams['chrome'] != '0')));
// Logs unloading of window with modifications for Google Drive file
if (!mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp)
{
window.onunload = mxUtils.bind(this, function()
{
var file = this.getCurrentFile();
if (file != null && file.isModified())
{
var evt = {category: 'DISCARD-FILE-' + file.getHash(),
action: ((file.savingFile) ? 'saving' : '') +
((file.savingFile && file.savingFileTime != null) ? '_' +
Math.round((Date.now() - file.savingFileTime.getTime()) / 1000) : '') +
((file.saveLevel != null) ? ('-sl_' + file.saveLevel) : '') +
'-age_' + ((file.ageStart != null) ? Math.round((Date.now() - file.ageStart.getTime()) / 1000) : 'x') +
((this.editor.autosave) ? '' : '-nosave') +
((file.isAutosave()) ? '' : '-noauto') +
'-open_' + ((file.opened != null) ? Math.round((Date.now() - file.opened.getTime()) / 1000) : 'x') +
'-save_' + ((file.lastSaved != null) ? Math.round((Date.now() - file.lastSaved.getTime()) / 1000) : 'x') +
'-change_' + ((file.lastChanged != null) ? Math.round((Date.now() - file.lastChanged.getTime()) / 1000) : 'x') +
'-alive_' + Math.round((Date.now() - App.startTime.getTime()) / 1000),
label: (file.sync != null) ? ('client_' + file.sync.clientId) : 'nosync'};
if (file.constructor == DriveFile && file.desc != null && this.drive != null)
{
evt.label += ((this.drive.user != null) ? ('-user_' + this.drive.user.id) : '-nouser') + '-rev_' +
file.desc.headRevisionId + '-mod_' + file.desc.modifiedDate + '-size_' + file.getSize() +
'-mime_' + file.desc.mimeType;
}
EditorUi.logEvent(evt);
}
});
}
// Logs changes to autosave
this.editor.addListener('autosaveChanged', mxUtils.bind(this, function()
{
var file = this.getCurrentFile();
if (file != null)
{
EditorUi.logEvent({category: ((this.editor.autosave) ? 'ON' : 'OFF') +
'-AUTOSAVE-FILE-' + file.getHash(), action: 'changed',
label: 'autosave_' + ((this.editor.autosave) ? 'on' : 'off')});
}
}));
// Pre-fetches images
if (mxClient.IS_SVG)
{
mxGraph.prototype.warningImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAE7SURBVHjaYvz//z8DJQAggBjwGXDuHMP/tWuD/uPTCxBAOA0AaQRK/f/+XeJ/cbHlf1wGAAQQTgPu3QNLgfHSpZo4DQAIIKwGwGyH4e/fFbG6AiQJEEAs2Ew2NFzH8OOHBMO6dT/A/KCg7wxGRh+wuhQggDBcALMdFIAcHBxgDGJjcwVIIUAAYbhAUXEdVos4OO4DXcGBIQ4QQCguQPY7sgtgAYruCpAgQACx4LJdU1OCwctLEcyWlLwPJF+AXQE0EMUBAAEEdwF6yMOiD4RRY0QT7gqQAEAAseDzu6XldYYPH9DD4joQa8L5AAEENgWb7SBcXa0JDQMBrK4AcQACiAlfyOMCEFdAnAYQQEz4FLa0XGf4/v0H0IIPONUABBAjyBmMjIwMS5cK/L927QORbtBkaG29DtYLEGAAH6f7oq3Zc+kAAAAASUVORK5CYII=';
}
else
{
var img = new Image();
img.src = mxGraph.prototype.warningImage.src;
}
// Global helper method to deal with popup blockers
window.openWindow = mxUtils.bind(this, function(url, pre, fallback)
{
if (urlParams['openInSameWin'] == '1')
{
fallback();
return;
}
var wnd = null;
try
{
wnd = window.open(url);
}
catch (e)
{
// ignore
}
if (wnd == null || wnd === undefined)
{
this.showDialog(new PopupDialog(this, url, pre, fallback).container, 320, 140, true, true);
}
else if (pre != null)
{
pre();
}
});
// Initial state for toolbar items is disabled
this.updateDocumentTitle();
this.updateUi();
// Global helper method to display error messages
window.showOpenAlert = mxUtils.bind(this, function(message)
{
// Cancel must be called before showing error message
if (window.openFile != null)
{
window.openFile.cancel(true);
}
this.handleError(message);
});
// Handles opening files via drag and drop
if (!this.editor.chromeless || this.editor.editable)
{
this.addFileDropHandler([document]);
}
// Process the queue for waiting plugins
if (App.DrawPlugins != null)
{
for (var i = 0; i < App.DrawPlugins.length; i++)
{
try
{
App.DrawPlugins[i](this);
}
catch (e)
{
if (window.console != null)
{
console.log('Plugin Error:', e, App.DrawPlugins[i]);
}
}
finally
{
App.embedModePluginsCount--;
this.initializeEmbedMode();
}
}
// Installs global callback for plugins
window.Draw.loadPlugin = mxUtils.bind(this, function(callback)
{
try
{
callback(this);
}
finally
{
App.embedModePluginsCount--;
this.initializeEmbedMode();
}
});
//Set a timeout in case a plugin doesn't load quickly or doesn't load at all
setTimeout(mxUtils.bind(this, function()
{
//Force finish loading if its not yet called
if (App.embedModePluginsCount > 0)
{
App.embedModePluginsCount = 0;
this.initializeEmbedMode();
}
}), 5000); //5 sec timeout
}
this.load();
};
/**
* Timeout error
*/
App.ERROR_TIMEOUT = 'timeout';
/**
* Busy error
*/
App.ERROR_BUSY = 'busy';
/**
* Unknown error
*/
App.ERROR_UNKNOWN = 'unknown';
/**
* Google drive mode
*/
App.MODE_GOOGLE = 'google';
/**
* Dropbox mode
*/
App.MODE_DROPBOX = 'dropbox';
/**
* OneDrive Mode
*/
App.MODE_ONEDRIVE = 'onedrive';
/**
* Github Mode
*/
App.MODE_GITHUB = 'github';
/**
* Gitlab mode
*/
App.MODE_GITLAB = 'gitlab';
/**
* Device Mode
*/
App.MODE_DEVICE = 'device';
/**
* Browser Mode
*/
App.MODE_BROWSER = 'browser';
/**
* Trello App Mode
*/
App.MODE_TRELLO = 'trello';
/**
* Embed App Mode
*/
App.MODE_EMBED = 'embed';
/**
* Sets the delay for autosave in milliseconds. Default is 2000.
*/
App.DROPBOX_APPKEY = window.DRAWIO_DROPBOX_ID;
/**
* Sets URL to load the Dropbox SDK from
*/
App.DROPBOX_URL = window.DRAWIO_BASE_URL + '/js/dropbox/Dropbox-sdk.min.js';
/**
* Sets URL to load the Dropbox dropins JS from.
*/
App.DROPINS_URL = 'https://www.dropbox.com/static/api/2/dropins.js';
/**
* OneDrive Client JS (file/folder picker). This is a slightly modified version to allow using accessTokens
* But it doesn't work for IE11, so we fallback to the original one
*/
App.ONEDRIVE_URL = mxClient.IS_IE11? 'https://js.live.net/v7.2/OneDrive.js' : window.DRAWIO_BASE_URL + '/js/onedrive/OneDrive.js';
App.ONEDRIVE_INLINE_PICKER_URL = window.DRAWIO_BASE_URL + '/js/onedrive/mxODPicker.js';
/**
* Trello URL
*/
App.TRELLO_URL = 'https://api.trello.com/1/client.js';
/**
* Trello JQuery dependency
*/
App.TRELLO_JQUERY_URL = 'https://code.jquery.com/jquery-1.7.1.min.js';
/**
* Specifies the key for the pusher project.
*/
App.PUSHER_KEY = '1e756b07a690c5bdb054';
/**
* Specifies the key for the pusher project.
*/
App.PUSHER_CLUSTER = 'eu';
/**
* Specifies the URL for the pusher API.
*/
App.PUSHER_URL = 'https://js.pusher.com/4.3/pusher.min.js';
/**
* Socket.io library
*/
App.SOCKET_IO_URL = window.DRAWIO_BASE_URL + '/js/socket.io/socket.io.min.js';
App.SIMPLE_PEER_URL = window.DRAWIO_BASE_URL + '/js/socket.io/simplepeer9.10.0.min.js';
App.SOCKET_IO_SRV = 'http://localhost:3030';
/**
* Google APIs to load. The realtime API is needed to notify collaborators of conversion
* of the realtime files, but after Dec 11 it's read-only and hence no longer needed.
*/
App.GOOGLE_APIS = 'drive-share';
/**
* Function: authorize
*
* Authorizes the client, gets the userId and calls <open>.
*/
App.startTime = new Date();
/**
* Defines plugin IDs for loading via p URL parameter. Update the table at
* https://www.diagrams.net/doc/faq/supported-url-parameters
*/
App.pluginRegistry = {'4xAKTrabTpTzahoLthkwPNUn': 'plugins/explore.js',
'ex': 'plugins/explore.js', 'p1': 'plugins/p1.js',
'ac': 'plugins/connect.js', 'acj': 'plugins/connectJira.js',
'ac148': 'plugins/cConf-1-4-8.js', 'ac148cmnt': 'plugins/cConf-comments.js',
'voice': 'plugins/voice.js',
'tips': 'plugins/tooltips.js', 'svgdata': 'plugins/svgdata.js',
'electron': 'plugins/electron.js',
'number': 'plugins/number.js', 'sql': 'plugins/sql.js',
'props': 'plugins/props.js', 'text': 'plugins/text.js',
'anim': 'plugins/animation.js', 'update': 'plugins/update.js',
'trees': 'plugins/trees/trees.js', 'import': 'plugins/import.js',
'replay': 'plugins/replay.js', 'anon': 'plugins/anonymize.js',
'tr': 'plugins/trello.js', 'f5': 'plugins/rackF5.js',
'tickets': 'plugins/tickets.js', 'flow': 'plugins/flow.js',
'webcola': 'plugins/webcola/webcola.js', 'rnd': 'plugins/random.js',
'page': 'plugins/page.js', 'gd': 'plugins/googledrive.js',
'tags': 'plugins/tags.js'};
App.publicPlugin = [
'ex',
'voice',
'tips',
'svgdata',
'number',
'sql',
'props',
'text',
'anim',
'update',
'trees',
// 'import',
'replay',
'anon',
'tickets',
'flow',
'webcola',
// 'rnd', 'page', 'gd',
'tags'
];
/**
* Loads all given scripts and invokes onload after
* all scripts have finished loading.
*/
App.loadScripts = function(scripts, onload)
{
var n = scripts.length;
for (var i = 0; i < n; i++)
{
mxscript(scripts[i], function()
{
if (--n == 0 && onload != null)
{
onload();
}
});
}
};
/**
* Function: getStoredMode
*
* Returns the current mode.
*/
App.getStoredMode = function()
{
var mode = null;
if (mode == null && isLocalStorage)
{
mode = localStorage.getItem('.mode');
}
if (mode == null && typeof(Storage) != 'undefined')
{
var cookies = document.cookie.split(";");
for (var i = 0; i < cookies.length; i++)
{
// Removes spaces around cookie
var cookie = mxUtils.trim(cookies[i]);
if (cookie.substring(0, 5) == 'MODE=')
{
mode = cookie.substring(5);
break;
}
}
if (mode != null && isLocalStorage)
{
// Moves to local storage
var expiry = new Date();
expiry.setYear(expiry.getFullYear() - 1);
document.cookie = 'MODE=; expires=' + expiry.toUTCString();
localStorage.setItem('.mode', mode);
}
}
return mode;
};
/**
* Static Application initializer executed at load-time.
*/
(function()
{
if (!mxClient.IS_CHROMEAPP)
{
if (urlParams['offline'] != '1')
{
// Switches to dropbox mode for db.draw.io
if (window.location.hostname == 'db.draw.io' && urlParams['mode'] == null)
{
urlParams['mode'] = 'dropbox';
}
App.mode = urlParams['mode'];
}
if (App.mode == null)
{
// Stored mode overrides preferred mode
App.mode = App.getStoredMode();
}
/**
* Lazy loading backends.
*/
if (window.mxscript != null)
{
// Loads gapi for all browsers but IE8 and below if not disabled or if enabled and in embed mode
if (urlParams['embed'] != '1')
{
if (typeof window.DriveClient === 'function')
{
if (urlParams['gapi'] != '0' && isSvgBrowser &&
(document.documentMode == null || document.documentMode >= 10))
{
// Immediately loads client
if (App.mode == App.MODE_GOOGLE || (urlParams['state'] != null &&
window.location.hash == '') || (window.location.hash != null &&
window.location.hash.substring(0, 2) == '#G'))
{
mxscript('https://apis.google.com/js/api.js');
}
// Keeps lazy loading for fallback to authenticated Google file if not public in loadFile
else if (urlParams['chrome'] == '0' && (window.location.hash == null ||
window.location.hash.substring(0, 45) !== '#Uhttps%3A%2F%2Fdrive.google.com%2Fuc%3Fid%3D'))
{
// Disables loading of client
window.DriveClient = null;
}
}
else
{
// Disables loading of client
window.DriveClient = null;
}
}
// Loads dropbox for all browsers but IE8 and below (no CORS) if not disabled or if enabled and in embed mode
// KNOWN: Picker does not work in IE11 (https://dropbox.zendesk.com/requests/1650781)
if (typeof window.DropboxClient === 'function')
{
if (urlParams['db'] != '0' && isSvgBrowser &&
(document.documentMode == null || document.documentMode > 9))
{
// Immediately loads client
if (App.mode == App.MODE_DROPBOX || (window.location.hash != null &&
window.location.hash.substring(0, 2) == '#D'))
{
mxscript(App.DROPBOX_URL, function()
{
// Must load this after the dropbox SDK since they use the same namespace
mxscript(App.DROPINS_URL, null, 'dropboxjs', App.DROPBOX_APPKEY, true);
});
}
else if (urlParams['chrome'] == '0')
{
window.DropboxClient = null;
}
}
else
{
// Disables loading of client
window.DropboxClient = null;
}
}
// Loads OneDrive for all browsers but IE6/IOS if not disabled or if enabled and in embed mode
if (typeof window.OneDriveClient === 'function')
{
if (urlParams['od'] != '0' && (navigator.userAgent == null ||
navigator.userAgent.indexOf('MSIE') < 0 || document.documentMode >= 10))
{
// Immediately loads client
if (App.mode == App.MODE_ONEDRIVE || (window.location.hash != null &&
window.location.hash.substring(0, 2) == '#W'))
{
if (urlParams['inlinePicker'] == '1' || mxClient.IS_ANDROID || mxClient.IS_IOS)
{
mxscript(App.ONEDRIVE_INLINE_PICKER_URL, function()
{
window.OneDrive = {}; //Needed to allow code that check its existance to work BUT it's not used
});
}
else
{
mxscript(App.ONEDRIVE_URL);
}
}
else if (urlParams['chrome'] == '0')
{
window.OneDriveClient = null;
}
}
else
{
// Disables loading of client
window.OneDriveClient = null;
}
}
// Loads Trello for all browsers but < IE10 if not disabled or if enabled and in embed mode
if (typeof window.TrelloClient === 'function')
{
if (urlParams['tr'] == '1' && isSvgBrowser && !mxClient.IS_IE11 &&
(document.documentMode == null || document.documentMode >= 10))
{
// Immediately loads client
if (App.mode == App.MODE_TRELLO || (window.location.hash != null &&
window.location.hash.substring(0, 2) == '#T'))
{
mxscript(App.TRELLO_JQUERY_URL, function()
{
mxscript(App.TRELLO_URL);
});
}
else if (urlParams['chrome'] == '0')
{
window.TrelloClient = null;
}
}
else
{
// Disables loading of client
window.TrelloClient = null;
}
}
}
}
}
})();
/**
* Clears the PWA cache.
*/
App.clearServiceWorker = function(success)
{
navigator.serviceWorker.getRegistrations().then(function(registrations)
{
if (registrations != null && registrations.length > 0)
{
for (var i = 0; i < registrations.length; i++)
{
registrations[i].unregister();
}
if (success != null)
{
success();
}
}
});
};
/**
* Program flow starts here.
*
* Optional callback is called with the app instance.
*/
App.main = function(callback, createUi)
{
// Logs uncaught errors
window.onerror = function(message, url, linenumber, colno, err)
{
EditorUi.logError('Global: ' + ((message != null) ? message : ''),
url, linenumber, colno, err, null, true);
};
// Blocks stand-alone mode for certain subdomains
if (window.top == window.self &&
(/ac\.draw\.io$/.test(window.location.hostname) ||
/ac-ent\.draw\.io$/.test(window.location.hostname) ||
/aj\.draw\.io$/.test(window.location.hostname)))
{
document.body.innerHTML = '<div style="margin-top:10%;text-align:center;">Stand-alone mode not allowed for this domain.</div>';
return;
}
// Removes info text in embed mode
if (urlParams['embed'] == '1' || urlParams['lightbox'] == '1')
{
var geInfo = document.getElementById('geInfo');
if (geInfo != null)
{
geInfo.parentNode.removeChild(geInfo);
}
}
// Redirects to the latest AWS icons
if (document.referrer != null && urlParams['libs'] == 'aws3' &&
document.referrer.substring(0, 42) == 'https://aws.amazon.com/architecture/icons/')
{
urlParams['libs'] = 'aws4';
}
if (window.mxscript != null)
{
// Checks for script content changes to avoid CSP errors in production
if (urlParams['dev'] == '1' && CryptoJS != null && App.mode != App.MODE_DROPBOX && App.mode != App.MODE_TRELLO)
{
var scripts = document.getElementsByTagName('script');
// Checks bootstrap script
if (scripts != null && scripts.length > 0)
{
var content = mxUtils.getTextContent(scripts[0]);
if (CryptoJS.MD5(content).toString() != 'b02227617087e21bd49f2faa15164112')
{
console.log('Change bootstrap script MD5 in the previous line:', CryptoJS.MD5(content).toString());
alert('[Dev] Bootstrap script change requires update of CSP');
}
}
// Checks main script
if (scripts != null && scripts.length > 1)
{
var content = mxUtils.getTextContent(scripts[scripts.length - 1]);
if (CryptoJS.MD5(content).toString() != 'd53805dd6f0bbba2da4966491ca0a505')
{
console.log('Change main script MD5 in the previous line:', CryptoJS.MD5(content).toString());
alert('[Dev] Main script change requires update of CSP');
}
}
}
try
{
// Removes PWA cache on www.draw.io to force use of new domain via redirect
if (Editor.enableServiceWorker && (urlParams['offline'] == '0' ||
/www\.draw\.io$/.test(window.location.hostname) ||
(urlParams['offline'] != '1' && urlParams['dev'] == '1')))
{
App.clearServiceWorker(function()
{
if (urlParams['offline'] == '0')
{
alert('Cache cleared');
}
});
}
else if (Editor.enableServiceWorker)
{
// Runs as progressive web app if service workers are supported
navigator.serviceWorker.register('/service-worker.js');
}
}
catch (e)
{
if (window.console != null)
{
console.error(e);
}
}
// Loads Pusher API
if (('ArrayBuffer' in window) && !mxClient.IS_CHROMEAPP && !EditorUi.isElectronApp &&
DrawioFile.SYNC == 'auto' && (urlParams['embed'] != '1' || urlParams['embedRT'] == '1') && urlParams['local'] != '1' &&
(urlParams['chrome'] != '0' || urlParams['rt'] == '1') &&
urlParams['stealth'] != '1' && urlParams['offline'] != '1')
{
// TODO: Check if async loading is fast enough
mxscript(App.PUSHER_URL);
if (urlParams['rtCursors'] == '1')
{
mxscript(App.SOCKET_IO_URL);
mxscript(App.SIMPLE_PEER_URL);
}
}
// Loads plugins
if (urlParams['plugins'] != '0' && urlParams['offline'] != '1')
{
// mxSettings is not yet initialized in configure mode, redirect parameter
// to p URL parameter in caller for plugins in embed mode
var plugins = (mxSettings.settings != null) ? mxSettings.getPlugins() : null;
// Configured plugins in embed mode with configure=1 URL should be loaded so we
// look ahead here and parse the config to fetch the list of custom plugins
if (mxSettings.settings == null && isLocalStorage && typeof(JSON) !== 'undefined')
{
try
{
var temp = JSON.parse(localStorage.getItem(mxSettings.key));
if (temp != null)
{
plugins = temp.plugins;
}
}
catch (e)
{
// ignore
}
}
var temp = urlParams['p'];
App.initPluginCallback();
if (temp != null)
{
// Mapping from key to URL in App.plugins
App.loadPlugins(temp.split(';'));
}
if (plugins != null && plugins.length > 0 && urlParams['plugins'] != '0')
{
// Loading plugins inside the asynchronous block below stops the page from loading so a
// hardcoded message for the warning dialog is used since the resources are loadd below
var warning = 'The page has requested to load the following plugin(s):\n \n {1}\n \n Would you like to load these plugin(s) now?\n \n NOTE : Only allow plugins to run if you fully understand the security implications of doing so.\n';
var tmp = window.location.protocol + '//' + window.location.host;
var local = true;
for (var i = 0; i < plugins.length && local; i++)
{
if (plugins[i].charAt(0) != '/' && plugins[i].substring(0, tmp.length) != tmp)
{
local = false;
}
}
if (local || mxUtils.confirm(mxResources.replacePlaceholders(warning, [plugins.join('\n')]).replace(/\\n/g, '\n')))
{
for (var i = 0; i < plugins.length; i++)
{
try
{
if (App.pluginsLoaded[plugins[i]] == null)
{
App.pluginsLoaded[plugins[i]] = true;
App.embedModePluginsCount++;
if (plugins[i].charAt(0) == '/')
{
plugins[i] = PLUGINS_BASE_PATH + plugins[i];
}
mxscript(plugins[i]);
}
}
catch (e)
{
// ignore
}
}
}
}
}
// Loads gapi for all browsers but IE8 and below if not disabled or if enabled and in embed mode
// Special case: Cannot load in asynchronous code below
if (typeof window.DriveClient === 'function' &&
(typeof gapi === 'undefined' && (((urlParams['embed'] != '1' && urlParams['gapi'] != '0') ||
(urlParams['embed'] == '1' && urlParams['gapi'] == '1')) && isSvgBrowser &&
isLocalStorage && (document.documentMode == null || document.documentMode >= 10))))
{
mxscript('https://apis.google.com/js/api.js?onload=DrawGapiClientCallback', null, null, null, mxClient.IS_SVG);
}
// Disables client
else if (typeof window.gapi === 'undefined')
{
window.DriveClient = null;
}
}
/**
* Asynchronous MathJax extension.
*/
if (urlParams['math'] != '0')
{
Editor.initMath();
}
function doLoad(bundle)
{
// Prefetches asynchronous requests so that below code runs synchronous
// Loading the correct bundle (one file) via the fallback system in mxResources. The stylesheet
// is compiled into JS in the build process and is only needed for local development.
mxUtils.getAll((urlParams['dev'] != '1') ? [bundle] : [bundle,
STYLE_PATH + '/default.xml', STYLE_PATH + '/dark-default.xml'], function(xhr)
{
// Adds bundle text to resources
mxResources.parse(xhr[0].getText());
// Configuration mode
if (isLocalStorage && localStorage != null && window.location.hash != null &&
window.location.hash.substring(0, 9) == '#_CONFIG_')
{
try
{
var trustedPlugins = {};
for (var key in App.pluginRegistry)
{
trustedPlugins[App.pluginRegistry[key]] = true;
}
// Only allows trusted plugins
function checkPlugins(plugins)
{
if (plugins != null)
{
for (var i = 0; i < plugins.length; i++)
{
if (!trustedPlugins[plugins[i]])
{
throw new Error(mxResources.get('invalidInput') + ' "' + plugins[i]) + '"';
}
}
}
return true;
};
var value = JSON.parse(Graph.decompress(window.location.hash.substring(9)));
if (value != null && checkPlugins(value.plugins))
{
EditorUi.debug('Setting configuration', JSON.stringify(value));
if (value.merge != null)
{
var temp = localStorage.getItem(Editor.configurationKey);
if (temp != null)
{
try
{
var config = JSON.parse(temp);
for (var key in value.merge)
{
config[key] = value.merge[key];
}
value = config;
}
catch (e)
{
window.location.hash = '';
alert(e);
}
}
else
{
value = value.merge;
}
}
if (confirm(mxResources.get('configLinkWarn')) &&
confirm(mxResources.get('configLinkConfirm')))
{
localStorage.setItem(Editor.configurationKey, JSON.stringify(value));
window.location.hash = '';
window.location.reload();
}
}
window.location.hash = '';
}
catch (e)
{
window.location.hash = '';
alert(e);
}
}
// Prepares themes with mapping from old default-style to old XML file
if (xhr.length > 2)
{
Graph.prototype.defaultThemes['default-style2'] = xhr[1].getDocumentElement();
Graph.prototype.defaultThemes['darkTheme'] = xhr[2].getDocumentElement();
}
// Main
function realMain()
{
var ui = (createUi != null) ? createUi() : new App(new Editor(
urlParams['chrome'] == '0' || uiTheme == 'min',
null, null, null, urlParams['chrome'] != '0'));
if (window.mxscript != null)
{
// Loads dropbox for all browsers but IE8 and below (no CORS) if not disabled or if enabled and in embed mode
// KNOWN: Picker does not work in IE11 (https://dropbox.zendesk.com/requests/1650781)
if (typeof window.DropboxClient === 'function' &&
(window.Dropbox == null && window.DrawDropboxClientCallback != null &&
(((urlParams['embed'] != '1' && urlParams['db'] != '0') ||
(urlParams['embed'] == '1' && urlParams['db'] == '1')) &&
isSvgBrowser && (document.documentMode == null || document.documentMode > 9))))
{
mxscript(App.DROPBOX_URL, function()
{
// Must load this after the dropbox SDK since they use the same namespace
mxscript(App.DROPINS_URL, function()
{
DrawDropboxClientCallback();
}, 'dropboxjs', App.DROPBOX_APPKEY);
});
}
// Disables client
else if (typeof window.Dropbox === 'undefined' || typeof window.Dropbox.choose === 'undefined')
{
window.DropboxClient = null;
}
// Loads OneDrive for all browsers but IE6/IOS if not disabled or if enabled and in embed mode
if (typeof window.OneDriveClient === 'function' &&
(typeof OneDrive === 'undefined' && window.DrawOneDriveClientCallback != null &&
(((urlParams['embed'] != '1' && urlParams['od'] != '0') || (urlParams['embed'] == '1' &&
urlParams['od'] == '1')) && (navigator.userAgent == null ||
navigator.userAgent.indexOf('MSIE') < 0 || document.documentMode >= 10))))
{
if (urlParams['inlinePicker'] == '1' || mxClient.IS_ANDROID || mxClient.IS_IOS)
{
mxscript(App.ONEDRIVE_INLINE_PICKER_URL, function()
{
window.OneDrive = {}; //Needed to allow code that check its existance to work BUT it's not used
window.DrawOneDriveClientCallback();
});
}
else
{
mxscript(App.ONEDRIVE_URL, window.DrawOneDriveClientCallback);
}
}
// Disables client
else if (typeof window.OneDrive === 'undefined')
{
window.OneDriveClient = null;
}
// Loads Trello for all browsers but < IE10 if not disabled or if enabled and in embed mode
if (typeof window.TrelloClient === 'function' && !mxClient.IS_IE11 &&
typeof window.Trello === 'undefined' && window.DrawTrelloClientCallback != null &&
urlParams['tr'] == '1' && (navigator.userAgent == null ||
navigator.userAgent.indexOf('MSIE') < 0 || document.documentMode >= 10))
{
mxscript(App.TRELLO_JQUERY_URL, function()
{
// Must load this after the dropbox SDK since they use the same namespace
mxscript(App.TRELLO_URL, function()
{
DrawTrelloClientCallback();
});
});
}
// Disables client
else if (typeof window.Trello === 'undefined')
{
window.TrelloClient = null;
}
}
if (callback != null)
{
callback(ui);
}
/**
* For developers only
*/
if (urlParams['chrome'] != '0' && urlParams['test'] == '1')
{
EditorUi.debug('App.start', [ui, (new Date().getTime() - t0.getTime()) + 'ms']);
if (urlParams['export'] != null)
{
EditorUi.debug('Export:', EXPORT_URL);
}
}
};
if (urlParams['dev'] == '1' || EditorUi.isElectronApp) //TODO check if we can remove these scripts loading from index.html
{
realMain();
}
else
{
mxStencilRegistry.allowEval = false;
App.loadScripts(['js/shapes-14-6-5.min.js', 'js/stencils.min.js',
'js/extensions.min.js'], realMain);
}
}, function(xhr)
{
var st = document.getElementById('geStatus');
if (st != null)
{
st.innerHTML = 'Error loading page. <a>Please try refreshing.</a>';
// Tries reload with default resources in case any language resources were not available
st.getElementsByTagName('a')[0].onclick = function()
{
mxLanguage = 'en';
doLoad(mxResources.getDefaultBundle(RESOURCE_BASE, mxLanguage) ||
mxResources.getSpecialBundle(RESOURCE_BASE, mxLanguage));
};
}
});
};
function doMain()
{
// Optional override for autosaveDelay and defaultEdgeLength
try
{
if (mxSettings.settings != null)
{
document.body.style.backgroundColor = (uiTheme == 'dark' ||
mxSettings.settings.darkMode) ? '#2a2a2a' : '#ffffff';
if (mxSettings.settings.autosaveDelay != null)
{
var val = parseInt(mxSettings.settings.autosaveDelay);
if (!isNaN(val) && val > 0)
{
DrawioFile.prototype.autosaveDelay = val;
EditorUi.debug('Setting autosaveDelay', val);
}
else
{
EditorUi.debug('Invalid autosaveDelay', val);
}
}
if (mxSettings.settings.defaultEdgeLength != null)
{
var val = parseInt(mxSettings.settings.defaultEdgeLength);
if (!isNaN(val) && val > 0)
{
Graph.prototype.defaultEdgeLength = val;
EditorUi.debug('Using defaultEdgeLength', val);
}
else
{
EditorUi.debug('Invalid defaultEdgeLength', val);
}
}
}
}
catch (e)
{
if (window.console != null)
{
console.error(e);
}
}
// Prefetches default fonts with URLs
if (Menus.prototype.defaultFonts != null)
{
for (var i = 0; i < Menus.prototype.defaultFonts.length; i++)
{
var value = Menus.prototype.defaultFonts[i];
if (typeof value !== 'string' &&
value.fontFamily != null &&
value.fontUrl != null)
{
Graph.addFont(value.fontFamily, value.fontUrl);
}
}
}
// Adds required resources (disables loading of fallback properties, this can only
// be used if we know that all keys are defined in the language specific file)
mxResources.loadDefaultBundle = false;
doLoad(mxResources.getDefaultBundle(RESOURCE_BASE, mxLanguage) ||
mxResources.getSpecialBundle(RESOURCE_BASE, mxLanguage));
};
// Sends load event if configuration is requested and waits for configure message
if (urlParams['configure'] == '1')
{
var op = window.opener || window.parent;
var configHandler = function(evt)
{
if (evt.source == op)
{
try
{
var data = JSON.parse(evt.data);
if (data != null && data.action == 'configure')
{
mxEvent.removeListener(window, 'message', configHandler);
Editor.configure(data.config, true);
mxSettings.load();
doMain();
}
}
catch (e)
{
if (window.console != null)
{
console.log('Error in configure message: ' + e, evt.data);
}
}
}
};
// Receives XML message from opener and puts it into the graph
mxEvent.addListener(window, 'message', configHandler);
op.postMessage(JSON.stringify({event: 'configure'}), '*');
}
else
{
if (Editor.config == null)
{
// Loads configuration from global scope or local storage
if (window.DRAWIO_CONFIG != null)
{
try
{
EditorUi.debug('Using global configuration', window.DRAWIO_CONFIG);
Editor.configure(window.DRAWIO_CONFIG);
mxSettings.load();
}
catch (e)
{
if (window.console != null)
{
console.error(e);
}
}
}
// Loads configuration from local storage
if (isLocalStorage && localStorage != null && urlParams['embed'] != '1')
{
var configData = localStorage.getItem(Editor.configurationKey);
if (configData != null)
{
try
{
configData = JSON.parse(configData);
if (configData != null)
{
EditorUi.debug('Using local configuration', configData);
Editor.configure(configData);
mxSettings.load();
}
}
catch (e)
{
if (window.console != null)
{
console.error(e);
}
}
}
}
}
doMain();
}
};
//Extends EditorUi
mxUtils.extend(App, EditorUi);
/**
* Executes the first step for connecting to Google Drive.
*/
App.prototype.defaultUserPicture = IMAGE_PATH + '/default-user.jpg';
/**
*
*/
App.prototype.shareImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2RpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDowOTgwMTE3NDA3MjA2ODExODhDNkFGMDBEQkQ0RTgwOSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDoxMjU2NzdEMTcwRDIxMUUxQjc0MDkxRDhCNUQzOEFGRCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDoxMjU2NzdEMDcwRDIxMUUxQjc0MDkxRDhCNUQzOEFGRCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNjgwMTE3NDA3MjA2ODExODcxRkM4MUY1OTFDMjQ5OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowNzgwMTE3NDA3MjA2ODExODhDNkFGMDBEQkQ0RTgwOSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PrM/fs0AAADgSURBVHjaYmDAA/7//88MwgzkAKDGFiD+BsQ/QWxSNaf9RwN37twpI8WAS+gGfP78+RpQSoRYA36iG/D379+vQClNdLVMOMz4gi7w79+/n0CKg1gD9qELvH379hzIHGK9oA508ieY8//8+fO5rq4uFCilRKwL1JmYmNhhHEZGRiZ+fn6Q2meEbDYG4u3/cYCfP38uA7kOm0ZOIJ7zn0jw48ePPiDFhmzArv8kgi9fvuwB+w5qwH9ykjswbFSZyM4sEMDPBDTlL5BxkFSd7969OwZ2BZKYGhDzkmjOJ4AAAwBhpRqGnEFb8QAAAABJRU5ErkJggg==';
/**
*
*/
App.prototype.chevronUpImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/chevron-up.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDg2NEE3NUY1MUVBMTFFM0I3MUVEMTc0N0YyOUI4QzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDg2NEE3NjA1MUVBMTFFM0I3MUVEMTc0N0YyOUI4QzEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0ODY0QTc1RDUxRUExMUUzQjcxRUQxNzQ3RjI5QjhDMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0ODY0QTc1RTUxRUExMUUzQjcxRUQxNzQ3RjI5QjhDMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pg+qUokAAAAMUExURQAAANnZ2b+/v////5bgre4AAAAEdFJOU////wBAKqn0AAAAL0lEQVR42mJgRgMMRAswMKAKMDDARBjg8lARBoR6KImkH0wTbygT6YaS4DmAAAMAYPkClOEDDD0AAAAASUVORK5CYII=';
/**
*
*/
App.prototype.chevronDownImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/chevron-down.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDg2NEE3NUI1MUVBMTFFM0I3MUVEMTc0N0YyOUI4QzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDg2NEE3NUM1MUVBMTFFM0I3MUVEMTc0N0YyOUI4QzEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0ODY0QTc1OTUxRUExMUUzQjcxRUQxNzQ3RjI5QjhDMSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0ODY0QTc1QTUxRUExMUUzQjcxRUQxNzQ3RjI5QjhDMSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsCtve8AAAAMUExURQAAANnZ2b+/v////5bgre4AAAAEdFJOU////wBAKqn0AAAALUlEQVR42mJgRgMMRAkwQEXBNAOcBSPhclB1cNVwfcxI+vEZykSpoSR6DiDAAF23ApT99bZ+AAAAAElFTkSuQmCC';
/**
*
*/
App.prototype.formatShowImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/format-show.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODdCREY5REY1NkQ3MTFFNTkyNjNEMTA5NjgwODUyRTgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODdCREY5RTA1NkQ3MTFFNTkyNjNEMTA5NjgwODUyRTgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4N0JERjlERDU2RDcxMUU1OTI2M0QxMDk2ODA4NTJFOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4N0JERjlERTU2RDcxMUU1OTI2M0QxMDk2ODA4NTJFOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PlnMQ/8AAAAJUExURQAAAP///3FxcTfTiAsAAAACdFJOU/8A5bcwSgAAACFJREFUeNpiYEQDDEQJMMABTAAixcQ00ALoDiPRcwABBgB6DADly9Yx8wAAAABJRU5ErkJggg==';
/**
*
*/
App.prototype.formatHideImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/format-hide.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODdCREY5REI1NkQ3MTFFNTkyNjNEMTA5NjgwODUyRTgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODdCREY5REM1NkQ3MTFFNTkyNjNEMTA5NjgwODUyRTgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4N0JERjlEOTU2RDcxMUU1OTI2M0QxMDk2ODA4NTJFOCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4N0JERjlEQTU2RDcxMUU1OTI2M0QxMDk2ODA4NTJFOCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqjT9SMAAAAGUExURQAAAP///6XZn90AAAACdFJOU/8A5bcwSgAAAB9JREFUeNpiYEQDDEQJMMABTAAmNdAC6A4j0XMAAQYAcbwA1Xvj1CgAAAAASUVORK5CYII=';
/**
*
*/
App.prototype.fullscreenImage = (!mxClient.IS_SVG) ? IMAGE_PATH + '/fullscreen.png' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAABlBMVEUAAAAAAAClZ7nPAAAAAXRSTlMAQObYZgAAABpJREFUCNdjgAAbGxAy4AEh5gNwBBGByoIBAIueBd12TUjqAAAAAElFTkSuQmCC';
/**
* Interval to show dialog for unsaved data if autosave is on.
* Default is 300000 (5 minutes).
*/
App.prototype.warnInterval = 300000;
/**
*
*/
App.prototype.compactMode = false;
/**
*
*/
App.prototype.fullscreenMode = false;
/**
* Overriden UI settings depending on mode.
*/
if (urlParams['embed'] != '1')
{
App.prototype.menubarHeight = 64;
}
else
{
App.prototype.footerHeight = 0;
}
/**
* Queue for loading plugins and wait for UI instance
*/
App.initPluginCallback = function()
{
if (App.DrawPlugins == null)
{
// Workaround for need to load plugins now but wait for UI instance
App.DrawPlugins = [];
// Global entry point for plugins is Draw.loadPlugin. This is the only
// long-term supported solution for access to the EditorUi instance.
window.Draw = new Object();
window.Draw.loadPlugin = function(callback)
{
App.DrawPlugins.push(callback);
};
}
};
/**
*
*/
App.pluginsLoaded = {};
App.embedModePluginsCount = 0;
/**
* Queue for loading plugins and wait for UI instance
*/
App.loadPlugins = function(plugins, useInclude)
{
EditorUi.debug('Loading plugins', plugins);
for (var i = 0; i < plugins.length; i++)
{
if (plugins[i] != null && plugins[i].length > 0)
{
try
{
var url = PLUGINS_BASE_PATH + App.pluginRegistry[plugins[i]];
if (url != null)
{
if (App.pluginsLoaded[url] == null)
{
App.pluginsLoaded[url] = true;
App.embedModePluginsCount++;
if (typeof window.drawDevUrl === 'undefined')
{
if (useInclude)
{
mxinclude(url);
}
else
{
mxscript(url);
}
}
else
{
if (useInclude)
{
mxinclude(url);
}
else
{
mxscript(drawDevUrl + url);
}
}
}
}
else if (window.console != null)
{
console.log('Unknown plugin:', plugins[i]);
}
}
catch (e)
{
if (window.console != null)
{
console.log('Error loading plugin:', plugins[i], e);
}
}
}
}
};
/**
* Delay embed mode initialization until all plugins are loaded
*/
App.prototype.initializeEmbedMode = function()
{
if (urlParams['embed'] == '1')
{
if (window.location.hostname == 'app.diagrams.net')
{
this.showBanner('EmbedDeprecationFooter', 'app.diagrams.net will stop working for embed mode. Please use embed.diagrams.net.');
}
if (App.embedModePluginsCount > 0 || this.initEmbedDone)
{
return; //Wait for plugins to load, or this is a duplicate call due to timeout
}
else
{
this.initEmbedDone = true;
}
EditorUi.prototype.initializeEmbedMode.apply(this, arguments);
}
};
/**
* TODO: Define viewer protocol and implement new viewer style toolbar
*/
App.prototype.initializeViewerMode = function()
{
var parent = window.opener || window.parent;
if (parent != null)
{
this.editor.graph.addListener(mxEvent.SIZE, mxUtils.bind(this, function()
{
parent.postMessage(JSON.stringify(this.createLoadMessage('size')), '*');
}));
}
};
/**
* Translates this point by the given vector.
*
* @param {number} dx X-coordinate of the translation.
* @param {number} dy Y-coordinate of the translation.
*/
App.prototype.init = function()
{
EditorUi.prototype.init.apply(this, arguments);
/**
* Specifies the default filename.
*/
this.defaultLibraryName = mxResources.get('untitledLibrary');
/**
* Holds the listener for description changes.
*/
this.descriptorChangedListener = mxUtils.bind(this, this.descriptorChanged);
/**
* Creates github client.
*/
this.gitHub = (!mxClient.IS_IE || document.documentMode == 10 ||
mxClient.IS_IE11 || mxClient.IS_EDGE) &&
(urlParams['gh'] != '0' && (urlParams['embed'] != '1' ||
urlParams['gh'] == '1')) ? new GitHubClient(this) : null;
if (this.gitHub != null)
{
this.gitHub.addListener('userChanged', mxUtils.bind(this, function()
{
this.updateUserElement();
this.restoreLibraries();
}))
}
/**
* Creates gitlab client.
*/
this.gitLab = (!mxClient.IS_IE || document.documentMode == 10 ||
mxClient.IS_IE11 || mxClient.IS_EDGE) &&
(urlParams['gl'] != '0' && (urlParams['embed'] != '1' ||
urlParams['gl'] == '1')) ? new GitLabClient(this) : null;
if (this.gitLab != null)
{
this.gitLab.addListener('userChanged', mxUtils.bind(this, function()
{
this.updateUserElement();
this.restoreLibraries();
}));
}
/**
* Lazy-loading for individual backends
*/
if (urlParams['embed'] != '1' || urlParams['od'] == '1')
{
/**
* Creates onedrive client if all required libraries are available.
*/
var initOneDriveClient = mxUtils.bind(this, function()
{
if (typeof OneDrive !== 'undefined')
{
/**
* Holds the x-coordinate of the point.
*/
this.oneDrive = new OneDriveClient(this);
this.oneDrive.addListener('userChanged', mxUtils.bind(this, function()
{
this.updateUserElement();
this.restoreLibraries();
}));
// Notifies listeners of new client
this.fireEvent(new mxEventObject('clientLoaded', 'client', this.oneDrive));
}
else if (window.DrawOneDriveClientCallback == null)
{
window.DrawOneDriveClientCallback = initOneDriveClient;
}
});
initOneDriveClient();
}
/**
* Lazy-loading for Trello
*/
if (urlParams['embed'] != '1' || urlParams['tr'] == '1')
{
/**
* Creates Trello client if all required libraries are available.
*/
var initTrelloClient = mxUtils.bind(this, function()
{
if (typeof window.Trello !== 'undefined')
{
try
{
this.trello = new TrelloClient(this);
//TODO we have no user info from Trello so we don't set a user
this.trello.addListener('userChanged', mxUtils.bind(this, function()
{
this.updateUserElement();
this.restoreLibraries();
}));
// Notifies listeners of new client
this.fireEvent(new mxEventObject('clientLoaded', 'client', this.trello));
}
catch (e)
{
if (window.console != null)
{
console.error(e);
}
}
}
else if (window.DrawTrelloClientCallback == null)
{
window.DrawTrelloClientCallback = initTrelloClient;
}
});
initTrelloClient();
}
/**
* Creates drive client with all required libraries are available.
*/
if (urlParams['embed'] != '1' || urlParams['gapi'] == '1')
{
var initDriveClient = mxUtils.bind(this, function()
{
/**
* Creates google drive client if all required libraries are available.
*/
if (typeof gapi !== 'undefined')
{
var doInit = mxUtils.bind(this, function()
{
this.drive = new DriveClient(this);
this.drive.addListener('userChanged', mxUtils.bind(this, function()
{
this.updateUserElement();
this.restoreLibraries();
this.checkLicense();
}))
// Notifies listeners of new client
this.fireEvent(new mxEventObject('clientLoaded', 'client', this.drive));
});
if (window.DrawGapiClientCallback != null)
{
gapi.load(((urlParams['picker'] != '0') ? 'picker,': '') + App.GOOGLE_APIS, doInit);
/**
* Clears any callbacks.
*/
window.DrawGapiClientCallback = null;
}
else
{
doInit();
}
}
else if (window.DrawGapiClientCallback == null)
{
window.DrawGapiClientCallback = initDriveClient;
}
});
initDriveClient();
}
if (urlParams['embed'] != '1' || urlParams['db'] == '1')
{
/**
* Creates dropbox client if all required libraries are available.
*/
var initDropboxClient = mxUtils.bind(this, function()
{
if (typeof Dropbox === 'function' && typeof Dropbox.choose !== 'undefined')
{
/**
* Clears dropbox client callback.
*/
window.DrawDropboxClientCallback = null;
/**
* Holds the x-coordinate of the point.
*/
try
{
this.dropbox = new DropboxClient(this);
this.dropbox.addListener('userChanged', mxUtils.bind(this, function()
{
this.updateUserElement();
this.restoreLibraries();
}));
// Notifies listeners of new client
this.fireEvent(new mxEventObject('clientLoaded', 'client', this.dropbox));
}
catch (e)
{
if (window.console != null)
{
console.error(e);
}
}
}
else if (window.DrawDropboxClientCallback == null)
{
window.DrawDropboxClientCallback = initDropboxClient;
}
});
initDropboxClient();
}
if (urlParams['embed'] != '1')
{
/**
* Holds the background element.
*/
this.bg = this.createBackground();
document.body.appendChild(this.bg);
this.diagramContainer.style.visibility = 'hidden';
this.formatContainer.style.visibility = 'hidden';
this.hsplit.style.display = 'none';
this.sidebarContainer.style.display = 'none';
this.sidebarFooterContainer.style.display = 'none';
// Sets the initial mode
if (urlParams['local'] == '1')
{
this.setMode(App.MODE_DEVICE);
}
else
{
this.mode = App.mode;
}
// Add to Home Screen dialog for mobile devices
if ('serviceWorker' in navigator && !this.editor.isChromelessView() &&
(mxClient.IS_ANDROID || mxClient.IS_IOS))
{
window.addEventListener('beforeinstallprompt', mxUtils.bind(this, function(e)
{
this.showBanner('AddToHomeScreenFooter', mxResourc