(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 iconsmaster
|
@ -1,14 +1,21 @@
|
|||
node_modules
|
||||
|
||||
# Vendor/minified files
|
||||
editor/jquery.js
|
||||
editor/jspdf/jspdf.min.js
|
||||
editor/jspdf/underscore-min.js
|
||||
editor/jquery.min.js
|
||||
editor/jquery-ui
|
||||
|
||||
editor/jgraduate/jpicker.min.js
|
||||
editor/jgraduate/jquery.jgraduate.min.js
|
||||
editor/jquery-ui
|
||||
|
||||
editor/jquerybbq
|
||||
editor/js-hotkeys
|
||||
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/sinon
|
||||
|
|
|
@ -121,7 +121,6 @@ def parseComment(line, line_num, enabled_flags):
|
|||
|
||||
return line
|
||||
|
||||
|
||||
def ship(inFileName, enabled_flags):
|
||||
# read in HTML file
|
||||
lines = file(inFileName, 'r').readlines()
|
||||
|
@ -141,7 +140,7 @@ def ship(inFileName, enabled_flags):
|
|||
else: # else append line to the output list
|
||||
out_lines.append(line)
|
||||
i += 1
|
||||
|
||||
|
||||
return ''.join(out_lines)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 6.2 KiB |
|
@ -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.
|
|
@ -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()` | |
|
|
@ -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>
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals $, svgedit */
|
||||
/* globals jQuery */
|
||||
/**
|
||||
* Package: svgedit.browser
|
||||
*
|
||||
|
@ -12,177 +11,168 @@
|
|||
// Dependencies:
|
||||
// 1) jQuery (for $.alert())
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
import './pathseg.js';
|
||||
import {NS} from './svgedit.js';
|
||||
|
||||
if (!svgedit.browser) {
|
||||
svgedit.browser = {};
|
||||
}
|
||||
const $ = jQuery;
|
||||
|
||||
// alias
|
||||
var NS = svgedit.NS;
|
||||
|
||||
var supportsSvg_ = (function () {
|
||||
return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
|
||||
const supportsSvg_ = (function () {
|
||||
return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
|
||||
}());
|
||||
|
||||
svgedit.browser.supportsSvg = function () { return supportsSvg_; };
|
||||
if (!svgedit.browser.supportsSvg()) {
|
||||
window.location = 'browser-not-supported.html';
|
||||
return;
|
||||
}
|
||||
export const supportsSvg = () => supportsSvg_;
|
||||
|
||||
var userAgent = navigator.userAgent;
|
||||
var svg = document.createElementNS(NS.SVG, 'svg');
|
||||
const {userAgent} = navigator;
|
||||
const svg = document.createElementNS(NS.SVG, 'svg');
|
||||
|
||||
// Note: Browser sniffing should only be used if no other detection method is possible
|
||||
var isOpera_ = !!window.opera;
|
||||
var isWebkit_ = userAgent.indexOf('AppleWebKit') >= 0;
|
||||
var isGecko_ = userAgent.indexOf('Gecko/') >= 0;
|
||||
var isIE_ = userAgent.indexOf('MSIE') >= 0;
|
||||
var isChrome_ = userAgent.indexOf('Chrome/') >= 0;
|
||||
var isWindows_ = userAgent.indexOf('Windows') >= 0;
|
||||
var isMac_ = userAgent.indexOf('Macintosh') >= 0;
|
||||
var isTouch_ = 'ontouchstart' in window;
|
||||
const isOpera_ = !!window.opera;
|
||||
const isWebkit_ = userAgent.includes('AppleWebKit');
|
||||
const isGecko_ = userAgent.includes('Gecko/');
|
||||
const isIE_ = userAgent.includes('MSIE');
|
||||
const isChrome_ = userAgent.includes('Chrome/');
|
||||
const isWindows_ = userAgent.includes('Windows');
|
||||
const isMac_ = userAgent.includes('Macintosh');
|
||||
const isTouch_ = 'ontouchstart' in window;
|
||||
|
||||
var supportsSelectors_ = (function () {
|
||||
return !!svg.querySelector;
|
||||
const supportsSelectors_ = (function () {
|
||||
return !!svg.querySelector;
|
||||
}());
|
||||
|
||||
var supportsXpath_ = (function () {
|
||||
return !!document.evaluate;
|
||||
const supportsXpath_ = (function () {
|
||||
return !!document.evaluate;
|
||||
}());
|
||||
|
||||
// segList functions (for FF1.5 and 2.0)
|
||||
var supportsPathReplaceItem_ = (function () {
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,10');
|
||||
var seglist = path.pathSegList;
|
||||
var seg = path.createSVGPathSegLinetoAbs(5, 5);
|
||||
try {
|
||||
seglist.replaceItem(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
const supportsPathReplaceItem_ = (function () {
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,10');
|
||||
const seglist = path.pathSegList;
|
||||
const seg = path.createSVGPathSegLinetoAbs(5, 5);
|
||||
try {
|
||||
seglist.replaceItem(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
}());
|
||||
|
||||
var supportsPathInsertItemBefore_ = (function () {
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,10');
|
||||
var seglist = path.pathSegList;
|
||||
var seg = path.createSVGPathSegLinetoAbs(5, 5);
|
||||
try {
|
||||
seglist.insertItemBefore(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
const supportsPathInsertItemBefore_ = (function () {
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,10');
|
||||
const seglist = path.pathSegList;
|
||||
const seg = path.createSVGPathSegLinetoAbs(5, 5);
|
||||
try {
|
||||
seglist.insertItemBefore(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
}());
|
||||
|
||||
// text character positioning (for IE9)
|
||||
var supportsGoodTextCharPos_ = (function () {
|
||||
var svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgroot);
|
||||
svgcontent.setAttribute('x', 5);
|
||||
svgroot.appendChild(svgcontent);
|
||||
var text = document.createElementNS(NS.SVG, 'text');
|
||||
text.textContent = 'a';
|
||||
svgcontent.appendChild(text);
|
||||
var pos = text.getStartPositionOfChar(0).x;
|
||||
document.documentElement.removeChild(svgroot);
|
||||
return (pos === 0);
|
||||
const supportsGoodTextCharPos_ = (function () {
|
||||
const svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
const svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgroot);
|
||||
svgcontent.setAttribute('x', 5);
|
||||
svgroot.appendChild(svgcontent);
|
||||
const text = document.createElementNS(NS.SVG, 'text');
|
||||
text.textContent = 'a';
|
||||
svgcontent.appendChild(text);
|
||||
const pos = text.getStartPositionOfChar(0).x;
|
||||
document.documentElement.removeChild(svgroot);
|
||||
return (pos === 0);
|
||||
}());
|
||||
|
||||
var supportsPathBBox_ = (function () {
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgcontent);
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
|
||||
svgcontent.appendChild(path);
|
||||
var bbox = path.getBBox();
|
||||
document.documentElement.removeChild(svgcontent);
|
||||
return (bbox.height > 4 && bbox.height < 5);
|
||||
const supportsPathBBox_ = (function () {
|
||||
const svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgcontent);
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
|
||||
svgcontent.appendChild(path);
|
||||
const bbox = path.getBBox();
|
||||
document.documentElement.removeChild(svgcontent);
|
||||
return (bbox.height > 4 && bbox.height < 5);
|
||||
}());
|
||||
|
||||
// Support for correct bbox sizing on groups with horizontal/vertical lines
|
||||
var supportsHVLineContainerBBox_ = (function () {
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgcontent);
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,0');
|
||||
var path2 = document.createElementNS(NS.SVG, 'path');
|
||||
path2.setAttribute('d', 'M5,0 15,0');
|
||||
var g = document.createElementNS(NS.SVG, 'g');
|
||||
g.appendChild(path);
|
||||
g.appendChild(path2);
|
||||
svgcontent.appendChild(g);
|
||||
var bbox = g.getBBox();
|
||||
document.documentElement.removeChild(svgcontent);
|
||||
// Webkit gives 0, FF gives 10, Opera (correctly) gives 15
|
||||
return (bbox.width === 15);
|
||||
const supportsHVLineContainerBBox_ = (function () {
|
||||
const svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgcontent);
|
||||
const path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,0');
|
||||
const path2 = document.createElementNS(NS.SVG, 'path');
|
||||
path2.setAttribute('d', 'M5,0 15,0');
|
||||
const g = document.createElementNS(NS.SVG, 'g');
|
||||
g.appendChild(path);
|
||||
g.appendChild(path2);
|
||||
svgcontent.appendChild(g);
|
||||
const bbox = g.getBBox();
|
||||
document.documentElement.removeChild(svgcontent);
|
||||
// Webkit gives 0, FF gives 10, Opera (correctly) gives 15
|
||||
return (bbox.width === 15);
|
||||
}());
|
||||
|
||||
var supportsEditableText_ = (function () {
|
||||
// TODO: Find better way to check support for this
|
||||
return isOpera_;
|
||||
const supportsEditableText_ = (function () {
|
||||
// TODO: Find better way to check support for this
|
||||
return isOpera_;
|
||||
}());
|
||||
|
||||
var supportsGoodDecimals_ = (function () {
|
||||
// Correct decimals on clone attributes (Opera < 10.5/win/non-en)
|
||||
var rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('x', 0.1);
|
||||
var crect = rect.cloneNode(false);
|
||||
var retValue = (crect.getAttribute('x').indexOf(',') === -1);
|
||||
if (!retValue) {
|
||||
$.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.');
|
||||
}
|
||||
return retValue;
|
||||
const supportsGoodDecimals_ = (function () {
|
||||
// Correct decimals on clone attributes (Opera < 10.5/win/non-en)
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('x', 0.1);
|
||||
const crect = rect.cloneNode(false);
|
||||
const retValue = (!crect.getAttribute('x').includes(','));
|
||||
if (!retValue) {
|
||||
$.alert('NOTE: This version of Opera is known to contain bugs in SVG-edit.\n' +
|
||||
'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.');
|
||||
}
|
||||
return retValue;
|
||||
}());
|
||||
|
||||
var supportsNonScalingStroke_ = (function () {
|
||||
var rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('style', 'vector-effect:non-scaling-stroke');
|
||||
return rect.style.vectorEffect === 'non-scaling-stroke';
|
||||
const supportsNonScalingStroke_ = (function () {
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('style', 'vector-effect:non-scaling-stroke');
|
||||
return rect.style.vectorEffect === 'non-scaling-stroke';
|
||||
}());
|
||||
|
||||
var supportsNativeSVGTransformLists_ = (function () {
|
||||
var rect = document.createElementNS(NS.SVG, 'rect');
|
||||
var rxform = rect.transform.baseVal;
|
||||
var t1 = svg.createSVGTransform();
|
||||
rxform.appendItem(t1);
|
||||
var r1 = rxform.getItem(0);
|
||||
return r1 instanceof SVGTransform && t1 instanceof SVGTransform &&
|
||||
r1.type === t1.type && r1.angle === t1.angle &&
|
||||
r1.matrix.a === t1.matrix.a &&
|
||||
r1.matrix.b === t1.matrix.b &&
|
||||
r1.matrix.c === t1.matrix.c &&
|
||||
r1.matrix.d === t1.matrix.d &&
|
||||
r1.matrix.e === t1.matrix.e &&
|
||||
r1.matrix.f === t1.matrix.f;
|
||||
const supportsNativeSVGTransformLists_ = (function () {
|
||||
const rect = document.createElementNS(NS.SVG, 'rect');
|
||||
const rxform = rect.transform.baseVal;
|
||||
const t1 = svg.createSVGTransform();
|
||||
rxform.appendItem(t1);
|
||||
const r1 = rxform.getItem(0);
|
||||
// Todo: Do frame-independent instance checking
|
||||
return r1 instanceof SVGTransform && t1 instanceof SVGTransform &&
|
||||
r1.type === t1.type && r1.angle === t1.angle &&
|
||||
r1.matrix.a === t1.matrix.a &&
|
||||
r1.matrix.b === t1.matrix.b &&
|
||||
r1.matrix.c === t1.matrix.c &&
|
||||
r1.matrix.d === t1.matrix.d &&
|
||||
r1.matrix.e === t1.matrix.e &&
|
||||
r1.matrix.f === t1.matrix.f;
|
||||
}());
|
||||
|
||||
// Public API
|
||||
|
||||
svgedit.browser.isOpera = function () { return isOpera_; };
|
||||
svgedit.browser.isWebkit = function () { return isWebkit_; };
|
||||
svgedit.browser.isGecko = function () { return isGecko_; };
|
||||
svgedit.browser.isIE = function () { return isIE_; };
|
||||
svgedit.browser.isChrome = function () { return isChrome_; };
|
||||
svgedit.browser.isWindows = function () { return isWindows_; };
|
||||
svgedit.browser.isMac = function () { return isMac_; };
|
||||
svgedit.browser.isTouch = function () { return isTouch_; };
|
||||
export const isOpera = () => isOpera_;
|
||||
export const isWebkit = () => isWebkit_;
|
||||
export const isGecko = () => isGecko_;
|
||||
export const isIE = () => isIE_;
|
||||
export const isChrome = () => isChrome_;
|
||||
export const isWindows = () => isWindows_;
|
||||
export const isMac = () => isMac_;
|
||||
export const isTouch = () => isTouch_;
|
||||
|
||||
svgedit.browser.supportsSelectors = function () { return supportsSelectors_; };
|
||||
svgedit.browser.supportsXpath = function () { return supportsXpath_; };
|
||||
export const supportsSelectors = () => supportsSelectors_;
|
||||
export const supportsXpath = () => supportsXpath_;
|
||||
|
||||
svgedit.browser.supportsPathReplaceItem = function () { return supportsPathReplaceItem_; };
|
||||
svgedit.browser.supportsPathInsertItemBefore = function () { return supportsPathInsertItemBefore_; };
|
||||
svgedit.browser.supportsPathBBox = function () { return supportsPathBBox_; };
|
||||
svgedit.browser.supportsHVLineContainerBBox = function () { return supportsHVLineContainerBBox_; };
|
||||
svgedit.browser.supportsGoodTextCharPos = function () { return supportsGoodTextCharPos_; };
|
||||
svgedit.browser.supportsEditableText = function () { return supportsEditableText_; };
|
||||
svgedit.browser.supportsGoodDecimals = function () { return supportsGoodDecimals_; };
|
||||
svgedit.browser.supportsNonScalingStroke = function () { return supportsNonScalingStroke_; };
|
||||
svgedit.browser.supportsNativeTransformLists = function () { return supportsNativeSVGTransformLists_; };
|
||||
}());
|
||||
export const supportsPathReplaceItem = () => supportsPathReplaceItem_;
|
||||
export const supportsPathInsertItemBefore = () => supportsPathInsertItemBefore_;
|
||||
export const supportsPathBBox = () => supportsPathBBox_;
|
||||
export const supportsHVLineContainerBBox = () => supportsHVLineContainerBBox_;
|
||||
export const supportsGoodTextCharPos = () => supportsGoodTextCharPos_;
|
||||
export const supportsEditableText = () => supportsEditableText_;
|
||||
export const supportsGoodDecimals = () => supportsGoodDecimals_;
|
||||
export const supportsNonScalingStroke = () => supportsNonScalingStroke_;
|
||||
export const supportsNativeTransformLists = () => supportsNativeSVGTransformLists_;
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
/* eslint-disable no-var */
|
||||
/**
|
||||
* A class to parse color values
|
||||
* @author Stoyan Stefanov <sstoo@gmail.com>
|
||||
* @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
|
||||
'use strict';
|
||||
export default function RGBColor (colorString) {
|
||||
this.ok = false;
|
||||
|
||||
// strip any leading #
|
||||
|
@ -19,7 +17,7 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
|
|||
|
||||
// before getting into regexps, try simple matches
|
||||
// and overwrite the input
|
||||
var simpleColors = {
|
||||
const simpleColors = {
|
||||
aliceblue: 'f0f8ff',
|
||||
antiquewhite: 'faebd7',
|
||||
aqua: '00ffff',
|
||||
|
@ -164,8 +162,7 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
|
|||
yellow: 'ffff00',
|
||||
yellowgreen: '9acd32'
|
||||
};
|
||||
var key;
|
||||
for (key in simpleColors) {
|
||||
for (const key in simpleColors) {
|
||||
if (simpleColors.hasOwnProperty(key)) {
|
||||
if (colorString === key) {
|
||||
colorString = simpleColors[key];
|
||||
|
@ -175,11 +172,11 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
|
|||
// emd of simple type-in colors
|
||||
|
||||
// array of color definition objects
|
||||
var colorDefs = [
|
||||
const colorDefs = [
|
||||
{
|
||||
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
|
||||
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
|
||||
process: function (bits) {
|
||||
process (bits) {
|
||||
return [
|
||||
parseInt(bits[1], 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})$/,
|
||||
example: ['#00ff00', '336699'],
|
||||
process: function (bits) {
|
||||
process (bits) {
|
||||
return [
|
||||
parseInt(bits[1], 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})$/,
|
||||
example: ['#fb0', 'f0f'],
|
||||
process: function (bits) {
|
||||
process (bits) {
|
||||
return [
|
||||
parseInt(bits[1] + bits[1], 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
|
||||
for (i = 0; i < colorDefs.length; i++) {
|
||||
var re = colorDefs[i].re;
|
||||
var processor = colorDefs[i].process;
|
||||
var bits = re.exec(colorString);
|
||||
for (let i = 0; i < colorDefs.length; i++) {
|
||||
const {re} = colorDefs[i];
|
||||
const processor = colorDefs[i].process;
|
||||
const bits = re.exec(colorString);
|
||||
if (bits) {
|
||||
var channels = processor(bits);
|
||||
const channels = processor(bits);
|
||||
this.r = channels[0];
|
||||
this.g = channels[1];
|
||||
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 + ')';
|
||||
};
|
||||
this.toHex = function () {
|
||||
var r = this.r.toString(16);
|
||||
var g = this.g.toString(16);
|
||||
var b = this.b.toString(16);
|
||||
let r = this.r.toString(16);
|
||||
let g = this.g.toString(16);
|
||||
let b = this.b.toString(16);
|
||||
if (r.length === 1) { r = '0' + r; }
|
||||
if (g.length === 1) { g = '0' + g; }
|
||||
if (b.length === 1) { b = '0' + b; }
|
||||
|
@ -247,30 +243,28 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
|
|||
|
||||
// help
|
||||
this.getHelpXML = function () {
|
||||
var i, j;
|
||||
var examples = [];
|
||||
const examples = [];
|
||||
// add regexps
|
||||
for (i = 0; i < colorDefs.length; i++) {
|
||||
var example = colorDefs[i].example;
|
||||
for (j = 0; j < example.length; j++) {
|
||||
for (let i = 0; i < colorDefs.length; i++) {
|
||||
const {example} = colorDefs[i];
|
||||
for (let j = 0; j < example.length; j++) {
|
||||
examples[examples.length] = example[j];
|
||||
}
|
||||
}
|
||||
// add type-in colors
|
||||
var sc;
|
||||
for (sc in simpleColors) {
|
||||
for (const sc in simpleColors) {
|
||||
if (simpleColors.hasOwnProperty(sc)) {
|
||||
examples[examples.length] = sc;
|
||||
}
|
||||
}
|
||||
|
||||
var xml = document.createElement('ul');
|
||||
const xml = document.createElement('ul');
|
||||
xml.setAttribute('id', 'rgbcolor-examples');
|
||||
for (i = 0; i < examples.length; i++) {
|
||||
for (let i = 0; i < examples.length; i++) {
|
||||
try {
|
||||
var listItem = document.createElement('li');
|
||||
var listColor = new RGBColor(examples[i]);
|
||||
var exampleDiv = document.createElement('div');
|
||||
const listItem = document.createElement('li');
|
||||
const listColor = new RGBColor(examples[i]);
|
||||
const exampleDiv = document.createElement('div');
|
||||
exampleDiv.style.cssText =
|
||||
'margin: 3px; ' +
|
||||
'border: 1px solid black; ' +
|
||||
|
@ -278,7 +272,7 @@ function RGBColor (colorString) { // eslint-disable-line no-unused-vars
|
|||
'color:' + listColor.toHex()
|
||||
;
|
||||
exampleDiv.appendChild(document.createTextNode('test'));
|
||||
var listItemValue = document.createTextNode(
|
||||
const listItemValue = document.createTextNode(
|
||||
' ' + examples[i] + ' -> ' + listColor.toRGB() + ' -> ' + listColor.toHex()
|
||||
);
|
||||
listItem.appendChild(exampleDiv);
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// CREATE A NEW FILE config.js AND ADD CONTENTS
|
||||
// SUCH AS SHOWN BELOW INTO THAT FILE.
|
||||
|
||||
/* globals svgEditor */
|
||||
/*
|
||||
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
|
||||
|
@ -19,6 +18,8 @@ See defaultConfig and defaultExtensions in svg-editor.js for a list
|
|||
See svg-editor.js for documentation on using setConfig().
|
||||
*/
|
||||
|
||||
import svgEditor from './svg-editor.js';
|
||||
|
||||
// URL OVERRIDE CONFIG
|
||||
svgEditor.setConfig({
|
||||
/**
|
||||
|
@ -117,25 +118,23 @@ As with configuration, one may use allowInitialUserOverride, but
|
|||
Failing to use allowInitialUserOverride will ensure preferences
|
||||
are hard-coded here regardless of URL or prior user storage setting.
|
||||
*/
|
||||
svgEditor.setConfig(
|
||||
{
|
||||
// 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
|
||||
/**
|
||||
* When showing the preferences dialog, svg-editor.js currently relies
|
||||
* 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
|
||||
* far as determining which color shows initially in the preferences
|
||||
* dialog (though it can be changed and saved).
|
||||
*/
|
||||
// bkgd_color: '#FFF',
|
||||
// bkgd_url: '',
|
||||
// img_save: 'embed',
|
||||
// Only shows in UI as far as alert notices
|
||||
// save_notice_done: false,
|
||||
// export_notice_done: false
|
||||
}
|
||||
);
|
||||
svgEditor.setConfig({
|
||||
// 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
|
||||
/**
|
||||
* When showing the preferences dialog, svg-editor.js currently relies
|
||||
* 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
|
||||
* far as determining which color shows initially in the preferences
|
||||
* dialog (though it can be changed and saved).
|
||||
*/
|
||||
// bkgd_color: '#FFF',
|
||||
// bkgd_url: '',
|
||||
// img_save: 'embed',
|
||||
// Only shows in UI as far as alert notices
|
||||
// save_notice_done: false,
|
||||
// export_notice_done: false
|
||||
});
|
||||
svgEditor.setConfig(
|
||||
{
|
||||
// Indicate pref settings here if you wish to allow user storage or URL settings
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals $, svgEditor */
|
||||
/* globals jQuery */
|
||||
/**
|
||||
* Package: svgedit.contextmenu
|
||||
*
|
||||
|
@ -9,58 +8,50 @@
|
|||
*/
|
||||
// Dependencies:
|
||||
// 1) jQuery (for dom injection of context menus)
|
||||
var svgedit = svgedit || {}; // eslint-disable-line no-use-before-define
|
||||
(function () {
|
||||
var self = this;
|
||||
if (!svgedit.contextmenu) {
|
||||
svgedit.contextmenu = {};
|
||||
}
|
||||
self.contextMenuExtensions = {};
|
||||
var menuItemIsValid = function (menuItem) {
|
||||
|
||||
const $ = jQuery;
|
||||
|
||||
let contextMenuExtensions = {};
|
||||
|
||||
const menuItemIsValid = function (menuItem) {
|
||||
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}
|
||||
if (!menuItemIsValid(menuItem)) {
|
||||
console.error('Menu items must be defined and have at least properties: id, label, action, where action must be a function');
|
||||
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"');
|
||||
return;
|
||||
}
|
||||
// Register menuItem action, see below for deferred menu dom injection
|
||||
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
|
||||
};
|
||||
var hasCustomHandler = function (handlerKey) {
|
||||
return self.contextMenuExtensions[handlerKey] && true;
|
||||
export const hasCustomMenuItemHandler = function (handlerKey) {
|
||||
return Boolean(contextMenuExtensions[handlerKey]);
|
||||
};
|
||||
var getCustomHandler = function (handlerKey) {
|
||||
return self.contextMenuExtensions[handlerKey].action;
|
||||
export const getCustomMenuItemHandler = function (handlerKey) {
|
||||
return contextMenuExtensions[handlerKey].action;
|
||||
};
|
||||
var injectExtendedContextMenuItemIntoDom = function (menuItem) {
|
||||
if (Object.keys(self.contextMenuExtensions).length === 0) {
|
||||
const injectExtendedContextMenuItemIntoDom = function (menuItem) {
|
||||
if (!Object.keys(contextMenuExtensions).length) {
|
||||
// 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.
|
||||
$('#cmenu_canvas').append("<li class='separator'>");
|
||||
}
|
||||
var shortcut = menuItem.shortcut || '';
|
||||
const shortcut = menuItem.shortcut || '';
|
||||
$('#cmenu_canvas').append("<li class='disabled'><a href='#" + menuItem.id + "'>" +
|
||||
menuItem.label + "<span class='shortcut'>" +
|
||||
shortcut + '</span></a></li>');
|
||||
};
|
||||
// Defer injection to wait out initial menu processing. This probably goes away once all context
|
||||
// menu behavior is brought here.
|
||||
svgEditor.ready(function () {
|
||||
var menuItem;
|
||||
for (menuItem in self.contextMenuExtensions) {
|
||||
injectExtendedContextMenuItemIntoDom(self.contextMenuExtensions[menuItem]);
|
||||
|
||||
export const injectExtendedContextMenuItemsIntoDom = function () {
|
||||
for (const menuItem in contextMenuExtensions) {
|
||||
injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]);
|
||||
}
|
||||
});
|
||||
svgedit.contextmenu.resetCustomMenus = function () { self.contextMenuExtensions = {}; };
|
||||
svgedit.contextmenu.add = addContextMenuItem;
|
||||
svgedit.contextmenu.hasCustomHandler = hasCustomHandler;
|
||||
svgedit.contextmenu.getCustomHandler = getCustomHandler;
|
||||
}());
|
||||
};
|
||||
export const resetCustomMenus = function () { contextMenuExtensions = {}; };
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals jQuery, $, svgedit */
|
||||
// Todo: Update to latest version and adapt (and needs jQuery update as well): https://github.com/swisnl/jQuery-contextMenu
|
||||
// jQuery Context Menu Plugin
|
||||
//
|
||||
// Version 1.01
|
||||
|
@ -15,191 +14,190 @@
|
|||
// This plugin is dual-licensed under the GNU General Public License
|
||||
// and the MIT License and is copyright A Beautiful Site, LLC.
|
||||
//
|
||||
if (jQuery) {
|
||||
(function () {
|
||||
var win = $(window);
|
||||
var doc = $(document);
|
||||
import {isMac} from './browser.js';
|
||||
|
||||
$.extend($.fn, {
|
||||
export default function ($) {
|
||||
const win = $(window);
|
||||
const doc = $(document);
|
||||
|
||||
contextMenu: function (o, callback) {
|
||||
// Defaults
|
||||
if (o.menu === undefined) return false;
|
||||
if (o.inSpeed === undefined) o.inSpeed = 150;
|
||||
if (o.outSpeed === undefined) o.outSpeed = 75;
|
||||
// 0 needs to be -1 for expected results (no fade)
|
||||
if (o.inSpeed === 0) o.inSpeed = -1;
|
||||
if (o.outSpeed === 0) o.outSpeed = -1;
|
||||
// Loop each context menu
|
||||
$(this).each(function () {
|
||||
var el = $(this);
|
||||
var offset = $(el).offset();
|
||||
$.extend($.fn, {
|
||||
contextMenu (o, callback) {
|
||||
// Defaults
|
||||
if (o.menu === undefined) return false;
|
||||
if (o.inSpeed === undefined) o.inSpeed = 150;
|
||||
if (o.outSpeed === undefined) o.outSpeed = 75;
|
||||
// 0 needs to be -1 for expected results (no fade)
|
||||
if (o.inSpeed === 0) o.inSpeed = -1;
|
||||
if (o.outSpeed === 0) o.outSpeed = -1;
|
||||
// Loop each context menu
|
||||
$(this).each(function () {
|
||||
const el = $(this);
|
||||
const offset = $(el).offset();
|
||||
|
||||
var menu = $('#' + o.menu);
|
||||
const menu = $('#' + o.menu);
|
||||
|
||||
// Add contextMenu class
|
||||
menu.addClass('contextMenu');
|
||||
// Simulate a true right click
|
||||
$(this).bind('mousedown', function (e) {
|
||||
var evt = e;
|
||||
$(this).mouseup(function (e) {
|
||||
var srcElement = $(this);
|
||||
srcElement.unbind('mouseup');
|
||||
if (evt.button === 2 || o.allowLeft ||
|
||||
(evt.ctrlKey && svgedit.browser.isMac())) {
|
||||
e.stopPropagation();
|
||||
// Hide context menus that may be showing
|
||||
$('.contextMenu').hide();
|
||||
// Get this context menu
|
||||
// Add contextMenu class
|
||||
menu.addClass('contextMenu');
|
||||
// Simulate a true right click
|
||||
$(this).bind('mousedown', function (e) {
|
||||
const evt = e;
|
||||
$(this).mouseup(function (e) {
|
||||
const srcElement = $(this);
|
||||
srcElement.unbind('mouseup');
|
||||
if (evt.button === 2 || o.allowLeft ||
|
||||
(evt.ctrlKey && isMac())) {
|
||||
e.stopPropagation();
|
||||
// Hide context menus that may be showing
|
||||
$('.contextMenu').hide();
|
||||
// Get this context menu
|
||||
|
||||
if (el.hasClass('disabled')) return false;
|
||||
if (el.hasClass('disabled')) return false;
|
||||
|
||||
// Detect mouse position
|
||||
var x = e.pageX, y = e.pageY;
|
||||
// Detect mouse position
|
||||
let x = e.pageX, y = e.pageY;
|
||||
|
||||
var xOff = win.width() - menu.width(),
|
||||
yOff = win.height() - menu.height();
|
||||
const xOff = win.width() - menu.width(),
|
||||
yOff = win.height() - menu.height();
|
||||
|
||||
if (x > xOff - 15) x = xOff - 15;
|
||||
if (y > yOff - 30) y = yOff - 30; // 30 is needed to prevent scrollbars in FF
|
||||
if (x > xOff - 15) x = xOff - 15;
|
||||
if (y > yOff - 30) y = yOff - 30; // 30 is needed to prevent scrollbars in FF
|
||||
|
||||
// Show the menu
|
||||
doc.unbind('click');
|
||||
menu.css({ top: y, left: x }).fadeIn(o.inSpeed);
|
||||
// Hover events
|
||||
menu.find('A').mouseover(function () {
|
||||
menu.find('LI.hover').removeClass('hover');
|
||||
$(this).parent().addClass('hover');
|
||||
}).mouseout(function () {
|
||||
menu.find('LI.hover').removeClass('hover');
|
||||
});
|
||||
// Show the menu
|
||||
doc.unbind('click');
|
||||
menu.css({ top: y, left: x }).fadeIn(o.inSpeed);
|
||||
// Hover events
|
||||
menu.find('A').mouseover(function () {
|
||||
menu.find('LI.hover').removeClass('hover');
|
||||
$(this).parent().addClass('hover');
|
||||
}).mouseout(function () {
|
||||
menu.find('LI.hover').removeClass('hover');
|
||||
});
|
||||
|
||||
// Keyboard
|
||||
doc.keypress(function (e) {
|
||||
switch (e.keyCode) {
|
||||
case 38: // up
|
||||
if (!menu.find('LI.hover').length) {
|
||||
menu.find('LI:last').addClass('hover');
|
||||
} else {
|
||||
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');
|
||||
}
|
||||
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;
|
||||
// Keyboard
|
||||
doc.keypress(function (e) {
|
||||
switch (e.keyCode) {
|
||||
case 38: // up
|
||||
if (!menu.find('LI.hover').length) {
|
||||
menu.find('LI:last').addClass('hover');
|
||||
} else {
|
||||
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');
|
||||
}
|
||||
});
|
||||
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
|
||||
menu.find('A').unbind('mouseup');
|
||||
menu.find('LI:not(.disabled) A').mouseup(function () {
|
||||
// When items are selected
|
||||
menu.find('A').unbind('mouseup');
|
||||
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');
|
||||
$('.contextMenu').hide();
|
||||
// Callback
|
||||
if (callback) callback($(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y});
|
||||
menu.fadeOut(o.outSpeed);
|
||||
return false;
|
||||
});
|
||||
|
||||
// Hide bindings
|
||||
setTimeout(function () { // Delay for Mozilla
|
||||
doc.click(function () {
|
||||
doc.unbind('click').unbind('keypress');
|
||||
menu.fadeOut(o.outSpeed);
|
||||
return false;
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}, 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
|
||||
disableContextMenuItems: function (o) {
|
||||
if (o === undefined) {
|
||||
// Disable all
|
||||
$(this).find('LI').addClass('disabled');
|
||||
return $(this);
|
||||
// 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; }); });
|
||||
}
|
||||
$(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().addClass('disabled');
|
||||
}
|
||||
}
|
||||
});
|
||||
return $(this);
|
||||
},
|
||||
// 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);
|
||||
},
|
||||
|
||||
// Enable context menu items on the fly
|
||||
enableContextMenuItems: function (o) {
|
||||
if (o === undefined) {
|
||||
// Enable all
|
||||
$(this).find('LI.disabled').removeClass('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');
|
||||
});
|
||||
// Disable context menu items on the fly
|
||||
disableContextMenuItems (o) {
|
||||
if (o === undefined) {
|
||||
// Disable all
|
||||
$(this).find('LI').addClass('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().addClass('disabled');
|
||||
}
|
||||
}
|
||||
});
|
||||
return $(this);
|
||||
},
|
||||
|
||||
});
|
||||
})(jQuery);
|
||||
// Enable context menu items on the fly
|
||||
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 $;
|
||||
}
|
||||
|
|
183
editor/coords.js
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals $, svgroot */
|
||||
/* globals jQuery */
|
||||
/**
|
||||
* Coords.
|
||||
*
|
||||
|
@ -8,25 +7,21 @@
|
|||
*/
|
||||
|
||||
// Dependencies:
|
||||
// 1) jquery.js
|
||||
// 2) math.js
|
||||
// 3) pathseg.js
|
||||
// 4) browser.js
|
||||
// 5) svgutils.js
|
||||
// 6) units.js
|
||||
// 7) svgtransformlist.js
|
||||
// 1) jquery.min.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 () {
|
||||
'use strict';
|
||||
|
||||
if (!svgedit.coords) {
|
||||
svgedit.coords = {};
|
||||
}
|
||||
const $ = jQuery;
|
||||
|
||||
// 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'];
|
||||
|
||||
/**
|
||||
|
@ -35,12 +30,12 @@ var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
|
|||
* @property {function} getGridSnapping
|
||||
* @property {function} getDrawing
|
||||
*/
|
||||
var editorContext_ = null;
|
||||
let editorContext_ = null;
|
||||
|
||||
/**
|
||||
* @param {editorContext} editorContext
|
||||
*/
|
||||
svgedit.coords.init = function (editorContext) {
|
||||
export const init = function (editorContext) {
|
||||
editorContext_ = editorContext;
|
||||
};
|
||||
|
||||
|
@ -50,47 +45,45 @@ svgedit.coords.init = function (editorContext) {
|
|||
* @param {Object} changes - Object with changes to be remapped
|
||||
* @param {SVGMatrix} m - Matrix object to use for remapping coordinates
|
||||
*/
|
||||
svgedit.coords.remapElement = function (selected, changes, m) {
|
||||
var i, type,
|
||||
remap = function (x, y) { return svgedit.math.transformPoint(x, y, m); },
|
||||
export const remapElement = function (selected, changes, m) {
|
||||
const remap = function (x, y) { return transformPoint(x, y, m); },
|
||||
scalew = function (w) { return m.a * w; },
|
||||
scaleh = function (h) { return m.d * h; },
|
||||
doSnapping = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg',
|
||||
finishUp = function () {
|
||||
var o;
|
||||
if (doSnapping) {
|
||||
for (o in changes) {
|
||||
changes[o] = svgedit.utilities.snapToGrid(changes[o]);
|
||||
for (const o in changes) {
|
||||
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++) {
|
||||
type = i === 0 ? 'fill' : 'stroke';
|
||||
var attrVal = selected.getAttribute(type);
|
||||
if (attrVal && attrVal.indexOf('url(') === 0) {
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const type = i === 0 ? 'fill' : 'stroke';
|
||||
const attrVal = selected.getAttribute(type);
|
||||
if (attrVal && attrVal.startsWith('url(')) {
|
||||
if (m.a < 0 || m.d < 0) {
|
||||
var grad = svgedit.utilities.getRefElem(attrVal);
|
||||
var newgrad = grad.cloneNode(true);
|
||||
const grad = getRefElem(attrVal);
|
||||
const newgrad = grad.cloneNode(true);
|
||||
if (m.a < 0) {
|
||||
// flip x
|
||||
var x1 = newgrad.getAttribute('x1');
|
||||
var x2 = newgrad.getAttribute('x2');
|
||||
const x1 = newgrad.getAttribute('x1');
|
||||
const x2 = newgrad.getAttribute('x2');
|
||||
newgrad.setAttribute('x1', -(x1 - 1));
|
||||
newgrad.setAttribute('x2', -(x2 - 1));
|
||||
}
|
||||
|
||||
if (m.d < 0) {
|
||||
// flip y
|
||||
var y1 = newgrad.getAttribute('y1');
|
||||
var y2 = newgrad.getAttribute('y2');
|
||||
const y1 = newgrad.getAttribute('y1');
|
||||
const y2 = newgrad.getAttribute('y2');
|
||||
newgrad.setAttribute('y1', -(y1 - 1));
|
||||
newgrad.setAttribute('y2', -(y2 - 1));
|
||||
}
|
||||
newgrad.id = editorContext_.getDrawing().getNextId();
|
||||
svgedit.utilities.findDefs().appendChild(newgrad);
|
||||
findDefs().appendChild(newgrad);
|
||||
selected.setAttribute(type, 'url(#' + newgrad.id + ')');
|
||||
}
|
||||
|
||||
|
@ -101,43 +94,42 @@ svgedit.coords.remapElement = function (selected, changes, m) {
|
|||
}
|
||||
}
|
||||
|
||||
var elName = selected.tagName;
|
||||
var chlist, mt;
|
||||
const elName = selected.tagName;
|
||||
if (elName === 'g' || elName === 'text' || elName === 'tspan' || elName === 'use') {
|
||||
// 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)) {
|
||||
// [T][M] = [M][T']
|
||||
// therefore [T'] = [M_inv][T][M]
|
||||
var existing = svgedit.math.transformListToTransform(selected).matrix,
|
||||
tNew = svgedit.math.matrixMultiply(existing.inverse(), m, existing);
|
||||
const existing = transformListToTransform(selected).matrix,
|
||||
tNew = matrixMultiply(existing.inverse(), m, existing);
|
||||
changes.x = parseFloat(changes.x) + tNew.e;
|
||||
changes.y = parseFloat(changes.y) + tNew.f;
|
||||
} else {
|
||||
// we just absorb all matrices into the element and don't do any remapping
|
||||
chlist = svgedit.transformlist.getTransformList(selected);
|
||||
mt = svgroot.createSVGTransform();
|
||||
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
|
||||
const chlist = getTransformList(selected);
|
||||
const mt = editorContext_.getSVGRoot().createSVGTransform();
|
||||
mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m));
|
||||
chlist.clear();
|
||||
chlist.appendItem(mt);
|
||||
}
|
||||
}
|
||||
var c, pt, pt1, pt2, len;
|
||||
|
||||
// now we have a set of changes and an applied reduced transform list
|
||||
// we apply the changes directly to the DOM
|
||||
switch (elName) {
|
||||
case 'foreignObject':
|
||||
case 'rect':
|
||||
case 'image':
|
||||
case 'image': {
|
||||
// Allow images to be inverted (give them matrix when flipped)
|
||||
if (elName === 'image' && (m.a < 0 || m.d < 0)) {
|
||||
// Convert to matrix
|
||||
chlist = svgedit.transformlist.getTransformList(selected);
|
||||
mt = svgroot.createSVGTransform();
|
||||
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
|
||||
const chlist = getTransformList(selected);
|
||||
const mt = editorContext_.getSVGRoot().createSVGTransform();
|
||||
mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m));
|
||||
chlist.clear();
|
||||
chlist.appendItem(mt);
|
||||
} else {
|
||||
pt1 = remap(changes.x, changes.y);
|
||||
const pt1 = remap(changes.x, changes.y);
|
||||
changes.width = scalew(changes.width);
|
||||
changes.height = scaleh(changes.height);
|
||||
changes.x = pt1.x + Math.min(0, changes.width);
|
||||
|
@ -147,8 +139,8 @@ svgedit.coords.remapElement = function (selected, changes, m) {
|
|||
}
|
||||
finishUp();
|
||||
break;
|
||||
case 'ellipse':
|
||||
c = remap(changes.cx, changes.cy);
|
||||
} case 'ellipse': {
|
||||
const c = remap(changes.cx, changes.cy);
|
||||
changes.cx = c.x;
|
||||
changes.cy = c.y;
|
||||
changes.rx = scalew(changes.rx);
|
||||
|
@ -157,62 +149,61 @@ svgedit.coords.remapElement = function (selected, changes, m) {
|
|||
changes.ry = Math.abs(changes.ry);
|
||||
finishUp();
|
||||
break;
|
||||
case 'circle':
|
||||
c = remap(changes.cx, changes.cy);
|
||||
} case 'circle': {
|
||||
const c = remap(changes.cx, changes.cy);
|
||||
changes.cx = c.x;
|
||||
changes.cy = c.y;
|
||||
// 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);
|
||||
var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y;
|
||||
const tbox = transformBox(box.x, box.y, box.width, box.height, m);
|
||||
const w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y;
|
||||
changes.r = Math.min(w / 2, h / 2);
|
||||
|
||||
if (changes.r) { changes.r = Math.abs(changes.r); }
|
||||
finishUp();
|
||||
break;
|
||||
case 'line':
|
||||
pt1 = remap(changes.x1, changes.y1);
|
||||
pt2 = remap(changes.x2, changes.y2);
|
||||
} case 'line': {
|
||||
const pt1 = remap(changes.x1, changes.y1);
|
||||
const pt2 = remap(changes.x2, changes.y2);
|
||||
changes.x1 = pt1.x;
|
||||
changes.y1 = pt1.y;
|
||||
changes.x2 = pt2.x;
|
||||
changes.y2 = pt2.y;
|
||||
// deliberately fall through here
|
||||
} // Fallthrough
|
||||
case 'text':
|
||||
case 'tspan':
|
||||
case 'use':
|
||||
case 'use': {
|
||||
finishUp();
|
||||
break;
|
||||
case 'g':
|
||||
var gsvg = $(selected).data('gsvg');
|
||||
} case 'g': {
|
||||
const gsvg = $(selected).data('gsvg');
|
||||
if (gsvg) {
|
||||
svgedit.utilities.assignAttributes(gsvg, changes, 1000, true);
|
||||
assignAttributes(gsvg, changes, 1000, true);
|
||||
}
|
||||
break;
|
||||
case 'polyline':
|
||||
case 'polygon':
|
||||
len = changes.points.length;
|
||||
for (i = 0; i < len; ++i) {
|
||||
pt = changes.points[i];
|
||||
pt = remap(pt.x, pt.y);
|
||||
changes.points[i].x = pt.x;
|
||||
changes.points[i].y = pt.y;
|
||||
} case 'polyline':
|
||||
case 'polygon': {
|
||||
const len = changes.points.length;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const pt = changes.points[i];
|
||||
const {x, y} = remap(pt.x, pt.y);
|
||||
changes.points[i].x = x;
|
||||
changes.points[i].y = y;
|
||||
}
|
||||
|
||||
len = changes.points.length;
|
||||
var pstr = '';
|
||||
for (i = 0; i < len; ++i) {
|
||||
pt = changes.points[i];
|
||||
// const len = changes.points.length;
|
||||
let pstr = '';
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const pt = changes.points[i];
|
||||
pstr += pt.x + ',' + pt.y + ' ';
|
||||
}
|
||||
selected.setAttribute('points', pstr);
|
||||
break;
|
||||
case 'path':
|
||||
var seg;
|
||||
var segList = selected.pathSegList;
|
||||
len = segList.numberOfItems;
|
||||
} case 'path': {
|
||||
const segList = selected.pathSegList;
|
||||
let len = segList.numberOfItems;
|
||||
changes.d = [];
|
||||
for (i = 0; i < len; ++i) {
|
||||
seg = segList.getItem(i);
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const seg = segList.getItem(i);
|
||||
changes.d[i] = {
|
||||
type: seg.pathSegType,
|
||||
x: seg.x,
|
||||
|
@ -230,21 +221,21 @@ svgedit.coords.remapElement = function (selected, changes, m) {
|
|||
}
|
||||
|
||||
len = changes.d.length;
|
||||
var firstseg = changes.d[0],
|
||||
const firstseg = changes.d[0],
|
||||
currentpt = remap(firstseg.x, firstseg.y);
|
||||
changes.d[0].x = currentpt.x;
|
||||
changes.d[0].y = currentpt.y;
|
||||
for (i = 1; i < len; ++i) {
|
||||
seg = changes.d[i];
|
||||
type = seg.type;
|
||||
for (let i = 1; i < len; ++i) {
|
||||
const seg = changes.d[i];
|
||||
const {type} = seg;
|
||||
// if absolute or first segment, we want to remap x, y, x1, y1, x2, y2
|
||||
// if relative, we want to scalew, scaleh
|
||||
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
|
||||
pt = remap(thisx, thisy);
|
||||
pt1 = remap(seg.x1, seg.y1);
|
||||
pt2 = remap(seg.x2, seg.y2);
|
||||
const pt = remap(thisx, thisy);
|
||||
const pt1 = remap(seg.x1, seg.y1);
|
||||
const pt2 = remap(seg.x2, seg.y2);
|
||||
seg.x = pt.x;
|
||||
seg.y = pt.y;
|
||||
seg.x1 = pt1.x;
|
||||
|
@ -265,11 +256,11 @@ svgedit.coords.remapElement = function (selected, changes, m) {
|
|||
}
|
||||
} // for each segment
|
||||
|
||||
var dstr = '';
|
||||
let dstr = '';
|
||||
len = changes.d.length;
|
||||
for (i = 0; i < len; ++i) {
|
||||
seg = changes.d[i];
|
||||
type = seg.type;
|
||||
for (let i = 0; i < len; ++i) {
|
||||
const seg = changes.d[i];
|
||||
const {type} = seg;
|
||||
dstr += pathMap[type];
|
||||
switch (type) {
|
||||
case 13: // relative horizontal line (h)
|
||||
|
@ -312,5 +303,5 @@ svgedit.coords.remapElement = function (selected, changes, m) {
|
|||
selected.setAttribute('d', dstr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
|
1195
editor/draw.js
|
@ -1,21 +1,21 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals $, EmbeddedSVGEdit */
|
||||
var initEmbed; // eslint-disable-line no-unused-vars
|
||||
/* globals jQuery */
|
||||
import EmbeddedSVGEdit from './embedapi.js';
|
||||
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 () {
|
||||
'use strict';
|
||||
|
||||
var svgCanvas = null;
|
||||
var frame;
|
||||
let svgCanvas = null;
|
||||
|
||||
initEmbed = function () {
|
||||
var doc, mainButton;
|
||||
svgCanvas = new EmbeddedSVGEdit(frame);
|
||||
// Hide main button, as we will be controlling new, load, save, etc. from the host document
|
||||
doc = frame.contentDocument || frame.contentWindow.document;
|
||||
mainButton = doc.getElementById('main_button');
|
||||
const doc = frame.contentDocument || frame.contentWindow.document;
|
||||
const mainButton = doc.getElementById('main_button');
|
||||
mainButton.style.display = 'none';
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@ $(function () {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,9 @@ $(function () {
|
|||
}
|
||||
|
||||
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>'),
|
||||
'svg-edit-exportWindow'
|
||||
);
|
||||
|
@ -47,7 +47,7 @@ $(function () {
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -58,7 +58,7 @@ $(function () {
|
|||
return;
|
||||
*/
|
||||
|
||||
var exportWindow = window.open(
|
||||
const exportWindow = window.open(
|
||||
'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'),
|
||||
'svg-edit-exportWindow'
|
||||
);
|
||||
|
@ -76,5 +76,5 @@ $(function () {
|
|||
'" width="900px" height="600px" id="svgedit" onload="initEmbed();"></iframe>'
|
||||
)
|
||||
);
|
||||
frame = document.getElementById('svgedit');
|
||||
const frame = document.getElementById('svgedit');
|
||||
});
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Embed API</title>
|
||||
<script src="jquery.js"></script>
|
||||
<script src="embedapi.js"></script>
|
||||
<script src="embedapi-dom.js"></script>
|
||||
<link rel="icon" type="image/png" href="images/logo.png"/>
|
||||
<script src="jquery.min.js"></script>
|
||||
<script type="module" src="embedapi-dom.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<button id="load">Load example</button>
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
/* eslint-disable no-var */
|
||||
/*
|
||||
Embedded SVG-edit API
|
||||
|
||||
General usage:
|
||||
- Have an iframe somewhere pointing to a version of svg-edit > r1000
|
||||
- Initialize the magic with:
|
||||
var svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
|
||||
const svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
|
||||
- Pass functions in this format:
|
||||
svgCanvas.setSvgString('string')
|
||||
- Or if a callback is needed:
|
||||
|
@ -32,18 +31,15 @@ JavaScript methods on the frame itself.
|
|||
The only other difference is
|
||||
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)})
|
||||
*/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var cbid = 0;
|
||||
let cbid = 0;
|
||||
|
||||
function getCallbackSetter (d) {
|
||||
return function () {
|
||||
var t = this, // New callback
|
||||
const t = this, // New callback
|
||||
args = [].slice.call(arguments),
|
||||
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
|
||||
*/
|
||||
function addCallback (t, data) {
|
||||
var result = data.result || data.error,
|
||||
const result = data.result || data.error,
|
||||
cbid = data.id;
|
||||
if (t.callbacks[cbid]) {
|
||||
if (data.result) {
|
||||
|
@ -76,11 +72,11 @@ function messageListener (e) {
|
|||
if (typeof e.data !== 'string') {
|
||||
return;
|
||||
}
|
||||
var allowedOrigins = this.allowedOrigins,
|
||||
const {allowedOrigins} = this,
|
||||
data = e.data && JSON.parse(e.data);
|
||||
if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' ||
|
||||
e.source !== this.frame.contentWindow ||
|
||||
(allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1)
|
||||
(!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -99,80 +95,77 @@ function getMessageListener (t) {
|
|||
* 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
|
||||
*/
|
||||
function EmbeddedSVGEdit (frame, allowedOrigins) {
|
||||
if (!(this instanceof EmbeddedSVGEdit)) { // Allow invocation without 'new' keyword
|
||||
return new EmbeddedSVGEdit(frame);
|
||||
}
|
||||
this.allowedOrigins = allowedOrigins || [];
|
||||
// Initialize communication
|
||||
this.frame = frame;
|
||||
this.callbacks = {};
|
||||
// List of functions extracted with this:
|
||||
// Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
|
||||
class EmbeddedSVGEdit {
|
||||
constructor (frame, allowedOrigins) {
|
||||
this.allowedOrigins = allowedOrigins || [];
|
||||
// Initialize communication
|
||||
this.frame = frame;
|
||||
this.callbacks = {};
|
||||
// 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
|
||||
// var functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString',
|
||||
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
|
||||
// 'moveSelectedToLayer', 'clear'];
|
||||
// for (const i=0,q=[],f = document.querySelectorAll('div.CFunction h3.CTitle a'); i < f.length; i++) { q.push(f[i].name); }; q
|
||||
// const functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString',
|
||||
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
|
||||
// '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
|
||||
// var svgCanvas = frame.contentWindow.svgCanvas;
|
||||
// var l = []; for (var i in svgCanvas){ if (typeof svgCanvas[i] == 'function') { l.push(i);} };
|
||||
// alert("['" + l.join("', '") + "']");
|
||||
// Run in svgedit itself
|
||||
var i,
|
||||
functions = [
|
||||
// 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
|
||||
// const {svgCanvas} = frame.contentWindow;
|
||||
// const l = [];
|
||||
// for (const i in svgCanvas) { if (typeof svgCanvas[i] === 'function') { l.push(i);} };
|
||||
// alert("['" + l.join("', '") + "']");
|
||||
// Run in svgedit itself
|
||||
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'
|
||||
];
|
||||
|
||||
// TODO: rewrite the following, it's pretty scary.
|
||||
for (i = 0; i < functions.length; i++) {
|
||||
this[functions[i]] = getCallbackSetter(functions[i]);
|
||||
// TODO: rewrite the following, it's pretty scary.
|
||||
for (let i = 0; i < functions.length; 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
|
||||
window.addEventListener('message', getMessageListener(this), false);
|
||||
send (name, args, callback) {
|
||||
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) {
|
||||
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
|
||||
}());
|
||||
export default EmbeddedSVGEdit;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgCanvas, $ */
|
||||
/* globals jQuery, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-arrows.js
|
||||
*
|
||||
|
@ -10,11 +9,10 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('Arrows', function (S) {
|
||||
var // svgcontent = S.svgcontent,
|
||||
const $ = jQuery;
|
||||
const // {svgcontent} = S,
|
||||
addElem = S.addSvgElementFromJson,
|
||||
nonce = S.nonce,
|
||||
randomizeIds = S.randomize_ids,
|
||||
selElems, pathdata,
|
||||
{nonce} = S,
|
||||
langList = {
|
||||
'en': [
|
||||
{'id': 'arrow_none', 'textContent': 'No arrow'}
|
||||
|
@ -23,9 +21,10 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
{'id': 'arrow_none', 'textContent': 'Sans flèche'}
|
||||
]
|
||||
},
|
||||
arrowprefix,
|
||||
prefix = 'se_arrow_';
|
||||
|
||||
let selElems, arrowprefix, randomizeIds = S.randomize_ids;
|
||||
|
||||
function setArrowNonce (window, n) {
|
||||
randomizeIds = true;
|
||||
arrowprefix = prefix + n + '_';
|
||||
|
@ -49,15 +48,15 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
arrowprefix = prefix;
|
||||
}
|
||||
|
||||
pathdata = {
|
||||
const pathdata = {
|
||||
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'}
|
||||
};
|
||||
|
||||
function getLinked (elem, attr) {
|
||||
var str = elem.getAttribute(attr);
|
||||
const str = elem.getAttribute(attr);
|
||||
if (!str) { return null; }
|
||||
var m = str.match(/\(#(.*)\)/);
|
||||
const m = str.match(/\(#(.*)\)/);
|
||||
if (!m || m.length !== 2) {
|
||||
return null;
|
||||
}
|
||||
|
@ -67,12 +66,11 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
function showPanel (on) {
|
||||
$('#arrow_panel').toggle(on);
|
||||
if (on) {
|
||||
var el = selElems[0];
|
||||
var end = el.getAttribute('marker-end');
|
||||
var start = el.getAttribute('marker-start');
|
||||
var mid = el.getAttribute('marker-mid');
|
||||
var val;
|
||||
|
||||
const el = selElems[0];
|
||||
const end = el.getAttribute('marker-end');
|
||||
const start = el.getAttribute('marker-start');
|
||||
const mid = el.getAttribute('marker-mid');
|
||||
let val;
|
||||
if (end && start) {
|
||||
val = 'both';
|
||||
} else if (end) {
|
||||
|
@ -81,7 +79,7 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
val = 'start';
|
||||
} else if (mid) {
|
||||
val = 'mid';
|
||||
if (mid.indexOf('bk') !== -1) {
|
||||
if (mid.includes('bk')) {
|
||||
val = 'mid_bk';
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +93,7 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
}
|
||||
|
||||
function resetMarker () {
|
||||
var el = selElems[0];
|
||||
const el = selElems[0];
|
||||
el.removeAttribute('marker-start');
|
||||
el.removeAttribute('marker-mid');
|
||||
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
|
||||
id = id || arrowprefix + dir;
|
||||
|
||||
var marker = S.getElem(id);
|
||||
var data = pathdata[dir];
|
||||
const data = pathdata[dir];
|
||||
|
||||
if (type === 'mid') {
|
||||
data.refx = 5;
|
||||
}
|
||||
|
||||
let marker = S.getElem(id);
|
||||
if (!marker) {
|
||||
marker = addElem({
|
||||
'element': 'marker',
|
||||
'attr': {
|
||||
'viewBox': '0 0 10 10',
|
||||
'id': id,
|
||||
'refY': 5,
|
||||
'markerUnits': 'strokeWidth',
|
||||
'markerWidth': 5,
|
||||
'markerHeight': 5,
|
||||
'orient': 'auto',
|
||||
'style': 'pointer-events:none' // Currently needed for Opera
|
||||
element: 'marker',
|
||||
attr: {
|
||||
viewBox: '0 0 10 10',
|
||||
id,
|
||||
refY: 5,
|
||||
markerUnits: 'strokeWidth',
|
||||
markerWidth: 5,
|
||||
markerHeight: 5,
|
||||
orient: 'auto',
|
||||
style: 'pointer-events:none' // Currently needed for Opera
|
||||
}
|
||||
});
|
||||
var arrow = addElem({
|
||||
'element': 'path',
|
||||
'attr': {
|
||||
'd': data.d,
|
||||
'fill': '#000000'
|
||||
const arrow = addElem({
|
||||
element: 'path',
|
||||
attr: {
|
||||
d: data.d,
|
||||
fill: '#000000'
|
||||
}
|
||||
});
|
||||
marker.appendChild(arrow);
|
||||
|
@ -143,15 +141,15 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
}
|
||||
|
||||
function setArrow () {
|
||||
var type = this.value;
|
||||
resetMarker();
|
||||
|
||||
let type = this.value;
|
||||
if (type === 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set marker on element
|
||||
var dir = 'fw';
|
||||
let dir = 'fw';
|
||||
if (type === 'mid_bk') {
|
||||
type = 'mid';
|
||||
dir = 'bk';
|
||||
|
@ -170,23 +168,23 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
}
|
||||
|
||||
function colorChanged (elem) {
|
||||
var color = elem.getAttribute('stroke');
|
||||
var mtypes = ['start', 'mid', 'end'];
|
||||
var defs = S.findDefs();
|
||||
const color = elem.getAttribute('stroke');
|
||||
const mtypes = ['start', 'mid', 'end'];
|
||||
const defs = S.findDefs();
|
||||
|
||||
$.each(mtypes, function (i, type) {
|
||||
var marker = getLinked(elem, 'marker-' + type);
|
||||
const marker = getLinked(elem, 'marker-' + type);
|
||||
if (!marker) { return; }
|
||||
|
||||
var curColor = $(marker).children().attr('fill');
|
||||
var curD = $(marker).children().attr('d');
|
||||
var newMarker = null;
|
||||
const curColor = $(marker).children().attr('fill');
|
||||
const curD = $(marker).children().attr('d');
|
||||
if (curColor === color) { return; }
|
||||
|
||||
var allMarkers = $(defs).find('marker');
|
||||
const allMarkers = $(defs).find('marker');
|
||||
let newMarker = null;
|
||||
// Different color, check if already made
|
||||
allMarkers.each(function () {
|
||||
var attrs = $(this).children().attr(['fill', 'd']);
|
||||
const attrs = $(this).children().attr(['fill', 'd']);
|
||||
if (attrs.fill === color && attrs.d === curD) {
|
||||
// Found another marker with this color and this path
|
||||
newMarker = this;
|
||||
|
@ -195,8 +193,8 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
|
||||
if (!newMarker) {
|
||||
// Create a new marker with this color
|
||||
var lastId = marker.id;
|
||||
var dir = lastId.indexOf('_fw') !== -1 ? 'fw' : 'bk';
|
||||
const lastId = marker.id;
|
||||
const dir = lastId.includes('_fw') ? 'fw' : 'bk';
|
||||
|
||||
newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length);
|
||||
|
||||
|
@ -206,9 +204,9 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
$(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')');
|
||||
|
||||
// Check if last marker can be removed
|
||||
var remove = true;
|
||||
let remove = true;
|
||||
$(S.svgcontent).find('line, polyline, path, polygon').each(function () {
|
||||
var elem = this;
|
||||
const elem = this;
|
||||
$.each(mtypes, function (j, mtype) {
|
||||
if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') {
|
||||
remove = false;
|
||||
|
@ -245,25 +243,25 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
change: setArrow
|
||||
}
|
||||
}],
|
||||
callback: function () {
|
||||
callback () {
|
||||
$('#arrow_panel').hide();
|
||||
// Set ID so it can be translated in locale file
|
||||
$('#arrow_list option')[0].id = 'connector_no_arrow';
|
||||
},
|
||||
addLangData: function (lang) {
|
||||
addLangData (lang) {
|
||||
return {
|
||||
data: langList[lang]
|
||||
};
|
||||
},
|
||||
selectedChanged: function (opts) {
|
||||
selectedChanged (opts) {
|
||||
// Use this to update the current selected elements
|
||||
selElems = opts.elems;
|
||||
|
||||
var i = selElems.length;
|
||||
var markerElems = ['line', 'path', 'polyline', 'polygon'];
|
||||
const markerElems = ['line', 'path', 'polyline', 'polygon'];
|
||||
let i = selElems.length;
|
||||
while (i--) {
|
||||
var elem = selElems[i];
|
||||
if (elem && $.inArray(elem.tagName, markerElems) !== -1) {
|
||||
const elem = selElems[i];
|
||||
if (elem && markerElems.includes(elem.tagName)) {
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
showPanel(true);
|
||||
} else {
|
||||
|
@ -274,16 +272,16 @@ svgEditor.addExtension('Arrows', function (S) {
|
|||
}
|
||||
}
|
||||
},
|
||||
elementChanged: function (opts) {
|
||||
var elem = opts.elems[0];
|
||||
elementChanged (opts) {
|
||||
const elem = opts.elems[0];
|
||||
if (elem && (
|
||||
elem.getAttribute('marker-start') ||
|
||||
elem.getAttribute('marker-mid') ||
|
||||
elem.getAttribute('marker-end')
|
||||
)) {
|
||||
// var start = elem.getAttribute('marker-start');
|
||||
// var mid = elem.getAttribute('marker-mid');
|
||||
// var end = elem.getAttribute('marker-end');
|
||||
// const start = elem.getAttribute('marker-start');
|
||||
// const mid = elem.getAttribute('marker-mid');
|
||||
// const end = elem.getAttribute('marker-end');
|
||||
// Has marker, so see if it should match color
|
||||
colorChanged(elem);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, $ */
|
||||
/* globals jQuery, svgEditor */
|
||||
/*
|
||||
* ext-closepath.js
|
||||
*
|
||||
|
@ -8,41 +7,42 @@
|
|||
* Copyright(c) 2010 Jeff Schiller
|
||||
*
|
||||
*/
|
||||
// import './pathseg.js';
|
||||
|
||||
// This extension adds a simple button to the contextual panel for paths
|
||||
// The button toggles whether the path is open or closed
|
||||
svgEditor.addExtension('ClosePath', function () {
|
||||
'use strict';
|
||||
var selElems,
|
||||
updateButton = function (path) {
|
||||
var seglist = path.pathSegList,
|
||||
closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1,
|
||||
showbutton = closed ? '#tool_openpath' : '#tool_closepath',
|
||||
hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
|
||||
$(hidebutton).hide();
|
||||
$(showbutton).show();
|
||||
},
|
||||
showPanel = function (on) {
|
||||
$('#closepath_panel').toggle(on);
|
||||
if (on) {
|
||||
var path = selElems[0];
|
||||
if (path) { updateButton(path); }
|
||||
const $ = jQuery;
|
||||
let selElems;
|
||||
const updateButton = function (path) {
|
||||
const seglist = path.pathSegList,
|
||||
closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1,
|
||||
showbutton = closed ? '#tool_openpath' : '#tool_closepath',
|
||||
hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
|
||||
$(hidebutton).hide();
|
||||
$(showbutton).show();
|
||||
};
|
||||
const showPanel = function (on) {
|
||||
$('#closepath_panel').toggle(on);
|
||||
if (on) {
|
||||
const path = selElems[0];
|
||||
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());
|
||||
}
|
||||
},
|
||||
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);
|
||||
}
|
||||
};
|
||||
updateButton(path);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
name: 'ClosePath',
|
||||
|
@ -53,7 +53,7 @@ svgEditor.addExtension('ClosePath', function () {
|
|||
panel: 'closepath_panel',
|
||||
title: 'Open path',
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
toggleClosed();
|
||||
}
|
||||
}
|
||||
|
@ -64,19 +64,19 @@ svgEditor.addExtension('ClosePath', function () {
|
|||
panel: 'closepath_panel',
|
||||
title: 'Close path',
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
toggleClosed();
|
||||
}
|
||||
}
|
||||
}],
|
||||
callback: function () {
|
||||
callback () {
|
||||
$('#closepath_panel').hide();
|
||||
},
|
||||
selectedChanged: function (opts) {
|
||||
selectedChanged (opts) {
|
||||
selElems = opts.elems;
|
||||
var i = selElems.length;
|
||||
let i = selElems.length;
|
||||
while (i--) {
|
||||
var elem = selElems[i];
|
||||
const elem = selElems[i];
|
||||
if (elem && elem.tagName === 'path') {
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
showPanel(true);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgCanvas, $ */
|
||||
/* globals jQuery, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-connector.js
|
||||
*
|
||||
|
@ -10,27 +9,26 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('Connector', function (S) {
|
||||
var svgcontent = S.svgcontent,
|
||||
svgroot = S.svgroot,
|
||||
getNextId = S.getNextId,
|
||||
getElem = S.getElem,
|
||||
const $ = jQuery;
|
||||
const {svgroot, getNextId, getElem, curConfig} = S,
|
||||
addElem = S.addSvgElementFromJson,
|
||||
selManager = S.selectorManager,
|
||||
curConfig = svgEditor.curConfig,
|
||||
started = false,
|
||||
startX,
|
||||
connSel = '.se_connector',
|
||||
// connect_str = '-SE_CONNECT-',
|
||||
elData = $.data;
|
||||
|
||||
let startX,
|
||||
startY,
|
||||
curLine,
|
||||
startElem,
|
||||
endElem,
|
||||
connections = [],
|
||||
connSel = '.se_connector',
|
||||
seNs,
|
||||
// connect_str = '-SE_CONNECT-',
|
||||
selElems = [],
|
||||
elData = $.data;
|
||||
{svgcontent} = S,
|
||||
started = false,
|
||||
connections = [],
|
||||
selElems = [];
|
||||
|
||||
var langList = {
|
||||
const langList = {
|
||||
'en': [
|
||||
{'id': 'mode_connect', 'title': 'Connect two objects'}
|
||||
],
|
||||
|
@ -49,15 +47,14 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
bb.y -= offset / 2;
|
||||
}
|
||||
|
||||
var midX = bb.x + bb.width / 2;
|
||||
var midY = bb.y + bb.height / 2;
|
||||
var lenX = x - midX;
|
||||
var lenY = y - midY;
|
||||
const midX = bb.x + bb.width / 2;
|
||||
const midY = bb.y + bb.height / 2;
|
||||
const lenX = x - midX;
|
||||
const lenY = y - midY;
|
||||
|
||||
var slope = Math.abs(lenY / lenX);
|
||||
|
||||
var ratio;
|
||||
const slope = Math.abs(lenY / lenX);
|
||||
|
||||
let ratio;
|
||||
if (slope < bb.height / bb.width) {
|
||||
ratio = (bb.width / 2) / Math.abs(lenX);
|
||||
} else {
|
||||
|
@ -71,16 +68,16 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
}
|
||||
|
||||
function getOffset (side, line) {
|
||||
var giveOffset = !!line.getAttribute('marker-' + side);
|
||||
// var giveOffset = $(line).data(side+'_off');
|
||||
const giveOffset = !!line.getAttribute('marker-' + side);
|
||||
// const giveOffset = $(line).data(side+'_off');
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
function showPanel (on) {
|
||||
var connRules = $('#connector_rules');
|
||||
let connRules = $('#connector_rules');
|
||||
if (!connRules.length) {
|
||||
connRules = $('<style id="connector_rules"></style>').appendTo('head');
|
||||
}
|
||||
|
@ -89,8 +86,8 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
}
|
||||
|
||||
function setPoint (elem, pos, x, y, setMid) {
|
||||
var i, pts = elem.points;
|
||||
var pt = svgroot.createSVGPoint();
|
||||
const pts = elem.points;
|
||||
const pt = svgroot.createSVGPoint();
|
||||
pt.x = x;
|
||||
pt.y = y;
|
||||
if (pos === 'end') { pos = pts.numberOfItems - 1; }
|
||||
|
@ -99,8 +96,8 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
pts.replaceItem(pt, pos);
|
||||
} catch (err) {
|
||||
// Should only occur in FF which formats points attr as "n,n n,n", so just split
|
||||
var ptArr = elem.getAttribute('points').split(' ');
|
||||
for (i = 0; i < ptArr.length; i++) {
|
||||
const ptArr = elem.getAttribute('points').split(' ');
|
||||
for (let i = 0; i < ptArr.length; i++) {
|
||||
if (i === pos) {
|
||||
ptArr[i] = x + ',' + y;
|
||||
}
|
||||
|
@ -110,67 +107,69 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
|
||||
if (setMid) {
|
||||
// Add center point
|
||||
var ptStart = pts.getItem(0);
|
||||
var ptEnd = pts.getItem(pts.numberOfItems - 1);
|
||||
const ptStart = pts.getItem(0);
|
||||
const ptEnd = pts.getItem(pts.numberOfItems - 1);
|
||||
setPoint(elem, 1, (ptEnd.x + ptStart.x) / 2, (ptEnd.y + ptStart.y) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
function updateLine (diffX, diffY) {
|
||||
// Update line with element
|
||||
var i = connections.length;
|
||||
let i = connections.length;
|
||||
while (i--) {
|
||||
var conn = connections[i];
|
||||
var line = conn.connector;
|
||||
// var elem = conn.elem;
|
||||
const conn = connections[i];
|
||||
const line = conn.connector;
|
||||
// const {elem} = conn;
|
||||
|
||||
var pre = conn.is_start ? 'start' : 'end';
|
||||
// var sw = line.getAttribute('stroke-width') * 5;
|
||||
const pre = conn.is_start ? 'start' : 'end';
|
||||
// const sw = line.getAttribute('stroke-width') * 5;
|
||||
|
||||
// Update bbox for this element
|
||||
var bb = elData(line, pre + '_bb');
|
||||
const bb = elData(line, pre + '_bb');
|
||||
bb.x = conn.start_x + diffX;
|
||||
bb.y = conn.start_y + diffY;
|
||||
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
|
||||
var bb2 = elData(line, altPre + '_bb');
|
||||
var srcX = bb2.x + bb2.width / 2;
|
||||
var srcY = bb2.y + bb2.height / 2;
|
||||
const bb2 = elData(line, altPre + '_bb');
|
||||
const srcX = bb2.x + bb2.width / 2;
|
||||
const srcY = bb2.y + bb2.height / 2;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
function findConnectors (elems) {
|
||||
var i;
|
||||
if (!elems) { elems = selElems; }
|
||||
var connectors = $(svgcontent).find(connSel);
|
||||
/**
|
||||
*
|
||||
* @param {array} [elem=selElems] Array of elements
|
||||
*/
|
||||
function findConnectors (elems = selElems) {
|
||||
const connectors = $(svgcontent).find(connSel);
|
||||
connections = [];
|
||||
|
||||
// Loop through connectors to see if one is connected to the element
|
||||
connectors.each(function () {
|
||||
var addThis;
|
||||
let addThis;
|
||||
function add () {
|
||||
if ($.inArray(this, elems) !== -1) {
|
||||
if (elems.includes(this)) {
|
||||
// Pretend this element is selected
|
||||
addThis = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Grab the ends
|
||||
var parts = [];
|
||||
const parts = [];
|
||||
['start', 'end'].forEach(function (pos, i) {
|
||||
var key = 'c_' + pos;
|
||||
var part = elData(this, key);
|
||||
const key = 'c_' + pos;
|
||||
let part = elData(this, key);
|
||||
if (part == null) {
|
||||
part = document.getElementById(
|
||||
this.attributes['se:connector'].value.split(' ')[i]
|
||||
|
@ -181,8 +180,8 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
parts.push(part);
|
||||
}.bind(this));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
var cElem = parts[i];
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const cElem = parts[i];
|
||||
|
||||
addThis = false;
|
||||
// The connected element might be part of a selected group
|
||||
|
@ -192,8 +191,8 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
$(this).remove();
|
||||
continue;
|
||||
}
|
||||
if ($.inArray(cElem, elems) !== -1 || addThis) {
|
||||
var bb = svgCanvas.getStrokedBBox([cElem]);
|
||||
if (elems.includes(cElem) || addThis) {
|
||||
const bb = svgCanvas.getStrokedBBox([cElem]);
|
||||
connections.push({
|
||||
elem: cElem,
|
||||
connector: this,
|
||||
|
@ -210,47 +209,46 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
// Updates connector lines based on selected elements
|
||||
// Is not used on mousemove, as it runs getStrokedBBox every time,
|
||||
// which isn't necessary there.
|
||||
var i, j;
|
||||
findConnectors(elems);
|
||||
if (connections.length) {
|
||||
// Update line with element
|
||||
i = connections.length;
|
||||
let i = connections.length;
|
||||
while (i--) {
|
||||
var conn = connections[i];
|
||||
var line = conn.connector;
|
||||
var elem = conn.elem;
|
||||
const conn = connections[i];
|
||||
const line = conn.connector;
|
||||
const {elem} = conn;
|
||||
|
||||
// var sw = line.getAttribute('stroke-width') * 5;
|
||||
var pre = conn.is_start ? 'start' : 'end';
|
||||
// const sw = line.getAttribute('stroke-width') * 5;
|
||||
const pre = conn.is_start ? 'start' : 'end';
|
||||
|
||||
// Update bbox for this element
|
||||
var bb = svgCanvas.getStrokedBBox([elem]);
|
||||
const bb = svgCanvas.getStrokedBBox([elem]);
|
||||
bb.x = conn.start_x;
|
||||
bb.y = conn.start_y;
|
||||
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
|
||||
var bb2 = elData(line, altPre + '_bb');
|
||||
var srcX = bb2.x + bb2.width / 2;
|
||||
var srcY = bb2.y + bb2.height / 2;
|
||||
const bb2 = elData(line, altPre + '_bb');
|
||||
const srcX = bb2.x + bb2.width / 2;
|
||||
const srcY = bb2.y + bb2.height / 2;
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// Update points attribute manually for webkit
|
||||
if (navigator.userAgent.indexOf('AppleWebKit') !== -1) {
|
||||
var pts = line.points;
|
||||
var len = pts.numberOfItems;
|
||||
var ptArr = [];
|
||||
for (j = 0; j < len; j++) {
|
||||
if (navigator.userAgent.includes('AppleWebKit')) {
|
||||
const pts = line.points;
|
||||
const len = pts.numberOfItems;
|
||||
const ptArr = [];
|
||||
for (let j = 0; j < len; j++) {
|
||||
pt = pts.getItem(j);
|
||||
ptArr[j] = pt.x + ',' + pt.y;
|
||||
}
|
||||
|
@ -262,17 +260,17 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
|
||||
// Do once
|
||||
(function () {
|
||||
var gse = svgCanvas.groupSelectedElements;
|
||||
const gse = svgCanvas.groupSelectedElements;
|
||||
|
||||
svgCanvas.groupSelectedElements = function () {
|
||||
svgCanvas.removeFromSelection($(connSel).toArray());
|
||||
return gse.apply(this, arguments);
|
||||
};
|
||||
|
||||
var mse = svgCanvas.moveSelectedElements;
|
||||
const mse = svgCanvas.moveSelectedElements;
|
||||
|
||||
svgCanvas.moveSelectedElements = function () {
|
||||
var cmd = mse.apply(this, arguments);
|
||||
const cmd = mse.apply(this, arguments);
|
||||
updateConnectors();
|
||||
return cmd;
|
||||
};
|
||||
|
@ -284,12 +282,12 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
function init () {
|
||||
// Make sure all connectors have data set
|
||||
$(svgcontent).find('*').each(function () {
|
||||
var conn = this.getAttributeNS(seNs, 'connector');
|
||||
const conn = this.getAttributeNS(seNs, 'connector');
|
||||
if (conn) {
|
||||
this.setAttribute('class', connSel.substr(1));
|
||||
var connData = conn.split(' ');
|
||||
var sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]);
|
||||
var ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]);
|
||||
const connData = conn.split(' ');
|
||||
const sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]);
|
||||
const ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]);
|
||||
$(this).data('c_start', connData[0])
|
||||
.data('c_end', connData[1])
|
||||
.data('start_bb', sbb)
|
||||
|
@ -325,40 +323,40 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
position: 1
|
||||
},
|
||||
events: {
|
||||
'click': function () {
|
||||
click () {
|
||||
svgCanvas.setMode('connector');
|
||||
}
|
||||
}
|
||||
}],
|
||||
addLangData: function (lang) {
|
||||
addLangData (lang) {
|
||||
return {
|
||||
data: langList[lang]
|
||||
};
|
||||
},
|
||||
mouseDown: function (opts) {
|
||||
var e = opts.event;
|
||||
mouseDown (opts) {
|
||||
const e = opts.event;
|
||||
startX = opts.start_x;
|
||||
startY = opts.start_y;
|
||||
var mode = svgCanvas.getMode();
|
||||
const mode = svgCanvas.getMode();
|
||||
|
||||
if (mode === 'connector') {
|
||||
if (started) { return; }
|
||||
|
||||
var mouseTarget = e.target;
|
||||
const mouseTarget = e.target;
|
||||
|
||||
var parents = $(mouseTarget).parents();
|
||||
const parents = $(mouseTarget).parents();
|
||||
|
||||
if ($.inArray(svgcontent, parents) !== -1) {
|
||||
// Connectable element
|
||||
|
||||
// If child of foreignObject, use parent
|
||||
var fo = $(mouseTarget).closest('foreignObject');
|
||||
const fo = $(mouseTarget).closest('foreignObject');
|
||||
startElem = fo.length ? fo[0] : mouseTarget;
|
||||
|
||||
// Get center of source element
|
||||
var bb = svgCanvas.getStrokedBBox([startElem]);
|
||||
var x = bb.x + bb.width / 2;
|
||||
var y = bb.y + bb.height / 2;
|
||||
const bb = svgCanvas.getStrokedBBox([startElem]);
|
||||
const x = bb.x + bb.width / 2;
|
||||
const y = bb.y + bb.height / 2;
|
||||
|
||||
started = true;
|
||||
curLine = addElem({
|
||||
|
@ -383,21 +381,21 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
findConnectors();
|
||||
}
|
||||
},
|
||||
mouseMove: function (opts) {
|
||||
var zoom = svgCanvas.getZoom();
|
||||
// var e = opts.event;
|
||||
var x = opts.mouse_x / zoom;
|
||||
var y = opts.mouse_y / zoom;
|
||||
mouseMove (opts) {
|
||||
const zoom = svgCanvas.getZoom();
|
||||
// const e = opts.event;
|
||||
const x = opts.mouse_x / zoom;
|
||||
const y = opts.mouse_y / zoom;
|
||||
|
||||
var diffX = x - startX,
|
||||
const diffX = x - startX,
|
||||
diffY = y - startY;
|
||||
|
||||
var mode = svgCanvas.getMode();
|
||||
const mode = svgCanvas.getMode();
|
||||
|
||||
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)
|
||||
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;
|
||||
startY = pt.y;
|
||||
|
||||
|
@ -406,10 +404,9 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
// Set end point
|
||||
setPoint(curLine, 'end', x, y, true);
|
||||
} else if (mode === 'select') {
|
||||
var slen = selElems.length;
|
||||
|
||||
let slen = selElems.length;
|
||||
while (slen--) {
|
||||
var elem = selElems[slen];
|
||||
const elem = selElems[slen];
|
||||
// Look for selected connector elements
|
||||
if (elem && elData(elem, 'c_start')) {
|
||||
// Remove the "translate" transform given to move
|
||||
|
@ -422,18 +419,18 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
}
|
||||
}
|
||||
},
|
||||
mouseUp: function (opts) {
|
||||
// var zoom = svgCanvas.getZoom();
|
||||
var e = opts.event,
|
||||
// x = opts.mouse_x / zoom,
|
||||
// y = opts.mouse_y / zoom,
|
||||
mouseTarget = e.target;
|
||||
mouseUp (opts) {
|
||||
// const zoom = svgCanvas.getZoom();
|
||||
const e = opts.event;
|
||||
// , x = opts.mouse_x / zoom,
|
||||
// , y = opts.mouse_y / zoom,
|
||||
let mouseTarget = e.target;
|
||||
|
||||
if (svgCanvas.getMode() === 'connector') {
|
||||
var fo = $(mouseTarget).closest('foreignObject');
|
||||
const fo = $(mouseTarget).closest('foreignObject');
|
||||
if (fo.length) { mouseTarget = fo[0]; }
|
||||
|
||||
var parents = $(mouseTarget).parents();
|
||||
const parents = $(mouseTarget).parents();
|
||||
|
||||
if (mouseTarget === startElem) {
|
||||
// Start line through click
|
||||
|
@ -441,7 +438,7 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
return {
|
||||
keep: true,
|
||||
element: null,
|
||||
started: started
|
||||
started
|
||||
};
|
||||
}
|
||||
if ($.inArray(svgcontent, parents) === -1) {
|
||||
|
@ -451,18 +448,18 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
return {
|
||||
keep: false,
|
||||
element: null,
|
||||
started: started
|
||||
started
|
||||
};
|
||||
}
|
||||
// Valid end element
|
||||
endElem = mouseTarget;
|
||||
|
||||
var startId = startElem.id, endId = endElem.id;
|
||||
var connStr = startId + ' ' + endId;
|
||||
var altStr = endId + ' ' + startId;
|
||||
const startId = startElem.id, endId = endElem.id;
|
||||
const connStr = startId + ' ' + endId;
|
||||
const altStr = endId + ' ' + startId;
|
||||
// Don't create connector if one already exists
|
||||
var dupe = $(svgcontent).find(connSel).filter(function () {
|
||||
var conn = this.getAttributeNS(seNs, 'connector');
|
||||
const dupe = $(svgcontent).find(connSel).filter(function () {
|
||||
const conn = this.getAttributeNS(seNs, 'connector');
|
||||
if (conn === connStr || conn === altStr) { return true; }
|
||||
});
|
||||
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);
|
||||
$(curLine)
|
||||
.data('c_start', startId)
|
||||
|
@ -493,11 +490,11 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
return {
|
||||
keep: true,
|
||||
element: curLine,
|
||||
started: started
|
||||
started
|
||||
};
|
||||
}
|
||||
},
|
||||
selectedChanged: function (opts) {
|
||||
selectedChanged (opts) {
|
||||
// TODO: Find better way to skip operations if no connectors are in use
|
||||
if (!$(svgcontent).find(connSel).length) { return; }
|
||||
|
||||
|
@ -508,10 +505,9 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
// Use this to update the current selected elements
|
||||
selElems = opts.elems;
|
||||
|
||||
var i = selElems.length;
|
||||
|
||||
let i = selElems.length;
|
||||
while (i--) {
|
||||
var elem = selElems[i];
|
||||
const elem = selElems[i];
|
||||
if (elem && elData(elem, 'c_start')) {
|
||||
selManager.requestSelector(elem).showGrips(false);
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
|
@ -526,8 +522,8 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
}
|
||||
updateConnectors();
|
||||
},
|
||||
elementChanged: function (opts) {
|
||||
var elem = opts.elems[0];
|
||||
elementChanged (opts) {
|
||||
let elem = opts.elems[0];
|
||||
if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') {
|
||||
// Update svgcontent (can change on import)
|
||||
svgcontent = elem;
|
||||
|
@ -535,15 +531,14 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
}
|
||||
|
||||
// Has marker, so change offset
|
||||
var start;
|
||||
if (elem && (
|
||||
elem.getAttribute('marker-start') ||
|
||||
elem.getAttribute('marker-mid') ||
|
||||
elem.getAttribute('marker-end')
|
||||
)) {
|
||||
start = elem.getAttribute('marker-start');
|
||||
var mid = elem.getAttribute('marker-mid');
|
||||
var end = elem.getAttribute('marker-end');
|
||||
const start = elem.getAttribute('marker-start');
|
||||
const mid = elem.getAttribute('marker-mid');
|
||||
const end = elem.getAttribute('marker-end');
|
||||
curLine = elem;
|
||||
$(elem)
|
||||
.data('start_off', !!start)
|
||||
|
@ -552,14 +547,14 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
if (elem.tagName === 'line' && mid) {
|
||||
// Convert to polyline to accept mid-arrow
|
||||
|
||||
var x1 = Number(elem.getAttribute('x1'));
|
||||
var x2 = Number(elem.getAttribute('x2'));
|
||||
var y1 = Number(elem.getAttribute('y1'));
|
||||
var y2 = Number(elem.getAttribute('y2'));
|
||||
var id = elem.id;
|
||||
const x1 = Number(elem.getAttribute('x1'));
|
||||
const x2 = Number(elem.getAttribute('x2'));
|
||||
const y1 = Number(elem.getAttribute('y1'));
|
||||
const y2 = Number(elem.getAttribute('y2'));
|
||||
const {id} = elem;
|
||||
|
||||
var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
|
||||
var pline = addElem({
|
||||
const midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
|
||||
const pline = addElem({
|
||||
'element': 'polyline',
|
||||
'attr': {
|
||||
'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2),
|
||||
|
@ -579,14 +574,14 @@ svgEditor.addExtension('Connector', function (S) {
|
|||
}
|
||||
// Update line if it's a connector
|
||||
if (elem.getAttribute('class') === connSel.substr(1)) {
|
||||
start = getElem(elData(elem, 'c_start'));
|
||||
const start = getElem(elData(elem, 'c_start'));
|
||||
updateConnectors([start]);
|
||||
} else {
|
||||
updateConnectors();
|
||||
}
|
||||
},
|
||||
IDsUpdated: function (input) {
|
||||
var remove = [];
|
||||
IDsUpdated (input) {
|
||||
const remove = [];
|
||||
input.elems.forEach(function (elem) {
|
||||
if ('se:connector' in elem.attr) {
|
||||
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 ($('#mode_connect').hasClass('tool_button_current')) {
|
||||
svgEditor.clickSelect();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgedit, $ */
|
||||
/* globals jQuery, svgEditor, svgedit */
|
||||
/*
|
||||
* ext-eyedropper.js
|
||||
*
|
||||
|
@ -16,12 +15,11 @@
|
|||
// 4) svgcanvas.js
|
||||
|
||||
svgEditor.addExtension('eyedropper', function (S) {
|
||||
'use strict';
|
||||
var // NS = svgedit.NS,
|
||||
// svgcontent = S.svgcontent,
|
||||
const $ = jQuery;
|
||||
const // {svgcontent} = S,
|
||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
svgCanvas = svgEditor.canvas,
|
||||
ChangeElementCommand = svgedit.history.ChangeElementCommand,
|
||||
{ChangeElementCommand} = svgedit.history,
|
||||
addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
|
||||
currentStyle = {
|
||||
fillPaint: 'red', fillOpacity: 1.0,
|
||||
|
@ -34,14 +32,14 @@ svgEditor.addExtension('eyedropper', function (S) {
|
|||
|
||||
function getStyle (opts) {
|
||||
// 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; }
|
||||
|
||||
var elem = null;
|
||||
var tool = $('#tool_eyedropper');
|
||||
const tool = $('#tool_eyedropper');
|
||||
// enable-eye-dropper if one element is selected
|
||||
let elem = null;
|
||||
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];
|
||||
tool.removeClass('disabled');
|
||||
|
@ -70,7 +68,7 @@ svgEditor.addExtension('eyedropper', function (S) {
|
|||
title: 'Eye Dropper Tool',
|
||||
key: 'I',
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
svgCanvas.setMode('eyedropper');
|
||||
}
|
||||
}
|
||||
|
@ -80,15 +78,15 @@ svgEditor.addExtension('eyedropper', function (S) {
|
|||
selectedChanged: getStyle,
|
||||
elementChanged: getStyle,
|
||||
|
||||
mouseDown: function (opts) {
|
||||
var mode = svgCanvas.getMode();
|
||||
mouseDown (opts) {
|
||||
const mode = svgCanvas.getMode();
|
||||
if (mode === 'eyedropper') {
|
||||
var e = opts.event;
|
||||
var target = e.target;
|
||||
if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) {
|
||||
var changes = {};
|
||||
const e = opts.event;
|
||||
const {target} = e;
|
||||
if (!['svg', 'g', 'use'].includes(target.nodeName)) {
|
||||
const changes = {};
|
||||
|
||||
var change = function (elem, attrname, newvalue) {
|
||||
const change = function (elem, attrname, newvalue) {
|
||||
changes[attrname] = elem.getAttribute(attrname);
|
||||
elem.setAttribute(attrname, newvalue);
|
||||
};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgedit, svgCanvas, $ */
|
||||
/* globals jQuery, svgEditor, svgedit, svgCanvas */
|
||||
/*
|
||||
* ext-foreignobject.js
|
||||
*
|
||||
|
@ -10,25 +9,23 @@
|
|||
*
|
||||
*/
|
||||
|
||||
svgEditor.addExtension('foreignObject', function (S) {
|
||||
var NS = svgedit.NS,
|
||||
Utils = svgedit.utilities,
|
||||
// svgcontent = S.svgcontent,
|
||||
// addElem = S.addSvgElementFromJson,
|
||||
selElems,
|
||||
editingforeign = false,
|
||||
svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
started,
|
||||
newFO;
|
||||
import {NS} from './svgedit.js';
|
||||
|
||||
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
|
||||
var height = $('#svg_source_container').height() - 80;
|
||||
const height = $('#svg_source_container').height() - 80;
|
||||
$('#svg_source_textarea').css('height', height);
|
||||
};
|
||||
|
||||
function showPanel (on) {
|
||||
var fcRules = $('#fc_rules');
|
||||
let fcRules = $('#fc_rules');
|
||||
if (!fcRules.length) {
|
||||
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
|
||||
}
|
||||
|
@ -41,6 +38,11 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
$('#foreign_save, #foreign_cancel').toggle(on);
|
||||
}
|
||||
|
||||
let selElems,
|
||||
started,
|
||||
newFO,
|
||||
editingforeign = false;
|
||||
|
||||
// Function: setForeignString(xmlString, elt)
|
||||
// This function sets the content of element elt to the input XML.
|
||||
//
|
||||
|
@ -51,10 +53,10 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
// Returns:
|
||||
// This function returns false if the set was unsuccessful, true otherwise.
|
||||
function setForeignString (xmlString) {
|
||||
var elt = selElems[0];
|
||||
const elt = selElems[0];
|
||||
try {
|
||||
// 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
|
||||
S.sanitizeSvg(newDoc.documentElement);
|
||||
elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
|
||||
|
@ -69,13 +71,13 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
}
|
||||
|
||||
function showForeignEditor () {
|
||||
var elt = selElems[0];
|
||||
const elt = selElems[0];
|
||||
if (!elt || editingforeign) { return; }
|
||||
editingforeign = true;
|
||||
toggleSourceButtons(true);
|
||||
elt.removeAttribute('fill');
|
||||
|
||||
var str = S.svgToString(elt, 0);
|
||||
const str = S.svgToString(elt, 0);
|
||||
$('#svg_source_textarea').val(str);
|
||||
$('#svg_source_editor').fadeIn();
|
||||
properlySourceSizeTextArea();
|
||||
|
@ -95,7 +97,7 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
type: 'mode',
|
||||
title: 'Foreign Object Tool',
|
||||
events: {
|
||||
'click': function () {
|
||||
click () {
|
||||
svgCanvas.setMode('foreign');
|
||||
}
|
||||
}
|
||||
|
@ -105,7 +107,7 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
panel: 'foreignObject_panel',
|
||||
title: 'Edit ForeignObject Content',
|
||||
events: {
|
||||
'click': function () {
|
||||
click () {
|
||||
showForeignEditor();
|
||||
}
|
||||
}
|
||||
|
@ -119,7 +121,7 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
label: 'w',
|
||||
size: 3,
|
||||
events: {
|
||||
change: function () {
|
||||
change () {
|
||||
setAttr('width', this.value);
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +132,7 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
id: 'foreign_height',
|
||||
label: 'h',
|
||||
events: {
|
||||
change: function () {
|
||||
change () {
|
||||
setAttr('height', this.value);
|
||||
}
|
||||
}
|
||||
|
@ -143,17 +145,17 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
size: 2,
|
||||
defval: 16,
|
||||
events: {
|
||||
change: function () {
|
||||
change () {
|
||||
setAttr('font-size', this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
],
|
||||
callback: function () {
|
||||
callback () {
|
||||
$('#foreignObject_panel').hide();
|
||||
|
||||
var endChanges = function () {
|
||||
const endChanges = function () {
|
||||
$('#svg_source_editor').hide();
|
||||
editingforeign = false;
|
||||
$('#svg_source_textarea').blur();
|
||||
|
@ -163,7 +165,7 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
// TODO: Needs to be done after orig icon loads
|
||||
setTimeout(function () {
|
||||
// Create source save/cancel buttons
|
||||
/* var save = */ $('#tool_source_save').clone()
|
||||
/* const save = */ $('#tool_source_save').clone()
|
||||
.hide().attr('id', 'foreign_save').unbind()
|
||||
.appendTo('#tool_source_back').click(function () {
|
||||
if (!editingforeign) { return; }
|
||||
|
@ -179,15 +181,15 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
// setSelectMode();
|
||||
});
|
||||
|
||||
/* var cancel = */ $('#tool_source_cancel').clone()
|
||||
/* const cancel = */ $('#tool_source_cancel').clone()
|
||||
.hide().attr('id', 'foreign_cancel').unbind()
|
||||
.appendTo('#tool_source_back').click(function () {
|
||||
endChanges();
|
||||
});
|
||||
}, 3000);
|
||||
},
|
||||
mouseDown: function (opts) {
|
||||
// var e = opts.event;
|
||||
mouseDown (opts) {
|
||||
// const e = opts.event;
|
||||
|
||||
if (svgCanvas.getMode() === 'foreign') {
|
||||
started = true;
|
||||
|
@ -203,15 +205,15 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
'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.setAttribute('display', 'inline');
|
||||
var mi = svgdoc.createElementNS(NS.MATH, 'mi');
|
||||
const mi = svgdoc.createElementNS(NS.MATH, 'mi');
|
||||
mi.setAttribute('mathvariant', 'normal');
|
||||
mi.textContent = '\u03A6';
|
||||
var mo = svgdoc.createElementNS(NS.MATH, 'mo');
|
||||
const mo = svgdoc.createElementNS(NS.MATH, 'mo');
|
||||
mo.textContent = '\u222A';
|
||||
var mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
|
||||
const mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
|
||||
mi2.textContent = '\u2133';
|
||||
m.appendChild(mi);
|
||||
m.appendChild(mo);
|
||||
|
@ -222,27 +224,26 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
};
|
||||
}
|
||||
},
|
||||
mouseUp: function (opts) {
|
||||
// var e = opts.event;
|
||||
mouseUp (opts) {
|
||||
// const e = opts.event;
|
||||
if (svgCanvas.getMode() === 'foreign' && started) {
|
||||
var attrs = $(newFO).attr(['width', 'height']);
|
||||
var keep = (attrs.width !== '0' || attrs.height !== '0');
|
||||
const attrs = $(newFO).attr(['width', 'height']);
|
||||
const keep = (attrs.width !== '0' || attrs.height !== '0');
|
||||
svgCanvas.addToSelection([newFO], true);
|
||||
|
||||
return {
|
||||
keep: keep,
|
||||
keep,
|
||||
element: newFO
|
||||
};
|
||||
}
|
||||
},
|
||||
selectedChanged: function (opts) {
|
||||
selectedChanged (opts) {
|
||||
// Use this to update the current selected elements
|
||||
selElems = opts.elems;
|
||||
|
||||
var i = selElems.length;
|
||||
|
||||
let i = selElems.length;
|
||||
while (i--) {
|
||||
var elem = selElems[i];
|
||||
const elem = selElems[i];
|
||||
if (elem && elem.tagName === 'foreignObject') {
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
$('#foreign_font_size').val(elem.getAttribute('font-size'));
|
||||
|
@ -257,8 +258,8 @@ svgEditor.addExtension('foreignObject', function (S) {
|
|||
}
|
||||
}
|
||||
},
|
||||
elementChanged: function (opts) {
|
||||
// var elem = opts.elems[0];
|
||||
elementChanged (opts) {
|
||||
// const elem = opts.elems[0];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgedit, svgCanvas, $ */
|
||||
/* globals jQuery, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-grid.js
|
||||
*
|
||||
|
@ -14,97 +13,97 @@
|
|||
// 1) units.js
|
||||
// 2) everything else
|
||||
|
||||
svgEditor.addExtension('view_grid', function () {
|
||||
'use strict';
|
||||
import {NS} from './svgedit.js';
|
||||
import {getTypeMap} from './units.js';
|
||||
|
||||
var NS = svgedit.NS,
|
||||
svgdoc = document.getElementById('svgcanvas').ownerDocument,
|
||||
showGrid = svgEditor.curConfig.showGrid || false,
|
||||
assignAttributes = svgCanvas.assignAttributes,
|
||||
svgEditor.addExtension('view_grid', function () {
|
||||
const $ = jQuery;
|
||||
const svgdoc = document.getElementById('svgcanvas').ownerDocument,
|
||||
{assignAttributes} = svgCanvas,
|
||||
hcanvas = document.createElement('canvas'),
|
||||
canvBG = $('#canvasBackground'),
|
||||
units = svgedit.units.getTypeMap(),
|
||||
units = getTypeMap(),
|
||||
intervals = [0.01, 0.1, 1, 10, 100, 1000];
|
||||
let showGrid = svgEditor.curConfig.showGrid || false;
|
||||
|
||||
$(hcanvas).hide().appendTo('body');
|
||||
|
||||
var canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
|
||||
const canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
|
||||
assignAttributes(canvasGrid, {
|
||||
'id': 'canvasGrid',
|
||||
'width': '100%',
|
||||
'height': '100%',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'overflow': 'visible',
|
||||
'display': 'none'
|
||||
id: 'canvasGrid',
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
x: 0,
|
||||
y: 0,
|
||||
overflow: 'visible',
|
||||
display: 'none'
|
||||
});
|
||||
canvBG.append(canvasGrid);
|
||||
|
||||
// grid-pattern
|
||||
var gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
|
||||
const gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
|
||||
assignAttributes(gridPattern, {
|
||||
'id': 'gridpattern',
|
||||
'patternUnits': 'userSpaceOnUse',
|
||||
'x': 0, // -(value.strokeWidth / 2), // position for strokewidth
|
||||
'y': 0, // -(value.strokeWidth / 2), // position for strokewidth
|
||||
'width': 100,
|
||||
'height': 100
|
||||
id: 'gridpattern',
|
||||
patternUnits: 'userSpaceOnUse',
|
||||
x: 0, // -(value.strokeWidth / 2), // position for strokewidth
|
||||
y: 0, // -(value.strokeWidth / 2), // position for strokewidth
|
||||
width: 100,
|
||||
height: 100
|
||||
});
|
||||
|
||||
var gridimg = svgdoc.createElementNS(NS.SVG, 'image');
|
||||
const gridimg = svgdoc.createElementNS(NS.SVG, 'image');
|
||||
assignAttributes(gridimg, {
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'width': 100,
|
||||
'height': 100
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 100,
|
||||
height: 100
|
||||
});
|
||||
gridPattern.appendChild(gridimg);
|
||||
$('#svgroot defs').append(gridPattern);
|
||||
|
||||
// grid-box
|
||||
var gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
|
||||
const gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
|
||||
assignAttributes(gridBox, {
|
||||
'width': '100%',
|
||||
'height': '100%',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
x: 0,
|
||||
y: 0,
|
||||
'stroke-width': 0,
|
||||
'stroke': 'none',
|
||||
'fill': 'url(#gridpattern)',
|
||||
'style': 'pointer-events: none; display:visible;'
|
||||
stroke: 'none',
|
||||
fill: 'url(#gridpattern)',
|
||||
style: 'pointer-events: none; display:visible;'
|
||||
});
|
||||
$('#canvasGrid').append(gridBox);
|
||||
|
||||
function updateGrid (zoom) {
|
||||
var i;
|
||||
// TODO: Try this with <line> elements, then compare performance difference
|
||||
var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
|
||||
var uMulti = unit * zoom;
|
||||
const unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
|
||||
const uMulti = unit * zoom;
|
||||
// Calculate the main number interval
|
||||
var rawM = 100 / uMulti;
|
||||
var multi = 1;
|
||||
for (i = 0; i < intervals.length; i++) {
|
||||
var num = intervals[i];
|
||||
const rawM = 100 / uMulti;
|
||||
let multi = 1;
|
||||
for (let i = 0; i < intervals.length; i++) {
|
||||
const num = intervals[i];
|
||||
multi = num;
|
||||
if (rawM <= num) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
var bigInt = multi * uMulti;
|
||||
const bigInt = multi * uMulti;
|
||||
|
||||
// Set the canvas size to the width of the container
|
||||
hcanvas.width = bigInt;
|
||||
hcanvas.height = bigInt;
|
||||
var ctx = hcanvas.getContext('2d');
|
||||
var curD = 0.5;
|
||||
var part = bigInt / 10;
|
||||
const ctx = hcanvas.getContext('2d');
|
||||
const curD = 0.5;
|
||||
const part = bigInt / 10;
|
||||
|
||||
ctx.globalAlpha = 0.2;
|
||||
ctx.strokeStyle = svgEditor.curConfig.gridColor;
|
||||
for (i = 1; i < 10; i++) {
|
||||
var subD = Math.round(part * i) + 0.5;
|
||||
// var lineNum = (i % 2)?12:10;
|
||||
var lineNum = 0;
|
||||
for (let i = 1; i < 10; i++) {
|
||||
const subD = Math.round(part * i) + 0.5;
|
||||
// const lineNum = (i % 2)?12:10;
|
||||
const lineNum = 0;
|
||||
ctx.moveTo(subD, bigInt);
|
||||
ctx.lineTo(subD, lineNum);
|
||||
ctx.moveTo(bigInt, subD);
|
||||
|
@ -120,7 +119,7 @@ svgEditor.addExtension('view_grid', function () {
|
|||
ctx.lineTo(0, curD);
|
||||
ctx.stroke();
|
||||
|
||||
var datauri = hcanvas.toDataURL('image/png');
|
||||
const datauri = hcanvas.toDataURL('image/png');
|
||||
gridimg.setAttribute('width', bigInt);
|
||||
gridimg.setAttribute('height', bigInt);
|
||||
gridimg.parentNode.setAttribute('width', bigInt);
|
||||
|
@ -139,10 +138,10 @@ svgEditor.addExtension('view_grid', function () {
|
|||
name: 'view_grid',
|
||||
svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml',
|
||||
|
||||
zoomChanged: function (zoom) {
|
||||
zoomChanged (zoom) {
|
||||
if (showGrid) { updateGrid(zoom); }
|
||||
},
|
||||
callback: function () {
|
||||
callback () {
|
||||
if (showGrid) {
|
||||
gridUpdate();
|
||||
}
|
||||
|
@ -153,7 +152,7 @@ svgEditor.addExtension('view_grid', function () {
|
|||
panel: 'editor_panel',
|
||||
title: 'Show/Hide Grid',
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
svgEditor.curConfig.showGrid = showGrid = !showGrid;
|
||||
gridUpdate();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgCanvas, $ */
|
||||
/* globals jQuery, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-helloworld.js
|
||||
*
|
||||
|
@ -16,8 +15,7 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('Hello World', function () {
|
||||
'use strict';
|
||||
|
||||
const $ = jQuery;
|
||||
return {
|
||||
name: 'Hello World',
|
||||
// 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: {
|
||||
'click': function () {
|
||||
click () {
|
||||
// The action taken when the button is clicked on.
|
||||
// For "mode" buttons, any other button will
|
||||
// automatically be de-pressed.
|
||||
|
@ -48,7 +46,7 @@ svgEditor.addExtension('Hello World', function () {
|
|||
}],
|
||||
// This is triggered when the main mouse button is pressed down
|
||||
// on the editor canvas (not the tool panels)
|
||||
mouseDown: function () {
|
||||
mouseDown () {
|
||||
// Check the mode on mousedown
|
||||
if (svgCanvas.getMode() === 'hello_world') {
|
||||
// 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
|
||||
// to true (see above). Note that "opts" is an object with event info
|
||||
mouseUp: function (opts) {
|
||||
mouseUp (opts) {
|
||||
// Check the mode on mouseup
|
||||
if (svgCanvas.getMode() === 'hello_world') {
|
||||
var zoom = svgCanvas.getZoom();
|
||||
const zoom = svgCanvas.getZoom();
|
||||
|
||||
// Get the actual coordinate by dividing by the zoom value
|
||||
var x = opts.mouse_x / zoom;
|
||||
var y = opts.mouse_y / zoom;
|
||||
const x = opts.mouse_x / 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;
|
||||
|
||||
// Show the text using the custom alert function
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals $, svgEditor, svgedit, svgCanvas, DOMParser */
|
||||
/* globals jQuery, svgEditor, svgedit, svgCanvas */
|
||||
/*
|
||||
* ext-imagelib.js
|
||||
*
|
||||
|
@ -10,9 +9,8 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('imagelib', function () {
|
||||
'use strict';
|
||||
|
||||
var uiStrings = svgEditor.uiStrings;
|
||||
const $ = jQuery;
|
||||
const {uiStrings} = svgEditor;
|
||||
|
||||
$.extend(uiStrings, {
|
||||
imagelib: {
|
||||
|
@ -24,7 +22,7 @@ svgEditor.addExtension('imagelib', function () {
|
|||
}
|
||||
});
|
||||
|
||||
var imgLibs = [
|
||||
const imgLibs = [
|
||||
{
|
||||
name: 'Demo library (local)',
|
||||
url: svgEditor.curConfig.extPath + 'imagelib/index.html',
|
||||
|
@ -47,7 +45,7 @@ svgEditor.addExtension('imagelib', function () {
|
|||
}
|
||||
|
||||
function importImage (url) {
|
||||
var newImage = svgCanvas.addSvgElementFromJson({
|
||||
const newImage = svgCanvas.addSvgElementFromJson({
|
||||
'element': 'image',
|
||||
'attr': {
|
||||
'x': 0,
|
||||
|
@ -63,58 +61,64 @@ svgEditor.addExtension('imagelib', function () {
|
|||
svgCanvas.setImageURL(url);
|
||||
}
|
||||
|
||||
var mode = 's';
|
||||
var multiArr = [];
|
||||
var transferStopped = false;
|
||||
var pending = {};
|
||||
var preview, submit;
|
||||
const pending = {};
|
||||
|
||||
let mode = 's';
|
||||
let multiArr = [];
|
||||
let transferStopped = false;
|
||||
let preview, submit;
|
||||
|
||||
window.addEventListener('message', function (evt) {
|
||||
// Receive postMessage data
|
||||
var response = evt.data;
|
||||
// Receive `postMessage` 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
|
||||
return;
|
||||
}
|
||||
try { // This block can be removed if embedAPI moves away from a string to an object (if IE9 support not needed)
|
||||
var res = JSON.parse(response);
|
||||
if (res.namespace) { // Part of embedAPI communications
|
||||
try {
|
||||
// Todo: This block can be removed (and the above check changed to
|
||||
// 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;
|
||||
}
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
var char1 = response.charAt(0);
|
||||
var id;
|
||||
var svgStr;
|
||||
var imgStr;
|
||||
const hasName = 'name' in response;
|
||||
const hasHref = 'href' in response;
|
||||
|
||||
if (char1 !== '{' && transferStopped) {
|
||||
if (!hasName && transferStopped) {
|
||||
transferStopped = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (char1 === '|') {
|
||||
var secondpos = response.indexOf('|', 1);
|
||||
id = response.substr(1, secondpos - 1);
|
||||
response = response.substr(secondpos + 1);
|
||||
char1 = response.charAt(0);
|
||||
let id;
|
||||
if (hasHref) {
|
||||
id = response.href;
|
||||
response = response.data;
|
||||
}
|
||||
|
||||
// Hide possible transfer dialog box
|
||||
$('#dialog_box').hide();
|
||||
var entry, curMeta;
|
||||
switch (char1) {
|
||||
case '{':
|
||||
let entry, curMeta, svgStr, imgStr;
|
||||
const type = hasName
|
||||
? 'meta'
|
||||
: response.charAt(0);
|
||||
switch (type) {
|
||||
case 'meta': {
|
||||
// Metadata
|
||||
transferStopped = false;
|
||||
curMeta = JSON.parse(response);
|
||||
curMeta = response;
|
||||
|
||||
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') {
|
||||
$.process_cancel(message, function () {
|
||||
|
@ -130,24 +134,26 @@ svgEditor.addExtension('imagelib', function () {
|
|||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case '<':
|
||||
svgStr = true;
|
||||
break;
|
||||
case 'd':
|
||||
if (response.indexOf('data:image/svg+xml') === 0) {
|
||||
var pre = 'data:image/svg+xml;base64,';
|
||||
var src = response.substring(pre.length);
|
||||
case 'd': {
|
||||
if (response.startsWith('data:image/svg+xml')) {
|
||||
const pre = 'data:image/svg+xml;base64,';
|
||||
const src = response.substring(pre.length);
|
||||
response = svgedit.utilities.decode64(src);
|
||||
svgStr = true;
|
||||
break;
|
||||
} else if (response.indexOf('data:image/') === 0) {
|
||||
} else if (response.startsWith('data:image/')) {
|
||||
imgStr = true;
|
||||
break;
|
||||
}
|
||||
// Else fall through
|
||||
}
|
||||
// Else fall through
|
||||
default:
|
||||
// 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
|
||||
// importImage(str);
|
||||
|
@ -181,14 +187,14 @@ svgEditor.addExtension('imagelib', function () {
|
|||
case 'm':
|
||||
// Import multiple
|
||||
multiArr.push([(svgStr ? 'svg' : 'img'), response]);
|
||||
var title;
|
||||
curMeta = pending[id];
|
||||
let title;
|
||||
if (svgStr) {
|
||||
if (curMeta && curMeta.name) {
|
||||
title = curMeta.name;
|
||||
} else {
|
||||
// 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 + ')';
|
||||
}
|
||||
if (curMeta) {
|
||||
|
@ -260,8 +266,8 @@ svgEditor.addExtension('imagelib', function () {
|
|||
.appendTo('#imgbrowse')
|
||||
.on('click touchend', function () {
|
||||
$.each(multiArr, function (i) {
|
||||
var type = this[0];
|
||||
var data = this[1];
|
||||
const type = this[0];
|
||||
const data = this[1];
|
||||
if (type === 'svg') {
|
||||
svgCanvas.importSvgString(data);
|
||||
} else {
|
||||
|
@ -284,25 +290,25 @@ svgEditor.addExtension('imagelib', function () {
|
|||
}
|
||||
|
||||
function showBrowser () {
|
||||
var browser = $('#imgbrowse');
|
||||
let browser = $('#imgbrowse');
|
||||
if (!browser.length) {
|
||||
$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' +
|
||||
'</div></div>').insertAfter('#svg_docprops');
|
||||
browser = $('#imgbrowse');
|
||||
|
||||
var allLibs = uiStrings.imagelib.select_lib;
|
||||
const allLibs = uiStrings.imagelib.select_lib;
|
||||
|
||||
var libOpts = $('<ul id=imglib_opts>').appendTo(browser);
|
||||
var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
|
||||
const libOpts = $('<ul id=imglib_opts>').appendTo(browser);
|
||||
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',
|
||||
top: 0,
|
||||
left: 0,
|
||||
width: '100%'
|
||||
});
|
||||
|
||||
var cancel = $('<button>' + uiStrings.common.cancel + '</button>')
|
||||
const cancel = $('<button>' + uiStrings.common.cancel + '</button>')
|
||||
.appendTo(browser)
|
||||
.on('click touchend', function () {
|
||||
$('#imgbrowse_holder').hide();
|
||||
|
@ -312,9 +318,9 @@ svgEditor.addExtension('imagelib', function () {
|
|||
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)
|
||||
.on('click touchend', function () {
|
||||
frame.attr('src', 'about:blank').hide();
|
||||
|
@ -325,7 +331,7 @@ svgEditor.addExtension('imagelib', function () {
|
|||
'margin-right': 5
|
||||
}).hide();
|
||||
|
||||
/* var type = */ $('<select><option value=s>' +
|
||||
/* const type = */ $('<select><option value=s>' +
|
||||
uiStrings.imagelib.import_single + '</option><option value=m>' +
|
||||
uiStrings.imagelib.import_multi + '</option><option value=o>' +
|
||||
uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function () {
|
||||
|
@ -372,10 +378,10 @@ svgEditor.addExtension('imagelib', function () {
|
|||
position: 4,
|
||||
title: 'Image library',
|
||||
events: {
|
||||
'mouseup': showBrowser
|
||||
mouseup: showBrowser
|
||||
}
|
||||
}],
|
||||
callback: function () {
|
||||
callback () {
|
||||
$('<style>').text(
|
||||
'#imgbrowse_holder {' +
|
||||
'position: absolute;' +
|
||||
|
|
|
@ -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."
|
||||
}
|
||||
};
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgCanvas, $ */
|
||||
/* globals jQuery, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-markers.js
|
||||
*
|
||||
|
@ -33,21 +32,19 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('Markers', function (S) {
|
||||
var // svgcontent = S.svgcontent,
|
||||
addElem = S.addSvgElementFromJson,
|
||||
selElems;
|
||||
|
||||
var mtypes = ['start', 'mid', 'end'];
|
||||
|
||||
var markerPrefix = 'se_marker_';
|
||||
var idPrefix = 'mkr_';
|
||||
const $ = jQuery;
|
||||
const // {svgcontent} = S,
|
||||
addElem = S.addSvgElementFromJson;
|
||||
const mtypes = ['start', 'mid', 'end'];
|
||||
const markerPrefix = 'se_marker_';
|
||||
const idPrefix = 'mkr_';
|
||||
|
||||
// note - to add additional marker types add them below with a unique id
|
||||
// and add the associated icon(s) to marker-icons.svg
|
||||
// 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
|
||||
// remember that the coordinate system has +y downward
|
||||
var markerTypes = {
|
||||
const markerTypes = {
|
||||
nomarker: {},
|
||||
leftarrow:
|
||||
{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}}
|
||||
};
|
||||
|
||||
var langList = {
|
||||
const langList = {
|
||||
'en': [
|
||||
{id: 'start_marker_list', title: 'Select start 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
|
||||
// returns the marker element that is linked to the graphic element
|
||||
function getLinked (elem, attr) {
|
||||
var str = elem.getAttribute(attr);
|
||||
const str = elem.getAttribute(attr);
|
||||
if (!str) { return null; }
|
||||
var m = str.match(/\(#(.*)\)/);
|
||||
const m = str.match(/\(#(.*)\)/);
|
||||
if (!m || m.length !== 2) {
|
||||
return null;
|
||||
}
|
||||
|
@ -120,24 +117,24 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
|
||||
function setIcon (pos, id) {
|
||||
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());
|
||||
$(ci).addClass('current').siblings().removeClass('current');
|
||||
}
|
||||
|
||||
let selElems;
|
||||
// toggles context tool panel off/on
|
||||
// sets the controls with the selected element's settings
|
||||
function showPanel (on) {
|
||||
$('#marker_panel').toggle(on);
|
||||
|
||||
if (on) {
|
||||
var el = selElems[0];
|
||||
var val;
|
||||
var ci;
|
||||
const el = selElems[0];
|
||||
|
||||
let val, ci;
|
||||
$.each(mtypes, function (i, pos) {
|
||||
var m = getLinked(el, 'marker-' + pos);
|
||||
var txtbox = $('#' + pos + '_marker');
|
||||
const m = getLinked(el, 'marker-' + pos);
|
||||
const txtbox = $('#' + pos + '_marker');
|
||||
if (!m) {
|
||||
val = '\\nomarker';
|
||||
ci = val;
|
||||
|
@ -160,28 +157,27 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
}
|
||||
|
||||
function addMarker (id, val) {
|
||||
var txtBoxBg = '#ffffff';
|
||||
var txtBoxBorder = 'none';
|
||||
var txtBoxStrokeWidth = 0;
|
||||
|
||||
var marker = S.getElem(id);
|
||||
const txtBoxBg = '#ffffff';
|
||||
const txtBoxBorder = 'none';
|
||||
const txtBoxStrokeWidth = 0;
|
||||
|
||||
let marker = S.getElem(id);
|
||||
if (marker) { return; }
|
||||
|
||||
if (val === '' || val === '\\nomarker') { return; }
|
||||
|
||||
var el = selElems[0];
|
||||
var color = el.getAttribute('stroke');
|
||||
const el = selElems[0];
|
||||
const color = el.getAttribute('stroke');
|
||||
// NOTE: Safari didn't like a negative value in viewBox
|
||||
// so we use a standardized 0 0 100 100
|
||||
// with 50 50 being mapped to the marker position
|
||||
var refX = 50;
|
||||
var refY = 50;
|
||||
var viewBox = '0 0 100 100';
|
||||
var markerWidth = 5;
|
||||
var markerHeight = 5;
|
||||
var strokeWidth = 10;
|
||||
var seType;
|
||||
const strokeWidth = 10;
|
||||
let refX = 50;
|
||||
let refY = 50;
|
||||
let viewBox = '0 0 100 100';
|
||||
let markerWidth = 5;
|
||||
let markerHeight = 5;
|
||||
let seType;
|
||||
if (val.substr(0, 1) === '\\') {
|
||||
seType = val.substr(1);
|
||||
} else { seType = 'textmarker'; }
|
||||
|
@ -190,32 +186,34 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
|
||||
// create a generic marker
|
||||
marker = addElem({
|
||||
'element': 'marker',
|
||||
'attr': {
|
||||
'id': id,
|
||||
'markerUnits': 'strokeWidth',
|
||||
'orient': 'auto',
|
||||
'style': 'pointer-events:none',
|
||||
'se_type': seType
|
||||
element: 'marker',
|
||||
attr: {
|
||||
id,
|
||||
markerUnits: 'strokeWidth',
|
||||
orient: 'auto',
|
||||
style: 'pointer-events:none',
|
||||
se_type: seType
|
||||
}
|
||||
});
|
||||
|
||||
if (seType !== 'textmarker') {
|
||||
var mel = addElem(markerTypes[seType]);
|
||||
var fillcolor = color;
|
||||
if (seType.substr(-2) === '_o') { fillcolor = 'none'; }
|
||||
const mel = addElem(markerTypes[seType]);
|
||||
const fillcolor = (seType.substr(-2) === '_o')
|
||||
? 'none'
|
||||
: color;
|
||||
|
||||
mel.setAttribute('fill', fillcolor);
|
||||
mel.setAttribute('stroke', color);
|
||||
mel.setAttribute('stroke-width', strokeWidth);
|
||||
marker.appendChild(mel);
|
||||
} else {
|
||||
var text = addElem(markerTypes[seType]);
|
||||
const text = addElem(markerTypes[seType]);
|
||||
// have to add text to get bounding box
|
||||
text.textContent = val;
|
||||
var tb = text.getBBox();
|
||||
const tb = text.getBBox();
|
||||
// alert(tb.x + ' ' + tb.y + ' ' + tb.width + ' ' + tb.height);
|
||||
var pad = 1;
|
||||
var bb = tb;
|
||||
const pad = 1;
|
||||
const bb = tb;
|
||||
bb.x = 0;
|
||||
bb.y = 0;
|
||||
bb.width += pad * 2;
|
||||
|
@ -230,7 +228,7 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
markerWidth = bb.width / 10;
|
||||
markerHeight = bb.height / 10;
|
||||
|
||||
var box = addElem({
|
||||
const box = addElem({
|
||||
'element': 'rect',
|
||||
'attr': {
|
||||
'x': bb.x,
|
||||
|
@ -264,14 +262,14 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
|
||||
// Convert to polyline to accept mid-arrow
|
||||
|
||||
var x1 = Number(elem.getAttribute('x1'));
|
||||
var x2 = Number(elem.getAttribute('x2'));
|
||||
var y1 = Number(elem.getAttribute('y1'));
|
||||
var y2 = Number(elem.getAttribute('y2'));
|
||||
var id = elem.id;
|
||||
const x1 = Number(elem.getAttribute('x1'));
|
||||
const x2 = Number(elem.getAttribute('x2'));
|
||||
const y1 = Number(elem.getAttribute('y1'));
|
||||
const y2 = Number(elem.getAttribute('y2'));
|
||||
const {id} = elem;
|
||||
|
||||
var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
|
||||
var pline = addElem({
|
||||
const midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
|
||||
const pline = addElem({
|
||||
'element': 'polyline',
|
||||
'attr': {
|
||||
'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
|
||||
var nam = 'marker-' + pos;
|
||||
var m = elem.getAttribute(nam);
|
||||
const nam = 'marker-' + pos;
|
||||
const m = 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.InsertElementCommand(pline));
|
||||
|
||||
|
@ -300,14 +298,14 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
}
|
||||
|
||||
function setMarker () {
|
||||
var poslist = {'start_marker': 'start', 'mid_marker': 'mid', 'end_marker': 'end'};
|
||||
var pos = poslist[this.id];
|
||||
var markerName = 'marker-' + pos;
|
||||
var val = this.value;
|
||||
var el = selElems[0];
|
||||
var marker = getLinked(el, markerName);
|
||||
const poslist = {'start_marker': 'start', 'mid_marker': 'mid', 'end_marker': 'end'};
|
||||
const pos = poslist[this.id];
|
||||
const markerName = 'marker-' + pos;
|
||||
let el = selElems[0];
|
||||
const marker = getLinked(el, markerName);
|
||||
if (marker) { $(marker).remove(); }
|
||||
el.removeAttribute(markerName);
|
||||
let val = this.value;
|
||||
if (val === '') { val = '\\nomarker'; }
|
||||
if (val === '\\nomarker') {
|
||||
setIcon(pos, val);
|
||||
|
@ -315,7 +313,7 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
return;
|
||||
}
|
||||
// Set marker on element
|
||||
var id = markerPrefix + pos + '_' + el.id;
|
||||
const id = markerPrefix + pos + '_' + el.id;
|
||||
addMarker(id, val);
|
||||
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
|
||||
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
|
||||
// this routine changes the associated markers to be the same color
|
||||
function colorChanged (elem) {
|
||||
var color = elem.getAttribute('stroke');
|
||||
const color = elem.getAttribute('stroke');
|
||||
|
||||
$.each(mtypes, function (i, pos) {
|
||||
var marker = getLinked(elem, 'marker-' + pos);
|
||||
const marker = getLinked(elem, 'marker-' + pos);
|
||||
if (!marker) { return; }
|
||||
if (!marker.attributes.se_type) { return; } // not created by this extension
|
||||
var ch = marker.lastElementChild;
|
||||
const ch = marker.lastElementChild;
|
||||
if (!ch) { return; }
|
||||
var curfill = ch.getAttribute('fill');
|
||||
var curstroke = ch.getAttribute('stroke');
|
||||
const curfill = ch.getAttribute('fill');
|
||||
const curstroke = ch.getAttribute('stroke');
|
||||
if (curfill && curfill !== 'none') { ch.setAttribute('fill', 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
|
||||
function updateReferences (el) {
|
||||
$.each(mtypes, function (i, pos) {
|
||||
var id = markerPrefix + pos + '_' + el.id;
|
||||
var markerName = 'marker-' + pos;
|
||||
var marker = getLinked(el, markerName);
|
||||
const id = markerPrefix + pos + '_' + el.id;
|
||||
const markerName = 'marker-' + pos;
|
||||
const marker = getLinked(el, markerName);
|
||||
if (!marker || !marker.attributes.se_type) { return; } // not created by this extension
|
||||
var url = el.getAttribute(markerName);
|
||||
const url = el.getAttribute(markerName);
|
||||
if (url) {
|
||||
var len = el.id.length;
|
||||
var linkid = url.substr(-len - 1, len);
|
||||
const len = el.id.length;
|
||||
const linkid = url.substr(-len - 1, len);
|
||||
if (el.id !== linkid) {
|
||||
var val = $('#' + pos + '_marker').attr('value');
|
||||
const val = $('#' + pos + '_marker').attr('value');
|
||||
addMarker(id, val);
|
||||
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
|
||||
if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); }
|
||||
|
@ -368,13 +366,13 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
function triggerTextEntry (pos, val) {
|
||||
$('#' + pos + '_marker').val(val);
|
||||
$('#' + pos + '_marker').change();
|
||||
// var txtbox = $('#'+pos+'_marker');
|
||||
// const txtbox = $('#'+pos+'_marker');
|
||||
// if (val.substr(0,1)=='\\') {txtbox.hide();}
|
||||
// else {txtbox.show();}
|
||||
}
|
||||
|
||||
function showTextPrompt (pos) {
|
||||
var def = $('#' + pos + '_marker').val();
|
||||
let def = $('#' + pos + '_marker').val();
|
||||
if (def.substr(0, 1) === '\\') { def = ''; }
|
||||
$.prompt('Enter text for ' + pos + ' marker', def, function (txt) {
|
||||
if (txt) { triggerTextEntry(pos, txt); }
|
||||
|
@ -383,8 +381,8 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
|
||||
/*
|
||||
function setMarkerSet(obj) {
|
||||
var parts = this.id.split('_');
|
||||
var set = parts[2];
|
||||
const parts = this.id.split('_');
|
||||
const set = parts[2];
|
||||
switch (set) {
|
||||
case 'off':
|
||||
triggerTextEntry('start','\\nomarker');
|
||||
|
@ -406,9 +404,9 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
*/
|
||||
// callback function for a toolbar button click
|
||||
function setArrowFromButton (obj) {
|
||||
var parts = this.id.split('_');
|
||||
var pos = parts[1];
|
||||
var val = parts[2];
|
||||
const parts = this.id.split('_');
|
||||
const pos = parts[1];
|
||||
let val = parts[2];
|
||||
if (parts[3]) { val += '_' + parts[3]; }
|
||||
|
||||
if (val !== 'textmarker') {
|
||||
|
@ -418,9 +416,9 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
}
|
||||
}
|
||||
|
||||
function getTitle (lang, id) {
|
||||
var i, list = langList[lang];
|
||||
for (i in list) {
|
||||
function getTitle (lang = 'en', id) {
|
||||
const list = langList[lang];
|
||||
for (const i in list) {
|
||||
if (list.hasOwnProperty(i) && list[i].id === id) {
|
||||
return list[i].title;
|
||||
}
|
||||
|
@ -429,10 +427,9 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
}
|
||||
|
||||
// build the toolbar button array from the marker definitions
|
||||
// TODO: need to incorporate language specific titles
|
||||
function buildButtonList () {
|
||||
var buttons = [];
|
||||
// var i = 0;
|
||||
function buildButtonList (lang) {
|
||||
const buttons = [];
|
||||
// const i = 0;
|
||||
/*
|
||||
buttons.push({
|
||||
id: idPrefix + 'markers_off',
|
||||
|
@ -457,14 +454,14 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
});
|
||||
*/
|
||||
$.each(mtypes, function (k, pos) {
|
||||
var listname = pos + '_marker_list';
|
||||
var def = true;
|
||||
const listname = pos + '_marker_list';
|
||||
let def = true;
|
||||
$.each(markerTypes, function (id, v) {
|
||||
var title = getTitle('en', String(id));
|
||||
const title = getTitle(lang, String(id));
|
||||
buttons.push({
|
||||
id: idPrefix + pos + '_' + id,
|
||||
svgicon: id,
|
||||
title: title,
|
||||
title,
|
||||
type: 'context',
|
||||
events: {'click': setArrowFromButton},
|
||||
panel: 'marker_panel',
|
||||
|
@ -477,76 +474,28 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
return buttons;
|
||||
}
|
||||
|
||||
return {
|
||||
let currentLang;
|
||||
const ret = {
|
||||
name: 'Markers',
|
||||
svgicons: svgEditor.curConfig.extPath + 'markers-icons.xml',
|
||||
buttons: buildButtonList(),
|
||||
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 () {
|
||||
callback () {
|
||||
$('#marker_panel').addClass('toolset').hide();
|
||||
},
|
||||
addLangData: function (lang) {
|
||||
addLangData (lang) {
|
||||
currentLang = lang;
|
||||
return { data: langList[lang] };
|
||||
},
|
||||
selectedChanged: function (opts) {
|
||||
selectedChanged (opts) {
|
||||
// Use this to update the current selected elements
|
||||
// console.log('selectChanged',opts);
|
||||
selElems = opts.elems;
|
||||
|
||||
var i = selElems.length;
|
||||
var markerElems = ['line', 'path', 'polyline', 'polygon'];
|
||||
const markerElems = ['line', 'path', 'polyline', 'polygon'];
|
||||
|
||||
let i = selElems.length;
|
||||
while (i--) {
|
||||
var elem = selElems[i];
|
||||
if (elem && $.inArray(elem.tagName, markerElems) !== -1) {
|
||||
const elem = selElems[i];
|
||||
if (elem && markerElems.includes(elem.tagName)) {
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
showPanel(true);
|
||||
} else {
|
||||
|
@ -558,9 +507,9 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
}
|
||||
},
|
||||
|
||||
elementChanged: function (opts) {
|
||||
elementChanged (opts) {
|
||||
// console.log('elementChanged',opts);
|
||||
var elem = opts.elems[0];
|
||||
const elem = opts.elems[0];
|
||||
if (elem && (
|
||||
elem.getAttribute('marker-start') ||
|
||||
elem.getAttribute('marker-mid') ||
|
||||
|
@ -572,4 +521,66 @@ svgEditor.addExtension('Markers', function (S) {
|
|||
// 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;
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals MathJax, svgEditor, svgCanvas, $ */
|
||||
/* globals jQuery, MathJax, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-mathjax.js
|
||||
*
|
||||
|
@ -10,11 +9,12 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('mathjax', function () {
|
||||
'use strict';
|
||||
const $ = jQuery;
|
||||
|
||||
// Configuration of the MathJax extention.
|
||||
|
||||
// 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({\
|
||||
extensions: ["tex2jax.js"],\
|
||||
jax: ["input/TeX","output/SVG"],\
|
||||
|
@ -37,12 +37,15 @@ svgEditor.addExtension('mathjax', function () {
|
|||
});\
|
||||
</script>', */
|
||||
// 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,
|
||||
locationX,
|
||||
locationY,
|
||||
mathjaxLoaded = false,
|
||||
uiStrings = svgEditor.uiStrings;
|
||||
mathjaxLoaded = false;
|
||||
|
||||
// TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback.
|
||||
$.extend(uiStrings, {
|
||||
|
@ -56,7 +59,7 @@ svgEditor.addExtension('mathjax', function () {
|
|||
});
|
||||
|
||||
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
|
||||
// less fancy!
|
||||
MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']);
|
||||
|
@ -75,22 +78,17 @@ svgEditor.addExtension('mathjax', function () {
|
|||
*/
|
||||
MathJax.Hub.queue.Push(
|
||||
function () {
|
||||
var mathjaxMath = $('.MathJax_SVG');
|
||||
var svg = $(mathjaxMath.html());
|
||||
const mathjaxMath = $('.MathJax_SVG');
|
||||
const svg = $(mathjaxMath.html());
|
||||
svg.find('use').each(function () {
|
||||
var x, y, id, transform;
|
||||
|
||||
// TODO: find a less pragmatic and more elegant solution to this.
|
||||
if ($(this).attr('href')) {
|
||||
id = $(this).attr('href').slice(1); // Works in Chrome.
|
||||
} else {
|
||||
id = $(this).attr('xlink:href').slice(1); // Works in Firefox.
|
||||
}
|
||||
|
||||
var glymph = $('#' + id).clone().removeAttr('id');
|
||||
x = $(this).attr('x');
|
||||
y = $(this).attr('y');
|
||||
transform = $(this).attr('transform');
|
||||
const id = $(this).attr('href')
|
||||
? $(this).attr('href').slice(1) // Works in Chrome.
|
||||
: $(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');
|
||||
const transform = $(this).attr('transform');
|
||||
if (transform && (x || y)) {
|
||||
glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')');
|
||||
} else if (transform) {
|
||||
|
@ -120,7 +118,7 @@ svgEditor.addExtension('mathjax', function () {
|
|||
type: 'mode',
|
||||
title: 'Add Mathematics',
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
// 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.
|
||||
if (mathjaxLoaded === false) {
|
||||
|
@ -166,6 +164,8 @@ svgEditor.addExtension('mathjax', function () {
|
|||
$('body').addClass('tex2jax_ignore');
|
||||
|
||||
// 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)
|
||||
.done(function (script, textStatus) {
|
||||
// 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') {
|
||||
return {started: true};
|
||||
}
|
||||
},
|
||||
mouseUp: function (opts) {
|
||||
mouseUp (opts) {
|
||||
if (svgCanvas.getMode() === 'mathjax') {
|
||||
// Get the coordinates from your mouse.
|
||||
var zoom = svgCanvas.getZoom();
|
||||
const zoom = svgCanvas.getZoom();
|
||||
// Get the actual coordinate by dividing by the zoom value
|
||||
locationX = opts.mouse_x / zoom;
|
||||
locationY = opts.mouse_y / zoom;
|
||||
|
@ -205,7 +205,7 @@ svgEditor.addExtension('mathjax', function () {
|
|||
return {started: false}; // Otherwise the last selected object dissapears.
|
||||
}
|
||||
},
|
||||
callback: function () {
|
||||
callback () {
|
||||
$('<style>').text(
|
||||
'#mathjax fieldset{' +
|
||||
'padding: 5px;' +
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgedit, $ */
|
||||
/* globals jQuery, svgEditor, svgedit */
|
||||
/*
|
||||
* ext-overview_window.js
|
||||
*
|
||||
|
@ -9,21 +8,21 @@
|
|||
*
|
||||
*/
|
||||
|
||||
var overviewWindowGlobals = {};
|
||||
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
|
||||
// https://code.google.com/p/chromium/issues/detail?id=565120.
|
||||
if (svgedit.browser.isChrome()) {
|
||||
var verIndex = navigator.userAgent.indexOf('Chrome/') + 7;
|
||||
var chromeVersion = parseInt(navigator.userAgent.substring(verIndex), 10);
|
||||
const verIndex = navigator.userAgent.indexOf('Chrome/') + 7;
|
||||
const chromeVersion = parseInt(navigator.userAgent.substring(verIndex), 10);
|
||||
if (chromeVersion < 49) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 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" style="position:relative; left:12px; top:0px;">' +
|
||||
'<div style="background-color:#A0A0A0; display:inline-block; overflow:visible;">' +
|
||||
|
@ -38,20 +37,20 @@ svgEditor.addExtension('overview_window', function () {
|
|||
$('#sidepanels').append(propsWindowHtml);
|
||||
|
||||
// Define dynamic animation of the view box.
|
||||
var updateViewBox = function () {
|
||||
var portHeight = parseFloat($('#workarea').css('height'));
|
||||
var portWidth = parseFloat($('#workarea').css('width'));
|
||||
var portX = $('#workarea').scrollLeft();
|
||||
var portY = $('#workarea').scrollTop();
|
||||
var windowWidth = parseFloat($('#svgcanvas').css('width'));
|
||||
var windowHeight = parseFloat($('#svgcanvas').css('height'));
|
||||
var overviewWidth = $('#overviewMiniView').attr('width');
|
||||
var overviewHeight = $('#overviewMiniView').attr('height');
|
||||
const updateViewBox = function () {
|
||||
const portHeight = parseFloat($('#workarea').css('height'));
|
||||
const portWidth = parseFloat($('#workarea').css('width'));
|
||||
const portX = $('#workarea').scrollLeft();
|
||||
const portY = $('#workarea').scrollTop();
|
||||
const windowWidth = parseFloat($('#svgcanvas').css('width'));
|
||||
const windowHeight = parseFloat($('#svgcanvas').css('height'));
|
||||
const overviewWidth = $('#overviewMiniView').attr('width');
|
||||
const overviewHeight = $('#overviewMiniView').attr('height');
|
||||
|
||||
var viewBoxX = portX / windowWidth * overviewWidth;
|
||||
var viewBoxY = portY / windowHeight * overviewHeight;
|
||||
var viewBoxWidth = portWidth / windowWidth * overviewWidth;
|
||||
var viewBoxHeight = portHeight / windowHeight * overviewHeight;
|
||||
const viewBoxX = portX / windowWidth * overviewWidth;
|
||||
const viewBoxY = portY / windowHeight * overviewHeight;
|
||||
const viewBoxWidth = portWidth / windowWidth * overviewWidth;
|
||||
const viewBoxHeight = portHeight / windowHeight * overviewHeight;
|
||||
|
||||
$('#overview_window_view_box').css('min-width', viewBoxWidth + 'px');
|
||||
$('#overview_window_view_box').css('min-height', viewBoxHeight + 'px');
|
||||
|
@ -67,12 +66,12 @@ svgEditor.addExtension('overview_window', function () {
|
|||
updateViewBox();
|
||||
|
||||
// Compensate for changes in zoom and canvas size.
|
||||
var updateViewDimensions = function () {
|
||||
var viewWidth = $('#svgroot').attr('width');
|
||||
var viewHeight = $('#svgroot').attr('height');
|
||||
var viewX = 640;
|
||||
var viewY = 480;
|
||||
const updateViewDimensions = function () {
|
||||
const viewWidth = $('#svgroot').attr('width');
|
||||
const viewHeight = $('#svgroot').attr('height');
|
||||
|
||||
let viewX = 640;
|
||||
let viewY = 480;
|
||||
if (svgedit.browser.isIE()) {
|
||||
// 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.
|
||||
|
@ -84,8 +83,8 @@ svgEditor.addExtension('overview_window', function () {
|
|||
viewY = 0;
|
||||
}
|
||||
|
||||
var svgWidthOld = $('#overviewMiniView').attr('width');
|
||||
var svgHeightNew = viewHeight / viewWidth * svgWidthOld;
|
||||
const svgWidthOld = $('#overviewMiniView').attr('width');
|
||||
const svgHeightNew = viewHeight / viewWidth * svgWidthOld;
|
||||
$('#overviewMiniView').attr('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight);
|
||||
$('#overviewMiniView').attr('height', svgHeightNew);
|
||||
updateViewBox();
|
||||
|
@ -94,16 +93,16 @@ svgEditor.addExtension('overview_window', function () {
|
|||
|
||||
// Set up the overview window as a controller for the view port.
|
||||
overviewWindowGlobals.viewBoxDragging = false;
|
||||
var updateViewPortFromViewBox = function () {
|
||||
var windowWidth = parseFloat($('#svgcanvas').css('width'));
|
||||
var windowHeight = parseFloat($('#svgcanvas').css('height'));
|
||||
var overviewWidth = $('#overviewMiniView').attr('width');
|
||||
var overviewHeight = $('#overviewMiniView').attr('height');
|
||||
var viewBoxX = parseFloat($('#overview_window_view_box').css('left'));
|
||||
var viewBoxY = parseFloat($('#overview_window_view_box').css('top'));
|
||||
const updateViewPortFromViewBox = function () {
|
||||
const windowWidth = parseFloat($('#svgcanvas').css('width'));
|
||||
const windowHeight = parseFloat($('#svgcanvas').css('height'));
|
||||
const overviewWidth = $('#overviewMiniView').attr('width');
|
||||
const overviewHeight = $('#overviewMiniView').attr('height');
|
||||
const viewBoxX = parseFloat($('#overview_window_view_box').css('left'));
|
||||
const viewBoxY = parseFloat($('#overview_window_view_box').css('top'));
|
||||
|
||||
var portX = viewBoxX / overviewWidth * windowWidth;
|
||||
var portY = viewBoxY / overviewHeight * windowHeight;
|
||||
const portX = viewBoxX / overviewWidth * windowWidth;
|
||||
const portY = viewBoxY / overviewHeight * windowHeight;
|
||||
|
||||
$('#workarea').scrollLeft(portX);
|
||||
$('#workarea').scrollTop(portY);
|
||||
|
@ -111,20 +110,20 @@ svgEditor.addExtension('overview_window', function () {
|
|||
$('#overview_window_view_box').draggable({
|
||||
containment: 'parent',
|
||||
drag: updateViewPortFromViewBox,
|
||||
start: function () { overviewWindowGlobals.viewBoxDragging = true; },
|
||||
stop: function () { overviewWindowGlobals.viewBoxDragging = false; }
|
||||
start () { overviewWindowGlobals.viewBoxDragging = true; },
|
||||
stop () { overviewWindowGlobals.viewBoxDragging = false; }
|
||||
});
|
||||
$('#overviewMiniView').click(function (evt) {
|
||||
// Firefox doesn't support evt.offsetX and evt.offsetY.
|
||||
var mouseX = (evt.offsetX || evt.originalEvent.layerX);
|
||||
var mouseY = (evt.offsetY || evt.originalEvent.layerY);
|
||||
var overviewWidth = $('#overviewMiniView').attr('width');
|
||||
var overviewHeight = $('#overviewMiniView').attr('height');
|
||||
var viewBoxWidth = parseFloat($('#overview_window_view_box').css('min-width'));
|
||||
var viewBoxHeight = parseFloat($('#overview_window_view_box').css('min-height'));
|
||||
const mouseX = (evt.offsetX || evt.originalEvent.layerX);
|
||||
const mouseY = (evt.offsetY || evt.originalEvent.layerY);
|
||||
const overviewWidth = $('#overviewMiniView').attr('width');
|
||||
const overviewHeight = $('#overviewMiniView').attr('height');
|
||||
const viewBoxWidth = parseFloat($('#overview_window_view_box').css('min-width'));
|
||||
const viewBoxHeight = parseFloat($('#overview_window_view_box').css('min-height'));
|
||||
|
||||
var viewBoxX = mouseX - 0.5 * viewBoxWidth;
|
||||
var viewBoxY = mouseY - 0.5 * viewBoxHeight;
|
||||
let viewBoxX = mouseX - 0.5 * viewBoxWidth;
|
||||
let viewBoxY = mouseY - 0.5 * viewBoxHeight;
|
||||
// deal with constraints
|
||||
if (viewBoxX < 0) {
|
||||
viewBoxX = 0;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('ext-panning', function () {
|
||||
'use strict';
|
||||
return {
|
||||
name: 'Extension Panning',
|
||||
svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml',
|
||||
|
@ -22,18 +21,18 @@ svgEditor.addExtension('ext-panning', function () {
|
|||
type: 'mode',
|
||||
title: 'Panning',
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
svgCanvas.setMode('ext-panning');
|
||||
}
|
||||
}
|
||||
}],
|
||||
mouseDown: function () {
|
||||
mouseDown () {
|
||||
if (svgCanvas.getMode() === 'ext-panning') {
|
||||
svgEditor.setPanning(true);
|
||||
return {started: true};
|
||||
}
|
||||
},
|
||||
mouseUp: function () {
|
||||
mouseUp () {
|
||||
if (svgCanvas.getMode() === 'ext-panning') {
|
||||
svgEditor.setPanning(false);
|
||||
return {
|
||||
|
|
|
@ -1,22 +1,21 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals $, svgCanvas, svgEditor */
|
||||
/* globals jQuery, svgCanvas, svgEditor */
|
||||
// TODO: Might add support for "exportImage" custom
|
||||
// handler as in "ext-server_opensave.js" (and in savefile.php)
|
||||
|
||||
svgEditor.addExtension('php_savefile', {
|
||||
callback: function () {
|
||||
'use strict';
|
||||
callback () {
|
||||
const $ = jQuery;
|
||||
function getFileNameFromTitle () {
|
||||
var title = svgCanvas.getDocumentTitle();
|
||||
return $.trim(title);
|
||||
const title = svgCanvas.getDocumentTitle();
|
||||
return title.trim();
|
||||
}
|
||||
var saveSvgAction = svgEditor.curConfig.extPath + 'savefile.php';
|
||||
const saveSvgAction = svgEditor.curConfig.extPath + 'savefile.php';
|
||||
svgEditor.setCustomHandlers({
|
||||
save: function (win, data) {
|
||||
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,
|
||||
save (win, data) {
|
||||
const svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,
|
||||
filename = getFileNameFromTitle();
|
||||
|
||||
$.post(saveSvgAction, {output_svg: svg, filename: filename});
|
||||
$.post(saveSvgAction, {output_svg: svg, filename});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgCanvas, $ */
|
||||
/* globals jQuery, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-polygon.js
|
||||
*
|
||||
|
@ -9,35 +8,33 @@
|
|||
*
|
||||
*/
|
||||
svgEditor.addExtension('polygon', function (S) {
|
||||
'use strict';
|
||||
|
||||
var // NS = svgedit.NS,
|
||||
// svgcontent = S.svgcontent,
|
||||
const $ = jQuery;
|
||||
const // {svgcontent} = S,
|
||||
// addElem = S.addSvgElementFromJson,
|
||||
selElems,
|
||||
editingitex = false,
|
||||
editingitex = false;
|
||||
let selElems,
|
||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
|
||||
// edg = 0,
|
||||
// undoCommand = 'Not image';
|
||||
started, newFO;
|
||||
|
||||
// var ccZoom;
|
||||
// var wEl, hEl;
|
||||
// var wOffset, hOffset;
|
||||
// var ccRBG;
|
||||
// var ccOpacity;
|
||||
// var brushW, brushH;
|
||||
// const ccZoom;
|
||||
// const wEl, hEl;
|
||||
// const wOffset, hOffset;
|
||||
// const ccRBG;
|
||||
// const ccOpacity;
|
||||
// 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
|
||||
var height = $('#svg_source_container').height() - 80;
|
||||
const height = $('#svg_source_container').height() - 80;
|
||||
$('#svg_source_textarea').css('height', height);
|
||||
}; */
|
||||
function showPanel (on) {
|
||||
var fcRules = $('#fc_rules');
|
||||
let fcRules = $('#fc_rules');
|
||||
if (!fcRules.length) {
|
||||
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
|
||||
}
|
||||
|
@ -74,25 +71,25 @@ svgEditor.addExtension('polygon', function (S) {
|
|||
*/
|
||||
/*
|
||||
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/',
|
||||
ajaxEndpoint = '../../itex';
|
||||
var elt = selElems[0];
|
||||
const elt = selElems[0];
|
||||
try {
|
||||
var math = svgdoc.createElementNS(mathns, 'math');
|
||||
const math = svgdoc.createElementNS(mathns, 'math');
|
||||
math.setAttributeNS(xmlnsns, 'xmlns', mathns);
|
||||
math.setAttribute('display', 'inline');
|
||||
var semantics = document.createElementNS(mathns, 'semantics');
|
||||
var annotation = document.createElementNS(mathns, 'annotation');
|
||||
const semantics = document.createElementNS(mathns, 'semantics');
|
||||
const annotation = document.createElementNS(mathns, 'annotation');
|
||||
annotation.setAttribute('encoding', 'application/x-tex');
|
||||
annotation.textContent = tex;
|
||||
var mrow = document.createElementNS(mathns, 'mrow');
|
||||
const mrow = document.createElementNS(mathns, 'mrow');
|
||||
semantics.appendChild(mrow);
|
||||
semantics.appendChild(annotation);
|
||||
math.appendChild(semantics);
|
||||
// make an AJAX request to the server, to get the MathML
|
||||
$.post(ajaxEndpoint, {'tex': tex, 'display': 'inline'}, function(data){
|
||||
var children = data.documentElement.childNodes;
|
||||
$.post(ajaxEndpoint, {tex, 'display': 'inline'}, function(data){
|
||||
const children = data.documentElement.childNodes;
|
||||
while (children.length > 0) {
|
||||
mrow.appendChild(svgdoc.adoptNode(children[0], true));
|
||||
}
|
||||
|
@ -119,7 +116,7 @@ svgEditor.addExtension('polygon', function (S) {
|
|||
title: 'Polygon Tool',
|
||||
position: 11,
|
||||
events: {
|
||||
'click': function () {
|
||||
click () {
|
||||
svgCanvas.setMode('polygon');
|
||||
showPanel(true);
|
||||
}
|
||||
|
@ -135,22 +132,22 @@ svgEditor.addExtension('polygon', function (S) {
|
|||
size: 3,
|
||||
defval: 5,
|
||||
events: {
|
||||
change: function () {
|
||||
change () {
|
||||
setAttr('sides', this.value);
|
||||
}
|
||||
}
|
||||
}],
|
||||
|
||||
callback: function () {
|
||||
callback () {
|
||||
$('#polygon_panel').hide();
|
||||
|
||||
var endChanges = function () {
|
||||
const endChanges = function () {
|
||||
};
|
||||
|
||||
// TODO: Needs to be done after orig icon loads
|
||||
setTimeout(function () {
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
|
@ -169,18 +166,18 @@ svgEditor.addExtension('polygon', function (S) {
|
|||
// 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();
|
||||
});
|
||||
}, 3000);
|
||||
},
|
||||
mouseDown: function (opts) {
|
||||
// var e = opts.event;
|
||||
var rgb = svgCanvas.getColor('fill');
|
||||
// var ccRgbEl = rgb.substring(1, rgb.length);
|
||||
var sRgb = svgCanvas.getColor('stroke');
|
||||
mouseDown (opts) {
|
||||
// const e = opts.event;
|
||||
const rgb = svgCanvas.getColor('fill');
|
||||
// const ccRgbEl = rgb.substring(1, rgb.length);
|
||||
const sRgb = svgCanvas.getColor('stroke');
|
||||
// ccSRgbEl = sRgb.substring(1, rgb.length);
|
||||
var sWidth = svgCanvas.getStrokeWidth();
|
||||
const sWidth = svgCanvas.getStrokeWidth();
|
||||
|
||||
if (svgCanvas.getMode() === 'polygon') {
|
||||
started = true;
|
||||
|
@ -206,39 +203,37 @@ svgEditor.addExtension('polygon', function (S) {
|
|||
};
|
||||
}
|
||||
},
|
||||
mouseMove: function (opts) {
|
||||
mouseMove (opts) {
|
||||
if (!started) {
|
||||
return;
|
||||
}
|
||||
if (svgCanvas.getMode() === 'polygon') {
|
||||
// var e = opts.event;
|
||||
var x = opts.mouse_x;
|
||||
var y = opts.mouse_y;
|
||||
var c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']);
|
||||
var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, sides = c.sides,
|
||||
// orient = c.orient,
|
||||
// const e = opts.event;
|
||||
const c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']);
|
||||
let x = opts.mouse_x;
|
||||
let y = opts.mouse_y;
|
||||
const {cx, cy, fill, strokecolor, strokeWidth, sides} = c, // {orient} = c,
|
||||
edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
|
||||
newFO.setAttributeNS(null, 'edge', edg);
|
||||
|
||||
var inradius = (edg / 2) * cot(Math.PI / sides);
|
||||
var circumradius = inradius * sec(Math.PI / sides);
|
||||
var points = '';
|
||||
var s;
|
||||
for (s = 0; sides >= s; s++) {
|
||||
var angle = 2.0 * Math.PI * s / sides;
|
||||
const inradius = (edg / 2) * cot(Math.PI / sides);
|
||||
const circumradius = inradius * sec(Math.PI / sides);
|
||||
let points = '';
|
||||
for (let s = 0; sides >= s; s++) {
|
||||
const angle = 2.0 * Math.PI * s / sides;
|
||||
x = (circumradius * Math.cos(angle)) + cx;
|
||||
y = (circumradius * Math.sin(angle)) + cy;
|
||||
|
||||
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, 'fill', fill);
|
||||
newFO.setAttributeNS(null, 'stroke', strokecolor);
|
||||
newFO.setAttributeNS(null, 'stroke-width', strokewidth);
|
||||
newFO.setAttributeNS(null, 'stroke-width', strokeWidth);
|
||||
// newFO.setAttributeNS(null, 'transform', 'rotate(-90)');
|
||||
// var shape = newFO.getAttributeNS(null, 'shape');
|
||||
// const shape = newFO.getAttributeNS(null, 'shape');
|
||||
// newFO.appendChild(poly);
|
||||
// DrawPoly(cx, cy, sides, edg, orient);
|
||||
return {
|
||||
|
@ -247,25 +242,24 @@ svgEditor.addExtension('polygon', function (S) {
|
|||
}
|
||||
},
|
||||
|
||||
mouseUp: function (opts) {
|
||||
mouseUp (opts) {
|
||||
if (svgCanvas.getMode() === 'polygon') {
|
||||
var attrs = $(newFO).attr('edge');
|
||||
var keep = (attrs.edge !== '0');
|
||||
const attrs = $(newFO).attr('edge');
|
||||
const keep = (attrs.edge !== '0');
|
||||
// svgCanvas.addToSelection([newFO], true);
|
||||
return {
|
||||
keep: keep,
|
||||
keep,
|
||||
element: newFO
|
||||
};
|
||||
}
|
||||
},
|
||||
selectedChanged: function (opts) {
|
||||
selectedChanged (opts) {
|
||||
// Use this to update the current selected elements
|
||||
selElems = opts.elems;
|
||||
|
||||
var i = selElems.length;
|
||||
|
||||
let i = selElems.length;
|
||||
while (i--) {
|
||||
var elem = selElems[i];
|
||||
const elem = selElems[i];
|
||||
if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') {
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
$('#polySides').val(elem.getAttribute('sides'));
|
||||
|
@ -279,8 +273,8 @@ svgEditor.addExtension('polygon', function (S) {
|
|||
}
|
||||
}
|
||||
},
|
||||
elementChanged: function (opts) {
|
||||
// var elem = opts.elems[0];
|
||||
elementChanged (opts) {
|
||||
// const elem = opts.elems[0];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgedit, svgCanvas, canvg, $, top */
|
||||
/* globals jQuery, svgEditor, svgedit, svgCanvas, canvg */
|
||||
/*
|
||||
* ext-server_moinsave.js
|
||||
*
|
||||
|
@ -13,32 +12,32 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('server_opensave', {
|
||||
callback: function () {
|
||||
'use strict';
|
||||
var Utils = svgedit.utilities;
|
||||
var saveSvgAction = '/+modify';
|
||||
callback () {
|
||||
const $ = jQuery;
|
||||
const Utils = svgedit.utilities;
|
||||
const saveSvgAction = '/+modify';
|
||||
|
||||
// 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({
|
||||
save: function (win, data) {
|
||||
var svg = '<?xml version="1.0"?>\n' + data;
|
||||
var qstr = $.param.querystring();
|
||||
var name = qstr.substr(9).split('/+get/')[1];
|
||||
var svgData = Utils.encode64(svg);
|
||||
save (win, data) {
|
||||
const svg = '<?xml version="1.0"?>\n' + data;
|
||||
const qstr = $.param.querystring();
|
||||
const name = qstr.substr(9).split('/+get/')[1];
|
||||
const svgData = Utils.encode64(svg);
|
||||
if (!$('#export_canvas').length) {
|
||||
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
|
||||
}
|
||||
var c = $('#export_canvas')[0];
|
||||
const c = $('#export_canvas')[0];
|
||||
c.width = svgCanvas.contentW;
|
||||
c.height = svgCanvas.contentH;
|
||||
Utils.buildCanvgCallback(function () {
|
||||
canvg(c, svg, {renderCallback: function () {
|
||||
var datauri = c.toDataURL('image/png');
|
||||
// var uiStrings = svgEditor.uiStrings;
|
||||
var pngData = Utils.encode64(datauri); // Brett: This encoding seems unnecessary
|
||||
/* var form = */ $('<form>').attr({
|
||||
canvg(c, svg, {renderCallback () {
|
||||
const datauri = c.toDataURL('image/png');
|
||||
// const {uiStrings} = svgEditor;
|
||||
const pngData = Utils.encode64(datauri); // Brett: This encoding seems unnecessary
|
||||
/* const form = */ $('<form>').attr({
|
||||
method: 'post',
|
||||
action: saveSvgAction + '/' + name,
|
||||
target: 'output_frame'
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgedit, svgCanvas, canvg, $ */
|
||||
/* globals jQuery, svgEditor, svgedit, svgCanvas, canvg */
|
||||
/*
|
||||
* ext-server_opensave.js
|
||||
*
|
||||
|
@ -10,37 +9,36 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('server_opensave', {
|
||||
callback: function () {
|
||||
'use strict';
|
||||
callback () {
|
||||
const $ = jQuery;
|
||||
function getFileNameFromTitle () {
|
||||
var title = svgCanvas.getDocumentTitle();
|
||||
const title = svgCanvas.getDocumentTitle();
|
||||
// We convert (to underscore) only those disallowed Win7 file name characters
|
||||
return $.trim(title).replace(/[/\\:*?"<>|]/g, '_');
|
||||
return title.trim().replace(/[/\\:*?"<>|]/g, '_');
|
||||
}
|
||||
function xhtmlEscape (str) {
|
||||
return str.replace(/&(?!amp;)/g, '&').replace(/"/g, '"').replace(/</g, '<'); // < is actually disallowed above anyways
|
||||
}
|
||||
function clientDownloadSupport (filename, suffix, uri) {
|
||||
var a,
|
||||
support = $('<a>')[0].download === '';
|
||||
const support = $('<a>')[0].download === '';
|
||||
let a;
|
||||
if (support) {
|
||||
a = $('<a>hidden</a>').attr({download: (filename || 'image') + suffix, href: uri}).css('display', 'none').appendTo('body');
|
||||
a[0].click();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
var openSvgAction, importSvgAction, importImgAction,
|
||||
openSvgForm, importSvgForm, importImgForm,
|
||||
const
|
||||
saveSvgAction = svgEditor.curConfig.extPath + 'filesave.php',
|
||||
saveImgAction = svgEditor.curConfig.extPath + 'filesave.php',
|
||||
// Create upload target (hidden iframe)
|
||||
cancelled = false,
|
||||
Utils = svgedit.utilities;
|
||||
let cancelled = false;
|
||||
|
||||
$('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
|
||||
svgEditor.setCustomHandlers({
|
||||
save: function (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
|
||||
save (win, data) {
|
||||
const svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works
|
||||
filename = getFileNameFromTitle();
|
||||
|
||||
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')
|
||||
.submit().remove();
|
||||
},
|
||||
exportPDF: function (win, data) {
|
||||
var filename = getFileNameFromTitle(),
|
||||
exportPDF (win, data) {
|
||||
const filename = getFileNameFromTitle(),
|
||||
datauri = data.dataurlstring;
|
||||
if (clientDownloadSupport(filename, '.pdf', datauri)) {
|
||||
return;
|
||||
|
@ -73,27 +71,23 @@ svgEditor.addExtension('server_opensave', {
|
|||
.submit().remove();
|
||||
},
|
||||
// Todo: Integrate this extension with a new built-in exportWindowType, "download"
|
||||
exportImage: function (win, data) {
|
||||
var c,
|
||||
issues = data.issues,
|
||||
mimeType = data.mimeType,
|
||||
quality = data.quality;
|
||||
exportImage (win, data) {
|
||||
const {issues, mimeType, quality} = data;
|
||||
|
||||
if (!$('#export_canvas').length) {
|
||||
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
|
||||
}
|
||||
c = $('#export_canvas')[0];
|
||||
const c = $('#export_canvas')[0];
|
||||
|
||||
c.width = svgCanvas.contentW;
|
||||
c.height = svgCanvas.contentH;
|
||||
Utils.buildCanvgCallback(function () {
|
||||
canvg(c, data.svg, {renderCallback: function () {
|
||||
var pre, filename, suffix,
|
||||
datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType),
|
||||
// uiStrings = svgEditor.uiStrings,
|
||||
note = '';
|
||||
canvg(c, data.svg, {renderCallback () {
|
||||
const datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType);
|
||||
// {uiStrings} = svgEditor;
|
||||
|
||||
// Check if there are issues
|
||||
let pre, note = '';
|
||||
if (issues.length) {
|
||||
pre = '\n \u2022 ';
|
||||
note += ('\n\n' + pre + issues.join(pre));
|
||||
|
@ -103,8 +97,8 @@ svgEditor.addExtension('server_opensave', {
|
|||
alert(note);
|
||||
}
|
||||
|
||||
filename = getFileNameFromTitle();
|
||||
suffix = '.' + data.type.toLowerCase();
|
||||
const filename = getFileNameFromTitle();
|
||||
const suffix = '.' + data.type.toLowerCase();
|
||||
|
||||
if (clientDownloadSupport(filename, suffix, datauri)) {
|
||||
return;
|
||||
|
@ -128,13 +122,13 @@ svgEditor.addExtension('server_opensave', {
|
|||
if (window.FileReader) { return; }
|
||||
|
||||
// Change these to appropriate script file
|
||||
openSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg';
|
||||
importSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg';
|
||||
importImgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img';
|
||||
const openSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg';
|
||||
const importSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg';
|
||||
const importImgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img';
|
||||
|
||||
// Set up function for PHP uploader to use
|
||||
svgEditor.processFile = function (str64, type) {
|
||||
var xmlstr;
|
||||
let xmlstr;
|
||||
if (cancelled) {
|
||||
cancelled = false;
|
||||
return;
|
||||
|
@ -163,7 +157,7 @@ svgEditor.addExtension('server_opensave', {
|
|||
};
|
||||
|
||||
// Create upload form
|
||||
openSvgForm = $('<form>');
|
||||
const openSvgForm = $('<form>');
|
||||
openSvgForm.attr({
|
||||
enctype: 'multipart/form-data',
|
||||
method: 'post',
|
||||
|
@ -172,16 +166,16 @@ svgEditor.addExtension('server_opensave', {
|
|||
});
|
||||
|
||||
// Create import form
|
||||
importSvgForm = openSvgForm.clone().attr('action', importSvgAction);
|
||||
const importSvgForm = openSvgForm.clone().attr('action', importSvgAction);
|
||||
|
||||
// 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
|
||||
// selected so the same file can be picked and the change event can fire.
|
||||
function rebuildInput (form) {
|
||||
form.empty();
|
||||
var inp = $('<input type="file" name="svg_file">').appendTo(form);
|
||||
const inp = $('<input type="file" name="svg_file">').appendTo(form);
|
||||
|
||||
function submit () {
|
||||
// This submits the form, which returns the file data using svgEditor.processFile()
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, $, DOMParser */
|
||||
/* globals jQuery, svgEditor */
|
||||
/*
|
||||
* ext-shapes.js
|
||||
*
|
||||
|
@ -11,16 +10,13 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('shapes', function () {
|
||||
'use strict';
|
||||
var currentD, curShapeId;
|
||||
var canv = svgEditor.canvas;
|
||||
var curShape;
|
||||
var startX, startY;
|
||||
var svgroot = canv.getRootElem();
|
||||
var lastBBox = {};
|
||||
const $ = jQuery;
|
||||
const canv = svgEditor.canvas;
|
||||
const svgroot = canv.getRootElem();
|
||||
let lastBBox = {};
|
||||
|
||||
// This populates the category list
|
||||
var categories = {
|
||||
const categories = {
|
||||
basic: 'Basic',
|
||||
object: 'Objects',
|
||||
symbol: 'Symbols',
|
||||
|
@ -37,7 +33,7 @@ svgEditor.addExtension('shapes', function () {
|
|||
raphael_2: 'raphaeljs.com set 2'
|
||||
};
|
||||
|
||||
var library = {
|
||||
const library = {
|
||||
basic: {
|
||||
data: {
|
||||
'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;
|
||||
var modeId = 'shapelib';
|
||||
var startClientPos = {};
|
||||
const modeId = 'shapelib';
|
||||
const startClientPos = {};
|
||||
|
||||
let currentD, curShapeId, curShape, startX, startY;
|
||||
let curLib = library.basic;
|
||||
|
||||
function loadIcons () {
|
||||
$('#shape_buttons').empty().append(curLib.buttons);
|
||||
}
|
||||
|
||||
function makeButtons (cat, shapes) {
|
||||
var size = curLib.size || 300;
|
||||
var fill = curLib.fill || false;
|
||||
var off = size * 0.05;
|
||||
var vb = [-off, -off, size + off * 2, size + off * 2].join(' ');
|
||||
var stroke = fill ? 0 : (size / 30);
|
||||
var shapeIcon = new DOMParser().parseFromString(
|
||||
const size = curLib.size || 300;
|
||||
const fill = curLib.fill || false;
|
||||
const off = size * 0.05;
|
||||
const vb = [-off, -off, size + off * 2, size + off * 2].join(' ');
|
||||
const stroke = fill ? 0 : (size / 30);
|
||||
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>',
|
||||
'text/xml');
|
||||
|
||||
var width = 24;
|
||||
var height = 24;
|
||||
const width = 24;
|
||||
const height = 24;
|
||||
shapeIcon.documentElement.setAttribute('width', width);
|
||||
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 = [];
|
||||
var id;
|
||||
for (id in data) {
|
||||
var pathD = data[id];
|
||||
var icon = svgElem.clone();
|
||||
for (const id in data) {
|
||||
const pathD = data[id];
|
||||
const icon = svgElem.clone();
|
||||
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,
|
||||
title: id
|
||||
});
|
||||
|
@ -117,7 +114,7 @@ svgEditor.addExtension('shapes', function () {
|
|||
}
|
||||
|
||||
function loadLibrary (catId) {
|
||||
var lib = library[catId];
|
||||
const lib = library[catId];
|
||||
|
||||
if (!lib) {
|
||||
$('#shape_buttons').html('Loading...');
|
||||
|
@ -145,12 +142,12 @@ svgEditor.addExtension('shapes', function () {
|
|||
position: 6,
|
||||
title: 'Shape library',
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
canv.setMode(modeId);
|
||||
}
|
||||
}
|
||||
}],
|
||||
callback: function () {
|
||||
callback () {
|
||||
$('<style>').text(
|
||||
'#shape_buttons {' +
|
||||
'overflow: auto;' +
|
||||
|
@ -179,20 +176,20 @@ svgEditor.addExtension('shapes', function () {
|
|||
'font-weight: bold;' +
|
||||
'}').appendTo('head');
|
||||
|
||||
var btnDiv = $('<div id="shape_buttons">');
|
||||
const btnDiv = $('<div id="shape_buttons">');
|
||||
$('#tools_shapelib > *').wrapAll(btnDiv);
|
||||
|
||||
var shower = $('#tools_shapelib_show');
|
||||
const shower = $('#tools_shapelib_show');
|
||||
|
||||
loadLibrary('basic');
|
||||
|
||||
// Do mouseup on parent element rather than each button
|
||||
$('#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; }
|
||||
|
||||
var copy = btn.children().clone();
|
||||
const copy = btn.children().clone();
|
||||
shower.children(':not(.flyout_arrow_horiz)').remove();
|
||||
shower
|
||||
.append(copy)
|
||||
|
@ -206,15 +203,15 @@ svgEditor.addExtension('shapes', function () {
|
|||
$('.tools_flyout').fadeOut();
|
||||
});
|
||||
|
||||
var shapeCats = $('<div id="shape_cats">');
|
||||
var catStr = '';
|
||||
const shapeCats = $('<div id="shape_cats">');
|
||||
|
||||
let catStr = '';
|
||||
$.each(categories, function (id, label) {
|
||||
catStr += '<div data-cat=' + id + '>' + label + '</div>';
|
||||
});
|
||||
|
||||
shapeCats.html(catStr).children().bind('mouseup', function () {
|
||||
var catlink = $(this);
|
||||
const catlink = $(this);
|
||||
catlink.siblings().removeClass('current');
|
||||
catlink.addClass('current');
|
||||
|
||||
|
@ -232,21 +229,21 @@ svgEditor.addExtension('shapes', function () {
|
|||
});
|
||||
$('#tool_shapelib').remove();
|
||||
|
||||
var h = $('#tools_shapelib').height();
|
||||
const h = $('#tools_shapelib').height();
|
||||
$('#tools_shapelib').css({
|
||||
'margin-top': -(h / 2 - 15),
|
||||
'margin-left': 3
|
||||
});
|
||||
},
|
||||
mouseDown: function (opts) {
|
||||
var mode = canv.getMode();
|
||||
mouseDown (opts) {
|
||||
const mode = canv.getMode();
|
||||
if (mode !== modeId) { return; }
|
||||
|
||||
startX = opts.start_x;
|
||||
var x = startX;
|
||||
const x = startX;
|
||||
startY = opts.start_y;
|
||||
var y = startY;
|
||||
var curStyle = canv.getStyle();
|
||||
const y = startY;
|
||||
const curStyle = canv.getStyle();
|
||||
|
||||
startClientPos.x = opts.event.clientX;
|
||||
startClientPos.y = opts.event.clientY;
|
||||
|
@ -272,7 +269,7 @@ svgEditor.addExtension('shapes', function () {
|
|||
|
||||
canv.recalculateDimensions(curShape);
|
||||
|
||||
/* var tlist = */ canv.getTransformList(curShape);
|
||||
/* const tlist = */ canv.getTransformList(curShape);
|
||||
|
||||
lastBBox = curShape.getBBox();
|
||||
|
||||
|
@ -280,50 +277,56 @@ svgEditor.addExtension('shapes', function () {
|
|||
started: true
|
||||
};
|
||||
},
|
||||
mouseMove: function (opts) {
|
||||
var mode = canv.getMode();
|
||||
mouseMove (opts) {
|
||||
const mode = canv.getMode();
|
||||
if (mode !== modeId) { return; }
|
||||
|
||||
var zoom = canv.getZoom();
|
||||
var evt = opts.event;
|
||||
const zoom = canv.getZoom();
|
||||
const evt = opts.event;
|
||||
|
||||
var x = opts.mouse_x / zoom;
|
||||
var y = opts.mouse_y / zoom;
|
||||
const x = opts.mouse_x / zoom;
|
||||
const y = opts.mouse_y / zoom;
|
||||
|
||||
var tlist = canv.getTransformList(curShape),
|
||||
const tlist = canv.getTransformList(curShape),
|
||||
box = curShape.getBBox(),
|
||||
left = box.x, top = box.y, width = box.width,
|
||||
height = box.height;
|
||||
var dx = (x - startX), dy = (y - startY);
|
||||
left = box.x, top = box.y;
|
||||
// {width, height} = box,
|
||||
// const dx = (x - startX), dy = (y - startY);
|
||||
|
||||
var newbox = {
|
||||
const newbox = {
|
||||
'x': Math.min(startX, x),
|
||||
'y': Math.min(startY, y),
|
||||
'width': Math.abs(x - startX),
|
||||
'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 = (newbox.width / lastBBox.width) || 1;
|
||||
sy = (newbox.height / lastBBox.height) || 1;
|
||||
let sx = (newbox.width / lastBBox.width) || 1;
|
||||
let sy = (newbox.height / lastBBox.height) || 1;
|
||||
|
||||
// Not perfect, but mostly works...
|
||||
let tx = 0;
|
||||
if (x < startX) {
|
||||
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
|
||||
var translateOrigin = svgroot.createSVGTransform(),
|
||||
const translateOrigin = svgroot.createSVGTransform(),
|
||||
scale = svgroot.createSVGTransform(),
|
||||
translateBack = svgroot.createSVGTransform();
|
||||
|
||||
translateOrigin.setTranslate(-(left + tx), -(top + ty));
|
||||
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);
|
||||
sy = max * (sy < 0 ? -1 : 1);
|
||||
|
@ -339,11 +342,11 @@ svgEditor.addExtension('shapes', function () {
|
|||
|
||||
lastBBox = curShape.getBBox();
|
||||
},
|
||||
mouseUp: function (opts) {
|
||||
var mode = canv.getMode();
|
||||
mouseUp (opts) {
|
||||
const mode = canv.getMode();
|
||||
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 {
|
||||
keep: keepObject,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgCanvas, $ */
|
||||
/* globals jQuery, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-star.js
|
||||
*
|
||||
|
@ -10,10 +9,8 @@
|
|||
*/
|
||||
|
||||
svgEditor.addExtension('star', function (S) {
|
||||
'use strict';
|
||||
|
||||
var // NS = svgedit.NS,
|
||||
// svgcontent = S.svgcontent,
|
||||
const $ = jQuery;
|
||||
let // {svgcontent} = S,
|
||||
selElems,
|
||||
// editingitex = false,
|
||||
// svgdoc = S.svgroot.parentNode.ownerDocument,
|
||||
|
@ -25,7 +22,7 @@ svgEditor.addExtension('star', function (S) {
|
|||
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
|
||||
|
||||
function showPanel (on) {
|
||||
var fcRules = $('#fc_rules');
|
||||
let fcRules = $('#fc_rules');
|
||||
if (!fcRules.length) {
|
||||
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
|
||||
}
|
||||
|
@ -63,7 +60,7 @@ svgEditor.addExtension('star', function (S) {
|
|||
title: 'Star Tool',
|
||||
position: 12,
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
showPanel(true);
|
||||
svgCanvas.setMode('star');
|
||||
}
|
||||
|
@ -79,7 +76,7 @@ svgEditor.addExtension('star', function (S) {
|
|||
size: 3,
|
||||
defval: 5,
|
||||
events: {
|
||||
change: function () {
|
||||
change () {
|
||||
setAttr('point', this.value);
|
||||
}
|
||||
}
|
||||
|
@ -100,21 +97,21 @@ svgEditor.addExtension('star', function (S) {
|
|||
size: 3,
|
||||
defval: 0,
|
||||
events: {
|
||||
change: function () {
|
||||
change () {
|
||||
setAttr('radialshift', this.value);
|
||||
}
|
||||
}
|
||||
}],
|
||||
callback: function () {
|
||||
callback () {
|
||||
$('#star_panel').hide();
|
||||
// var endChanges = function(){};
|
||||
// const endChanges = function(){};
|
||||
},
|
||||
mouseDown: function (opts) {
|
||||
var rgb = svgCanvas.getColor('fill');
|
||||
// var ccRgbEl = rgb.substring(1, rgb.length);
|
||||
var sRgb = svgCanvas.getColor('stroke');
|
||||
// var ccSRgbEl = sRgb.substring(1, rgb.length);
|
||||
var sWidth = svgCanvas.getStrokeWidth();
|
||||
mouseDown (opts) {
|
||||
const rgb = svgCanvas.getColor('fill');
|
||||
// const ccRgbEl = rgb.substring(1, rgb.length);
|
||||
const sRgb = svgCanvas.getColor('stroke');
|
||||
// const ccSRgbEl = sRgb.substring(1, rgb.length);
|
||||
const sWidth = svgCanvas.getStrokeWidth();
|
||||
|
||||
if (svgCanvas.getMode() === 'star') {
|
||||
started = true;
|
||||
|
@ -141,23 +138,24 @@ svgEditor.addExtension('star', function (S) {
|
|||
};
|
||||
}
|
||||
},
|
||||
mouseMove: function (opts) {
|
||||
mouseMove (opts) {
|
||||
if (!started) {
|
||||
return;
|
||||
}
|
||||
if (svgCanvas.getMode() === 'star') {
|
||||
var x = opts.mouse_x;
|
||||
var y = opts.mouse_y;
|
||||
var c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
|
||||
const 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, 'r2', inradius);
|
||||
|
||||
var polyPoints = '';
|
||||
var s;
|
||||
for (s = 0; point >= s; s++) {
|
||||
var angle = 2.0 * Math.PI * (s / point);
|
||||
let polyPoints = '';
|
||||
for (let s = 0; point >= s; s++) {
|
||||
let angle = 2.0 * Math.PI * (s / point);
|
||||
if (orient === 'point') {
|
||||
angle -= (Math.PI / 2);
|
||||
} else if (orient === 'edge') {
|
||||
|
@ -187,17 +185,17 @@ svgEditor.addExtension('star', function (S) {
|
|||
newFO.setAttributeNS(null, 'points', polyPoints);
|
||||
newFO.setAttributeNS(null, 'fill', fill);
|
||||
newFO.setAttributeNS(null, 'stroke', strokecolor);
|
||||
newFO.setAttributeNS(null, 'stroke-width', strokewidth);
|
||||
/* var shape = */ newFO.getAttributeNS(null, 'shape');
|
||||
newFO.setAttributeNS(null, 'stroke-width', strokeWidth);
|
||||
/* const shape = */ newFO.getAttributeNS(null, 'shape');
|
||||
|
||||
return {
|
||||
started: true
|
||||
};
|
||||
}
|
||||
},
|
||||
mouseUp: function () {
|
||||
mouseUp () {
|
||||
if (svgCanvas.getMode() === 'star') {
|
||||
var attrs = $(newFO).attr(['r']);
|
||||
const attrs = $(newFO).attr(['r']);
|
||||
// svgCanvas.addToSelection([newFO], true);
|
||||
return {
|
||||
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
|
||||
selElems = opts.elems;
|
||||
|
||||
var i = selElems.length;
|
||||
|
||||
let i = selElems.length;
|
||||
while (i--) {
|
||||
var elem = selElems[i];
|
||||
const elem = selElems[i];
|
||||
if (elem && elem.getAttributeNS(null, 'shape') === 'star') {
|
||||
if (opts.selectedElement && !opts.multiselected) {
|
||||
// $('#starRadiusMulitplier').val(elem.getAttribute('r2'));
|
||||
|
@ -227,8 +224,8 @@ svgEditor.addExtension('star', function (S) {
|
|||
}
|
||||
}
|
||||
},
|
||||
elementChanged: function (opts) {
|
||||
// var elem = opts.elems[0];
|
||||
elementChanged (opts) {
|
||||
// const elem = opts.elems[0];
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgCanvas, $, widget */
|
||||
/* globals jQuery, svgEditor, svgCanvas */
|
||||
/*
|
||||
* ext-storage.js
|
||||
*
|
||||
|
@ -17,7 +16,11 @@
|
|||
* separate extension to make the setting behavior optional, and adapted
|
||||
* to inform the user of its setting of local data.
|
||||
*/
|
||||
/*
|
||||
Dependencies:
|
||||
|
||||
1. jQuery BBQ (for deparam)
|
||||
*/
|
||||
/*
|
||||
TODOS
|
||||
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
|
||||
initial (or URL-forced) dialog.
|
||||
*/
|
||||
import confirmSetStorage from './ext-locale/storage.js';
|
||||
|
||||
svgEditor.addExtension('storage', function () {
|
||||
const $ = jQuery;
|
||||
// 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
|
||||
// said "no"; instead, we'll let those who already set it, delete it themselves;
|
||||
// to change, set the "emptyStorageOnDecline" config setting to true
|
||||
// in config.js.
|
||||
var emptyStorageOnDecline = svgEditor.curConfig.emptyStorageOnDecline,
|
||||
const {
|
||||
emptyStorageOnDecline,
|
||||
// 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
|
||||
// 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
|
||||
// or adding of new storage takes place regardless of settings, set
|
||||
// the "noStorageOnLoad" config setting to true in config.js.
|
||||
noStorageOnLoad = svgEditor.curConfig.noStorageOnLoad,
|
||||
forceStorage = svgEditor.curConfig.forceStorage,
|
||||
storage = svgEditor.storage;
|
||||
noStorageOnLoad,
|
||||
forceStorage
|
||||
} = svgEditor.curConfig;
|
||||
const {storage} = svgEditor;
|
||||
|
||||
function replaceStoragePrompt (val) {
|
||||
val = val ? 'storagePrompt=' + val : '';
|
||||
var loc = top.location; // Allow this to work with the embedded editor as well
|
||||
if (loc.href.indexOf('storagePrompt=') > -1) {
|
||||
const loc = top.location; // Allow this to work with the embedded editor as well
|
||||
if (loc.href.includes('storagePrompt=')) {
|
||||
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
|
||||
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
|
||||
});
|
||||
} else {
|
||||
loc.href += (loc.href.indexOf('?') > -1 ? '&' : '?') + val;
|
||||
loc.href += (loc.href.includes('?') ? '&' : '?') + val;
|
||||
}
|
||||
}
|
||||
function setSVGContentStorage (val) {
|
||||
if (storage) {
|
||||
var name = 'svgedit-' + svgEditor.curConfig.canvasName;
|
||||
const name = 'svgedit-' + svgEditor.curConfig.canvasName;
|
||||
if (!val) {
|
||||
storage.removeItem(name);
|
||||
} else {
|
||||
|
@ -78,8 +86,7 @@ svgEditor.addExtension('storage', function () {
|
|||
|
||||
function emptyStorage () {
|
||||
setSVGContentStorage('');
|
||||
var name;
|
||||
for (name in svgEditor.curPrefs) {
|
||||
for (let name in svgEditor.curPrefs) {
|
||||
if (svgEditor.curPrefs.hasOwnProperty(name)) {
|
||||
name = 'svg-edit-' + name;
|
||||
if (storage) {
|
||||
|
@ -106,7 +113,6 @@ svgEditor.addExtension('storage', function () {
|
|||
if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) {
|
||||
return;
|
||||
}
|
||||
var key;
|
||||
if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) {
|
||||
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.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
|
||||
var val = curPrefs[key],
|
||||
store = (val !== undefined);
|
||||
let val = curPrefs[key];
|
||||
const store = (val !== undefined);
|
||||
key = 'svg-edit-' + key;
|
||||
if (!store) {
|
||||
continue;
|
||||
|
@ -127,7 +133,7 @@ svgEditor.addExtension('storage', function () {
|
|||
if (storage) {
|
||||
storage.setItem(key, val);
|
||||
} else if (window.widget) {
|
||||
widget.setPreferenceForKey(val, key);
|
||||
window.widget.setPreferenceForKey(val, key);
|
||||
} else {
|
||||
val = encodeURIComponent(val);
|
||||
document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
|
||||
|
@ -137,32 +143,18 @@ svgEditor.addExtension('storage', function () {
|
|||
}, 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;
|
||||
let loaded = false;
|
||||
return {
|
||||
name: 'storage',
|
||||
langReady: function (data) {
|
||||
var // lang = data.lang,
|
||||
uiStrings = data.uiStrings, // No need to store as dialog should only run once
|
||||
storagePrompt = $.deparam.querystring(true).storagePrompt;
|
||||
langReady (data) {
|
||||
// const {uiStrings: {confirmSetStorage}} = data, // No need to store as dialog should only run once
|
||||
const {lang} = data;
|
||||
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
|
||||
// changes the language
|
||||
|
@ -191,22 +183,22 @@ svgEditor.addExtension('storage', function () {
|
|||
)
|
||||
// ...then show the storage prompt.
|
||||
)) {
|
||||
var options = [];
|
||||
const options = [];
|
||||
if (storage) {
|
||||
options.unshift(
|
||||
{value: 'prefsAndContent', text: uiStrings.confirmSetStorage.storagePrefsAndContent},
|
||||
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly},
|
||||
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent}
|
||||
{value: 'prefsAndContent', text: storagePrefsAndContent},
|
||||
{value: 'prefsOnly', text: storagePrefsOnly},
|
||||
{value: 'noPrefsOrContent', text: storageNoPrefsOrContent}
|
||||
);
|
||||
} else {
|
||||
options.unshift(
|
||||
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs},
|
||||
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs}
|
||||
{value: 'prefsOnly', text: storagePrefs},
|
||||
{value: 'noPrefsOrContent', text: storageNoPrefs}
|
||||
);
|
||||
}
|
||||
|
||||
// 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,
|
||||
oldContentHeight = $('#dialog_content')[0].style.height,
|
||||
oldContainerHeight = $('#dialog_container')[0].style.height;
|
||||
|
@ -216,8 +208,9 @@ svgEditor.addExtension('storage', function () {
|
|||
$('#dialog_container')[0].style.marginLeft = '-400px';
|
||||
|
||||
// Open select-with-checkbox dialog
|
||||
// From svg-editor.js
|
||||
$.select(
|
||||
uiStrings.confirmSetStorage.message,
|
||||
message,
|
||||
options,
|
||||
function (pref, checked) {
|
||||
if (pref && pref !== 'noPrefsOrContent') {
|
||||
|
@ -272,9 +265,9 @@ svgEditor.addExtension('storage', function () {
|
|||
null,
|
||||
null,
|
||||
{
|
||||
label: uiStrings.confirmSetStorage.rememberLabel,
|
||||
label: rememberLabel,
|
||||
checked: false,
|
||||
tooltip: uiStrings.confirmSetStorage.rememberTooltip
|
||||
tooltip: rememberTooltip
|
||||
}
|
||||
);
|
||||
} else if (!noStorageOnLoad || forceStorage) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor */
|
||||
/*
|
||||
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
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var pathID,
|
||||
saveMessage = 'webapp-save',
|
||||
const saveMessage = 'webapp-save',
|
||||
readMessage = 'webapp-read',
|
||||
excludedMessages = [readMessage, saveMessage];
|
||||
let pathID;
|
||||
|
||||
// Todo: Update to new API once released
|
||||
window.addEventListener('message', function (e) {
|
||||
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;
|
||||
}
|
||||
var svgString,
|
||||
messageType = e.data[0];
|
||||
const messageType = e.data[0];
|
||||
let svgString;
|
||||
switch (messageType) {
|
||||
case 'webapp-view':
|
||||
// Populate the contents
|
||||
|
@ -54,7 +52,7 @@ svgEditor.addExtension('WebAppFind', function () {
|
|||
title: 'Save Image back to Disk',
|
||||
position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)")
|
||||
events: {
|
||||
click: function () {
|
||||
click () {
|
||||
if (!pathID) { // Not ready yet as haven't received first payload
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgEditor, svgCanvas */
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
svgEditor.addExtension('xdomain-messaging', function () {
|
||||
'use strict';
|
||||
try {
|
||||
window.addEventListener('message', function (e) {
|
||||
// We accept and post strings for the sake of IE9 support
|
||||
if (typeof e.data !== 'string' || e.data.charAt() === '|') {
|
||||
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') {
|
||||
return;
|
||||
}
|
||||
// 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
|
||||
allowedOrigins = svgEditor.curConfig.allowedOrigins;
|
||||
if (allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1) {
|
||||
const {allowedOrigins} = svgEditor.curConfig;
|
||||
if (!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin)) {
|
||||
return;
|
||||
}
|
||||
cbid = data.id;
|
||||
name = data.name;
|
||||
args = data.args;
|
||||
message = {
|
||||
const cbid = data.id;
|
||||
const {name, args} = data;
|
||||
const message = {
|
||||
namespace: 'svg-edit',
|
||||
id: cbid
|
||||
};
|
||||
|
|
Before Width: | Height: | Size: 718 B After Width: | Height: | Size: 568 B |
|
@ -4,7 +4,7 @@
|
|||
<meta charset="utf-8" />
|
||||
<title>-</title>
|
||||
<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>
|
||||
<body>
|
||||
|
||||
|
|
|
@ -1,50 +1,47 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals $ */
|
||||
/* globals jQuery */
|
||||
const $ = jQuery;
|
||||
$('a').click(function () {
|
||||
'use strict';
|
||||
var metaStr;
|
||||
var href = this.href;
|
||||
var target = window.parent;
|
||||
const {href} = this;
|
||||
const target = window.parent;
|
||||
const post = (message) => {
|
||||
// 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
|
||||
// (this could also have been done server-side by the library)
|
||||
if (this.href.indexOf('.svg') === -1) {
|
||||
metaStr = JSON.stringify({
|
||||
name: $(this).text(),
|
||||
id: href
|
||||
});
|
||||
target.postMessage(metaStr, '*');
|
||||
|
||||
var img = new Image();
|
||||
// Send metadata (also indicates file is about to be sent)
|
||||
post({
|
||||
name: $(this).text(),
|
||||
id: href
|
||||
});
|
||||
if (!this.href.includes('.svg')) {
|
||||
const img = new Image();
|
||||
img.onload = function () {
|
||||
var canvas = document.createElement('canvas');
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = this.width;
|
||||
canvas.height = this.height;
|
||||
// load the raster image into the canvas
|
||||
canvas.getContext('2d').drawImage(this, 0, 0);
|
||||
// retrieve the data: URL
|
||||
var dataurl;
|
||||
let data;
|
||||
try {
|
||||
dataurl = canvas.toDataURL();
|
||||
data = canvas.toDataURL();
|
||||
} catch (err) {
|
||||
// This fails in Firefox with file:// URLs :(
|
||||
alert('Data URL conversion failed: ' + err);
|
||||
dataurl = '';
|
||||
data = '';
|
||||
}
|
||||
target.postMessage('|' + href + '|' + dataurl, '*');
|
||||
post({href, data});
|
||||
};
|
||||
img.src = href;
|
||||
} 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
|
||||
$.get(href, function (data) {
|
||||
data = '|' + href + '|' + data;
|
||||
// This is where the magic happens!
|
||||
target.postMessage(data, '*');
|
||||
post({href, data});
|
||||
}, 'html'); // 'html' is necessary to keep returned data as a string
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -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);
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable no-var */
|
||||
/* globals svgedit */
|
||||
/**
|
||||
* Package: svgedit.history
|
||||
*
|
||||
|
@ -8,16 +6,10 @@
|
|||
* Copyright(c) 2016 Flint O'Brien
|
||||
*/
|
||||
|
||||
// Dependencies:
|
||||
// 1) history.js
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
if (!svgedit.history) {
|
||||
svgedit.history = {};
|
||||
}
|
||||
var history = svgedit.history;
|
||||
import {
|
||||
BatchCommand, MoveElementCommand, InsertElementCommand, RemoveElementCommand,
|
||||
ChangeElementCommand
|
||||
} from './history.js';
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* See singleton: HistoryRecordingService.NO_HISTORY
|
||||
*/
|
||||
var HistoryRecordingService = history.HistoryRecordingService = function (undoManager) {
|
||||
this.undoManager_ = undoManager;
|
||||
this.currentBatchCommand_ = null;
|
||||
this.batchCommandStack_ = [];
|
||||
};
|
||||
export default class HistoryRecordingService {
|
||||
constructor (undoManager) {
|
||||
this.undoManager_ = undoManager;
|
||||
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
|
||||
* in to functions that record history, but the caller requires that no history be recorded.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
|
Before Width: | Height: | Size: 291 B After Width: | Height: | Size: 161 B |
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 175 B |
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 194 B |
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 173 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 165 B |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 219 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 907 B |
Before Width: | Height: | Size: 812 B After Width: | Height: | Size: 610 B |
Before Width: | Height: | Size: 715 B After Width: | Height: | Size: 597 B |
Before Width: | Height: | Size: 852 B After Width: | Height: | Size: 637 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 893 B |
Before Width: | Height: | Size: 663 B After Width: | Height: | Size: 390 B |
Before Width: | Height: | Size: 688 B After Width: | Height: | Size: 514 B |
Before Width: | Height: | Size: 811 B After Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 750 B After Width: | Height: | Size: 665 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 109 B After Width: | Height: | Size: 99 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 872 B |
Before Width: | Height: | Size: 683 B After Width: | Height: | Size: 551 B |
Before Width: | Height: | Size: 652 B After Width: | Height: | Size: 559 B |
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 799 B |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 898 B |
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 542 B |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 737 B After Width: | Height: | Size: 664 B |
Before Width: | Height: | Size: 663 B After Width: | Height: | Size: 530 B |
Before Width: | Height: | Size: 571 B After Width: | Height: | Size: 526 B |
Before Width: | Height: | Size: 589 B After Width: | Height: | Size: 557 B |
Before Width: | Height: | Size: 136 B After Width: | Height: | Size: 120 B |
Before Width: | Height: | Size: 919 B After Width: | Height: | Size: 795 B |
Before Width: | Height: | Size: 906 B After Width: | Height: | Size: 698 B |
Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 788 B |
Before Width: | Height: | Size: 881 B After Width: | Height: | Size: 557 B |
Before Width: | Height: | Size: 404 B After Width: | Height: | Size: 379 B |
Before Width: | Height: | Size: 921 B After Width: | Height: | Size: 656 B |
Before Width: | Height: | Size: 980 B After Width: | Height: | Size: 646 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 694 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 566 B |
Before Width: | Height: | Size: 828 B After Width: | Height: | Size: 731 B |
Before Width: | Height: | Size: 93 B After Width: | Height: | Size: 74 B |
Before Width: | Height: | Size: 553 B After Width: | Height: | Size: 476 B |
Before Width: | Height: | Size: 666 B After Width: | Height: | Size: 575 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 893 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 422 B After Width: | Height: | Size: 328 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 600 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 938 B |