编辑 | blame | 历史 | 原始文档

Version 3.0.0

3.0.0 offers a number of changes since 2.8.1, including many refactoring
ones meant to make the code more maintainable and leverage current standards
for more readable and semantic code, as well as a good number of fixes and
enhancements.

Please see the CHANGES file (or the Git history or Github tracker) for more
detailed descriptions of individual changes than that provided by the
below summaries.

Concomitant with switching to npm (semantic) versioning, future releases
should be added for any changes on a more frequent schedule.

Breaking changes

There were also the following breaking changes. Not included among these are
those handful of breaking changes which only applied to those adopting
3.0.0 pre-release versions and which are marked as
"Breaking change (prerelease)" in CHANGES).

Modularization-related breaking changes

A number of changes were made to improve modularization.

Source code converted to ES6 Modules

If you were modifying source files directly, the module format has now changed
to ES6 Modules. This allows us to specify, in a standard fashion, all of
the external dependencies of a file, without any "magic" variables appearing
in the code with no indication of their source (unless they are browser
globals which should be well-known). Use of modules also avoids the need
to keep track of dependencies non-contextually within the HTML and allows us
to avoid polluting our HTML with additional script tags.

File names were also changed. See "Other breaking changes" for these.

Note that compilation no longer occurs with a Makefile but is handled by
Rollup, a library for bundling ES6 Modules. Our Rollup routine also
handles applying Babel and minification.

Note that while the number of script tags in the HTML has been reduced,
certain polyfill files (dom-polyfill and @babel/polyfill) have now been
added and are required for older browsers. They could be dropped in the
future once browser support is available or if you are only targeting
browser versions that have no need of them.

For ES6 Modules being available as a distribution option, see "Enhancements".

Design choices for applying modules (Technical)

The jQuery files have not been added in ES6 Modules format, however, because
they do not have such a distribution and adding an import in source which
converts them to ES6 Modules through plugin would require compilation
whereas we'd prefer that at least the modular editor file be able to work
without compilation for faster debugging (note, however, that rather than
importing our external npm dependencies directly from node_modules, we
have a copy-deps script for copying these files into our repository, so
experimenting on these files should probably be done within the
editor/external directory and such changes must not be committed unless
the source packages are also updated and the copy-deps routine brings them
in).

The file redirect-on-lacking-support.js has not been bundled with the main
svgedit-config-es.js script so that browsers not supporting SVG are
redirected faster (and, in the same vein as polyfills, it may be more
logically consistent to add this external to the main code anyways).

The file redirect-on-no-module-support.js, which redirects when module
support is not available, is not bundled for the same type of reason.

JavaScript config file breaking changes

Unlike version 2.8.1 which had a config-sample.js file which needed
to be copied to config.js in the same editor directory, in version 3.0.0,
things work out of the box by pointing to the pre-built config files (also
an advantage for our use of Github-based project hosts like
raw.githack.com), but these config files have been moved out of the
editor folder and are looked for in the parent directory (project root
if using the editor within our repository).

These files also now have different names (svgedit-config-es.js
for svg-editor-es.html and svgedit-config-iife.js for svg-editor.html)
for a measure of namespacing.

This move is intended to allow config to be stored semi-independently
of editor files.

Also note that while the config file was optional in 2.8.1, the config
file in 3.* includes (or for, the ES version, imports) all of the main
SVG-Edit code, so the file (or one like it) cannot be omitted. This has
the advantage of avoiding an extra script tag and for the non-ES version,
an extra HTTP request. But if you are working with the non-modular HTML
and are not running the build routines to compile ES to non-modular
JavaScript, you will be required to directly modify your config within
the large non-modular, bundled JavaScript config file that includes most
of the SVG codebase.

The build routines include npm run build-config to convert the
JavaScript config to non-modular form, npm run rollup to convert the other
source files to non-modular form, and npm run build-html to build the
non-modular HTML out of the modular HTML (all of these are run during
npm run test-prep, or if you want to run the tests, also as a part of
npm test and npm run browser-test).

Stylesheet breaking changes

In version 2.8.1, one could place a custom.css file in the same directory
as the editor and it would be used.

The default is now looked for in the parent directory of the editor HTML
and is expected as svgedit-custom.css.

You may change the stylesheets which are loaded by changing the default
JavaScript stylesheet config (see the
"JavaScript config file breaking changes" section for the location of
these files). The default behavior is equivalent to this:

svgEditor.setConfig({
  stylesheets: ['@default', '../svgedit-custom.css']
});

...which indicates that all default stylesheets will be loaded and then
one's custom file. You may omit either of these and/or add your own.

See "Other breaking changes -> HTML" for removal of the "scoped"
attribute on a stylesheet within the HTML.

Base path breaking changes

With extensions and locales now also expressed as ES6 modules in source
(see their respective breaking changes section below), the non-modular
versions of these files have been compiled into the new dist directory,
and in order to avoid path resolution problems, the config properties
extPath and langPath now have different defaults, depending
on whether a module environment is detected or not.

The non-modular versions will now default to ../dist/extensions/ and
../dist/locale/, respectively, whereas the modular version will use the
old default paths (extensions/ and locale/).

Also, since we have not copying extension icons over to dist and the path
resolution of extension icons would otherwise break, we have now added new
a config property, extIconsPath, distinct from extPath, which points
by default to extensions/ for both modular and non-modular environments.

And because our dependencies canvg and jspdf are now building from module
and would break as a result of this move as well, we have added the config
canvgPath and jspdfPath which default respectively to canvg/ and
jspdf/ in modular loads and to ../dist/ for both path types within
non-modular loads.

(imgPath and jGraduatePath remain unchanged since they, as with
extIconsPath, are not looking for module-expressed files.)

Locale breaking changes

Locale files are now formatted as ES6 Module exports (rather than as
calls to svgEditor.readLang).

In order for their value to be discovered when compiled and loaded
in a non-modular context, in such contexts they will be auto-defined
as global variables (as "svgEditorLang_" followed by the
locale file name with any hyphens replaced as underscores).

In the spirit of modularization and only loading what is needed,
locale strings pertaining solely to extensions were moved to
editor/extensons/ext-locale/<extension name>/<language code>.js.

A new method, importLocale, is passed to extensions (see
"Summary of enhancements -> APIs") which can load locale files within
this hierarchy, requiring no arguments if relying on the detected locale.

The npm run rollup routine (also a part of npm run test-prep or
the full test routines) will build any properly named and formatted ES6
Modules locale file into a non-modular file within dist/locale.

Extension breaking changes

Extension files are now formatted as ES6 Module exports (rather than as
calls to svgEditor.addExtension). The latter may still be used, but
support for passing an object (with a callback method as an init function)
is not (callback may be present on the return object of extension init
method, however).

In order for their value to be discovered when compiled and loaded
in a non-modular context, in such contexts they will be auto-defined
as global variables (as "svgEditorExtension_" followed by the
extension file name with any hyphens replaced as underscores).

The name supplied as the first argument to addExtension should instead
be expressed as a property on an object exported by the extension (or
it can be omitted to default to a name derived from the file name; this is
only used as a unique identifier).

Any init function previously supplied as second argument to addExtension
should be expressed as an init method on the object exported by the
extension, and it should return what the init function had been returning.
Its this value will be set to the editor object.

For the object returned by init, invocation of any callback method
will also be invoked with the this value set to the editor object.

The npm run rollup routine (also a part of npm run test-prep or
the full test routines) will build any properly named and formatted ES6
Modules extension file into a non-modular file within dist/extensions.

See also "Locale breaking changes".

Other breaking changes

  • Usage - Avoid zoom with scroll unless shift key pressed; checkbox
    for persisting choice of initial use storage approval in storage
    extension dialog is now turned on by default for convenience of
    most users (must still hit "ok" and users can still turn off the checkbox)
  • Process changes:
  • Change PDF export to check exportWindowName for filename and change
    default from download to svg.pdf, distinguishing from other downloads
  • HTML changes: Remove now obsolete scoped attribute from style
    and move tag to head
  • File renames/removal - Files were renamed for greater clarity and
    consistency
  • Minified file renaming/removal
    • jquery.js to jquery.min.js
    • extensions/mathjax/MathJax.js to extensions/mathjax/MathJax.min.js
    • Remove minified jgraduate/spinbtn files (minified now within Rollup
      bundling)
  • Avoid "SVG" in file names except for main file, svg-editor.js,
    long-time core, svgcanvas.js, and polyfills with "SVG" in actual
    variable name ("pathseg.js" to "svgpathseg.js"); also make clear
    distinct file purpose ("svgedit.js" to "namespaces.js" and
    "svgutils.js" to "utilities.js")
  • Consistent jQuery-based-file naming (and reflect name of class):
    "jquery-svg.js" to "jQuery.attr.js"
    "jquery.contextMenu.js" to "jQuery.contextMenu.js",
    "jquery.jpicker.js" to "jQuery.jPicker.js",
    "JQuerySpinBtn.css" to "jQuery.SpinButton.css",
    "JQuerySpinBtn.js" to "jQuery.SpinButton.js",
    "jquery.svgicons.js" to "jQuery.svgIcons.js",
    "jquery.jgraduate.js" to "jQuery.jGraduate.js"
  • Method naming:
  • Switch where feasible to capitalized acronyms
    (addSvgElementFromJson() to addSVGElementFromJson,
    changeSvgContent() to changeSVGContent())
  • APIs
  • Modularity/removing globals
    • Remove window.svgCanvas and svgCanvas.ready (use
      svgEditor.canvas and svgEditor.ready instead)
    • Avoid passing canvg to extensions (have them import)
    • As part of possible deprecation of "private" methods separate from public
      methods of SvgCanvas or svgEditor, avoid adding the following methods
      already available on canvas to getPrivateMethods which is passed to
      extensions: assignAttributes, addSVGElementFromJson,
      call, copyElem, findDefs, getElem, getId,
      getIntersectionList, getMouseTarget, getNextId, getUrlFromAttr,
      hasMatrixTransform, matrixMultiply,
      recalculateAllSelectedDimensions, recalculateDimensions,
      remapElement, removeUnusedDefElems, round, runExtensions,
      sanitizeSvg, setGradient transformListToTransform (and mistaken
      toString export)
  • Other breaking API changes - To allow extensions to add images without
    select image dialog, only "image" mode will trigger dialog; require new
    with EmbeddedSVGEdit; for ext-imagelib, change to an object-based
    encoding for namespacing of messages (though will keep stringifying/parsing
    internally until we remove IE9 support); the WebAppFind extension was
    modified to use its new API; svgcanvas.setUiStrings must now be called
    if not using svg-editor.js in order to get strings (for sake of i18n)
    (and if using path.js alone, it must also have its setUiStrings
    called); RGBColor must accept new; readLang no longer calls
    setLang (locales need not call this anymore anyways; it will be
    imported); the dropping of XML internal subsets (as a security fix
    for entity expansion) might cause breakage with documents using
    entities (though browser support for entity declarations has been
    low); remove storagePromptClosed state boolean in favor of
    storagePromptState
  • Extensions
  • ext-arrows - Change name from Arrows to arrows
    for sake of consistency with file path (not localized anyways; only
    used for unique identification)
  • ext-overview-window - Avoid setting global overviewWindowGlobals

Deprecations and situational regressions

  • While string based messaging continues to work with ext-imagelib, the
    object-based messaging should be used instead (as also used now in
    the embedded editor API and ext-xdomain-messaging)
  • The IAN image library, for which access is built-in to svgedit, has
    already adjusted to deploy our new recommended object-based messaging
    format. After more of their users migrate to version 3.* of svgedit,
    we should then hopefully be able to avoid passing this site an argument,
    (svgedit=3) within their URL (a flag, if not present, which they are
    using to employ the old object messaging mode).
  • Situational regressions: Remove Openclipart as its site's now setting of
    X-Frame-Options to "sameorigin" makes it unusable on our end
    for our cross-origin uses (even with an attempt to use their API). We
    did make and keep a file openclipart-es.html (and auto-converted file,
    openclipart.html) within editor/extensions/imagelib for a
    convenient browser of their library, but the SVG files it finds cannot
    be accessed cross-origin to integrate into SVG-Edit; see also
    Summary of Fixes (Embedded Editor -> Cross-origin issues and
    Browser/device-specific fixes).

Summary of fixes

Since 2.8.1, there have been a number of fixes. Here is a summary (though
we do not include regressions made during the 3.0.0 prereleases which
have since been fixed; search CHANGES for "regression" for these):

  • Security fixes:
  • URL Config: 'extPath', 'imgPath', 'langPath' were not being prevented
    from URL setting
  • Imagelib extension: Avoid XSS, prevent billion laughs attack, only
    allow imgLibs config origins for messaging
  • xdomain HTML: Namespace this file to avoid it being used to modify
    non-domain storage on the same domain
  • Embedded API: Avoid arbitrary property setting for trusted domains
  • toXml: Ensure all apostrophes are escaped for toXml utility
  • Localization/i18n: French and German updates; adding simplified Chinese
    to pull-down; bad characters in Persian locale file; fix "lv" locale;
    clarify locale messages re: save as; fix lang and dir for locales
    (though not in use currently); allow language in settings to be properly
    set back to a different locale, ensure language changes are retained and
    available before settings dialog is closed; ensure langReady changes
    are available when dialog is closed and that its changes have occurred
    by extensions' first load to ensure extension loading complete and the
    updating of canvas at this time based on storagePromptState has seen
    langReady including the storage extension possibly having set a
    storagePromptState of "waiting"
  • Directly user-visible fixes: center canvas properly on load;
    imported images with rubberband box placement and unattached dragtool;
    hidden font-size setting; resizing nullifying the stroke; layers panel;
    zoom centered on cursor when scrolled, avoiding when shift key is pressed;
    Document Properties dialog positioning; ensure repeated selection of same
    file overwrites with that file's contents
    • Export fixes - Alert if exportWindow blocked; avoid error
      if URL is not defined; polygon/polyline in PDF export; see also
      "browser-specific"
  • Keyboard/Command: keypress double binding; text element not
    being triggered by input as well as keyup events; pasting lines with
    markers in certain cases; backspace key in Firefox navigating out of frame;
    ensure shift-key cycling through flyouts works with extension-added
    includeWith as well as toolbarbuttons; ensure line tool shows as
    selected when "L" key command is used
  • Processing fixes: browser feature detection
    (supportsPathInsertItemBefore and supportsPathReplaceItem); layer fixes;
    multiple selection; cloning of path segments during moving; convertPath
    with complex paths; preserving rx and ry on ellipses to allow disabling
    of rendering; proper handling in ext-connector of 2 connecting elements
    with same y-coordinate; removeFromSelection length issues; avoid errors
    for tspan passed to getGradient; avoid race condition in applying arrows
    revealing flyouts and ensure this icon is cloned so can be applied to
    more than one extension; avoid setting Math.precision pseudo-global in
    jPicker; precision argument had not been passed in previously to jPicker;
    for image import, avoid race condition and avoid 0 width/height import
  • API fixes: Trigger svgEditorReady when canvas is ready and via
    iframe; properly default rasterExport without imgType
  • Embedded editor:
  • Do not add parent URL to iframe src URL when query string is empty.
  • Cross-origin issues: Due to Chrome having applied more restrictions
    on cross-origin iframes, the embedded editor broke in some contexts.
    We now avoid errors for same-origin checking, and avoid or recover
    from exceptions with cross-origin localStorage or contentDocument
    access; apparently works with Access-Control-Allow-Origin header and
    locally set with allowedOrigins with * or the given origin(s)
    (such as in the xdomain editor); however, localStorage, as is
    needed for clipboard and saving in storage, does not work regardless;
    we should allow a listener in the parent frame (made configurable
    through the embedded API), so it can get and set its own storage in
    response to SVG-Edit events. We are also still throwing for some
    localStorage access (e.g., context menu cut).
  • Browser/device-specific fixes impacting Overview Panel performance;
    multiselect with zoom; multiple element selection; getInsectionList;
    pathseg; supportsNativeTransformLists detection; save/export;
    removing identity matrices; recover from tspan having no getBBox
    image export; supportsGoodTextCharPos; force PDF download in Chrome
    (dropped dataURI with window opening); map extension click events to
    "mousedown" so they can be received on touch devices
  • Extension fixes: ForeignObject editor dialog had not been opening; fix
    name for moinsave; error during resize with MathML; add images
    for fallback and referenced relative to new extIconsPath; extension
    includeWith flyout button conflicts; avoid erring if inradius is NaN
    in Star extension. A fix was added to allow mouseup triggering for
    extensions in "zoom" and "select" modes, but was reverted in 3.0.1.
  • Linting-discovered fixes: Inadvertent global assignments; bad variable
    scope declarations including within jquery.jgraduate.js
  • Minor fixes such as broken links and switching to https, adding of
    ignore files, etc.

Summary of enhancements

  • Directly user-visible changes: If adding a new image, delete that image
    upon dialog cancel
  • i18n: i18nize path.js strings and canvas notifications; more i18n
    of extensions; have general locales load first so extensions may use;
    placeholders for picking stroke and fill paint opacity and
    popupWindowBlocked; update saveFromBrowser
  • Configuration: Configure text font and stroke; add StackBlur to
    canvg by default; allow path config for canvg and jspdf (not needed
    for built-in)
  • Security: Link placeholder defaults to https
  • APIs: Current zoom level; addSvgElementFromJson capabilities;
    ability to set SVG drawings without adding to the undo stack; add
    to methods passed to extensions; allow addSvgElementFromJson to
    accept non-SVG namespaces as well with explicit namespace property;
    add extensions_added event; make setStrings public on editor for
    late setting; add message event to relay messages; return promise
    for rasterExport, exportPDF, and embedImage; add
    pointsAdded canvas event; supply importLocale to init,
    langReady and addLangData for extension locale loading; allow
    avoiding "name" in extension export
  • Optimizations: getBBox and loading time; remove unused scripts,
    compress images; for setSvgString, return false earlier if element
    content is not SVG; avoid rewriting points attribute for free-hand path
  • Error handling: Extension loading error logging and recovery
  • Keys/Commands: Clipboard works across tabs and windows, "Escape"
    to work with hotkeys within text boxes such as source textarea;
    allow 'a' also with meta key to select all; global escape key listener
    to clear the selection
  • Publishing options: npm, packagist.org; unpkg.com and
    raw.githack.com; for Github.io, add latest directory for hosting
    latest release
  • Cross-origin option: New and auto-generated xdomain-svg-editor-es.html
    and xdomain-svg-editor.html files are now available which possess default
    config which allows cross-origin use. It saves in a storage namespace
    distinct from the main editor so as to avoid potential data corruption
    or unauthorized retrieval of data created in the main editor by other
    domains.
  • Modular JavaScript: ES6 modules distribution format and module-based
    svg-editor-es.html HTML (for modern browsers only; otherwise, use one of
    the UMD distributions or svg-editor.html file) and also separate versions
    for xdomain-svg-editor-es.html; make SpinButton plugin independent of
    svgedit (though still currently bundled)
  • JavaScript-only distribution files - While SVG-Edit's JavaScript
    currently very much presumes a certain HTML structure, for anyone who
    wishes to copy and possibly modify that HTML file outside of the editor
    folder (bearing in mind that certain paths may need to be adjusted),
    they may reference the JavaScript builds within dist. There is an
    ES6 Module distribution (for modern browsers only) as well as a UMD
    distribution. In the package.json file, for the sake of minimizing
    config needed by any bundlers of SVG-Edit, the ES distribution is
    pointed to by the module property and the UMD distribution is pointed
    to by main.
  • Modular stylesheets - Add stylesheets config for indicating custom
    stylesheets to load in parallel with any built-in; use "@default"
    within this array of stylesheet paths to indicate inclusion of default
    stylesheets (or omit "@default" to exclude them).
  • Process improvements: Sort SVG attributes alphabetically

Refactoring/Testing

  • ES6 Modules: Use in source, including jQuery plugins, extensions,
    locales, tests; see "Breaking Changes"
  • Updates: QUnit and jQuery version within imagelib extension; include
    Mathjax local copy
  • Other code refactoring: HistoryRecordingService, Command base class,
    migration away from svgcanvas to separate files (e.g., layer.js); various
    clean-up, readability, simplification, and consistency changes; avoid
    inline listeners and styles; more ES5/ES6 usage (e.g., class,
    includes, destructuring, object shorthand, arrow functions), prefer
    const and then let and place closer to used block, add favicons;
    clearer and more camelCase variable names; throw error objects instead
    of strings; allow Promises; add polyfills for Babel and
    ChildNode/ParentNode; use new Event constructors
  • Linting: Move to ESLint, using a derivative of the "standard" convention;
    80 char. lines; use LGTM
  • Testing: Add skeleton support for UI and accessibility testing with
    TestCafe (along with ESLint plugin/rules for it); add a draw test file;
    separate JavaScript files out of HTML; use static server; fix timing of
    all_tests.html for iframe size; comment out unused jQuery SVG
    test while adding test1 and svgutils_performance_test to all tests page;
    fix inadequate mocking in Path test

Non-code/meta changes

  • License: Indicate license types and rename files to reflect
    type; rename/add license file name for jgraduate and screencast to reflect
    type (Apache 2.0)
  • npm: SVG-Edit is now published on npm; add ESLint, uglify, start, and
    test scripts
  • Documentation: Moved to JSDocs (with Markdown plugin, a custom template
    to support overflow, and an script to check for overly generic types)
    and added documentation for public module methods as well as adding mutual
    linking between JSDocs tutorial docs; included online at https://svg-edit.github.io/svgedit/releases/svg-edit-3.0.0/docs/jsdoc/
    (or for the latest release, use
    https://svg-edit.github.io/svgedit/releases/latest/docs/jsdoc/);
    update Release notes and add Contributing file, integrate Github wiki pages
    into docs, and copy over old docs. Begin "Editor" doc file to help general
    users
  • Demos: Add svgcanvas demo (in using svgcanvas.js without an editor)
  • i18n: Locales now use ES6 Modules and extension locales are now
    contained in separate files relative to the extensions directory (for
    the sake of true modularity); see "Breaking Changes"