- Enhancement (svgIcons): Fix JSDoc param def; add `alt` options

- Accessibility: Begin work, add aria-label to some buttons and
    form controls; add `role=main`; `<img alt>`; `<iframe title>`
- i18n: Add `lang` attribute
- Refactoring: lbs, simplify i18nized element retrieval call
- Docs: Some JSDoc descriptions, JSDoc spacing, fix svgIcons param
    def; add todo
- Testing: Avoid reporting meta-viewport (have own zooming
    controls and difficult to fix)
master
Brett Zamir 2019-04-03 12:49:48 +08:00
parent 69ea647286
commit 056f4f197c
36 changed files with 968 additions and 382 deletions

View File

@ -16,6 +16,11 @@
- Optimization fix: Properly run code conditionally on browser check; - Optimization fix: Properly run code conditionally on browser check;
fixes #312 (@ianli-sc) fixes #312 (@ianli-sc)
- Enhancement: Add CAD Placemark extension (@NeiroNx) - Enhancement: Add CAD Placemark extension (@NeiroNx)
- Enhancement (svgIcons): Fix JSDoc param def; add `alt` options
- Accessibility: Begin work, add aria-label to some buttons and
form controls; add `role=main`; `<img alt>`; `<iframe title>`
- i18n: Add `lang` attribute
- Refactoring: lbs, simplify i18nized element retrieval call
- Refactoring: Make dialog OK button retrievable locale-independently - Refactoring: Make dialog OK button retrievable locale-independently
via a `data-ok` attribute (using for testing) via a `data-ok` attribute (using for testing)
- Linting (ESLint): Update polyfills to new compat rules of - Linting (ESLint): Update polyfills to new compat rules of
@ -25,6 +30,10 @@
- Testing (UI Refactoring): Abstract out to helper file functions - Testing (UI Refactoring): Abstract out to helper file functions
- Testing (UI Refactoring): Avoid testing being locale-dependent; - Testing (UI Refactoring): Avoid testing being locale-dependent;
approve storage (and set locale to English) before each test approve storage (and set locale to English) before each test
- Testing: Avoid reporting meta-viewport (have own zooming
controls and difficult to fix)
- Docs: Some JSDoc descriptions, JSDoc spacing, fix svgIcons param
def; add todo
- npm: Update devDeps; update nested deps for security audit; remove - npm: Update devDeps; update nested deps for security audit; remove
one unneeded) one unneeded)

View File

@ -2,7 +2,8 @@ var svgEditorExtensionLocale_server_moinsave_en = (function () {
'use strict'; 'use strict';
var en = { var en = {
saved: 'Saved! Return to Item View!' saved: 'Saved! Return to Item View!',
hiddenframe: 'Frame to store hidden values'
}; };
return en; return en;

View File

@ -2,7 +2,8 @@ var svgEditorExtensionLocale_server_moinsave_zh_CN = (function () {
'use strict'; 'use strict';
var zhCN = { var zhCN = {
saved: '已保存! 返回视图!' saved: '已保存! 返回视图!',
hiddenframe: 'Frame to store hidden values'
}; };
return zhCN; return zhCN;

View File

@ -2,7 +2,8 @@ var svgEditorExtensionLocale_server_opensave_en = (function () {
'use strict'; 'use strict';
var en = { var en = {
uploading: 'Uploading...' uploading: 'Uploading...',
hiddenframe: 'Frame to store hidden values'
}; };
return en; return en;

View File

@ -2,7 +2,8 @@ var svgEditorExtensionLocale_server_opensave_zh_CN = (function () {
'use strict'; 'use strict';
var zhCN = { var zhCN = {
uploading: '正在上传...' uploading: '正在上传...',
hiddenframe: 'Frame to store hidden values'
}; };
return zhCN; return zhCN;

View File

@ -4887,7 +4887,7 @@ var svgEditorExtension_server_moinsave = (function () {
/* const target = */ /* const target = */
$('<iframe name="output_frame" style="width: 0; height: 0;" src="#"/>').appendTo('body'); $("<iframe name=\"output_frame\" title=\"".concat(strings.hiddenframe, "\"\n style=\"width: 0; height: 0;\" src=\"#\"/>")).appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function () { save: function () {
var _save = _asyncToGenerator( var _save = _asyncToGenerator(

View File

@ -5017,7 +5017,7 @@ var svgEditorExtension_server_opensave = (function () {
cancelled = false; // Hiding by size instead of display to avoid FF console errors cancelled = false; // Hiding by size instead of display to avoid FF console errors
// with `getBBox` in browser.js `supportsPathBBox_`) // with `getBBox` in browser.js `supportsPathBBox_`)
$('<iframe name="output_frame" style="width: 0; height: 0;" src="#"/>').appendTo('body'); $("<iframe name=\"output_frame\" title=\"".concat(strings.hiddenframe, "\"\n style=\"width: 0; height: 0;\" src=\"#\"/>")).appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function save(win, data) { save: function save(win, data) {
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,

225
dist/index-es.js vendored
View File

@ -9626,6 +9626,10 @@ function jQueryPluginDBox($) {
*/ */
/** /**
* Creates a dialog of the specified type with a given message
* and any defaults and type-specific metadata. Returns a `Promise`
* which resolves differently depending on whether the dialog
* was cancelled or okayed (with the response and any checked state).
* @param {"alert"|"prompt"|"select"|"process"} type * @param {"alert"|"prompt"|"select"|"process"} type
* @param {string} msg * @param {string} msg
* @param {string} [defaultVal] * @param {string} [defaultVal]
@ -9658,7 +9662,7 @@ function jQueryPluginDBox($) {
}); });
} else if (type === 'select') { } else if (type === 'select') {
var div = $('<div style="text-align:center;">'); var div = $('<div style="text-align:center;">');
ctrl = $('<select>').appendTo(div); ctrl = $("<select aria-label=\"".concat(msg, "\">")).appendTo(div);
if (checkbox) { if (checkbox) {
var label = $('<label>').text(checkbox.label); var label = $('<label>').text(checkbox.label);
@ -22304,11 +22308,17 @@ function jQueryPluginSVGIcons($) {
var svgIcons = {}; var svgIcons = {};
var fixIDs; var fixIDs;
/** /**
* List of raster images with each * Map of raster images with each key being the SVG icon ID
* key being the SVG icon ID to replace, and the value the image file name * to replace, and the value the image file name
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback * @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback
*/ */
/**
* Map of raster images with each key being the SVG icon ID
* whose `alt` will be set, and the value being the `alt` text
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Alts
*/
/** /**
* @function external:jQuery.svgIcons * @function external:jQuery.svgIcons
* @param {string} file The location of a local SVG or SVGz file * @param {string} file The location of a local SVG or SVGz file
@ -22317,21 +22327,29 @@ function jQueryPluginSVGIcons($) {
* @param {Float} [opts.h] The icon heights * @param {Float} [opts.h] The icon heights
* @param {external:jQuery.svgIcons.Fallback} [opts.fallback] * @param {external:jQuery.svgIcons.Fallback} [opts.fallback]
* @param {string} [opts.fallback_path] The path to use for all images * @param {string} [opts.fallback_path] The path to use for all images
listed under "fallback" * listed under "fallback"
* @param {boolean} [opts.replace] If set to `true`, HTML elements will be replaced by, * @param {boolean} [opts.replace] If set to `true`, HTML elements will
rather than include the SVG icon. * be replaced by, rather than include the SVG icon.
* @param {PlainObject.<string, string>} [opts.placement] List with selectors for keys and SVG icon ids * @param {PlainObject.<string, string>} [opts.placement] Map with selectors
as values. This provides a custom method of adding icons. * for keys and SVG icon ids as values. This provides a custom method of
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] List with selectors for keys and numbers * adding icons.
as values. This allows an easy way to resize specific icons. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] Map
* @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A function to call when all icons have been loaded. * with selectors for keys and numbers as values. This allows an easy way to
* @param {boolean} [opts.id_match=true] Automatically attempt to match SVG icon ids with * resize specific icons.
corresponding HTML id * @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A
* @param {boolean} [opts.no_img] Prevent attempting to convert the icon into an `<img>` * function to call when all icons have been loaded.
element (may be faster, help for browser consistency) * @param {boolean} [opts.id_match=true] Automatically attempt to match
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and thus not to * SVG icon ids with corresponding HTML id
parse as XML. SVGZ files add compression benefits, but getting data from * @param {boolean} [opts.no_img] Prevent attempting to convert the icon
them fails in Firefox 2 and older. * into an `<img>` element (may be faster, help for browser consistency)
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and
* thus not to parse as XML. SVGZ files add compression benefits, but
* getting data from them fails in Firefox 2 and older.
* @param {jQuery.svgIcons.Alts} [opts.alts] Map of images with each key
* being the SVG icon ID whose `alt` will be set, and the value being
* the `alt` text
* @param {string} [opts.testIconAlt="icon"] Alt text for the injected test image.
* In case wish to ensure have one for accessibility
* @returns {undefined} * @returns {undefined}
*/ */
@ -22442,7 +22460,8 @@ function jQueryPluginSVGIcons($) {
testImg = $(new Image()).attr({ testImg = $(new Image()).attr({
src: testSrc, src: testSrc,
width: 0, width: 0,
height: 0 height: 0,
alt: opts.testIconAlt || 'icon'
}).appendTo('body').load(function () { }).appendTo('body').load(function () {
// Safari 4 crashes, Opera and Chrome don't // Safari 4 crashes, Opera and Chrome don't
makeIcons(true); makeIcons(true);
@ -22460,7 +22479,7 @@ function jQueryPluginSVGIcons($) {
* @param {external:jQuery} target * @param {external:jQuery} target
* @param {external:jQuery} icon A wrapped `defs` or Image * @param {external:jQuery} icon A wrapped `defs` or Image
* @param {string} id SVG icon ID * @param {string} id SVG icon ID
* @param {string} setID * @param {boolean} setID Whether to set the ID attribute (with `id`)
* @returns {undefined} * @returns {undefined}
*/ */
@ -22472,6 +22491,17 @@ function jQueryPluginSVGIcons($) {
if (setID) icon.attr('id', id); if (setID) icon.attr('id', id);
var cl = target.attr('class'); var cl = target.attr('class');
if (cl) icon.attr('class', 'svg_icon ' + cl); if (cl) icon.attr('class', 'svg_icon ' + cl);
if (!target.alt) {
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon.attr('alt', alt);
}
target.replaceWith(icon); target.replaceWith(icon);
} else { } else {
target.append(icon); target.append(icon);
@ -22522,12 +22552,18 @@ function jQueryPluginSVGIcons($) {
var path = opts.fallback_path || ''; var path = opts.fallback_path || '';
$.each(fallback, function (id, imgsrc) { $.each(fallback, function (id, imgsrc) {
holder = $('#' + id); holder = $('#' + id);
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
var icon = $(new Image()).attr({ var icon = $(new Image()).attr({
class: 'svg_icon', class: 'svg_icon',
src: path + imgsrc, src: path + imgsrc,
width: iconW, width: iconW,
height: iconH, height: iconH,
alt: 'icon' alt: alt
}); });
addIcon(icon, id); addIcon(icon, id);
}); });
@ -22570,9 +22606,16 @@ function jQueryPluginSVGIcons($) {
if (toImage) { if (toImage) {
tempHolder.empty().append(svgroot); tempHolder.empty().append(svgroot);
var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot)))); var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot))));
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon = $(new Image()).attr({ icon = $(new Image()).attr({
class: 'svg_icon', class: 'svg_icon',
src: str src: str,
alt: alt
}); });
} else { } else {
icon = fixIDs($(svgroot), i); icon = fixIDs($(svgroot), i);
@ -22705,13 +22748,15 @@ function jQueryPluginSVGIcons($) {
*/ */
/** /**
* If a Float is used, it will represent width and height. Arrays contain the width and height. * If a Float is used, it will represent width and height. Arrays contain
* the width and height.
* @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size * @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size
*/ */
/** /**
* @function external:jQuery.resizeSvgIcons * @function external:jQuery.resizeSvgIcons
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with selectors as keys. The values are sizes. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with
* selectors as keys. The values are sizes.
* @returns {undefined} * @returns {undefined}
*/ */
@ -28023,10 +28068,24 @@ var jPicker = function jPicker($) {
var $$a = jQuery; var $$a = jQuery;
var langParam; var langParam;
/** /**
* @param {"content"|"title"} type * Looks for elements to localize using the supplied `obj` to indicate
* @param {module:locale.LocaleSelectorValue} obj * on which selectors (or IDs if `ids` is set to `true`) to set its
* @param {boolean} ids * strings (with selectors relative to the editor root element). All
* @returns {undefined} * keys will be translated, but for each selector, only the first item
* found matching will be modified.
* If the type is `content`, the selector-identified element's children
* will be checked, and the first (non-empty) text (placeholder) node
* found will have its text replaced.
* If the type is `title`, the element's `title`
* property will be set.
* If the type is `aria-label`, the element's `aria-label` attribute
* will be set (i.e., instructions for screen readers when there is
* otherwise no visible text to be read for the function of the form
* control).
* @param {"content"|"title"} type
* @param {module:locale.LocaleSelectorValue} obj Selectors or IDs keyed to strings
* @param {boolean} ids
* @returns {undefined}
*/ */
var setStrings = function setStrings(type, obj, ids) { var setStrings = function setStrings(type, obj, ids) {
@ -28048,12 +28107,18 @@ var setStrings = function setStrings(type, obj, ids) {
var $elem = parent.find(sel); var $elem = parent.find(sel);
if ($elem.length) { if ($elem.length) {
var elem = parent.find(sel)[0]; var elem = $elem[0];
switch (type) { switch (type) {
case 'aria-label':
elem.setAttribute('aria-label', val);
break;
case 'content': case 'content':
_toConsumableArray(elem.childNodes).some(function (node) { _toConsumableArray(elem.childNodes).some(function (node) {
if (node.nodeType === 3 && node.textContent.trim()) { if (node.nodeType === 3
/* Node.TEXT_NODE */
&& node.textContent.trim()) {
node.textContent = val; node.textContent = val;
return true; return true;
} }
@ -28091,10 +28156,11 @@ var setStrings = function setStrings(type, obj, ids) {
var editor_; var editor_;
/** /**
* @function init * Sets the current editor instance (on which `addLangData`) exists.
* @memberof module:locale * @function init
* @param {module:locale.LocaleEditorInit} editor * @memberof module:locale
* @returns {undefined} * @param {module:locale.LocaleEditorInit} editor
* @returns {undefined}
*/ */
var init$7 = function init(editor) { var init$7 = function init(editor) {
@ -28119,7 +28185,7 @@ function () {
var _ref3 = _asyncToGenerator( var _ref3 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee(langData) { regeneratorRuntime.mark(function _callee(langData) {
var more, _langData, tools, properties, config, layers, common, ui, opts; var more, _langData, tools, properties, config, layers, common, ui, opts, ariaLabels;
return regeneratorRuntime.wrap(function _callee$(_context) { return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) { while (1) {
@ -28146,6 +28212,7 @@ function () {
case 6: case 6:
_langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui; _langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui;
setStrings('content', { setStrings('content', {
// Todo: Add this powered by (probably by default) but with config to remove
// copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html // copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html
curve_segments: properties.curve_segments, curve_segments: properties.curve_segments,
fitToContent: tools.fitToContent, fitToContent: tools.fitToContent,
@ -28203,14 +28270,41 @@ function () {
}, true); // Context menus }, true); // Context menus
opts = {}; opts = {};
$$a.each(['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'], function () { ['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'].forEach(function (item) {
opts['#cmenu_canvas a[href="#' + this + '"]'] = tools[this]; opts['#cmenu_canvas a[href="#' + item + '"]'] = tools[item];
}); });
$$a.each(['dupe', 'merge_down', 'merge_all'], function () { ['dupe', 'merge_down', 'merge_all'].forEach(function (item) {
opts['#cmenu_layers a[href="#' + this + '"]'] = layers[this]; opts['#cmenu_layers a[href="#' + item + '"]'] = layers[item];
}); });
opts['#cmenu_layers a[href="#delete"]'] = layers.del; opts['#cmenu_layers a[href="#delete"]'] = layers.del;
setStrings('content', opts); setStrings('content', opts);
ariaLabels = {};
Object.entries({
tool_blur: properties.blur,
tool_position: tools.align_to_page,
tool_font_family: properties.font_family,
zoom_panel: ui.zoom_level,
stroke_linejoin: properties.linejoin_miter,
stroke_linecap: properties.linecap_butt,
tool_opacity: properties.opacity
}).forEach(function (_ref4) {
var _ref5 = _slicedToArray(_ref4, 2),
id = _ref5[0],
value = _ref5[1];
ariaLabels['#' + id + ' button'] = value;
});
Object.entries({
group_opacity: properties.opacity,
zoom: ui.zoom_level
}).forEach(function (_ref6) {
var _ref7 = _slicedToArray(_ref6, 2),
id = _ref7[0],
value = _ref7[1];
ariaLabels['#' + id] = value;
});
setStrings('aria-label', ariaLabels);
setStrings('title', { setStrings('title', {
align_relative_to: tools.align_relative_to, align_relative_to: tools.align_relative_to,
circle_cx: properties.circle_cx, circle_cx: properties.circle_cx,
@ -28314,7 +28408,7 @@ function () {
langData: langData langData: langData
}); });
case 15: case 19:
case "end": case "end":
return _context.stop(); return _context.stop();
} }
@ -28327,20 +28421,21 @@ function () {
}; };
}(); }();
/** /**
* @function module:locale.putLocale *
* @param {string} givenParam * @function module:locale.putLocale
* @param {string[]} goodLangs * @param {string} givenParam
* @param {{langPath: string}} conf * @param {string[]} goodLangs
* @fires module:svgcanvas.SvgCanvas#event:ext-addLangData * @param {{langPath: string}} conf
* @fires module:svgcanvas.SvgCanvas#event:ext-langReady * @fires module:svgcanvas.SvgCanvas#event:ext-addLangData
* @fires module:svgcanvas.SvgCanvas#event:ext-langChanged * @fires module:svgcanvas.SvgCanvas#event:ext-langReady
* @returns {Promise} Resolves to result of {@link module:locale.readLang} * @fires module:svgcanvas.SvgCanvas#event:ext-langChanged
* @returns {Promise} Resolves to result of {@link module:locale.readLang}
*/ */
var putLocale = var putLocale =
/*#__PURE__*/ /*#__PURE__*/
function () { function () {
var _ref4 = _asyncToGenerator( var _ref8 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) { regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) {
var url; var url;
@ -28396,7 +28491,7 @@ function () {
})); }));
return function putLocale(_x2, _x3, _x4) { return function putLocale(_x2, _x3, _x4) {
return _ref4.apply(this, arguments); return _ref8.apply(this, arguments);
}; };
}(); }();
@ -29881,6 +29976,8 @@ editor.init = function () {
no_img: !isWebkit(), no_img: !isWebkit(),
// Opera & Firefox 4 gives odd behavior w/images // Opera & Firefox 4 gives odd behavior w/images
fallback_path: curConfig.imgPath, fallback_path: curConfig.imgPath,
// Todo: Set `alts: {}` with keys as the IDs in fallback set to
// `uiStrings` (localized) values
fallback: { fallback: {
logo: 'logo.png', logo: 'logo.png',
select: 'select.png', select: 'select.png',
@ -31896,7 +31993,7 @@ editor.init = function () {
var _ref13 = _asyncToGenerator( var _ref13 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee5(win, ext) { regeneratorRuntime.mark(function _callee5(win, ext) {
var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, placementObj, holders; var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, altsObj, placementObj, holders;
return regeneratorRuntime.wrap(function _callee5$(_context5) { return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) { while (1) {
switch (_context5.prev = _context5.next) { switch (_context5.prev = _context5.next) {
@ -32086,7 +32183,7 @@ editor.init = function () {
break; break;
} }
fallbackObj = {}, placementObj = {}, holders = {}; fallbackObj = {}, altsObj = {}, placementObj = {}, holders = {};
/** /**
* @typedef {GenericArray} module:SVGEditor.KeyArray * @typedef {GenericArray} module:SVGEditor.KeyArray
* @property {string} 0 The key to bind (on `keydown`) * @property {string} 0 The key to bind (on `keydown`)
@ -32131,9 +32228,10 @@ editor.init = function () {
var icon; var icon;
if (!svgicons) { if (!svgicons) {
icon = $$b('<img src="' + btn.icon + '">'); icon = $$b('<img src="' + btn.icon + (btn.title ? '" alt="' + btn.title : '') + '">');
} else { } else {
fallbackObj[id] = btn.icon; fallbackObj[id] = btn.icon;
altsObj[id] = btn.title;
var svgicon = btn.svgicon || btn.id; var svgicon = btn.svgicon || btn.id;
if (btn.type === 'app_menu') { if (btn.type === 'app_menu') {
@ -36045,6 +36143,13 @@ editor.init = function () {
return _context17.abrupt("return"); return _context17.abrupt("return");
case 5: case 5:
// Todo: Remove `allStrings.lang` property in locale in
// favor of just `lang`?
document.documentElement.lang = allStrings.lang; // lang;
// Todo: Add proper RTL Support!
// Todo: Use RTL detection instead and take out of locales?
// document.documentElement.dir = allStrings.dir;
$$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused $$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused
// $.extend will only replace the given strings // $.extend will only replace the given strings
@ -36060,11 +36165,11 @@ editor.init = function () {
if (!extsPreLang.length) { if (!extsPreLang.length) {
_context17.next = 17; _context17.next = 18;
break; break;
} }
_context17.next = 14; _context17.next = 15;
return Promise.all(extsPreLang.map(function (ext) { return Promise.all(extsPreLang.map(function (ext) {
loadedExtensionNames.push(ext.name); loadedExtensionNames.push(ext.name);
return ext.langReady({ return ext.langReady({
@ -36077,12 +36182,12 @@ editor.init = function () {
}); });
})); }));
case 14: case 15:
extsPreLang.length = 0; extsPreLang.length = 0;
_context17.next = 18; _context17.next = 19;
break; break;
case 17: case 18:
loadedExtensionNames.forEach(function (loadedExtensionName) { loadedExtensionNames.forEach(function (loadedExtensionName) {
svgCanvas.runExtension(loadedExtensionName, 'langReady', svgCanvas.runExtension(loadedExtensionName, 'langReady',
/** @type {module:svgcanvas.SvgCanvas#event:ext-langReady} */ /** @type {module:svgcanvas.SvgCanvas#event:ext-langReady} */
@ -36096,7 +36201,7 @@ editor.init = function () {
}); });
}); });
case 18: case 19:
svgCanvas.runExtensions('langChanged', svgCanvas.runExtensions('langChanged',
/** @type {module:svgcanvas.SvgCanvas#event:ext-langChanged} */ /** @type {module:svgcanvas.SvgCanvas#event:ext-langChanged} */
lang); // Update flyout tooltips lang); // Update flyout tooltips
@ -36117,7 +36222,7 @@ editor.init = function () {
$$b('#tool_pos' + this.id.substr(10))[0].title = this.title; $$b('#tool_pos' + this.id.substr(10))[0].title = this.title;
}); });
case 23: case 24:
case "end": case "end":
return _context17.stop(); return _context17.stop();
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

195
dist/index-umd.js vendored
View File

@ -9632,6 +9632,10 @@
*/ */
/** /**
* Creates a dialog of the specified type with a given message
* and any defaults and type-specific metadata. Returns a `Promise`
* which resolves differently depending on whether the dialog
* was cancelled or okayed (with the response and any checked state).
* @param {"alert"|"prompt"|"select"|"process"} type * @param {"alert"|"prompt"|"select"|"process"} type
* @param {string} msg * @param {string} msg
* @param {string} [defaultVal] * @param {string} [defaultVal]
@ -9664,7 +9668,7 @@
}); });
} else if (type === 'select') { } else if (type === 'select') {
var div = $('<div style="text-align:center;">'); var div = $('<div style="text-align:center;">');
ctrl = $('<select>').appendTo(div); ctrl = $("<select aria-label=\"".concat(msg, "\">")).appendTo(div);
if (checkbox) { if (checkbox) {
var label = $('<label>').text(checkbox.label); var label = $('<label>').text(checkbox.label);
@ -22310,11 +22314,17 @@
var svgIcons = {}; var svgIcons = {};
var fixIDs; var fixIDs;
/** /**
* List of raster images with each * Map of raster images with each key being the SVG icon ID
* key being the SVG icon ID to replace, and the value the image file name * to replace, and the value the image file name
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback * @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback
*/ */
/**
* Map of raster images with each key being the SVG icon ID
* whose `alt` will be set, and the value being the `alt` text
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Alts
*/
/** /**
* @function external:jQuery.svgIcons * @function external:jQuery.svgIcons
* @param {string} file The location of a local SVG or SVGz file * @param {string} file The location of a local SVG or SVGz file
@ -22323,21 +22333,29 @@
* @param {Float} [opts.h] The icon heights * @param {Float} [opts.h] The icon heights
* @param {external:jQuery.svgIcons.Fallback} [opts.fallback] * @param {external:jQuery.svgIcons.Fallback} [opts.fallback]
* @param {string} [opts.fallback_path] The path to use for all images * @param {string} [opts.fallback_path] The path to use for all images
listed under "fallback" * listed under "fallback"
* @param {boolean} [opts.replace] If set to `true`, HTML elements will be replaced by, * @param {boolean} [opts.replace] If set to `true`, HTML elements will
rather than include the SVG icon. * be replaced by, rather than include the SVG icon.
* @param {PlainObject.<string, string>} [opts.placement] List with selectors for keys and SVG icon ids * @param {PlainObject.<string, string>} [opts.placement] Map with selectors
as values. This provides a custom method of adding icons. * for keys and SVG icon ids as values. This provides a custom method of
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] List with selectors for keys and numbers * adding icons.
as values. This allows an easy way to resize specific icons. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] Map
* @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A function to call when all icons have been loaded. * with selectors for keys and numbers as values. This allows an easy way to
* @param {boolean} [opts.id_match=true] Automatically attempt to match SVG icon ids with * resize specific icons.
corresponding HTML id * @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A
* @param {boolean} [opts.no_img] Prevent attempting to convert the icon into an `<img>` * function to call when all icons have been loaded.
element (may be faster, help for browser consistency) * @param {boolean} [opts.id_match=true] Automatically attempt to match
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and thus not to * SVG icon ids with corresponding HTML id
parse as XML. SVGZ files add compression benefits, but getting data from * @param {boolean} [opts.no_img] Prevent attempting to convert the icon
them fails in Firefox 2 and older. * into an `<img>` element (may be faster, help for browser consistency)
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and
* thus not to parse as XML. SVGZ files add compression benefits, but
* getting data from them fails in Firefox 2 and older.
* @param {jQuery.svgIcons.Alts} [opts.alts] Map of images with each key
* being the SVG icon ID whose `alt` will be set, and the value being
* the `alt` text
* @param {string} [opts.testIconAlt="icon"] Alt text for the injected test image.
* In case wish to ensure have one for accessibility
* @returns {undefined} * @returns {undefined}
*/ */
@ -22448,7 +22466,8 @@
testImg = $(new Image()).attr({ testImg = $(new Image()).attr({
src: testSrc, src: testSrc,
width: 0, width: 0,
height: 0 height: 0,
alt: opts.testIconAlt || 'icon'
}).appendTo('body').load(function () { }).appendTo('body').load(function () {
// Safari 4 crashes, Opera and Chrome don't // Safari 4 crashes, Opera and Chrome don't
makeIcons(true); makeIcons(true);
@ -22466,7 +22485,7 @@
* @param {external:jQuery} target * @param {external:jQuery} target
* @param {external:jQuery} icon A wrapped `defs` or Image * @param {external:jQuery} icon A wrapped `defs` or Image
* @param {string} id SVG icon ID * @param {string} id SVG icon ID
* @param {string} setID * @param {boolean} setID Whether to set the ID attribute (with `id`)
* @returns {undefined} * @returns {undefined}
*/ */
@ -22478,6 +22497,17 @@
if (setID) icon.attr('id', id); if (setID) icon.attr('id', id);
var cl = target.attr('class'); var cl = target.attr('class');
if (cl) icon.attr('class', 'svg_icon ' + cl); if (cl) icon.attr('class', 'svg_icon ' + cl);
if (!target.alt) {
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon.attr('alt', alt);
}
target.replaceWith(icon); target.replaceWith(icon);
} else { } else {
target.append(icon); target.append(icon);
@ -22528,12 +22558,18 @@
var path = opts.fallback_path || ''; var path = opts.fallback_path || '';
$.each(fallback, function (id, imgsrc) { $.each(fallback, function (id, imgsrc) {
holder = $('#' + id); holder = $('#' + id);
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
var icon = $(new Image()).attr({ var icon = $(new Image()).attr({
class: 'svg_icon', class: 'svg_icon',
src: path + imgsrc, src: path + imgsrc,
width: iconW, width: iconW,
height: iconH, height: iconH,
alt: 'icon' alt: alt
}); });
addIcon(icon, id); addIcon(icon, id);
}); });
@ -22576,9 +22612,16 @@
if (toImage) { if (toImage) {
tempHolder.empty().append(svgroot); tempHolder.empty().append(svgroot);
var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot)))); var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot))));
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon = $(new Image()).attr({ icon = $(new Image()).attr({
class: 'svg_icon', class: 'svg_icon',
src: str src: str,
alt: alt
}); });
} else { } else {
icon = fixIDs($(svgroot), i); icon = fixIDs($(svgroot), i);
@ -22711,13 +22754,15 @@
*/ */
/** /**
* If a Float is used, it will represent width and height. Arrays contain the width and height. * If a Float is used, it will represent width and height. Arrays contain
* the width and height.
* @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size * @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size
*/ */
/** /**
* @function external:jQuery.resizeSvgIcons * @function external:jQuery.resizeSvgIcons
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with selectors as keys. The values are sizes. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with
* selectors as keys. The values are sizes.
* @returns {undefined} * @returns {undefined}
*/ */
@ -28029,8 +28074,22 @@
var $$a = jQuery; var $$a = jQuery;
var langParam; var langParam;
/** /**
* Looks for elements to localize using the supplied `obj` to indicate
* on which selectors (or IDs if `ids` is set to `true`) to set its
* strings (with selectors relative to the editor root element). All
* keys will be translated, but for each selector, only the first item
* found matching will be modified.
* If the type is `content`, the selector-identified element's children
* will be checked, and the first (non-empty) text (placeholder) node
* found will have its text replaced.
* If the type is `title`, the element's `title`
* property will be set.
* If the type is `aria-label`, the element's `aria-label` attribute
* will be set (i.e., instructions for screen readers when there is
* otherwise no visible text to be read for the function of the form
* control).
* @param {"content"|"title"} type * @param {"content"|"title"} type
* @param {module:locale.LocaleSelectorValue} obj * @param {module:locale.LocaleSelectorValue} obj Selectors or IDs keyed to strings
* @param {boolean} ids * @param {boolean} ids
* @returns {undefined} * @returns {undefined}
*/ */
@ -28054,12 +28113,18 @@
var $elem = parent.find(sel); var $elem = parent.find(sel);
if ($elem.length) { if ($elem.length) {
var elem = parent.find(sel)[0]; var elem = $elem[0];
switch (type) { switch (type) {
case 'aria-label':
elem.setAttribute('aria-label', val);
break;
case 'content': case 'content':
_toConsumableArray(elem.childNodes).some(function (node) { _toConsumableArray(elem.childNodes).some(function (node) {
if (node.nodeType === 3 && node.textContent.trim()) { if (node.nodeType === 3
/* Node.TEXT_NODE */
&& node.textContent.trim()) {
node.textContent = val; node.textContent = val;
return true; return true;
} }
@ -28097,6 +28162,7 @@
var editor_; var editor_;
/** /**
* Sets the current editor instance (on which `addLangData`) exists.
* @function init * @function init
* @memberof module:locale * @memberof module:locale
* @param {module:locale.LocaleEditorInit} editor * @param {module:locale.LocaleEditorInit} editor
@ -28125,7 +28191,7 @@
var _ref3 = _asyncToGenerator( var _ref3 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee(langData) { regeneratorRuntime.mark(function _callee(langData) {
var more, _langData, tools, properties, config, layers, common, ui, opts; var more, _langData, tools, properties, config, layers, common, ui, opts, ariaLabels;
return regeneratorRuntime.wrap(function _callee$(_context) { return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) { while (1) {
@ -28152,6 +28218,7 @@
case 6: case 6:
_langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui; _langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui;
setStrings('content', { setStrings('content', {
// Todo: Add this powered by (probably by default) but with config to remove
// copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html // copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html
curve_segments: properties.curve_segments, curve_segments: properties.curve_segments,
fitToContent: tools.fitToContent, fitToContent: tools.fitToContent,
@ -28209,14 +28276,41 @@
}, true); // Context menus }, true); // Context menus
opts = {}; opts = {};
$$a.each(['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'], function () { ['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'].forEach(function (item) {
opts['#cmenu_canvas a[href="#' + this + '"]'] = tools[this]; opts['#cmenu_canvas a[href="#' + item + '"]'] = tools[item];
}); });
$$a.each(['dupe', 'merge_down', 'merge_all'], function () { ['dupe', 'merge_down', 'merge_all'].forEach(function (item) {
opts['#cmenu_layers a[href="#' + this + '"]'] = layers[this]; opts['#cmenu_layers a[href="#' + item + '"]'] = layers[item];
}); });
opts['#cmenu_layers a[href="#delete"]'] = layers.del; opts['#cmenu_layers a[href="#delete"]'] = layers.del;
setStrings('content', opts); setStrings('content', opts);
ariaLabels = {};
Object.entries({
tool_blur: properties.blur,
tool_position: tools.align_to_page,
tool_font_family: properties.font_family,
zoom_panel: ui.zoom_level,
stroke_linejoin: properties.linejoin_miter,
stroke_linecap: properties.linecap_butt,
tool_opacity: properties.opacity
}).forEach(function (_ref4) {
var _ref5 = _slicedToArray(_ref4, 2),
id = _ref5[0],
value = _ref5[1];
ariaLabels['#' + id + ' button'] = value;
});
Object.entries({
group_opacity: properties.opacity,
zoom: ui.zoom_level
}).forEach(function (_ref6) {
var _ref7 = _slicedToArray(_ref6, 2),
id = _ref7[0],
value = _ref7[1];
ariaLabels['#' + id] = value;
});
setStrings('aria-label', ariaLabels);
setStrings('title', { setStrings('title', {
align_relative_to: tools.align_relative_to, align_relative_to: tools.align_relative_to,
circle_cx: properties.circle_cx, circle_cx: properties.circle_cx,
@ -28320,7 +28414,7 @@
langData: langData langData: langData
}); });
case 15: case 19:
case "end": case "end":
return _context.stop(); return _context.stop();
} }
@ -28333,6 +28427,7 @@
}; };
}(); }();
/** /**
*
* @function module:locale.putLocale * @function module:locale.putLocale
* @param {string} givenParam * @param {string} givenParam
* @param {string[]} goodLangs * @param {string[]} goodLangs
@ -28346,7 +28441,7 @@
var putLocale = var putLocale =
/*#__PURE__*/ /*#__PURE__*/
function () { function () {
var _ref4 = _asyncToGenerator( var _ref8 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) { regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) {
var url; var url;
@ -28402,7 +28497,7 @@
})); }));
return function putLocale(_x2, _x3, _x4) { return function putLocale(_x2, _x3, _x4) {
return _ref4.apply(this, arguments); return _ref8.apply(this, arguments);
}; };
}(); }();
@ -29887,6 +29982,8 @@
no_img: !isWebkit(), no_img: !isWebkit(),
// Opera & Firefox 4 gives odd behavior w/images // Opera & Firefox 4 gives odd behavior w/images
fallback_path: curConfig.imgPath, fallback_path: curConfig.imgPath,
// Todo: Set `alts: {}` with keys as the IDs in fallback set to
// `uiStrings` (localized) values
fallback: { fallback: {
logo: 'logo.png', logo: 'logo.png',
select: 'select.png', select: 'select.png',
@ -31902,7 +31999,7 @@
var _ref13 = _asyncToGenerator( var _ref13 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee5(win, ext) { regeneratorRuntime.mark(function _callee5(win, ext) {
var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, placementObj, holders; var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, altsObj, placementObj, holders;
return regeneratorRuntime.wrap(function _callee5$(_context5) { return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) { while (1) {
switch (_context5.prev = _context5.next) { switch (_context5.prev = _context5.next) {
@ -32092,7 +32189,7 @@
break; break;
} }
fallbackObj = {}, placementObj = {}, holders = {}; fallbackObj = {}, altsObj = {}, placementObj = {}, holders = {};
/** /**
* @typedef {GenericArray} module:SVGEditor.KeyArray * @typedef {GenericArray} module:SVGEditor.KeyArray
* @property {string} 0 The key to bind (on `keydown`) * @property {string} 0 The key to bind (on `keydown`)
@ -32137,9 +32234,10 @@
var icon; var icon;
if (!svgicons) { if (!svgicons) {
icon = $$b('<img src="' + btn.icon + '">'); icon = $$b('<img src="' + btn.icon + (btn.title ? '" alt="' + btn.title : '') + '">');
} else { } else {
fallbackObj[id] = btn.icon; fallbackObj[id] = btn.icon;
altsObj[id] = btn.title;
var svgicon = btn.svgicon || btn.id; var svgicon = btn.svgicon || btn.id;
if (btn.type === 'app_menu') { if (btn.type === 'app_menu') {
@ -36051,6 +36149,13 @@
return _context17.abrupt("return"); return _context17.abrupt("return");
case 5: case 5:
// Todo: Remove `allStrings.lang` property in locale in
// favor of just `lang`?
document.documentElement.lang = allStrings.lang; // lang;
// Todo: Add proper RTL Support!
// Todo: Use RTL detection instead and take out of locales?
// document.documentElement.dir = allStrings.dir;
$$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused $$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused
// $.extend will only replace the given strings // $.extend will only replace the given strings
@ -36066,11 +36171,11 @@
if (!extsPreLang.length) { if (!extsPreLang.length) {
_context17.next = 17; _context17.next = 18;
break; break;
} }
_context17.next = 14; _context17.next = 15;
return Promise.all(extsPreLang.map(function (ext) { return Promise.all(extsPreLang.map(function (ext) {
loadedExtensionNames.push(ext.name); loadedExtensionNames.push(ext.name);
return ext.langReady({ return ext.langReady({
@ -36083,12 +36188,12 @@
}); });
})); }));
case 14: case 15:
extsPreLang.length = 0; extsPreLang.length = 0;
_context17.next = 18; _context17.next = 19;
break; break;
case 17: case 18:
loadedExtensionNames.forEach(function (loadedExtensionName) { loadedExtensionNames.forEach(function (loadedExtensionName) {
svgCanvas.runExtension(loadedExtensionName, 'langReady', svgCanvas.runExtension(loadedExtensionName, 'langReady',
/** @type {module:svgcanvas.SvgCanvas#event:ext-langReady} */ /** @type {module:svgcanvas.SvgCanvas#event:ext-langReady} */
@ -36102,7 +36207,7 @@
}); });
}); });
case 18: case 19:
svgCanvas.runExtensions('langChanged', svgCanvas.runExtensions('langChanged',
/** @type {module:svgcanvas.SvgCanvas#event:ext-langChanged} */ /** @type {module:svgcanvas.SvgCanvas#event:ext-langChanged} */
lang); // Update flyout tooltips lang); // Update flyout tooltips
@ -36123,7 +36228,7 @@
$$b('#tool_pos' + this.id.substr(10))[0].title = this.title; $$b('#tool_pos' + this.id.substr(10))[0].title = this.title;
}); });
case 23: case 24:
case "end": case "end":
return _context17.stop(); return _context17.stop();
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2661,6 +2661,10 @@ var SvgCanvas = (function () {
*/ */
/** /**
* Creates a dialog of the specified type with a given message
* and any defaults and type-specific metadata. Returns a `Promise`
* which resolves differently depending on whether the dialog
* was cancelled or okayed (with the response and any checked state).
* @param {"alert"|"prompt"|"select"|"process"} type * @param {"alert"|"prompt"|"select"|"process"} type
* @param {string} msg * @param {string} msg
* @param {string} [defaultVal] * @param {string} [defaultVal]
@ -2693,7 +2697,7 @@ var SvgCanvas = (function () {
}); });
} else if (type === 'select') { } else if (type === 'select') {
var div = $('<div style="text-align:center;">'); var div = $('<div style="text-align:center;">');
ctrl = $('<select>').appendTo(div); ctrl = $("<select aria-label=\"".concat(msg, "\">")).appendTo(div);
if (checkbox) { if (checkbox) {
var label = $('<label>').text(checkbox.label); var label = $('<label>').text(checkbox.label);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -28,10 +28,16 @@ to use less-distracting single quotes if not
## Special properties ## Special properties
The `lang` property should define its HTML `lang` value (which should
probably always be the same as "<lang>" within the "lang.<lang>.js"
file name). This is important for accessibility (screen readers),
search engines, and, for some languages, font selection (e.g., Chinese,
Japanese and Korean languages are expected in different font styles,
despite many characters being shared). `lang` can also potentially be
used programmatically for different styling or behaviors.
While not currently in use, the `dir` property should be used to indicate While not currently in use, the `dir` property should be used to indicate
the default directionality of the language of the locale, while the `lang` the default directionality of the language of the locale.
should define its HTML `lang` value (which should probably always be the
same as "<lang>" within the "lang.<lang>.js" file name).
## Location of locale files (including for extensions) ## Location of locale files (including for extensions)

View File

@ -49,6 +49,10 @@ export default function jQueryPluginDBox ($, strings = {ok: 'Ok', cancel: 'Cance
* @returns {undefined} * @returns {undefined}
*/ */
/** /**
* Creates a dialog of the specified type with a given message
* and any defaults and type-specific metadata. Returns a `Promise`
* which resolves differently depending on whether the dialog
* was cancelled or okayed (with the response and any checked state).
* @param {"alert"|"prompt"|"select"|"process"} type * @param {"alert"|"prompt"|"select"|"process"} type
* @param {string} msg * @param {string} msg
* @param {string} [defaultVal] * @param {string} [defaultVal]
@ -81,7 +85,7 @@ export default function jQueryPluginDBox ($, strings = {ok: 'Ok', cancel: 'Cance
ctrl.bind('keydown', 'return', function () { ok.click(); }); ctrl.bind('keydown', 'return', function () { ok.click(); });
} else if (type === 'select') { } else if (type === 'select') {
const div = $('<div style="text-align:center;">'); const div = $('<div style="text-align:center;">');
ctrl = $('<select>').appendTo(div); ctrl = $(`<select aria-label="${msg}">`).appendTo(div);
if (checkbox) { if (checkbox) {
const label = $('<label>').text(checkbox.label); const label = $('<label>').text(checkbox.label);
chkbx = $('<input type="checkbox">').appendTo(label); chkbx = $('<input type="checkbox">').appendTo(label);

View File

@ -1,3 +1,4 @@
export default { export default {
saved: 'Saved! Return to Item View!' saved: 'Saved! Return to Item View!',
hiddenframe: 'Moinsave frame to store hidden values'
}; };

View File

@ -0,0 +1,4 @@
export default {
uploading: 'Uploading...',
hiddenframe: 'Opensave frame to store hidden values'
};

View File

@ -0,0 +1,4 @@
export default {
uploading: '正在上传...',
hiddenframe: 'Opensave frame to store hidden values'
};

View File

@ -1,3 +1,4 @@
export default { export default {
saved: '已保存! 返回视图!' saved: '已保存! 返回视图!',
hiddenframe: 'Moinsave frame to store hidden values'
}; };

View File

@ -1,3 +0,0 @@
export default {
uploading: 'Uploading...'
};

View File

@ -1,3 +0,0 @@
export default {
uploading: '正在上传...'
};

View File

@ -20,7 +20,10 @@ export default {
// Create upload target (hidden iframe) // Create upload target (hidden iframe)
// Hiding by size instead of display to avoid FF console errors // Hiding by size instead of display to avoid FF console errors
// with `getBBox` in browser.js `supportsPathBBox_`) // with `getBBox` in browser.js `supportsPathBBox_`)
/* const target = */ $('<iframe name="output_frame" style="width: 0; height: 0;" src="#"/>').appendTo('body'); /* const target = */ $(
`<iframe name="output_frame" title="${strings.hiddenframe}"
style="width: 0; height: 0;" src="#"/>`
).appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
async save (win, data) { async save (win, data) {

View File

@ -61,7 +61,10 @@ export default {
// Hiding by size instead of display to avoid FF console errors // Hiding by size instead of display to avoid FF console errors
// with `getBBox` in browser.js `supportsPathBBox_`) // with `getBBox` in browser.js `supportsPathBBox_`)
$('<iframe name="output_frame" style="width: 0; height: 0;" src="#"/>').appendTo('body'); $(
`<iframe name="output_frame" title="${strings.hiddenframe}"
style="width: 0; height: 0;" src="#"/>`
).appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save (win, data) { save (win, data) {
const svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works const svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works

View File

@ -31,10 +31,24 @@ const $ = jQuery;
let langParam; let langParam;
/** /**
* @param {"content"|"title"} type * Looks for elements to localize using the supplied `obj` to indicate
* @param {module:locale.LocaleSelectorValue} obj * on which selectors (or IDs if `ids` is set to `true`) to set its
* @param {boolean} ids * strings (with selectors relative to the editor root element). All
* @returns {undefined} * keys will be translated, but for each selector, only the first item
* found matching will be modified.
* If the type is `content`, the selector-identified element's children
* will be checked, and the first (non-empty) text (placeholder) node
* found will have its text replaced.
* If the type is `title`, the element's `title`
* property will be set.
* If the type is `aria-label`, the element's `aria-label` attribute
* will be set (i.e., instructions for screen readers when there is
* otherwise no visible text to be read for the function of the form
* control).
* @param {"content"|"title"} type
* @param {module:locale.LocaleSelectorValue} obj Selectors or IDs keyed to strings
* @param {boolean} ids
* @returns {undefined}
*/ */
export const setStrings = function (type, obj, ids) { export const setStrings = function (type, obj, ids) {
// Root element to look for element from // Root element to look for element from
@ -47,12 +61,17 @@ export const setStrings = function (type, obj, ids) {
if (ids) { sel = '#' + sel; } if (ids) { sel = '#' + sel; }
const $elem = parent.find(sel); const $elem = parent.find(sel);
if ($elem.length) { if ($elem.length) {
const elem = parent.find(sel)[0]; const elem = $elem[0];
switch (type) { switch (type) {
case 'aria-label':
elem.setAttribute('aria-label', val);
break;
case 'content': case 'content':
[...elem.childNodes].some((node) => { [...elem.childNodes].some((node) => {
if (node.nodeType === 3 && node.textContent.trim()) { if (node.nodeType === 3 /* Node.TEXT_NODE */ &&
node.textContent.trim()
) {
node.textContent = val; node.textContent = val;
return true; return true;
} }
@ -88,10 +107,11 @@ export const setStrings = function (type, obj, ids) {
let editor_; let editor_;
/** /**
* @function init * Sets the current editor instance (on which `addLangData`) exists.
* @memberof module:locale * @function init
* @param {module:locale.LocaleEditorInit} editor * @memberof module:locale
* @returns {undefined} * @param {module:locale.LocaleEditorInit} editor
* @returns {undefined}
*/ */
export const init = (editor) => { export const init = (editor) => {
editor_ = editor; editor_ = editor;
@ -127,6 +147,7 @@ export const readLang = async function (langData) {
} = langData; } = langData;
setStrings('content', { setStrings('content', {
// Todo: Add this powered by (probably by default) but with config to remove
// copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html // copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html
curve_segments: properties.curve_segments, curve_segments: properties.curve_segments,
fitToContent: tools.fitToContent, fitToContent: tools.fitToContent,
@ -197,18 +218,42 @@ export const readLang = async function (langData) {
// Context menus // Context menus
const opts = {}; const opts = {};
$.each(['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'], function () { [
opts['#cmenu_canvas a[href="#' + this + '"]'] = tools[this]; 'cut', 'copy', 'paste', 'paste_in_place', 'delete',
'group', 'ungroup', 'move_front', 'move_up',
'move_down', 'move_back'
].forEach((item) => {
opts['#cmenu_canvas a[href="#' + item + '"]'] = tools[item];
}); });
$.each(['dupe', 'merge_down', 'merge_all'], function () { ['dupe', 'merge_down', 'merge_all'].forEach((item) => {
opts['#cmenu_layers a[href="#' + this + '"]'] = layers[this]; opts['#cmenu_layers a[href="#' + item + '"]'] = layers[item];
}); });
opts['#cmenu_layers a[href="#delete"]'] = layers.del; opts['#cmenu_layers a[href="#delete"]'] = layers.del;
setStrings('content', opts); setStrings('content', opts);
const ariaLabels = {};
Object.entries({
tool_blur: properties.blur,
tool_position: tools.align_to_page,
tool_font_family: properties.font_family,
zoom_panel: ui.zoom_level,
stroke_linejoin: properties.linejoin_miter,
stroke_linecap: properties.linecap_butt,
tool_opacity: properties.opacity
}).forEach(([id, value]) => {
ariaLabels['#' + id + ' button'] = value;
});
Object.entries({
group_opacity: properties.opacity,
zoom: ui.zoom_level
}).forEach(([id, value]) => {
ariaLabels['#' + id] = value;
});
setStrings('aria-label', ariaLabels);
setStrings('title', { setStrings('title', {
align_relative_to: tools.align_relative_to, align_relative_to: tools.align_relative_to,
circle_cx: properties.circle_cx, circle_cx: properties.circle_cx,
@ -313,14 +358,15 @@ export const readLang = async function (langData) {
}; };
/** /**
* @function module:locale.putLocale *
* @param {string} givenParam * @function module:locale.putLocale
* @param {string[]} goodLangs * @param {string} givenParam
* @param {{langPath: string}} conf * @param {string[]} goodLangs
* @fires module:svgcanvas.SvgCanvas#event:ext-addLangData * @param {{langPath: string}} conf
* @fires module:svgcanvas.SvgCanvas#event:ext-langReady * @fires module:svgcanvas.SvgCanvas#event:ext-addLangData
* @fires module:svgcanvas.SvgCanvas#event:ext-langChanged * @fires module:svgcanvas.SvgCanvas#event:ext-langReady
* @returns {Promise} Resolves to result of {@link module:locale.readLang} * @fires module:svgcanvas.SvgCanvas#event:ext-langChanged
* @returns {Promise} Resolves to result of {@link module:locale.readLang}
*/ */
export const putLocale = async function (givenParam, goodLangs, conf) { export const putLocale = async function (givenParam, goodLangs, conf) {
if (givenParam) { if (givenParam) {

View File

@ -43,7 +43,7 @@
<body> <body>
<div id="svg_container" style="visibility: hidden;"> <div id="svg_container" style="visibility: hidden;">
<div id="svg_editor"> <div id="svg_editor" role="main">
<div id="rulers"> <div id="rulers">
<div id="ruler_corner"></div> <div id="ruler_corner"></div>
<div id="ruler_x"> <div id="ruler_x">

View File

@ -44,7 +44,7 @@
<body> <body>
<div id="svg_container" style="visibility: hidden;"> <div id="svg_container" style="visibility: hidden;">
<div id="svg_editor"> <div id="svg_editor" role="main">
<div id="rulers"> <div id="rulers">
<div id="ruler_corner"></div> <div id="ruler_corner"></div>
<div id="ruler_x"> <div id="ruler_x">

View File

@ -1175,6 +1175,8 @@ editor.init = function () {
id_match: false, id_match: false,
no_img: !isWebkit(), // Opera & Firefox 4 gives odd behavior w/images no_img: !isWebkit(), // Opera & Firefox 4 gives odd behavior w/images
fallback_path: curConfig.imgPath, fallback_path: curConfig.imgPath,
// Todo: Set `alts: {}` with keys as the IDs in fallback set to
// `uiStrings` (localized) values
fallback: { fallback: {
logo: 'logo.png', logo: 'logo.png',
@ -2149,7 +2151,10 @@ editor.init = function () {
const bNoFill = (svgCanvas.getColor('fill') === 'none'); const bNoFill = (svgCanvas.getColor('fill') === 'none');
const bNoStroke = (svgCanvas.getColor('stroke') === 'none'); const bNoStroke = (svgCanvas.getColor('stroke') === 'none');
const buttonsNeedingStroke = ['#tool_fhpath', '#tool_line']; const buttonsNeedingStroke = ['#tool_fhpath', '#tool_line'];
const buttonsNeedingFillAndStroke = ['#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path']; const buttonsNeedingFillAndStroke = [
'#tools_rect .tool_button', '#tools_ellipse .tool_button',
'#tool_text', '#tool_path'
];
if (bNoStroke) { if (bNoStroke) {
buttonsNeedingStroke.forEach((btn) => { buttonsNeedingStroke.forEach((btn) => {
@ -2177,10 +2182,13 @@ editor.init = function () {
}); });
} }
svgCanvas.runExtensions('toolButtonStateUpdate', /** @type {module:svgcanvas.SvgCanvas#event:ext-toolButtonStateUpdate} */ { svgCanvas.runExtensions(
'toolButtonStateUpdate',
/** @type {module:svgcanvas.SvgCanvas#event:ext-toolButtonStateUpdate} */ {
nofill: bNoFill, nofill: bNoFill,
nostroke: bNoStroke nostroke: bNoStroke
}); }
);
// Disable flyouts if all inside are disabled // Disable flyouts if all inside are disabled
$('.tools_flyout').each(function () { $('.tools_flyout').each(function () {
@ -3194,6 +3202,7 @@ editor.init = function () {
const {svgicons} = ext; const {svgicons} = ext;
if (ext.buttons) { if (ext.buttons) {
const fallbackObj = {}, const fallbackObj = {},
altsObj = {},
placementObj = {}, placementObj = {},
holders = {}; holders = {};
@ -3235,9 +3244,14 @@ editor.init = function () {
let icon; let icon;
if (!svgicons) { if (!svgicons) {
icon = $('<img src="' + btn.icon + '">'); icon = $(
'<img src="' + btn.icon +
(btn.title ? '" alt="' + btn.title : '') +
'">'
);
} else { } else {
fallbackObj[id] = btn.icon; fallbackObj[id] = btn.icon;
altsObj[id] = btn.title;
const svgicon = btn.svgicon || btn.id; const svgicon = btn.svgicon || btn.id;
if (btn.type === 'app_menu') { if (btn.type === 'app_menu') {
placementObj['#' + id + ' > div'] = svgicon; placementObj['#' + id + ' > div'] = svgicon;
@ -4931,7 +4945,11 @@ editor.init = function () {
// added these event handlers for all the push buttons so they // added these event handlers for all the push buttons so they
// behave more like buttons being pressed-in and not images // behave more like buttons being pressed-in and not images
(function () { (function () {
const toolnames = ['clear', 'open', 'save', 'source', 'delete', 'delete_multi', 'paste', 'clone', 'clone_multi', 'move_top', 'move_bottom']; const toolnames = [
'clear', 'open', 'save', 'source', 'delete',
'delete_multi', 'paste', 'clone', 'clone_multi',
'move_top', 'move_bottom'
];
const curClass = 'tool_button_current'; const curClass = 'tool_button_current';
let allTools = ''; let allTools = '';
@ -4967,7 +4985,11 @@ editor.init = function () {
if (button) { if (button) {
const {title} = button; const {title} = button;
const index = title.indexOf('Ctrl+'); const index = title.indexOf('Ctrl+');
button.title = [title.substr(0, index), 'Cmd+', title.substr(index + 5)].join(''); button.title = [
title.substr(0, index),
'Cmd+',
title.substr(index + 5)
].join('');
} }
} }
} }
@ -6200,6 +6222,12 @@ editor.init = function () {
if (!allStrings) { if (!allStrings) {
return; return;
} }
// Todo: Remove `allStrings.lang` property in locale in
// favor of just `lang`?
document.documentElement.lang = allStrings.lang; // lang;
// Todo: Add proper RTL Support!
// Todo: Use RTL detection instead and take out of locales?
// document.documentElement.dir = allStrings.dir;
$.extend(uiStrings, allStrings); $.extend(uiStrings, allStrings);
// const notif = allStrings.notification; // Currently unused // const notif = allStrings.notification; // Currently unused

View File

@ -103,10 +103,15 @@ export default function jQueryPluginSVGIcons ($) {
let fixIDs; let fixIDs;
/** /**
* List of raster images with each * Map of raster images with each key being the SVG icon ID
* key being the SVG icon ID to replace, and the value the image file name * to replace, and the value the image file name
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback * @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback
*/ */
/**
* Map of raster images with each key being the SVG icon ID
* whose `alt` will be set, and the value being the `alt` text
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Alts
*/
/** /**
* @function external:jQuery.svgIcons * @function external:jQuery.svgIcons
* @param {string} file The location of a local SVG or SVGz file * @param {string} file The location of a local SVG or SVGz file
@ -115,21 +120,29 @@ export default function jQueryPluginSVGIcons ($) {
* @param {Float} [opts.h] The icon heights * @param {Float} [opts.h] The icon heights
* @param {external:jQuery.svgIcons.Fallback} [opts.fallback] * @param {external:jQuery.svgIcons.Fallback} [opts.fallback]
* @param {string} [opts.fallback_path] The path to use for all images * @param {string} [opts.fallback_path] The path to use for all images
listed under "fallback" * listed under "fallback"
* @param {boolean} [opts.replace] If set to `true`, HTML elements will be replaced by, * @param {boolean} [opts.replace] If set to `true`, HTML elements will
rather than include the SVG icon. * be replaced by, rather than include the SVG icon.
* @param {PlainObject.<string, string>} [opts.placement] List with selectors for keys and SVG icon ids * @param {PlainObject.<string, string>} [opts.placement] Map with selectors
as values. This provides a custom method of adding icons. * for keys and SVG icon ids as values. This provides a custom method of
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] List with selectors for keys and numbers * adding icons.
as values. This allows an easy way to resize specific icons. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] Map
* @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A function to call when all icons have been loaded. * with selectors for keys and numbers as values. This allows an easy way to
* @param {boolean} [opts.id_match=true] Automatically attempt to match SVG icon ids with * resize specific icons.
corresponding HTML id * @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A
* @param {boolean} [opts.no_img] Prevent attempting to convert the icon into an `<img>` * function to call when all icons have been loaded.
element (may be faster, help for browser consistency) * @param {boolean} [opts.id_match=true] Automatically attempt to match
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and thus not to * SVG icon ids with corresponding HTML id
parse as XML. SVGZ files add compression benefits, but getting data from * @param {boolean} [opts.no_img] Prevent attempting to convert the icon
them fails in Firefox 2 and older. * into an `<img>` element (may be faster, help for browser consistency)
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and
* thus not to parse as XML. SVGZ files add compression benefits, but
* getting data from them fails in Firefox 2 and older.
* @param {jQuery.svgIcons.Alts} [opts.alts] Map of images with each key
* being the SVG icon ID whose `alt` will be set, and the value being
* the `alt` text
* @param {string} [opts.testIconAlt="icon"] Alt text for the injected test image.
* In case wish to ensure have one for accessibility
* @returns {undefined} * @returns {undefined}
*/ */
$.svgIcons = function (file, opts = {}) { $.svgIcons = function (file, opts = {}) {
@ -228,7 +241,8 @@ export default function jQueryPluginSVGIcons ($) {
testImg = $(new Image()).attr({ testImg = $(new Image()).attr({
src: testSrc, src: testSrc,
width: 0, width: 0,
height: 0 height: 0,
alt: opts.testIconAlt || 'icon'
}).appendTo('body') }).appendTo('body')
.load(function () { .load(function () {
// Safari 4 crashes, Opera and Chrome don't // Safari 4 crashes, Opera and Chrome don't
@ -248,7 +262,7 @@ export default function jQueryPluginSVGIcons ($) {
* @param {external:jQuery} target * @param {external:jQuery} target
* @param {external:jQuery} icon A wrapped `defs` or Image * @param {external:jQuery} icon A wrapped `defs` or Image
* @param {string} id SVG icon ID * @param {string} id SVG icon ID
* @param {string} setID * @param {boolean} setID Whether to set the ID attribute (with `id`)
* @returns {undefined} * @returns {undefined}
*/ */
function setIcon (target, icon, id, setID) { function setIcon (target, icon, id, setID) {
@ -257,6 +271,13 @@ export default function jQueryPluginSVGIcons ($) {
if (setID) icon.attr('id', id); if (setID) icon.attr('id', id);
const cl = target.attr('class'); const cl = target.attr('class');
if (cl) icon.attr('class', 'svg_icon ' + cl); if (cl) icon.attr('class', 'svg_icon ' + cl);
if (!target.alt) {
let alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon.attr('alt', alt);
}
target.replaceWith(icon); target.replaceWith(icon);
} else { } else {
target.append(icon); target.append(icon);
@ -300,13 +321,17 @@ export default function jQueryPluginSVGIcons ($) {
const path = opts.fallback_path || ''; const path = opts.fallback_path || '';
$.each(fallback, function (id, imgsrc) { $.each(fallback, function (id, imgsrc) {
holder = $('#' + id); holder = $('#' + id);
let alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
const icon = $(new Image()) const icon = $(new Image())
.attr({ .attr({
class: 'svg_icon', class: 'svg_icon',
src: path + imgsrc, src: path + imgsrc,
width: iconW, width: iconW,
height: iconH, height: iconH,
alt: 'icon' alt
}); });
addIcon(icon, id); addIcon(icon, id);
@ -352,9 +377,15 @@ export default function jQueryPluginSVGIcons ($) {
let icon; let icon;
if (toImage) { if (toImage) {
tempHolder.empty().append(svgroot); tempHolder.empty().append(svgroot);
const str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot)))); const str = dataPre + encode64(unescape(encodeURIComponent(
new XMLSerializer().serializeToString(svgroot)
)));
let alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon = $(new Image()) icon = $(new Image())
.attr({class: 'svg_icon', src: str}); .attr({class: 'svg_icon', src: str, alt});
} else { } else {
icon = fixIDs($(svgroot), i); icon = fixIDs($(svgroot), i);
} }
@ -479,13 +510,15 @@ export default function jQueryPluginSVGIcons ($) {
*/ */
/** /**
* If a Float is used, it will represent width and height. Arrays contain the width and height. * If a Float is used, it will represent width and height. Arrays contain
* the width and height.
* @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size * @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size
*/ */
/** /**
* @function external:jQuery.resizeSvgIcons * @function external:jQuery.resizeSvgIcons
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with selectors as keys. The values are sizes. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with
* selectors as keys. The values are sizes.
* @returns {undefined} * @returns {undefined}
*/ */
$.resizeSvgIcons = function (obj) { $.resizeSvgIcons = function (obj) {

View File

@ -44,7 +44,7 @@
<body> <body>
<div id="svg_container" style="visibility: hidden;"> <div id="svg_container" style="visibility: hidden;">
<div id="svg_editor"> <div id="svg_editor" role="main">
<div id="rulers"> <div id="rulers">
<div id="ruler_corner"></div> <div id="ruler_corner"></div>
<div id="ruler_x"> <div id="ruler_x">

View File

@ -44,7 +44,7 @@
<body> <body>
<div id="svg_container" style="visibility: hidden;"> <div id="svg_container" style="visibility: hidden;">
<div id="svg_editor"> <div id="svg_editor" role="main">
<div id="rulers"> <div id="rulers">
<div id="ruler_corner"></div> <div id="ruler_corner"></div>
<div id="ruler_x"> <div id="ruler_x">

View File

@ -9629,6 +9629,10 @@
*/ */
/** /**
* Creates a dialog of the specified type with a given message
* and any defaults and type-specific metadata. Returns a `Promise`
* which resolves differently depending on whether the dialog
* was cancelled or okayed (with the response and any checked state).
* @param {"alert"|"prompt"|"select"|"process"} type * @param {"alert"|"prompt"|"select"|"process"} type
* @param {string} msg * @param {string} msg
* @param {string} [defaultVal] * @param {string} [defaultVal]
@ -9661,7 +9665,7 @@
}); });
} else if (type === 'select') { } else if (type === 'select') {
var div = $('<div style="text-align:center;">'); var div = $('<div style="text-align:center;">');
ctrl = $('<select>').appendTo(div); ctrl = $("<select aria-label=\"".concat(msg, "\">")).appendTo(div);
if (checkbox) { if (checkbox) {
var label = $('<label>').text(checkbox.label); var label = $('<label>').text(checkbox.label);
@ -22307,11 +22311,17 @@
var svgIcons = {}; var svgIcons = {};
var fixIDs; var fixIDs;
/** /**
* List of raster images with each * Map of raster images with each key being the SVG icon ID
* key being the SVG icon ID to replace, and the value the image file name * to replace, and the value the image file name
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback * @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback
*/ */
/**
* Map of raster images with each key being the SVG icon ID
* whose `alt` will be set, and the value being the `alt` text
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Alts
*/
/** /**
* @function external:jQuery.svgIcons * @function external:jQuery.svgIcons
* @param {string} file The location of a local SVG or SVGz file * @param {string} file The location of a local SVG or SVGz file
@ -22320,21 +22330,29 @@
* @param {Float} [opts.h] The icon heights * @param {Float} [opts.h] The icon heights
* @param {external:jQuery.svgIcons.Fallback} [opts.fallback] * @param {external:jQuery.svgIcons.Fallback} [opts.fallback]
* @param {string} [opts.fallback_path] The path to use for all images * @param {string} [opts.fallback_path] The path to use for all images
listed under "fallback" * listed under "fallback"
* @param {boolean} [opts.replace] If set to `true`, HTML elements will be replaced by, * @param {boolean} [opts.replace] If set to `true`, HTML elements will
rather than include the SVG icon. * be replaced by, rather than include the SVG icon.
* @param {PlainObject.<string, string>} [opts.placement] List with selectors for keys and SVG icon ids * @param {PlainObject.<string, string>} [opts.placement] Map with selectors
as values. This provides a custom method of adding icons. * for keys and SVG icon ids as values. This provides a custom method of
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] List with selectors for keys and numbers * adding icons.
as values. This allows an easy way to resize specific icons. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] Map
* @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A function to call when all icons have been loaded. * with selectors for keys and numbers as values. This allows an easy way to
* @param {boolean} [opts.id_match=true] Automatically attempt to match SVG icon ids with * resize specific icons.
corresponding HTML id * @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A
* @param {boolean} [opts.no_img] Prevent attempting to convert the icon into an `<img>` * function to call when all icons have been loaded.
element (may be faster, help for browser consistency) * @param {boolean} [opts.id_match=true] Automatically attempt to match
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and thus not to * SVG icon ids with corresponding HTML id
parse as XML. SVGZ files add compression benefits, but getting data from * @param {boolean} [opts.no_img] Prevent attempting to convert the icon
them fails in Firefox 2 and older. * into an `<img>` element (may be faster, help for browser consistency)
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and
* thus not to parse as XML. SVGZ files add compression benefits, but
* getting data from them fails in Firefox 2 and older.
* @param {jQuery.svgIcons.Alts} [opts.alts] Map of images with each key
* being the SVG icon ID whose `alt` will be set, and the value being
* the `alt` text
* @param {string} [opts.testIconAlt="icon"] Alt text for the injected test image.
* In case wish to ensure have one for accessibility
* @returns {undefined} * @returns {undefined}
*/ */
@ -22445,7 +22463,8 @@
testImg = $(new Image()).attr({ testImg = $(new Image()).attr({
src: testSrc, src: testSrc,
width: 0, width: 0,
height: 0 height: 0,
alt: opts.testIconAlt || 'icon'
}).appendTo('body').load(function () { }).appendTo('body').load(function () {
// Safari 4 crashes, Opera and Chrome don't // Safari 4 crashes, Opera and Chrome don't
makeIcons(true); makeIcons(true);
@ -22463,7 +22482,7 @@
* @param {external:jQuery} target * @param {external:jQuery} target
* @param {external:jQuery} icon A wrapped `defs` or Image * @param {external:jQuery} icon A wrapped `defs` or Image
* @param {string} id SVG icon ID * @param {string} id SVG icon ID
* @param {string} setID * @param {boolean} setID Whether to set the ID attribute (with `id`)
* @returns {undefined} * @returns {undefined}
*/ */
@ -22475,6 +22494,17 @@
if (setID) icon.attr('id', id); if (setID) icon.attr('id', id);
var cl = target.attr('class'); var cl = target.attr('class');
if (cl) icon.attr('class', 'svg_icon ' + cl); if (cl) icon.attr('class', 'svg_icon ' + cl);
if (!target.alt) {
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon.attr('alt', alt);
}
target.replaceWith(icon); target.replaceWith(icon);
} else { } else {
target.append(icon); target.append(icon);
@ -22525,12 +22555,18 @@
var path = opts.fallback_path || ''; var path = opts.fallback_path || '';
$.each(fallback, function (id, imgsrc) { $.each(fallback, function (id, imgsrc) {
holder = $('#' + id); holder = $('#' + id);
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
var icon = $(new Image()).attr({ var icon = $(new Image()).attr({
class: 'svg_icon', class: 'svg_icon',
src: path + imgsrc, src: path + imgsrc,
width: iconW, width: iconW,
height: iconH, height: iconH,
alt: 'icon' alt: alt
}); });
addIcon(icon, id); addIcon(icon, id);
}); });
@ -22573,9 +22609,16 @@
if (toImage) { if (toImage) {
tempHolder.empty().append(svgroot); tempHolder.empty().append(svgroot);
var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot)))); var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot))));
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon = $(new Image()).attr({ icon = $(new Image()).attr({
class: 'svg_icon', class: 'svg_icon',
src: str src: str,
alt: alt
}); });
} else { } else {
icon = fixIDs($(svgroot), i); icon = fixIDs($(svgroot), i);
@ -22708,13 +22751,15 @@
*/ */
/** /**
* If a Float is used, it will represent width and height. Arrays contain the width and height. * If a Float is used, it will represent width and height. Arrays contain
* the width and height.
* @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size * @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size
*/ */
/** /**
* @function external:jQuery.resizeSvgIcons * @function external:jQuery.resizeSvgIcons
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with selectors as keys. The values are sizes. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with
* selectors as keys. The values are sizes.
* @returns {undefined} * @returns {undefined}
*/ */
@ -28026,8 +28071,22 @@
var $$a = jQuery; var $$a = jQuery;
var langParam; var langParam;
/** /**
* Looks for elements to localize using the supplied `obj` to indicate
* on which selectors (or IDs if `ids` is set to `true`) to set its
* strings (with selectors relative to the editor root element). All
* keys will be translated, but for each selector, only the first item
* found matching will be modified.
* If the type is `content`, the selector-identified element's children
* will be checked, and the first (non-empty) text (placeholder) node
* found will have its text replaced.
* If the type is `title`, the element's `title`
* property will be set.
* If the type is `aria-label`, the element's `aria-label` attribute
* will be set (i.e., instructions for screen readers when there is
* otherwise no visible text to be read for the function of the form
* control).
* @param {"content"|"title"} type * @param {"content"|"title"} type
* @param {module:locale.LocaleSelectorValue} obj * @param {module:locale.LocaleSelectorValue} obj Selectors or IDs keyed to strings
* @param {boolean} ids * @param {boolean} ids
* @returns {undefined} * @returns {undefined}
*/ */
@ -28051,12 +28110,18 @@
var $elem = parent.find(sel); var $elem = parent.find(sel);
if ($elem.length) { if ($elem.length) {
var elem = parent.find(sel)[0]; var elem = $elem[0];
switch (type) { switch (type) {
case 'aria-label':
elem.setAttribute('aria-label', val);
break;
case 'content': case 'content':
_toConsumableArray(elem.childNodes).some(function (node) { _toConsumableArray(elem.childNodes).some(function (node) {
if (node.nodeType === 3 && node.textContent.trim()) { if (node.nodeType === 3
/* Node.TEXT_NODE */
&& node.textContent.trim()) {
node.textContent = val; node.textContent = val;
return true; return true;
} }
@ -28094,6 +28159,7 @@
var editor_; var editor_;
/** /**
* Sets the current editor instance (on which `addLangData`) exists.
* @function init * @function init
* @memberof module:locale * @memberof module:locale
* @param {module:locale.LocaleEditorInit} editor * @param {module:locale.LocaleEditorInit} editor
@ -28122,7 +28188,7 @@
var _ref3 = _asyncToGenerator( var _ref3 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee(langData) { regeneratorRuntime.mark(function _callee(langData) {
var more, _langData, tools, properties, config, layers, common, ui, opts; var more, _langData, tools, properties, config, layers, common, ui, opts, ariaLabels;
return regeneratorRuntime.wrap(function _callee$(_context) { return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) { while (1) {
@ -28149,6 +28215,7 @@
case 6: case 6:
_langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui; _langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui;
setStrings('content', { setStrings('content', {
// Todo: Add this powered by (probably by default) but with config to remove
// copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html // copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html
curve_segments: properties.curve_segments, curve_segments: properties.curve_segments,
fitToContent: tools.fitToContent, fitToContent: tools.fitToContent,
@ -28206,14 +28273,41 @@
}, true); // Context menus }, true); // Context menus
opts = {}; opts = {};
$$a.each(['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'], function () { ['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'].forEach(function (item) {
opts['#cmenu_canvas a[href="#' + this + '"]'] = tools[this]; opts['#cmenu_canvas a[href="#' + item + '"]'] = tools[item];
}); });
$$a.each(['dupe', 'merge_down', 'merge_all'], function () { ['dupe', 'merge_down', 'merge_all'].forEach(function (item) {
opts['#cmenu_layers a[href="#' + this + '"]'] = layers[this]; opts['#cmenu_layers a[href="#' + item + '"]'] = layers[item];
}); });
opts['#cmenu_layers a[href="#delete"]'] = layers.del; opts['#cmenu_layers a[href="#delete"]'] = layers.del;
setStrings('content', opts); setStrings('content', opts);
ariaLabels = {};
Object.entries({
tool_blur: properties.blur,
tool_position: tools.align_to_page,
tool_font_family: properties.font_family,
zoom_panel: ui.zoom_level,
stroke_linejoin: properties.linejoin_miter,
stroke_linecap: properties.linecap_butt,
tool_opacity: properties.opacity
}).forEach(function (_ref4) {
var _ref5 = _slicedToArray(_ref4, 2),
id = _ref5[0],
value = _ref5[1];
ariaLabels['#' + id + ' button'] = value;
});
Object.entries({
group_opacity: properties.opacity,
zoom: ui.zoom_level
}).forEach(function (_ref6) {
var _ref7 = _slicedToArray(_ref6, 2),
id = _ref7[0],
value = _ref7[1];
ariaLabels['#' + id] = value;
});
setStrings('aria-label', ariaLabels);
setStrings('title', { setStrings('title', {
align_relative_to: tools.align_relative_to, align_relative_to: tools.align_relative_to,
circle_cx: properties.circle_cx, circle_cx: properties.circle_cx,
@ -28317,7 +28411,7 @@
langData: langData langData: langData
}); });
case 15: case 19:
case "end": case "end":
return _context.stop(); return _context.stop();
} }
@ -28330,6 +28424,7 @@
}; };
}(); }();
/** /**
*
* @function module:locale.putLocale * @function module:locale.putLocale
* @param {string} givenParam * @param {string} givenParam
* @param {string[]} goodLangs * @param {string[]} goodLangs
@ -28343,7 +28438,7 @@
var putLocale = var putLocale =
/*#__PURE__*/ /*#__PURE__*/
function () { function () {
var _ref4 = _asyncToGenerator( var _ref8 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) { regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) {
var url; var url;
@ -28399,7 +28494,7 @@
})); }));
return function putLocale(_x2, _x3, _x4) { return function putLocale(_x2, _x3, _x4) {
return _ref4.apply(this, arguments); return _ref8.apply(this, arguments);
}; };
}(); }();
@ -29884,6 +29979,8 @@
no_img: !isWebkit(), no_img: !isWebkit(),
// Opera & Firefox 4 gives odd behavior w/images // Opera & Firefox 4 gives odd behavior w/images
fallback_path: curConfig.imgPath, fallback_path: curConfig.imgPath,
// Todo: Set `alts: {}` with keys as the IDs in fallback set to
// `uiStrings` (localized) values
fallback: { fallback: {
logo: 'logo.png', logo: 'logo.png',
select: 'select.png', select: 'select.png',
@ -31899,7 +31996,7 @@
var _ref13 = _asyncToGenerator( var _ref13 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee5(win, ext) { regeneratorRuntime.mark(function _callee5(win, ext) {
var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, placementObj, holders; var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, altsObj, placementObj, holders;
return regeneratorRuntime.wrap(function _callee5$(_context5) { return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) { while (1) {
switch (_context5.prev = _context5.next) { switch (_context5.prev = _context5.next) {
@ -32089,7 +32186,7 @@
break; break;
} }
fallbackObj = {}, placementObj = {}, holders = {}; fallbackObj = {}, altsObj = {}, placementObj = {}, holders = {};
/** /**
* @typedef {GenericArray} module:SVGEditor.KeyArray * @typedef {GenericArray} module:SVGEditor.KeyArray
* @property {string} 0 The key to bind (on `keydown`) * @property {string} 0 The key to bind (on `keydown`)
@ -32134,9 +32231,10 @@
var icon; var icon;
if (!svgicons) { if (!svgicons) {
icon = $$b('<img src="' + btn.icon + '">'); icon = $$b('<img src="' + btn.icon + (btn.title ? '" alt="' + btn.title : '') + '">');
} else { } else {
fallbackObj[id] = btn.icon; fallbackObj[id] = btn.icon;
altsObj[id] = btn.title;
var svgicon = btn.svgicon || btn.id; var svgicon = btn.svgicon || btn.id;
if (btn.type === 'app_menu') { if (btn.type === 'app_menu') {
@ -36048,6 +36146,13 @@
return _context17.abrupt("return"); return _context17.abrupt("return");
case 5: case 5:
// Todo: Remove `allStrings.lang` property in locale in
// favor of just `lang`?
document.documentElement.lang = allStrings.lang; // lang;
// Todo: Add proper RTL Support!
// Todo: Use RTL detection instead and take out of locales?
// document.documentElement.dir = allStrings.dir;
$$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused $$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused
// $.extend will only replace the given strings // $.extend will only replace the given strings
@ -36063,11 +36168,11 @@
if (!extsPreLang.length) { if (!extsPreLang.length) {
_context17.next = 17; _context17.next = 18;
break; break;
} }
_context17.next = 14; _context17.next = 15;
return Promise.all(extsPreLang.map(function (ext) { return Promise.all(extsPreLang.map(function (ext) {
loadedExtensionNames.push(ext.name); loadedExtensionNames.push(ext.name);
return ext.langReady({ return ext.langReady({
@ -36080,12 +36185,12 @@
}); });
})); }));
case 14: case 15:
extsPreLang.length = 0; extsPreLang.length = 0;
_context17.next = 18; _context17.next = 19;
break; break;
case 17: case 18:
loadedExtensionNames.forEach(function (loadedExtensionName) { loadedExtensionNames.forEach(function (loadedExtensionName) {
svgCanvas.runExtension(loadedExtensionName, 'langReady', svgCanvas.runExtension(loadedExtensionName, 'langReady',
/** @type {module:svgcanvas.SvgCanvas#event:ext-langReady} */ /** @type {module:svgcanvas.SvgCanvas#event:ext-langReady} */
@ -36099,7 +36204,7 @@
}); });
}); });
case 18: case 19:
svgCanvas.runExtensions('langChanged', svgCanvas.runExtensions('langChanged',
/** @type {module:svgcanvas.SvgCanvas#event:ext-langChanged} */ /** @type {module:svgcanvas.SvgCanvas#event:ext-langChanged} */
lang); // Update flyout tooltips lang); // Update flyout tooltips
@ -36120,7 +36225,7 @@
$$b('#tool_pos' + this.id.substr(10))[0].title = this.title; $$b('#tool_pos' + this.id.substr(10))[0].title = this.title;
}); });
case 23: case 24:
case "end": case "end":
return _context17.stop(); return _context17.stop();
} }

View File

@ -9629,6 +9629,10 @@
*/ */
/** /**
* Creates a dialog of the specified type with a given message
* and any defaults and type-specific metadata. Returns a `Promise`
* which resolves differently depending on whether the dialog
* was cancelled or okayed (with the response and any checked state).
* @param {"alert"|"prompt"|"select"|"process"} type * @param {"alert"|"prompt"|"select"|"process"} type
* @param {string} msg * @param {string} msg
* @param {string} [defaultVal] * @param {string} [defaultVal]
@ -9661,7 +9665,7 @@
}); });
} else if (type === 'select') { } else if (type === 'select') {
var div = $('<div style="text-align:center;">'); var div = $('<div style="text-align:center;">');
ctrl = $('<select>').appendTo(div); ctrl = $("<select aria-label=\"".concat(msg, "\">")).appendTo(div);
if (checkbox) { if (checkbox) {
var label = $('<label>').text(checkbox.label); var label = $('<label>').text(checkbox.label);
@ -22307,11 +22311,17 @@
var svgIcons = {}; var svgIcons = {};
var fixIDs; var fixIDs;
/** /**
* List of raster images with each * Map of raster images with each key being the SVG icon ID
* key being the SVG icon ID to replace, and the value the image file name * to replace, and the value the image file name
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback * @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Fallback
*/ */
/**
* Map of raster images with each key being the SVG icon ID
* whose `alt` will be set, and the value being the `alt` text
* @typedef {PlainObject.<string, string>} external:jQuery.svgIcons.Alts
*/
/** /**
* @function external:jQuery.svgIcons * @function external:jQuery.svgIcons
* @param {string} file The location of a local SVG or SVGz file * @param {string} file The location of a local SVG or SVGz file
@ -22320,21 +22330,29 @@
* @param {Float} [opts.h] The icon heights * @param {Float} [opts.h] The icon heights
* @param {external:jQuery.svgIcons.Fallback} [opts.fallback] * @param {external:jQuery.svgIcons.Fallback} [opts.fallback]
* @param {string} [opts.fallback_path] The path to use for all images * @param {string} [opts.fallback_path] The path to use for all images
listed under "fallback" * listed under "fallback"
* @param {boolean} [opts.replace] If set to `true`, HTML elements will be replaced by, * @param {boolean} [opts.replace] If set to `true`, HTML elements will
rather than include the SVG icon. * be replaced by, rather than include the SVG icon.
* @param {PlainObject.<string, string>} [opts.placement] List with selectors for keys and SVG icon ids * @param {PlainObject.<string, string>} [opts.placement] Map with selectors
as values. This provides a custom method of adding icons. * for keys and SVG icon ids as values. This provides a custom method of
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] List with selectors for keys and numbers * adding icons.
as values. This allows an easy way to resize specific icons. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} [opts.resize] Map
* @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A function to call when all icons have been loaded. * with selectors for keys and numbers as values. This allows an easy way to
* @param {boolean} [opts.id_match=true] Automatically attempt to match SVG icon ids with * resize specific icons.
corresponding HTML id * @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A
* @param {boolean} [opts.no_img] Prevent attempting to convert the icon into an `<img>` * function to call when all icons have been loaded.
element (may be faster, help for browser consistency) * @param {boolean} [opts.id_match=true] Automatically attempt to match
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and thus not to * SVG icon ids with corresponding HTML id
parse as XML. SVGZ files add compression benefits, but getting data from * @param {boolean} [opts.no_img] Prevent attempting to convert the icon
them fails in Firefox 2 and older. * into an `<img>` element (may be faster, help for browser consistency)
* @param {boolean} [opts.svgz] Indicate that the file is an SVGZ file, and
* thus not to parse as XML. SVGZ files add compression benefits, but
* getting data from them fails in Firefox 2 and older.
* @param {jQuery.svgIcons.Alts} [opts.alts] Map of images with each key
* being the SVG icon ID whose `alt` will be set, and the value being
* the `alt` text
* @param {string} [opts.testIconAlt="icon"] Alt text for the injected test image.
* In case wish to ensure have one for accessibility
* @returns {undefined} * @returns {undefined}
*/ */
@ -22445,7 +22463,8 @@
testImg = $(new Image()).attr({ testImg = $(new Image()).attr({
src: testSrc, src: testSrc,
width: 0, width: 0,
height: 0 height: 0,
alt: opts.testIconAlt || 'icon'
}).appendTo('body').load(function () { }).appendTo('body').load(function () {
// Safari 4 crashes, Opera and Chrome don't // Safari 4 crashes, Opera and Chrome don't
makeIcons(true); makeIcons(true);
@ -22463,7 +22482,7 @@
* @param {external:jQuery} target * @param {external:jQuery} target
* @param {external:jQuery} icon A wrapped `defs` or Image * @param {external:jQuery} icon A wrapped `defs` or Image
* @param {string} id SVG icon ID * @param {string} id SVG icon ID
* @param {string} setID * @param {boolean} setID Whether to set the ID attribute (with `id`)
* @returns {undefined} * @returns {undefined}
*/ */
@ -22475,6 +22494,17 @@
if (setID) icon.attr('id', id); if (setID) icon.attr('id', id);
var cl = target.attr('class'); var cl = target.attr('class');
if (cl) icon.attr('class', 'svg_icon ' + cl); if (cl) icon.attr('class', 'svg_icon ' + cl);
if (!target.alt) {
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon.attr('alt', alt);
}
target.replaceWith(icon); target.replaceWith(icon);
} else { } else {
target.append(icon); target.append(icon);
@ -22525,12 +22555,18 @@
var path = opts.fallback_path || ''; var path = opts.fallback_path || '';
$.each(fallback, function (id, imgsrc) { $.each(fallback, function (id, imgsrc) {
holder = $('#' + id); holder = $('#' + id);
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
var icon = $(new Image()).attr({ var icon = $(new Image()).attr({
class: 'svg_icon', class: 'svg_icon',
src: path + imgsrc, src: path + imgsrc,
width: iconW, width: iconW,
height: iconH, height: iconH,
alt: 'icon' alt: alt
}); });
addIcon(icon, id); addIcon(icon, id);
}); });
@ -22573,9 +22609,16 @@
if (toImage) { if (toImage) {
tempHolder.empty().append(svgroot); tempHolder.empty().append(svgroot);
var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot)))); var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot))));
var alt = 'icon';
if (opts.alts) {
alt = opts.alts[id] || alt;
}
icon = $(new Image()).attr({ icon = $(new Image()).attr({
class: 'svg_icon', class: 'svg_icon',
src: str src: str,
alt: alt
}); });
} else { } else {
icon = fixIDs($(svgroot), i); icon = fixIDs($(svgroot), i);
@ -22708,13 +22751,15 @@
*/ */
/** /**
* If a Float is used, it will represent width and height. Arrays contain the width and height. * If a Float is used, it will represent width and height. Arrays contain
* the width and height.
* @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size * @typedef {module:jQuerySVGIcons.Dimensions|Float} module:jQuerySVGIcons.Size
*/ */
/** /**
* @function external:jQuery.resizeSvgIcons * @function external:jQuery.resizeSvgIcons
* @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with selectors as keys. The values are sizes. * @param {PlainObject.<string, module:jQuerySVGIcons.Size>} obj Object with
* selectors as keys. The values are sizes.
* @returns {undefined} * @returns {undefined}
*/ */
@ -28026,8 +28071,22 @@
var $$a = jQuery; var $$a = jQuery;
var langParam; var langParam;
/** /**
* Looks for elements to localize using the supplied `obj` to indicate
* on which selectors (or IDs if `ids` is set to `true`) to set its
* strings (with selectors relative to the editor root element). All
* keys will be translated, but for each selector, only the first item
* found matching will be modified.
* If the type is `content`, the selector-identified element's children
* will be checked, and the first (non-empty) text (placeholder) node
* found will have its text replaced.
* If the type is `title`, the element's `title`
* property will be set.
* If the type is `aria-label`, the element's `aria-label` attribute
* will be set (i.e., instructions for screen readers when there is
* otherwise no visible text to be read for the function of the form
* control).
* @param {"content"|"title"} type * @param {"content"|"title"} type
* @param {module:locale.LocaleSelectorValue} obj * @param {module:locale.LocaleSelectorValue} obj Selectors or IDs keyed to strings
* @param {boolean} ids * @param {boolean} ids
* @returns {undefined} * @returns {undefined}
*/ */
@ -28051,12 +28110,18 @@
var $elem = parent.find(sel); var $elem = parent.find(sel);
if ($elem.length) { if ($elem.length) {
var elem = parent.find(sel)[0]; var elem = $elem[0];
switch (type) { switch (type) {
case 'aria-label':
elem.setAttribute('aria-label', val);
break;
case 'content': case 'content':
_toConsumableArray(elem.childNodes).some(function (node) { _toConsumableArray(elem.childNodes).some(function (node) {
if (node.nodeType === 3 && node.textContent.trim()) { if (node.nodeType === 3
/* Node.TEXT_NODE */
&& node.textContent.trim()) {
node.textContent = val; node.textContent = val;
return true; return true;
} }
@ -28094,6 +28159,7 @@
var editor_; var editor_;
/** /**
* Sets the current editor instance (on which `addLangData`) exists.
* @function init * @function init
* @memberof module:locale * @memberof module:locale
* @param {module:locale.LocaleEditorInit} editor * @param {module:locale.LocaleEditorInit} editor
@ -28122,7 +28188,7 @@
var _ref3 = _asyncToGenerator( var _ref3 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee(langData) { regeneratorRuntime.mark(function _callee(langData) {
var more, _langData, tools, properties, config, layers, common, ui, opts; var more, _langData, tools, properties, config, layers, common, ui, opts, ariaLabels;
return regeneratorRuntime.wrap(function _callee$(_context) { return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) { while (1) {
@ -28149,6 +28215,7 @@
case 6: case 6:
_langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui; _langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui;
setStrings('content', { setStrings('content', {
// Todo: Add this powered by (probably by default) but with config to remove
// copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html // copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html
curve_segments: properties.curve_segments, curve_segments: properties.curve_segments,
fitToContent: tools.fitToContent, fitToContent: tools.fitToContent,
@ -28206,14 +28273,41 @@
}, true); // Context menus }, true); // Context menus
opts = {}; opts = {};
$$a.each(['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'], function () { ['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'].forEach(function (item) {
opts['#cmenu_canvas a[href="#' + this + '"]'] = tools[this]; opts['#cmenu_canvas a[href="#' + item + '"]'] = tools[item];
}); });
$$a.each(['dupe', 'merge_down', 'merge_all'], function () { ['dupe', 'merge_down', 'merge_all'].forEach(function (item) {
opts['#cmenu_layers a[href="#' + this + '"]'] = layers[this]; opts['#cmenu_layers a[href="#' + item + '"]'] = layers[item];
}); });
opts['#cmenu_layers a[href="#delete"]'] = layers.del; opts['#cmenu_layers a[href="#delete"]'] = layers.del;
setStrings('content', opts); setStrings('content', opts);
ariaLabels = {};
Object.entries({
tool_blur: properties.blur,
tool_position: tools.align_to_page,
tool_font_family: properties.font_family,
zoom_panel: ui.zoom_level,
stroke_linejoin: properties.linejoin_miter,
stroke_linecap: properties.linecap_butt,
tool_opacity: properties.opacity
}).forEach(function (_ref4) {
var _ref5 = _slicedToArray(_ref4, 2),
id = _ref5[0],
value = _ref5[1];
ariaLabels['#' + id + ' button'] = value;
});
Object.entries({
group_opacity: properties.opacity,
zoom: ui.zoom_level
}).forEach(function (_ref6) {
var _ref7 = _slicedToArray(_ref6, 2),
id = _ref7[0],
value = _ref7[1];
ariaLabels['#' + id] = value;
});
setStrings('aria-label', ariaLabels);
setStrings('title', { setStrings('title', {
align_relative_to: tools.align_relative_to, align_relative_to: tools.align_relative_to,
circle_cx: properties.circle_cx, circle_cx: properties.circle_cx,
@ -28317,7 +28411,7 @@
langData: langData langData: langData
}); });
case 15: case 19:
case "end": case "end":
return _context.stop(); return _context.stop();
} }
@ -28330,6 +28424,7 @@
}; };
}(); }();
/** /**
*
* @function module:locale.putLocale * @function module:locale.putLocale
* @param {string} givenParam * @param {string} givenParam
* @param {string[]} goodLangs * @param {string[]} goodLangs
@ -28343,7 +28438,7 @@
var putLocale = var putLocale =
/*#__PURE__*/ /*#__PURE__*/
function () { function () {
var _ref4 = _asyncToGenerator( var _ref8 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) { regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) {
var url; var url;
@ -28399,7 +28494,7 @@
})); }));
return function putLocale(_x2, _x3, _x4) { return function putLocale(_x2, _x3, _x4) {
return _ref4.apply(this, arguments); return _ref8.apply(this, arguments);
}; };
}(); }();
@ -29884,6 +29979,8 @@
no_img: !isWebkit(), no_img: !isWebkit(),
// Opera & Firefox 4 gives odd behavior w/images // Opera & Firefox 4 gives odd behavior w/images
fallback_path: curConfig.imgPath, fallback_path: curConfig.imgPath,
// Todo: Set `alts: {}` with keys as the IDs in fallback set to
// `uiStrings` (localized) values
fallback: { fallback: {
logo: 'logo.png', logo: 'logo.png',
select: 'select.png', select: 'select.png',
@ -31899,7 +31996,7 @@
var _ref13 = _asyncToGenerator( var _ref13 = _asyncToGenerator(
/*#__PURE__*/ /*#__PURE__*/
regeneratorRuntime.mark(function _callee5(win, ext) { regeneratorRuntime.mark(function _callee5(win, ext) {
var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, placementObj, holders; var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, altsObj, placementObj, holders;
return regeneratorRuntime.wrap(function _callee5$(_context5) { return regeneratorRuntime.wrap(function _callee5$(_context5) {
while (1) { while (1) {
switch (_context5.prev = _context5.next) { switch (_context5.prev = _context5.next) {
@ -32089,7 +32186,7 @@
break; break;
} }
fallbackObj = {}, placementObj = {}, holders = {}; fallbackObj = {}, altsObj = {}, placementObj = {}, holders = {};
/** /**
* @typedef {GenericArray} module:SVGEditor.KeyArray * @typedef {GenericArray} module:SVGEditor.KeyArray
* @property {string} 0 The key to bind (on `keydown`) * @property {string} 0 The key to bind (on `keydown`)
@ -32134,9 +32231,10 @@
var icon; var icon;
if (!svgicons) { if (!svgicons) {
icon = $$b('<img src="' + btn.icon + '">'); icon = $$b('<img src="' + btn.icon + (btn.title ? '" alt="' + btn.title : '') + '">');
} else { } else {
fallbackObj[id] = btn.icon; fallbackObj[id] = btn.icon;
altsObj[id] = btn.title;
var svgicon = btn.svgicon || btn.id; var svgicon = btn.svgicon || btn.id;
if (btn.type === 'app_menu') { if (btn.type === 'app_menu') {
@ -36048,6 +36146,13 @@
return _context17.abrupt("return"); return _context17.abrupt("return");
case 5: case 5:
// Todo: Remove `allStrings.lang` property in locale in
// favor of just `lang`?
document.documentElement.lang = allStrings.lang; // lang;
// Todo: Add proper RTL Support!
// Todo: Use RTL detection instead and take out of locales?
// document.documentElement.dir = allStrings.dir;
$$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused $$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused
// $.extend will only replace the given strings // $.extend will only replace the given strings
@ -36063,11 +36168,11 @@
if (!extsPreLang.length) { if (!extsPreLang.length) {
_context17.next = 17; _context17.next = 18;
break; break;
} }
_context17.next = 14; _context17.next = 15;
return Promise.all(extsPreLang.map(function (ext) { return Promise.all(extsPreLang.map(function (ext) {
loadedExtensionNames.push(ext.name); loadedExtensionNames.push(ext.name);
return ext.langReady({ return ext.langReady({
@ -36080,12 +36185,12 @@
}); });
})); }));
case 14: case 15:
extsPreLang.length = 0; extsPreLang.length = 0;
_context17.next = 18; _context17.next = 19;
break; break;
case 17: case 18:
loadedExtensionNames.forEach(function (loadedExtensionName) { loadedExtensionNames.forEach(function (loadedExtensionName) {
svgCanvas.runExtension(loadedExtensionName, 'langReady', svgCanvas.runExtension(loadedExtensionName, 'langReady',
/** @type {module:svgcanvas.SvgCanvas#event:ext-langReady} */ /** @type {module:svgcanvas.SvgCanvas#event:ext-langReady} */
@ -36099,7 +36204,7 @@
}); });
}); });
case 18: case 19:
svgCanvas.runExtensions('langChanged', svgCanvas.runExtensions('langChanged',
/** @type {module:svgcanvas.SvgCanvas#event:ext-langChanged} */ /** @type {module:svgcanvas.SvgCanvas#event:ext-langChanged} */
lang); // Update flyout tooltips lang); // Update flyout tooltips
@ -36120,7 +36225,7 @@
$$b('#tool_pos' + this.id.substr(10))[0].title = this.title; $$b('#tool_pos' + this.id.substr(10))[0].title = this.title;
}); });
case 23: case 24:
case "end": case "end":
return _context17.stop(); return _context17.stop();
} }

View File

@ -3,18 +3,40 @@
// https://github.com/helen-dikareva/axe-testcafe // https://github.com/helen-dikareva/axe-testcafe
import axeCheck from 'axe-testcafe'; import axeCheck from 'axe-testcafe';
/**
* @external TestcafeTest
*/
/**
* @param {external.TestcafeTest} t
* @returns {Promise}
*/
function axeCheckWithConfig (t) {
return axeCheck(
t,
// context: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#context-parameter
undefined,
// https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#options-parameter
{
rules: {
'meta-viewport': {enabled: false}
}
}
// , (err, results) {} // https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#results-object
);
}
fixture`TestCafe Axe accessibility tests (Editor - no parameters)` fixture`TestCafe Axe accessibility tests (Editor - no parameters)`
.page`http://localhost:8000/editor/svg-editor.html`; .page`http://localhost:8000/editor/svg-editor.html`;
test('Editor - no parameters', async (t) => { test('Editor - no parameters', async (t) => {
await axeCheck(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun await axeCheckWithConfig(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun
}); });
fixture`TestCafe Axe accessibility tests (Editor - with all extensions)` fixture`TestCafe Axe accessibility tests (Editor - with all extensions)`
.page`http://localhost:8000/editor/svg-editor.html?extensions=ext-arrows.js,ext-closepath.js,ext-foreignobject.js,ext-helloworld.js,ext-mathjax.js,ext-php_savefile.js,ext-server_moinsave.js,ext-server_opensave.js,ext-webappfind.js,ext-xdomain-messaging.js`; .page`http://localhost:8000/editor/svg-editor.html?extensions=ext-arrows.js,ext-closepath.js,ext-foreignobject.js,ext-helloworld.js,ext-mathjax.js,ext-php_savefile.js,ext-server_moinsave.js,ext-server_opensave.js,ext-webappfind.js,ext-xdomain-messaging.js`;
test('Editor ES - with all extensions', async (t) => { test('Editor - with all extensions', async (t) => {
await axeCheck(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun await axeCheckWithConfig(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun
}); });
/* eslint-disable qunit/no-commented-tests */ /* eslint-disable qunit/no-commented-tests */
@ -24,21 +46,21 @@ fixture`TestCafe Axe accessibility tests (Editor ES - no parameters)`
.page`http://localhost:8000/editor/svg-editor-es.html`; .page`http://localhost:8000/editor/svg-editor-es.html`;
test('Editor ES - no parameters', async t => { test('Editor ES - no parameters', async t => {
await axeCheck(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun await axeCheckWithConfig(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun
}); });
fixture`TestCafe Axe accessibility tests (Editor ES - with all extensions)` fixture`TestCafe Axe accessibility tests (Editor ES - with all extensions)`
.page`http://localhost:8000/editor/svg-editor-es.html?extensions=ext-arrows.js,ext-closepath.js,ext-foreignobject.js,ext-helloworld.js,ext-mathjax.js,ext-php_savefile.js,ext-server_moinsave.js,ext-server_opensave.js,ext-webappfind.js,ext-xdomain-messaging.js`; .page`http://localhost:8000/editor/svg-editor-es.html?extensions=ext-arrows.js,ext-closepath.js,ext-foreignobject.js,ext-helloworld.js,ext-mathjax.js,ext-php_savefile.js,ext-server_moinsave.js,ext-server_opensave.js,ext-webappfind.js,ext-xdomain-messaging.js`;
test('Editor ES - with all extensions', async t => { test('Editor ES - with all extensions', async t => {
await axeCheck(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun await axeCheckWithConfig(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun
}); });
fixture`TestCafe Axe accessibility tests (Embedded - no parameters)` fixture`TestCafe Axe accessibility tests (Embedded - no parameters)`
.page`http://localhost:8000/editor/embedapi.html`; .page`http://localhost:8000/editor/embedapi.html`;
test('Embedded - no parameters', async t => { test('Embedded - no parameters', async t => {
await axeCheck(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun await axeCheckWithConfig(t); // , axeContent, axeOptions: https://github.com/dequelabs/axe-core/blob/develop/doc/API.md#api-name-axerun
}); });
*/ */
/* eslint-enable qunit/no-commented-tests */ /* eslint-enable qunit/no-commented-tests */