מדיה ויקי:Gadget-AutoComplete.js: הבדלים בין גרסאות בדף

תוכן שנמחק תוכן שנוסף
ניסוי
ערן (שיחה | תרומות)
מ תמיכה בשליפת פרמטרים לתבנית ומילוי פרמטרים שנתמכים בtemplatedata
שורה 3:
Written by [[משתמש:ערן]]
*/
mw.loader.using(['jquery.ui.widget', 'jquery.ui.autocomplete', 'jquery.textSelection'], function() {
//extends jquery with autoCompleteWikiText functionality for autocomplete of links and templates
$.fn.autoCompleteWikiText = function(options) {
var mode = "none";
var templateDataCache = {};
var ctrl=$(this);
var settingsctrl = $.extend(true, {this);
var settings = $.extend(true, {
positionMy: $('body').is('.rtl') ? "left top" : "right top", // be default, open below the control
positionAt: $('body').is('.rtl') ? "left bottom" : "right bottom",
positionOf: ctrl,
positionOffset: "0",
filterResponse: function(a) {
return a;
}, // function that expects array of string and returns array of strings
menuCSS: {
menuCSS: {width: 'auto', maxHeight: '30em', 'overflow-y': 'auto'},
width: 'auto',
itemCSS: { right: 'inherit' },
maxHeight: '30em',
onselected: function(item){
'overflow-y': 'auto'
var pos=ctrl.textSelection('getCaretPosition')-1;
},
var txt=ctrl.val();
itemCSS: {
var link = mode == "link",
right: 'inherit'
open = link ? "[[" : "{{",
close = link ? "]]" : "|} }",
onselected: function(item) {
caretBackwards = link ? 0 : 2;
var pos = ctrl.textSelection('getCaretPosition') - 1,
switch(mode){
txt = ctrl.val();
case "none": return;
var open, close, caretBackwards;
case "template":
item=item.substr(mw.config.get('wgFormattedNamespaces')[10].length+1);
link = false;
caretBackwards = 2;
break;
case "link":
if(item[item.length-1]==')') item+='|';
break;
}
var lastbegin=txt.lastIndexOf(open, pos);
if (txt[lastbegin + 2] == ':')
item = ':' + item;
 
switch (mode) {
var newTxt=txt.substr(0,lastbegin)+ open +item+ close + txt.substr(pos+1);
case "none":
var orgScroll=ctrl.scrollTop();
return;
ctrl.val(newTxt);
case "templateValue":
ctrl.textSelection('setSelection',{start:lastbegin + (open+item+close).length - caretBackwards});
open = "|";
ctrl.scrollTop(orgScroll);
close = "";
}
caretBackwards = 0;
}, options);
break;
case "templateParams":
open = "|";
close = "=";
caretBackwards = 0;
break;
case "template":
item = item.substr(mw.config.get('wgFormattedNamespaces')[10].length + 1);
caretBackwards = 2;
open = "{{";
close = "|}}";
break;
case "link":
open = "[[";
close = "]]";
caretBackwards = 0;
if (item[item.length - 1] == ')') item += '|';
break;
}
var lastbegin = txt.lastIndexOf(open, pos);
if (txt[lastbegin + 2] == ':')
item = ':' + item;
 
var newTxt = txt.substr(0, lastbegin) + open + item + close + txt.substr(pos + 1);
function findLinks(res){
var orgScroll = ctrl.scrollTop();
var pos=ctrl.textSelection('getCaretPosition')-1;
var txt= ctrl.val(newTxt);
ctrl.textSelection('setSelection', {
start: lastbegin + (open + item + close).length - caretBackwards
});
ctrl.scrollTop(orgScroll);
}
}, options);
 
function findLinks(res) {
var lastbegin=txt.lastIndexOf("[[",pos);
var pos = ctrl.textSelection('getCaretPosition') - 1;
var lastend=txt.lastIndexOf("]]",pos);
var txt = ctrl.val();
var isLink=lastbegin>lastend;
if(isLink) {
fillLinksList(res,txt.substr(lastbegin+2,pos-lastbegin));
mode='link';
}
else{
lastbegin=txt.lastIndexOf("{{",pos);
lastend=txt.lastIndexOf("}}",pos);
var isTemplate=lastbegin>lastend;
if(isTemplate){
var prefixName=mw.config.get('wgFormattedNamespaces')[10]+':'+txt.substr(lastbegin+2,pos-lastbegin);
fillLinksList(res,prefixName);
mode='template';
}
else{
res([]);
mode="none";
}
}
}
 
var lastbegin = txt.lastIndexOf("[[", pos);
function fillLinksList(res,txt){
txt var lastend = $txt.trimlastIndexOf(txt"]]", pos);
var isLink = lastbegin > lastend;
if(txt.length<=1 || txt.indexOf('|')>-1 || (txt.indexOf('#')>-1 && mw.config.get('wgNamespaceNumber')==0)) res([]);
if (isLink) {
else if(txt.indexOf('#')>-1){
mode = 'link';
var pageTitle=txt.substr(0,txt.indexOf('#'));
fillLinksList(res, txt.substr(lastbegin + 2, pos - lastbegin));
var sectionPrefix=txt.substr(txt.indexOf('#')+1);
} else {
$.getJSON(mw.util.wikiScript('api'),{action:'parse',page:pageTitle,prop:'sections',format:'json'},function(data){
lastbegin = txt.lastIndexOf("{{", pos);
if(data && data.parse && data.parse.sections) res($(data.parse.sections).map(function(){return this.line.indexOf(sectionPrefix) ==0 ? (pageTitle+'#'+this.line):null;
lastend = txt.lastIndexOf("}}", pos);
}));
var isTemplate = lastbegin > lastend;
});
if (isTemplate) {
}
var prefixName = mw.config.get('wgFormattedNamespaces')[10] + ':' + txt.substr(lastbegin + 2, pos - lastbegin - 1);
else $.getJSON(
mode = (prefixName.indexOf('|') > -1) ? 'templateParams' : 'template';
mw.util.wikiScript('api'),
fillLinksList(res, prefixName);
{action:'opensearch', search:txt, format:'json'},
function(data) } else {
if(data[1]) mode = "none";
res(settings.filterResponse(data[1]));
}
}
}
 
 
function resolveTempalte(templateName) {
var dfd = new jQuery.Deferred();
if (!templateName) return dfd.reject().promise();
if (templateDataCache[templateName]) return dfd.resolve().promise();
var api = new mw.Api();
api.get({
action: 'templatedata',
titles: templateName,
redirects: 1
}).done(function(data) {
if (!data.pages) return dfd.reject();
for (var pageid in data.pages) {
templateDataCache[templateName] = data.pages[pageid];
dfd.resolve();
}
if (!templateDataCache[templateName]) dfd.reject();
});
return dfd.promise();
}
}
 
function resolveApi(queryType, queryValue) {
ctrl.autocomplete( {
var dfd = new jQuery.Deferred();
source: function( request, response ) {
var api = new mw.Api();
if(fixArrowsBug(this))
response([]);
else
findLinks(response);
},
focus:function(){return false;},
select:function(e,ui){
settings.onselected(ui.item.value);return false;
},
open:function(){
$(".ui-autocomplete")
.css(settings.menuCSS)
.position({
my: settings.positionMy,
at: settings.positionAt,
of: settings.positionOf,
offset: settings.positionOffset,
collision: 'none fit'
})
.find('li').css(settings.itemCSS);
}
});
var fixed=false;
//this is hack to prevent known serious bug in autocomplete.js that prevent default of the up and down key which may drive you crazy....
function fixArrowsBug(self){
if(fixed) return false;
fixed=true;
ctrl.off("keydown.autocomplete");
ctrl.off("keydown.autocomplete0");
ctrl.on("keydown.autocomplete",
function(event) {
var keyCode = $.ui.keyCode;
switch( event.keyCode ) {
case keyCode.PAGE_UP:
self._move( "previousPage", event );
break;
case keyCode.PAGE_DOWN:
self._move( "nextPage", event );
break;
case keyCode.UP:
if (!self.menu.element.is(":visible")) return;
self._move( "previous", event );
// prevent moving cursor to beginning of text field in some browsers
event.preventDefault();
break;
case keyCode.DOWN:
if (!self.menu.element.is(":visible")) return;
self._move( "next", event );
// prevent moving cursor to end of text field in some browsers
event.preventDefault();
break;
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
// when menu is open or has focus
if ( self.menu.active ) {
event.preventDefault();
}
//passthrough - ENTER and TAB both select the current element
case keyCode.TAB:
if ( !self.menu.active ) {
return;
}
self.menu.select( event );
break;
case keyCode.ESCAPE:
self.element.val( self.term );
self.close( event );
break;
case keyCode.LEFT:
case keyCode.RIGHT:
case keyCode.SHIFT:
case keyCode.CONTROL:
case keyCode.ALT:
case keyCode.COMMAND:
case keyCode.COMMAND_RIGHT:
case keyCode.INSERT:
case keyCode.CAPS_LOCK:
case keyCode.END:
case keyCode.HOME:
// ignore metakeys (shift, ctrl, alt)
break;
default:
// keypress is triggered before the input value is changed
clearTimeout( self.searching );
self.searching = setTimeout(function() {
self.search( null, event );
}, self.options.delay );
break;
}
});
return true;
}
}
});
 
switch (queryType) {
if($.inArray(mw.config.get('wgAction'), ['edit', 'submit'])+1)
case 'users':
mw.loader.using(['jquery.ui.widget','jquery.ui.autocomplete','jquery.textSelection'],function(){
api.get({
//enable autocomplete for editbox, relative to editform in an offset of -80 vertical
action: 'query',
$( "#wpTextbox1" ).autoCompleteWikiText(
list: 'allusers',
{
auactiveusers: 1,
positionAt: $('#wpTextbox1').prop('dir')=='rtl'? "left top" : "right top",
auprefix: queryValue
positionOf: '#editform',
}).done(function(data) {
positionOffset: "0 0",
if (data && data.query && data.query.allusers) dfd.resolve($.map(data.query.allusers, function(e) {
menuCSS: { background:'#E0EEF7', opacity:0.8},
return e.name;
itemCSS: {padding: 0, margin: 0 }
}));
});
else dfd.reject();
});
break;
case 'pages':
api.get({
action: 'opensearch',
search: queryValue
}).done(function(data) {
if (data[1]) dfd.resolve(settings.filterResponse(data[1]));
else dfd.reject();
});
break;
default:
throw 'unexpected queryType';
}
 
return dfd.promise();
}
 
function fillLinksList(res, txt) {
txt = $.trim(txt);
if (txt.length <= 1 || (mode != 'templateParams' && txt.indexOf('|') > -1) || (txt.indexOf('#') > -1 && mw.config.get('wgNamespaceNumber') === 0)) res([]);
else if (mode === 'templateParams') {
var templateMatch = /(.+?)\|(?:.*\|)?([^=]+$)/.exec(txt);
$.when(resolveTempalte(templateMatch && templateMatch[1])).done(function() {
var curTemplateData = templateDataCache[templateMatch[1]];
var suggestions = [];
var curParamIndex = txt.split('|').length - 1;
for (var paramName in curTemplateData.params) {
if (paramName == curParamIndex) {
var paramValue = templateMatch[2];
var dfd;
switch (curTemplateData.params[paramName].type) {
case 'wiki-page-name':
dfd = $.when(resolveApi('pages', paramValue));
mode = 'templateValue';
break;
case 'wiki-file-name':
dfd = $.when(resolveApi('pages', 'File:' + paramValue));
mode = 'templateValue';
break;
case 'wiki-user-name':
dfd = $.when(resolveApi('users', paramValue));
mode = 'templateValue';
break;
default:
return res([]); // dont suggest for this indexed param
}
return dfd.done(res).fail(function() {
res([])
});
}
if (paramName === '1' || txt.indexOf(paramName) > -1) continue; //dont suggest used params
suggestions.push(paramName);
}
res(suggestions);
}).fail(res);
} else if (txt.indexOf('#') > -1) {
var pageTitle = txt.substr(0, txt.indexOf('#'));
var sectionPrefix = txt.substr(txt.indexOf('#') + 1);
var api = new mw.Api();
api.get({
action: 'parse',
page: pageTitle,
prop: 'sections'
}).done(function(data) {
if (data && data.parse && data.parse.sections) res($(data.parse.sections).map(function() {
return this.line.indexOf(sectionPrefix) == 0 ? (pageTitle + '#' + this.line) : null;
}));
});
} else {
$.when(resolveApi('pages', txt)).done(res).fail(function() {
res([])
});
}
}
 
ctrl.autocomplete({
source: function(request, response) {
if (fixArrowsBug(this))
response([]);
else
findLinks(response);
},
focus: function() {
return false;
},
select: function(e, ui) {
settings.onselected(ui.item.value);
return false;
},
open: function() {
$(".ui-autocomplete")
.css(settings.menuCSS)
.position({
my: settings.positionMy,
at: settings.positionAt,
of: settings.positionOf,
offset: settings.positionOffset,
collision: 'none fit'
})
.find('li').css(settings.itemCSS);
}
});
var fixed = false;
//this is hack to prevent known serious bug in autocomplete.js that prevent default of the up and down key which may drive you crazy....
function fixArrowsBug(self) {
if (fixed) return false;
fixed = true;
ctrl.off("keydown.autocomplete");
ctrl.off("keydown.autocomplete0");
ctrl.on("keydown.autocomplete",
function(event) {
var keyCode = $.ui.keyCode;
switch (event.keyCode) {
case keyCode.PAGE_UP:
self._move("previousPage", event);
break;
case keyCode.PAGE_DOWN:
self._move("nextPage", event);
break;
case keyCode.UP:
if (!self.menu.element.is(":visible")) return;
self._move("previous", event);
// prevent moving cursor to beginning of text field in some browsers
event.preventDefault();
break;
case keyCode.DOWN:
if (!self.menu.element.is(":visible")) return;
self._move("next", event);
// prevent moving cursor to end of text field in some browsers
event.preventDefault();
break;
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
// when menu is open or has focus
if (self.menu.active) {
event.preventDefault();
}
//passthrough - ENTER and TAB both select the current element
case keyCode.TAB:
if (!self.menu.active) {
return;
}
self.menu.select(event);
break;
case keyCode.ESCAPE:
self.element.val(self.term);
self.close(event);
break;
case keyCode.LEFT:
case keyCode.RIGHT:
case keyCode.SHIFT:
case keyCode.CONTROL:
case keyCode.ALT:
case keyCode.COMMAND:
case keyCode.COMMAND_RIGHT:
case keyCode.INSERT:
case keyCode.CAPS_LOCK:
case keyCode.END:
case keyCode.HOME:
// ignore metakeys (shift, ctrl, alt)
break;
default:
// keypress is triggered before the input value is changed
clearTimeout(self.searching);
self.searching = setTimeout(function() {
self.search(null, event);
}, self.options.delay);
break;
}
});
return true;
}
}
});
 
if ($.inArray(mw.config.get('wgAction'), ['edit', 'submit']) + 1)
mw.loader.using(['jquery.ui.widget', 'jquery.ui.autocomplete', 'jquery.textSelection'], function() {
//enable autocomplete for editbox, relative to editform in an offset of -80 vertical
$("#wpTextbox1").autoCompleteWikiText({
positionAt: $('#wpTextbox1').prop('dir') == 'rtl' ? "left top" : "right top",
positionOf: '#editform',
positionOffset: "0 0",
menuCSS: {
background: '#E0EEF7',
opacity: 0.8
},
itemCSS: {
padding: 0,
margin: 0
}
});
});