UNPKG

drawio-offline

Version:
1,661 lines (1,476 loc) 208 kB
/** * 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