diff --git a/build/deps.js b/build/deps.js index 92051758d..df71f6a33 100644 --- a/build/deps.js +++ b/build/deps.js @@ -45,8 +45,6 @@ var deps = { CommonUI: { src: [ - 'Control.Draw.js', - 'Toolbar.js', 'Tooltip.js' ], desc: 'Common UI components used.', @@ -55,7 +53,10 @@ var deps = { DrawUI: { src: [ - 'draw/DrawToolbar.js' + 'draw/DrawToolbar.js', + 'draw/control/Draw.Control.Cancel.js', + 'draw/control/Draw.Control.RemoveLastPoint.js', + 'draw/control/DrawToolbar.Control.js' ], desc: 'Draw toolbar.', deps: ['DrawHandlers', 'CommonUI'] @@ -64,8 +65,12 @@ var deps = { EditUI: { src: [ 'edit/EditToolbar.js', - 'edit/handler/EditToolbar.Edit.js', - 'edit/handler/EditToolbar.Delete.js' + 'edit/control/Edit.Control.Edit.js', + 'edit/control/Edit.Control.Delete.js', + 'edit/control/EditToolbar.Control.js', + 'edit/popup/Edit.Popup.Edit.js', + 'edit/popup/Edit.Popup.Delete.js', + 'edit/popup/EditToolbar.Popup.js' ], desc: 'Edit toolbar.', deps: ['EditHandlers', 'CommonUI'] diff --git a/dist/leaflet.draw.css b/dist/leaflet.draw.css index 7bc9978d1..e760d50ec 100644 --- a/dist/leaflet.draw.css +++ b/dist/leaflet.draw.css @@ -6,8 +6,8 @@ position: relative; } -.leaflet-draw-toolbar { - margin-top: 12px; +.leaflet-draw-toolbar.leaflet-control-toolbar { + margin: 0; } .leaflet-draw-toolbar-top { @@ -22,12 +22,12 @@ border-bottom-right-radius: 0; } -.leaflet-draw-toolbar a { +.leaflet-draw-toolbar > li > a { background-image: url('images/spritesheet.png'); background-repeat: no-repeat; } -.leaflet-retina .leaflet-draw-toolbar a { +.leaflet-retina .leaflet-draw-toolbar > li > a { background-image: url('images/spritesheet-2x.png'); background-size: 270px 30px; } diff --git a/examples/basic.html b/examples/basic.html index 52b71a456..1a84b48bd 100644 --- a/examples/basic.html +++ b/examples/basic.html @@ -4,10 +4,11 @@ Leaflet.draw drawing and editing tools + - + @@ -15,6 +16,7 @@ + @@ -32,12 +34,21 @@ - + + + + + + + - - + + + + +
@@ -55,7 +66,7 @@ L.drawLocal.draw.toolbar.buttons.polygon = 'Draw a sexy polygon!'; var drawControl = new L.Control.Draw({ - position: 'topright', + position: 'topleft', draw: { polyline: { metric: true @@ -83,7 +94,7 @@ remove: false } }); - map.addControl(drawControl); + drawControl.addTo(map); map.on('draw:created', function (e) { var type = e.layerType, diff --git a/examples/full.html b/examples/full.html index 2ef223619..d09f22c7d 100644 --- a/examples/full.html +++ b/examples/full.html @@ -3,43 +3,52 @@ Leaflet.draw vector editing handlers - - - + - - + + - - - - - + + + + + + - - - - + + + - - - - + + + + + + - - - - - + + + + + + + + + + + + + +
diff --git a/examples/libs/leaflet.toolbar-src.js b/examples/libs/leaflet.toolbar-src.js new file mode 100644 index 000000000..11ade5be6 --- /dev/null +++ b/examples/libs/leaflet.toolbar-src.js @@ -0,0 +1,363 @@ +(function(window, document, undefined) { + +"use strict"; + +L.Toolbar = L.Class.extend({ + statics: { + baseClass: 'leaflet-toolbar' + }, + + includes: L.Mixin.Events, + + options: { + className: '', + filter: function() { return true; }, + actions: [] + }, + + initialize: function(options) { + L.setOptions(this, options); + this._toolbar_type = this.constructor._toolbar_class_id; + }, + + addTo: function(map) { + this._arguments = [].slice.call(arguments); + + map.addLayer(this); + + return this; + }, + + onAdd: function(map) { + var currentToolbar = map._toolbars[this._toolbar_type]; + + if (this._calculateDepth() === 0) { + if (currentToolbar) { map.removeLayer(currentToolbar); } + map._toolbars[this._toolbar_type] = this; + } + }, + + onRemove: function(map) { + /* + * TODO: Cleanup event listeners. + * For some reason, this throws: + * "Uncaught TypeError: Cannot read property 'dragging' of null" + * on this._marker when a toolbar icon is clicked. + */ + // for (var i = 0, l = this._disabledEvents.length; i < l; i++) { + // L.DomEvent.off(this._ul, this._disabledEvents[i], L.DomEvent.stopPropagation); + // } + + if (this._calculateDepth() === 0) { + delete map._toolbars[this._toolbar_type]; + } + }, + + appendToContainer: function(container) { + var baseClass = this.constructor.baseClass + '-' + this._calculateDepth(), + className = baseClass + ' ' + this.options.className, + Action, action, + i, j, l, m; + + this._container = container; + this._ul = L.DomUtil.create('ul', className, container); + + /* Ensure that clicks, drags, etc. don't bubble up to the map. */ + this._disabledEvents = ['click', 'mousemove', 'dblclick']; + + for (j = 0, m = this._disabledEvents.length; j < m; j++) { + L.DomEvent.on(this._ul, this._disabledEvents[j], L.DomEvent.stopPropagation); + } + + /* Instantiate each toolbar action and add its corresponding toolbar icon. */ + for (i = 0, l = this.options.actions.length; i < l; i++) { + Action = this._getActionConstructor(this.options.actions[i]); + + action = new Action(); + action._createIcon(this, this._ul, this._arguments); + } + }, + + _getActionConstructor: function(Action) { + var args = this._arguments, + toolbar = this; + + return Action.extend({ + initialize: function() { + Action.prototype.initialize.apply(this, args); + }, + enable: function() { + /* Ensure that only one action in a toolbar will be active at a time. */ + if (toolbar._active) { toolbar._active.disable(); } + toolbar._active = this; + + Action.prototype.enable.call(this); + } + }); + }, + + /* Used to hide subToolbars without removing them from the map. */ + _hide: function() { + this._ul.style.display = 'none'; + }, + + /* Used to show subToolbars without removing them from the map. */ + _show: function() { + this._ul.style.display = 'block'; + }, + + _calculateDepth: function() { + var depth = 0, + toolbar = this.parentToolbar; + + while (toolbar) { + depth += 1; + toolbar = toolbar.parentToolbar; + } + + return depth; + } +}); + +L.toolbar = {}; + +var toolbar_class_id = 0; + +L.Toolbar.extend = function extend(props) { + var statics = L.extend({}, props.statics, { + "_toolbar_class_id": toolbar_class_id + }); + + toolbar_class_id += 1; + L.extend(props, { statics: statics }); + + return L.Class.extend.call(this, props); +}; + +L.Map.addInitHook(function() { + this._toolbars = {}; +}); + +L.ToolbarAction = L.Handler.extend({ + statics: { + baseClass: 'leaflet-toolbar-icon' + }, + + options: { + toolbarIcon: { + html: '', + className: '', + tooltip: '' + }, + subToolbar: new L.Toolbar() + }, + + initialize: function(options) { + var defaultIconOptions = L.ToolbarAction.prototype.options.toolbarIcon; + + L.setOptions(this, options); + this.options.toolbarIcon = L.extend({}, defaultIconOptions, this.options.toolbarIcon); + }, + + enable: function() { + if (this._enabled) { return; } + this._enabled = true; + + if (this.addHooks) { this.addHooks(); } + }, + + disable: function() { + if (!this._enabled) { return; } + this._enabled = false; + + if (this.removeHooks) { this.removeHooks(); } + }, + + _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); + + 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); + }, + + _addSubToolbar: function(toolbar, container, args) { + var subToolbar = this.options.subToolbar, + addHooks = this.addHooks, + removeHooks = this.removeHooks; + + /* For calculating the nesting depth. */ + subToolbar.parentToolbar = toolbar; + + if (subToolbar.options.actions.length > 0) { + /* Make a copy of args so as not to pollute the args array used by other actions. */ + args = [].slice.call(args); + args.push(this); + + subToolbar.addTo.apply(subToolbar, args); + subToolbar.appendToContainer(container); + + this.addHooks = function(map) { + if (typeof addHooks === 'function') { addHooks.call(this, map); } + subToolbar._show(); + }; + + this.removeHooks = function(map) { + if (typeof removeHooks === 'function') { removeHooks.call(this, map); } + subToolbar._hide(); + }; + } + } +}); + +L.toolbarAction = function toolbarAction(options) { + return new L.ToolbarAction(options); +}; + +L.ToolbarAction.extendOptions = function(options) { + return this.extend({ options: options }); +}; + +L.Toolbar.Control = L.Toolbar.extend({ + statics: { + baseClass: 'leaflet-control-toolbar ' + L.Toolbar.baseClass + }, + + initialize: function(options) { + L.Toolbar.prototype.initialize.call(this, options); + + this._control = new L.Control.Toolbar(this.options); + }, + + onAdd: function(map) { + this._control.addTo(map); + + L.Toolbar.prototype.onAdd.call(this, map); + + this.appendToContainer(this._control.getContainer()); + }, + + onRemove: function(map) { + L.Toolbar.prototype.onRemove.call(this, map); + this._control.removeFrom(map); + } +}); + +L.Control.Toolbar = L.Control.extend({ + onAdd: function() { + return L.DomUtil.create('div', ''); + } +}); + +L.toolbar.control = function(options) { + return new L.Toolbar.Control(options); +}; + +// A convenience class for built-in popup toolbars. + +L.Toolbar.Popup = L.Toolbar.extend({ + statics: { + baseClass: 'leaflet-popup-toolbar ' + L.Toolbar.baseClass + }, + + options: { + anchor: [0, 0] + }, + + initialize: function(latlng, options) { + L.Toolbar.prototype.initialize.call(this, options); + + /* + * Developers can't pass a DivIcon in the options for L.Toolbar.Popup + * (the use of DivIcons is an implementation detail which may change). + */ + this._marker = new L.Marker(latlng, { + icon : new L.DivIcon({ + className: this.options.className, + iconAnchor: [0, 0] + }) + }); + }, + + onAdd: function(map) { + this._map = map; + this._marker.addTo(map); + + L.Toolbar.prototype.onAdd.call(this, map); + + this.appendToContainer(this._marker._icon); + + this._setStyles(); + }, + + onRemove: function(map) { + map.removeLayer(this._marker); + + L.Toolbar.prototype.onRemove.call(this, map); + + delete this._map; + }, + + setLatLng: function(latlng) { + this._marker.setLatLng(latlng); + + return this; + }, + + _setStyles: function() { + var container = this._container, + toolbar = this._ul, + anchor = L.point(this.options.anchor), + icons = toolbar.querySelectorAll('.leaflet-toolbar-icon'), + buttonHeights = [], + toolbarWidth = 0, + toolbarHeight, + tipSize, + tipAnchor; + + /* Calculate the dimensions of the toolbar. */ + for (var i = 0, l = icons.length; i < l; i++) { + if (icons[i].parentNode.parentNode === toolbar) { + buttonHeights.push(parseInt(L.DomUtil.getStyle(icons[i], 'height'), 10)); + toolbarWidth += Math.ceil(parseFloat(L.DomUtil.getStyle(icons[i], 'width'))); + } + } + toolbar.style.width = toolbarWidth + 'px'; + + /* Create and place the toolbar tip. */ + this._tipContainer = L.DomUtil.create('div', 'leaflet-toolbar-tip-container', container); + this._tipContainer.style.width = toolbarWidth + 'px'; + + this._tip = L.DomUtil.create('div', 'leaflet-toolbar-tip', this._tipContainer); + + /* Set the tipAnchor point. */ + toolbarHeight = Math.max.apply(undefined, buttonHeights); + tipSize = parseInt(L.DomUtil.getStyle(this._tip, 'width'), 10); + tipAnchor = new L.Point(toolbarWidth/2, toolbarHeight + 0.7071*tipSize); + + /* The anchor option allows app developers to adjust the toolbar's position. */ + container.style.marginLeft = (anchor.x - tipAnchor.x) + 'px'; + container.style.marginTop = (anchor.y - tipAnchor.y) + 'px'; + } +}); + +L.toolbar.popup = function(options) { + return new L.Toolbar.Popup(options); +}; + + +})(window, document); \ No newline at end of file diff --git a/examples/libs/leaflet.toolbar.css b/examples/libs/leaflet.toolbar.css new file mode 100644 index 000000000..790981fc3 --- /dev/null +++ b/examples/libs/leaflet.toolbar.css @@ -0,0 +1,117 @@ +/* Variables and Mixins */ +/* Generic L.Toolbar */ +.leaflet-toolbar-0 { + list-style: none; + padding-left: 0; + box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65); +} +.leaflet-toolbar-0 > li { + position: relative; +} +.leaflet-toolbar-0 > li > .leaflet-toolbar-icon { + display: block; + width: 26px; + height: 26px; + line-height: 26px; + margin-right: 0; + padding-right: 0; + border-right: 0; + text-align: center; + text-decoration: none; + background-color: #ffffff; +} +.leaflet-toolbar-0 > li > .leaflet-toolbar-icon:hover { + background-color: #f4f4f4; +} +.leaflet-toolbar-0 .leaflet-toolbar-1 { + display: none; + list-style: none; +} +.leaflet-toolbar-tip-container { + margin: 0 auto; + height: 12px; + position: relative; + overflow: hidden; +} +.leaflet-toolbar-tip { + width: 12px; + height: 12px; + margin: -6px auto 0; + background-color: #ffffff; + box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65); + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); +} +/* L.Toolbar.Control */ +.leaflet-control-toolbar { + /* Secondary Toolbar */ +} +.leaflet-control-toolbar > li > .leaflet-toolbar-icon { + border-bottom: 1px solid #ccc; +} +.leaflet-control-toolbar > li:first-child > .leaflet-toolbar-icon { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +.leaflet-control-toolbar > li:last-child > .leaflet-toolbar-icon { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-width: 0; +} +.leaflet-control-toolbar .leaflet-toolbar-1 { + margin: 0; + padding: 0; + position: absolute; + left: 26px; + /* leaflet-draw-toolbar.left + leaflet-draw-toolbar.width */ + top: 0; + white-space: nowrap; + height: 26px; +} +.leaflet-control-toolbar .leaflet-toolbar-1 > li { + display: inline-block; +} +.leaflet-control-toolbar .leaflet-toolbar-1 > li > .leaflet-toolbar-icon { + display: block; + background-color: #919187; + border-left: 1px solid #aaa; + color: #fff; + font: 11px/19px "Helvetica Neue", Arial, Helvetica, sans-serif; + line-height: 26px; + text-decoration: none; + padding-left: 10px; + padding-right: 10px; + height: 26px; +} +.leaflet-control-toolbar .leaflet-toolbar-1 > li > .leaflet-toolbar-icon:hover { + background-color: #a0a098; +} +/* L.Toolbar.Popup */ +.leaflet-popup-toolbar { + position: relative; +} +.leaflet-popup-toolbar > li { + float: left; +} +.leaflet-popup-toolbar > li:first-child > .leaflet-toolbar-icon { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} +.leaflet-popup-toolbar > li:last-child > .leaflet-toolbar-icon { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom-width: 0; +} +.leaflet-popup-toolbar .leaflet-toolbar-1 { + position: absolute; + top: 26px; + left: 0; + padding-left: 0; +} +.leaflet-popup-toolbar .leaflet-toolbar-1 > li > .leaflet-toolbar-icon { + position: relative; + float: left; + width: 26px; + height: 26px; +} diff --git a/package.json b/package.json index 59f4e9c51..a4ff0d2e9 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "happen": "~0.1.3", "karma": "^0.12.19", "karma-mocha": "~0.1.0", - "karma-coverage": "~0.1.3" + "karma-coverage": "~0.1.3", + "leaflet-toolbar": "~0.1.2" }, "main": "dist/leaflet.draw.js", "directories": { diff --git a/spec/karma.conf.js b/spec/karma.conf.js index 903ade0a9..7284f52a5 100644 --- a/spec/karma.conf.js +++ b/spec/karma.conf.js @@ -3,6 +3,7 @@ module.exports = function (config) { var libSources = require(__dirname+'/../build/build.js').getFiles(); var leafletSources = require(__dirname+'/../node_modules/leaflet/build/build.js').getFiles(); + var leafletToolbar = __dirname+'/../node_modules/leaflet-toolbar/dist/leaflet.toolbar-src.js'; for (var i=0; i < leafletSources.length; i++) { leafletSources[i] = __dirname+"/../node_modules/leaflet/" + leafletSources[i]; @@ -12,7 +13,7 @@ module.exports = function (config) { "spec/before.js", "spec/sinon.js", "spec/expect.js" - ].concat(leafletSources, libSources, [ + ].concat(leafletSources, leafletToolbar, libSources, [ "spec/after.js", "node_modules/happen/happen.js", "spec/suites/SpecHelper.js", diff --git a/spec/suites/DrawControlSpec.js b/spec/suites/DrawControlSpec.js deleted file mode 100644 index cd15d5041..000000000 --- a/spec/suites/DrawControlSpec.js +++ /dev/null @@ -1,14 +0,0 @@ -describe("Control.Draw", function () { - var map, control, container; - - beforeEach(function () { - map = L.map(document.createElement('div')); - control = new L.Control.Draw({}); - map.addControl(control); - container = control.getContainer(); - }); - - it("exists", function () { - expect(container.innerHTML).to.be.ok(); - }); -}); diff --git a/spec/suites/DrawToolbarSpec.js b/spec/suites/DrawToolbarSpec.js new file mode 100644 index 000000000..49dda9f49 --- /dev/null +++ b/spec/suites/DrawToolbarSpec.js @@ -0,0 +1,7 @@ +describe("DrawToolbar.Control", function () { + var map, control, container; + + beforeEach(function () { + map = L.map(document.createElement('div')); + }); +}); diff --git a/spec/suites/EditSpec.js b/spec/suites/EditSpec.js index 7c6ce22e1..f19f59c65 100644 --- a/spec/suites/EditSpec.js +++ b/spec/suites/EditSpec.js @@ -41,9 +41,8 @@ describe("L.Edit", function () { beforeEach(function () { drawnItems = new L.FeatureGroup().addTo(map); - edit = new L.EditToolbar.Edit(map, { - featureGroup: drawnItems, - selectedPathOptions: L.EditToolbar.prototype.options.edit.selectedPathOptions + edit = new L.Edit.Control.Edit(map, { + featureGroup: drawnItems }); poly = new L.Polyline(L.latLng(41, -87), L.latLng(42, -88)); }); diff --git a/src/Control.Draw.js b/src/Control.Draw.js index 909d0aa8a..4ae2c6d14 100644 --- a/src/Control.Draw.js +++ b/src/Control.Draw.js @@ -11,29 +11,28 @@ L.Control.Draw = L.Control.extend({ throw new Error('Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/'); } + L.setOptions(this, options); + L.Control.prototype.initialize.call(this, options); - var toolbar; + var position = { position: this.options.position }, + drawOptions = L.Util.extend(this.options.draw, position), + editOptions = L.Util.extend(this.options.edit, position), + id, toolbar; this._toolbars = {}; // Initialize toolbars - if (L.DrawToolbar && this.options.draw) { - toolbar = new L.DrawToolbar(this.options.draw); - - this._toolbars[L.DrawToolbar.TYPE] = toolbar; - - // Listen for when toolbar is enabled - this._toolbars[L.DrawToolbar.TYPE].on('enable', this._toolbarEnabled, this); + if (L.DrawToolbar.Control && this.options.draw) { + toolbar = new L.DrawToolbar.Control(drawOptions); + id = L.stamp(toolbar); + this._toolbars[id] = toolbar; } - if (L.EditToolbar && this.options.edit) { - toolbar = new L.EditToolbar(this.options.edit); - - this._toolbars[L.EditToolbar.TYPE] = toolbar; - - // Listen for when toolbar is enabled - this._toolbars[L.EditToolbar.TYPE].on('enable', this._toolbarEnabled, this); + if (L.EditToolbar.Control && this.options.edit) { + toolbar = new L.EditToolbar.Control(editOptions); + id = L.stamp(toolbar); + this._toolbars[id] = toolbar; } }, @@ -45,49 +44,27 @@ L.Control.Draw = L.Control.extend({ for (var toolbarId in this._toolbars) { if (this._toolbars.hasOwnProperty(toolbarId)) { - toolbarContainer = this._toolbars[toolbarId].addToolbar(map); - - if (toolbarContainer) { - // Add class to the first toolbar to remove the margin - if (!addedTopClass) { - if (!L.DomUtil.hasClass(toolbarContainer, topClassName)) { - L.DomUtil.addClass(toolbarContainer.childNodes[0], topClassName); - } - addedTopClass = true; - } - - container.appendChild(toolbarContainer); - } + this._toolbars[toolbarId].addTo(map); } } return container; }, - onRemove: function () { + onRemove: function (map) { for (var toolbarId in this._toolbars) { if (this._toolbars.hasOwnProperty(toolbarId)) { - this._toolbars[toolbarId].removeToolbar(); + map.removeLayer(this._toolbars[toolbarId]); } } }, setDrawingOptions: function (options) { for (var toolbarId in this._toolbars) { - if (this._toolbars[toolbarId] instanceof L.DrawToolbar) { + if (this._toolbars[toolbarId] instanceof L.DrawToolbar.Control) { this._toolbars[toolbarId].setOptions(options); } } - }, - - _toolbarEnabled: function (e) { - var enabledToolbar = e.target; - - for (var toolbarId in this._toolbars) { - if (this._toolbars[toolbarId] !== enabledToolbar) { - this._toolbars[toolbarId].disable(); - } - } } }); @@ -101,4 +78,4 @@ L.Map.addInitHook(function () { this.drawControl = new L.Control.Draw(); this.addControl(this.drawControl); } -}); +}); \ No newline at end of file diff --git a/src/Leaflet.draw.js b/src/Leaflet.draw.js index 92932c568..21e635a9f 100644 --- a/src/Leaflet.draw.js +++ b/src/Leaflet.draw.js @@ -95,4 +95,4 @@ L.drawLocal = { } } } -}; +}; \ No newline at end of file diff --git a/src/Toolbar.js b/src/Toolbar.js deleted file mode 100644 index 671e13ad3..000000000 --- a/src/Toolbar.js +++ /dev/null @@ -1,244 +0,0 @@ -L.Toolbar = L.Class.extend({ - includes: [L.Mixin.Events], - - initialize: function (options) { - L.setOptions(this, options); - - this._modes = {}; - this._actionButtons = []; - this._activeMode = null; - }, - - enabled: function () { - return this._activeMode !== null; - }, - - disable: function () { - if (!this.enabled()) { return; } - - this._activeMode.handler.disable(); - }, - - addToolbar: function (map) { - var container = L.DomUtil.create('div', 'leaflet-draw-section'), - buttonIndex = 0, - buttonClassPrefix = this._toolbarClass || '', - modeHandlers = this.getModeHandlers(map), - i; - - this._toolbarContainer = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar'); - this._map = map; - - for (i = 0; i < modeHandlers.length; i++) { - if (modeHandlers[i].enabled) { - this._initModeHandler( - modeHandlers[i].handler, - this._toolbarContainer, - buttonIndex++, - buttonClassPrefix, - modeHandlers[i].title - ); - } - } - - // if no buttons were added, do not add the toolbar - if (!buttonIndex) { - return; - } - - // Save button index of the last button, -1 as we would have ++ after the last button - this._lastButtonIndex = --buttonIndex; - - // Create empty actions part of the toolbar - this._actionsContainer = L.DomUtil.create('ul', 'leaflet-draw-actions'); - - // Add draw and cancel containers to the control container - container.appendChild(this._toolbarContainer); - container.appendChild(this._actionsContainer); - - return container; - }, - - removeToolbar: function () { - // Dispose each handler - for (var handlerId in this._modes) { - if (this._modes.hasOwnProperty(handlerId)) { - // Unbind handler button - this._disposeButton( - this._modes[handlerId].button, - this._modes[handlerId].handler.enable, - this._modes[handlerId].handler - ); - - // Make sure is disabled - this._modes[handlerId].handler.disable(); - - // Unbind handler - this._modes[handlerId].handler - .off('enabled', this._handlerActivated, this) - .off('disabled', this._handlerDeactivated, this); - } - } - this._modes = {}; - - // Dispose the actions toolbar - for (var i = 0, l = this._actionButtons.length; i < l; i++) { - this._disposeButton( - this._actionButtons[i].button, - this._actionButtons[i].callback, - this - ); - } - this._actionButtons = []; - this._actionsContainer = null; - }, - - _initModeHandler: function (handler, container, buttonIndex, classNamePredix, buttonTitle) { - var type = handler.type; - - this._modes[type] = {}; - - this._modes[type].handler = handler; - - this._modes[type].button = this._createButton({ - title: buttonTitle, - className: classNamePredix + '-' + type, - container: container, - callback: this._modes[type].handler.enable, - context: this._modes[type].handler - }); - - this._modes[type].buttonIndex = buttonIndex; - - this._modes[type].handler - .on('enabled', this._handlerActivated, this) - .on('disabled', this._handlerDeactivated, this); - }, - - _createButton: function (options) { - var link = L.DomUtil.create('a', options.className || '', options.container); - link.href = '#'; - - if (options.text) { - link.innerHTML = options.text; - } - - if (options.title) { - link.title = options.title; - } - - L.DomEvent - .on(link, 'click', L.DomEvent.stopPropagation) - .on(link, 'mousedown', L.DomEvent.stopPropagation) - .on(link, 'dblclick', L.DomEvent.stopPropagation) - .on(link, 'click', L.DomEvent.preventDefault) - .on(link, 'click', options.callback, options.context); - - return link; - }, - - _disposeButton: function (button, callback) { - L.DomEvent - .off(button, 'click', L.DomEvent.stopPropagation) - .off(button, 'mousedown', L.DomEvent.stopPropagation) - .off(button, 'dblclick', L.DomEvent.stopPropagation) - .off(button, 'click', L.DomEvent.preventDefault) - .off(button, 'click', callback); - }, - - _handlerActivated: function (e) { - // Disable active mode (if present) - this.disable(); - - // Cache new active feature - this._activeMode = this._modes[e.handler]; - - L.DomUtil.addClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled'); - - this._showActionsToolbar(); - - this.fire('enable'); - }, - - _handlerDeactivated: function () { - this._hideActionsToolbar(); - - L.DomUtil.removeClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled'); - - this._activeMode = null; - - this.fire('disable'); - }, - - _createActions: function (handler) { - var container = this._actionsContainer, - buttons = this.getActions(handler), - l = buttons.length, - li, di, dl, button; - - // Dispose the actions toolbar (todo: dispose only not used buttons) - for (di = 0, dl = this._actionButtons.length; di < dl; di++) { - this._disposeButton(this._actionButtons[di].button, this._actionButtons[di].callback); - } - this._actionButtons = []; - - // Remove all old buttons - while (container.firstChild) { - container.removeChild(container.firstChild); - } - - for (var i = 0; i < l; i++) { - if ('enabled' in buttons[i] && !buttons[i].enabled) { - continue; - } - - li = L.DomUtil.create('li', '', container); - - button = this._createButton({ - title: buttons[i].title, - text: buttons[i].text, - container: li, - callback: buttons[i].callback, - context: buttons[i].context - }); - - this._actionButtons.push({ - button: button, - callback: buttons[i].callback - }); - } - }, - - _showActionsToolbar: function () { - var buttonIndex = this._activeMode.buttonIndex, - lastButtonIndex = this._lastButtonIndex, - toolbarPosition = this._activeMode.button.offsetTop - 1; - - // Recreate action buttons on every click - this._createActions(this._activeMode.handler); - - // Correctly position the cancel button - this._actionsContainer.style.top = toolbarPosition + 'px'; - - if (buttonIndex === 0) { - L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop'); - L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-top'); - } - - if (buttonIndex === lastButtonIndex) { - L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom'); - L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-bottom'); - } - - this._actionsContainer.style.display = 'block'; - }, - - _hideActionsToolbar: function () { - this._actionsContainer.style.display = 'none'; - - L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop'); - L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom'); - L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-top'); - L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-bottom'); - } -}); diff --git a/src/draw/DrawToolbar.js b/src/draw/DrawToolbar.js index 812f10bd3..63cb4abd8 100644 --- a/src/draw/DrawToolbar.js +++ b/src/draw/DrawToolbar.js @@ -1,87 +1 @@ -L.DrawToolbar = L.Toolbar.extend({ - - statics: { - TYPE: 'draw' - }, - - options: { - polyline: {}, - polygon: {}, - rectangle: {}, - circle: {}, - marker: {} - }, - - initialize: function (options) { - // Ensure that the options are merged correctly since L.extend is only shallow - for (var type in this.options) { - if (this.options.hasOwnProperty(type)) { - if (options[type]) { - options[type] = L.extend({}, this.options[type], options[type]); - } - } - } - - this._toolbarClass = 'leaflet-draw-draw'; - L.Toolbar.prototype.initialize.call(this, options); - }, - - getModeHandlers: function (map) { - return [ - { - enabled: this.options.polyline, - handler: new L.Draw.Polyline(map, this.options.polyline), - title: L.drawLocal.draw.toolbar.buttons.polyline - }, - { - enabled: this.options.polygon, - handler: new L.Draw.Polygon(map, this.options.polygon), - title: L.drawLocal.draw.toolbar.buttons.polygon - }, - { - enabled: this.options.rectangle, - handler: new L.Draw.Rectangle(map, this.options.rectangle), - title: L.drawLocal.draw.toolbar.buttons.rectangle - }, - { - enabled: this.options.circle, - handler: new L.Draw.Circle(map, this.options.circle), - title: L.drawLocal.draw.toolbar.buttons.circle - }, - { - enabled: this.options.marker, - handler: new L.Draw.Marker(map, this.options.marker), - title: L.drawLocal.draw.toolbar.buttons.marker - } - ]; - }, - - // Get the actions part of the toolbar - getActions: function (handler) { - return [ - { - enabled: handler.deleteLastVertex, - title: L.drawLocal.draw.toolbar.undo.title, - text: L.drawLocal.draw.toolbar.undo.text, - callback: handler.deleteLastVertex, - context: handler - }, - { - title: L.drawLocal.draw.toolbar.actions.title, - text: L.drawLocal.draw.toolbar.actions.text, - callback: this.disable, - context: this - } - ]; - }, - - setOptions: function (options) { - L.setOptions(this, options); - - for (var type in this._modes) { - if (this._modes.hasOwnProperty(type) && options.hasOwnProperty(type)) { - this._modes[type].handler.setOptions(options[type]); - } - } - } -}); +L.DrawToolbar = {}; \ No newline at end of file diff --git a/src/draw/control/Draw.Control.Cancel.js b/src/draw/control/Draw.Control.Cancel.js new file mode 100644 index 000000000..91667e7cf --- /dev/null +++ b/src/draw/control/Draw.Control.Cancel.js @@ -0,0 +1,18 @@ +L.Draw = L.Draw || {}; +L.Draw.Control = L.Draw.Control || {}; + +L.Draw.Control.Cancel = L.ToolbarAction.extend({ + options: { + toolbarIcon: { html: 'Cancel' } + }, + + initialize: function (map, drawing) { + this.drawing = drawing; + L.ToolbarAction.prototype.initialize.call(this); + }, + + addHooks: function () { + this.drawing.disable(); + this.disable(); + } +}); \ No newline at end of file diff --git a/src/draw/control/Draw.Control.RemoveLastPoint.js b/src/draw/control/Draw.Control.RemoveLastPoint.js new file mode 100644 index 000000000..291d8179c --- /dev/null +++ b/src/draw/control/Draw.Control.RemoveLastPoint.js @@ -0,0 +1,18 @@ +L.Draw = L.Draw || {}; +L.Draw.Control = L.Draw.Control || {}; + +L.Draw.Control.RemoveLastPoint = L.ToolbarAction.extend({ + options: { + toolbarIcon: { html: 'Delete last point' } + }, + + initialize: function (map, drawing) { + this.drawing = drawing; + L.ToolbarAction.prototype.initialize.call(this); + }, + + addHooks: function () { + this.drawing.deleteLastVertex(); + this.disable(); + } +}); \ No newline at end of file diff --git a/src/draw/control/Draw.Control.ToolbarAction.js b/src/draw/control/Draw.Control.ToolbarAction.js new file mode 100644 index 000000000..639c889c5 --- /dev/null +++ b/src/draw/control/Draw.Control.ToolbarAction.js @@ -0,0 +1,91 @@ +L.Draw = L.Draw || {}; +L.Draw.Control = L.Draw.Control || {}; + +L.Draw.Control.ToolbarAction = L.ToolbarAction.extend({ + options: {}, + + initialize: function (map, options) { + this.drawHandler = new options.DrawAction(map, options); + + this.drawHandler + .on('enabled', this.enable, this) + .on('disabled', this.disable, this); + + L.ToolbarAction.prototype.initialize.call(this, options); + }, + + enable: function () { + if (this._enabled) { return; } + + L.ToolbarAction.prototype.enable.call(this); + + this.drawHandler.enable(); + }, + + disable: function () { + if (!this._enabled) { return; } + + L.ToolbarAction.prototype.disable.call(this); + + this.drawHandler.disable(); + } +}); + +L.Draw.Control.Circle = L.Draw.Control.ToolbarAction.extend({ + options: { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-circle', + tooltip: L.drawLocal.draw.toolbar.buttons.circle + } + } +}); + +L.Draw.Control.Marker = L.Draw.Control.ToolbarAction.extend({ + options: { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-marker', + tooltip: L.drawLocal.draw.toolbar.buttons.marker + } + } +}); + +L.Draw.Control.Polyline = L.Draw.Control.ToolbarAction.extend({ + options: { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel, L.Draw.Control.RemoveLastPoint] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-polyline', + tooltip: L.drawLocal.draw.toolbar.buttons.polyline + } + }, + + deleteLastVertex: function () { + this._drawHandler.deleteLastVertex(); + } +}); + +L.Draw.Control.Polygon = L.Draw.Control.Polyline .extend({ + options: { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel, L.Draw.Control.RemoveLastPoint] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-polygon', + tooltip: L.drawLocal.draw.toolbar.buttons.polygon + } + } +}); + +L.Draw.Control.Rectangle = L.Draw.Control.ToolbarAction.extend({ + options: { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-rectangle', + tooltip: L.drawLocal.draw.toolbar.buttons.rectangle + } + } +}); \ No newline at end of file diff --git a/src/draw/control/DrawToolbar.Control.js b/src/draw/control/DrawToolbar.Control.js new file mode 100644 index 000000000..6a9de1390 --- /dev/null +++ b/src/draw/control/DrawToolbar.Control.js @@ -0,0 +1,167 @@ +L.DrawToolbar.Control = L.Toolbar.Control.extend({ + options: { + className: 'leaflet-draw-toolbar', + polyline: {}, + polygon: {}, + rectangle: {}, + circle: {}, + marker: {} + }, + + initialize: function (options) { + L.setOptions(this, options); + + this._actions = {}; + this.options.actions = {}; + + if (this.options.polygon) { + this.options.actions.polygon = { + action: L.Draw.Control.Polygon, + options: L.Util.extend(this.options.polygon, { DrawAction: L.Draw.Polygon }) + } + } + + if (this.options.polyline) { + this.options.actions.polyline = { + action: L.Draw.Control.Polyline, + options: L.Util.extend(this.options.polyline, { DrawAction: L.Draw.Polyline }) + } + } + + if (this.options.circle) { + this.options.actions.circle = { + action: L.Draw.Control.Circle, + options: L.Util.extend(this.options.circle, { DrawAction: L.Draw.Circle }) + } + } + + if (this.options.rectangle) { + this.options.actions.rectangle = { + action: L.Draw.Control.Rectangle, + options: L.Util.extend(this.options.rectangle, { DrawAction: L.Draw.Rectangle }) + } + } + + if (this.options.marker) { + this.options.actions.marker = { + action: L.Draw.Control.Marker, + options: L.Util.extend(this.options.marker, { DrawAction: L.Draw.Marker }) + } + } + + L.Toolbar.Control.prototype.initialize.call(this, options); + }, + + // Sets an actions options just in case we want to change options half way through. + setOptions: function (options) { + L.setOptions(this, options); + + for (var type in this._actions) { + if (this._actions.hasOwnProperty(type) && options.hasOwnProperty(type)) { + this._actions[type].drawHandler.setOptions(options[type]); + } + } + } +}); + +L.Toolbar.Control.prototype.appendToContainer = function (container) { + var baseClass = this.constructor.baseClass + '-' + this._calculateDepth(), + className = baseClass + ' ' + this.options.className, + Action, action, + i, j, l, m; + + this._container = container; + this._ul = L.DomUtil.create('ul', className, container); + + /* Ensure that clicks, drags, etc. don't bubble up to the map. */ + this._disabledEvents = ['click', 'mousemove', 'dblclick']; + + for (j = 0, m = this._disabledEvents.length; j < m; j++) { + L.DomEvent.on(this._ul, this._disabledEvents[j], L.DomEvent.stopPropagation); + } + + /* Instantiate each toolbar action and add its corresponding toolbar icon. */ + for (var actionIndex in this.options.actions) { + Action = this._getActionConstructor(this.options.actions[actionIndex].action, this.options.actions[actionIndex].options); + + this._actions[actionIndex] = new Action(); + this._actions[actionIndex]._createIcon(this, this._ul, this._arguments); + } +}; + +L.Toolbar.Control.prototype._getActionConstructor = function (Action, actionOptions) { + var map = this._arguments[0], + args = [map, actionOptions], + toolbar = this; + + return Action.extend({ + initialize: function() { + Action.prototype.initialize.apply(this, args); + }, + enable: function() { + if (toolbar._active == this) { + return; + } + + /* Ensure that only one action in a toolbar will be active at a time. */ + if (toolbar._active) { + toolbar._active.disable(); + } + toolbar._active = this; + + Action.prototype.enable.call(this); + }, + disable: function () { + toolbar._active = null; + + Action.prototype.disable.call(this); + } + }); +}; + +/* Include sub-toolbars. */ +/*L.setOptions(L.Draw.Polygon.prototype, { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel, L.Draw.Control.RemoveLastPoint] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-polygon', + tooltip: L.drawLocal.draw.toolbar.buttons.polygon + } +}); + +L.setOptions(L.Draw.Polyline.prototype, { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel, L.Draw.Control.RemoveLastPoint] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-polyline', + tooltip: L.drawLocal.draw.toolbar.buttons.polyline + } +}); + +L.setOptions(L.Draw.Marker.prototype, { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-marker', + tooltip: L.drawLocal.draw.toolbar.buttons.marker + } +}); + +L.setOptions(L.Draw.Rectangle.prototype, { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-rectangle', + tooltip: L.drawLocal.draw.toolbar.buttons.rectangle + } +}); + +L.setOptions(L.Draw.Circle.prototype, { + subToolbar: new L.Toolbar({ actions: [L.Draw.Control.Cancel] }), + + toolbarIcon: { + className: 'leaflet-draw-draw-circle', + tooltip: L.drawLocal.draw.toolbar.buttons.circle + } +});*/ + diff --git a/src/draw/handler/Draw.Feature.js b/src/draw/handler/Draw.Feature.js index 1465fba34..4d497df94 100644 --- a/src/draw/handler/Draw.Feature.js +++ b/src/draw/handler/Draw.Feature.js @@ -4,15 +4,16 @@ L.Draw.Feature = L.Handler.extend({ includes: L.Mixin.Events, initialize: function (map, options) { - this._map = map; + L.Handler.prototype.initialize.call(this, map); + this._container = map._container; this._overlayPane = map._panes.overlayPane; this._popupPane = map._panes.popupPane; // Merge default shapeOptions options with custom shapeOptions - if (options && options.shapeOptions) { + /*if (options && options.shapeOptions) { options.shapeOptions = L.Util.extend({}, this.options.shapeOptions, options.shapeOptions); - } + }*/ L.setOptions(this, options); }, diff --git a/src/draw/handler/Draw.Rectangle.js b/src/draw/handler/Draw.Rectangle.js index d83120f27..cae8b7531 100644 --- a/src/draw/handler/Draw.Rectangle.js +++ b/src/draw/handler/Draw.Rectangle.js @@ -14,7 +14,7 @@ L.Draw.Rectangle = L.Draw.SimpleShape.extend({ fillOpacity: 0.2, clickable: true }, - metric: true // Whether to use the metric meaurement system or imperial + metric: true // Whether to use the metric meaurement system or imperial, }, initialize: function (map, options) { diff --git a/src/edit/EditToolbar.js b/src/edit/EditToolbar.js index 143be1656..9c4cef3e6 100644 --- a/src/edit/EditToolbar.js +++ b/src/edit/EditToolbar.js @@ -1,154 +1 @@ -/*L.Map.mergeOptions({ - editControl: true -});*/ - -L.EditToolbar = L.Toolbar.extend({ - statics: { - TYPE: 'edit' - }, - - options: { - edit: { - selectedPathOptions: { - color: '#fe57a1', /* Hot pink all the things! */ - opacity: 0.6, - dashArray: '10, 10', - - fill: true, - fillColor: '#fe57a1', - fillOpacity: 0.1, - - // Whether to user the existing layers color - maintainColor: false - } - }, - remove: {}, - featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */ - }, - - initialize: function (options) { - // Need to set this manually since null is an acceptable value here - if (options.edit) { - if (typeof options.edit.selectedPathOptions === 'undefined') { - options.edit.selectedPathOptions = this.options.edit.selectedPathOptions; - } - options.edit.selectedPathOptions = L.extend({}, this.options.edit.selectedPathOptions, options.edit.selectedPathOptions); - } - - if (options.remove) { - options.remove = L.extend({}, this.options.remove, options.remove); - } - - this._toolbarClass = 'leaflet-draw-edit'; - L.Toolbar.prototype.initialize.call(this, options); - - this._selectedFeatureCount = 0; - }, - - getModeHandlers: function (map) { - var featureGroup = this.options.featureGroup; - return [ - { - enabled: this.options.edit, - handler: new L.EditToolbar.Edit(map, { - featureGroup: featureGroup, - selectedPathOptions: this.options.edit.selectedPathOptions - }), - title: L.drawLocal.edit.toolbar.buttons.edit - }, - { - enabled: this.options.remove, - handler: new L.EditToolbar.Delete(map, { - featureGroup: featureGroup - }), - title: L.drawLocal.edit.toolbar.buttons.remove - } - ]; - }, - - getActions: function () { - return [ - { - title: L.drawLocal.edit.toolbar.actions.save.title, - text: L.drawLocal.edit.toolbar.actions.save.text, - callback: this._save, - context: this - }, - { - title: L.drawLocal.edit.toolbar.actions.cancel.title, - text: L.drawLocal.edit.toolbar.actions.cancel.text, - callback: this.disable, - context: this - } - ]; - }, - - addToolbar: function (map) { - var container = L.Toolbar.prototype.addToolbar.call(this, map); - - this._checkDisabled(); - - this.options.featureGroup.on('layeradd layerremove', this._checkDisabled, this); - - return container; - }, - - removeToolbar: function () { - this.options.featureGroup.off('layeradd layerremove', this._checkDisabled, this); - - L.Toolbar.prototype.removeToolbar.call(this); - }, - - disable: function () { - if (!this.enabled()) { return; } - - this._activeMode.handler.revertLayers(); - - L.Toolbar.prototype.disable.call(this); - }, - - _save: function () { - this._activeMode.handler.save(); - this._activeMode.handler.disable(); - }, - - _checkDisabled: function () { - var featureGroup = this.options.featureGroup, - hasLayers = featureGroup.getLayers().length !== 0, - button; - - if (this.options.edit) { - button = this._modes[L.EditToolbar.Edit.TYPE].button; - - if (hasLayers) { - L.DomUtil.removeClass(button, 'leaflet-disabled'); - } else { - L.DomUtil.addClass(button, 'leaflet-disabled'); - } - - button.setAttribute( - 'title', - hasLayers ? - L.drawLocal.edit.toolbar.buttons.edit - : L.drawLocal.edit.toolbar.buttons.editDisabled - ); - } - - if (this.options.remove) { - button = this._modes[L.EditToolbar.Delete.TYPE].button; - - if (hasLayers) { - L.DomUtil.removeClass(button, 'leaflet-disabled'); - } else { - L.DomUtil.addClass(button, 'leaflet-disabled'); - } - - button.setAttribute( - 'title', - hasLayers ? - L.drawLocal.edit.toolbar.buttons.remove - : L.drawLocal.edit.toolbar.buttons.removeDisabled - ); - } - } -}); +L.EditToolbar = {}; \ No newline at end of file diff --git a/src/edit/handler/EditToolbar.Delete.js b/src/edit/control/Edit.Control.Delete.js similarity index 86% rename from src/edit/handler/EditToolbar.Delete.js rename to src/edit/control/Edit.Control.Delete.js index d23252137..4c1b48c92 100644 --- a/src/edit/handler/EditToolbar.Delete.js +++ b/src/edit/control/Edit.Control.Delete.js @@ -1,24 +1,32 @@ -L.EditToolbar.Delete = L.Handler.extend({ +L.Edit = L.Edit || {}; +L.Edit.Control = L.Edit.Control || {}; + +L.Edit.Control.Delete = L.ToolbarAction.extend({ statics: { TYPE: 'remove' // not delete as delete is reserved in js }, + options: { + toolbarIcon: { className: 'leaflet-draw-edit-remove' } + }, + includes: L.Mixin.Events, initialize: function (map, options) { - L.Handler.prototype.initialize.call(this, map); + L.ToolbarAction.prototype.initialize.call(this, map); L.Util.setOptions(this, options); // Store the selectable layer group for ease of access this._deletableLayers = this.options.featureGroup; + this._map = map; if (!(this._deletableLayers instanceof L.FeatureGroup)) { throw new Error('options.featureGroup must be a L.FeatureGroup'); } // Save the type so super can fire, need to do this as cannot do this.TYPE :( - this.type = L.EditToolbar.Delete.TYPE; + this.type = this.constructor.TYPE; }, enable: function () { @@ -29,7 +37,7 @@ L.EditToolbar.Delete = L.Handler.extend({ this._map.fire('draw:deletestart', { handler: this.type }); - L.Handler.prototype.enable.call(this); + L.ToolbarAction.prototype.enable.call(this); this._deletableLayers .on('layeradd', this._enableLayerDelete, this) @@ -43,7 +51,7 @@ L.EditToolbar.Delete = L.Handler.extend({ .off('layeradd', this._enableLayerDelete, this) .off('layerremove', this._disableLayerDelete, this); - L.Handler.prototype.disable.call(this); + L.ToolbarAction.prototype.disable.call(this); this._map.fire('draw:deletestop', { handler: this.type }); @@ -57,7 +65,7 @@ L.EditToolbar.Delete = L.Handler.extend({ map.getContainer().focus(); this._deletableLayers.eachLayer(this._enableLayerDelete, this); - this._deletedLayers = new L.LayerGroup(); + this._deletedLayers = new L.layerGroup(); this._tooltip = new L.Tooltip(this._map); this._tooltip.updateContent({ text: L.drawLocal.edit.handlers.remove.tooltip.text }); diff --git a/src/edit/handler/EditToolbar.Edit.js b/src/edit/control/Edit.Control.Edit.js similarity index 87% rename from src/edit/handler/EditToolbar.Edit.js rename to src/edit/control/Edit.Control.Edit.js index fcbd04378..b29259279 100644 --- a/src/edit/handler/EditToolbar.Edit.js +++ b/src/edit/control/Edit.Control.Edit.js @@ -1,17 +1,37 @@ -L.EditToolbar.Edit = L.Handler.extend({ +L.Edit = L.Edit || {}; +L.Edit.Control = L.Edit.Control || {}; + +L.Edit.Control.Edit = L.ToolbarAction.extend({ statics: { TYPE: 'edit' }, + options: { + selectedPathOptions: { + color: '#fe57a1', /* Hot pink all the things! */ + opacity: 0.6, + dashArray: '10, 10', + + fill: true, + fillColor: '#fe57a1', + fillOpacity: 0.1, + + // Whether to user the existing layers color + maintainColor: false + }, + toolbarIcon: { className: 'leaflet-draw-edit-edit' } + }, + includes: L.Mixin.Events, initialize: function (map, options) { - L.Handler.prototype.initialize.call(this, map); + L.ToolbarAction.prototype.initialize.call(this, map); L.setOptions(this, options); // Store the selectable layer group for ease of access - this._featureGroup = options.featureGroup; + this._featureGroup = this.options.featureGroup; + this._map = map; if (!(this._featureGroup instanceof L.FeatureGroup)) { throw new Error('options.featureGroup must be a L.FeatureGroup'); @@ -20,7 +40,7 @@ L.EditToolbar.Edit = L.Handler.extend({ this._uneditedLayerProps = {}; // Save the type so super can fire, need to do this as cannot do this.TYPE :( - this.type = L.EditToolbar.Edit.TYPE; + this.type = this.constructor.TYPE; }, enable: function () { @@ -33,7 +53,7 @@ L.EditToolbar.Edit = L.Handler.extend({ this._map.fire('draw:editstart', { handler: this.type }); //allow drawLayer to be updated before beginning edition. - L.Handler.prototype.enable.call(this); + L.ToolbarAction.prototype.enable.call(this); this._featureGroup .on('layeradd', this._enableLayerEdit, this) .on('layerremove', this._disableLayerEdit, this); @@ -44,7 +64,7 @@ L.EditToolbar.Edit = L.Handler.extend({ this._featureGroup .off('layeradd', this._enableLayerEdit, this) .off('layerremove', this._disableLayerEdit, this); - L.Handler.prototype.disable.call(this); + L.ToolbarAction.prototype.disable.call(this); this._map.fire('draw:editstop', { handler: this.type }); this.fire('disabled', {handler: this.type}); }, diff --git a/src/edit/control/EditToolbar.Control.js b/src/edit/control/EditToolbar.Control.js new file mode 100644 index 000000000..1e32d0080 --- /dev/null +++ b/src/edit/control/EditToolbar.Control.js @@ -0,0 +1,72 @@ +L.EditToolbar.Control = L.Toolbar.Control.extend({ + options: { + className: 'leaflet-draw-toolbar', + edit: {}, + remove: {}, + featureGroup: null /* REQUIRED! TODO: perhaps if not set then all layers on the map are selectable? */ + }, + + initialize: function (options) { + L.setOptions(this, options); + + this._actions = {}; + this.options.actions = {}; + + if (this.options.edit) { + this.options.actions.edit = { + action: L.Edit.Control.Edit, + options: L.Util.extend(this.options.edit, { featureGroup: this.options.featureGroup }) + } + } + + if (this.options.remove) { + this.options.actions.remove = { + action: L.Edit.Control.Delete, + options: L.Util.extend(this.options.edit, { featureGroup: this.options.featureGroup }) + } + } + + L.Toolbar.Control.prototype.initialize.call(this, options); + } +}); + +L.EditToolbar.Save = L.ToolbarAction.extend({ + options: { + toolbarIcon: { html: 'Save' } + }, + + initialize: function (map, editing) { + this.editing = editing; + L.ToolbarAction.prototype.initialize.call(this); + }, + + addHooks: function () { + this.editing.save(); + this.editing.disable(); + } +}); + +L.EditToolbar.Undo = L.ToolbarAction.extend({ + options: { + toolbarIcon: { html: 'Undo' } + }, + + initialize: function (map, editing) { + this.editing = editing; + L.ToolbarAction.prototype.initialize.call(this); + }, + + addHooks: function () { + this.editing.revertLayers(); + this.editing.disable(); + } +}); + +/* Enable save and undo functionality for edit and delete modes. */ +L.setOptions(L.Edit.Control.Delete.prototype, { + subToolbar: new L.Toolbar({ actions: [L.EditToolbar.Save, L.EditToolbar.Undo] }) +}); + +L.setOptions(L.Edit.Control.Edit.prototype, { + subToolbar: new L.Toolbar({ actions: [L.EditToolbar.Save, L.EditToolbar.Undo] }) +}); \ No newline at end of file diff --git a/src/edit/handler/Edit.Poly.js b/src/edit/handler/Edit.Poly.js index 3ee4e2128..ac91718cf 100644 --- a/src/edit/handler/Edit.Poly.js +++ b/src/edit/handler/Edit.Poly.js @@ -257,7 +257,7 @@ L.Edit.Poly = L.Handler.extend({ L.Polyline.addInitHook(function () { - // Check to see if handler has already been initialized. This is to support versions of Leaflet that still have L.Handler.PolyEdit + // Check to see if handler has already been initialized. This is to support versions of Leaflet that still have L.ToolbarAction.PolyEdit if (this.editing) { return; } diff --git a/src/edit/popup/Edit.Popup.Delete.js b/src/edit/popup/Edit.Popup.Delete.js new file mode 100644 index 000000000..16f14564e --- /dev/null +++ b/src/edit/popup/Edit.Popup.Delete.js @@ -0,0 +1,20 @@ +L.Edit = L.Edit || {}; +L.Edit.Popup = L.Edit.Popup || {}; + +L.Edit.Popup.Delete = L.ToolbarAction.extend({ + options: { + toolbarIcon: { className: 'leaflet-draw-edit-remove' } + }, + + initialize: function (map, shape, options) { + this._map = map; + this._shape = shape; + + L.ToolbarAction.prototype.initialize.call(this, map, options); + }, + + addHooks: function () { + this._map.removeLayer(this._shape); + this._map.removeLayer(this.toolbar); + } +}); diff --git a/src/edit/popup/Edit.Popup.Edit.js b/src/edit/popup/Edit.Popup.Edit.js new file mode 100644 index 000000000..d5b0036bb --- /dev/null +++ b/src/edit/popup/Edit.Popup.Edit.js @@ -0,0 +1,29 @@ +L.Edit = L.Edit || {}; +L.Edit.Popup = L.Edit.Popup || {}; + +L.Edit.Popup.Edit = L.ToolbarAction.extend({ + options: { + toolbarIcon: { className: 'leaflet-draw-edit-edit' } + }, + + initialize: function (map, shape, options) { + this._map = map; + + this._shape = shape; + this._shape.options.editing = this._shape.options.editing || {}; + + L.ToolbarAction.prototype.initialize.call(this, map, options); + }, + + enable: function () { + var map = this._map, + shape = this._shape; + + shape.editing.enable(); + map.removeLayer(this.toolbar); + + map.on('click', function () { + shape.editing.disable(); + }); + } +}); \ No newline at end of file diff --git a/src/edit/popup/EditToolbar.Popup.js b/src/edit/popup/EditToolbar.Popup.js new file mode 100644 index 000000000..8dd6ed123 --- /dev/null +++ b/src/edit/popup/EditToolbar.Popup.js @@ -0,0 +1,19 @@ +L.EditToolbar.Popup = L.Toolbar.Popup.extend({ + options: { + actions: [ + L.Edit.Popup.Edit, + L.Edit.Popup.Delete + ] + }, + + onAdd: function (map) { + var shape = this._arguments[1]; + + if (shape instanceof L.Marker) { + /* Adjust the toolbar position so that it doesn't cover the marker. */ + this.options.anchor = L.point(shape.options.icon.options.popupAnchor); + } + + L.Toolbar.Popup.prototype.onAdd.call(this, map); + } +}); \ No newline at end of file