Retrieving double redirects through MediaWiki API - javascript

I want to write a script to resolve double redirects automatically after a page move. Here is what I have started with:
(function () {
var api = new mw.Api();
api.get( {
action: 'query',
list: 'backlinks',
blpageid: mw.config.get('wgArticleId'),
blfilterredir: 'redirects',
blredirect: true,
bllimit: 500
} ).done( function (data) {
var fixed = 0;
redirects = data.query.backlinks;
for (var i=0; i<redirects.length; i++) {
var doubles = redirects[i].redirlinks;
if (doubles === undefined) {
continue;
}
for (var j=0; j<doubles.length; j++) {
console.log(doubles[j]);
fixed ++;
}
}
mw.notify(fixed);
} );
})();
The problem is that if I run this function on a page like Wikipedia:Blocking policy the script returns some pages that are not actually double-redirects, but merely redirects containing links to it.
I can check each of them to see where they are actually pointing to, but isn't there any better way? i.e. a simple method to retrieve double redirects only.

If you are happy with using python and the pywikibot framework there is https://m.mediawiki.org/wiki/Manual:Pywikibot/redirect.py which should do what you want.
Otherwise you might want to work with the output of Special:DoubleRedirects.

Related

How to create a bookmarklet with multiple functions

I'm new to creating JavaScript bookmarklets but have got a certain way in solving my problems but have got stuck on one final bit.
Basically, I want to create a bookmarklet that will replace text in 2 places in the URL - the subdomain and the URI.
I have managed to do this for the first part:
(function() {
window.location = window.location
.toString()
.replace(/^https:\/\/www\./, "https://edit.");
})();
Next, I need to grab some metadata (cab-id) from the page. I've managed to do this an print it to the console:
function getCabID() {
var metas = document.getElementsByTagName("meta");
for (var i = 0; i < metas.length; i++) {
if (metas[i].getAttribute("name") == "cab-id") {
return metas[i].getAttribute("content");
}
}
return "";
}
console.log(getCabID());
The next thing I need to do is replace the end of the url (everything from "www.xxxxxx.org.uk/*" with the following:
/EPiServer/CMS/Home#context=epi.cms.contentdata:///
I can't figure out how to do this, I'm really struggling. I've come up with the following but it's not working:
(function() {
var url=window.location.href;
stringUrl=String(url);
stringUrl=stringUrl.replace(/^https:\/\/www.xxxxxx.org.uk\/, "https://edit.xxxxxx.org.uk/EPiServer/CMS/Home#context=epi.cms.contentdata:///");
document.location=stringUrl;
})();
I'll also need to pop the cab-id at the end of all this directly after ///.
Sorry for the long question but what I need to do is:
Make the 3rd one actually work!
Combine the 3 functions
Any tips would be massively appreciated :D
As I understood your question, the following bookmarklet probably allows to combine the 2nd and 3rd steps:
javascript:(function() {
window.location.href = "https://edit.xxxxxx.org.uk/EPiServer/CMS/Home#context=epi.cms.contentdata:///" + getCabID();
function getCabID() {
var metas = document.getElementsByTagName("meta");
for (var i = 0; i < metas.length; i++) {
if (metas[i].getAttribute("name") == "cab-id") {
return metas[i].getAttribute("content");
}
}
return "";
}
})();

Objects display differently in console and act differently in Javascript

The following is a screenshot of two objects in my Chrome console. Both were created by a Javascript function that interacts with a Google Script file. The first was defined with the key-value pair, the second was defined as empty and then had key-value pairs added to it by a for-loop.
The bottom one appears empty, but is actually not. The info button tells me that it was 'evaluated just now'.
The problem is that I am sending this object to a Google Script function, and when I do that, it comes through as an empty object. Is there any way to force the object into the first form before executing the code that sends it to Google Scripts?
Setting a timeout on the execution of the Google Script call works, but only when the for loop that creates the object has finished in time.
My code looks like this:
function logIt(blob) {
var page_labs = {};
PDFJS.getDocument({data: blob}).then(function (PDFdoc) {
for (var i=1; i<=PDFdoc.numPages; i++) {
PDFdoc.getPage(i).then(function (PDFpage) {
var page_number = PDFpage.pageIndex + 1;
var labs = ''
PDFpage.getTextContent().then(function (text) {
for (var j in text.items) {
var item = text.items[j]
if (item.str.substr(0,1) == '♩') {
labs += '♩'
}
}
page_labs['Page ' + page_number.toString()] = labs
})
})
}
})
console.log({'Page 1': '♩♩♩♩♩♩♩♩♩♩♩♩'})
console.log(page_labs);
google.script.run.lofNumbers(page_labs)
}
console.log it by using JSON.stringify method,
example:
console.log(JSON.stringify(page_labs))

How do I trigger events using Meteor server side events

I am using Meteor, which uses Mongodb as its database. I have code that inserts several documents into a collection when users fill out a form. When these documents are inserted, I would like to fire some JavaScript code within the server side directories that sorts through the collection in question for documents with matching fields as the documents just inserted.
My problem is that I do not know how to fire code on the server when the new documents arrive. Would it make sense to Meteor.call a Meteor.method at the end of the code involved with inserting, with the Meteor.method called preforming the sorting code I need?
Edit:
As you can see, in the below code I'm not calling any Meteor methods as none exist yet. The vast majority of this code is simply lead up for the insert({}) at the end of the page, so I think it can be safely ignored. The only server side code I have is to declare the possibleGames mongo collection.
I am not sure what you mean by call a plain JavaScript function, my problem is getting any code firing at all.
possibleGames = new Mongo.Collection("possibleGames");
Template.meet_form.events({
"submit .meet_form": function(event, template){
event.preventDefault();
var user = Meteor.userId();
var where = event.target.where.value;
var checkedGames = [];
function gameCheck (game) {
if (game.checked === true){
checkedGames.push(game.value);
};
};
var checkedDays = [];
function dayCheck (day) {
if (day.checked === true){
checkedDays.push(day.value);
};
};
console.log(event.target.where.value)
gameCheck(event.target.dnd);
gameCheck(event.target.savageWorlds);
gameCheck(event.target.shadowRun);
console.log(checkedGames);
dayCheck(event.target.monday);
dayCheck(event.target.tuesday);
dayCheck(event.target.wednesday);
dayCheck(event.target.thursday);
dayCheck(event.target.friday);
dayCheck(event.target.saturday);
dayCheck(event.target.sunday);
console.log(checkedDays);
var whereWhat = [];
for (i = 0; i < checkedGames.length; i++) {
var prepareWhereWhat = where.concat(checkedGames[i]);
whereWhat.push(prepareWhereWhat);
};
console.log(whereWhat);
var whereWhatWhen = [];
for (a = 0; a < whereWhat.length; a++) {
var prepareWWW1 = whereWhat[a];
for (b = 0; b < checkedDays.length; b++) {
var prepareWWW2 = prepareWWW1.concat(checkedDays[b]);
whereWhatWhen.push(prepareWWW2);
};
};
console.log(whereWhatWhen);
for (i = 0; i < whereWhatWhen.length; i++) {
possibleGames.insert({
game: whereWhatWhen[i],
user: user,
created_on: new Date().getTime()
})
}
}
});
You don't need to do a meteor.call on the server because you're already on the server.
Just call a plain javascript function.
If what you want to call from your first Meteor.method is already in another Meteor.method, then refactor that function to extract out the common bit.
Some code would also help if this is still confusing.

Strange behavior checking for Web Storage availability

Here's my code:
if(typeof(Storage)!==undefined) {
// Web storage support
if(localStorage.hashes != "") {
var hashes = jQuery.parseJSON(localStorage.hashes);
for (var i = 0; i < hashes.length; i++) {
// Do stuff here
}
}
else {
var hashes = [];
}
}
else {
// No web storage support
}
I don't really know what's going on, but when I try to load the page with this code from a device for the first time, the rest of my code doesn't work the way it should. However, if I comment it out then visit the page for the first time everything works. I can then uncomment it, reload the page, and everything will continue to work. This is really the best I can describe what's happening.
I believe you could have done a little more debugging before posting this.
Have you tried logging/ adding checks (to see where exactly this issue is coming from and what the error is) ?
But since we're here, here are my tips for localStorage :
Use modernizr (http://modernizr.com/)
if(Modernizr.localstorage){ /* Your code */}
Make some generic get and set functions
function get(key) {
if(Modernizr.localstorage) {
if(localStorage[key] != null) {
return localStorage[key];
}
}
return null;
}
function set(key, value) {
if(Modernizr.localstorage) {
localStorage[key] = value;
}
return null;
}
This is pretty rough, you tweek it to make it safer and respond to your needs
Put try/catch inside your get and set functions, you don't want write operations to impact your program
I figured it out! So in the above code I check if they had localStorage available, and if they do, I just assume that they have some hashes stored in there. This obviously creates a problem on their first visit as they wouldn't have any hashes saved yet. So I have to check if they have any, if they do, then do the for loop, otherwise just set it to an empty array. Like so!
if(typeof(Storage) !== "undefined") {
// Web storage support
if(localStorage.hashes != "") {
hashes = JSON.parse(localStorage.getItem("hashes"));
if(hashes) {
for (var i = 0; i < hashes.length; i++) {
// Do Stuff
}
} else {
hashes = [];
}
}
else {
hashes = [];
}
}
else {
// No web storage support
hashes = [];
}
Thanks to jbabey for tips on cleaning up my code some!

IE Caching issue is breaking my lookup field

I'm doing a project which uses javascript to get info from a view (written in Python and using the Django interface) based on the text a user enters in a field (querying on every keyup), and then display that info back. Basically, this either displays 'no job found' or displays the name, username, and balance for that job. In Firefox, this all works great. I can enter a JobID, it tells me the ID is new, and I can create the job. I can then immediately come back to the page and enter that ID, and my lookup returns the right info about the job.
The thing is, Internet Explorer 8 is being lazy. If I type a job ID in IE8, my functions calls the lookup page (/deposits/orglookup/?q=123) and gets a value. So if, for example, it gets False, I can then create a new job with that ID. If I then browse back and enter that same number in that same lookup field, Internet Explorer does not refresh the lookup page, so it returns false again. If I browse to that lookup page, I see that false value, but if I refresh it, I get the right information again. Any idea on how I can force this query every time I type in my lookup field, and not like IE refer to the cached page?
I will add that it does not do me much good to fix this on a per-user basis, as this is an organization-wide application, so I really could use a fix I can write into my code somewhere to force IE to actually refresh the lookup page every time it is supposed to.
Here's the code for the lookup function, if it helps. It is a bit messy, but I didn't write it so I'll try to include everything relevant:
$("#id_JobID").keyup(
function(event){
//only fire gets on 0-9, kp 0-9, backspace, and delete
if (event.keyCode in { 96:1, 97:1, 98:1, 99:1, 100:1, 101:1, 102:1, 103:1, 104:1, 105:1,
46:1,48:1, 49:1, 50:1, 51:1, 52:1, 53:1, 54:1, 55:1, 56:1, 57:1, 8:1})
{
if ($("#loadimg").attr("src") != "/static/icons/loading.gif") {
$("#loadimg").attr("src", "/static/icons/loading.gif");
}
if ($("#loadimg").length < 1) {
$("#id_JobID").parent().append("<img id=loadimg src=/static/icons/loading.gif>");
}
clearTimeouts(null); //clear all existing timeouts to stop any running lookups
GetCounter++;
currLoc = window.location.href.slice(window.location.href.indexOf('?') + 1).split('/').slice(-2,-1);
if (currLoc == 'restorebatch') {
var TimeoutId = setTimeout(function() {dynamicSearch('restorelookup');}, 400);
} else {
var TimeoutId = setTimeout(function() {dynamicSearch('orglookup');}, 400);
}
//alert(TimeoutID);
TimeoutBag[GetCounter] = {
'RequestNumber': GetCounter,
'TimeoutId': TimeoutId
}
}
}
);
function clearTimeouts(TimeoutBagKeys) //TimeoutBagKeys is an array that contains keys into the TimeoutBag of Timeout's you want to clear
{
if(TimeoutBagKeys == null) //if TimeoutBagKeys is null, clear all timeouts.
{
for (var i = 0; i < TimeoutBag.length; i++)
{
if (TimeoutBag[i] != null) {
clearTimeout(TimeoutBag[i].TimeoutId);
}
}
}
else //otherwise, an array of keys for the timeout bag has been passed in. clear those timeouts.
{
var ClearedIdsString = "";
for (var i = 0; i < TimeoutBagKeys.length; i++)
{
if (TimeoutBag[TimeoutBagKeys[i]] != null)
{
clearTimeout(TimeoutBag[TimeoutBagKeys[i]].TimeoutId);
ClearedIdsString += TimeoutBag[TimeoutBagKeys[i]].TimeoutId;
}
}
}
}
function dynamicSearch(viewname) {
$(".lookup_info").slideUp();
if ($("#id_JobID").val().length >= 3) {
var orgLookupUrl = "/deposits/" + viewname + "/?q=" + $("#id_JobID").val();
getBatchInfo(orgLookupUrl);
}
else if ($("#id_JobID").val().length == 0) {
$("#loadimg").attr("src", "/static/icons/blank.gif");
$(".lookup_info").slideUp();
}
else {
$("#loadimg").attr("src", "/static/icons/loading.gif");
$(".lookup_info").slideUp();
}
}
function getBatchInfo(orgLookupUrl) {
$.get(orgLookupUrl, function(data){
if (data == "False") {
$("#loadimg").attr("src", "/static/icons/red_x.png");
$(".lookup_info").html("No batch found - creating new batch.");
$("#lookup_submit").val("Create");
$(".lookup_info").slideDown();
toggleDepInputs("on");
}
else {
$("#loadimg").attr("src", "/static/icons/green_check.png");
$("#lookup_submit").val("Submit");
$(".lookup_info").html(data);
$(".lookup_info").slideDown()
toggleDepInputs("off");
};
});
}
There are three solutions to this:
Use $.post instead of $.get.
Add a random GET parameter to your URL, e.g. ?update=10202203930489 (of course, it needs to be different on every request).
Prohibit caching on server-side by sending the right headers (if-modified-since).
You need to make the URL unique for every request. The failproof way is to introduce new GET parameter which has a timestamp as its value - so the URL is unique with every request, since timestamp is always changing, so IE can't cache it.
url = "/deposits/orglookup/?q=123&t=" + new Date().getTime()
So instead of only one parameter (q) you now have two (q and t) but since servers usually don't care bout extra parameters then it's all right
One trick that often works is to append a timestamp to the lookup URL as a querystring parameter, thus generating a unique URL each time the request is made.
var orgLookupUrl = "/deposits/" +
viewname + "/?q=" +
$("#id_JobID").val() + "&time=" + new Date().getTime();;

Categories