Allow dropping SVGs into editor [#45]

This commit is contained in:
David Evans 2018-02-02 21:22:30 +00:00
parent 262ac71844
commit 703129d3d0
6 changed files with 136 additions and 20 deletions

View File

@ -9394,6 +9394,15 @@ define('sequence/SequenceDiagram',[
themes.push(theme); themes.push(theme);
} }
function extractCodeFromSVG(svg) {
const dom = new DOMParser().parseFromString(svg, 'image/svg+xml');
const meta = dom.querySelector('metadata');
if(!meta) {
return '';
}
return meta.textContent;
}
class SequenceDiagram extends EventObject { class SequenceDiagram extends EventObject {
constructor(code = null, options = {}) { constructor(code = null, options = {}) {
super(); super();
@ -9538,20 +9547,15 @@ define('sequence/SequenceDiagram',[
} }
} }
extractCodeFromSVG(svg) {
return extractCodeFromSVG(svg);
}
dom() { dom() {
return this.renderer.svg(); return this.renderer.svg();
} }
} }
function extractCodeFromSVG(svg) {
const dom = new DOMParser().parseFromString(svg, 'image/svg+xml');
const meta = dom.querySelector('metadata');
if(!meta) {
return '';
}
return meta.textContent;
}
function convert(element, code = null, options = {}) { function convert(element, code = null, options = {}) {
if(element.tagName === 'svg') { if(element.tagName === 'svg') {
return null; return null;

File diff suppressed because one or more lines are too long

View File

@ -101,6 +101,39 @@ define(['require'], (require) => {
}); });
} }
function hasDroppedFile(event, mime) {
if(!event.dataTransfer.items && event.dataTransfer.files.length === 0) {
// Work around Safari not supporting dataTransfer.items
return [...event.dataTransfer.types].includes('Files');
}
const items = (event.dataTransfer.items || event.dataTransfer.files);
return (items.length === 1 && items[0].type === mime);
}
function getDroppedFile(event, mime) {
const items = (event.dataTransfer.items || event.dataTransfer.files);
if(items.length !== 1 || items[0].type !== mime) {
return null;
}
const item = items[0];
if(item.getAsFile) {
return item.getAsFile();
} else {
return item;
}
}
function getFileContent(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.addEventListener('loadend', () => {
resolve(reader.result);
}, {once: true});
reader.readAsText(file);
});
}
return class Interface { return class Interface {
constructor({ constructor({
sequenceDiagram, sequenceDiagram,
@ -127,6 +160,8 @@ define(['require'], (require) => {
this._downloadSVGClick = this._downloadSVGClick.bind(this); this._downloadSVGClick = this._downloadSVGClick.bind(this);
this._downloadPNGClick = this._downloadPNGClick.bind(this); this._downloadPNGClick = this._downloadPNGClick.bind(this);
this._downloadPNGFocus = this._downloadPNGFocus.bind(this); this._downloadPNGFocus = this._downloadPNGFocus.bind(this);
this._showDropStyle = this._showDropStyle.bind(this);
this._hideDropStyle = this._hideDropStyle.bind(this);
this._enhanceEditor(); this._enhanceEditor();
} }
@ -221,6 +256,28 @@ define(['require'], (require) => {
this.code.focus(); this.code.focus();
} }
}); });
this.container.addEventListener('dragover', (event) => {
event.preventDefault();
if(hasDroppedFile(event, 'image/svg+xml')) {
event.dataTransfer.dropEffect = 'copy';
this._showDropStyle();
} else {
event.dataTransfer.dropEffect = 'none';
}
});
this.container.addEventListener('dragleave', this._hideDropStyle);
this.container.addEventListener('dragend', this._hideDropStyle);
this.container.addEventListener('drop', (event) => {
event.preventDefault();
this._hideDropStyle();
const file = getDroppedFile(event, 'image/svg+xml');
if(file) {
this.loadFile(file);
}
});
} }
buildLibrary(container) { buildLibrary(container) {
@ -303,6 +360,7 @@ define(['require'], (require) => {
} }
build(container) { build(container) {
this.container = container;
const hold = makeNode('div', {'class': 'pane-hold'}); const hold = makeNode('div', {'class': 'pane-hold'});
const lPane = makeNode('div', {'class': 'pane-side'}); const lPane = makeNode('div', {'class': 'pane-side'});
hold.appendChild(lPane); hold.appendChild(lPane);
@ -421,6 +479,27 @@ define(['require'], (require) => {
} }
} }
setValue(code) {
if(this.code.getDoc) {
const doc = this.code.getDoc();
doc.setValue(code);
doc.clearHistory();
} else {
this.code.value = code;
}
this.update(true);
this.diagram.setHighlight(null);
}
loadFile(file) {
return getFileContent(file).then((svg) => {
const code = this.diagram.extractCodeFromSVG(svg);
if(code) {
this.setValue(code);
}
});
}
update(immediate = true) { update(immediate = true) {
const src = this.value(); const src = this.value();
this.saveCode(src); this.saveCode(src);
@ -476,6 +555,14 @@ define(['require'], (require) => {
return true; return true;
} }
_showDropStyle() {
this.container.setAttribute('class', 'drop-target');
}
_hideDropStyle() {
this.container.setAttribute('class', '');
}
_downloadPNGFocus() { _downloadPNGFocus() {
this.updatePNGLink(); this.updatePNGLink();
} }

View File

@ -28,7 +28,10 @@ defineDescribe('Interface', ['./Interface'], (Interface) => {
}); });
sequenceDiagram.getSize.and.returnValue({width: 10, height: 20}); sequenceDiagram.getSize.and.returnValue({width: 10, height: 20});
sequenceDiagram.dom.and.returnValue(document.createElement('svg')); sequenceDiagram.dom.and.returnValue(document.createElement('svg'));
container = jasmine.createSpyObj('container', ['appendChild']); container = jasmine.createSpyObj('container', [
'appendChild',
'addEventListener',
]);
ui = new Interface({ ui = new Interface({
sequenceDiagram, sequenceDiagram,

View File

@ -51,6 +51,15 @@ define([
themes.push(theme); themes.push(theme);
} }
function extractCodeFromSVG(svg) {
const dom = new DOMParser().parseFromString(svg, 'image/svg+xml');
const meta = dom.querySelector('metadata');
if(!meta) {
return '';
}
return meta.textContent;
}
class SequenceDiagram extends EventObject { class SequenceDiagram extends EventObject {
constructor(code = null, options = {}) { constructor(code = null, options = {}) {
super(); super();
@ -195,20 +204,15 @@ define([
} }
} }
extractCodeFromSVG(svg) {
return extractCodeFromSVG(svg);
}
dom() { dom() {
return this.renderer.svg(); return this.renderer.svg();
} }
} }
function extractCodeFromSVG(svg) {
const dom = new DOMParser().parseFromString(svg, 'image/svg+xml');
const meta = dom.querySelector('metadata');
if(!meta) {
return '';
}
return meta.textContent;
}
function convert(element, code = null, options = {}) { function convert(element, code = null, options = {}) {
if(element.tagName === 'svg') { if(element.tagName === 'svg') {
return null; return null;

View File

@ -36,6 +36,24 @@ html, body {
margin: 0 10px 10px; margin: 0 10px 10px;
} }
.drop-target:after {
content: 'Drop SVG to Load Code';
position: absolute;
top: 5px;
left: 5px;
right: 5px;
bottom: 5px;
background: rgba(255, 255, 255, 0.6);
text-shadow: 0 0 3px #FFFFFF;
font-size: 3em;
padding-top: 100px;
text-align: center;
border: 5px solid #88CC66;
border-radius: 20px;
pointer-events: none;
z-index: 99999;
}
.pane-hold { .pane-hold {
position: absolute; position: absolute;
left: 0; left: 0;