diff --git a/app.py b/app.py index f31025b4c494169fc83b5bc16ff6a1b043c06da1..5993b6d55040185cc3b18440d20218604ef5699c 100644 --- a/app.py +++ b/app.py @@ -221,10 +221,15 @@ def catalogue(): params = params) -# ---------------------------------------------------------- +# _ _ +# ___ __ _| |_ __ _| | ___ __ _ _ _ ___ +# / __/ _` | __/ _` | |/ _ \ / _` | | | |/ _ \ +# | (_| (_| | || (_| | | (_) | (_| | |_| | __/ +# \___\__,_|\__\__,_|_|\___/ \__, |\__,_|\___| +# |___/ +# +# FIGLET 2 SVGBOB INTERACTIVE CATALOGUE -def make_svg (): - return '' @app.route('/hpgl/<id>') def hpgl (id): @@ -245,7 +250,6 @@ def hpgl (id): # store as a temporary file (svg_file, svg_path) = tempfile.mkstemp('.svg') - with open(svg_file, 'w') as svg_handle: svg_handle.write(svg) diff --git a/static/css/interface.css b/static/css/interface.css index a6ea4e6119a44e8ccfe34a4df3c4d900f8dc4b0d..8e2bbfa0f18c0ab749b546d109fbbe85b871df9a 100644 --- a/static/css/interface.css +++ b/static/css/interface.css @@ -323,4 +323,13 @@ body.check-fix .fix{ } .draw .f-ascii{ padding: 0; +} +.draw .f-svg{ + padding: 0; +} +.f-svg iframe{ + border: none !important; + width: 100%; + height: 100%; + display: block; } \ No newline at end of file diff --git a/static/js/FileSaver.js b/static/js/FileSaver.js new file mode 100644 index 0000000000000000000000000000000000000000..54fc090045afa4f7808a748b5a80651827a90a15 --- /dev/null +++ b/static/js/FileSaver.js @@ -0,0 +1,188 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define([], factory); + } else if (typeof exports !== "undefined") { + factory(); + } else { + var mod = { + exports: {} + }; + factory(); + global.FileSaver = mod.exports; + } +})(this, function () { + "use strict"; + + /* + * FileSaver.js + * A saveAs() FileSaver implementation. + * + * By Eli Grey, http://eligrey.com + * + * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) + * source : http://purl.eligrey.com/github/FileSaver.js + */ + // The one and only way of getting global scope in all environments + // https://stackoverflow.com/q/3277182/1008999 + var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0; + + function bom(blob, opts) { + if (typeof opts === 'undefined') opts = { + autoBom: false + };else if (typeof opts !== 'object') { + console.warn('Deprecated: Expected third argument to be a object'); + opts = { + autoBom: !opts + }; + } // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + + if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xFEFF), blob], { + type: blob.type + }); + } + + return blob; + } + + function download(url, name, opts) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'blob'; + + xhr.onload = function () { + saveAs(xhr.response, name, opts); + }; + + xhr.onerror = function () { + console.error('could not download file'); + }; + + xhr.send(); + } + + function corsEnabled(url) { + var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker + + xhr.open('HEAD', url, false); + + try { + xhr.send(); + } catch (e) {} + + return xhr.status >= 200 && xhr.status <= 299; + } // `a.click()` doesn't work for all browsers (#465) + + + function click(node) { + try { + node.dispatchEvent(new MouseEvent('click')); + } catch (e) { + var evt = document.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); + node.dispatchEvent(evt); + } + } // Detect WebView inside a native macOS app by ruling out all browsers + // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too + // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos + + + var isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent); + var saveAs = _global.saveAs || ( // probably in some web worker + typeof window !== 'object' || window !== _global ? function saveAs() {} + /* noop */ + // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView + : 'download' in HTMLAnchorElement.prototype && !isMacOSWebView ? function saveAs(blob, name, opts) { + var URL = _global.URL || _global.webkitURL; + var a = document.createElement('a'); + name = name || blob.name || 'download'; + a.download = name; + a.rel = 'noopener'; // tabnabbing + // TODO: detect chrome extensions & packaged apps + // a.target = '_blank' + + if (typeof blob === 'string') { + // Support regular links + a.href = blob; + + if (a.origin !== location.origin) { + corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank'); + } else { + click(a); + } + } else { + // Support blobs + a.href = URL.createObjectURL(blob); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 4E4); // 40s + + setTimeout(function () { + click(a); + }, 0); + } + } // Use msSaveOrOpenBlob as a second approach + : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) { + name = name || blob.name || 'download'; + + if (typeof blob === 'string') { + if (corsEnabled(blob)) { + download(blob, name, opts); + } else { + var a = document.createElement('a'); + a.href = blob; + a.target = '_blank'; + setTimeout(function () { + click(a); + }); + } + } else { + navigator.msSaveOrOpenBlob(bom(blob, opts), name); + } + } // Fallback to using FileReader and a popup + : function saveAs(blob, name, opts, popup) { + // Open a popup immediately do go around popup blocker + // Mostly only available on user interaction and the fileReader is async so... + popup = popup || open('', '_blank'); + + if (popup) { + popup.document.title = popup.document.body.innerText = 'downloading...'; + } + + if (typeof blob === 'string') return download(blob, name, opts); + var force = blob.type === 'application/octet-stream'; + + var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari; + + var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); + + if ((isChromeIOS || force && isSafari || isMacOSWebView) && typeof FileReader !== 'undefined') { + // Safari doesn't allow downloading of blob URLs + var reader = new FileReader(); + + reader.onloadend = function () { + var url = reader.result; + url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); + if (popup) popup.location.href = url;else location = url; + popup = null; // reverse-tabnabbing #460 + }; + + reader.readAsDataURL(blob); + } else { + var URL = _global.URL || _global.webkitURL; + var url = URL.createObjectURL(blob); + if (popup) popup.location = url;else location.href = url; + popup = null; // reverse-tabnabbing #460 + + setTimeout(function () { + URL.revokeObjectURL(url); + }, 4E4); // 40s + } + }); + _global.saveAs = saveAs.saveAs = saveAs; + + if (typeof module !== 'undefined') { + module.exports = saveAs; + } +}); diff --git a/templates/catalogue.html b/templates/catalogue.html index 8401d63b0b8563aa6a3fe3d330ae0a7fc318e842..4e1f5e542ad703f48c0e8d4334bca547751c7a1d 100644 --- a/templates/catalogue.html +++ b/templates/catalogue.html @@ -100,5 +100,9 @@ </details> {% endfor %} + <script> + + </script> + {% endblock %} diff --git a/templates/draw.html b/templates/draw.html index dcdbdaba8871f5b72024854c88a69262e0cedd96..60d6735100e09a23ba6a5d385425a2efa3e547cc 100644 --- a/templates/draw.html +++ b/templates/draw.html @@ -76,10 +76,6 @@ <iframe id="svg-iframe" src="/drawing/{{params['pad']}}"> </iframe> </div> - <aside class="right"> - <button>> SVG</button> - <button>> HPGL</button> - </aside> </div> {% endblock %} diff --git a/templates/drawing.html b/templates/drawing.html index b4000ac6e3043444986ca43a2d927e18dd79cbbc..767ab41ae5cd70df52bf70f8c9349ab153cc1256 100644 --- a/templates/drawing.html +++ b/templates/drawing.html @@ -3,10 +3,38 @@ <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="stylesheet" type="text/css" href="static/css/reset.css" /> - <link rel="stylesheet" type="text/css" href="static/css/interface.css" /> + <script src="/static/js/FileSaver.js"></script> + <style> + #save-svg{ + position: fixed; + top: 0.5em; + right: 0.5em; + } + </style> </head> - <body class=""> + + <body> + {{ svg|safe }} + + <button id="save-svg">> SVG</button> + <!-- <button>> HPGL</button> --> + + <script> + let save_button = document.getElementById('save-svg'); + + save_button.addEventListener('click', function(){ + //get svg element. + let svg = document.getElementsByTagName("svg")[0]; + + //get svg source. + let serializer = new XMLSerializer(); + let source = serializer.serializeToString(svg); + + let blob = new Blob([source], {type: "text/plain;charset=utf-8"}); + saveAs(blob, 'cobbled-paths.svg'); + }); + </script> + </body> </html> \ No newline at end of file