Merge branch 'contextmenu'
This commit is contained in:
commit
0bdf29f10b
8 changed files with 770 additions and 7 deletions
|
@ -20,6 +20,11 @@ folder 'vendor/assets' do
|
||||||
file "images/#{image}", "https://unpkg.com/leaflet@1.0.3/dist/images/#{image}"
|
file "images/#{image}", "https://unpkg.com/leaflet@1.0.3/dist/images/#{image}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
from 'git://github.com/aratcliffe/Leaflet.contextmenu.git', :tag => 'v1.2.1' do
|
||||||
|
file 'leaflet.contextmenu.js', 'dist/leaflet.contextmenu.js'
|
||||||
|
file 'leaflet.contextmenu.css', 'dist/leaflet.contextmenu.css'
|
||||||
|
end
|
||||||
|
|
||||||
from 'git://github.com/kajic/leaflet-locationfilter.git' do
|
from 'git://github.com/kajic/leaflet-locationfilter.git' do
|
||||||
file 'leaflet.locationfilter.css', 'src/locationfilter.css'
|
file 'leaflet.locationfilter.css', 'src/locationfilter.css'
|
||||||
file 'leaflet.locationfilter.js', 'src/locationfilter.js'
|
file 'leaflet.locationfilter.js', 'src/locationfilter.js'
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
//= require leaflet.share
|
//= require leaflet.share
|
||||||
//= require leaflet.polyline
|
//= require leaflet.polyline
|
||||||
//= require leaflet.query
|
//= require leaflet.query
|
||||||
|
//= require leaflet.contextmenu
|
||||||
|
//= require index/contextmenu
|
||||||
//= require index/search
|
//= require index/search
|
||||||
//= require index/browse
|
//= require index/browse
|
||||||
//= require index/export
|
//= require index/export
|
||||||
|
@ -77,7 +79,9 @@ $(document).ready(function () {
|
||||||
|
|
||||||
var map = new L.OSM.Map("map", {
|
var map = new L.OSM.Map("map", {
|
||||||
zoomControl: false,
|
zoomControl: false,
|
||||||
layerControl: false
|
layerControl: false,
|
||||||
|
contextmenu: true,
|
||||||
|
contextmenuWidth: 140
|
||||||
});
|
});
|
||||||
|
|
||||||
map.attributionControl.setPrefix('');
|
map.attributionControl.setPrefix('');
|
||||||
|
@ -147,6 +151,8 @@ $(document).ready(function () {
|
||||||
L.control.scale()
|
L.control.scale()
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
|
|
||||||
|
OSM.initializeContextMenu(map);
|
||||||
|
|
||||||
if (OSM.STATUS !== 'api_offline' && OSM.STATUS !== 'database_offline') {
|
if (OSM.STATUS !== 'api_offline' && OSM.STATUS !== 'database_offline') {
|
||||||
OSM.initializeNotes(map);
|
OSM.initializeNotes(map);
|
||||||
if (params.layers.indexOf(map.noteLayer.options.code) >= 0) {
|
if (params.layers.indexOf(map.noteLayer.options.code) >= 0) {
|
||||||
|
|
86
app/assets/javascripts/index/contextmenu.js
Normal file
86
app/assets/javascripts/index/contextmenu.js
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
OSM.initializeContextMenu = function (map) {
|
||||||
|
map.contextmenu.addItem({
|
||||||
|
text: I18n.t("javascripts.context.directions_from"),
|
||||||
|
callback: function directionsFromHere(e) {
|
||||||
|
var precision = OSM.zoomPrecision(map.getZoom()),
|
||||||
|
latlng = e.latlng.wrap(),
|
||||||
|
lat = latlng.lat.toFixed(precision),
|
||||||
|
lng = latlng.lng.toFixed(precision);
|
||||||
|
|
||||||
|
OSM.router.route("/directions?" + querystring.stringify({
|
||||||
|
route: lat + "," + lng + ";" + $("#route_to").val()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
map.contextmenu.addItem({
|
||||||
|
text: I18n.t("javascripts.context.directions_to"),
|
||||||
|
callback: function directionsToHere(e) {
|
||||||
|
var precision = OSM.zoomPrecision(map.getZoom()),
|
||||||
|
latlng = e.latlng.wrap(),
|
||||||
|
lat = latlng.lat.toFixed(precision),
|
||||||
|
lng = latlng.lng.toFixed(precision);
|
||||||
|
|
||||||
|
OSM.router.route("/directions?" + querystring.stringify({
|
||||||
|
route: $("#route_from").val() + ";" + lat + "," + lng
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
map.contextmenu.addItem({
|
||||||
|
text: I18n.t("javascripts.context.add_note"),
|
||||||
|
callback: function addNoteHere(e) {
|
||||||
|
var precision = OSM.zoomPrecision(map.getZoom()),
|
||||||
|
latlng = e.latlng.wrap(),
|
||||||
|
lat = latlng.lat.toFixed(precision),
|
||||||
|
lng = latlng.lng.toFixed(precision);
|
||||||
|
|
||||||
|
OSM.router.route("/note/new?lat=" + lat + "&lon=" + lng);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
map.contextmenu.addItem({
|
||||||
|
text: I18n.t("javascripts.context.show_address"),
|
||||||
|
callback: function describeLocation(e) {
|
||||||
|
var precision = OSM.zoomPrecision(map.getZoom()),
|
||||||
|
latlng = e.latlng.wrap(),
|
||||||
|
lat = latlng.lat.toFixed(precision),
|
||||||
|
lng = latlng.lng.toFixed(precision);
|
||||||
|
|
||||||
|
OSM.router.route("/search?query=" + encodeURIComponent(lat + "," + lng));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
map.contextmenu.addItem({
|
||||||
|
text: I18n.t("javascripts.context.query_features"),
|
||||||
|
callback: function queryFeatures(e) {
|
||||||
|
var precision = OSM.zoomPrecision(map.getZoom()),
|
||||||
|
latlng = e.latlng.wrap(),
|
||||||
|
lat = latlng.lat.toFixed(precision),
|
||||||
|
lng = latlng.lng.toFixed(precision);
|
||||||
|
|
||||||
|
OSM.router.route("/query?lat=" + lat + "&lon=" + lng);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
map.contextmenu.addItem({
|
||||||
|
text: I18n.t("javascripts.context.centre_map"),
|
||||||
|
callback: function centreMap(e) {
|
||||||
|
map.panTo(e.latlng);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on("mousedown", function (e) {
|
||||||
|
if (e.shiftKey) map.contextmenu.disable();
|
||||||
|
}).on("mouseup", function () {
|
||||||
|
map.contextmenu.enable();
|
||||||
|
});
|
||||||
|
|
||||||
|
var updateMenu = function updateMenu () {
|
||||||
|
map.contextmenu.setDisabled(2, map.getZoom() < 12);
|
||||||
|
map.contextmenu.setDisabled(4, map.getZoom() < 14);
|
||||||
|
};
|
||||||
|
|
||||||
|
map.on("zoomend", updateMenu);
|
||||||
|
updateMenu();
|
||||||
|
};
|
|
@ -77,7 +77,9 @@ OSM.NewNote = function(map) {
|
||||||
}
|
}
|
||||||
|
|
||||||
page.pushstate = page.popstate = function (path) {
|
page.pushstate = page.popstate = function (path) {
|
||||||
OSM.loadSidebarContent(path, page.load);
|
OSM.loadSidebarContent(path, function () {
|
||||||
|
page.load(path);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
function newHalo(loc, a) {
|
function newHalo(loc, a) {
|
||||||
|
@ -97,7 +99,7 @@ OSM.NewNote = function(map) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
page.load = function () {
|
page.load = function (path) {
|
||||||
if (addNoteButton.hasClass("disabled")) return;
|
if (addNoteButton.hasClass("disabled")) return;
|
||||||
if (addNoteButton.hasClass("active")) return;
|
if (addNoteButton.hasClass("active")) return;
|
||||||
|
|
||||||
|
@ -105,12 +107,34 @@ OSM.NewNote = function(map) {
|
||||||
|
|
||||||
map.addLayer(noteLayer);
|
map.addLayer(noteLayer);
|
||||||
|
|
||||||
var mapSize = map.getSize();
|
var params = querystring.parse(path.substring(path.indexOf('?') + 1));
|
||||||
var markerPosition;
|
var markerLatlng;
|
||||||
|
|
||||||
markerPosition = [mapSize.x / 2, mapSize.y / 2];
|
if (params.lat && params.lon) {
|
||||||
|
markerLatlng = L.latLng(params.lat, params.lon);
|
||||||
|
|
||||||
newNote = L.marker(map.containerPointToLatLng(markerPosition), {
|
var markerPosition = map.latLngToContainerPoint(markerLatlng),
|
||||||
|
mapSize = map.getSize(),
|
||||||
|
panBy = L.point(0, 0);
|
||||||
|
|
||||||
|
if (markerPosition.x < 50) {
|
||||||
|
panBy.x = markerPosition.x - 50;
|
||||||
|
} else if (markerPosition.x > mapSize.x - 50) {
|
||||||
|
panBy.x = 50 - mapSize.x + markerPosition.x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (markerPosition.y < 50) {
|
||||||
|
panBy.y = markerPosition.y - 50;
|
||||||
|
} else if (markerPosition.y > mapSize.y - 50) {
|
||||||
|
panBy.y = 50 - mapSize.y + markerPosition.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.panBy(panBy);
|
||||||
|
} else {
|
||||||
|
markerLatlng = map.getCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
newNote = L.marker(markerLatlng, {
|
||||||
icon: noteIcons["new"],
|
icon: noteIcons["new"],
|
||||||
opacity: 0.9,
|
opacity: 0.9,
|
||||||
draggable: true
|
draggable: true
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
*= require leaflet
|
*= require leaflet
|
||||||
*= require leaflet.locationfilter
|
*= require leaflet.locationfilter
|
||||||
|
*= require leaflet.contextmenu
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Override to serve images through the asset pipeline. */
|
/* Override to serve images through the asset pipeline. */
|
||||||
|
|
|
@ -2305,6 +2305,13 @@ en:
|
||||||
nothing_found: No features found
|
nothing_found: No features found
|
||||||
error: "Error contacting %{server}: %{error}"
|
error: "Error contacting %{server}: %{error}"
|
||||||
timeout: "Timeout contacting %{server}"
|
timeout: "Timeout contacting %{server}"
|
||||||
|
context:
|
||||||
|
directions_from: Directions from here
|
||||||
|
directions_to: Directions to here
|
||||||
|
add_note: Add a note here
|
||||||
|
show_address: Show address
|
||||||
|
query_features: Query features
|
||||||
|
centre_map: Centre map here
|
||||||
redaction:
|
redaction:
|
||||||
edit:
|
edit:
|
||||||
description: "Description"
|
description: "Description"
|
||||||
|
|
54
vendor/assets/leaflet/leaflet.contextmenu.css
vendored
Normal file
54
vendor/assets/leaflet/leaflet.contextmenu.css
vendored
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
.leaflet-contextmenu {
|
||||||
|
display: none;
|
||||||
|
box-shadow: 0 1px 7px rgba(0,0,0,0.4);
|
||||||
|
-webkit-border-radius: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px 0;
|
||||||
|
background-color: #fff;
|
||||||
|
cursor: default;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-contextmenu a.leaflet-contextmenu-item {
|
||||||
|
display: block;
|
||||||
|
color: #222;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 0 12px;
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
cursor: default;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-contextmenu a.leaflet-contextmenu-item-disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-contextmenu a.leaflet-contextmenu-item.over {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
border-top: 1px solid #f0f0f0;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-contextmenu a.leaflet-contextmenu-item-disabled.over {
|
||||||
|
background-color: inherit;
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-contextmenu-icon {
|
||||||
|
margin: 2px 8px 0 0;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
float: left;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-contextmenu-separator {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
580
vendor/assets/leaflet/leaflet.contextmenu.js
vendored
Normal file
580
vendor/assets/leaflet/leaflet.contextmenu.js
vendored
Normal file
|
@ -0,0 +1,580 @@
|
||||||
|
/*
|
||||||
|
Leaflet.contextmenu, a context menu for Leaflet.
|
||||||
|
(c) 2015, Adam Ratcliffe, GeoSmart Maps Limited
|
||||||
|
|
||||||
|
@preserve
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function(factory) {
|
||||||
|
// Packaging/modules magic dance
|
||||||
|
var L;
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
// AMD
|
||||||
|
define(['leaflet'], factory);
|
||||||
|
} else if (typeof module === 'object' && typeof module.exports === 'object') {
|
||||||
|
// Node/CommonJS
|
||||||
|
L = require('leaflet');
|
||||||
|
module.exports = factory(L);
|
||||||
|
} else {
|
||||||
|
// Browser globals
|
||||||
|
if (typeof window.L === 'undefined') {
|
||||||
|
throw new Error('Leaflet must be loaded first');
|
||||||
|
}
|
||||||
|
factory(window.L);
|
||||||
|
}
|
||||||
|
})(function(L) {
|
||||||
|
L.Map.mergeOptions({
|
||||||
|
contextmenuItems: []
|
||||||
|
});
|
||||||
|
|
||||||
|
L.Map.ContextMenu = L.Handler.extend({
|
||||||
|
_touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',
|
||||||
|
|
||||||
|
statics: {
|
||||||
|
BASE_CLS: 'leaflet-contextmenu'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function (map) {
|
||||||
|
L.Handler.prototype.initialize.call(this, map);
|
||||||
|
|
||||||
|
this._items = [];
|
||||||
|
this._visible = false;
|
||||||
|
|
||||||
|
var container = this._container = L.DomUtil.create('div', L.Map.ContextMenu.BASE_CLS, map._container);
|
||||||
|
container.style.zIndex = 10000;
|
||||||
|
container.style.position = 'absolute';
|
||||||
|
|
||||||
|
if (map.options.contextmenuWidth) {
|
||||||
|
container.style.width = map.options.contextmenuWidth + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
this._createItems();
|
||||||
|
|
||||||
|
L.DomEvent
|
||||||
|
.on(container, 'click', L.DomEvent.stop)
|
||||||
|
.on(container, 'mousedown', L.DomEvent.stop)
|
||||||
|
.on(container, 'dblclick', L.DomEvent.stop)
|
||||||
|
.on(container, 'contextmenu', L.DomEvent.stop);
|
||||||
|
},
|
||||||
|
|
||||||
|
addHooks: function () {
|
||||||
|
var container = this._map.getContainer();
|
||||||
|
|
||||||
|
L.DomEvent
|
||||||
|
.on(container, 'mouseleave', this._hide, this)
|
||||||
|
.on(document, 'keydown', this._onKeyDown, this);
|
||||||
|
|
||||||
|
if (L.Browser.touch) {
|
||||||
|
L.DomEvent.on(document, this._touchstart, this._hide, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._map.on({
|
||||||
|
contextmenu: this._show,
|
||||||
|
mousedown: this._hide,
|
||||||
|
movestart: this._hide,
|
||||||
|
zoomstart: this._hide
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeHooks: function () {
|
||||||
|
var container = this._map.getContainer();
|
||||||
|
|
||||||
|
L.DomEvent
|
||||||
|
.off(container, 'mouseleave', this._hide, this)
|
||||||
|
.off(document, 'keydown', this._onKeyDown, this);
|
||||||
|
|
||||||
|
if (L.Browser.touch) {
|
||||||
|
L.DomEvent.off(document, this._touchstart, this._hide, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._map.off({
|
||||||
|
contextmenu: this._show,
|
||||||
|
mousedown: this._hide,
|
||||||
|
movestart: this._hide,
|
||||||
|
zoomstart: this._hide
|
||||||
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
showAt: function (point, data) {
|
||||||
|
if (point instanceof L.LatLng) {
|
||||||
|
point = this._map.latLngToContainerPoint(point);
|
||||||
|
}
|
||||||
|
this._showAtPoint(point, data);
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function () {
|
||||||
|
this._hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
addItem: function (options) {
|
||||||
|
return this.insertItem(options);
|
||||||
|
},
|
||||||
|
|
||||||
|
insertItem: function (options, index) {
|
||||||
|
index = index !== undefined ? index: this._items.length;
|
||||||
|
|
||||||
|
var item = this._createItem(this._container, options, index);
|
||||||
|
|
||||||
|
this._items.push(item);
|
||||||
|
|
||||||
|
this._sizeChanged = true;
|
||||||
|
|
||||||
|
this._map.fire('contextmenu.additem', {
|
||||||
|
contextmenu: this,
|
||||||
|
el: item.el,
|
||||||
|
index: index
|
||||||
|
});
|
||||||
|
|
||||||
|
return item.el;
|
||||||
|
},
|
||||||
|
|
||||||
|
removeItem: function (item) {
|
||||||
|
var container = this._container;
|
||||||
|
|
||||||
|
if (!isNaN(item)) {
|
||||||
|
item = container.children[item];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
this._removeItem(L.Util.stamp(item));
|
||||||
|
|
||||||
|
this._sizeChanged = true;
|
||||||
|
|
||||||
|
this._map.fire('contextmenu.removeitem', {
|
||||||
|
contextmenu: this,
|
||||||
|
el: item
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeAllItems: function () {
|
||||||
|
var item;
|
||||||
|
|
||||||
|
while (this._container.children.length) {
|
||||||
|
item = this._container.children[0];
|
||||||
|
this._removeItem(L.Util.stamp(item));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
hideAllItems: function () {
|
||||||
|
var item, i, l;
|
||||||
|
|
||||||
|
for (i = 0, l = this._items.length; i < l; i++) {
|
||||||
|
item = this._items[i];
|
||||||
|
item.el.style.display = 'none';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
showAllItems: function () {
|
||||||
|
var item, i, l;
|
||||||
|
|
||||||
|
for (i = 0, l = this._items.length; i < l; i++) {
|
||||||
|
item = this._items[i];
|
||||||
|
item.el.style.display = '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setDisabled: function (item, disabled) {
|
||||||
|
var container = this._container,
|
||||||
|
itemCls = L.Map.ContextMenu.BASE_CLS + '-item';
|
||||||
|
|
||||||
|
if (!isNaN(item)) {
|
||||||
|
item = container.children[item];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item && L.DomUtil.hasClass(item, itemCls)) {
|
||||||
|
if (disabled) {
|
||||||
|
L.DomUtil.addClass(item, itemCls + '-disabled');
|
||||||
|
this._map.fire('contextmenu.disableitem', {
|
||||||
|
contextmenu: this,
|
||||||
|
el: item
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
L.DomUtil.removeClass(item, itemCls + '-disabled');
|
||||||
|
this._map.fire('contextmenu.enableitem', {
|
||||||
|
contextmenu: this,
|
||||||
|
el: item
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isVisible: function () {
|
||||||
|
return this._visible;
|
||||||
|
},
|
||||||
|
|
||||||
|
_createItems: function () {
|
||||||
|
var itemOptions = this._map.options.contextmenuItems,
|
||||||
|
item,
|
||||||
|
i, l;
|
||||||
|
|
||||||
|
for (i = 0, l = itemOptions.length; i < l; i++) {
|
||||||
|
this._items.push(this._createItem(this._container, itemOptions[i]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_createItem: function (container, options, index) {
|
||||||
|
if (options.separator || options === '-') {
|
||||||
|
return this._createSeparator(container, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemCls = L.Map.ContextMenu.BASE_CLS + '-item',
|
||||||
|
cls = options.disabled ? (itemCls + ' ' + itemCls + '-disabled') : itemCls,
|
||||||
|
el = this._insertElementAt('a', cls, container, index),
|
||||||
|
callback = this._createEventHandler(el, options.callback, options.context, options.hideOnSelect),
|
||||||
|
icon = this._getIcon(options),
|
||||||
|
iconCls = this._getIconCls(options),
|
||||||
|
html = '';
|
||||||
|
|
||||||
|
if (icon) {
|
||||||
|
html = '<img class="' + L.Map.ContextMenu.BASE_CLS + '-icon" src="' + icon + '"/>';
|
||||||
|
} else if (iconCls) {
|
||||||
|
html = '<span class="' + L.Map.ContextMenu.BASE_CLS + '-icon ' + iconCls + '"></span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
el.innerHTML = html + options.text;
|
||||||
|
el.href = '#';
|
||||||
|
|
||||||
|
L.DomEvent
|
||||||
|
.on(el, 'mouseover', this._onItemMouseOver, this)
|
||||||
|
.on(el, 'mouseout', this._onItemMouseOut, this)
|
||||||
|
.on(el, 'mousedown', L.DomEvent.stopPropagation)
|
||||||
|
.on(el, 'click', callback);
|
||||||
|
|
||||||
|
if (L.Browser.touch) {
|
||||||
|
L.DomEvent.on(el, this._touchstart, L.DomEvent.stopPropagation);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Devices without a mouse fire "mouseover" on tap, but never “mouseout"
|
||||||
|
if (!L.Browser.pointer) {
|
||||||
|
L.DomEvent.on(el, 'click', this._onItemMouseOut, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: L.Util.stamp(el),
|
||||||
|
el: el,
|
||||||
|
callback: callback
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeItem: function (id) {
|
||||||
|
var item,
|
||||||
|
el,
|
||||||
|
i, l, callback;
|
||||||
|
|
||||||
|
for (i = 0, l = this._items.length; i < l; i++) {
|
||||||
|
item = this._items[i];
|
||||||
|
|
||||||
|
if (item.id === id) {
|
||||||
|
el = item.el;
|
||||||
|
callback = item.callback;
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
L.DomEvent
|
||||||
|
.off(el, 'mouseover', this._onItemMouseOver, this)
|
||||||
|
.off(el, 'mouseover', this._onItemMouseOut, this)
|
||||||
|
.off(el, 'mousedown', L.DomEvent.stopPropagation)
|
||||||
|
.off(el, 'click', callback);
|
||||||
|
|
||||||
|
if (L.Browser.touch) {
|
||||||
|
L.DomEvent.off(el, this._touchstart, L.DomEvent.stopPropagation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!L.Browser.pointer) {
|
||||||
|
L.DomEvent.on(el, 'click', this._onItemMouseOut, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._container.removeChild(el);
|
||||||
|
this._items.splice(i, 1);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_createSeparator: function (container, index) {
|
||||||
|
var el = this._insertElementAt('div', L.Map.ContextMenu.BASE_CLS + '-separator', container, index);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: L.Util.stamp(el),
|
||||||
|
el: el
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
_createEventHandler: function (el, func, context, hideOnSelect) {
|
||||||
|
var me = this,
|
||||||
|
map = this._map,
|
||||||
|
disabledCls = L.Map.ContextMenu.BASE_CLS + '-item-disabled',
|
||||||
|
hideOnSelect = (hideOnSelect !== undefined) ? hideOnSelect : true;
|
||||||
|
|
||||||
|
return function (e) {
|
||||||
|
if (L.DomUtil.hasClass(el, disabledCls)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hideOnSelect) {
|
||||||
|
me._hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (func) {
|
||||||
|
func.call(context || map, me._showLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
me._map.fire('contextmenu:select', {
|
||||||
|
contextmenu: me,
|
||||||
|
el: el
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
_insertElementAt: function (tagName, className, container, index) {
|
||||||
|
var refEl,
|
||||||
|
el = document.createElement(tagName);
|
||||||
|
|
||||||
|
el.className = className;
|
||||||
|
|
||||||
|
if (index !== undefined) {
|
||||||
|
refEl = container.children[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refEl) {
|
||||||
|
container.insertBefore(el, refEl);
|
||||||
|
} else {
|
||||||
|
container.appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
},
|
||||||
|
|
||||||
|
_show: function (e) {
|
||||||
|
this._showAtPoint(e.containerPoint, e);
|
||||||
|
},
|
||||||
|
|
||||||
|
_showAtPoint: function (pt, data) {
|
||||||
|
if (this._items.length) {
|
||||||
|
var map = this._map,
|
||||||
|
layerPoint = map.containerPointToLayerPoint(pt),
|
||||||
|
latlng = map.layerPointToLatLng(layerPoint),
|
||||||
|
event = L.extend(data || {}, {contextmenu: this});
|
||||||
|
|
||||||
|
this._showLocation = {
|
||||||
|
latlng: latlng,
|
||||||
|
layerPoint: layerPoint,
|
||||||
|
containerPoint: pt
|
||||||
|
};
|
||||||
|
|
||||||
|
if (data && data.relatedTarget){
|
||||||
|
this._showLocation.relatedTarget = data.relatedTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._setPosition(pt);
|
||||||
|
|
||||||
|
if (!this._visible) {
|
||||||
|
this._container.style.display = 'block';
|
||||||
|
this._visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._map.fire('contextmenu.show', event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_hide: function () {
|
||||||
|
if (this._visible) {
|
||||||
|
this._visible = false;
|
||||||
|
this._container.style.display = 'none';
|
||||||
|
this._map.fire('contextmenu.hide', {contextmenu: this});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getIcon: function (options) {
|
||||||
|
return L.Browser.retina && options.retinaIcon || options.icon;
|
||||||
|
},
|
||||||
|
|
||||||
|
_getIconCls: function (options) {
|
||||||
|
return L.Browser.retina && options.retinaIconCls || options.iconCls;
|
||||||
|
},
|
||||||
|
|
||||||
|
_setPosition: function (pt) {
|
||||||
|
var mapSize = this._map.getSize(),
|
||||||
|
container = this._container,
|
||||||
|
containerSize = this._getElementSize(container),
|
||||||
|
anchor;
|
||||||
|
|
||||||
|
if (this._map.options.contextmenuAnchor) {
|
||||||
|
anchor = L.point(this._map.options.contextmenuAnchor);
|
||||||
|
pt = pt.add(anchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
container._leaflet_pos = pt;
|
||||||
|
|
||||||
|
if (pt.x + containerSize.x > mapSize.x) {
|
||||||
|
container.style.left = 'auto';
|
||||||
|
container.style.right = Math.min(Math.max(mapSize.x - pt.x, 0), mapSize.x - containerSize.x - 1) + 'px';
|
||||||
|
} else {
|
||||||
|
container.style.left = Math.max(pt.x, 0) + 'px';
|
||||||
|
container.style.right = 'auto';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pt.y + containerSize.y > mapSize.y) {
|
||||||
|
container.style.top = 'auto';
|
||||||
|
container.style.bottom = Math.min(Math.max(mapSize.y - pt.y, 0), mapSize.y - containerSize.y - 1) + 'px';
|
||||||
|
} else {
|
||||||
|
container.style.top = Math.max(pt.y, 0) + 'px';
|
||||||
|
container.style.bottom = 'auto';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getElementSize: function (el) {
|
||||||
|
var size = this._size,
|
||||||
|
initialDisplay = el.style.display;
|
||||||
|
|
||||||
|
if (!size || this._sizeChanged) {
|
||||||
|
size = {};
|
||||||
|
|
||||||
|
el.style.left = '-999999px';
|
||||||
|
el.style.right = 'auto';
|
||||||
|
el.style.display = 'block';
|
||||||
|
|
||||||
|
size.x = el.offsetWidth;
|
||||||
|
size.y = el.offsetHeight;
|
||||||
|
|
||||||
|
el.style.left = 'auto';
|
||||||
|
el.style.display = initialDisplay;
|
||||||
|
|
||||||
|
this._sizeChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onKeyDown: function (e) {
|
||||||
|
var key = e.keyCode;
|
||||||
|
|
||||||
|
// If ESC pressed and context menu is visible hide it
|
||||||
|
if (key === 27) {
|
||||||
|
this._hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onItemMouseOver: function (e) {
|
||||||
|
L.DomUtil.addClass(e.target || e.srcElement, 'over');
|
||||||
|
},
|
||||||
|
|
||||||
|
_onItemMouseOut: function (e) {
|
||||||
|
L.DomUtil.removeClass(e.target || e.srcElement, 'over');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
L.Map.addInitHook('addHandler', 'contextmenu', L.Map.ContextMenu);
|
||||||
|
L.Mixin.ContextMenu = {
|
||||||
|
bindContextMenu: function (options) {
|
||||||
|
L.setOptions(this, options);
|
||||||
|
this._initContextMenu();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
unbindContextMenu: function (){
|
||||||
|
this.off('contextmenu', this._showContextMenu, this);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
addContextMenuItem: function (item) {
|
||||||
|
this.options.contextmenuItems.push(item);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeContextMenuItemWithIndex: function (index) {
|
||||||
|
var items = [];
|
||||||
|
for (var i = 0; i < this.options.contextmenuItems.length; i++) {
|
||||||
|
if (this.options.contextmenuItems[i].index == index){
|
||||||
|
items.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var elem = items.pop();
|
||||||
|
while (elem !== undefined) {
|
||||||
|
this.options.contextmenuItems.splice(elem,1);
|
||||||
|
elem = items.pop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
replaceContextMenuItem: function (item) {
|
||||||
|
this.removeContextMenuItemWithIndex(item.index);
|
||||||
|
this.addContextMenuItem(item);
|
||||||
|
},
|
||||||
|
|
||||||
|
_initContextMenu: function () {
|
||||||
|
this._items = [];
|
||||||
|
|
||||||
|
this.on('contextmenu', this._showContextMenu, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
_showContextMenu: function (e) {
|
||||||
|
var itemOptions,
|
||||||
|
data, pt, i, l;
|
||||||
|
|
||||||
|
if (this._map.contextmenu) {
|
||||||
|
data = L.extend({relatedTarget: this}, e);
|
||||||
|
|
||||||
|
pt = this._map.mouseEventToContainerPoint(e.originalEvent);
|
||||||
|
|
||||||
|
if (!this.options.contextmenuInheritItems) {
|
||||||
|
this._map.contextmenu.hideAllItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, l = this.options.contextmenuItems.length; i < l; i++) {
|
||||||
|
itemOptions = this.options.contextmenuItems[i];
|
||||||
|
this._items.push(this._map.contextmenu.insertItem(itemOptions, itemOptions.index));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._map.once('contextmenu.hide', this._hideContextMenu, this);
|
||||||
|
|
||||||
|
this._map.contextmenu.showAt(pt, data);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_hideContextMenu: function () {
|
||||||
|
var i, l;
|
||||||
|
|
||||||
|
for (i = 0, l = this._items.length; i < l; i++) {
|
||||||
|
this._map.contextmenu.removeItem(this._items[i]);
|
||||||
|
}
|
||||||
|
this._items.length = 0;
|
||||||
|
|
||||||
|
if (!this.options.contextmenuInheritItems) {
|
||||||
|
this._map.contextmenu.showAllItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var classes = [L.Marker, L.Path],
|
||||||
|
defaultOptions = {
|
||||||
|
contextmenu: false,
|
||||||
|
contextmenuItems: [],
|
||||||
|
contextmenuInheritItems: true
|
||||||
|
},
|
||||||
|
cls, i, l;
|
||||||
|
|
||||||
|
for (i = 0, l = classes.length; i < l; i++) {
|
||||||
|
cls = classes[i];
|
||||||
|
|
||||||
|
// L.Class should probably provide an empty options hash, as it does not test
|
||||||
|
// for it here and add if needed
|
||||||
|
if (!cls.prototype.options) {
|
||||||
|
cls.prototype.options = defaultOptions;
|
||||||
|
} else {
|
||||||
|
cls.mergeOptions(defaultOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
cls.addInitHook(function () {
|
||||||
|
if (this.options.contextmenu) {
|
||||||
|
this._initContextMenu();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
cls.include(L.Mixin.ContextMenu);
|
||||||
|
}
|
||||||
|
return L.Map.ContextMenu;
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue