User:Ricordisamoa/FlagSense/unstable.js
Jump to navigation
Jump to search
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
Documentation for this user script can be added at User:Ricordisamoa/FlagSense/unstable. |
- Report page listing warnings and errors.
/* <nowiki>
* FlagSense by Ricordisamoa
* https://commons.wikimedia.org/wiki/User:Ricordisamoa/FlagSense
*/
FlagSense={
messages:{
"add-template-VVA":{
"en":"Add {{Vector version available}} to the file description page",
"it":"Aggiungi {{Vector version available}} alla pagina di descrizione del file"
},
"add-template-toSVG":{
"en":"Add {{Convert to SVG|flag}} to the file description page",
"it":"Aggiungi {{Convert to SVG|flag}} alla pagina di descrizione del file"
},
"add-template-toPNG":{
"en":"Add {{Convert to PNG}} to the file description page",
"it":"Aggiungi {{Convert to PNG}} alla pagina di descrizione del file"
},
"add-template-ssPNG":{
"en":"Add {{SupersededPNG}} to the file description page",
"it":"Aggiungi {{SupersededPNG}} alla pagina di descrizione del file"
},
"feature-not-available":{
"en":"Add {{SupersededPNG}} to the file description page",
"it":"Aggiungi {{SupersededPNG}} alla pagina di descrizione del file"
},
"alreadySVG":{
"en":"This is already a vector image.\nIt doesn't need to be converted in SVG again.",
"it":"Questa è già una immagine vettoriale.\nNon necessita di essere convertita in SVG di nuovo."
},
"vvaConfirmToSVG":{
"en":"This page already contains the template {{Vector version available}}\n"+
"To replace {{Vector version available}} with {{Convert to SVG}}, press OK;\n"+
"To skip editing this page, press UNDO",
"it":"Questa pagina contiene già il template {{Vector version available}}\n"+
"Per sostituire {{Vector version available}} con {{Convert to SVG}}, premi OK;\n"+
"Per evitare di modificare questa pagina, premi ANNULLA"
},
"vvaConfirmToPNG":{
"en":"This page already contains the template {{Vector version available}}\n"+
"To replace {{Vector version available}} with {{Convert to PNG}}, press OK;\n"+
"To skip editing this page, press UNDO",
"it":"Questa pagina contiene già il template {{Vector version available}}\n"+
"Per sostituire {{Vector version available}} con {{Convert to PNG}}, premi OK;\n"+
"Per evitare di modificare questa pagina, premi ANNULLA"
},
"vvaConfirmNew":{
"en":"This page already contains the template {{Vector version available}}\n"+
"To replace the existing istance with this new one, press OK;\n"+
"To skip editing this page, press UNDO",
"it":"Questa pagina contiene già il template {{Vector version available}}\n"+
"Per sostituire la vecchia istanza con quella nuova, premi OK;\n"+
"Per evitare di modificare questa pagina, premi ANNULLA"
},
"svgAlternative":{
"en":"The name of the SVG alternative (without File: prefix):",
"it":"Il nome dell'alternativa SVG (senza prefisso File:)"
},
"pngAlternative":{
"en":"The name of the PNG alternative (without File: prefix):",
"it":"Il nome dell'alternativa PNG (senza prefisso File:)"
},
"alreadySameCategory":{
"en":function(width,height,cat){return "FlagSense detected that, by a size of "+width+"×"+height+", the proper category for this image was: «"+cat+"».\n"+
"However, the image is already in this category."},
"it":function(width,height,cat){return "FlagSense ha rilevato che, con una dimensione di "+width+"×"+height+", la categoria appropriata per questa immagine sarebbe stata: «"+cat+"».\n"+
"Tuttavia, l'immagine è già in questa categoria."}
},
"alreadyOtherCategory":{
"en":function(width,height,cat){return "FlagSense detected that, by a size of "+width+"×"+height+", the proper category for this image would be: «"+cat+"».\n"+
"However, the image is already categorized by aspect ratio.\nDo you anyway want to replace the old category with this one?"},
"it":function(width,height,cat){return "FlagSense ha rilevato che, con una dimensione di "+width+"×"+height+", la categoria appropriata per questa immagine sarebbe: «"+cat+"».\n"+
"Tuttavia, l'immagine è già categorizzata per proporzioni.\nVuoi comunque sostituire la vecchia categoria con questa?"}
},
"noMatchFound":{
"en":function(width,height){return "FlagSense tried to search the proper category for this image, but no matches were found.\n\n"+
"Details:\nimage size: "+width+"×"+height+"\naspect ratio: "+width/FlagSense.gcd(width,height)+"/"+height/FlagSense.gcd(width,height)},
"it":function(width,height){return "FlagSense ha provato a cercate la categoria appropriata per questa immagine, ma non ha trovato corrispondenze.\n\n"+
"Dettagli:\ndimensioni immagine: "+width+"×"+height+"\nproporzioni: "+width/FlagSense.gcd(width,height)+"/"+height/FlagSense.gcd(width,height)}
}
},
start:function(){
// Make sure the utilities module is loaded (will only load if not already)
mw.loader.using( "mediawiki.util", function () {
if(wgCanonicalNamespace=="File"){// Make sure the page is a file description
// Wait for the page to be parsed
$(document).ready( function () {
wgFileExtension=wgPageName.split('.')[wgPageName.split('.').length-1].toLowerCase();
// parse the file extension from the page name
// the variable is global, so can be used later for automatic categorization
var $_GET=[]; // object which contains key/value pairs of the querystring
if(location.search&&location.search.toString().length>1){ // the querystring is present
for(s in location.search.split("?")[1].split("&")){ // split the pairs
var key=location.search.split("?")[1].split("&")[s].split("="); // split the key
$_GET[decodeURIComponent(key[0])]=decodeURIComponent(key[1]); // from the value
}
}
if(document.getElementById("editform")&&((sessionStorage&&sessionStorage["FlagSense-currentAction"])||$_GET["flagsense"])){
// the user is editing the page and the current page was previously marked for editing
var f = document.editform; // the edit form
var t = f.wpTextbox1; // the edit textarea
var s = f.wpSummary; // the summary of changes
var m = f.wpMinoredit; // the checkbox for marking a minor edit
switch($_GET["flagsense"]?$_GET["flagsense"]:sessionStorage["FlagSense-currentAction"]){
// the user is going to mark this image as to be converted to SVG
case "toSVG":(function(){
var template="{{Convert to SVG|flag}}"; // no comment!
if(FlagSense.regex["VVA"].test(t.value)==false){
t.value=template+"\n"+t.value; // add the template code at the top
}
else if(confirm(FlagSense.getMessage("vvaConfirmToSVG"))==true){ // ask for a confirmation
t.value=t.value.replace(FlagSense.regex["VVA"],template); // replace "Vector version available" with "Convert to SVG";
}
else{
window.history.back(); // go back to the file description page
}
s.value="Added template {{[[Template:Convert to SVG|Convert to SVG]]|flag}} using [[User:Ricordisamoa/FlagSense|FlagSense]]"; // precompiled summary
FlagSense.closeEdit();
})();break;
// the user is going to mark this image as to be converted to PNG
case "toPNG":(function(){
var template="{{Convert to PNG}}"; // no comment!
if(FlagSense.regex["VVA"].test(t.value)==false){
t.value=template+"\n"+t.value; // add the template code at the top
}
else if(confirm(FlagSense.getMessage("vvaConfirmToPNG"))==true){ // ask for a confirmation
t.value=t.value.replace(FlagSense.regex["VVA"],template); // replace "Vector version available" with "Convert to SVG";
}
else{
window.history.back(); // go back to the file description page
}
s.value="Added template {{[[Template:Convert to PNG|Convert to PNG]]}} using [[User:Ricordisamoa/FlagSense|FlagSense]]"; // precompiled summary
FlagSense.closeEdit();
})();break;
// the user is going to point out a vector version of this image
case "VVA":(function(){
var dial=$("<div>");
var input=$("<input>").appendTo(dial);
dial.dialog({title:FlagSense.getMessage("svgAlternative"),buttons:{
"OK":function(){
var template="{{Vector version available|"+input.val()+"}}";
if(FlagSense.regex["VVA"].test(t.value)==false){
t.value=template+"\n"+t.value; // add the template code at the top
}
else if(confirm(FlagSense.getMessage("vvaConfirmNew"))==true){ // ask for a confirmation
t.value=t.value.replace(FlagSense.regex["VVA"],template); // replace the old "Vector version available" with the new one;
}
else{
window.history.back(); // go back to the file description page
}
s.value="Added template {{[[Template:Vector version available|Vector version available]]}} using [[User:Ricordisamoa/FlagSense|FlagSense]]"; // precompiled summary
$(this).dialog("close");
FlagSense.closeEdit();
},
"Cancel":function(){$(this).dialog("close");}
}});
})();break;
// the user is going to point out a PNG version of this image
case "ssPNG":(function(){
var dial=$("<div>");
var input=$("<input>").appendTo(dial);
dial.dialog({title:FlagSense.getMessage("pngAlternative"),buttons:{
"OK":function(){
var template="{{SupersededPNG|"+input.val()+"}}";
if(FlagSense.regex["VVA"].test(t.value)==false){
t.value=template+"\n"+t.value; // add the template code at the top
}
else if(confirm(FlagSense.getMessage("vvaConfirmToPNG"))==true){ // ask for a confirmation
t.value=t.value.replace(FlagSense.regex["VVA"],template); // replace the old "Vector version available" with the new one;
}
else{
window.history.back(); // go back to the file description page
}
s.value="Added template {{[[Template:SupersededPNG|SupersededPNG]]}} using [[User:Ricordisamoa/FlagSense|FlagSense]]"; // precompiled summary
$(this).dialog("close");
FlagSense.closeEdit();
},
"Cancel":function(){$(this).dialog("close");}
}});
})();break;
case "cat":(function(){
var cat=sessionStorage?sessionStorage["FlagSense-category"]:$_GET["cat"]; // category from sessionStorage or querystring
var accuracy=parseFloat(sessionStorage?sessionStorage["FlagSense-accuracy"]:$_GET["accuracy"]); // category from sessionStorage or querystring
var oldCatTest=/\[\[Category:[^\[\]]*Flag[^\[\]]+aspect ratio[^\[\]]+\]\]/gi;
if(oldCatTest.test(t.value)){
oldCatTest.lastIndex=0;
s.value="removed [[:Category:"+oldCatTest.exec(t.value)[0].toString().replace(/\[\[Category:/i,"")+"; "; // precompiled summary
t.value=t.value.replace(oldCatTest,"[[Category:"+cat+"]]"); // replace the old category with the new one
}
else t.value+=(/\n$/.test(t.value)?"":"\n")+"[[Category:"+cat+"]]"; // add the category at the bottom
s.value+="added [[:Category:"+cat+"]] using [[User:Ricordisamoa/FlagSense|FlagSense]]"+(accuracy>0?" with an error of ±"+accuracy:""); // precompiled summary
m.checked=true;
FlagSense.closeEdit();
})();break;
}
}
else{
var width=$(".filehistory>tbody>tr:nth-child(2)>td:nth-child(4)")[0].firstChild.nodeValue.split(' ').join('').split('\u00A0').join('').split('×');
var height=parseInt(width[1]);
width=parseInt(width[0]);
var g=FlagSense.gcd(width,height); // greatest common divisor of width and height
var ratio=width/g+":"+height/g;
var cat=FlagSense.categoryByAspectRatio(width,height);
$("div#file").prepend(
$(document.createElement("div"))
.css({float:"right",background:"whitesmoke",padding:"8px"})
.append("<h3>FlagSense</h3>")
.append("Format: "+wgFileExtension.toUpperCase())
.append(
(wgFileExtension!="svg"?// check for non-SVG images
$(document.createElement("p"))
.attr("id","FlagSense-nonSVG")
.append($("<button>VVA</button>")
.attr("id","FlagSense-button-VVA")
.attr("title",FlagSense.getMessage("add-template-VVA"))
.click(function(event){
FlagSense.openEdit("VVA");
}))
:""))
.append(
(wgFileExtension!="png"?// check for non-PNG images
$(document.createElement("p"))
.attr("id","FlagSense-nonPNG")
.append($("<button>SupersededPNG</button>")
.attr("id","FlagSense-button-ssPNG")
.attr("title",FlagSense.getMessage("add-template-ssPNG"))
.click(function(event){
FlagSense.openEdit("ssPNG");
}))
:""))
.append($(new Image()).attr(
(cat&&cat!=null&&wgCategories.indexOf(cat.cat)!=-1)?{
"src":"//upload.wikimedia.org/wikipedia/commons/thumb/b/be/P_yes.svg/20px-P_yes.svg.png",
"title":"already in this category"
}:(cat==null?{
"src":"//upload.wikimedia.org/wikipedia/commons/thumb/4/42/P_no.svg/20px-P_no.svg.png",
"title":"no proper category available for this image"
}:{
"src":"//upload.wikimedia.org/wikipedia/commons/thumb/5/5e/Exclamation.svg/20px-Exclamation.svg.png",
"title":"a category has been found"+(FlagSense.isCategorizedByAspectRatio()==true?" but the image is already categorized by aspect ratio":"")
})
).css("background","none"))// remove the default checkered background
.append("Aspect ratio: ")
.append(cat!=null?$("<a>"+cat.ratio+"</a>").attr("href",mw.util.getUrl("Category:"+cat.cat)):ratio)
.append(cat!=null?(" with"+(cat.accuracy>0?" an error of ±"+Math.round(cat.accuracy*100000)/100000:"out error")):"")
.append(
(cat!=null&&wgCategories.indexOf(cat.cat)==-1)?$("<button>"+(FlagSense.isCategorizedByAspectRatio()==true?"Change category":"Add category")+"</button>")
.click(function(event){
FlagSense.openEdit("cat",cat.cat,Math.round(cat.accuracy*100000)/100000);
})
:"")
.append($("<br/><button>Categorize by elements and colors<br/>(experimental)</button>")
.click(function(event){
// create an HTML5 Canvas
var canvas=$(document.createElement("canvas"))
.attr({"width":$("div#file a>img").attr("width"),"height":$("div#file a>img").attr("height")})
.css("background",$("div#file a>img").css("background"));
var ctx=canvas[0].getContext("2d");
var imageObj=new Image();
imageObj.crossOrigin="Anonymous";// allow CORS images
imageObj.onload=function(){
ctx.drawImage(imageObj,0,0);// draw the image on the canvas
canvas.click(function(event){
var obj=this;
var top=0;
var left=0;
while(obj!=document.body) {
top+=obj.offsetTop;
left+=obj.offsetLeft;
obj=obj.offsetParent;
}
var x=event.clientX-left+window.pageXOffset;
var y=event.clientY-top+window.pageYOffset;
var imageData=this.getContext("2d").getImageData(x,y,1,1).data;
var red=imageData[0];
var green=imageData[1];
var blue=imageData[2];
var alpha=imageData[3];
alert("x: "+x+"\ny: "+y+"\nrgba("+[red,green,blue,alpha].join()+")\n"+FlagSense.colorByRGBA(red,green,blue,alpha));
});
var imageColors=FlagSense.colorsByData(canvas.get(0).getContext("2d").getImageData(0,0,canvas.get(0).width,canvas.get(0).height).data);
console.log(JSON.stringify(imageColors));
$.each(imageColors,function(index,element){
var li=$(document.createElement("li")).text(element.shift());
$.each(element,function(i,e){
li.append(
$(document.createElement("span"))
.css({
"display":"inline-block",
"width":"12pt",
"height":"12pt",
"background":e
})
);
});
$("ul#FlagSense-colors").append(li);
});
}
imageObj.src=$("div#file a>img").attr("src");// get the URL of the in-page thumbnail
$("div#file a>img").parent().replaceWith(canvas);// replace the in-page thumb (and the link)
$(this).replaceWith($(document.createElement("ul")).attr("id","FlagSense-colors"));// remove the button
})
)
);
if($("p#FlagSense-nonSVG").length>0){
FlagSense.isTemplated(FlagSense.regex["toSVG"],function(result){
if(result===false){
$("p#FlagSense-nonSVG").prepend($("<button>Should be SVG</button>")
.attr("id","FlagSense-button-toSVG")
.attr("title",FlagSense.getMessage("add-template-toSVG"))
.click(function(event){
FlagSense.openEdit("toSVG");
}))
}
});
FlagSense.isTemplated(FlagSense.regex["VVA"],function(result){
if(result===true){
$("button#FlagSense-button-VVA")
.attr("title",$("button#FlagSense-button-VVA").attr("title")+" (change)")
.append(" (change)")
}
});
}
if($("p#FlagSense-nonPNG").length>0){
FlagSense.isTemplated(FlagSense.regex["toPNG"],function(result){
if(result===false){
$("p#FlagSense-nonPNG").prepend($("<button>Should be PNG</button>")
.attr("id","FlagSense-button-toPNG")
.attr("title",FlagSense.getMessage("add-template-toPNG"))
.click(function(event){
FlagSense.openEdit("toPNG");
}))
}
});
FlagSense.isTemplated(FlagSense.regex["ssPNG"],function(result){
if(result===true){
$("button#FlagSense-button-ssPNG")
.attr("title",$("button#FlagSense-button-ssPNG").attr("title")+" (change)")
.append(" (change)")
}
});
}
}
});
}
});
},
colorsByData:function(data){
var colors=[];
for(i=0;i<data.length;i+=4){
var red=data[i];
var green=data[i+1];
var blue=data[i+2];
var alpha=data[i+3];
var color=FlagSense.colorByRGBA(red,green,blue,alpha);
var rgba="rgba("+[red,green,blue,alpha].join()+")";
if(color!=null){
$.each(colors,function(index,element){
if(element.shift()==color&&element.indexOf(rgba)==-1) element.push(rgba);
else if(index==colors.length-1) colors.push([color,rgba]);
});
if(colors.length==0) colors.push([color,rgba]);
}
}
return colors;
},
colorByRGBA:function(red,green,blue,alpha){
if(alpha==255){
if(red>green&&red>blue) return "red";
else if(green>red&&green>blue) return "green";
else if(blue>red&&blue>green) return "blue";
else if(red==green&&red==blue){
if(red==255) return "white";
else if(red==0) return "black";
else return "gray";
}
}
else if(alpha==0) return "transparent";
else return null;
},
categoryByAspectRatio:function(width,height){
// see https://commons.wikimedia.org/wiki/Category:Flags_by_aspect_ratio
var ratios=["1:1","2:1","3:2","4:3","5:3","18:11","18:13","20:11","25:14","8:5"];
var g=FlagSense.gcd(width,height); // greatest common divisor of width and height
var ratio=width/g+":"+height/g;
var accuracy=0; // accuracy is the difference between the flag's aspect ratio and the closest existing category
var paragorns=[];
for(r in ratios){
var rs=ratios[r].split(':');
var diff=Math.abs(parseInt(rs[0])/parseInt(rs[1])-width/height); // absolute difference between the two ratios
console.log("FlagSense: examining ratio: "+rs.join("/")+"; difference is: "+diff);
if(diff<.04) paragorns.push([ratios[r],diff]);
}
if(paragorns.length>0){ // sort all ratios whose difference is lower than 0.04
// the first is the most appropriate
console.log("FlagSense: unordered ratios: "+paragorns);
paragorn=paragorns.sort(this.sortRatios)[0];
console.log("FlagSense: most appropriate ratio: "+paragorn);
var cat="Flags with an aspect ratio of "+paragorn[0]; // proper category by aspect ratio
var ratio=paragorn[0];
var accuracy=paragorn[1];
if(ratio=="1:1") cat="Square flags";
if(wgFileExtension=="svg"){
if(ratio=="1:1") cat="SVG square flags";
else cat=cat.replace(/^Flags/,"SVG flags").replace(/an (aspect)/,"$1");
}
if(ratio=="3:2"){
if(wgFileExtension=="png") cat="PNG flags - aspect ratio of 3:2";
else if(wgFileExtension=="gif") cat="GIF flags with aspect ratio of 3:2";
}
return {
ratio:ratio,
cat:cat,
accuracy:accuracy
};
}
else{
return null;
}
},
sortRatios:function(a,b){
return a[1]-b[1]; // sort two aspect ratios basing on the accuracy level
},
isTemplated:function(regex,callback){
$.get(wgServer+"/w/index.php?title="+wgPageName+"&action=raw",function(data){
callback(regex.test(data));
});
},
gcd:function(a,b){ // recursive function for Greatest Common Divisor
if(b) return this.gcd(b,a%b);
else return Math.abs(a);
},
getMessage:function(message){
return FlagSense.messages[message][wgUserLanguage];
},
isCategorizedByAspectRatio:function(){
$.each(wgCategories,function(index,cat){// loop in all categories of the image
if(cat.indexOf("flag")!=-1&&cat.indexOf("aspect ratio")!=-1) return true;// there is a category by aspect ratio
});
return false;// there aren't
},
openEdit:function(action,category,accuracy){
if(sessionStorage){
sessionStorage["FlagSense-currentAction"]=action;// mark this page for adding the template (just later)
if(category!=null&&accuracy!=null){
sessionStorage["FlagSense-category"]=category;
sessionStorage["FlagSense-accuracy"]=accuracy;
}
}
document.location=$("li#ca-edit a").attr("href")+(!sessionStorage?"&flagsense="+action+((category&&accuracy&&category!=null&&accuracy!=null)?"&cat="+category+"&accuracy="+accuracy:""):""); // go to edit page
},
closeEdit:function(){
if(sessionStorage){
sessionStorage.removeItem("FlagSense-currentAction"); // unmark the page
sessionStorage.removeItem("FlagSense-category");
sessionStorage.removeItem("FlagSense-accuracy");
}
if(this.autoSubmit&&this.autoSubmit==true) document.editform.submit(); // automatically submit the edit form
},
regex:{
"VVA":/\{\{(Vector Version Available|Converted to SVG|SVG available|NowSVG|VVA)\|[^\n\{\}]+\}\}/i,
"toSVG":/\{\{([Cc]onvert( to |[Tt]o)|[Ss]hould( be |[Bb]e)|[Tt]o)?SVG(\|[a-zA-Z]+)?\}\}/,
"toPNG":/\{\{([Cc]onvert to |[Ss]hould( be |[Bb]e))PNG\}\}/,
"ssPNG":/\{\{[Ss]upersededPNG\|[^\n\{\}]+\}\}/
},
autoSubmit:false
};
FlagSense.start();
/* </nowiki> */