remove jquery in updatetoolbar
parent
bdb51c478c
commit
a489cd17da
|
@ -640,13 +640,13 @@ export default {
|
|||
return {remove};
|
||||
},
|
||||
toolButtonStateUpdate (opts) {
|
||||
const button = document.getElementById('mode_connect');
|
||||
if (opts.nostroke) {
|
||||
if ($('#mode_connect').hasClass('tool_button_current')) {
|
||||
if (button.pressed === true) {
|
||||
svgEditor.clickSelect();
|
||||
}
|
||||
}
|
||||
$('#mode_connect')
|
||||
.toggleClass('disabled', opts.nostroke);
|
||||
button.disabled = opts.nostroke;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -146,24 +146,10 @@ export default {
|
|||
updateGrid(svgCanvas.getZoom());
|
||||
}
|
||||
$('#canvasGrid').toggle(showGrid);
|
||||
$('#view_grid').toggleClass('push_button_pressed tool_button');
|
||||
document.getElementById('view_grid').pressed = showGrid;
|
||||
}
|
||||
const buttons = [{
|
||||
id: 'view_grid',
|
||||
icon: 'grid.png',
|
||||
type: 'context',
|
||||
panel: 'editor_panel',
|
||||
events: {
|
||||
click () {
|
||||
svgEditor.curConfig.showGrid = showGrid = !showGrid;
|
||||
gridUpdate();
|
||||
}
|
||||
}
|
||||
}];
|
||||
return {
|
||||
name: strings.name,
|
||||
svgicons: 'grid-icon.xml',
|
||||
|
||||
zoomChanged (zoom) {
|
||||
if (showGrid) { updateGrid(zoom); }
|
||||
},
|
||||
|
@ -172,9 +158,13 @@ export default {
|
|||
gridUpdate();
|
||||
}
|
||||
},
|
||||
buttons: strings.buttons.map((button, i) => {
|
||||
return Object.assign(buttons[i], button);
|
||||
})
|
||||
events: {
|
||||
id: 'view_grid',
|
||||
click () {
|
||||
svgEditor.curConfig.showGrid = showGrid = !showGrid;
|
||||
gridUpdate();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -33,33 +33,16 @@ export default {
|
|||
const svgCanvas = svgEditor.canvas;
|
||||
return {
|
||||
name: strings.name,
|
||||
// For more notes on how to make an icon file, see the source of
|
||||
// the helloworld-icon.xml
|
||||
svgicons: 'helloworld-icon.xml',
|
||||
|
||||
// Multiple buttons can be added in this array
|
||||
buttons: [{
|
||||
events: [{
|
||||
// Must match the icon ID in helloworld-icon.xml
|
||||
id: 'hello_world',
|
||||
|
||||
// Fallback, e.g., for `file:///` access
|
||||
icon: 'helloworld.png',
|
||||
|
||||
// This indicates that the button will be added to the "mode"
|
||||
// button panel on the left side
|
||||
type: 'mode',
|
||||
|
||||
// Tooltip text
|
||||
title: strings.buttons[0].title,
|
||||
|
||||
// Events
|
||||
events: {
|
||||
click () {
|
||||
// The action taken when the button is clicked on.
|
||||
// For "mode" buttons, any other button will
|
||||
// automatically be de-pressed.
|
||||
svgCanvas.setMode('hello_world');
|
||||
}
|
||||
click () {
|
||||
// The action taken when the button is clicked on.
|
||||
// For "mode" buttons, any other button will
|
||||
// automatically be de-pressed.
|
||||
svgCanvas.setMode('hello_world');
|
||||
}
|
||||
}],
|
||||
// This is triggered when the main mouse button is pressed down
|
||||
|
|
|
@ -121,7 +121,7 @@ export default {
|
|||
function setIcon (pos, id) {
|
||||
if (id.substr(0, 1) !== '\\') { id = '\\textmarker'; }
|
||||
const ci = '#' + idPrefix + pos + '_' + id.substr(1);
|
||||
svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children());
|
||||
// svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children());
|
||||
$(ci).addClass('current').siblings().removeClass('current');
|
||||
}
|
||||
|
||||
|
|
|
@ -33,22 +33,6 @@ export default {
|
|||
// edg = 0,
|
||||
// undoCommand = 'Not image';
|
||||
started, newFO;
|
||||
|
||||
// const ccZoom;
|
||||
// const wEl, hEl;
|
||||
// const wOffset, hOffset;
|
||||
// const ccRBG;
|
||||
// const ccOpacity;
|
||||
// const brushW, brushH;
|
||||
|
||||
// const ccDebug = document.getElementById('debugpanel');
|
||||
|
||||
/* const properlySourceSizeTextArea = function(){
|
||||
// TODO: remove magic numbers here and get values from CSS
|
||||
const height = $('#svg_source_container').height() - 80;
|
||||
$('#svg_source_textarea').css('height', height);
|
||||
}; */
|
||||
|
||||
/**
|
||||
* @param {boolean} on
|
||||
* @returns {void}
|
||||
|
@ -102,55 +86,13 @@ export default {
|
|||
* @param {string} tex The itex text.
|
||||
* @returns {boolean} This function returns false if the set was unsuccessful, true otherwise.
|
||||
*/
|
||||
/*
|
||||
function setItexString(tex) {
|
||||
const mathns = 'http://www.w3.org/1998/Math/MathML',
|
||||
xmlnsns = 'http://www.w3.org/2000/xmlns/',
|
||||
ajaxEndpoint = '../../itex';
|
||||
const elt = selElems[0];
|
||||
try {
|
||||
const math = svgdoc.createElementNS(mathns, 'math');
|
||||
math.setAttributeNS(xmlnsns, 'xmlns', mathns);
|
||||
math.setAttribute('display', 'inline');
|
||||
const semantics = document.createElementNS(mathns, 'semantics');
|
||||
const annotation = document.createElementNS(mathns, 'annotation');
|
||||
annotation.setAttribute('encoding', 'application/x-tex');
|
||||
annotation.textContent = tex;
|
||||
const mrow = document.createElementNS(mathns, 'mrow');
|
||||
semantics.append(mrow, annotation);
|
||||
math.append(semantics);
|
||||
// make an AJAX request to the server, to get the MathML
|
||||
$.post(ajaxEndpoint, {tex, display: 'inline'}, function(data){
|
||||
const children = data.documentElement.childNodes;
|
||||
while (children.length > 0) {
|
||||
mrow.append(svgdoc.adoptNode(children[0], true));
|
||||
}
|
||||
svgCanvas.sanitizeSvg(math);
|
||||
svgCanvas.call('changed', [elt]);
|
||||
});
|
||||
elt.firstChild.replaceWith(math);
|
||||
svgCanvas.call('changed', [elt]);
|
||||
svgCanvas.clearSelection();
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
const buttons = [{
|
||||
const events = {
|
||||
id: 'tool_polygon',
|
||||
icon: 'polygon.png',
|
||||
type: 'mode',
|
||||
position: 11,
|
||||
events: {
|
||||
click () {
|
||||
svgCanvas.setMode('polygon');
|
||||
showPanel(true);
|
||||
}
|
||||
click () {
|
||||
svgCanvas.setMode('polygon');
|
||||
showPanel(true);
|
||||
}
|
||||
}];
|
||||
};
|
||||
const contextTools = [{
|
||||
type: 'input',
|
||||
panel: 'polygon_panel',
|
||||
|
@ -164,11 +106,8 @@ export default {
|
|||
}
|
||||
}];
|
||||
return {
|
||||
newUI: true,
|
||||
name: strings.name,
|
||||
buttons: strings.buttons.map((button, i) => {
|
||||
return Object.assign(buttons[i], button);
|
||||
}),
|
||||
events,
|
||||
context_tools: strings.contextTools.map((contextTool, i) => {
|
||||
return Object.assign(contextTools[i], contextTool);
|
||||
}),
|
||||
|
|
|
@ -7,23 +7,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
const loadExtensionTranslation = async function (lang) {
|
||||
let translationModule;
|
||||
try {
|
||||
translationModule = await import(`./locale/${encodeURIComponent(lang)}.js`);
|
||||
} catch (_error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(`Missing translation (${lang}) - using 'en'`);
|
||||
translationModule = await import(`./locale/en.js`);
|
||||
}
|
||||
return translationModule.default;
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'shapes',
|
||||
async init ({$}) {
|
||||
init ({$}) {
|
||||
const svgEditor = this;
|
||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
||||
const canv = svgEditor.canvas;
|
||||
const svgroot = canv.getRootElem();
|
||||
let lastBBox = {};
|
||||
|
@ -35,21 +22,15 @@ export default {
|
|||
let startX;
|
||||
let startY;
|
||||
|
||||
const buttons = [{
|
||||
id: 'tool_shapelib_show',
|
||||
type: 'mode_flyout',
|
||||
events: {
|
||||
click () {
|
||||
canv.setMode(modeId);
|
||||
}
|
||||
const events = {
|
||||
id: 'tool_shapelib',
|
||||
click () {
|
||||
canv.setMode(modeId);
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
return {
|
||||
newUI: true,
|
||||
buttons: strings.buttons.map((button, i) => {
|
||||
return Object.assign(buttons[i], button);
|
||||
}),
|
||||
events,
|
||||
callback () {
|
||||
// should later register the event
|
||||
},
|
||||
|
@ -57,7 +38,7 @@ export default {
|
|||
const mode = canv.getMode();
|
||||
if (mode !== modeId) { return undefined; }
|
||||
|
||||
const currentD = document.getElementById('tool_shapelib_show').dataset.draw;
|
||||
const currentD = document.getElementById('tool_shapelib').dataset.draw;
|
||||
startX = opts.start_x;
|
||||
const x = startX;
|
||||
startY = opts.start_y;
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.7 KiB |
|
@ -1,13 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<!--
|
||||
Sample icons file. This file looks like an SVG file with groups as its
|
||||
children. Each group element has an ID that must match the ID of the button given
|
||||
in the extension. The SVG inside the group makes up the actual icon, and
|
||||
needs use a viewBox instead of width/height for it to scale properly.
|
||||
|
||||
Multiple icons can be included, each within their own group.
|
||||
-->
|
||||
<g id="view_grid">
|
||||
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<g>
|
||||
<rect fill="#ffffff" stroke="#848484" x="2" y="2" width="20" height="20"/>
|
||||
|
@ -25,6 +15,4 @@
|
|||
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="10.0625" y="16.59375" width="4" height="4"/>
|
||||
<rect fill="#d8d8d8" stroke="#000000" stroke-width="0" x="16.8125" y="16.59375" width="4" height="4"/>
|
||||
</g>
|
||||
</svg>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.6 KiB |
|
@ -96,6 +96,7 @@
|
|||
<div class="tool_sep"></div>
|
||||
<se-button id="tool_source" title="Edit Source" shortcut="U" src="./images/source.svg"></se-button>
|
||||
<se-button id="tool_wireframe" title="Wireframe Mode" shortcut="F" src="./images/wireframe.svg"></se-button>
|
||||
<se-button id="view_grid" title="Show grid" src="./images/grid.svg"></se-button>
|
||||
</div> <!-- editor_panel -->
|
||||
<div id="history_panel">
|
||||
<div class="tool_sep"></div>
|
||||
|
@ -299,7 +300,7 @@
|
|||
<div id="tools_left">
|
||||
<se-button id="tool_select" title="Select Tool" src="./images/select.svg"></se-button>
|
||||
<se-button id="tool_fhpath" title="Pencil Tool" src="./images/pencil.svg" shortcut="Q"></se-button>
|
||||
<se-flyingbutton id="tools_line_show" title="Line Tool (L)/Connect two objects">
|
||||
<se-flyingbutton id="tools_line" title="Line Tool (L)/Connect two objects">
|
||||
<se-button id="tool_line" title="Line Tool" src="./images/pen.svg" shortcut="L"></se-button>
|
||||
<se-button id="mode_connect" title="Connect two objects" src="./images/conn.svg"></se-button>
|
||||
</se-flyingbutton>
|
||||
|
@ -308,13 +309,13 @@
|
|||
<se-button id="tool_square" title="Square" src="./images/square.svg"></se-button>
|
||||
<se-button id="tool_fhrect" title="Free-Hand Rectangle" src="./images/fh_rect.svg"></se-button>
|
||||
</se-flyingbutton>
|
||||
<se-flyingbutton id="tools_ellipse_show" title="Ellipse/Circle Tool">
|
||||
<se-flyingbutton id="tools_ellipse" title="Ellipse/Circle Tool">
|
||||
<se-button id="tool_ellipse" title="Rectangle" src="./images/ellipse.svg" shortcut="E"></se-button>
|
||||
<se-button id="tool_circle" title="Square" src="./images/circle.svg"></se-button>
|
||||
<se-button id="tool_fhellipse" title="Free-Hand Rectangle" src="./images/fh_ellipse.svg"></se-button>
|
||||
</se-flyingbutton>
|
||||
<se-button id="tool_path" title="Path Tool" src="./images/path.svg" shortcut="P"></se-button>
|
||||
<se-explorerbutton id="tool_shapelib_show" title="Shape library" lib="./extensions/ext-shapes/shapelib/"
|
||||
<se-explorerbutton id="tool_shapelib" title="Shape library" lib="./extensions/ext-shapes/shapelib/"
|
||||
src="./images/shapelib.svg"></se-explorerbutton>
|
||||
<se-button id="tool_text" title="Text Tool" src="./images/text.svg" shortcut="T"></se-button>
|
||||
<se-button id="tool_image" title="Image Tool" src="./images/image.svg"></se-button>
|
||||
|
|
|
@ -535,7 +535,7 @@ div.toolset label span {
|
|||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#tools_top input {
|
||||
#tools_top se-input, se-spin-input {
|
||||
margin-top: 5px;
|
||||
height: 15px;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import deparam from 'deparam';
|
|||
|
||||
import './touch.js';
|
||||
import {NS} from '../common/namespaces.js';
|
||||
import {isWebkit, isChrome, isGecko, isIE, isMac, isTouch} from '../common/browser.js';
|
||||
import {isChrome, isGecko, isIE, isMac, isTouch} from '../common/browser.js';
|
||||
|
||||
// Until we split this into smaller files, this helps distinguish utilities
|
||||
// from local methods
|
||||
|
@ -34,7 +34,6 @@ import SvgCanvas from '../svgcanvas/svgcanvas.js';
|
|||
import Layer from '../common/layer.js';
|
||||
|
||||
import jQueryPluginJSHotkeys from './js-hotkeys/jquery.hotkeys.min.js';
|
||||
import jQueryPluginSVGIcons from './svgicons/jQuery.svgIcons.js';
|
||||
import jQueryPluginJGraduate from './jgraduate/jQuery.jGraduate.js';
|
||||
import jQueryPluginContextMenu from './contextmenu/jQuery.contextMenu.js';
|
||||
import jQueryPluginJPicker from './jgraduate/jQuery.jPicker.js';
|
||||
|
@ -50,7 +49,7 @@ const {$q, $qq, $id} = Utils;
|
|||
const editor = {};
|
||||
|
||||
const $ = [
|
||||
jQueryPluginJSHotkeys, jQueryPluginSVGIcons, jQueryPluginJGraduate,
|
||||
jQueryPluginJSHotkeys, jQueryPluginJGraduate,
|
||||
jQueryPluginContextMenu, jQueryPluginJPicker
|
||||
].reduce((jq, func) => func(jq), jQuery);
|
||||
|
||||
|
@ -731,24 +730,6 @@ editor.init = () => {
|
|||
})();
|
||||
setupCurPrefs();
|
||||
|
||||
/**
|
||||
* Called internally.
|
||||
* @function module:SVGEditor.setIcon
|
||||
* @param {string|Element|external:jQuery} elem
|
||||
* @param {string|external:jQuery} iconId
|
||||
* @param {Float} forcedSize Not in use
|
||||
* @returns {void}
|
||||
*/
|
||||
const setIcon = editor.setIcon = function (elem, iconId, forcedSize) {
|
||||
const icon = (typeof iconId === 'string') ? $.getSvgIcon(iconId, true) : iconId.clone();
|
||||
if (!icon) {
|
||||
// Todo: Investigate why this still occurs in some cases
|
||||
console.log('NOTE: Icon image missing: ' + iconId); // eslint-disable-line no-console
|
||||
return;
|
||||
}
|
||||
$(elem).empty().append(icon);
|
||||
};
|
||||
|
||||
/**
|
||||
* @fires module:svgcanvas.SvgCanvas#event:ext_addLangData
|
||||
* @fires module:svgcanvas.SvgCanvas#event:ext_langReady
|
||||
|
@ -847,8 +828,6 @@ editor.init = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const stateObj = {tool_scale: editor.tool_scale};
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
|
@ -869,87 +848,6 @@ editor.init = () => {
|
|||
return '';
|
||||
}());
|
||||
|
||||
/**
|
||||
* Called internally.
|
||||
* @function module:SVGEditor.setIconSize
|
||||
* @param {module:SVGEditor.IconSize} size
|
||||
* @returns {void}
|
||||
*/
|
||||
const setIconSize = editor.setIconSize = function (size) {
|
||||
const selToscale = '#tools_top .toolset, #editor_panel > *, #history_panel > *,' +
|
||||
' #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,' +
|
||||
' #g_panel > *, #tool_font_size > *';
|
||||
|
||||
const elems = $(selToscale);
|
||||
|
||||
let scale = 1;
|
||||
if (typeof size === 'number') {
|
||||
scale = size;
|
||||
} else {
|
||||
const iconSizes = {s: 0.75, m: 1, l: 1.25, xl: 1.5};
|
||||
scale = iconSizes[size];
|
||||
}
|
||||
|
||||
stateObj.tool_scale = editor.tool_scale = scale;
|
||||
|
||||
const hiddenPs = elems.parents(':hidden');
|
||||
hiddenPs.css('visibility', 'hidden').show();
|
||||
hiddenPs.css('visibility', 'visible').hide();
|
||||
// return;
|
||||
|
||||
editor.pref('iconsize', size);
|
||||
const $editDialog = document.getElementById('se-edit-prefs');
|
||||
$editDialog.setAttribute('iconsize', size);
|
||||
|
||||
// Note that all rules will be prefixed with '#svg_editor' when parsed
|
||||
const cssResizeRules = {
|
||||
'#tools_top': {
|
||||
left: 50 + $('#main_button').width(),
|
||||
height: 72
|
||||
},
|
||||
'#tools_left': {
|
||||
width: 31,
|
||||
top: 74
|
||||
},
|
||||
'div#workarea': {
|
||||
left: 38,
|
||||
top: 74
|
||||
}
|
||||
};
|
||||
|
||||
let ruleElem = $('#tool_size_rules');
|
||||
if (!ruleElem.length) {
|
||||
ruleElem = $('<style id="tool_size_rules"></style>').appendTo('head');
|
||||
} else {
|
||||
ruleElem.empty();
|
||||
}
|
||||
|
||||
if (size !== 'm') {
|
||||
let styleStr = '';
|
||||
$.each(cssResizeRules, function (selector, rules) {
|
||||
selector = '#svg_editor ' + selector.replace(/,/g, ', #svg_editor');
|
||||
styleStr += selector + '{';
|
||||
$.each(rules, function (prop, values) {
|
||||
let val;
|
||||
if (typeof values === 'number') {
|
||||
val = (values * scale) + 'px';
|
||||
} else if (values[size] || values.all) {
|
||||
val = (values[size] || values.all);
|
||||
}
|
||||
styleStr += (prop + ':' + val + ';');
|
||||
});
|
||||
styleStr += '}';
|
||||
});
|
||||
// this.style[uaPrefix + 'Transform'] = 'scale(' + scale + ')';
|
||||
const prefix = '-' + uaPrefix.toLowerCase() + '-';
|
||||
styleStr += (selToscale + '{' + prefix + 'transform: scale(' + scale + ');}' +
|
||||
' #svg_editor div.toolset .toolset {' + prefix + 'transform: scale(1); margin: 1px !important;}' + // Hack for markers
|
||||
' #svg_editor .ui-slider {' + prefix + 'transform: scale(' + (1 / scale) + ');}' // Hack for sliders
|
||||
);
|
||||
ruleElem.text(styleStr);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @name module:SVGEditor.canvas
|
||||
* @type {module:svgcanvas.SvgCanvas}
|
||||
|
@ -966,7 +864,6 @@ editor.init = () => {
|
|||
const canvMenu = $('#cmenu_canvas');
|
||||
const paintBox = {fill: null, stroke: null};
|
||||
|
||||
let resizeTimer;
|
||||
let exportWindow = null,
|
||||
defaultImageURL = curConfig.imgPath + 'logo.svg',
|
||||
zoomInIcon = 'crosshair',
|
||||
|
@ -1045,7 +942,6 @@ editor.init = () => {
|
|||
const selLayerNames = $('#selLayerNames').empty();
|
||||
const drawing = svgCanvas.getCurrentDrawing();
|
||||
const currentLayerName = drawing.getCurrentLayerName();
|
||||
const icon = $.getSvgIcon('eye');
|
||||
let layer = svgCanvas.getCurrentDrawing().getNumLayers();
|
||||
// we get the layers in the reverse z-order (the layer rendered on top is listed first)
|
||||
while (layer--) {
|
||||
|
@ -1056,11 +952,6 @@ editor.init = () => {
|
|||
layerlist.append(layerTr.append(layerVis, layerName));
|
||||
selLayerNames.append('<option value="' + name + '">' + name + '</option>');
|
||||
}
|
||||
if (icon !== undefined) {
|
||||
const copy = icon.clone();
|
||||
$('td.layervis', layerlist).append(copy);
|
||||
$.resizeSvgIcons({'td.layervis .svg_icon': 14});
|
||||
}
|
||||
// handle selection of layer
|
||||
$('#layerlist td.layername')
|
||||
.mouseup(function (evt) {
|
||||
|
@ -1240,7 +1131,6 @@ editor.init = () => {
|
|||
if (changeElem) {
|
||||
svgCanvas.setStrokeAttr('stroke-' + pre, val);
|
||||
}
|
||||
setIcon('#cur_' + pre, id, 20);
|
||||
$(opt).addClass('current').siblings().removeClass('current');
|
||||
}
|
||||
|
||||
|
@ -1585,38 +1475,40 @@ editor.init = () => {
|
|||
* @fires module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate
|
||||
* @returns {void}
|
||||
*/
|
||||
const updateToolButtonState = function () {
|
||||
const updateToolButtonState = () => {
|
||||
const bNoFill = (svgCanvas.getColor('fill') === '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'
|
||||
'tools_rect', 'tools_ellipse',
|
||||
'tool_text', 'tool_path'
|
||||
];
|
||||
|
||||
if (bNoStroke) {
|
||||
buttonsNeedingStroke.forEach((btn) => {
|
||||
if ($(btn).hasClass('tool_button_current')) {
|
||||
// if btn is pressed, change to select button
|
||||
if ($id(btn).pressed) {
|
||||
clickSelect();
|
||||
}
|
||||
$(btn).addClass('disabled');
|
||||
$(btn).disabled = true;
|
||||
});
|
||||
} else {
|
||||
buttonsNeedingStroke.forEach((btn) => {
|
||||
$(btn).removeClass('disabled');
|
||||
$id(btn).disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
if (bNoStroke && bNoFill) {
|
||||
buttonsNeedingFillAndStroke.forEach((btn) => {
|
||||
if ($(btn).hasClass('tool_button_current')) {
|
||||
// if btn is pressed, change to select button
|
||||
if ($id(btn).pressed) {
|
||||
clickSelect();
|
||||
}
|
||||
$(btn).addClass('disabled');
|
||||
$(btn).disabled = true;
|
||||
});
|
||||
} else {
|
||||
buttonsNeedingFillAndStroke.forEach((btn) => {
|
||||
$(btn).removeClass('disabled');
|
||||
$id(btn).disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1771,17 +1663,16 @@ editor.init = () => {
|
|||
}
|
||||
|
||||
// Elements in this array cannot be converted to a path
|
||||
const noPath = !['image', 'text', 'path', 'g', 'use'].includes(elname);
|
||||
$('#tool_topath').toggle(noPath);
|
||||
$('#tool_reorient').toggle(elname === 'path');
|
||||
$('#tool_reorient').toggleClass('disabled', angle === 0);
|
||||
$id('tool_topath').style.display = ['image', 'text', 'path', 'g', 'use'].includes(elname) ? 'none' : 'block';
|
||||
$id('tool_reorient').style.display = (elname === 'path') ? 'block' : 'none';
|
||||
$id('tool_reorient').disabled = (angle === 0);
|
||||
} else {
|
||||
const point = path.getNodePoint();
|
||||
$('#tool_add_subpath').pressed = false;
|
||||
$('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes);
|
||||
|
||||
// Show open/close button based on selected point
|
||||
setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path');
|
||||
// setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path');
|
||||
|
||||
if (point) {
|
||||
const segType = $('#seg_type');
|
||||
|
@ -2222,75 +2113,6 @@ editor.init = () => {
|
|||
paintBox.stroke.prep();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} elemSel
|
||||
* @param {string} listSel
|
||||
* @param {external:jQuery.Function} callback
|
||||
* @param {PlainObject} opts
|
||||
* @param {boolean} opts.dropUp
|
||||
* @param {boolean} opts.seticon
|
||||
* @param {boolean} opts.multiclick
|
||||
* @todo Combine this with `addDropDown` or find other way to optimize.
|
||||
* @returns {void}
|
||||
*/
|
||||
const addAltDropDown = function (elemSel, listSel, callback, opts) {
|
||||
const button = $(elemSel);
|
||||
const {dropUp} = opts;
|
||||
const list = $(listSel);
|
||||
if (dropUp) {
|
||||
$(elemSel).addClass('dropup');
|
||||
}
|
||||
list.find('li').bind('mouseup', function (...args) {
|
||||
if (opts.seticon) {
|
||||
setIcon('#cur_' + button[0].id, $(this).children());
|
||||
$(this).addClass('current').siblings().removeClass('current');
|
||||
}
|
||||
callback.apply(this, ...args);
|
||||
});
|
||||
|
||||
let onButton = false;
|
||||
$(window).mouseup(function (evt) {
|
||||
if (!onButton) {
|
||||
button.removeClass('down');
|
||||
list.hide();
|
||||
list.css({top: 0, left: 0});
|
||||
}
|
||||
onButton = false;
|
||||
});
|
||||
|
||||
// const height = list.height(); // Currently unused
|
||||
button.bind('mousedown', function () {
|
||||
const off = button.offset();
|
||||
if (dropUp) {
|
||||
off.top -= list.height();
|
||||
off.left += 8;
|
||||
} else {
|
||||
off.top += button.height();
|
||||
}
|
||||
list.offset(off);
|
||||
|
||||
if (!button.hasClass('down')) {
|
||||
list.show();
|
||||
onButton = true;
|
||||
} else {
|
||||
// CSS position must be reset for Webkit
|
||||
list.hide();
|
||||
list.css({top: 0, left: 0});
|
||||
}
|
||||
button.toggleClass('down');
|
||||
}).hover(function () {
|
||||
onButton = true;
|
||||
}).mouseout(function () {
|
||||
onButton = false;
|
||||
});
|
||||
|
||||
if (opts.multiclick) {
|
||||
list.mousedown(function () {
|
||||
onButton = true;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {external:Window} win
|
||||
* @param {module:svgcanvas.SvgCanvas#event:extension_added} ext
|
||||
|
@ -2302,7 +2124,6 @@ editor.init = () => {
|
|||
return undefined;
|
||||
}
|
||||
let cbCalled = false;
|
||||
let resizeDone = false;
|
||||
|
||||
if (ext.langReady) {
|
||||
if (editor.langChanged) { // We check for this since the "lang" pref could have been set by storage
|
||||
|
@ -2310,23 +2131,6 @@ editor.init = () => {
|
|||
await ext.langReady({lang});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Clear resize timer if present and if not previously performed,
|
||||
* perform an icon resize.
|
||||
* @returns {void}
|
||||
*/
|
||||
function prepResize () {
|
||||
if (resizeTimer) {
|
||||
clearTimeout(resizeTimer);
|
||||
resizeTimer = null;
|
||||
}
|
||||
if (!resizeDone) {
|
||||
resizeTimer = setTimeout(function () {
|
||||
resizeDone = true;
|
||||
setIconSize(editor.pref('iconsize'));
|
||||
}, 50);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -2339,8 +2143,6 @@ editor.init = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const btnSelects = [];
|
||||
|
||||
/**
|
||||
* @typedef {PlainObject} module:SVGEditor.ContextTool
|
||||
* @property {string} panel The ID of the existing panel to which the tool is being added. Required.
|
||||
|
@ -2405,15 +2207,6 @@ editor.init = () => {
|
|||
|
||||
// Creates the tool, hides & adds it, returns the select element
|
||||
/* const dropdown = */ $(html).appendTo(panel).children();
|
||||
|
||||
btnSelects.push({
|
||||
elem: ('#' + tool.id),
|
||||
list: ('#' + tool.id + '_opts'),
|
||||
title: tool.title,
|
||||
callback: tool.events.change,
|
||||
cur: ('#cur_' + tool.id)
|
||||
});
|
||||
|
||||
break;
|
||||
} case 'input': {
|
||||
html = '<label' + contId + '>' +
|
||||
|
@ -2440,184 +2233,10 @@ editor.init = () => {
|
|||
});
|
||||
}
|
||||
|
||||
const {svgicons} = ext;
|
||||
if (ext.buttons && !ext.newUI) {
|
||||
const fallbackObj = {},
|
||||
altsObj = {},
|
||||
placementObj = {};
|
||||
|
||||
/**
|
||||
* @typedef {GenericArray} module:SVGEditor.KeyArray
|
||||
* @property {string} 0 The key to bind (on `keydown`)
|
||||
* @property {boolean} 1 Whether to `preventDefault` on the `keydown` event
|
||||
* @property {boolean} 2 Not apparently in use (NoDisableInInput)
|
||||
*/
|
||||
/**
|
||||
* @typedef {string|module:SVGEditor.KeyArray} module:SVGEditor.Key
|
||||
*/
|
||||
/**
|
||||
* @typedef {PlainObject} module:SVGEditor.Button
|
||||
* @property {string} id A unique identifier for this button. If SVG icons are used, this must match the ID used in the icon file. Required.
|
||||
* @property {"mode_flyout"|"mode"|"context"|"app_menu"} type Type of button. Required.
|
||||
* @property {string} title The tooltip text that will appear when the user hovers over the icon. Required.
|
||||
* @property {PlainObject<string, external:jQuery.Function>|PlainObject<"click", external:jQuery.Function>} events DOM event names with associated functions. Example: `{click () { alert('Button was clicked') } }`. Click is used with `includeWith` and `type` of "mode_flyout" (and "mode"); any events may be added if `list` is not present. Expected.
|
||||
* @property {string} panel The ID of the context panel to be included, if type is "context". Required only if type is "context".
|
||||
* @property {string} icon The file path to the raster version of the icon image source. Required only if no `svgicons` is supplied from [ExtensionInitResponse]{@link module:svgcanvas.ExtensionInitResponse}.
|
||||
* @property {string} [svgicon] If absent, will utilize the button "id"; used to set "placement" on the `svgIcons` call
|
||||
* @property {string} [list] Points to the "id" of a `context_tools` item of type "button-select" into which the button will be added as a panel list item
|
||||
* @property {Integer} [position] The numeric index for placement; defaults to last position (as of the time of extension addition) if not present. For use with {@link http://api.jquery.com/eq/}.
|
||||
* @property {boolean} [isDefault] Whether or not the button is the default. Used with `list`.
|
||||
* @property {module:SVGEditor.Key} [key] The key to bind to the button
|
||||
*/
|
||||
// Add buttons given by extension
|
||||
$.each(ext.buttons, function (i, /** @type {module:SVGEditor.Button} */ btn) {
|
||||
let {id} = btn;
|
||||
let num = i;
|
||||
// Give button a unique ID
|
||||
while ($('#' + id).length) {
|
||||
id = btn.id + '_' + (++num);
|
||||
}
|
||||
|
||||
let icon;
|
||||
if (!svgicons) {
|
||||
icon = $(
|
||||
'<img src="' + btn.icon +
|
||||
(btn.title ? '" alt="' + btn.title : '') +
|
||||
'">'
|
||||
);
|
||||
} else {
|
||||
fallbackObj[id] = btn.icon;
|
||||
altsObj[id] = btn.title;
|
||||
const svgicon = btn.svgicon || btn.id;
|
||||
if (btn.type === 'app_menu') {
|
||||
placementObj['#' + id + ' > div'] = svgicon;
|
||||
} else {
|
||||
placementObj['#' + id] = svgicon;
|
||||
}
|
||||
}
|
||||
|
||||
let cls, parent;
|
||||
|
||||
// Set button up according to its type
|
||||
switch (btn.type) {
|
||||
case 'mode_flyout':
|
||||
case 'mode':
|
||||
cls = 'tool_button';
|
||||
parent = '#tools_left';
|
||||
break;
|
||||
case 'context':
|
||||
cls = 'tool_button';
|
||||
parent = '#' + btn.panel;
|
||||
// create the panel if it doesn't exist
|
||||
if (!$(parent).length) {
|
||||
$('<div>', {id: btn.panel}).appendTo('#tools_top');
|
||||
}
|
||||
break;
|
||||
case 'app_menu':
|
||||
cls = '';
|
||||
parent = '#main_menu ul';
|
||||
break;
|
||||
}
|
||||
|
||||
const button = $((btn.list || btn.type === 'app_menu') ? '<li/>' : '<div/>')
|
||||
.attr('id', id)
|
||||
.attr('title', btn.title)
|
||||
.addClass(cls);
|
||||
if (!btn.includeWith && !btn.list) {
|
||||
if ('position' in btn) {
|
||||
if ($(parent).children().eq(btn.position).length) {
|
||||
$(parent).children().eq(btn.position).before(button);
|
||||
} else {
|
||||
$(parent).children().last().after(button);
|
||||
}
|
||||
} else {
|
||||
button.appendTo(parent);
|
||||
}
|
||||
|
||||
if (btn.type === 'app_menu') {
|
||||
button.append('<div>').append(btn.title);
|
||||
}
|
||||
} else if (btn.list) {
|
||||
// Add button to list
|
||||
button.addClass('push_button');
|
||||
$('#' + btn.list + '_opts').append(button);
|
||||
if (btn.isDefault) {
|
||||
$('#cur_' + btn.list).append(button.children().clone());
|
||||
const svgicon = btn.svgicon || btn.id;
|
||||
placementObj['#cur_' + btn.list] = svgicon;
|
||||
}
|
||||
}
|
||||
if (!svgicons) {
|
||||
button.append(icon);
|
||||
}
|
||||
|
||||
if (!btn.list) {
|
||||
// Add given events to button
|
||||
$.each(btn.events, function (name, func) {
|
||||
if (name === 'click' && btn.type === 'mode') {
|
||||
// `touch.js` changes `touchstart` to `mousedown`,
|
||||
// so we must map extension click events as well
|
||||
if (isTouch() && name === 'click') {
|
||||
name = 'mousedown';
|
||||
}
|
||||
if (btn.includeWith) {
|
||||
button.bind(name, func);
|
||||
} else {
|
||||
button.bind(name, function () {
|
||||
if (updateLeftPanel(button)) {
|
||||
func();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (btn.key) {
|
||||
$(document).bind('keydown', btn.key, func);
|
||||
if (btn.title) {
|
||||
button.attr('title', btn.title + ' [' + btn.key + ']');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
button.bind(name, func);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
$.each(btnSelects, function () {
|
||||
addAltDropDown(this.elem, this.list, this.callback, {seticon: true});
|
||||
});
|
||||
|
||||
if (svgicons) {
|
||||
return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new
|
||||
$.svgIcons(`${curConfig.imgPath}${svgicons}`, {
|
||||
w: 24, h: 24,
|
||||
id_match: false,
|
||||
no_img: (!isWebkit()),
|
||||
fallback: fallbackObj,
|
||||
placement: placementObj,
|
||||
callback (icons) {
|
||||
// Non-ideal hack to make the icon match the current size
|
||||
// if (curPrefs.iconsize && curPrefs.iconsize !== 'm') {
|
||||
if (editor.pref('iconsize') !== 'm') {
|
||||
prepResize();
|
||||
}
|
||||
runCallback();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
if (ext.buttons && ext.newUI) {
|
||||
ext.buttons.forEach((btn) => {
|
||||
// Set button up according to its type
|
||||
switch (btn.type) {
|
||||
case 'mode_flyout':
|
||||
case 'mode':
|
||||
$id(btn.id).addEventListener('click', () => {
|
||||
if (updateLeftPanel(btn.id)) {
|
||||
btn.events.click();
|
||||
}
|
||||
});
|
||||
break;
|
||||
if (ext.events) {
|
||||
$id(ext.events.id).addEventListener('click', () => {
|
||||
if (updateLeftPanel(ext.events.id)) {
|
||||
ext.events.click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -3117,6 +2736,7 @@ editor.init = () => {
|
|||
}
|
||||
});
|
||||
|
||||
/*
|
||||
addAltDropDown('#stroke_linecap', '#linecap_opts', function () {
|
||||
setStrokeOpt(this, true);
|
||||
}, {dropUp: true});
|
||||
|
@ -3129,6 +2749,7 @@ editor.init = () => {
|
|||
const letter = this.id.replace('tool_pos', '').charAt(0);
|
||||
svgCanvas.alignSelectedElements(letter, 'page');
|
||||
}, {multiclick: true});
|
||||
*/
|
||||
|
||||
// Unfocus text input when workarea is mousedowned.
|
||||
(function () {
|
||||
|
@ -3261,8 +2882,8 @@ editor.init = () => {
|
|||
* @returns {void}
|
||||
*/
|
||||
const zoomImage = function (multiplier) {
|
||||
const res = svgCanvas.getResolution();
|
||||
multiplier = multiplier ? res.zoom * multiplier : 1;
|
||||
const resolution = svgCanvas.getResolution();
|
||||
multiplier = multiplier ? resolution.zoom * multiplier : 1;
|
||||
// setResolution(res.w * multiplier, res.h * multiplier, true);
|
||||
$id('zoom').value = (multiplier * 100).toFixed(1);
|
||||
svgCanvas.setZoom(multiplier);
|
||||
|
@ -3735,11 +3356,6 @@ editor.init = () => {
|
|||
updateToolButtonState();
|
||||
};
|
||||
|
||||
/* $('#svg_prefs_container').draggable({
|
||||
cancel: 'button,fieldset',
|
||||
containment: 'window'
|
||||
}).css('position', 'absolute'); */
|
||||
|
||||
let docprops = false;
|
||||
let preferences = false;
|
||||
|
||||
|
@ -3753,14 +3369,14 @@ editor.init = () => {
|
|||
const $imgDialog = document.getElementById('se-img-prop');
|
||||
|
||||
// update resolution option with actual resolution
|
||||
const res = svgCanvas.getResolution();
|
||||
const resolution = svgCanvas.getResolution();
|
||||
if (curConfig.baseUnit !== 'px') {
|
||||
res.w = convertUnit(res.w) + curConfig.baseUnit;
|
||||
res.h = convertUnit(res.h) + curConfig.baseUnit;
|
||||
resolution.w = convertUnit(resolution.w) + curConfig.baseUnit;
|
||||
resolution.h = convertUnit(resolution.h) + curConfig.baseUnit;
|
||||
}
|
||||
$imgDialog.setAttribute('save', editor.pref('img_save'));
|
||||
$imgDialog.setAttribute('width', res.w);
|
||||
$imgDialog.setAttribute('height', res.h);
|
||||
$imgDialog.setAttribute('width', resolution.w);
|
||||
$imgDialog.setAttribute('height', resolution.h);
|
||||
$imgDialog.setAttribute('title', svgCanvas.getDocumentTitle());
|
||||
$imgDialog.setAttribute('dialog', 'open');
|
||||
};
|
||||
|
@ -3855,7 +3471,7 @@ editor.init = () => {
|
|||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Event} e
|
||||
* @returns {boolean} Whether there were problems saving the document properties
|
||||
*/
|
||||
const saveDocProperties = function (e) {
|
||||
|
@ -3885,11 +3501,12 @@ editor.init = () => {
|
|||
|
||||
/**
|
||||
* Save user preferences based on current values in the UI.
|
||||
* @param {Event} e
|
||||
* @function module:SVGEditor.savePreferences
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const savePreferences = editor.savePreferences = async function (e) {
|
||||
const {lang, iconsize, bgcolor, bgurl, gridsnappingon, gridsnappingstep, gridcolor, showrulers, baseunit} = e.detail;
|
||||
const {lang, bgcolor, bgurl, gridsnappingon, gridsnappingstep, gridcolor, showrulers, baseunit} = e.detail;
|
||||
// Set background
|
||||
setBackground(bgcolor, bgurl);
|
||||
|
||||
|
@ -3899,9 +3516,6 @@ editor.init = () => {
|
|||
await setLang(langParam, langData);
|
||||
}
|
||||
|
||||
// set icon size
|
||||
setIconSize(iconsize);
|
||||
|
||||
// set grid setting
|
||||
curConfig.gridSnapping = gridsnappingon;
|
||||
curConfig.snappingStep = gridsnappingstep;
|
||||
|
@ -4631,8 +4245,8 @@ editor.init = () => {
|
|||
|
||||
// Tooltips not directly associated with a single function
|
||||
const keyAssocs = {
|
||||
'4/Shift+4': '#tools_rect_show',
|
||||
'5/Shift+5': '#tools_ellipse_show'
|
||||
'4/Shift+4': '#tools_rect',
|
||||
'5/Shift+5': '#tools_ellipse'
|
||||
};
|
||||
|
||||
return {
|
||||
|
|
|
@ -1,544 +0,0 @@
|
|||
/**
|
||||
* @file SVG Icon Loader 2.0
|
||||
*
|
||||
* jQuery Plugin for loading SVG icons from a single file
|
||||
*
|
||||
* Adds {@link external:jQuery.svgIcons}, {@link external:jQuery.getSvgIcon}, {@link external:jQuery.resizeSvgIcons}
|
||||
*
|
||||
* How to use:
|
||||
|
||||
1. Create the SVG master file that includes all icons:
|
||||
|
||||
The master SVG icon-containing file is an SVG file that contains
|
||||
`<g>` elements. Each `<g>` element should contain the markup of an SVG
|
||||
icon. The `<g>` element has an ID that should
|
||||
correspond with the ID of the HTML element used on the page that should contain
|
||||
or optionally be replaced by the icon. Additionally, one empty element should be
|
||||
added at the end with id "svg_eof".
|
||||
|
||||
2. Optionally create fallback raster images for each SVG icon.
|
||||
|
||||
3. Include the jQuery and the SVG Icon Loader scripts on your page.
|
||||
|
||||
4. Run `$.svgIcons()` when the document is ready. See its signature
|
||||
|
||||
5. To access an icon at a later point without using the callback, use this:
|
||||
`$.getSvgIcon(id (string), uniqueClone (boolean))`;
|
||||
|
||||
This will return the icon (as jQuery object) with a given ID.
|
||||
|
||||
6. To resize icons at a later point without using the callback, use this:
|
||||
`$.resizeSvgIcons(resizeOptions)` (use the same way as the "resize" parameter)
|
||||
*
|
||||
* @module jQuerySVGIcons
|
||||
* @license MIT
|
||||
* @copyright (c) 2009 Alexis Deveria
|
||||
* {@link http://a.deveria.com}
|
||||
* @example
|
||||
$(function () {
|
||||
$.svgIcons('my_icon_set.svg'); // The SVG file that contains all icons
|
||||
// No options have been set, so all icons will automatically be inserted
|
||||
// into HTML elements that match the same IDs.
|
||||
});
|
||||
|
||||
* @example
|
||||
$(function () {
|
||||
// The SVG file that contains all icons
|
||||
$.svgIcons('my_icon_set.svg', {
|
||||
callback (icons) { // Custom callback function that sets click
|
||||
// events for each icon
|
||||
$.each(icons, function (id, icon) {
|
||||
icon.click(function () {
|
||||
alert('You clicked on the icon with id ' + id);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
* @example
|
||||
$(function () {
|
||||
// The SVGZ file that contains all icons
|
||||
$.svgIcons('my_icon_set.svgz', {
|
||||
w: 32, // All icons will be 32px wide
|
||||
h: 32, // All icons will be 32px high
|
||||
fallback_path: 'icons/', // All fallback files can be found here
|
||||
fallback: {
|
||||
'#open_icon': 'open.png', // The "open.png" will be appended to the
|
||||
// HTML element with ID "open_icon"
|
||||
'#close_icon': 'close.png',
|
||||
'#save_icon': 'save.png'
|
||||
},
|
||||
placement: {'.open_icon': 'open'}, // The "open" icon will be added
|
||||
// to all elements with class "open_icon"
|
||||
resize: {
|
||||
'#save_icon .svg_icon': 64 // The "save" icon will be resized to 64 x 64px
|
||||
},
|
||||
|
||||
callback (icons) { // Sets background color for "close" icon
|
||||
icons.close.css('background', 'red');
|
||||
},
|
||||
|
||||
svgz: true // Indicates that an SVGZ file is being used
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
// Todo: Move to own module (and have it import a modular base64 encoder)
|
||||
import {encode64} from '../../common/utilities.js';
|
||||
|
||||
const isOpera = Boolean(window.opera);
|
||||
|
||||
const fixIDs = function (svgEl, svgNum, force) {
|
||||
const defs = svgEl.find('defs');
|
||||
if (!defs.length) return svgEl;
|
||||
|
||||
const idElems = (isOpera)
|
||||
? defs.find('*').filter(function () {
|
||||
return Boolean(this.id);
|
||||
})
|
||||
: defs.find('[id]');
|
||||
|
||||
const allElems = svgEl[0].getElementsByTagName('*'),
|
||||
len = allElems.length;
|
||||
|
||||
idElems.each(function (i) {
|
||||
const {id} = this;
|
||||
/*
|
||||
const noDupes = ($(svgdoc).find('#' + id).length <= 1);
|
||||
if (isOpera) noDupes = false; // Opera didn't clone svgEl, so not reliable
|
||||
if(!force && noDupes) return;
|
||||
*/
|
||||
const newId = 'x' + id + svgNum + i;
|
||||
this.id = newId;
|
||||
|
||||
const oldVal = 'url(#' + id + ')';
|
||||
const newVal = 'url(#' + newId + ')';
|
||||
|
||||
// Selector method, possibly faster but fails in Opera / jQuery 1.4.3
|
||||
// svgEl.find('[fill="url(#' + id + ')"]').each(function() {
|
||||
// this.setAttribute('fill', 'url(#' + newId + ')');
|
||||
// }).end().find('[stroke="url(#' + id + ')"]').each(function() {
|
||||
// this.setAttribute('stroke', 'url(#' + newId + ')');
|
||||
// }).end().find('use').each(function() {
|
||||
// if(this.getAttribute('xlink:href') == '#' + id) {
|
||||
// this.setAttributeNS(xlinkns,'href','#' + newId);
|
||||
// }
|
||||
// }).end().find('[filter="url(#' + id + ')"]').each(function() {
|
||||
// this.setAttribute('filter', 'url(#' + newId + ')');
|
||||
// });
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
const elem = allElems[i];
|
||||
if (elem.getAttribute('fill') === oldVal) {
|
||||
elem.setAttribute('fill', newVal);
|
||||
}
|
||||
if (elem.getAttribute('stroke') === oldVal) {
|
||||
elem.setAttribute('stroke', newVal);
|
||||
}
|
||||
if (elem.getAttribute('filter') === oldVal) {
|
||||
elem.setAttribute('filter', newVal);
|
||||
}
|
||||
}
|
||||
});
|
||||
return svgEl;
|
||||
};
|
||||
|
||||
/**
|
||||
* @callback module:jQuerySVGIcons.SVGIconsLoadedCallback
|
||||
* @param {PlainObject<string, external:jQuery>} svgIcons IDs keyed to jQuery objects of images
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @function module:jQuerySVGIcons.jQuerySVGIcons
|
||||
* @param {external:jQuery} $ Its keys include all icon IDs and the values, the icon as a jQuery object
|
||||
* @returns {external:jQuery} The enhanced jQuery object
|
||||
*/
|
||||
export default function jQueryPluginSVGIcons ($) {
|
||||
const svgIcons = {};
|
||||
|
||||
/**
|
||||
* Map of raster images with each key being the SVG icon ID
|
||||
* to replace, and the value the image file name.
|
||||
* @typedef {PlainObject<string, string>} external:jQuery.svgIcons.Fallback
|
||||
*/
|
||||
/**
|
||||
* 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
|
||||
* @param {string} file The location of a local SVG or SVGz file
|
||||
* @param {PlainObject} [opts]
|
||||
* @param {Float} [opts.w] The icon widths
|
||||
* @param {Float} [opts.h] The icon heights
|
||||
* @param {external:jQuery.svgIcons.Fallback} [opts.fallback]
|
||||
* @param {string} [opts.fallback_path] The path to use for all images
|
||||
* listed under "fallback"
|
||||
* @param {boolean} [opts.replace] If set to `true`, HTML elements will
|
||||
* be replaced by, rather than include the SVG icon.
|
||||
* @param {PlainObject<string, string>} [opts.placement] Map with selectors
|
||||
* for keys and SVG icon ids as values. This provides a custom method of
|
||||
* adding icons.
|
||||
* @param {PlainObject<string, module:jQuerySVGIcons.Size>} [opts.resize] Map
|
||||
* with selectors for keys and numbers as values. This allows an easy way to
|
||||
* resize specific icons.
|
||||
* @param {module:jQuerySVGIcons.SVGIconsLoadedCallback} [opts.callback] A
|
||||
* function to call when all icons have been loaded.
|
||||
* @param {boolean} [opts.id_match=true] Automatically attempt to match
|
||||
* SVG icon ids with corresponding HTML id
|
||||
* @param {boolean} [opts.no_img] Prevent attempting to convert the icon
|
||||
* 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 {void}
|
||||
*/
|
||||
$.svgIcons = function (file, opts = {}) {
|
||||
const svgns = 'http://www.w3.org/2000/svg',
|
||||
xlinkns = 'http://www.w3.org/1999/xlink',
|
||||
iconW = opts.w || 24,
|
||||
iconH = opts.h || 24;
|
||||
let elems, svgdoc, testImg,
|
||||
iconsMade = false,
|
||||
dataLoaded = false,
|
||||
loadAttempts = 0;
|
||||
const // ua = navigator.userAgent,
|
||||
// isSafari = (ua.includes('Safari/') && !ua.includes('Chrome/')),
|
||||
dataPre = 'data:image/svg+xml;charset=utf-8;base64,';
|
||||
|
||||
let dataEl;
|
||||
if (opts.svgz) {
|
||||
dataEl = $('<object data="' + file + '" type=image/svg+xml>').appendTo('body').hide();
|
||||
try {
|
||||
svgdoc = dataEl[0].contentDocument;
|
||||
dataEl.load(getIcons);
|
||||
getIcons(0, true); // Opera will not run "load" event if file is already cached
|
||||
} catch (err1) {
|
||||
useFallback();
|
||||
}
|
||||
} else {
|
||||
const parser = new DOMParser();
|
||||
$.ajax({
|
||||
url: file,
|
||||
dataType: 'string',
|
||||
success (data) {
|
||||
if (!data) {
|
||||
$(useFallback);
|
||||
return;
|
||||
}
|
||||
svgdoc = parser.parseFromString(data, 'text/xml');
|
||||
$(function () {
|
||||
getIcons('ajax');
|
||||
});
|
||||
},
|
||||
error (err) {
|
||||
// TODO: Fix Opera widget icon bug
|
||||
if (window.opera) {
|
||||
$(function () {
|
||||
useFallback();
|
||||
});
|
||||
} else if (err.responseText) {
|
||||
svgdoc = parser.parseFromString(err.responseText, 'text/xml');
|
||||
|
||||
if (!svgdoc.childNodes.length) {
|
||||
$(useFallback);
|
||||
}
|
||||
$(function () {
|
||||
getIcons('ajax');
|
||||
});
|
||||
} else {
|
||||
$(useFallback);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {"ajax"|0|void} evt
|
||||
* @param {boolean} [noWait]
|
||||
* @returns {void}
|
||||
*/
|
||||
function getIcons (evt, noWait) {
|
||||
if (evt !== 'ajax') {
|
||||
if (dataLoaded) return;
|
||||
// Webkit sometimes says svgdoc is undefined, other times
|
||||
// it fails to load all nodes. Thus we must make sure the "eof"
|
||||
// element is loaded.
|
||||
svgdoc = dataEl[0].contentDocument; // Needed again for Webkit
|
||||
const isReady = (svgdoc && svgdoc.getElementById('svg_eof'));
|
||||
if (!isReady && !(noWait && isReady)) {
|
||||
loadAttempts++;
|
||||
if (loadAttempts < 50) {
|
||||
setTimeout(getIcons, 20);
|
||||
} else {
|
||||
useFallback();
|
||||
dataLoaded = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
dataLoaded = true;
|
||||
}
|
||||
|
||||
elems = $(svgdoc.firstChild).children(); // .getElementsByTagName('foreignContent');
|
||||
|
||||
if (!opts.no_img) {
|
||||
const testSrc = dataPre +
|
||||
'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zd' +
|
||||
'mciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D';
|
||||
|
||||
testImg = $(new Image()).attr({
|
||||
src: testSrc,
|
||||
width: 0,
|
||||
height: 0,
|
||||
alt: opts.testIconAlt || 'icon'
|
||||
}).appendTo('body')
|
||||
.load(function () {
|
||||
// Safari 4 crashes, Opera and Chrome don't
|
||||
makeIcons(true);
|
||||
}).error(function () {
|
||||
makeIcons();
|
||||
});
|
||||
} else {
|
||||
setTimeout(function () {
|
||||
if (!iconsMade) makeIcons();
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {external:jQuery} target
|
||||
* @param {external:jQuery} icon A wrapped `defs` or Image
|
||||
* @param {string} id SVG icon ID
|
||||
* @param {boolean} setID Whether to set the ID attribute (with `id`)
|
||||
* @returns {void}
|
||||
*/
|
||||
function setIcon (target, icon, id, setID) {
|
||||
if (isOpera) icon.css('visibility', 'hidden');
|
||||
if (opts.replace) {
|
||||
if (setID) icon.attr('id', id);
|
||||
const cl = target.attr('class');
|
||||
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);
|
||||
} else {
|
||||
target.append(icon);
|
||||
}
|
||||
if (isOpera) {
|
||||
setTimeout(function () {
|
||||
icon.removeAttr('style');
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
|
||||
let holder;
|
||||
/**
|
||||
* @param {external:jQuery} icon A wrapped `defs` or Image
|
||||
* @param {string} id SVG icon ID
|
||||
* @returns {void}
|
||||
*/
|
||||
function addIcon (icon, id) {
|
||||
if (opts.id_match === undefined || opts.id_match !== false) {
|
||||
setIcon(holder, icon, id, true);
|
||||
}
|
||||
svgIcons[id] = icon;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {boolean} [toImage]
|
||||
* @param {external:jQuery.svgIcons.Fallback} [fallback=false]
|
||||
* @returns {void}
|
||||
*/
|
||||
function makeIcons (toImage = false, fallback = false) {
|
||||
if (iconsMade) return;
|
||||
if (opts.no_img) toImage = false;
|
||||
|
||||
let tempHolder;
|
||||
if (toImage) {
|
||||
tempHolder = $(document.createElement('div'));
|
||||
tempHolder.hide().appendTo('body');
|
||||
}
|
||||
if (fallback) {
|
||||
const path = opts.fallback_path || '';
|
||||
$.each(fallback, function (id, imgsrc) {
|
||||
holder = $('#' + id);
|
||||
let alt = 'icon';
|
||||
if (opts.alts) {
|
||||
alt = opts.alts[id] || alt;
|
||||
}
|
||||
const icon = $(new Image())
|
||||
.attr({
|
||||
class: 'svg_icon',
|
||||
src: path + imgsrc,
|
||||
width: iconW,
|
||||
height: iconH,
|
||||
alt
|
||||
});
|
||||
|
||||
addIcon(icon, id);
|
||||
});
|
||||
} else {
|
||||
const len = elems.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const elem = elems[i];
|
||||
const {id} = elem;
|
||||
if (id === 'svg_eof') break;
|
||||
holder = $('#' + id);
|
||||
const svgroot = document.createElementNS(svgns, 'svg');
|
||||
// Per https://www.w3.org/TR/xml-names11/#defaulting, the namespace for
|
||||
// attributes should have no value.
|
||||
svgroot.setAttribute('viewBox', [0, 0, iconW, iconH].join(' '));
|
||||
|
||||
let svg = elem.getElementsByTagNameNS(svgns, 'svg')[0];
|
||||
|
||||
// Make flexible by converting width/height to viewBox
|
||||
const w = svg.getAttribute('width');
|
||||
const h = svg.getAttribute('height');
|
||||
svg.removeAttribute('width');
|
||||
svg.removeAttribute('height');
|
||||
|
||||
const vb = svg.getAttribute('viewBox');
|
||||
if (!vb) {
|
||||
svg.setAttribute('viewBox', [0, 0, w, h].join(' '));
|
||||
}
|
||||
|
||||
// Not using jQuery to be a bit faster
|
||||
svgroot.setAttribute('xmlns', svgns);
|
||||
svgroot.setAttribute('width', iconW);
|
||||
svgroot.setAttribute('height', iconH);
|
||||
svgroot.setAttribute('xmlns:xlink', xlinkns);
|
||||
svgroot.setAttribute('class', 'svg_icon');
|
||||
|
||||
// Without cloning, Firefox will make another GET request.
|
||||
// With cloning, causes issue in Opera/Win/Non-EN
|
||||
if (!isOpera) svg = svg.cloneNode(true);
|
||||
|
||||
svgroot.append(svg);
|
||||
|
||||
let icon;
|
||||
if (toImage) {
|
||||
tempHolder.empty().append(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())
|
||||
.attr({class: 'svg_icon', src: str, alt});
|
||||
} else {
|
||||
icon = fixIDs($(svgroot), i);
|
||||
}
|
||||
addIcon(icon, id);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts.placement) {
|
||||
$.each(opts.placement, function (sel, id) {
|
||||
if (!svgIcons[id]) return;
|
||||
$(sel).each(function (i) {
|
||||
let copy = svgIcons[id].clone();
|
||||
if (i > 0 && !toImage) copy = fixIDs(copy, i, true);
|
||||
setIcon($(this), copy, id);
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!fallback) {
|
||||
if (toImage) tempHolder.remove();
|
||||
if (dataEl) dataEl.remove();
|
||||
if (testImg) testImg.remove();
|
||||
}
|
||||
if (opts.resize) $.resizeSvgIcons(opts.resize);
|
||||
iconsMade = true;
|
||||
|
||||
if (opts.callback) opts.callback(svgIcons);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {void}
|
||||
*/
|
||||
function useFallback () {
|
||||
if (file.includes('.svgz')) {
|
||||
const regFile = file.replace('.svgz', '.svg');
|
||||
if (window.console) {
|
||||
console.log('.svgz failed, trying with .svg'); // eslint-disable-line no-console
|
||||
}
|
||||
$.svgIcons(regFile, opts);
|
||||
} else if (opts.fallback) {
|
||||
makeIcons(false, opts.fallback);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @function external:jQuery.getSvgIcon
|
||||
* @param {string} id
|
||||
* @param {boolean} uniqueClone Whether to clone
|
||||
* @returns {external:jQuery} The icon (optionally cloned)
|
||||
*/
|
||||
$.getSvgIcon = function (id, uniqueClone) {
|
||||
let icon = svgIcons[id];
|
||||
if (uniqueClone && icon) {
|
||||
icon = fixIDs(icon, 0, true).clone(true);
|
||||
}
|
||||
return icon;
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {GenericArray} module:jQuerySVGIcons.Dimensions
|
||||
* @property {Integer} length 2
|
||||
* @property {Float} 0 Width
|
||||
* @property {Float} 1 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
|
||||
*/
|
||||
|
||||
/**
|
||||
* @function external:jQuery.resizeSvgIcons
|
||||
* @param {PlainObject<string, module:jQuerySVGIcons.Size>} obj Object with
|
||||
* selectors as keys. The values are sizes.
|
||||
* @returns {void}
|
||||
*/
|
||||
$.resizeSvgIcons = function (obj) {
|
||||
// FF2 and older don't detect .svg_icon, so we change it detect svg elems instead
|
||||
const changeSel = !$('.svg_icon:first').length;
|
||||
$.each(obj, function (sel, size) {
|
||||
const arr = Array.isArray(size);
|
||||
const w = arr ? size[0] : size,
|
||||
h = arr ? size[1] : size;
|
||||
if (changeSel) {
|
||||
sel = sel.replace(/\.svg_icon/g, 'svg');
|
||||
}
|
||||
$(sel).each(function () {
|
||||
this.setAttribute('width', w);
|
||||
this.setAttribute('height', h);
|
||||
if (window.opera && window.widget) {
|
||||
this.parentNode.style.width = w + 'px';
|
||||
this.parentNode.style.height = h + 'px';
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
return $;
|
||||
}
|
Loading…
Reference in New Issue