8.5.3 release

This commit is contained in:
David Benson 2018-04-04 14:12:26 +01:00
parent 7a7e167f66
commit 52575c1aa0
17 changed files with 1868 additions and 946 deletions

View file

@ -1,3 +1,8 @@
04-MAR-2018: 8.5.3
- Gliffy import improvement
- Fix for anchor download issue in Chrome 65
31-MAR-2018: 8.5.2
- Add mass gliffy import in Confluence Cloud

View file

@ -1 +1 @@
8.5.2
8.5.3

606
etc/slidesaddon/Code.gs Normal file
View file

@ -0,0 +1,606 @@
/**
* Draw.io Diagrams Docs add-on v1.9
* Copyright (c) 2018, JGraph Ltd
*/
var EXPORT_URL = "https://exp.draw.io/ImageExport4/export";
var DRAW_URL = "https://www.draw.io/";
var SCALING_VALUE = 0.8; // Google Docs seem to be downscaling all images by this amount
/**
* Creates a menu entry in the Google Docs UI when the document is opened.
*/
function onOpen()
{
SlidesApp.getUi().createAddonMenu()
.addItem("Insert Diagrams", "insertDiagrams")
.addItem("Update Selected", "updateSelected")
.addItem("Update All", "updateAll")
.addToUi();
}
/**
* Runs when the add-on is installed.
*/
function onInstall()
{
onOpen();
}
/**
* Gets the user's OAuth 2.0 access token so that it can be passed to Picker.
* This technique keeps Picker from needing to show its own authorization
* dialog, but is only possible if the OAuth scope that Picker needs is
* available in Apps Script. In this case, the function includes an unused call
* to a DriveApp method to ensure that Apps Script requests access to all files
* in the user's Drive.
*
* @return {string} The user's OAuth 2.0 access token.
*/
function getOAuthToken() {
DriveApp.getRootFolder();
return ScriptApp.getOAuthToken();
}
/**
* Shows a picker and lets the user select multiple diagrams to insert.
*/
function insertDiagrams()
{
var html = HtmlService.createHtmlOutputFromFile('Picker.html')
.setWidth(620).setHeight(440)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SlidesApp.getUi().showModalDialog(html, 'Select draw.io Diagrams');
}
/**
* Inserts an image for the given diagram.
*/
function pickerHandler(items)
{
var app = UiApp.getActiveApplication();
// Delay after closing the picker used to show spinner on client-side
app.close();
if (items != null && items.length > 0)
{
var inserted = 0;
var errors = [];
// if there are selected items in the slides, assume they are going to be replaced
// by the newly inserted images
var selectionCoordinates = getSelectionCoordinates();
var offsetX = selectionCoordinates[0];
var offsetY = selectionCoordinates[1];
deleteSelectedElements();
var step = 10;
for (var i = 0; i < items.length; i++)
{
try
{
if (insertDiagram(items[i].id, items[i].page, offsetX, offsetY) != null)
{
inserted++;
offsetX = offsetX + step;
offsetY = offsetY + step;
}
else
{
errors.push("- " + items[i].name + ": Unknown error");
}
}
catch (e)
{
errors.push("- " + items[i].name + ": " + e.message);
}
}
// Shows message only in case of errors
if (errors.length > 0)
{
var msg = "";
if (errors.length > 0)
{
msg += errors.length + " insert" + ((errors.length > 1) ? "s" : "") + " failed:\n";
}
msg += errors.join("\n");
SlidesApp.getUi().alert(msg);
}
}
}
/**
Finds left-most and top-most coordinates of selected page elements; (0,0) by default
@return left-most and top-most coordinates in an array
**/
function getSelectionCoordinates()
{
var selection = SlidesApp.getActivePresentation().getSelection();
switch (selection.getSelectionType())
{
case SlidesApp.SelectionType.PAGE_ELEMENT:
{
// only interested if selection is containing page elements
var elements = selection.getPageElementRange();
var top = 1000000;
var left = 1000000;
if (elements)
{
// find the left-most, top-most coordinate of selected elements
var pageElements = elements.getPageElements();
for (var i = 0; i < pageElements.length; i++)
{
var element = pageElements[i];
var elementTop = element.getTop();
var elementLeft = element.getLeft();
if (top > elementTop)
top = elementTop;
if (left > elementLeft)
left = elementLeft;
}
return [left, top];
}
}
}
return [0, 0];
}
/**
Deletes selected elements
**/
function deleteSelectedElements()
{
var selection = SlidesApp.getActivePresentation().getSelection();
switch (selection.getSelectionType())
{
case SlidesApp.SelectionType.PAGE_ELEMENT:
{
// only interested if selection is containing page elements
var elements = selection.getPageElementRange();
if (elements) {
var pageElements = elements.getPageElements();
// find the left-most, top-most coordinate of selected elements
for (var i = 0; i < pageElements.length; i++)
{
// delete all selected page elements
var element = pageElements[i];
element.remove();
}
}
}
}
}
/**
* Inserts the given diagram at the given position.
*/
function insertDiagram(id, page, offsetX, offsetY)
{
var scale = 2;
var result = fetchImage(id, page, scale);
var blob = result[0];
var w = result[1] * SCALING_VALUE;
var h = result[2] * SCALING_VALUE;
var img = null;
if (blob != null)
{
var slide = SlidesApp.getActivePresentation().getSelection().getCurrentPage().asSlide();
var img = slide.insertImage(blob);
img.setLeft(offsetX);
img.setTop(offsetY);
var wmax = SlidesApp.getActivePresentation().getPageWidth();
var hmax = SlidesApp.getActivePresentation().getPageHeight();
var link = createLink(id, page, scale);
img.setLinkUrl(link);
// Scales to document width if not placeholder
if (w == 0 && h == 0) {
var w = img.getWidth();
var h = img.getHeight();
}
var nw = w;
var nh = h;
// adjust scale (retina/HiDPI display support)
w /= scale;
h /= scale;
if (wmax > 0 && w > wmax)
{
var aspect = w / h;
// Keeps width and aspect
nw = wmax;
nh = wmax / aspect;
}
else if (hmax > 0 && h > hmax) {
var aspect = h / w;
// Keeps height and aspect
nh = hmax;
nw = hmax / aspect;
}
img.setWidth(w);
img.setHeight(h);
}
else
{
throw new Error("Invalid image " + id);
}
return img;
}
/**
* Updates the selected diagrams in-place.
*/
function updateSelected()
{
var selection = SlidesApp.getActivePresentation().getSelection();
if (selection)
{
switch (selection.getSelectionType())
{
case SlidesApp.SelectionType.PAGE_ELEMENT:
{
var selected = selection.getPageElementRange();
if (!selected)
return;
selected = selected.getPageElements();
var elts = [];
// Unwraps selection elements
for (var i = 0; i < selected.length; i++)
{
var pageElement = selected[i];
switch (pageElement.getPageElementType())
{
case SlidesApp.PageElementType.IMAGE:
{
elts.push(selected[i].asImage());
}
}
}
updateElements(elts);
}
}
}
else
{
SlidesApp.getUi().alert("No selection");
}
}
/**
* Updates all diagrams in the document.
*/
function updateAll()
{
// collect all slides
var slides = SlidesApp.getActivePresentation().getSlides();
var images = [];
for (var i = 0; i < slides.length; i++)
{
// collect all images on all slides
var slide = slides[i];
var slideImages = slide.getImages();
images = images.concat(slideImages);
}
updateElements(images);
}
/**
* Updates all diagrams in the document.
*/
function updateElements(elts)
{
if (elts != null)
{
var updated = 0;
var errors = [];
for (var i = 0; i < elts.length; i++)
{
try
{
if (updateElement(elts[i]) != null)
{
updated++;
}
}
catch (e)
{
errors.push("- " + e.message);
}
}
// Shows status in case of errors or multiple updates
if (errors.length > 0 || updated > 1)
{
var msg = "";
if (updated > 0)
{
msg += updated + " diagram" + ((updated > 1) ? "s" : "") + " updated\n";
}
if (errors.length > 0)
{
msg += errors.length + " update" + ((errors.length > 1) ? "s" : "") + " failed:\n";
}
msg += errors.join("\n");
SlidesApp.getUi().alert(msg);
}
}
}
/**
* Returns true if the given URL points to draw.io
*/
function createLink(id, page, scale)
{
var params = [];
if (page != null && page != "0")
{
params.push('page=' + page);
}
// This URL parameter is ignored and is used internally to
// store the retina flag since there is no other storage
if (scale != null && scale != 1)
{
params.push('scale=' + scale);
}
return DRAW_URL + ((params.length > 0) ? "?" + params.join("&") : "") + "#G" + id;
}
/**
* Returns true if the given URL points to draw.io
*/
function isValidLink(url)
{
return url != null && (url.substring(0, DRAW_URL.length) == DRAW_URL || url.substring(0, 22) == "https://drive.draw.io/");
}
/**
* Returns the diagram ID for the given URL.
*/
function getDiagramId(url)
{
return url.substring(url.lastIndexOf("#G") + 2);
}
/**
* Returns the diagram ID for the given URL.
*/
function getUrlParams(url)
{
var result = {};
var idx = url.indexOf("?");
if (idx > 0)
{
var idx2 = url.indexOf("#", idx + 1);
if (idx2 < 0)
{
idx2 = url.length;
}
if (idx2 > idx)
{
var search = url.substring(idx + 1, idx2);
var tokens = search.split("&");
for (var i = 0; i < tokens.length; i++)
{
var idx3 = tokens[i].indexOf('=');
if (idx3 > 0)
{
result[tokens[i].substring(0, idx3)] = tokens[i].substring(idx3 + 1);
}
}
}
}
return result;
}
/**
* Updates the diagram in the given inline image and returns the new inline image.
*/
function updateElement(elt)
{
var result = null;
if (elt.getPageElementType() == SlidesApp.PageElementType.IMAGE)
{
var url = elt.getLink();
if (url != null)
url = url.getUrl();
if (url == null)
{
// commenting this out - missing link is most of the time an indicator image is not coming from draw.io
// we probably don't want to have this popping out as an error
// throw new Error("Missing link")
}
else if (isValidLink(url))
{
var id = getDiagramId(url);
var params = getUrlParams(url);
if (id != null && id.length > 0)
{
result = updateDiagram(id, params["page"], parseFloat(params["scale"] || 1), elt);
}
else
{
// commenting this out as well - invalid link might indicate image is not coming from draw.io
// throw new Error("Invalid link " + url);
}
}
}
return result;
}
/**
* Updates the diagram in the given inline image and returns the new inline image.
*/
function updateDiagram(id, page, scale, elt)
{
var img = null;
var result = fetchImage(id, page, scale);
var isOK = false;
if (result != null)
{
var blob = result[0];
var w = result[1] / scale;
var h = result[2] / scale;
if (blob != null)
{
isOK = true;
// There doesn't seem to be a natural way to replace images in SlidesApp
// Slides API seems to only provide means to get a page and a group associated with the image
// Groups only allow removal of elements though, not insertions (seems like a half-baked API)
// This code just adds a new image to page to the same position as the old image and removes the old image
// TODO: No group information will be preserved right now
// TODO: A question about it was posted here:
// TODO: https://plus.google.com/111221846870143003075/posts/EPAM8HrZhe2
// TODO: if there is a satisfying answer, it will be implemented
var page = elt.getParentPage();
var left = elt.getLeft();
var top = elt.getTop();
var width = elt.getWidth();
var height = elt.getHeight();
// This part addresses the possibility of updated diagrams having completely different shapes,
// causing diagrams no longer fitting into page
// Keep top-left corner, adjust width x height
// keep either original width or height together with new aspect ratio
if (w == 0 && h == 0)
{
w = width;
h = height;
}
// make sure dimensions are reasonable
if (w == 0 || h == 0)
throw new Error("One or both image dimensions are zero!");
var nw = w;
var nh = h;
// if aspect w/h < 1, use original width, otherwise use original height
// i.e. the smaller dimension keeps preserved (seems more natural while testing than preserving the larger dimension; can be changed anyway)
var aspect = w / h;
if (aspect < 1)
{
nw = width;
nh = width / aspect;
}
else
{
nw = height * aspect;
nh = height;
}
// now check if the image is still not too large
var wmax = SlidesApp.getActivePresentation().getPageWidth();
var hmax = SlidesApp.getActivePresentation().getPageHeight();
if (wmax > 0 && w > wmax)
{
aspect = w / h;
// Keeps width and aspect
nw = wmax;
nh = wmax / aspect;
}
else if (hmax > 0 && h > hmax) {
aspect = h / w;
// Keeps height and aspect
nh = hmax;
nw = hmax / aspect;
}
// make sure image is at least 1 pixel wide/high
nw = Math.max(1, nw);
nh = Math.max(1, nh);
// replace image with the same link
var img = page.insertImage(blob, left, top, nw, nh);
var link = createLink(id, page, scale);
img.setLinkUrl(link);
elt.remove();
}
}
if (!isOK)
{
throw new Error("Invalid image " + id);
}
return img;
}
/**
* Fetches the diagram for the given document ID.
*/
function fetchImage(id, page, scale)
{
var file = DriveApp.getFileById(id);
if (file != null && file.getSize() > 0)
{
var response = UrlFetchApp.fetch(EXPORT_URL,
{
"method": "post",
"payload":
{
"format": "png",
"scale": scale || "1",
// "border": (scale == 2) ? "1" : "0", // not sure why it was set to 1, it looks better with 0 now, so I commented it out
"border": "0",
"from": page || "0",
"xml": encodeURIComponent(file.getBlob().getDataAsString())
}
});
var headers = response.getHeaders();
return [response.getBlob(), headers["content-ex-width"] || 0, headers["content-ex-height"] || 0];
}
else
{
// Returns an empty, transparent 1x1 PNG image as a placeholder
return Utilities.newBlob(Utilities.base64Decode("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNg+M9QDwADgQF/e5IkGQAAAABJRU5ErkJggg=="), "image/png");
}
}

252
etc/slidesaddon/Picker.html Normal file
View file

@ -0,0 +1,252 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<script type="text/javascript">
var DIALOG_DIMENSIONS = {width: 600, height: 420};
var DEVELOPER_KEY = 'AIzaSyB4sU8tc25bR_87qNb7eUVQN72_vv8mpbU';
/**
* Loads the Google Picker API.
*/
function onApiLoad()
{
gapi.load('picker', {'callback': function()
{
getOAuthToken();
}});
}
/**
* Gets the user's OAuth 2.0 access token from the server-side script so that
* it can be passed to Picker. This technique keeps Picker from needing to
* show its own authorization dialog, but is only possible if the OAuth scope
* that Picker needs is available in Apps Script. Otherwise, your Picker code
* will need to declare its own OAuth scopes.
*/
function getOAuthToken()
{
try
{
google.script.run.withSuccessHandler(createPicker)
.withFailureHandler(showError).getOAuthToken();
}
catch (e)
{
showError(e.message);
}
}
/**
* Creates a Picker that can access the user's spreadsheets. This function
* uses advanced options to hide the Picker's left navigation panel and
* default title bar.
*
* @param {string} token An OAuth 2.0 access token that lets Picker access the
* file type specified in the addView call.
*/
function createPicker(token)
{
if (token)
{
var view1 = new google.picker.DocsView(google.picker.ViewId.FOLDERS)
.setParent('root')
.setIncludeFolders(true)
.setMimeTypes('*/*');
var view2 = new google.picker.DocsView()
.setIncludeFolders(true);
var view3 = new google.picker.DocsView()
.setEnableTeamDrives(true)
.setIncludeFolders(true);
var view4 = new google.picker.DocsUploadView()
.setIncludeFolders(true);
var picker = new google.picker.PickerBuilder()
.addView(view1)
.addView(view2)
.addView(view3)
.addView(view4)
.addView(google.picker.ViewId.RECENTLY_PICKED)
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.enableFeature(google.picker.Feature.SUPPORT_TEAM_DRIVES)
.hideTitleBar()
.setOAuthToken(token)
.setDeveloperKey(DEVELOPER_KEY)
.setCallback(pickerCallback)
.setOrigin(google.script.host.origin)
.setSize(DIALOG_DIMENSIONS.width - 2, DIALOG_DIMENSIONS.height - 2)
.build();
picker.setVisible(true);
}
else
{
showError('Unable to load the file picker.');
}
}
/**
* A callback function that extracts the chosen document's metadata from the
* response object. For details on the response object, see
* https://developers.google.com/picker/docs/result
*
* @param {object} data The response object.
*/
function pickerCallback(data)
{
var action = data[google.picker.Response.ACTION];
if (action == google.picker.Action.PICKED)
{
var items = [];
var docs = data[google.picker.Response.DOCUMENTS];
for (var i = 0; i < docs.length; i++)
{
items.push({name: docs[i][google.picker.Document.NAME], id: docs[i][google.picker.Document.ID]});
}
if (items.length > 0)
{
selectPages(items, function(execute)
{
if (execute)
{
document.getElementById('status').innerHTML = (items.length > 1) ?
'Inserting ' + items.length + ' Diagrams...' : "Inserting Diagram...";
google.script.run.withSuccessHandler(closeWindow).pickerHandler(items);
}
else
{
google.script.host.close();
}
});
}
else
{
google.script.host.close();
}
}
else if (action == google.picker.Action.CANCEL)
{
google.script.host.close();
}
}
/**
* Closes the window after all diagrams have been inserted.
*/
function selectPages(items, handler)
{
document.getElementById('spinner').style.display = 'none';
var pageInputs = [];
var table = document.createElement('table');
table.setAttribute('cellpadding', '4');
table.style.width = '100%';
var tbody = document.createElement('tbody');
var title = document.createElement('td');
title.setAttribute('colspan', '2');
title.innerHTML = '<font size="3">Select ' + ((items.length > 1) ? 'Pages' : 'Page') +
' and Click Insert</font>';
var row = document.createElement('tr');
row.appendChild(title);
tbody.appendChild(row);
for (var i = 0; i < items.length; i++)
{
var row = document.createElement('tr');
var td1 = document.createElement('td');
td1.appendChild(document.createTextNode(items[i].name));
td1.setAttribute('title', 'ID ' + items[i].id);
row.appendChild(td1);
var td2 = document.createElement('td');
td2.style.paddingLeft = '10px';
td2.setAttribute('align', 'right');
td2.innerHTML = 'Page: ';
var input = document.createElement('input');
input.setAttribute('type', 'number');
input.setAttribute('min', '1');
input.setAttribute('value', '1');
input.style.width = '60px';
td2.appendChild(input);
pageInputs.push(input);
row.appendChild(td2);
tbody.appendChild(row);
}
var buttons = document.createElement('td');
buttons.setAttribute('colspan', '2');
buttons.setAttribute('align', 'right');
var cancelButton = document.createElement('button');
cancelButton.innerHTML = 'Cancel';
buttons.appendChild(cancelButton);
cancelButton.addEventListener('click', function()
{
handler(false);
});
var insertButton = document.createElement('button');
insertButton.innerHTML = 'Insert';
insertButton.className = 'blue';
buttons.appendChild(insertButton);
insertButton.addEventListener('click', function()
{
table.parentNode.removeChild(table);
document.getElementById('spinner').style.display = '';
for (var i = 0; i < items.length; i++)
{
items[i].page = (parseInt(pageInputs[i].value) || 1) - 1;
}
handler(true);
});
var row = document.createElement('tr');
row.appendChild(buttons);
tbody.appendChild(row);
table.appendChild(tbody);
document.body.appendChild(table);
}
/**
* Closes the window after all diagrams have been inserted.
*/
function closeWindow()
{
google.script.host.close();
}
/**
* Displays an error message within the #result element.
*
* @param {string} message The error message to display.
*/
function showError(message)
{
document.getElementById('icon').setAttribute('src', 'https://www.draw.io/images/stop-flat-icon-80.png');
document.getElementById('status').innerHTML = 'Error: ' + message;
}
</script>
</head>
<body>
<div id="spinner" style="text-align:center;padding-top:100px;">
<img id="icon" src="https://www.draw.io/images/ajax-loader.gif"/>
<h3 id="status" style="margin-top:6px;">Loading...</h3>
</div>
<script src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>

15
etc/slidesaddon/README Normal file
View file

@ -0,0 +1,15 @@
For Testing:
As david.benson@appsscripttesting.com use (see Tools, Script Editor):
- TBA -
For Deployment:
As david@jgraph.com use (see Tools, Script Editor):
- TBA -
Open the web app script in the script editor.
Make the changes you wanted. Test the code to ensure it functions as intended and is bug-free.
Click File > Manage Versions. Enter a new version description and click Save New Version. Click OK to close the dialog.
Click Publish > Deploy as Docs add-on. Update the Project version to the new version you just created.
Click Update.

View file

@ -1121,8 +1121,7 @@ com.gliffy.shape.network.network_v3.business.comm_link=mxgraph.networks.comm_lin
com.gliffy.shape.network.network_v3.business.user=image;image=img/lib/clip_art/people/Tech_Man_128x128.png
com.gliffy.shape.network.network_v3.business.user_female=image;image=img/lib/clip_art/people/Worker_Woman_128x128.png
com.gliffy.shape.network.network_v3.business.user_male=image;image=img/lib/clip_art/people/Tech_Man_128x128.png
#composite
com.gliffy.shape.network.network_v3.business.user_group=rect
com.gliffy.shape.network.network_v3.business.user_group=mxgraph.networks.users;strokeColor=#ffffff
com.gliffy.shape.network.network_v3.business.server=image;image=img/lib/clip_art/computers/Server_Tower_128x128.png
com.gliffy.shape.network.network_v3.business.database_server=image;image=img/lib/clip_art/computers/Server_Tower_128x128.png
com.gliffy.shape.network.network_v3.business.mail_server=image;image=img/lib/clip_art/computers/Server_Tower_128x128.png
@ -1141,7 +1140,7 @@ com.gliffy.shape.network.network_v3.business.mainframe=image;image=img/lib/clip_
com.gliffy.shape.network.network_v3.business.rack_server_1u=image;image=img/lib/clip_art/computers/Server_128x128.png
com.gliffy.shape.network.network_v3.business.multi_u_server=image;image=img/lib/clip_art/computers/Server_128x128.png
com.gliffy.shape.network.network_v3.business.rack=image;image=img/lib/clip_art/computers/Server_Rack_Empty_128x128.png
#com.gliffy.shape.network.network_v3.business.telephone=
com.gliffy.shape.network.network_v3.business.telephone=image;image=img/lib/clip_art/telecommunication/iPhone_128x128.png
#com.gliffy.shape.network.network_v3.business.flash_drive=
#It needs a new modern icon to match the remaining icons
com.gliffy.shape.network.network_v3.business.tape_backup=mxgraph.networks.tape_storage;strokeColor=#ffffff

View file

@ -1,7 +1,7 @@
CACHE MANIFEST
# THIS FILE WAS GENERATED. DO NOT MODIFY!
# 03/31/2018 02:35 PM
# 04/04/2018 01:26 PM
app.html
index.html?offline=1

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -4306,8 +4306,8 @@ App.prototype.convertFile = function(url, filename, mimeType, extension, success
gitHubUrl = true;
}
// Workaround for wrong binary response with VSDX files
if (/\.vsdx$/i.test(filename) && Graph.fileSupport && new XMLHttpRequest().upload &&
// Workaround for wrong binary response with VSDX/VSD files
if ((/\.vsdx$/i.test(filename) || /\.vsd$/i.test(filename)) && Graph.fileSupport && new XMLHttpRequest().upload &&
typeof new XMLHttpRequest().responseType === 'string')
{
var req = new XMLHttpRequest();
@ -4335,7 +4335,7 @@ App.prototype.convertFile = function(url, filename, mimeType, extension, success
this.importVisio(blob, mxUtils.bind(this, function(xml)
{
success(new LocalFile(this, xml, name, true));
}), error)
}), error, filename)
});
req.send();

View file

@ -2156,12 +2156,12 @@
}
});
if (file != null && img != null && ((/(\.vsdx)($|\?)/i.test(img)) || /(\.vssx)($|\?)/i.test(img)))
if (file != null && img != null && ((/(\.vsdx)($|\?)/i.test(img)) || /(\.vssx)($|\?)/i.test(img) || (/(\.vsd)($|\?)/i.test(img))))
{
this.importVisio(file, function(xml)
{
doImport(xml, 'text/xml');
});
}, null, img);
}
else if (!this.isOffline() && new XMLHttpRequest().upload && this.isRemoteFileFormat(data, img) && file != null)
{
@ -2745,12 +2745,8 @@
{
a.download = filename;
}
else
{
// Workaround for same window in Safari
a.setAttribute('target', '_blank');
}
a.setAttribute('target', '_blank');
document.body.appendChild(a);
try
@ -5389,8 +5385,10 @@
/**
* Imports the given Visio file
*/
EditorUi.prototype.importVisio = function(file, done, onerror)
EditorUi.prototype.importVisio = function(file, done, onerror, filename)
{
filename = (filename != null) ? filename : file.name;
onerror = (onerror != null) ? onerror : mxUtils.bind(this, function(e)
{
this.handleError(e);
@ -5402,13 +5400,47 @@
if (this.doImportVisio)
{
try
if (/(\.vsd)($|\?)/i.test(filename))
{
this.doImportVisio(file, done, onerror);
}
catch (e)
{
onerror(e);
var formData = new FormData();
formData.append("file1", file);
var xhr = new XMLHttpRequest();
xhr.open('POST', VSD_CONVERT_URL);
xhr.responseType = "blob";
xhr.onreadystatechange = mxUtils.bind(this, function()
{
if (xhr.readyState == 4)
{
if (xhr.status >= 200 && xhr.status <= 299)
{
try
{
this.doImportVisio(xhr.response, done, onerror);
}
catch (e)
{
onerror(e);
}
}
else
{
onerror({});
}
}
});
xhr.send(formData);
} else {
try
{
this.doImportVisio(file, done, onerror);
}
catch (e)
{
onerror(e);
}
}
}
});
@ -5874,7 +5906,11 @@
}
}));
}
else if (file != null && filename != null && ((/(\.vsdx)($|\?)/i.test(filename)) || /(\.vssx)($|\?)/i.test(filename)))
// else if (file != null && filename != null && ((/(\.vsdx)($|\?)/i.test(filename)) || /(\.vssx)($|\?)/i.test(filename) || /(\.vsd)($|\?)/i.test(filename)))
// {
//
// }
else if (file != null && filename != null && ((/(\.vsdx)($|\?)/i.test(filename)) || /(\.vssx)($|\?)/i.test(filename) || /(\.vsd)($|\?)/i.test(filename)))
{
// LATER: done and async are a hack before making this asynchronous
async = true;
@ -6282,7 +6318,7 @@
});
// Handles special cases
if (/(\.vsdx)($|\?)/i.test(file.name) || /(\.vssx)($|\?)/i.test(file.name))
if (/(\.vsdx)($|\?)/i.test(file.name) || /(\.vssx)($|\?)/i.test(file.name) || /(\.vsd)($|\?)/i.test(file.name))
{
fn(null, file.type, x + index * gs, y + index * gs, 240, 160, file.name, function(cells)
{
@ -8091,7 +8127,7 @@
}
});
if (/(\.vsdx)($|\?)/i.test(name) || /(\.vssx)($|\?)/i.test(name))
if (/(\.vsdx)($|\?)/i.test(name) || /(\.vssx)($|\?)/i.test(name) || /(\.vsd)($|\?)/i.test(name))
{
this.importVisio(file, mxUtils.bind(this, function(xml)
{

View file

@ -9,6 +9,7 @@ window.isSvgBrowser = window.isSvgBrowser || (navigator.userAgent.indexOf('MSIE'
// CUSTOM_PARAMETERS - URLs for save and export
window.EXPORT_URL = window.EXPORT_URL || 'https://exp.draw.io/ImageExport4/export';
window.VSD_CONVERT_URL = window.VSD_CONVERT_URL || "https://convert.draw.io/VsdConverter/api/converter";
window.SAVE_URL = window.SAVE_URL || 'save';
window.OPEN_URL = window.OPEN_URL || 'open';
window.PROXY_URL = window.PROXY_URL || 'proxy';

View file

@ -184,7 +184,7 @@ f)+"\n"+t+"}":"{"+z.join(",")+"}";f=t;return l}}"function"!==typeof Date.prototy
e=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,f,g,h={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},k;"function"!==typeof JSON.stringify&&(JSON.stringify=function(a,b,d){var e;g=f="";if("number"===typeof d)for(e=0;e<d;e+=1)g+=" ";else"string"===typeof d&&(g=d);if((k=b)&&"function"!==typeof b&&("object"!==typeof b||"number"!==typeof b.length))throw Error("JSON.stringify");return c("",{"":a})});
"function"!==typeof JSON.parse&&(JSON.parse=function(a,b){function c(a,d){var e,f,g=a[d];if(g&&"object"===typeof g)for(e in g)Object.prototype.hasOwnProperty.call(g,e)&&(f=c(g,e),void 0!==f?g[e]=f:delete g[e]);return b.call(a,d,g)}var e;a=""+a;d.lastIndex=0;d.test(a)&&(a=a.replace(d,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return e=eval("("+a+")"),"function"===typeof b?c({"":e},""):e;throw new SyntaxError("JSON.parse");})})();"undefined"===typeof window.mxBasePath&&(window.mxBasePath="https://www.draw.io/mxgraph/");window.mxLoadStylesheets=window.mxLoadStylesheets||!1;window.mxLoadResources=window.mxLoadResources||!1;window.mxLanguage=window.mxLanguage||"en";window.urlParams=window.urlParams||{};window.MAX_REQUEST_SIZE=window.MAX_REQUEST_SIZE||10485760;window.MAX_AREA=window.MAX_AREA||225E6;window.EXPORT_URL=window.EXPORT_URL||"/export";window.SAVE_URL=window.SAVE_URL||"/save";window.OPEN_URL=window.OPEN_URL||"/open";window.RESOURCES_PATH=window.RESOURCES_PATH||"resources";window.RESOURCE_BASE=window.RESOURCE_BASE||window.RESOURCES_PATH+"/grapheditor";window.STENCIL_PATH=window.STENCIL_PATH||"stencils";window.IMAGE_PATH=window.IMAGE_PATH||"images";
window.STYLE_PATH=window.STYLE_PATH||"styles";window.CSS_PATH=window.CSS_PATH||"styles";window.OPEN_FORM=window.OPEN_FORM||"open.html";window.mxBasePath=window.mxBasePath||"../../../src";window.mxLanguage=window.mxLanguage||urlParams.lang;window.mxLanguages=window.mxLanguages||["de"];var mxClient={VERSION:"8.5.2",IS_IE:0<=navigator.userAgent.indexOf("MSIE"),IS_IE6:0<=navigator.userAgent.indexOf("MSIE 6"),IS_IE11:!!navigator.userAgent.match(/Trident\/7\./),IS_EDGE:!!navigator.userAgent.match(/Edge\//),IS_QUIRKS:0<=navigator.userAgent.indexOf("MSIE")&&(null==document.documentMode||5==document.documentMode),IS_EM:"spellcheck"in document.createElement("textarea")&&8==document.documentMode,VML_PREFIX:"v",OFFICE_PREFIX:"o",IS_NS:0<=navigator.userAgent.indexOf("Mozilla/")&&0>navigator.userAgent.indexOf("MSIE")&&
window.STYLE_PATH=window.STYLE_PATH||"styles";window.CSS_PATH=window.CSS_PATH||"styles";window.OPEN_FORM=window.OPEN_FORM||"open.html";window.mxBasePath=window.mxBasePath||"../../../src";window.mxLanguage=window.mxLanguage||urlParams.lang;window.mxLanguages=window.mxLanguages||["de"];var mxClient={VERSION:"8.5.3",IS_IE:0<=navigator.userAgent.indexOf("MSIE"),IS_IE6:0<=navigator.userAgent.indexOf("MSIE 6"),IS_IE11:!!navigator.userAgent.match(/Trident\/7\./),IS_EDGE:!!navigator.userAgent.match(/Edge\//),IS_QUIRKS:0<=navigator.userAgent.indexOf("MSIE")&&(null==document.documentMode||5==document.documentMode),IS_EM:"spellcheck"in document.createElement("textarea")&&8==document.documentMode,VML_PREFIX:"v",OFFICE_PREFIX:"o",IS_NS:0<=navigator.userAgent.indexOf("Mozilla/")&&0>navigator.userAgent.indexOf("MSIE")&&
0>navigator.userAgent.indexOf("Edge/"),IS_OP:0<=navigator.userAgent.indexOf("Opera/")||0<=navigator.userAgent.indexOf("OPR/"),IS_OT:0<=navigator.userAgent.indexOf("Presto/")&&0>navigator.userAgent.indexOf("Presto/2.4.")&&0>navigator.userAgent.indexOf("Presto/2.3.")&&0>navigator.userAgent.indexOf("Presto/2.2.")&&0>navigator.userAgent.indexOf("Presto/2.1.")&&0>navigator.userAgent.indexOf("Presto/2.0.")&&0>navigator.userAgent.indexOf("Presto/1."),IS_SF:0<=navigator.userAgent.indexOf("AppleWebKit/")&&
0>navigator.userAgent.indexOf("Chrome/")&&0>navigator.userAgent.indexOf("Edge/"),IS_IOS:navigator.userAgent.match(/(iPad|iPhone|iPod)/g)?!0:!1,IS_GC:0<=navigator.userAgent.indexOf("Chrome/")&&0>navigator.userAgent.indexOf("Edge/"),IS_CHROMEAPP:null!=window.chrome&&null!=chrome.app&&null!=chrome.app.runtime,IS_FF:0<=navigator.userAgent.indexOf("Firefox/"),IS_MT:0<=navigator.userAgent.indexOf("Firefox/")&&0>navigator.userAgent.indexOf("Firefox/1.")&&0>navigator.userAgent.indexOf("Firefox/2.")||0<=navigator.userAgent.indexOf("Iceweasel/")&&
0>navigator.userAgent.indexOf("Iceweasel/1.")&&0>navigator.userAgent.indexOf("Iceweasel/2.")||0<=navigator.userAgent.indexOf("SeaMonkey/")&&0>navigator.userAgent.indexOf("SeaMonkey/1.")||0<=navigator.userAgent.indexOf("Iceape/")&&0>navigator.userAgent.indexOf("Iceape/1."),IS_SVG:0<=navigator.userAgent.indexOf("Firefox/")||0<=navigator.userAgent.indexOf("Iceweasel/")||0<=navigator.userAgent.indexOf("Seamonkey/")||0<=navigator.userAgent.indexOf("Iceape/")||0<=navigator.userAgent.indexOf("Galeon/")||

View file

@ -184,7 +184,7 @@ f)+"\n"+t+"}":"{"+z.join(",")+"}";f=t;return l}}"function"!==typeof Date.prototy
e=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,f,g,h={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},k;"function"!==typeof JSON.stringify&&(JSON.stringify=function(a,b,d){var e;g=f="";if("number"===typeof d)for(e=0;e<d;e+=1)g+=" ";else"string"===typeof d&&(g=d);if((k=b)&&"function"!==typeof b&&("object"!==typeof b||"number"!==typeof b.length))throw Error("JSON.stringify");return c("",{"":a})});
"function"!==typeof JSON.parse&&(JSON.parse=function(a,b){function c(a,d){var e,f,g=a[d];if(g&&"object"===typeof g)for(e in g)Object.prototype.hasOwnProperty.call(g,e)&&(f=c(g,e),void 0!==f?g[e]=f:delete g[e]);return b.call(a,d,g)}var e;a=""+a;d.lastIndex=0;d.test(a)&&(a=a.replace(d,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return e=eval("("+a+")"),"function"===typeof b?c({"":e},""):e;throw new SyntaxError("JSON.parse");})})();"undefined"===typeof window.mxBasePath&&(window.mxBasePath="https://www.draw.io/mxgraph/");window.mxLoadStylesheets=window.mxLoadStylesheets||!1;window.mxLoadResources=window.mxLoadResources||!1;window.mxLanguage=window.mxLanguage||"en";window.urlParams=window.urlParams||{};window.MAX_REQUEST_SIZE=window.MAX_REQUEST_SIZE||10485760;window.MAX_AREA=window.MAX_AREA||225E6;window.EXPORT_URL=window.EXPORT_URL||"/export";window.SAVE_URL=window.SAVE_URL||"/save";window.OPEN_URL=window.OPEN_URL||"/open";window.RESOURCES_PATH=window.RESOURCES_PATH||"resources";window.RESOURCE_BASE=window.RESOURCE_BASE||window.RESOURCES_PATH+"/grapheditor";window.STENCIL_PATH=window.STENCIL_PATH||"stencils";window.IMAGE_PATH=window.IMAGE_PATH||"images";
window.STYLE_PATH=window.STYLE_PATH||"styles";window.CSS_PATH=window.CSS_PATH||"styles";window.OPEN_FORM=window.OPEN_FORM||"open.html";window.mxBasePath=window.mxBasePath||"../../../src";window.mxLanguage=window.mxLanguage||urlParams.lang;window.mxLanguages=window.mxLanguages||["de"];var mxClient={VERSION:"8.5.2",IS_IE:0<=navigator.userAgent.indexOf("MSIE"),IS_IE6:0<=navigator.userAgent.indexOf("MSIE 6"),IS_IE11:!!navigator.userAgent.match(/Trident\/7\./),IS_EDGE:!!navigator.userAgent.match(/Edge\//),IS_QUIRKS:0<=navigator.userAgent.indexOf("MSIE")&&(null==document.documentMode||5==document.documentMode),IS_EM:"spellcheck"in document.createElement("textarea")&&8==document.documentMode,VML_PREFIX:"v",OFFICE_PREFIX:"o",IS_NS:0<=navigator.userAgent.indexOf("Mozilla/")&&0>navigator.userAgent.indexOf("MSIE")&&
window.STYLE_PATH=window.STYLE_PATH||"styles";window.CSS_PATH=window.CSS_PATH||"styles";window.OPEN_FORM=window.OPEN_FORM||"open.html";window.mxBasePath=window.mxBasePath||"../../../src";window.mxLanguage=window.mxLanguage||urlParams.lang;window.mxLanguages=window.mxLanguages||["de"];var mxClient={VERSION:"8.5.3",IS_IE:0<=navigator.userAgent.indexOf("MSIE"),IS_IE6:0<=navigator.userAgent.indexOf("MSIE 6"),IS_IE11:!!navigator.userAgent.match(/Trident\/7\./),IS_EDGE:!!navigator.userAgent.match(/Edge\//),IS_QUIRKS:0<=navigator.userAgent.indexOf("MSIE")&&(null==document.documentMode||5==document.documentMode),IS_EM:"spellcheck"in document.createElement("textarea")&&8==document.documentMode,VML_PREFIX:"v",OFFICE_PREFIX:"o",IS_NS:0<=navigator.userAgent.indexOf("Mozilla/")&&0>navigator.userAgent.indexOf("MSIE")&&
0>navigator.userAgent.indexOf("Edge/"),IS_OP:0<=navigator.userAgent.indexOf("Opera/")||0<=navigator.userAgent.indexOf("OPR/"),IS_OT:0<=navigator.userAgent.indexOf("Presto/")&&0>navigator.userAgent.indexOf("Presto/2.4.")&&0>navigator.userAgent.indexOf("Presto/2.3.")&&0>navigator.userAgent.indexOf("Presto/2.2.")&&0>navigator.userAgent.indexOf("Presto/2.1.")&&0>navigator.userAgent.indexOf("Presto/2.0.")&&0>navigator.userAgent.indexOf("Presto/1."),IS_SF:0<=navigator.userAgent.indexOf("AppleWebKit/")&&
0>navigator.userAgent.indexOf("Chrome/")&&0>navigator.userAgent.indexOf("Edge/"),IS_IOS:navigator.userAgent.match(/(iPad|iPhone|iPod)/g)?!0:!1,IS_GC:0<=navigator.userAgent.indexOf("Chrome/")&&0>navigator.userAgent.indexOf("Edge/"),IS_CHROMEAPP:null!=window.chrome&&null!=chrome.app&&null!=chrome.app.runtime,IS_FF:0<=navigator.userAgent.indexOf("Firefox/"),IS_MT:0<=navigator.userAgent.indexOf("Firefox/")&&0>navigator.userAgent.indexOf("Firefox/1.")&&0>navigator.userAgent.indexOf("Firefox/2.")||0<=navigator.userAgent.indexOf("Iceweasel/")&&
0>navigator.userAgent.indexOf("Iceweasel/1.")&&0>navigator.userAgent.indexOf("Iceweasel/2.")||0<=navigator.userAgent.indexOf("SeaMonkey/")&&0>navigator.userAgent.indexOf("SeaMonkey/1.")||0<=navigator.userAgent.indexOf("Iceape/")&&0>navigator.userAgent.indexOf("Iceape/1."),IS_SVG:0<=navigator.userAgent.indexOf("Firefox/")||0<=navigator.userAgent.indexOf("Iceweasel/")||0<=navigator.userAgent.indexOf("Seamonkey/")||0<=navigator.userAgent.indexOf("Iceape/")||0<=navigator.userAgent.indexOf("Galeon/")||

File diff suppressed because one or more lines are too long