- Linting (ESLint): Stricter rules (or switch to warning)

- Breaking internal API change: `updateGripCursor` moved to be class method of Selector rather than instance method
- Breaking internal API change: `subpathIsClosed` moved to be class method of `Path` rather than instance method
- Refactoring: Reuse utilities base64 encoder for SVG icons plugin
- Docs (JSDoc): Fix return of the `mouseUp` (can also be an object) and `mouseDown` (may also be a boolean) of `pathActions`; other JSDoc additions/improvements
This commit is contained in:
Brett Zamir
2018-11-07 14:51:50 +08:00
parent 901c9547fe
commit 7c470e9909
126 changed files with 2081 additions and 1373 deletions

View File

@@ -1,3 +1,5 @@
// Todo: Move to own module (and have it import a modular base64 encoder)
import {encode64} from '../utilities.js';
/**
* SVG Icon Loader 2.0
*
@@ -96,18 +98,22 @@ $(function() {
* @param {external:jQuery} $ Its keys include all icon IDs and the values, the icon as a jQuery object
* @returns {external:jQuery} The enhanced jQuery object
*/
export default function ($) {
export default function jQueryPluginSVGIcons ($) {
const svgIcons = {};
let fixIDs;
/**
* List of raster images with each
* key being the SVG icon ID to replace, and the value the image file name
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback
*/
/**
* @function external:jQuery.svgIcons
* @param {string} file The location of a local SVG or SVGz file
* @param {PlainObject} [opts]
* @param {Float} [opts.w] The icon widths
* @param {Float} [opts.h] The icon heights
* @param {PlainObject.<string, string>} [opts.fallback] List of raster images with each
key being the SVG icon ID to replace, and the value the image file name
* @param {external:jQuery.svgIcons.Fallback} [opts.fallback]
* @param {string} [opts.fallback_path] The path to use for all images
listed under "fallback"
* @param {boolean} [opts.replace] If set to `true`, HTML elements will be replaced by,
@@ -132,8 +138,10 @@ export default function ($) {
iconW = opts.w || 24,
iconH = opts.h || 24;
let elems, svgdoc, testImg,
iconsMade = false, dataLoaded = false, loadAttempts = 0;
const isOpera = !!window.opera,
iconsMade = false,
dataLoaded = false,
loadAttempts = 0;
const isOpera = Boolean(window.opera),
// ua = navigator.userAgent,
// isSafari = (ua.includes('Safari/') && !ua.includes('Chrome/')),
dataPre = 'data:image/svg+xml;charset=utf-8;base64,';
@@ -169,24 +177,28 @@ export default function ($) {
$(function () {
useFallback();
});
} else {
if (err.responseText) {
svgdoc = parser.parseFromString(err.responseText, 'text/xml');
} else if (err.responseText) {
svgdoc = parser.parseFromString(err.responseText, 'text/xml');
if (!svgdoc.childNodes.length) {
$(useFallback);
}
$(function () {
getIcons('ajax');
});
} else {
if (!svgdoc.childNodes.length) {
$(useFallback);
}
$(function () {
getIcons('ajax');
});
} else {
$(useFallback);
}
}
});
}
/**
*
* @param {"ajax"|0|undefined} evt
* @param {boolean} [noWait]
* @returns {undefined}
*/
function getIcons (evt, noWait) {
if (evt !== 'ajax') {
if (dataLoaded) return;
@@ -231,6 +243,14 @@ export default function ($) {
}
}
/**
*
* @param {external:jQuery} target
* @param {external:jQuery} icon A wrapped `defs` or Image
* @param {string} id SVG icon ID
* @param {string} setID
* @returns {undefined}
*/
function setIcon (target, icon, id, setID) {
if (isOpera) icon.css('visibility', 'hidden');
if (opts.replace) {
@@ -249,6 +269,11 @@ export default function ($) {
}
let holder;
/**
* @param {external:jQuery} icon A wrapped `defs` or Image
* @param {string} id SVG icon ID
* @returns {undefined}
*/
function addIcon (icon, id) {
if (opts.id_match === undefined || opts.id_match !== false) {
setIcon(holder, icon, id, true);
@@ -256,7 +281,13 @@ export default function ($) {
svgIcons[id] = icon;
}
function makeIcons (toImage, fallback) {
/**
*
* @param {boolean} [toImage]
* @param {external:jQuery.svgIcons.Fallback} [fallback]
* @returns {undefined}
*/
function makeIcons (toImage = false, fallback) {
if (iconsMade) return;
if (opts.no_img) toImage = false;
@@ -359,13 +390,14 @@ export default function ($) {
let idElems;
if (isOpera) {
idElems = defs.find('*').filter(function () {
return !!this.id;
return Boolean(this.id);
});
} else {
idElems = defs.find('[id]');
}
const allElems = svgEl[0].getElementsByTagName('*'), len = allElems.length;
const allElems = svgEl[0].getElementsByTagName('*'),
len = allElems.length;
idElems.each(function (i) {
const {id} = this;
@@ -409,49 +441,20 @@ export default function ($) {
return svgEl;
};
/**
* @returns {undefined}
*/
function useFallback () {
if (file.includes('.svgz')) {
const regFile = file.replace('.svgz', '.svg');
if (window.console) {
console.log('.svgz failed, trying with .svg');
console.log('.svgz failed, trying with .svg'); // eslint-disable-line no-console
}
$.svgIcons(regFile, opts);
} else if (opts.fallback) {
makeIcons(false, opts.fallback);
}
}
function encode64 (input) {
// base64 strings are 4/3 larger than the original string
if (window.btoa) return window.btoa(input);
const _keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
const output = new Array(Math.floor((input.length + 2) / 3) * 4);
let i = 0, p = 0;
do {
const chr1 = input.charCodeAt(i++);
const chr2 = input.charCodeAt(i++);
const chr3 = input.charCodeAt(i++);
const enc1 = chr1 >> 2;
const enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
let enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
let enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output[p++] = _keyStr.charAt(enc1);
output[p++] = _keyStr.charAt(enc2);
output[p++] = _keyStr.charAt(enc3);
output[p++] = _keyStr.charAt(enc4);
} while (i < input.length);
return output.join('');
}
};
/**