From 4b33c73f00ff6fc208140ef7da01f67c42a1100c Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Sun, 5 Jan 2020 17:58:50 +0800 Subject: [PATCH] - Refactoring: Remove BBQ in favor of `deparam` (with npm script to copy in) - Fix: `initFill`/`initStroke` `color`, and `bkgd_color` problematic when using decimal-component-only hex; fixes #314 --- .eslintignore | 3 - docs/jsdoc-config.js | 2 +- editor/external/deparam/deparam.esm.js | 102 +++++++++++++++++++++++++ editor/jquerybbq/jquery.bbq.min.js | 26 ------- editor/svg-editor.js | 39 +++++----- package-lock.json | 5 ++ package.json | 4 +- 7 files changed, 131 insertions(+), 50 deletions(-) create mode 100644 editor/external/deparam/deparam.esm.js delete mode 100644 editor/jquerybbq/jquery.bbq.min.js diff --git a/.eslintignore b/.eslintignore index fa52452d..ef11c935 100644 --- a/.eslintignore +++ b/.eslintignore @@ -15,9 +15,6 @@ editor/xdomain-svgedit-config-iife.js editor/jquery.min.js editor/jquery-ui -# Previously minified though exporting -editor/jquerybbq - # Previously minified though exporting editor/js-hotkeys diff --git a/docs/jsdoc-config.js b/docs/jsdoc-config.js index 7fd4fbe6..ac1b4001 100644 --- a/docs/jsdoc-config.js +++ b/docs/jsdoc-config.js @@ -66,7 +66,7 @@ module.exports = { 'screencasts', 'test' ], - excludePattern: 'svgedit-config-*|build-html.js|rollup*|external/babel-polyfill|extensions/mathjax|imagelib/jquery.min.js|jspdf/jspdf.min.js|jspdf/underscore-min.js|jquery-ui|jquery.min.js|jquerybbq|js-hotkeys' + excludePattern: 'svgedit-config-*|build-html.js|rollup*|external/babel-polyfill|extensions/mathjax|imagelib/jquery.min.js|jspdf/jspdf.min.js|jspdf/underscore-min.js|jquery-ui|jquery.min.js|js-hotkeys' }, sourceType: 'module', tags: { diff --git a/editor/external/deparam/deparam.esm.js b/editor/external/deparam/deparam.esm.js new file mode 100644 index 00000000..4846b7d4 --- /dev/null +++ b/editor/external/deparam/deparam.esm.js @@ -0,0 +1,102 @@ +/** + * Created by alexey2baranov on 28.01.17. + */ +/* + An extraction of the deparam method from Ben Alman's jQuery BBQ + http://benalman.com/projects/jquery-bbq-plugin/ + */ + +const coerce_types = {'true': !0, 'false': !1, 'null': null}; + +function deparam (params, coerce) { + // console.log(params) + const obj = {}; + + // Iterate over all name=value pairs. + params.replace(/\+/g, ' ').split('&').forEach(function (v) { + const param = v.split('='); + + let + key = decodeURIComponent(param[0]), + // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it + // into its component parts. + keys = key.split(']['), + keys_last = keys.length - 1; + + // If the first keys part contains [ and the last ends with ], then [] + // are correctly balanced. + if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) { + // Remove the trailing ] from the last keys part. + keys[keys_last] = keys[keys_last].replace(/\]$/, ''); + + // Split first keys part into two parts on the [ and add them back onto + // the beginning of the keys array. + keys = keys.shift().split('[').concat(keys); + + keys_last = keys.length - 1; + } else { + // Basic 'foo' style key. + keys_last = 0; + } + + // Are we dealing with a name=value pair, or just a name? + if (param.length >= 2) { + let val = decodeURIComponent(param.slice(1).join('=')); + + // Coerce values. + if (coerce) { + val = val && !isNaN(val) ? +val // number + : val === 'undefined' ? undefined // undefined + : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null + : val; // string + } + + if (keys_last) { + let cur = obj; + // Complex key, build deep object structure based on a few rules: + // * The 'cur' pointer starts at the object top-level. + // * [] = array push (n is set to array length), [n] = array if n is + // numeric, otherwise object. + // * If at the last keys part, set the value. + // * For each keys part, if the current level is undefined create an + // object or array based on the type of the next keys part. + // * Move the 'cur' pointer to the next level. + // * Rinse & repeat. + for (let i = 0; i <= keys_last; i++) { + key = keys[i] === '' ? cur.length : keys[i]; + cur = cur[key] = i < keys_last + ? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : []) + : val; + } + + } else { + // Simple key, even simpler rules, since only scalars and shallow + // arrays are allowed. + + if (Array.isArray(obj[key])) { + // val is already an array, so push on the next value. + obj[key].push(val); + + } else if (obj[key] !== undefined) { + // val isn't an array, but since a second value has been specified, + // convert val into an array. + obj[key] = [obj[key], val]; + + } else { + // val is a scalar. + obj[key] = val; + } + } + + } else if (key) { + // No value was defined, so set something meaningful. + obj[key] = coerce + ? undefined + : ''; + } + }); + + return obj; +} + +export default deparam; diff --git a/editor/jquerybbq/jquery.bbq.min.js b/editor/jquerybbq/jquery.bbq.min.js deleted file mode 100644 index 2ab92caa..00000000 --- a/editor/jquerybbq/jquery.bbq.min.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Todo: Update to latest at https://github.com/cowboy/jquery-bbq ? - * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 - * http://benalman.com/projects/jquery-bbq-plugin/ - * - * Copyright (c) 2010 "Cowboy" Ben Alman - * Dual licensed under the MIT and GPL licenses. - * http://benalman.com/about/license/ - */ - -// For sake of modules, added this wrapping export and changed `this` to `window` -export default function (jQuery) { - -(function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,window); - -return jQuery; -} diff --git a/editor/svg-editor.js b/editor/svg-editor.js index c30c6aec..4e6e4dec 100644 --- a/editor/svg-editor.js +++ b/editor/svg-editor.js @@ -15,12 +15,6 @@ * @borrows module:locale.setStrings as setStrings */ -/* -* Dependencies to remove: -* -* 1. jQuery BBQ (for deparam) - */ - import './touch.js'; import {NS} from './namespaces.js'; import {isWebkit, isChrome, isGecko, isIE, isMac, isTouch} from './browser.js'; @@ -30,12 +24,12 @@ import { hasCustomHandler, getCustomHandler, injectExtendedContextMenuItemsIntoDom } from './contextmenu.js'; import {importSetGlobalDefault} from './external/dynamic-import-polyfill/importModule.js'; +import deparam from './external/deparam/deparam.esm.js'; import SvgCanvas from './svgcanvas.js'; import Layer from './layer.js'; import jQueryPluginJSHotkeys from './js-hotkeys/jquery.hotkeys.min.js'; -import jQueryPluginBBQ from './jquerybbq/jquery.bbq.min.js'; import jQueryPluginSVGIcons from './svgicons/jQuery.svgIcons.js'; import jQueryPluginJGraduate from './jgraduate/jQuery.jGraduate.js'; import jQueryPluginSpinButton from './spinbtn/jQuery.SpinButton.js'; @@ -54,7 +48,7 @@ import loadStylesheets from './external/load-stylesheets/index-es.js'; const editor = {}; const $ = [ - jQueryPluginJSHotkeys, jQueryPluginBBQ, jQueryPluginSVGIcons, jQueryPluginJGraduate, + jQueryPluginJSHotkeys, jQueryPluginSVGIcons, jQueryPluginJGraduate, jQueryPluginSpinButton, jQueryPluginSVG, jQueryPluginContextMenu, jQueryPluginJPicker ].reduce((jq, func) => func(jq), jQuery); @@ -298,7 +292,7 @@ const callbacks = [], */ uiStrings = editor.uiStrings = {}; -let svgCanvas, urldata, +let svgCanvas, urldata = {}, isReady = false, customExportImage = false, customExportPDF = false, @@ -517,10 +511,7 @@ editor.setConfig = function (opts, cfgCfg) { cfgObj[key] = val; } } - $.each(opts, function (key, val) { - if (!{}.hasOwnProperty.call(opts, key)) { - return; - } + Object.entries(opts).forEach(function ([key, val]) { // Only allow prefs defined in defaultPrefs or... if ({}.hasOwnProperty.call(defaultPrefs, key)) { if (cfgCfg.overwrite === false && ( @@ -732,15 +723,27 @@ editor.init = function () { } (() => { // Load config/data from URL if given - urldata = $.deparam.querystring(true); - if (!$.isEmptyObject(urldata)) { + const {search, searchParams} = new URL(location); + + if (search) { + urldata = deparam(searchParams.toString(), true); + + ['initStroke', 'initFill'].forEach((prop) => { + if (searchParams.has(`${prop}[color]`)) { + // Restore back to original non-deparamed value to avoid color + // strings being converted to numbers + urldata[prop].color = searchParams.get(`${prop}[color]`); + } + }); + + if (searchParams.has('bkgd_color')) { + urldata.bkgd_color = '#' + searchParams.get('bkgd_color'); + } + if (urldata.dimensions) { urldata.dimensions = urldata.dimensions.split(','); } - if (urldata.bkgd_color) { - urldata.bkgd_color = '#' + urldata.bkgd_color; - } if (urldata.extensions) { // For security reasons, disallow cross-domain or cross-folder diff --git a/package-lock.json b/package-lock.json index 1e0803d4..d30db4ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3600,6 +3600,11 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, + "deparam": { + "version": "git+https://github.com/brettz9/deparam.git#3ae917fb3550640237b4c8ae36cd455ef7cc15d5", + "from": "git+https://github.com/brettz9/deparam.git#updates", + "dev": true + }, "deps-sort": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", diff --git a/package.json b/package.json index 47449a92..c530d05e 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "open-docs": "run-p start open-docs-no-start", "build-html": "npx babel-node --plugins @babel/plugin-transform-modules-commonjs build-html.js", "compress-images": "imageoptim \"chrome-app/*.png\" \"editor/extensions/*.png\" \"editor/spinbtn/*.png\" \"editor/jgraduate/images/*.{png,gif}\" \"editor/images/*.png\"", - "copy": "copyfiles -f node_modules/load-stylesheets/dist/index-es.js editor/external/load-stylesheets && copyfiles -f node_modules/jamilih/dist/jml-es.js editor/external/jamilih && copyfiles -f node_modules/query-result/esm/index.js editor/external/query-result/esm && copyfiles -f node_modules/qr-manipulation/dist/index-es.js editor/external/qr-manipulation/dist && copyfiles -f node_modules/stackblur-canvas/dist/stackblur-es.js editor/external/stackblur-canvas/dist && copyfiles -f node_modules/regenerator-runtime/runtime.js editor/external/regenerator-runtime && copyfiles -f \"node_modules/core-js-bundle//minified*\" editor/external/core-js-bundle && copyfiles -f \"node_modules/underscore/underscore-*\" editor/jspdf", + "copy": "copyfiles -f node_modules/load-stylesheets/dist/index-es.js editor/external/load-stylesheets && copyfiles -f node_modules/jamilih/dist/jml-es.js editor/external/jamilih && copyfiles -f node_modules/query-result/esm/index.js editor/external/query-result/esm && copyfiles -f node_modules/qr-manipulation/dist/index-es.js editor/external/qr-manipulation/dist && copyfiles -f node_modules/stackblur-canvas/dist/stackblur-es.js editor/external/stackblur-canvas/dist && copyfiles -f node_modules/regenerator-runtime/runtime.js editor/external/regenerator-runtime && copyfiles -f \"node_modules/core-js-bundle//minified*\" editor/external/core-js-bundle && copyfiles -f \"node_modules/underscore/underscore-*\" editor/jspdf && copyfiles -f \"node_modules/deparam/dist/deparam.esm.js\" editor/external/deparam", "remark": "remark -q -f .", "eslint-fix": "eslint --fix --ext js,md,html .", "eslint": "eslint --ext js,md,html .", @@ -62,7 +62,6 @@ "editor/external/**", "editor/jquery.min.js", "editor/jquery-ui/**", - "editor/jquerybbq/**", "editor/js-hotkeys/**", "editor/jspdf/jspdf.min.js", "editor/jspdf/underscore-min.js", @@ -135,6 +134,7 @@ "coveradge": "^0.2.0", "cypress": "^3.8.1", "cypress-axe": "^0.5.3", + "deparam": "git+https://github.com/brettz9/deparam.git#updates", "eslint": "^6.8.0", "eslint-config-ash-nazg": "^16.4.0", "eslint-config-standard": "^14.1.0",