MediaWiki:Gadget-HotArticleRate2.js

//

var ArticleRatings = { 0 : {'option' : 'No brainstar', 'value' : 0, 'template' : '', 'comment' : 'ordinary' }, 1 : {'option' : 'Copper', 'value' : 1, 'template' : , 'comment' :  }, 2 : {'option' : 'Bronze', 'value' : 2, 'template' : , 'comment' :  }, 3 : {'option' : 'Silver', 'value' : 3, 'template' : , 'comment' :  }, 4 : {'option' : 'Gold',  'value' : 4,   'template' : ,   'comment' :  } }

var ArticleRatingCats = ["Copper-level articles", "Bronze-level articles", "Silver-level articles", "Cover story articles"];

var MaxRatings = 4;

var ArticleImportance = { 0 : {'option' : 'LOW', 'value' : 'LOW',  'comment' : 'LOW' }, 1 : {'option' : 'MID', 'value' : 'MID',  'comment' : 'MID' }, 2 : {'option' : 'HIGH', 'value' : 'HIGH', 'comment' : 'HIGH' } }

var ArticleImportanceNames = { 'LOW' : 0, 'MID' : 1, 'HIGH' : 2 }

var MaxImportance = 2;

var HAR = new function {

this.form = null;

this.textToSave = '';

this.parameters = {}

this.display = "table";

this.token = ""; this.basetimestamp = ""; this.starttimestamp = "";

this.submitted = false;

this.modified = false;

this.scanTemplates = function(text) { var i = 0; var nestingLevel = 0; var openingBrackets = 0; var closingBrackets = 0; var openingLBrackets = 0; var closingLBrackets = 0; var openingComment = 0; var closingComment = 0; var templateName = ''; var inComment = false; var linkNesting = 0; var templateStart = 0; var paramStart = 0; var unnamedParam = 0; var paramName = ''; var parameters = new Array; var state = new Array; state.push({'ts':templateStart,'tn':templateName,'up':unnamedParam,'pn':paramName,'ps' : paramStart,'p':parameters}); var templates = new Array;

while (i < text.length) { if (                ( text.charAt(i) == '!' && openingComment == 1 ) ||                 ( text.charAt(i) == '-' && ( openingComment == 2 || openingComment == 3 ) )            ) { openingComment++; } else { if ( text.charAt(i) == '<' ) { openingComment = 1; } else { openingComment = 0; }           }

if ( inComment ) { if (                    ( text.charAt(i) == '-' && closingComment == 1 ) ||                     ( text.charAt(i) == '>' && closingComment == 2 )                ) { closingComment++; } else { if ( text.charAt(i) == '-' ) { if ( closingComment != 2 ) { closingComment = 1; }                   } else { closingComment = 0; }               }

if ( closingComment == 3 ) { inComment = false; }

//skip further processing for commented out stuff i++; continue;

}

if ( openingComment == 4 ) { inComment = true; i++; continue; }

//end comment handling

if (text.charAt(i) == '[') { openingLBrackets++; } else { openingLBrackets = 0; }           if (text.charAt(i) == ']') { closingLBrackets++; } else { closingLBrackets = 0; }

if ( openingLBrackets == 2 ) { linkNesting++; }

if ( closingLBrackets == 2 && linkNesting > 0 ) { linkNesting--; }

if ( linkNesting > 0 ) { i++; continue; }           //end link handling

if (text.charAt(i) == '{') { openingBrackets++; } else { openingBrackets = 0; }           if (text.charAt(i) == '}') { closingBrackets++; } else { closingBrackets = 0; }

if ( text.charAt(i) == '=' && templateName != '' ) { paramName = text.substring(paramStart+1,i); }           if ( text.charAt(i) == '|' || ( closingBrackets == 2 && nestingLevel > 0 ) ) { if ( templateName == '' ) { if ( nestingLevel > 0 ) { templateName = text.substring(templateStart+1,( text.charAt(i) == '|' ? i : i-1 ) ); templateName = templateName.replace(/^\s*([\S\s]*?)\s*$/, '$1'); //alert('template name: ' + templateName); if ( text.charAt(i) == '|' ) { paramStart = i;                       } }               } else { var paramstring = text.substring(paramStart+1,( text.charAt(i) == '|' ? i : i-1 ) ); //alert('paramstring: ' + paramstring);

if ( paramName.replace(/^\s*([\S\s]*?)\s*$/, '$1') != '' ) { var paramValue = paramstring.substring(paramName.length+1); paramName = paramName.replace(/^\s*([\S\s]*?)\s*$/, '$1'); paramValue = paramValue.replace(/^\s*([\S\s]*?)\s*$/, '$1'); parameters[paramName] = paramValue; paramName = ''; } else { unnamedParam++; //the mediawiki parser does not trim unnamed parameters, we want to keep that behaviour parameters[unnamedParam] = paramstring; //.replace(/^\s*([\S\s]*?)\s*$/, '$1'); }

if ( text.charAt(i) == '|' ) { paramStart = i;                   } }

}           if ( openingBrackets == 2 ) { nestingLevel++; state.push({'ts':templateStart,'tn':templateName,'up':unnamedParam,'pn':paramName,'ps' : paramStart,'p':parameters}); templateStart = i;               templateName = ''; unnamedParam = 0; openingBrackets = 0; paramName = ''; paramStart = i;               parameters = new Array; }           if ( closingBrackets == 2 && nestingLevel > 0 ) { nestingLevel--; templates.push({'name':templateName,'params':parameters,'start':templateStart-1,'end':i}); s = state.pop; templateStart = s['ts']; templateName = s['tn']; unnamedParam = s['up']; paramName = s['pn']; paramStart = s['ps']; parameters = s['p'] closingBrackets = 0; }

i++; }

return templates; };

this.lcfirst = function(s) { return s.charAt(0).toLowerCase + s.substr(1); };

this.searchForRated = function(text) { var templates = this.scanTemplates(text); for ( var i=0; i 0 ? text.substring(0,templates[i]['start']-1) : "" ) + text.substring(templates[i]['end']+1); //adjust start and end of other templates for ( var j=0; j templates[i]['end'] ) { templates[j]['start'] -= (templates[i]['end'] - templates[i]['start']) + 1; }                   if ( templates[j]['end'] > templates[i]['end'] ) { templates[j]['end'] -= (templates[i]['end'] - templates[i]['start']) + 1; }               }                //extract parameters this.parameters[1] = templates[i]['params'][1]; this.parameters[2] = templates[i]['params'][2]; this.parameters[3] = templates[i]['params'][3]; this.parameters[4] = templates[i]['params'][4]; this.parameters[5] = templates[i]['params'][5]; }       }        this.textToSave = text; };

this.preloadValues = function { if ( this.parameters[1] != undefined ) { ratingInput = document.getElementById('ratingInput'); if ( ratingInput ) { for(var i = 0; i < ratingInput.length; i++) { if ( ratingInput.options[i].value == this.parameters[1] ) { if ( this.submitted && ratingInput.selectedIndex != i ) { element = document.getElementById('ratingInput'); if ( element ) { element.parentNode.appendChild(document.createTextNode("Edit conflict: " + ArticleRatings[this.parameters[1]]['option'])); }                       } else { ratingInput.selectedIndex = i;                       } }               }            }        }

if ( this.parameters[2] != undefined ) { var categoryPreloaded = false; catInput = document.getElementById('catInput'); if ( catInput ) { for(var i = 0; i < catInput.length; i++) { if ( catInput.options[i].value == this.parameters[2] ) { categoryPreloaded = true; if ( this.submitted && catInput.selectedIndex != i ) { catInput.parentNode.appendChild(document.createTextNode("Edit conflict: " + this.parameters[2])); } else { catInput.selectedIndex = i;                       } }               }            }            if ( !categoryPreloaded ) { catInputText = document.getElementById('catInputText'); if ( catInputText ) { if ( this.submitted ) { if ( catInputText.value != this.parameters[2] ) { catInputText.parentNode.appendChild(document.createTextNode("Edit conflict: " + this.parameters[2])); }                   } else { catInputText.value = this.parameters[2]; }               }            }        }

if ( this.parameters[3] != undefined ) { iconInput = document.getElementById('iconInput'); if ( iconInput ) { if ( this.submitted ) { if ( iconInput.value != this.parameters[3] ) { iconInput.parentNode.appendChild(document.createTextNode("Edit conflict: " + this.parameters[3])); }               } else { iconInput.value = this.parameters[3]; }           }        }        if ( this.parameters[4] != undefined ) { importanceInput = document.getElementById('importanceInput'); if ( importanceInput ) { for(var i = 0; i < importanceInput.length; i++) { if ( importanceInput.options[i].value == this.parameters[4] ) { if ( this.submitted && importanceInput.selectedIndex != i ) { element = document.getElementById('importanceInput'); if ( element ) { element.parentNode.appendChild(document.createTextNode("Edit conflict: " + this.parameters[4] )); }                       } else { importanceInput.selectedIndex = i;                       } }               }            }        }        if ( this.parameters[5] != undefined ) { commentsInput = document.getElementById('commentsInput'); if ( commentsInput ) { if ( this.submitted ) { if ( commentsInput.value != this.parameters[5] ) { commentsInput.value += this.parameters[5]; }               } else { commentsInput.value = this.parameters[5]; }           }        }

ratebutton = document.getElementById('rate_button'); if ( ratebutton ) ratebutton.disabled = false;

};

this.getTalkProp = function {

var req = sajax_init_object; req.open("GET", wgServer + wgScriptPath + "/api.php?format=json&action=query&prop=revisions|info&rvprop=timestamp&intoken=edit&indexpageids&titles="                  + wgFormattedNamespaces["1"] +  ":" + wgTitle , true); _self = this; req.onreadystatechange = function { if (req.readyState == 4 && req.status == 200) { var response = eval('(' + req.responseText + ')'); _self.edittoken = response['query']['pages'][response['query']['pageids'][0]]['edittoken']; _self.starttimestamp = response['query']['pages'][response['query']['pageids'][0]]['starttimestamp']; if ( response['query']['pageids'][0] == "-1" ) { _self.basetimestamp = _self.starttimestamp; } else { _self.basetimestamp = response['query']['pages'][response['query']['pageids'][0]]['revisions']['0']['timestamp']; _self.scanTalkPage(response['query']['pages'][response['query']['pageids'][0]]['lastrevid']); }           }        }        req.send(null); };

this.scanTalkPage = function(currid) { var req = sajax_init_object; var _self = this; req.onreadystatechange = function { if (req.readyState == 4) { if ( req.status == 200) { _self.searchForRated(req.responseText); }               _self.preloadValues; }       };        //we don't know if we're on the article or its talk page, but wgTitle return the page name without the namespace, so it doesn't matter req.open("GET", wgServer + wgScript + "?title=" + wgFormattedNamespaces["1"] + ":" + wgTitle + "&action=raw&oldid=" + currid, true); req.send(null); };

this.updateArticle = function(rating) { var req = sajax_init_object; req.open("GET", wgServer + wgScriptPath + "/api.php?format=json&action=query&prop=revisions|info&rvprop=timestamp&intoken=edit&indexpageids&titles="                  + wgTitle , true); _self = this;

var articletoken; var articlestarttime; var articleedittime;

req.onreadystatechange = function { if (req.readyState == 4 && req.status == 200) { var response = eval('(' + req.responseText + ')'); articletoken = response['query']['pages'][response['query']['pageids'][0]]['edittoken']; articlestarttime = response['query']['pages'][response['query']['pageids'][0]]['starttimestamp']; if ( response['query']['pageids'][0] != "-1" ) { articleedittime = response['query']['pages'][response['query']['pageids'][0]]['revisions']['0']['timestamp']; var currid = response['query']['pages'][response['query']['pageids'][0]]['lastrevid'];

var req2 = sajax_init_object;

req2.onreadystatechange = function { if (req2.readyState == 4) { if ( req2.status == 200) { var articletext = ArticleRatings[rating]['template'] + req2.responseText.replace(//g,""); var comment = "Added brainstar";

var params = "action=edit&format=json&title=" + encodeURIComponent(wgTitle) + ((wgUserGroups.indexOf("bot") == -1) ? "" : "&bot=1" ) + "&text=" + encodeURIComponent(articletext) + "&summary=" + encodeURIComponent(comment) + "&token=" + encodeURIComponent(articletoken) + "&starttimestamp=" + encodeURIComponent(articlestarttime) + "&basetimestamp=" + encodeURIComponent(articleedittime);

var req3 = sajax_init_object;

req3.onreadystatechange = function { if (req3.readyState == 4) { if ( req3.status == 200) { var response = eval('(' + req3.responseText + ')'); if ( response['edit'] != undefined && response['edit']['result'] != undefined && response['edit']['result'] == "Success" ) { window.location.reload; } else if ( response['error'] != undefined && response['error']['code'] != undefined && response['error']['code'] == "editconflict") { alert('Edit conflict detected, please reload and try again.'); } else if ( response['error'] != undefined && response['error']['code'] != undefined && response['error']['info'] != undefined) { alert('Error editing talk page: ' + response['error']['info'] ); } else { alert('Error editing talk page: ' + req3.responseText ); }                                       }                                    }                                };                                req3.open("POST",wgServer+wgScriptPath+"/api.php",true); req3.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); req3.setRequestHeader('Connection', 'keep-alive'); req3.setRequestHeader('Content-length', params.length); req3.send(params);

}                       }                    };

req2.open("GET", wgServer + wgScript + "?title=" + wgTitle + "&action=raw&oldid=" + currid, true); req2.send(null); }           }        }        req.send(null);

};

this.rate = function { ratebutton = document.getElementById('rate_button'); ratebutton.disabled = true;

var rating = document.getElementById("ratingInput").value; var cat = ""; if (document.getElementById("catInputText").value != "") { cat = document.getElementById("catInputText").value; } else { if ( document.getElementById("catInput") ) { cat = document.getElementById("catInput").value; }       }        var icon = document.getElementById("iconInput").value; var imp = document.getElementById("importanceInput").value; var comments = document.getElementById("commentsInput").value;

var pr = "\n\n";

var comment = (this.modified ? "Changed" : "Added") + " article rating " + (this.modified ? "to " : "") + ArticleRatings[rating]['comment'] + ", " + ArticleImportance[ArticleImportanceNames[imp]]['comment'] + ( cat != "" ? ", in category " + cat : ", uncategorized" ) + " using HotArticleRate";

var params = "action=edit&format=json&title=" + encodeURIComponent(wgFormattedNamespaces["1"] + ":" + wgTitle) + ((wgUserGroups.indexOf("bot") == -1) ? "" : "&bot=1" ) + "&text=" + encodeURIComponent(pr + this.textToSave.replace(/^\s+/, '')) + "&summary=" + encodeURIComponent(comment) + "&token=" + encodeURIComponent(this.edittoken) + "&starttimestamp=" + encodeURIComponent(this.starttimestamp) + "&basetimestamp=" + encodeURIComponent(this.basetimestamp);

var req = sajax_init_object; var _self = this; req.onreadystatechange = function { if (req.readyState == 4) { if ( req.status == 200) { var response = eval('(' + req.responseText + ')'); if ( response['edit'] != undefined && response['edit']['result'] != undefined && response['edit']['result'] == "Success" ) { _self.updateArticle(rating); } else if ( response['error'] != undefined && response['error']['code'] != undefined && response['error']['code'] == "editconflict") { //alert('Edit conflict detected, please reload and try again.'); _self.getTalkProp; } else if ( response['error'] != undefined && response['error']['code'] != undefined && response['error']['info'] != undefined) { alert('Error editing talk page: ' + response['error']['info'] ); ratebutton = document.getElementById('rate_button'); if ( ratebutton ) ratebutton.disabled = false; } else { alert('Error editing talk page: ' + req.responseText ); ratebutton = document.getElementById('rate_button'); if ( ratebutton ) ratebutton.disabled = false; }               }            }        };        req.open("POST",wgServer+wgScriptPath+"/api.php",true); req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); req.setRequestHeader('Connection', 'keep-alive'); req.setRequestHeader('Content-length', params.length); this.submitted = true; req.send(params); };

this.buildForm = function { this.form = document.createElement("form"); this.form.id = "ratingForm"; var fieldset = document.createElement("fieldset") this.form.appendChild(fieldset);

var _self = this; this.form.onsubmit = function { _self.rate; return false; };

var element; var option;

element = document.createElement("legend"); element.appendChild(document.createTextNode("Rate this article")); fieldset.appendChild(element);

var table = document.createElement("table"); fieldset.appendChild(table); var tbody = document.createElement("tbody"); table.appendChild(tbody);

var trow; var tcell;

trow = document.createElement("tr"); tcell = document.createElement("td"); tcell.className = "error"; tcell.innerHTML = 'Please disable this gadget and enable the one above it instead.'; tcell.colSpan="2"; trow.appendChild(tcell); tbody.appendChild(trow);

trow = document.createElement("tr"); tcell = document.createElement("td"); tcell.className = "mw-label";

element = document.createElement("label"); element.htmlFor = "ratingInput"; element.appendChild(document.createTextNode("Rating:")); tcell.appendChild(element); trow.appendChild(tcell);

tcell = document.createElement("td"); tcell.className = "mw-input";

element = document.createElement("select"); element.id = "ratingInput";

for (var i=0; i<=MaxRatings; ++i) { option = document.createElement("option"); option.value = ArticleRatings[i]['value']; option.appendChild(document.createTextNode(ArticleRatings[i]['option'])); element.appendChild(option); }       tcell.appendChild(element);

trow.appendChild(tcell); tbody.appendChild(trow);

trow = document.createElement("tr"); tcell = document.createElement("td"); tcell.className = "mw-label";

element = document.createElement("label"); element.appendChild(document.createTextNode("Category:"));

//TODO: load categories via api if we're on the talk page. var categories = wgCategories; categories = categories.filter(function(i) {return !(ArticleRatingCats.indexOf(i) > -1);});

if ( categories.length > 0 && wgNamespaceNumber == 0 ) {

element.htmlFor = "catInput"; tcell.appendChild(element); trow.appendChild(tcell);

tcell = document.createElement("td"); tcell.className = "mw-input";

element = document.createElement("select"); element.id = "catInput";

for (var c in categories) { option = document.createElement("option"); option.value = categories[c]; option.appendChild(document.createTextNode(categories[c])); element.appendChild(option); }

tcell.appendChild(element); trow.appendChild(tcell); tbody.appendChild(trow);

trow = document.createElement("tr"); tcell = document.createElement("td"); tcell.className = "mw-label";

element = document.createElement("label"); element.appendChild(document.createTextNode("Other category:"));

}

element.htmlFor = "catInputText"; tcell.appendChild(element); trow.appendChild(tcell);

tcell = document.createElement("td"); tcell.className = "mw-input";

element = document.createElement("input"); element.id = "catInputText"; element.size = "45"; tcell.appendChild(element); trow.appendChild(tcell); tbody.appendChild(trow);

if ( categories.length > 0 && wgNamespaceNumber == 0 ) { trow = document.createElement("tr"); tcell = document.createElement("td"); trow.appendChild(tcell); tcell = document.createElement("td"); tcell.className = "htmlform-tip"; tcell.appendChild(document.createTextNode("Other category will override the category selected in the dropdown box.")) trow.appendChild(tcell); tbody.appendChild(trow); }

trow = document.createElement("tr"); tcell = document.createElement("td"); tcell.className = "mw-label";

element = document.createElement("label"); element.appendChild(document.createTextNode("Icon (optional):")); element.htmlFor = "iconInput"; tcell.appendChild(element); trow.appendChild(tcell);

tcell = document.createElement("td"); tcell.className = "mw-input";

element = document.createElement("input"); element.id = "iconInput"; element.size = "45"; tcell.appendChild(element); trow.appendChild(tcell); tbody.appendChild(trow);

trow = document.createElement("tr"); tcell = document.createElement("td"); trow.appendChild(tcell); tcell = document.createElement("td"); tcell.className = "htmlform-tip"; tcell.innerHTML = 'The icon defaults to "Icon category.svg". If "Icon category.svg" doesn\'t exist, consider making a redirect to an appropriate icon in Category:Portal icons instead of specifying an icon explicitly.'; trow.appendChild(tcell); tbody.appendChild(trow);

trow = document.createElement("tr"); tcell = document.createElement("td"); tcell.className = "mw-label";

element = document.createElement("label"); element.htmlFor = "importanceInput"; element.appendChild(document.createTextNode("Importance:")); tcell.appendChild(element); trow.appendChild(tcell);

tcell = document.createElement("td"); tcell.className = "mw-input";

element = document.createElement("select"); element.id = "importanceInput";

for (var i=0; i<=MaxImportance; ++i) { option = document.createElement("option"); option.value = ArticleImportance[i]['value']; option.appendChild(document.createTextNode(ArticleImportance[i]['option'])); element.appendChild(option); }       tcell.appendChild(element);

trow.appendChild(tcell); tbody.appendChild(trow);

trow = document.createElement("tr"); tcell = document.createElement("td"); tcell.className = "mw-label";

element = document.createElement("label"); element.htmlFor = "commentsInput"; element.appendChild(document.createTextNode("Comments (optional):")); tcell.appendChild(element); trow.appendChild(tcell);

tcell = document.createElement("td"); tcell.className = "mw-input";

element = document.createElement("textarea"); element.id = "commentsInput"; element.rows = "10"; element.placeholder = "Some editorial comments on what would improve the article."; tcell.appendChild(element); trow.appendChild(tcell); tbody.appendChild(trow);

trow = document.createElement("tr"); tcell = document.createElement("td"); tcell.style.paddingTop = "1em"; trow.appendChild(tcell); tcell = document.createElement("td"); tcell.className = "mw-submit"; tcell.style.paddingTop = "1em"; element = document.createElement("button"); element.id = "rate_button"; element.appendChild(document.createTextNode("Rate")); tcell.appendChild(element); trow.appendChild(tcell); tbody.appendChild(trow); };

this.toggleForm = function { tempform = document.getElementById("ratingForm"); if ( tempform ) { //remove the form from the page and store it in this.form this.form = tempform.parentNode.removeChild(tempform); document.getElementById("ca-rate").className = ''; ratingbox = document.getElementById("ratingbox"); if ( ratingbox ) { ratingbox.style.display = this.display; }           return; }       content = document.getElementById("content"); bodyContent = document.getElementById("bodyContent"); //bail out if we can't insert the form if ( !content || !bodyContent ) return; ratingbox = document.getElementById("ratingbox"); if ( ratingbox ) { this.display = ratingbox.style.display; ratingbox.style.display = "none"; }

//check if we already have the form var firstTime = false; if ( !this.form ) { //we need to construct the form firstTime = true; this.buildForm; }       content.insertBefore(this.form, bodyContent); document.getElementById("ca-rate").className = 'selected'; if ( firstTime ) { this.getTalkProp; }   };

this.setup = function { if ( wgNamespaceNumber != 0 && wgNamespaceNumber != 1) return; //exit if we're on the main page or its talk page if ( wgTitle == wgMainPageTitle ) return; edittab = document.getElementById("ca-edit"); //if we can't edit the page, we won't be able to rate it. if ( !edittab ) return;

var ratebutton = document.createElement("a"); ratebutton.title = "Rate this article"; var ratespan = document.createElement("span"); ratespan.appendChild(document.createTextNode("Rate")); ratebutton.appendChild(ratespan); var _self = this; ratebutton.onclick = function { _self.toggleForm; }; var holdingtab = document.createElement("li"); holdingtab.id = "ca-rate"; holdingtab.appendChild(ratebutton); if ( edittab.nextSibling ) { edittab.parentNode.insertBefore(holdingtab,edittab.nextSibling); } else { edittab.parentNode.appendChild(holdingtab); }   }; }

function setupHAR { HAR.setup; }

addOnloadHook(setupHAR);

//