diff options
author | BrLi | 2020-12-07 16:08:40 +0800 |
---|---|---|
committer | BrLi | 2020-12-07 16:08:40 +0800 |
commit | 3e212e864fe9e223a44f301dc6dae614854beae7 (patch) | |
tree | 1f09f2681eeb32ee38c8100aa065bfce6c3b0351 | |
parent | 760529b50c29e7624621fbbfac2081e1d2b7c3eb (diff) | |
download | aur-3e212e864fe9e223a44f301dc6dae614854beae7.tar.gz |
introduce upstream fix for various bugs
-rw-r--r-- | .SRCINFO | 10 | ||||
-rw-r--r-- | PKGBUILD | 16 | ||||
-rw-r--r-- | fix-package-json.patch (renamed from fixed-package-json.patch) | 27 | ||||
-rw-r--r-- | upstream.patch | 5539 |
4 files changed, 5576 insertions, 16 deletions
@@ -1,18 +1,20 @@ pkgbase = pencil pkgdesc = Sketching and GUI prototyping/wireframing tool pkgver = 3.1.0 - pkgrel = 6 + pkgrel = 7 url = https://github.com/evolus/pencil arch = any license = GPL2 makedepends = yarn - depends = electron9 + depends = electron conflicts = evolus-pencil-bin conflicts = pencil-v2 source = https://github.com/evolus/pencil/archive/v3.1.0.tar.gz - source = fixed-package-json.patch + source = fix-package-json.patch + source = upstream.patch sha256sums = e14eddd0aad28919cfdf8d47b726f9c75a3a0d2042605e8da96309c23a995f44 - sha256sums = ab36a7476d4a04dc684441f67faa3f7f84168a725b4e977d467e0b4321eb0d50 + sha256sums = 7094d33707a1fa27b79f296b3083584643150935ac4e464ebd44a82ed04ad036 + sha256sums = 78c28950a497495f3efef0b915283c10fd834c83996471291ae6ac18e3256997 pkgname = pencil @@ -3,24 +3,28 @@ pkgname=pencil pkgver=3.1.0 -pkgrel=6 +pkgrel=7 pkgdesc="Sketching and GUI prototyping/wireframing tool" arch=('any') license=('GPL2') url="https://github.com/evolus/pencil" -depends=(electron9) +depends=(electron) makedepends=(yarn) source=("https://github.com/evolus/pencil/archive/v$pkgver.tar.gz" - 'fixed-package-json.patch') + 'fix-package-json.patch' + 'upstream.patch') sha256sums=('e14eddd0aad28919cfdf8d47b726f9c75a3a0d2042605e8da96309c23a995f44' - 'ab36a7476d4a04dc684441f67faa3f7f84168a725b4e977d467e0b4321eb0d50') + '7094d33707a1fa27b79f296b3083584643150935ac4e464ebd44a82ed04ad036' + '78c28950a497495f3efef0b915283c10fd834c83996471291ae6ac18e3256997') conflicts=('evolus-pencil-bin' 'pencil-v2') prepare() { cd "${srcdir}/${pkgname}-${pkgver}" + + patch -Np1 -i "${srcdir}/upstream.patch" # We don't build electron and friends, and don't depends on postinstall script - patch -Np1 -i "${srcdir}/fixed-package-json.patch" + patch -Np1 -i "${srcdir}/fix-package-json.patch" sed '/^\s*\"electron.*$/d;/postinstall/d' -i app/package.json } @@ -57,7 +61,7 @@ package() { install -Dm755 /dev/stdin "${pkgdir}/usr/bin/${pkgname}" <<END #!/bin/sh -exec electron9 /${_destdir} "\$@" +exec electron /${_destdir} "\$@" END cd "${srcdir}/${pkgname}-${pkgver}" diff --git a/fixed-package-json.patch b/fix-package-json.patch index 6d9227a96cf2..a7e61c18207a 100644 --- a/fixed-package-json.patch +++ b/fix-package-json.patch @@ -1,10 +1,21 @@ ---- a/package.json 2019-10-18 19:38:10.000000000 +0800 -+++ b/package.json 2020-10-12 11:52:41.353799990 +0800 +From f6b62008495253f0c68ea1a03eb6815e3bd60e97 Mon Sep 17 00:00:00 2001 +From: BrLi <brli@chakralinux.org> +Date: Mon, 7 Dec 2020 15:58:13 +0800 +Subject: [PATCH] fix package.json + +--- + package.json | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/package.json b/package.json +index 9c2d20c..4ad8321 100644 +--- a/package.json ++++ b/package.json @@ -1,9 +1,6 @@ { "name": "Pencil", "devDependencies": { -- "electron": "6.0.1", +- "electron": "10.1.5", - "electron-builder": "20.28.4", - "electron-rebuild": "^1.8.5", "rimraf": "^2.5.4" @@ -20,11 +31,15 @@ "fileAssociations": { "ext": [ "ep", -@@ -68,7 +62,6 @@ +@@ -68,8 +62,6 @@ } }, "scripts": { - "postinstall": "install-app-deps", - "install-app-deps": "node ./node_modules/electron-builder/out/install-app-deps.js", +- "install-app-deps": "node ./node_modules/electron-builder/out/install-app-deps.js", "start": "./node_modules/.bin/electron ./app", - "start:dev": "./node_modules/.bin/electron ./app --enable-dev --enable-transparent-visuals --disable-gpu", + "start:dev": "./node_modules/.bin/electron ./app --enable-dev --enable-transparent-visuals", + "start:mac": "./node_modules/.bin/electron ./app --enable-dev", +-- +2.29.2 + diff --git a/upstream.patch b/upstream.patch new file mode 100644 index 000000000000..c71cb18b9d73 --- /dev/null +++ b/upstream.patch @@ -0,0 +1,5539 @@ +diff --git a/app/app.xhtml b/app/app.xhtml +index fa1f556..869a5f6 100644 +--- a/app/app.xhtml ++++ b/app/app.xhtml +@@ -4,7 +4,7 @@ + <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="http://evolus.vn/Namespaces/WebUI/1.0"> + <head> + <title>Pencil</title> +- ++ <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="stylesheet" href="css/material-icons.css" /> + + <link rel="stylesheet" href="css/pencil.css"/> +@@ -15,6 +15,7 @@ + <script type="text/javascript" src="lib/codemirror/codemirror.js"></script> + <link rel="stylesheet" href="lib/codemirror/codemirror.css"/> + <script type="text/javascript" src="lib/codemirror/javascript.js"></script> ++ <script type="text/javascript" src="lib/codemirror/xml.js"></script> + + <!-- Pencil Core --> + <script type="text/javascript" src="pencil-core/common/pencilNamespaces.js"></script> +@@ -46,6 +47,7 @@ + <script type="text/javascript" src="pencil-core/canvasHelper/canvasMemento.js"></script> + <script type="text/javascript" src="pencil-core/canvasHelper/canvasImpl.js"></script> + <script type="text/javascript" src="pencil-core/canvasHelper/snappingHelper.js"></script> ++ <script type="text/javascript" src="pencil-core/canvasHelper/GestureHelper.js"></script> + + <script type="text/javascript" src="pencil-core/privateCollection/privateCollection.js"></script> + <script type="text/javascript" src="pencil-core/privateCollection/privateShapeDef.js"></script> +@@ -147,7 +149,7 @@ + + <script type="text/javascript" src="pencil-core/clipartBrowser/webUtil.js"></script> + <script type="text/javascript" src="pencil-core/clipartBrowser/searchEngine.js"></script> +- <script type="text/javascript" src="pencil-core/clipartBrowser/openClipartSearch.js"></script> ++ <script type="text/javascript" src="pencil-core/clipartBrowser/newOpenClipartSearch.js"></script> + + <!--<script type="text/javascript" src="pencil-core/mainWindow.js"></script>--> + +diff --git a/app/css/theme.css b/app/css/theme.css +index 8db875f..bccd7c3 100644 +--- a/app/css/theme.css ++++ b/app/css/theme.css +@@ -18,7 +18,7 @@ button { + white-space: nowrap; + vertical-align: middle; + cursor: pointer; +- border: 1px solid #CCC; ++ border: none; + border-radius: 4px; + + line-height: 2.4em; +@@ -27,11 +27,11 @@ button { + + border-radius: 0.3ex; + +- background: #FFF; ++ background: #FEFEFE; ++ color: #000000DD; + outline: none; + + text-shadow: 0px 1px 0px #FFF; +- background-image: linear-gradient(to bottom, #FFF 0px, #E0E0E0 100%); + background-repeat: repeat-x; + display: inline-flex; + align-items: center; +diff --git a/app/index.js b/app/index.js +index 4e0ac9e..79fec6a 100644 +--- a/app/index.js ++++ b/app/index.js +@@ -4,23 +4,36 @@ const {app, protocol, shell, BrowserWindow} = require("electron"); + const pkg = require("./package.json"); + const fs = require("fs"); + const path = require("path"); ++const os = require("os"); + +-app.commandLine.appendSwitch("allow-file-access-from-files"); +-app.commandLine.appendSwitch("allow-file-access"); ++app.commandLine.appendSwitch("no-sandbox"); ++app.commandLine.appendSwitch("allow-file-access-from-files", "1"); ++app.commandLine.appendSwitch("allow-file-access", "1"); + app.commandLine.appendSwitch("disable-smooth-scrolling"); + app.commandLine.appendSwitch("disable-site-isolation-trials"); + + // Disable hardware acceleration by default for Linux + // TODO: implement a setting for this one and requires a restart after changing that value + if (process.platform.trim().toLowerCase() == "linux" && app.disableHardwareAcceleration) { +- if (process.argv.indexOf("--with-hwa") < 0) { ++ var useHWAConfig = getAppConfig("core.useHardwareAcceleration"); ++ console.log("useHWAConfig: ", useHWAConfig); ++ if (process.argv.indexOf("--with-hwa") < 0 && !useHWAConfig) { + console.log("Hardware acceleration disabled for Linux."); + app.disableHardwareAcceleration(); + } else { + console.log("Hardware acceleration forcibly enabled."); + } + } +- ++function getAppConfig(name) { ++ var p = path.join(path.join(os.homedir(), ".pencil"), "config.json"); ++ try { ++ var json = fs.readFileSync(p, "utf8"); ++ var data = JSON.parse(json); ++ return data[name]; ++ } catch (e) { ++ return undefined; ++ } ++} + global.sharedObject = { appArguments: process.argv }; + + var handleRedirect = (e, url) => { +@@ -38,7 +51,8 @@ function createWindow() { + allowRunningInsecureContent: true, + allowDisplayingInsecureContent: true, + defaultEncoding: "UTF-8", +- nodeIntegration: true ++ nodeIntegration: true, ++ enableRemoteModule: true + }, + }; + +@@ -60,7 +74,7 @@ function createWindow() { + mainWindow.maximize(); + + if (devEnable) { +- mainWindow.webContents.openDevTools(); ++ //mainWindow.webContents.openDevTools(); + } else { + mainWindow.setMenu(null); + } +@@ -106,9 +120,9 @@ app.on('ready', function() { + + fs.readFile(path, function (err, data) { + if (err) { +- callback({mimeType: "text/html", data: new Buffer("Not found")}); ++ callback({mimeType: "text/html", data: Buffer.from("Not found")}); + } else { +- callback({mimeType: "image/jpeg", data: new Buffer(data)}); ++ callback({mimeType: "image/jpeg", data: Buffer.from(data)}); + } + }); + +diff --git a/app/lib/codemirror/xml.js b/app/lib/codemirror/xml.js +new file mode 100644 +index 0000000..73c6e0e +--- /dev/null ++++ b/app/lib/codemirror/xml.js +@@ -0,0 +1,413 @@ ++// CodeMirror, copyright (c) by Marijn Haverbeke and others ++// Distributed under an MIT license: https://codemirror.net/LICENSE ++ ++(function(mod) { ++ if (typeof exports == "object" && typeof module == "object") // CommonJS ++ mod(require("../../lib/codemirror")); ++ else if (typeof define == "function" && define.amd) // AMD ++ define(["../../lib/codemirror"], mod); ++ else // Plain browser env ++ mod(CodeMirror); ++})(function(CodeMirror) { ++"use strict"; ++ ++var htmlConfig = { ++ autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true, ++ 'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true, ++ 'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true, ++ 'track': true, 'wbr': true, 'menuitem': true}, ++ implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true, ++ 'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true, ++ 'th': true, 'tr': true}, ++ contextGrabbers: { ++ 'dd': {'dd': true, 'dt': true}, ++ 'dt': {'dd': true, 'dt': true}, ++ 'li': {'li': true}, ++ 'option': {'option': true, 'optgroup': true}, ++ 'optgroup': {'optgroup': true}, ++ 'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true, ++ 'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true, ++ 'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, ++ 'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true, ++ 'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true}, ++ 'rp': {'rp': true, 'rt': true}, ++ 'rt': {'rp': true, 'rt': true}, ++ 'tbody': {'tbody': true, 'tfoot': true}, ++ 'td': {'td': true, 'th': true}, ++ 'tfoot': {'tbody': true}, ++ 'th': {'td': true, 'th': true}, ++ 'thead': {'tbody': true, 'tfoot': true}, ++ 'tr': {'tr': true} ++ }, ++ doNotIndent: {"pre": true}, ++ allowUnquoted: true, ++ allowMissing: true, ++ caseFold: true ++} ++ ++var xmlConfig = { ++ autoSelfClosers: {}, ++ implicitlyClosed: {}, ++ contextGrabbers: {}, ++ doNotIndent: {}, ++ allowUnquoted: false, ++ allowMissing: false, ++ allowMissingTagName: false, ++ caseFold: false ++} ++ ++CodeMirror.defineMode("xml", function(editorConf, config_) { ++ var indentUnit = editorConf.indentUnit ++ var config = {} ++ var defaults = config_.htmlMode ? htmlConfig : xmlConfig ++ for (var prop in defaults) config[prop] = defaults[prop] ++ for (var prop in config_) config[prop] = config_[prop] ++ ++ // Return variables for tokenizers ++ var type, setStyle; ++ ++ function inText(stream, state) { ++ function chain(parser) { ++ state.tokenize = parser; ++ return parser(stream, state); ++ } ++ ++ var ch = stream.next(); ++ if (ch == "<") { ++ if (stream.eat("!")) { ++ if (stream.eat("[")) { ++ if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>")); ++ else return null; ++ } else if (stream.match("--")) { ++ return chain(inBlock("comment", "-->")); ++ } else if (stream.match("DOCTYPE", true, true)) { ++ stream.eatWhile(/[\w\._\-]/); ++ return chain(doctype(1)); ++ } else { ++ return null; ++ } ++ } else if (stream.eat("?")) { ++ stream.eatWhile(/[\w\._\-]/); ++ state.tokenize = inBlock("meta", "?>"); ++ return "meta"; ++ } else { ++ type = stream.eat("/") ? "closeTag" : "openTag"; ++ state.tokenize = inTag; ++ return "tag bracket"; ++ } ++ } else if (ch == "&") { ++ var ok; ++ if (stream.eat("#")) { ++ if (stream.eat("x")) { ++ ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";"); ++ } else { ++ ok = stream.eatWhile(/[\d]/) && stream.eat(";"); ++ } ++ } else { ++ ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";"); ++ } ++ return ok ? "atom" : "error"; ++ } else { ++ stream.eatWhile(/[^&<]/); ++ return null; ++ } ++ } ++ inText.isInText = true; ++ ++ function inTag(stream, state) { ++ var ch = stream.next(); ++ if (ch == ">" || (ch == "/" && stream.eat(">"))) { ++ state.tokenize = inText; ++ type = ch == ">" ? "endTag" : "selfcloseTag"; ++ return "tag bracket"; ++ } else if (ch == "=") { ++ type = "equals"; ++ return null; ++ } else if (ch == "<") { ++ state.tokenize = inText; ++ state.state = baseState; ++ state.tagName = state.tagStart = null; ++ var next = state.tokenize(stream, state); ++ return next ? next + " tag error" : "tag error"; ++ } else if (/[\'\"]/.test(ch)) { ++ state.tokenize = inAttribute(ch); ++ state.stringStartCol = stream.column(); ++ return state.tokenize(stream, state); ++ } else { ++ stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/); ++ return "word"; ++ } ++ } ++ ++ function inAttribute(quote) { ++ var closure = function(stream, state) { ++ while (!stream.eol()) { ++ if (stream.next() == quote) { ++ state.tokenize = inTag; ++ break; ++ } ++ } ++ return "string"; ++ }; ++ closure.isInAttribute = true; ++ return closure; ++ } ++ ++ function inBlock(style, terminator) { ++ return function(stream, state) { ++ while (!stream.eol()) { ++ if (stream.match(terminator)) { ++ state.tokenize = inText; ++ break; ++ } ++ stream.next(); ++ } ++ return style; ++ } ++ } ++ ++ function doctype(depth) { ++ return function(stream, state) { ++ var ch; ++ while ((ch = stream.next()) != null) { ++ if (ch == "<") { ++ state.tokenize = doctype(depth + 1); ++ return state.tokenize(stream, state); ++ } else if (ch == ">") { ++ if (depth == 1) { ++ state.tokenize = inText; ++ break; ++ } else { ++ state.tokenize = doctype(depth - 1); ++ return state.tokenize(stream, state); ++ } ++ } ++ } ++ return "meta"; ++ }; ++ } ++ ++ function Context(state, tagName, startOfLine) { ++ this.prev = state.context; ++ this.tagName = tagName; ++ this.indent = state.indented; ++ this.startOfLine = startOfLine; ++ if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent)) ++ this.noIndent = true; ++ } ++ function popContext(state) { ++ if (state.context) state.context = state.context.prev; ++ } ++ function maybePopContext(state, nextTagName) { ++ var parentTagName; ++ while (true) { ++ if (!state.context) { ++ return; ++ } ++ parentTagName = state.context.tagName; ++ if (!config.contextGrabbers.hasOwnProperty(parentTagName) || ++ !config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) { ++ return; ++ } ++ popContext(state); ++ } ++ } ++ ++ function baseState(type, stream, state) { ++ if (type == "openTag") { ++ state.tagStart = stream.column(); ++ return tagNameState; ++ } else if (type == "closeTag") { ++ return closeTagNameState; ++ } else { ++ return baseState; ++ } ++ } ++ function tagNameState(type, stream, state) { ++ if (type == "word") { ++ state.tagName = stream.current(); ++ setStyle = "tag"; ++ return attrState; ++ } else if (config.allowMissingTagName && type == "endTag") { ++ setStyle = "tag bracket"; ++ return attrState(type, stream, state); ++ } else { ++ setStyle = "error"; ++ return tagNameState; ++ } ++ } ++ function closeTagNameState(type, stream, state) { ++ if (type == "word") { ++ var tagName = stream.current(); ++ if (state.context && state.context.tagName != tagName && ++ config.implicitlyClosed.hasOwnProperty(state.context.tagName)) ++ popContext(state); ++ if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) { ++ setStyle = "tag"; ++ return closeState; ++ } else { ++ setStyle = "tag error"; ++ return closeStateErr; ++ } ++ } else if (config.allowMissingTagName && type == "endTag") { ++ setStyle = "tag bracket"; ++ return closeState(type, stream, state); ++ } else { ++ setStyle = "error"; ++ return closeStateErr; ++ } ++ } ++ ++ function closeState(type, _stream, state) { ++ if (type != "endTag") { ++ setStyle = "error"; ++ return closeState; ++ } ++ popContext(state); ++ return baseState; ++ } ++ function closeStateErr(type, stream, state) { ++ setStyle = "error"; ++ return closeState(type, stream, state); ++ } ++ ++ function attrState(type, _stream, state) { ++ if (type == "word") { ++ setStyle = "attribute"; ++ return attrEqState; ++ } else if (type == "endTag" || type == "selfcloseTag") { ++ var tagName = state.tagName, tagStart = state.tagStart; ++ state.tagName = state.tagStart = null; ++ if (type == "selfcloseTag" || ++ config.autoSelfClosers.hasOwnProperty(tagName)) { ++ maybePopContext(state, tagName); ++ } else { ++ maybePopContext(state, tagName); ++ state.context = new Context(state, tagName, tagStart == state.indented); ++ } ++ return baseState; ++ } ++ setStyle = "error"; ++ return attrState; ++ } ++ function attrEqState(type, stream, state) { ++ if (type == "equals") return attrValueState; ++ if (!config.allowMissing) setStyle = "error"; ++ return attrState(type, stream, state); ++ } ++ function attrValueState(type, stream, state) { ++ if (type == "string") return attrContinuedState; ++ if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;} ++ setStyle = "error"; ++ return attrState(type, stream, state); ++ } ++ function attrContinuedState(type, stream, state) { ++ if (type == "string") return attrContinuedState; ++ return attrState(type, stream, state); ++ } ++ ++ return { ++ startState: function(baseIndent) { ++ var state = {tokenize: inText, ++ state: baseState, ++ indented: baseIndent || 0, ++ tagName: null, tagStart: null, ++ context: null} ++ if (baseIndent != null) state.baseIndent = baseIndent ++ return state ++ }, ++ ++ token: function(stream, state) { ++ if (!state.tagName && stream.sol()) ++ state.indented = stream.indentation(); ++ ++ if (stream.eatSpace()) return null; ++ type = null; ++ var style = state.tokenize(stream, state); ++ if ((style || type) && style != "comment") { ++ setStyle = null; ++ state.state = state.state(type || style, stream, state); ++ if (setStyle) ++ style = setStyle == "error" ? style + " error" : setStyle; ++ } ++ return style; ++ }, ++ ++ indent: function(state, textAfter, fullLine) { ++ var context = state.context; ++ // Indent multi-line strings (e.g. css). ++ if (state.tokenize.isInAttribute) { ++ if (state.tagStart == state.indented) ++ return state.stringStartCol + 1; ++ else ++ return state.indented + indentUnit; ++ } ++ if (context && context.noIndent) return CodeMirror.Pass; ++ if (state.tokenize != inTag && state.tokenize != inText) ++ return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0; ++ // Indent the starts of attribute names. ++ if (state.tagName) { ++ if (config.multilineTagIndentPastTag !== false) ++ return state.tagStart + state.tagName.length + 2; ++ else ++ return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1); ++ } ++ if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0; ++ var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter); ++ if (tagAfter && tagAfter[1]) { // Closing tag spotted ++ while (context) { ++ if (context.tagName == tagAfter[2]) { ++ context = context.prev; ++ break; ++ } else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) { ++ context = context.prev; ++ } else { ++ break; ++ } ++ } ++ } else if (tagAfter) { // Opening tag spotted ++ while (context) { ++ var grabbers = config.contextGrabbers[context.tagName]; ++ if (grabbers && grabbers.hasOwnProperty(tagAfter[2])) ++ context = context.prev; ++ else ++ break; ++ } ++ } ++ while (context && context.prev && !context.startOfLine) ++ context = context.prev; ++ if (context) return context.indent + indentUnit; ++ else return state.baseIndent || 0; ++ }, ++ ++ electricInput: /<\/[\s\w:]+>$/, ++ blockCommentStart: "<!--", ++ blockCommentEnd: "-->", ++ ++ configuration: config.htmlMode ? "html" : "xml", ++ helperType: config.htmlMode ? "html" : "xml", ++ ++ skipAttribute: function(state) { ++ if (state.state == attrValueState) ++ state.state = attrState ++ }, ++ ++ xmlCurrentTag: function(state) { ++ return state.tagName ? {name: state.tagName, close: state.type == "closeTag"} : null ++ }, ++ ++ xmlCurrentContext: function(state) { ++ var context = [] ++ for (var cx = state.context; cx; cx = cx.prev) ++ if (cx.tagName) context.push(cx.tagName) ++ return context.reverse() ++ } ++ }; ++}); ++ ++CodeMirror.defineMIME("text/xml", "xml"); ++CodeMirror.defineMIME("application/xml", "xml"); ++if (!CodeMirror.mimeModes.hasOwnProperty("text/html")) ++ CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true}); ++ ++}); +diff --git a/app/lib/widget/Common.js b/app/lib/widget/Common.js +index c8b208c..4b322f0 100644 +--- a/app/lib/widget/Common.js ++++ b/app/lib/widget/Common.js +@@ -597,6 +597,13 @@ widget.reloadDesktopFont = function() { + } + document.body.style.fontSize = size; + } ++ ++ var family = Config.get(Config.UI_CUSTOM_FONT_FAMILY); ++ if (family) document.body.style.fontFamily = family; ++ ++ var size = Config.get(Config.UI_CUSTOM_FONT_SIZE); ++ if (size) document.body.style.fontSize = size; ++ + resolve(config); + }); + }); +diff --git a/app/lib/widget/Tree.js b/app/lib/widget/Tree.js +index 266bf36..f1658d7 100644 +--- a/app/lib/widget/Tree.js ++++ b/app/lib/widget/Tree.js +@@ -90,6 +90,8 @@ widget.Tree = function() { + if (!target || !Dom.hasClass(target, "Checkbox") || target.nodeName.toLowerCase() != "input") return; + if (target.disabled) return; + ++ if (event.which == 2) target.checked = !target.checked; ++ + var treeContainer = Dom.findUpward(target, { + eval: function(n) { + return n._tree; +@@ -102,7 +104,7 @@ widget.Tree = function() { + if ((target.checked && tree.options.propagateCheckActionDownwards) + || (!target.checked && tree.options.propagateUncheckActionDownwards)) { + var itemNode = target.parentNode.parentNode; +- setItemsCheckedRecursivelyFromNodes(getChildrenContainerFromItemNode(itemNode).childNodes, target.checked); ++ if (event.which != 2) setItemsCheckedRecursivelyFromNodes(getChildrenContainerFromItemNode(itemNode).childNodes, target.checked); + } + + Dom.emitEvent("blur", treeContainer, {}); +@@ -189,13 +191,13 @@ widget.Tree = function() { + this.ensureNodeExpanded(itemNode); + } + }; +- ++ + /* + Tree.prototype.sort = function(item) { + if (item.sort) return; + if (item.children && item.children.length > 0) { + item.children.sort(sortNameByAsc); +- ++ + for (var i = 0; i < item.children.length; i++) { + if (item.children[i].children && item.children[i].children.length > 0) { + this.sort(item.children[i]); +@@ -204,11 +206,11 @@ widget.Tree = function() { + } + }; + */ +- ++ + Tree.prototype.loadChildren = function(parentItem, childrenContainer, callback) { + Dom.addClass(childrenContainer, "Loading"); + var thiz = this; +- ++ + this.source(parentItem, function(children) { + childrenContainer.innerHTML = ""; + if (!children) children = []; +@@ -456,7 +458,7 @@ widget.Tree = function() { + this.listener = listener; + return this; + }; +- ++ + Tree.prototype.findParentItem = function (contextNode) { + var thiz = this; + var node = Dom.findUpward(contextNode, { +@@ -464,15 +466,15 @@ widget.Tree = function() { + return n._item || n == thiz.container; + } + }); +- ++ + if (!node || !node._item) return null; +- ++ + node = Dom.findUpward(node.parentNode, { + eval: function (n) { + return n._item || n == thiz.container; + } + }); +- ++ + if (node && node._item) return node._item; + return null; + }; +diff --git a/app/package-lock.json b/app/package-lock.json +index f002744..d5c1306 100644 +--- a/app/package-lock.json ++++ b/app/package-lock.json +@@ -1,6 +1,6 @@ + { + "name": "Pencil", +- "version": "3.0.5", ++ "version": "3.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { +@@ -3235,6 +3235,29 @@ + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" ++ }, ++ "tar": { ++ "version": "2.2.2", ++ "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", ++ "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", ++ "requires": { ++ "block-stream": "*", ++ "fstream": "^1.0.12", ++ "inherits": "2" ++ }, ++ "dependencies": { ++ "fstream": { ++ "version": "1.0.12", ++ "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", ++ "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", ++ "requires": { ++ "graceful-fs": "^4.1.2", ++ "inherits": "~2.0.0", ++ "mkdirp": ">=0.5 0", ++ "rimraf": "2" ++ } ++ } ++ } + } + } + }, +diff --git a/app/pencil-core/canvasHelper/GestureHelper.js b/app/pencil-core/canvasHelper/GestureHelper.js +new file mode 100644 +index 0000000..cba1dd0 +--- /dev/null ++++ b/app/pencil-core/canvasHelper/GestureHelper.js +@@ -0,0 +1,86 @@ ++function GestureHelper(canvas) { ++ this.canvas = canvas; ++ this.canvas.gestureHelper = this; ++ ++ this.init(); ++} ++ ++GestureHelper.prototype.init = function () { ++ var thiz = this; ++ this.heldKeyCodes = []; ++ ++ this.canvas.focusableBox.addEventListener("keydown", function (event) { ++ if (thiz.heldKeyCodes.indexOf(event.keyCode) >= 0) return; ++ ++ thiz.heldKeyCodes.push(event.keyCode); ++ thiz.updateKeyCodes(); ++ }, false); ++ ++ this.canvas.focusableBox.addEventListener("keyup", function (event) { ++ var index = thiz.heldKeyCodes.indexOf(event.keyCode); ++ if (index < 0) return; ++ ++ thiz.heldKeyCodes.splice(index, 1); ++ thiz.updateKeyCodes(); ++ }, false); ++ ++ this.canvas.focusableBox.addEventListener("blur", function (event) { ++ thiz.heldKeyCodes.length = 0; ++ thiz.updateKeyCodes(); ++ }, false); ++ ++ // sample registry ++ this.gestureRegistry = { ++ keys: { ++ "R": { ++ type: "Shape", ++ defId: "dgthanhan.MaterialDesktopMockup:rectangle" ++ } ++ } ++ }; ++}; ++ ++GestureHelper.prototype.handleMouseDown = function (event) { ++ if (!this.activeGestureDef) return false; ++ if (this.activeGestureDef.type == "Shape") { ++ var def = CollectionManager.shapeDefinition.locateDefinition(this.activeGestureDef.defId); ++ if (!def) return; ++ ++ var loc = this.canvas.getEventLocation(event); ++ this.canvas.insertShape(def); ++ ++ var controller = this.canvas.currentController; ++ var bbox = controller.getBoundingRect(); ++ controller.moveBy(loc.x, loc.y, true); ++ controller.setProperty("box", new Dimension(0, 0)); ++ ++ this.canvas.selectShape(controller.svg); ++ window.setTimeout(function () { ++ this.canvas.geometryEditor.handleMouseDown(event); ++ this.canvas.geometryEditor.currentAnchor = this.canvas.geometryEditor.anchor4; ++ }.bind(this), 10); ++ ++ return true; ++ } ++ ++ return false; ++}; ++GestureHelper.prototype.handleMouseUp = function (event) { ++ return false; ++}; ++GestureHelper.prototype.updateKeyCodes = function () { ++ if (!GestureHelper._output) { ++ GestureHelper._output = document.createElement("div"); ++ ApplicationPane._instance.contentHeader.appendChild(GestureHelper._output); ++ } ++ ++ this.activeGestureDef = null; ++ ++ for (var code of this.heldKeyCodes) { ++ var c = String.fromCharCode(code); ++ this.activeGestureDef = this.gestureRegistry.keys[c]; ++ if (this.activeGestureDef) break; ++ } ++ ++ GestureHelper._output.innerHTML = this.heldKeyCodes.join(", "); ++}; +diff --git a/app/pencil-core/canvasHelper/snappingHelper.js b/app/pencil-core/canvasHelper/snappingHelper.js +index 5d2f2f8..fff47ad 100644 +--- a/app/pencil-core/canvasHelper/snappingHelper.js ++++ b/app/pencil-core/canvasHelper/snappingHelper.js +@@ -4,8 +4,6 @@ function SnappingHelper(canvas) { + Config.set("object.snapping.enabled", true); + } + this.init(); +- +- //var this = new SnappingHelper + }; + SnappingHelper.prototype.isGridSnappingEnabled = function () { + return Config.get("edit.snap.grid") == true; +@@ -113,20 +111,20 @@ SnappingHelper.prototype.rebuildSnappingGuide = function () { + } + + var margin = (Pencil.controller && !this.canvas.options.ignorePageMarging) ? Pencil.controller.getDocumentPageMargin() : 0; +- if (margin) { +- var uid = Util.newUUID(); +- this.snappingGuide[uid] = { +- vertical: [ +- new SnappingData("MarginSnap", margin, "Left", true, uid), +- new SnappingData("MarginSnap", this.canvas.width - margin, "Right", true, uid) +- ], +- horizontal: [ +- new SnappingData("MarginSnap", margin, "Top", false, uid), +- new SnappingData("MarginSnap", this.canvas.height - margin, "Bottom", false, uid) +- ] +- }; +- +- } ++ margin = parseInt(margin, 10); ++ if (isNaN(margin) || margin < 0) margin = 0; ++ var uid = Util.newUUID(); ++ var snap = { ++ vertical: [ ++ new SnappingData("MarginSnap", margin, "Left", true, uid), ++ new SnappingData("MarginSnap", this.canvas.width - margin, "Right", true, uid) ++ ], ++ horizontal: [ ++ new SnappingData("MarginSnap", margin, "Top", false, uid), ++ new SnappingData("MarginSnap", this.canvas.height - margin, "Bottom", false, uid) ++ ] ++ }; ++ this.snappingGuide[uid] = snap; + + this.sortData(); + }; +@@ -148,6 +146,9 @@ SnappingHelper.prototype.updateSnappingGuide = function (controller, remove) { + this.sortData(); + } + }; ++SnappingHelper.prototype.onControllerSnapshot = function (controller) { ++ this.lastSnappingGuideSnapshot = (controller && controller.getSnappingGuide) ? controller.getSnappingGuide() : null; ++}; + SnappingHelper.prototype.sortData = function () { + var x = []; + var y = []; +@@ -162,106 +163,103 @@ SnappingHelper.prototype.sortData = function () { + this.snappedX = false; + this.snappedY = false; + }; +-SnappingHelper.prototype.findSnapping = function (drawX, drawY, ghost, snap, shift, grid) { +- if (!this.isSnappingEnabled()) return; +- try { +- if (drawX && !grid) { +- this.clearSnappingGuideX(); +- } +- if (drawY && !grid) { +- this.clearSnappingGuideY(); +- } +- +- //debug("start ***"); +- if (!ghost && (!this.canvas.controllerHeld || !this.canvas.currentController || !this.canvas.currentController.getSnappingGuide)) return null; +- +- var _snap = snap ? snap : Pencil.SNAP; +- if (shift) { +- _snap = 1; +- } +- +- var b = !ghost ? this.canvas.currentController.getSnappingGuide() : ghost; ++SnappingHelper.prototype.applySnapping = function (dx, dy, controller) { ++ if (!this.isSnappingEnabled()) return null; ++ if (!this.lastSnappingGuideSnapshot) return null; ++ var currentControllerId = controller.id; + +- var snappingData = this.findSnappingImpl(this.canvas.currentController, b, _snap, grid); +- var currentDx = Pencil.SNAP + 10; +- var currentDy = Pencil.SNAP + 10; +- if (grid) { +- currentDx = Pencil.getGridSize().w; +- currentDy = Pencil.getGridSize().h; +- } ++ var xsnap = this.applySnappingValue(dx, this.lastSnappingGuideSnapshot.vertical, this.lastXData, controller); ++ var ysnap = this.applySnappingValue(dy, this.lastSnappingGuideSnapshot.horizontal, this.lastYData, controller); + +- var snapDelta = { +- dx: 0, dy: 0 +- }; ++ this.drawSnaps(xsnap, ysnap); + +- if (snappingData.bestVertical) { +- if (Math.abs(snappingData.bestVertical.dx) < Math.abs(currentDx)) { +- currentDx = snappingData.bestVertical.dx; +- } ++ return { ++ xsnap: xsnap, ++ ysnap: ysnap ++ }; ++}; ++SnappingHelper.prototype.drawSnaps = function (xsnap, ysnap) { ++ var thiz = this; + +- if (Math.abs(currentDx) < _snap) { +- if (drawX && !grid) { +- for (var l = 0; l < snappingData.verticals.length; l++) { +- var verticalGuide = document.createElementNS(PencilNamespaces.svg, "line"); ++ this.clearSnappingGuideX(); ++ if (xsnap && xsnap.matchingGuides) { ++ xsnap.matchingGuides.forEach(function (guide) { ++ var verticalGuide = document.createElementNS(PencilNamespaces.svg, "line"); + +- verticalGuide.setAttribute("class", snappingData.verticals[l].x.type); +- verticalGuide.setAttribute("x1", Math.round(snappingData.verticals[l].x.pos) * this.canvas.zoom); +- verticalGuide.setAttribute("y1", 0); +- verticalGuide.setAttribute("x2", Math.round(snappingData.verticals[l].x.pos) * this.canvas.zoom); +- verticalGuide.setAttribute("y2", this.canvas.height * this.canvas.zoom); ++ verticalGuide.setAttribute("class", guide.type); ++ verticalGuide.setAttribute("x1", Math.round(guide.pos * thiz.canvas.zoom)); ++ verticalGuide.setAttribute("y1", 0); ++ verticalGuide.setAttribute("x2", Math.round(guide.pos * thiz.canvas.zoom)); ++ verticalGuide.setAttribute("y2", Math.round(thiz.canvas.height * thiz.canvas.zoom)); + +- this.snappingGuideContainerX.appendChild(verticalGuide); ++ thiz.snappingGuideContainerX.appendChild(verticalGuide); + +- this._snappingGuideContainerXEmpty = false; +- } +- } +- if (grid) { +- this.unsnapX = (Pencil.getGridSize().w / 2) + 3; +- } else { +- this.unsnapX = Pencil.UNSNAP; +- } +- snapDelta.dx = currentDx; +- } +- } ++ thiz._snappingGuideContainerXEmpty = false; ++ }); ++ } + +- if (snappingData.bestHorizontal) { +- if (Math.abs(snappingData.bestHorizontal.dy) < Math.abs(currentDy)) { +- currentDy = snappingData.bestHorizontal.dy; +- } +- if (Math.abs(currentDy) < _snap) { +- if (drawY && !grid) { +- for (var l = 0; l < snappingData.horizontals.length; l++) { +- var horizontalGuide = document.createElementNS(PencilNamespaces.svg, "line"); ++ this.clearSnappingGuideY(); ++ if (ysnap && ysnap.matchingGuides) { ++ ysnap.matchingGuides.forEach(function (guide) { ++ var horizontalGuide = document.createElementNS(PencilNamespaces.svg, "line"); + +- horizontalGuide.setAttribute("class", snappingData.horizontals[l].y.type); +- horizontalGuide.setAttribute("x1", 0 * this.canvas.zoom); +- horizontalGuide.setAttribute("y1", Math.round(snappingData.horizontals[l].y.pos) * this.canvas.zoom); +- horizontalGuide.setAttribute("x2", this.canvas.width * this.canvas.zoom); +- horizontalGuide.setAttribute("y2", Math.round(snappingData.horizontals[l].y.pos) * this.canvas.zoom); ++ horizontalGuide.setAttribute("class", guide.type); ++ horizontalGuide.setAttribute("x1", 0); ++ horizontalGuide.setAttribute("y1", Math.round(guide.pos * thiz.canvas.zoom)); ++ horizontalGuide.setAttribute("x2", Math.round(thiz.canvas.width * thiz.canvas.zoom)); ++ horizontalGuide.setAttribute("y2", Math.round(guide.pos * thiz.canvas.zoom)); + +- this.snappingGuideContainerY.appendChild(horizontalGuide); ++ thiz.snappingGuideContainerY.appendChild(horizontalGuide); + +- this._snappingGuideContainerYEmpty = false; +- } +- } +- if (grid) { +- this.unsnapY = (Pencil.getGridSize().h / 2) + 3; +- } else { +- this.unsnapY = Pencil.UNSNAP; +- } +- snapDelta.dy = currentDy; ++ thiz._snappingGuideContainerYEmpty = false; ++ }); ++ } ++}; ++SnappingHelper.prototype.applySnappingValue = function (d, controllerPositions, canvasPositions, controller) { ++ var currentControllerId = controller.id; ++ var closestDistance = Number.MAX_VALUE; ++ var closestDelta = undefined; ++ var closestGuide = undefined; ++ var matchingGuides = []; ++ canvasPositions.forEach(function (canvasGuide) { ++ if (!canvasGuide || canvasGuide.id == currentControllerId || canvasGuide.disabled) return; ++ if (controller.containsControllerId && controller.containsControllerId(canvasGuide.id)) return; ++ ++ controllerPositions.forEach(function (controllerGuide) { ++ if (!controllerGuide || controllerGuide.disabled) return; ++ ++ var delta = canvasGuide.pos - (controllerGuide.pos + d); ++ var distance = Math.abs(delta); ++ if (distance < closestDistance) { ++ closestDistance = distance; ++ closestDelta = delta; ++ closestGuide = canvasGuide; ++ matchingGuides = [canvasGuide]; ++ } else if (delta == closestDelta) { ++ matchingGuides.push(canvasGuide); + } +- } ++ }); ++ }); + +- //debug("end ***"); +- return snapDelta; +- } catch(e) { +- error(e); ++ if (closestDistance <= Pencil.SNAP) { ++ return { ++ d: d + closestDelta, ++ matchingGuides: matchingGuides ++ } ++ } else { ++ return null; + } +- +- return null; + }; ++ + SnappingHelper.prototype.sort = function(d) { ++ // var d2 = []; ++ // var positions = []; ++ // d.forEach(function (v) { ++ // if (positions.indexOf(v.pos) >= 0) return; ++ // d2.push(v); ++ // positions.push(v.pos); ++ // }); ++ // d = d2; + for (var i = 0; i < d.length - 1; i++) { + for (var j = i + 1; j < d.length; j++) { + if (d[j].pos < d[i].pos) { +@@ -284,106 +282,3 @@ SnappingHelper.prototype.allowSnapping = function (v, x) { + + return false; + }; +-SnappingHelper.prototype.findSnappingImpl = function(controller, ghost, snap, grid) { +- +- try { +- var c = !ghost ? controller.getSnappingGuide() : ghost; +- var currentControllerId = controller.id; +- +- var verticals = []; +- var horizontals = []; +- +- var x = this.lastXData; +- var y = this.lastYData; +- +- var _minsnap = snap ? snap : Pencil.SNAP; +- +- var bestV = null; +- for (var v = 0; v < c.vertical.length; v++) { +- var vertical = { }; +- for (var i = 0; i < x.length; i++) { +- if (!x[i].disabled +- && !c.vertical[v].disabled +- && x[i].id != currentControllerId +- && (!controller.containsControllerId || !controller.containsControllerId(x[i].id)) +- && this.allowSnapping(c.vertical[v], x[i])) { +- if ((grid && x[i].type == "GridSnap" && Math.abs(x[i].pos - c.vertical[v].pos) <= _minsnap) +- || (!grid && x[i].type != "GridSnap" && Math.abs(x[i].pos - c.vertical[v].pos) <= _minsnap)) { +- +- _minsnap = Math.abs(x[i].pos - c.vertical[v].pos); +- vertical.x = x[i]; +- vertical.dx = x[i].pos - c.vertical[v].pos; +- +- if (!bestV || Math.abs(bestV.dx > vertical.dx)) { +- bestV = vertical; +- } +- } +- } +- } +- if (vertical.x) { +- verticals.push(vertical); +- } +- } +- +- //debug("found: " + verticals.length); +- //for (var v = 0; v < verticals.length; v++) { +- // debug(verticals[v].toSource()); +- //} +- +- // if (verticals.length > 0) { +- // while (Math.abs(verticals[0].dx) != Math.abs(verticals[verticals.length - 1].dx)) { +- // //debug("delete"); +- // verticals.splice(0, 1); +- // } +- // } +- +- var _minsnap = snap ? snap : Pencil.SNAP; +- +- var bestH = null; +- for (var v = 0; v < c.horizontal.length; v++) { +- var horizontal = { }; +- for (var i = 0; i < y.length; i++) { +- if (!y[i].disabled +- && !c.horizontal[v].disabled +- && y[i].id != currentControllerId +- && (!controller.containsControllerId || !controller.containsControllerId(y[i].id)) +- && this.allowSnapping(c.horizontal[v], y[i])) { +- if ((grid && y[i].type == "GridSnap" && Math.abs(y[i].pos - c.horizontal[v].pos) <= _minsnap) +- || (!grid && y[i].type != "GridSnap" && Math.abs(y[i].pos - c.horizontal[v].pos) <= _minsnap)) { +- +- _minsnap = Math.abs(y[i].pos - c.horizontal[v].pos); +- horizontal.y = y[i]; +- horizontal.dy = y[i].pos - c.horizontal[v].pos; +- +- if (!bestH || Math.abs(bestH.dy > horizontal.dy)) { +- bestH = horizontal; +- } +- } +- } +- } +- if (horizontal.y) { +- horizontals.push(horizontal); +- } +- } +- +- //debug("found: " + horizontals.length); +- //for (var v = 0; v < horizontals.length; v++) { +- // debug(horizontals[v].toSource()); +- //} +- +- // if (horizontals.length > 0) { +- // while (Math.abs(horizontals[0].dy) != Math.abs(horizontals[horizontals.length - 1].dy)) { +- // horizontals.splice(0, 1); +- // } +- // } +- +- return { +- verticals: verticals.sort(function (a, b) { return Math.abs(a.dx) - Math.abs(b.dx)}), +- horizontals: horizontals.sort(function (a, b) { return Math.abs(a.dy) - Math.abs(b.dy)}), +- bestVertical: bestV, +- bestHorizontal: bestH +- }; +- } catch(e) { +- Console.dumpError(e); +- } +-}; +diff --git a/app/pencil-core/clipartBrowser/newOpenClipartSearch.js b/app/pencil-core/clipartBrowser/newOpenClipartSearch.js +index 57f317c..7f5fe1b 100644 +--- a/app/pencil-core/clipartBrowser/newOpenClipartSearch.js ++++ b/app/pencil-core/clipartBrowser/newOpenClipartSearch.js +@@ -1,275 +1,80 @@ + + function OpenClipartSearch2() { +- this.title = "OpenClipart.org (API)"; +- this.name = "OpenClipart.org (API)"; ++ this.title = "OpenClipart.org (cchost)"; ++ this.name = "OpenClipart.org (cchost)"; + this.uri = "http://openclipart.org/"; + + this.icon = "data:image/png;base64," + +- "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" + +- "OcJp9XCvYoAsH/B//9k="; +- +- +- this.baseUri = "http://openclipart.org/api/search/"; ++ "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" + ++ "/xX/BwSxr+GgTUkRAAAAAElFTkSuQmCC"; ++ ++ ++ this.baseUri = "http://www.openclipart.org/cchost/media/api/search"; + + this.options = { +- page: 1 ++ offset: this.offset, ++ limit: this.limit, ++ f: "js" + }; + + this.req = []; +@@ -313,7 +118,7 @@ OpenClipartSearch2.prototype.searchImpl = function(query, options, callback) { + + var thiz = this; + debug("OpenClipart: searching '" + query + "'"); +- debug("url: " + url); ++ //debug("url: " + url); + WebUtil.get(url, function(response) { + var r = thiz.parseSearchResult(response); + if (callback) { +@@ -321,114 +126,25 @@ OpenClipartSearch2.prototype.searchImpl = function(query, options, callback) { + } + }, this.req); + }; ++ + OpenClipartSearch2.prototype.parseSearchResult = function (response) { + var r = {result: [], resultCount: 0}; + if (!response) return r; + try { +- var dom = Dom.parseDocument(response); +- +- Dom.workOn("//*/item", dom, function (itemNode) { +- var item = { +- name: Dom.getSingleValue("./title/text()", itemNode), +- des: Dom.getSingleValue("./description/text()", itemNode), +- src: Dom.getSingleValue("./enclosure/@url", itemNode), +- type: Dom.getSingleValue("./enclosure/@type", itemNode), +- length: Dom.getSingleValue("./enclosure/@length", itemNode), +- thumb: Dom.getSingleValue("./media:thumbnail/@url", itemNode), +- creator: Dom.getSingleValue("./dc:creator/text()", itemNode), +- license: Dom.getSingleValue("./rcc:license/text()", itemNode), +- pubDate: Dom.getSingleValue("./pubDate/text()", itemNode), +- link: Dom.getSingleValue("./link/text()", itemNode) +- }; ++ // FIXME: should use JSON parser ++ response = JSON.parse(response); ++ r.resultCount = response.length; ++ for (var i = 0; i < response.length; i++) { ++ var item = {name: response[i].upload_name, author: response[i].user_real_name, desc: response[i].upload_description, images: []}; ++ for (var j = 0; j < response[i].files.length; j++) { ++ item.images.push({src: response[i].files[j].download_url, type: response[i].files[j].file_format_info.mime_type, typeName: this.formatType(response[i].files[j].file_format_info.mime_type), size: response[i].files[j].file_rawsize}); ++ } + r.result.push(item); +- }); ++ } + } catch (e) { +- error("error: " + e); ++ Console.dumpError(e); + } + return r; + }; + +-function OpenClipartHandler() { +- this.items = []; +- this.currentItem = null; +- this.currentState = OpenClipartHandler.STATE_CHANNEL; +-} +- +-OpenClipartHandler.prototype.startDocument = function() { +-} +- +-OpenClipartHandler.prototype.endDocument = function() { +-} +- +-OpenClipartHandler.prototype.startElement = function(name, attribs) { +- if (!name || name === "") return; +- if (name === "item") { +- this.currentState = OpenClipartHandler.STATE_ITEM; +- this.currentItem = {images: [{type: "image/svg+xml", typeName: "SVG"}]}; +- } else if (name === "title") { +- if (this.currentState >= OpenClipartHandler.STATE_ITEM) { +- this.currentState = OpenClipartHandler.STATE_TITLE; +- } +- } else if (name === "dc:creator") { +- if (this.currentState >= OpenClipartHandler.STATE_ITEM) { +- this.currentState = OpenClipartHandler.STATE_AUTHOR; +- } +- } else if (name === "description") { +- if (this.currentState >= OpenClipartHandler.STATE_ITEM) { +- this.currentState = OpenClipartHandler.STATE_DESC; +- } +- } else if (name === "enclosure") { +- if (this.currentState >= OpenClipartHandler.STATE_ITEM) { +- this.currentItem.images[0].src = attribs["url"]; +- this.currentState = OpenClipartHandler.STATE_URL; +- } +- } else if (name === "media:thumbnail") { +- if (this.currentState >= OpenClipartHandler.STATE_ITEM) { +- this.currentItem.images[0].thumbnail = attribs["url"]; +- this.currentState = OpenClipartHandler.STATE_THUMBNAIL; +- } +- } +-} +-OpenClipartHandler.prototype.endElement = function(name) { +- if (!name || name === "") return; +- if (name === "item") { +- this.currentState = OpenClipartHandler.STATE_CHANNEL; +- this.items.push(this.currentItem); +- } else if (name === "title") { +- if (this.currentState == OpenClipartHandler.STATE_TITLE) { +- this.currentItem.name = this.currentText; +- this.currentState = OpenClipartHandler.STATE_ITEM; +- } +- } else if (name === "dc:creator") { +- if (this.currentState == OpenClipartHandler.STATE_AUTHOR) { +- this.currentItem.author = this.currentText; +- this.currentState = OpenClipartHandler.STATE_ITEM; +- } +- } else if (name === "description") { +- if (this.currentState == OpenClipartHandler.STATE_DESC) { +- this.currentItem.desc = this.currentText; +- this.currentState = OpenClipartHandler.STATE_ITEM; +- } +- } else if (name === "enclosure ") { +- if (this.currentState == OpenClipartHandler.STATE_URL) { +- this.currentState = OpenClipartHandler.STATE_ITEM; +- } +- } else if (name === "media:thumbnail ") { +- if (this.currentState == OpenClipartHandler.STATE_THUMBNAIL) { +- this.currentState = OpenClipartHandler.STATE_ITEM; +- } +- } +-} +-OpenClipartHandler.prototype.characters = function(data) { +- this.currentText = data; +-} +- +-OpenClipartHandler.STATE_CHANNEL = 0; +-OpenClipartHandler.STATE_ITEM = 2; +-OpenClipartHandler.STATE_TITLE = 21; +-OpenClipartHandler.STATE_DESC = 22; +-OpenClipartHandler.STATE_AUTHOR = 23; +-OpenClipartHandler.STATE_URL = 24; +-OpenClipartHandler.STATE_THUMBNAIL = 25; +- +-// SearchManager.registerSearchEngine(OpenClipartSearch2, true); ++SearchManager.registerSearchEngine(OpenClipartSearch2, true); +diff --git a/app/pencil-core/common/Canvas.js b/app/pencil-core/common/Canvas.js +index 95f85bd..12f2995 100644 +--- a/app/pencil-core/common/Canvas.js ++++ b/app/pencil-core/common/Canvas.js +@@ -171,6 +171,7 @@ function Canvas(element, options, containerScrollPane) { + "RangeBound"); + + this.snappingHelper = new SnappingHelper(this); ++ new GestureHelper(this); + + this.idSeed = 1; + +@@ -960,6 +961,8 @@ Canvas.prototype.handleScrollPane = function(event) { + } + + Canvas.prototype.handleMouseUp = function (event) { ++ if (this.gestureHelper && this.gestureHelper.handleMouseUp(event)) return; ++ + if (this.resizing) { + this.commitResize(event); + this.isSelectingRange = false; +@@ -981,7 +984,7 @@ Canvas.prototype.handleMouseUp = function (event) { + setter : null + }); + } +- ++ + Connector.prepareInvalidation(this); + + if (this.currentController.invalidateOutboundConnections) { +@@ -990,7 +993,7 @@ Canvas.prototype.handleMouseUp = function (event) { + if (this.currentController.invalidateInboundConnections) { + this.currentController.invalidateInboundConnections(); + } +- ++ + Connector.finishInvalidation(); + } + if (this.controllerHeld && this.hasMoved) { +@@ -1005,7 +1008,7 @@ Canvas.prototype.handleMouseUp = function (event) { + this.hasMoved = true; + + this.controllerHeld = false; +- ++ + if (this.isSelectingRange) { + this.setRangeBoundVisibility(false); + this.isSelectingRange = false; +@@ -1156,7 +1159,7 @@ Canvas.prototype.handleResizeMouseMove = function (event) { + + var dw = Math.round((event.clientX - this.resizeInfo.ox) / this.zoom); + var dh = Math.round((event.clientY - this.resizeInfo.oy) / this.zoom); +- ++ + if (event.shiftKey) dw = 0; + + var newW = this.resizeInfo.ow + dw; +@@ -1277,7 +1280,7 @@ Canvas.prototype.handleMouseMove = function (event, fake) { + + var dx = newX - this.oX; + var dy = newY - this.oY; +- ++ + //direction ratios + var hdr = event.ctrlKey && Math.abs(dx) < Math.abs(dy) ? 0 : 1; + var vdr = event.ctrlKey && Math.abs(dx) >= Math.abs(dy) ? 0 : 1; +@@ -1297,92 +1300,17 @@ Canvas.prototype.handleMouseMove = function (event, fake) { + + this.hasMoved = true; + +- var gridSize = Pencil.getGridSize(); +- var snap = null; +- if (Config.get("object.snapping.enabled", true) == true) { +- snap = this.snappingHelper.findSnapping(accX +- && !this.snappingHelper.snappedX, accY +- && !this.snappingHelper.snappedY, null, null, +- event.shiftKey); +- } +- if (Config.get("edit.snap.grid", false) == true) { +- var snapGrid = this.snappingHelper.findSnapping(accX +- && !this.snappingHelper.snappedX, accY +- && !this.snappingHelper.snappedY, null, gridSize.w / 2, +- event.shiftKey, true); +- if (snap && snapGrid) { +- if (snap.dx == 0) { +- snap.dx = snapGrid.dx; +- } +- if (snap.dy == 0) { +- snap.dy = snapGrid.dy; +- } +- } else { +- snap = snapGrid; +- } +- // debug("snap grid: " + [snapGrid.dx, snapGrid.dy]); +- } +- // debug("snap: " + [snap.dx, snap.dy, this.snappedX, +- // this.snappedY]); +- if (!event.shiftKey +- && snap +- && ((snap.dx != 0 && !this.snappingHelper.snappedX && accX) +- || (snap.dy != 0 && !this.snappingHelper.snappedY && accY) +- )) { +- if (snap.dx != 0 && !this.snappingHelper.snappedX) { +- this.snappingHelper.snappedX = true; +- this.snappingHelper.snapX = newX; +- this.currentController._pSnapshot.lastDX += snap.dx; +- // debug("snapX"); +- } +- if (snap.dy != 0 && !this.snappingHelper.snappedY) { +- this.snappingHelper.snappedY = true; +- this.snappingHelper.snapY = newY; +- this.currentController._pSnapshot.lastDY += snap.dy; +- // debug("snapY"); +- } +- this.currentController.moveBy(snap.dx * hdr, snap.dy * vdr); +- } else { +- var unsnapX = event.shiftKey +- || (this.snappingHelper.snapX != 0 && (Math +- .abs(this.snappingHelper.snapX - newX) > this.snappingHelper.unsnapX)); +- var unsnapY = event.shiftKey +- || (this.snappingHelper.snapY != 0 && (Math +- .abs(this.snappingHelper.snapY - newY) > this.snappingHelper.unsnapY)); +- // debug("unsnap: " + [unsnapX, unsnapY]); +- +- if (!this.snappingHelper.snappedX +- && !this.snappingHelper.snappedY) { +- this.currentController.moveFromSnapshot(dx * hdr, dy * vdr); +- } else { +- if (unsnapX || !this.snappingHelper.snappedX) { +- this.currentController +- .moveFromSnapshot( +- dx * hdr, +- this.snappingHelper.snappedY ? this.currentController._pSnapshot.lastDY * vdr +- : dy * vdr); +- } +- if (unsnapY || !this.snappingHelper.snappedY) { +- this.currentController +- .moveFromSnapshot( +- this.snappingHelper.snappedX ? this.currentController._pSnapshot.lastDX * hdr +- : dx * hdr, dy * vdr); +- this.snappingHelper.snapY = 0; +- this.snappingHelper.snappedY = false; +- } +- if (unsnapX || !this.snappingHelper.snappedX) { +- this.snappingHelper.snapX = 0; +- this.snappingHelper.snappedX = false; +- } +- +- if (unsnapX) { +- this.snappingHelper.clearSnappingGuideX(); +- } +- if (unsnapY) { +- this.snappingHelper.clearSnappingGuideY(); +- } +- } ++ dx = dx * hdr; ++ dy = dy * vdr; ++ ++ if (!event.shiftKey) { ++ var snapResult = this.snappingHelper.applySnapping(dx, dy, this.currentController); ++ if (snapResult && snapResult.xsnap) dx = snapResult.xsnap.d; ++ if (snapResult && snapResult.ysnap) dy = snapResult.ysnap.d; + } ++ ++ this.currentController.moveFromSnapshot(dx, dy); ++ + if (this.currentController.dockingManager) { + this.currentController.dockingManager.altKey = event.altKey; + } +@@ -1474,7 +1402,7 @@ Canvas.prototype.handleKeyPress = function (event) { + this.run(function () { + // this.currentController.moveBy(dx, dy); + this.currentController.moveBy(dx, dy, false, true); +- ++ + Connector.prepareInvalidation(this); + if (this.currentController.invalidateOutboundConnections) { + this.currentController.invalidateOutboundConnections(); +@@ -1925,7 +1853,7 @@ Canvas.prototype.invalidateEditors = function (source) { + e.invalidate(); + } + +- // Pencil.invalidateSharedEditor(); ++ Pencil.invalidateSharedEditor(); + // invalidates all selections + for (var i = 0; i < this.selectionContainer.childNodes.length; i++) { + var rect = this.selectionContainer.childNodes[i]; +@@ -2115,7 +2043,7 @@ Canvas.prototype.doPaste = function (withAlternative) { + if (image) { + var id = Pencil.controller.nativeImageToRefSync(image); + var size = image.getSize(); +- ++ + contents.push({ + type: PNGImageXferHelper.MIME_TYPE, + data: new ImageData(size.width, size.height, ImageData.idToRefString(id)) +@@ -2154,6 +2082,8 @@ Canvas.prototype.handleMouseDown = function (event) { + tick("begin"); + Dom.emitEvent("p:CanvasMouseDown", this.element, {}); + ++ if (this.gestureHelper && this.gestureHelper.handleMouseDown(event)) return; ++ + var canvasList = Pencil.getCanvasList(); + for (var i = 0; i < canvasList.length; i++) { + if (canvasList[i] != this) { +@@ -2175,9 +2105,9 @@ Canvas.prototype.handleMouseDown = function (event) { + return node.hasAttributeNS + && node.hasAttributeNS(PencilNamespaces.p, "type"); + }); +- ++ + if (top && this.isShapeLocked(top)) top = null; +- ++ + if (!top) { + this.lastTop = null; + // this.clearSelection(); +@@ -2196,7 +2126,7 @@ Canvas.prototype.handleMouseDown = function (event) { + width : 0, + height : 0 + }; +- ++ + this._sayTargetChanged(); + this.endFormatPainter(); + +@@ -2289,6 +2219,7 @@ Canvas.prototype.handleMouseDown = function (event) { + + tick("before setPositionSnapshot"); + thiz.currentController.setPositionSnapshot(); ++ thiz.snappingHelper.onControllerSnapshot(this.currentController); + tick("after setPositionSnapshot"); + + thiz.duplicateFunc = null; +@@ -2332,6 +2263,7 @@ Canvas.prototype.handleMouseDown = function (event) { + + tick("before setPositionSnapshot"); + this.currentController.setPositionSnapshot(); ++ this.snappingHelper.onControllerSnapshot(this.currentController); + tick("after setPositionSnapshot"); + + if (event.button == 0) +@@ -2923,6 +2855,7 @@ Canvas.prototype.startFakeMove = function (event) { + this.oldPos = this.currentController.getGeometry(); + + this.currentController.setPositionSnapshot(); ++ this.snappingHelper.onControllerSnapshot(this.currentController); + + // OnScreenTextEditor._hide(); + +@@ -2979,6 +2912,9 @@ Canvas.prototype.__dragenter = function (event) { + }; + Canvas.prototype.__dragleave = function (event) { + // this.element.removeAttribute("p:selection"); ++ this.element.removeAttribute("is-dragover"); ++ this.element.removeAttribute("p:holding"); ++ + if (!this.currentDragObserver) + return; + try { +@@ -2986,8 +2922,6 @@ Canvas.prototype.__dragleave = function (event) { + } catch (e) { + Console.dumpError(e); + } +- this.element.removeAttribute("is-dragover"); +- this.element.removeAttribute("p:holding"); + }; + Canvas.prototype.__dragend = function (event) { + this.element.removeAttribute("is-dragover"); +diff --git a/app/pencil-core/common/DocumentHandler.js b/app/pencil-core/common/DocumentHandler.js +index 747206b..8cb7b9c 100644 +--- a/app/pencil-core/common/DocumentHandler.js ++++ b/app/pencil-core/common/DocumentHandler.js +@@ -46,11 +46,11 @@ DocumentHandler.prototype.openDocument = function (callback) { + filters: [ + { name: "Pencil Documents", extensions: thiz.getAllSupportedExtensions(false) } + ] +- }, function (filenames) { +- if (!filenames || filenames.length <= 0) return; +- Config.set("document.open.recentlyDirPath", path.dirname(filenames[0])); ++ }).then(function (res) { ++ if (!res || !res.filePaths || res.filePaths.length <= 0) return; ++ Config.set("document.open.recentlyDirPath", path.dirname(res.filePaths[0])); + +- thiz.loadDocument(filenames[0], callback); ++ thiz.loadDocument(res.filePaths[0], callback); + + }); + }; +@@ -146,8 +146,9 @@ DocumentHandler.prototype.pickupTargetFileToSave = function (callback) { + title: "Save as", + defaultPath: defaultPath, + filters: filters +- }, function (filePath) { +- if (filePath) { ++ }).then(function (res) { ++ if (res && res.filePath) { ++ var filePath = res.filePath; + var ext = path.extname(filePath); + if (ext != defaultFileType && fs.existsSync(filePath)) { + Dialog.confirm("Are you sure you want to overwrite the existing file?", filePath, +@@ -166,7 +167,7 @@ DocumentHandler.prototype.pickupTargetFileToSave = function (callback) { + Config.set("document.save.recentlyDirPath", path.dirname(filePath)); + } + if (callback) { +- callback(filePath); ++ callback(res.filePath); + } + }); + }; +diff --git a/app/pencil-core/common/FontLoader.js b/app/pencil-core/common/FontLoader.js +index 11efd5d..0d566fa 100644 +--- a/app/pencil-core/common/FontLoader.js ++++ b/app/pencil-core/common/FontLoader.js +@@ -151,7 +151,7 @@ FontLoader.prototype.embedToDocumentRepo = function (faces) { + var font = this.userRepo.getFont(f); + var userFont = this.documentRepo.getFont(f); + if (userFont) { +- if (!font.autoEmbed) { ++ if (font && !font.autoEmbed) { + this.documentRepo.removeFont(userFont); + } + return; +diff --git a/app/pencil-core/common/canvas-external-renderer.js b/app/pencil-core/common/canvas-external-renderer.js +index 2f5f6de..86439f1 100644 +--- a/app/pencil-core/common/canvas-external-renderer.js ++++ b/app/pencil-core/common/canvas-external-renderer.js +@@ -94,7 +94,7 @@ function init() { + if (ext == ".png") mine = "image/png"; + + fs.readFile(sourcePath, function (error, bitmap) { +- var url = "data:" + mime + ";base64," + new Buffer(bitmap).toString("base64"); ++ var url = "data:" + mime + ";base64," + Buffer.from(bitmap).toString("base64"); + + image.setAttributeNS(xlink, "href", url); + totalImageLength += url.length; +diff --git a/app/pencil-core/common/config.js b/app/pencil-core/common/config.js +index 5e14de7..ca91c8c 100644 +--- a/app/pencil-core/common/config.js ++++ b/app/pencil-core/common/config.js +@@ -73,3 +73,4 @@ Config.DEVICE_ADB_PATH = Config.define("device.adb_path", "adb"); + Config.EXPORT_CROP_FOR_CLIPBOARD = Config.define("export.crop_for_clipboard", false); + Config.EXPORT_DEFAULT_SCALE = Config.define("export.default_scale", 1); + Config.EXPORT_DEFAULT_BACKGROUND_COLOR = Config.define("export.default_background_color", ""); ++Config.CORE_USE_HWA = Config.define("core.useHardwareAcceleration", false); +diff --git a/app/pencil-core/common/controller.js b/app/pencil-core/common/controller.js +index 8a6e2c2..7f92fdb 100644 +--- a/app/pencil-core/common/controller.js ++++ b/app/pencil-core/common/controller.js +@@ -1158,12 +1158,13 @@ Controller.prototype.rasterizeCurrentPage = function (targetPage) { + filters: [ + { name: "PNG Image (*.png)", extensions: ["png"] } + ] +- }, function (filePath) { +- if (!filePath) return; ++ }).then(function (res) { ++ if (!res || !res.filePath) return; ++ var filePath = res.filePath; + this.applicationPane.rasterizer.rasterizePageToFile(page, filePath, function (p, error) { + if (!error) { + NotificationPopup.show("Page exprted as '" + path.basename(filePath) + "'.", "View", function () { +- shell.openItem(filePath); ++ shell.openPath(filePath); + }); + } + }, undefined, false, options); +@@ -1204,7 +1205,8 @@ Controller.prototype.copyPageBitmap = function (targetPage) { + var filePath = tmp.tmpNameSync(); + thiz.applicationPane.rasterizer.rasterizePageToFile(page, filePath, function (p, error) { + if (!error) { +- clipboard.writeImage(filePath); ++ var image = nativeImage.createFromPath(filePath); ++ var result = clipboard.writeImage(image); + fs.unlinkSync(filePath); + NotificationPopup.show("Page bitmap copied into clipboard."); + } +@@ -1232,7 +1234,8 @@ Controller.prototype.rasterizeSelection = function (options) { + + this.applicationPane.rasterizer.rasterizeSelectionToFile(target, filePath, function (p, error) { + if (!error) { +- clipboard.writeImage(filePath); ++ var image = nativeImage.createFromPath(filePath); ++ clipboard.writeImage(image); + fs.unlinkSync(filePath); + NotificationPopup.show("Page bitmap copied into clipboard."); + } +@@ -1244,12 +1247,13 @@ Controller.prototype.rasterizeSelection = function (options) { + filters: [ + { name: "PNG Image (*.png)", extensions: ["png"] } + ] +- }, function (filePath) { +- if (!filePath) return; ++ }).then(function (res) { ++ if (!res || !res.filePath) return; ++ var filePath = res.filePath; + this.applicationPane.rasterizer.rasterizeSelectionToFile(target, filePath, function (p, error) { + if (!error) { + NotificationPopup.show("Selection exprted as '" + path.basename(filePath) + "'.", "View", function () { +- shell.openItem(filePath); ++ shell.openPath(filePath); + }); + } + }, undefined, options); +@@ -1684,14 +1688,14 @@ Controller.prototype.exportAsLayout = function () { + title: "Export Layout", + defaultPath: defaultPath, + filters: [{name: 'XHTML Layout', extensions: ["xhtml"]}] +- }, function (filePath) { +- if (filePath) { +- outputPath = filePath; +- outputImage = path.join(path.dirname(outputPath), IMAGE_FILE); +- Pencil.rasterizer.rasterizePageToFile(thiz.activePage, outputImage, function (p, error) { +- done(); +- }); +- } ++ }).then(function (res) { ++ if (!res || !res.filePath) return; ++ var filePath = res.filePath; ++ outputPath = filePath; ++ outputImage = path.join(path.dirname(outputPath), IMAGE_FILE); ++ Pencil.rasterizer.rasterizePageToFile(thiz.activePage, outputImage, function (p, error) { ++ done(); ++ }); + }); + }; + +diff --git a/app/pencil-core/common/externalEditorSupports.js b/app/pencil-core/common/externalEditorSupports.js +index e55d600..4e187d5 100644 +--- a/app/pencil-core/common/externalEditorSupports.js ++++ b/app/pencil-core/common/externalEditorSupports.js +@@ -6,6 +6,15 @@ ExternalEditorSupports.getEditorPath = function (extension) { + || extension == "gif" + || extension == "png") return Config.get("external.editor.bitmap.path", "/usr/bin/gimp -n %f"); + ++ var configName = "external.editor." + extension + ".path"; ++ var p = Config.get(configName, null); ++ ++ if (p) { ++ return p; ++ } else if (p == null) { ++ Config.define(configName, ""); ++ } ++ + throw Util.getMessage("unsupported.type", extension); + }; + ExternalEditorSupports.queue = []; +@@ -39,14 +48,22 @@ ExternalEditorSupports.handleEditRequest = function (contentProvider, contentRec + params.push(tmpFile.name); + } + ++ var startedAt = new Date().getTime(); + var process = spawn(executablePath, params); + + var timeOutId = null; + process.on("close", function () { ++ var closedAt = new Date().getTime(); ++ console.log("Closed: ", closedAt - startedAt); ++ if (closedAt - startedAt < 2000) { ++ Dialog.alert("Editor exited almost immediately", "The external edit has exited almost immediately after be launched. This is usually caused by the case where an existing instance of the editor software is running. Please make sure that is not the case."); ++ } + try { + contentReceiver.update(tmpFile.name); + if (timeOutId) window.clearTimeout(timeOutId); +- tmpFile.removeCallback(); ++ window.setTimeout(function () { ++ tmpFile.removeCallback(); ++ }, 3000); + } catch (e) { + console.error(e); + } +diff --git a/app/pencil-core/common/renderer.js b/app/pencil-core/common/renderer.js +index 7cbc182..5e13b2e 100644 +--- a/app/pencil-core/common/renderer.js ++++ b/app/pencil-core/common/renderer.js +@@ -78,7 +78,7 @@ module.exports = function () { + if (err) throw err; + + var svg = data.svg; +- var delay = 10; ++ var delay = 500; + console.log("data.scale", data.scale); + var scale = typeof(data.scale) == "number" ? data.scale : 1; + +@@ -112,8 +112,10 @@ module.exports = function () { + + ' window.setTimeout(function () {\n' + + ' window.requestAnimationFrame(function () {\n' + + ' window.requestAnimationFrame(function () {\n' +- + ' ipcRenderer.send("render-rendered", {objectsWithLinking: window.objectsWithLinking});\n' +- + ' console.log("Rendered signaled");\n' ++ + ' window.setTimeout(function () {\n' ++ + ' ipcRenderer.send("render-rendered", {objectsWithLinking: window.objectsWithLinking});\n' ++ + ' console.log("Rendered signaled");\n' ++ + ' }, 500);\n' + + ' });\n' + + ' });\n' + + ' }, ' + delay + ');\n' +@@ -141,7 +143,7 @@ module.exports = function () { + event.sender.send(data.id, {url: "", objectsWithLinking: renderedData.objectsWithLinking}); + __callback(); + } else { +- rendererWindow.capturePage(function (nativeImage) { ++ rendererWindow.capturePage().then(function (nativeImage) { + var dataURL = nativeImage.toDataURL(); + + cleanupCallback(); +diff --git a/app/pencil-core/common/shared-util.js b/app/pencil-core/common/shared-util.js +index 3e8864a..3bae7f0 100644 +--- a/app/pencil-core/common/shared-util.js ++++ b/app/pencil-core/common/shared-util.js +@@ -51,7 +51,7 @@ module.exports = function () { + var format = FORMAT_MAP[ext]; + if (!format) format = "truetype"; + +- var url = "data:" + mime + ";base64," + new Buffer(bytes).toString("base64"); ++ var url = "data:" + mime + ";base64," + Buffer.from(bytes).toString("base64"); + + combinedCSS += "@font-face {\n" + + " font-family: '" + installedFace.name + "';\n" +diff --git a/app/pencil-core/common/svgRasterizer.js b/app/pencil-core/common/svgRasterizer.js +index 977c8c7..398d1f2 100644 +--- a/app/pencil-core/common/svgRasterizer.js ++++ b/app/pencil-core/common/svgRasterizer.js +@@ -44,7 +44,7 @@ Rasterizer.ipcBasedBackend = { + // if (scale != 1) { + // svgNode.setAttribute("width", w + "px"); + // svgNode.setAttribute("height", h + "px"); +- // ++ // + // svgNode.setAttribute("viewBox", "0 0 " + width + " " + height); + // } + +@@ -125,7 +125,7 @@ Rasterizer.inProcessCanvasBasedBackend = { + if (ext == ".png") mine = "image/png"; + + fs.readFile(sourcePath, function (error, bitmap) { +- var url = "data:" + mime + ";base64," + new Buffer(bitmap).toString("base64"); ++ var url = "data:" + mime + ";base64," + Buffer.from(bitmap).toString("base64"); + + image.setAttributeNS(PencilNamespaces.xlink, "href", url); + totalImageLength += url.length; +@@ -167,9 +167,67 @@ Rasterizer.inProcessCanvasBasedBackend = { + convertNext(); + } + }; ++Rasterizer.inProcessFileCanvasBasedBackend = { ++ init: function () { ++ //the in-process rasterize requires basicly nothing to init :) ++ }, ++ rasterize: function (svgNode, width, height, s, callback, parseLinks, options) { ++ console.log("rasterize() called", [svgNode, width, height, s, callback, parseLinks, options]); ++ var images = svgNode.querySelectorAll("image"); ++ var totalImageLength = 0; ++ ++ for (var i = 0; i < images.length; i ++) { ++ var image = images[i]; ++ var href = image.getAttributeNS(PencilNamespaces.xlink, "href"); ++ if (href && href.match("^file://(.+)$")) { ++ var sourcePath = decodeURI(RegExp.$1); ++ try { ++ fs.accessSync(sourcePath, fs.R_OK); ++ image.setAttribute("crossorigin", "anonymous"); ++ } catch (e) { ++ image.setAttributeNS(PencilNamespaces.xlink, "href", ""); ++ } ++ } ++ } ++ ++ var tempFile = tmp.fileSync({postfix: ".svg" }); ++ fs.writeFileSync(tempFile.name, Controller.serializer.serializeToString(svgNode), XMLDocumentPersister.CHARSET); ++ ++ var delay = 500; ++ ++ var canvas = document.createElement("canvas"); ++ canvas.setAttribute("style", "display: none;"); ++ canvas.setAttribute("width", width * s); ++ canvas.setAttribute("height", height * s); ++ document.body.appendChild(canvas); ++ var ctx = canvas.getContext("2d"); ++ ++ var img = document.createElement("img"); + ++ img.onload = function () { ++ ctx.save(); ++ ctx.scale(s, s); ++ ctx.drawImage(img, 0, 0); ++ ctx.setTransform(1, 0, 0, 1, 0, 0); ++ ++ setTimeout(function () { ++ callback(canvas.toDataURL()); ++ ctx.restore(); ++ img.onload = null; ++ img.src = ""; ++ }, delay); ++ }; ++ ++ img.setAttribute("crossorigin", "anonymous"); ++ img.setAttribute("style", "display: none;"); ++ document.body.appendChild(img); ++ ++ img.setAttribute("src", "file://" + tempFile.name); ++ } ++}; + Rasterizer.prototype.getBackend = function () { + //TODO: options or condition? ++ // return Rasterizer.inProcessFileCanvasBasedBackend; + return Rasterizer.ipcBasedBackend; + // return Rasterizer.outProcessCanvasBasedBackend; + }; +@@ -194,7 +252,7 @@ Rasterizer.prototype.rasterizePageToUrl = function (page, callback, scale, parse + g.appendChild(svg.removeChild(svg.firstChild)); + } + svg.appendChild(g); +- ++ + w -= 2 * m; + h -= 2 * m; + svg.setAttribute("width", w); +@@ -281,7 +339,7 @@ Rasterizer.prototype.rasterizePageToFile = function (page, filePath, callback, s + var base64Data = dataURI; + if (base64Data.startsWith(prefix)) base64Data = base64Data.substring(prefix.length); + +- var buffer = new Buffer(base64Data, "base64"); ++ var buffer = Buffer.from(base64Data, "base64"); + fs.writeFile(actualPath, buffer, "utf8", function (err) { + console.log("Finish rasterizing page: ", page.name, actualPath); + callback(parseLinks ? {actualPath: actualPath, objectsWithLinking: data.objectsWithLinking} : actualPath, err); +@@ -290,7 +348,7 @@ Rasterizer.prototype.rasterizePageToFile = function (page, filePath, callback, s + }; + Rasterizer.getExportScale = function (inputScale) { + if (typeof(inputScale) == "number") return inputScale; +- ++ + var configScale = Config.get(Config.EXPORT_DEFAULT_SCALE, 1.0); + if (typeof(configScale) == "number") { + return configScale; +@@ -347,7 +405,7 @@ Rasterizer.prototype.rasterizeSelectionToFile = function (target, filePath, call + var base64Data = dataURI; + if (base64Data.startsWith(prefix)) base64Data = base64Data.substring(prefix.length); + +- var buffer = new Buffer(base64Data, "base64"); ++ var buffer = Buffer.from(base64Data, "base64"); + fs.writeFile(actualPath, buffer, {}, function (err) { + callback(actualPath, err); + }); +diff --git a/app/pencil-core/common/util.js b/app/pencil-core/common/util.js +index a6c761e..ac9ad79 100644 +--- a/app/pencil-core/common/util.js ++++ b/app/pencil-core/common/util.js +@@ -2154,13 +2154,20 @@ Util.imageOnloadListener = function (event) { + + }; + Util.setupImage = function (image, src, mode, allowUpscale) { +- image.onload = Util.imageOnloadListener; +- image.style.visibility = "hidden"; +- image.style.width = "0px"; +- image.style.height = "0px"; +- image._mode = mode; +- image._allowUpscale = allowUpscale; ++ // image.onload = Util.imageOnloadListener; ++ // image.style.visibility = "hidden"; ++ image.style.width = "100%"; ++ image.style.height = "100%"; ++ image.style.opacity = "0"; + image.src = src; ++ ++ mode = mode || "center-crop"; ++ ++ var hp = (mode.indexOf("left") >= 0) ? "left" : ((mode.indexOf("right") >= 0) ? "right" : " center"); ++ var vp = (mode.indexOf("top") >= 0) ? "top" : ((mode.indexOf("bottom") >= 0) ? "bottom" : " center"); ++ image.parentNode.style.backgroundImage = "url('" + src + "')"; ++ image.parentNode.style.backgroundPosition = hp + " " + vp; ++ image.parentNode.style.backgroundSize = (mode.indexOf("crop") >= 0) ? "cover" : "contain"; + }; + + Util.isDev = function() { +@@ -2466,6 +2473,33 @@ function copyFolderRecursiveSync(source, target) { + } + } + ++function PropertyMask(names) { ++ this.names = (typeof(names) == "string") ? [names] : names; ++} ++PropertyMask.prototype.and = function (other) { ++ return new PropertyMask(this.names.concat.other.names); ++}; ++PropertyMask.prototype.contains = function (name) { ++ return this.names.indexOf(name) >= 0; ++}; ++PropertyMask.prototype.apply = function (original, newValue) { ++ if (!original || !newValue) return original; ++ var value = new original.constructor(); ++ for (var name in original) { ++ if (original.hasOwnProperty(name)) { ++ value[name] = original[name]; ++ } ++ } ++ ++ for (var name of this.names) { ++ if (newValue.hasOwnProperty(name)) { ++ value[name] = newValue[name]; ++ } ++ } ++ ++ return value; ++}; ++ + function getStaticFilePath(subPath) { + var filePath = __dirname; + if (!subPath) return filePath; +diff --git a/app/pencil-core/common/webPrinter.js b/app/pencil-core/common/webPrinter.js +index f9db73a..27184d2 100644 +--- a/app/pencil-core/common/webPrinter.js ++++ b/app/pencil-core/common/webPrinter.js +@@ -38,17 +38,7 @@ module.exports = function () { + // } + // } + // }); +- browserWindow.webContents.printToPDF(options, function(error, pdfBuffer) { +- if (error) { +- try { +- global.mainWindow.webContents.send(data.id, {success: false, message: error.message}); +- } finally { +- __callback(); +- } +- +- return; +- } +- ++ browserWindow.webContents.printToPDF(options).then(function(pdfBuffer) { + fs.writeFile(data.targetFilePath, pdfBuffer, function(error) { + try { + if (error) { +@@ -60,6 +50,12 @@ module.exports = function () { + } finally { + __callback(); + } ++ }).catch (function (error) { ++ try { ++ global.mainWindow.webContents.send(data.id, {success: false, message: error.message}); ++ } finally { ++ __callback(); ++ } + }) + }); + } else { +diff --git a/app/pencil-core/definition/collectionManager.js b/app/pencil-core/definition/collectionManager.js +index d3962ad..2435b5d 100644 +--- a/app/pencil-core/definition/collectionManager.js ++++ b/app/pencil-core/definition/collectionManager.js +@@ -313,10 +313,10 @@ CollectionManager.installNewCollection = function (callback) { + { name: "Stencil files", extensions: ["zip", "epc"] } + ] + +- }, function (filenames) { +- if (!filenames || filenames.length <= 0) return; +- Config.set("collection.install.recentlyDirPath", path.dirname(filenames[0])); +- CollectionManager.installCollectionFromFilePath(filenames[0], callback); ++ }).then(function (res) { ++ if (!res || !res.filePaths || res.filePaths.length <= 0) return; ++ Config.set("collection.install.recentlyDirPath", path.dirname(res.filePaths[0])); ++ CollectionManager.installCollectionFromFilePath(res.filePaths[0], callback); + }); + }; + +diff --git a/app/pencil-core/editor/geometryEditor.js b/app/pencil-core/editor/geometryEditor.js +index 13ab8b2..824770a 100644 +--- a/app/pencil-core/editor/geometryEditor.js ++++ b/app/pencil-core/editor/geometryEditor.js +@@ -16,6 +16,7 @@ GeometryEditor.prototype.resetAccomulatedChanges = function () { + }; + GeometryEditor.prototype.install = function (canvas) { + this.canvas = canvas; ++ this.canvas.geometryEditor = this; + this.canvas.onScreenEditors.push(this); + this.svgElement = canvas.ownerDocument.importNode(Dom.getSingle("/p:Config/svg:g", GeometryEditor.configDoc), true); + +@@ -314,6 +315,7 @@ GeometryEditor.prototype.handleMouseUp = function (event) { + }, this, Util.getMessage("action.move.shape")); + } + } finally { ++ console.log("Setting currentAnchor = null"); + this.currentAnchor = null; + } + }; +@@ -361,6 +363,7 @@ GeometryEditor.prototype.handleMouseMove = function (event) { + var uPoint1 = Svg.vectorInCTM(new Point(this.oX, this.oY), this.geo.ctm); + var uPoint2 = Svg.vectorInCTM(new Point(event.clientX, event.clientY), this.geo.ctm); + ++ + var matrix = this.currentAnchor._matrix; + var t = event.shiftKey ? {x: 1, y: 1} : this.getGridSize(); //Svg.vectorInCTM(this.getGridSize(), this.geo.ctm, true); + var grid = {w: t.x * this.canvas.zoom, h: t.y * this.canvas.zoom}; +@@ -390,6 +393,8 @@ GeometryEditor.prototype.handleMouseMove = function (event) { + var controller = this.canvas.currentController; + var bound = controller.getBounding(); + ++ var xsnap = null; ++ + //HORIZONTAL + if (!locking.width) { + dx = matrix.dx * mdx; +@@ -404,28 +409,13 @@ GeometryEditor.prototype.handleMouseMove = function (event) { + + var delta = newXNormalized - newX; + +- if (!locking.ratio) { ++ if (!locking.ratio && !event.shiftKey) { + var snapping = this._lastGuides.left ? this._lastGuides.left.clone() : + new SnappingData("Left", bound.x, "Left", true, Util.newUUID()); +- snapping.pos += dx; +- var snap = this.canvas.snappingHelper.findSnapping(true, false, { +- vertical: [ snapping ], horizontal: [] +- }, (grid.w / 2) - 1); +- +- if (snap && (snap.dx != 0 && !this.canvas.snappingHelper.snappedX)) { +- this.canvas.snappingHelper.snappedX = true; +- this.canvas.snappingHelper.snapX = newX; +- delta = snap.dx; +- } else { +- var unsnapX = (this.canvas.snappingHelper.snapX != 0 && (Math.abs(this.canvas.snappingHelper.snapX - newX) > grid.w / 2)); +- if (unsnapX || !this.canvas.snappingHelper.snappedX) { +- this.canvas.snappingHelper.snapX = 0; +- this.canvas.snappingHelper.snappedX = false; +- this.canvas.snappingHelper.clearSnappingGuideX(); +- } else { +- delta = snap.dx; +- } +- } ++ ++ xsnap = this.canvas.snappingHelper.applySnappingValue(dx, [snapping], this.canvas.snappingHelper.lastXData, this.canvas.currentController); ++ if (xsnap) delta = xsnap.d - dx; ++ this.canvas.snappingHelper.drawSnaps(xsnap, null); + } + + dx += delta; +@@ -438,28 +428,13 @@ GeometryEditor.prototype.handleMouseMove = function (event) { + + var delta = newX2Normalized - newX2; + +- if (!locking.ratio) { ++ if (!locking.ratio && !event.shiftKey) { + var snapping = this._lastGuides.right ? this._lastGuides.right.clone() : +- new SnappingData("Right", bound.x + bound.width, "Right", true, Util.newUUID()); +- snapping.pos += dw; +- +- var snap = this.canvas.snappingHelper.findSnapping(true, false, { +- vertical: [snapping], horizontal: [] +- }, (grid.w / 2) - 1); +- if (snap && (snap.dx != 0 && !this.canvas.snappingHelper.snappedX)) { +- this.canvas.snappingHelper.snappedX = true; +- this.canvas.snappingHelper.snapX = newX2; +- delta = snap.dx; +- } else { +- var unsnapX = (this.canvas.snappingHelper.snapX != 0 && (Math.abs(this.canvas.snappingHelper.snapX - newX2) > grid.w / 2)); +- if (unsnapX || !this.canvas.snappingHelper.snappedX) { +- this.canvas.snappingHelper.snapX = 0; +- this.canvas.snappingHelper.snappedX = false; +- this.canvas.snappingHelper.clearSnappingGuideX(); +- } else { +- delta = snap.dx; +- } +- } ++ new SnappingData("Right", bound.x + bound.width, "Right", true, Util.newUUID()); ++ ++ xsnap = this.canvas.snappingHelper.applySnappingValue(dw, [snapping], this.canvas.snappingHelper.lastXData, this.canvas.currentController); ++ if (xsnap) delta = xsnap.d - dw; ++ this.canvas.snappingHelper.drawSnaps(xsnap, null); + } + + dw += delta; +@@ -481,29 +456,13 @@ GeometryEditor.prototype.handleMouseMove = function (event) { + + var delta = newYNormalized - newY; + +- if (!locking.ratio) { ++ if (!locking.ratio && !event.shiftKey) { + var snapping = this._lastGuides.top ? this._lastGuides.top.clone() : +- new SnappingData("Top", bound.y, "Top", true, Util.newUUID()); +- snapping.pos += dy; +- +- var snap = this.canvas.snappingHelper.findSnapping(false, true, { +- vertical: [], +- horizontal: [snapping] +- }, (grid.w / 2) - 1); +- if (snap && (snap.dy != 0 && !this.canvas.snappingHelper.snappedY)) { +- this.canvas.snappingHelper.snappedY = true; +- this.canvas.snappingHelper.snapY = newY; +- delta = snap.dy; +- } else { +- var unsnapY = (this.canvas.snappingHelper.snapY != 0 && (Math.abs(this.canvas.snappingHelper.snapY - newY) > grid.w / 2)); +- if (unsnapY || !this.canvas.snappingHelper.snappedY) { +- this.canvas.snappingHelper.snapY = 0; +- this.canvas.snappingHelper.snappedY = false; +- this.canvas.snappingHelper.clearSnappingGuideY(); +- } else { +- delta = snap.dy; +- } +- } ++ new SnappingData("Top", bound.y, "Top", true, Util.newUUID()); ++ ++ var ysnap = this.canvas.snappingHelper.applySnappingValue(dy, [snapping], this.canvas.snappingHelper.lastYData, this.canvas.currentController); ++ if (ysnap) delta = ysnap.d - dy; ++ this.canvas.snappingHelper.drawSnaps(xsnap, ysnap); + } + + dy += delta; +@@ -515,30 +474,13 @@ GeometryEditor.prototype.handleMouseMove = function (event) { + + var delta = newY2Normalized - newY2; + +- if (!locking.ratio) { ++ if (!locking.ratio && !event.shiftKey) { + var snapping = this._lastGuides.bottom ? this._lastGuides.bottom.clone() : +- new SnappingData("Bottom", bound.y + bound.height, "Bottom", true, Util.newUUID()); +- snapping.pos += dh; +- +- +- var snap = this.canvas.snappingHelper.findSnapping(false, true, { +- vertical: [], +- horizontal: [snapping] +- }, (grid.w / 2) - 1); +- if (snap && (snap.dy != 0 && !this.canvas.snappingHelper.snappedY)) { +- this.canvas.snappingHelper.snappedY = true; +- this.canvas.snappingHelper.snapY = newY2; +- delta = snap.dy; +- } else { +- var unsnapY = (this.canvas.snappingHelper.snapY != 0 && (Math.abs(this.canvas.snappingHelper.snapY - newY2) > grid.w / 2)); +- if (unsnapY || !this.canvas.snappingHelper.snappedY) { +- this.canvas.snappingHelper.snapY = 0; +- this.canvas.snappingHelper.snappedY = false; +- this.canvas.snappingHelper.clearSnappingGuideY(); +- } else { +- delta = snap.dy; +- } +- } ++ new SnappingData("Bottom", bound.y + bound.height, "Bottom", true, Util.newUUID()); ++ ++ var ysnap = this.canvas.snappingHelper.applySnappingValue(dh, [snapping], this.canvas.snappingHelper.lastYData, this.canvas.currentController); ++ if (ysnap) delta = ysnap.d - dh; ++ this.canvas.snappingHelper.drawSnaps(xsnap, ysnap); + } + + dh += delta; +diff --git a/app/pencil-core/exporter/documentExportManager.js b/app/pencil-core/exporter/documentExportManager.js +index 872a0e5..ae6bf1c 100644 +--- a/app/pencil-core/exporter/documentExportManager.js ++++ b/app/pencil-core/exporter/documentExportManager.js +@@ -36,6 +36,7 @@ DocumentExportManager.prototype.generateFriendlyId = function (page, usedFriendl + return name; + }; + DocumentExportManager.prototype._exportDocumentWithParamsImpl = function (doc, forcedExporterId, params) { ++ console.log("Export requested..."); + var exporter = Pencil.getDocumentExporterById(params.exporterId); + if (!exporter) return; + +@@ -140,13 +141,14 @@ DocumentExportManager.prototype._exportDocumentWithParamsImpl = function (doc, f + thiz._exportDocumentToXML(doc, pages, pageExtraInfos, destFile, params, function () { + listener.onTaskDone(); + NotificationPopup.show(Util.getMessage("document.has.been.exported", destFile), "View", function () { +- shell.openItem(destFile); ++ shell.openPath(destFile); + }); + }); + }) + return; + } + var page = pages[pageIndex]; ++ console.log("Rasiterizing " + page.name); + + //signal progress + var task = Util.getMessage("exporting.page.no.prefix", page.name); +@@ -184,7 +186,7 @@ DocumentExportManager.prototype._exportDocumentWithParamsImpl = function (doc, f + listener.onTaskDone(); + if (destFile) { + NotificationPopup.show(Util.getMessage("document.has.been.exported", destFile), "View", function () { +- shell.openItem(destFile); ++ shell.openPath(destFile); + }); + } else { + NotificationPopup.show("Document has been exported."); +@@ -407,7 +409,8 @@ DocumentExportManager.prototype._exportDocumentToXML = function (doc, pages, pag + + try { + exporter.export(this.doc, exportSelection, destFile, xmlFile.name, function () { +- xmlFile.removeCallback(); ++ console.log("xmlFile:" + xmlFile.name); ++ //xmlFile.removeCallback(); + callback(); + }); + } catch (e) { +diff --git a/app/pencil-core/privateCollection/privateCollectionManager.js b/app/pencil-core/privateCollection/privateCollectionManager.js +index b4aaa6b..fed0dbd 100644 +--- a/app/pencil-core/privateCollection/privateCollectionManager.js ++++ b/app/pencil-core/privateCollection/privateCollectionManager.js +@@ -11,8 +11,7 @@ PrivateCollectionManager.loadPrivateCollections = function () { + var privateCollectionXmlLocation = path.join(PrivateCollectionManager.getPrivateCollectionDirectory(), "PrivateCollection.xml"); + + // privateCollectionXmlLocation.append("PrivateCollection.xml"); +- var stat = fs.statSync(privateCollectionXmlLocation); +- if (!stat) return; ++ if (!fs.existsSync(privateCollectionXmlLocation)) return; + + // var fileContents = FileIO.read(privateCollectionXmlLocation, ShapeDefCollectionParser.CHARSET); + var fileContents = fs.readFileSync(privateCollectionXmlLocation, ShapeDefCollectionParser.CHARSET); +diff --git a/app/pencil-core/propertyType/alignment.js b/app/pencil-core/propertyType/alignment.js +index 2adca1c..a7a49a0 100644 +--- a/app/pencil-core/propertyType/alignment.js ++++ b/app/pencil-core/propertyType/alignment.js +@@ -2,6 +2,10 @@ function Alignment(h, v) { + this.h = h ? h : 0; + this.v = v ? v : 0; + } ++ ++Alignment.H = new PropertyMask("h"); ++Alignment.V = new PropertyMask("v"); ++ + Alignment.REG_EX = /^([0-9]+)\,([0-9]+)$/; + Alignment.fromString = function(literal) { + var align = new Alignment(0, 0); +diff --git a/app/pencil-core/propertyType/font.js b/app/pencil-core/propertyType/font.js +index 7b6d42e..971b0f4 100644 +--- a/app/pencil-core/propertyType/font.js ++++ b/app/pencil-core/propertyType/font.js +@@ -9,6 +9,14 @@ function Font() { + Font.REG_EX = /^([^\|]+)\|([^\|]+)\|([^\|]+)\|([0-9]+[a-z]+)$/i; + Font.REG_EX_2 = /^([^\|]+)\|([^\|]+)\|([^\|]+)\|([0-9]+[a-z]+)\|([^\|]+)$/i; + Font.REG_EX_3 = /^([^\|]+)\|([^\|]+)\|([^\|]+)\|([0-9]+[a-z]+)\|([^\|]+)\|([0-9\.]+)$/i; ++ ++Font.FAMILY = new PropertyMask("family"); ++Font.STYLE = new PropertyMask("style"); ++Font.WEIGHT = new PropertyMask("weight"); ++Font.SIZE = new PropertyMask("size"); ++Font.DECOR = new PropertyMask("decor"); ++Font.LINE_HEIGHT = new PropertyMask("lineHeight"); ++ + Font.fromString = function (literal) { + var font = new Font(); + font.decor = "none"; +diff --git a/app/pencil-core/propertyType/shadowStyle.js b/app/pencil-core/propertyType/shadowStyle.js +index 26c4807..87c09f5 100644 +--- a/app/pencil-core/propertyType/shadowStyle.js ++++ b/app/pencil-core/propertyType/shadowStyle.js +@@ -8,6 +8,12 @@ function ShadowStyle() { + + ShadowStyle.DEFAULT_COLOR = "#000000"; + ++ShadowStyle.DX = new PropertyMask("dx"); ++ShadowStyle.DY = new PropertyMask("dy"); ++ShadowStyle.SIZE = new PropertyMask("size"); ++ShadowStyle.OPACITY = new PropertyMask("opacity"); ++ShadowStyle.COLOR = new PropertyMask("color"); ++ + ShadowStyle.REG_EX = /^([^\|]+)\|([^\|]+)\|([^\|]+)(\|([^\|]+))?(\|([^\|]+))?$/i; + ShadowStyle.fromString = function (literal) { + var shadowStyle = new ShadowStyle(); +diff --git a/app/pencil-core/propertyType/strokeStyle.js b/app/pencil-core/propertyType/strokeStyle.js +index 350e92d..de574ac 100644 +--- a/app/pencil-core/propertyType/strokeStyle.js ++++ b/app/pencil-core/propertyType/strokeStyle.js +@@ -2,6 +2,10 @@ function StrokeStyle(w, array) { + this.w = (typeof(w) == "number") ? w : 1; + this.array = typeof(array) != "undefined" ? array : null; + } ++ ++StrokeStyle.W = new PropertyMask("w"); ++StrokeStyle.ARRAY = new PropertyMask("array"); ++ + StrokeStyle.REG_EX = /^([0-9]+)\|([0-9 \,]*)$/; + StrokeStyle.fromString = function(literal) { + var style = new StrokeStyle(); +diff --git a/app/pencil-core/target/group.js b/app/pencil-core/target/group.js +index 2a38d9d..1f411f6 100644 +--- a/app/pencil-core/target/group.js ++++ b/app/pencil-core/target/group.js +@@ -75,9 +75,9 @@ Group.prototype.getProperties = function () { + Group.prototype.getPropertyGroups = function () { + return [this.propertyGroup]; + }; +-Group.prototype.setProperty = function (name, value) { ++Group.prototype.setProperty = function (name, value, nested, mask) { + for (t in this.targets) { +- this.targets[t].setProperty(name, value); ++ this.targets[t].setProperty(name, value, nested, mask); + } + }; + Group.prototype.getProperty = function (name) { +diff --git a/app/pencil-core/target/shape.js b/app/pencil-core/target/shape.js +index 25807d7..fa7a2b2 100644 +--- a/app/pencil-core/target/shape.js ++++ b/app/pencil-core/target/shape.js +@@ -362,7 +362,13 @@ Shape.prototype.evalExpression = function (expression, value) { + return defaultValue; + } + }; +-Shape.prototype.setProperty = function (name, value, nested) { ++Shape.prototype.setProperty = function (name, value, nested, mask) { ++ if (mask) { ++ try { ++ value = mask.apply(this.getProperty(name), value); ++ } catch (e) { ++ } ++ } + if (!nested) { + this._appliedTargets = []; + this.canvas.run( function () { +@@ -1131,6 +1137,10 @@ Shape.prototype.getSnappingGuide = function () { + + var customSnappingData = this.performAction("getSnappingGuide"); + if (customSnappingData) { ++ if (customSnappingData._ignoreBuiltIns) { ++ vertical.length = 0; ++ horizontal.length = 0; ++ } + for (var i = 0; i < customSnappingData.length; i++) { + var data = customSnappingData[i]; + var m = this.svg.getTransformToElement(this.canvas.drawingLayer); +@@ -1146,7 +1156,7 @@ Shape.prototype.getSnappingGuide = function () { + ik = k; + } + } +- if (ik != -1) { ++ if (ik != -1 && !customSnappingData._allowTypeDuplications) { + vertical[ik] = data; + } else { + vertical.push(data); +@@ -1161,7 +1171,7 @@ Shape.prototype.getSnappingGuide = function () { + ik = k; + } + } +- if (ik != -1) { ++ if (ik != -1 && !customSnappingData._allowTypeDuplications) { + horizontal[ik] = data; + } else { + horizontal.push(data); +diff --git a/app/pencil-core/target/targetSet.js b/app/pencil-core/target/targetSet.js +index 5194cc9..b3eaa3c 100644 +--- a/app/pencil-core/target/targetSet.js ++++ b/app/pencil-core/target/targetSet.js +@@ -64,9 +64,9 @@ TargetSet.prototype.applyBehaviorForProperty = function (name) { + TargetSet.prototype.getPropertyGroups = function () { + return [this.propertyGroup]; + }; +-TargetSet.prototype.setProperty = function (name, value) { ++TargetSet.prototype.setProperty = function (name, value, nested, mask) { + for (t in this.targets) { +- this.targets[t].setProperty(name, value); ++ this.targets[t].setProperty(name, value, nested, mask); + } + }; + TargetSet.prototype.getProperty = function (name, any) { +diff --git a/app/pencil-core/templates/HTML/prototype.HTML/Resources/expand.png b/app/pencil-core/templates/HTML/prototype.HTML/Resources/expand.png +new file mode 100644 +index 0000000..a906329 +Binary files /dev/null and b/app/pencil-core/templates/HTML/prototype.HTML/Resources/expand.png differ +diff --git a/app/pencil-core/templates/HTML/prototype.HTML/Resources/fit.png b/app/pencil-core/templates/HTML/prototype.HTML/Resources/fit.png +new file mode 100644 +index 0000000..497b3fc +Binary files /dev/null and b/app/pencil-core/templates/HTML/prototype.HTML/Resources/fit.png differ +diff --git a/app/pencil-core/templates/HTML/prototype.HTML/Resources/script.js b/app/pencil-core/templates/HTML/prototype.HTML/Resources/script.js +index 1c1fed0..43e7767 100644 +--- a/app/pencil-core/templates/HTML/prototype.HTML/Resources/script.js ++++ b/app/pencil-core/templates/HTML/prototype.HTML/Resources/script.js +@@ -8,77 +8,87 @@ function scaleMap(page, r) { + } else { + container.innerHTML = ""; + } +- ++ + map.querySelectorAll("area").forEach(function (area) { + var original = area._originalCoords || area.getAttribute("coords"); + area._originalCoords = original; + var coords = original.split(/\,/).map(function (v) { + return Math.round(parseFloat(v) / r); + }); +- ++ + area.setAttribute("coords", coords.join(",")); + var a = document.createElement("a"); +- a.style.left = coords[0] + "px"; +- a.style.top = coords[1] + "px"; +- a.style.width = (coords[2] - coords[0]) + "px"; +- a.style.height = (coords[3] - coords[1]) + "px"; ++ a.style.left = convertRatio(coords[0]) + "px"; ++ a.style.top = convertRatio(coords[1]) + "px"; ++ a.style.width = convertRatio(coords[2] - coords[0]) + "px"; ++ a.style.height = convertRatio(coords[3] - coords[1]) + "px"; + a.setAttribute("href", area.getAttribute("href")); +- ++ + container.appendChild(a); + }); + } ++function convertRatio(value) { ++ return parseFloat(value); // * window.devicePixelRatio; ++} + + function fitImages() { + var pages = document.querySelectorAll("body > div.Page"); + var W = 0; + var H = 0; +- ++ + var activePage = null; +- ++ + pages.forEach(function (page) { + if (page.offsetWidth == 0 || page.offsetHeight == 0) return; +- +- W = page.offsetWidth - 30; +- H = page.offsetHeight - 30; ++ ++ W = page.offsetWidth - (window.useExpandedMode ? 200 : 40); ++ H = page.offsetHeight - 40; + activePage = page; + }); +- ++ + if (activePage && window.lastActivePage != activePage) { +- document.querySelectorAll(".TOC > div").forEach(function (item) { ++ window.useExpandedMode = false; ++ invalidateExpandMode("dontFit"); ++ window.lastSize = null; ++ ++ document.body.querySelectorAll(".TOC > div").forEach(function (item) { + var matched = item.classList.contains("Page_" + activePage.id); + if (matched) { ++ document.title = item._name + " - " + window.originalTitle; + item.classList.add("Focused"); + item.focus(); + } else { + item.classList.remove("Focused"); + } + }); ++ ++ window.lastActivePage = activePage; + } +- +- ++ ++ + if (W && H) { + if (window.lastSize && window.lastSize.W == W && window.lastSize.H == H) return; + + var imgs = document.querySelectorAll("body > div.Page img"); + imgs.forEach(function (img) { +- var r = Math.max(img.naturalWidth / W, img.naturalHeight / H); +- +- if (r < 1) r = 1; ++ var r = window.useExpandedMode ? Math.min(img.naturalWidth / W, img.naturalHeight / H) : Math.max(img.naturalWidth / W, img.naturalHeight / H); ++ ++ if (r < 1 && !window.useExpandedMode) r = 1; + var w = Math.round(img.naturalWidth / r); + var h = Math.round(img.naturalHeight / r); +- ++ + img.style.width = w + "px"; + img.style.height = h + "px"; +- ++ + img.setAttribute("width", w); + img.setAttribute("height", h); +- ++ + var page = img; + while (!page.classList.contains("Page")) page = page.parentNode; +- +- scaleMap(page, r); ++ ++ scaleMap(page, r * (img._originalWidth / img.naturalWidth)); + }); +- ++ + window.lastSize = {W: W, H: H}; + } + } +@@ -90,7 +100,7 @@ function checkActivePage() { + if (!firstPage) firstPage = page; + if (page.offsetWidth != 0 && page.offsetHeight != 0) found = true; + }); +- ++ + if (!found && firstPage) { + location.hash = "#" + firstPage.id; + fitImages(); +@@ -122,7 +132,7 @@ function handleMouseMove() { + if (!document.body.classList.contains("Active")) { + document.body.classList.add("Active"); + } +- ++ + if (idleTimeout) window.clearTimeout(idleTimeout); + idleTimeout = window.setTimeout(function () { + document.body.classList.remove("Active"); +@@ -139,17 +149,17 @@ function buildThumbnail(url, callback) { + image.onload = function () { + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); +- ++ + var r = Math.max(image.width / THUMB_WIDTH, image.height / THUMB_HEIGHT); + var w = image.width / r, h = image.height / r; + canvas.width = w; + canvas.height = h; +- ++ + ctx.drawImage(image, 0, 0, w, h); +- ++ + callback(canvas.toDataURL('image/png'), w, h); + }; +- ++ + image.src = url; + } + +@@ -160,65 +170,78 @@ function generateTOC() { + pages.forEach(function (page) { + var title = page.querySelector("h2"); + var img = page.querySelector(".ImageContainer img"); +- ++ + var item = document.createElement("div"); + var imageWrapper = document.createElement("a"); + var itemImage = document.createElement("img"); +- ++ + item.classList.add("Page_" + page.id); + item.setAttribute("tabindex", 0); +- +- imageWrapper.style.width = THUMB_DISPLAY_SIZE + "px"; +- ++ item._name = title.textContent; ++ + imageWrapper.setAttribute("href", "#" + page.id); + + item.appendChild(imageWrapper); + var name = document.createElement("strong"); + name.innerHTML = title.innerHTML; +- item.appendChild(name); +- ++ + toc.appendChild(item); +- ++ + buildThumbnail(img.src, function (dataUrl, w, h) { + var r = Math.max(w / THUMB_DISPLAY_SIZE, h / THUMB_DISPLAY_SIZE); + var w = w / r, h = h / r; +- ++ + imageWrapper.appendChild(itemImage); + itemImage.style.width = w + "px"; + itemImage.style.height = h + "px"; + itemImage.src = dataUrl; ++ ++ imageWrapper.appendChild(name); + }); + }); +- ++ + document.body.appendChild(toc); + } + ++function invalidateExpandMode(dontFit) { ++ if (window.useExpandedMode) { ++ document.body.classList.add("ExpandMode"); ++ } else { ++ document.body.classList.remove("ExpandMode"); ++ } ++ ++ if (!dontFit) fitImages(); ++} ++ + function boot() { ++ window.originalTitle = document.title; + document.addEventListener("mousemove", handleMouseMove); + var style = document.createElement("link"); + style.setAttribute("rel", "stylesheet"); + style.setAttribute("href", "Resources/style.css"); + document.querySelector("head").appendChild(style); +- workingThreadFunction(); +- generateTOC(); +-} +- +-window.onload = boot; +- +- +- +- +- +- +- +- +- +- +- + ++ var imgs = document.querySelectorAll("body > div.Page img"); ++ imgs.forEach(function (img) { ++ img._originalWidth = parseInt(img.getAttribute("width"), 10); ++ img._originalHeight = parseInt(img.getAttribute("height"), 10); ++ }); + + ++ generateTOC(); ++ workingThreadFunction(); + + ++ window.zoomToggleButton = document.createElement("button"); ++ window.zoomToggleButton.classList.add("ToggleZoomButton"); ++ window.zoomToggleButton.setAttribute("title", "Toggle expand/fit mode"); ++ document.body.appendChild(window.zoomToggleButton); + ++ window.zoomToggleButton.addEventListener("click", function () { ++ window.useExpandedMode = window.useExpandedMode ? false : true; ++ window.lastSize = null; ++ invalidateExpandMode(); ++ }, false); ++} + ++window.onload = boot; +diff --git a/app/pencil-core/templates/HTML/prototype.HTML/Resources/style.css b/app/pencil-core/templates/HTML/prototype.HTML/Resources/style.css +index 1419b77..1c967f8 100644 +--- a/app/pencil-core/templates/HTML/prototype.HTML/Resources/style.css ++++ b/app/pencil-core/templates/HTML/prototype.HTML/Resources/style.css +@@ -20,14 +20,22 @@ body, html { + top: 0px; + right: 0px; + bottom: 0px; +- ++ background: #00000077; ++ text-align: center; ++} ++body:not(.ExpandMode) .Page { + display: flex; ++ flex-direction: column; + align-items: center; + justify-content: center; +- background: #00000077; ++} ++body.ExpandMode .Page { ++ overflow: auto; ++ padding: 20px; ++ text-align: center; + } + .Page:not(:target) { +- display: none; ++ display: none !important; + } + + .Page > h2 { +@@ -36,7 +44,10 @@ body, html { + .Page .ImageContainer { + box-shadow: 0px 0px 1em #00000077; + } +- ++body.ExpandMode .Page .ImageContainer { ++ display: inline-block; ++ margin-bottom: 20px; ++} + .Page .ImageContainer { + position: relative; + } +@@ -60,7 +71,7 @@ body.Active .Page .ImageContainer > .Links > a { + width: 230px; + display: flex; + flex-direction: column; +- ++ + overflow-y: auto; + overflow-x: visible; + z-index: 2; +@@ -69,28 +80,36 @@ body.Active .Page .ImageContainer > .Links > a { + .TOC > div { + display: flex; + flex-direction: column; +- align-items: center; +- padding: 1em; +- background: transparent; +- transition: background 0.2s ease; + } +-.TOC > div.Focused { ++.TOC > div.Focused > a { + background: #5294E2; + } +-.TOC > div:not(.Focused):hover { ++.TOC > div:not(.Focused):hover > a { + background: #5294E266; + } ++.TOC > div:not(.Focused):not(:hover) { ++ opacity: 0.7; ++} + .TOC > div + div { + margin-top: 1em; + } + + .TOC > div > a { ++ flex: 1 1 auto; ++ display: flex; ++ flex-direction: column; ++ align-items: center; ++ padding: 1em; ++ background: transparent; ++ transition: background 0.2s ease; ++ text-decoration: none; ++} ++.TOC > div > a > img { + display: block; + border: solid 2px #FFF; + box-shadow: 0px 0px 5px #000; + } +- +-.TOC > div > strong { ++.TOC > div > a > strong { + display: block; + text-align: center; + color: #FFF; +@@ -98,32 +117,27 @@ body.Active .Page .ImageContainer > .Links > a { + margin-top: 0.3em; + } + ++.ToggleZoomButton { ++ position: fixed; ++ top: 0.5em; ++ right: 0.5em; ++ width: 1.5em; ++ height: 1.5em; ++ padding: 0.3em; ++ box-sizing: content-box; ++ background: url(expand.png) 50% 50% no-repeat #CCCCCC; ++ background-origin: content-box; ++ background-size: contain; + +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- ++ border: solid 1px #777; ++} ++.ToggleZoomButton:active { ++ margin-top: 1px; ++ margin-left: 1px; ++} ++.ToggleZoomButton:not(:hover) { ++ opacity: 0.3; ++} ++body.ExpandMode .ToggleZoomButton { ++ background-image: url(fit.png) ++} +diff --git a/app/pencil-core/xferHelper/pngImageXferHelper.js b/app/pencil-core/xferHelper/pngImageXferHelper.js +index 5b04db6..6879391 100644 +--- a/app/pencil-core/xferHelper/pngImageXferHelper.js ++++ b/app/pencil-core/xferHelper/pngImageXferHelper.js +@@ -32,7 +32,8 @@ PNGImageXferHelper.prototype.handleDataImpl = function (imageData, shapeId) { + this.canvas.insertShape(bitmapDef, this.canvas.lastMouse || {x: 10, y: 10}); + + if (this.canvas.currentController) { +- var dim = new Dimension(imageData.w, imageData.h); ++ var ratio = window.devicePixelRatio || 1; ++ var dim = new Dimension(Math.round(imageData.w / ratio), Math.round(imageData.h / ratio)); + this.canvas.currentController.setProperty("imageData", imageData); + this.canvas.currentController.setProperty("box", dim); + this.canvas.invalidateEditors(); +@@ -67,7 +68,8 @@ JPGGIFImageXferHelper.prototype.handleData = function (url) { + var thiz = this; + + var handler = function (imageData) { +- var dim = new Dimension(imageData.w, imageData.h); ++ var ratio = window.devicePixelRatio || 1; ++ var dim = new Dimension(Math.round(imageData.w / ratio), Math.round(imageData.h / ratio)); + thiz.canvas.currentController.setProperty("imageData", imageData); + thiz.canvas.currentController.setProperty("box", dim); + thiz.canvas.invalidateEditors(); +diff --git a/app/views/ApplicationPane.js b/app/views/ApplicationPane.js +index 704fbac..7e2f960 100644 +--- a/app/views/ApplicationPane.js ++++ b/app/views/ApplicationPane.js +@@ -125,13 +125,24 @@ ApplicationPane.prototype.onAttached = function () { + // }); + // }); + // }, 100); +- +- ++ ++ + }; ++ ++Config.UI_CUSTOM_FONT_FAMILY = Config.define("ui.customUIFontFamily", ""); ++Config.UI_CUSTOM_FONT_SIZE = Config.define("ui.customUIFontSize", ""); ++ + ApplicationPane.prototype.invalidateUIForConfig = function () { + debug("BOOT: invalidating UI using configuration"); + var useCompactLayout = Config.get("view.useCompactLayout", false); + document.body.setAttribute("compact-layout", useCompactLayout); ++ ++ var family = Config.get(Config.UI_CUSTOM_FONT_FAMILY); ++ if (family) document.body.style.fontFamily = family; ++ ++ var size = Config.get(Config.UI_CUSTOM_FONT_SIZE); ++ if (size) document.body.style.fontSize = size; ++ + this.toolBarSrollView.invalidate(); + }; + ApplicationPane.prototype.invalidateUIForControllerStatus = function () { +@@ -172,19 +183,19 @@ ApplicationPane.prototype.createCanvas = function () { + var stencilToolbar = new StencilShapeCanvasToolbar().into(wrapper); + + var canvas = null; +- +- ++ ++ + scrollPane.addEventListener("mousedown", function (e) { + scrollPane._mouseDownAt = e.timeStamp; + }); +- ++ + scrollPane.addEventListener("mouseup", function (e) { + if (!scrollPane._mouseDownAt || (e.timeStamp - scrollPane._mouseDownAt) > 150) return; + if (!Dom.findParentWithClass(e.target, "CanvasWrapper")) { + if (!canvas.isSelectingRange) canvas.selectNone(); + } + }); +- ++ + canvas = new Canvas(container, null, scrollPane); + + this.getCanvasContainer().appendChild(scrollPane); +@@ -288,7 +299,7 @@ ApplicationPane.prototype.showStartupPane = function () { + const NO_CONTENT_VALUE = 22; + ApplicationPane.prototype.getNoContentValue = function () { + var compact = Config.get("view.useCompactLayout", false); +- return compact ? 0 : NO_CONTENT_VALUE; ++ return compact ? 10 : NO_CONTENT_VALUE; + } + ApplicationPane.prototype.getCanvasToolbarHeight = function () { + return StencilCollectionBuilder.isDocumentConfiguredAsStencilCollection() ? Math.round(3 * Util.em()) : 0; +diff --git a/app/views/ExportDialog.js b/app/views/ExportDialog.js +index 9e9dcb4..34b6679 100644 +--- a/app/views/ExportDialog.js ++++ b/app/views/ExportDialog.js +@@ -243,10 +243,10 @@ ExportDialog.prototype.getDialogActions = function () { + } + + dialogOptions.filters = filters; +- console.log("dialogOptions", dialogOptions); +- dialog.showSaveDialog(dialogOptions, function (filename) { +- if (!filename) return; +- result.targetPath = filename; ++ dialog.showSaveDialog(dialogOptions).then(function (res) { ++ if (!res || !res.filePath) return; ++ result.targetPath = res.filePath; ++ console.log("Selected", res.filePath); + + this.close(result); + +@@ -262,9 +262,9 @@ ExportDialog.prototype.getDialogActions = function () { + } + } + +- dialog.showOpenDialog(dialogOptions, function (filenames) { +- if (!filenames || filenames.length <= 0) return; +- result.targetPath = filenames[0]; ++ dialog.showOpenDialog(dialogOptions).then(function (res) { ++ if (!res || !res.filePaths || res.filePaths.length <= 0) return; ++ result.targetPath = res.filePaths[0]; + + this.close(result); + +diff --git a/app/views/StartUpDocumentView.js b/app/views/StartUpDocumentView.js +index 8e02e23..93bf998 100644 +--- a/app/views/StartUpDocumentView.js ++++ b/app/views/StartUpDocumentView.js +@@ -24,7 +24,7 @@ function StartUpDocumentView() { + if (pinDocs && pinDocs.indexOf(filePath) >= 0) Dom.addClass(binding.pin, "Unpin"); + if (thumbPath) { + window.setTimeout(function () { +- Util.setupImage(binding.thumbnailImage, ImageData.filePathToURL(thumbPath), "center-crop", "allowUpscale"); ++ Util.setupImage(binding.thumbnailImage, ImageData.filePathToURL(thumbPath), "center-top-crop", "allowUpscale"); + }, 10); + } + binding._node._filePath = filePath; +diff --git a/app/views/StartUpDocumentView.xhtml b/app/views/StartUpDocumentView.xhtml +index 05e6eeb..3f136f9 100644 +--- a/app/views/StartUpDocumentView.xhtml ++++ b/app/views/StartUpDocumentView.xhtml +@@ -44,7 +44,7 @@ + } + @recentDocumentPane .Repeater-Document vbox[role="item"] .ImageContainer { + width: 22ex; +- height: 25ex; ++ height: 14ex; + background: #FFF; + } + @recentDocumentPane .Repeater-Document vbox[role="item"] .InfoPane { +diff --git a/app/views/collections/BaseCollectionPane.js b/app/views/collections/BaseCollectionPane.js +index 9019fb0..aff7054 100644 +--- a/app/views/collections/BaseCollectionPane.js ++++ b/app/views/collections/BaseCollectionPane.js +@@ -224,12 +224,13 @@ BaseCollectionPane.prototype.reload = function (selectedCollectionId) { + BaseCollectionPane.prototype.filterCollections = function () { + var filter = this.searchInput.value; + this.clearTextButton.style.display = filter != null && filter.length > 0 ? "block" : "none" +- var collectionNodes = Dom.getList(".//*[@class='Item']", this.selectorPane); ++ var collectionNodes = this.selectorPane.querySelectorAll(".Item"); + var hasLast = false; + var firstNode = null; + for (var i in collectionNodes) { + var collectionNode = collectionNodes[i]; + var collection = collectionNodes[i]._collection; ++ if (!collection) continue; + collection._shapeCount = 0; + collection._filteredShapes = []; + if (!filter) { +@@ -244,6 +245,7 @@ BaseCollectionPane.prototype.filterCollections = function () { + collection._filteredShapes.push(def); + } + } ++ + if (collection._shapeCount <= 0) { + collectionNode.setAttribute("_hidden", true); + collectionNode.style.display = "none"; +diff --git a/app/views/collections/CollectionBrowserDialog.js b/app/views/collections/CollectionBrowserDialog.js +index b2b7edf..e6917f8 100644 +--- a/app/views/collections/CollectionBrowserDialog.js ++++ b/app/views/collections/CollectionBrowserDialog.js +@@ -9,9 +9,9 @@ function CollectionBrowserDialog (collectionPanel, managerDialog) { + this.managerDialog = managerDialog; + this.title = "Collection Repository"; + this.subTitle = "Browse the user-contributed collection repository." +- ++ + var thiz = this; +- ++ + this.bind("e:TabChange", function (event) { + var tab = this.tabPane.getActiveTabPane(); + if (!tab._initialized) { +diff --git a/app/views/common/Dialog.xhtml b/app/views/common/Dialog.xhtml +index fd43ad3..9acee3c 100644 +--- a/app/views/common/Dialog.xhtml ++++ b/app/views/common/Dialog.xhtml +@@ -52,8 +52,8 @@ + background: rgba(0, 0, 0, 0.05); + } + body @dialogFrame @dialogTitle { +- color: #555555; +- font-size: 1em; ++ color: #567ab4; ++ font-size: 1.3em; + display: block; + } + body @dialogFrame @dialogSubTitle { +@@ -63,18 +63,18 @@ + display: none; + } + body @dialogFrame @dialogTitleContainer { +- padding: 0.5em; + } + body @dialogFrame @dialogHeaderPane { + margin-bottom: 0em; +- background: #d3d3d3; + } + body @dialogFrame @dialogBody { + padding: 1.2em; + overflow: hidden; + } + body @dialogFrame @dialogHeaderPane { +- padding: 0.4em 0.7em; ++ padding: 1.2em; ++ padding-bottom: 0.2em; ++ align-items: center; + } + body @dialogFrame @dialogBody { + padding-bottom: 0em; +@@ -96,6 +96,8 @@ + min-width: 6em; + text-align: center; + display: inline-block; ++ font-weight: bold; ++ text-transform: capitalize; + } + + body @dialogFooter > hbox > button[mode='accept'] { +diff --git a/app/views/common/PageThumbnailView.js b/app/views/common/PageThumbnailView.js +index 46cadd9..fd1f0d2 100644 +--- a/app/views/common/PageThumbnailView.js ++++ b/app/views/common/PageThumbnailView.js +@@ -1,24 +1,24 @@ + function PageThumbnailView() { + BaseTemplatedWidget.call(this); +- this.bind("load", function (event) { +- var W = this.pageThumbnailContainer.offsetWidth - 2; +- var H = this.pageThumbnailContainer.offsetHeight - 2; +- var w = this.pageThumbnail.naturalWidth; +- var h = this.pageThumbnail.naturalHeight; +- +- var r = Math.min(w/W, h/H); +- +- w /= r; +- h /= r; +- +- this.pageThumbnail.style.width = w + "px"; +- this.pageThumbnail.style.height = h + "px"; +- +- this.pageThumbnail.style.left = (W - w) / 2 + "px"; +- this.pageThumbnail.style.top = (H - h) / 2 + "px"; +- +- this.pageThumbnail.style.visibility = "visible"; +- }, this.pageThumbnail); ++ // this.bind("load", function (event) { ++ // var W = this.pageThumbnailContainer.offsetWidth - 2; ++ // var H = this.pageThumbnailContainer.offsetHeight - 2; ++ // var w = this.pageThumbnail.naturalWidth; ++ // var h = this.pageThumbnail.naturalHeight; ++ // ++ // var r = Math.min(w/W, h/H); ++ // ++ // w /= r; ++ // h /= r; ++ // ++ // this.pageThumbnail.style.width = w + "px"; ++ // this.pageThumbnail.style.height = h + "px"; ++ // ++ // this.pageThumbnail.style.left = (W - w) / 2 + "px"; ++ // this.pageThumbnail.style.top = (H - h) / 2 + "px"; ++ // ++ // this.pageThumbnail.style.visibility = "visible"; ++ // }, this.pageThumbnail); + + this.pageThumbnail.style.visibility = "hidden"; + +@@ -47,7 +47,7 @@ PageThumbnailView.prototype.setPage = function (page, childMenu) { + PageThumbnailView.prototype._updateUI = function () { + this.pageThumbnail.style.visibility = "hidden"; + if (!this.page.children || this.page.children.length == 0) this.pageActionButton.style.visibility = "hidden"; +- if (this.page.thumbPath) this.pageThumbnail.src = this.page.thumbPath + "?time=" + (new Date().getTime()); ++ if (this.page.thumbPath) Util.setupImage(this.pageThumbnail, this.page.thumbPath + "?time=" + (new Date().getTime()), "center-top-crop", "allowUpscale"); + // this.pageTitle.appendChild(document.createTextNode(this.page.name)); + this.pageTitle.innerHTML = Dom.htmlEncode(this.page.name); + this.node().setAttribute("title", this.page.name); +diff --git a/app/views/common/ProgressiveJobDialog.xhtml b/app/views/common/ProgressiveJobDialog.xhtml +index ba92c73..c233dc2 100644 +--- a/app/views/common/ProgressiveJobDialog.xhtml ++++ b/app/views/common/ProgressiveJobDialog.xhtml +@@ -7,7 +7,7 @@ + } + @progressBar, + @statusLabel { +- width: 18em; ++ width: 24em; + overflow: hidden; + text-overflow: ellipsis; + } +@@ -15,6 +15,9 @@ + height: 100%; + background: @selected_bg; + } ++ @statusLabel { ++ white-space: nowrap; ++ } + @container { + padding: 1em; + } +diff --git a/app/views/common/Tree.js b/app/views/common/Tree.js +index 2b7ae54..7ac27fa 100644 +--- a/app/views/common/Tree.js ++++ b/app/views/common/Tree.js +@@ -96,7 +96,7 @@ var Tree = function() { + if ((target.checked && tree.options.propagateCheckActionDownwards) + || (!target.checked && tree.options.propagateUncheckActionDownwards)) { + var itemNode = target.parentNode.parentNode; +- setItemsCheckedRecursivelyFromNodes(getChildrenContainerFromItemNode(itemNode).childNodes, target.checked); ++ if (!event.shiftKey) setItemsCheckedRecursivelyFromNodes(getChildrenContainerFromItemNode(itemNode).childNodes, target.checked); + } + + Dom.emitEvent("blur", treeContainer, {}); +diff --git a/app/views/editors/AlignEditor.js b/app/views/editors/AlignEditor.js +index 88132c2..84d2dac 100644 +--- a/app/views/editors/AlignEditor.js ++++ b/app/views/editors/AlignEditor.js +@@ -10,12 +10,12 @@ AlignEditor.prototype.setup = function () { + AlignEditor.prototype._handleClick = function (event) { + var button = Dom.findParentByTagName(event.target, "button"); + if (!button) return; +- ++ + button.parentNode.querySelectorAll("button").forEach(function (b) { + b.setAttribute("checked", b == button); + }); +- +- this.fireChangeEvent(); ++ ++ this.fireChangeEvent(button.parentNode == this.horizontalGroup ? Alignment.H : Alignment.V); + }; + AlignEditor.prototype.setValue = function (alignment) { + this.horizontalGroup.querySelectorAll("button").forEach(function (button) { +diff --git a/app/views/editors/ColorSelector.js b/app/views/editors/ColorSelector.js +index 39f93f1..bb5583f 100644 +--- a/app/views/editors/ColorSelector.js ++++ b/app/views/editors/ColorSelector.js +@@ -193,14 +193,14 @@ function ColorSelector() { + } + this.recentlyUsedColor.addEventListener("click", colorListSelectHandler, false); + this.documentPaletteContainer.addEventListener("click", colorListSelectHandler, false); +- ++ + this.bind("contextmenu", function (event) { + var color = Dom.findUpwardForData(event.target, "_color"); + if (!color) return; + + ColorSelector._handlePaletteMenu(thiz, color, event); + }, this.documentPaletteContainer); +- ++ + this.bind("click", this.pickColor, this.pickerButton); + this.bind("click", this.addToPalette, this.addToPaletteButton); + } +@@ -235,7 +235,7 @@ ColorSelector._handlePaletteMenu = function (thiz, color, event) { + } + }); + } +- ++ + ColorSelector._colorToRemove = color; + ColorSelector._instanceForMenu = thiz; + ColorSelector._paletteMenu.showMenuAt(event.clientX, event.clientY); +@@ -354,7 +354,7 @@ ColorSelector.prototype.setupColors = function () { + }; + ColorSelector.prototype.loadRecentlyUsedColors = function () { + var colors = Config.get("gridcolorpicker.recentlyUsedColors", ""); +- ++ + this._lastUsedColors = colors; + var c = colors.split(","); + this.recentlyUsedColors = c; +@@ -378,16 +378,16 @@ ColorSelector.prototype.addToPalette = function () { + ColorSelector.prototype.loadDocumentColors = function () { + Dom.toggleClass(this.documentPalettePane, "NoDocument", Pencil.controller && Pencil.controller.doc ? false : true); + if (!Pencil.controller || !Pencil.controller.doc) return; +- ++ + Dom.setInnerText(this.paletteTitle, (Pencil.controller.doc.name || "Untitled Document") + " color palette:") +- ++ + var colors = Pencil.controller.getDocumentColorPalette(); + if (!colors || colors.length == 0) { + Dom.addClass(this.documentPalettePane, "Empty"); + } else { + Dom.removeClass(this.documentPalettePane, "Empty"); + } +- ++ + Dom.empty(this.documentPaletteContainer); + colors.forEach(function (c) { + var cell = document.createElement("div"); +@@ -543,20 +543,20 @@ ColorSelector.installGlobalListeners = function () { + ColorSelector.currentPickerInstance.onColorPickingCanceled(); + return; + } +- ++ + var maxWidth = 0; + var maxHeight = 0; + displays.forEach(function (d) { + maxWidth = Math.max(maxWidth, d.bounds.x + d.bounds.width); + maxHeight = Math.max(maxHeight, d.bounds.y + d.bounds.height); + }); +- ++ + + document.body.setAttribute("color-picker-active", "picking"); +- ++ + var x = event.screenX; + var y = event.screenY; +- ++ + new Capturer().captureFullScreenData( + { + x: 0, +@@ -574,7 +574,7 @@ ColorSelector.installGlobalListeners = function () { + ColorSelector.currentPickerInstance.onColorPickingCanceled(); + return; + } +- ++ + ColorSelector.currentPickerInstance.onColorPicked(color); + ColorSelector.currentPickerInstance = null; + }); +@@ -611,15 +611,17 @@ ColorSelector.installGlobalListeners = function () { + }; + ColorSelector.prototype.onColorPickingCanceled = function () { + document.body.removeAttribute("color-picker-active"); ++ document.body.removeAttribute("color-picker-active-external"); + BaseWidget.closableProcessingDisabled = false; + ColorSelector.currentPickerInstance = null; + BaseWidget.unregisterClosable(ColorSelector._pickerClosable); + }; + ColorSelector.prototype.onColorPicked = function (color) { + document.body.removeAttribute("color-picker-active"); ++ document.body.removeAttribute("color-picker-active-external"); + BaseWidget.closableProcessingDisabled = false; + BaseWidget.unregisterClosable(ColorSelector._pickerClosable); +- ++ + var a = this.color.a; + this.color = Color.fromString(color); + this.color.a = a; +@@ -633,7 +635,42 @@ ColorSelector._pickerClosable = { + } + }; + +-ColorSelector.prototype.pickColor = function () { ++ColorSelector.CONFIG_EXTERNAL_COLOR_PICKER_PATH = Config.define("color.external_picker_path", ""); ++ ++ColorSelector.prototype.pickColor = function (event) { ++ var externalPickerPath = Config.get(ColorSelector.CONFIG_EXTERNAL_COLOR_PICKER_PATH, ""); ++ if (!externalPickerPath) { ++ this.pickColorUsingElectronCapture(); ++ return; ++ } ++ ++ var thiz = this; ++ ++ if (event && event.shiftKey) { ++ window.setTimeout(function () { ++ thiz.pickColorUsingExternalTool(externalPickerPath); ++ }, 2000); ++ } else { ++ thiz.pickColorUsingExternalTool(externalPickerPath); ++ } ++}; ++ColorSelector.prototype.pickColorUsingExternalTool = function (externalPickerPath) { ++ var thiz = this; ++ ++ document.body.setAttribute("color-picker-active-external", true); ++ var exec = require("child_process").exec; ++ exec(externalPickerPath, function (error, stdout, stderr) { ++ var color = stdout; ++ console.log("Color: " + color); ++ if (color) { ++ thiz.onColorPicked(color.replace(/[^0-9#A-F]+/gi, "")); ++ } else { ++ thiz.onColorPickingCanceled(); ++ } ++ }); ++} ++ ++ColorSelector.prototype.pickColorUsingElectronCapture = function () { + ColorSelector.installGlobalListeners(); + + document.body.setAttribute("color-picker-active", true); +@@ -641,4 +678,4 @@ ColorSelector.prototype.pickColor = function () { + + ColorSelector.currentPickerInstance = this; + BaseWidget.registerClosable(ColorSelector._pickerClosable); +-}; +\ No newline at end of file ++}; +diff --git a/app/views/editors/ColorSelector.xhtml b/app/views/editors/ColorSelector.xhtml +index e46c0c7..51afcb3 100644 +--- a/app/views/editors/ColorSelector.xhtml ++++ b/app/views/editors/ColorSelector.xhtml +@@ -147,7 +147,8 @@ + margin-left: 0.2ex; + } + +- body[color-picker-active] .ColorPopup { ++ body[color-picker-active] .ColorPopup, ++ body[color-picker-active-external] .ColorPopup { + visibility: hidden !important; + } + body[color-picker-active="true"], +diff --git a/app/views/editors/FontEditor.js b/app/views/editors/FontEditor.js +index f0fdfc6..52fb49e 100644 +--- a/app/views/editors/FontEditor.js ++++ b/app/views/editors/FontEditor.js +@@ -37,14 +37,14 @@ FontEditor._loadFontItems = function (fontCombo, withNullValue) { + FontEditor.prototype.setup = function () { + var thiz = this; + FontEditor._setupFontCombo(this.fontCombo, function () { +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.FAMILY); + }); + + this.bind("p:ItemSelected", this.invalidateWeightCombo, this.fontCombo); + + this.pixelFontSize.addEventListener("input", function(event) { + if (!thiz.font || OnScreenTextEditor.isEditing || thiz.pixelFontSize.value == "" || thiz.pixelFontSize.value < 5) return; +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.SIZE); + }, false); + this.pixelFontSize.addEventListener("keyup", function(event) { + if (event.keyCode == 13 || event.keyCode == 10) { +@@ -52,19 +52,19 @@ FontEditor.prototype.setup = function () { + if (thiz.pixelFontSize.value == "" || thiz.pixelFontSize.value < 5) { + thiz.pixelFontSize.value = 5; + } +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.SIZE); + } + }, false); + this.pixelFontSize.addEventListener("wheel", function(event) { + if (!thiz.font || OnScreenTextEditor.isEditing || thiz.pixelFontSize.value == "" || thiz.pixelFontSize.value < 5) return; +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.SIZE); + }); + this.pixelFontSize.addEventListener("change", function(event) { + if (!thiz.font || OnScreenTextEditor.isEditing) return; + if (thiz.pixelFontSize.value == "" || thiz.pixelFontSize.value < 5) { + thiz.pixelFontSize.value = 5; + } +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.SIZE); + }, false); + + this.boldButton.addEventListener("click", function(event) { +@@ -76,12 +76,12 @@ FontEditor.prototype.setup = function () { + thiz.boldButton.setAttribute("checked", "true"); + checked = true; + } +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.WEIGHT); + }, false); + + this.bind("p:ItemSelected", function () { + if (!thiz.font || OnScreenTextEditor.isEditing) return; +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.WEIGHT); + }, this.weightCombo); + + this.italicButton.addEventListener("click", function(event) { +@@ -94,7 +94,7 @@ FontEditor.prototype.setup = function () { + checked = true; + } + +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.STYLE); + }, false); + + this.lineHeight.addEventListener("keyup", function(event) { +@@ -103,19 +103,19 @@ FontEditor.prototype.setup = function () { + if (thiz.lineHeight.value == "" || thiz.lineHeight.value < 0) { + thiz.lineHeight.value = 0; + } +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.WEIGHT); + } + }, false); + this.lineHeight.addEventListener("wheel", function(event) { + if (!thiz.font || OnScreenTextEditor.isEditing || thiz.lineHeight.value == "" || thiz.lineHeight.value < 0) return; +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.LINE_HEIGHT); + }); + this.lineHeight.addEventListener("change", function(event) { + if (!thiz.font || OnScreenTextEditor.isEditing) return; + if (thiz.lineHeight.value == "" || thiz.lineHeight.value < 0) { + thiz.lineHeight.value = 0; + } +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(Font.LINE_HEIGHT); + }, false); + + +diff --git a/app/views/editors/OnMenuEditor.js b/app/views/editors/OnMenuEditor.js +index 3b1a307..19fde9e 100644 +--- a/app/views/editors/OnMenuEditor.js ++++ b/app/views/editors/OnMenuEditor.js +@@ -132,7 +132,8 @@ OnMenuEditor.prototype.generateMenuItems = function () { + onDone: function (newImageData, options) { + thiz.targetObject.setProperty(propName, newImageData); + if (options && options.updateBox) { +- var dim = new Dimension(newImageData.w, newImageData.h); ++ var ratio = window.devicePixelRatio || 1; ++ var dim = new Dimension(Math.round(newImageData.w / ratio), Math.round(newImageData.h / ratio)); + thiz.targetObject.setProperty("box", dim); + } + } +diff --git a/app/views/editors/PropertyEditor.js b/app/views/editors/PropertyEditor.js +index 9e83182..0a76264 100644 +--- a/app/views/editors/PropertyEditor.js ++++ b/app/views/editors/PropertyEditor.js +@@ -4,7 +4,7 @@ function PropertyEditor() { + } + __extend(BaseTemplatedWidget, PropertyEditor); + +-PropertyEditor.prototype.fireChangeEvent = function () { ++PropertyEditor.prototype.fireChangeEvent = function (mask) { + this.modified = true; +- Dom.emitEvent("p:ValueChanged", this.node(), {}); ++ Dom.emitEvent("p:ValueChanged", this.node(), {mask: mask}); + }; +diff --git a/app/views/editors/ShadowStyleEditor.js b/app/views/editors/ShadowStyleEditor.js +index 2fc5512..000fc7b 100644 +--- a/app/views/editors/ShadowStyleEditor.js ++++ b/app/views/editors/ShadowStyleEditor.js +@@ -27,7 +27,7 @@ ShadowStyleEditor.prototype.setup = function () { + this.selector.addEventListener("ValueChange", function (event) { + thiz.color = thiz.selector.getColor().toRGBString(); + thiz.invalidateColorDisplay(); +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(ShadowStyle.COLOR); + }, false); + + this.selector.addEventListener("p:CloseColorSelector", function (event) { +@@ -37,8 +37,17 @@ ShadowStyleEditor.prototype.setup = function () { + } + }, false); + +- this.node().addEventListener("change", function (event) { +- thiz.fireChangeEvent(); ++ this.dx.addEventListener("change", function (event) { ++ thiz.fireChangeEvent(ShadowStyle.DX); ++ }, false); ++ this.dy.addEventListener("change", function (event) { ++ thiz.fireChangeEvent(ShadowStyle.DY); ++ }, false); ++ this.size.addEventListener("change", function (event) { ++ thiz.fireChangeEvent(ShadowStyle.SIZE); ++ }, false); ++ this.opacity.addEventListener("change", function (event) { ++ thiz.fireChangeEvent(ShadowStyle.OPACITY); + }, false); + }; + ShadowStyleEditor.prototype.setValue = function (shadowStyle) { +diff --git a/app/views/editors/SharedBorderStyleEditor.js b/app/views/editors/SharedBorderStyleEditor.js +index ccc5c72..72c410e 100644 +--- a/app/views/editors/SharedBorderStyleEditor.js ++++ b/app/views/editors/SharedBorderStyleEditor.js +@@ -14,10 +14,10 @@ SharedBorderStyleEditor.prototype.setup = function () { + + var thiz = this; + this.editor.addEventListener("p:ItemSelected", function (event) { +- thiz.handleCommandEvent(); ++ thiz.handleCommandEvent(StrokeStyle.ARRAY); + }, false); + this.editor.addEventListener("input", function (event) { +- thiz.handleCommandEvent(); ++ thiz.handleCommandEvent(StrokeStyle.W); + }, false); + + this.editor.addEventListener("keypress", function (event) { +@@ -27,11 +27,11 @@ SharedBorderStyleEditor.prototype.setup = function () { + }, false); + + }; +-SharedBorderStyleEditor.prototype.handleCommandEvent = function () { ++SharedBorderStyleEditor.prototype.handleCommandEvent = function (mask) { + var thiz = this; + var style = thiz.editor.getValue(); + Pencil.activeCanvas.run(function () { +- this.setProperty(SharedBorderStyleEditor.PROPERTY_NAME, thiz.editor.getValue()); ++ this.setProperty(SharedBorderStyleEditor.PROPERTY_NAME, thiz.editor.getValue(), false, mask); + Pencil.activeCanvas.snappingHelper.updateSnappingGuide(this); + thiz.invalidate(); + Pencil.activeCanvas.invalidateEditors(thiz); +diff --git a/app/views/editors/SharedFontEditor.js b/app/views/editors/SharedFontEditor.js +index b9f493e..d5df4af 100644 +--- a/app/views/editors/SharedFontEditor.js ++++ b/app/views/editors/SharedFontEditor.js +@@ -20,7 +20,7 @@ SharedFontEditor.prototype.setup = function () { + FontEditor._setupFontCombo(this.fontCombo, function(event) { + if (!thiz.target || !thiz.font || OnScreenTextEditor.isEditing) return; + thiz.font.family = thiz.fontCombo.getSelectedItem().family; +- thiz._applyValue(); ++ thiz._applyValue(Font.FAMILY); + }); + + this.bind("p:ItemSelected", this.invalidateWeightCombo, this.fontCombo); +@@ -28,20 +28,20 @@ SharedFontEditor.prototype.setup = function () { + this.pixelFontSize.addEventListener("input", function(event) { + if (!thiz.target || !thiz.font || OnScreenTextEditor.isEditing || thiz.pixelFontSize.value == "" || thiz.pixelFontSize.value == "0") return; + thiz.font.size = thiz.pixelFontSize.value + "px"; +- thiz._applyValue(); ++ thiz._applyValue(Font.SIZE); + }, false); + + this.pixelFontSize.addEventListener("wheel", function(event) { + if (!thiz.target || !thiz.font || OnScreenTextEditor.isEditing || thiz.pixelFontSize.value == "") return; + thiz.font.size = thiz.pixelFontSize.value + "px"; +- thiz._applyValue(); ++ thiz._applyValue(Font.SIZE); + }); + this.pixelFontSize.addEventListener("keyup", function(event) { + if (event.keyCode == 13 || event.keyCode == 10) { + if (!thiz.target || !thiz.font || OnScreenTextEditor.isEditing || thiz.pixelFontSize.value == "") return; + thiz.pixelFontSize.value = Math.max(5, parseInt(thiz.pixelFontSize.value, 10)); + thiz.font.size = thiz.pixelFontSize.value + "px"; +- thiz._applyValue(); ++ thiz._applyValue(Font.SIZE); + } + }, false); + this.pixelFontSize.addEventListener("change", function(event) { +@@ -60,13 +60,13 @@ SharedFontEditor.prototype.setup = function () { + checked = true; + } + thiz.font.weight = checked ? "bold" : "normal"; +- thiz._applyValue(); ++ thiz._applyValue(Font.WEIGHT); + }, false); + + this.bind("p:ItemSelected", function () { + if (!thiz.target || !thiz.font || OnScreenTextEditor.isEditing) return; + thiz.font.weight = thiz.weightCombo.getSelectedItem(); +- thiz._applyValue(); ++ thiz._applyValue(Font.WEIGHT); + + }, this.weightCombo); + +@@ -82,7 +82,7 @@ SharedFontEditor.prototype.setup = function () { + } + + thiz.font.style = checked ? "italic" : "normal"; +- thiz._applyValue(); ++ thiz._applyValue(Font.STYLE); + }, false); + + this.formatPainterButton.addEventListener("click", function (event) { +@@ -139,10 +139,10 @@ SharedFontEditor.prototype.beginFormatPainter = function () { + SharedFontEditor.prototype.isDisabled = function () { + return this.disabledEditor; + }; +-SharedFontEditor.prototype._applyValue = function () { ++SharedFontEditor.prototype._applyValue = function (attrMask) { + var thiz = this; + Pencil.activeCanvas.run(function() { +- this.setProperty(SharedFontEditor.PROPERTY_NAME, thiz.font); ++ this.setProperty(SharedFontEditor.PROPERTY_NAME, thiz.font, false, attrMask); + }, this.target, Util.getMessage("action.apply.properties.value")) + }; + SharedFontEditor.prototype.attach = function (target) { +diff --git a/app/views/editors/SharedPropertyEditor.js b/app/views/editors/SharedPropertyEditor.js +index 81226ec..62b8388 100644 +--- a/app/views/editors/SharedPropertyEditor.js ++++ b/app/views/editors/SharedPropertyEditor.js +@@ -18,7 +18,7 @@ SharedPropertyEditor.prototype.setup = function () { + if (!editor) return; + + var propertyName = editor._property.name; +- thiz.target.setProperty(propertyName, thiz.propertyEditor[propertyName].getValue()); ++ thiz.target.setProperty(propertyName, thiz.propertyEditor[propertyName].getValue(), false, event.mask); + + thiz.validationEditorUI(); + }, false); +diff --git a/app/views/editors/StrokeEditor.js b/app/views/editors/StrokeEditor.js +index 69179d0..7a03497 100644 +--- a/app/views/editors/StrokeEditor.js ++++ b/app/views/editors/StrokeEditor.js +@@ -61,11 +61,11 @@ StrokeEditor.prototype.setup = function () { + this.styleCombo.setItems(strokeItems); + var thiz = this; + this.styleCombo.addEventListener("p:ItemSelected", function (event) { +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(StrokeStyle.ARRAY); + }, false); + this.strokeWidth.addEventListener("input", function (event) { + if (thiz.strokeWidth.value == "") thiz.strokeWidth.value = 1; +- thiz.fireChangeEvent(); ++ thiz.fireChangeEvent(StrokeStyle.W); + }, false); + + }; +diff --git a/app/views/menus/MainMenu.js b/app/views/menus/MainMenu.js +index 6caddec..8007da2 100644 +--- a/app/views/menus/MainMenu.js ++++ b/app/views/menus/MainMenu.js +@@ -194,15 +194,15 @@ MainMenu.prototype.setup = function () { + } + })); + +- // developerToolSubItems.push(UICommandManager.register({ +- // key: "deployStencilCollection", +- // label: "Deploy Stencil Collection...", +- // shortcut: "Ctrl+Shift+D", +- // isAvailable: function () { return Pencil.controller && Pencil.controller.doc; }, +- // run: function () { +- // new StencilCollectionBuilder(Pencil.controller).deploy(); +- // } +- // })); ++ developerToolSubItems.push(UICommandManager.register({ ++ key: "deployStencilCollection", ++ label: "Deploy Stencil Collection...", ++ shortcut: "Ctrl+Shift+D", ++ isAvailable: function () { return Pencil.controller && Pencil.controller.doc; }, ++ run: function () { ++ new StencilCollectionBuilder(Pencil.controller).deploy(); ++ } ++ })); + + developerToolSubItems.push(UICommandManager.register({ + key: "checkMissingResources", +diff --git a/app/views/tools/OpenClipartPane.js b/app/views/tools/OpenClipartPane.js +index 9e34d54..3a2683a 100644 +--- a/app/views/tools/OpenClipartPane.js ++++ b/app/views/tools/OpenClipartPane.js +@@ -1,7 +1,7 @@ + function OpenClipartPane() { + BaseTemplatedWidget.call(this); + var thiz = this; +- this.backend = new OpenClipartSearch(); ++ this.backend = new OpenClipartSearch2(); + + function injectSvgInfo (svg) { + try { +diff --git a/app/views/tools/ScriptEditorDialog.js b/app/views/tools/ScriptEditorDialog.js +index 591d79c..b2eae60 100644 +--- a/app/views/tools/ScriptEditorDialog.js ++++ b/app/views/tools/ScriptEditorDialog.js +@@ -1,6 +1,10 @@ +-function ScriptEditorDialog() { ++function ScriptEditorDialog(large) { + Dialog.call(this); + this.title = "Script Editor"; ++ ++ if (large) { ++ Dom.addClass(this.scriptInputContainer, "Large"); ++ } + } + __extend(Dialog, ScriptEditorDialog); + +diff --git a/app/views/tools/ScriptEditorDialog.xhtml b/app/views/tools/ScriptEditorDialog.xhtml +index 8276528..4b617e3 100644 +--- a/app/views/tools/ScriptEditorDialog.xhtml ++++ b/app/views/tools/ScriptEditorDialog.xhtml +@@ -17,6 +17,10 @@ + height: 40em; + width: 60em; + } ++ @scriptInputContainer.Large { ++ height: 55em; ++ width: 100em; ++ } + + </style> + <hbox flex="1" anon-id="scriptInputContainer"> +diff --git a/app/views/tools/StencilGeneratorDialog.js b/app/views/tools/StencilGeneratorDialog.js +index 6610dab..aff5834 100644 +--- a/app/views/tools/StencilGeneratorDialog.js ++++ b/app/views/tools/StencilGeneratorDialog.js +@@ -241,7 +241,7 @@ StencilGeneratorDialog.prototype.loadStencil = function (result, stencils, index + try { + var readOnDone = function (fileData) { + //var data = Base64.encode(fileData, true); +- var data = new Buffer(fileData).toString("base64"); ++ var data = Buffer.from(fileData).toString("base64"); + var st = { + id: "img_" + _index, + label: _stencils[_index]._label, +diff --git a/package-lock.json b/package-lock.json +index d07ef39..89df0d2 100644 +--- a/package-lock.json ++++ b/package-lock.json +@@ -9,10 +9,96 @@ + "integrity": "sha512-XtGk+IF57pr852UK1AhQJXqmm1WmSgS5uISL+LPs0z/iAxXouMvdlLJrHPeukP6gd7yR2rDTMSMkHNODgwIq7A==", + "dev": true + }, ++ "@electron/get": { ++ "version": "1.12.2", ++ "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.12.2.tgz", ++ "integrity": "sha512-vAuHUbfvBQpYTJ5wB7uVIDq5c/Ry0fiTBMs7lnEYAo/qXXppIVcWdfBr57u6eRnKdVso7KSiH6p/LbQAG6Izrg==", ++ "dev": true, ++ "requires": { ++ "debug": "^4.1.1", ++ "env-paths": "^2.2.0", ++ "fs-extra": "^8.1.0", ++ "global-agent": "^2.0.2", ++ "global-tunnel-ng": "^2.7.1", ++ "got": "^9.6.0", ++ "progress": "^2.0.3", ++ "sanitize-filename": "^1.6.2", ++ "sumchecker": "^3.0.1" ++ }, ++ "dependencies": { ++ "debug": { ++ "version": "4.2.0", ++ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", ++ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", ++ "dev": true, ++ "requires": { ++ "ms": "2.1.2" ++ } ++ }, ++ "get-stream": { ++ "version": "4.1.0", ++ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", ++ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", ++ "dev": true, ++ "requires": { ++ "pump": "^3.0.0" ++ } ++ }, ++ "got": { ++ "version": "9.6.0", ++ "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", ++ "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", ++ "dev": true, ++ "requires": { ++ "@sindresorhus/is": "^0.14.0", ++ "@szmarczak/http-timer": "^1.1.2", ++ "cacheable-request": "^6.0.0", ++ "decompress-response": "^3.3.0", ++ "duplexer3": "^0.1.4", ++ "get-stream": "^4.1.0", ++ "lowercase-keys": "^1.0.1", ++ "mimic-response": "^1.0.1", ++ "p-cancelable": "^1.0.0", ++ "to-readable-stream": "^1.0.0", ++ "url-parse-lax": "^3.0.0" ++ } ++ }, ++ "prepend-http": { ++ "version": "2.0.0", ++ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", ++ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", ++ "dev": true ++ }, ++ "url-parse-lax": { ++ "version": "3.0.0", ++ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", ++ "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", ++ "dev": true, ++ "requires": { ++ "prepend-http": "^2.0.0" ++ } ++ } ++ } ++ }, ++ "@sindresorhus/is": { ++ "version": "0.14.0", ++ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", ++ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", ++ "dev": true ++ }, ++ "@szmarczak/http-timer": { ++ "version": "1.1.2", ++ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", ++ "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", ++ "dev": true, ++ "requires": { ++ "defer-to-connect": "^1.0.1" ++ } ++ }, + "@types/node": { +- "version": "10.14.15", +- "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.15.tgz", +- "integrity": "sha512-CBR5avlLcu0YCILJiDIXeU2pTw7UK/NIxfC63m7d7CVamho1qDEzXKkOtEauQRPMy6MI8mLozth+JJkas7HY6g==", ++ "version": "12.19.2", ++ "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.2.tgz", ++ "integrity": "sha512-SRH6QM0IMOBBFmDiJ75vlhcbUEYEquvSuhsVW9ijG20JvdFTfOrB1p6ddZxz5y/JNnbf+9HoHhjhOVSX2hsJyA==", + "dev": true + }, + "abbrev": { +@@ -208,12 +294,6 @@ + "sprintf-js": "~1.0.2" + } + }, +- "array-find-index": { +- "version": "1.0.2", +- "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", +- "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", +- "dev": true +- }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", +@@ -289,6 +369,13 @@ + "bluebird": "^3.5.5" + } + }, ++ "boolean": { ++ "version": "3.0.1", ++ "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.0.1.tgz", ++ "integrity": "sha512-HRZPIjPcbwAVQvOTxR4YE3o8Xs98NqbbL1iEZDCz7CL8ql0Lt5iOyJFxfnAB0oFs8Oh02F/lLlg30Mexv46LjA==", ++ "dev": true, ++ "optional": true ++ }, + "boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", +@@ -369,6 +456,12 @@ + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, ++ "buffer-crc32": { ++ "version": "0.2.13", ++ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", ++ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", ++ "dev": true ++ }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", +@@ -437,20 +530,36 @@ + } + } + }, +- "camelcase": { +- "version": "2.1.1", +- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", +- "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", +- "dev": true +- }, +- "camelcase-keys": { +- "version": "2.1.0", +- "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", +- "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", ++ "cacheable-request": { ++ "version": "6.1.0", ++ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", ++ "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { +- "camelcase": "^2.0.0", +- "map-obj": "^1.0.0" ++ "clone-response": "^1.0.2", ++ "get-stream": "^5.1.0", ++ "http-cache-semantics": "^4.0.0", ++ "keyv": "^3.0.0", ++ "lowercase-keys": "^2.0.0", ++ "normalize-url": "^4.1.0", ++ "responselike": "^1.0.2" ++ }, ++ "dependencies": { ++ "get-stream": { ++ "version": "5.2.0", ++ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", ++ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", ++ "dev": true, ++ "requires": { ++ "pump": "^3.0.0" ++ } ++ }, ++ "lowercase-keys": { ++ "version": "2.0.0", ++ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", ++ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", ++ "dev": true ++ } + } + }, + "capture-stack-trace": { +@@ -566,6 +675,15 @@ + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, ++ "clone-response": { ++ "version": "1.0.2", ++ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", ++ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", ++ "dev": true, ++ "requires": { ++ "mimic-response": "^1.0.0" ++ } ++ }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", +@@ -617,51 +735,24 @@ + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", +- "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", ++ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" +- }, +- "dependencies": { +- "isarray": { +- "version": "1.0.0", +- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", +- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", +- "dev": true +- }, +- "readable-stream": { +- "version": "2.3.6", +- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", +- "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", +- "dev": true, +- "requires": { +- "core-util-is": "~1.0.0", +- "inherits": "~2.0.3", +- "isarray": "~1.0.0", +- "process-nextick-args": "~2.0.0", +- "safe-buffer": "~5.1.1", +- "string_decoder": "~1.1.1", +- "util-deprecate": "~1.0.1" +- } +- }, +- "safe-buffer": { +- "version": "5.1.2", +- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", +- "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", +- "dev": true +- }, +- "string_decoder": { +- "version": "1.1.1", +- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", +- "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", +- "dev": true, +- "requires": { +- "safe-buffer": "~5.1.0" +- } +- } ++ } ++ }, ++ "config-chain": { ++ "version": "1.1.12", ++ "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", ++ "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "ini": "^1.3.4", ++ "proto-list": "~1.2.1" + } + }, + "configstore": { +@@ -684,6 +775,13 @@ + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, ++ "core-js": { ++ "version": "3.6.5", ++ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", ++ "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", ++ "dev": true, ++ "optional": true ++ }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", +@@ -734,15 +832,6 @@ + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, +- "currently-unhandled": { +- "version": "0.4.1", +- "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", +- "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", +- "dev": true, +- "requires": { +- "array-find-index": "^1.0.1" +- } +- }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", +@@ -775,6 +864,15 @@ + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, ++ "decompress-response": { ++ "version": "3.3.0", ++ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", ++ "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", ++ "dev": true, ++ "requires": { ++ "mimic-response": "^1.0.0" ++ } ++ }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", +@@ -790,6 +888,22 @@ + "clone": "^1.0.2" + } + }, ++ "defer-to-connect": { ++ "version": "1.1.3", ++ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", ++ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", ++ "dev": true ++ }, ++ "define-properties": { ++ "version": "1.1.3", ++ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", ++ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "object-keys": "^1.0.12" ++ } ++ }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", +@@ -808,6 +922,13 @@ + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true + }, ++ "detect-node": { ++ "version": "2.0.4", ++ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", ++ "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", ++ "dev": true, ++ "optional": true ++ }, + "dmg-builder": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-5.3.1.tgz", +@@ -868,13 +989,13 @@ + "dev": true + }, + "electron": { +- "version": "6.0.1", +- "resolved": "https://registry.npmjs.org/electron/-/electron-6.0.1.tgz", +- "integrity": "sha512-XY69rI5IThIxsOS2BD+1ZkHE9hqkm4xN5a3WQFSmFRr2by4q5CnIe9vXmptlouGPTLs3tb7ySX/+K9CvH3szvg==", ++ "version": "10.1.5", ++ "resolved": "https://registry.npmjs.org/electron/-/electron-10.1.5.tgz", ++ "integrity": "sha512-fys/KnEfJq05TtMij+lFvLuKkuVH030CHYx03iZrW5DNNLwjE6cW3pysJ420lB0FRSfPjTHBMu2eVCf5TG71zQ==", + "dev": true, + "requires": { +- "@types/node": "^10.12.18", +- "electron-download": "^4.1.0", ++ "@electron/get": "^1.0.1", ++ "@types/node": "^12.0.12", + "extract-zip": "^1.0.3" + } + }, +@@ -1047,34 +1168,6 @@ + } + } + }, +- "electron-download": { +- "version": "4.1.1", +- "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.1.tgz", +- "integrity": "sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg==", +- "dev": true, +- "requires": { +- "debug": "^3.0.0", +- "env-paths": "^1.0.0", +- "fs-extra": "^4.0.1", +- "minimist": "^1.2.0", +- "nugget": "^2.0.1", +- "path-exists": "^3.0.0", +- "rc": "^1.2.1", +- "semver": "^5.4.1", +- "sumchecker": "^2.0.2" +- }, +- "dependencies": { +- "debug": { +- "version": "3.2.6", +- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", +- "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", +- "dev": true, +- "requires": { +- "ms": "^2.1.1" +- } +- } +- } +- }, + "electron-osx-sign": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.10.tgz", +@@ -1162,6 +1255,13 @@ + "integrity": "sha1-kzoEBShgyF6DwSJHnEdIqOTHIVY=", + "dev": true + }, ++ "encodeurl": { ++ "version": "1.0.2", ++ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", ++ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", ++ "dev": true, ++ "optional": true ++ }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", +@@ -1172,19 +1272,17 @@ + } + }, + "env-paths": { +- "version": "1.0.0", +- "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-1.0.0.tgz", +- "integrity": "sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA=", ++ "version": "2.2.0", ++ "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", ++ "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==", + "dev": true + }, +- "error-ex": { +- "version": "1.3.2", +- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", +- "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", ++ "es6-error": { ++ "version": "4.1.1", ++ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", ++ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, +- "requires": { +- "is-arrayish": "^0.2.1" +- } ++ "optional": true + }, + "escape-string-regexp": { + "version": "1.0.5", +@@ -1220,15 +1318,32 @@ + "dev": true + }, + "extract-zip": { +- "version": "1.6.7", +- "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", +- "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", ++ "version": "1.7.0", ++ "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", ++ "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "dev": true, + "requires": { +- "concat-stream": "1.6.2", +- "debug": "2.6.9", +- "mkdirp": "0.5.1", +- "yauzl": "2.4.1" ++ "concat-stream": "^1.6.2", ++ "debug": "^2.6.9", ++ "mkdirp": "^0.5.4", ++ "yauzl": "^2.10.0" ++ }, ++ "dependencies": { ++ "minimist": { ++ "version": "1.2.5", ++ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", ++ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", ++ "dev": true ++ }, ++ "mkdirp": { ++ "version": "0.5.5", ++ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", ++ "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", ++ "dev": true, ++ "requires": { ++ "minimist": "^1.2.5" ++ } ++ } + } + }, + "extsprintf": { +@@ -1250,35 +1365,14 @@ + "dev": true + }, + "fd-slicer": { +- "version": "1.0.1", +- "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", +- "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", ++ "version": "1.1.0", ++ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", ++ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, +- "find-up": { +- "version": "1.1.2", +- "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", +- "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", +- "dev": true, +- "requires": { +- "path-exists": "^2.0.0", +- "pinkie-promise": "^2.0.0" +- }, +- "dependencies": { +- "path-exists": { +- "version": "2.1.0", +- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", +- "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", +- "dev": true, +- "requires": { +- "pinkie-promise": "^2.0.0" +- } +- } +- } +- }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", +@@ -1297,12 +1391,12 @@ + } + }, + "fs-extra": { +- "version": "4.0.3", +- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", +- "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", ++ "version": "8.1.0", ++ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", ++ "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { +- "graceful-fs": "^4.1.2", ++ "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } +@@ -1367,12 +1461,6 @@ + "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", + "dev": true + }, +- "get-stdin": { +- "version": "4.0.1", +- "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", +- "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", +- "dev": true +- }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", +@@ -1402,6 +1490,31 @@ + "path-is-absolute": "^1.0.0" + } + }, ++ "global-agent": { ++ "version": "2.1.12", ++ "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-2.1.12.tgz", ++ "integrity": "sha512-caAljRMS/qcDo69X9BfkgrihGUgGx44Fb4QQToNQjsiWh+YlQ66uqYVAdA8Olqit+5Ng0nkz09je3ZzANMZcjg==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "boolean": "^3.0.1", ++ "core-js": "^3.6.5", ++ "es6-error": "^4.1.1", ++ "matcher": "^3.0.0", ++ "roarr": "^2.15.3", ++ "semver": "^7.3.2", ++ "serialize-error": "^7.0.1" ++ }, ++ "dependencies": { ++ "semver": { ++ "version": "7.3.2", ++ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", ++ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", ++ "dev": true, ++ "optional": true ++ } ++ } ++ }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", +@@ -1411,6 +1524,29 @@ + "ini": "^1.3.4" + } + }, ++ "global-tunnel-ng": { ++ "version": "2.7.1", ++ "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", ++ "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "encodeurl": "^1.0.2", ++ "lodash": "^4.17.10", ++ "npm-conf": "^1.1.3", ++ "tunnel": "^0.0.6" ++ } ++ }, ++ "globalthis": { ++ "version": "1.0.1", ++ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.1.tgz", ++ "integrity": "sha512-mJPRTc/P39NH/iNG4mXa9aIhNymaQikTrnspeCa2ZuJ+mH2QN/rXwtX3XwKrHqWgUQFbNZKtHM105aHzJalElw==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "define-properties": "^1.1.3" ++ } ++ }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", +@@ -1473,6 +1609,12 @@ + "lru-cache": "^5.1.1" + } + }, ++ "http-cache-semantics": { ++ "version": "4.1.0", ++ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", ++ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", ++ "dev": true ++ }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", +@@ -1505,15 +1647,6 @@ + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, +- "indent-string": { +- "version": "2.1.0", +- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", +- "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", +- "dev": true, +- "requires": { +- "repeating": "^2.0.0" +- } +- }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", +@@ -1542,12 +1675,6 @@ + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, +- "is-arrayish": { +- "version": "0.2.1", +- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", +- "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", +- "dev": true +- }, + "is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", +@@ -1557,15 +1684,6 @@ + "ci-info": "^1.5.0" + } + }, +- "is-finite": { +- "version": "1.0.2", +- "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", +- "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", +- "dev": true, +- "requires": { +- "number-is-nan": "^1.0.0" +- } +- }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", +@@ -1630,16 +1748,10 @@ + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, +- "is-utf8": { +- "version": "0.2.1", +- "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", +- "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", +- "dev": true +- }, + "isarray": { +- "version": "0.0.1", +- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", +- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", ++ "version": "1.0.0", ++ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", ++ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isbinaryfile": { +@@ -1679,6 +1791,12 @@ + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, ++ "json-buffer": { ++ "version": "3.0.0", ++ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", ++ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", ++ "dev": true ++ }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", +@@ -1727,6 +1845,15 @@ + "verror": "1.10.0" + } + }, ++ "keyv": { ++ "version": "3.1.0", ++ "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", ++ "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", ++ "dev": true, ++ "requires": { ++ "json-buffer": "3.0.0" ++ } ++ }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", +@@ -1751,19 +1878,6 @@ + "invert-kv": "^2.0.0" + } + }, +- "load-json-file": { +- "version": "1.1.0", +- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", +- "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", +- "dev": true, +- "requires": { +- "graceful-fs": "^4.1.2", +- "parse-json": "^2.2.0", +- "pify": "^2.0.0", +- "pinkie-promise": "^2.0.0", +- "strip-bom": "^2.0.0" +- } +- }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", +@@ -1774,6 +1888,13 @@ + "path-exists": "^3.0.0" + } + }, ++ "lodash": { ++ "version": "4.17.20", ++ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", ++ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", ++ "dev": true, ++ "optional": true ++ }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", +@@ -1789,16 +1910,6 @@ + "chalk": "^2.0.1" + } + }, +- "loud-rejection": { +- "version": "1.6.0", +- "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", +- "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", +- "dev": true, +- "requires": { +- "currently-unhandled": "^0.4.1", +- "signal-exit": "^3.0.0" +- } +- }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", +@@ -1840,11 +1951,24 @@ + "p-defer": "^1.0.0" + } + }, +- "map-obj": { +- "version": "1.0.1", +- "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", +- "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", +- "dev": true ++ "matcher": { ++ "version": "3.0.0", ++ "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", ++ "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "escape-string-regexp": "^4.0.0" ++ }, ++ "dependencies": { ++ "escape-string-regexp": { ++ "version": "4.0.0", ++ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", ++ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", ++ "dev": true, ++ "optional": true ++ } ++ } + }, + "mem": { + "version": "4.3.0", +@@ -1865,24 +1989,6 @@ + } + } + }, +- "meow": { +- "version": "3.7.0", +- "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", +- "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", +- "dev": true, +- "requires": { +- "camelcase-keys": "^2.0.0", +- "decamelize": "^1.1.2", +- "loud-rejection": "^1.0.0", +- "map-obj": "^1.0.1", +- "minimist": "^1.1.3", +- "normalize-package-data": "^2.3.4", +- "object-assign": "^4.0.1", +- "read-pkg-up": "^1.0.1", +- "redent": "^1.0.0", +- "trim-newlines": "^1.0.0" +- } +- }, + "mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", +@@ -1910,6 +2016,12 @@ + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true + }, ++ "mimic-response": { ++ "version": "1.0.1", ++ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", ++ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", ++ "dev": true ++ }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", +@@ -2030,6 +2142,23 @@ + "validate-npm-package-license": "^3.0.1" + } + }, ++ "normalize-url": { ++ "version": "4.5.0", ++ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", ++ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", ++ "dev": true ++ }, ++ "npm-conf": { ++ "version": "1.1.3", ++ "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", ++ "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "config-chain": "^1.1.11", ++ "pify": "^3.0.0" ++ } ++ }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", +@@ -2051,21 +2180,6 @@ + "set-blocking": "~2.0.0" + } + }, +- "nugget": { +- "version": "2.0.1", +- "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", +- "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=", +- "dev": true, +- "requires": { +- "debug": "^2.1.3", +- "minimist": "^1.1.0", +- "pretty-bytes": "^1.0.2", +- "progress-stream": "^1.1.0", +- "request": "^2.45.0", +- "single-line-log": "^1.1.2", +- "throttleit": "0.0.2" +- } +- }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", +@@ -2085,10 +2199,11 @@ + "dev": true + }, + "object-keys": { +- "version": "0.4.0", +- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", +- "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", +- "dev": true ++ "version": "1.1.1", ++ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", ++ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", ++ "dev": true, ++ "optional": true + }, + "once": { + "version": "1.4.0", +@@ -2211,6 +2326,12 @@ + "os-tmpdir": "^1.0.0" + } + }, ++ "p-cancelable": { ++ "version": "1.1.0", ++ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", ++ "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", ++ "dev": true ++ }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", +@@ -2282,15 +2403,6 @@ + } + } + }, +- "parse-json": { +- "version": "2.2.0", +- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", +- "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", +- "dev": true, +- "requires": { +- "error-ex": "^1.2.0" +- } +- }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", +@@ -2321,17 +2433,6 @@ + "integrity": "sha1-1i27VnlAXXLEc37FhgDp3c8G0kw=", + "dev": true + }, +- "path-type": { +- "version": "1.1.0", +- "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", +- "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", +- "dev": true, +- "requires": { +- "graceful-fs": "^4.1.2", +- "pify": "^2.0.0", +- "pinkie-promise": "^2.0.0" +- } +- }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", +@@ -2345,25 +2446,11 @@ + "dev": true + }, + "pify": { +- "version": "2.3.0", +- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", +- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", +- "dev": true +- }, +- "pinkie": { +- "version": "2.0.4", +- "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", +- "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", +- "dev": true +- }, +- "pinkie-promise": { +- "version": "2.0.1", +- "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", +- "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", ++ "version": "3.0.0", ++ "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", ++ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, +- "requires": { +- "pinkie": "^2.0.0" +- } ++ "optional": true + }, + "plist": { + "version": "3.0.1", +@@ -2396,31 +2483,24 @@ + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, +- "pretty-bytes": { +- "version": "1.0.4", +- "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-1.0.4.tgz", +- "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", +- "dev": true, +- "requires": { +- "get-stdin": "^4.0.1", +- "meow": "^3.1.0" +- } +- }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=", + "dev": true + }, +- "progress-stream": { +- "version": "1.2.0", +- "resolved": "https://registry.npmjs.org/progress-stream/-/progress-stream-1.2.0.tgz", +- "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=", ++ "progress": { ++ "version": "2.0.3", ++ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", ++ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", ++ "dev": true ++ }, ++ "proto-list": { ++ "version": "1.2.4", ++ "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", ++ "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true, +- "requires": { +- "speedometer": "~0.1.2", +- "through2": "~0.2.3" +- } ++ "optional": true + }, + "pseudomap": { + "version": "1.0.2", +@@ -2485,47 +2565,27 @@ + "lazy-val": "^1.0.3" + } + }, +- "read-pkg": { +- "version": "1.1.0", +- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", +- "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", +- "dev": true, +- "requires": { +- "load-json-file": "^1.0.0", +- "normalize-package-data": "^2.3.2", +- "path-type": "^1.0.0" +- } +- }, +- "read-pkg-up": { +- "version": "1.0.1", +- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", +- "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", +- "dev": true, +- "requires": { +- "find-up": "^1.0.0", +- "read-pkg": "^1.0.0" +- } +- }, + "readable-stream": { +- "version": "1.1.14", +- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", +- "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", ++ "version": "2.3.7", ++ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", ++ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", +- "inherits": "~2.0.1", +- "isarray": "0.0.1", +- "string_decoder": "~0.10.x" +- } +- }, +- "redent": { +- "version": "1.0.0", +- "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", +- "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", +- "dev": true, +- "requires": { +- "indent-string": "^2.1.0", +- "strip-indent": "^1.0.1" ++ "inherits": "~2.0.3", ++ "isarray": "~1.0.0", ++ "process-nextick-args": "~2.0.0", ++ "safe-buffer": "~5.1.1", ++ "string_decoder": "~1.1.1", ++ "util-deprecate": "~1.0.1" ++ }, ++ "dependencies": { ++ "safe-buffer": { ++ "version": "5.1.2", ++ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", ++ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", ++ "dev": true ++ } + } + }, + "registry-auth-token": { +@@ -2547,15 +2607,6 @@ + "rc": "^1.0.1" + } + }, +- "repeating": { +- "version": "2.0.1", +- "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", +- "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", +- "dev": true, +- "requires": { +- "is-finite": "^1.0.0" +- } +- }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", +@@ -2605,6 +2656,15 @@ + "path-parse": "^1.0.6" + } + }, ++ "responselike": { ++ "version": "1.0.2", ++ "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", ++ "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", ++ "dev": true, ++ "requires": { ++ "lowercase-keys": "^1.0.0" ++ } ++ }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", +@@ -2624,6 +2684,30 @@ + "glob": "^7.0.5" + } + }, ++ "roarr": { ++ "version": "2.15.4", ++ "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", ++ "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "boolean": "^3.0.1", ++ "detect-node": "^2.0.4", ++ "globalthis": "^1.0.1", ++ "json-stringify-safe": "^5.0.1", ++ "semver-compare": "^1.0.0", ++ "sprintf-js": "^1.1.2" ++ }, ++ "dependencies": { ++ "sprintf-js": { ++ "version": "1.1.2", ++ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", ++ "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", ++ "dev": true, ++ "optional": true ++ } ++ } ++ }, + "rxjs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", +@@ -2666,6 +2750,13 @@ + "integrity": "sha1-eQp89v6lRZuslhELKbYEEtyP+Ws=", + "dev": true + }, ++ "semver-compare": { ++ "version": "1.0.0", ++ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", ++ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", ++ "dev": true, ++ "optional": true ++ }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", +@@ -2675,6 +2766,16 @@ + "semver": "^5.0.3" + } + }, ++ "serialize-error": { ++ "version": "7.0.1", ++ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", ++ "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", ++ "dev": true, ++ "optional": true, ++ "requires": { ++ "type-fest": "^0.13.1" ++ } ++ }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", +@@ -2702,15 +2803,6 @@ + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, +- "single-line-log": { +- "version": "1.1.2", +- "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz", +- "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=", +- "dev": true, +- "requires": { +- "string-width": "^1.0.1" +- } +- }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", +@@ -2787,12 +2879,6 @@ + "integrity": "sha1-NpS1gEVnpFjTyARYQqY1hjL2JlQ=", + "dev": true + }, +- "speedometer": { +- "version": "0.1.4", +- "resolved": "https://registry.npmjs.org/speedometer/-/speedometer-0.1.4.tgz", +- "integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=", +- "dev": true +- }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", +@@ -2834,10 +2920,21 @@ + } + }, + "string_decoder": { +- "version": "0.10.31", +- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", +- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", +- "dev": true ++ "version": "1.1.1", ++ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", ++ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", ++ "dev": true, ++ "requires": { ++ "safe-buffer": "~5.1.0" ++ }, ++ "dependencies": { ++ "safe-buffer": { ++ "version": "5.1.2", ++ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", ++ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", ++ "dev": true ++ } ++ } + }, + "strip-ansi": { + "version": "3.0.1", +@@ -2848,30 +2945,12 @@ + "ansi-regex": "^2.0.0" + } + }, +- "strip-bom": { +- "version": "2.0.0", +- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", +- "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", +- "dev": true, +- "requires": { +- "is-utf8": "^0.2.0" +- } +- }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, +- "strip-indent": { +- "version": "1.0.1", +- "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", +- "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", +- "dev": true, +- "requires": { +- "get-stdin": "^4.0.1" +- } +- }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", +@@ -2879,12 +2958,23 @@ + "dev": true + }, + "sumchecker": { +- "version": "2.0.2", +- "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-2.0.2.tgz", +- "integrity": "sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4=", ++ "version": "3.0.1", ++ "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", ++ "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "requires": { +- "debug": "^2.2.0" ++ "debug": "^4.1.0" ++ }, ++ "dependencies": { ++ "debug": { ++ "version": "4.2.0", ++ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", ++ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", ++ "dev": true, ++ "requires": { ++ "ms": "2.1.2" ++ } ++ } + } + }, + "supports-color": { +@@ -2943,28 +3033,18 @@ + "execa": "^0.7.0" + } + }, +- "throttleit": { +- "version": "0.0.2", +- "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", +- "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", +- "dev": true +- }, +- "through2": { +- "version": "0.2.3", +- "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", +- "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", +- "dev": true, +- "requires": { +- "readable-stream": "~1.1.9", +- "xtend": "~2.1.1" +- } +- }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, ++ "to-readable-stream": { ++ "version": "1.0.0", ++ "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", ++ "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", ++ "dev": true ++ }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", +@@ -2983,12 +3063,6 @@ + } + } + }, +- "trim-newlines": { +- "version": "1.0.0", +- "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", +- "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", +- "dev": true +- }, + "truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", +@@ -3004,6 +3078,13 @@ + "integrity": "sha1-w8GflZc/sKYpc/sJ2Q2WHuQ+XIo=", + "dev": true + }, ++ "tunnel": { ++ "version": "0.0.6", ++ "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", ++ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", ++ "dev": true, ++ "optional": true ++ }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", +@@ -3019,6 +3100,13 @@ + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, ++ "type-fest": { ++ "version": "0.13.1", ++ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", ++ "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", ++ "dev": true, ++ "optional": true ++ }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", +@@ -3276,15 +3364,6 @@ + "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", + "dev": true + }, +- "xtend": { +- "version": "2.1.2", +- "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", +- "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", +- "dev": true, +- "requires": { +- "object-keys": "~0.4.0" +- } +- }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", +@@ -3377,12 +3456,13 @@ + } + }, + "yauzl": { +- "version": "2.4.1", +- "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", +- "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", ++ "version": "2.10.0", ++ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", ++ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { +- "fd-slicer": "~1.0.1" ++ "buffer-crc32": "~0.2.3", ++ "fd-slicer": "~1.1.0" + } + } + } +diff --git a/package.json b/package.json +index db31c3b..9c2d20c 100644 +--- a/package.json ++++ b/package.json +@@ -1,7 +1,7 @@ + { + "name": "Pencil", + "devDependencies": { +- "electron": "6.0.1", ++ "electron": "10.1.5", + "electron-builder": "20.28.4", + "electron-rebuild": "^1.8.5", + "rimraf": "^2.5.4" +@@ -71,7 +71,7 @@ + "postinstall": "install-app-deps", + "install-app-deps": "node ./node_modules/electron-builder/out/install-app-deps.js", + "start": "./node_modules/.bin/electron ./app", +- "start:dev": "./node_modules/.bin/electron ./app --enable-dev --enable-transparent-visuals --disable-gpu", ++ "start:dev": "./node_modules/.bin/electron ./app --enable-dev --enable-transparent-visuals", + "start:mac": "./node_modules/.bin/electron ./app --enable-dev", + "clean": "rimraf dist", + "pack": "build", |