extract config related code to ConfigObj
parent
594b4c68d8
commit
ed7d672815
|
@ -0,0 +1,477 @@
|
||||||
|
/* globals $ */
|
||||||
|
|
||||||
|
// eslint-disable-next-line node/no-unpublished-import
|
||||||
|
import deparam from 'deparam';
|
||||||
|
import * as Utils from '../common/utilities.js';
|
||||||
|
/**
|
||||||
|
* @class configObj
|
||||||
|
*/
|
||||||
|
export default class ConfigObj {
|
||||||
|
/**
|
||||||
|
* @param {PlainObject} editor
|
||||||
|
*/
|
||||||
|
constructor (editor) {
|
||||||
|
/**
|
||||||
|
* Preferences.
|
||||||
|
* @interface module:SVGEditor.Prefs
|
||||||
|
* @property {string} [lang="en"] Two-letter language code. The language must exist in the Editor Preferences language list. Defaults to "en" if `locale.js` detection does not detect another language.
|
||||||
|
* @property {module:SVGEditor.IconSize} [iconsize="s" || "m"] Size of the toolbar icons. Will default to 's' if the window height is smaller than the minimum height and 'm' otherwise.
|
||||||
|
* @property {string} [bkgd_color="#FFF"] Color hex for canvas background color. Defaults to white.
|
||||||
|
* @property {string} [bkgd_url=""] Background raster image URL. This image will fill the background of the document; useful for tracing purposes.
|
||||||
|
* @property {"embed"|"ref"} [img_save="embed"] Defines whether included raster images should be saved as Data URIs when possible, or as URL references. Settable in the Document Properties dialog.
|
||||||
|
* @property {boolean} [save_notice_done=false] Used to track alert status
|
||||||
|
* @property {boolean} [export_notice_done=false] Used to track alert status
|
||||||
|
* @todo `save_notice_done` and `export_notice_done` should be changed to flags rather than preferences
|
||||||
|
*/
|
||||||
|
this.defaultPrefs = {
|
||||||
|
// EDITOR OPTIONS (DIALOG)
|
||||||
|
/**
|
||||||
|
* Default to "en" if locale.js detection does not detect another language.
|
||||||
|
*/
|
||||||
|
lang: '',
|
||||||
|
/**
|
||||||
|
* Will default to 's' if the window height is smaller than the minimum
|
||||||
|
* height and 'm' otherwise.
|
||||||
|
*/
|
||||||
|
iconsize: '',
|
||||||
|
bkgd_color: '#FFF',
|
||||||
|
bkgd_url: '',
|
||||||
|
// DOCUMENT PROPERTIES (DIALOG)
|
||||||
|
img_save: 'embed',
|
||||||
|
// ALERT NOTICES
|
||||||
|
// Only shows in UI as far as alert notices, but useful to remember, so keeping as pref
|
||||||
|
save_notice_done: false,
|
||||||
|
export_notice_done: false
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* @tutorial ConfigOptions
|
||||||
|
* @interface module:SVGEditor.Config
|
||||||
|
* @property {string} [canvasName="default"] Used to namespace storage provided via `ext-storage.js`; you can use this if you wish to have multiple independent instances of SVG Edit on the same domain
|
||||||
|
* @property {boolean} [no_save_warning=false] If `true`, prevents the warning dialog box from appearing when closing/reloading the page. Mostly useful for testing.
|
||||||
|
* @property {string} [imgPath="images/"] The path where the SVG icons are located, with trailing slash. Note that as of version 2.7, this is not configurable by URL for security reasons.
|
||||||
|
* @property {boolean} [preventAllURLConfig=false] Set to `true` to override the ability for URLs to set non-content configuration (including extension config). Must be set early, i.e., in `svgedit-config-iife.js`; extension loading is too late!
|
||||||
|
* @property {boolean} [preventURLContentLoading=false] Set to `true` to override the ability for URLs to set URL-based SVG content. Must be set early, i.e., in `svgedit-config-iife.js`; extension loading is too late!
|
||||||
|
* @property {boolean} [lockExtensions=false] Set to `true` to override the ability for URLs to set their own extensions; disallowed in URL setting. There is no need for this when `preventAllURLConfig` is used. Must be set early, i.e., in `svgedit-config-iife.js`; extension loading is too late!
|
||||||
|
* @property {boolean} [noDefaultExtensions=false] If set to `true`, prohibits automatic inclusion of default extensions (though "extensions" can still be used to add back any desired default extensions along with any other extensions). This can only be meaningfully used in `svgedit-config-iife.js` or in the URL
|
||||||
|
* @property {boolean} [noStorageOnLoad=false] Some interaction with `ext-storage.js`; prevent even the loading of previously saved local storage.
|
||||||
|
* @property {boolean} [forceStorage=false] Some interaction with `ext-storage.js`; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not (and may be required by law in some regions)
|
||||||
|
* @property {boolean} [emptyStorageOnDecline=false] Used by `ext-storage.js`; empty any prior storage if the user declines to store
|
||||||
|
* @property {boolean} [avoidClientSide=false] DEPRECATED (use `avoidClientSideDownload` instead); Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
|
||||||
|
* @property {boolean} [avoidClientSideDownload=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
|
||||||
|
* @property {boolean} [avoidClientSideOpen=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always open from the server and not only as fallback when FileReader client support is lacking
|
||||||
|
* @property {string[]} [extensions=[]] Extensions to load on startup. Use an array in `setConfig` and comma separated file names in the URL. Extension names must begin with "ext-". Note that as of version 2.7, paths containing "/", "\", or ":", are disallowed for security reasons. Although previous versions of this list would entirely override the default list, as of version 2.7, the defaults will always be added to this explicit list unless the configuration `noDefaultExtensions` is included. See {@link module:SVGEditor~defaultExtensions}.
|
||||||
|
* @property {string[]} [allowedOrigins=[]] Used by `ext-xdomain-messaging.js` to indicate which origins are permitted for cross-domain messaging (e.g., between the embedded editor and main editor code). Besides explicit domains, one might add '*' to allow all domains (not recommended for privacy/data integrity of your user's content!), `window.location.origin` for allowing the same origin (should be safe if you trust all apps on your domain), 'null' to allow `file:///` URL usage
|
||||||
|
* @property {null|PlainObject} [colorPickerCSS=null] Object of CSS properties mapped to values (for jQuery) to apply to the color picker. See {@link http://api.jquery.com/css/#css-properties}. A `null` value (the default) will cause the CSS to default to `left` with a position equal to that of the `fill_color` or `stroke_color` element minus 140, and a `bottom` equal to 40
|
||||||
|
* @property {string} [paramurl] This was available via URL only. Allowed an un-encoded URL within the query string (use "url" or "source" with a data: URI instead)
|
||||||
|
* @property {Float} [canvas_expansion=3] The minimum area visible outside the canvas, as a multiple of the image dimensions. The larger the number, the more one can scroll outside the canvas.
|
||||||
|
* @property {PlainObject} [initFill] Init fill properties
|
||||||
|
* @property {string} [initFill.color="FF0000"] The initial fill color. Must be a hex code string. Defaults to solid red.
|
||||||
|
* @property {Float} [initFill.opacity=1] The initial fill opacity. Must be a number between 0 and 1
|
||||||
|
* @property {PlainObject} [initStroke] Init stroke properties
|
||||||
|
* @property {Float} [initStroke.width=5] The initial stroke width. Must be a positive number.
|
||||||
|
* @property {string} [initStroke.color="000000"] The initial stroke color. Must be a hex code. Defaults to solid black.
|
||||||
|
* @property {Float} [initStroke.opacity=1] The initial stroke opacity. Must be a number between 0 and 1.
|
||||||
|
* @property {PlainObject} text Text style properties
|
||||||
|
* @property {Float} [text.stroke_width=0] Text stroke width
|
||||||
|
* @property {Float} [text.font_size=24] Text font size
|
||||||
|
* @property {string} [text.font_family="serif"] Text font family
|
||||||
|
* @property {Float} [initOpacity=1] Initial opacity (multiplied by 100)
|
||||||
|
* @property {module:SVGEditor.XYDimensions} [dimensions=[640, 480]] The default width/height of a new document. Use an array in `setConfig` (e.g., `[800, 600]`) and comma separated numbers in the URL.
|
||||||
|
* @property {boolean} [gridSnapping=false] Enable snap to grid by default. Set in Editor Options.
|
||||||
|
* @property {string} [gridColor="#000"] Accepts hex, e.g., '#000'. Set in Editor Options. Defaults to black.
|
||||||
|
* @property {string} [baseUnit="px"] Set in Editor Options.
|
||||||
|
* @property {Float} [snappingStep=10] Set the default grid snapping value. Set in Editor Options.
|
||||||
|
* @property {boolean} [showRulers=true] Initial state of ruler display (v2.6). Set in Editor Options.
|
||||||
|
* @property {string} [initTool="select"] The initially selected tool. Must be either the ID of the button for the tool, or the ID without `tool_` prefix (e.g., "select").
|
||||||
|
* @property {boolean} [wireframe=false] Start in wireframe mode
|
||||||
|
* @property {boolean} [showlayers=false] Open the layers side-panel by default.
|
||||||
|
* @property {"new"|"same"} [exportWindowType="new"] Can be "new" or "same" to indicate whether new windows will be generated for each export; the `window.name` of the export window is namespaced based on the `canvasName` (and incremented if "new" is selected as the type). Introduced 2.8.
|
||||||
|
* @property {boolean} [showGrid=false] Set by `ext-grid.js`; determines whether or not to show the grid by default
|
||||||
|
* @property {boolean} [show_outside_canvas=true] Defines whether or not elements outside the canvas should be visible. Set and used in `svgcanvas.js`.
|
||||||
|
* @property {boolean} [selectNew=true] If true, will replace the selection with the current element and automatically select element objects (when not in "path" mode) after they are created, showing their grips (v2.6). Set and used in `svgcanvas.js` (`mouseUp`).
|
||||||
|
* @todo Some others could be preferences as well (e.g., preventing URL changing of extensions, defaultExtensions, stylesheets, colorPickerCSS); Change the following to preferences and add pref controls where missing to the UI (e.g., `canvas_expansion`, `initFill`, `initStroke`, `text`, `initOpacity`, `dimensions`, `initTool`, `wireframe`, `showlayers`, `gridSnapping`, `gridColor`, `baseUnit`, `snappingStep`, `showRulers`, `exportWindowType`, `showGrid`, `show_outside_canvas`, `selectNew`)?
|
||||||
|
*/
|
||||||
|
this.defaultConfig = {
|
||||||
|
canvasName: 'default',
|
||||||
|
canvas_expansion: 3,
|
||||||
|
initFill: {
|
||||||
|
color: 'FF0000', // solid red
|
||||||
|
opacity: 1
|
||||||
|
},
|
||||||
|
initStroke: {
|
||||||
|
width: 5,
|
||||||
|
color: '000000', // solid black
|
||||||
|
opacity: 1
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
stroke_width: 0,
|
||||||
|
font_size: 24,
|
||||||
|
font_family: 'serif'
|
||||||
|
},
|
||||||
|
initOpacity: 1,
|
||||||
|
colorPickerCSS: null, // Defaults to 'left' with a position equal to that of the fill_color or stroke_color element minus 140, and a 'bottom' equal to 40
|
||||||
|
initTool: 'select',
|
||||||
|
exportWindowType: 'new', // 'same' (todo: also support 'download')
|
||||||
|
wireframe: false,
|
||||||
|
showlayers: false,
|
||||||
|
no_save_warning: false,
|
||||||
|
// PATH CONFIGURATION
|
||||||
|
// The following path configuration items are disallowed in the URL (as should any future path configurations)
|
||||||
|
imgPath: './images/',
|
||||||
|
// DOCUMENT PROPERTIES
|
||||||
|
// Change the following to a preference (already in the Document Properties dialog)?
|
||||||
|
dimensions: [640, 480],
|
||||||
|
// EDITOR OPTIONS
|
||||||
|
// Change the following to preferences (already in the Editor Options dialog)?
|
||||||
|
gridSnapping: false,
|
||||||
|
gridColor: '#000',
|
||||||
|
baseUnit: 'px',
|
||||||
|
snappingStep: 10,
|
||||||
|
showRulers: true,
|
||||||
|
// URL BEHAVIOR CONFIGURATION
|
||||||
|
preventAllURLConfig: false,
|
||||||
|
preventURLContentLoading: false,
|
||||||
|
// EXTENSION CONFIGURATION (see also preventAllURLConfig)
|
||||||
|
lockExtensions: false, // Disallowed in URL setting
|
||||||
|
noDefaultExtensions: false, // noDefaultExtensions can only be meaningfully used in `svgedit-config-iife.js` or in the URL
|
||||||
|
// EXTENSION-RELATED (GRID)
|
||||||
|
showGrid: false, // Set by ext-grid.js
|
||||||
|
// EXTENSION-RELATED (STORAGE)
|
||||||
|
noStorageOnLoad: false, // Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
|
||||||
|
forceStorage: false, // Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
|
||||||
|
emptyStorageOnDecline: false, // Used by ext-storage.js; empty any prior storage if the user declines to store
|
||||||
|
// EXTENSION (CLIENT VS. SERVER SAVING/OPENING)
|
||||||
|
avoidClientSide: false, // Deprecated in favor of `avoidClientSideDownload`
|
||||||
|
avoidClientSideDownload: false,
|
||||||
|
avoidClientSideOpen: false
|
||||||
|
};
|
||||||
|
|
||||||
|
this.curPrefs = {};
|
||||||
|
// Note: The difference between Prefs and Config is that Prefs
|
||||||
|
// can be changed in the UI and are stored in the browser,
|
||||||
|
// while config cannot
|
||||||
|
this.curConfig = {
|
||||||
|
// We do not put on defaultConfig to simplify object copying
|
||||||
|
// procedures (we obtain instead from defaultExtensions)
|
||||||
|
extensions: [],
|
||||||
|
userExtensions: [],
|
||||||
|
/**
|
||||||
|
* Can use `location.origin` to indicate the current
|
||||||
|
* origin. Can contain a '*' to allow all domains or 'null' (as
|
||||||
|
* a string) to support all `file:///` URLs. Cannot be set by
|
||||||
|
* URL for security reasons (not safe, at least for
|
||||||
|
* privacy or data integrity of SVG content).
|
||||||
|
* Might have been fairly safe to allow
|
||||||
|
* `new URL(location.href).origin` by default but
|
||||||
|
* avoiding it ensures some more security that even third
|
||||||
|
* party apps on the same domain also cannot communicate
|
||||||
|
* with this app by default.
|
||||||
|
* For use with `ext-xdomain-messaging.js`
|
||||||
|
* @todo We might instead make as a user-facing preference.
|
||||||
|
*/
|
||||||
|
allowedOrigins: []
|
||||||
|
};
|
||||||
|
this.urldata = {};
|
||||||
|
/**
|
||||||
|
* @name module:SVGEditor~defaultExtensions
|
||||||
|
* @type {string[]}
|
||||||
|
*/
|
||||||
|
this.defaultExtensions = [
|
||||||
|
'ext-connector',
|
||||||
|
'ext-eyedropper',
|
||||||
|
'ext-grid',
|
||||||
|
'ext-imagelib',
|
||||||
|
'ext-markers',
|
||||||
|
'ext-overview_window',
|
||||||
|
'ext-panning',
|
||||||
|
'ext-polygon',
|
||||||
|
'ext-shapes',
|
||||||
|
'ext-star',
|
||||||
|
'ext-storage'
|
||||||
|
];
|
||||||
|
this.editor = editor;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @function setupCurPrefs
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
setupCurPrefs () {
|
||||||
|
const curPrefs = {...this.defaultPrefs, ...this.curPrefs}; // Now safe to merge with priority for curPrefs in the event any are already set
|
||||||
|
// Export updated prefs
|
||||||
|
this.curPrefs = curPrefs;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets up current config based on defaults.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
setupCurConfig () {
|
||||||
|
const curConfig = {...this.defaultConfig, ...this.curConfig}; // Now safe to merge with priority for curConfig in the event any are already set
|
||||||
|
|
||||||
|
// Now deal with extensions and other array config
|
||||||
|
if (!curConfig.noDefaultExtensions) {
|
||||||
|
curConfig.extensions = curConfig.extensions.concat(this.defaultExtensions);
|
||||||
|
}
|
||||||
|
// ...and remove any dupes
|
||||||
|
['extensions', 'allowedOrigins'].forEach(function (cfg) {
|
||||||
|
curConfig[cfg] = $.grep(curConfig[cfg], function (n, i) { // Supposedly faster than filter per http://amandeep1986.blogspot.hk/2015/02/jquery-grep-vs-js-filter.html
|
||||||
|
return i === curConfig[cfg].indexOf(n);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Export updated config
|
||||||
|
this.curConfig = curConfig;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @function loadFromURL Load config/data from URL if given
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
loadFromURL () {
|
||||||
|
const {search, searchParams} = new URL(location);
|
||||||
|
|
||||||
|
if (search) {
|
||||||
|
this.urldata = deparam(searchParams.toString(), true);
|
||||||
|
|
||||||
|
['initStroke', 'initFill'].forEach((prop) => {
|
||||||
|
if (searchParams.has(`${prop}[color]`)) {
|
||||||
|
// Restore back to original non-deparamed value to avoid color
|
||||||
|
// strings being converted to numbers
|
||||||
|
this.urldata[prop].color = searchParams.get(`${prop}[color]`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (searchParams.has('bkgd_color')) {
|
||||||
|
this.urldata.bkgd_color = '#' + searchParams.get('bkgd_color');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.urldata.dimensions) {
|
||||||
|
this.urldata.dimensions = this.urldata.dimensions.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.urldata.extensions) {
|
||||||
|
// For security reasons, disallow cross-domain or cross-folder
|
||||||
|
// extensions via URL
|
||||||
|
this.urldata.extensions = this.urldata.extensions.match(/[:/\\]/)
|
||||||
|
? ''
|
||||||
|
: this.urldata.extensions.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallowing extension paths via URL for
|
||||||
|
// security reasons, even for same-domain
|
||||||
|
// ones given potential to interact in undesirable
|
||||||
|
// ways with other script resources
|
||||||
|
['userExtensions', 'imgPath']
|
||||||
|
.forEach(function (pathConfig) {
|
||||||
|
if (this.urldata[pathConfig]) {
|
||||||
|
delete this.urldata[pathConfig];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Note: `source` and `url` (as with `storagePrompt` later) are not
|
||||||
|
// set on config but are used below
|
||||||
|
this.setConfig(this.urldata, {overwrite: false});
|
||||||
|
this.setupCurConfig();
|
||||||
|
|
||||||
|
if (!this.curConfig.preventURLContentLoading) {
|
||||||
|
let {source} = this.urldata;
|
||||||
|
if (!source) { // urldata.source may have been null if it ended with '='
|
||||||
|
const src = searchParams.get('source');
|
||||||
|
if (src && src.startsWith('data:')) {
|
||||||
|
source = src;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (source) {
|
||||||
|
if (source.startsWith('data:')) {
|
||||||
|
this.editor.loadFromDataURI(source);
|
||||||
|
} else {
|
||||||
|
this.editor.loadFromString(source);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.urldata.url) {
|
||||||
|
this.editor.loadFromURL(this.urldata.url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.urldata.noStorageOnLoad || this.curConfig.forceStorage) {
|
||||||
|
this.loadContentAndPrefs();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setupCurConfig();
|
||||||
|
this.loadContentAndPrefs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Where permitted, sets canvas and/or `configObj.defaultPrefs` based on previous
|
||||||
|
* storage. This will override URL settings (for security reasons) but
|
||||||
|
* not `svgedit-config-iife.js` configuration (unless initial user
|
||||||
|
* overriding is explicitly permitted there via `allowInitialUserOverride`).
|
||||||
|
* @function module:SVGEditor.loadContentAndPrefs
|
||||||
|
* @todo Split `allowInitialUserOverride` into `allowOverrideByURL` and
|
||||||
|
* `allowOverrideByUserStorage` so `svgedit-config-iife.js` can disallow some
|
||||||
|
* individual items for URL setting but allow for user storage AND/OR
|
||||||
|
* change URL setting so that it always uses a different namespace,
|
||||||
|
* so it won't affect pre-existing user storage (but then if users saves
|
||||||
|
* that, it will then be subject to tampering
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
loadContentAndPrefs () {
|
||||||
|
if (!this.curConfig.forceStorage &&
|
||||||
|
(this.curConfig.noStorageOnLoad ||
|
||||||
|
!document.cookie.match(/(?:^|;\s*)svgeditstore=(?:prefsAndContent|prefsOnly)/)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOAD CONTENT
|
||||||
|
if (this.editor.storage && // Cookies do not have enough available memory to hold large documents
|
||||||
|
(this.curConfig.forceStorage ||
|
||||||
|
(!this.curConfig.noStorageOnLoad &&
|
||||||
|
document.cookie.match(/(?:^|;\s*)svgeditstore=prefsAndContent/))
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
const name = 'svgedit-' + this.curConfig.canvasName;
|
||||||
|
const cached = this.editor.storage.getItem(name);
|
||||||
|
if (cached) {
|
||||||
|
this.editor.loadFromString(cached);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOAD PREFS
|
||||||
|
Object.keys(this.defaultPrefs).forEach((key) => {
|
||||||
|
const storeKey = 'svg-edit-' + key;
|
||||||
|
if (this.editor.storage) {
|
||||||
|
const val = this.editor.storage.getItem(storeKey);
|
||||||
|
if (val) {
|
||||||
|
this.defaultPrefs[key] = String(val); // Convert to string for FF (.value fails in Webkit)
|
||||||
|
}
|
||||||
|
} else if (window.widget) {
|
||||||
|
this.defaultPrefs[key] = window.widget.preferenceForKey(storeKey);
|
||||||
|
} else {
|
||||||
|
const result = document.cookie.match(
|
||||||
|
new RegExp('(?:^|;\\s*)' + Utils.regexEscape(
|
||||||
|
encodeURIComponent(storeKey)
|
||||||
|
) + '=([^;]+)')
|
||||||
|
);
|
||||||
|
this.defaultPrefs[key] = result ? decodeURIComponent(result[1]) : '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows setting of preferences or configuration (including extensions).
|
||||||
|
* @function module:SVGEditor.setConfig
|
||||||
|
* @param {module:SVGEditor.Config|module:SVGEditor.Prefs} opts The preferences or configuration (including extensions). See the tutorial on {@tutorial ConfigOptions} for info on config and preferences.
|
||||||
|
* @param {PlainObject} [cfgCfg] Describes configuration which applies to the
|
||||||
|
* particular batch of supplied options
|
||||||
|
* @param {boolean} [cfgCfg.allowInitialUserOverride=false] Set to true if you wish
|
||||||
|
* to allow initial overriding of settings by the user via the URL
|
||||||
|
* (if permitted) or previously stored preferences (if permitted);
|
||||||
|
* note that it will be too late if you make such calls in extension
|
||||||
|
* code because the URL or preference storage settings will
|
||||||
|
* have already taken place.
|
||||||
|
* @param {boolean} [cfgCfg.overwrite=true] Set to false if you wish to
|
||||||
|
* prevent the overwriting of prior-set preferences or configuration
|
||||||
|
* (URL settings will always follow this requirement for security
|
||||||
|
* reasons, so `svgedit-config-iife.js` settings cannot be overridden unless it
|
||||||
|
* explicitly permits via `allowInitialUserOverride` but extension config
|
||||||
|
* can be overridden as they will run after URL settings). Should
|
||||||
|
* not be needed in `svgedit-config-iife.js`.
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
setConfig (opts, cfgCfg = {}) {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {module:SVGEditor.Config|module:SVGEditor.Prefs} cfgObj
|
||||||
|
* @param {string} key
|
||||||
|
* @param {any} val See {@link module:SVGEditor.Config} or {@link module:SVGEditor.Prefs}
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
const extendOrAdd = (cfgObj, key, val) => {
|
||||||
|
if (cfgObj[key] && typeof cfgObj[key] === 'object') {
|
||||||
|
$.extend(true, cfgObj[key], val);
|
||||||
|
} else {
|
||||||
|
cfgObj[key] = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Object.entries(opts).forEach(([key, val]) => {
|
||||||
|
// Only allow prefs defined in configObj.defaultPrefs or...
|
||||||
|
if (this.defaultPrefs[key]) {
|
||||||
|
if (cfgCfg.overwrite === false && (
|
||||||
|
this.curConfig.preventAllURLConfig ||
|
||||||
|
this.curPrefs[key])
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cfgCfg.allowInitialUserOverride === true) {
|
||||||
|
this.defaultPrefs[key] = val;
|
||||||
|
} else {
|
||||||
|
this.pref(key, val);
|
||||||
|
}
|
||||||
|
} else if (['extensions', 'userExtensions', 'allowedOrigins'].includes(key)) {
|
||||||
|
if (cfgCfg.overwrite === false &&
|
||||||
|
(
|
||||||
|
this.curConfig.preventAllURLConfig ||
|
||||||
|
['allowedOrigins'].includes(key) ||
|
||||||
|
(key === 'extensions' && this.curConfig.lockExtensions)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.curConfig[key] = this.curConfig[key].concat(val); // We will handle any dupes later
|
||||||
|
// Only allow other configObj.curConfig if defined in configObj.defaultConfig
|
||||||
|
} else if ({}.hasOwnProperty.call(this.defaultConfig, key)) {
|
||||||
|
if (cfgCfg.overwrite === false && (
|
||||||
|
this.curConfig.preventAllURLConfig ||
|
||||||
|
{}.hasOwnProperty.call(this.curConfig, key)
|
||||||
|
)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Potentially overwriting of previously set config
|
||||||
|
if ({}.hasOwnProperty.call(this.curConfig, key)) {
|
||||||
|
if (cfgCfg.overwrite === false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extendOrAdd(this.curConfig, key, val);
|
||||||
|
} else if (cfgCfg.allowInitialUserOverride === true) {
|
||||||
|
extendOrAdd(this.defaultConfig, key, val);
|
||||||
|
} else if (this.defaultConfig[key] && typeof this.defaultConfig[key] === 'object') {
|
||||||
|
this.curConfig[key] = Array.isArray(this.defaultConfig[key]) ? [] : {};
|
||||||
|
$.extend(true, this.curConfig[key], val); // Merge properties recursively, e.g., on initFill, initStroke objects
|
||||||
|
} else {
|
||||||
|
this.curConfig[key] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Store and retrieve preferences.
|
||||||
|
* @function pref
|
||||||
|
* @param {string} key The preference name to be retrieved or set
|
||||||
|
* @param {string} [val] The value. If the value supplied is missing or falsey, no change to the preference will
|
||||||
|
* be made unless `mayBeEmpty` is set.
|
||||||
|
* @param {boolean} [mayBeEmpty] If value may be falsey.
|
||||||
|
* @returns {string|void} If val is missing or falsey and `mayBeEmpty` is not set, the
|
||||||
|
* value of the previously stored preference will be returned.
|
||||||
|
* @todo Review whether any remaining existing direct references to
|
||||||
|
* getting `curPrefs` can be changed to use `svgEditor.pref()` getting to ensure
|
||||||
|
* `defaultPrefs` fallback (also for sake of `allowInitialUserOverride`);
|
||||||
|
* specifically, `bkgd_color` could be changed so that the pref dialog has a
|
||||||
|
* button to auto-calculate background, but otherwise uses `svgEditor.pref()` to
|
||||||
|
* be able to get default prefs or overridable settings
|
||||||
|
*/
|
||||||
|
pref (key, val, mayBeEmpty) {
|
||||||
|
if (mayBeEmpty || val) {
|
||||||
|
this.curPrefs[key] = val;
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return (key in this.curPrefs) ? this.curPrefs[key] : this.defaultPrefs[key];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @function load load Config
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
load () {
|
||||||
|
this.loadFromURL(this.editor);
|
||||||
|
this.setupCurPrefs(this.editor);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ export default {
|
||||||
name: 'arrows',
|
name: 'arrows',
|
||||||
async init (S) {
|
async init (S) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const svgCanvas = svgEditor.canvas;
|
const svgCanvas = svgEditor.canvas;
|
||||||
const
|
const
|
||||||
addElem = svgCanvas.addSVGElementFromJson,
|
addElem = svgCanvas.addSVGElementFromJson,
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default {
|
||||||
name: 'closepath',
|
name: 'closepath',
|
||||||
async init ({importLocale, $}) {
|
async init ({importLocale, $}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
let selElems;
|
let selElems;
|
||||||
const updateButton = function (path) {
|
const updateButton = function (path) {
|
||||||
const seglist = path.pathSegList,
|
const seglist = path.pathSegList,
|
||||||
|
|
|
@ -356,7 +356,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
return {
|
return {
|
||||||
/** @todo JFH special flag */
|
/** @todo JFH special flag */
|
||||||
newUI: true,
|
newUI: true,
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
||||||
name: 'eyedropper',
|
name: 'eyedropper',
|
||||||
async init (S) {
|
async init (S) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const {$, ChangeElementCommand} = S, // , svgcontent,
|
const {$, ChangeElementCommand} = S, // , svgcontent,
|
||||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||||
svgCanvas = svgEditor.canvas,
|
svgCanvas = svgEditor.canvas,
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default {
|
||||||
// addElem = svgCanvas.addSVGElementFromJson,
|
// addElem = svgCanvas.addSVGElementFromJson,
|
||||||
svgdoc = S.svgroot.parentNode.ownerDocument;
|
svgdoc = S.svgroot.parentNode.ownerDocument;
|
||||||
|
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
|
|
||||||
const properlySourceSizeTextArea = function () {
|
const properlySourceSizeTextArea = function () {
|
||||||
// TODO: remove magic numbers here and get values from CSS
|
// TODO: remove magic numbers here and get values from CSS
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
||||||
name: 'grid',
|
name: 'grid',
|
||||||
async init ({$, NS, getTypeMap}) {
|
async init ({$, NS, getTypeMap}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const svgCanvas = svgEditor.canvas;
|
const svgCanvas = svgEditor.canvas;
|
||||||
const svgdoc = document.getElementById('svgcanvas').ownerDocument,
|
const svgdoc = document.getElementById('svgcanvas').ownerDocument,
|
||||||
{assignAttributes} = svgCanvas,
|
{assignAttributes} = svgCanvas,
|
||||||
|
|
|
@ -29,7 +29,7 @@ export default {
|
||||||
name: 'helloworld',
|
name: 'helloworld',
|
||||||
async init ({$, importLocale}) {
|
async init ({$, importLocale}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const svgCanvas = svgEditor.canvas;
|
const svgCanvas = svgEditor.canvas;
|
||||||
return {
|
return {
|
||||||
name: strings.name,
|
name: strings.name,
|
||||||
|
|
|
@ -23,7 +23,7 @@ export default {
|
||||||
name: 'imagelib',
|
name: 'imagelib',
|
||||||
async init ({$, decode64, dropXMLInternalSubset}) {
|
async init ({$, decode64, dropXMLInternalSubset}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const imagelibStrings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const imagelibStrings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
|
|
||||||
const {uiStrings, canvas: svgCanvas} = svgEditor;
|
const {uiStrings, canvas: svgCanvas} = svgEditor;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ export default {
|
||||||
name: 'markers',
|
name: 'markers',
|
||||||
async init (S) {
|
async init (S) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const {$} = S;
|
const {$} = S;
|
||||||
const svgCanvas = svgEditor.canvas;
|
const svgCanvas = svgEditor.canvas;
|
||||||
const // {svgcontent} = S,
|
const // {svgcontent} = S,
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default {
|
||||||
name: 'mathjax',
|
name: 'mathjax',
|
||||||
async init ({$}) {
|
async init ({$}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const svgCanvas = svgEditor.canvas;
|
const svgCanvas = svgEditor.canvas;
|
||||||
|
|
||||||
// Configuration of the MathJax extention.
|
// Configuration of the MathJax extention.
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default {
|
||||||
name: 'panning',
|
name: 'panning',
|
||||||
async init ({importLocale}) {
|
async init ({importLocale}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const svgCanvas = svgEditor.canvas;
|
const svgCanvas = svgEditor.canvas;
|
||||||
const buttons = [{
|
const buttons = [{
|
||||||
id: 'ext-panning',
|
id: 'ext-panning',
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default {
|
||||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
|
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
|
||||||
// undoCommand = 'Not image',
|
// undoCommand = 'Not image',
|
||||||
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
|
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const markerTypes = {
|
const markerTypes = {
|
||||||
nomarker: {},
|
nomarker: {},
|
||||||
forwardslash:
|
forwardslash:
|
||||||
|
|
|
@ -26,7 +26,7 @@ export default {
|
||||||
const {$} = S, // {svgcontent}
|
const {$} = S, // {svgcontent}
|
||||||
// addElem = svgCanvas.addSVGElementFromJson,
|
// addElem = svgCanvas.addSVGElementFromJson,
|
||||||
editingitex = false;
|
editingitex = false;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
let selElems,
|
let selElems,
|
||||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
|
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
|
||||||
|
|
|
@ -25,7 +25,7 @@ export default {
|
||||||
name: 'server_moinsave',
|
name: 'server_moinsave',
|
||||||
async init ({$, encode64, importLocale}) {
|
async init ({$, encode64, importLocale}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const svgCanvas = svgEditor.canvas;
|
const svgCanvas = svgEditor.canvas;
|
||||||
const saveSvgAction = '/+modify';
|
const saveSvgAction = '/+modify';
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ export default {
|
||||||
name: 'server_opensave',
|
name: 'server_opensave',
|
||||||
async init ({$, decode64, encode64}) {
|
async init ({$, decode64, encode64}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const {
|
const {
|
||||||
curConfig: {
|
curConfig: {
|
||||||
avoidClientSide, // Deprecated
|
avoidClientSide, // Deprecated
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default {
|
||||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
|
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
|
||||||
// undoCommand = 'Not image',
|
// undoCommand = 'Not image',
|
||||||
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
|
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
|
|
@ -179,7 +179,7 @@ export default {
|
||||||
name: 'storage',
|
name: 'storage',
|
||||||
async langReady ({lang}) {
|
async langReady ({lang}) {
|
||||||
const storagePrompt = new URL(top.location).searchParams.get('storagePrompt');
|
const storagePrompt = new URL(top.location).searchParams.get('storagePrompt');
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const {
|
const {
|
||||||
message, storagePrefsAndContent, storagePrefsOnly,
|
message, storagePrefsAndContent, storagePrefsOnly,
|
||||||
storagePrefs, storageNoPrefsOrContent, storageNoPrefs,
|
storagePrefs, storageNoPrefsOrContent, storageNoPrefs,
|
||||||
|
|
|
@ -22,7 +22,7 @@ export default {
|
||||||
name: 'webappfind',
|
name: 'webappfind',
|
||||||
async init ({$}) {
|
async init ({$}) {
|
||||||
const svgEditor = this;
|
const svgEditor = this;
|
||||||
const strings = await loadExtensionTranslation(svgEditor.curPrefs.lang);
|
const strings = await loadExtensionTranslation(svgEditor.pref('lang'));
|
||||||
const saveMessage = 'save',
|
const saveMessage = 'save',
|
||||||
readMessage = 'read',
|
readMessage = 'read',
|
||||||
excludedMessages = [readMessage, saveMessage];
|
excludedMessages = [readMessage, saveMessage];
|
||||||
|
|
|
@ -16,9 +16,6 @@
|
||||||
* @borrows module:locale.setStrings as setStrings
|
* @borrows module:locale.setStrings as setStrings
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// eslint-disable-next-line node/no-unpublished-import
|
|
||||||
import deparam from 'deparam';
|
|
||||||
|
|
||||||
import './touch.js';
|
import './touch.js';
|
||||||
import {NS} from '../common/namespaces.js';
|
import {NS} from '../common/namespaces.js';
|
||||||
import {isChrome, isGecko, isMac} from '../common/browser.js';
|
import {isChrome, isGecko, isMac} from '../common/browser.js';
|
||||||
|
@ -39,6 +36,7 @@ import jQueryPluginContextMenu from './contextmenu/jQuery.contextMenu.js';
|
||||||
import jQueryPluginJPicker from './jgraduate/jQuery.jPicker.js';
|
import jQueryPluginJPicker from './jgraduate/jQuery.jPicker.js';
|
||||||
import jQueryPluginDBox from '../svgcanvas/dbox.js';
|
import jQueryPluginDBox from '../svgcanvas/dbox.js';
|
||||||
|
|
||||||
|
import ConfigObj from './ConfigObj.js';
|
||||||
import LayersPanel from './LayersPanel.js';
|
import LayersPanel from './LayersPanel.js';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -86,177 +84,7 @@ const $ = [
|
||||||
const homePage = 'https://github.com/SVG-Edit/svgedit';
|
const homePage = 'https://github.com/SVG-Edit/svgedit';
|
||||||
|
|
||||||
const callbacks = [];
|
const callbacks = [];
|
||||||
/**
|
|
||||||
* Preferences.
|
|
||||||
* @interface module:SVGEditor.Prefs
|
|
||||||
* @property {string} [lang="en"] Two-letter language code. The language must exist in the Editor Preferences language list. Defaults to "en" if `locale.js` detection does not detect another language.
|
|
||||||
* @property {module:SVGEditor.IconSize} [iconsize="s" || "m"] Size of the toolbar icons. Will default to 's' if the window height is smaller than the minimum height and 'm' otherwise.
|
|
||||||
* @property {string} [bkgd_color="#FFF"] Color hex for canvas background color. Defaults to white.
|
|
||||||
* @property {string} [bkgd_url=""] Background raster image URL. This image will fill the background of the document; useful for tracing purposes.
|
|
||||||
* @property {"embed"|"ref"} [img_save="embed"] Defines whether included raster images should be saved as Data URIs when possible, or as URL references. Settable in the Document Properties dialog.
|
|
||||||
* @property {boolean} [save_notice_done=false] Used to track alert status
|
|
||||||
* @property {boolean} [export_notice_done=false] Used to track alert status
|
|
||||||
* @todo `save_notice_done` and `export_notice_done` should be changed to flags rather than preferences
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @namespace {module:SVGEditor.Prefs} defaultPrefs
|
|
||||||
* @memberof module:SVGEditor~
|
|
||||||
* @implements {module:SVGEditor.Prefs}
|
|
||||||
*/
|
|
||||||
// The iteration algorithm for defaultPrefs does not currently support array/objects
|
|
||||||
const defaultPrefs = /** @lends module:SVGEditor~defaultPrefs */ {
|
|
||||||
// EDITOR OPTIONS (DIALOG)
|
|
||||||
/**
|
|
||||||
* Default to "en" if locale.js detection does not detect another language.
|
|
||||||
*/
|
|
||||||
lang: '',
|
|
||||||
/**
|
|
||||||
* Will default to 's' if the window height is smaller than the minimum
|
|
||||||
* height and 'm' otherwise.
|
|
||||||
*/
|
|
||||||
iconsize: '',
|
|
||||||
bkgd_color: '#FFF',
|
|
||||||
bkgd_url: '',
|
|
||||||
// DOCUMENT PROPERTIES (DIALOG)
|
|
||||||
img_save: 'embed',
|
|
||||||
// ALERT NOTICES
|
|
||||||
// Only shows in UI as far as alert notices, but useful to remember, so keeping as pref
|
|
||||||
save_notice_done: false,
|
|
||||||
export_notice_done: false
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* @name module:SVGEditor~defaultExtensions
|
|
||||||
* @type {string[]}
|
|
||||||
*/
|
|
||||||
const defaultExtensions = [
|
|
||||||
'ext-connector',
|
|
||||||
'ext-eyedropper',
|
|
||||||
'ext-grid',
|
|
||||||
'ext-imagelib',
|
|
||||||
'ext-markers',
|
|
||||||
'ext-overview_window',
|
|
||||||
'ext-panning',
|
|
||||||
'ext-polygon',
|
|
||||||
'ext-shapes',
|
|
||||||
'ext-star',
|
|
||||||
'ext-storage'
|
|
||||||
];
|
|
||||||
/**
|
|
||||||
* @typedef {"@default"|string} module:SVGEditor.Stylesheet `@default` will automatically load all of the default CSS paths for SVGEditor
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @typedef {GenericArray} module:SVGEditor.XYDimensions
|
|
||||||
* @property {Integer} length 2
|
|
||||||
* @property {Float} 0
|
|
||||||
* @property {Float} 1
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @tutorial ConfigOptions
|
|
||||||
* @interface module:SVGEditor.Config
|
|
||||||
* @property {string} [canvasName="default"] Used to namespace storage provided via `ext-storage.js`; you can use this if you wish to have multiple independent instances of SVG Edit on the same domain
|
|
||||||
* @property {boolean} [no_save_warning=false] If `true`, prevents the warning dialog box from appearing when closing/reloading the page. Mostly useful for testing.
|
|
||||||
* @property {string} [imgPath="images/"] The path where the SVG icons are located, with trailing slash. Note that as of version 2.7, this is not configurable by URL for security reasons.
|
|
||||||
* @property {boolean} [preventAllURLConfig=false] Set to `true` to override the ability for URLs to set non-content configuration (including extension config). Must be set early, i.e., in `svgedit-config-iife.js`; extension loading is too late!
|
|
||||||
* @property {boolean} [preventURLContentLoading=false] Set to `true` to override the ability for URLs to set URL-based SVG content. Must be set early, i.e., in `svgedit-config-iife.js`; extension loading is too late!
|
|
||||||
* @property {boolean} [lockExtensions=false] Set to `true` to override the ability for URLs to set their own extensions; disallowed in URL setting. There is no need for this when `preventAllURLConfig` is used. Must be set early, i.e., in `svgedit-config-iife.js`; extension loading is too late!
|
|
||||||
* @property {boolean} [noDefaultExtensions=false] If set to `true`, prohibits automatic inclusion of default extensions (though "extensions" can still be used to add back any desired default extensions along with any other extensions). This can only be meaningfully used in `svgedit-config-iife.js` or in the URL
|
|
||||||
* @property {boolean} [noStorageOnLoad=false] Some interaction with `ext-storage.js`; prevent even the loading of previously saved local storage.
|
|
||||||
* @property {boolean} [forceStorage=false] Some interaction with `ext-storage.js`; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not (and may be required by law in some regions)
|
|
||||||
* @property {boolean} [emptyStorageOnDecline=false] Used by `ext-storage.js`; empty any prior storage if the user declines to store
|
|
||||||
* @property {boolean} [avoidClientSide=false] DEPRECATED (use `avoidClientSideDownload` instead); Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
|
|
||||||
* @property {boolean} [avoidClientSideDownload=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always save to server and not only as fallback when client support is lacking
|
|
||||||
* @property {boolean} [avoidClientSideOpen=false] Used by `ext-server_opensave.js`; set to `true` if you wish to always open from the server and not only as fallback when FileReader client support is lacking
|
|
||||||
* @property {string[]} [extensions=[]] Extensions to load on startup. Use an array in `setConfig` and comma separated file names in the URL. Extension names must begin with "ext-". Note that as of version 2.7, paths containing "/", "\", or ":", are disallowed for security reasons. Although previous versions of this list would entirely override the default list, as of version 2.7, the defaults will always be added to this explicit list unless the configuration `noDefaultExtensions` is included. See {@link module:SVGEditor~defaultExtensions}.
|
|
||||||
* @property {string[]} [allowedOrigins=[]] Used by `ext-xdomain-messaging.js` to indicate which origins are permitted for cross-domain messaging (e.g., between the embedded editor and main editor code). Besides explicit domains, one might add '*' to allow all domains (not recommended for privacy/data integrity of your user's content!), `window.location.origin` for allowing the same origin (should be safe if you trust all apps on your domain), 'null' to allow `file:///` URL usage
|
|
||||||
* @property {null|PlainObject} [colorPickerCSS=null] Object of CSS properties mapped to values (for jQuery) to apply to the color picker. See {@link http://api.jquery.com/css/#css-properties}. A `null` value (the default) will cause the CSS to default to `left` with a position equal to that of the `fill_color` or `stroke_color` element minus 140, and a `bottom` equal to 40
|
|
||||||
* @property {string} [paramurl] This was available via URL only. Allowed an un-encoded URL within the query string (use "url" or "source" with a data: URI instead)
|
|
||||||
* @property {Float} [canvas_expansion=3] The minimum area visible outside the canvas, as a multiple of the image dimensions. The larger the number, the more one can scroll outside the canvas.
|
|
||||||
* @property {PlainObject} [initFill] Init fill properties
|
|
||||||
* @property {string} [initFill.color="FF0000"] The initial fill color. Must be a hex code string. Defaults to solid red.
|
|
||||||
* @property {Float} [initFill.opacity=1] The initial fill opacity. Must be a number between 0 and 1
|
|
||||||
* @property {PlainObject} [initStroke] Init stroke properties
|
|
||||||
* @property {Float} [initStroke.width=5] The initial stroke width. Must be a positive number.
|
|
||||||
* @property {string} [initStroke.color="000000"] The initial stroke color. Must be a hex code. Defaults to solid black.
|
|
||||||
* @property {Float} [initStroke.opacity=1] The initial stroke opacity. Must be a number between 0 and 1.
|
|
||||||
* @property {PlainObject} text Text style properties
|
|
||||||
* @property {Float} [text.stroke_width=0] Text stroke width
|
|
||||||
* @property {Float} [text.font_size=24] Text font size
|
|
||||||
* @property {string} [text.font_family="serif"] Text font family
|
|
||||||
* @property {Float} [initOpacity=1] Initial opacity (multiplied by 100)
|
|
||||||
* @property {module:SVGEditor.XYDimensions} [dimensions=[640, 480]] The default width/height of a new document. Use an array in `setConfig` (e.g., `[800, 600]`) and comma separated numbers in the URL.
|
|
||||||
* @property {boolean} [gridSnapping=false] Enable snap to grid by default. Set in Editor Options.
|
|
||||||
* @property {string} [gridColor="#000"] Accepts hex, e.g., '#000'. Set in Editor Options. Defaults to black.
|
|
||||||
* @property {string} [baseUnit="px"] Set in Editor Options.
|
|
||||||
* @property {Float} [snappingStep=10] Set the default grid snapping value. Set in Editor Options.
|
|
||||||
* @property {boolean} [showRulers=true] Initial state of ruler display (v2.6). Set in Editor Options.
|
|
||||||
* @property {string} [initTool="select"] The initially selected tool. Must be either the ID of the button for the tool, or the ID without `tool_` prefix (e.g., "select").
|
|
||||||
* @property {boolean} [wireframe=false] Start in wireframe mode
|
|
||||||
* @property {boolean} [showlayers=false] Open the layers side-panel by default.
|
|
||||||
* @property {"new"|"same"} [exportWindowType="new"] Can be "new" or "same" to indicate whether new windows will be generated for each export; the `window.name` of the export window is namespaced based on the `canvasName` (and incremented if "new" is selected as the type). Introduced 2.8.
|
|
||||||
* @property {boolean} [showGrid=false] Set by `ext-grid.js`; determines whether or not to show the grid by default
|
|
||||||
* @property {boolean} [show_outside_canvas=true] Defines whether or not elements outside the canvas should be visible. Set and used in `svgcanvas.js`.
|
|
||||||
* @property {boolean} [selectNew=true] If true, will replace the selection with the current element and automatically select element objects (when not in "path" mode) after they are created, showing their grips (v2.6). Set and used in `svgcanvas.js` (`mouseUp`).
|
|
||||||
* @todo Some others could be preferences as well (e.g., preventing URL changing of extensions, defaultExtensions, stylesheets, colorPickerCSS); Change the following to preferences and add pref controls where missing to the UI (e.g., `canvas_expansion`, `initFill`, `initStroke`, `text`, `initOpacity`, `dimensions`, `initTool`, `wireframe`, `showlayers`, `gridSnapping`, `gridColor`, `baseUnit`, `snappingStep`, `showRulers`, `exportWindowType`, `showGrid`, `show_outside_canvas`, `selectNew`)?
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @namespace {module:SVGEditor.Config} defaultConfig
|
|
||||||
* @memberof module:SVGEditor~
|
|
||||||
* @implements {module:SVGEditor.Config}
|
|
||||||
*/
|
|
||||||
const defaultConfig = {
|
|
||||||
canvasName: 'default',
|
|
||||||
canvas_expansion: 3,
|
|
||||||
initFill: {
|
|
||||||
color: 'FF0000', // solid red
|
|
||||||
opacity: 1
|
|
||||||
},
|
|
||||||
initStroke: {
|
|
||||||
width: 5,
|
|
||||||
color: '000000', // solid black
|
|
||||||
opacity: 1
|
|
||||||
},
|
|
||||||
text: {
|
|
||||||
stroke_width: 0,
|
|
||||||
font_size: 24,
|
|
||||||
font_family: 'serif'
|
|
||||||
},
|
|
||||||
initOpacity: 1,
|
|
||||||
colorPickerCSS: null, // Defaults to 'left' with a position equal to that of the fill_color or stroke_color element minus 140, and a 'bottom' equal to 40
|
|
||||||
initTool: 'select',
|
|
||||||
exportWindowType: 'new', // 'same' (todo: also support 'download')
|
|
||||||
wireframe: false,
|
|
||||||
showlayers: false,
|
|
||||||
no_save_warning: false,
|
|
||||||
// PATH CONFIGURATION
|
|
||||||
// The following path configuration items are disallowed in the URL (as should any future path configurations)
|
|
||||||
imgPath: './images/',
|
|
||||||
// DOCUMENT PROPERTIES
|
|
||||||
// Change the following to a preference (already in the Document Properties dialog)?
|
|
||||||
dimensions: [640, 480],
|
|
||||||
// EDITOR OPTIONS
|
|
||||||
// Change the following to preferences (already in the Editor Options dialog)?
|
|
||||||
gridSnapping: false,
|
|
||||||
gridColor: '#000',
|
|
||||||
baseUnit: 'px',
|
|
||||||
snappingStep: 10,
|
|
||||||
showRulers: true,
|
|
||||||
// URL BEHAVIOR CONFIGURATION
|
|
||||||
preventAllURLConfig: false,
|
|
||||||
preventURLContentLoading: false,
|
|
||||||
// EXTENSION CONFIGURATION (see also preventAllURLConfig)
|
|
||||||
lockExtensions: false, // Disallowed in URL setting
|
|
||||||
noDefaultExtensions: false, // noDefaultExtensions can only be meaningfully used in `svgedit-config-iife.js` or in the URL
|
|
||||||
// EXTENSION-RELATED (GRID)
|
|
||||||
showGrid: false, // Set by ext-grid.js
|
|
||||||
// EXTENSION-RELATED (STORAGE)
|
|
||||||
noStorageOnLoad: false, // Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
|
|
||||||
forceStorage: false, // Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
|
|
||||||
emptyStorageOnDecline: false, // Used by ext-storage.js; empty any prior storage if the user declines to store
|
|
||||||
// EXTENSION (CLIENT VS. SERVER SAVING/OPENING)
|
|
||||||
avoidClientSide: false, // Deprecated in favor of `avoidClientSideDownload`
|
|
||||||
avoidClientSideDownload: false,
|
|
||||||
avoidClientSideOpen: false
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* LOCALE.
|
* LOCALE.
|
||||||
* @name module:SVGEditor.uiStrings
|
* @name module:SVGEditor.uiStrings
|
||||||
|
@ -264,35 +92,10 @@ const defaultConfig = {
|
||||||
*/
|
*/
|
||||||
const uiStrings = editor.uiStrings = {};
|
const uiStrings = editor.uiStrings = {};
|
||||||
|
|
||||||
let svgCanvas, urldata = {},
|
let svgCanvas,
|
||||||
isReady = false,
|
isReady = false,
|
||||||
customExportImage = false,
|
customExportImage = false,
|
||||||
customExportPDF = false,
|
customExportPDF = false;
|
||||||
curPrefs = {},
|
|
||||||
// Note: The difference between Prefs and Config is that Prefs
|
|
||||||
// can be changed in the UI and are stored in the browser,
|
|
||||||
// while config cannot
|
|
||||||
curConfig = {
|
|
||||||
// We do not put on defaultConfig to simplify object copying
|
|
||||||
// procedures (we obtain instead from defaultExtensions)
|
|
||||||
extensions: [],
|
|
||||||
userExtensions: [],
|
|
||||||
/**
|
|
||||||
* Can use `location.origin` to indicate the current
|
|
||||||
* origin. Can contain a '*' to allow all domains or 'null' (as
|
|
||||||
* a string) to support all `file:///` URLs. Cannot be set by
|
|
||||||
* URL for security reasons (not safe, at least for
|
|
||||||
* privacy or data integrity of SVG content).
|
|
||||||
* Might have been fairly safe to allow
|
|
||||||
* `new URL(location.href).origin` by default but
|
|
||||||
* avoiding it ensures some more security that even third
|
|
||||||
* party apps on the same domain also cannot communicate
|
|
||||||
* with this app by default.
|
|
||||||
* For use with `ext-xdomain-messaging.js`
|
|
||||||
* @todo We might instead make as a user-facing preference.
|
|
||||||
*/
|
|
||||||
allowedOrigins: []
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -309,190 +112,16 @@ const loadSvgString = (str, {noAlert} = {}) => {
|
||||||
throw new Error('Error loading SVG');
|
throw new Error('Error loading SVG');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const configObj = new ConfigObj(editor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXPORTS.
|
* EXPORTS.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
editor.pref = configObj.pref.bind(configObj);
|
||||||
* Store and retrieve preferences.
|
editor.setConfig = configObj.setConfig.bind(configObj);
|
||||||
* @function module:SVGEditor.pref
|
editor.curPrefs = configObj.curPrefs;
|
||||||
* @param {string} key The preference name to be retrieved or set
|
editor.curConfig = configObj.curConfig;
|
||||||
* @param {string} [val] The value. If the value supplied is missing or falsey, no change to the preference will
|
|
||||||
* be made unless `mayBeEmpty` is set.
|
|
||||||
* @param {boolean} [mayBeEmpty] If value may be falsey.
|
|
||||||
* @returns {string|void} If val is missing or falsey and `mayBeEmpty` is not set, the
|
|
||||||
* value of the previously stored preference will be returned.
|
|
||||||
* @todo Review whether any remaining existing direct references to
|
|
||||||
* getting `curPrefs` can be changed to use `svgEditor.pref()` getting to ensure
|
|
||||||
* `defaultPrefs` fallback (also for sake of `allowInitialUserOverride`);
|
|
||||||
* specifically, `bkgd_color` could be changed so that the pref dialog has a
|
|
||||||
* button to auto-calculate background, but otherwise uses `svgEditor.pref()` to
|
|
||||||
* be able to get default prefs or overridable settings
|
|
||||||
*/
|
|
||||||
editor.pref = function (key, val, mayBeEmpty) {
|
|
||||||
if (mayBeEmpty || val) {
|
|
||||||
curPrefs[key] = val;
|
|
||||||
/**
|
|
||||||
* @name curPrefs
|
|
||||||
* @memberof module:SVGEditor
|
|
||||||
* @implements {module:SVGEditor.Prefs}
|
|
||||||
*/
|
|
||||||
editor.curPrefs = curPrefs; // Update exported value
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return (key in curPrefs) ? curPrefs[key] : defaultPrefs[key];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where permitted, sets canvas and/or `defaultPrefs` based on previous
|
|
||||||
* storage. This will override URL settings (for security reasons) but
|
|
||||||
* not `svgedit-config-iife.js` configuration (unless initial user
|
|
||||||
* overriding is explicitly permitted there via `allowInitialUserOverride`).
|
|
||||||
* @function module:SVGEditor.loadContentAndPrefs
|
|
||||||
* @todo Split `allowInitialUserOverride` into `allowOverrideByURL` and
|
|
||||||
* `allowOverrideByUserStorage` so `svgedit-config-iife.js` can disallow some
|
|
||||||
* individual items for URL setting but allow for user storage AND/OR
|
|
||||||
* change URL setting so that it always uses a different namespace,
|
|
||||||
* so it won't affect pre-existing user storage (but then if users saves
|
|
||||||
* that, it will then be subject to tampering
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
editor.loadContentAndPrefs = () => {
|
|
||||||
if (!curConfig.forceStorage &&
|
|
||||||
(curConfig.noStorageOnLoad ||
|
|
||||||
!document.cookie.match(/(?:^|;\s*)svgeditstore=(?:prefsAndContent|prefsOnly)/)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// LOAD CONTENT
|
|
||||||
if (editor.storage && // Cookies do not have enough available memory to hold large documents
|
|
||||||
(curConfig.forceStorage ||
|
|
||||||
(!curConfig.noStorageOnLoad &&
|
|
||||||
document.cookie.match(/(?:^|;\s*)svgeditstore=prefsAndContent/))
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const name = 'svgedit-' + curConfig.canvasName;
|
|
||||||
const cached = editor.storage.getItem(name);
|
|
||||||
if (cached) {
|
|
||||||
editor.loadFromString(cached);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LOAD PREFS
|
|
||||||
Object.keys(defaultPrefs).forEach((key) => {
|
|
||||||
const storeKey = 'svg-edit-' + key;
|
|
||||||
if (editor.storage) {
|
|
||||||
const val = editor.storage.getItem(storeKey);
|
|
||||||
if (val) {
|
|
||||||
defaultPrefs[key] = String(val); // Convert to string for FF (.value fails in Webkit)
|
|
||||||
}
|
|
||||||
} else if (window.widget) {
|
|
||||||
defaultPrefs[key] = window.widget.preferenceForKey(storeKey);
|
|
||||||
} else {
|
|
||||||
const result = document.cookie.match(
|
|
||||||
new RegExp('(?:^|;\\s*)' + Utils.regexEscape(
|
|
||||||
encodeURIComponent(storeKey)
|
|
||||||
) + '=([^;]+)')
|
|
||||||
);
|
|
||||||
defaultPrefs[key] = result ? decodeURIComponent(result[1]) : '';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows setting of preferences or configuration (including extensions).
|
|
||||||
* @function module:SVGEditor.setConfig
|
|
||||||
* @param {module:SVGEditor.Config|module:SVGEditor.Prefs} opts The preferences or configuration (including extensions). See the tutorial on {@tutorial ConfigOptions} for info on config and preferences.
|
|
||||||
* @param {PlainObject} [cfgCfg] Describes configuration which applies to the
|
|
||||||
* particular batch of supplied options
|
|
||||||
* @param {boolean} [cfgCfg.allowInitialUserOverride=false] Set to true if you wish
|
|
||||||
* to allow initial overriding of settings by the user via the URL
|
|
||||||
* (if permitted) or previously stored preferences (if permitted);
|
|
||||||
* note that it will be too late if you make such calls in extension
|
|
||||||
* code because the URL or preference storage settings will
|
|
||||||
* have already taken place.
|
|
||||||
* @param {boolean} [cfgCfg.overwrite=true] Set to false if you wish to
|
|
||||||
* prevent the overwriting of prior-set preferences or configuration
|
|
||||||
* (URL settings will always follow this requirement for security
|
|
||||||
* reasons, so `svgedit-config-iife.js` settings cannot be overridden unless it
|
|
||||||
* explicitly permits via `allowInitialUserOverride` but extension config
|
|
||||||
* can be overridden as they will run after URL settings). Should
|
|
||||||
* not be needed in `svgedit-config-iife.js`.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
editor.setConfig = function (opts, cfgCfg = {}) {
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {module:SVGEditor.Config|module:SVGEditor.Prefs} cfgObj
|
|
||||||
* @param {string} key
|
|
||||||
* @param {any} val See {@link module:SVGEditor.Config} or {@link module:SVGEditor.Prefs}
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
function extendOrAdd (cfgObj, key, val) {
|
|
||||||
if (cfgObj[key] && typeof cfgObj[key] === 'object') {
|
|
||||||
$.extend(true, cfgObj[key], val);
|
|
||||||
} else {
|
|
||||||
cfgObj[key] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object.entries(opts).forEach(function ([key, val]) {
|
|
||||||
// Only allow prefs defined in defaultPrefs or...
|
|
||||||
if ({}.hasOwnProperty.call(defaultPrefs, key)) {
|
|
||||||
if (cfgCfg.overwrite === false && (
|
|
||||||
curConfig.preventAllURLConfig ||
|
|
||||||
{}.hasOwnProperty.call(curPrefs, key)
|
|
||||||
)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (cfgCfg.allowInitialUserOverride === true) {
|
|
||||||
defaultPrefs[key] = val;
|
|
||||||
} else {
|
|
||||||
editor.pref(key, val);
|
|
||||||
}
|
|
||||||
} else if (['extensions', 'userExtensions', 'allowedOrigins'].includes(key)) {
|
|
||||||
if (cfgCfg.overwrite === false &&
|
|
||||||
(
|
|
||||||
curConfig.preventAllURLConfig ||
|
|
||||||
['allowedOrigins'].includes(key) ||
|
|
||||||
(key === 'extensions' && curConfig.lockExtensions)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
curConfig[key] = curConfig[key].concat(val); // We will handle any dupes later
|
|
||||||
// Only allow other curConfig if defined in defaultConfig
|
|
||||||
} else if ({}.hasOwnProperty.call(defaultConfig, key)) {
|
|
||||||
if (cfgCfg.overwrite === false && (
|
|
||||||
curConfig.preventAllURLConfig ||
|
|
||||||
{}.hasOwnProperty.call(curConfig, key)
|
|
||||||
)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Potentially overwriting of previously set config
|
|
||||||
if ({}.hasOwnProperty.call(curConfig, key)) {
|
|
||||||
if (cfgCfg.overwrite === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
extendOrAdd(curConfig, key, val);
|
|
||||||
} else if (cfgCfg.allowInitialUserOverride === true) {
|
|
||||||
extendOrAdd(defaultConfig, key, val);
|
|
||||||
} else if (defaultConfig[key] && typeof defaultConfig[key] === 'object') {
|
|
||||||
curConfig[key] = Array.isArray(defaultConfig[key]) ? [] : {};
|
|
||||||
$.extend(true, curConfig[key], val); // Merge properties recursively, e.g., on initFill, initStroke objects
|
|
||||||
} else {
|
|
||||||
curConfig[key] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
/**
|
|
||||||
* @name curConfig
|
|
||||||
* @memberof module:SVGEditor
|
|
||||||
* @implements {module:SVGEditor.Config}
|
|
||||||
*/
|
|
||||||
editor.curConfig = curConfig; // Update exported value
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All methods are optional.
|
* All methods are optional.
|
||||||
|
@ -607,117 +236,10 @@ editor.init = () => {
|
||||||
document.body.append(newSeEditPrefsDialog);
|
document.body.append(newSeEditPrefsDialog);
|
||||||
} catch (err) {}
|
} catch (err) {}
|
||||||
|
|
||||||
|
configObj.load();
|
||||||
|
|
||||||
// eslint-disable-next-line max-len
|
// eslint-disable-next-line max-len
|
||||||
const goodLangs = ['ar', 'cs', 'de', 'en', 'es', 'fa', 'fr', 'fy', 'hi', 'it', 'ja', 'nl', 'pl', 'pt-BR', 'ro', 'ru', 'sk', 'sl', 'zh-CN', 'zh-TW'];
|
const goodLangs = ['ar', 'cs', 'de', 'en', 'es', 'fa', 'fr', 'fy', 'hi', 'it', 'ja', 'nl', 'pl', 'pt-BR', 'ro', 'ru', 'sk', 'sl', 'zh-CN', 'zh-TW'];
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up current preferences based on defaults.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
function setupCurPrefs () {
|
|
||||||
curPrefs = {...defaultPrefs, ...curPrefs}; // Now safe to merge with priority for curPrefs in the event any are already set
|
|
||||||
// Export updated prefs
|
|
||||||
editor.curPrefs = curPrefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up current config based on defaults.
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
function setupCurConfig () {
|
|
||||||
curConfig = {...defaultConfig, ...curConfig}; // Now safe to merge with priority for curConfig in the event any are already set
|
|
||||||
|
|
||||||
// Now deal with extensions and other array config
|
|
||||||
if (!curConfig.noDefaultExtensions) {
|
|
||||||
curConfig.extensions = curConfig.extensions.concat(defaultExtensions);
|
|
||||||
}
|
|
||||||
// ...and remove any dupes
|
|
||||||
['extensions', 'allowedOrigins'].forEach(function (cfg) {
|
|
||||||
curConfig[cfg] = $.grep(curConfig[cfg], function (n, i) { // Supposedly faster than filter per http://amandeep1986.blogspot.hk/2015/02/jquery-grep-vs-js-filter.html
|
|
||||||
return i === curConfig[cfg].indexOf(n);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
// Export updated config
|
|
||||||
editor.curConfig = curConfig;
|
|
||||||
}
|
|
||||||
(() => {
|
|
||||||
// Load config/data from URL if given
|
|
||||||
const {search, searchParams} = new URL(location);
|
|
||||||
|
|
||||||
if (search) {
|
|
||||||
urldata = deparam(searchParams.toString(), true);
|
|
||||||
|
|
||||||
['initStroke', 'initFill'].forEach((prop) => {
|
|
||||||
if (searchParams.has(`${prop}[color]`)) {
|
|
||||||
// Restore back to original non-deparamed value to avoid color
|
|
||||||
// strings being converted to numbers
|
|
||||||
urldata[prop].color = searchParams.get(`${prop}[color]`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (searchParams.has('bkgd_color')) {
|
|
||||||
urldata.bkgd_color = '#' + searchParams.get('bkgd_color');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urldata.dimensions) {
|
|
||||||
urldata.dimensions = urldata.dimensions.split(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (urldata.extensions) {
|
|
||||||
// For security reasons, disallow cross-domain or cross-folder
|
|
||||||
// extensions via URL
|
|
||||||
urldata.extensions = urldata.extensions.match(/[:/\\]/)
|
|
||||||
? ''
|
|
||||||
: urldata.extensions.split(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Disallowing extension paths via URL for
|
|
||||||
// security reasons, even for same-domain
|
|
||||||
// ones given potential to interact in undesirable
|
|
||||||
// ways with other script resources
|
|
||||||
['userExtensions', 'imgPath']
|
|
||||||
.forEach(function (pathConfig) {
|
|
||||||
if (urldata[pathConfig]) {
|
|
||||||
delete urldata[pathConfig];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Note: `source` and `url` (as with `storagePrompt` later) are not
|
|
||||||
// set on config but are used below
|
|
||||||
editor.setConfig(urldata, {overwrite: false});
|
|
||||||
setupCurConfig();
|
|
||||||
|
|
||||||
if (!curConfig.preventURLContentLoading) {
|
|
||||||
let {source} = urldata;
|
|
||||||
if (!source) { // urldata.source may have been null if it ended with '='
|
|
||||||
const src = searchParams.get('source');
|
|
||||||
if (src && src.startsWith('data:')) {
|
|
||||||
source = src;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (source) {
|
|
||||||
if (source.startsWith('data:')) {
|
|
||||||
editor.loadFromDataURI(source);
|
|
||||||
} else {
|
|
||||||
editor.loadFromString(source);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (urldata.url) {
|
|
||||||
editor.loadFromURL(urldata.url);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!urldata.noStorageOnLoad || curConfig.forceStorage) {
|
|
||||||
editor.loadContentAndPrefs();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setupCurConfig();
|
|
||||||
editor.loadContentAndPrefs();
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
setupCurPrefs();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @fires module:svgcanvas.SvgCanvas#event:ext_addLangData
|
* @fires module:svgcanvas.SvgCanvas#event:ext_addLangData
|
||||||
* @fires module:svgcanvas.SvgCanvas#event:ext_langReady
|
* @fires module:svgcanvas.SvgCanvas#event:ext_langReady
|
||||||
|
@ -737,7 +259,7 @@ editor.init = () => {
|
||||||
try {
|
try {
|
||||||
// load standard extensions
|
// load standard extensions
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
curConfig.extensions.map(async (extname) => {
|
configObj.curConfig.extensions.map(async (extname) => {
|
||||||
/**
|
/**
|
||||||
* @tutorial ExtensionDocs
|
* @tutorial ExtensionDocs
|
||||||
* @typedef {PlainObject} module:SVGEditor.ExtensionObject
|
* @typedef {PlainObject} module:SVGEditor.ExtensionObject
|
||||||
|
@ -760,7 +282,7 @@ editor.init = () => {
|
||||||
);
|
);
|
||||||
// load user extensions (given as pathNames)
|
// load user extensions (given as pathNames)
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
curConfig.userExtensions.map(async (extPathName) => {
|
configObj.curConfig.userExtensions.map(async (extPathName) => {
|
||||||
/**
|
/**
|
||||||
* @tutorial ExtensionDocs
|
* @tutorial ExtensionDocs
|
||||||
* @typedef {PlainObject} module:SVGEditor.ExtensionObject
|
* @typedef {PlainObject} module:SVGEditor.ExtensionObject
|
||||||
|
@ -842,7 +364,7 @@ editor.init = () => {
|
||||||
*/
|
*/
|
||||||
editor.canvas = svgCanvas = new SvgCanvas(
|
editor.canvas = svgCanvas = new SvgCanvas(
|
||||||
$id('svgcanvas'),
|
$id('svgcanvas'),
|
||||||
curConfig
|
configObj.curConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -855,7 +377,7 @@ editor.init = () => {
|
||||||
if (!Utils.isNullish(elem) && !elem.parentNode) { elem = null; }
|
if (!Utils.isNullish(elem) && !elem.parentNode) { elem = null; }
|
||||||
const currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName();
|
const currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName();
|
||||||
const currentMode = svgCanvas.getMode();
|
const currentMode = svgCanvas.getMode();
|
||||||
const unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null;
|
const unit = configObj.curConfig.baseUnit !== 'px' ? configObj.curConfig.baseUnit : null;
|
||||||
|
|
||||||
const isNode = currentMode === 'pathedit'; // elem ? (elem.id && elem.id.startsWith('pathpointgrip')) : false;
|
const isNode = currentMode === 'pathedit'; // elem ? (elem.id && elem.id.startsWith('pathpointgrip')) : false;
|
||||||
const menuItems = $('#cmenu_canvas li');
|
const menuItems = $('#cmenu_canvas li');
|
||||||
|
@ -992,7 +514,7 @@ editor.init = () => {
|
||||||
|
|
||||||
$.each(curPanel, function (i, item) {
|
$.each(curPanel, function (i, item) {
|
||||||
let attrVal = elem.getAttribute(item);
|
let attrVal = elem.getAttribute(item);
|
||||||
if (curConfig.baseUnit !== 'px' && elem[item]) {
|
if (configObj.curConfig.baseUnit !== 'px' && elem[item]) {
|
||||||
const bv = elem[item].baseVal.value;
|
const bv = elem[item].baseVal.value;
|
||||||
attrVal = convertUnit(bv);
|
attrVal = convertUnit(bv);
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +589,7 @@ editor.init = () => {
|
||||||
const paintBox = {fill: null, stroke: null};
|
const paintBox = {fill: null, stroke: null};
|
||||||
|
|
||||||
let exportWindow = null,
|
let exportWindow = null,
|
||||||
defaultImageURL = curConfig.imgPath + 'logo.svg',
|
defaultImageURL = configObj.curConfig.imgPath + 'logo.svg',
|
||||||
zoomInIcon = 'crosshair',
|
zoomInIcon = 'crosshair',
|
||||||
zoomOutIcon = 'crosshair',
|
zoomOutIcon = 'crosshair',
|
||||||
uiContext = 'toolbars';
|
uiContext = 'toolbars';
|
||||||
|
@ -1368,7 +890,7 @@ editor.init = () => {
|
||||||
const limit = 30000;
|
const limit = 30000;
|
||||||
const contentElem = svgCanvas.getContentElem();
|
const contentElem = svgCanvas.getContentElem();
|
||||||
const units = getTypeMap();
|
const units = getTypeMap();
|
||||||
const unit = units[curConfig.baseUnit]; // 1 = 1px
|
const unit = units[configObj.curConfig.baseUnit]; // 1 = 1px
|
||||||
|
|
||||||
// draw x ruler then y ruler
|
// draw x ruler then y ruler
|
||||||
for (d = 0; d < 2; d++) {
|
for (d = 0; d < 2; d++) {
|
||||||
|
@ -1528,7 +1050,7 @@ editor.init = () => {
|
||||||
x: wArea[0].scrollLeft + wOrig / 2,
|
x: wArea[0].scrollLeft + wOrig / 2,
|
||||||
y: wArea[0].scrollTop + hOrig / 2
|
y: wArea[0].scrollTop + hOrig / 2
|
||||||
};
|
};
|
||||||
const multi = curConfig.canvas_expansion;
|
const multi = configObj.curConfig.canvas_expansion;
|
||||||
w = Math.max(wOrig, svgCanvas.contentW * zoom * multi);
|
w = Math.max(wOrig, svgCanvas.contentW * zoom * multi);
|
||||||
h = Math.max(hOrig, svgCanvas.contentH * zoom * multi);
|
h = Math.max(hOrig, svgCanvas.contentH * zoom * multi);
|
||||||
|
|
||||||
|
@ -1581,12 +1103,12 @@ editor.init = () => {
|
||||||
wArea[0].scrollLeft = newCtr.x - wOrig / 2;
|
wArea[0].scrollLeft = newCtr.x - wOrig / 2;
|
||||||
wArea[0].scrollTop = newCtr.y - hOrig / 2;
|
wArea[0].scrollTop = newCtr.y - hOrig / 2;
|
||||||
}
|
}
|
||||||
if (curConfig.showRulers) {
|
if (configObj.curConfig.showRulers) {
|
||||||
updateRulers(cnvs, zoom);
|
updateRulers(cnvs, zoom);
|
||||||
workarea.scroll();
|
workarea.scroll();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (urldata.storagePrompt !== true && editor.storagePromptState === 'ignore') {
|
if (configObj.urldata.storagePrompt !== true && editor.storagePromptState === 'ignore') {
|
||||||
$('#dialog_box').hide();
|
$('#dialog_box').hide();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2207,9 +1729,9 @@ editor.init = () => {
|
||||||
|
|
||||||
// update resolution option with actual resolution
|
// update resolution option with actual resolution
|
||||||
const res = svgCanvas.getResolution();
|
const res = svgCanvas.getResolution();
|
||||||
if (curConfig.baseUnit !== 'px') {
|
if (configObj.curConfig.baseUnit !== 'px') {
|
||||||
res.w = convertUnit(res.w) + curConfig.baseUnit;
|
res.w = convertUnit(res.w) + configObj.curConfig.baseUnit;
|
||||||
res.h = convertUnit(res.h) + curConfig.baseUnit;
|
res.h = convertUnit(res.h) + configObj.curConfig.baseUnit;
|
||||||
}
|
}
|
||||||
$('#se-img-prop').attr('dialog', 'close');
|
$('#se-img-prop').attr('dialog', 'close');
|
||||||
$('#se-img-prop').attr('title', svgCanvas.getDocumentTitle());
|
$('#se-img-prop').attr('title', svgCanvas.getDocumentTitle());
|
||||||
|
@ -2353,13 +1875,13 @@ editor.init = () => {
|
||||||
if (attr !== 'id' && attr !== 'class') {
|
if (attr !== 'id' && attr !== 'class') {
|
||||||
if (isNaN(val)) {
|
if (isNaN(val)) {
|
||||||
val = svgCanvas.convertToNum(attr, val);
|
val = svgCanvas.convertToNum(attr, val);
|
||||||
} else if (curConfig.baseUnit !== 'px') {
|
} else if (configObj.curConfig.baseUnit !== 'px') {
|
||||||
// Convert unitless value to one with given unit
|
// Convert unitless value to one with given unit
|
||||||
|
|
||||||
const unitData = getTypeMap();
|
const unitData = getTypeMap();
|
||||||
|
|
||||||
if (selectedElement[attr] || svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') {
|
if (selectedElement[attr] || svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') {
|
||||||
val *= unitData[curConfig.baseUnit];
|
val *= unitData[configObj.curConfig.baseUnit];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2391,13 +1913,13 @@ editor.init = () => {
|
||||||
if (attr !== 'id' && attr !== 'class') {
|
if (attr !== 'id' && attr !== 'class') {
|
||||||
if (isNaN(val)) {
|
if (isNaN(val)) {
|
||||||
val = svgCanvas.convertToNum(attr, val);
|
val = svgCanvas.convertToNum(attr, val);
|
||||||
} else if (curConfig.baseUnit !== 'px') {
|
} else if (configObj.curConfig.baseUnit !== 'px') {
|
||||||
// Convert unitless value to one with given unit
|
// Convert unitless value to one with given unit
|
||||||
|
|
||||||
const unitData = getTypeMap();
|
const unitData = getTypeMap();
|
||||||
|
|
||||||
if (selectedElement[attr] || svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') {
|
if (selectedElement[attr] || svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') {
|
||||||
val *= unitData[curConfig.baseUnit];
|
val *= unitData[configObj.curConfig.baseUnit];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2933,9 +2455,9 @@ editor.init = () => {
|
||||||
*/
|
*/
|
||||||
const moveSelected = function (dx, dy) {
|
const moveSelected = function (dx, dy) {
|
||||||
if (!Utils.isNullish(selectedElement) || multiselected) {
|
if (!Utils.isNullish(selectedElement) || multiselected) {
|
||||||
if (curConfig.gridSnapping) {
|
if (configObj.curConfig.gridSnapping) {
|
||||||
// Use grid snap value regardless of zoom level
|
// Use grid snap value regardless of zoom level
|
||||||
const multi = svgCanvas.getZoom() * curConfig.snappingStep;
|
const multi = svgCanvas.getZoom() * configObj.curConfig.snappingStep;
|
||||||
dx *= multi;
|
dx *= multi;
|
||||||
dy *= multi;
|
dy *= multi;
|
||||||
}
|
}
|
||||||
|
@ -3027,7 +2549,7 @@ editor.init = () => {
|
||||||
* @returns {Promise<void>} Resolves to `undefined`
|
* @returns {Promise<void>} Resolves to `undefined`
|
||||||
*/
|
*/
|
||||||
const clickClear = async () => {
|
const clickClear = async () => {
|
||||||
const [x, y] = curConfig.dimensions;
|
const [x, y] = configObj.curConfig.dimensions;
|
||||||
const ok = await $.confirm(uiStrings.notification.QwantToClear);
|
const ok = await $.confirm(uiStrings.notification.QwantToClear);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
|
@ -3112,10 +2634,10 @@ editor.init = () => {
|
||||||
*/
|
*/
|
||||||
function openExportWindow () {
|
function openExportWindow () {
|
||||||
const {loadingImage} = uiStrings.notification;
|
const {loadingImage} = uiStrings.notification;
|
||||||
if (curConfig.exportWindowType === 'new') {
|
if (configObj.curConfig.exportWindowType === 'new') {
|
||||||
editor.exportWindowCt++;
|
editor.exportWindowCt++;
|
||||||
}
|
}
|
||||||
exportWindowName = curConfig.canvasName + editor.exportWindowCt;
|
exportWindowName = configObj.curConfig.canvasName + editor.exportWindowCt;
|
||||||
let popHTML, popURL;
|
let popHTML, popURL;
|
||||||
if (loadingURL) {
|
if (loadingURL) {
|
||||||
popURL = loadingURL;
|
popURL = loadingURL;
|
||||||
|
@ -3269,9 +2791,9 @@ editor.init = () => {
|
||||||
|
|
||||||
// update resolution option with actual resolution
|
// update resolution option with actual resolution
|
||||||
const resolution = svgCanvas.getResolution();
|
const resolution = svgCanvas.getResolution();
|
||||||
if (curConfig.baseUnit !== 'px') {
|
if (configObj.curConfig.baseUnit !== 'px') {
|
||||||
resolution.w = convertUnit(resolution.w) + curConfig.baseUnit;
|
resolution.w = convertUnit(resolution.w) + configObj.curConfig.baseUnit;
|
||||||
resolution.h = convertUnit(resolution.h) + curConfig.baseUnit;
|
resolution.h = convertUnit(resolution.h) + configObj.curConfig.baseUnit;
|
||||||
}
|
}
|
||||||
$imgDialog.setAttribute('save', editor.pref('img_save'));
|
$imgDialog.setAttribute('save', editor.pref('img_save'));
|
||||||
$imgDialog.setAttribute('width', resolution.w);
|
$imgDialog.setAttribute('width', resolution.w);
|
||||||
|
@ -3290,14 +2812,14 @@ editor.init = () => {
|
||||||
const $editDialog = document.getElementById('se-edit-prefs');
|
const $editDialog = document.getElementById('se-edit-prefs');
|
||||||
$('#main_menu').hide();
|
$('#main_menu').hide();
|
||||||
// Update background color with current one
|
// Update background color with current one
|
||||||
const canvasBg = curPrefs.bkgd_color;
|
const canvasBg = configObj.curPrefs.bkgd_color;
|
||||||
const url = editor.pref('bkgd_url');
|
const url = editor.pref('bkgd_url');
|
||||||
if (url) {
|
if (url) {
|
||||||
$editDialog.setAttribute('bgurl', url);
|
$editDialog.setAttribute('bgurl', url);
|
||||||
}
|
}
|
||||||
$editDialog.setAttribute('gridsnappingon', curConfig.gridSnapping);
|
$editDialog.setAttribute('gridsnappingon', configObj.curConfig.gridSnapping);
|
||||||
$editDialog.setAttribute('gridsnappingstep', curConfig.snappingStep);
|
$editDialog.setAttribute('gridsnappingstep', configObj.curConfig.snappingStep);
|
||||||
$editDialog.setAttribute('gridcolor', curConfig.gridColor);
|
$editDialog.setAttribute('gridcolor', configObj.curConfig.gridColor);
|
||||||
$editDialog.setAttribute('canvasbg', canvasBg);
|
$editDialog.setAttribute('canvasbg', canvasBg);
|
||||||
$editDialog.setAttribute('dialog', 'open');
|
$editDialog.setAttribute('dialog', 'open');
|
||||||
};
|
};
|
||||||
|
@ -3416,16 +2938,16 @@ editor.init = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set grid setting
|
// set grid setting
|
||||||
curConfig.gridSnapping = gridsnappingon;
|
configObj.curConfig.gridSnapping = gridsnappingon;
|
||||||
curConfig.snappingStep = gridsnappingstep;
|
configObj.curConfig.snappingStep = gridsnappingstep;
|
||||||
curConfig.gridColor = gridcolor;
|
configObj.curConfig.gridColor = gridcolor;
|
||||||
curConfig.showRulers = showrulers;
|
configObj.curConfig.showRulers = showrulers;
|
||||||
|
|
||||||
$('#rulers').toggle(curConfig.showRulers);
|
$('#rulers').toggle(configObj.curConfig.showRulers);
|
||||||
if (curConfig.showRulers) { updateRulers(); }
|
if (configObj.curConfig.showRulers) { updateRulers(); }
|
||||||
curConfig.baseUnit = baseunit;
|
configObj.curConfig.baseUnit = baseunit;
|
||||||
|
|
||||||
svgCanvas.setConfig(curConfig);
|
svgCanvas.setConfig(configObj.curConfig);
|
||||||
updateCanvas();
|
updateCanvas();
|
||||||
hidePreferences();
|
hidePreferences();
|
||||||
};
|
};
|
||||||
|
@ -3501,13 +3023,13 @@ editor.init = () => {
|
||||||
cancel: '.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker',
|
cancel: '.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker',
|
||||||
containment: 'window'
|
containment: 'window'
|
||||||
})
|
})
|
||||||
.css(curConfig.colorPickerCSS || {left: pos.left - 140, bottom: 40})
|
.css(configObj.curConfig.colorPickerCSS || {left: pos.left - 140, bottom: 40})
|
||||||
.jGraduate(
|
.jGraduate(
|
||||||
{
|
{
|
||||||
images: {clientPath: './jgraduate/images/'},
|
images: {clientPath: './jgraduate/images/'},
|
||||||
paint,
|
paint,
|
||||||
window: {pickerTitle: title},
|
window: {pickerTitle: title},
|
||||||
// images: {clientPath: curConfig.imgPath},
|
// images: {clientPath: configObj.curConfig.imgPath},
|
||||||
newstop: 'inverse'
|
newstop: 'inverse'
|
||||||
},
|
},
|
||||||
function (p) {
|
function (p) {
|
||||||
|
@ -3531,7 +3053,7 @@ editor.init = () => {
|
||||||
* @param {"fill"} type
|
* @param {"fill"} type
|
||||||
*/
|
*/
|
||||||
constructor (container, type) {
|
constructor (container, type) {
|
||||||
const cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke'];
|
const cur = configObj.curConfig[type === 'fill' ? 'initFill' : 'initStroke'];
|
||||||
// set up gradients to be used for the buttons
|
// set up gradients to be used for the buttons
|
||||||
const svgdocbox = new DOMParser().parseFromString(
|
const svgdocbox = new DOMParser().parseFromString(
|
||||||
`<svg xmlns="http://www.w3.org/2000/svg" width="16.5" height="16.5">
|
`<svg xmlns="http://www.w3.org/2000/svg" width="16.5" height="16.5">
|
||||||
|
@ -3671,8 +3193,8 @@ editor.init = () => {
|
||||||
paintBox.fill = new PaintBox('#fill_color', 'fill');
|
paintBox.fill = new PaintBox('#fill_color', 'fill');
|
||||||
paintBox.stroke = new PaintBox('#stroke_color', 'stroke');
|
paintBox.stroke = new PaintBox('#stroke_color', 'stroke');
|
||||||
|
|
||||||
$('#stroke_width').val(curConfig.initStroke.width);
|
$('#stroke_width').val(configObj.curConfig.initStroke.width);
|
||||||
$('#group_opacity').val(curConfig.initOpacity * 100);
|
$('#group_opacity').val(configObj.curConfig.initOpacity * 100);
|
||||||
|
|
||||||
// Use this SVG elem to test vectorEffect support
|
// Use this SVG elem to test vectorEffect support
|
||||||
const testEl = paintBox.fill.rect.cloneNode(false);
|
const testEl = paintBox.fill.rect.cloneNode(false);
|
||||||
|
@ -4135,8 +3657,8 @@ editor.init = () => {
|
||||||
|
|
||||||
// Select given tool
|
// Select given tool
|
||||||
editor.ready(function () {
|
editor.ready(function () {
|
||||||
const preTool = $id(`tool_${curConfig.initTool}`);
|
const preTool = $id(`tool_${configObj.curConfig.initTool}`);
|
||||||
const regTool = $id(curConfig.initTool);
|
const regTool = $id(configObj.curConfig.initTool);
|
||||||
const selectTool = $id('tool_select');
|
const selectTool = $id('tool_select');
|
||||||
const $editDialog = $id('se-edit-prefs');
|
const $editDialog = $id('se-edit-prefs');
|
||||||
|
|
||||||
|
@ -4148,34 +3670,34 @@ editor.init = () => {
|
||||||
selectTool.click();
|
selectTool.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curConfig.wireframe) {
|
if (configObj.curConfig.wireframe) {
|
||||||
$id('tool_wireframe').click();
|
$id('tool_wireframe').click();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curConfig.showlayers) {
|
if (configObj.curConfig.showlayers) {
|
||||||
toggleSidePanel();
|
toggleSidePanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#rulers').toggle(Boolean(curConfig.showRulers));
|
$('#rulers').toggle(Boolean(configObj.curConfig.showRulers));
|
||||||
|
|
||||||
if (curConfig.showRulers) {
|
if (configObj.curConfig.showRulers) {
|
||||||
$editDialog.setAttribute('showrulers', true);
|
$editDialog.setAttribute('showrulers', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curConfig.baseUnit) {
|
if (configObj.curConfig.baseUnit) {
|
||||||
$editDialog.setAttribute('baseunit', curConfig.baseUnit);
|
$editDialog.setAttribute('baseunit', configObj.curConfig.baseUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curConfig.gridSnapping) {
|
if (configObj.curConfig.gridSnapping) {
|
||||||
$editDialog.setAttribute('gridsnappingon', true);
|
$editDialog.setAttribute('gridsnappingon', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curConfig.snappingStep) {
|
if (configObj.curConfig.snappingStep) {
|
||||||
$editDialog.setAttribute('gridsnappingstep', curConfig.snappingStep);
|
$editDialog.setAttribute('gridsnappingstep', configObj.curConfig.snappingStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curConfig.gridColor) {
|
if (configObj.curConfig.gridColor) {
|
||||||
$editDialog.setAttribute('gridcolor', curConfig.gridColor);
|
$editDialog.setAttribute('gridcolor', configObj.curConfig.gridColor);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4265,7 +3787,7 @@ editor.init = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// showSaveWarning is set to 'false' when the page is saved.
|
// showSaveWarning is set to 'false' when the page is saved.
|
||||||
if (!curConfig.no_save_warning && editor.showSaveWarning) {
|
if (!configObj.curConfig.no_save_warning && editor.showSaveWarning) {
|
||||||
// Browser already asks question about closing the page
|
// Browser already asks question about closing the page
|
||||||
e.returnValue = uiStrings.notification.unsavedChanges; // Firefox needs this when beforeunload set by addEventListener (even though message is not used)
|
e.returnValue = uiStrings.notification.unsavedChanges; // Firefox needs this when beforeunload set by addEventListener (even though message is not used)
|
||||||
return uiStrings.notification.unsavedChanges;
|
return uiStrings.notification.unsavedChanges;
|
||||||
|
@ -4650,12 +4172,10 @@ editor.loadFromDataURI = function (str, {noAlert} = {}) {
|
||||||
editor.addExtension = (name, init, initArgs) => {
|
editor.addExtension = (name, init, initArgs) => {
|
||||||
// Note that we don't want this on editor.ready since some extensions
|
// Note that we don't want this on editor.ready since some extensions
|
||||||
// may want to run before then (like server_opensave).
|
// may want to run before then (like server_opensave).
|
||||||
// $(() => {
|
|
||||||
if (!svgCanvas) {
|
if (!svgCanvas) {
|
||||||
throw new Error('Extension added too early');
|
throw new Error('Extension added too early');
|
||||||
}
|
}
|
||||||
return svgCanvas.addExtension.call(this, name, init, initArgs);
|
return svgCanvas.addExtension.call(editor, name, init, initArgs);
|
||||||
// });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Defer injection to wait out initial menu processing. This probably goes
|
// Defer injection to wait out initial menu processing. This probably goes
|
||||||
|
|
Loading…
Reference in New Issue