MediaWiki:Gadget-WikitextAutocompleter.js: Difference between revisions
Jump to navigation
Jump to search
KokoroSenshi (talk | contribs) m (Ensure it only runs on an Edit page) |
KokoroSenshi (talk | contribs) (Pushed/Mainspaced sandbox changes - More general, more functionality, though under simplified assumptions, not fully tested: https://zelda.gamepedia.com/index.php?title=User%3AKokoroSenshi%2Fcommon.js&type=revision&diff=630041&oldid=629917) |
||
Line 1: | Line 1: | ||
/** | /** | ||
* Autocomplete/Dropdown list | * Autocomplete/Dropdown list | ||
* Uses https://yuku-t.com/textcomplete/ | * Uses https://yuku-t.com/textcomplete/ | ||
* | * | ||
* Notes: | * Notes: | ||
* - Won't work with CodeEditor since it doesn't use a textarea but that's fine | * - Won't work with CodeEditor since it doesn't use a textarea but that's fine | ||
* since CodeEditor won't be used for wikitext | * since CodeEditor won't be used for wikitext | ||
* - $.getScript() is used since mw.loader.load() doesn't wait for the code to load | * - $.getScript() is used since mw.loader.load() doesn't wait for the code to load | ||
Line 10: | Line 10: | ||
* Bugs: | * Bugs: | ||
* - The regex fails if there is an instance of {{Color| before it in the textarea? tho it's fine in the example webpage | * - The regex fails if there is an instance of {{Color| before it in the textarea? tho it's fine in the example webpage | ||
* - In addition, | * - In addition, when you start a "{{Color|", then pop over to a different "{{Color|", it'll show dropdown, but append to the first "{{Color|"" | ||
* | * | ||
*/ | */ | ||
if (mw.config.get("wgAction") == 'edit') { | if (mw.config.get("wgAction") == 'edit') { | ||
/* Make the strategy/ies to add */ | |||
var Strategies = {}; | var Strategies = {}; | ||
Strategies.Template = {}; | Strategies.Templates = []; | ||
Strategies. | Strategies.Templates.push(new TemplateStrategy( | ||
"Color", | |||
function() { | |||
var self = this; | |||
$.get( "https://zelda.gamepedia.com/Template:Color?action=raw", function( data ) { | |||
/** Store parameter options in instance variable */ | |||
self.params["1"] = readColorArrayFromString(data); | |||
/** Callback */ | |||
self.registerStrategies(); | |||
}); | |||
var readColorArrayFromString = function(text) { | |||
var colorArray = []; | |||
text.split("</includeonly>")[0] | |||
.split("#switch:{{{1\|}}}")[1] | |||
.split("\|#default")[0] | |||
.match(/\|[a-zA-Z0-9 ]*/g) | |||
.forEach(function(value, index){ | |||
var colorName = value.slice(1); | |||
colorArray.push(colorName); | |||
}); | |||
return colorArray; | |||
}; | |||
} | |||
)); | |||
Strategies.Templates.push(new TemplateStrategy( | |||
"KSTest", | |||
function() { // Need to have self/this for params and registerStrategies() | |||
var self = this; | |||
/** Store parameter options in instance variable */ | |||
self.params["1"] = ["testparam1value1","testparam1value2","testparam1value3"]; | |||
self.params["2"] = ["testparam2value1","testparam2value2","testparam2value3"]; | |||
self.params["3"] = ["testparam3value1","testparam3value2","testparam3value3"]; | |||
/** Callback */ | |||
self.registerStrategies(); | |||
} | |||
)); | |||
/* Load Textcomplete then register the strategy/ies */ | |||
$(document).ready(function() { | $(document).ready(function() { | ||
getTextcompleteScript( | |||
Strategies.Templates // Array of TemplateStrategy objects to register each of | |||
); | |||
} ); | } ); | ||
} | } | ||
function getTextcompleteScript(templateStrategyArray) { | |||
console.log( "Loading textcomplete..." ); | |||
$.getScript( "https://unpkg.com/textcomplete/dist/textcomplete.min.js", function( data, textStatus, jqxhr ) { | |||
console.log( [ data, textStatus, jqxhr.status ] ); // Data returned, Success, 200 | |||
console.log( "Loaded textcomplete. (Warning: May not be executed yet)" ); | |||
// (Global) Textarea object: https://github.com/yuku-t/textcomplete/issues/114#issuecomment-318352383 | |||
Textarea = Textcomplete.editors.Textarea; | |||
templateStrategyArray.forEach(function(templateStrategy){ templateStrategy.register(); }); | |||
}); | |||
} | |||
// Been going over OOP in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Example | // Been going over OOP in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Example | ||
Line 40: | Line 90: | ||
/** | /** | ||
* Constructor | * Constructor (and non-prototype definitions) | ||
* (instance variables can't be accessed without "this." etc.) | * (instance variables can't be accessed without "this." etc.) | ||
*/ | */ | ||
function TemplateStrategy(templateName) { | function TemplateStrategy(templateName, getParametersFunction) { | ||
var self = this; | |||
/********************* | |||
** Public variables ** | |||
**********************/ | |||
this.templateName = templateName; | |||
this.params = {}; // params.<name_of_param> = array of options // should each param have a 'description' variable too? applicable to both preset options and open-ended | |||
this.strategies = []; | |||
/******************** | |||
** Public methods ** | |||
********************/ | |||
/** | |||
* register method | |||
*/ | |||
this.register = function() { | this.register = function() { | ||
self.getParameters(); // Must have callback to registerStrategies() | |||
}; | }; | ||
this.getParameters = getParametersFunction; | |||
this.registerStrategies = function() { | |||
var | var params = self.params; | ||
var strategies = self.strategies; | |||
/** Validate parameters */ | |||
console.log("params: "); | console.log("params: "); | ||
console.log(params); | console.log(params); | ||
var | /** | ||
* Turn each parameter into a strategy; assume no named parameters for now | |||
*/ | |||
for (var paramName in params) { | |||
if (params.hasOwnProperty(paramName)) { | |||
console.log(paramName + " -> " + params[paramName]); | |||
// Assume paramName is a number (as a String) | |||
var precedingParamRegex = ""; | |||
var paramNum = parseInt(paramName); | |||
for (var i = 1; i < paramNum; i++) { | |||
precedingParamRegex += "\\|[^\\|]*"; | |||
} | |||
var strategy = self.createStrategy( | |||
templateName, | |||
paramName, | |||
new RegExp("({{" + templateName + precedingParamRegex + "\\|)([^\\|]*)$","m"), | |||
params[paramName], | |||
function(name) { return name; }, | |||
function(name) { return "$1" + name; } // Removed the '}}' for generality for now; maybe will make exceptions for single or no parameter templates? | |||
); | |||
strategies.push(strategy); | |||
paramName = "1"; //paramName is taken as the last value set, for all the strats^???? | |||
} | } | ||
} | } | ||
var editor = new Textarea(document.getElementById('wpTextbox1')) | var editor = new Textarea(document.getElementById('wpTextbox1')) | ||
Line 102: | Line 160: | ||
} | } | ||
, textcomplete = new Textcomplete(editor, options); | , textcomplete = new Textcomplete(editor, options); | ||
textcomplete.register( | textcomplete.register(strategies); | ||
}; | }; | ||
this.createStrategy = function(name, param, match, paramArray, template, replace) { | |||
var strategy = | |||
{ | |||
id: "Template:" + name + "_" + param, | |||
match: match, | |||
search: function (term, callback) { // term is probably the 2nd capture group of the match regexp | |||
var nameArray = paramArray.filter(function(currentValue) { return currentValue.startsWith(term); }); | |||
callback(nameArray); // List of possible completions ('names') | |||
}, | |||
template: function (name) { | |||
var displayName = template(name); | |||
return displayName; // What to display in the list | |||
}, | |||
replace: function (name) { | |||
var replacementString = replace(name); | |||
return replacementString; // What to replace the matched typed text with | |||
} | |||
}; | |||
return strategy; | |||
}; | |||
} | } |
Revision as of 14:33, 4 May 2018
/**
* Autocomplete/Dropdown list
* Uses https://yuku-t.com/textcomplete/
*
* Notes:
* - Won't work with CodeEditor since it doesn't use a textarea but that's fine
* since CodeEditor won't be used for wikitext
* - $.getScript() is used since mw.loader.load() doesn't wait for the code to load
* mw.loader.load('https://unpkg.com/textcomplete@0.13.1/dist/textcomplete.min.js');
* Bugs:
* - The regex fails if there is an instance of {{Color| before it in the textarea? tho it's fine in the example webpage
* - In addition, when you start a "{{Color|", then pop over to a different "{{Color|", it'll show dropdown, but append to the first "{{Color|""
*
*/
if (mw.config.get("wgAction") == 'edit') {
/* Make the strategy/ies to add */
var Strategies = {};
Strategies.Templates = [];
Strategies.Templates.push(new TemplateStrategy(
"Color",
function() {
var self = this;
$.get( "https://zelda.gamepedia.com/Template:Color?action=raw", function( data ) {
/** Store parameter options in instance variable */
self.params["1"] = readColorArrayFromString(data);
/** Callback */
self.registerStrategies();
});
var readColorArrayFromString = function(text) {
var colorArray = [];
text.split("</includeonly>")[0]
.split("#switch:{{{1\|}}}")[1]
.split("\|#default")[0]
.match(/\|[a-zA-Z0-9 ]*/g)
.forEach(function(value, index){
var colorName = value.slice(1);
colorArray.push(colorName);
});
return colorArray;
};
}
));
Strategies.Templates.push(new TemplateStrategy(
"KSTest",
function() { // Need to have self/this for params and registerStrategies()
var self = this;
/** Store parameter options in instance variable */
self.params["1"] = ["testparam1value1","testparam1value2","testparam1value3"];
self.params["2"] = ["testparam2value1","testparam2value2","testparam2value3"];
self.params["3"] = ["testparam3value1","testparam3value2","testparam3value3"];
/** Callback */
self.registerStrategies();
}
));
/* Load Textcomplete then register the strategy/ies */
$(document).ready(function() {
getTextcompleteScript(
Strategies.Templates // Array of TemplateStrategy objects to register each of
);
} );
}
function getTextcompleteScript(templateStrategyArray) {
console.log( "Loading textcomplete..." );
$.getScript( "https://unpkg.com/textcomplete/dist/textcomplete.min.js", function( data, textStatus, jqxhr ) {
console.log( [ data, textStatus, jqxhr.status ] ); // Data returned, Success, 200
console.log( "Loaded textcomplete. (Warning: May not be executed yet)" );
// (Global) Textarea object: https://github.com/yuku-t/textcomplete/issues/114#issuecomment-318352383
Textarea = Textcomplete.editors.Textarea;
templateStrategyArray.forEach(function(templateStrategy){ templateStrategy.register(); });
});
}
// Been going over OOP in JavaScript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#Example
/**
* Strategy Object
*/
/**
* Constructor (and non-prototype definitions)
* (instance variables can't be accessed without "this." etc.)
*/
function TemplateStrategy(templateName, getParametersFunction) {
var self = this;
/*********************
** Public variables **
**********************/
this.templateName = templateName;
this.params = {}; // params.<name_of_param> = array of options // should each param have a 'description' variable too? applicable to both preset options and open-ended
this.strategies = [];
/********************
** Public methods **
********************/
/**
* register method
*/
this.register = function() {
self.getParameters(); // Must have callback to registerStrategies()
};
this.getParameters = getParametersFunction;
this.registerStrategies = function() {
var params = self.params;
var strategies = self.strategies;
/** Validate parameters */
console.log("params: ");
console.log(params);
/**
* Turn each parameter into a strategy; assume no named parameters for now
*/
for (var paramName in params) {
if (params.hasOwnProperty(paramName)) {
console.log(paramName + " -> " + params[paramName]);
// Assume paramName is a number (as a String)
var precedingParamRegex = "";
var paramNum = parseInt(paramName);
for (var i = 1; i < paramNum; i++) {
precedingParamRegex += "\\|[^\\|]*";
}
var strategy = self.createStrategy(
templateName,
paramName,
new RegExp("({{" + templateName + precedingParamRegex + "\\|)([^\\|]*)$","m"),
params[paramName],
function(name) { return name; },
function(name) { return "$1" + name; } // Removed the '}}' for generality for now; maybe will make exceptions for single or no parameter templates?
);
strategies.push(strategy);
paramName = "1"; //paramName is taken as the last value set, for all the strats^????
}
}
var editor = new Textarea(document.getElementById('wpTextbox1'))
, options = {
dropdown: {
maxCount: 500,
style: { 'margin-top': (-parseFloat($('body').css('margin-top')))+'px' }
}
}
, textcomplete = new Textcomplete(editor, options);
textcomplete.register(strategies);
};
this.createStrategy = function(name, param, match, paramArray, template, replace) {
var strategy =
{
id: "Template:" + name + "_" + param,
match: match,
search: function (term, callback) { // term is probably the 2nd capture group of the match regexp
var nameArray = paramArray.filter(function(currentValue) { return currentValue.startsWith(term); });
callback(nameArray); // List of possible completions ('names')
},
template: function (name) {
var displayName = template(name);
return displayName; // What to display in the list
},
replace: function (name) {
var replacementString = replace(name);
return replacementString; // What to replace the matched typed text with
}
};
return strategy;
};
}