User:Khanson/editsuggest.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Khanson/editsuggest. |
//script config
var es_namespaces = [0, 10, 14, 6]
var es_namespaces_names = {0: '', 6:'Image', 10:'\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0{\{\u00A0',
14:'Category'}
if (wgContentLanguage == 'ru') {
es_namespaces_names[14] = 'Категория'
es_namespaces_names[6] = 'Изображение'
}
var editSuggest = new function(){ //global wrapper
var esForm, esText, linkName, esNS, isCtrlOrShift, txtBox, keyPrev
var selRange, selScroll, selWorking
this.start = function(){
if (!esForm) init()
if (esForm.style.display == 'none'){
esText.value = getWikiText()
setNS(0)
showForm(true)
}else{
focusTextarea() //second click - hide form
}
}
this.insert = ev_onsubmit
function init(){
txtBox = document.getElementById('wpTextbox1')
//create form
esForm = document.createElement('form')
esForm.id = 'es_form'
esForm.action = 'javascript:editSuggest.insert()'
esForm.style.cssText = 'position:absolute; z-index:100; border:1px solid gray; padding:1px; background:#E0E0E0; opacity:0.8'
//try { esForm.style.background = 'inherit'} catch(e){esForm.style.background = 'white'} //damn IE
//add label
var lbl = document.createElement('span')
lbl.id = 'es_label'
lbl.style.cssText = 'background:inherit; width:2em; font-size:125%; cursor:pointer; padding-right:5px'
addHandler(lbl, 'click', cycleNS)
esForm.appendChild(lbl)
//add text field
esText = appendInput('text', 'es_text', 'width:350px')
esText.tabIndex = 0
addHandler(esText, 'keydown', ev_onkeydown)
addHandler(esText, 'keyup', ev_onkeyup)
//add NS field
esNS = appendInput('hidden', 'es_namespace')
esNS.value = 1
//position form
var pos = os_getElementPosition('wpTextbox1')
esForm.style.top = (pos.top +2)+'px'
esForm.style.left = (pos.left+2)+'px'
//attach form and enable autosuggest
document.body.appendChild(esForm)
os_enableSuggestionsOn('es_text', 'es_form')
os_createContainer(os_map['es_text'])
esForm.style.display = 'none' //so it's not hidden by ev_onfocusTextarea
return
function appendInput(type, id, css){
var inp = document.createElement('input')
inp.type = type
if (id) inp.id = inp.name = id
if (css) inp.style.cssText = css
esForm.appendChild(inp)
return inp
}
}
// *** METHODS ***
function showForm(isOn){
isOn = isOn==true
esText.disabled = !isOn
esForm.style.display = isOn ? '' : 'none'
var el = document.getElementById('es_textSuggest')
if (el) el.style.display = isOn ? '' : 'none' //"hidden" is not enouugh here: text cursor disappears under it in Firefox
if (isOn){
esText.focus()
esText.select()
fetchResults()
setTimeout(setTextareaFocusHandler, 20) //if we set it now, weird IE6 will execute it
}else{
delHandler(txtBox, 'focus', ev_onfocusTextarea)
}
}
function setTextareaFocusHandler(){ addHandler(txtBox, 'focus', ev_onfocusTextarea) }
function getWikiText(){ //returns target to search, remembers link name
linkName = selGet()
var targ, ma
if (ma=linkName.match(/ *\[\[([^\]\|]+)\|?([^\]]+)?\]\] */)){ //user selected existing wikilink
targ = ma[1]; linkName = ma[2] || ''
}else
targ = linkName
return targ.replace(/́/g,'').replace(/ +$/, '') //remove accent and spaces at the end
}
function fetchResults(){
var r = os_map['es_text']
//r.query = '---' //null old query so the results are always shown
r.original = ''
//injectSpinner(esText, 'es')
os_fetchResults(r, esText.value, 0)
}
function setWikiText(targ, name){
//remove space at the end
var isSpace = / +$/.test(name)
if (isSpace) name = name.replace(/ +$/, '')
var txt
if (getNS() == 10){ //template
txt = '{\{' + targ.substring(targ.indexOf(':')) + '|' + name + '}}'
}else{ //construct wiki link
txt = '[\['
if (normalize(name).indexOf(normalize(targ)) == 0) //target is substring
txt += name.substring(0, targ.length) + ']]' + name.substring(targ.length)
else //target is different
txt += targ + '|' + name + ']]'
}
//insert link
if (isSpace) txt += ' '
selSet(txt, true)
}
function focusSuggest(){esText.focus()}
function focusTextarea(){txtBox.focus(); selSelect()}
function setNS(ns){
esNS.name = 'ns' + ns
if (typeof es_namespaces_names[ns] != 'undefined') ns = es_namespaces_names[ns]
document.getElementById('es_label').innerHTML = ns
}
function getNS(){
var ns = esNS.name
return ns = ns ? ns.substring(2) : 0
}
function cycleNS(){
var ns = getNS()
for (var i=0; i<es_namespaces.length; i++) if (ns == es_namespaces[i]) break //find it in the list
i++; if (i >= es_namespaces.length) i = 0 //get next in the list
setNS(es_namespaces[i]) //set new namespace
}
// *** EVENTS ***
function ev_onkeydown(e){
e = e || window.event
var key = (window.Event) ? e.which : e.keyCode
switch (key){
//Ctrl or Shift
case 16: case 17: isCtrlOrShift = true; break
//Escape
case 27:
//if (keyPrev==27 || !esText.value)
setTimeout(focusTextarea, 50)
//else setTimeout(focusSuggest, 50) // bring cursor back after Escape, mwsuggest Opera issue
break
}
keyPrev = key
//if (key == 9) focusTextarea() //Tab
}
function ev_onfocusTextarea(){
if (esForm && (esForm.style.display != 'none')) setTimeout(showForm, 20)
}
function ev_onkeyup(e){
e = e || window.event
var key = (window.Event) ? e.which : e.keyCode
switch (key){
/*Ctrl or Shift*/ case 16: case 17: isCtrlOrShift = false; break
// /*Escape*/ case 27: //e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation() //break
/*Space*/ case 32: if (!esText.value.replace(/ /g,'')){ cycleNS(); esText.value = ''}; break
/*PgDnl*/ case 34: /*ScrollLock*/ case 145: cycleNS(); fetchResults(); break
}
}
function ev_onsubmit(e){
if (isCtrlOrShift){
window.open (mw.config.get('wgServer') + mw.config.get('wgArticlePath').replace('\$1', esText.value))
}else{
setWikiText(esText.value, linkName)
showForm(false)
setTimeout(focusTextarea, 100)
}
return
}
// *** misc ***
function normalize(tt){ return (tt.substring(0,1).toUpperCase() + tt.substring(1)).replace(/_/g, ' ') }
function delHandler(element, event, handler){
if (window.removeEventListener) element.removeEventListener(event, handler, false)
else if (window.detachEvent) element.detachEvent('on' + event, handler)
}
//cross-browser textarea selection, need txtBox var
function selGet(){
if (document.selection) { //IE/Opera
selScroll = document.documentElement.scrollTop
txtBox.focus()
selRange = document.selection.createRange()
return selRange.text
}else if (txtBox.selectionStart || txtBox.selectionStart == '0') { // Mozilla
selScroll = txtBox.scrollTop
//this.selStart = txtBox.selectionStart
//txtBox.focus()
return txtBox.value.substring(txtBox.selectionStart, txtBox.selectionEnd)
}else return null
}
function selSelect(){ if(selRange) selRange.select() } //for IE only
function selSet(txt, isSelect){
txtBox.focus()
if (document.selection) { //IE/Opera
selRange.text = txt
selRange.select()
//no need to restore scroll if the action is not instant
//document.documentElement.scrollTop = this.selScroll //restore window scroll position
}else if (txtBox.selectionStart || txtBox.selectionStart == '0') { // Mozilla
var p1 = txtBox.selectionStart, p2 = txtBox.selectionEnd
txtBox.value = txtBox.value.substring(0, p1) + txt + txtBox.value.substring(p2, txtBox.value.length)
txtBox.selectionStart = p1 + txt.length //restore cursor position at end
txtBox.selectionEnd = txtBox.selectionStart
txtarea.scrollTop = selScroll //restore txtarea scroll
}
if (isSelect) selMove (-txt.length)
}
function selMove(mv1, mv2){
if (document.selection) { //IE/Opera
if (!selRange.moveStart) return
if (mv1) selRange.moveStart('character', mv1)
if (mv2) selRange.moveEnd ('character', mv2)
}else if (txtBox.selectionStart || txtBox.selectionStart == '0') { // Mozilla
if (mv1) txtBox.selectionStart += mv1
if (mv2) txtBox.selectionEnd += mv2
}
}
}
if (window.wgMWSuggestTemplate && (wgAction=='edit' || wgAction=='submit'))
addOnloadHook(editSuggestButton)
function editSuggestButton(){
var tlb = document.getElementById('toolbar')
if (!tlb) return
var btn = document.createElement('input'); btn.type = 'button'
btn.style.cssText = 'background:#adbede; height:22px; vertical-align:middle; padding:0'
btn.value = '[\[↓]]'; btn.title = 'Suggest link'
btn.onclick = editSuggest.start; btn.id = 'editSuggest'
tlb.appendChild(btn)
if (window.es_accesskey){
btn.accessKey = es_accesskey
btn.title += ' ['+es_accesskey+']'
updateTooltipAccessKeys([btn])
}
}