(INCOMPLETE: ES6 Module conversion and linting)

- Breaking change: Require `new` with `EmbeddedSVGEdit` (allows us to use `class` internally)
- Breaking change: If `svgcanvas.setUiStrings` must now be called if not using editor in order
    to get strings (for sake of i18n) (and if using path.js alone, must also have its `setUiStrings` called)
- Breaking change (ext-overview-window): Avoid global `overviewWindowGlobals`
- Breaking change (ext-imagelib): Change to object-based encoding for namespacing of
    messages (though keep stringifying/parsing ourselves until we remove IE9 support)
- Breaking change: Rename `jquery.js` to `jquery.min.js`
- Breaking change: Remove `scoped` attribute from `style`; it is now deprecated and
    obsolete; also move to head (after other stylesheets)
- Enhancement: Make SpinButton plugin independent of SVGEdit via
    generic state object for tool_scale
- Enhancement: Remove now unused Python l10n scripts (#238)
- Enhancement: ES6 Modules (including jQuery plugins but not jQuery)
- Enhancement: Further JSDoc (incomplete)
- Enhancement (Optimization): Compress images using imageoptim (and add
    npm script) (per #215)
- Fix: i18nize path.js strings and canvas notifications
- Fix: Attempt i18n for ext-markers
- Refactoring (ext-storage): Move locale info to own file imported by the extension (toward modularity; still should be split into separate files by language and *dynamically* imported, but we'll wait for better `import` support to refactor this)
- Refactoring: For imagelib, add local jQuery copy (using old 1.4.4 as had
    been using from server)
- Refactoring: For MathJax, add local copy (using old 2.3 as had been using from
    server); server had not been working
- Refactoring: Remove `use strict` (implicit in modules)
- Refactoring: Remove trailing whitespace, fix some code within comments
- Refactoring: Expect `jQuery` global rather than `$` for better modularity
    (also to adapt line later once available via `import`)
- Refactoring: Prefer `const` (and then `let`)
- Refactoring: Add block scope keywords closer to first block in which they appear
- Refactoring: Use ES6 `class`
- Refactoring `$.isArray` -> `Array.isArray` and avoid some other jQuery core methods
    with simple VanillaJS replacements
- Refactoring: Use abbreviated object property syntax
- Refactoring: Object destructuring
- Refactoring: Remove `uiStrings` contents in svg-editor.js (obtains from locale)
- Refactoring: Add favicon to embedded API file
- Refactoring: Use arrow functions for brief functions (incomplete)
- Refactoring: Use `Array.prototype.includes`/`String.prototype.includes`;
    `String.prototype.startsWith`, `String.prototype.trim`
- Refactoring: Remove now unnecessary svgutils do/while resetting of variables
- Refactoring: Use shorthand methods for object literals (avoid ": function")
- Refactoring: Avoid quoting object property keys where unnecessary
- Refactoring: Just do truthy/falsey check for lengths in place of comparison to 0
- Refactoring (Testing): Avoid jQuery usage within most test files (defer script,
    also in preparation for future switch to ES6 modules for tests)
- Refactoring: Make jpicker variable declaration indent bearable
- Refactoring (Linting): Finish svgcanvas.js
- Docs: Mention in comment no longer an entry file as before
- Docs: Migrate old config, extensions, and FAQ docs
- Licensing: Indicate MIT is license type of rgbcolor; rename/add license file name for
    jgraduate and screencast to reflect type (Apache 2.0); rename file to reflect it
    contains license information (of type MIT) for Raphael icons
This commit is contained in:
Brett Zamir
2018-05-18 11:25:45 +08:00
parent 7cf976cfb8
commit ae2394f086
249 changed files with 24738 additions and 23260 deletions

View File

@@ -1,14 +1,21 @@
node_modules node_modules
# Vendor/minified files # Vendor/minified files
editor/jquery.js editor/jquery.min.js
editor/jspdf/jspdf.min.js editor/jquery-ui
editor/jspdf/underscore-min.js
editor/jgraduate/jpicker.min.js editor/jgraduate/jpicker.min.js
editor/jgraduate/jquery.jgraduate.min.js editor/jgraduate/jquery.jgraduate.min.js
editor/jquery-ui
editor/jquerybbq editor/jquerybbq
editor/js-hotkeys editor/js-hotkeys
editor/spinbtn/JQuerySpinBtn.min.js editor/spinbtn/JQuerySpinBtn.min.js
editor/jspdf/jspdf.min.js
editor/jspdf/underscore-min.js
editor/extensions/imagelib/jquery.min.js
editor/extensions/mathjax
test/qunit test/qunit
test/sinon test/sinon

View File

@@ -121,7 +121,6 @@ def parseComment(line, line_num, enabled_flags):
return line return line
def ship(inFileName, enabled_flags): def ship(inFileName, enabled_flags):
# read in HTML file # read in HTML file
lines = file(inFileName, 'r').readlines() lines = file(inFileName, 'r').readlines()
@@ -141,7 +140,7 @@ def ship(inFileName, enabled_flags):
else: # else append line to the output list else: # else append line to the output list
out_lines.append(line) out_lines.append(line)
i += 1 i += 1
return ''.join(out_lines) return ''.join(out_lines)
if __name__ == '__main__': if __name__ == '__main__':

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

118
docs/ConfigOptions.md Normal file
View File

@@ -0,0 +1,118 @@
# Introduction
As of version 2.5, SVG-edit has several configuration settings that can be overridden either by adding URL parameters or by setting the options in JavaScript. As of version 2.7, a few among these options related to paths are disallowed via URL though they can still be set by `svgEditor.setConfig`.
## How to set the options
Options can be set using `svgEditor.setConfig(options)`, where `options` is an object literal of keys and values. This must be run before the actual page or DOM is loaded, otherwise it will have no effect. Note that one may create a `config.js` file within the "editor" directory and add such configuration directives to it without needing to modify the repository editor code (and note version 2.8 adds support for a custom.css file for the same purpose).
## Example:
```js
svgEditor.setConfig({
dimensions: [320, 240],
canvas_expansion: 5,
initFill: {
color: '0000FF'
}
});
```
This will set the default width/height of the image, the size of the outside canvas, and the default "fill" color.
The same options can be set in the URL like this:
```
.../svg-editor.html?dimensions=300,240&canvas_expansion=5&initFill[color]=0000FF
```
As of version 2.7, if options are set both using `.setConfig()` as well as in the URL, the `.setConfig()` value will be used. The reverse was true in previous versions but was changed for security reasons.
One may optionally pass another object to `.setConfig()` as the second argument to further adjust configuration behavior.
If an `overwrite` boolean is set to false on this additional object, it will, as occurs with all URL type configurations, prevent the current configuration from overwriting any explicitly set previous configurations. The default is true except for URLs which always are false.
If an `allowInitialUserOverride` boolean is set to true, it will allow subsequent configuration overwriting via URL (e.g., if you do want the user to have the option to override certain or your (`config.js`) `.setConfig()` directives via URL while still wishing to provide them with your own default value, you should add this property).
## Configurable options
Note that those items marked as preferences are configuration items which can also be set via the UI (and specifically via Editor Options except where mentioned). Those items which appear in the UI but are not treated internally as preferences are marked with "Maybe" as their status may change.
| Property | Description | Default | Preference | |:---------|:------------|:--------|:-----------|
| `lang` | Two-letter language code. The language must exist in the Editor Preferences language list | Default to "en" if `locale.js` detection does not detect another language | Yes |
| `bkgd_url` | Background raster image URL. This image will fill the background of the document, useful for tracing purposes | (none) | Yes |
| `img_save` | Defines whether included raster images should be saved as Data URIs when possible, or as URL references. Must be either 'embed' or 'ref'. Settable in the Document Properties dialog. | embed | Yes |
| `dimensions` | The default width/height of a new document. Use an array in `setConfig` (e.g., `[800, 600]`) and comma separated numbers in the URL | `[640, 480]` | Maybe |
| `initFill[color]` | The initial fill color. Must be a hex code string. | FF0000 (solid red) | No |
| `initFill[opacity]` | The initial fill opacity. Must be a number between 0 and 1 | 1 | No |
| `initStroke[color]` | The initial stroke color. Must be a hex code. | 000000 (solid black) | No |
| `initStroke[width]` | The initial stroke width. Must be a positive number. | 5 | No |
| `initStroke[opacity]` | The initial stroke opacity. Must be a number between 0 and 1 | 1 | No |
| `initTool` | The initially selected tool. Must be either the ID of the button for the tool, or the ID without "tool_" prefix_| select | No |
| `exportWindowType` | New as of 2.8. 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) | new | No |
| `imgPath` | 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. | `images/` | No |
| `jGraduatePath` | The path where jGraduate images are located. Note that as of version 2.7, this is not configurable by URL for security reasons. | `jgraduate/images/` | No |
| `langPath` | The path where the language files are located, with trailing slash. Note that as of version 2.7, this is not configurable by URL for security reasons. | `locale/` | No |
| `extPath` | The path used for extension files, with trailing slash. Note that as of version 2.7, this is not configurable by URL for security reasons. | `extensions/` | No |
| `extensions` | Extensions to load on startup. Use an array in setConfig and comma separated file names in the URL. 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. | `['ext-overview_window.js','ext-markers.js','ext-connector.js','ext-eyedropper.js','ext-shapes.js','ext-imagelib.js','ext-grid.js','ext-polygon.js','ext-star.js','ext-panning.js','ext-storage.js']` | No |
| `showlayers` | Open the layers side-panel by default | `false` | No |
| `wireframe` | Start in wireframe mode | `false` | No |
| `gridSnapping` | Enable snap to grid by default. Set in Editor Options. | `false` | Maybe |
| `gridColor` | Set in Editor Options. | #000 (black) | Maybe |
| `baseUnit` | Set in Editor Options. | px | Maybe |
| `snappingStep` | Set the default grid snapping value. Set in Editor Options. | 10 | Maybe |
| `showRulers` | Initial state of ruler display (v2.6). Set in Editor Options. | `true` | Maybe |
| `no_save_warning` | A boolean that when `true` prevents the warning dialog box from appearing when closing/reloading the page. Mostly useful for testing. | `false` | No |
| `canvas_expansion` | 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. | 3 | No |
| `show_outside_canvas` | A boolean that defines whether or not elements outside the canvas should be visible; set by `svgcanvas.js` | `true` | No |
| `iconsize` | Size of the toolbar icons. Must be one of the following: 's', 'm', 'l', 'xl' | Will default to 's' if the window height is smaller than the minimum height and 'm' otherwise | Yes |
| `bkgd_color` | Canvas background color | #FFF (white) | Yes |
| `selectNew` | Initial state of option to automatically select objects after they are created (v2.6) | `true` | No |
| `save_notice_done` | Used to track alert status | `false` | Yes |
| `export_notice_done` | Used to track alert status | `false` | Yes |
| `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| `[]` | Maybe |
| `canvasName` | 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 | default | No |
| `initOpacity` | Initial opacity (multiplied by 100) | 1 | No |
| `colorPickerCSS` | Object of CSS properties mapped to values (for jQuery) to apply to the color picker. 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 | `null` (see description) | No |
| `preventAllURLConfig` | Set to `true` (in `config.js`; extension loading is too late!) to override the ability for URLs to set non-content configuration (including extension config) | `false` | No |
| `preventURLContentLoading` | Set to `true` (in `config.js`; extension loading is too late!) to override the ability for URLs to set URL-based SVG content | `false` | No |
| `lockExtensions` | Set to `true` (in config.js; extension loading is too late!) 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. | `false` | No |
| `noDefaultExtensions` | 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); can only be meaningfully used in `config.js` or in the URL | `false` | No |
| `showGrid` | Set by `ext-grid.js`; determines whether or not to show the grid by default | `false` | No |
| `noStorageOnLoad` | Some interaction with `ext-storage.js`; prevents even the loading of previously saved local storage | `false` | No |
| `forceStorage` | 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 | `false` | No |
| `emptyStorageOnDecline` | Used by `ext-storage.js`; empty any prior storage if the user declines to store | `false` | No |
| `paramurl` | This is available via URL only. Deprecated and removed in trunk. Allowed an un-encoded URL within the query string (use "url" or "source" with a data: URI instead) | (None) | No |
| `selectNew` | Set by svgcanvas.js; used by mouseUp; it true, will replace the selection with the current element and show grips | `true` | No |
## Preload a file
It is also possible to start the editor with preloaded SVG file, using the following methods.
However, one should bear in mind that if one wishes to immediately set a particular string, especially if in config.js (and prevent the user from saving their own text), one should first set the config option "noStorageOnLoad" to false or otherwise any previous local storage may overwrite your own string.
```js
// Serialized string:
svgEditor.loadFromString('...');
// Data URI:
svgEditor.loadFromDataURI('data:image/svg+xml;base64,...');
// Local URL:
svgEditor.loadFromURL('images/logo.svg');
```
Or as URL parameter:
```js
// Data URI
'?source=' + encodeURIComponent('data:image/svg+xml;utf8,') + encodeURIComponent(/*...*/)
// Data URI (base 64):
'?source=' + encodeURIComponent('data:image/svg+xml;base64,' + /* ... */); // data%3Aimage%2Fsvg%2Bxml%3Bbase64%2C ...
// Local URL:
'?url=' + encodeURIComponent('images/logo.svg'); // images%2Flogo.svg
```
**Note:** There is currently a bug that prevents data URIs ending with equals (=) characters from being parsed. Removing these characters seem to allow the import to work as expected.

314
docs/ExtensionDocs.md Normal file
View File

@@ -0,0 +1,314 @@
# Introduction
As of version 2.5, SVG-Edit has support for extensions. This an (in-progress) guide for creating SVG-Edit plugins.
## Basic format
SVG-Edit plugins are standalone JavaScript files that can be either included in the HTML file or loaded using setConfig or through the URL (see ConfigOptions for usage).
Note that if you create a `config.js` file in the "editor" directory, this will be used to execute commands before extensions are loaded, e.g., if you wish to make configuration changes which affect extension loading behavior. Normally, however, it should be preferable for modularity to use the extension mechanism, as this can allow you or users to customize which extensions are loaded (whereas `config.js` will always run if present).
This is the general format for an extension:
```js
svgEditor.addExtension('extensionName', function (methods) {
return extensionData;
});
```
The first parameter (`extensionName`) is the unique name for this extension.
The second parameter is a function that supplies methods and variables from svgCanvas and can return an object that includes properties and functions related to the extension.
The basic Hello world extension can be used as an example on how to create a basic extension. This extension adds a "mode" button to the bottom of the left panel that changes the mode, then shows a "Hello world" message whenever the canvas is clicked on. See [extension in action](https://svg-edit.github.io/svgedit/releases/svg-edit-2.8.1/svg-editor.html?extensions=ext-helloworld.js).
The basic structure of this plugin looks like this:
```js
svgEditor.addExtension('Hello World', function () {
// Returning an object is optional as of v2.7+
return {
// name: '', // A name has traditionally been added but apparently not needed?
svgicons: 'extensions/helloworld-icon.xml',
buttons: [{...}],
mouseDown() {
...
},
mouseUp(opts) {
...
}
};
});
```
Note how the returned properties include information on the buttons, as well as the functions that should be run when certain events take place.
## Creating buttons
Buttons can appear either in the mode panel (left panel) or the context panel (top panel, changes depending on selection). Their icons can either consist of SVG icons (recommended) or just raster images.
Each button is an object with the following properties (added to the array "buttons" on the object provided by the extension):
| Property | Description | Required? |
|:---------|:------------|:----------|
| `id` (string) | A unique identifier for this button. If SVG icons are used, this must match the ID used in the icon file. | Yes |
| `type` (string) | Type of button. Must be either 'mode' or 'context' | Yes |
| `title` (string) | The tooltip text that will appear when the user hovers over the icon | Yes |
| `icon` (string) | The file path to the raster version of the icon. | Only if no svgicons is supplied |
| `svgicon` (string) | If absent, will utilize the button "id"; used to set "placement" on the svgIcons call | No |
| `list` (string) | Points to the "id" of a context_tools item of type "button-select" into which the button will be added as a panel list item | No |
| `position` (integer) | The numeric index for placement; defaults to last position (as of the time of extension addition) if not present | No |
| `panel` (string) | The ID of the context panel to be included, if type is "context". | Only if type is "context" |
| `events` (object) | DOM event names with associated functions. Example: {'click': function() { alert('Button was clicked') } } | Yes |
| `includeWith` (object) | Object with flyout menu data (see following properties) | No |
| `includeWith[button]` (string) | jQuery selector of the existing button to be joined. Example: '#tool_line' | Yes (if includeWith is used) |
| `includeWith[isDefault]` (boolean) | Option indicating whether button is default in flyout list or not | No |
| `isDefault` (boolean) | Whether or not the default is the default | No |
| `includeWith[position]` (integer) | Position of icon in flyout list, will be added to end if not indicated | No |
| `key` (string) | The key to bind to the button | No |
## Creating SVG icons
The SVG-Edit project uses icons created using basic SVG (generally using SVG-Edit as design tool), and extensions are encouraged to do so too. This allows the interface toolbars to be resized and icons to be reused at various sizes. If your extension uses multiple icons, they can all be stored in the same file. To specify icon file used, set the path under the extension's returned svgicons property.
An SVG icon file is an XML document that consists of a root SVG element with child group elements (`<g></g>`). Each of these has an ID that should match the ID specified in the associated button object. Its content should be the SVG source of the icon. See the Hello World icon as an example.
For further information, see the SVG Icon Loader project.
## Creating context tools
Context tools appear in the top toolbar whenever a certain type of element is selected.
These are added by the extension returning an object with the property "context_tools".
| Property | Description | Required? |
|:---------|:------------|:----------|
| `panel` (string) | The ID of the existing panel for the tool to be added to | Yes |
| `container_id` (string) | The ID to be given to the tool's container element | No |
| `type` (string) | The type of tool being added. Must be one of the following: 'tool_button', 'select', 'input' | Yes |
| `id` (string) | The ID of the actual tool element | Yes |
| `events` (object) | DOM event names with associated functions. Example: {'change': function() { alert('Option was changed') } } | Yes |
| `options` (object) | List of options and their labels for select tools. Example: `{'1': 'One', '2': 'Two', 'all': 'All' } | Only for "select" tools |
| `defval` (string) | Default value | No |
| `label` (string) | Label associated with the tool, visible in the UI | No |
| `title` (string) | The tooltip text that will appear when the user hovers over the tool | Yes |
| `size` (integer) | Value of the "size" attribute of the tool input | No |
| `spindata` (object) | When added to a tool of type "input", this tool becomes a "spinner" which allows the number to be in/decreased. For data required see The SpinButton script | No |
| `colnum` (integer) | Added as part of the option list class. | No |
## SVG-Edit events
Most plugins will want to run functions when certain events are triggered. This is a list of the current events that can be hooked onto. All events are optional.
| Event | Description | Parameters | Return value expected | |:------|:------------|:-----------|:----------------------|
| `mouseDown` | The main (left) mouse button is held down on the canvas area | Supplies an object with these properties: `evt` (the event object), `start_x` (x coordinate on canvas), `start_y` (y coordinate on canvas), `selectedElements` (an array of the selected Elements) | An optional object with started: true to indicate that creating/editing has started |
| `mouseMove` | The mouse is moved on the canvas area | Same as for `mouseDown`, but with a selected property that refers to the first selected element | None |
| `mouseUp` | The main (left) mouse button is released (anywhere) | Same as for `mouseDown` | An optional object with these properties: `element` (the element being affected), `keep` (boolean that indicates if the current element should be kept) `started` (boolean that indicates if editing should still be considered as "started") |
| `zoomChanged` | The zoom level is changed | Supplies the new zoom level as a number (not percentage) | None |
| `selectedChanged` | The element selection has changed (elements were added/removed from selection | Supplies an object with these properties: `elems` (array of the newly selected elements), `selectedElement` (the single selected element), `multiselected` (a boolean that indicates whether one or more elements was selected) | None |
| `elementChanged` | One or more elements were changed | Object with properties: `elems` (array of the affected elements) | None |
| `elementTransition` | Called when part of element is in process of changing, generally on mousemove actions like rotate, move, etc. | Object with properties: `elems` (array of transitioning elements) | None |
| `toolButtonStateUpdate` | The bottom panel was updated | Object with these properties: `nofill` (boolean that indicates fill is disabled), `nostroke` (boolean that indicates stroke is disabled) | None |
| `langChanged` | The language was changed | Two-letter code of the new language | None |
| `langReady` | Invoked as soon as the locale is ready | An object with properties "lang" containing the two-letter language code and "uiStrings" as an alias for svgEditor.uiStrings | None |
| `addlangData` | Means for an extension to add locale data | The two-letter language code | Object with "data" property set to an object containing two-letter language codes keyed to an array of objects with "id" and "title" or "textContent" properties |
| `callback` | Invoked upon addition of the extension, or, if svgicons are set, then after the icons are ready | None | None |
| `canvasUpdated` | Invoked upon updates to the canvas | Object with properties: new_x, new_y, old_x, old_y, d_x, d_y | None |
| `onNewDocument` | Called when new image is created | None | None |
| `workareaResized` | Called when sidepanel is resized or toggled | None | None |
## Helper functions
A variety of methods can be accessed within plugins. In the future, we hope to have them all properly documented, for now here is the current list of function/variable names.
## `svgCanvas` variables
These are supplied in an object through the first parameter of the extension function (see "methods" variable in above example).
| Name | Description |
|:-----|:------------|
| `svgroot` (element) | The workarea's root SVG element. NOT the root SVG element of the image being edited |
| `svgcontent` (element) | The root SVG element of the image being edited |
| `nonce` (number) | The unique identifier given to this image |
| `selectorManager` (object) | The object that manages selection information |
## `svgEditor` public methods
| Name | Description | Params | Return value |
|:-----|:------------|:-------|:-------------|
| `setCustomHandlers()` | Override default SVG open, save, and export behaviors | Accepts object with all optional properties, `open`, `save`, and `exportImage`; `open` is not passed any parameters; `saved` is passed a string containing the SVG; `exportImage` is passed an object containing the properties: `svg` with the SVG contents as a string, `datauri` with the contents as a data URI, `issues` with an array of UI strings pertaining to relevant known CanVG issues, `type` indicating the chosen image type ("PNG", "JPEG", "BMP", "WEBP") (or, as planned for 3.0.0, "PDF" type), `mimeType` for the MIME type, `exportWindowName` as a convenience for passing along a window.name to target a window on which the export could be added, and `quality` as a decimal between 0 and 1 (for use with JPEG or WEBP) | (None) | | ... | ... | ... | ... |
## `svgCanvas` private methods
These are supplied in an object through the first parameter of the extension function (see `methods` variable in above example).
| Name | Description |
|:-----|:------------|
| `addCommandToHistory()` | |
| `addGradient()` | |
| `addSvgElementFromJson()` | |
| `assignAttributes()` | |
| `BatchCommand()` | |
| `call()` | |
| `ChangeElementCommand()` | |
| `cleanupElement()` | |
| `copyElem()` | |
| `ffClone()` | |
| `findDefs()` | |
| `findDuplicateGradient()` | |
| `fromXml()` | |
| `getElem()` | |
| `getId()` | |
| `getIntersectionList()` | |
| `getNextId()` | |
| `getPathBBox()` | |
| `getUrlFromAttr()` | |
| `hasMatrixTransform()` | |
| `identifyLayers()` | |
| `InsertElementCommand()` | |
| `isIdentity()` | |
| `logMatrix()` | |
| `matrixMultiply()` | |
| `MoveElementCommand()` | |
| `preventClickDefault()` | |
| `recalculateAllSelectedDimensions()` | |
| `recalculateDimensions()` | |
| `remapElement()` | |
| `RemoveElementCommand()` | |
| `removeUnusedGrads()` | |
| `resetUndoStack()` | |
| `round()` | |
| `runExtensions()` | |
| `sanitizeSvg()` | |
| `Selector()` | |
| `SelectorManager()` | |
| `shortFloat()` | |
| `svgCanvasToString()` | |
| `SVGEditTransformList()` | |
| `svgToString()` | |
| `toString()` | |
| `toXml()` | |
| `transformBox()` | |
| `transformListToTransform()` | |
| `transformPoint()` | |
| `transformToObj()` | |
| `walkTree()` | |
## `svgCanvas` public methods
| Name | Description |
|:-----|:------------|
| `addToSelection()` | |
| `alignSelectedElements()` | |
| `beginUndoableChange()` | |
| `bind()` | |
| `changeSelectedAttribute()` | |
| `changeSelectedAttributeNoUndo()` | |
| `clear()` | |
| `clearSelection()` | |
| `cloneSelectedElements()` | |
| `convertToPath()` | |
| `createLayer()` | |
| `cycleElement()` | |
| `deleteCurrentLayer()` | |
| `deleteSelectedElements()` | |
| `each()` | |
| `embedImage()` | |
| `finishUndoableChange()` | |
| `fixOperaXML()` | |
| `getBBox()` | |
| `getBold()` | |
| `getContentElem()` | |
| `getCurrentLayer()` | |
| `getEditorNS()` | |
| `getFillColor()` | |
| `getFillOpacity()` | |
| `getFontFamily()` | |
| `getFontSize()` | |
| `getHistoryPosition()` | |
| `getImageTitle()` | |
| `getItalic()` | |
| `getLayer()` | |
| `getLayerOpacity()` | |
| `getLayerVisibility()` | |
| `getMode()` | |
| `getNextRedoCommandText()` | |
| `getNextUndoCommandText()` | |
| `getNumLayers()` | |
| `getOffset()` | |
| `getOpacity()` | |
| `getPrivateMethods()` | |
| `getRedoStackSize()` | |
| `getResolution()` | |
| `getRootElem()` | |
| `getRotationAngle()` | |
| `getSelectedElems()` | |
| `getStrokeColor()` | |
| `getStrokeOpacity()` | |
| `getStrokeStyle()` | |
| `getStrokeWidth()` | |
| `getStrokedBBox()` | |
| `getSvgString()` | |
| `getText()` | |
| `getTransformList()` | |
| `getUndoStackSize()` | |
| `getUrlFromAttr()` | |
| `getVersion()` | |
| `getVisibleElements()` | |
| `getZoom()` | |
| `groupSelectedElements()` | |
| `importSvgString()` | |
| `isValidUnit()` | |
| `linkControlPoints()` | |
| `matrixMultiply()` | |
| `moveSelectedElements()` | |
| `moveSelectedToLayer()` | |
| `moveToBottomSelectedElement()` | |
| `moveToTopSelectedElement()` | |
| `open()` | |
| `randomizeIds()` | |
| `ready()` | |
| `redo()` | |
| `removeFromSelection()` | |
| `renameCurrentLayer()` | |
| `runExtensions()` | |
| `save()` | |
| `selectAllInCurrentLayer()` | |
| `setBBoxZoom()` | |
| `setBackground()` | |
| `setBold()` | |
| `setConfig()` | |
| `setCurrentLayer()` | |
| `setCurrentLayerPosition()` | |
| `setFillColor()` | |
| `setFillOpacity()` | |
| `setFillPaint()` | |
| `setFontFamily()` | |
| `setFontSize()` | |
| `setIdPrefix()` | |
| `setImageTitle()` | |
| `setImageURL()` | |
| `setItalic()` | |
| `setLayerOpacity()` | |
| `setLayerVisibility()` | |
| `setMode()` | |
| `setOpacity()` | |
| `setRectRadius()` | |
| `setResolution()` | |
| `setRotationAngle()` | |
| `setSegType()` | |
| `setStrokeColor()` | |
| `setStrokeOpacity()` | |
| `setStrokePaint()` | |
| `setStrokeStyle()` | |
| `setStrokeWidth()` | |
| `setSvgString()` | |
| `setTextContent()` | |
| `setUiStrings()` | |
| `setZoom()` | |
| `smoothControlPoints()` | |
| `undo()` | |
| `ungroupSelectedElement()` | |
| `updateCanvas()` | |
| `updateElementFromJson()` | |

View File

@@ -0,0 +1,54 @@
**NOTE: The following may contain outdated content.**
**Q: Why doesn't SVG-edit work in Internet Explorer 6-7-8?**
A: SVG-edit only works in IE6-7-8 if you have installed the Google Chrome Frame plugin. Internet Explorer 8 and under do not natively support Scalable Vector Graphics (SVG), however IE9+ does, and thus is supported starting in SVG-edit 2.6
In theory there are several other possibilities that could allow SVG-edit to work in IE: * someone gets it to work with the SVG Web shim * someone gets it to work with IE and the Adobe SVG Viewer * someone gets it to work with another SVG plugin
**Q: How can I make SVG-edit save files on my server?**
A: As of SVG-edit 2.5.1, an extension is available that overrides the default open/save behavior and instead uses PHP files to allow proper open/save dialog boxes. You can include the extension by adding `ext-server_opensave.js` to the `curConfig.extension` array in `svg-editor.js` or through other methods mentioned on our ConfigOptions page.
For other server-saving behavior you'll want to modify `ext-server_opensave.js` or the `filesave.php` file, both available under `editor/extensions/`.
**Q: How can I set the stroke to 'none'?**
A: Shift-clicking palette squares sets the Stroke paint value. Thus, you can shift-click on the None box (red x on white background) to clear the Stroke paint.
**Q: How can I help?**
A: See How to participate
**Q: How can I select an element when it's hidden or behind another one?**
A: Select an object. Shift+O will select the previous object Shift+P will select the next object. Using the wireframe mode may also help in seeing hidden objects.
**Q: How can I edit shapes that have been grouped?**
A: Double-click the group and you will shift the editing context to the group. The rest of the image will not be editable while you are in the group context. Once you are done editing inside the group, press Escape.
**Q: Can I trace over a raster (PNG, JPEG...) image?**
A: Yes, there are two methods you can use as of SVG-edit 2.4. 1. Go to the Document Properties, and enter the URL of the image under "Editor Background". This image will then fill the background without being saved as part of the image.
Add a layer from the layer panel. Then draw a raster image (image icon) and enter your URL. Use the layer above this one to trace over the image without moving. Note that you can also hide/show layers to help your work.
**Q: How do I use the Wave Gadget?**
A: (Note that this information refers to the SVG-edit 2.3 Wave Gadget, the Wave Gadget has not been worked on for years though) Go to this wave wavesandbox.com!w+W7VzCLZk%A and there will be a button on the bottom that says "Install" and when you are editing things, you will see a SVG-edit icon in your toolbar that you can click to include the gadget into any blip.
**Q: How do I copy the style of an object to other(s)?**
A:
- Select the object you want to copy the style from. You'll see its Fill and Stroke style attributes displayed in the bottom toolbar.
- Holding Shift to keep the first object selected, select one or several other objects.
- Open the colorpicker by clicking on the color blocks in the bottom toolbar. If you want to copy the fill, select the Fill block. If you want to copy the stroke, select the Stroke block.
- Hit "Ok" in the colorpicker
The other objects will get the Fill or the Stroke of the first object.
**Q: How can I serve SVG graphic editor from my own server?**
A: You need to download the latest version to your server and unzip. The exact commands/instructions are here: <http://howik.com/Improve_your_user%27s_experience_by_adding_svg_graphic_editor_to_your_website_in_less_than_2_minutes>

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery */
/* globals $, svgedit */
/** /**
* Package: svgedit.browser * Package: svgedit.browser
* *
@@ -12,177 +11,168 @@
// Dependencies: // Dependencies:
// 1) jQuery (for $.alert()) // 1) jQuery (for $.alert())
(function () { import './pathseg.js';
'use strict'; import {NS} from './svgedit.js';
if (!svgedit.browser) { const $ = jQuery;
svgedit.browser = {};
}
// alias const supportsSvg_ = (function () {
var NS = svgedit.NS; return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
var supportsSvg_ = (function () {
return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
}()); }());
svgedit.browser.supportsSvg = function () { return supportsSvg_; }; export const supportsSvg = () => supportsSvg_;
if (!svgedit.browser.supportsSvg()) {
window.location = 'browser-not-supported.html';
return;
}
var userAgent = navigator.userAgent; const {userAgent} = navigator;
var svg = document.createElementNS(NS.SVG, 'svg'); const svg = document.createElementNS(NS.SVG, 'svg');
// Note: Browser sniffing should only be used if no other detection method is possible // Note: Browser sniffing should only be used if no other detection method is possible
var isOpera_ = !!window.opera; const isOpera_ = !!window.opera;
var isWebkit_ = userAgent.indexOf('AppleWebKit') >= 0; const isWebkit_ = userAgent.includes('AppleWebKit');
var isGecko_ = userAgent.indexOf('Gecko/') >= 0; const isGecko_ = userAgent.includes('Gecko/');
var isIE_ = userAgent.indexOf('MSIE') >= 0; const isIE_ = userAgent.includes('MSIE');
var isChrome_ = userAgent.indexOf('Chrome/') >= 0; const isChrome_ = userAgent.includes('Chrome/');
var isWindows_ = userAgent.indexOf('Windows') >= 0; const isWindows_ = userAgent.includes('Windows');
var isMac_ = userAgent.indexOf('Macintosh') >= 0; const isMac_ = userAgent.includes('Macintosh');
var isTouch_ = 'ontouchstart' in window; const isTouch_ = 'ontouchstart' in window;
var supportsSelectors_ = (function () { const supportsSelectors_ = (function () {
return !!svg.querySelector; return !!svg.querySelector;
}()); }());
var supportsXpath_ = (function () { const supportsXpath_ = (function () {
return !!document.evaluate; return !!document.evaluate;
}()); }());
// segList functions (for FF1.5 and 2.0) // segList functions (for FF1.5 and 2.0)
var supportsPathReplaceItem_ = (function () { const supportsPathReplaceItem_ = (function () {
var path = document.createElementNS(NS.SVG, 'path'); const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 10,10'); path.setAttribute('d', 'M0,0 10,10');
var seglist = path.pathSegList; const seglist = path.pathSegList;
var seg = path.createSVGPathSegLinetoAbs(5, 5); const seg = path.createSVGPathSegLinetoAbs(5, 5);
try { try {
seglist.replaceItem(seg, 1); seglist.replaceItem(seg, 1);
return true; return true;
} catch (err) {} } catch (err) {}
return false; return false;
}()); }());
var supportsPathInsertItemBefore_ = (function () { const supportsPathInsertItemBefore_ = (function () {
var path = document.createElementNS(NS.SVG, 'path'); const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 10,10'); path.setAttribute('d', 'M0,0 10,10');
var seglist = path.pathSegList; const seglist = path.pathSegList;
var seg = path.createSVGPathSegLinetoAbs(5, 5); const seg = path.createSVGPathSegLinetoAbs(5, 5);
try { try {
seglist.insertItemBefore(seg, 1); seglist.insertItemBefore(seg, 1);
return true; return true;
} catch (err) {} } catch (err) {}
return false; return false;
}()); }());
// text character positioning (for IE9) // text character positioning (for IE9)
var supportsGoodTextCharPos_ = (function () { const supportsGoodTextCharPos_ = (function () {
var svgroot = document.createElementNS(NS.SVG, 'svg'); const svgroot = document.createElementNS(NS.SVG, 'svg');
var svgcontent = document.createElementNS(NS.SVG, 'svg'); const svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgroot); document.documentElement.appendChild(svgroot);
svgcontent.setAttribute('x', 5); svgcontent.setAttribute('x', 5);
svgroot.appendChild(svgcontent); svgroot.appendChild(svgcontent);
var text = document.createElementNS(NS.SVG, 'text'); const text = document.createElementNS(NS.SVG, 'text');
text.textContent = 'a'; text.textContent = 'a';
svgcontent.appendChild(text); svgcontent.appendChild(text);
var pos = text.getStartPositionOfChar(0).x; const pos = text.getStartPositionOfChar(0).x;
document.documentElement.removeChild(svgroot); document.documentElement.removeChild(svgroot);
return (pos === 0); return (pos === 0);
}()); }());
var supportsPathBBox_ = (function () { const supportsPathBBox_ = (function () {
var svgcontent = document.createElementNS(NS.SVG, 'svg'); const svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgcontent); document.documentElement.appendChild(svgcontent);
var path = document.createElementNS(NS.SVG, 'path'); const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 C0,0 10,10 10,0'); path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
svgcontent.appendChild(path); svgcontent.appendChild(path);
var bbox = path.getBBox(); const bbox = path.getBBox();
document.documentElement.removeChild(svgcontent); document.documentElement.removeChild(svgcontent);
return (bbox.height > 4 && bbox.height < 5); return (bbox.height > 4 && bbox.height < 5);
}()); }());
// Support for correct bbox sizing on groups with horizontal/vertical lines // Support for correct bbox sizing on groups with horizontal/vertical lines
var supportsHVLineContainerBBox_ = (function () { const supportsHVLineContainerBBox_ = (function () {
var svgcontent = document.createElementNS(NS.SVG, 'svg'); const svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgcontent); document.documentElement.appendChild(svgcontent);
var path = document.createElementNS(NS.SVG, 'path'); const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 10,0'); path.setAttribute('d', 'M0,0 10,0');
var path2 = document.createElementNS(NS.SVG, 'path'); const path2 = document.createElementNS(NS.SVG, 'path');
path2.setAttribute('d', 'M5,0 15,0'); path2.setAttribute('d', 'M5,0 15,0');
var g = document.createElementNS(NS.SVG, 'g'); const g = document.createElementNS(NS.SVG, 'g');
g.appendChild(path); g.appendChild(path);
g.appendChild(path2); g.appendChild(path2);
svgcontent.appendChild(g); svgcontent.appendChild(g);
var bbox = g.getBBox(); const bbox = g.getBBox();
document.documentElement.removeChild(svgcontent); document.documentElement.removeChild(svgcontent);
// Webkit gives 0, FF gives 10, Opera (correctly) gives 15 // Webkit gives 0, FF gives 10, Opera (correctly) gives 15
return (bbox.width === 15); return (bbox.width === 15);
}()); }());
var supportsEditableText_ = (function () { const supportsEditableText_ = (function () {
// TODO: Find better way to check support for this // TODO: Find better way to check support for this
return isOpera_; return isOpera_;
}()); }());
var supportsGoodDecimals_ = (function () { const supportsGoodDecimals_ = (function () {
// Correct decimals on clone attributes (Opera < 10.5/win/non-en) // Correct decimals on clone attributes (Opera < 10.5/win/non-en)
var rect = document.createElementNS(NS.SVG, 'rect'); const rect = document.createElementNS(NS.SVG, 'rect');
rect.setAttribute('x', 0.1); rect.setAttribute('x', 0.1);
var crect = rect.cloneNode(false); const crect = rect.cloneNode(false);
var retValue = (crect.getAttribute('x').indexOf(',') === -1); const retValue = (!crect.getAttribute('x').includes(','));
if (!retValue) { if (!retValue) {
$.alert('NOTE: This version of Opera is known to contain bugs in SVG-edit.\n' + $.alert('NOTE: This version of Opera is known to contain bugs in SVG-edit.\n' +
'Please upgrade to the <a href="https://www.opera.com/download">latest version</a> in which the problems have been fixed.'); 'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.');
} }
return retValue; return retValue;
}()); }());
var supportsNonScalingStroke_ = (function () { const supportsNonScalingStroke_ = (function () {
var rect = document.createElementNS(NS.SVG, 'rect'); const rect = document.createElementNS(NS.SVG, 'rect');
rect.setAttribute('style', 'vector-effect:non-scaling-stroke'); rect.setAttribute('style', 'vector-effect:non-scaling-stroke');
return rect.style.vectorEffect === 'non-scaling-stroke'; return rect.style.vectorEffect === 'non-scaling-stroke';
}()); }());
var supportsNativeSVGTransformLists_ = (function () { const supportsNativeSVGTransformLists_ = (function () {
var rect = document.createElementNS(NS.SVG, 'rect'); const rect = document.createElementNS(NS.SVG, 'rect');
var rxform = rect.transform.baseVal; const rxform = rect.transform.baseVal;
var t1 = svg.createSVGTransform(); const t1 = svg.createSVGTransform();
rxform.appendItem(t1); rxform.appendItem(t1);
var r1 = rxform.getItem(0); const r1 = rxform.getItem(0);
return r1 instanceof SVGTransform && t1 instanceof SVGTransform && // Todo: Do frame-independent instance checking
r1.type === t1.type && r1.angle === t1.angle && return r1 instanceof SVGTransform && t1 instanceof SVGTransform &&
r1.matrix.a === t1.matrix.a && r1.type === t1.type && r1.angle === t1.angle &&
r1.matrix.b === t1.matrix.b && r1.matrix.a === t1.matrix.a &&
r1.matrix.c === t1.matrix.c && r1.matrix.b === t1.matrix.b &&
r1.matrix.d === t1.matrix.d && r1.matrix.c === t1.matrix.c &&
r1.matrix.e === t1.matrix.e && r1.matrix.d === t1.matrix.d &&
r1.matrix.f === t1.matrix.f; r1.matrix.e === t1.matrix.e &&
r1.matrix.f === t1.matrix.f;
}()); }());
// Public API // Public API
svgedit.browser.isOpera = function () { return isOpera_; }; export const isOpera = () => isOpera_;
svgedit.browser.isWebkit = function () { return isWebkit_; }; export const isWebkit = () => isWebkit_;
svgedit.browser.isGecko = function () { return isGecko_; }; export const isGecko = () => isGecko_;
svgedit.browser.isIE = function () { return isIE_; }; export const isIE = () => isIE_;
svgedit.browser.isChrome = function () { return isChrome_; }; export const isChrome = () => isChrome_;
svgedit.browser.isWindows = function () { return isWindows_; }; export const isWindows = () => isWindows_;
svgedit.browser.isMac = function () { return isMac_; }; export const isMac = () => isMac_;
svgedit.browser.isTouch = function () { return isTouch_; }; export const isTouch = () => isTouch_;
svgedit.browser.supportsSelectors = function () { return supportsSelectors_; }; export const supportsSelectors = () => supportsSelectors_;
svgedit.browser.supportsXpath = function () { return supportsXpath_; }; export const supportsXpath = () => supportsXpath_;
svgedit.browser.supportsPathReplaceItem = function () { return supportsPathReplaceItem_; }; export const supportsPathReplaceItem = () => supportsPathReplaceItem_;
svgedit.browser.supportsPathInsertItemBefore = function () { return supportsPathInsertItemBefore_; }; export const supportsPathInsertItemBefore = () => supportsPathInsertItemBefore_;
svgedit.browser.supportsPathBBox = function () { return supportsPathBBox_; }; export const supportsPathBBox = () => supportsPathBBox_;
svgedit.browser.supportsHVLineContainerBBox = function () { return supportsHVLineContainerBBox_; }; export const supportsHVLineContainerBBox = () => supportsHVLineContainerBBox_;
svgedit.browser.supportsGoodTextCharPos = function () { return supportsGoodTextCharPos_; }; export const supportsGoodTextCharPos = () => supportsGoodTextCharPos_;
svgedit.browser.supportsEditableText = function () { return supportsEditableText_; }; export const supportsEditableText = () => supportsEditableText_;
svgedit.browser.supportsGoodDecimals = function () { return supportsGoodDecimals_; }; export const supportsGoodDecimals = () => supportsGoodDecimals_;
svgedit.browser.supportsNonScalingStroke = function () { return supportsNonScalingStroke_; }; export const supportsNonScalingStroke = () => supportsNonScalingStroke_;
svgedit.browser.supportsNativeTransformLists = function () { return supportsNativeSVGTransformLists_; }; export const supportsNativeTransformLists = () => supportsNativeSVGTransformLists_;
}());

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,10 @@
/* eslint-disable no-var */
/** /**
* A class to parse color values * A class to parse color values
* @author Stoyan Stefanov <sstoo@gmail.com> * @author Stoyan Stefanov <sstoo@gmail.com>
* @link https://www.phpied.com/rgb-color-parser-in-javascript/ * @link https://www.phpied.com/rgb-color-parser-in-javascript/
* @license Use it if you like it * @license MIT
*/ */
function RGBColor (colorString) { // eslint-disable-line no-unused-vars export default function RGBColor (colorString) {
'use strict';
this.ok = false; this.ok = false;
// strip any leading # // strip any leading #
@@ -19,7 +17,7 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
// before getting into regexps, try simple matches // before getting into regexps, try simple matches
// and overwrite the input // and overwrite the input
var simpleColors = { const simpleColors = {
aliceblue: 'f0f8ff', aliceblue: 'f0f8ff',
antiquewhite: 'faebd7', antiquewhite: 'faebd7',
aqua: '00ffff', aqua: '00ffff',
@@ -164,8 +162,7 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
yellow: 'ffff00', yellow: 'ffff00',
yellowgreen: '9acd32' yellowgreen: '9acd32'
}; };
var key; for (const key in simpleColors) {
for (key in simpleColors) {
if (simpleColors.hasOwnProperty(key)) { if (simpleColors.hasOwnProperty(key)) {
if (colorString === key) { if (colorString === key) {
colorString = simpleColors[key]; colorString = simpleColors[key];
@@ -175,11 +172,11 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
// emd of simple type-in colors // emd of simple type-in colors
// array of color definition objects // array of color definition objects
var colorDefs = [ const colorDefs = [
{ {
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process: function (bits) { process (bits) {
return [ return [
parseInt(bits[1], 10), parseInt(bits[1], 10),
parseInt(bits[2], 10), parseInt(bits[2], 10),
@@ -190,7 +187,7 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
{ {
re: /^(\w{2})(\w{2})(\w{2})$/, re: /^(\w{2})(\w{2})(\w{2})$/,
example: ['#00ff00', '336699'], example: ['#00ff00', '336699'],
process: function (bits) { process (bits) {
return [ return [
parseInt(bits[1], 16), parseInt(bits[1], 16),
parseInt(bits[2], 16), parseInt(bits[2], 16),
@@ -201,7 +198,7 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
{ {
re: /^(\w{1})(\w{1})(\w{1})$/, re: /^(\w{1})(\w{1})(\w{1})$/,
example: ['#fb0', 'f0f'], example: ['#fb0', 'f0f'],
process: function (bits) { process (bits) {
return [ return [
parseInt(bits[1] + bits[1], 16), parseInt(bits[1] + bits[1], 16),
parseInt(bits[2] + bits[2], 16), parseInt(bits[2] + bits[2], 16),
@@ -211,14 +208,13 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
} }
]; ];
var i;
// search through the definitions to find a match // search through the definitions to find a match
for (i = 0; i < colorDefs.length; i++) { for (let i = 0; i < colorDefs.length; i++) {
var re = colorDefs[i].re; const {re} = colorDefs[i];
var processor = colorDefs[i].process; const processor = colorDefs[i].process;
var bits = re.exec(colorString); const bits = re.exec(colorString);
if (bits) { if (bits) {
var channels = processor(bits); const channels = processor(bits);
this.r = channels[0]; this.r = channels[0];
this.g = channels[1]; this.g = channels[1];
this.b = channels[2]; this.b = channels[2];
@@ -236,9 +232,9 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
}; };
this.toHex = function () { this.toHex = function () {
var r = this.r.toString(16); let r = this.r.toString(16);
var g = this.g.toString(16); let g = this.g.toString(16);
var b = this.b.toString(16); let b = this.b.toString(16);
if (r.length === 1) { r = '0' + r; } if (r.length === 1) { r = '0' + r; }
if (g.length === 1) { g = '0' + g; } if (g.length === 1) { g = '0' + g; }
if (b.length === 1) { b = '0' + b; } if (b.length === 1) { b = '0' + b; }
@@ -247,30 +243,28 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
// help // help
this.getHelpXML = function () { this.getHelpXML = function () {
var i, j; const examples = [];
var examples = [];
// add regexps // add regexps
for (i = 0; i < colorDefs.length; i++) { for (let i = 0; i < colorDefs.length; i++) {
var example = colorDefs[i].example; const {example} = colorDefs[i];
for (j = 0; j < example.length; j++) { for (let j = 0; j < example.length; j++) {
examples[examples.length] = example[j]; examples[examples.length] = example[j];
} }
} }
// add type-in colors // add type-in colors
var sc; for (const sc in simpleColors) {
for (sc in simpleColors) {
if (simpleColors.hasOwnProperty(sc)) { if (simpleColors.hasOwnProperty(sc)) {
examples[examples.length] = sc; examples[examples.length] = sc;
} }
} }
var xml = document.createElement('ul'); const xml = document.createElement('ul');
xml.setAttribute('id', 'rgbcolor-examples'); xml.setAttribute('id', 'rgbcolor-examples');
for (i = 0; i < examples.length; i++) { for (let i = 0; i < examples.length; i++) {
try { try {
var listItem = document.createElement('li'); const listItem = document.createElement('li');
var listColor = new RGBColor(examples[i]); const listColor = new RGBColor(examples[i]);
var exampleDiv = document.createElement('div'); const exampleDiv = document.createElement('div');
exampleDiv.style.cssText = exampleDiv.style.cssText =
'margin: 3px; ' + 'margin: 3px; ' +
'border: 1px solid black; ' + 'border: 1px solid black; ' +
@@ -278,7 +272,7 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
'color:' + listColor.toHex() 'color:' + listColor.toHex()
; ;
exampleDiv.appendChild(document.createTextNode('test')); exampleDiv.appendChild(document.createTextNode('test'));
var listItemValue = document.createTextNode( const listItemValue = document.createTextNode(
' ' + examples[i] + ' -> ' + listColor.toRGB() + ' -> ' + listColor.toHex() ' ' + examples[i] + ' -> ' + listColor.toRGB() + ' -> ' + listColor.toHex()
); );
listItem.appendChild(exampleDiv); listItem.appendChild(exampleDiv);

View File

@@ -3,7 +3,6 @@
// CREATE A NEW FILE config.js AND ADD CONTENTS // CREATE A NEW FILE config.js AND ADD CONTENTS
// SUCH AS SHOWN BELOW INTO THAT FILE. // SUCH AS SHOWN BELOW INTO THAT FILE.
/* globals svgEditor */
/* /*
The config.js file is intended for the setting of configuration or The config.js file is intended for the setting of configuration or
preferences which must run early on; if this is not needed, it is preferences which must run early on; if this is not needed, it is
@@ -19,6 +18,8 @@ See defaultConfig and defaultExtensions in svg-editor.js for a list
See svg-editor.js for documentation on using setConfig(). See svg-editor.js for documentation on using setConfig().
*/ */
import svgEditor from './svg-editor.js';
// URL OVERRIDE CONFIG // URL OVERRIDE CONFIG
svgEditor.setConfig({ svgEditor.setConfig({
/** /**
@@ -117,25 +118,23 @@ As with configuration, one may use allowInitialUserOverride, but
Failing to use allowInitialUserOverride will ensure preferences Failing to use allowInitialUserOverride will ensure preferences
are hard-coded here regardless of URL or prior user storage setting. are hard-coded here regardless of URL or prior user storage setting.
*/ */
svgEditor.setConfig( svgEditor.setConfig({
{ // lang: '', // Set dynamically within locale.js if not previously set
// lang: '', // Set dynamically within locale.js if not previously set // iconsize: '', // Will default to 's' if the window height is smaller than the minimum height and 'm' otherwise
// iconsize: '', // Will default to 's' if the window height is smaller than the minimum height and 'm' otherwise /**
/** * When showing the preferences dialog, svg-editor.js currently relies
* When showing the preferences dialog, svg-editor.js currently relies * on curPrefs instead of $.pref, so allowing an override for bkgd_color
* on curPrefs instead of $.pref, so allowing an override for bkgd_color * means that this value won't have priority over block auto-detection as
* means that this value won't have priority over block auto-detection as * far as determining which color shows initially in the preferences
* far as determining which color shows initially in the preferences * dialog (though it can be changed and saved).
* dialog (though it can be changed and saved). */
*/ // bkgd_color: '#FFF',
// bkgd_color: '#FFF', // bkgd_url: '',
// bkgd_url: '', // img_save: 'embed',
// img_save: 'embed', // Only shows in UI as far as alert notices
// Only shows in UI as far as alert notices // save_notice_done: false,
// save_notice_done: false, // export_notice_done: false
// export_notice_done: false });
}
);
svgEditor.setConfig( svgEditor.setConfig(
{ {
// Indicate pref settings here if you wish to allow user storage or URL settings // Indicate pref settings here if you wish to allow user storage or URL settings

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery */
/* globals $, svgEditor */
/** /**
* Package: svgedit.contextmenu * Package: svgedit.contextmenu
* *
@@ -9,58 +8,50 @@
*/ */
// Dependencies: // Dependencies:
// 1) jQuery (for dom injection of context menus) // 1) jQuery (for dom injection of context menus)
var svgedit = svgedit || {}; // eslint-disable-line no-use-before-define
(function () { const $ = jQuery;
var self = this;
if (!svgedit.contextmenu) { let contextMenuExtensions = {};
svgedit.contextmenu = {};
} const menuItemIsValid = function (menuItem) {
self.contextMenuExtensions = {};
var menuItemIsValid = function (menuItem) {
return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action === 'function'; return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action === 'function';
}; };
var addContextMenuItem = function (menuItem) { export const addContextMenuItem = function (menuItem) {
// menuItem: {id, label, shortcut, action} // menuItem: {id, label, shortcut, action}
if (!menuItemIsValid(menuItem)) { if (!menuItemIsValid(menuItem)) {
console.error('Menu items must be defined and have at least properties: id, label, action, where action must be a function'); console.error('Menu items must be defined and have at least properties: id, label, action, where action must be a function');
return; return;
} }
if (menuItem.id in self.contextMenuExtensions) { if (menuItem.id in contextMenuExtensions) {
console.error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"'); console.error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"');
return; return;
} }
// Register menuItem action, see below for deferred menu dom injection // Register menuItem action, see below for deferred menu dom injection
console.log('Registed contextmenu item: {id:' + menuItem.id + ', label:' + menuItem.label + '}'); console.log('Registed contextmenu item: {id:' + menuItem.id + ', label:' + menuItem.label + '}');
self.contextMenuExtensions[menuItem.id] = menuItem; contextMenuExtensions[menuItem.id] = menuItem;
// TODO: Need to consider how to handle custom enable/disable behavior // TODO: Need to consider how to handle custom enable/disable behavior
}; };
var hasCustomHandler = function (handlerKey) { export const hasCustomMenuItemHandler = function (handlerKey) {
return self.contextMenuExtensions[handlerKey] && true; return Boolean(contextMenuExtensions[handlerKey]);
}; };
var getCustomHandler = function (handlerKey) { export const getCustomMenuItemHandler = function (handlerKey) {
return self.contextMenuExtensions[handlerKey].action; return contextMenuExtensions[handlerKey].action;
}; };
var injectExtendedContextMenuItemIntoDom = function (menuItem) { const injectExtendedContextMenuItemIntoDom = function (menuItem) {
if (Object.keys(self.contextMenuExtensions).length === 0) { if (!Object.keys(contextMenuExtensions).length) {
// all menuItems appear at the bottom of the menu in their own container. // all menuItems appear at the bottom of the menu in their own container.
// if this is the first extension menu we need to add the separator. // if this is the first extension menu we need to add the separator.
$('#cmenu_canvas').append("<li class='separator'>"); $('#cmenu_canvas').append("<li class='separator'>");
} }
var shortcut = menuItem.shortcut || ''; const shortcut = menuItem.shortcut || '';
$('#cmenu_canvas').append("<li class='disabled'><a href='#" + menuItem.id + "'>" + $('#cmenu_canvas').append("<li class='disabled'><a href='#" + menuItem.id + "'>" +
menuItem.label + "<span class='shortcut'>" + menuItem.label + "<span class='shortcut'>" +
shortcut + '</span></a></li>'); shortcut + '</span></a></li>');
}; };
// Defer injection to wait out initial menu processing. This probably goes away once all context
// menu behavior is brought here. export const injectExtendedContextMenuItemsIntoDom = function () {
svgEditor.ready(function () { for (const menuItem in contextMenuExtensions) {
var menuItem; injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]);
for (menuItem in self.contextMenuExtensions) {
injectExtendedContextMenuItemIntoDom(self.contextMenuExtensions[menuItem]);
} }
}); };
svgedit.contextmenu.resetCustomMenus = function () { self.contextMenuExtensions = {}; }; export const resetCustomMenus = function () { contextMenuExtensions = {}; };
svgedit.contextmenu.add = addContextMenuItem;
svgedit.contextmenu.hasCustomHandler = hasCustomHandler;
svgedit.contextmenu.getCustomHandler = getCustomHandler;
}());

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ // Todo: Update to latest version and adapt (and needs jQuery update as well): https://github.com/swisnl/jQuery-contextMenu
/* globals jQuery, $, svgedit */
// jQuery Context Menu Plugin // jQuery Context Menu Plugin
// //
// Version 1.01 // Version 1.01
@@ -15,191 +14,190 @@
// This plugin is dual-licensed under the GNU General Public License // This plugin is dual-licensed under the GNU General Public License
// and the MIT License and is copyright A Beautiful Site, LLC. // and the MIT License and is copyright A Beautiful Site, LLC.
// //
if (jQuery) { import {isMac} from './browser.js';
(function () {
var win = $(window);
var doc = $(document);
$.extend($.fn, { export default function ($) {
const win = $(window);
const doc = $(document);
contextMenu: function (o, callback) { $.extend($.fn, {
// Defaults contextMenu (o, callback) {
if (o.menu === undefined) return false; // Defaults
if (o.inSpeed === undefined) o.inSpeed = 150; if (o.menu === undefined) return false;
if (o.outSpeed === undefined) o.outSpeed = 75; if (o.inSpeed === undefined) o.inSpeed = 150;
// 0 needs to be -1 for expected results (no fade) if (o.outSpeed === undefined) o.outSpeed = 75;
if (o.inSpeed === 0) o.inSpeed = -1; // 0 needs to be -1 for expected results (no fade)
if (o.outSpeed === 0) o.outSpeed = -1; if (o.inSpeed === 0) o.inSpeed = -1;
// Loop each context menu if (o.outSpeed === 0) o.outSpeed = -1;
$(this).each(function () { // Loop each context menu
var el = $(this); $(this).each(function () {
var offset = $(el).offset(); const el = $(this);
const offset = $(el).offset();
var menu = $('#' + o.menu); const menu = $('#' + o.menu);
// Add contextMenu class // Add contextMenu class
menu.addClass('contextMenu'); menu.addClass('contextMenu');
// Simulate a true right click // Simulate a true right click
$(this).bind('mousedown', function (e) { $(this).bind('mousedown', function (e) {
var evt = e; const evt = e;
$(this).mouseup(function (e) { $(this).mouseup(function (e) {
var srcElement = $(this); const srcElement = $(this);
srcElement.unbind('mouseup'); srcElement.unbind('mouseup');
if (evt.button === 2 || o.allowLeft || if (evt.button === 2 || o.allowLeft ||
(evt.ctrlKey && svgedit.browser.isMac())) { (evt.ctrlKey && isMac())) {
e.stopPropagation(); e.stopPropagation();
// Hide context menus that may be showing // Hide context menus that may be showing
$('.contextMenu').hide(); $('.contextMenu').hide();
// Get this context menu // Get this context menu
if (el.hasClass('disabled')) return false; if (el.hasClass('disabled')) return false;
// Detect mouse position // Detect mouse position
var x = e.pageX, y = e.pageY; let x = e.pageX, y = e.pageY;
var xOff = win.width() - menu.width(), const xOff = win.width() - menu.width(),
yOff = win.height() - menu.height(); yOff = win.height() - menu.height();
if (x > xOff - 15) x = xOff - 15; if (x > xOff - 15) x = xOff - 15;
if (y > yOff - 30) y = yOff - 30; // 30 is needed to prevent scrollbars in FF if (y > yOff - 30) y = yOff - 30; // 30 is needed to prevent scrollbars in FF
// Show the menu // Show the menu
doc.unbind('click'); doc.unbind('click');
menu.css({ top: y, left: x }).fadeIn(o.inSpeed); menu.css({ top: y, left: x }).fadeIn(o.inSpeed);
// Hover events // Hover events
menu.find('A').mouseover(function () { menu.find('A').mouseover(function () {
menu.find('LI.hover').removeClass('hover'); menu.find('LI.hover').removeClass('hover');
$(this).parent().addClass('hover'); $(this).parent().addClass('hover');
}).mouseout(function () { }).mouseout(function () {
menu.find('LI.hover').removeClass('hover'); menu.find('LI.hover').removeClass('hover');
}); });
// Keyboard // Keyboard
doc.keypress(function (e) { doc.keypress(function (e) {
switch (e.keyCode) { switch (e.keyCode) {
case 38: // up case 38: // up
if (!menu.find('LI.hover').length) { if (!menu.find('LI.hover').length) {
menu.find('LI:last').addClass('hover'); menu.find('LI:last').addClass('hover');
} else { } else {
menu.find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); menu.find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover');
if (!menu.find('LI.hover').length) menu.find('LI:last').addClass('hover'); if (!menu.find('LI.hover').length) menu.find('LI:last').addClass('hover');
}
break;
case 40: // down
if (menu.find('LI.hover').length === 0) {
menu.find('LI:first').addClass('hover');
} else {
menu.find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover');
if (!menu.find('LI.hover').length) menu.find('LI:first').addClass('hover');
}
break;
case 13: // enter
menu.find('LI.hover A').trigger('click');
break;
case 27: // esc
doc.trigger('click');
break;
} }
}); break;
case 40: // down
if (!menu.find('LI.hover').length) {
menu.find('LI:first').addClass('hover');
} else {
menu.find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover');
if (!menu.find('LI.hover').length) menu.find('LI:first').addClass('hover');
}
break;
case 13: // enter
menu.find('LI.hover A').trigger('click');
break;
case 27: // esc
doc.trigger('click');
break;
}
});
// When items are selected // When items are selected
menu.find('A').unbind('mouseup'); menu.find('A').unbind('mouseup');
menu.find('LI:not(.disabled) A').mouseup(function () { menu.find('LI:not(.disabled) A').mouseup(function () {
doc.unbind('click').unbind('keypress');
$('.contextMenu').hide();
// Callback
if (callback) callback($(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y});
return false;
});
// Hide bindings
setTimeout(function () { // Delay for Mozilla
doc.click(function () {
doc.unbind('click').unbind('keypress'); doc.unbind('click').unbind('keypress');
$('.contextMenu').hide(); menu.fadeOut(o.outSpeed);
// Callback
if (callback) callback($(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y});
return false; return false;
}); });
}, 0);
// Hide bindings }
setTimeout(function () { // Delay for Mozilla
doc.click(function () {
doc.unbind('click').unbind('keypress');
menu.fadeOut(o.outSpeed);
return false;
});
}, 0);
}
});
}); });
// Disable text selection
if ($.browser.mozilla) {
$('#' + o.menu).each(function () { $(this).css({'MozUserSelect': 'none'}); });
} else if ($.browser.msie) {
$('#' + o.menu).each(function () { $(this).bind('selectstart.disableTextSelect', function () { return false; }); });
} else {
$('#' + o.menu).each(function () { $(this).bind('mousedown.disableTextSelect', function () { return false; }); });
}
// Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
$(el).add($('UL.contextMenu')).bind('contextmenu', function () { return false; });
}); });
return $(this);
},
// Disable context menu items on the fly // Disable text selection
disableContextMenuItems: function (o) { if ($.browser.mozilla) {
if (o === undefined) { $('#' + o.menu).each(function () { $(this).css({'MozUserSelect': 'none'}); });
// Disable all } else if ($.browser.msie) {
$(this).find('LI').addClass('disabled'); $('#' + o.menu).each(function () { $(this).bind('selectstart.disableTextSelect', function () { return false; }); });
return $(this); } else {
$('#' + o.menu).each(function () { $(this).bind('mousedown.disableTextSelect', function () { return false; }); });
} }
$(this).each(function () { // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome)
if (o !== undefined) { $(el).add($('UL.contextMenu')).bind('contextmenu', function () { return false; });
var d = o.split(','); });
for (var i = 0; i < d.length; i++) { return $(this);
$(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); },
}
}
});
return $(this);
},
// Enable context menu items on the fly // Disable context menu items on the fly
enableContextMenuItems: function (o) { disableContextMenuItems (o) {
if (o === undefined) { if (o === undefined) {
// Enable all // Disable all
$(this).find('LI.disabled').removeClass('disabled'); $(this).find('LI').addClass('disabled');
return $(this);
}
$(this).each(function () {
if (o !== undefined) {
var d = o.split(',');
for (var i = 0; i < d.length; i++) {
$(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled');
}
}
});
return $(this);
},
// Disable context menu(s)
disableContextMenu: function () {
$(this).each(function () {
$(this).addClass('disabled');
});
return $(this);
},
// Enable context menu(s)
enableContextMenu: function () {
$(this).each(function () {
$(this).removeClass('disabled');
});
return $(this);
},
// Destroy context menu(s)
destroyContextMenu: function () {
// Destroy specified context menus
$(this).each(function () {
// Disable action
$(this).unbind('mousedown').unbind('mouseup');
});
return $(this); return $(this);
} }
$(this).each(function () {
if (o !== undefined) {
const d = o.split(',');
for (let i = 0; i < d.length; i++) {
$(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled');
}
}
});
return $(this);
},
}); // Enable context menu items on the fly
})(jQuery); enableContextMenuItems (o) {
if (o === undefined) {
// Enable all
$(this).find('LI.disabled').removeClass('disabled');
return $(this);
}
$(this).each(function () {
if (o !== undefined) {
const d = o.split(',');
for (let i = 0; i < d.length; i++) {
$(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled');
}
}
});
return $(this);
},
// Disable context menu(s)
disableContextMenu () {
$(this).each(function () {
$(this).addClass('disabled');
});
return $(this);
},
// Enable context menu(s)
enableContextMenu () {
$(this).each(function () {
$(this).removeClass('disabled');
});
return $(this);
},
// Destroy context menu(s)
destroyContextMenu () {
// Destroy specified context menus
$(this).each(function () {
// Disable action
$(this).unbind('mousedown').unbind('mouseup');
});
return $(this);
}
});
return $;
} }

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery */
/* globals $, svgroot */
/** /**
* Coords. * Coords.
* *
@@ -8,25 +7,21 @@
*/ */
// Dependencies: // Dependencies:
// 1) jquery.js // 1) jquery.min.js
// 2) math.js
// 3) pathseg.js
// 4) browser.js
// 5) svgutils.js
// 6) units.js
// 7) svgtransformlist.js
var svgedit = svgedit || {}; // eslint-disable-line no-use-before-define import './pathseg.js';
import {
snapToGrid, assignAttributes, getBBox, getRefElem, findDefs
} from './svgutils.js';
import {
transformPoint, transformListToTransform, matrixMultiply, transformBox
} from './math.js';
import {getTransformList} from './svgtransformlist.js';
(function () { const $ = jQuery;
'use strict';
if (!svgedit.coords) {
svgedit.coords = {};
}
// this is how we map paths to our preferred relative segment types // this is how we map paths to our preferred relative segment types
var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', const pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; 'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
/** /**
@@ -35,12 +30,12 @@ var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
* @property {function} getGridSnapping * @property {function} getGridSnapping
* @property {function} getDrawing * @property {function} getDrawing
*/ */
var editorContext_ = null; let editorContext_ = null;
/** /**
* @param {editorContext} editorContext * @param {editorContext} editorContext
*/ */
svgedit.coords.init = function (editorContext) { export const init = function (editorContext) {
editorContext_ = editorContext; editorContext_ = editorContext;
}; };
@@ -50,47 +45,45 @@ svgedit.coords.init = function (editorContext) {
* @param {Object} changes - Object with changes to be remapped * @param {Object} changes - Object with changes to be remapped
* @param {SVGMatrix} m - Matrix object to use for remapping coordinates * @param {SVGMatrix} m - Matrix object to use for remapping coordinates
*/ */
svgedit.coords.remapElement = function (selected, changes, m) { export const remapElement = function (selected, changes, m) {
var i, type, const remap = function (x, y) { return transformPoint(x, y, m); },
remap = function (x, y) { return svgedit.math.transformPoint(x, y, m); },
scalew = function (w) { return m.a * w; }, scalew = function (w) { return m.a * w; },
scaleh = function (h) { return m.d * h; }, scaleh = function (h) { return m.d * h; },
doSnapping = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg', doSnapping = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg',
finishUp = function () { finishUp = function () {
var o;
if (doSnapping) { if (doSnapping) {
for (o in changes) { for (const o in changes) {
changes[o] = svgedit.utilities.snapToGrid(changes[o]); changes[o] = snapToGrid(changes[o]);
} }
} }
svgedit.utilities.assignAttributes(selected, changes, 1000, true); assignAttributes(selected, changes, 1000, true);
}, },
box = svgedit.utilities.getBBox(selected); box = getBBox(selected);
for (i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
type = i === 0 ? 'fill' : 'stroke'; const type = i === 0 ? 'fill' : 'stroke';
var attrVal = selected.getAttribute(type); const attrVal = selected.getAttribute(type);
if (attrVal && attrVal.indexOf('url(') === 0) { if (attrVal && attrVal.startsWith('url(')) {
if (m.a < 0 || m.d < 0) { if (m.a < 0 || m.d < 0) {
var grad = svgedit.utilities.getRefElem(attrVal); const grad = getRefElem(attrVal);
var newgrad = grad.cloneNode(true); const newgrad = grad.cloneNode(true);
if (m.a < 0) { if (m.a < 0) {
// flip x // flip x
var x1 = newgrad.getAttribute('x1'); const x1 = newgrad.getAttribute('x1');
var x2 = newgrad.getAttribute('x2'); const x2 = newgrad.getAttribute('x2');
newgrad.setAttribute('x1', -(x1 - 1)); newgrad.setAttribute('x1', -(x1 - 1));
newgrad.setAttribute('x2', -(x2 - 1)); newgrad.setAttribute('x2', -(x2 - 1));
} }
if (m.d < 0) { if (m.d < 0) {
// flip y // flip y
var y1 = newgrad.getAttribute('y1'); const y1 = newgrad.getAttribute('y1');
var y2 = newgrad.getAttribute('y2'); const y2 = newgrad.getAttribute('y2');
newgrad.setAttribute('y1', -(y1 - 1)); newgrad.setAttribute('y1', -(y1 - 1));
newgrad.setAttribute('y2', -(y2 - 1)); newgrad.setAttribute('y2', -(y2 - 1));
} }
newgrad.id = editorContext_.getDrawing().getNextId(); newgrad.id = editorContext_.getDrawing().getNextId();
svgedit.utilities.findDefs().appendChild(newgrad); findDefs().appendChild(newgrad);
selected.setAttribute(type, 'url(#' + newgrad.id + ')'); selected.setAttribute(type, 'url(#' + newgrad.id + ')');
} }
@@ -101,43 +94,42 @@ svgedit.coords.remapElement = function (selected, changes, m) {
} }
} }
var elName = selected.tagName; const elName = selected.tagName;
var chlist, mt;
if (elName === 'g' || elName === 'text' || elName === 'tspan' || elName === 'use') { if (elName === 'g' || elName === 'text' || elName === 'tspan' || elName === 'use') {
// if it was a translate, then just update x,y // if it was a translate, then just update x,y
if (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && (m.e !== 0 || m.f !== 0)) { if (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && (m.e !== 0 || m.f !== 0)) {
// [T][M] = [M][T'] // [T][M] = [M][T']
// therefore [T'] = [M_inv][T][M] // therefore [T'] = [M_inv][T][M]
var existing = svgedit.math.transformListToTransform(selected).matrix, const existing = transformListToTransform(selected).matrix,
tNew = svgedit.math.matrixMultiply(existing.inverse(), m, existing); tNew = matrixMultiply(existing.inverse(), m, existing);
changes.x = parseFloat(changes.x) + tNew.e; changes.x = parseFloat(changes.x) + tNew.e;
changes.y = parseFloat(changes.y) + tNew.f; changes.y = parseFloat(changes.y) + tNew.f;
} else { } else {
// we just absorb all matrices into the element and don't do any remapping // we just absorb all matrices into the element and don't do any remapping
chlist = svgedit.transformlist.getTransformList(selected); const chlist = getTransformList(selected);
mt = svgroot.createSVGTransform(); const mt = editorContext_.getSVGRoot().createSVGTransform();
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m)); mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m));
chlist.clear(); chlist.clear();
chlist.appendItem(mt); chlist.appendItem(mt);
} }
} }
var c, pt, pt1, pt2, len;
// now we have a set of changes and an applied reduced transform list // now we have a set of changes and an applied reduced transform list
// we apply the changes directly to the DOM // we apply the changes directly to the DOM
switch (elName) { switch (elName) {
case 'foreignObject': case 'foreignObject':
case 'rect': case 'rect':
case 'image': case 'image': {
// Allow images to be inverted (give them matrix when flipped) // Allow images to be inverted (give them matrix when flipped)
if (elName === 'image' && (m.a < 0 || m.d < 0)) { if (elName === 'image' && (m.a < 0 || m.d < 0)) {
// Convert to matrix // Convert to matrix
chlist = svgedit.transformlist.getTransformList(selected); const chlist = getTransformList(selected);
mt = svgroot.createSVGTransform(); const mt = editorContext_.getSVGRoot().createSVGTransform();
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m)); mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m));
chlist.clear(); chlist.clear();
chlist.appendItem(mt); chlist.appendItem(mt);
} else { } else {
pt1 = remap(changes.x, changes.y); const pt1 = remap(changes.x, changes.y);
changes.width = scalew(changes.width); changes.width = scalew(changes.width);
changes.height = scaleh(changes.height); changes.height = scaleh(changes.height);
changes.x = pt1.x + Math.min(0, changes.width); changes.x = pt1.x + Math.min(0, changes.width);
@@ -147,8 +139,8 @@ svgedit.coords.remapElement = function (selected, changes, m) {
} }
finishUp(); finishUp();
break; break;
case 'ellipse': } case 'ellipse': {
c = remap(changes.cx, changes.cy); const c = remap(changes.cx, changes.cy);
changes.cx = c.x; changes.cx = c.x;
changes.cy = c.y; changes.cy = c.y;
changes.rx = scalew(changes.rx); changes.rx = scalew(changes.rx);
@@ -157,62 +149,61 @@ svgedit.coords.remapElement = function (selected, changes, m) {
changes.ry = Math.abs(changes.ry); changes.ry = Math.abs(changes.ry);
finishUp(); finishUp();
break; break;
case 'circle': } case 'circle': {
c = remap(changes.cx, changes.cy); const c = remap(changes.cx, changes.cy);
changes.cx = c.x; changes.cx = c.x;
changes.cy = c.y; changes.cy = c.y;
// take the minimum of the new selected box's dimensions for the new circle radius // take the minimum of the new selected box's dimensions for the new circle radius
var tbox = svgedit.math.transformBox(box.x, box.y, box.width, box.height, m); const tbox = transformBox(box.x, box.y, box.width, box.height, m);
var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y; const w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y;
changes.r = Math.min(w / 2, h / 2); changes.r = Math.min(w / 2, h / 2);
if (changes.r) { changes.r = Math.abs(changes.r); } if (changes.r) { changes.r = Math.abs(changes.r); }
finishUp(); finishUp();
break; break;
case 'line': } case 'line': {
pt1 = remap(changes.x1, changes.y1); const pt1 = remap(changes.x1, changes.y1);
pt2 = remap(changes.x2, changes.y2); const pt2 = remap(changes.x2, changes.y2);
changes.x1 = pt1.x; changes.x1 = pt1.x;
changes.y1 = pt1.y; changes.y1 = pt1.y;
changes.x2 = pt2.x; changes.x2 = pt2.x;
changes.y2 = pt2.y; changes.y2 = pt2.y;
// deliberately fall through here } // Fallthrough
case 'text': case 'text':
case 'tspan': case 'tspan':
case 'use': case 'use': {
finishUp(); finishUp();
break; break;
case 'g': } case 'g': {
var gsvg = $(selected).data('gsvg'); const gsvg = $(selected).data('gsvg');
if (gsvg) { if (gsvg) {
svgedit.utilities.assignAttributes(gsvg, changes, 1000, true); assignAttributes(gsvg, changes, 1000, true);
} }
break; break;
case 'polyline': } case 'polyline':
case 'polygon': case 'polygon': {
len = changes.points.length; const len = changes.points.length;
for (i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
pt = changes.points[i]; const pt = changes.points[i];
pt = remap(pt.x, pt.y); const {x, y} = remap(pt.x, pt.y);
changes.points[i].x = pt.x; changes.points[i].x = x;
changes.points[i].y = pt.y; changes.points[i].y = y;
} }
len = changes.points.length; // const len = changes.points.length;
var pstr = ''; let pstr = '';
for (i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
pt = changes.points[i]; const pt = changes.points[i];
pstr += pt.x + ',' + pt.y + ' '; pstr += pt.x + ',' + pt.y + ' ';
} }
selected.setAttribute('points', pstr); selected.setAttribute('points', pstr);
break; break;
case 'path': } case 'path': {
var seg; const segList = selected.pathSegList;
var segList = selected.pathSegList; let len = segList.numberOfItems;
len = segList.numberOfItems;
changes.d = []; changes.d = [];
for (i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
seg = segList.getItem(i); const seg = segList.getItem(i);
changes.d[i] = { changes.d[i] = {
type: seg.pathSegType, type: seg.pathSegType,
x: seg.x, x: seg.x,
@@ -230,21 +221,21 @@ svgedit.coords.remapElement = function (selected, changes, m) {
} }
len = changes.d.length; len = changes.d.length;
var firstseg = changes.d[0], const firstseg = changes.d[0],
currentpt = remap(firstseg.x, firstseg.y); currentpt = remap(firstseg.x, firstseg.y);
changes.d[0].x = currentpt.x; changes.d[0].x = currentpt.x;
changes.d[0].y = currentpt.y; changes.d[0].y = currentpt.y;
for (i = 1; i < len; ++i) { for (let i = 1; i < len; ++i) {
seg = changes.d[i]; const seg = changes.d[i];
type = seg.type; const {type} = seg;
// if absolute or first segment, we want to remap x, y, x1, y1, x2, y2 // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2
// if relative, we want to scalew, scaleh // if relative, we want to scalew, scaleh
if (type % 2 === 0) { // absolute if (type % 2 === 0) { // absolute
var thisx = (seg.x !== undefined) ? seg.x : currentpt.x, // for V commands const thisx = (seg.x !== undefined) ? seg.x : currentpt.x, // for V commands
thisy = (seg.y !== undefined) ? seg.y : currentpt.y; // for H commands thisy = (seg.y !== undefined) ? seg.y : currentpt.y; // for H commands
pt = remap(thisx, thisy); const pt = remap(thisx, thisy);
pt1 = remap(seg.x1, seg.y1); const pt1 = remap(seg.x1, seg.y1);
pt2 = remap(seg.x2, seg.y2); const pt2 = remap(seg.x2, seg.y2);
seg.x = pt.x; seg.x = pt.x;
seg.y = pt.y; seg.y = pt.y;
seg.x1 = pt1.x; seg.x1 = pt1.x;
@@ -265,11 +256,11 @@ svgedit.coords.remapElement = function (selected, changes, m) {
} }
} // for each segment } // for each segment
var dstr = ''; let dstr = '';
len = changes.d.length; len = changes.d.length;
for (i = 0; i < len; ++i) { for (let i = 0; i < len; ++i) {
seg = changes.d[i]; const seg = changes.d[i];
type = seg.type; const {type} = seg;
dstr += pathMap[type]; dstr += pathMap[type];
switch (type) { switch (type) {
case 13: // relative horizontal line (h) case 13: // relative horizontal line (h)
@@ -312,5 +303,5 @@ svgedit.coords.remapElement = function (selected, changes, m) {
selected.setAttribute('d', dstr); selected.setAttribute('d', dstr);
break; break;
} }
}
}; };
}());

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,21 @@
/* eslint-disable no-var */ /* globals jQuery */
/* globals $, EmbeddedSVGEdit */ import EmbeddedSVGEdit from './embedapi.js';
var initEmbed; // eslint-disable-line no-unused-vars const $ = jQuery;
// Todo: Get rid of frame.contentWindow dependencies so can be more easily adjusted to work cross-domain // Todo: Add iframe load listener
var initEmbed;
// Todo: Get rid of frame.contentWindow dependencies so can be more
// easily adjusted to work cross-domain
$(function () { $(function () {
'use strict'; let svgCanvas = null;
var svgCanvas = null;
var frame;
initEmbed = function () { initEmbed = function () {
var doc, mainButton;
svgCanvas = new EmbeddedSVGEdit(frame); svgCanvas = new EmbeddedSVGEdit(frame);
// Hide main button, as we will be controlling new, load, save, etc. from the host document // Hide main button, as we will be controlling new, load, save, etc. from the host document
doc = frame.contentDocument || frame.contentWindow.document; const doc = frame.contentDocument || frame.contentWindow.document;
mainButton = doc.getElementById('main_button'); const mainButton = doc.getElementById('main_button');
mainButton.style.display = 'none'; mainButton.style.display = 'none';
}; };
@@ -28,7 +28,7 @@ $(function () {
} }
function loadSvg () { function loadSvg () {
var svgexample = '<svg width="640" height="480" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><g><title>Layer 1</title><rect stroke-width="5" stroke="#000000" fill="#FF0000" id="svg_1" height="35" width="51" y="35" x="32"/><ellipse ry="15" rx="24" stroke-width="5" stroke="#000000" fill="#0000ff" id="svg_2" cy="60" cx="66"/></g></svg>'; const svgexample = '<svg width="640" height="480" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><g><title>Layer 1</title><rect stroke-width="5" stroke="#000000" fill="#FF0000" id="svg_1" height="35" width="51" y="35" x="32"/><ellipse ry="15" rx="24" stroke-width="5" stroke="#000000" fill="#0000ff" id="svg_2" cy="60" cx="66"/></g></svg>';
svgCanvas.setSvgString(svgexample); svgCanvas.setSvgString(svgexample);
} }
@@ -37,9 +37,9 @@ $(function () {
} }
function exportPNG () { function exportPNG () {
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage; const str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage;
var exportWindow = window.open( const exportWindow = window.open(
'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'), 'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'),
'svg-edit-exportWindow' 'svg-edit-exportWindow'
); );
@@ -47,7 +47,7 @@ $(function () {
} }
function exportPDF () { function exportPDF () {
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage; const str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage;
/** /**
// If you want to handle the PDF blob yourself, do as follows // If you want to handle the PDF blob yourself, do as follows
@@ -58,7 +58,7 @@ $(function () {
return; return;
*/ */
var exportWindow = window.open( const exportWindow = window.open(
'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'), 'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'),
'svg-edit-exportWindow' 'svg-edit-exportWindow'
); );
@@ -76,5 +76,5 @@ $(function () {
'" width="900px" height="600px" id="svgedit" onload="initEmbed();"></iframe>' '" width="900px" height="600px" id="svgedit" onload="initEmbed();"></iframe>'
) )
); );
frame = document.getElementById('svgedit'); const frame = document.getElementById('svgedit');
}); });

View File

@@ -3,9 +3,9 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>Embed API</title> <title>Embed API</title>
<script src="jquery.js"></script> <link rel="icon" type="image/png" href="images/logo.png"/>
<script src="embedapi.js"></script> <script src="jquery.min.js"></script>
<script src="embedapi-dom.js"></script> <script type="module" src="embedapi-dom.js"></script>
</head> </head>
<body> <body>
<button id="load">Load example</button> <button id="load">Load example</button>

View File

@@ -1,11 +1,10 @@
/* eslint-disable no-var */
/* /*
Embedded SVG-edit API Embedded SVG-edit API
General usage: General usage:
- Have an iframe somewhere pointing to a version of svg-edit > r1000 - Have an iframe somewhere pointing to a version of svg-edit > r1000
- Initialize the magic with: - Initialize the magic with:
var svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit); const svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
- Pass functions in this format: - Pass functions in this format:
svgCanvas.setSvgString('string') svgCanvas.setSvgString('string')
- Or if a callback is needed: - Or if a callback is needed:
@@ -32,18 +31,15 @@ JavaScript methods on the frame itself.
The only other difference is The only other difference is
when handling returns: the callback notation is used instead. when handling returns: the callback notation is used instead.
var blah = new EmbeddedSVGEdit(window.frames.svgedit); const blah = new EmbeddedSVGEdit(window.frames.svgedit);
blah.clearSelection('woot', 'blah', 1337, [1, 2, 3, 4, 5, 'moo'], -42, {a: 'tree',b:6, c: 9})(function(){console.log('GET DATA',arguments)}) blah.clearSelection('woot', 'blah', 1337, [1, 2, 3, 4, 5, 'moo'], -42, {a: 'tree',b:6, c: 9})(function(){console.log('GET DATA',arguments)})
*/ */
(function () { let cbid = 0;
'use strict';
var cbid = 0;
function getCallbackSetter (d) { function getCallbackSetter (d) {
return function () { return function () {
var t = this, // New callback const t = this, // New callback
args = [].slice.call(arguments), args = [].slice.call(arguments),
cbid = t.send(d, args, function () {}); // The callback (currently it's nothing, but will be set later) cbid = t.send(d, args, function () {}); // The callback (currently it's nothing, but will be set later)
@@ -59,7 +55,7 @@ function getCallbackSetter (d) {
* of same domain control * of same domain control
*/ */
function addCallback (t, data) { function addCallback (t, data) {
var result = data.result || data.error, const result = data.result || data.error,
cbid = data.id; cbid = data.id;
if (t.callbacks[cbid]) { if (t.callbacks[cbid]) {
if (data.result) { if (data.result) {
@@ -76,11 +72,11 @@ function messageListener (e) {
if (typeof e.data !== 'string') { if (typeof e.data !== 'string') {
return; return;
} }
var allowedOrigins = this.allowedOrigins, const {allowedOrigins} = this,
data = e.data && JSON.parse(e.data); data = e.data && JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' || if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' ||
e.source !== this.frame.contentWindow || e.source !== this.frame.contentWindow ||
(allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1) (!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin))
) { ) {
return; return;
} }
@@ -99,80 +95,77 @@ function getMessageListener (t) {
* messages will be allowed when same origin is not used; defaults to none. * messages will be allowed when same origin is not used; defaults to none.
* If supplied, it should probably be the same as svgEditor's allowedOrigins * If supplied, it should probably be the same as svgEditor's allowedOrigins
*/ */
function EmbeddedSVGEdit (frame, allowedOrigins) { class EmbeddedSVGEdit {
if (!(this instanceof EmbeddedSVGEdit)) { // Allow invocation without 'new' keyword constructor (frame, allowedOrigins) {
return new EmbeddedSVGEdit(frame); this.allowedOrigins = allowedOrigins || [];
} // Initialize communication
this.allowedOrigins = allowedOrigins || []; this.frame = frame;
// Initialize communication this.callbacks = {};
this.frame = frame; // List of functions extracted with this:
this.callbacks = {}; // Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
// List of functions extracted with this:
// Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
// for (var i=0,q=[],f = document.querySelectorAll('div.CFunction h3.CTitle a'); i < f.length; i++) { q.push(f[i].name); }; q // for (const i=0,q=[],f = document.querySelectorAll('div.CFunction h3.CTitle a'); i < f.length; i++) { q.push(f[i].name); }; q
// var functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString', // const functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString',
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility', // 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
// 'moveSelectedToLayer', 'clear']; // 'moveSelectedToLayer', 'clear'];
// Newer, well, it extracts things that aren't documented as well. All functions accessible through the normal thingy can now be accessed though the API // Newer, well, it extracts things that aren't documented as well. All functions accessible through the normal thingy can now be accessed though the API
// var svgCanvas = frame.contentWindow.svgCanvas; // const {svgCanvas} = frame.contentWindow;
// var l = []; for (var i in svgCanvas){ if (typeof svgCanvas[i] == 'function') { l.push(i);} }; // const l = [];
// alert("['" + l.join("', '") + "']"); // for (const i in svgCanvas) { if (typeof svgCanvas[i] === 'function') { l.push(i);} };
// Run in svgedit itself // alert("['" + l.join("', '") + "']");
var i, // Run in svgedit itself
functions = [ const functions = [
'clearSvgContentElement', 'setIdPrefix', 'getCurrentDrawing', 'addSvgElementFromJson', 'getTransformList', 'matrixMultiply', 'hasMatrixTransform', 'transformListToTransform', 'convertToNum', 'findDefs', 'getUrlFromAttr', 'getHref', 'setHref', 'getBBox', 'getRotationAngle', 'getElem', 'getRefElem', 'assignAttributes', 'cleanupElement', 'remapElement', 'recalculateDimensions', 'sanitizeSvg', 'runExtensions', 'addExtension', 'round', 'getIntersectionList', 'getStrokedBBox', 'getVisibleElements', 'getVisibleElementsAndBBoxes', 'groupSvgElem', 'getId', 'getNextId', 'call', 'bind', 'prepareSvg', 'setRotationAngle', 'recalculateAllSelectedDimensions', 'clearSelection', 'addToSelection', 'selectOnly', 'removeFromSelection', 'selectAllInCurrentLayer', 'getMouseTarget', 'removeUnusedDefElems', 'svgCanvasToString', 'svgToString', 'embedImage', 'setGoodImage', 'open', 'save', 'rasterExport', 'exportPDF', 'getSvgString', 'randomizeIds', 'uniquifyElems', 'setUseData', 'convertGradients', 'convertToGroup', 'setSvgString', 'importSvgString', 'identifyLayers', 'createLayer', 'cloneLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility', 'moveSelectedToLayer', 'mergeLayer', 'mergeAllLayers', 'leaveContext', 'setContext', 'clear', 'linkControlPoints', 'getContentElem', 'getRootElem', 'getSelectedElems', 'getResolution', 'getZoom', 'getVersion', 'setUiStrings', 'setConfig', 'getTitle', 'setGroupTitle', 'getDocumentTitle', 'setDocumentTitle', 'getEditorNS', 'setResolution', 'getOffset', 'setBBoxZoom', 'setZoom', 'getMode', 'setMode', 'getColor', 'setColor', 'setGradient', 'setPaint', 'setStrokePaint', 'setFillPaint', 'getStrokeWidth', 'setStrokeWidth', 'setStrokeAttr', 'getStyle', 'getOpacity', 'setOpacity', 'getFillOpacity', 'getStrokeOpacity', 'setPaintOpacity', 'getPaintOpacity', 'getBlur', 'setBlurNoUndo', 'setBlurOffsets', 'setBlur', 'getBold', 'setBold', 'getItalic', 'setItalic', 'getFontFamily', 'setFontFamily', 'setFontColor', 'getFontColor', 'getFontSize', 'setFontSize', 'getText', 'setTextContent', 'setImageURL', 'setLinkURL', 'setRectRadius', 'makeHyperlink', 'removeHyperlink', 'setSegType', 'convertToPath', 'changeSelectedAttribute', 'deleteSelectedElements', 'cutSelectedElements', 'copySelectedElements', 'pasteElements', 'groupSelectedElements', 'pushGroupProperties', 'ungroupSelectedElement', 'moveToTopSelectedElement', 'moveToBottomSelectedElement', 'moveUpDownSelected', 'moveSelectedElements', 'cloneSelectedElements', 'alignSelectedElements', 'updateCanvas', 'setBackground', 'cycleElement', 'getPrivateMethods', 'zoomChanged', 'ready' 'clearSvgContentElement', 'setIdPrefix', 'getCurrentDrawing', 'addSvgElementFromJson', 'getTransformList', 'matrixMultiply', 'hasMatrixTransform', 'transformListToTransform', 'convertToNum', 'findDefs', 'getUrlFromAttr', 'getHref', 'setHref', 'getBBox', 'getRotationAngle', 'getElem', 'getRefElem', 'assignAttributes', 'cleanupElement', 'remapElement', 'recalculateDimensions', 'sanitizeSvg', 'runExtensions', 'addExtension', 'round', 'getIntersectionList', 'getStrokedBBox', 'getVisibleElements', 'getVisibleElementsAndBBoxes', 'groupSvgElem', 'getId', 'getNextId', 'call', 'bind', 'prepareSvg', 'setRotationAngle', 'recalculateAllSelectedDimensions', 'clearSelection', 'addToSelection', 'selectOnly', 'removeFromSelection', 'selectAllInCurrentLayer', 'getMouseTarget', 'removeUnusedDefElems', 'svgCanvasToString', 'svgToString', 'embedImage', 'setGoodImage', 'open', 'save', 'rasterExport', 'exportPDF', 'getSvgString', 'randomizeIds', 'uniquifyElems', 'setUseData', 'convertGradients', 'convertToGroup', 'setSvgString', 'importSvgString', 'identifyLayers', 'createLayer', 'cloneLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility', 'moveSelectedToLayer', 'mergeLayer', 'mergeAllLayers', 'leaveContext', 'setContext', 'clear', 'linkControlPoints', 'getContentElem', 'getRootElem', 'getSelectedElems', 'getResolution', 'getZoom', 'getVersion', 'setUiStrings', 'setConfig', 'getTitle', 'setGroupTitle', 'getDocumentTitle', 'setDocumentTitle', 'getEditorNS', 'setResolution', 'getOffset', 'setBBoxZoom', 'setZoom', 'getMode', 'setMode', 'getColor', 'setColor', 'setGradient', 'setPaint', 'setStrokePaint', 'setFillPaint', 'getStrokeWidth', 'setStrokeWidth', 'setStrokeAttr', 'getStyle', 'getOpacity', 'setOpacity', 'getFillOpacity', 'getStrokeOpacity', 'setPaintOpacity', 'getPaintOpacity', 'getBlur', 'setBlurNoUndo', 'setBlurOffsets', 'setBlur', 'getBold', 'setBold', 'getItalic', 'setItalic', 'getFontFamily', 'setFontFamily', 'setFontColor', 'getFontColor', 'getFontSize', 'setFontSize', 'getText', 'setTextContent', 'setImageURL', 'setLinkURL', 'setRectRadius', 'makeHyperlink', 'removeHyperlink', 'setSegType', 'convertToPath', 'changeSelectedAttribute', 'deleteSelectedElements', 'cutSelectedElements', 'copySelectedElements', 'pasteElements', 'groupSelectedElements', 'pushGroupProperties', 'ungroupSelectedElement', 'moveToTopSelectedElement', 'moveToBottomSelectedElement', 'moveUpDownSelected', 'moveSelectedElements', 'cloneSelectedElements', 'alignSelectedElements', 'updateCanvas', 'setBackground', 'cycleElement', 'getPrivateMethods', 'zoomChanged', 'ready'
]; ];
// TODO: rewrite the following, it's pretty scary. // TODO: rewrite the following, it's pretty scary.
for (i = 0; i < functions.length; i++) { for (let i = 0; i < functions.length; i++) {
this[functions[i]] = getCallbackSetter(functions[i]); this[functions[i]] = getCallbackSetter(functions[i]);
}
// Older IE may need a polyfill for addEventListener, but so it would for SVG
window.addEventListener('message', getMessageListener(this), false);
} }
// Older IE may need a polyfill for addEventListener, but so it would for SVG send (name, args, callback) {
window.addEventListener('message', getMessageListener(this), false); const t = this;
cbid++;
this.callbacks[cbid] = callback;
setTimeout((function (cbid) {
return function () { // Delay for the callback to be set in case its synchronous
/*
* Todo: Handle non-JSON arguments and return values (undefined,
* nonfinite numbers, functions, and built-in objects like Date,
* RegExp), etc.? Allow promises instead of callbacks? Review
* SVG-Edit functions for whether JSON-able parameters can be
* made compatile with all API functionality
*/
// We accept and post strings for the sake of IE9 support
if (window.location.origin === t.frame.contentWindow.location.origin) {
// Although we do not really need this API if we are working same
// domain, it could allow us to write in a way that would work
// cross-domain as well, assuming we stick to the argument limitations
// of the current JSON-based communication API (e.g., not passing
// callbacks). We might be able to address these shortcomings; see
// the todo elsewhere in this file.
const message = {id: cbid},
{svgCanvas} = t.frame.contentWindow;
try {
message.result = svgCanvas[name].apply(svgCanvas, args);
} catch (err) {
message.error = err.message;
}
addCallback(t, message);
} else { // Requires the ext-xdomain-messaging.js extension
t.frame.contentWindow.postMessage(JSON.stringify({namespace: 'svgCanvas', id: cbid, name, args}), '*');
}
};
}(cbid)), 0);
return cbid;
}
} }
EmbeddedSVGEdit.prototype.send = function (name, args, callback) { export default EmbeddedSVGEdit;
var t = this;
cbid++;
this.callbacks[cbid] = callback;
setTimeout((function (cbid) {
return function () { // Delay for the callback to be set in case its synchronous
/*
* Todo: Handle non-JSON arguments and return values (undefined,
* nonfinite numbers, functions, and built-in objects like Date,
* RegExp), etc.? Allow promises instead of callbacks? Review
* SVG-Edit functions for whether JSON-able parameters can be
* made compatile with all API functionality
*/
// We accept and post strings for the sake of IE9 support
if (window.location.origin === t.frame.contentWindow.location.origin) {
// Although we do not really need this API if we are working same
// domain, it could allow us to write in a way that would work
// cross-domain as well, assuming we stick to the argument limitations
// of the current JSON-based communication API (e.g., not passing
// callbacks). We might be able to address these shortcomings; see
// the todo elsewhere in this file.
var message = {id: cbid},
svgCanvas = t.frame.contentWindow.svgCanvas;
try {
message.result = svgCanvas[name].apply(svgCanvas, args);
} catch (err) {
message.error = err.message;
}
addCallback(t, message);
} else { // Requires the ext-xdomain-messaging.js extension
t.frame.contentWindow.postMessage(JSON.stringify({namespace: 'svgCanvas', id: cbid, name: name, args: args}), '*');
}
};
}(cbid)), 0);
return cbid;
};
window.embedded_svg_edit = EmbeddedSVGEdit; // Export old, deprecated API
window.EmbeddedSVGEdit = EmbeddedSVGEdit; // Follows common JS convention of CamelCase and, as enforced in JSLint, of initial caps for constructors
}());

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgCanvas */
/* globals svgEditor, svgCanvas, $ */
/* /*
* ext-arrows.js * ext-arrows.js
* *
@@ -10,11 +9,10 @@
*/ */
svgEditor.addExtension('Arrows', function (S) { svgEditor.addExtension('Arrows', function (S) {
var // svgcontent = S.svgcontent, const $ = jQuery;
const // {svgcontent} = S,
addElem = S.addSvgElementFromJson, addElem = S.addSvgElementFromJson,
nonce = S.nonce, {nonce} = S,
randomizeIds = S.randomize_ids,
selElems, pathdata,
langList = { langList = {
'en': [ 'en': [
{'id': 'arrow_none', 'textContent': 'No arrow'} {'id': 'arrow_none', 'textContent': 'No arrow'}
@@ -23,9 +21,10 @@ svgEditor.addExtension('Arrows', function (S) {
{'id': 'arrow_none', 'textContent': 'Sans flèche'} {'id': 'arrow_none', 'textContent': 'Sans flèche'}
] ]
}, },
arrowprefix,
prefix = 'se_arrow_'; prefix = 'se_arrow_';
let selElems, arrowprefix, randomizeIds = S.randomize_ids;
function setArrowNonce (window, n) { function setArrowNonce (window, n) {
randomizeIds = true; randomizeIds = true;
arrowprefix = prefix + n + '_'; arrowprefix = prefix + n + '_';
@@ -49,15 +48,15 @@ svgEditor.addExtension('Arrows', function (S) {
arrowprefix = prefix; arrowprefix = prefix;
} }
pathdata = { const pathdata = {
fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw'}, fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw'},
bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'} bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'}
}; };
function getLinked (elem, attr) { function getLinked (elem, attr) {
var str = elem.getAttribute(attr); const str = elem.getAttribute(attr);
if (!str) { return null; } if (!str) { return null; }
var m = str.match(/\(#(.*)\)/); const m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) { if (!m || m.length !== 2) {
return null; return null;
} }
@@ -67,12 +66,11 @@ svgEditor.addExtension('Arrows', function (S) {
function showPanel (on) { function showPanel (on) {
$('#arrow_panel').toggle(on); $('#arrow_panel').toggle(on);
if (on) { if (on) {
var el = selElems[0]; const el = selElems[0];
var end = el.getAttribute('marker-end'); const end = el.getAttribute('marker-end');
var start = el.getAttribute('marker-start'); const start = el.getAttribute('marker-start');
var mid = el.getAttribute('marker-mid'); const mid = el.getAttribute('marker-mid');
var val; let val;
if (end && start) { if (end && start) {
val = 'both'; val = 'both';
} else if (end) { } else if (end) {
@@ -81,7 +79,7 @@ svgEditor.addExtension('Arrows', function (S) {
val = 'start'; val = 'start';
} else if (mid) { } else if (mid) {
val = 'mid'; val = 'mid';
if (mid.indexOf('bk') !== -1) { if (mid.includes('bk')) {
val = 'mid_bk'; val = 'mid_bk';
} }
} }
@@ -95,7 +93,7 @@ svgEditor.addExtension('Arrows', function (S) {
} }
function resetMarker () { function resetMarker () {
var el = selElems[0]; const el = selElems[0];
el.removeAttribute('marker-start'); el.removeAttribute('marker-start');
el.removeAttribute('marker-mid'); el.removeAttribute('marker-mid');
el.removeAttribute('marker-end'); el.removeAttribute('marker-end');
@@ -105,32 +103,32 @@ svgEditor.addExtension('Arrows', function (S) {
// TODO: Make marker (or use?) per arrow type, since refX can be different // TODO: Make marker (or use?) per arrow type, since refX can be different
id = id || arrowprefix + dir; id = id || arrowprefix + dir;
var marker = S.getElem(id); const data = pathdata[dir];
var data = pathdata[dir];
if (type === 'mid') { if (type === 'mid') {
data.refx = 5; data.refx = 5;
} }
let marker = S.getElem(id);
if (!marker) { if (!marker) {
marker = addElem({ marker = addElem({
'element': 'marker', element: 'marker',
'attr': { attr: {
'viewBox': '0 0 10 10', viewBox: '0 0 10 10',
'id': id, id,
'refY': 5, refY: 5,
'markerUnits': 'strokeWidth', markerUnits: 'strokeWidth',
'markerWidth': 5, markerWidth: 5,
'markerHeight': 5, markerHeight: 5,
'orient': 'auto', orient: 'auto',
'style': 'pointer-events:none' // Currently needed for Opera style: 'pointer-events:none' // Currently needed for Opera
} }
}); });
var arrow = addElem({ const arrow = addElem({
'element': 'path', element: 'path',
'attr': { attr: {
'd': data.d, d: data.d,
'fill': '#000000' fill: '#000000'
} }
}); });
marker.appendChild(arrow); marker.appendChild(arrow);
@@ -143,15 +141,15 @@ svgEditor.addExtension('Arrows', function (S) {
} }
function setArrow () { function setArrow () {
var type = this.value;
resetMarker(); resetMarker();
let type = this.value;
if (type === 'none') { if (type === 'none') {
return; return;
} }
// Set marker on element // Set marker on element
var dir = 'fw'; let dir = 'fw';
if (type === 'mid_bk') { if (type === 'mid_bk') {
type = 'mid'; type = 'mid';
dir = 'bk'; dir = 'bk';
@@ -170,23 +168,23 @@ svgEditor.addExtension('Arrows', function (S) {
} }
function colorChanged (elem) { function colorChanged (elem) {
var color = elem.getAttribute('stroke'); const color = elem.getAttribute('stroke');
var mtypes = ['start', 'mid', 'end']; const mtypes = ['start', 'mid', 'end'];
var defs = S.findDefs(); const defs = S.findDefs();
$.each(mtypes, function (i, type) { $.each(mtypes, function (i, type) {
var marker = getLinked(elem, 'marker-' + type); const marker = getLinked(elem, 'marker-' + type);
if (!marker) { return; } if (!marker) { return; }
var curColor = $(marker).children().attr('fill'); const curColor = $(marker).children().attr('fill');
var curD = $(marker).children().attr('d'); const curD = $(marker).children().attr('d');
var newMarker = null;
if (curColor === color) { return; } if (curColor === color) { return; }
var allMarkers = $(defs).find('marker'); const allMarkers = $(defs).find('marker');
let newMarker = null;
// Different color, check if already made // Different color, check if already made
allMarkers.each(function () { allMarkers.each(function () {
var attrs = $(this).children().attr(['fill', 'd']); const attrs = $(this).children().attr(['fill', 'd']);
if (attrs.fill === color && attrs.d === curD) { if (attrs.fill === color && attrs.d === curD) {
// Found another marker with this color and this path // Found another marker with this color and this path
newMarker = this; newMarker = this;
@@ -195,8 +193,8 @@ svgEditor.addExtension('Arrows', function (S) {
if (!newMarker) { if (!newMarker) {
// Create a new marker with this color // Create a new marker with this color
var lastId = marker.id; const lastId = marker.id;
var dir = lastId.indexOf('_fw') !== -1 ? 'fw' : 'bk'; const dir = lastId.includes('_fw') ? 'fw' : 'bk';
newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length); newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length);
@@ -206,9 +204,9 @@ svgEditor.addExtension('Arrows', function (S) {
$(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')'); $(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')');
// Check if last marker can be removed // Check if last marker can be removed
var remove = true; let remove = true;
$(S.svgcontent).find('line, polyline, path, polygon').each(function () { $(S.svgcontent).find('line, polyline, path, polygon').each(function () {
var elem = this; const elem = this;
$.each(mtypes, function (j, mtype) { $.each(mtypes, function (j, mtype) {
if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') { if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') {
remove = false; remove = false;
@@ -245,25 +243,25 @@ svgEditor.addExtension('Arrows', function (S) {
change: setArrow change: setArrow
} }
}], }],
callback: function () { callback () {
$('#arrow_panel').hide(); $('#arrow_panel').hide();
// Set ID so it can be translated in locale file // Set ID so it can be translated in locale file
$('#arrow_list option')[0].id = 'connector_no_arrow'; $('#arrow_list option')[0].id = 'connector_no_arrow';
}, },
addLangData: function (lang) { addLangData (lang) {
return { return {
data: langList[lang] data: langList[lang]
}; };
}, },
selectedChanged: function (opts) { selectedChanged (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; const markerElems = ['line', 'path', 'polyline', 'polygon'];
var markerElems = ['line', 'path', 'polyline', 'polygon']; let i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; const elem = selElems[i];
if (elem && $.inArray(elem.tagName, markerElems) !== -1) { if (elem && markerElems.includes(elem.tagName)) {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
showPanel(true); showPanel(true);
} else { } else {
@@ -274,16 +272,16 @@ svgEditor.addExtension('Arrows', function (S) {
} }
} }
}, },
elementChanged: function (opts) { elementChanged (opts) {
var elem = opts.elems[0]; const elem = opts.elems[0];
if (elem && ( if (elem && (
elem.getAttribute('marker-start') || elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') || elem.getAttribute('marker-mid') ||
elem.getAttribute('marker-end') elem.getAttribute('marker-end')
)) { )) {
// var start = elem.getAttribute('marker-start'); // const start = elem.getAttribute('marker-start');
// var mid = elem.getAttribute('marker-mid'); // const mid = elem.getAttribute('marker-mid');
// var end = elem.getAttribute('marker-end'); // const end = elem.getAttribute('marker-end');
// Has marker, so see if it should match color // Has marker, so see if it should match color
colorChanged(elem); colorChanged(elem);
} }

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor */
/* globals svgEditor, $ */
/* /*
* ext-closepath.js * ext-closepath.js
* *
@@ -8,41 +7,42 @@
* Copyright(c) 2010 Jeff Schiller * Copyright(c) 2010 Jeff Schiller
* *
*/ */
// import './pathseg.js';
// This extension adds a simple button to the contextual panel for paths // This extension adds a simple button to the contextual panel for paths
// The button toggles whether the path is open or closed // The button toggles whether the path is open or closed
svgEditor.addExtension('ClosePath', function () { svgEditor.addExtension('ClosePath', function () {
'use strict'; const $ = jQuery;
var selElems, let selElems;
updateButton = function (path) { const updateButton = function (path) {
var seglist = path.pathSegList, const seglist = path.pathSegList,
closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1, closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1,
showbutton = closed ? '#tool_openpath' : '#tool_closepath', showbutton = closed ? '#tool_openpath' : '#tool_closepath',
hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
$(hidebutton).hide(); $(hidebutton).hide();
$(showbutton).show(); $(showbutton).show();
}, };
showPanel = function (on) { const showPanel = function (on) {
$('#closepath_panel').toggle(on); $('#closepath_panel').toggle(on);
if (on) { if (on) {
var path = selElems[0]; const path = selElems[0];
if (path) { updateButton(path); } if (path) { updateButton(path); }
}
};
const toggleClosed = function () {
const path = selElems[0];
if (path) {
const seglist = path.pathSegList,
last = seglist.numberOfItems - 1;
// is closed
if (seglist.getItem(last).pathSegType === 1) {
seglist.removeItem(last);
} else {
seglist.appendItem(path.createSVGPathSegClosePath());
} }
}, updateButton(path);
toggleClosed = function () { }
var path = selElems[0]; };
if (path) {
var seglist = path.pathSegList,
last = seglist.numberOfItems - 1;
// is closed
if (seglist.getItem(last).pathSegType === 1) {
seglist.removeItem(last);
} else {
seglist.appendItem(path.createSVGPathSegClosePath());
}
updateButton(path);
}
};
return { return {
name: 'ClosePath', name: 'ClosePath',
@@ -53,7 +53,7 @@ svgEditor.addExtension('ClosePath', function () {
panel: 'closepath_panel', panel: 'closepath_panel',
title: 'Open path', title: 'Open path',
events: { events: {
click: function () { click () {
toggleClosed(); toggleClosed();
} }
} }
@@ -64,19 +64,19 @@ svgEditor.addExtension('ClosePath', function () {
panel: 'closepath_panel', panel: 'closepath_panel',
title: 'Close path', title: 'Close path',
events: { events: {
click: function () { click () {
toggleClosed(); toggleClosed();
} }
} }
}], }],
callback: function () { callback () {
$('#closepath_panel').hide(); $('#closepath_panel').hide();
}, },
selectedChanged: function (opts) { selectedChanged (opts) {
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; let i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; const elem = selElems[i];
if (elem && elem.tagName === 'path') { if (elem && elem.tagName === 'path') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
showPanel(true); showPanel(true);

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgCanvas */
/* globals svgEditor, svgCanvas, $ */
/* /*
* ext-connector.js * ext-connector.js
* *
@@ -10,27 +9,26 @@
*/ */
svgEditor.addExtension('Connector', function (S) { svgEditor.addExtension('Connector', function (S) {
var svgcontent = S.svgcontent, const $ = jQuery;
svgroot = S.svgroot, const {svgroot, getNextId, getElem, curConfig} = S,
getNextId = S.getNextId,
getElem = S.getElem,
addElem = S.addSvgElementFromJson, addElem = S.addSvgElementFromJson,
selManager = S.selectorManager, selManager = S.selectorManager,
curConfig = svgEditor.curConfig, connSel = '.se_connector',
started = false, // connect_str = '-SE_CONNECT-',
startX, elData = $.data;
let startX,
startY, startY,
curLine, curLine,
startElem, startElem,
endElem, endElem,
connections = [],
connSel = '.se_connector',
seNs, seNs,
// connect_str = '-SE_CONNECT-', {svgcontent} = S,
selElems = [], started = false,
elData = $.data; connections = [],
selElems = [];
var langList = { const langList = {
'en': [ 'en': [
{'id': 'mode_connect', 'title': 'Connect two objects'} {'id': 'mode_connect', 'title': 'Connect two objects'}
], ],
@@ -49,15 +47,14 @@ svgEditor.addExtension('Connector', function (S) {
bb.y -= offset / 2; bb.y -= offset / 2;
} }
var midX = bb.x + bb.width / 2; const midX = bb.x + bb.width / 2;
var midY = bb.y + bb.height / 2; const midY = bb.y + bb.height / 2;
var lenX = x - midX; const lenX = x - midX;
var lenY = y - midY; const lenY = y - midY;
var slope = Math.abs(lenY / lenX); const slope = Math.abs(lenY / lenX);
var ratio;
let ratio;
if (slope < bb.height / bb.width) { if (slope < bb.height / bb.width) {
ratio = (bb.width / 2) / Math.abs(lenX); ratio = (bb.width / 2) / Math.abs(lenX);
} else { } else {
@@ -71,16 +68,16 @@ svgEditor.addExtension('Connector', function (S) {
} }
function getOffset (side, line) { function getOffset (side, line) {
var giveOffset = !!line.getAttribute('marker-' + side); const giveOffset = !!line.getAttribute('marker-' + side);
// var giveOffset = $(line).data(side+'_off'); // const giveOffset = $(line).data(side+'_off');
// TODO: Make this number (5) be based on marker width/height // TODO: Make this number (5) be based on marker width/height
var size = line.getAttribute('stroke-width') * 5; const size = line.getAttribute('stroke-width') * 5;
return giveOffset ? size : 0; return giveOffset ? size : 0;
} }
function showPanel (on) { function showPanel (on) {
var connRules = $('#connector_rules'); let connRules = $('#connector_rules');
if (!connRules.length) { if (!connRules.length) {
connRules = $('<style id="connector_rules"></style>').appendTo('head'); connRules = $('<style id="connector_rules"></style>').appendTo('head');
} }
@@ -89,8 +86,8 @@ svgEditor.addExtension('Connector', function (S) {
} }
function setPoint (elem, pos, x, y, setMid) { function setPoint (elem, pos, x, y, setMid) {
var i, pts = elem.points; const pts = elem.points;
var pt = svgroot.createSVGPoint(); const pt = svgroot.createSVGPoint();
pt.x = x; pt.x = x;
pt.y = y; pt.y = y;
if (pos === 'end') { pos = pts.numberOfItems - 1; } if (pos === 'end') { pos = pts.numberOfItems - 1; }
@@ -99,8 +96,8 @@ svgEditor.addExtension('Connector', function (S) {
pts.replaceItem(pt, pos); pts.replaceItem(pt, pos);
} catch (err) { } catch (err) {
// Should only occur in FF which formats points attr as "n,n n,n", so just split // Should only occur in FF which formats points attr as "n,n n,n", so just split
var ptArr = elem.getAttribute('points').split(' '); const ptArr = elem.getAttribute('points').split(' ');
for (i = 0; i < ptArr.length; i++) { for (let i = 0; i < ptArr.length; i++) {
if (i === pos) { if (i === pos) {
ptArr[i] = x + ',' + y; ptArr[i] = x + ',' + y;
} }
@@ -110,67 +107,69 @@ svgEditor.addExtension('Connector', function (S) {
if (setMid) { if (setMid) {
// Add center point // Add center point
var ptStart = pts.getItem(0); const ptStart = pts.getItem(0);
var ptEnd = pts.getItem(pts.numberOfItems - 1); const ptEnd = pts.getItem(pts.numberOfItems - 1);
setPoint(elem, 1, (ptEnd.x + ptStart.x) / 2, (ptEnd.y + ptStart.y) / 2); setPoint(elem, 1, (ptEnd.x + ptStart.x) / 2, (ptEnd.y + ptStart.y) / 2);
} }
} }
function updateLine (diffX, diffY) { function updateLine (diffX, diffY) {
// Update line with element // Update line with element
var i = connections.length; let i = connections.length;
while (i--) { while (i--) {
var conn = connections[i]; const conn = connections[i];
var line = conn.connector; const line = conn.connector;
// var elem = conn.elem; // const {elem} = conn;
var pre = conn.is_start ? 'start' : 'end'; const pre = conn.is_start ? 'start' : 'end';
// var sw = line.getAttribute('stroke-width') * 5; // const sw = line.getAttribute('stroke-width') * 5;
// Update bbox for this element // Update bbox for this element
var bb = elData(line, pre + '_bb'); const bb = elData(line, pre + '_bb');
bb.x = conn.start_x + diffX; bb.x = conn.start_x + diffX;
bb.y = conn.start_y + diffY; bb.y = conn.start_y + diffY;
elData(line, pre + '_bb', bb); elData(line, pre + '_bb', bb);
var altPre = conn.is_start ? 'end' : 'start'; const altPre = conn.is_start ? 'end' : 'start';
// Get center pt of connected element // Get center pt of connected element
var bb2 = elData(line, altPre + '_bb'); const bb2 = elData(line, altPre + '_bb');
var srcX = bb2.x + bb2.width / 2; const srcX = bb2.x + bb2.width / 2;
var srcY = bb2.y + bb2.height / 2; const srcY = bb2.y + bb2.height / 2;
// Set point of element being moved // Set point of element being moved
var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0 const pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0
setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true);
// Set point of connected element // Set point of connected element
var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); const pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line));
setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
} }
} }
function findConnectors (elems) { /**
var i; *
if (!elems) { elems = selElems; } * @param {array} [elem=selElems] Array of elements
var connectors = $(svgcontent).find(connSel); */
function findConnectors (elems = selElems) {
const connectors = $(svgcontent).find(connSel);
connections = []; connections = [];
// Loop through connectors to see if one is connected to the element // Loop through connectors to see if one is connected to the element
connectors.each(function () { connectors.each(function () {
var addThis; let addThis;
function add () { function add () {
if ($.inArray(this, elems) !== -1) { if (elems.includes(this)) {
// Pretend this element is selected // Pretend this element is selected
addThis = true; addThis = true;
} }
} }
// Grab the ends // Grab the ends
var parts = []; const parts = [];
['start', 'end'].forEach(function (pos, i) { ['start', 'end'].forEach(function (pos, i) {
var key = 'c_' + pos; const key = 'c_' + pos;
var part = elData(this, key); let part = elData(this, key);
if (part == null) { if (part == null) {
part = document.getElementById( part = document.getElementById(
this.attributes['se:connector'].value.split(' ')[i] this.attributes['se:connector'].value.split(' ')[i]
@@ -181,8 +180,8 @@ svgEditor.addExtension('Connector', function (S) {
parts.push(part); parts.push(part);
}.bind(this)); }.bind(this));
for (i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
var cElem = parts[i]; const cElem = parts[i];
addThis = false; addThis = false;
// The connected element might be part of a selected group // The connected element might be part of a selected group
@@ -192,8 +191,8 @@ svgEditor.addExtension('Connector', function (S) {
$(this).remove(); $(this).remove();
continue; continue;
} }
if ($.inArray(cElem, elems) !== -1 || addThis) { if (elems.includes(cElem) || addThis) {
var bb = svgCanvas.getStrokedBBox([cElem]); const bb = svgCanvas.getStrokedBBox([cElem]);
connections.push({ connections.push({
elem: cElem, elem: cElem,
connector: this, connector: this,
@@ -210,47 +209,46 @@ svgEditor.addExtension('Connector', function (S) {
// Updates connector lines based on selected elements // Updates connector lines based on selected elements
// Is not used on mousemove, as it runs getStrokedBBox every time, // Is not used on mousemove, as it runs getStrokedBBox every time,
// which isn't necessary there. // which isn't necessary there.
var i, j;
findConnectors(elems); findConnectors(elems);
if (connections.length) { if (connections.length) {
// Update line with element // Update line with element
i = connections.length; let i = connections.length;
while (i--) { while (i--) {
var conn = connections[i]; const conn = connections[i];
var line = conn.connector; const line = conn.connector;
var elem = conn.elem; const {elem} = conn;
// var sw = line.getAttribute('stroke-width') * 5; // const sw = line.getAttribute('stroke-width') * 5;
var pre = conn.is_start ? 'start' : 'end'; const pre = conn.is_start ? 'start' : 'end';
// Update bbox for this element // Update bbox for this element
var bb = svgCanvas.getStrokedBBox([elem]); const bb = svgCanvas.getStrokedBBox([elem]);
bb.x = conn.start_x; bb.x = conn.start_x;
bb.y = conn.start_y; bb.y = conn.start_y;
elData(line, pre + '_bb', bb); elData(line, pre + '_bb', bb);
/* var addOffset = */ elData(line, pre + '_off'); /* const addOffset = */ elData(line, pre + '_off');
var altPre = conn.is_start ? 'end' : 'start'; const altPre = conn.is_start ? 'end' : 'start';
// Get center pt of connected element // Get center pt of connected element
var bb2 = elData(line, altPre + '_bb'); const bb2 = elData(line, altPre + '_bb');
var srcX = bb2.x + bb2.width / 2; const srcX = bb2.x + bb2.width / 2;
var srcY = bb2.y + bb2.height / 2; const srcY = bb2.y + bb2.height / 2;
// Set point of element being moved // Set point of element being moved
var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); let pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line));
setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true);
// Set point of connected element // Set point of connected element
var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); const pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line));
setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
// Update points attribute manually for webkit // Update points attribute manually for webkit
if (navigator.userAgent.indexOf('AppleWebKit') !== -1) { if (navigator.userAgent.includes('AppleWebKit')) {
var pts = line.points; const pts = line.points;
var len = pts.numberOfItems; const len = pts.numberOfItems;
var ptArr = []; const ptArr = [];
for (j = 0; j < len; j++) { for (let j = 0; j < len; j++) {
pt = pts.getItem(j); pt = pts.getItem(j);
ptArr[j] = pt.x + ',' + pt.y; ptArr[j] = pt.x + ',' + pt.y;
} }
@@ -262,17 +260,17 @@ svgEditor.addExtension('Connector', function (S) {
// Do once // Do once
(function () { (function () {
var gse = svgCanvas.groupSelectedElements; const gse = svgCanvas.groupSelectedElements;
svgCanvas.groupSelectedElements = function () { svgCanvas.groupSelectedElements = function () {
svgCanvas.removeFromSelection($(connSel).toArray()); svgCanvas.removeFromSelection($(connSel).toArray());
return gse.apply(this, arguments); return gse.apply(this, arguments);
}; };
var mse = svgCanvas.moveSelectedElements; const mse = svgCanvas.moveSelectedElements;
svgCanvas.moveSelectedElements = function () { svgCanvas.moveSelectedElements = function () {
var cmd = mse.apply(this, arguments); const cmd = mse.apply(this, arguments);
updateConnectors(); updateConnectors();
return cmd; return cmd;
}; };
@@ -284,12 +282,12 @@ svgEditor.addExtension('Connector', function (S) {
function init () { function init () {
// Make sure all connectors have data set // Make sure all connectors have data set
$(svgcontent).find('*').each(function () { $(svgcontent).find('*').each(function () {
var conn = this.getAttributeNS(seNs, 'connector'); const conn = this.getAttributeNS(seNs, 'connector');
if (conn) { if (conn) {
this.setAttribute('class', connSel.substr(1)); this.setAttribute('class', connSel.substr(1));
var connData = conn.split(' '); const connData = conn.split(' ');
var sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]); const sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]);
var ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]); const ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]);
$(this).data('c_start', connData[0]) $(this).data('c_start', connData[0])
.data('c_end', connData[1]) .data('c_end', connData[1])
.data('start_bb', sbb) .data('start_bb', sbb)
@@ -325,40 +323,40 @@ svgEditor.addExtension('Connector', function (S) {
position: 1 position: 1
}, },
events: { events: {
'click': function () { click () {
svgCanvas.setMode('connector'); svgCanvas.setMode('connector');
} }
} }
}], }],
addLangData: function (lang) { addLangData (lang) {
return { return {
data: langList[lang] data: langList[lang]
}; };
}, },
mouseDown: function (opts) { mouseDown (opts) {
var e = opts.event; const e = opts.event;
startX = opts.start_x; startX = opts.start_x;
startY = opts.start_y; startY = opts.start_y;
var mode = svgCanvas.getMode(); const mode = svgCanvas.getMode();
if (mode === 'connector') { if (mode === 'connector') {
if (started) { return; } if (started) { return; }
var mouseTarget = e.target; const mouseTarget = e.target;
var parents = $(mouseTarget).parents(); const parents = $(mouseTarget).parents();
if ($.inArray(svgcontent, parents) !== -1) { if ($.inArray(svgcontent, parents) !== -1) {
// Connectable element // Connectable element
// If child of foreignObject, use parent // If child of foreignObject, use parent
var fo = $(mouseTarget).closest('foreignObject'); const fo = $(mouseTarget).closest('foreignObject');
startElem = fo.length ? fo[0] : mouseTarget; startElem = fo.length ? fo[0] : mouseTarget;
// Get center of source element // Get center of source element
var bb = svgCanvas.getStrokedBBox([startElem]); const bb = svgCanvas.getStrokedBBox([startElem]);
var x = bb.x + bb.width / 2; const x = bb.x + bb.width / 2;
var y = bb.y + bb.height / 2; const y = bb.y + bb.height / 2;
started = true; started = true;
curLine = addElem({ curLine = addElem({
@@ -383,21 +381,21 @@ svgEditor.addExtension('Connector', function (S) {
findConnectors(); findConnectors();
} }
}, },
mouseMove: function (opts) { mouseMove (opts) {
var zoom = svgCanvas.getZoom(); const zoom = svgCanvas.getZoom();
// var e = opts.event; // const e = opts.event;
var x = opts.mouse_x / zoom; const x = opts.mouse_x / zoom;
var y = opts.mouse_y / zoom; const y = opts.mouse_y / zoom;
var diffX = x - startX, const diffX = x - startX,
diffY = y - startY; diffY = y - startY;
var mode = svgCanvas.getMode(); const mode = svgCanvas.getMode();
if (mode === 'connector' && started) { if (mode === 'connector' && started) {
// var sw = curLine.getAttribute('stroke-width') * 3; // const sw = curLine.getAttribute('stroke-width') * 3;
// Set start point (adjusts based on bb) // Set start point (adjusts based on bb)
var pt = getBBintersect(x, y, elData(curLine, 'start_bb'), getOffset('start', curLine)); const pt = getBBintersect(x, y, elData(curLine, 'start_bb'), getOffset('start', curLine));
startX = pt.x; startX = pt.x;
startY = pt.y; startY = pt.y;
@@ -406,10 +404,9 @@ svgEditor.addExtension('Connector', function (S) {
// Set end point // Set end point
setPoint(curLine, 'end', x, y, true); setPoint(curLine, 'end', x, y, true);
} else if (mode === 'select') { } else if (mode === 'select') {
var slen = selElems.length; let slen = selElems.length;
while (slen--) { while (slen--) {
var elem = selElems[slen]; const elem = selElems[slen];
// Look for selected connector elements // Look for selected connector elements
if (elem && elData(elem, 'c_start')) { if (elem && elData(elem, 'c_start')) {
// Remove the "translate" transform given to move // Remove the "translate" transform given to move
@@ -422,18 +419,18 @@ svgEditor.addExtension('Connector', function (S) {
} }
} }
}, },
mouseUp: function (opts) { mouseUp (opts) {
// var zoom = svgCanvas.getZoom(); // const zoom = svgCanvas.getZoom();
var e = opts.event, const e = opts.event;
// x = opts.mouse_x / zoom, // , x = opts.mouse_x / zoom,
// y = opts.mouse_y / zoom, // , y = opts.mouse_y / zoom,
mouseTarget = e.target; let mouseTarget = e.target;
if (svgCanvas.getMode() === 'connector') { if (svgCanvas.getMode() === 'connector') {
var fo = $(mouseTarget).closest('foreignObject'); const fo = $(mouseTarget).closest('foreignObject');
if (fo.length) { mouseTarget = fo[0]; } if (fo.length) { mouseTarget = fo[0]; }
var parents = $(mouseTarget).parents(); const parents = $(mouseTarget).parents();
if (mouseTarget === startElem) { if (mouseTarget === startElem) {
// Start line through click // Start line through click
@@ -441,7 +438,7 @@ svgEditor.addExtension('Connector', function (S) {
return { return {
keep: true, keep: true,
element: null, element: null,
started: started started
}; };
} }
if ($.inArray(svgcontent, parents) === -1) { if ($.inArray(svgcontent, parents) === -1) {
@@ -451,18 +448,18 @@ svgEditor.addExtension('Connector', function (S) {
return { return {
keep: false, keep: false,
element: null, element: null,
started: started started
}; };
} }
// Valid end element // Valid end element
endElem = mouseTarget; endElem = mouseTarget;
var startId = startElem.id, endId = endElem.id; const startId = startElem.id, endId = endElem.id;
var connStr = startId + ' ' + endId; const connStr = startId + ' ' + endId;
var altStr = endId + ' ' + startId; const altStr = endId + ' ' + startId;
// Don't create connector if one already exists // Don't create connector if one already exists
var dupe = $(svgcontent).find(connSel).filter(function () { const dupe = $(svgcontent).find(connSel).filter(function () {
var conn = this.getAttributeNS(seNs, 'connector'); const conn = this.getAttributeNS(seNs, 'connector');
if (conn === connStr || conn === altStr) { return true; } if (conn === connStr || conn === altStr) { return true; }
}); });
if (dupe.length) { if (dupe.length) {
@@ -474,9 +471,9 @@ svgEditor.addExtension('Connector', function (S) {
}; };
} }
var bb = svgCanvas.getStrokedBBox([endElem]); const bb = svgCanvas.getStrokedBBox([endElem]);
var pt = getBBintersect(startX, startY, bb, getOffset('start', curLine)); const pt = getBBintersect(startX, startY, bb, getOffset('start', curLine));
setPoint(curLine, 'end', pt.x, pt.y, true); setPoint(curLine, 'end', pt.x, pt.y, true);
$(curLine) $(curLine)
.data('c_start', startId) .data('c_start', startId)
@@ -493,11 +490,11 @@ svgEditor.addExtension('Connector', function (S) {
return { return {
keep: true, keep: true,
element: curLine, element: curLine,
started: started started
}; };
} }
}, },
selectedChanged: function (opts) { selectedChanged (opts) {
// TODO: Find better way to skip operations if no connectors are in use // TODO: Find better way to skip operations if no connectors are in use
if (!$(svgcontent).find(connSel).length) { return; } if (!$(svgcontent).find(connSel).length) { return; }
@@ -508,10 +505,9 @@ svgEditor.addExtension('Connector', function (S) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; let i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; const elem = selElems[i];
if (elem && elData(elem, 'c_start')) { if (elem && elData(elem, 'c_start')) {
selManager.requestSelector(elem).showGrips(false); selManager.requestSelector(elem).showGrips(false);
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
@@ -526,8 +522,8 @@ svgEditor.addExtension('Connector', function (S) {
} }
updateConnectors(); updateConnectors();
}, },
elementChanged: function (opts) { elementChanged (opts) {
var elem = opts.elems[0]; let elem = opts.elems[0];
if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') { if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') {
// Update svgcontent (can change on import) // Update svgcontent (can change on import)
svgcontent = elem; svgcontent = elem;
@@ -535,15 +531,14 @@ svgEditor.addExtension('Connector', function (S) {
} }
// Has marker, so change offset // Has marker, so change offset
var start;
if (elem && ( if (elem && (
elem.getAttribute('marker-start') || elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') || elem.getAttribute('marker-mid') ||
elem.getAttribute('marker-end') elem.getAttribute('marker-end')
)) { )) {
start = elem.getAttribute('marker-start'); const start = elem.getAttribute('marker-start');
var mid = elem.getAttribute('marker-mid'); const mid = elem.getAttribute('marker-mid');
var end = elem.getAttribute('marker-end'); const end = elem.getAttribute('marker-end');
curLine = elem; curLine = elem;
$(elem) $(elem)
.data('start_off', !!start) .data('start_off', !!start)
@@ -552,14 +547,14 @@ svgEditor.addExtension('Connector', function (S) {
if (elem.tagName === 'line' && mid) { if (elem.tagName === 'line' && mid) {
// Convert to polyline to accept mid-arrow // Convert to polyline to accept mid-arrow
var x1 = Number(elem.getAttribute('x1')); const x1 = Number(elem.getAttribute('x1'));
var x2 = Number(elem.getAttribute('x2')); const x2 = Number(elem.getAttribute('x2'));
var y1 = Number(elem.getAttribute('y1')); const y1 = Number(elem.getAttribute('y1'));
var y2 = Number(elem.getAttribute('y2')); const y2 = Number(elem.getAttribute('y2'));
var id = elem.id; const {id} = elem;
var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' '); const midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
var pline = addElem({ const pline = addElem({
'element': 'polyline', 'element': 'polyline',
'attr': { 'attr': {
'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2), 'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2),
@@ -579,14 +574,14 @@ svgEditor.addExtension('Connector', function (S) {
} }
// Update line if it's a connector // Update line if it's a connector
if (elem.getAttribute('class') === connSel.substr(1)) { if (elem.getAttribute('class') === connSel.substr(1)) {
start = getElem(elData(elem, 'c_start')); const start = getElem(elData(elem, 'c_start'));
updateConnectors([start]); updateConnectors([start]);
} else { } else {
updateConnectors(); updateConnectors();
} }
}, },
IDsUpdated: function (input) { IDsUpdated (input) {
var remove = []; const remove = [];
input.elems.forEach(function (elem) { input.elems.forEach(function (elem) {
if ('se:connector' in elem.attr) { if ('se:connector' in elem.attr) {
elem.attr['se:connector'] = elem.attr['se:connector'].split(' ') elem.attr['se:connector'] = elem.attr['se:connector'].split(' ')
@@ -599,9 +594,9 @@ svgEditor.addExtension('Connector', function (S) {
} }
} }
}); });
return {remove: remove}; return {remove};
}, },
toolButtonStateUpdate: function (opts) { toolButtonStateUpdate (opts) {
if (opts.nostroke) { if (opts.nostroke) {
if ($('#mode_connect').hasClass('tool_button_current')) { if ($('#mode_connect').hasClass('tool_button_current')) {
svgEditor.clickSelect(); svgEditor.clickSelect();

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgedit */
/* globals svgEditor, svgedit, $ */
/* /*
* ext-eyedropper.js * ext-eyedropper.js
* *
@@ -16,12 +15,11 @@
// 4) svgcanvas.js // 4) svgcanvas.js
svgEditor.addExtension('eyedropper', function (S) { svgEditor.addExtension('eyedropper', function (S) {
'use strict'; const $ = jQuery;
var // NS = svgedit.NS, const // {svgcontent} = S,
// svgcontent = S.svgcontent,
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
svgCanvas = svgEditor.canvas, svgCanvas = svgEditor.canvas,
ChangeElementCommand = svgedit.history.ChangeElementCommand, {ChangeElementCommand} = svgedit.history,
addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); }, addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
currentStyle = { currentStyle = {
fillPaint: 'red', fillOpacity: 1.0, fillPaint: 'red', fillOpacity: 1.0,
@@ -34,14 +32,14 @@ svgEditor.addExtension('eyedropper', function (S) {
function getStyle (opts) { function getStyle (opts) {
// if we are in eyedropper mode, we don't want to disable the eye-dropper tool // if we are in eyedropper mode, we don't want to disable the eye-dropper tool
var mode = svgCanvas.getMode(); const mode = svgCanvas.getMode();
if (mode === 'eyedropper') { return; } if (mode === 'eyedropper') { return; }
var elem = null; const tool = $('#tool_eyedropper');
var tool = $('#tool_eyedropper');
// enable-eye-dropper if one element is selected // enable-eye-dropper if one element is selected
let elem = null;
if (!opts.multiselected && opts.elems[0] && if (!opts.multiselected && opts.elems[0] &&
$.inArray(opts.elems[0].nodeName, ['svg', 'g', 'use']) === -1 !['svg', 'g', 'use'].includes(opts.elems[0].nodeName)
) { ) {
elem = opts.elems[0]; elem = opts.elems[0];
tool.removeClass('disabled'); tool.removeClass('disabled');
@@ -70,7 +68,7 @@ svgEditor.addExtension('eyedropper', function (S) {
title: 'Eye Dropper Tool', title: 'Eye Dropper Tool',
key: 'I', key: 'I',
events: { events: {
click: function () { click () {
svgCanvas.setMode('eyedropper'); svgCanvas.setMode('eyedropper');
} }
} }
@@ -80,15 +78,15 @@ svgEditor.addExtension('eyedropper', function (S) {
selectedChanged: getStyle, selectedChanged: getStyle,
elementChanged: getStyle, elementChanged: getStyle,
mouseDown: function (opts) { mouseDown (opts) {
var mode = svgCanvas.getMode(); const mode = svgCanvas.getMode();
if (mode === 'eyedropper') { if (mode === 'eyedropper') {
var e = opts.event; const e = opts.event;
var target = e.target; const {target} = e;
if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) { if (!['svg', 'g', 'use'].includes(target.nodeName)) {
var changes = {}; const changes = {};
var change = function (elem, attrname, newvalue) { const change = function (elem, attrname, newvalue) {
changes[attrname] = elem.getAttribute(attrname); changes[attrname] = elem.getAttribute(attrname);
elem.setAttribute(attrname, newvalue); elem.setAttribute(attrname, newvalue);
}; };

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgedit, svgCanvas */
/* globals svgEditor, svgedit, svgCanvas, $ */
/* /*
* ext-foreignobject.js * ext-foreignobject.js
* *
@@ -10,25 +9,23 @@
* *
*/ */
svgEditor.addExtension('foreignObject', function (S) { import {NS} from './svgedit.js';
var NS = svgedit.NS,
Utils = svgedit.utilities,
// svgcontent = S.svgcontent,
// addElem = S.addSvgElementFromJson,
selElems,
editingforeign = false,
svgdoc = S.svgroot.parentNode.ownerDocument,
started,
newFO;
var properlySourceSizeTextArea = function () { svgEditor.addExtension('foreignObject', function (S) {
const $ = jQuery;
const Utils = svgedit.utilities,
// {svgcontent} = S,
// addElem = S.addSvgElementFromJson,
svgdoc = S.svgroot.parentNode.ownerDocument;
const properlySourceSizeTextArea = function () {
// TODO: remove magic numbers here and get values from CSS // TODO: remove magic numbers here and get values from CSS
var height = $('#svg_source_container').height() - 80; const height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height); $('#svg_source_textarea').css('height', height);
}; };
function showPanel (on) { function showPanel (on) {
var fcRules = $('#fc_rules'); let fcRules = $('#fc_rules');
if (!fcRules.length) { if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
} }
@@ -41,6 +38,11 @@ svgEditor.addExtension('foreignObject', function (S) {
$('#foreign_save, #foreign_cancel').toggle(on); $('#foreign_save, #foreign_cancel').toggle(on);
} }
let selElems,
started,
newFO,
editingforeign = false;
// Function: setForeignString(xmlString, elt) // Function: setForeignString(xmlString, elt)
// This function sets the content of element elt to the input XML. // This function sets the content of element elt to the input XML.
// //
@@ -51,10 +53,10 @@ svgEditor.addExtension('foreignObject', function (S) {
// Returns: // Returns:
// This function returns false if the set was unsuccessful, true otherwise. // This function returns false if the set was unsuccessful, true otherwise.
function setForeignString (xmlString) { function setForeignString (xmlString) {
var elt = selElems[0]; const elt = selElems[0];
try { try {
// convert string into XML document // convert string into XML document
var newDoc = Utils.text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>'); const newDoc = Utils.text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>');
// run it through our sanitizer to remove anything we do not support // run it through our sanitizer to remove anything we do not support
S.sanitizeSvg(newDoc.documentElement); S.sanitizeSvg(newDoc.documentElement);
elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt); elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
@@ -69,13 +71,13 @@ svgEditor.addExtension('foreignObject', function (S) {
} }
function showForeignEditor () { function showForeignEditor () {
var elt = selElems[0]; const elt = selElems[0];
if (!elt || editingforeign) { return; } if (!elt || editingforeign) { return; }
editingforeign = true; editingforeign = true;
toggleSourceButtons(true); toggleSourceButtons(true);
elt.removeAttribute('fill'); elt.removeAttribute('fill');
var str = S.svgToString(elt, 0); const str = S.svgToString(elt, 0);
$('#svg_source_textarea').val(str); $('#svg_source_textarea').val(str);
$('#svg_source_editor').fadeIn(); $('#svg_source_editor').fadeIn();
properlySourceSizeTextArea(); properlySourceSizeTextArea();
@@ -95,7 +97,7 @@ svgEditor.addExtension('foreignObject', function (S) {
type: 'mode', type: 'mode',
title: 'Foreign Object Tool', title: 'Foreign Object Tool',
events: { events: {
'click': function () { click () {
svgCanvas.setMode('foreign'); svgCanvas.setMode('foreign');
} }
} }
@@ -105,7 +107,7 @@ svgEditor.addExtension('foreignObject', function (S) {
panel: 'foreignObject_panel', panel: 'foreignObject_panel',
title: 'Edit ForeignObject Content', title: 'Edit ForeignObject Content',
events: { events: {
'click': function () { click () {
showForeignEditor(); showForeignEditor();
} }
} }
@@ -119,7 +121,7 @@ svgEditor.addExtension('foreignObject', function (S) {
label: 'w', label: 'w',
size: 3, size: 3,
events: { events: {
change: function () { change () {
setAttr('width', this.value); setAttr('width', this.value);
} }
} }
@@ -130,7 +132,7 @@ svgEditor.addExtension('foreignObject', function (S) {
id: 'foreign_height', id: 'foreign_height',
label: 'h', label: 'h',
events: { events: {
change: function () { change () {
setAttr('height', this.value); setAttr('height', this.value);
} }
} }
@@ -143,17 +145,17 @@ svgEditor.addExtension('foreignObject', function (S) {
size: 2, size: 2,
defval: 16, defval: 16,
events: { events: {
change: function () { change () {
setAttr('font-size', this.value); setAttr('font-size', this.value);
} }
} }
} }
], ],
callback: function () { callback () {
$('#foreignObject_panel').hide(); $('#foreignObject_panel').hide();
var endChanges = function () { const endChanges = function () {
$('#svg_source_editor').hide(); $('#svg_source_editor').hide();
editingforeign = false; editingforeign = false;
$('#svg_source_textarea').blur(); $('#svg_source_textarea').blur();
@@ -163,7 +165,7 @@ svgEditor.addExtension('foreignObject', function (S) {
// TODO: Needs to be done after orig icon loads // TODO: Needs to be done after orig icon loads
setTimeout(function () { setTimeout(function () {
// Create source save/cancel buttons // Create source save/cancel buttons
/* var save = */ $('#tool_source_save').clone() /* const save = */ $('#tool_source_save').clone()
.hide().attr('id', 'foreign_save').unbind() .hide().attr('id', 'foreign_save').unbind()
.appendTo('#tool_source_back').click(function () { .appendTo('#tool_source_back').click(function () {
if (!editingforeign) { return; } if (!editingforeign) { return; }
@@ -179,15 +181,15 @@ svgEditor.addExtension('foreignObject', function (S) {
// setSelectMode(); // setSelectMode();
}); });
/* var cancel = */ $('#tool_source_cancel').clone() /* const cancel = */ $('#tool_source_cancel').clone()
.hide().attr('id', 'foreign_cancel').unbind() .hide().attr('id', 'foreign_cancel').unbind()
.appendTo('#tool_source_back').click(function () { .appendTo('#tool_source_back').click(function () {
endChanges(); endChanges();
}); });
}, 3000); }, 3000);
}, },
mouseDown: function (opts) { mouseDown (opts) {
// var e = opts.event; // const e = opts.event;
if (svgCanvas.getMode() === 'foreign') { if (svgCanvas.getMode() === 'foreign') {
started = true; started = true;
@@ -203,15 +205,15 @@ svgEditor.addExtension('foreignObject', function (S) {
'style': 'pointer-events:inherit' 'style': 'pointer-events:inherit'
} }
}); });
var m = svgdoc.createElementNS(NS.MATH, 'math'); const m = svgdoc.createElementNS(NS.MATH, 'math');
m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH); m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH);
m.setAttribute('display', 'inline'); m.setAttribute('display', 'inline');
var mi = svgdoc.createElementNS(NS.MATH, 'mi'); const mi = svgdoc.createElementNS(NS.MATH, 'mi');
mi.setAttribute('mathvariant', 'normal'); mi.setAttribute('mathvariant', 'normal');
mi.textContent = '\u03A6'; mi.textContent = '\u03A6';
var mo = svgdoc.createElementNS(NS.MATH, 'mo'); const mo = svgdoc.createElementNS(NS.MATH, 'mo');
mo.textContent = '\u222A'; mo.textContent = '\u222A';
var mi2 = svgdoc.createElementNS(NS.MATH, 'mi'); const mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
mi2.textContent = '\u2133'; mi2.textContent = '\u2133';
m.appendChild(mi); m.appendChild(mi);
m.appendChild(mo); m.appendChild(mo);
@@ -222,27 +224,26 @@ svgEditor.addExtension('foreignObject', function (S) {
}; };
} }
}, },
mouseUp: function (opts) { mouseUp (opts) {
// var e = opts.event; // const e = opts.event;
if (svgCanvas.getMode() === 'foreign' && started) { if (svgCanvas.getMode() === 'foreign' && started) {
var attrs = $(newFO).attr(['width', 'height']); const attrs = $(newFO).attr(['width', 'height']);
var keep = (attrs.width !== '0' || attrs.height !== '0'); const keep = (attrs.width !== '0' || attrs.height !== '0');
svgCanvas.addToSelection([newFO], true); svgCanvas.addToSelection([newFO], true);
return { return {
keep: keep, keep,
element: newFO element: newFO
}; };
} }
}, },
selectedChanged: function (opts) { selectedChanged (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; let i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; const elem = selElems[i];
if (elem && elem.tagName === 'foreignObject') { if (elem && elem.tagName === 'foreignObject') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
$('#foreign_font_size').val(elem.getAttribute('font-size')); $('#foreign_font_size').val(elem.getAttribute('font-size'));
@@ -257,8 +258,8 @@ svgEditor.addExtension('foreignObject', function (S) {
} }
} }
}, },
elementChanged: function (opts) { elementChanged (opts) {
// var elem = opts.elems[0]; // const elem = opts.elems[0];
} }
}; };
}); });

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgCanvas */
/* globals svgEditor, svgedit, svgCanvas, $ */
/* /*
* ext-grid.js * ext-grid.js
* *
@@ -14,97 +13,97 @@
// 1) units.js // 1) units.js
// 2) everything else // 2) everything else
svgEditor.addExtension('view_grid', function () { import {NS} from './svgedit.js';
'use strict'; import {getTypeMap} from './units.js';
var NS = svgedit.NS, svgEditor.addExtension('view_grid', function () {
svgdoc = document.getElementById('svgcanvas').ownerDocument, const $ = jQuery;
showGrid = svgEditor.curConfig.showGrid || false, const svgdoc = document.getElementById('svgcanvas').ownerDocument,
assignAttributes = svgCanvas.assignAttributes, {assignAttributes} = svgCanvas,
hcanvas = document.createElement('canvas'), hcanvas = document.createElement('canvas'),
canvBG = $('#canvasBackground'), canvBG = $('#canvasBackground'),
units = svgedit.units.getTypeMap(), units = getTypeMap(),
intervals = [0.01, 0.1, 1, 10, 100, 1000]; intervals = [0.01, 0.1, 1, 10, 100, 1000];
let showGrid = svgEditor.curConfig.showGrid || false;
$(hcanvas).hide().appendTo('body'); $(hcanvas).hide().appendTo('body');
var canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg'); const canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
assignAttributes(canvasGrid, { assignAttributes(canvasGrid, {
'id': 'canvasGrid', id: 'canvasGrid',
'width': '100%', width: '100%',
'height': '100%', height: '100%',
'x': 0, x: 0,
'y': 0, y: 0,
'overflow': 'visible', overflow: 'visible',
'display': 'none' display: 'none'
}); });
canvBG.append(canvasGrid); canvBG.append(canvasGrid);
// grid-pattern // grid-pattern
var gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern'); const gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
assignAttributes(gridPattern, { assignAttributes(gridPattern, {
'id': 'gridpattern', id: 'gridpattern',
'patternUnits': 'userSpaceOnUse', patternUnits: 'userSpaceOnUse',
'x': 0, // -(value.strokeWidth / 2), // position for strokewidth x: 0, // -(value.strokeWidth / 2), // position for strokewidth
'y': 0, // -(value.strokeWidth / 2), // position for strokewidth y: 0, // -(value.strokeWidth / 2), // position for strokewidth
'width': 100, width: 100,
'height': 100 height: 100
}); });
var gridimg = svgdoc.createElementNS(NS.SVG, 'image'); const gridimg = svgdoc.createElementNS(NS.SVG, 'image');
assignAttributes(gridimg, { assignAttributes(gridimg, {
'x': 0, x: 0,
'y': 0, y: 0,
'width': 100, width: 100,
'height': 100 height: 100
}); });
gridPattern.appendChild(gridimg); gridPattern.appendChild(gridimg);
$('#svgroot defs').append(gridPattern); $('#svgroot defs').append(gridPattern);
// grid-box // grid-box
var gridBox = svgdoc.createElementNS(NS.SVG, 'rect'); const gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
assignAttributes(gridBox, { assignAttributes(gridBox, {
'width': '100%', width: '100%',
'height': '100%', height: '100%',
'x': 0, x: 0,
'y': 0, y: 0,
'stroke-width': 0, 'stroke-width': 0,
'stroke': 'none', stroke: 'none',
'fill': 'url(#gridpattern)', fill: 'url(#gridpattern)',
'style': 'pointer-events: none; display:visible;' style: 'pointer-events: none; display:visible;'
}); });
$('#canvasGrid').append(gridBox); $('#canvasGrid').append(gridBox);
function updateGrid (zoom) { function updateGrid (zoom) {
var i;
// TODO: Try this with <line> elements, then compare performance difference // TODO: Try this with <line> elements, then compare performance difference
var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px const unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
var uMulti = unit * zoom; const uMulti = unit * zoom;
// Calculate the main number interval // Calculate the main number interval
var rawM = 100 / uMulti; const rawM = 100 / uMulti;
var multi = 1; let multi = 1;
for (i = 0; i < intervals.length; i++) { for (let i = 0; i < intervals.length; i++) {
var num = intervals[i]; const num = intervals[i];
multi = num; multi = num;
if (rawM <= num) { if (rawM <= num) {
break; break;
} }
} }
var bigInt = multi * uMulti; const bigInt = multi * uMulti;
// Set the canvas size to the width of the container // Set the canvas size to the width of the container
hcanvas.width = bigInt; hcanvas.width = bigInt;
hcanvas.height = bigInt; hcanvas.height = bigInt;
var ctx = hcanvas.getContext('2d'); const ctx = hcanvas.getContext('2d');
var curD = 0.5; const curD = 0.5;
var part = bigInt / 10; const part = bigInt / 10;
ctx.globalAlpha = 0.2; ctx.globalAlpha = 0.2;
ctx.strokeStyle = svgEditor.curConfig.gridColor; ctx.strokeStyle = svgEditor.curConfig.gridColor;
for (i = 1; i < 10; i++) { for (let i = 1; i < 10; i++) {
var subD = Math.round(part * i) + 0.5; const subD = Math.round(part * i) + 0.5;
// var lineNum = (i % 2)?12:10; // const lineNum = (i % 2)?12:10;
var lineNum = 0; const lineNum = 0;
ctx.moveTo(subD, bigInt); ctx.moveTo(subD, bigInt);
ctx.lineTo(subD, lineNum); ctx.lineTo(subD, lineNum);
ctx.moveTo(bigInt, subD); ctx.moveTo(bigInt, subD);
@@ -120,7 +119,7 @@ svgEditor.addExtension('view_grid', function () {
ctx.lineTo(0, curD); ctx.lineTo(0, curD);
ctx.stroke(); ctx.stroke();
var datauri = hcanvas.toDataURL('image/png'); const datauri = hcanvas.toDataURL('image/png');
gridimg.setAttribute('width', bigInt); gridimg.setAttribute('width', bigInt);
gridimg.setAttribute('height', bigInt); gridimg.setAttribute('height', bigInt);
gridimg.parentNode.setAttribute('width', bigInt); gridimg.parentNode.setAttribute('width', bigInt);
@@ -139,10 +138,10 @@ svgEditor.addExtension('view_grid', function () {
name: 'view_grid', name: 'view_grid',
svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml', svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml',
zoomChanged: function (zoom) { zoomChanged (zoom) {
if (showGrid) { updateGrid(zoom); } if (showGrid) { updateGrid(zoom); }
}, },
callback: function () { callback () {
if (showGrid) { if (showGrid) {
gridUpdate(); gridUpdate();
} }
@@ -153,7 +152,7 @@ svgEditor.addExtension('view_grid', function () {
panel: 'editor_panel', panel: 'editor_panel',
title: 'Show/Hide Grid', title: 'Show/Hide Grid',
events: { events: {
click: function () { click () {
svgEditor.curConfig.showGrid = showGrid = !showGrid; svgEditor.curConfig.showGrid = showGrid = !showGrid;
gridUpdate(); gridUpdate();
} }

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgCanvas */
/* globals svgEditor, svgCanvas, $ */
/* /*
* ext-helloworld.js * ext-helloworld.js
* *
@@ -16,8 +15,7 @@
*/ */
svgEditor.addExtension('Hello World', function () { svgEditor.addExtension('Hello World', function () {
'use strict'; const $ = jQuery;
return { return {
name: 'Hello World', name: 'Hello World',
// For more notes on how to make an icon file, see the source of // For more notes on how to make an icon file, see the source of
@@ -38,7 +36,7 @@ svgEditor.addExtension('Hello World', function () {
// Events // Events
events: { events: {
'click': function () { click () {
// The action taken when the button is clicked on. // The action taken when the button is clicked on.
// For "mode" buttons, any other button will // For "mode" buttons, any other button will
// automatically be de-pressed. // automatically be de-pressed.
@@ -48,7 +46,7 @@ svgEditor.addExtension('Hello World', function () {
}], }],
// This is triggered when the main mouse button is pressed down // This is triggered when the main mouse button is pressed down
// on the editor canvas (not the tool panels) // on the editor canvas (not the tool panels)
mouseDown: function () { mouseDown () {
// Check the mode on mousedown // Check the mode on mousedown
if (svgCanvas.getMode() === 'hello_world') { if (svgCanvas.getMode() === 'hello_world') {
// The returned object must include "started" with // The returned object must include "started" with
@@ -59,16 +57,16 @@ svgEditor.addExtension('Hello World', function () {
// This is triggered from anywhere, but "started" must have been set // This is triggered from anywhere, but "started" must have been set
// to true (see above). Note that "opts" is an object with event info // to true (see above). Note that "opts" is an object with event info
mouseUp: function (opts) { mouseUp (opts) {
// Check the mode on mouseup // Check the mode on mouseup
if (svgCanvas.getMode() === 'hello_world') { if (svgCanvas.getMode() === 'hello_world') {
var zoom = svgCanvas.getZoom(); const zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value // Get the actual coordinate by dividing by the zoom value
var x = opts.mouse_x / zoom; const x = opts.mouse_x / zoom;
var y = opts.mouse_y / zoom; const y = opts.mouse_y / zoom;
var text = 'Hello World!\n\nYou clicked here: ' + const text = 'Hello World!\n\nYou clicked here: ' +
x + ', ' + y; x + ', ' + y;
// Show the text using the custom alert function // Show the text using the custom alert function

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgedit, svgCanvas */
/* globals $, svgEditor, svgedit, svgCanvas, DOMParser */
/* /*
* ext-imagelib.js * ext-imagelib.js
* *
@@ -10,9 +9,8 @@
*/ */
svgEditor.addExtension('imagelib', function () { svgEditor.addExtension('imagelib', function () {
'use strict'; const $ = jQuery;
const {uiStrings} = svgEditor;
var uiStrings = svgEditor.uiStrings;
$.extend(uiStrings, { $.extend(uiStrings, {
imagelib: { imagelib: {
@@ -24,7 +22,7 @@ svgEditor.addExtension('imagelib', function () {
} }
}); });
var imgLibs = [ const imgLibs = [
{ {
name: 'Demo library (local)', name: 'Demo library (local)',
url: svgEditor.curConfig.extPath + 'imagelib/index.html', url: svgEditor.curConfig.extPath + 'imagelib/index.html',
@@ -47,7 +45,7 @@ svgEditor.addExtension('imagelib', function () {
} }
function importImage (url) { function importImage (url) {
var newImage = svgCanvas.addSvgElementFromJson({ const newImage = svgCanvas.addSvgElementFromJson({
'element': 'image', 'element': 'image',
'attr': { 'attr': {
'x': 0, 'x': 0,
@@ -63,58 +61,64 @@ svgEditor.addExtension('imagelib', function () {
svgCanvas.setImageURL(url); svgCanvas.setImageURL(url);
} }
var mode = 's'; const pending = {};
var multiArr = [];
var transferStopped = false; let mode = 's';
var pending = {}; let multiArr = [];
var preview, submit; let transferStopped = false;
let preview, submit;
window.addEventListener('message', function (evt) { window.addEventListener('message', function (evt) {
// Receive postMessage data // Receive `postMessage` data
var response = evt.data; let response = evt.data;
if (!response || typeof response !== 'string') { // Todo: Should namespace postMessage API for this extension and filter out here if (!response || typeof response !== 'string') {
// Do nothing // Do nothing
return; return;
} }
try { // This block can be removed if embedAPI moves away from a string to an object (if IE9 support not needed) try {
var res = JSON.parse(response); // Todo: This block can be removed (and the above check changed to
if (res.namespace) { // Part of embedAPI communications // insist on an object) if embedAPI moves away from a string to
// an object (if IE9 support not needed)
response = JSON.parse(response);
if (response.namespace !== 'imagelib') {
return; return;
} }
} catch (e) {} } catch (e) {
return;
}
var char1 = response.charAt(0); const hasName = 'name' in response;
var id; const hasHref = 'href' in response;
var svgStr;
var imgStr;
if (char1 !== '{' && transferStopped) { if (!hasName && transferStopped) {
transferStopped = false; transferStopped = false;
return; return;
} }
if (char1 === '|') { let id;
var secondpos = response.indexOf('|', 1); if (hasHref) {
id = response.substr(1, secondpos - 1); id = response.href;
response = response.substr(secondpos + 1); response = response.data;
char1 = response.charAt(0);
} }
// Hide possible transfer dialog box // Hide possible transfer dialog box
$('#dialog_box').hide(); $('#dialog_box').hide();
var entry, curMeta; let entry, curMeta, svgStr, imgStr;
switch (char1) { const type = hasName
case '{': ? 'meta'
: response.charAt(0);
switch (type) {
case 'meta': {
// Metadata // Metadata
transferStopped = false; transferStopped = false;
curMeta = JSON.parse(response); curMeta = response;
pending[curMeta.id] = curMeta; pending[curMeta.id] = curMeta;
var name = (curMeta.name || 'file'); const name = (curMeta.name || 'file');
var message = uiStrings.notification.retrieving.replace('%s', name); const message = uiStrings.notification.retrieving.replace('%s', name);
if (mode !== 'm') { if (mode !== 'm') {
$.process_cancel(message, function () { $.process_cancel(message, function () {
@@ -130,24 +134,26 @@ svgEditor.addExtension('imagelib', function () {
} }
return; return;
}
case '<': case '<':
svgStr = true; svgStr = true;
break; break;
case 'd': case 'd': {
if (response.indexOf('data:image/svg+xml') === 0) { if (response.startsWith('data:image/svg+xml')) {
var pre = 'data:image/svg+xml;base64,'; const pre = 'data:image/svg+xml;base64,';
var src = response.substring(pre.length); const src = response.substring(pre.length);
response = svgedit.utilities.decode64(src); response = svgedit.utilities.decode64(src);
svgStr = true; svgStr = true;
break; break;
} else if (response.indexOf('data:image/') === 0) { } else if (response.startsWith('data:image/')) {
imgStr = true; imgStr = true;
break; break;
} }
// Else fall through }
// Else fall through
default: default:
// TODO: See if there's a way to base64 encode the binary data stream // TODO: See if there's a way to base64 encode the binary data stream
// var str = 'data:;base64,' + svgedit.utilities.encode64(response, true); // const str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
// Assume it's raw image data // Assume it's raw image data
// importImage(str); // importImage(str);
@@ -181,14 +187,14 @@ svgEditor.addExtension('imagelib', function () {
case 'm': case 'm':
// Import multiple // Import multiple
multiArr.push([(svgStr ? 'svg' : 'img'), response]); multiArr.push([(svgStr ? 'svg' : 'img'), response]);
var title;
curMeta = pending[id]; curMeta = pending[id];
let title;
if (svgStr) { if (svgStr) {
if (curMeta && curMeta.name) { if (curMeta && curMeta.name) {
title = curMeta.name; title = curMeta.name;
} else { } else {
// Try to find a title // Try to find a title
var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement; const xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')'; title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
} }
if (curMeta) { if (curMeta) {
@@ -260,8 +266,8 @@ svgEditor.addExtension('imagelib', function () {
.appendTo('#imgbrowse') .appendTo('#imgbrowse')
.on('click touchend', function () { .on('click touchend', function () {
$.each(multiArr, function (i) { $.each(multiArr, function (i) {
var type = this[0]; const type = this[0];
var data = this[1]; const data = this[1];
if (type === 'svg') { if (type === 'svg') {
svgCanvas.importSvgString(data); svgCanvas.importSvgString(data);
} else { } else {
@@ -284,25 +290,25 @@ svgEditor.addExtension('imagelib', function () {
} }
function showBrowser () { function showBrowser () {
var browser = $('#imgbrowse'); let browser = $('#imgbrowse');
if (!browser.length) { if (!browser.length) {
$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' + $('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' +
'</div></div>').insertAfter('#svg_docprops'); '</div></div>').insertAfter('#svg_docprops');
browser = $('#imgbrowse'); browser = $('#imgbrowse');
var allLibs = uiStrings.imagelib.select_lib; const allLibs = uiStrings.imagelib.select_lib;
var libOpts = $('<ul id=imglib_opts>').appendTo(browser); const libOpts = $('<ul id=imglib_opts>').appendTo(browser);
var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>'); const frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
var header = $('<h1>').prependTo(browser).text(allLibs).css({ const header = $('<h1>').prependTo(browser).text(allLibs).css({
position: 'absolute', position: 'absolute',
top: 0, top: 0,
left: 0, left: 0,
width: '100%' width: '100%'
}); });
var cancel = $('<button>' + uiStrings.common.cancel + '</button>') const cancel = $('<button>' + uiStrings.common.cancel + '</button>')
.appendTo(browser) .appendTo(browser)
.on('click touchend', function () { .on('click touchend', function () {
$('#imgbrowse_holder').hide(); $('#imgbrowse_holder').hide();
@@ -312,9 +318,9 @@ svgEditor.addExtension('imagelib', function () {
right: -10 right: -10
}); });
var leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser); const leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser);
var back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>') const back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>')
.appendTo(leftBlock) .appendTo(leftBlock)
.on('click touchend', function () { .on('click touchend', function () {
frame.attr('src', 'about:blank').hide(); frame.attr('src', 'about:blank').hide();
@@ -325,7 +331,7 @@ svgEditor.addExtension('imagelib', function () {
'margin-right': 5 'margin-right': 5
}).hide(); }).hide();
/* var type = */ $('<select><option value=s>' + /* const type = */ $('<select><option value=s>' +
uiStrings.imagelib.import_single + '</option><option value=m>' + uiStrings.imagelib.import_single + '</option><option value=m>' +
uiStrings.imagelib.import_multi + '</option><option value=o>' + uiStrings.imagelib.import_multi + '</option><option value=o>' +
uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function () { uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function () {
@@ -372,10 +378,10 @@ svgEditor.addExtension('imagelib', function () {
position: 4, position: 4,
title: 'Image library', title: 'Image library',
events: { events: {
'mouseup': showBrowser mouseup: showBrowser
} }
}], }],
callback: function () { callback () {
$('<style>').text( $('<style>').text(
'#imgbrowse_holder {' + '#imgbrowse_holder {' +
'position: absolute;' + 'position: absolute;' +

View File

@@ -0,0 +1,44 @@
export default {
en: {
message: 'By default and where supported, SVG-Edit can store your editor ' +
'preferences and SVG content locally on your machine so you do not ' +
'need to add these back each time you load SVG-Edit. If, for privacy ' +
'reasons, you do not wish to store this information on your machine, ' +
'you can change away from the default option below.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
},
de: {
message: 'Standardmäßig kann SVG-Edit Ihre Editor-Einstellungen ' +
'und die SVG-Inhalte lokal auf Ihrem Gerät abspeichern. So brauchen Sie ' +
'nicht jedes Mal die SVG neu laden. Falls Sie aus Datenschutzgründen ' +
'dies nicht wollen, ' +
'können Sie die Standardeinstellung im Folgenden ändern.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
},
fr: {
message: "Par défaut et si supporté, SVG-Edit peut stocker les préférences de l'éditeur " +
"et le contenu SVG localement sur votre machine de sorte que vous n'ayez pas besoin de les " +
'rajouter chaque fois que vous chargez SVG-Edit. Si, pour des raisons de confidentialité, ' +
'vous ne souhaitez pas stocker ces données sur votre machine, vous pouvez changer ce ' +
'comportement ci-dessous.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: "Si vous choisissez de désactiver le stockage en mémorisant le choix, l'URL va changer afin que la question ne vous soit plus reposée."
}
};

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgCanvas */
/* globals svgEditor, svgCanvas, $ */
/* /*
* ext-markers.js * ext-markers.js
* *
@@ -33,21 +32,19 @@
*/ */
svgEditor.addExtension('Markers', function (S) { svgEditor.addExtension('Markers', function (S) {
var // svgcontent = S.svgcontent, const $ = jQuery;
addElem = S.addSvgElementFromJson, const // {svgcontent} = S,
selElems; addElem = S.addSvgElementFromJson;
const mtypes = ['start', 'mid', 'end'];
var mtypes = ['start', 'mid', 'end']; const markerPrefix = 'se_marker_';
const idPrefix = 'mkr_';
var markerPrefix = 'se_marker_';
var idPrefix = 'mkr_';
// note - to add additional marker types add them below with a unique id // note - to add additional marker types add them below with a unique id
// and add the associated icon(s) to marker-icons.svg // and add the associated icon(s) to marker-icons.svg
// the geometry is normallized to a 100x100 box with the origin at lower left // the geometry is normallized to a 100x100 box with the origin at lower left
// Safari did not like negative values for low left of viewBox // Safari did not like negative values for low left of viewBox
// remember that the coordinate system has +y downward // remember that the coordinate system has +y downward
var markerTypes = { const markerTypes = {
nomarker: {}, nomarker: {},
leftarrow: leftarrow:
{element: 'path', attr: {d: 'M0,50 L100,90 L70,50 L100,10 Z'}}, {element: 'path', attr: {d: 'M0,50 L100,90 L70,50 L100,10 Z'}},
@@ -74,7 +71,7 @@ svgEditor.addExtension('Markers', function (S) {
{element: 'circle', attr: {r: 30, cx: 50, cy: 50}} {element: 'circle', attr: {r: 30, cx: 50, cy: 50}}
}; };
var langList = { const langList = {
'en': [ 'en': [
{id: 'start_marker_list', title: 'Select start marker type'}, {id: 'start_marker_list', title: 'Select start marker type'},
{id: 'mid_marker_list', title: 'Select mid marker type'}, {id: 'mid_marker_list', title: 'Select mid marker type'},
@@ -109,9 +106,9 @@ svgEditor.addExtension('Markers', function (S) {
// attr - marker-start, marker-mid, or marker-end // attr - marker-start, marker-mid, or marker-end
// returns the marker element that is linked to the graphic element // returns the marker element that is linked to the graphic element
function getLinked (elem, attr) { function getLinked (elem, attr) {
var str = elem.getAttribute(attr); const str = elem.getAttribute(attr);
if (!str) { return null; } if (!str) { return null; }
var m = str.match(/\(#(.*)\)/); const m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) { if (!m || m.length !== 2) {
return null; return null;
} }
@@ -120,24 +117,24 @@ svgEditor.addExtension('Markers', function (S) {
function setIcon (pos, id) { function setIcon (pos, id) {
if (id.substr(0, 1) !== '\\') { id = '\\textmarker'; } if (id.substr(0, 1) !== '\\') { id = '\\textmarker'; }
var ci = '#' + idPrefix + pos + '_' + id.substr(1); const ci = '#' + idPrefix + pos + '_' + id.substr(1);
svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children()); svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children());
$(ci).addClass('current').siblings().removeClass('current'); $(ci).addClass('current').siblings().removeClass('current');
} }
let selElems;
// toggles context tool panel off/on // toggles context tool panel off/on
// sets the controls with the selected element's settings // sets the controls with the selected element's settings
function showPanel (on) { function showPanel (on) {
$('#marker_panel').toggle(on); $('#marker_panel').toggle(on);
if (on) { if (on) {
var el = selElems[0]; const el = selElems[0];
var val;
var ci;
let val, ci;
$.each(mtypes, function (i, pos) { $.each(mtypes, function (i, pos) {
var m = getLinked(el, 'marker-' + pos); const m = getLinked(el, 'marker-' + pos);
var txtbox = $('#' + pos + '_marker'); const txtbox = $('#' + pos + '_marker');
if (!m) { if (!m) {
val = '\\nomarker'; val = '\\nomarker';
ci = val; ci = val;
@@ -160,28 +157,27 @@ svgEditor.addExtension('Markers', function (S) {
} }
function addMarker (id, val) { function addMarker (id, val) {
var txtBoxBg = '#ffffff'; const txtBoxBg = '#ffffff';
var txtBoxBorder = 'none'; const txtBoxBorder = 'none';
var txtBoxStrokeWidth = 0; const txtBoxStrokeWidth = 0;
var marker = S.getElem(id);
let marker = S.getElem(id);
if (marker) { return; } if (marker) { return; }
if (val === '' || val === '\\nomarker') { return; } if (val === '' || val === '\\nomarker') { return; }
var el = selElems[0]; const el = selElems[0];
var color = el.getAttribute('stroke'); const color = el.getAttribute('stroke');
// NOTE: Safari didn't like a negative value in viewBox // NOTE: Safari didn't like a negative value in viewBox
// so we use a standardized 0 0 100 100 // so we use a standardized 0 0 100 100
// with 50 50 being mapped to the marker position // with 50 50 being mapped to the marker position
var refX = 50; const strokeWidth = 10;
var refY = 50; let refX = 50;
var viewBox = '0 0 100 100'; let refY = 50;
var markerWidth = 5; let viewBox = '0 0 100 100';
var markerHeight = 5; let markerWidth = 5;
var strokeWidth = 10; let markerHeight = 5;
var seType; let seType;
if (val.substr(0, 1) === '\\') { if (val.substr(0, 1) === '\\') {
seType = val.substr(1); seType = val.substr(1);
} else { seType = 'textmarker'; } } else { seType = 'textmarker'; }
@@ -190,32 +186,34 @@ svgEditor.addExtension('Markers', function (S) {
// create a generic marker // create a generic marker
marker = addElem({ marker = addElem({
'element': 'marker', element: 'marker',
'attr': { attr: {
'id': id, id,
'markerUnits': 'strokeWidth', markerUnits: 'strokeWidth',
'orient': 'auto', orient: 'auto',
'style': 'pointer-events:none', style: 'pointer-events:none',
'se_type': seType se_type: seType
} }
}); });
if (seType !== 'textmarker') { if (seType !== 'textmarker') {
var mel = addElem(markerTypes[seType]); const mel = addElem(markerTypes[seType]);
var fillcolor = color; const fillcolor = (seType.substr(-2) === '_o')
if (seType.substr(-2) === '_o') { fillcolor = 'none'; } ? 'none'
: color;
mel.setAttribute('fill', fillcolor); mel.setAttribute('fill', fillcolor);
mel.setAttribute('stroke', color); mel.setAttribute('stroke', color);
mel.setAttribute('stroke-width', strokeWidth); mel.setAttribute('stroke-width', strokeWidth);
marker.appendChild(mel); marker.appendChild(mel);
} else { } else {
var text = addElem(markerTypes[seType]); const text = addElem(markerTypes[seType]);
// have to add text to get bounding box // have to add text to get bounding box
text.textContent = val; text.textContent = val;
var tb = text.getBBox(); const tb = text.getBBox();
// alert(tb.x + ' ' + tb.y + ' ' + tb.width + ' ' + tb.height); // alert(tb.x + ' ' + tb.y + ' ' + tb.width + ' ' + tb.height);
var pad = 1; const pad = 1;
var bb = tb; const bb = tb;
bb.x = 0; bb.x = 0;
bb.y = 0; bb.y = 0;
bb.width += pad * 2; bb.width += pad * 2;
@@ -230,7 +228,7 @@ svgEditor.addExtension('Markers', function (S) {
markerWidth = bb.width / 10; markerWidth = bb.width / 10;
markerHeight = bb.height / 10; markerHeight = bb.height / 10;
var box = addElem({ const box = addElem({
'element': 'rect', 'element': 'rect',
'attr': { 'attr': {
'x': bb.x, 'x': bb.x,
@@ -264,14 +262,14 @@ svgEditor.addExtension('Markers', function (S) {
// Convert to polyline to accept mid-arrow // Convert to polyline to accept mid-arrow
var x1 = Number(elem.getAttribute('x1')); const x1 = Number(elem.getAttribute('x1'));
var x2 = Number(elem.getAttribute('x2')); const x2 = Number(elem.getAttribute('x2'));
var y1 = Number(elem.getAttribute('y1')); const y1 = Number(elem.getAttribute('y1'));
var y2 = Number(elem.getAttribute('y2')); const y2 = Number(elem.getAttribute('y2'));
var id = elem.id; const {id} = elem;
var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' '); const midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
var pline = addElem({ const pline = addElem({
'element': 'polyline', 'element': 'polyline',
'attr': { 'attr': {
'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2), 'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2),
@@ -282,12 +280,12 @@ svgEditor.addExtension('Markers', function (S) {
} }
}); });
$.each(mtypes, function (i, pos) { // get any existing marker definitions $.each(mtypes, function (i, pos) { // get any existing marker definitions
var nam = 'marker-' + pos; const nam = 'marker-' + pos;
var m = elem.getAttribute(nam); const m = elem.getAttribute(nam);
if (m) { pline.setAttribute(nam, elem.getAttribute(nam)); } if (m) { pline.setAttribute(nam, elem.getAttribute(nam)); }
}); });
var batchCmd = new S.BatchCommand(); const batchCmd = new S.BatchCommand();
batchCmd.addSubCommand(new S.RemoveElementCommand(elem, elem.parentNode)); batchCmd.addSubCommand(new S.RemoveElementCommand(elem, elem.parentNode));
batchCmd.addSubCommand(new S.InsertElementCommand(pline)); batchCmd.addSubCommand(new S.InsertElementCommand(pline));
@@ -300,14 +298,14 @@ svgEditor.addExtension('Markers', function (S) {
} }
function setMarker () { function setMarker () {
var poslist = {'start_marker': 'start', 'mid_marker': 'mid', 'end_marker': 'end'}; const poslist = {'start_marker': 'start', 'mid_marker': 'mid', 'end_marker': 'end'};
var pos = poslist[this.id]; const pos = poslist[this.id];
var markerName = 'marker-' + pos; const markerName = 'marker-' + pos;
var val = this.value; let el = selElems[0];
var el = selElems[0]; const marker = getLinked(el, markerName);
var marker = getLinked(el, markerName);
if (marker) { $(marker).remove(); } if (marker) { $(marker).remove(); }
el.removeAttribute(markerName); el.removeAttribute(markerName);
let val = this.value;
if (val === '') { val = '\\nomarker'; } if (val === '') { val = '\\nomarker'; }
if (val === '\\nomarker') { if (val === '\\nomarker') {
setIcon(pos, val); setIcon(pos, val);
@@ -315,7 +313,7 @@ svgEditor.addExtension('Markers', function (S) {
return; return;
} }
// Set marker on element // Set marker on element
var id = markerPrefix + pos + '_' + el.id; const id = markerPrefix + pos + '_' + el.id;
addMarker(id, val); addMarker(id, val);
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')'); svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); } if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); }
@@ -326,16 +324,16 @@ svgEditor.addExtension('Markers', function (S) {
// called when the main system modifies an object // called when the main system modifies an object
// this routine changes the associated markers to be the same color // this routine changes the associated markers to be the same color
function colorChanged (elem) { function colorChanged (elem) {
var color = elem.getAttribute('stroke'); const color = elem.getAttribute('stroke');
$.each(mtypes, function (i, pos) { $.each(mtypes, function (i, pos) {
var marker = getLinked(elem, 'marker-' + pos); const marker = getLinked(elem, 'marker-' + pos);
if (!marker) { return; } if (!marker) { return; }
if (!marker.attributes.se_type) { return; } // not created by this extension if (!marker.attributes.se_type) { return; } // not created by this extension
var ch = marker.lastElementChild; const ch = marker.lastElementChild;
if (!ch) { return; } if (!ch) { return; }
var curfill = ch.getAttribute('fill'); const curfill = ch.getAttribute('fill');
var curstroke = ch.getAttribute('stroke'); const curstroke = ch.getAttribute('stroke');
if (curfill && curfill !== 'none') { ch.setAttribute('fill', color); } if (curfill && curfill !== 'none') { ch.setAttribute('fill', color); }
if (curstroke && curstroke !== 'none') { ch.setAttribute('stroke', color); } if (curstroke && curstroke !== 'none') { ch.setAttribute('stroke', color); }
}); });
@@ -345,16 +343,16 @@ svgEditor.addExtension('Markers', function (S) {
// primary purpose is create new markers for cloned objects // primary purpose is create new markers for cloned objects
function updateReferences (el) { function updateReferences (el) {
$.each(mtypes, function (i, pos) { $.each(mtypes, function (i, pos) {
var id = markerPrefix + pos + '_' + el.id; const id = markerPrefix + pos + '_' + el.id;
var markerName = 'marker-' + pos; const markerName = 'marker-' + pos;
var marker = getLinked(el, markerName); const marker = getLinked(el, markerName);
if (!marker || !marker.attributes.se_type) { return; } // not created by this extension if (!marker || !marker.attributes.se_type) { return; } // not created by this extension
var url = el.getAttribute(markerName); const url = el.getAttribute(markerName);
if (url) { if (url) {
var len = el.id.length; const len = el.id.length;
var linkid = url.substr(-len - 1, len); const linkid = url.substr(-len - 1, len);
if (el.id !== linkid) { if (el.id !== linkid) {
var val = $('#' + pos + '_marker').attr('value'); const val = $('#' + pos + '_marker').attr('value');
addMarker(id, val); addMarker(id, val);
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')'); svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); } if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); }
@@ -368,13 +366,13 @@ svgEditor.addExtension('Markers', function (S) {
function triggerTextEntry (pos, val) { function triggerTextEntry (pos, val) {
$('#' + pos + '_marker').val(val); $('#' + pos + '_marker').val(val);
$('#' + pos + '_marker').change(); $('#' + pos + '_marker').change();
// var txtbox = $('#'+pos+'_marker'); // const txtbox = $('#'+pos+'_marker');
// if (val.substr(0,1)=='\\') {txtbox.hide();} // if (val.substr(0,1)=='\\') {txtbox.hide();}
// else {txtbox.show();} // else {txtbox.show();}
} }
function showTextPrompt (pos) { function showTextPrompt (pos) {
var def = $('#' + pos + '_marker').val(); let def = $('#' + pos + '_marker').val();
if (def.substr(0, 1) === '\\') { def = ''; } if (def.substr(0, 1) === '\\') { def = ''; }
$.prompt('Enter text for ' + pos + ' marker', def, function (txt) { $.prompt('Enter text for ' + pos + ' marker', def, function (txt) {
if (txt) { triggerTextEntry(pos, txt); } if (txt) { triggerTextEntry(pos, txt); }
@@ -383,8 +381,8 @@ svgEditor.addExtension('Markers', function (S) {
/* /*
function setMarkerSet(obj) { function setMarkerSet(obj) {
var parts = this.id.split('_'); const parts = this.id.split('_');
var set = parts[2]; const set = parts[2];
switch (set) { switch (set) {
case 'off': case 'off':
triggerTextEntry('start','\\nomarker'); triggerTextEntry('start','\\nomarker');
@@ -406,9 +404,9 @@ svgEditor.addExtension('Markers', function (S) {
*/ */
// callback function for a toolbar button click // callback function for a toolbar button click
function setArrowFromButton (obj) { function setArrowFromButton (obj) {
var parts = this.id.split('_'); const parts = this.id.split('_');
var pos = parts[1]; const pos = parts[1];
var val = parts[2]; let val = parts[2];
if (parts[3]) { val += '_' + parts[3]; } if (parts[3]) { val += '_' + parts[3]; }
if (val !== 'textmarker') { if (val !== 'textmarker') {
@@ -418,9 +416,9 @@ svgEditor.addExtension('Markers', function (S) {
} }
} }
function getTitle (lang, id) { function getTitle (lang = 'en', id) {
var i, list = langList[lang]; const list = langList[lang];
for (i in list) { for (const i in list) {
if (list.hasOwnProperty(i) && list[i].id === id) { if (list.hasOwnProperty(i) && list[i].id === id) {
return list[i].title; return list[i].title;
} }
@@ -429,10 +427,9 @@ svgEditor.addExtension('Markers', function (S) {
} }
// build the toolbar button array from the marker definitions // build the toolbar button array from the marker definitions
// TODO: need to incorporate language specific titles function buildButtonList (lang) {
function buildButtonList () { const buttons = [];
var buttons = []; // const i = 0;
// var i = 0;
/* /*
buttons.push({ buttons.push({
id: idPrefix + 'markers_off', id: idPrefix + 'markers_off',
@@ -457,14 +454,14 @@ svgEditor.addExtension('Markers', function (S) {
}); });
*/ */
$.each(mtypes, function (k, pos) { $.each(mtypes, function (k, pos) {
var listname = pos + '_marker_list'; const listname = pos + '_marker_list';
var def = true; let def = true;
$.each(markerTypes, function (id, v) { $.each(markerTypes, function (id, v) {
var title = getTitle('en', String(id)); const title = getTitle(lang, String(id));
buttons.push({ buttons.push({
id: idPrefix + pos + '_' + id, id: idPrefix + pos + '_' + id,
svgicon: id, svgicon: id,
title: title, title,
type: 'context', type: 'context',
events: {'click': setArrowFromButton}, events: {'click': setArrowFromButton},
panel: 'marker_panel', panel: 'marker_panel',
@@ -477,76 +474,28 @@ svgEditor.addExtension('Markers', function (S) {
return buttons; return buttons;
} }
return { let currentLang;
const ret = {
name: 'Markers', name: 'Markers',
svgicons: svgEditor.curConfig.extPath + 'markers-icons.xml', svgicons: svgEditor.curConfig.extPath + 'markers-icons.xml',
buttons: buildButtonList(), callback () {
context_tools: [
{
type: 'input',
panel: 'marker_panel',
title: 'Start marker',
id: 'start_marker',
label: 's',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle('en', 'start_marker_list'),
id: 'start_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
title: 'Middle marker',
id: 'mid_marker',
label: 'm',
defval: '',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle('en', 'mid_marker_list'),
id: 'mid_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
title: 'End marker',
id: 'end_marker',
label: 'e',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle('en', 'end_marker_list'),
id: 'end_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}
],
callback: function () {
$('#marker_panel').addClass('toolset').hide(); $('#marker_panel').addClass('toolset').hide();
}, },
addLangData: function (lang) { addLangData (lang) {
currentLang = lang;
return { data: langList[lang] }; return { data: langList[lang] };
}, },
selectedChanged: function (opts) { selectedChanged (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
// console.log('selectChanged',opts); // console.log('selectChanged',opts);
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; const markerElems = ['line', 'path', 'polyline', 'polygon'];
var markerElems = ['line', 'path', 'polyline', 'polygon'];
let i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; const elem = selElems[i];
if (elem && $.inArray(elem.tagName, markerElems) !== -1) { if (elem && markerElems.includes(elem.tagName)) {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
showPanel(true); showPanel(true);
} else { } else {
@@ -558,9 +507,9 @@ svgEditor.addExtension('Markers', function (S) {
} }
}, },
elementChanged: function (opts) { elementChanged (opts) {
// console.log('elementChanged',opts); // console.log('elementChanged',opts);
var elem = opts.elems[0]; const elem = opts.elems[0];
if (elem && ( if (elem && (
elem.getAttribute('marker-start') || elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') || elem.getAttribute('marker-mid') ||
@@ -572,4 +521,66 @@ svgEditor.addExtension('Markers', function (S) {
// changing_flag = false; // Not apparently in use // changing_flag = false; // Not apparently in use
} }
}; };
// Todo: Check if the lang will be available in time
Object.defineProperties(ret, {
buttons: {
get () {
return buildButtonList(currentLang);
}
},
context_tools: {
get () {
return [
{
type: 'input',
panel: 'marker_panel',
title: 'Start marker',
id: 'start_marker',
label: 's',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle(currentLang, 'start_marker_list'),
id: 'start_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
title: 'Middle marker',
id: 'mid_marker',
label: 'm',
defval: '',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle(currentLang, 'mid_marker_list'),
id: 'mid_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
title: 'End marker',
id: 'end_marker',
label: 'e',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle(currentLang, 'end_marker_list'),
id: 'end_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}
];
}
}
});
return ret;
}); });

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, MathJax, svgEditor, svgCanvas */
/* globals MathJax, svgEditor, svgCanvas, $ */
/* /*
* ext-mathjax.js * ext-mathjax.js
* *
@@ -10,11 +9,12 @@
*/ */
svgEditor.addExtension('mathjax', function () { svgEditor.addExtension('mathjax', function () {
'use strict'; const $ = jQuery;
// Configuration of the MathJax extention. // Configuration of the MathJax extention.
// This will be added to the head tag before MathJax is loaded. // This will be added to the head tag before MathJax is loaded.
var /* mathjaxConfiguration = '<script type="text/x-mathjax-config">\ const /* mathjaxConfiguration = '<script type="text/x-mathjax-config">\
MathJax.Hub.Config({\ MathJax.Hub.Config({\
extensions: ["tex2jax.js"],\ extensions: ["tex2jax.js"],\
jax: ["input/TeX","output/SVG"],\ jax: ["input/TeX","output/SVG"],\
@@ -37,12 +37,15 @@ svgEditor.addExtension('mathjax', function () {
});\ });\
</script>', */ </script>', */
// mathjaxSrc = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js', // mathjaxSrc = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js',
mathjaxSrcSecure = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG.js', // Had been on https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG.js
// Obtained Text-AMS-MML_SVG.js from https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.3/config/TeX-AMS-MML_SVG.js
mathjaxSrcSecure = 'mathjax/MathJax.js?config=TeX-AMS-MML_SVG.js',
{uiStrings} = svgEditor;
let
math, math,
locationX, locationX,
locationY, locationY,
mathjaxLoaded = false, mathjaxLoaded = false;
uiStrings = svgEditor.uiStrings;
// TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback. // TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback.
$.extend(uiStrings, { $.extend(uiStrings, {
@@ -56,7 +59,7 @@ svgEditor.addExtension('mathjax', function () {
}); });
function saveMath () { function saveMath () {
var code = $('#mathjax_code_textarea').val(); const code = $('#mathjax_code_textarea').val();
// displaystyle to force MathJax NOT to use the inline style. Because it is // displaystyle to force MathJax NOT to use the inline style. Because it is
// less fancy! // less fancy!
MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']); MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']);
@@ -75,22 +78,17 @@ svgEditor.addExtension('mathjax', function () {
*/ */
MathJax.Hub.queue.Push( MathJax.Hub.queue.Push(
function () { function () {
var mathjaxMath = $('.MathJax_SVG'); const mathjaxMath = $('.MathJax_SVG');
var svg = $(mathjaxMath.html()); const svg = $(mathjaxMath.html());
svg.find('use').each(function () { svg.find('use').each(function () {
var x, y, id, transform;
// TODO: find a less pragmatic and more elegant solution to this. // TODO: find a less pragmatic and more elegant solution to this.
if ($(this).attr('href')) { const id = $(this).attr('href')
id = $(this).attr('href').slice(1); // Works in Chrome. ? $(this).attr('href').slice(1) // Works in Chrome.
} else { : $(this).attr('xlink:href').slice(1); // Works in Firefox.
id = $(this).attr('xlink:href').slice(1); // Works in Firefox. const glymph = $('#' + id).clone().removeAttr('id');
} const x = $(this).attr('x');
const y = $(this).attr('y');
var glymph = $('#' + id).clone().removeAttr('id'); const transform = $(this).attr('transform');
x = $(this).attr('x');
y = $(this).attr('y');
transform = $(this).attr('transform');
if (transform && (x || y)) { if (transform && (x || y)) {
glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')'); glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')');
} else if (transform) { } else if (transform) {
@@ -120,7 +118,7 @@ svgEditor.addExtension('mathjax', function () {
type: 'mode', type: 'mode',
title: 'Add Mathematics', title: 'Add Mathematics',
events: { events: {
click: function () { click () {
// Only load Mathjax when needed, we don't want to strain Svg-Edit any more. // Only load Mathjax when needed, we don't want to strain Svg-Edit any more.
// From this point on it is very probable that it will be needed, so load it. // From this point on it is very probable that it will be needed, so load it.
if (mathjaxLoaded === false) { if (mathjaxLoaded === false) {
@@ -166,6 +164,8 @@ svgEditor.addExtension('mathjax', function () {
$('body').addClass('tex2jax_ignore'); $('body').addClass('tex2jax_ignore');
// Now get (and run) the MathJax Library. // Now get (and run) the MathJax Library.
// Todo: insert script with `s.type = 'module';` once modules widely supported
// and if this ends up providing an ES6 module export
$.getScript(mathjaxSrcSecure) $.getScript(mathjaxSrcSecure)
.done(function (script, textStatus) { .done(function (script, textStatus) {
// When MathJax is loaded get the div where the math will be rendered. // When MathJax is loaded get the div where the math will be rendered.
@@ -188,15 +188,15 @@ svgEditor.addExtension('mathjax', function () {
} }
}], }],
mouseDown: function () { mouseDown () {
if (svgCanvas.getMode() === 'mathjax') { if (svgCanvas.getMode() === 'mathjax') {
return {started: true}; return {started: true};
} }
}, },
mouseUp: function (opts) { mouseUp (opts) {
if (svgCanvas.getMode() === 'mathjax') { if (svgCanvas.getMode() === 'mathjax') {
// Get the coordinates from your mouse. // Get the coordinates from your mouse.
var zoom = svgCanvas.getZoom(); const zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value // Get the actual coordinate by dividing by the zoom value
locationX = opts.mouse_x / zoom; locationX = opts.mouse_x / zoom;
locationY = opts.mouse_y / zoom; locationY = opts.mouse_y / zoom;
@@ -205,7 +205,7 @@ svgEditor.addExtension('mathjax', function () {
return {started: false}; // Otherwise the last selected object dissapears. return {started: false}; // Otherwise the last selected object dissapears.
} }
}, },
callback: function () { callback () {
$('<style>').text( $('<style>').text(
'#mathjax fieldset{' + '#mathjax fieldset{' +
'padding: 5px;' + 'padding: 5px;' +

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgedit */
/* globals svgEditor, svgedit, $ */
/* /*
* ext-overview_window.js * ext-overview_window.js
* *
@@ -9,21 +8,21 @@
* *
*/ */
var overviewWindowGlobals = {};
svgEditor.addExtension('overview_window', function () { svgEditor.addExtension('overview_window', function () {
'use strict'; const $ = jQuery;
const overviewWindowGlobals = {};
// Disabled in Chrome 48-, see https://github.com/SVG-Edit/svgedit/issues/26 and // Disabled in Chrome 48-, see https://github.com/SVG-Edit/svgedit/issues/26 and
// https://code.google.com/p/chromium/issues/detail?id=565120. // https://code.google.com/p/chromium/issues/detail?id=565120.
if (svgedit.browser.isChrome()) { if (svgedit.browser.isChrome()) {
var verIndex = navigator.userAgent.indexOf('Chrome/') + 7; const verIndex = navigator.userAgent.indexOf('Chrome/') + 7;
var chromeVersion = parseInt(navigator.userAgent.substring(verIndex), 10); const chromeVersion = parseInt(navigator.userAgent.substring(verIndex), 10);
if (chromeVersion < 49) { if (chromeVersion < 49) {
return; return;
} }
} }
// Define and insert the base html element. // Define and insert the base html element.
var propsWindowHtml = const propsWindowHtml =
'<div id="overview_window_content_pane" style="width:100%; word-wrap:break-word; display:inline-block; margin-top:20px;">' + '<div id="overview_window_content_pane" style="width:100%; word-wrap:break-word; display:inline-block; margin-top:20px;">' +
'<div id="overview_window_content" style="position:relative; left:12px; top:0px;">' + '<div id="overview_window_content" style="position:relative; left:12px; top:0px;">' +
'<div style="background-color:#A0A0A0; display:inline-block; overflow:visible;">' + '<div style="background-color:#A0A0A0; display:inline-block; overflow:visible;">' +
@@ -38,20 +37,20 @@ svgEditor.addExtension('overview_window', function () {
$('#sidepanels').append(propsWindowHtml); $('#sidepanels').append(propsWindowHtml);
// Define dynamic animation of the view box. // Define dynamic animation of the view box.
var updateViewBox = function () { const updateViewBox = function () {
var portHeight = parseFloat($('#workarea').css('height')); const portHeight = parseFloat($('#workarea').css('height'));
var portWidth = parseFloat($('#workarea').css('width')); const portWidth = parseFloat($('#workarea').css('width'));
var portX = $('#workarea').scrollLeft(); const portX = $('#workarea').scrollLeft();
var portY = $('#workarea').scrollTop(); const portY = $('#workarea').scrollTop();
var windowWidth = parseFloat($('#svgcanvas').css('width')); const windowWidth = parseFloat($('#svgcanvas').css('width'));
var windowHeight = parseFloat($('#svgcanvas').css('height')); const windowHeight = parseFloat($('#svgcanvas').css('height'));
var overviewWidth = $('#overviewMiniView').attr('width'); const overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height'); const overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxX = portX / windowWidth * overviewWidth; const viewBoxX = portX / windowWidth * overviewWidth;
var viewBoxY = portY / windowHeight * overviewHeight; const viewBoxY = portY / windowHeight * overviewHeight;
var viewBoxWidth = portWidth / windowWidth * overviewWidth; const viewBoxWidth = portWidth / windowWidth * overviewWidth;
var viewBoxHeight = portHeight / windowHeight * overviewHeight; const viewBoxHeight = portHeight / windowHeight * overviewHeight;
$('#overview_window_view_box').css('min-width', viewBoxWidth + 'px'); $('#overview_window_view_box').css('min-width', viewBoxWidth + 'px');
$('#overview_window_view_box').css('min-height', viewBoxHeight + 'px'); $('#overview_window_view_box').css('min-height', viewBoxHeight + 'px');
@@ -67,12 +66,12 @@ svgEditor.addExtension('overview_window', function () {
updateViewBox(); updateViewBox();
// Compensate for changes in zoom and canvas size. // Compensate for changes in zoom and canvas size.
var updateViewDimensions = function () { const updateViewDimensions = function () {
var viewWidth = $('#svgroot').attr('width'); const viewWidth = $('#svgroot').attr('width');
var viewHeight = $('#svgroot').attr('height'); const viewHeight = $('#svgroot').attr('height');
var viewX = 640;
var viewY = 480;
let viewX = 640;
let viewY = 480;
if (svgedit.browser.isIE()) { if (svgedit.browser.isIE()) {
// This has only been tested with Firefox 10 and IE 9 (without chrome frame). // This has only been tested with Firefox 10 and IE 9 (without chrome frame).
// I am not sure if if is Firefox or IE that is being non compliant here. // I am not sure if if is Firefox or IE that is being non compliant here.
@@ -84,8 +83,8 @@ svgEditor.addExtension('overview_window', function () {
viewY = 0; viewY = 0;
} }
var svgWidthOld = $('#overviewMiniView').attr('width'); const svgWidthOld = $('#overviewMiniView').attr('width');
var svgHeightNew = viewHeight / viewWidth * svgWidthOld; const svgHeightNew = viewHeight / viewWidth * svgWidthOld;
$('#overviewMiniView').attr('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight); $('#overviewMiniView').attr('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight);
$('#overviewMiniView').attr('height', svgHeightNew); $('#overviewMiniView').attr('height', svgHeightNew);
updateViewBox(); updateViewBox();
@@ -94,16 +93,16 @@ svgEditor.addExtension('overview_window', function () {
// Set up the overview window as a controller for the view port. // Set up the overview window as a controller for the view port.
overviewWindowGlobals.viewBoxDragging = false; overviewWindowGlobals.viewBoxDragging = false;
var updateViewPortFromViewBox = function () { const updateViewPortFromViewBox = function () {
var windowWidth = parseFloat($('#svgcanvas').css('width')); const windowWidth = parseFloat($('#svgcanvas').css('width'));
var windowHeight = parseFloat($('#svgcanvas').css('height')); const windowHeight = parseFloat($('#svgcanvas').css('height'));
var overviewWidth = $('#overviewMiniView').attr('width'); const overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height'); const overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxX = parseFloat($('#overview_window_view_box').css('left')); const viewBoxX = parseFloat($('#overview_window_view_box').css('left'));
var viewBoxY = parseFloat($('#overview_window_view_box').css('top')); const viewBoxY = parseFloat($('#overview_window_view_box').css('top'));
var portX = viewBoxX / overviewWidth * windowWidth; const portX = viewBoxX / overviewWidth * windowWidth;
var portY = viewBoxY / overviewHeight * windowHeight; const portY = viewBoxY / overviewHeight * windowHeight;
$('#workarea').scrollLeft(portX); $('#workarea').scrollLeft(portX);
$('#workarea').scrollTop(portY); $('#workarea').scrollTop(portY);
@@ -111,20 +110,20 @@ svgEditor.addExtension('overview_window', function () {
$('#overview_window_view_box').draggable({ $('#overview_window_view_box').draggable({
containment: 'parent', containment: 'parent',
drag: updateViewPortFromViewBox, drag: updateViewPortFromViewBox,
start: function () { overviewWindowGlobals.viewBoxDragging = true; }, start () { overviewWindowGlobals.viewBoxDragging = true; },
stop: function () { overviewWindowGlobals.viewBoxDragging = false; } stop () { overviewWindowGlobals.viewBoxDragging = false; }
}); });
$('#overviewMiniView').click(function (evt) { $('#overviewMiniView').click(function (evt) {
// Firefox doesn't support evt.offsetX and evt.offsetY. // Firefox doesn't support evt.offsetX and evt.offsetY.
var mouseX = (evt.offsetX || evt.originalEvent.layerX); const mouseX = (evt.offsetX || evt.originalEvent.layerX);
var mouseY = (evt.offsetY || evt.originalEvent.layerY); const mouseY = (evt.offsetY || evt.originalEvent.layerY);
var overviewWidth = $('#overviewMiniView').attr('width'); const overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height'); const overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxWidth = parseFloat($('#overview_window_view_box').css('min-width')); const viewBoxWidth = parseFloat($('#overview_window_view_box').css('min-width'));
var viewBoxHeight = parseFloat($('#overview_window_view_box').css('min-height')); const viewBoxHeight = parseFloat($('#overview_window_view_box').css('min-height'));
var viewBoxX = mouseX - 0.5 * viewBoxWidth; let viewBoxX = mouseX - 0.5 * viewBoxWidth;
var viewBoxY = mouseY - 0.5 * viewBoxHeight; let viewBoxY = mouseY - 0.5 * viewBoxHeight;
// deal with constraints // deal with constraints
if (viewBoxX < 0) { if (viewBoxX < 0) {
viewBoxX = 0; viewBoxX = 0;

View File

@@ -13,7 +13,6 @@
*/ */
svgEditor.addExtension('ext-panning', function () { svgEditor.addExtension('ext-panning', function () {
'use strict';
return { return {
name: 'Extension Panning', name: 'Extension Panning',
svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml', svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml',
@@ -22,18 +21,18 @@ svgEditor.addExtension('ext-panning', function () {
type: 'mode', type: 'mode',
title: 'Panning', title: 'Panning',
events: { events: {
click: function () { click () {
svgCanvas.setMode('ext-panning'); svgCanvas.setMode('ext-panning');
} }
} }
}], }],
mouseDown: function () { mouseDown () {
if (svgCanvas.getMode() === 'ext-panning') { if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(true); svgEditor.setPanning(true);
return {started: true}; return {started: true};
} }
}, },
mouseUp: function () { mouseUp () {
if (svgCanvas.getMode() === 'ext-panning') { if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(false); svgEditor.setPanning(false);
return { return {

View File

@@ -1,22 +1,21 @@
/* eslint-disable no-var */ /* globals jQuery, svgCanvas, svgEditor */
/* globals $, svgCanvas, svgEditor */
// TODO: Might add support for "exportImage" custom // TODO: Might add support for "exportImage" custom
// handler as in "ext-server_opensave.js" (and in savefile.php) // handler as in "ext-server_opensave.js" (and in savefile.php)
svgEditor.addExtension('php_savefile', { svgEditor.addExtension('php_savefile', {
callback: function () { callback () {
'use strict'; const $ = jQuery;
function getFileNameFromTitle () { function getFileNameFromTitle () {
var title = svgCanvas.getDocumentTitle(); const title = svgCanvas.getDocumentTitle();
return $.trim(title); return title.trim();
} }
var saveSvgAction = svgEditor.curConfig.extPath + 'savefile.php'; const saveSvgAction = svgEditor.curConfig.extPath + 'savefile.php';
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function (win, data) { save (win, data) {
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, const svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,
filename = getFileNameFromTitle(); filename = getFileNameFromTitle();
$.post(saveSvgAction, {output_svg: svg, filename: filename}); $.post(saveSvgAction, {output_svg: svg, filename});
} }
}); });
} }

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgCanvas */
/* globals svgEditor, svgCanvas, $ */
/* /*
* ext-polygon.js * ext-polygon.js
* *
@@ -9,35 +8,33 @@
* *
*/ */
svgEditor.addExtension('polygon', function (S) { svgEditor.addExtension('polygon', function (S) {
'use strict'; const $ = jQuery;
const // {svgcontent} = S,
var // NS = svgedit.NS,
// svgcontent = S.svgcontent,
// addElem = S.addSvgElementFromJson, // addElem = S.addSvgElementFromJson,
selElems, editingitex = false;
editingitex = false, let selElems,
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG, // newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
// edg = 0, // edg = 0,
// undoCommand = 'Not image'; // undoCommand = 'Not image';
started, newFO; started, newFO;
// var ccZoom; // const ccZoom;
// var wEl, hEl; // const wEl, hEl;
// var wOffset, hOffset; // const wOffset, hOffset;
// var ccRBG; // const ccRBG;
// var ccOpacity; // const ccOpacity;
// var brushW, brushH; // const brushW, brushH;
// var ccDebug = document.getElementById('debugpanel'); // const ccDebug = document.getElementById('debugpanel');
/* var 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
var height = $('#svg_source_container').height() - 80; const height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height); $('#svg_source_textarea').css('height', height);
}; */ }; */
function showPanel (on) { function showPanel (on) {
var fcRules = $('#fc_rules'); let fcRules = $('#fc_rules');
if (!fcRules.length) { if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
} }
@@ -74,25 +71,25 @@ svgEditor.addExtension('polygon', function (S) {
*/ */
/* /*
function setItexString(tex) { function setItexString(tex) {
var mathns = 'http://www.w3.org/1998/Math/MathML', const mathns = 'http://www.w3.org/1998/Math/MathML',
xmlnsns = 'http://www.w3.org/2000/xmlns/', xmlnsns = 'http://www.w3.org/2000/xmlns/',
ajaxEndpoint = '../../itex'; ajaxEndpoint = '../../itex';
var elt = selElems[0]; const elt = selElems[0];
try { try {
var math = svgdoc.createElementNS(mathns, 'math'); const math = svgdoc.createElementNS(mathns, 'math');
math.setAttributeNS(xmlnsns, 'xmlns', mathns); math.setAttributeNS(xmlnsns, 'xmlns', mathns);
math.setAttribute('display', 'inline'); math.setAttribute('display', 'inline');
var semantics = document.createElementNS(mathns, 'semantics'); const semantics = document.createElementNS(mathns, 'semantics');
var annotation = document.createElementNS(mathns, 'annotation'); const annotation = document.createElementNS(mathns, 'annotation');
annotation.setAttribute('encoding', 'application/x-tex'); annotation.setAttribute('encoding', 'application/x-tex');
annotation.textContent = tex; annotation.textContent = tex;
var mrow = document.createElementNS(mathns, 'mrow'); const mrow = document.createElementNS(mathns, 'mrow');
semantics.appendChild(mrow); semantics.appendChild(mrow);
semantics.appendChild(annotation); semantics.appendChild(annotation);
math.appendChild(semantics); math.appendChild(semantics);
// make an AJAX request to the server, to get the MathML // make an AJAX request to the server, to get the MathML
$.post(ajaxEndpoint, {'tex': tex, 'display': 'inline'}, function(data){ $.post(ajaxEndpoint, {tex, 'display': 'inline'}, function(data){
var children = data.documentElement.childNodes; const children = data.documentElement.childNodes;
while (children.length > 0) { while (children.length > 0) {
mrow.appendChild(svgdoc.adoptNode(children[0], true)); mrow.appendChild(svgdoc.adoptNode(children[0], true));
} }
@@ -119,7 +116,7 @@ svgEditor.addExtension('polygon', function (S) {
title: 'Polygon Tool', title: 'Polygon Tool',
position: 11, position: 11,
events: { events: {
'click': function () { click () {
svgCanvas.setMode('polygon'); svgCanvas.setMode('polygon');
showPanel(true); showPanel(true);
} }
@@ -135,22 +132,22 @@ svgEditor.addExtension('polygon', function (S) {
size: 3, size: 3,
defval: 5, defval: 5,
events: { events: {
change: function () { change () {
setAttr('sides', this.value); setAttr('sides', this.value);
} }
} }
}], }],
callback: function () { callback () {
$('#polygon_panel').hide(); $('#polygon_panel').hide();
var endChanges = function () { const endChanges = function () {
}; };
// TODO: Needs to be done after orig icon loads // TODO: Needs to be done after orig icon loads
setTimeout(function () { setTimeout(function () {
// Create source save/cancel buttons // Create source save/cancel buttons
/* var save = */ $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo('#tool_source_back').click(function () { /* const save = */ $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo('#tool_source_back').click(function () {
if (!editingitex) { if (!editingitex) {
return; return;
} }
@@ -169,18 +166,18 @@ svgEditor.addExtension('polygon', function (S) {
// setSelectMode(); // setSelectMode();
}); });
/* var cancel = */ $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo('#tool_source_back').click(function () { /* const cancel = */ $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo('#tool_source_back').click(function () {
endChanges(); endChanges();
}); });
}, 3000); }, 3000);
}, },
mouseDown: function (opts) { mouseDown (opts) {
// var e = opts.event; // const e = opts.event;
var rgb = svgCanvas.getColor('fill'); const rgb = svgCanvas.getColor('fill');
// var ccRgbEl = rgb.substring(1, rgb.length); // const ccRgbEl = rgb.substring(1, rgb.length);
var sRgb = svgCanvas.getColor('stroke'); const sRgb = svgCanvas.getColor('stroke');
// ccSRgbEl = sRgb.substring(1, rgb.length); // ccSRgbEl = sRgb.substring(1, rgb.length);
var sWidth = svgCanvas.getStrokeWidth(); const sWidth = svgCanvas.getStrokeWidth();
if (svgCanvas.getMode() === 'polygon') { if (svgCanvas.getMode() === 'polygon') {
started = true; started = true;
@@ -206,39 +203,37 @@ svgEditor.addExtension('polygon', function (S) {
}; };
} }
}, },
mouseMove: function (opts) { mouseMove (opts) {
if (!started) { if (!started) {
return; return;
} }
if (svgCanvas.getMode() === 'polygon') { if (svgCanvas.getMode() === 'polygon') {
// var e = opts.event; // const e = opts.event;
var x = opts.mouse_x; const c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']);
var y = opts.mouse_y; let x = opts.mouse_x;
var c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']); let y = opts.mouse_y;
var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, sides = c.sides, const {cx, cy, fill, strokecolor, strokeWidth, sides} = c, // {orient} = c,
// orient = c.orient,
edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5; edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
newFO.setAttributeNS(null, 'edge', edg); newFO.setAttributeNS(null, 'edge', edg);
var inradius = (edg / 2) * cot(Math.PI / sides); const inradius = (edg / 2) * cot(Math.PI / sides);
var circumradius = inradius * sec(Math.PI / sides); const circumradius = inradius * sec(Math.PI / sides);
var points = ''; let points = '';
var s; for (let s = 0; sides >= s; s++) {
for (s = 0; sides >= s; s++) { const angle = 2.0 * Math.PI * s / sides;
var angle = 2.0 * Math.PI * s / sides;
x = (circumradius * Math.cos(angle)) + cx; x = (circumradius * Math.cos(angle)) + cx;
y = (circumradius * Math.sin(angle)) + cy; y = (circumradius * Math.sin(angle)) + cy;
points += x + ',' + y + ' '; points += x + ',' + y + ' ';
} }
// var poly = newFO.createElementNS(NS.SVG, 'polygon'); // const poly = newFO.createElementNS(NS.SVG, 'polygon');
newFO.setAttributeNS(null, 'points', points); newFO.setAttributeNS(null, 'points', points);
newFO.setAttributeNS(null, 'fill', fill); newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor); newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokewidth); newFO.setAttributeNS(null, 'stroke-width', strokeWidth);
// newFO.setAttributeNS(null, 'transform', 'rotate(-90)'); // newFO.setAttributeNS(null, 'transform', 'rotate(-90)');
// var shape = newFO.getAttributeNS(null, 'shape'); // const shape = newFO.getAttributeNS(null, 'shape');
// newFO.appendChild(poly); // newFO.appendChild(poly);
// DrawPoly(cx, cy, sides, edg, orient); // DrawPoly(cx, cy, sides, edg, orient);
return { return {
@@ -247,25 +242,24 @@ svgEditor.addExtension('polygon', function (S) {
} }
}, },
mouseUp: function (opts) { mouseUp (opts) {
if (svgCanvas.getMode() === 'polygon') { if (svgCanvas.getMode() === 'polygon') {
var attrs = $(newFO).attr('edge'); const attrs = $(newFO).attr('edge');
var keep = (attrs.edge !== '0'); const keep = (attrs.edge !== '0');
// svgCanvas.addToSelection([newFO], true); // svgCanvas.addToSelection([newFO], true);
return { return {
keep: keep, keep,
element: newFO element: newFO
}; };
} }
}, },
selectedChanged: function (opts) { selectedChanged (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; let i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; const elem = selElems[i];
if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') { if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
$('#polySides').val(elem.getAttribute('sides')); $('#polySides').val(elem.getAttribute('sides'));
@@ -279,8 +273,8 @@ svgEditor.addExtension('polygon', function (S) {
} }
} }
}, },
elementChanged: function (opts) { elementChanged (opts) {
// var elem = opts.elems[0]; // const elem = opts.elems[0];
} }
}; };
}); });

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgedit, svgCanvas, canvg */
/* globals svgEditor, svgedit, svgCanvas, canvg, $, top */
/* /*
* ext-server_moinsave.js * ext-server_moinsave.js
* *
@@ -13,32 +12,32 @@
*/ */
svgEditor.addExtension('server_opensave', { svgEditor.addExtension('server_opensave', {
callback: function () { callback () {
'use strict'; const $ = jQuery;
var Utils = svgedit.utilities; const Utils = svgedit.utilities;
var saveSvgAction = '/+modify'; const saveSvgAction = '/+modify';
// Create upload target (hidden iframe) // Create upload target (hidden iframe)
/* var target = */ $('<iframe name="output_frame" src="#"/>').hide().appendTo('body'); /* const target = */ $('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function (win, data) { save (win, data) {
var svg = '<?xml version="1.0"?>\n' + data; const svg = '<?xml version="1.0"?>\n' + data;
var qstr = $.param.querystring(); const qstr = $.param.querystring();
var name = qstr.substr(9).split('/+get/')[1]; const name = qstr.substr(9).split('/+get/')[1];
var svgData = Utils.encode64(svg); const svgData = Utils.encode64(svg);
if (!$('#export_canvas').length) { if (!$('#export_canvas').length) {
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body'); $('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
} }
var c = $('#export_canvas')[0]; const c = $('#export_canvas')[0];
c.width = svgCanvas.contentW; c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH; c.height = svgCanvas.contentH;
Utils.buildCanvgCallback(function () { Utils.buildCanvgCallback(function () {
canvg(c, svg, {renderCallback: function () { canvg(c, svg, {renderCallback () {
var datauri = c.toDataURL('image/png'); const datauri = c.toDataURL('image/png');
// var uiStrings = svgEditor.uiStrings; // const {uiStrings} = svgEditor;
var pngData = Utils.encode64(datauri); // Brett: This encoding seems unnecessary const pngData = Utils.encode64(datauri); // Brett: This encoding seems unnecessary
/* var form = */ $('<form>').attr({ /* const form = */ $('<form>').attr({
method: 'post', method: 'post',
action: saveSvgAction + '/' + name, action: saveSvgAction + '/' + name,
target: 'output_frame' target: 'output_frame'

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgedit, svgCanvas, canvg */
/* globals svgEditor, svgedit, svgCanvas, canvg, $ */
/* /*
* ext-server_opensave.js * ext-server_opensave.js
* *
@@ -10,37 +9,36 @@
*/ */
svgEditor.addExtension('server_opensave', { svgEditor.addExtension('server_opensave', {
callback: function () { callback () {
'use strict'; const $ = jQuery;
function getFileNameFromTitle () { function getFileNameFromTitle () {
var title = svgCanvas.getDocumentTitle(); const title = svgCanvas.getDocumentTitle();
// We convert (to underscore) only those disallowed Win7 file name characters // We convert (to underscore) only those disallowed Win7 file name characters
return $.trim(title).replace(/[/\\:*?"<>|]/g, '_'); return title.trim().replace(/[/\\:*?"<>|]/g, '_');
} }
function xhtmlEscape (str) { function xhtmlEscape (str) {
return str.replace(/&(?!amp;)/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;'); // < is actually disallowed above anyways return str.replace(/&(?!amp;)/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;'); // < is actually disallowed above anyways
} }
function clientDownloadSupport (filename, suffix, uri) { function clientDownloadSupport (filename, suffix, uri) {
var a, const support = $('<a>')[0].download === '';
support = $('<a>')[0].download === ''; let a;
if (support) { if (support) {
a = $('<a>hidden</a>').attr({download: (filename || 'image') + suffix, href: uri}).css('display', 'none').appendTo('body'); a = $('<a>hidden</a>').attr({download: (filename || 'image') + suffix, href: uri}).css('display', 'none').appendTo('body');
a[0].click(); a[0].click();
return true; return true;
} }
} }
var openSvgAction, importSvgAction, importImgAction, const
openSvgForm, importSvgForm, importImgForm,
saveSvgAction = svgEditor.curConfig.extPath + 'filesave.php', saveSvgAction = svgEditor.curConfig.extPath + 'filesave.php',
saveImgAction = svgEditor.curConfig.extPath + 'filesave.php', saveImgAction = svgEditor.curConfig.extPath + 'filesave.php',
// Create upload target (hidden iframe) // Create upload target (hidden iframe)
cancelled = false,
Utils = svgedit.utilities; Utils = svgedit.utilities;
let cancelled = false;
$('<iframe name="output_frame" src="#"/>').hide().appendTo('body'); $('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function (win, data) { save (win, data) {
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works const svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works
filename = getFileNameFromTitle(); filename = getFileNameFromTitle();
if (clientDownloadSupport(filename, '.svg', 'data:image/svg+xml;charset=UTF-8;base64,' + Utils.encode64(svg))) { if (clientDownloadSupport(filename, '.svg', 'data:image/svg+xml;charset=UTF-8;base64,' + Utils.encode64(svg))) {
@@ -56,8 +54,8 @@ svgEditor.addExtension('server_opensave', {
.appendTo('body') .appendTo('body')
.submit().remove(); .submit().remove();
}, },
exportPDF: function (win, data) { exportPDF (win, data) {
var filename = getFileNameFromTitle(), const filename = getFileNameFromTitle(),
datauri = data.dataurlstring; datauri = data.dataurlstring;
if (clientDownloadSupport(filename, '.pdf', datauri)) { if (clientDownloadSupport(filename, '.pdf', datauri)) {
return; return;
@@ -73,27 +71,23 @@ svgEditor.addExtension('server_opensave', {
.submit().remove(); .submit().remove();
}, },
// Todo: Integrate this extension with a new built-in exportWindowType, "download" // Todo: Integrate this extension with a new built-in exportWindowType, "download"
exportImage: function (win, data) { exportImage (win, data) {
var c, const {issues, mimeType, quality} = data;
issues = data.issues,
mimeType = data.mimeType,
quality = data.quality;
if (!$('#export_canvas').length) { if (!$('#export_canvas').length) {
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body'); $('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
} }
c = $('#export_canvas')[0]; const c = $('#export_canvas')[0];
c.width = svgCanvas.contentW; c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH; c.height = svgCanvas.contentH;
Utils.buildCanvgCallback(function () { Utils.buildCanvgCallback(function () {
canvg(c, data.svg, {renderCallback: function () { canvg(c, data.svg, {renderCallback () {
var pre, filename, suffix, const datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType);
datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType), // {uiStrings} = svgEditor;
// uiStrings = svgEditor.uiStrings,
note = '';
// Check if there are issues // Check if there are issues
let pre, note = '';
if (issues.length) { if (issues.length) {
pre = '\n \u2022 '; pre = '\n \u2022 ';
note += ('\n\n' + pre + issues.join(pre)); note += ('\n\n' + pre + issues.join(pre));
@@ -103,8 +97,8 @@ svgEditor.addExtension('server_opensave', {
alert(note); alert(note);
} }
filename = getFileNameFromTitle(); const filename = getFileNameFromTitle();
suffix = '.' + data.type.toLowerCase(); const suffix = '.' + data.type.toLowerCase();
if (clientDownloadSupport(filename, suffix, datauri)) { if (clientDownloadSupport(filename, suffix, datauri)) {
return; return;
@@ -128,13 +122,13 @@ svgEditor.addExtension('server_opensave', {
if (window.FileReader) { return; } if (window.FileReader) { return; }
// Change these to appropriate script file // Change these to appropriate script file
openSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg'; const openSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg';
importSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg'; const importSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg';
importImgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img'; const importImgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img';
// Set up function for PHP uploader to use // Set up function for PHP uploader to use
svgEditor.processFile = function (str64, type) { svgEditor.processFile = function (str64, type) {
var xmlstr; let xmlstr;
if (cancelled) { if (cancelled) {
cancelled = false; cancelled = false;
return; return;
@@ -163,7 +157,7 @@ svgEditor.addExtension('server_opensave', {
}; };
// Create upload form // Create upload form
openSvgForm = $('<form>'); const openSvgForm = $('<form>');
openSvgForm.attr({ openSvgForm.attr({
enctype: 'multipart/form-data', enctype: 'multipart/form-data',
method: 'post', method: 'post',
@@ -172,16 +166,16 @@ svgEditor.addExtension('server_opensave', {
}); });
// Create import form // Create import form
importSvgForm = openSvgForm.clone().attr('action', importSvgAction); const importSvgForm = openSvgForm.clone().attr('action', importSvgAction);
// Create image form // Create image form
importImgForm = openSvgForm.clone().attr('action', importImgAction); const importImgForm = openSvgForm.clone().attr('action', importImgAction);
// It appears necessary to rebuild this input every time a file is // It appears necessary to rebuild this input every time a file is
// selected so the same file can be picked and the change event can fire. // selected so the same file can be picked and the change event can fire.
function rebuildInput (form) { function rebuildInput (form) {
form.empty(); form.empty();
var inp = $('<input type="file" name="svg_file">').appendTo(form); const inp = $('<input type="file" name="svg_file">').appendTo(form);
function submit () { function submit () {
// This submits the form, which returns the file data using svgEditor.processFile() // This submits the form, which returns the file data using svgEditor.processFile()

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor */
/* globals svgEditor, $, DOMParser */
/* /*
* ext-shapes.js * ext-shapes.js
* *
@@ -11,16 +10,13 @@
*/ */
svgEditor.addExtension('shapes', function () { svgEditor.addExtension('shapes', function () {
'use strict'; const $ = jQuery;
var currentD, curShapeId; const canv = svgEditor.canvas;
var canv = svgEditor.canvas; const svgroot = canv.getRootElem();
var curShape; let lastBBox = {};
var startX, startY;
var svgroot = canv.getRootElem();
var lastBBox = {};
// This populates the category list // This populates the category list
var categories = { const categories = {
basic: 'Basic', basic: 'Basic',
object: 'Objects', object: 'Objects',
symbol: 'Symbols', symbol: 'Symbols',
@@ -37,7 +33,7 @@ svgEditor.addExtension('shapes', function () {
raphael_2: 'raphaeljs.com set 2' raphael_2: 'raphaeljs.com set 2'
}; };
var library = { const library = {
basic: { basic: {
data: { data: {
'heart': 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z', 'heart': 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z',
@@ -74,40 +70,41 @@ svgEditor.addExtension('shapes', function () {
} }
}; };
var curLib = library.basic; const modeId = 'shapelib';
var modeId = 'shapelib'; const startClientPos = {};
var startClientPos = {};
let currentD, curShapeId, curShape, startX, startY;
let curLib = library.basic;
function loadIcons () { function loadIcons () {
$('#shape_buttons').empty().append(curLib.buttons); $('#shape_buttons').empty().append(curLib.buttons);
} }
function makeButtons (cat, shapes) { function makeButtons (cat, shapes) {
var size = curLib.size || 300; const size = curLib.size || 300;
var fill = curLib.fill || false; const fill = curLib.fill || false;
var off = size * 0.05; const off = size * 0.05;
var vb = [-off, -off, size + off * 2, size + off * 2].join(' '); const vb = [-off, -off, size + off * 2, size + off * 2].join(' ');
var stroke = fill ? 0 : (size / 30); const stroke = fill ? 0 : (size / 30);
var shapeIcon = new DOMParser().parseFromString( const shapeIcon = new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="' + (fill ? '#333' : 'none') + '" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>', '<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="' + (fill ? '#333' : 'none') + '" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>',
'text/xml'); 'text/xml');
var width = 24; const width = 24;
var height = 24; const height = 24;
shapeIcon.documentElement.setAttribute('width', width); shapeIcon.documentElement.setAttribute('width', width);
shapeIcon.documentElement.setAttribute('height', height); shapeIcon.documentElement.setAttribute('height', height);
var svgElem = $(document.importNode(shapeIcon.documentElement, true)); const svgElem = $(document.importNode(shapeIcon.documentElement, true));
var data = shapes.data; const {data} = shapes;
curLib.buttons = []; curLib.buttons = [];
var id; for (const id in data) {
for (id in data) { const pathD = data[id];
var pathD = data[id]; const icon = svgElem.clone();
var icon = svgElem.clone();
icon.find('path').attr('d', pathD); icon.find('path').attr('d', pathD);
var iconBtn = icon.wrap('<div class="tool_button">').parent().attr({ const iconBtn = icon.wrap('<div class="tool_button">').parent().attr({
id: modeId + '_' + id, id: modeId + '_' + id,
title: id title: id
}); });
@@ -117,7 +114,7 @@ svgEditor.addExtension('shapes', function () {
} }
function loadLibrary (catId) { function loadLibrary (catId) {
var lib = library[catId]; const lib = library[catId];
if (!lib) { if (!lib) {
$('#shape_buttons').html('Loading...'); $('#shape_buttons').html('Loading...');
@@ -145,12 +142,12 @@ svgEditor.addExtension('shapes', function () {
position: 6, position: 6,
title: 'Shape library', title: 'Shape library',
events: { events: {
click: function () { click () {
canv.setMode(modeId); canv.setMode(modeId);
} }
} }
}], }],
callback: function () { callback () {
$('<style>').text( $('<style>').text(
'#shape_buttons {' + '#shape_buttons {' +
'overflow: auto;' + 'overflow: auto;' +
@@ -179,20 +176,20 @@ svgEditor.addExtension('shapes', function () {
'font-weight: bold;' + 'font-weight: bold;' +
'}').appendTo('head'); '}').appendTo('head');
var btnDiv = $('<div id="shape_buttons">'); const btnDiv = $('<div id="shape_buttons">');
$('#tools_shapelib > *').wrapAll(btnDiv); $('#tools_shapelib > *').wrapAll(btnDiv);
var shower = $('#tools_shapelib_show'); const shower = $('#tools_shapelib_show');
loadLibrary('basic'); loadLibrary('basic');
// Do mouseup on parent element rather than each button // Do mouseup on parent element rather than each button
$('#shape_buttons').mouseup(function (evt) { $('#shape_buttons').mouseup(function (evt) {
var btn = $(evt.target).closest('div.tool_button'); const btn = $(evt.target).closest('div.tool_button');
if (!btn.length) { return; } if (!btn.length) { return; }
var copy = btn.children().clone(); const copy = btn.children().clone();
shower.children(':not(.flyout_arrow_horiz)').remove(); shower.children(':not(.flyout_arrow_horiz)').remove();
shower shower
.append(copy) .append(copy)
@@ -206,15 +203,15 @@ svgEditor.addExtension('shapes', function () {
$('.tools_flyout').fadeOut(); $('.tools_flyout').fadeOut();
}); });
var shapeCats = $('<div id="shape_cats">'); const shapeCats = $('<div id="shape_cats">');
var catStr = '';
let catStr = '';
$.each(categories, function (id, label) { $.each(categories, function (id, label) {
catStr += '<div data-cat=' + id + '>' + label + '</div>'; catStr += '<div data-cat=' + id + '>' + label + '</div>';
}); });
shapeCats.html(catStr).children().bind('mouseup', function () { shapeCats.html(catStr).children().bind('mouseup', function () {
var catlink = $(this); const catlink = $(this);
catlink.siblings().removeClass('current'); catlink.siblings().removeClass('current');
catlink.addClass('current'); catlink.addClass('current');
@@ -232,21 +229,21 @@ svgEditor.addExtension('shapes', function () {
}); });
$('#tool_shapelib').remove(); $('#tool_shapelib').remove();
var h = $('#tools_shapelib').height(); const h = $('#tools_shapelib').height();
$('#tools_shapelib').css({ $('#tools_shapelib').css({
'margin-top': -(h / 2 - 15), 'margin-top': -(h / 2 - 15),
'margin-left': 3 'margin-left': 3
}); });
}, },
mouseDown: function (opts) { mouseDown (opts) {
var mode = canv.getMode(); const mode = canv.getMode();
if (mode !== modeId) { return; } if (mode !== modeId) { return; }
startX = opts.start_x; startX = opts.start_x;
var x = startX; const x = startX;
startY = opts.start_y; startY = opts.start_y;
var y = startY; const y = startY;
var curStyle = canv.getStyle(); const curStyle = canv.getStyle();
startClientPos.x = opts.event.clientX; startClientPos.x = opts.event.clientX;
startClientPos.y = opts.event.clientY; startClientPos.y = opts.event.clientY;
@@ -272,7 +269,7 @@ svgEditor.addExtension('shapes', function () {
canv.recalculateDimensions(curShape); canv.recalculateDimensions(curShape);
/* var tlist = */ canv.getTransformList(curShape); /* const tlist = */ canv.getTransformList(curShape);
lastBBox = curShape.getBBox(); lastBBox = curShape.getBBox();
@@ -280,50 +277,56 @@ svgEditor.addExtension('shapes', function () {
started: true started: true
}; };
}, },
mouseMove: function (opts) { mouseMove (opts) {
var mode = canv.getMode(); const mode = canv.getMode();
if (mode !== modeId) { return; } if (mode !== modeId) { return; }
var zoom = canv.getZoom(); const zoom = canv.getZoom();
var evt = opts.event; const evt = opts.event;
var x = opts.mouse_x / zoom; const x = opts.mouse_x / zoom;
var y = opts.mouse_y / zoom; const y = opts.mouse_y / zoom;
var tlist = canv.getTransformList(curShape), const tlist = canv.getTransformList(curShape),
box = curShape.getBBox(), box = curShape.getBBox(),
left = box.x, top = box.y, width = box.width, left = box.x, top = box.y;
height = box.height; // {width, height} = box,
var dx = (x - startX), dy = (y - startY); // const dx = (x - startX), dy = (y - startY);
var newbox = { const newbox = {
'x': Math.min(startX, x), 'x': Math.min(startX, x),
'y': Math.min(startY, y), 'y': Math.min(startY, y),
'width': Math.abs(x - startX), 'width': Math.abs(x - startX),
'height': Math.abs(y - startY) 'height': Math.abs(y - startY)
}; };
var tx = 0, ty = 0, /*
sy = height ? (height + dy) / height : 1, // This is currently serving no purpose, so commenting out
let sy = height ? (height + dy) / height : 1,
sx = width ? (width + dx) / width : 1; sx = width ? (width + dx) / width : 1;
*/
sx = (newbox.width / lastBBox.width) || 1; let sx = (newbox.width / lastBBox.width) || 1;
sy = (newbox.height / lastBBox.height) || 1; let sy = (newbox.height / lastBBox.height) || 1;
// Not perfect, but mostly works... // Not perfect, but mostly works...
let tx = 0;
if (x < startX) { if (x < startX) {
tx = lastBBox.width; tx = lastBBox.width;
} }
if (y < startY) { ty = lastBBox.height; } let ty = 0;
if (y < startY) {
ty = lastBBox.height;
}
// update the transform list with translate,scale,translate // update the transform list with translate,scale,translate
var translateOrigin = svgroot.createSVGTransform(), const translateOrigin = svgroot.createSVGTransform(),
scale = svgroot.createSVGTransform(), scale = svgroot.createSVGTransform(),
translateBack = svgroot.createSVGTransform(); translateBack = svgroot.createSVGTransform();
translateOrigin.setTranslate(-(left + tx), -(top + ty)); translateOrigin.setTranslate(-(left + tx), -(top + ty));
if (!evt.shiftKey) { if (!evt.shiftKey) {
var max = Math.min(Math.abs(sx), Math.abs(sy)); const max = Math.min(Math.abs(sx), Math.abs(sy));
sx = max * (sx < 0 ? -1 : 1); sx = max * (sx < 0 ? -1 : 1);
sy = max * (sy < 0 ? -1 : 1); sy = max * (sy < 0 ? -1 : 1);
@@ -339,11 +342,11 @@ svgEditor.addExtension('shapes', function () {
lastBBox = curShape.getBBox(); lastBBox = curShape.getBBox();
}, },
mouseUp: function (opts) { mouseUp (opts) {
var mode = canv.getMode(); const mode = canv.getMode();
if (mode !== modeId) { return; } if (mode !== modeId) { return; }
var keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y); const keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y);
return { return {
keep: keepObject, keep: keepObject,

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgCanvas */
/* globals svgEditor, svgCanvas, $ */
/* /*
* ext-star.js * ext-star.js
* *
@@ -10,10 +9,8 @@
*/ */
svgEditor.addExtension('star', function (S) { svgEditor.addExtension('star', function (S) {
'use strict'; const $ = jQuery;
let // {svgcontent} = S,
var // NS = svgedit.NS,
// svgcontent = S.svgcontent,
selElems, selElems,
// editingitex = false, // editingitex = false,
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
@@ -25,7 +22,7 @@ svgEditor.addExtension('star', function (S) {
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH; // modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
function showPanel (on) { function showPanel (on) {
var fcRules = $('#fc_rules'); let fcRules = $('#fc_rules');
if (!fcRules.length) { if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
} }
@@ -63,7 +60,7 @@ svgEditor.addExtension('star', function (S) {
title: 'Star Tool', title: 'Star Tool',
position: 12, position: 12,
events: { events: {
click: function () { click () {
showPanel(true); showPanel(true);
svgCanvas.setMode('star'); svgCanvas.setMode('star');
} }
@@ -79,7 +76,7 @@ svgEditor.addExtension('star', function (S) {
size: 3, size: 3,
defval: 5, defval: 5,
events: { events: {
change: function () { change () {
setAttr('point', this.value); setAttr('point', this.value);
} }
} }
@@ -100,21 +97,21 @@ svgEditor.addExtension('star', function (S) {
size: 3, size: 3,
defval: 0, defval: 0,
events: { events: {
change: function () { change () {
setAttr('radialshift', this.value); setAttr('radialshift', this.value);
} }
} }
}], }],
callback: function () { callback () {
$('#star_panel').hide(); $('#star_panel').hide();
// var endChanges = function(){}; // const endChanges = function(){};
}, },
mouseDown: function (opts) { mouseDown (opts) {
var rgb = svgCanvas.getColor('fill'); const rgb = svgCanvas.getColor('fill');
// var ccRgbEl = rgb.substring(1, rgb.length); // const ccRgbEl = rgb.substring(1, rgb.length);
var sRgb = svgCanvas.getColor('stroke'); const sRgb = svgCanvas.getColor('stroke');
// var ccSRgbEl = sRgb.substring(1, rgb.length); // const ccSRgbEl = sRgb.substring(1, rgb.length);
var sWidth = svgCanvas.getStrokeWidth(); const sWidth = svgCanvas.getStrokeWidth();
if (svgCanvas.getMode() === 'star') { if (svgCanvas.getMode() === 'star') {
started = true; started = true;
@@ -141,23 +138,24 @@ svgEditor.addExtension('star', function (S) {
}; };
} }
}, },
mouseMove: function (opts) { mouseMove (opts) {
if (!started) { if (!started) {
return; return;
} }
if (svgCanvas.getMode() === 'star') { if (svgCanvas.getMode() === 'star') {
var x = opts.mouse_x; const c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
var y = opts.mouse_y;
var c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, radialShift = c.radialshift, point = c.point, orient = c.orient, circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5, inradius = circumradius / document.getElementById('starRadiusMulitplier').value; let x = opts.mouse_x;
let y = opts.mouse_y;
const {cx, cy, fill, strokecolor, strokeWidth, radialShift, point, orient} = c,
circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5,
inradius = circumradius / document.getElementById('starRadiusMulitplier').value;
newFO.setAttributeNS(null, 'r', circumradius); newFO.setAttributeNS(null, 'r', circumradius);
newFO.setAttributeNS(null, 'r2', inradius); newFO.setAttributeNS(null, 'r2', inradius);
var polyPoints = ''; let polyPoints = '';
var s; for (let s = 0; point >= s; s++) {
for (s = 0; point >= s; s++) { let angle = 2.0 * Math.PI * (s / point);
var angle = 2.0 * Math.PI * (s / point);
if (orient === 'point') { if (orient === 'point') {
angle -= (Math.PI / 2); angle -= (Math.PI / 2);
} else if (orient === 'edge') { } else if (orient === 'edge') {
@@ -187,17 +185,17 @@ svgEditor.addExtension('star', function (S) {
newFO.setAttributeNS(null, 'points', polyPoints); newFO.setAttributeNS(null, 'points', polyPoints);
newFO.setAttributeNS(null, 'fill', fill); newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor); newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokewidth); newFO.setAttributeNS(null, 'stroke-width', strokeWidth);
/* var shape = */ newFO.getAttributeNS(null, 'shape'); /* const shape = */ newFO.getAttributeNS(null, 'shape');
return { return {
started: true started: true
}; };
} }
}, },
mouseUp: function () { mouseUp () {
if (svgCanvas.getMode() === 'star') { if (svgCanvas.getMode() === 'star') {
var attrs = $(newFO).attr(['r']); const attrs = $(newFO).attr(['r']);
// svgCanvas.addToSelection([newFO], true); // svgCanvas.addToSelection([newFO], true);
return { return {
keep: (attrs.r !== '0'), keep: (attrs.r !== '0'),
@@ -205,14 +203,13 @@ svgEditor.addExtension('star', function (S) {
}; };
} }
}, },
selectedChanged: function (opts) { selectedChanged (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; let i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; const elem = selElems[i];
if (elem && elem.getAttributeNS(null, 'shape') === 'star') { if (elem && elem.getAttributeNS(null, 'shape') === 'star') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
// $('#starRadiusMulitplier').val(elem.getAttribute('r2')); // $('#starRadiusMulitplier').val(elem.getAttribute('r2'));
@@ -227,8 +224,8 @@ svgEditor.addExtension('star', function (S) {
} }
} }
}, },
elementChanged: function (opts) { elementChanged (opts) {
// var elem = opts.elems[0]; // const elem = opts.elems[0];
} }
}; };
}); });

View File

@@ -1,5 +1,4 @@
/* eslint-disable no-var */ /* globals jQuery, svgEditor, svgCanvas */
/* globals svgEditor, svgCanvas, $, widget */
/* /*
* ext-storage.js * ext-storage.js
* *
@@ -17,7 +16,11 @@
* separate extension to make the setting behavior optional, and adapted * separate extension to make the setting behavior optional, and adapted
* to inform the user of its setting of local data. * to inform the user of its setting of local data.
*/ */
/*
Dependencies:
1. jQuery BBQ (for deparam)
*/
/* /*
TODOS TODOS
1. Revisit on whether to use $.pref over directly setting curConfig in all 1. Revisit on whether to use $.pref over directly setting curConfig in all
@@ -26,13 +29,17 @@ TODOS
2. We might provide control of storage settings through the UI besides the 2. We might provide control of storage settings through the UI besides the
initial (or URL-forced) dialog. initial (or URL-forced) dialog.
*/ */
import confirmSetStorage from './ext-locale/storage.js';
svgEditor.addExtension('storage', function () { svgEditor.addExtension('storage', function () {
const $ = jQuery;
// We could empty any already-set data for users when they decline storage, // We could empty any already-set data for users when they decline storage,
// but it would be a risk for users who wanted to store but accidentally // but it would be a risk for users who wanted to store but accidentally
// said "no"; instead, we'll let those who already set it, delete it themselves; // said "no"; instead, we'll let those who already set it, delete it themselves;
// to change, set the "emptyStorageOnDecline" config setting to true // to change, set the "emptyStorageOnDecline" config setting to true
// in config.js. // in config.js.
var emptyStorageOnDecline = svgEditor.curConfig.emptyStorageOnDecline, const {
emptyStorageOnDecline,
// When the code in svg-editor.js prevents local storage on load per // When the code in svg-editor.js prevents local storage on load per
// user request, we also prevent storing on unload here so as to // user request, we also prevent storing on unload here so as to
// avoid third-party sites making XSRF requests or providing links // avoid third-party sites making XSRF requests or providing links
@@ -42,24 +49,25 @@ svgEditor.addExtension('storage', function () {
// user's prior work. To change this behavior so that no use of storage // user's prior work. To change this behavior so that no use of storage
// or adding of new storage takes place regardless of settings, set // or adding of new storage takes place regardless of settings, set
// the "noStorageOnLoad" config setting to true in config.js. // the "noStorageOnLoad" config setting to true in config.js.
noStorageOnLoad = svgEditor.curConfig.noStorageOnLoad, noStorageOnLoad,
forceStorage = svgEditor.curConfig.forceStorage, forceStorage
storage = svgEditor.storage; } = svgEditor.curConfig;
const {storage} = svgEditor;
function replaceStoragePrompt (val) { function replaceStoragePrompt (val) {
val = val ? 'storagePrompt=' + val : ''; val = val ? 'storagePrompt=' + val : '';
var loc = top.location; // Allow this to work with the embedded editor as well const loc = top.location; // Allow this to work with the embedded editor as well
if (loc.href.indexOf('storagePrompt=') > -1) { if (loc.href.includes('storagePrompt=')) {
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) { loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || '')); return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
}); });
} else { } else {
loc.href += (loc.href.indexOf('?') > -1 ? '&' : '?') + val; loc.href += (loc.href.includes('?') ? '&' : '?') + val;
} }
} }
function setSVGContentStorage (val) { function setSVGContentStorage (val) {
if (storage) { if (storage) {
var name = 'svgedit-' + svgEditor.curConfig.canvasName; const name = 'svgedit-' + svgEditor.curConfig.canvasName;
if (!val) { if (!val) {
storage.removeItem(name); storage.removeItem(name);
} else { } else {
@@ -78,8 +86,7 @@ svgEditor.addExtension('storage', function () {
function emptyStorage () { function emptyStorage () {
setSVGContentStorage(''); setSVGContentStorage('');
var name; for (let name in svgEditor.curPrefs) {
for (name in svgEditor.curPrefs) {
if (svgEditor.curPrefs.hasOwnProperty(name)) { if (svgEditor.curPrefs.hasOwnProperty(name)) {
name = 'svg-edit-' + name; name = 'svg-edit-' + name;
if (storage) { if (storage) {
@@ -106,7 +113,6 @@ svgEditor.addExtension('storage', function () {
if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) { if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) {
return; return;
} }
var key;
if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) { if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) {
setSVGContentStorage(svgCanvas.getSvgString()); setSVGContentStorage(svgCanvas.getSvgString());
} }
@@ -114,12 +120,12 @@ svgEditor.addExtension('storage', function () {
svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on
// svgEditor.showSaveWarning = false; // svgEditor.showSaveWarning = false;
var curPrefs = svgEditor.curPrefs; const {curPrefs} = svgEditor;
for (key in curPrefs) { for (let key in curPrefs) {
if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
var val = curPrefs[key], let val = curPrefs[key];
store = (val !== undefined); const store = (val !== undefined);
key = 'svg-edit-' + key; key = 'svg-edit-' + key;
if (!store) { if (!store) {
continue; continue;
@@ -127,7 +133,7 @@ svgEditor.addExtension('storage', function () {
if (storage) { if (storage) {
storage.setItem(key, val); storage.setItem(key, val);
} else if (window.widget) { } else if (window.widget) {
widget.setPreferenceForKey(val, key); window.widget.setPreferenceForKey(val, key);
} else { } else {
val = encodeURIComponent(val); val = encodeURIComponent(val);
document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
@@ -137,32 +143,18 @@ svgEditor.addExtension('storage', function () {
}, false); }, false);
} }
/* let loaded = false;
// We could add locales here instead (and also thereby avoid the need
// to keep our content within "langReady"), but this would be less
// convenient for translators.
$.extend(uiStrings, {confirmSetStorage: {
message: "By default and where supported, SVG-Edit can store your editor "+
"preferences and SVG content locally on your machine so you do not "+
"need to add these back each time you load SVG-Edit. If, for privacy "+
"reasons, you do not wish to store this information on your machine, "+
"you can change away from the default option below.",
storagePrefsAndContent: "Store preferences and SVG content locally",
storagePrefsOnly: "Only store preferences locally",
storagePrefs: "Store preferences locally",
storageNoPrefsOrContent: "Do not store my preferences or SVG content locally",
storageNoPrefs: "Do not store my preferences locally",
rememberLabel: "Remember this choice?",
rememberTooltip: "If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again."
}});
*/
var loaded = false;
return { return {
name: 'storage', name: 'storage',
langReady: function (data) { langReady (data) {
var // lang = data.lang, // const {uiStrings: {confirmSetStorage}} = data, // No need to store as dialog should only run once
uiStrings = data.uiStrings, // No need to store as dialog should only run once const {lang} = data;
storagePrompt = $.deparam.querystring(true).storagePrompt; const {storagePrompt} = $.deparam.querystring(true);
const {
message, storagePrefsAndContent, storagePrefsOnly,
storagePrefs, storageNoPrefsOrContent, storageNoPrefs,
rememberLabel, rememberTooltip
} = confirmSetStorage[lang];
// No need to run this one-time dialog again just because the user // No need to run this one-time dialog again just because the user
// changes the language // changes the language
@@ -191,22 +183,22 @@ svgEditor.addExtension('storage', function () {
) )
// ...then show the storage prompt. // ...then show the storage prompt.
)) { )) {
var options = []; const options = [];
if (storage) { if (storage) {
options.unshift( options.unshift(
{value: 'prefsAndContent', text: uiStrings.confirmSetStorage.storagePrefsAndContent}, {value: 'prefsAndContent', text: storagePrefsAndContent},
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly}, {value: 'prefsOnly', text: storagePrefsOnly},
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent} {value: 'noPrefsOrContent', text: storageNoPrefsOrContent}
); );
} else { } else {
options.unshift( options.unshift(
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs}, {value: 'prefsOnly', text: storagePrefs},
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs} {value: 'noPrefsOrContent', text: storageNoPrefs}
); );
} }
// Hack to temporarily provide a wide and high enough dialog // Hack to temporarily provide a wide and high enough dialog
var oldContainerWidth = $('#dialog_container')[0].style.width, const oldContainerWidth = $('#dialog_container')[0].style.width,
oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft, oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,
oldContentHeight = $('#dialog_content')[0].style.height, oldContentHeight = $('#dialog_content')[0].style.height,
oldContainerHeight = $('#dialog_container')[0].style.height; oldContainerHeight = $('#dialog_container')[0].style.height;
@@ -216,8 +208,9 @@ svgEditor.addExtension('storage', function () {
$('#dialog_container')[0].style.marginLeft = '-400px'; $('#dialog_container')[0].style.marginLeft = '-400px';
// Open select-with-checkbox dialog // Open select-with-checkbox dialog
// From svg-editor.js
$.select( $.select(
uiStrings.confirmSetStorage.message, message,
options, options,
function (pref, checked) { function (pref, checked) {
if (pref && pref !== 'noPrefsOrContent') { if (pref && pref !== 'noPrefsOrContent') {
@@ -272,9 +265,9 @@ svgEditor.addExtension('storage', function () {
null, null,
null, null,
{ {
label: uiStrings.confirmSetStorage.rememberLabel, label: rememberLabel,
checked: false, checked: false,
tooltip: uiStrings.confirmSetStorage.rememberTooltip tooltip: rememberTooltip
} }
); );
} else if (!noStorageOnLoad || forceStorage) { } else if (!noStorageOnLoad || forceStorage) {

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-var */
/* globals svgEditor */ /* globals svgEditor */
/* /*
Depends on Firefox add-on and executables from https://github.com/brettz9/webappfind Depends on Firefox add-on and executables from https://github.com/brettz9/webappfind
@@ -7,21 +6,20 @@ Todos:
1. See WebAppFind Readme for SVG-related todos 1. See WebAppFind Readme for SVG-related todos
*/ */
(function () { (function () {
'use strict'; const saveMessage = 'webapp-save',
var pathID,
saveMessage = 'webapp-save',
readMessage = 'webapp-read', readMessage = 'webapp-read',
excludedMessages = [readMessage, saveMessage]; excludedMessages = [readMessage, saveMessage];
let pathID;
// Todo: Update to new API once released
window.addEventListener('message', function (e) { window.addEventListener('message', function (e) {
if (e.origin !== window.location.origin || // PRIVACY AND SECURITY! (for viewing and saving, respectively) if (e.origin !== window.location.origin || // PRIVACY AND SECURITY! (for viewing and saving, respectively)
(!Array.isArray(e.data) || excludedMessages.indexOf(e.data[0]) > -1) // Validate format and avoid our post below (!Array.isArray(e.data) || excludedMessages.includes(e.data[0])) // Validate format and avoid our post below
) { ) {
return; return;
} }
var svgString, const messageType = e.data[0];
messageType = e.data[0]; let svgString;
switch (messageType) { switch (messageType) {
case 'webapp-view': case 'webapp-view':
// Populate the contents // Populate the contents
@@ -54,7 +52,7 @@ svgEditor.addExtension('WebAppFind', function () {
title: 'Save Image back to Disk', title: 'Save Image back to Disk',
position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)") position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)")
events: { events: {
click: function () { click () {
if (!pathID) { // Not ready yet as haven't received first payload if (!pathID) { // Not ready yet as haven't received first payload
return; return;
} }

View File

@@ -1,4 +1,3 @@
/* eslint-disable no-var */
/* globals svgEditor, svgCanvas */ /* globals svgEditor, svgCanvas */
/** /**
* Should not be needed for same domain control (just call via child frame), * Should not be needed for same domain control (just call via child frame),
@@ -6,27 +5,25 @@
* in embedapi.js with a demo at embedapi.html * in embedapi.js with a demo at embedapi.html
*/ */
svgEditor.addExtension('xdomain-messaging', function () { svgEditor.addExtension('xdomain-messaging', function () {
'use strict';
try { try {
window.addEventListener('message', function (e) { window.addEventListener('message', function (e) {
// We accept and post strings for the sake of IE9 support // We accept and post strings for the sake of IE9 support
if (typeof e.data !== 'string' || e.data.charAt() === '|') { if (typeof e.data !== 'string' || e.data.charAt() === '|') {
return; return;
} }
var cbid, name, args, message, allowedOrigins, data = JSON.parse(e.data); const data = JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svgCanvas') { if (!data || typeof data !== 'object' || data.namespace !== 'svgCanvas') {
return; return;
} }
// The default is not to allow any origins, including even the same domain or if run on a file:// URL // The default is not to allow any origins, including even the same domain or if run on a file:// URL
// See config-sample.js for an example of how to configure // See config-sample.js for an example of how to configure
allowedOrigins = svgEditor.curConfig.allowedOrigins; const {allowedOrigins} = svgEditor.curConfig;
if (allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1) { if (!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin)) {
return; return;
} }
cbid = data.id; const cbid = data.id;
name = data.name; const {name, args} = data;
args = data.args; const message = {
message = {
namespace: 'svg-edit', namespace: 'svg-edit',
id: cbid id: cbid
}; };

Binary file not shown.

Before

Width:  |  Height:  |  Size: 718 B

After

Width:  |  Height:  |  Size: 568 B

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>-</title> <title>-</title>
<link rel="icon" type="image/png" href="../../images/logo.png"/> <link rel="icon" type="image/png" href="../../images/logo.png"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> <script src="jquery.min.js"></script>
</head> </head>
<body> <body>

View File

@@ -1,50 +1,47 @@
/* eslint-disable no-var */ /* globals jQuery */
/* globals $ */ const $ = jQuery;
$('a').click(function () { $('a').click(function () {
'use strict'; const {href} = this;
var metaStr; const target = window.parent;
var href = this.href; const post = (message) => {
var target = window.parent; // Todo: Make origin customizable as set by opening window
// Todo: If dropping IE9, avoid stringifying
target.postMessage(JSON.stringify({
namespace: 'imagelib',
...message
}), '*');
};
// Convert Non-SVG images to data URL first // Convert Non-SVG images to data URL first
// (this could also have been done server-side by the library) // (this could also have been done server-side by the library)
if (this.href.indexOf('.svg') === -1) { // Send metadata (also indicates file is about to be sent)
metaStr = JSON.stringify({ post({
name: $(this).text(), name: $(this).text(),
id: href id: href
}); });
target.postMessage(metaStr, '*'); if (!this.href.includes('.svg')) {
const img = new Image();
var img = new Image();
img.onload = function () { img.onload = function () {
var canvas = document.createElement('canvas'); const canvas = document.createElement('canvas');
canvas.width = this.width; canvas.width = this.width;
canvas.height = this.height; canvas.height = this.height;
// load the raster image into the canvas // load the raster image into the canvas
canvas.getContext('2d').drawImage(this, 0, 0); canvas.getContext('2d').drawImage(this, 0, 0);
// retrieve the data: URL // retrieve the data: URL
var dataurl; let data;
try { try {
dataurl = canvas.toDataURL(); data = canvas.toDataURL();
} catch (err) { } catch (err) {
// This fails in Firefox with file:// URLs :( // This fails in Firefox with file:// URLs :(
alert('Data URL conversion failed: ' + err); alert('Data URL conversion failed: ' + err);
dataurl = ''; data = '';
} }
target.postMessage('|' + href + '|' + dataurl, '*'); post({href, data});
}; };
img.src = href; img.src = href;
} else { } else {
// Send metadata (also indicates file is about to be sent)
metaStr = JSON.stringify({
name: $(this).text(),
id: href
});
target.postMessage(metaStr, '*');
// Do ajax request for image's href value // Do ajax request for image's href value
$.get(href, function (data) { $.get(href, function (data) {
data = '|' + href + '|' + data; post({href, data});
// This is where the magic happens!
target.postMessage(data, '*');
}, 'html'); // 'html' is necessary to keep returned data as a string }, 'html'); // 'html' is necessary to keep returned data as a string
} }
return false; return false;

167
editor/extensions/imagelib/jquery.min.js vendored Normal file
View File

@@ -0,0 +1,167 @@
/*!
* jQuery JavaScript Library v1.4.4
* http://jquery.com/
*
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* Includes Sizzle.js
* http://sizzlejs.com/
* Copyright 2010, The Dojo Foundation
* Released under the MIT, BSD, and GPL Licenses.
*
* Date: Thu Nov 11 19:04:53 2010 -0500
*/
(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h=
h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"||
h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;
if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],
z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,
s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=
s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)||
[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u,
false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=
c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);
else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this,
a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=
c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",
colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===
1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "),
l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,
"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";
if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=
a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},
attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&
b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};
c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,
arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=
d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+
c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=
w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k===
"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+
d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=
B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type===
"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===
0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===
"object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}});
c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i,
[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];
break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,
q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=
l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*"));
return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==
B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===
i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=
i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g,
"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,
m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-
0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===
"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];
if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,
g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;
for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"),
i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);
n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&
function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||
p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=
t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?
function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;
c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},
not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=
h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):
c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,
2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,
b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&
e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1,
"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;
else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=
c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a,
b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):
this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",
prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||
b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length-
1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===
"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache=
false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset;
A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type",
b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=
encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",
[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),
e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});
if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",
3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",
d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,
d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===
"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L||
1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}
var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;
for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+=
parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a,
e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&
c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+
b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,3 @@
/* eslint-disable no-var */
/* globals svgedit */
/** /**
* Package: svgedit.history * Package: svgedit.history
* *
@@ -8,16 +6,10 @@
* Copyright(c) 2016 Flint O'Brien * Copyright(c) 2016 Flint O'Brien
*/ */
// Dependencies: import {
// 1) history.js BatchCommand, MoveElementCommand, InsertElementCommand, RemoveElementCommand,
ChangeElementCommand
(function () { } from './history.js';
'use strict';
if (!svgedit.history) {
svgedit.history = {};
}
var history = svgedit.history;
/** /**
* History recording service. * History recording service.
@@ -57,113 +49,113 @@ var history = svgedit.history;
* A value of null is valid for cases where no history recording is required. * A value of null is valid for cases where no history recording is required.
* See singleton: HistoryRecordingService.NO_HISTORY * See singleton: HistoryRecordingService.NO_HISTORY
*/ */
var HistoryRecordingService = history.HistoryRecordingService = function (undoManager) { export default class HistoryRecordingService {
this.undoManager_ = undoManager; constructor (undoManager) {
this.currentBatchCommand_ = null; this.undoManager_ = undoManager;
this.batchCommandStack_ = []; this.currentBatchCommand_ = null;
}; this.batchCommandStack_ = [];
}
/**
* Start a batch command so multiple commands can recorded as a single history command.
* Requires a corresponding call to endBatchCommand. Start and end commands can be nested.
*
* @param {string} text - Optional string describing the batch command.
* @returns {svgedit.history.HistoryRecordingService}
*/
startBatchCommand (text) {
if (!this.undoManager_) { return this; }
this.currentBatchCommand_ = new BatchCommand(text);
this.batchCommandStack_.push(this.currentBatchCommand_);
return this;
}
/**
* End a batch command and add it to the history or a parent batch command.
* @returns {svgedit.history.HistoryRecordingService}
*/
endBatchCommand () {
if (!this.undoManager_) { return this; }
if (this.currentBatchCommand_) {
const batchCommand = this.currentBatchCommand_;
this.batchCommandStack_.pop();
const {length} = this.batchCommandStack_;
this.currentBatchCommand_ = length ? this.batchCommandStack_[length - 1] : null;
this.addCommand_(batchCommand);
}
return this;
}
/**
* Add a MoveElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was moved
* @param {Element} oldNextSibling - The element's next sibling before it was moved
* @param {Element} oldParent - The element's parent before it was moved
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
moveElement (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new MoveElementCommand(elem, oldNextSibling, oldParent, text));
return this;
}
/**
* Add an InsertElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was added
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
insertElement (elem, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new InsertElementCommand(elem, text));
return this;
}
/**
* Add a RemoveElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was removed
* @param {Element} oldNextSibling - The element's next sibling before it was removed
* @param {Element} oldParent - The element's parent before it was removed
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
removeElement (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new RemoveElementCommand(elem, oldNextSibling, oldParent, text));
return this;
}
/**
* Add a ChangeElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was changed
* @param {Object} attrs - An object with the attributes to be changed and the values they had *before* the change
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
changeElement (elem, attrs, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new ChangeElementCommand(elem, attrs, text));
return this;
}
/**
* Private function to add a command to the history or current batch command.
* @param cmd
* @returns {svgedit.history.HistoryRecordingService}
* @private
*/
addCommand_ (cmd) {
if (!this.undoManager_) { return this; }
if (this.currentBatchCommand_) {
this.currentBatchCommand_.addSubCommand(cmd);
} else {
this.undoManager_.addCommandToHistory(cmd);
}
}
}
/** /**
* @type {svgedit.history.HistoryRecordingService} NO_HISTORY - Singleton that can be passed * @type {svgedit.history.HistoryRecordingService} NO_HISTORY - Singleton that can be passed
* in to functions that record history, but the caller requires that no history be recorded. * in to functions that record history, but the caller requires that no history be recorded.
*/ */
HistoryRecordingService.NO_HISTORY = new HistoryRecordingService(); HistoryRecordingService.NO_HISTORY = new HistoryRecordingService();
/**
* Start a batch command so multiple commands can recorded as a single history command.
* Requires a corresponding call to endBatchCommand. Start and end commands can be nested.
*
* @param {string} text - Optional string describing the batch command.
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.startBatchCommand = function (text) {
if (!this.undoManager_) { return this; }
this.currentBatchCommand_ = new history.BatchCommand(text);
this.batchCommandStack_.push(this.currentBatchCommand_);
return this;
};
/**
* End a batch command and add it to the history or a parent batch command.
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.endBatchCommand = function () {
if (!this.undoManager_) { return this; }
if (this.currentBatchCommand_) {
var batchCommand = this.currentBatchCommand_;
this.batchCommandStack_.pop();
var length = this.batchCommandStack_.length;
this.currentBatchCommand_ = length ? this.batchCommandStack_[length - 1] : null;
this.addCommand_(batchCommand);
}
return this;
};
/**
* Add a MoveElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was moved
* @param {Element} oldNextSibling - The element's next sibling before it was moved
* @param {Element} oldParent - The element's parent before it was moved
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.moveElement = function (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new history.MoveElementCommand(elem, oldNextSibling, oldParent, text));
return this;
};
/**
* Add an InsertElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was added
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.insertElement = function (elem, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new history.InsertElementCommand(elem, text));
return this;
};
/**
* Add a RemoveElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was removed
* @param {Element} oldNextSibling - The element's next sibling before it was removed
* @param {Element} oldParent - The element's parent before it was removed
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.removeElement = function (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new history.RemoveElementCommand(elem, oldNextSibling, oldParent, text));
return this;
};
/**
* Add a ChangeElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was changed
* @param {Object} attrs - An object with the attributes to be changed and the values they had *before* the change
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.changeElement = function (elem, attrs, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new history.ChangeElementCommand(elem, attrs, text));
return this;
};
/**
* Private function to add a command to the history or current batch command.
* @param cmd
* @returns {svgedit.history.HistoryRecordingService}
* @private
*/
HistoryRecordingService.prototype.addCommand_ = function (cmd) {
if (!this.undoManager_) { return this; }
if (this.currentBatchCommand_) {
this.currentBatchCommand_.addSubCommand(cmd);
} else {
this.undoManager_.addCommandToHistory(cmd);
}
};
}());

Binary file not shown.

Before

Width:  |  Height:  |  Size: 291 B

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 449 B

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 305 B

After

Width:  |  Height:  |  Size: 175 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 459 B

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 907 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 812 B

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 B

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 852 B

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 663 B

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 733 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 B

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 B

After

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 903 B

After

Width:  |  Height:  |  Size: 872 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 683 B

After

Width:  |  Height:  |  Size: 551 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 B

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 900 B

After

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 192 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 919 B

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 737 B

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 663 B

After

Width:  |  Height:  |  Size: 530 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 571 B

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 B

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 B

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 919 B

After

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 906 B

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 B

After

Width:  |  Height:  |  Size: 788 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 881 B

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 404 B

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 921 B

After

Width:  |  Height:  |  Size: 656 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 980 B

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 694 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 825 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 828 B

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 B

After

Width:  |  Height:  |  Size: 74 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 553 B

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

After

Width:  |  Height:  |  Size: 575 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 422 B

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 600 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 938 B

Some files were not shown because too many files have changed in this diff Show More