/** * Plugin for embed mode in Confluence Connect post version 1.4.8 */ Draw.loadPlugin(function(ui) { // Handle data governess by modifying external services URLs var allowedRegions = { eu: 1, us: 1 }; if (allowedRegions[urlParams['dataGov']]) { var region = urlParams['dataGov']; var urls = { 'EXPORT_URL': 'export', 'PLANT_URL': 'plant', 'VSD_CONVERT_URL': 'vsd', 'EMF_CONVERT_URL': 'emf', 'OPEN_URL': 'import' }; for (var key in urls) { var val = window[key]; if (val) { window[key] = '/region-' + urls[key] + '-' + region; } } } // Extracts macro data from JSON protocol var macroData = {}; mxEvent.addListener(window, 'message', mxUtils.bind(this, function(evt) { var data = evt.data; try { data = JSON.parse(data); if (data.action == 'load') { if (data.macroData != null) { macroData = data.macroData; if (ui.format != null) { ui.format.refresh(); } } ui.initComments(macroData.contentId || macroData.custContentId); macroData.diagramDisplayName = data.title; //Fetch notifications ui.fetchAndShowNotification('conf'); } } catch (e) { data = null; } })); var renameAction = ui.actions.get("rename"); renameAction.visible = true; renameAction.isEnabled = function() { return macroData.diagramDisplayName != null; } function descriptorChangedListener() { var curFile = ui.getCurrentFile(); var fileTitle = curFile.getTitle(); //Update file name in the UI var tmp = document.createElement('span'); mxUtils.write(tmp, mxUtils.htmlEntities(fileTitle)); if (ui.embedFilenameSpan != null) { ui.embedFilenameSpan.parentNode.removeChild(ui.embedFilenameSpan); } ui.buttonContainer.appendChild(tmp); ui.embedFilenameSpan = tmp; macroData.diagramDisplayName = fileTitle; var vSettings = curFile.desc.viewerSettings; if (vSettings != null) { macroData.tbstyle = vSettings.tbstyle; macroData.links = vSettings.links; macroData.simple = vSettings.simple; macroData.lbox = vSettings.lbox; macroData.zoom = vSettings.zoom; macroData.pCenter = vSettings.pCenter; macroData.aspect = vSettings.aspect; macroData.hiResPreview = vSettings.hiResPreview; if (ui.format != null) { ui.format.refresh(); } } }; var xdm_e = decodeURIComponent(urlParams['site']); var license = urlParams['atlas-lic']; ui.remoteInvoke('checkConfLicense', [license, xdm_e], null, function(licenseValid) { if (!licenseValid) { ui.menus.get('file').funct = function(menu, parent) { menu.addItem(mxResources.get('licenseRequired'), null, function() { // do nothing }, parent, null, false); } ui.menus.get('insertAdvanced').funct = function(menu, parent) { menu.addItem(mxResources.get('licenseRequired'), null, function() { // do nothing }, parent, null, false); } if (typeof(MathJax) !== 'undefined') { ui.actions.get('mathematicalTypesetting').funct = function() { ui.alert(mxResources.get('licenseRequired')); }; } EditorUi.prototype.insertPage = function(page, index) { this.alert(mxResources.get('licenseRequired')); }; Sidebar.prototype.searchEntries = function(searchTerms, count, page, success, error) { success(); }; Sidebar.prototype.insertSearchHint = function(div, searchTerm, count, page, results, len, more, terms) { var link = document.createElement('div'); link.className = 'geTitle'; link.style.cssText = 'background-color:#ffd350;border-radius:6px;color:black;' + 'border:1px solid black !important;text-align:center;white-space:normal;' + 'padding:6px 0px 6px 0px !important;margin:4px 4px 8px 2px;font-size:12px;'; mxUtils.write(link, mxResources.get('licenseRequired')); div.appendChild(link); }; DrawioFileSync.prototype.fileChangedNotify = function() { //Disable RT syncing }; ui.importFiles = function() { //Disable DnD and file import ui.alert(mxResources.get('licenseRequired')); } //Disable comments ui.getComments = function(success, error) { error({message: mxResources.get('licenseRequired')}); } ui.addComment = function(comment, success, error) { error(); } } }, function(){}); renameAction.funct = function() { var dlg = new FilenameDialog(ui, macroData.diagramDisplayName || "", mxResources.get('rename'), function(newName) { if (newName != null && newName.length > 0) { //TODO This is not needed with RT since title is added to desc macroData.diagramDisplayName = newName; var parent = window.opener || window.parent; parent.postMessage(JSON.stringify({event: 'rename', name: newName}), '*'); //Update and sync new name ui.getCurrentFile().rename(newName); } }, mxResources.get('rename'), function(name) { var err = ""; if (name == null || name.length == 0) { err = 'Filename too short'; } else if (/[&\*+=\\;/{}|\":<>\?~]/g.test(name)) { err = 'Invalid characters \\ / | : { } < > & + ? = ; * " ~'; } else { return true; } ui.showError(mxResources.get('error'), err, mxResources.get('ok')); return false; }); ui.showDialog(dlg.container, 300, 80, true, true); dlg.init(); } // Returns modified macro data to client var uiCreateLoadMessage = ui.createLoadMessage; ui.createLoadMessage = function(eventName) { var msg = uiCreateLoadMessage.apply(this, arguments); if (eventName == 'export') { msg.macroData = macroData; var desc = ui.getCurrentFile().getDescriptor(); //Until app.min.js is propagated, this code is necessary if (desc != null) { if (desc.key == null) { desc.key = Editor.guid(32); desc.channel = Editor.guid(32); desc.etagP = Editor.guid(32); desc.title = macroData.diagramDisplayName; } else if (desc.title) { macroData.diagramDisplayName = desc.title; } msg.desc = desc; } else { msg.desc = {}; } } return msg; }; // Adds new section for confluence cloud var diagramFormatPanelInit = DiagramFormatPanel.prototype.init; DiagramFormatPanel.prototype.init = function() { this.container.appendChild(this.addViewerOptions(this.createPanel())); diagramFormatPanelInit.apply(this, arguments); }; // Adds viewer config to style options and refreshes DiagramFormatPanel.prototype.addViewerOptions = function(div) { var ui = this.editorUi; var editor = ui.editor; var graph = editor.graph; div.appendChild(this.createTitle(mxResources.get('viewerSettings'))); // Viewer simple div.appendChild(this.createOption(mxResources.get('simpleViewer'), function() { return macroData.simple == '1'; }, function(checked) { macroData.simple = (checked) ? '1' : '0'; })); // Viewer lightbox div.appendChild(this.createOption(mxResources.get('lightbox'), function() { return macroData.lbox != '0'; }, function(checked) { macroData.lbox = (checked) ? '1' : '0'; })); // Viewer centering div.appendChild(this.createOption(mxResources.get('center'), function() { return macroData.pCenter == '1'; }, function(checked) { macroData.pCenter = (checked) ? '1' : '0'; })); // High Resolution Preview div.appendChild(this.createOption(mxResources.get('hiResPreview', null, 'High Res Preview'), function() { return (macroData.hiResPreview == null && Editor.config != null && Editor.config.hiResPreview) || macroData.hiResPreview == '1'; }, function(checked) { macroData.hiResPreview = (checked) ? '1' : '0'; ui.remoteInvoke('setHiResPreview', [checked], null, function(){}, function(){}); //Notify plugin of the change, ignoring both success and error callbacks })); // Toolbar var stylePanel = this.createPanel(); stylePanel.style.position = 'relative'; stylePanel.style.borderWidth = '0px'; stylePanel.style.marginLeft = '0px'; stylePanel.style.paddingTop = '8px'; stylePanel.style.paddingBottom = '4px'; stylePanel.style.fontWeight = 'normal'; stylePanel.className = 'geToolbarContainer'; mxUtils.write(stylePanel, mxResources.get('toolbar')); // Adds toolbar options var tbSelect = document.createElement('select'); tbSelect.style.position = 'absolute'; tbSelect.style.right = '20px'; tbSelect.style.width = '97px'; tbSelect.style.marginTop = '-2px'; var opts = [{value: 'top', title: mxResources.get('top')}, {value: 'inline', title: mxResources.get('embed')}, {value: 'hidden', title: mxResources.get('hidden')}] var validTb = false; for (var i = 0; i < opts.length; i++) { validTb = validTb || macroData.tbstyle == opts[i].value; var tbOption = document.createElement('option'); tbOption.setAttribute('value', opts[i].value); mxUtils.write(tbOption, opts[i].title); tbSelect.appendChild(tbOption); } tbSelect.value = (validTb) ? macroData.tbstyle : 'top'; stylePanel.appendChild(tbSelect); div.appendChild(stylePanel); mxEvent.addListener(tbSelect, 'change', function(evt) { macroData.tbstyle = tbSelect.value; mxEvent.consume(evt); }); // Links stylePanel = stylePanel.cloneNode(false); stylePanel.style.paddingTop = '4px'; mxUtils.write(stylePanel, mxResources.get('links')); // Adds links options var linksSelect = document.createElement('select'); linksSelect.style.position = 'absolute'; linksSelect.style.right = '20px'; linksSelect.style.width = '97px'; linksSelect.style.marginTop = '-2px'; var opts = [{value: 'auto', title: mxResources.get('automatic')}, {value: 'blank', title: mxResources.get('openInNewWindow')}, {value: 'self', title: mxResources.get('openInThisWindow')}] var validLinks = false; for (var i = 0; i < opts.length; i++) { validLinks = validLinks || macroData.links == opts[i].value; var linkOption = document.createElement('option'); linkOption.setAttribute('value', opts[i].value); mxUtils.write(linkOption, opts[i].title); linksSelect.appendChild(linkOption); } linksSelect.value = (validLinks) ? macroData.links : 'auto'; stylePanel.appendChild(linksSelect); div.appendChild(stylePanel); mxEvent.addListener(linksSelect, 'change', function(evt) { macroData.links = linksSelect.value; mxEvent.consume(evt); }); // Zoom var zoomOpt = this.createRelativeOption(mxResources.get('zoom'), null, null, function(input) { var value = (input.value == '') ? 100 : parseInt(input.value); value = Math.max(0, (isNaN(value)) ? 100 : value); input.value = value + ' %'; macroData.zoom = value / 100; }, function(input) { input.value = (parseFloat(macroData.zoom || 1) * 100) + '%'; }); zoomOpt.style.fontWeight = 'normal'; zoomOpt.style.paddingBottom = '6px'; zoomOpt.style.paddingTop = '6px'; zoomOpt.style.border = 'none'; div.appendChild(zoomOpt); //Page and layers settings div.appendChild(this.createTitle(mxResources.get('pageLayers', null, 'Page and Layers'))); var hasAspect = false; var pageId = null, layerIds = null; var customizeBtn = mxUtils.button(mxResources.get('customize', null, 'Customize'), function() { var dlg = new AspectDialog(ui, pageId, layerIds, function(info) { pageId = info.pageId; layerIds = info.layerIds; macroData.aspect = pageId + ' ' + layerIds.join(' '); ui.remoteInvoke('setAspect', [macroData.aspect], null, function(){}, function(){}); //Notify plugin of the change, ignoring both success and error callbacks }); ui.showDialog(dlg.container, 700, 465, true, true); dlg.init(); }); customizeBtn.className = 'geColorBtn'; customizeBtn.style.marginLeft = '10px'; customizeBtn.style.padding = '2px'; customizeBtn.setAttribute('disabled', 'disabled'); if (macroData.aspect != null) { var aspectArray = macroData.aspect.split(' '); if (aspectArray.length > 0) { pageId = aspectArray[0]; layerIds = aspectArray.slice(1); hasAspect = true; customizeBtn.removeAttribute('disabled'); } } var firstPageRadio = ui.addRadiobox(div, 'pageLayers', mxResources.get('firstPage', null, 'First Page (All Layers)'), !hasAspect); firstPageRadio.style.marginTop = '4px'; mxEvent.addListener(firstPageRadio, 'change', function() { if (this.checked) { macroData.aspect = null; ui.remoteInvoke('setAspect', [macroData.aspect], null, function(){}, function(){}); //Notify plugin of the change, ignoring both success and error callbacks customizeBtn.setAttribute('disabled', 'disabled'); } }); var currentStateRadio = ui.addRadiobox(div, 'pageLayers', mxResources.get('curEditorState', null, 'Current Editor State'), false); currentStateRadio.style.marginTop = '8px'; mxEvent.addListener(currentStateRadio, 'change', function() { if (this.checked) { var curPage = ui.updatePageRoot(ui.currentPage); var layerIds = [], layers = curPage.root.children; for (var i = 0; i < layers.length; i++) { if (layers[i].visible != false) { layerIds.push(layers[i].id); } } macroData.aspect = curPage.getId() + ' ' + layerIds.join(' '); ui.remoteInvoke('setAspect', [macroData.aspect], null, function(){}, function(){}); //Notify plugin of the change, ignoring both success and error callbacks customizeBtn.setAttribute('disabled', 'disabled'); } }); var customStateRadio = ui.addRadiobox(div, 'pageLayers', mxResources.get('custom', null, 'Custom'), hasAspect, false, true); customStateRadio.style.marginTop = '8px'; mxEvent.addListener(customStateRadio, 'change', function() { if (this.checked) { customizeBtn.removeAttribute('disabled'); } }); div.appendChild(customizeBtn); return div; }; if (ui.format != null) { ui.format.refresh(); } //Adding Link to Confluence Page Anchor var origLinkDialog = LinkDialog; LinkDialog = function(editorUi, initialValue, btnLabel, fn, showPages) { function modFn(link, selDoc) { if (anchorRadio.checked) { fn('data:confluence/anchor,' + anchorSelect.value); } else { fn(link, selDoc); } }; origLinkDialog.call(this, editorUi, initialValue, btnLabel, modFn, showPages); var baseUrl = ''; ui.remoteInvoke('getBaseUrl', null, null, function(url) { baseUrl = url; }, function() { //Extremely rare, we can safely ignore since the editor won't work }); var inner = this.container.querySelector('.geTitle'), urlInput = inner.querySelector('input[type="text"]'), urlCheck = urlInput.previousSibling; var lbl = document.createElement('div'); mxUtils.write(lbl, mxResources.get('confAnchor') + ':'); inner.appendChild(lbl); function addOption(select, name, value, isDisabled, isSelected) { var opt = document.createElement('option'); if (isDisabled) { opt.setAttribute('disabled', 'disabled'); } if (isSelected) { opt.setAttribute('selected', 'selected'); } if (value) { opt.setAttribute('value', value); } mxUtils.write(opt, name); select.appendChild(opt); } var anchorRadio = document.createElement('input'); anchorRadio.style.cssText = 'margin-right:8px;margin-bottom:8px;'; anchorRadio.setAttribute('value', 'url'); anchorRadio.setAttribute('type', 'radio'); var anchorSelect = document.createElement('select'); anchorSelect.style.marginTop = '6px'; anchorSelect.style.width = '680px'; var anchorBusyIcn = document.createElement('img'); anchorBusyIcn.src = '/images/spin.gif'; anchorBusyIcn.style.position = 'absolute'; var selAnchor = null; if (initialValue != null && initialValue.substring(0, 23) == 'data:confluence/anchor,') { urlInput.value = ''; selAnchor = initialValue.substring(23); anchorRadio.setAttribute('checked', 'checked'); anchorRadio.defaultChecked = true; } ui.remoteInvoke('getCurPageAnchors', null, null, function(headings) { addOption(anchorSelect, headings.length == 0? mxResources.get('noAnchorsFound') : mxResources.get('confAnchor'), null, true, selAnchor == null); if (headings.length == 0) { anchorSelect.setAttribute('disabled', 'disabled'); anchorRadio.setAttribute('disabled', 'disabled'); } else { for(var i = 0; i < headings.length; i++) { addOption(anchorSelect, headings[i], headings[i], false, selAnchor == headings[i]); } } anchorBusyIcn.style.display = 'none'; }, function() { anchorSelect.style.border = '1px solid red'; anchorSelect.setAttribute('disabled', 'disabled'); anchorRadio.setAttribute('disabled', 'disabled'); anchorBusyIcn.style.display = 'none'; }); mxEvent.addListener(anchorSelect, 'focus', function() { anchorRadio.setAttribute('checked', 'checked'); anchorRadio.checked = true; }); inner.appendChild(anchorRadio); inner.appendChild(anchorSelect); inner.appendChild(anchorBusyIcn); //Attachments select lbl = document.createElement('div'); mxUtils.write(lbl, mxResources.get('attachments') + ':'); inner.appendChild(lbl); var attSelect = document.createElement('select'); attSelect.style.margin = '6px 0 5px 0'; attSelect.style.width = '705px'; var attBusyIcn = document.createElement('img'); attBusyIcn.src = '/images/spin.gif'; attBusyIcn.style.position = 'absolute'; var attMap = {}; ui.remoteInvoke('getCurPageAttachments', null, null, function(atts) { addOption(attSelect, atts.length == 0? mxResources.get('noAttachments') : mxResources.get('attachments'), null, true, true); if (atts.length == 0) { attSelect.setAttribute('disabled', 'disabled'); } else { atts = atts.filter(function(a) { //Exclude draft and temp files return a.metadata.mediaType != 'application/vnd.jgraph.mxfile.cached' && !/^\~.+\.tmp$/.test(a.title); }); for(var i = 0; i < atts.length; i++) { attMap[atts[i].id] = atts[i]; addOption(attSelect, atts[i].title, atts[i].id, false, false); } } attBusyIcn.style.display = 'none'; }, function() { attSelect.style.border = '1px solid red'; attSelect.setAttribute('disabled', 'disabled'); attBusyIcn.style.display = 'none'; }); function setUrlValue(content) { //Attachment webui link doesn't work, so build it if (content.type == 'attachment') { var pageId = content._expandable.container.match(/\d+/)[0]; urlInput.value = baseUrl + '/pages/viewpageattachments.action?pageId=' + pageId + '&preview=/' + pageId + '/' + content.id.replace('att', '') + '/' + encodeURIComponent(content.title); } else { urlInput.value = baseUrl + content._links.webui; } urlCheck.checked = true; }; mxEvent.addListener(attSelect, 'change', function() { var att = attMap[attSelect.value]; if (att.metadata.mediaType == 'application/vnd.jgraph.mxfile') { attBusyIcn.style.display = ''; var pageId = att._expandable.container; pageId = pageId.substr(pageId.lastIndexOf('/') + 1); ui.remoteInvoke('getPageDrawioDiagrams', [pageId], null, function(drawioCCs) { var attCC = drawioCCs.filter(function(c) { return c.info.name == att.title; })[0]; if (attCC) { setUrlValue(attCC.obj); } else { setUrlValue(att); } attBusyIcn.style.display = 'none'; }, function() { attSelect.style.border = '1px solid red'; attBusyIcn.style.display = 'none'; }); } else { setUrlValue(att); } }); inner.appendChild(attSelect); inner.appendChild(attBusyIcn); //Search lbl = document.createElement('div'); mxUtils.write(lbl, mxResources.get('search') + ':'); inner.appendChild(lbl); var searchInput = document.createElement('input'); searchInput.placeholder = mxResources.get('search'); searchInput.style.margin = '6px 5px 5px 0'; searchInput.style.width = '490px'; var spaceSelect = document.createElement('select'); spaceSelect.style.marginTop = '6px'; spaceSelect.style.width = '202px'; var spaceBusyIcn = document.createElement('img'); spaceBusyIcn.src = '/images/spin.gif'; spaceBusyIcn.style.position = 'absolute'; var searchResult = document.createElement('div'); searchResult.style.cssText = 'border: 1px solid black;width: 705px;height:200px;overflow-y:auto; overflow-x:hidden'; addOption(spaceSelect, mxResources.get('allSpaces'), '*', false, true); var typesMap = { 'page': mxResources.get('page'), 'attachment': mxResources.get('attachment', null, 'Attachment'), 'blogpost': mxResources.get('blog'), 'ac:com.mxgraph.confluence.plugins.diagramly:drawio-diagram': mxResources.get('drawDiag') }; ui.remoteInvoke('getAvailableSpaces', null, null, function(spaces) { for(var i = 0; i < spaces.length; i++) { addOption(spaceSelect, spaces[i].title, spaces[i].space.key, false, false); } spaceBusyIcn.style.display = 'none'; }, function() { //We'll use all spaces and ignore error spaceBusyIcn.style.display = 'none'; }); var searchTimeout = null, searchResultsMap = {}; function resultRowClick() { var cId = this.getAttribute('data-url'); setUrlValue(searchResultsMap[cId]); }; function doSearch() { clearTimeout(searchTimeout); if(searchInput.value != '') { searchResult.innerHTML = ''; searchResultsMap = {}; ui.remoteInvoke('contentSearch', [searchInput.value, spaceSelect.value == '*'? null : [spaceSelect.value]], null, function(results) { searchResult.innerHTML = ''; results = results.filter(function(r) { //Exclude draft files and diagram files (since it is returned as custom contents) return r.metadata.mediaType != 'application/vnd.jgraph.mxfile.cached' && r.metadata.mediaType != 'application/vnd.jgraph.mxfile'; }); if (results.length == 0) { searchResult.innerHTML = mxResources.get('noSearchResults'); } else { var table = document.createElement('table'); table.className = 'geStripedTable'; table.innerHTML = '' + mxResources.get('title') + '' + mxResources.get('type') + '' + mxResources.get('space') + '' + mxResources.get('lastModified') + ''; for(var i = 0; i < results.length; i++) { var res = results[i]; searchResultsMap[res.id] = res; var spaceName = res.space? res.space.name : ''; var tr = document.createElement('tr'); tr.setAttribute('data-url', res.id); var type = typesMap[res.type]; tr.innerHTML = '' + mxUtils.htmlEntities(res.title) + '' + (type? type : mxResources.get('other')) + '' + mxUtils.htmlEntities(spaceName) + '' + mxUtils.htmlEntities(res.version.friendlyWhen) + ''; mxEvent.addListener(tr, 'click', resultRowClick); table.appendChild(tr); } searchResult.appendChild(table); } }, function() { searchResult.innerHTML = mxResources.get('confAErrOccured'); }); } }; mxEvent.addListener(searchInput, 'keypress', function(e) { if(e.which == 13) { doSearch(); } }); mxEvent.addListener(searchInput, 'input', function(e) { clearTimeout(searchTimeout); searchTimeout = setTimeout(doSearch, 1000); }); inner.appendChild(searchInput); inner.appendChild(spaceSelect); inner.appendChild(spaceBusyIcn); inner.appendChild(searchResult); var origInit = this.init; this.init = function() { origInit.apply(this, arguments); if (anchorRadio.checked) { anchorSelect.focus(); } }; }; mxUtils.extend(LinkDialog, origLinkDialog); ui.showLinkDialog = function(value, btnLabel, fn) { var dlg = new LinkDialog(this, value, btnLabel, fn, true); this.showDialog(dlg.container, 700, 470, true, true); dlg.init(); }; //Viewer also had to change this in viewer (Graph.prototype.customLinkClicked) var origHandleCustomLink = ui.handleCustomLink; //This code is similar to AC.gotoAnchor but we don't have access to AC here ui.handleCustomLink = function(href) { if (href.substring(0, 19) == 'data:confluence/id,') { var id = href.substring(19); var newWin = window.open(); if (id) { ui.remoteInvoke('getContentInfo', [id], null, function(info) { ui.remoteInvoke('getBaseUrl', null, null, function(url) { newWin.location = url + info._links.webui; }, function(){}); }, function() { newWin.document.writeln(mxResources.get('objectNotFound')); }); } else { throw new Error('Empty ID'); } } else if (href.substring(0, 23) == 'data:confluence/anchor,') { var anchor = href.substring(23); var newWin = window.open(); if (anchor) { ui.remoteInvoke('getPageInfo', [true], null, function(info) { var url = info.url; if (url != null) { //remove any hash var hash = url.indexOf('#'); if (hash > -1) { url = url.substring(0, hash); } //We assume the new editor for simplicity newWin.location = url + '#' + encodeURIComponent(anchor.replace(/\s/g, '-')); } }, function() { throw new Error('Unexpected Error'); }); } else { throw new Error('Empty Anchor'); } } else { origHandleCustomLink.apply(ui, arguments); } }; var origGetLinkTitle = ui.getLinkTitle; ui.getLinkTitle = function(href) { if (href.substring(0, 19) == 'data:confluence/id,') { return mxResources.get('link'); //We only have the id which is not helpful } else if (href.substring(0, 23) == 'data:confluence/anchor,') { return mxResources.get('anchor') + ': ' + href.substring(23); } else { return origGetLinkTitle.apply(ui, arguments); } }; //======================== Revisions ======================== ui.isRevisionHistoryEnabled = function() { return macroData.pageId != null; }; ui.isRevisionHistorySupported = function() { return true; }; /** * Get revisions of current file */ ui.getRevisions = function(success, error) { function getXml(success, error) { ui.remoteInvoke('getFileContent', [this.downloadUrl], null, success, error); }; function restoreFn(xml) { if (ui.spinner.spin(document.body, mxResources.get('restoring'))) { ui.replaceFileData(xml); ui.spinner.stop(); ui.hideDialog(); } }; ui.remoteInvoke('getDiagramRevisions', [macroData.diagramName, macroData.pageId], null, function(revisions) { //convert to editor format and add getXml function var revs = []; for (var i = 0; i < revisions.length; i++) { var rev = revisions[i]; rev.getXml = mxUtils.bind(rev, getXml); revs.push(rev); } success(revs, restoreFn); }, error); }; //============= Support Action =============== ui.actions.addAction('support...', function() { ui.remoteInvoke('getPageInfo', [true], null, function(info) { var url = info.url; if (url != null) { var wikiPos = url.indexOf('/wiki/'); if (wikiPos > -1) { url = url.substring(0, wikiPos); } ui.openLink(url + '/wiki/plugins/servlet/ac/com.mxgraph.confluence.plugins.diagramly/support'); } else { ui.openLink('https://about.draw.io/support/'); } }, function() { ui.openLink('https://about.draw.io/support/'); }); }); //=============Custom Libraries in More Shapes =================== function addImage(container, data, w, h, img) { var ew = 100; var eh = 100; var iw = w; var ih = h; if (w > ui.maxImageSize || h > ui.maxImageSize) { var s = Math.min(1, Math.min(ui.maxImageSize / Math.max(1, w)), ui.maxImageSize / Math.max(1, h)); w *= s; h *= s; } if (iw > ih) { ih = Math.round(ih * ew / iw); iw = ew; } else { iw = Math.round(iw * eh / ih); ih = eh; } var wrapper = document.createElement('div'); wrapper.setAttribute('draggable', 'true'); wrapper.style.display = 'inline-block'; wrapper.style.cursor = 'move'; if (data != null) { var elt = document.createElement('img'); elt.setAttribute('src', data); elt.style.width = iw + 'px'; elt.style.height = ih + 'px'; elt.style.margin = '10px'; elt.style.paddingBottom = Math.floor((eh - ih) / 2) + 'px'; elt.style.paddingLeft = Math.floor((ew - iw) / 2) + 'px'; wrapper.appendChild(elt); } else if (img != null) { var cells = ui.stringToCells(Graph.decompress(img.xml)); if (cells.length > 0) { ui.sidebar.createThumb(cells, ew, eh, wrapper, null, true, false); // Needs inline block on SVG for delete icon to appear on same line wrapper.firstChild.style.display = 'inline-block'; wrapper.firstChild.style.cursor = ''; } } container.appendChild(wrapper); }; var customLibraries = []; ui.actions.addAction('shapes...', mxUtils.bind(this, function() { ui.remoteInvoke('getCustomLibraries', null, null, function(libs) { customLibraries = libs; for(var i = 0; i < libs.length; i++) { libs[i].imageCallback = mxUtils.bind(libs[i], function(preview) { preview.innerHTML = ''; ui.remoteInvoke('getFileContent', [this.downloadUrl], null, function(libContent) { try { preview.innerHTML = ''; doc = mxUtils.parseXml(libContent); var images = JSON.parse(mxUtils.getTextContent(doc.documentElement)); for(var i = 0; i < images.length; i++) { addImage(preview, images[i].data, images[i].w, images[i].h, images[i]); } } catch(e) { preview.innerHTML = mxResources.get('confAErrOccured'); console.log(e); } }, function(err) { preview.innerHTML = mxResources.get('errorLoadingFile'); console.log(err); }); }); } var customLibsEntry = libs.length > 0? [{title : mxResources.get('customLib'), entries : libs}] : []; ui.showDialog(new MoreShapesDialog(ui, true, ui.sidebar.entries.concat(customLibsEntry)).container, 640, (isLocalStorage) ? ((mxClient.IS_IOS) ? 650 : 630) : 650, true, true); }, function(err) { console.log(err); ui.showDialog(new MoreShapesDialog(ui, true, ui.sidebar.entries).container, 640, (isLocalStorage) ? ((mxClient.IS_IOS) ? 650 : 630) : 650, true, true); }); })); var showEntriesOld = Sidebar.prototype.showEntries; Sidebar.prototype.showEntries = function(stc, remember, force) { showEntriesOld.apply(this, arguments); if(stc == null) return; var libIds = stc.split(';'); for(var i = 0; i < customLibraries.length; i++) { lib = customLibraries[i]; if(mxUtils.indexOf(libIds, lib.id) != -1) { ui.remoteInvoke('getFileContent', [lib.downloadUrl], null, mxUtils.bind(lib, function(libContent) { try { ui.loadLibrary(new RemoteLibrary(ui, libContent, this)); } catch (e) { //Ignore } }), function() { //Ignore }); } else { ui.closeLibrary(new RemoteLibrary(ui, '', lib)); } }; }; var isEntryVisibleOld = Sidebar.prototype.isEntryVisible; Sidebar.prototype.isEntryVisible = function(key) { var visible = isEntryVisibleOld.apply(this, arguments); var cVisible = false; var customLibSelection = mxSettings.getCustomLibraries(); for(var i = 0; i < customLibSelection.length; i++) { try { var hash = customLibSelection[i]; if (hash.charAt(0) == 'R') { if(JSON.parse(decodeURIComponent(hash.substr(1)))[0] == key) { cVisible = true; } } } catch(e){} //ignore } return visible || cVisible; }; //Show custom templates in templates dialog //Overriding the action here is too late as the ui button is created using the action function //The solution is to override the NewDialog itself but it's tricky and hacky var origNewDialog = NewDialog; NewDialog = function(editorUi, compact, showName, callback, createOnly, cancelCallback, leftHighlight, rightHighlight, rightHighlightBorder, itemPadding, templateFile, recentDocsCallback, searchDocsCallback, openExtDocCallback, showImport, createButtonLabel, customTempCallback, withoutType) { if (!showName && recentDocsCallback == null && searchDocsCallback == null && openExtDocCallback == null && customTempCallback == null) { openExtDocCallback = function(url, info, name) { ui.remoteInvoke('getFileContent', [url], null, callback, function() { ui.showError(mxResources.get('error'), mxResources.get('cantReadChckPerms'), mxResources.get('ok')); }); }; customTempCallback = function(customTempCallback) { ui.remoteInvoke('getCustomTemplates', null, null, customTempCallback, function() { customTempCallback({}, 0); //ignore error by sending empty templates }); }; } origNewDialog.call(this, editorUi, compact, showName, callback, createOnly, cancelCallback, leftHighlight, rightHighlight, rightHighlightBorder, itemPadding, templateFile, recentDocsCallback, searchDocsCallback, openExtDocCallback, showImport, createButtonLabel, customTempCallback, withoutType); }; mxUtils.extend(NewDialog, origNewDialog); for (var key in origNewDialog) { NewDialog[key] = origNewDialog[key]; } //=============Embed File with real-time collab support (based on remote invocation) //Until app.min.js is propagated, this code is necessary if (typeof EmbedFile === 'undefined') { var origInstallMessageHandler = ui.installMessageHandler; ui.installMessageHandler = function() { var parent = window.opener || window.parent; parent.postMessage(JSON.stringify({event: 'disableRT'}), '*'); origInstallMessageHandler.apply(this, arguments); } return; } /** * Workaround for changing etag after save is higher autosave delay to allow * for preflight etag update and decrease possible conflicts on file save. */ 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(); }; /** * Returns true if an autosave is required at the time of execution. */ EmbedFile.prototype.isAutosave = function() { return this.desc.id != null; }; /** * Specifies if the autosave checkbox should be shown in the document * properties dialog. Default is false. */ EmbedFile.prototype.isAutosaveOptional = function() { return this.desc.id == null; }; /** * */ EmbedFile.prototype.isRenamable = function() { return this.isEditable() && DrawioFile.prototype.isEditable.apply(this, arguments); }; /** * */ 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) { 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; this.createSecret(mxUtils.bind(this, function(secret, token) { var doSave = mxUtils.bind(this, function(realOverwrite, realRevision) { try { var lastDesc = this.desc; var savedData = this.getData(); this.desc.secret = secret; this.desc.key = this.desc.key? this.desc.key : Editor.guid(32); this.desc.channel = this.desc.channel? this.desc.channel : Editor.guid(32); this.desc.etagP = this.desc.etagP? this.desc.etagP : Editor.guid(32); this.desc.title = this.desc.title? this.desc.title : macroData.diagramDisplayName; ui.remoteInvoke('saveDraftWithFileDesc', [savedData, this.desc], null, mxUtils.bind(this, function(resp) { try { this.savingFile = false; // Handles special case where resp is false eg // if the old file was converted to realtime if (resp != false) { // Checks for changes during save this.setModified(this.getShadowModified()); if (revision) { this.lastAutosaveRevision = new Date().getTime(); } // Adaptive autosave delay this.autosaveDelay = Math.min(8000, Math.max(this.saveDelay + 500, EmbedFile.prototype.autosaveDelay)); this.desc = resp; // Shows possible errors but keeps the modified flag as the // file was saved but the cache entry could not be written if (token != null) { this.fileSaved(savedData, lastDesc, mxUtils.bind(this, function() { this.contentChanged(); if (success != null) { success(resp); } }), error, token); } else { success(resp); } } else if (error != null) { error(resp); } } catch (e) { this.savingFile = false; if (error != null) { error(e); } else { throw e; } } }), mxUtils.bind(this, function(err, desc) { //TODO EMBED desc is null here try { this.savingFile = false; if (this.isConflict(err)) { this.inConflictState = true; if (this.sync != null) { //Reduce number of retials since we already retry in AC.saveDraftWithFileDesc this.sync.maxCatchupRetries = 2; this.savingFile = true; this.sync.fileConflict(desc, mxUtils.bind(this, function() { // Adds random cool-off window.setTimeout(mxUtils.bind(this, function() { this.updateFileData(); this.setShadowModified(false); doSave(realOverwrite, true); }), 100 + Math.random() * 500 + (err.isLocked? 500 : 0)); }), 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(overwrite, revision); })); } } catch (e) { if (error != null) { error(e); } else { throw e; } } }; /** * */ EmbedFile.prototype.copyFile = function(success, error) { //Download a copy of the file since it is difficult to add a copy to current confluence page this.updateFileData(); ui.doSaveLocalFile(this.data, this.getTitle(), 'text/xml'); error(); //Since the problem is not fixed //TODO Confirm this is OK?? }; /** * */ EmbedFile.prototype.rename = function(title, success, error) { var etag = this.getCurrentEtag(); this.desc.title = title; ui.remoteInvoke('setFileDescriptor', [this.desc], null, mxUtils.bind(this, function(desc) { this.desc = desc; this.descriptorChanged(); if (this.sync != null) { this.sync.descriptorChanged(etag); } if (success != null) { success(desc); } }), error); }; /** * */ EmbedFile.prototype.getTitle = function() { return this.desc.title || macroData.diagramDisplayName; }; /** * */ EmbedFile.prototype.getHash = function() { return 'E' + this.getId(); }; /** * */ EmbedFile.prototype.getId = function() { return this.desc.id; }; /** * */ EmbedFile.prototype.isSyncSupported = function() { return this.desc.id != null; }; /** * */ EmbedFile.prototype.isRevisionHistorySupported = function() { return true; }; /** * */ EmbedFile.prototype.getLatestVersion = function(success, error) { ui.remoteInvoke('getDraftFileContent', null, null, mxUtils.bind(this, function(data, desc) { success(new EmbedFile(ui, data, desc)); }), error); }; /** * Gets the channel ID from the given descriptor. */ EmbedFile.prototype.getChannelId = function() { var chan = this.desc.channel; if (chan != null) { chan = 'E-' + this.getId() + '.' + chan; } return chan; }; /** * Gets the channel key from the given descriptor. */ EmbedFile.prototype.getChannelKey = function() { return this.desc.key; }; /** * */ EmbedFile.prototype.getLastModifiedDate = function() { return new Date(this.desc.modifiedDate); }; /** * */ 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; }; /** * Returns the secret from the given descriptor. */ EmbedFile.prototype.getDescriptorSecret = function(desc) { return desc.secret; }; /** * Updates the revision ID on the given descriptor. */ EmbedFile.prototype.setDescriptorRevisionId = function(desc, id) { desc.headRevisionId = id; }; /** * Returns the revision ID from the given descriptor. */ EmbedFile.prototype.getDescriptorRevisionId = function(desc) { return desc.headRevisionId; }; /** * */ EmbedFile.prototype.getDescriptorEtag = function(desc) { return desc.etag; }; /** * */ EmbedFile.prototype.setDescriptorEtag = function(desc, etag) { desc.etag = etag; }; /** * */ EmbedFile.prototype.patchDescriptor = function(desc, patch) { DrawioFile.prototype.patchDescriptor.apply(this, arguments); desc.headRevisionId = patch.headRevisionId; desc.modifiedDate = patch.modifiedDate; }; /** * */ EmbedFile.prototype.loadDescriptor = function(success, error) { ui.remoteInvoke('getFileDescriptor', null, null, success, error); }; var allowAutoSave = true; EmbedFile.prototype.isAutosaveNow = function(success, error) { return allowAutoSave; }; //Ensure saving of draft before publishing var origSaveAction = ui.actions.get('save').funct; ui.actions.get('save').funct = function(exit) { var actArgs = arguments; var curFile = ui.getCurrentFile(); var desc = curFile.getDescriptor(); var isNewFile = desc == null || desc.key == null; if (exit) { //Prevent stpping the spinner early by creating our own spinner var spinner = new Spinner({ lines: 12, // The number of lines to draw length: 24, // The length of each line width: 8, // The line thickness radius: 12, // The radius of the inner circle rotate: 0, // The rotation offset color: '#000', // #rgb or #rrggbb speed: 1.5, // Rounds per second trail: 60, // Afterglow percentage shadow: false, // Whether to render a shadow hwaccel: false, // Whether to use hardware acceleration zIndex: 2e9 // The z-index (defaults to 2000000000) }); if (!isNewFile) { spinner.spin(document.body); } allowAutoSave = false; if (desc != null) { desc.viewerSettings = { tbstyle: macroData.tbstyle, links: macroData.links, simple: macroData.simple, lbox: macroData.lbox, zoom: macroData.zoom, pCenter: macroData.pCenter, aspect: macroData.aspect, hiResPreview: macroData.hiResPreview }; } var etag = curFile.getCurrentEtag(); } function doActions() { origSaveAction.apply(ui, actArgs); if (exit && curFile.sync != null) { curFile.sync.descriptorChanged(etag); } }; function doSave() { if (curFile.saveStarted || curFile.savingFile) { setTimeout(doSave, 100); return; } if (curFile.isModified()) { //Save file (draft) first ui.saveFile(null, doActions); } else if (exit) //Save descriptor only to update the viewer settings { ui.remoteInvoke('setFileDescriptor', [desc], null, doActions, doActions); } else { doActions(); } }; if (isNewFile) { //New files are saved directly and descriptor is added during publishing after creating the custom content doActions(); } else { doSave(); } }; var p2pCollab = null; //Add file opening here (or it should be for all in EditorUi?) var origInstallMessageHandler = ui.installMessageHandler; ui.installMessageHandler = function(callback) { origInstallMessageHandler.call(this, function() { callback.apply(this, arguments); var file = ui.getCurrentFile(); file.loadDescriptor(function(desc) { file.desc = desc; ui.fileLoaded(file, true); if (file.desc) { var descChangedNeeded = false; if (file.desc.title && file.desc.title != macroData.diagramDisplayName) { macroData.diagramDisplayName = file.desc.title; descChangedNeeded = true; } if (file.desc.viewerSettings != null) { descChangedNeeded = true; } if (descChangedNeeded) { descriptorChangedListener(); } //RT Cursors if (urlParams['rtCursors'] == '1' && p2pCollab != null) { p2pCollab.joinFile(file.getChannelId()); file.p2pCollab = p2pCollab; } } }); file.addListener('descriptorChanged', descriptorChangedListener); }); } ui.editor.setModified = function() { //Cancel set modified of the editor and use the file's one }; //P2P RT if (urlParams['rtCursors'] == '1') { p2pCollab = new P2PCollab(ui); } });