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);
}
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 {
constructor(code = null, options = {}) {
super();
@ -9538,20 +9547,15 @@ define('sequence/SequenceDiagram',[
}
}
extractCodeFromSVG(svg) {
return extractCodeFromSVG(svg);
}
dom() {
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 = {}) {
if(element.tagName === 'svg') {
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 {
constructor({
sequenceDiagram,
@ -127,6 +160,8 @@ define(['require'], (require) => {
this._downloadSVGClick = this._downloadSVGClick.bind(this);
this._downloadPNGClick = this._downloadPNGClick.bind(this);
this._downloadPNGFocus = this._downloadPNGFocus.bind(this);
this._showDropStyle = this._showDropStyle.bind(this);
this._hideDropStyle = this._hideDropStyle.bind(this);
this._enhanceEditor();
}
@ -221,6 +256,28 @@ define(['require'], (require) => {
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) {
@ -303,6 +360,7 @@ define(['require'], (require) => {
}
build(container) {
this.container = container;
const hold = makeNode('div', {'class': 'pane-hold'});
const lPane = makeNode('div', {'class': 'pane-side'});
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) {
const src = this.value();
this.saveCode(src);
@ -476,6 +555,14 @@ define(['require'], (require) => {
return true;
}
_showDropStyle() {
this.container.setAttribute('class', 'drop-target');
}
_hideDropStyle() {
this.container.setAttribute('class', '');
}
_downloadPNGFocus() {
this.updatePNGLink();
}

View File

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

View File

@ -51,6 +51,15 @@ define([
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 {
constructor(code = null, options = {}) {
super();
@ -195,20 +204,15 @@ define([
}
}
extractCodeFromSVG(svg) {
return extractCodeFromSVG(svg);
}
dom() {
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 = {}) {
if(element.tagName === 'svg') {
return null;

View File

@ -36,6 +36,24 @@ html, body {
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 {
position: absolute;
left: 0;