From 0e68573471cee7fa41cc82bc61015fe63ad3b95b Mon Sep 17 00:00:00 2001 From: Pranshu Srivastava Date: Wed, 31 Jul 2019 00:14:27 +0530 Subject: [PATCH] Keymapper phase 2 enhancements (#243) * Control toolbar + Keymap guide + Util fn to make custom toolbars * Toolbar options * default toolbarType and expose Guides * fix conflicts * Update src/edit/tools/DistortableImage.Guides.js Co-Authored-By: rexagod * Update .gitignore * develop on sashadev-sky's review * delete extra bracket causing error after rebase * remove intent technique * Update Gruntfile.js * force build dist * all tests passing * removed guides * addToolbar -> keymapper * Control toolbar + Keymap guide + Util fn to make custom toolbars * Update src/edit/tools/DistortableImage.Guides.js Co-Authored-By: rexagod * Update .gitignore * develop on sashadev-sky's review * Update Gruntfile.js * force build dist * package-json fixed * add hiding functionality * relocate to ../ * remove erroneous coverage from build, extend from L.Handler, remove init code from LDI.edit.js, and exposed in *.html * merge position and init * make similar changes in select.html * set topright as default position * add disable functionality * modify keymapper ui #258 * Fix rebase * fixed rebase 2 * Fix rebase 3 * initiate orb algo UI integration * Revert "initiate orb algo UI integration" This reverts commit 45ffdee0e03ab727c18b59544ec1b918b6727e43. * Make updates on rexagods updates * keymapperinitially collapsed * Keymapper toggle no longer propogates and hides image toolbar * finished draft * add disable and instance check functionality * remove instance count for DistortableImage.Edit * remove .vscode from modified files * add removeHooks * merge changes * add enable functionality * fix so that enable works * Control toolbar + Keymap guide + Util fn to make custom toolbars * Toolbar options * default toolbarType and expose Guides * develop on sashadev-sky's review * force build dist * remove erroneous coverage from build, extend from L.Handler, remove init code from LDI.edit.js, and exposed in *.html * Fix rebase 3 * Make updates on rexagods updates * add disable and instance check functionality * remove instance count for DistortableImage.Edit * add removeHooks * fix so that enable works * all fixed * restructure * More refactoring * changge from button to a * updates * clean up * clean up * fix broken package-lock * bump version * position working and ui updates * modal * refactor * get rid of arrow collapse svg * finish cleanup * return extra line to css file * cleanup * update README * syntax * try to resolve npm travis trouble * try npm rebuild * try nuking cache * add node v 12 to .travis.yml * reorder dependencies undo gruntfile change * rebase again, readd a line deleted * update README * try updaing paths --- Gruntfile.js | 12 +- README.md | 132 +-- assets/icons/svg-min/crop_rotate.svg | 2 +- assets/icons/svg-min/explore.svg | 2 +- assets/icons/svg-min/flip_to_back.svg | 2 +- assets/icons/svg-min/flip_to_front.svg | 2 +- assets/icons/svg-min/keyboard_open.svg | 1 + assets/icons/svg-min/lock.svg | 2 +- assets/icons/svg-min/opacity.svg | 2 +- assets/icons/svg-min/opacity_empty.svg | 2 +- assets/icons/svg-min/restore.svg | 2 +- assets/icons/svg-min/unlock.svg | 2 +- assets/icons/svg/keyboard_open.svg | 3 + assets/icons/symbol/sprite.symbol.html | 441 --------- assets/icons/symbol/sprite.symbol.svg | 2 +- dist/leaflet.distortableimage.css | 129 ++- dist/leaflet.distortableimage.js | 479 ++++++---- examples/index.html | 11 +- examples/listeners.html | 1 - examples/select.html | 4 - package-lock.json | 894 ++++-------------- package.json | 2 +- src/components/DistortableImage.Keymapper.js | 151 +++ src/edit/BoxSelector.js | 1 - src/edit/DistortableImage.Edit.js | 13 +- src/edit/DistortableImage.Keymapper.js | 27 - src/edit/EditHandle.js | 14 +- src/edit/tools/DistortableImage.PopupBar.js | 20 +- src/edit/tools/EditAction.js | 33 +- src/iconsets/IconSet.js | 17 + src/iconsets/KeymapperIconSet.js | 6 + .../IconSet.js => iconsets/ToolbarIconSet.js} | 15 +- src/util/IconUtil.js | 36 + test/karma.conf.js | 94 +- test/src/edit/DistortableImageEditSpec.js | 1 - 35 files changed, 973 insertions(+), 1584 deletions(-) create mode 100644 assets/icons/svg-min/keyboard_open.svg create mode 100644 assets/icons/svg/keyboard_open.svg delete mode 100644 assets/icons/symbol/sprite.symbol.html create mode 100644 src/components/DistortableImage.Keymapper.js delete mode 100644 src/edit/DistortableImage.Keymapper.js create mode 100644 src/iconsets/IconSet.js create mode 100644 src/iconsets/KeymapperIconSet.js rename src/{edit/tools/IconSet.js => iconsets/ToolbarIconSet.js} (96%) create mode 100644 src/util/IconUtil.js diff --git a/Gruntfile.js b/Gruntfile.js index 9db5aefc0..4a6556d2b 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -78,9 +78,9 @@ module.exports = function(grunt) { { removeViewBox: false }, { removeEmptyAttrs: false }, { removeTitle: true }, // "leaflet-toolbar" lets us specify the title attribute later - { removeAttrs: - { - attrs: ['xmlns', 'fill'] + { + removeAttrs: { + attrs: ['xmlns', 'fill'] } } ] @@ -131,12 +131,14 @@ module.exports = function(grunt) { 'src/edit/RotateScaleHandle.js', 'src/edit/RotateHandle.js', 'src/edit/ScaleHandle.js', - 'src/edit/tools/IconSet.js', + 'src/iconsets/IconSet.js', + 'src/iconsets/KeymapperIconSet.js', + 'src/iconsets/ToolbarIconSet.js', 'src/edit/tools/EditAction.js', 'src/edit/tools/DistortableImage.PopupBar.js', 'src/edit/tools/DistortableImage.ControlBar.js', 'src/edit/DistortableImage.Edit.js', - 'src/edit/DistortableImage.Keymapper.js', + 'src/components/DistortableImage.Keymapper.js', 'src/edit/BoxSelector.js' ], dest: 'dist/leaflet.distortableimage.js' diff --git a/README.md b/README.md index f06c7326e..018a5e4e7 100644 --- a/README.md +++ b/README.md @@ -58,17 +58,16 @@ L.tileLayer('https://{s}.tiles.mapbox.com/v3/anishshah101.ipm9j6em/{z}/{x}/{y}.p }).addTo(map); // create an image -img = L.distortableImageOverlay( - 'example.png', { - // 'corners' is the only required option for this class - // and is in NW, NE, SW, SE order - corners: [ - L.latLng(51.52,-0.14), - L.latLng(51.52,-0.10), - L.latLng(51.50,-0.14), - L.latLng(51.50,-0.10) - ], - }).addTo(map); +img = L.distortableImageOverlay('example.png', { + // 'corners' is the only required option for this class + // and is in NW, NE, SW, SE order + corners: [ + L.latLng(51.52,-0.14), + L.latLng(51.52,-0.10), + L.latLng(51.50,-0.14), + L.latLng(51.50,-0.10) + ], +}).addTo(map); // enable editing L.DomEvent.on(img._image, 'load', img.editing.enable, img.editing); @@ -93,18 +92,15 @@ If you would like to overrwrite the default toolbar actions available for an ind For example, to overrwrite the toolbar to only include the `ToggleTransparency` and `Delete` actions: ``` JS -img = L.distortableImageOverlay( -* 'example.png', { - // 'corners' is the only required option for this class - // and is in NW, NE, SW, SE order - corners: [ - L.latLng(51.52,-0.14), - L.latLng(51.52,-0.10), - L.latLng(51.50,-0.14), - L.latLng(51.50,-0.10) - ], - actions: [ToggleTransparency, Delete] - }).addTo(map); +img = L.distortableImageOverlay('example.png', { + corners: [ + L.latLng(51.52,-0.14), + L.latLng(51.52,-0.10), + L.latLng(51.50,-0.14), + L.latLng(51.50,-0.10) + ], + actions: [ToggleTransparency, Delete] +}).addTo(map); ``` ### Corners @@ -180,13 +176,10 @@ In the below example, the image will be initialiazed with "rotateScale" handles: L.DomEvent.on(img._image, 'load', img.editing.enable, img.editing); ``` -### Keymapper - -`keymapper` (*optional*, default: true, value: *boolean*) +### Full-resolution download -By default, an image loads with a keymapper legend showing the available key bindings for different editing / interaction options. To suppress the keymapper, pass `keymapper: false` as an additional option to the image. +`fullResolutionSrc` (*optional*) -### Full-resolution download We've added a GPU-accelerated means to generate a full resolution version of the distorted image; it requires two additional dependencies to enable; see how we've included them in the demo: @@ -198,20 +191,15 @@ We've added a GPU-accelerated means to generate a full resolution version of the When instantiating a Distortable Image, pass in a `fullResolutionSrc` option set to the url of the higher resolution image. This image will be used in full-res exporting. ```JS -// create basic map setup from above - -// create an image - note the optional -// fullResolutionSrc option is now passed in -img = L.distortableImageOverlay( - 'example.png', { - corners: [ - L.latLng(51.52,-0.14), - L.latLng(51.52,-0.10), - L.latLng(51.50,-0.14), - L.latLng(51.50,-0.10) - ], - fullResolutionSrc: 'large.jpg' - }).addTo(map); +img = L.distortableImageOverlay('example.png', { + corners: [ + L.latLng(51.52,-0.14), + L.latLng(51.52,-0.10), + L.latLng(51.50,-0.14), + L.latLng(51.50,-0.10) + ], + fullResolutionSrc: 'large.jpg' +}).addTo(map); L.DomEvent.on(img._image, 'load', img.editing.enable, img.editing); ``` @@ -239,26 +227,22 @@ The setup is relatively similar - here is an example with two images: ```JS // 1. Instantiate map // 2. Instantiate images but this time *dont* add them directly to the map -img = L.distortableImageOverlay( - 'example.png', { - keymapper: false, - corners: [ - L.latLng(51.52, -0.14), - L.latLng(51.52,-0.10), - L.latLng(51.50, -0.14), - L.latLng(51.50,-0.10) - ], - }); +img = L.distortableImageOverlay('example.png', { + corners: [ + L.latLng(51.52, -0.14), + L.latLng(51.52,-0.10), + L.latLng(51.50, -0.14), + L.latLng(51.50,-0.10) + ], +}); -img2 = L.distortableImageOverlay( - 'example.png', { - keymapper: false, - corners: [ - L.latLng(51.51, -0.20), - L.latLng(51.51,-0.16), - L.latLng(51.49, -0.21), - L.latLng(51.49,-0.17) - ], +img2 = L.distortableImageOverlay('example.png', { + corners: [ + L.latLng(51.51, -0.20), + L.latLng(51.51,-0.16), + L.latLng(51.49, -0.21), + L.latLng(51.49,-0.17) + ], }); // 3. Instantiate an empty `DistortableCollection` group @@ -294,13 +278,15 @@ To add / remove a tool from the toolbar at runtime, we have also added the metho ### UI and functionalities Currently it supports multiple image selection and translations, and WIP we are working on porting all editing tools to work for it, such as transparency, etc. Image distortions still use the single-image interface. -**How to multi-select:** +**multi-select:** A single toolbar instance (using `L.control`) renders the set of tools available to use on collections of images. + + 1. Multi-selection works with cmd + `click` to toggle an individual image's inclusion in this interface. 2. Or shift + `drag` to use our `BoxSelector` handler to select multiple at once. 3. Or for touch devices, `touch` and `hold` (aka `longpress`). **How to un-multi-select:** - - A single toolbar instance (using `L.control`) renders the set of tools available to use on collections of images. + - In order to return to the single-image interface, where each `L.popup` toolbar only applies actions on the image it's attached to, you must toggle *all* images out of multi-select or... - ...Click on the map or hit the esc key to quickly deselect all images. - For the aforementioned 3 mutli-select methods, the `BoxSelector` method is the only one that doesn't also toggle _out_ of multi-select mode. @@ -403,6 +389,26 @@ Defaults: - `hasTool(action)` - Checks if the tool is already present in the currently rendered control toolbar. +## Additional Components + +### Keymapper + + +```JS +// add a position option with combinations of 'top', 'bottom', 'left' or 'right' +L.distortableImage.keymapper(map, { + position: 'topleft' +}); +``` + +Options: + - `position` (*optional*, default: 'topright', value: *string*) + + +Adds a control onto the map which opens a keymapper legend showing the available key bindings for different editing / interaction options. + +(WIP) Currently includes keybindings for all available actions and does not update yet if you use the `actions` API to limit available actions. + ## Contributing This plugin has basic functionality, and is in production as part of MapKnitter, but there are [plenty of outstanding issues to resolve](https://github.com/publiclab/Leaflet.DistortableImage/issues). Please consider helping out! diff --git a/assets/icons/svg-min/crop_rotate.svg b/assets/icons/svg-min/crop_rotate.svg index e0e445f78..d4fd73158 100644 --- a/assets/icons/svg-min/crop_rotate.svg +++ b/assets/icons/svg-min/crop_rotate.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg-min/explore.svg b/assets/icons/svg-min/explore.svg index bf8563e8f..d472ffc61 100644 --- a/assets/icons/svg-min/explore.svg +++ b/assets/icons/svg-min/explore.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg-min/flip_to_back.svg b/assets/icons/svg-min/flip_to_back.svg index 515b289a9..cea43270e 100644 --- a/assets/icons/svg-min/flip_to_back.svg +++ b/assets/icons/svg-min/flip_to_back.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg-min/flip_to_front.svg b/assets/icons/svg-min/flip_to_front.svg index 31ee51b2b..9fba3be5a 100644 --- a/assets/icons/svg-min/flip_to_front.svg +++ b/assets/icons/svg-min/flip_to_front.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg-min/keyboard_open.svg b/assets/icons/svg-min/keyboard_open.svg new file mode 100644 index 000000000..829e9d0c2 --- /dev/null +++ b/assets/icons/svg-min/keyboard_open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/svg-min/lock.svg b/assets/icons/svg-min/lock.svg index ccc151079..4b4fc834b 100644 --- a/assets/icons/svg-min/lock.svg +++ b/assets/icons/svg-min/lock.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg-min/opacity.svg b/assets/icons/svg-min/opacity.svg index 0bde93a18..04a6fb124 100644 --- a/assets/icons/svg-min/opacity.svg +++ b/assets/icons/svg-min/opacity.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg-min/opacity_empty.svg b/assets/icons/svg-min/opacity_empty.svg index 3369c1235..ea567b6ae 100644 --- a/assets/icons/svg-min/opacity_empty.svg +++ b/assets/icons/svg-min/opacity_empty.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg-min/restore.svg b/assets/icons/svg-min/restore.svg index a4a37eebc..3ce2ff8f2 100644 --- a/assets/icons/svg-min/restore.svg +++ b/assets/icons/svg-min/restore.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg-min/unlock.svg b/assets/icons/svg-min/unlock.svg index 50e7afa2e..2d65dade9 100644 --- a/assets/icons/svg-min/unlock.svg +++ b/assets/icons/svg-min/unlock.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/icons/svg/keyboard_open.svg b/assets/icons/svg/keyboard_open.svg new file mode 100644 index 000000000..39cb4d047 --- /dev/null +++ b/assets/icons/svg/keyboard_open.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/icons/symbol/sprite.symbol.html b/assets/icons/symbol/sprite.symbol.html deleted file mode 100644 index d34851273..000000000 --- a/assets/icons/symbol/sprite.symbol.html +++ /dev/null @@ -1,441 +0,0 @@ - - - - - - - - SVG <symbol> sprite preview | svg-sprite - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

SVG <symbol> sprite preview

-

This preview features two methods of using the generated sprite in conjunction with inline SVG. Please have a look at the HTML source for further details and be aware of the following constraints:

-
    -
  • Your browser has to support inline SVG for these techniques to work.
  • -
  • The embedded sprite (A) slightly differs from the generated external one. Please see the documentation for details on how to create such an embeddable sprite.
  • -
  • Internet Explorer up to version 11 doesn't support external sprites for use with inline SVG. For IE 9-11, you may polyfill this functionality with SVG for Everybody.
  • -
-
-
- - - -

A) Inline SVG with embedded sprite

-
    - -
  • -
    - - - - - - -
    -

    border_clear

    -
  • -
  • -
    - - - - - - -
    -

    border_outer

    -
  • -
  • -
    - - - - - - -
    -

    crop_rotate

    -
  • -
  • -
    - - - - - - -
    -

    delete_forever

    -
  • -
  • -
    - - - - - - -
    -

    explore

    -
  • -
  • -
    - - - - - - -
    -

    flip_to_back

    -
  • -
  • -
    - - - - - - -
    -

    flip_to_front

    -
  • -
  • -
    - - - - - - -
    -

    get_app

    -
  • -
  • -
    - - - - - - -
    -

    lock

    -
  • -
  • -
    - - - - - - -
    -

    opacity

    -
  • -
  • -
    - - - - - - -
    -

    opacity_empty

    -
  • -
  • -
    - - - - - - -
    -

    restore

    -
  • -
  • -
    - - - - - - -
    -

    transform

    -
  • -
  • -
    - - - - - - -
    -

    unlock

    -
  • -
- - - -
-
- - - -

B) Inline SVG with external sprite (IE 9-11 with polyfill only)

-
    - -
  • -
    - - - - - - -
    -

    border_clear

    -
  • -
  • -
    - - - - - - -
    -

    border_outer

    -
  • -
  • -
    - - - - - - -
    -

    crop_rotate

    -
  • -
  • -
    - - - - - - -
    -

    delete_forever

    -
  • -
  • -
    - - - - - - -
    -

    explore

    -
  • -
  • -
    - - - - - - -
    -

    flip_to_back

    -
  • -
  • -
    - - - - - - -
    -

    flip_to_front

    -
  • -
  • -
    - - - - - - -
    -

    get_app

    -
  • -
  • -
    - - - - - - -
    -

    lock

    -
  • -
  • -
    - - - - - - -
    -

    opacity

    -
  • -
  • -
    - - - - - - -
    -

    opacity_empty

    -
  • -
  • -
    - - - - - - -
    -

    restore

    -
  • -
  • -
    - - - - - - -
    -

    transform

    -
  • -
  • -
    - - - - - - -
    -

    unlock

    -
  • -
- - - -
-
-

Generated at Wed, 24 Jul 2019 05:09:34 GMT by svg-sprite.

-
- - diff --git a/assets/icons/symbol/sprite.symbol.svg b/assets/icons/symbol/sprite.symbol.svg index 7d7d00353..e0495dc62 100644 --- a/assets/icons/symbol/sprite.symbol.svg +++ b/assets/icons/symbol/sprite.symbol.svg @@ -1 +1 @@ - \ No newline at end of file + diff --git a/dist/leaflet.distortableimage.css b/dist/leaflet.distortableimage.css index 70f46b342..25ca1b0f7 100644 --- a/dist/leaflet.distortableimage.css +++ b/dist/leaflet.distortableimage.css @@ -1,3 +1,11 @@ +.ldi .leaflet-pane .leaflet-overlay-pane img { + pointer-events: all !important; +} + +.ldi img.leaflet-image-layer.selected { + box-shadow: 0px 0px 0px 12px #ffea00; +} + .ldi-icon { width: 18px; height: 18px; @@ -13,15 +21,15 @@ fill: #058dc4; } +.ldi-icon.ldi-keyboard_open { + fill: black; +} + input.ldi { position:absolute; top:-100px; } -.ldi .leaflet-pane .leaflet-overlay-pane img { - pointer-events: all !important; -} - .ldi .leaflet-toolbar-icon { box-sizing: initial; } @@ -30,42 +38,65 @@ input.ldi { box-sizing: border-box; } -.ldi img.leaflet-image-layer.selected { - box-shadow: 0px 0px 0px 12px #ffea00; -} - .ldi-keymapper { - background-color: rgb(255, 255, 255, 0.75); + background-color: rgb(255, 255, 255, 1); color: black; - padding: 0px 10px 6px 10px; - font-size: 14px; - font-weight: 400; - letter-spacing: 0.5px; - line-height: 1.2; + padding: 8px; + font-size: 13px; + letter-spacing: 0.2px; + line-height: 1.3; + height: auto; + width: 235px; + border-radius: 21px; + overflow: hidden; +} + +.ldi #keymapper-wrapper { + position: relative; + width: 100%; + overflow-x: hidden; + overflow-y: auto; + max-height: 186px; + min-height: 186px; +} + +.ldi .left { + width: 46%; +} + +.ldi .left span { + overflow-wrap: break-word; +} + +.ldi .right { + display: flex; + max-width: 40%; + flex-wrap: wrap; + margin-left: 20px; + align-items: flex-start; } -.ldi-keymapper table th { - font-size: 16px; - padding-top: 8px; +.ldi #keymapper-hr { + transform: rotate(90deg); + position: relative; + transform-origin: 0px; + left: 50%; + margin: -2px; + width: 200%; } -.ldi-keymapper th { - vertical-align: bottom; - border-bottom: 2px solid rgba(0, 0, 0, 0.06); - padding: 0.75rem; - vertical-align: top; - border-top: 1px solid rgba(0, 0, 0, 0.06); +.ldi-keymapper tr { + display: block; } .ldi-keymapper td { - padding: 0.3rem; - vertical-align: top; + padding: 0.2rem; + display: flex; + width: 100%; } .ldi-keymapper kbd { - font-weight: 500; padding: 0.2rem 0.4rem; - font-size: 95%; color: black; background-color: rgb(247, 247, 247); border-radius: 3px; @@ -76,3 +107,47 @@ input.ldi { box-shadow: 0 1px 1px rgba(0, 0, 0, .2), 0 2px 0 0 rgba(255, 255, 255, .7) inset; text-shadow: 0 0.5px 0 #fff; } + +#toggle-keymapper { + background-color: #fff; + padding: 0px; + width: 30px; + height: 30px; + border-radius: 4px; + right: 16px; + cursor: pointer; + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + text-align: center; + text-decoration: none; + border: 2px solid rgba(184, 178, 173, 0.9); + line-height: 30px; +} + +#toggle-keymapper:hover { + background-color: #f4f4f4; +} + +.close-icon#toggle-keymapper { + text-transform: uppercase; + width: 254px; + font-size: 11px; + border: 1px solid lightgray; + margin: 0; + padding: 0; + background-color: whitesmoke; + border-radius: 0; + border-bottom-left-radius: 21px; + border-bottom-right-radius: 21px; + position: relative; + height: 21px; + line-height: 22px; + color: gray; + top: 10px; + left: -10px +} + +.close-icon#toggle-keymapper:hover { + background-color: #efefef; +} diff --git a/dist/leaflet.distortableimage.js b/dist/leaflet.distortableimage.js index b9f23d61d..101acb6e5 100644 --- a/dist/leaflet.distortableimage.js +++ b/dist/leaflet.distortableimage.js @@ -51,6 +51,43 @@ L.DomUtil = L.extend(L.DomUtil, { }); +L.IconUtil = { + /** creates an svg elemenet with built in accessibility properties and standardized + * classes for styling, takes in the fragment identifier (id) of the symbol to reference. + * note for symplicity we allow providing the icon target with or without the '#' prefix */ + create: function(ref) { + if (/^#/.test(ref)) { + ref = ref.replace(/^#/, ''); + } + + return ( + '' + + '' + + '' + ); + }, + + /** finds the use element and toggles its icon reference */ + toggleXlink: function(container, ref1, ref2) { + if (!/^#/.test(ref1)) { ref1 = '#' + ref1; } + if (!/^#/.test(ref2)) { ref2 = '#' + ref2; } + + var use = container.querySelector('use'); + if (use) { + var toggled = use.getAttribute('xlink:href') === ref1 ? ref2 : ref1; + use.setAttribute('xlink:href', toggled); + return toggled; + } + return false; + }, + + toggleTooltip: function(container, title1, title2) { + var toggled = container.getAttribute('title') === title1 ? title2 : title1; + container.setAttribute('title', toggled); + return toggled; + } +}; + L.ImageUtil = { getCmPerPixel: function(overlay) { @@ -175,6 +212,113 @@ L.TrigUtil = { } }; +/** this is the baseclass other IconSets inherit from, we don't use it directly */ +L.IconSet = L.Class.extend({ + + _svg: '', + + _symbols: '', + + render: function() { + this.addSymbols(this._symbols); + return this._svg; + }, + + addSymbols: function(symbols) { + this._svg += symbols; + } + +}); + +L.ToolbarIconSet = L.IconSet.extend({ + + _symbols: + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + +}); + +L.KeymapperIconSet = L.IconSet.extend({ + + _symbols: + '', + +}); + +L.EditAction = L.Toolbar2.Action.extend({ + + options: { + toolbarIcon: { + svg: false, + html: '', + className: '', + tooltip: '' + }, + }, + + initialize: function(map, overlay, options) { + this._overlay = overlay; + this._map = map; + + L.setOptions(this, options); + L.Toolbar2.Action.prototype.initialize.call(this, options); + + this._injectIconSet(); + }, + + _createIcon: function(toolbar, container, args) { + var iconOptions = this.options.toolbarIcon; + + this.toolbar = toolbar; + this._icon = L.DomUtil.create('li', '', container); + this._link = L.DomUtil.create('a', '', this._icon); + + if (iconOptions.svg) { + this._link.innerHTML = L.IconUtil.create(iconOptions.html); + } else { + this._link.innerHTML = iconOptions.html; + } + + this._link.setAttribute('href', '#'); + this._link.setAttribute('title', iconOptions.tooltip); + this._link.setAttribute('role', 'button'); + + L.DomUtil.addClass(this._link, this.constructor.baseClass); + if (iconOptions.className) { + L.DomUtil.addClass(this._link, iconOptions.className); + } + + L.DomEvent.on(this._link, 'click', this.enable, this); + + /* Add secondary toolbar */ + this._addSubToolbar(toolbar, this._icon, args); + }, + + _injectIconSet: function() { + if (document.querySelector('#iconset')) { return; } + + var el = document.createElement('div'); + el.id = 'iconset'; + el.setAttribute('hidden', 'hidden'); + el.innerHTML = new L.ToolbarIconSet().render(); + + document.querySelector('.leaflet-marker-pane').appendChild(el); + } +}); + + L.DistortableImageOverlay = L.ImageOverlay.extend({ options: { @@ -1029,7 +1173,7 @@ L.EditHandle = L.Marker.extend({ zIndexOffset: 10 }; - if (options && options.hasOwnProperty("draggable")) { + if (options && options.hasOwnProperty('draggable')) { markerOptions.draggable = options.draggable; } @@ -1049,7 +1193,7 @@ L.EditHandle = L.Marker.extend({ }, _onHandleDragStart: function() { - this._handled.fire("editstart"); + this._handled.fire('editstart'); }, _onHandleDragEnd: function() { @@ -1058,7 +1202,7 @@ L.EditHandle = L.Marker.extend({ _fireEdit: function() { this._handled.edited = true; - this._handled.fire("edit"); + this._handled.fire('edit'); }, _bindListeners: function() { @@ -1071,9 +1215,9 @@ L.EditHandle = L.Marker.extend({ this ); - this._handled._map.on("zoomend", this.updateHandle, this); + this._handled._map.on('zoomend', this.updateHandle, this); - this._handled.on("update", this.updateHandle, this); + this._handled.on('update', this.updateHandle, this); }, _unbindListeners: function() { @@ -1086,8 +1230,8 @@ L.EditHandle = L.Marker.extend({ this ); - this._handled._map.off("zoomend", this.updateHandle, this); - this._handled.off("update", this.updateHandle, this); + this._handled._map.off('zoomend', this.updateHandle, this); + this._handled.off('update', this.updateHandle, this); }, /* Takes two latlngs and calculates the scaling difference. */ @@ -1276,122 +1420,6 @@ L.ScaleHandle = L.EditHandle.extend({ }, }); -L.IconSet = L.Class.extend({ - - _svg: '', - - render: function() { - this.addSymbols(); - return this._svg; - }, - - addSymbols: function() { - this._svg += - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' - ; - } -}); - -L.EditAction = L.Toolbar2.Action.extend({ - - options: { - toolbarIcon: { - svg: false, - html: '', - className: '', - tooltip: '' - }, - }, - - initialize: function(map, overlay, options) { - this._overlay = overlay; - this._map = map; - - L.setOptions(this, options); - L.Toolbar2.Action.prototype.initialize.call(this, options); - - this._injectIconSet(); - }, - - toggleXlink: function(ref1, ref2) { - var href1 = "#" + ref1, - href2 = "#" + ref2; - - if (this._link.querySelector('use')) { - var xlink = this._link.querySelector('use:nth-child(1)'); - var newXlink = xlink.getAttribute('xlink:href') === href1 ? href2 : href1; - xlink.setAttribute('xlink:href', newXlink); - return newXlink; - } - return false; - }, - - toggleTooltip: function(title1, title2) { - var newTt = this._link.getAttribute('title') === title1 ? title2 : title1; - this._link.setAttribute('title', newTt); - return newTt; - }, - - _createIcon: function(toolbar, container, args) { - var iconOptions = this.options.toolbarIcon; - - this.toolbar = toolbar; - this._icon = L.DomUtil.create('li', '', container); - this._link = L.DomUtil.create('a', '', this._icon); - - if (iconOptions.svg) { - this._link.innerHTML = this._svgIconHelper(iconOptions.html); - } else { - this._link.innerHTML = iconOptions.html; - } - - this._link.setAttribute('href', '#'); - this._link.setAttribute('title', iconOptions.tooltip); - - L.DomUtil.addClass(this._link, this.constructor.baseClass); - if (iconOptions.className) { - L.DomUtil.addClass(this._link, iconOptions.className); - } - - L.DomEvent.on(this._link, 'click', this.enable, this); - - /* Add secondary toolbar */ - this._addSubToolbar(toolbar, this._icon, args); - }, - - _svgIconHelper: function(ref) { - return ( - '' + - '' + - '' - ); - }, - - _injectIconSet: function() { - if (document.querySelector('#iconset')) { return; } - - var el = document.createElement('div'); - el.id = 'iconset'; - el.setAttribute('hidden', 'hidden'); - el.innerHTML = new L.IconSet().render(); - - document.querySelector('.leaflet-marker-pane').appendChild(el); - } -}); - L.DistortableImage = L.DistortableImage || {}; L.distortableImage = L.DistortableImage; @@ -1421,8 +1449,8 @@ var ToggleTransparency = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('opacity_empty', 'opacity'); - this.toggleTooltip('Make Image Opaque', 'Make Image Transparent'); + L.IconUtil.toggleXlink(this._link, 'opacity_empty', 'opacity'); + L.IconUtil.toggleTooltip(this._link, 'Make Image Opaque', 'Make Image Transparent'); editing._toggleTransparency(); } }); @@ -1453,8 +1481,8 @@ var ToggleOutline = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('border_clear', 'border_outer'); - this.toggleTooltip('Remove Border', 'Add Border'); + L.IconUtil.toggleXlink(this._link, 'border_clear', 'border_outer'); + L.IconUtil.toggleTooltip(this._link, 'Remove Border', 'Add Border'); editing._toggleOutline(); } }); @@ -1506,8 +1534,8 @@ var ToggleLock = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('unlock', 'lock'); - this.toggleTooltip('Unlock', 'Lock'); + L.IconUtil.toggleXlink(this._link, 'unlock', 'lock'); + L.IconUtil.toggleTooltip(this._link, 'Unlock', 'Lock'); editing._toggleLock(); } }); @@ -1538,8 +1566,8 @@ var ToggleRotateScale = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('transform', 'crop_rotate'); - this.toggleTooltip('Distort', 'Rotate+Scale'); + L.IconUtil.toggleXlink(this._link, 'transform', 'crop_rotate'); + L.IconUtil.toggleTooltip(this._link, 'Distort', 'Rotate+Scale'); editing._toggleRotateScale(); } }); @@ -1591,8 +1619,8 @@ var ToggleOrder = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('flip_to_front', 'flip_to_back'); - this.toggleTooltip('Stack to Front', 'Stack to Back'); + L.IconUtil.toggleXlink(this._link, 'flip_to_front', 'flip_to_back'); + L.IconUtil.toggleTooltip(this._link, 'Stack to Front', 'Stack to Back'); editing._toggleOrder(); } }); @@ -1855,24 +1883,13 @@ L.DistortableImage.Edit = L.Handler.extend({ this._transparent = false; this._outlined = false; - /* generate instance counts. TODO - add the keymapper to collection instead of individ. imgs perhaps? */ - this.instance_count = L.DistortableImage.Edit.prototype.instances = - L.DistortableImage.Edit.prototype.instances ? L.DistortableImage.Edit.prototype.instances + 1 : 1; - L.setOptions(this, options); }, /* Run on image selection. */ addHooks: function() { var overlay = this._overlay, - map = overlay._map, - keymapper_position; - - /* instantiate and render keymapper for one instance only */ - if (this.instance_count === 1 && overlay.options.keymapper !== false) { - keymapper_position = overlay.options.keymapper_position || 'topright'; - map.addControl(new L.DistortableImage.Keymapper({ position: keymapper_position })); - } + map = overlay._map; /* bring the selected image into view */ overlay.bringToFront(); @@ -2474,38 +2491,162 @@ L.DistortableImage.Edit = L.Handler.extend({ L.DomUtil = L.DomUtil || {}; L.DistortableImage = L.DistortableImage || {}; +L.distortableImage = L.DistortableImage; + +L.DistortableImage.Keymapper = L.Handler.extend({ + + options: { + position: 'topright' + }, + + initialize: function (map, options) { + this._map = map; + L.setOptions(this, options); + }, -L.DistortableImage.Keymapper = L.Control.extend({ - initialize: function(options) { - L.Control.prototype.initialize.call(this, options); - }, - - onAdd: function() { - var el_wrapper = L.DomUtil.create("div", "ldi-keymapper"); - el_wrapper.innerHTML = - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "
Keymappings
t: Transparency
o: Outline
l: Lock
caps: Rotate
s: Scale
d: Distort
r: Rotate+Scale
j, k: Stack up / down
esc: Deselect All
delete , backspace: Delete
"; - return el_wrapper; + addHooks: function () { + if (!this._keymapper) { + this._toggler = this._toggleButton(); + this._scrollWrapper = this._wrap(); + this._setMapper(this._toggler, this._scrollWrapper); + + L.DomEvent.on(this._toggler, 'click', this._toggleKeymapper, this); + + L.DomEvent.on(this._scrollWrapper, { + click: L.DomEvent.stop, + mouseenter: this._disableMap, + mouseleave: this._enableMap, + }, this); } -}); + }, + + removeHooks: function () { + if (this._keymapper) { + L.DomEvent.off(this._toggler, 'click', this._toggleKeymapper, this); + + L.DomEvent.off(this._scrollWrapper, { + click: L.DomEvent.stop, + mouseenter: this._disableMap, + mouseleave: this._enableMap, + }, this); + + L.DomUtil.remove(this._toggler); + L.DomUtil.remove(this._scrollWrapper); + L.DomUtil.remove(this._keymapper._container); + this._keymapper = false; + } + }, + + _toggleButton: function () { + var toggler = L.DomUtil.create('a', ''); + toggler.setAttribute('id', 'toggle-keymapper'); + toggler.setAttribute('href', '#'); + toggler.setAttribute('role', 'button'); + toggler.setAttribute('title', 'Show Keybindings'); + toggler.innerHTML = L.IconUtil.create("keyboard_open"); + + return toggler; + }, + + _wrap: function () { + var wrap = L.DomUtil.create('div', ''); + wrap.setAttribute('id', 'keymapper-wrapper'); + wrap.style.display = 'none'; + + return wrap; + }, + + _setMapper: function (button, wrap) { + this._keymapper = L.control({ position: this.options.position }); + + this._container = this._keymapper.onAdd = function () { + var el_wrapper = L.DomUtil.create('div', 'ldi-keymapper-hide'); + el_wrapper.setAttribute('id', 'ldi-keymapper'); + var divider = L.DomUtil.create('br', 'divider'); + el_wrapper.appendChild(divider); + el_wrapper.appendChild(wrap); + wrap.insertAdjacentHTML( + 'beforeend', + '' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Stack up / down
j\xa0k
Lock Image
l
Outline
o
Scale
s
Transparency
t
RotateScale
d\xa0r
Deselect All
esc
Delete Image
delete\xa0backspace
Rotate
caps
' + ); + el_wrapper.appendChild(button); + return el_wrapper; + }; + + this._keymapper.addTo(this._map); + }, + + _toggleKeymapper: function (e) { + L.DomEvent.stop(e); + var container = document.getElementById('ldi-keymapper'); + var keymapWrap = document.getElementById('keymapper-wrapper'); + + var newClass = container.className === 'ldi-keymapper leaflet-control' ? 'ldi-keymapper-hide leaflet-control' : 'ldi-keymapper leaflet-control'; + var newStyle = keymapWrap.style.display === 'none' ? 'block' : 'none'; + + container.className = newClass; + keymapWrap.style.display = newStyle; + + L.IconUtil.toggleTooltip(this._toggler, 'Show Keybindings', 'Hide Keybindings'); + this._toggler.innerHTML = this._toggler.innerHTML === 'close' ? L.IconUtil.create('keyboard_open') : 'close'; + L.DomUtil.toggleClass(this._toggler, 'close-icon'); + }, + + _disableMap: function() { + this._map.scrollWheelZoom.disable(); + this._map.dragging.disable(); + }, + + _enableMap: function() { + this._map.scrollWheelZoom.enable(); + this._map.dragging.enable(); + }, + + _injectIconSet: function() { + if (document.querySelector('#keymapper-iconset')) { return; } + + var el = document.createElement('div'); + el.id = 'keymapper-iconset'; + el.setAttribute('hidden', 'hidden'); + + this._iconset = new L.KeymapperIconSet().render(); + el.innerHTML = this._iconset; + + document.querySelector('.leaflet-control-container').appendChild(el); + } +}); + +L.DistortableImage.Keymapper.addInitHook(function() { + L.DistortableImage.Keymapper.prototype._n = + L.DistortableImage.Keymapper.prototype._n ? L.DistortableImage.Keymapper.prototype._n + 1 : 1; + + if (L.DistortableImage.Keymapper.prototype._n === 1) { + this.enable(); + this._injectIconSet(); + } +}); + +L.distortableImage.keymapper = function (map, options) { + return new L.DistortableImage.Keymapper(map, options); +}; + L.Map.mergeOptions({ boxSelector: true, boxZoom: false }); /** * primarily Leaflet 1.5.1 source code. Overriden so that its a selection box with our `L.DistortableCollection` class * instead of a zoom box. * */ - L.Map.BoxSelector = L.Map.BoxZoom.extend({ initialize: function(map) { this._map = map; diff --git a/examples/index.html b/examples/index.html index 1a450f958..a623b0016 100644 --- a/examples/index.html +++ b/examples/index.html @@ -33,7 +33,7 @@ var map; (function() { - // basic Leaflet map setup + map = L.map("map").setView([51.505, -0.09], 13); L.tileLayer( "https://{s}.tiles.mapbox.com/v3/anishshah101.ipm9j6em/{z}/{x}/{y}.png", @@ -47,10 +47,10 @@ }).addTo(map); // create an image - img = L.distortableImageOverlay("example.jpg", { - // add a keymapper_position field with combinations of 'top', 'bottom', 'left' or 'right' + img = L.distortableImageOverlay("example.png", { + // (WIP) add a toolbarType field with values 'popup' (default) or 'control' + // add a suppressToolbar: 'true' here to disable toolbars // mode: "distort", => default handle - keymapper: false, selected: true, corners: [ L.latLng(51.52, -0.14), @@ -61,6 +61,9 @@ fullResolutionSrc: "large.jpg" }).addTo(map); + // add a position option with combinations of 'top', 'bottom', 'left' or 'right' + kmpr1 = L.distortableImage.keymapper(map, { position: 'topleft' }); + L.DomEvent.on(img._image, "load", img.editing.enable, img.editing); })(); diff --git a/examples/listeners.html b/examples/listeners.html index f2f74b022..152688855 100644 --- a/examples/listeners.html +++ b/examples/listeners.html @@ -46,7 +46,6 @@ // create an image img = L.distortableImageOverlay( 'example.png', { - keymapper: false, corners: [ L.latLng(51.52,-0.10), L.latLng(51.52,-0.14), diff --git a/examples/select.html b/examples/select.html index 0b5cb44a1..40ae3a76d 100644 --- a/examples/select.html +++ b/examples/select.html @@ -49,7 +49,6 @@ map.whenReady(function() { img = L.distortableImageOverlay( 'example.jpg', { - keymapper: false, corners: [ L.latLng(51.52, -0.14), L.latLng(51.52,-0.10), @@ -62,7 +61,6 @@ // create a second image img2 = L.distortableImageOverlay( 'example.jpg', { - keymapper: false, corners: [ L.latLng(51.51, -0.20), L.latLng(51.51,-0.16), @@ -74,7 +72,6 @@ img3 = L.distortableImageOverlay( 'example.jpg', { - keymapper: false, corners: [ L.latLng(51.50, -0.13), L.latLng(51.50,-0.09), @@ -86,7 +83,6 @@ img4 = L.distortableImageOverlay( 'example.jpg', { actions: [Export, Delete, ToggleTransparency], - keymapper: false, corners: [ L.latLng(51.51, -0.07), L.latLng(51.51,-0.03), diff --git a/package-lock.json b/package-lock.json index a1f0c273d..0b89bd05f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "leaflet-distortableimage", - "version": "0.6.6", + "version": "0.6.7", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -68,9 +68,9 @@ "dev": true }, "ajv": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz", - "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==", + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", "dev": true, "requires": { "fast-deep-equal": "^2.0.1", @@ -108,24 +108,13 @@ } }, "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.0.3.tgz", + "integrity": "sha512-c6IvoeBECQlMVuYUjSwimnhmztImpErfxJzWZhIQinIvQWoGOnB0dLIgifbPHQt5heS6mNlaZG16f06H3C8t1g==", "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, "argparse": { @@ -225,12 +214,6 @@ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -353,9 +336,9 @@ } }, "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", "dev": true }, "blob": { @@ -579,25 +562,39 @@ "dev": true }, "chokidar": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz", - "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.2.tgz", + "integrity": "sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==", "dev": true, "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", + "anymatch": "^3.0.1", + "braces": "^3.0.2", + "fsevents": "^2.0.6", + "glob-parent": "^5.0.0", + "is-binary-path": "^2.1.0", + "is-glob": "^4.0.1", "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "readdirp": "^3.1.1" }, "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -606,6 +603,21 @@ "requires": { "is-extglob": "^2.1.1" } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } } } }, @@ -961,9 +973,9 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "core-js": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz", - "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz", + "integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==", "dev": true }, "core-util-is": { @@ -1022,21 +1034,15 @@ "dev": true }, "css-tree": { - "version": "1.0.0-alpha.28", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.28.tgz", - "integrity": "sha512-joNNW1gCp3qFFzj4St6zk+Wh/NBv0vM5YbEreZk0SD4S23S+1xBKb6cLDg2uj4P4k/GUMlIm6cKIDqIG+vdt0w==", + "version": "1.0.0-alpha.33", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.33.tgz", + "integrity": "sha512-SPt57bh5nQnpsTBsx/IXbO14sRc9xXu5MtMAVuo0BaQQmyf0NupNPPSoMaqiAF5tDFafYsTkfeH4Q/HCKXkg4w==", "dev": true, "requires": { - "mdn-data": "~1.1.0", + "mdn-data": "2.0.4", "source-map": "^0.5.3" } }, - "css-url-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/css-url-regex/-/css-url-regex-1.1.0.tgz", - "integrity": "sha1-g4NCMMyfdMRX3lnuvRVD/uuDt+w=", - "dev": true - }, "css-what": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", @@ -1067,6 +1073,12 @@ "mdn-data": "~1.1.0", "source-map": "^0.5.3" } + }, + "mdn-data": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", + "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", + "dev": true } } }, @@ -1101,9 +1113,9 @@ } }, "date-format": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.0.0.tgz", - "integrity": "sha512-M6UqVvZVgFYqZL1SfHsRGIQSz3ZL+qgbsV5Lp1Vj61LZVYuEwcMXYay7DRDtYs2HQQBK5hQtQ0fD9aEJ89V0LA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", "dev": true }, "date-now": { @@ -1953,552 +1965,11 @@ "dev": true }, "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", + "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } - } + "optional": true }, "function-bind": { "version": "1.1.1", @@ -2583,13 +2054,23 @@ } }, "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", "dev": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "is-glob": "^4.0.1" + }, + "dependencies": { + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + } } }, "global-modules": { @@ -2804,12 +2285,12 @@ }, "dependencies": { "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.14" } } } @@ -3194,12 +2675,12 @@ "dev": true }, "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "^2.0.0" } }, "is-buffer": { @@ -3569,18 +3050,18 @@ "dev": true }, "karma": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/karma/-/karma-4.1.0.tgz", - "integrity": "sha512-xckiDqyNi512U4dXGOOSyLKPwek6X/vUizSy2f3geYevbLj+UIdvNwbn7IwfUIL2g1GXEPWt/87qFD1fBbl/Uw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-4.2.0.tgz", + "integrity": "sha512-fmCuxN1rwJxTdZfOXK5LjlmS4Ana/OvzNMpkyLL/TLE8hmgSkpVpMYQ7RTVa8TNKRVQDZNl5W1oF5cfKfgIMlA==", "dev": true, "requires": { "bluebird": "^3.3.0", "body-parser": "^1.16.1", - "braces": "^2.3.2", - "chokidar": "^2.0.3", + "braces": "^3.0.2", + "chokidar": "^3.0.0", "colors": "^1.1.0", "connect": "^3.6.0", - "core-js": "^2.2.0", + "core-js": "^3.1.3", "di": "^0.0.1", "dom-serialize": "^2.2.0", "flatted": "^2.0.0", @@ -3603,6 +3084,24 @@ "useragent": "2.3.0" }, "dependencies": { + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, "glob": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", @@ -3617,11 +3116,26 @@ "path-is-absolute": "^1.0.0" } }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } } } }, @@ -3940,16 +3454,16 @@ } }, "log4js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.4.0.tgz", - "integrity": "sha512-xwRvmxFsq8Hb7YeS+XKfvCrsH114bXex6mIwJ2+KmYVi23pB3+hlzyGq1JPycSFTJWNLhD/7PCtM0RfPy6/2yg==", + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", + "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", "dev": true, "requires": { "date-format": "^2.0.0", "debug": "^4.1.1", "flatted": "^2.0.0", "rfdc": "^1.1.4", - "streamroller": "^1.0.5" + "streamroller": "^1.0.6" }, "dependencies": { "debug": { @@ -4071,9 +3585,9 @@ } }, "mdn-data": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", - "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", "dev": true }, "media-typer": { @@ -4385,13 +3899,6 @@ "integrity": "sha512-jFI/4UVRsRYdUbuDTKT7KzfOp7FiD5WzYmmwNwXyUVypC0xjoTL78Fqc0jHUPIvvGD+6DQSPHIt1NE7D1ArsqA==", "dev": true }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -4813,12 +4320,6 @@ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -4921,6 +4422,12 @@ "which": "^1.2.10" } }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "dev": true + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -4954,9 +4461,9 @@ "dev": true }, "pretty-bytes": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.2.0.tgz", - "integrity": "sha512-ujANBhiUsl9AhREUDUEY1GPOharMGm8x8juS7qOHybcLi7XsKfrYQ88hSly1l2i0klXHTDYrlL8ihMCG55Dc3w==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.3.0.tgz", + "integrity": "sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==", "dev": true }, "prettysize": { @@ -5081,46 +4588,12 @@ } }, "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.1.tgz", + "integrity": "sha512-XXdSXZrQuvqoETj50+JAitxz1UPdt5dupjT6T5nVB+WvjMv2XKYj+s7hPeAVCXvmJrL36O4YYyWlIC3an2ePiQ==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "picomatch": "^2.0.4" } }, "rechoir": { @@ -5736,9 +5209,9 @@ } }, "spdx-license-ids": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz", - "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", "dev": true }, "split-string": { @@ -5810,25 +5283,25 @@ "dev": true }, "streamroller": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.5.tgz", - "integrity": "sha512-iGVaMcyF5PcUY0cPbW3xFQUXnr9O4RZXNBBjhuLZgrjLO4XCLLGfx4T2sGqygSeylUjwgWRsnNbT9aV0Zb8AYw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", + "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", "dev": true, "requires": { "async": "^2.6.2", "date-format": "^2.0.0", "debug": "^3.2.6", "fs-extra": "^7.0.1", - "lodash": "^4.17.11" + "lodash": "^4.17.14" }, "dependencies": { "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.14" } }, "debug": { @@ -5985,12 +5458,12 @@ }, "dependencies": { "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.14" } }, "dateformat": { @@ -6069,17 +5542,16 @@ } }, "svgo": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.2.2.tgz", - "integrity": "sha512-rAfulcwp2D9jjdGu+0CuqlrAUin6bBWrpoqXWwKDZZZJfXcUXQSxLJOFJCQCSA0x0pP2U0TxSlJu2ROq5Bq6qA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz", + "integrity": "sha512-MLfUA6O+qauLDbym+mMZgtXCGRfIxyQoeH6IKVcFslyODEe/ElJNwr0FohQ3xG4C6HK6bk3KYPPXwHVJk3V5NQ==", "dev": true, "requires": { "chalk": "^2.4.1", "coa": "^2.0.2", "css-select": "^2.0.0", "css-select-base-adapter": "^0.1.1", - "css-tree": "1.0.0-alpha.28", - "css-url-regex": "^1.1.0", + "css-tree": "1.0.0-alpha.33", "csso": "^3.5.1", "js-yaml": "^3.13.1", "mkdirp": "~0.5.1", @@ -6381,12 +5853,6 @@ } } }, - "upath": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz", - "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==", - "dev": true - }, "uri-js": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", @@ -6557,12 +6023,12 @@ }, "dependencies": { "async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz", - "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", "dev": true, "requires": { - "lodash": "^4.17.11" + "lodash": "^4.17.14" } }, "readable-stream": { diff --git a/package.json b/package.json index 5cc53d5da..5481707fb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "leaflet-distortableimage", - "version": "0.6.6", + "version": "0.6.7", "description": "Leaflet plugin enabling image overlays to be distorted, stretched, and warped (built for Public Lab's MapKnitter: http://publiclab.org).", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/src/components/DistortableImage.Keymapper.js b/src/components/DistortableImage.Keymapper.js new file mode 100644 index 000000000..cec5d34d7 --- /dev/null +++ b/src/components/DistortableImage.Keymapper.js @@ -0,0 +1,151 @@ +L.DomUtil = L.DomUtil || {}; +L.DistortableImage = L.DistortableImage || {}; +L.distortableImage = L.DistortableImage; + +L.DistortableImage.Keymapper = L.Handler.extend({ + + options: { + position: 'topright' + }, + + initialize: function (map, options) { + this._map = map; + L.setOptions(this, options); + }, + + addHooks: function () { + if (!this._keymapper) { + this._toggler = this._toggleButton(); + this._scrollWrapper = this._wrap(); + this._setMapper(this._toggler, this._scrollWrapper); + + L.DomEvent.on(this._toggler, 'click', this._toggleKeymapper, this); + + L.DomEvent.on(this._scrollWrapper, { + click: L.DomEvent.stop, + mouseenter: this._disableMap, + mouseleave: this._enableMap, + }, this); + } + }, + + removeHooks: function () { + if (this._keymapper) { + L.DomEvent.off(this._toggler, 'click', this._toggleKeymapper, this); + + L.DomEvent.off(this._scrollWrapper, { + click: L.DomEvent.stop, + mouseenter: this._disableMap, + mouseleave: this._enableMap, + }, this); + + L.DomUtil.remove(this._toggler); + L.DomUtil.remove(this._scrollWrapper); + L.DomUtil.remove(this._keymapper._container); + this._keymapper = false; + } + }, + + _toggleButton: function () { + var toggler = L.DomUtil.create('a', ''); + toggler.setAttribute('id', 'toggle-keymapper'); + toggler.setAttribute('href', '#'); + toggler.setAttribute('role', 'button'); + toggler.setAttribute('title', 'Show Keybindings'); + toggler.innerHTML = L.IconUtil.create("keyboard_open"); + + return toggler; + }, + + _wrap: function () { + var wrap = L.DomUtil.create('div', ''); + wrap.setAttribute('id', 'keymapper-wrapper'); + wrap.style.display = 'none'; + + return wrap; + }, + + _setMapper: function (button, wrap) { + this._keymapper = L.control({ position: this.options.position }); + + this._container = this._keymapper.onAdd = function () { + var el_wrapper = L.DomUtil.create('div', 'ldi-keymapper-hide'); + el_wrapper.setAttribute('id', 'ldi-keymapper'); + var divider = L.DomUtil.create('br', 'divider'); + el_wrapper.appendChild(divider); + el_wrapper.appendChild(wrap); + wrap.insertAdjacentHTML( + 'beforeend', + '' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
Stack up / down
j\xa0k
Lock Image
l
Outline
o
Scale
s
Transparency
t
RotateScale
d\xa0r
Deselect All
esc
Delete Image
delete\xa0backspace
Rotate
caps
' + ); + el_wrapper.appendChild(button); + return el_wrapper; + }; + + this._keymapper.addTo(this._map); + }, + + _toggleKeymapper: function (e) { + L.DomEvent.stop(e); + var container = document.getElementById('ldi-keymapper'); + var keymapWrap = document.getElementById('keymapper-wrapper'); + + var newClass = container.className === 'ldi-keymapper leaflet-control' ? 'ldi-keymapper-hide leaflet-control' : 'ldi-keymapper leaflet-control'; + var newStyle = keymapWrap.style.display === 'none' ? 'block' : 'none'; + + container.className = newClass; + keymapWrap.style.display = newStyle; + + L.IconUtil.toggleTooltip(this._toggler, 'Show Keybindings', 'Hide Keybindings'); + this._toggler.innerHTML = this._toggler.innerHTML === 'close' ? L.IconUtil.create('keyboard_open') : 'close'; + L.DomUtil.toggleClass(this._toggler, 'close-icon'); + }, + + _disableMap: function() { + this._map.scrollWheelZoom.disable(); + this._map.dragging.disable(); + }, + + _enableMap: function() { + this._map.scrollWheelZoom.enable(); + this._map.dragging.enable(); + }, + + _injectIconSet: function() { + if (document.querySelector('#keymapper-iconset')) { return; } + + var el = document.createElement('div'); + el.id = 'keymapper-iconset'; + el.setAttribute('hidden', 'hidden'); + + this._iconset = new L.KeymapperIconSet().render(); + el.innerHTML = this._iconset; + + document.querySelector('.leaflet-control-container').appendChild(el); + } +}); + +L.DistortableImage.Keymapper.addInitHook(function() { + L.DistortableImage.Keymapper.prototype._n = + L.DistortableImage.Keymapper.prototype._n ? L.DistortableImage.Keymapper.prototype._n + 1 : 1; + + if (L.DistortableImage.Keymapper.prototype._n === 1) { + this.enable(); + this._injectIconSet(); + } +}); + +L.distortableImage.keymapper = function (map, options) { + return new L.DistortableImage.Keymapper(map, options); +}; diff --git a/src/edit/BoxSelector.js b/src/edit/BoxSelector.js index cb9b22d8c..435ab0437 100644 --- a/src/edit/BoxSelector.js +++ b/src/edit/BoxSelector.js @@ -4,7 +4,6 @@ L.Map.mergeOptions({ boxSelector: true, boxZoom: false }); * primarily Leaflet 1.5.1 source code. Overriden so that its a selection box with our `L.DistortableCollection` class * instead of a zoom box. * */ - L.Map.BoxSelector = L.Map.BoxZoom.extend({ initialize: function(map) { this._map = map; diff --git a/src/edit/DistortableImage.Edit.js b/src/edit/DistortableImage.Edit.js index f484a949f..5e132e689 100644 --- a/src/edit/DistortableImage.Edit.js +++ b/src/edit/DistortableImage.Edit.js @@ -30,24 +30,13 @@ L.DistortableImage.Edit = L.Handler.extend({ this._transparent = false; this._outlined = false; - /* generate instance counts. TODO - add the keymapper to collection instead of individ. imgs perhaps? */ - this.instance_count = L.DistortableImage.Edit.prototype.instances = - L.DistortableImage.Edit.prototype.instances ? L.DistortableImage.Edit.prototype.instances + 1 : 1; - L.setOptions(this, options); }, /* Run on image selection. */ addHooks: function() { var overlay = this._overlay, - map = overlay._map, - keymapper_position; - - /* instantiate and render keymapper for one instance only */ - if (this.instance_count === 1 && overlay.options.keymapper !== false) { - keymapper_position = overlay.options.keymapper_position || 'topright'; - map.addControl(new L.DistortableImage.Keymapper({ position: keymapper_position })); - } + map = overlay._map; /* bring the selected image into view */ overlay.bringToFront(); diff --git a/src/edit/DistortableImage.Keymapper.js b/src/edit/DistortableImage.Keymapper.js deleted file mode 100644 index cbdb04747..000000000 --- a/src/edit/DistortableImage.Keymapper.js +++ /dev/null @@ -1,27 +0,0 @@ -L.DomUtil = L.DomUtil || {}; -L.DistortableImage = L.DistortableImage || {}; - -L.DistortableImage.Keymapper = L.Control.extend({ - initialize: function(options) { - L.Control.prototype.initialize.call(this, options); - }, - - onAdd: function() { - var el_wrapper = L.DomUtil.create("div", "ldi-keymapper"); - el_wrapper.innerHTML = - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "" + - "
Keymappings
t: Transparency
o: Outline
l: Lock
caps: Rotate
s: Scale
d: Distort
r: Rotate+Scale
j, k: Stack up / down
esc: Deselect All
delete , backspace: Delete
"; - return el_wrapper; - } -}); \ No newline at end of file diff --git a/src/edit/EditHandle.js b/src/edit/EditHandle.js index f043bb24c..fdc9227d7 100644 --- a/src/edit/EditHandle.js +++ b/src/edit/EditHandle.js @@ -13,7 +13,7 @@ L.EditHandle = L.Marker.extend({ zIndexOffset: 10 }; - if (options && options.hasOwnProperty("draggable")) { + if (options && options.hasOwnProperty('draggable')) { markerOptions.draggable = options.draggable; } @@ -33,7 +33,7 @@ L.EditHandle = L.Marker.extend({ }, _onHandleDragStart: function() { - this._handled.fire("editstart"); + this._handled.fire('editstart'); }, _onHandleDragEnd: function() { @@ -42,7 +42,7 @@ L.EditHandle = L.Marker.extend({ _fireEdit: function() { this._handled.edited = true; - this._handled.fire("edit"); + this._handled.fire('edit'); }, _bindListeners: function() { @@ -55,9 +55,9 @@ L.EditHandle = L.Marker.extend({ this ); - this._handled._map.on("zoomend", this.updateHandle, this); + this._handled._map.on('zoomend', this.updateHandle, this); - this._handled.on("update", this.updateHandle, this); + this._handled.on('update', this.updateHandle, this); }, _unbindListeners: function() { @@ -70,8 +70,8 @@ L.EditHandle = L.Marker.extend({ this ); - this._handled._map.off("zoomend", this.updateHandle, this); - this._handled.off("update", this.updateHandle, this); + this._handled._map.off('zoomend', this.updateHandle, this); + this._handled.off('update', this.updateHandle, this); }, /* Takes two latlngs and calculates the scaling difference. */ diff --git a/src/edit/tools/DistortableImage.PopupBar.js b/src/edit/tools/DistortableImage.PopupBar.js index daa05561d..69207a875 100644 --- a/src/edit/tools/DistortableImage.PopupBar.js +++ b/src/edit/tools/DistortableImage.PopupBar.js @@ -27,8 +27,8 @@ var ToggleTransparency = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('opacity_empty', 'opacity'); - this.toggleTooltip('Make Image Opaque', 'Make Image Transparent'); + L.IconUtil.toggleXlink(this._link, 'opacity_empty', 'opacity'); + L.IconUtil.toggleTooltip(this._link, 'Make Image Opaque', 'Make Image Transparent'); editing._toggleTransparency(); } }); @@ -59,8 +59,8 @@ var ToggleOutline = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('border_clear', 'border_outer'); - this.toggleTooltip('Remove Border', 'Add Border'); + L.IconUtil.toggleXlink(this._link, 'border_clear', 'border_outer'); + L.IconUtil.toggleTooltip(this._link, 'Remove Border', 'Add Border'); editing._toggleOutline(); } }); @@ -112,8 +112,8 @@ var ToggleLock = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('unlock', 'lock'); - this.toggleTooltip('Unlock', 'Lock'); + L.IconUtil.toggleXlink(this._link, 'unlock', 'lock'); + L.IconUtil.toggleTooltip(this._link, 'Unlock', 'Lock'); editing._toggleLock(); } }); @@ -144,8 +144,8 @@ var ToggleRotateScale = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('transform', 'crop_rotate'); - this.toggleTooltip('Distort', 'Rotate+Scale'); + L.IconUtil.toggleXlink(this._link, 'transform', 'crop_rotate'); + L.IconUtil.toggleTooltip(this._link, 'Distort', 'Rotate+Scale'); editing._toggleRotateScale(); } }); @@ -197,8 +197,8 @@ var ToggleOrder = L.EditAction.extend({ addHooks: function() { var editing = this._overlay.editing; - this.toggleXlink('flip_to_front', 'flip_to_back'); - this.toggleTooltip('Stack to Front', 'Stack to Back'); + L.IconUtil.toggleXlink(this._link, 'flip_to_front', 'flip_to_back'); + L.IconUtil.toggleTooltip(this._link, 'Stack to Front', 'Stack to Back'); editing._toggleOrder(); } }); diff --git a/src/edit/tools/EditAction.js b/src/edit/tools/EditAction.js index 58b716cae..3a37e729f 100644 --- a/src/edit/tools/EditAction.js +++ b/src/edit/tools/EditAction.js @@ -19,25 +19,6 @@ L.EditAction = L.Toolbar2.Action.extend({ this._injectIconSet(); }, - toggleXlink: function(ref1, ref2) { - var href1 = "#" + ref1, - href2 = "#" + ref2; - - if (this._link.querySelector('use')) { - var xlink = this._link.querySelector('use:nth-child(1)'); - var newXlink = xlink.getAttribute('xlink:href') === href1 ? href2 : href1; - xlink.setAttribute('xlink:href', newXlink); - return newXlink; - } - return false; - }, - - toggleTooltip: function(title1, title2) { - var newTt = this._link.getAttribute('title') === title1 ? title2 : title1; - this._link.setAttribute('title', newTt); - return newTt; - }, - _createIcon: function(toolbar, container, args) { var iconOptions = this.options.toolbarIcon; @@ -46,13 +27,14 @@ L.EditAction = L.Toolbar2.Action.extend({ this._link = L.DomUtil.create('a', '', this._icon); if (iconOptions.svg) { - this._link.innerHTML = this._svgIconHelper(iconOptions.html); + this._link.innerHTML = L.IconUtil.create(iconOptions.html); } else { this._link.innerHTML = iconOptions.html; } this._link.setAttribute('href', '#'); this._link.setAttribute('title', iconOptions.tooltip); + this._link.setAttribute('role', 'button'); L.DomUtil.addClass(this._link, this.constructor.baseClass); if (iconOptions.className) { @@ -65,22 +47,15 @@ L.EditAction = L.Toolbar2.Action.extend({ this._addSubToolbar(toolbar, this._icon, args); }, - _svgIconHelper: function(ref) { - return ( - '' + - '' + - '' - ); - }, - _injectIconSet: function() { if (document.querySelector('#iconset')) { return; } var el = document.createElement('div'); el.id = 'iconset'; el.setAttribute('hidden', 'hidden'); - el.innerHTML = new L.IconSet().render(); + el.innerHTML = new L.ToolbarIconSet().render(); document.querySelector('.leaflet-marker-pane').appendChild(el); } }); + diff --git a/src/iconsets/IconSet.js b/src/iconsets/IconSet.js new file mode 100644 index 000000000..0fd4fff67 --- /dev/null +++ b/src/iconsets/IconSet.js @@ -0,0 +1,17 @@ +/** this is the baseclass other IconSets inherit from, we don't use it directly */ +L.IconSet = L.Class.extend({ + + _svg: '', + + _symbols: '', + + render: function() { + this.addSymbols(this._symbols); + return this._svg; + }, + + addSymbols: function(symbols) { + this._svg += symbols; + } + +}); diff --git a/src/iconsets/KeymapperIconSet.js b/src/iconsets/KeymapperIconSet.js new file mode 100644 index 000000000..59c0c39be --- /dev/null +++ b/src/iconsets/KeymapperIconSet.js @@ -0,0 +1,6 @@ +L.KeymapperIconSet = L.IconSet.extend({ + + _symbols: + '', + +}); diff --git a/src/edit/tools/IconSet.js b/src/iconsets/ToolbarIconSet.js similarity index 96% rename from src/edit/tools/IconSet.js rename to src/iconsets/ToolbarIconSet.js index a5c4688a1..96b375879 100644 --- a/src/edit/tools/IconSet.js +++ b/src/iconsets/ToolbarIconSet.js @@ -1,14 +1,6 @@ -L.IconSet = L.Class.extend({ +L.ToolbarIconSet = L.IconSet.extend({ - _svg: '', - - render: function() { - this.addSymbols(); - return this._svg; - }, - - addSymbols: function() { - this._svg += + _symbols: '' + '' + '' + @@ -23,6 +15,5 @@ L.IconSet = L.Class.extend({ '' + '' + '' - ; - } + }); diff --git a/src/util/IconUtil.js b/src/util/IconUtil.js new file mode 100644 index 000000000..6f322b222 --- /dev/null +++ b/src/util/IconUtil.js @@ -0,0 +1,36 @@ +L.IconUtil = { + /** creates an svg elemenet with built in accessibility properties and standardized + * classes for styling, takes in the fragment identifier (id) of the symbol to reference. + * note for symplicity we allow providing the icon target with or without the '#' prefix */ + create: function(ref) { + if (/^#/.test(ref)) { + ref = ref.replace(/^#/, ''); + } + + return ( + '' + + '' + + '' + ); + }, + + /** finds the use element and toggles its icon reference */ + toggleXlink: function(container, ref1, ref2) { + if (!/^#/.test(ref1)) { ref1 = '#' + ref1; } + if (!/^#/.test(ref2)) { ref2 = '#' + ref2; } + + var use = container.querySelector('use'); + if (use) { + var toggled = use.getAttribute('xlink:href') === ref1 ? ref2 : ref1; + use.setAttribute('xlink:href', toggled); + return toggled; + } + return false; + }, + + toggleTooltip: function(container, title1, title2) { + var toggled = container.getAttribute('title') === title1 ? title2 : title1; + container.setAttribute('title', toggled); + return toggled; + } +}; diff --git a/test/karma.conf.js b/test/karma.conf.js index c22d128c1..61a6c0a80 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -4,68 +4,70 @@ module.exports = function(config) { config.set({ // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: "../", + basePath: '../', plugins: [ - require("mocha"), - require("karma-mocha"), - require("karma-coverage"), - require("karma-mocha-reporter"), - require("karma-phantomjs-launcher"), - require("glfx"), - require("webgl-distort/dist/webgl-distort.js") + require('mocha'), + require('karma-mocha'), + require('karma-coverage'), + require('karma-mocha-reporter'), + require('karma-phantomjs-launcher'), + require('glfx'), + require('webgl-distort/dist/webgl-distort.js') ], // frameworks to use // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ["mocha"], + frameworks: ['mocha'], // list of files / patterns to load in the browser files: [ - { pattern: "examples/*.jpg", included: false, served: true }, - { pattern: "examples/*.png", included: false, served: true }, - "node_modules/leaflet/dist/leaflet-src.js", - "node_modules/leaflet/dist/leaflet.css", - "node_modules/leaflet-toolbar/dist/leaflet.toolbar.js", - "node_modules/leaflet-toolbar/dist/leaflet.toolbar.css", - "node_modules/webgl-distort/dist/webgl-distort.js", - "node_modules/glfx/glfx.js", - "node_modules/chai/chai.js", - "node_modules/sinon/pkg/sinon.js", - "src/util/*.js", - "src/edit/getEXIFdata.js", - "src/edit/BoxSelector.js", - "src/edit/tools/IconSet.js", - "src/edit/EditHandle.js", - "src/edit/LockHandle.js", - "src/edit/DistortHandle.js", - "src/edit/RotateScaleHandle.js", - "src/edit/RotateHandle.js", - "src/edit/ScaleHandle.js", - "src/DistortableCollection.js", - "src/DistortableImageOverlay.js", - "src/edit/DistortableImage.Keymapper.js", - "src/edit/tools/EditAction.js", - "src/edit/tools/DistortableImage.PopupBar.js", - "src/edit/tools/DistortableImage.ControlBar.js", - "src/edit/DistortableImage.Edit.js", - "test/SpecHelper.js", - "test/src/*Spec.js", - "test/src/**/*Spec.js" + { pattern: 'examples/*.jpg', included: false, served: true }, + { pattern: 'examples/*.png', included: false, served: true }, + 'node_modules/leaflet/dist/leaflet-src.js', + 'node_modules/leaflet/dist/leaflet.css', + 'node_modules/leaflet-toolbar/dist/leaflet.toolbar.js', + 'node_modules/leaflet-toolbar/dist/leaflet.toolbar.css', + 'node_modules/webgl-distort/dist/webgl-distort.js', + 'node_modules/glfx/glfx.js', + 'node_modules/chai/chai.js', + 'node_modules/sinon/pkg/sinon.js', + 'src/util/*.js', + 'src/edit/getEXIFdata.js', + 'src/edit/BoxSelector.js', + 'src/edit/EditHandle.js', + 'src/edit/LockHandle.js', + 'src/edit/DistortHandle.js', + 'src/edit/RotateScaleHandle.js', + 'src/edit/RotateHandle.js', + 'src/edit/ScaleHandle.js', + 'src/DistortableCollection.js', + 'src/DistortableImageOverlay.js', + 'src/iconsets/IconSet.js', + 'src/iconsets/KeymapperIconSet.js', + 'src/iconsets/ToolbarIconSet.js', + 'src/edit/tools/EditAction.js', + 'src/components/DistortableImage.Keymapper.js', + 'src/edit/tools/DistortableImage.PopupBar.js', + 'src/edit/tools/DistortableImage.ControlBar.js', + 'src/edit/DistortableImage.Edit.js', + 'test/SpecHelper.js', + 'test/src/*Spec.js', + 'test/src/**/*Spec.js' ], // so that karma can serve examples/example.png proxies: { - "/examples/": "/base/examples/" + '/examples/': '/base/examples/' }, // test results reporter to use // possible values: 'dots', 'progress' // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ["mocha", "coverage"], + reporters: ['mocha', 'coverage'], preprocessors: { - "../src/**/*.js": "coverage" + '../src/**/*.js': 'coverage' }, // web server port @@ -80,7 +82,7 @@ module.exports = function(config) { // start these browsers // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ["PhantomJS"], + browsers: ['PhantomJS'], // Continuous Integration mode // if true, Karma captures browsers, runs the tests and exits @@ -90,9 +92,9 @@ module.exports = function(config) { coverageReporter: { reporters: [ - { type: "text", dir: "../coverage/", file: "coverage.txt" }, - { type: "lcovonly", dir: "../coverage/" }, - { type: "html", dir: "../coverage/" } + { type: 'text', dir: '../coverage/', file: 'coverage.txt' }, + { type: 'lcovonly', dir: '../coverage/' }, + { type: 'html', dir: '../coverage/' } ] } }); diff --git a/test/src/edit/DistortableImageEditSpec.js b/test/src/edit/DistortableImageEditSpec.js index 7066343b9..d2b58f3c3 100644 --- a/test/src/edit/DistortableImageEditSpec.js +++ b/test/src/edit/DistortableImageEditSpec.js @@ -20,7 +20,6 @@ describe("L.DistortableImage.Edit", function() { afterEach(function () { L.DomUtil.remove(overlay); }); - }); it("Should be initialized along with each instance of L.DistortableImageOverlay.", function() {