User:Artoria2e5/Gadget-PRCoords.js

维基百科,自由的百科全书

注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。

// <nowiki>
/**
 * Gadget for PRCoords (People's Rectified Coordinates)
 * @file Gadget for inserting valid WGS-84 coords from GCJ-02/BD-09 input
 * @author User:Artoria2e5
 * @see [[User:Artoria2e5/PRCoords.js]]
 * @see [[:en:User:V111P/js/addToolbarButtons]]
 * @license CC0
 * 
 * Install it, edit something, select the coords (see Chinese howto #3), and
 * click the button.
 * 
 * 
 * 如何安装:
 * 1. 将这行加入[[User:<您的用户名>/common.js]]:
 *    importScript('User:Artoria2e5/Gadget-PRCoords.js') // [[User:Artoria2e5/Gadget-PRCoords.js]]
 * 
 * 如何使用:
 * 1. 使用GeoHack的卫星图或OpenStreetMap地图确认条目的坐标,若正确则无需处理。
 *    也可以检查地点是否碰巧在已知有偏移的地图上显示正确。若显示“正确”说明地点的
 *    位置信息也存在偏移,需要修正。
 * 2. 进入源码编辑。编辑工具栏上会出现两个长得一样的按钮(懒得上传不一样的了),
 *    鼠标放上去会显示是 gcj02 还是 bd09。
 *    后者基本只用于百度地图,前者见于其他的地图服务商。
 * 3. 找到您想要转换的坐标,如:
 *      {{coord|121.3213|31.9320}}
 *      {{coord|121|19|17|N|31|55|55|E}}
 *    本工具也支持较短的度数、度分格式。
 * 4. 选中中间的坐标部分,如“121.3213|31.9320”、“121|19|17|N|31|55|55|E”.
 *    复制坐标,以备第 7a 步重试。
 * 5. 按照提示的算法类型文字,点选两个按钮中的一个。
 * 6. 坐标会被直接换掉,Ctrl-Z不可撤销(因此建议选中时复制一下)。
 *    目前版本会判断度分秒格式,并输出一样的格式。
 *    格式转换其实可以拿出来做个功能。
 * 7. 预览条目,使用GeoHack的Bing或Google卫星图确认得到的坐标。
 *   a. 若不正确,粘贴恢复之前复制的坐标,尝试另一个转换模式。
 * 8. 清理小数点和摘要框。維基百科一般留 4 位經緯度小數,「秒」值則留到整數。
 * 
 * <pre>
 * 如何传教:
 * 1. 使用 WikiBlame (wikipedia.ramselehof.de/wikiblame.php?lang=zh) 在刚才修好
 *    的页面最近的 4096 次编辑中寻找加入了 "{{Coord" 的。
 * 2. 点进编辑。记下版本号。
 * 3. 跑到做出编辑的人的讨论页。
 * 4. 甩模板:
      {{subst:User:Artoria2e5/coord-notice
      |diff=11223344 <!-- 改成版本号 -->
      |type=GCJ-02   <!-- 改成混淆方法:GCJ-02/BD-09 -->
  	  |add=(被 Google 整了您这是?)}} <!-- 可选 -->
 * 5. 发布编辑。
 * </pre>
 * TODO:
 * We will eventually get some Bing satellite gadget GUI done some day.
 * Use [[User:Vanished_user_1929210/js/lib/EditorAPIs.js]] for VE, maybe.
 */

var coordInfo = {
	'N': [+1, 'lat'],
	'S': [-1, 'lat'],
	'E': [+1, 'lon'],
	'W': [-1, 'lon'],
}

var coordBack = {
	'+lat': 'N',
	'-lat': 'S',
	'+lon': 'E',
	'-lon': 'W',
}

/**
 * Attempts to parse all of these forms, minus extra params and '{{coord|':
 * {{coord|latitude|longitude|coordinate parameters|template parameters}}
 * {{coord|dd|N/S|dd|E/W|coordinate parameters|template parameters}}
 * {{coord|dd|mm|N/S|dd|mm|E/W|coordinate parameters|template parameters}}
 * {{coord|dd|mm|ss|N/S|dd|mm|ss|E/W|coordinate parameters|template parameters}}
 */
function parseCoord(seg) {
	var opts = seg.split('|')
	if (opts[opts.length - 1] == '')
		opts.length -= 1
	if (opts[0] == '')
		opts.shift()
	
	switch (opts.length) {
		case 2:
			return {
				lat: +opts[0],
				lon: +opts[1],
				format: 'dec',
			}
		case 4:
			return {
				lat: dmsToDec(opts[0], 0, 0, opts[1], 'lat'),
				lon: dmsToDec(opts[2], 0, 0, opts[3], 'lon'),
				format: 'd',
			}
		case 6:
			return {
				lat: dmsToDec(opts[0], opts[1], 0, opts[2], 'lat'),
				lon: dmsToDec(opts[3], opts[4], 0, opts[5], 'lon'),
				format: 'dm',
			}
		case 8:
			return {
				lat: dmsToDec(opts[0], opts[1], opts[2], opts[3], 'lat'),
				lon: dmsToDec(opts[4], opts[5], opts[6], opts[7], 'lon'),
				format: 'dms',
			}
		default:
			throw new RangeError("opts contains" + opts.length + "elements?")
	}
}

function dmsToDec(d, m, s, hemisphere = 'N', type = '') {
	if (type !== '') {
		if (coordInfo[hemisphere][1] !== type) {
			throw new RangeError('' + hemisphere + ' ' + type)
		}
	}
	return coordInfo[hemisphere][0] * ((+d) + (+m)/60 + (+s)/3600)
}

function decToDmsParams(dec, type) {
	var sign = (+dec) >= 0 ? 1 : -1
	var hemi = coordBack[(sign == -1 ? '-' : '+') + type]
	
	dec *= sign
	var d = Math.floor(dec)
	var m = Math.floor((dec-d)*60)
	var s = Math.round((dec-d-m/60)*3600*1e3)/1e3
	
	return [d, m, s, hemi].join('|')
}

function reformat(seg, func = 'gcj_wgs') {
	var coords = parseCoord(seg)
	var newCoords = PRCoords[func](coords)
	
	switch (coords.format) {
		case "dms":
		case "dm":
			return [decToDmsParams(newCoords.lat, 'lat'),
					decToDmsParams(newCoords.lon, 'lon')].join('|')
		default:
			// unexpected -- log it
			console.log(coords.format)
		case "dec":
		case "d":
			return [newCoords.lat, newCoords.lon].map(function(i) {
				return Math.round(i*1e6)/1e6
			}).join('|')
	}
}

if (['edit', 'submit'].indexOf(mw.config.get('wgAction')) !== -1) {
;mw.loader.using([
	'jquery.textSelection',
	'jquery.ui',
	'ext.wikiEditor',
]).then(function(){	// MW loader callback
$(function(){
"use strict"

mw.loader.load('https://zh.wikipedia.org/w/index.php?title=User:Artoria2e5/PRCoords.js&action=raw&ctype=text/javascript')
// The following trivial translation-associated routines are dedicated to the
// public domain under CC0 1.0.

// non-recursive fetching
var translation_fetch = {
	'zh-cn': ['zh-cn', 'zh-sg', 'zh-tw', 'zh-hk', 'zh-mo'],
	'zh-hans': ['zh-cn', 'zh-sg', 'zh-tw', 'zh-hk', 'zh-mo'],
	'zh-sg': ['zh-sg', 'zh-cn', 'zh-tw', 'zh-hk', 'zh-mo'],
	
	'zh-tw': ['zh-tw', 'zh-hk', 'zh-mo', 'zh-cn', 'zh-sg'],
	'zh-hant': ['zh-tw', 'zh-hk', 'zh-mo', 'zh-cn', 'zh-sg'],
	'zh-hk': ['zh-hk', 'zh-mo', 'zh-tw', 'zh-cn', 'zh-sg'],
	'zh-mo': ['zh-mo', 'zh-hk', 'zh-tw', 'zh-cn', 'zh-sg'],
}

// @config UI Locale (defaults to autodetection for current page)
var UILocale = mw.config.get("wgUserVariant") || mw.config.get("wgUserLanguage") || 'en'
UILocale = UILocale.toLowerCase()

// The text messages are probably not PD.
var messages = {
	'zh-cn': {
		'%1 conv': '%1转换',
		'Rectifying Chinese coordinates with [[User:Artoria2e5/Gadget-PRCoords.js]]: ':
			'使用[[User:Artoria2e5/Gadget-PRCoords.js]]修正中国坐标:',
		' ([not] satellite/osm verified)' :'(已/未经卫星图/OSM确认)'
	},
	'zh-tw': {
		'%1 conv': '%1變換'
	}
}

// Yes, absolutely no plural handling!
function grabT(s) {
	for (var i of (translation_fetch[UILocale] || [])) {
		if (typeof messages[i] !== 'object')
			continue
		if (typeof messages[i][s] !== 'undefined')
			return messages[i][s]
	}
	return s
}

// Now we should start playing with
// https://en.wikipedia.org/wiki/User:V111P/js/addToolbarButtons.js
var textArea = $('#wpTextbox1')
var summary = document.getElementById('wpSummary')
var editedOnce = false
var methods = {
	'gcj': 'GCJ-02',
	'bd' : 'BD-09',
}
function wrapCallback(method) {
	return function(s) {
		try {
			var sel = textArea.textSelection('getSelection')
			sel = sel.replace(/\r/g, '') // IE before 9 doesn't remove the \r's
			textArea.textSelection('encapsulateSelection', {
				pre: reformat(sel, method),
				replace: true
			})
			
			if (!editedOnce)
				summary.value += grabT('Rectifying Chinese coordinates with [[User:Artoria2e5/Gadget-PRCoords.js]]: ')
			
			summary.value += '[[' + methods[method.split('_', 1)[0]] +']]' + grabT(' ([not] satellite/osm verified)')
			editedOnce = true
		} catch (e) {
			alert(e)
		}
	}
}

function makeButton(method) {
	var refmt = function (method) {
		var splits = method.split('_')
		return splits.length >= 2 ? splits.slice(0, 2).join('→') : method;
	}
	return {
		id: 'prcoords_' + method,
		tooltip: grabT('%1 conv').replace('%1', refmt(method)),
		section: 'main',
		group: 'format',
		callback: wrapCallback(method),
		iconUrl: 'https://upload.wikimedia.org/wikipedia/commons/a/ac/Globe%2C_distorted_China.svg',
	}
}

window.toolbarButtonsToAdd = [makeButton('gcj_wgs_bored'), makeButton('bd_wgs_bored')]
if (mw.libs.addToolbarButtons) {
	mw.libs.addToolbarButtons(window.toolbarButtonsToAdd)
	window.toolbarButtonsToAdd = []
} else {
	mw.loader.load('//en.wikipedia.org/w/index.php?title=User:Artoria2e5/js/addToolbarButtons.js&action=raw&ctype=text/javascript')
}

function bing_sat_iframe(lat, lon, width = 500, height = 400) {
	let lats = '' + lat
	let lons = '' + lon
	let ret = document.createElement('iframe')
	
	// sty=h -> labelled (useless)
	ret.setAttribute('width', width)
	ret.setAttribute('height', height)
	ret.setAttribute('frameborder', 0)
	ret.src = 'https://www.bing.com/maps/embed/viewer.aspx?' +
		`v=${zoom}&cp=${lat}~${lon}&lvl=${zoom}&w=${width}&h=${height}&sty=a&typ=d` // '&pp=&ps=&dir=0&mkt=en-us&src=SHELL&form=BMEMJS'
    return ret
}
})})}
// </nowiki>