// ==UserScript==
// @name InteractiveMap
// @namespace Violentmonkey Scripts
// @match http*://nms.huijiwiki.com/wiki/%E6%97%A0%E4%BA%BA%E6%B7%B1%E7%A9%BA%E4%B8%AD%E6%96%87%E7%BB%B4%E5%9F%BA:%E6%B2%99%E7%9B%92
// @grant none
// @run-at document-idle
// @noframes
// ==/UserScript==
//<nowiki>
(function(leaflet, mw, $) {
'use strict';
$(document).ready(function() {
if ($(mapClass).length === 0) {
return;
}
init();
});
console.log('Loading interactive map module.');
// define class and attr names
var mapClass = '.interactive-map';
var mapSourceAttr = 'data-mapSource';
var mapMarkerAttr = 'data-markers';
var mapInitialZoom = 'data-initialZoom';
var mapInitialLocX = 'data-initialLocX';
var mapInitialLocY = 'data-initialLocY';
// default icon with modified path
var defaultIcon = leaflet.icon({
iconUrl:
'https://huiji-public.huijistatic.com/warframe/uploads/7/7a/Marker-icon.png',
shadowUrl:
'https://huiji-public.huijistatic.com/warframe/uploads/d/d4/Marker-shadow.png',
iconSize: [25, 41],
shadowSize: [41, 41],
iconAnchor: [12, 41],
shadowAnchor: [12, 41],
popupAnchor: [0, -41],
tooltipAnchor: [12, -30]
});
// store icon info to reduce redundant request
// {iconname:{url,width,height},...}
var iconMap = {};
// map working mode enum
var MODE = {
OVERLAY: 'overlay',
TILE: 'tile'
};
Object.freeze(MODE);
// initialization function
function init() {
$(mapClass).each(function() {
if (!$(this).attr('id') || $(this).prop('tagName') !== 'DIV') {
$(this).text('地图的id或标签设置有误!');
return;
}
// {image, markerPage, imageUrl, markerData([{coords{x,y},tooltip,markerImage},...]), markersLayerGroup, imageWidth, imageHeight, initialZoom, initialLocX, initialLocY, mapId, needSave}
var mapInfo = {};
mapInfo.mapId = $(this).attr('id');
mapInfo.image = $(this).attr(mapSourceAttr);
mapInfo.markerPage = $(this).attr(mapMarkerAttr);
mapInfo.initialZoom = Number($(this).attr(mapInitialZoom));
mapInfo.initialLocX = Number($(this).attr(mapInitialLocX));
mapInfo.initialLocY = Number($(this).attr(mapInitialLocY));
mapInfo.tileTemplate = $(this).attr('data-tileTemplate');
mapInfo.tileSize = $(this).attr('data-tileSize');
mapInfo.tileBounds = $(this).attr('data-tileBounds');
mapInfo.tileZoom = $(this).attr('data-tileZoom');
if (!mapInfo.image) {
if (!mapInfo.tileTemplate) {
mapInfo.image = '';
mapInfo.mode = MODE.OVERLAY;
} else {
mapInfo.tileTemplate = ucFirst(mapInfo.tileTemplate);
mapInfo.mode = MODE.TILE;
}
} else {
mapInfo.mode = MODE.OVERLAY;
}
if (!mapInfo.markerPage) {
if (mapInfo.mode === MODE.OVERLAY) {
if (mapInfo.image) {
mapInfo.markerPage = 'Data:' + mapInfo.image + '.json';
} else {
mapInfo.markerPage = '';
}
} else {
mapInfo.markerPage = 'Data:' + mapInfo.tileTemplate + '.json';
}
}
// start async setup procedure
setMapSrcUrl(mapInfo);
});
// help info modal
$('body').append(
'<div class="modal fade"id="map-help-info"tabindex="-1"role="dialog"aria-labelledby="myModalLabel"><div class="modal-dialog"role="document"><div class="modal-content"><div class="modal-header"><h3 class="modal-title">使用说明</h3></div><div class="modal-body"><h4 class="modal-title">添加标记</h4><p>在地图上点击鼠标右键,在弹出菜单中选择添加标记。</p><h4 class="modal-title">查看标记说明</h4><p>对于已经添加了说明信息的标记,可单击标记来查看说明文字。</p><h4 class="modal-title">编辑 / 删除标记</h4><p>在标记上点击鼠标右键,然后选择编辑 / 删除标记。</p><h4 class="modal-title">复制标记</h4><p>按住 <span class="label label-default"style="padding: .2em .6em;">Ctrl</span> 拖动一个已有标记,即可将该标记复制到目标位置。</p><h4 class="modal-title">保存改动</h4><p>对标记进行了修改后,点击地图右上角的 <i class="fa fa-save"aria-hidden="true"></i> 按钮来保存数据。</p><h4 class="modal-title">隐藏 / 显示标记</h4><p>点击地图左上角的 <i class="fa fa-eye"aria-hidden="true"></i> 按钮,来隐藏 / 显示标记。</p></div><div class="modal-footer"><button type="button"class="btn btn-default"data-dismiss="modal">关闭</button></div></div></div></div>'
);
}
function requestWithCallback(
queryData,
mapInfo,
callback,
reqType,
errCallback
) {
if (!reqType) {
reqType = 'GET';
}
if (!errCallback) {
errCallback = function() {
console.log('请求过程中出现错误!');
};
}
$.ajax({
url: '/api.php',
data: queryData,
type: reqType,
dataType: 'json',
cache: false,
timeout: 10000,
error: function(xhr) {
if (typeof errCallback === 'function') {
errCallback(xhr, mapInfo);
}
},
success: function(data) {
if (typeof callback === 'function') {
callback(data, mapInfo);
}
}
});
}
function setMapSrcUrl(mapInfo) {
if (mapInfo.mode === MODE.TILE) {
setMarkersData(mapInfo);
return;
}
var queryData = {
action: 'query',
format: 'json',
prop: 'imageinfo',
titles: 'File:' + mapInfo.image,
formatversion: '2',
iiprop: 'url|dimensions'
};
requestWithCallback(queryData, mapInfo, function(data, mapInfo) {
var pages = data.query.pages;
var pageid;
for (var p in pages) {
if (pages.hasOwnProperty(p)) {
if (pages[p].hasOwnProperty('missing')) {
$('#' + mapInfo.mapId).text('未找到地图:' + mapInfo.image);
return;
} else {
pageid = p;
break;
}
}
}
mapInfo.imageUrl = pages[pageid].imageinfo[0]['url'];
mapInfo.imageWidth = pages[pageid].imageinfo[0]['width'];
mapInfo.imageHeight = pages[pageid].imageinfo[0]['height'];
setMarkersData(mapInfo);
});
}
function setMarkersData(mapInfo, mapId) {
var queryData = {
action: 'query',
format: 'json',
prop: 'revisions',
titles: mapInfo.markerPage,
formatversion: '2',
rvprop: 'content',
rvlimit: '1'
};
requestWithCallback(queryData, mapInfo, function(data, mapInfo) {
var pages = data.query.pages;
var pageid;
for (var p in pages) {
if (pages.hasOwnProperty(p)) {
if (!pages[p].hasOwnProperty('missing')) {
try {
mapInfo.markerData = JSON.parse(
data.query.pages[0].revisions[0].content
).markers;
if (
typeof mapInfo.markerData !== 'object' ||
typeof mapInfo.markerData === null
) {
mapInfo.markerData = [];
}
} catch (error) {
console.log(error.messge);
mapInfo.markerData = [];
}
break;
}
}
}
if (!mapInfo.markerData) {
mapInfo.markerData = [];
}
loadMap(mapInfo);
});
}
function md5(string) {
var AA,
AddUnsigned,
BB,
CC,
ConvertToWordArray,
DD,
F,
FF,
G,
GG,
H,
HH,
I,
II,
RotateLeft,
S11,
S12,
S13,
S14,
S21,
S22,
S23,
S24,
S31,
S32,
S33,
S34,
S41,
S42,
S43,
S44,
Utf8Encode,
WordToHex,
a,
b,
c,
d,
k,
temp,
x;
RotateLeft = function(lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
};
AddUnsigned = function(lX, lY) {
var lResult, lX4, lX8, lY4, lY8;
lX8 = lX & 0x80000000;
lY8 = lY & 0x80000000;
lX4 = lX & 0x40000000;
lY4 = lY & 0x40000000;
lResult = (lX & 0x3fffffff) + (lY & 0x3fffffff);
if (lX4 & lY4) {
return lResult ^ 0x80000000 ^ lX8 ^ lY8;
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return lResult ^ 0xc0000000 ^ lX8 ^ lY8;
} else {
return lResult ^ 0x40000000 ^ lX8 ^ lY8;
}
} else {
return lResult ^ lX8 ^ lY8;
}
};
F = function(x, y, z) {
return (x & y) | (~x & z);
};
G = function(x, y, z) {
return (x & z) | (y & ~z);
};
H = function(x, y, z) {
return x ^ y ^ z;
};
I = function(x, y, z) {
return y ^ (x | ~z);
};
FF = function(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
GG = function(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
HH = function(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
II = function(a, b, c, d, x, s, ac) {
a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
return AddUnsigned(RotateLeft(a, s), b);
};
ConvertToWordArray = function(string) {
var lByteCount,
lBytePosition,
lMessageLength,
lNumberOfWords,
lNumberOfWords_temp1,
lNumberOfWords_temp2,
lWordArray,
lWordCount;
lMessageLength = string.length;
lNumberOfWords_temp1 = lMessageLength + 8;
lNumberOfWords_temp2 =
(lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
lWordArray = Array(lNumberOfWords - 1);
lBytePosition = 0;
lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] =
lWordArray[lWordCount] |
(string.charCodeAt(lByteCount) << lBytePosition);
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
WordToHex = function(lValue) {
var WordToHexValue, WordToHexValue_temp, lByte, lCount;
WordToHexValue = '';
WordToHexValue_temp = '';
lCount = 0;
while (lCount <= 3) {
lByte = (lValue >>> (lCount * 8)) & 255;
WordToHexValue_temp = '0' + lByte.toString(16);
WordToHexValue =
WordToHexValue +
WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
lCount++;
}
return WordToHexValue;
};
Utf8Encode = function(string) {
var c, n, utftext;
string = string.replace(/\r\n/g, '\n');
utftext = '';
n = 0;
while (n < string.length) {
c = string.charCodeAt(n);
if (c < 128) {
utftext += String.fromCharCode(c);
} else if (c > 127 && c < 2048) {
utftext += String.fromCharCode((c >> 6) | 192);
utftext += String.fromCharCode((c & 63) | 128);
} else {
utftext += String.fromCharCode((c >> 12) | 224);
utftext += String.fromCharCode(((c >> 6) & 63) | 128);
utftext += String.fromCharCode((c & 63) | 128);
}
n++;
}
return utftext;
};
x = Array();
S11 = 7;
S12 = 12;
S13 = 17;
S14 = 22;
S21 = 5;
S22 = 9;
S23 = 14;
S24 = 20;
S31 = 4;
S32 = 11;
S33 = 16;
S34 = 23;
S41 = 6;
S42 = 10;
S43 = 15;
S44 = 21;
string = Utf8Encode(string);
x = ConvertToWordArray(string);
a = 0x67452301;
b = 0xefcdab89;
c = 0x98badcfe;
d = 0x10325476;
k = 0;
while (k < x.length) {
AA = a;
BB = b;
CC = c;
DD = d;
a = FF(a, b, c, d, x[k + 0], S11, 0xd76aa478);
d = FF(d, a, b, c, x[k + 1], S12, 0xe8c7b756);
c = FF(c, d, a, b, x[k + 2], S13, 0x242070db);
b = FF(b, c, d, a, x[k + 3], S14, 0xc1bdceee);
a = FF(a, b, c, d, x[k + 4], S11, 0xf57c0faf);
d = FF(d, a, b, c, x[k + 5], S12, 0x4787c62a);
c = FF(c, d, a, b, x[k + 6], S13, 0xa8304613);
b = FF(b, c, d, a, x[k + 7], S14, 0xfd469501);
a = FF(a, b, c, d, x[k + 8], S11, 0x698098d8);
d = FF(d, a, b, c, x[k + 9], S12, 0x8b44f7af);
c = FF(c, d, a, b, x[k + 10], S13, 0xffff5bb1);
b = FF(b, c, d, a, x[k + 11], S14, 0x895cd7be);
a = FF(a, b, c, d, x[k + 12], S11, 0x6b901122);
d = FF(d, a, b, c, x[k + 13], S12, 0xfd987193);
c = FF(c, d, a, b, x[k + 14], S13, 0xa679438e);
b = FF(b, c, d, a, x[k + 15], S14, 0x49b40821);
a = GG(a, b, c, d, x[k + 1], S21, 0xf61e2562);
d = GG(d, a, b, c, x[k + 6], S22, 0xc040b340);
c = GG(c, d, a, b, x[k + 11], S23, 0x265e5a51);
b = GG(b, c, d, a, x[k + 0], S24, 0xe9b6c7aa);
a = GG(a, b, c, d, x[k + 5], S21, 0xd62f105d);
d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = GG(c, d, a, b, x[k + 15], S23, 0xd8a1e681);
b = GG(b, c, d, a, x[k + 4], S24, 0xe7d3fbc8);
a = GG(a, b, c, d, x[k + 9], S21, 0x21e1cde6);
d = GG(d, a, b, c, x[k + 14], S22, 0xc33707d6);
c = GG(c, d, a, b, x[k + 3], S23, 0xf4d50d87);
b = GG(b, c, d, a, x[k + 8], S24, 0x455a14ed);
a = GG(a, b, c, d, x[k + 13], S21, 0xa9e3e905);
d = GG(d, a, b, c, x[k + 2], S22, 0xfcefa3f8);
c = GG(c, d, a, b, x[k + 7], S23, 0x676f02d9);
b = GG(b, c, d, a, x[k + 12], S24, 0x8d2a4c8a);
a = HH(a, b, c, d, x[k + 5], S31, 0xfffa3942);
d = HH(d, a, b, c, x[k + 8], S32, 0x8771f681);
c = HH(c, d, a, b, x[k + 11], S33, 0x6d9d6122);
b = HH(b, c, d, a, x[k + 14], S34, 0xfde5380c);
a = HH(a, b, c, d, x[k + 1], S31, 0xa4beea44);
d = HH(d, a, b, c, x[k + 4], S32, 0x4bdecfa9);
c = HH(c, d, a, b, x[k + 7], S33, 0xf6bb4b60);
b = HH(b, c, d, a, x[k + 10], S34, 0xbebfbc70);
a = HH(a, b, c, d, x[k + 13], S31, 0x289b7ec6);
d = HH(d, a, b, c, x[k + 0], S32, 0xeaa127fa);
c = HH(c, d, a, b, x[k + 3], S33, 0xd4ef3085);
b = HH(b, c, d, a, x[k + 6], S34, 0x4881d05);
a = HH(a, b, c, d, x[k + 9], S31, 0xd9d4d039);
d = HH(d, a, b, c, x[k + 12], S32, 0xe6db99e5);
c = HH(c, d, a, b, x[k + 15], S33, 0x1fa27cf8);
b = HH(b, c, d, a, x[k + 2], S34, 0xc4ac5665);
a = II(a, b, c, d, x[k + 0], S41, 0xf4292244);
d = II(d, a, b, c, x[k + 7], S42, 0x432aff97);
c = II(c, d, a, b, x[k + 14], S43, 0xab9423a7);
b = II(b, c, d, a, x[k + 5], S44, 0xfc93a039);
a = II(a, b, c, d, x[k + 12], S41, 0x655b59c3);
d = II(d, a, b, c, x[k + 3], S42, 0x8f0ccc92);
c = II(c, d, a, b, x[k + 10], S43, 0xffeff47d);
b = II(b, c, d, a, x[k + 1], S44, 0x85845dd1);
a = II(a, b, c, d, x[k + 8], S41, 0x6fa87e4f);
d = II(d, a, b, c, x[k + 15], S42, 0xfe2ce6e0);
c = II(c, d, a, b, x[k + 6], S43, 0xa3014314);
b = II(b, c, d, a, x[k + 13], S44, 0x4e0811a1);
a = II(a, b, c, d, x[k + 4], S41, 0xf7537e82);
d = II(d, a, b, c, x[k + 11], S42, 0xbd3af235);
c = II(c, d, a, b, x[k + 2], S43, 0x2ad7d2bb);
b = II(b, c, d, a, x[k + 9], S44, 0xeb86d391);
a = AddUnsigned(a, AA);
b = AddUnsigned(b, BB);
c = AddUnsigned(c, CC);
d = AddUnsigned(d, DD);
k += 16;
}
temp = WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
return temp.toLowerCase();
}
function getImageUrl(filename) {
var hex = md5(filename);
return [
'https://huiji-public.huijistatic.com/' +
mw.config.get('wgHuijiPrefix') +
'/uploads',
hex[0],
hex[0] + hex[1],
filename
].join('/');
}
function parseNumPairParam(param) {
var paramList = param.split(',');
var result = [];
$.each(paramList, function(index, value) {
result.push(Number(value));
});
return result;
}
var NamePatternRegex = /\$x|\$y|\$z/g;
leaflet.TileLayer.CustomLayer = leaflet.TileLayer.extend({
getTileUrl: function(coords) {
var x = coords.x,
y = coords.y,
z = this._getZoomForUrl();
var fileName = this.options.namingPattern.replace(
NamePatternRegex,
function(m) {
var subst = {
$x: x,
$y: y,
$z: z
};
return subst[m];
}
);
return getImageUrl(fileName);
}
});
leaflet.tileLayer.customLayer = function(templateUrl, options) {
return new leaflet.TileLayer.CustomLayer(templateUrl, options);
};
function loadMap(mapInfo) {
if ($('#' + mapInfo.mapId).height() < 300) {
$('#' + mapInfo.mapId).height(300);
}
var saveButton = leaflet.easyButton({
position: 'topright',
states: [
{
stateName: 'need-save',
icon: 'fa fa-save',
title: '发现改动,点此保存',
onClick: function(btn, map) {
if (!mapInfo.needSave) {
return;
}
// save marker data
mapInfo.needSave = false;
btn.state('saving-data');
var newMarkerData = {};
newMarkerData.markers = getMarkerData(mapInfo);
var queryData = {
format: 'json',
action: 'edit',
contentformat: 'application/json',
title: mapInfo.markerPage,
summary: '更新地图标记信息',
text: JSON.stringify(newMarkerData),
minor: true,
token: mw.user.tokens.get('csrfToken')
};
requestWithCallback(
queryData,
mapInfo,
function(data, mapInfo) {
btn.state('need-save');
btn.disable();
},
'POST',
function(data, mapInfo) {
console.log('请求过程中出现错误!');
mapInfo.needSave = true;
btn.enable();
btn.state('need-save');
}
);
}
},
{
stateName: 'saving-data',
icon: 'fa fa-spin fa-cog',
title: '保存数据中,请稍候',
onClick: function(btn, map) {
// do nothing
}
}
]
});
saveButton.disable();
var toogleMarkerButton = leaflet.easyButton({
position: 'topleft',
states: [
{
stateName: 'show',
icon: 'fa fa-eye',
title: '点此隐藏标记',
onClick: function(btn, map) {
map.removeLayer(mapInfo.markersLayerGroup);
btn.state('hide');
}
},
{
stateName: 'hide',
icon: 'fa fa-eye-slash',
title: '点此显示标记',
onClick: function(btn, map) {
map.addLayer(mapInfo.markersLayerGroup);
btn.state('show');
}
}
]
});
var helpButton = leaflet.easyButton({
position: 'topright',
states: [
{
stateName: 'always',
icon: 'fa fa-question',
title: '查看地图使用说明',
onClick: function(btn, map) {
$('#map-help-info').modal('show');
}
}
]
});
var layer, bounds, minZoom, options;
if (mapInfo.mode === MODE.OVERLAY) {
bounds = [
[0, 0],
[mapInfo.imageHeight, mapInfo.imageWidth]
];
minZoom = -5;
options = {
attribution: '查看<a href="/wiki/File:' + mapInfo.image + '">原图</a>'
};
layer = leaflet.imageOverlay(mapInfo.imageUrl, bounds, options);
if (!mapInfo.initialZoom) {
mapInfo.initialZoom = 0;
}
if (!mapInfo.initialLocY) {
mapInfo.initialLocY = mapInfo.imageHeight / 2;
}
if (!mapInfo.initialLocX) {
mapInfo.initialLocX = mapInfo.imageWidth / 2;
}
} else {
var tileBounds = parseNumPairParam(mapInfo.tileBounds);
var tileZoom = parseNumPairParam(mapInfo.tileZoom);
var tileSize = parseNumPairParam(mapInfo.tileSize);
var scale = Math.pow(2, tileZoom[1]);
bounds = [
[0 - tileBounds[1] / scale, 0],
[0, tileBounds[0] / scale]
];
minZoom = tileZoom[0];
options = {
tileSize: leaflet.point(tileSize[0], tileSize[1]),
minZoom: minZoom,
maxZoom: tileZoom[1],
bounds: bounds,
namingPattern: mapInfo.tileTemplate,
attribution: ''
};
layer = leaflet.tileLayer.customLayer('', options);
if (!mapInfo.initialZoom) {
mapInfo.initialZoom = minZoom;
}
if (!mapInfo.initialLocY) {
mapInfo.initialLocY = bounds[0][0] / 2;
}
if (!mapInfo.initialLocX) {
mapInfo.initialLocX = bounds[1][1] / 2;
}
}
var map = leaflet.map(mapInfo.mapId, {
crs: leaflet.CRS.Simple,
minZoom: minZoom,
maxBounds: bounds,
contextmenu: true,
contextmenuItems: [
{
text:
'<i class="fa fa-map-marker" aria-hidden="true"></i> 添加标记',
callback: function(event) {
this.mapMarkerEditor.loadMarkerInfo(
'',
'',
event.latlng.lat,
event.latlng.lng
);
this.mapMarkerEditor.show();
}
}
]
});
map.setView(
[mapInfo.initialLocY, mapInfo.initialLocX],
mapInfo.initialZoom
);
// add controls to map object for easier access
map.mapInfo = mapInfo;
map.saveButton = saveButton;
// setup marker editor
var mapMarkerEditor = new markerEditor(map);
mapMarkerEditor.init();
map.mapMarkerEditor = mapMarkerEditor;
layer.addTo(map);
saveButton.addTo(map);
helpButton.addTo(map);
toogleMarkerButton.addTo(map);
// preload icon info then load markers
preLoadIconInfo(mapInfo);
setTimeout(function() {
mapInfo.markersLayerGroup = leaflet.layerGroup();
for (var m in mapInfo.markerData) {
addMarker(
map,
mapInfo,
mapInfo.markerData[m].coords.x,
mapInfo.markerData[m].coords.y,
mapInfo.markerData[m].tooltip,
mapInfo.markerData[m].markerImage
);
}
mapInfo.markersLayerGroup.addTo(map);
}, 1000);
}
// preload icon info
function preLoadIconInfo(mapInfo) {
for (var m in mapInfo.markerData) {
if (
typeof iconMap[mapInfo.markerData[m].markerImage] === 'undefined' &&
mapInfo.markerData[m].markerImage
) {
// mark the properties which need to be loaded with icon info later on
iconMap[mapInfo.markerData[m].markerImage] = 'ready';
}
}
var keys = Object.keys(iconMap);
if (keys.length === 0) {
return;
}
var icons = {
titles: [],
names: []
};
for (var i = 0, l = keys.length; i < l; i++) {
if (iconMap[keys[i]] !== 'ready') {
continue;
}
iconMap[keys[i]] = 'started';
icons.titles.push('File:' + keys[i]);
icons.names.push(keys[i]);
}
var queryData = {
action: 'query',
format: 'json',
prop: 'imageinfo',
titles: icons.titles.join('|'),
formatversion: '2',
iiprop: 'url|dimensions'
};
requestWithCallback(
queryData,
icons,
function(data, icons) {
var pages = data.query.pages;
var normalized = data.query.normalized;
var namePairs = {};
for (var i in icons.titles) {
for (var ii in normalized) {
if (normalized[ii].from === icons.titles[i]) {
namePairs[normalized[ii].to] = icons.names[i];
break;
}
}
}
for (var p in pages) {
if (pages.hasOwnProperty(p)) {
if (pages[p].hasOwnProperty('missing')) {
continue;
} else {
iconMap[namePairs[pages[p].title]] = {
url: pages[p].imageinfo[0]['url'],
width: pages[p].imageinfo[0]['width'],
height: pages[p].imageinfo[0]['height']
};
}
}
}
},
'GET',
function(xhr, icons) {
for (var i in icons.names) {
iconMap[icons.names[i]] = 'ready';
}
}
);
}
// define an object to handle marker info editing
function markerEditor(map) {
this.mapInfo = map.mapInfo;
this.map = map;
// editor mode: true - create marker; false - edit marker
var mode = false;
var markerCoords = {
x: undefined,
y: undefined
};
var _marker = undefined;
var markerImageIdSelector = '#' + map.mapInfo.mapId + '-markerImage';
var tooltipIdSelector = '#' + map.mapInfo.mapId + '-markerTooltip';
var confirmIdSelector = '#' + map.mapInfo.mapId + '-confirm';
var editorIdSelector = '#' + map.mapInfo.mapId + '-markerEditor';
this.init = function() {
$('body').append(
'<div id="' +
map.mapInfo.mapId +
'-markerEditor"class="modal fade"data-markerIndex="-1"><div class="modal-dialog"role="document"><div class="modal-content"><div class="modal-header"><h3 class="modal-title"style="font-size:18px;">编辑标记信息</h5></div><div class="modal-body"><form><div class="form-group"><label for="marker-image-name"class="form-control-label">标记图片名:</label><input id="' +
map.mapInfo.mapId +
'-markerImage"type="text"class="form-control"placeholder="请输入完整图片名,如“我的图片.png”,留空则使用默认标记"></div><div class="form-group"><label for="marker-tooltip"class="form-control-label">标记提示信息:</label><textarea id="' +
map.mapInfo.mapId +
'-markerTooltip"type="text"class="form-control"rows="5"placeholder="此处输入描述文字,文字中可以使用简单的内链,如[[XXX|XX]]和[[XXX]]"></textarea></div></form></div><div class="modal-footer"><button id="' +
map.mapInfo.mapId +
'-confirm"type="button"class="btn btn-primary">保存更改</button><button type="button"class="btn btn-secondary"data-dismiss="modal">关闭</button></div></div></div></div>'
);
$(confirmIdSelector).click(function(event) {
var markerImage = $(markerImageIdSelector).val();
var tooltip = $(tooltipIdSelector).val();
if (!mode) {
// edit marker
if (!tooltip) {
_marker.unbindPopup();
} else {
_marker.bindPopup(escapeInput(tooltip));
}
_marker.tooltip = tooltip;
_marker.markerImage = markerImage;
loadCustomMarkerIcon(_marker);
} else {
// create marker
addMarker(
map,
map.mapInfo,
markerCoords.x,
markerCoords.y,
tooltip,
markerImage
);
map.mapInfo.needSave = true;
map.saveButton.enable();
}
map.mapInfo.markerData = getMarkerData(map.mapInfo);
map.mapInfo.needSave = true;
map.saveButton.enable();
map.saveButton.state('need-save');
$(editorIdSelector).modal('hide');
});
};
// load existed marker
this.loadMarker = function(marker) {
_marker = marker;
$(markerImageIdSelector).val(marker.markerImage);
$(tooltipIdSelector).val(marker.tooltip);
mode = false;
};
// load marker info (create marker)
this.loadMarkerInfo = function(markerImage, markerTooltip, x, y) {
$(markerImageIdSelector).val(markerImage);
$(tooltipIdSelector).val(markerTooltip);
markerCoords.x = x;
markerCoords.y = y;
mode = true;
};
this.show = function() {
$(editorIdSelector).modal('show');
};
this.hide = function() {
$(editorIdSelector).modal('hide');
};
}
// load the marker icon set by marker.markerImage; revert to default icon if url is not found
function loadCustomMarkerIcon(marker) {
var markerImage = marker.markerImage;
if (!markerImage) {
marker.setIcon(defaultIcon);
return;
}
if (typeof iconMap[markerImage] === 'object') {
var customIcon = leaflet.icon({
iconUrl: iconMap[markerImage].url,
iconSize: [iconMap[markerImage].width, iconMap[markerImage].height],
iconAnchor: [
iconMap[markerImage].width / 2,
iconMap[markerImage].height / 2
],
popupAnchor: [0, 0 - iconMap[markerImage].height / 2],
tooltipAnchor: [iconMap[markerImage].width / 2, 0]
});
marker.setIcon(customIcon);
return;
}
var queryData = {
action: 'query',
format: 'json',
prop: 'imageinfo',
titles: 'File:' + markerImage,
formatversion: '2',
iiprop: 'url|dimensions'
};
requestWithCallback(queryData, undefined, function(data, undefined) {
var pages = data.query.pages;
var pageid;
for (var p in pages) {
if (pages.hasOwnProperty(p)) {
if (pages[p].hasOwnProperty('missing')) {
marker.setIcon(defaultIcon);
return;
} else {
pageid = p;
break;
}
}
}
var markerImageUrl = pages[pageid].imageinfo[0]['url'];
var markerImageWidth = pages[pageid].imageinfo[0]['width'];
var markerImageHeight = pages[pageid].imageinfo[0]['height'];
var customIcon = leaflet.icon({
iconUrl: markerImageUrl,
iconSize: [markerImageWidth, markerImageHeight],
iconAnchor: [markerImageWidth / 2, markerImageHeight / 2],
popupAnchor: [0, 0 - markerImageHeight / 2],
tooltipAnchor: [markerImageWidth / 2, 0]
});
marker.setIcon(customIcon);
iconMap[markerImage] = {
url: markerImageUrl,
width: markerImageWidth,
height: markerImageHeight
};
});
}
function getMarkerData(mapInfo) {
var markerData = [];
var layers = mapInfo.markersLayerGroup.getLayers();
for (var m in layers) {
markerData.push({
coords: {
x: layers[m].getLatLng().lat,
y: layers[m].getLatLng().lng
},
tooltip: layers[m].tooltip,
markerImage: layers[m].markerImage
});
}
return markerData;
}
function addMarker(map, mapInfo, x, y, tooltip, markerImage) {
var marker = leaflet.marker([x, y], {
draggable: true,
icon: defaultIcon,
contextmenu: true,
contextmenuInheritItems: false,
contextmenuItems: [
{
text:
'<i class="fa fa-pencil-square" aria-hidden="true"></i> 编辑标记',
callback: function(event) {
this.mapMarkerEditor.loadMarker(event.relatedTarget);
this.mapMarkerEditor.show();
}
},
{
text: '<i class="fa fa-trash" aria-hidden="true"></i> 删除标记',
callback: function(event) {
removeMarker(this, this.mapInfo, event.relatedTarget);
this.mapInfo.needSave = true;
this.saveButton.enable();
}
}
]
});
marker.on('dragend', function(event) {
mapInfo.markerData = getMarkerData(mapInfo);
mapInfo.needSave = true;
map.saveButton.enable();
});
marker.on('mousedown', function(event) {
if (event.originalEvent.ctrlKey) {
mapInfo.markersLayerGroup.addLayer(
cloneMarker(event.latlng.lat, event.latlng.lng, marker, map, mapInfo)
);
}
});
if (tooltip) {
marker.bindPopup(escapeInput(tooltip));
}
marker.tooltip = tooltip;
marker.markerImage = markerImage;
loadCustomMarkerIcon(marker);
mapInfo.markersLayerGroup.addLayer(marker);
}
function cloneMarker(lat, lng, marker, map, mapInfo) {
var newMarker = leaflet.marker([lat, lng], marker.options);
newMarker.on('dragend', function(event) {
mapInfo.markerData = getMarkerData(mapInfo);
mapInfo.needSave = true;
map.saveButton.enable();
});
newMarker.on('mousedown', function(event) {
if (event.originalEvent.ctrlKey) {
mapInfo.markersLayerGroup.addLayer(
cloneMarker(event.latlng.lat, event.latlng.lng, marker, map, mapInfo)
);
}
});
if (marker.tooltip) {
newMarker.bindPopup(escapeInput(marker.tooltip));
}
newMarker.tooltip = marker.tooltip;
newMarker.markerImage = marker.markerImage;
return newMarker;
}
function removeMarker(map, mapInfo, marker) {
var index = mapInfo.markersLayerGroup.getLayerId(marker);
if (index > -1) {
mapInfo.markersLayerGroup.removeLayer(index);
}
mapInfo.markerData = getMarkerData(mapInfo);
}
function ucFirst(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
function escapeInput(input) {
return $('<span/>')
.text(input)
.wrap('<span/>')
.parent()
.text()
.replace(/\[\[(.+?)\]\]/g, function(match, p1, offset, string) {
var result = /([^\|]+)\|(.+)/.exec(p1);
if (result === null) {
return $('<a/>')
.attr('href', '/wiki/' + p1)
.text(p1)
.wrap('<span/>')
.parent()
.html();
} else {
return $('<a/>')
.attr('href', '/wiki/' + result[1])
.text(result[2])
.wrap('<span/>')
.parent()
.html();
}
})
.replace(/\n/g, '<br/>');
}
})(L, mediaWiki, jQuery);
//</nowiki>