8

I have a userscript (for Chrome) that I am using to format duolingo's practice pages for me. It just applies a single line of css with

jQ(document).ready(function(){
    jQ('#start-button').css({"float": "left", "margin-right": "10em"});
});

And this works just fine the first time I come to the page. But they use Ajax to avoid page reloads. And the url does change, so if I detect that, I can refresh the css change and not lose the formatting with this site navigation pattern.

Anyone happen to know a good way to detect it?

edit: full user script implementing the popular solution several pointed out at first (which is not working):

// ==UserScript==
// @name         duolingo
// @namespace    http://your.homepage/
// @version      0.1
// @description  reformat /skills to not start timed practice by default
// @author       You
// @include      /^https?\:\/\/www\.duolingo\.com\/(skill|practice)?\/?.*/
// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
// @grant        none
// ==/UserScript==

window.jQ=jQuery.noConflict(true);

jQ(document).ready(function(){
    style_duolingo();
});
jQ(window).bind('hashchange', function() {
    style_duolingo();
});
jQ(document).ajaxComplete(function() {
    style_duolingo();
});


function style_duolingo() {
    jQ('#start-button').css({"float": "left", "margin-right": "10em"});
    console.log("Tampermonkey script: wrote css change");
}

edit #2:

For bounty reward

Please provide a working solution that does not load external libraries (I'd like to know what I am missing, not keep it in a black box), and solves the issue using events (no interval-based solution). If events (bizarrely) cannot be used, please provide the correction solution and the reason why events are not being triggered.

4
  • Does this help? stackoverflow.com/questions/6390341/how-to-detect-url-change Commented Feb 26, 2016 at 15:18
  • What is the parameter for type that you are passing in your AJAX call? Commented Mar 14, 2016 at 11:00
  • Perhaps this doesn't work at all on the target scenario, but would it be possible to insert a css line with !important annotation $('head').append("<style type='text/css'> #start-button{ float: left !important; margin-right: 10em; !important}</style>");? Commented Mar 14, 2016 at 12:14
  • yeah I've done that sort of this from time to time. Usually, that is a mistake, you can be more specific in your CSS, and failing that, you could remove the offending selector once you locate it with jQuery. However, it can be injected programmatically by the site, and that doesn't have to happen once only — so sometimes it really is important in userscript. Commented Mar 14, 2016 at 12:47

5 Answers 5

3
+50

To change the url Duolingo uses history.pushstate. I recommend you galambalazs answer to similar question

This is his code:

(function(history){
    var pushState = history.pushState;
    history.pushState = function(state) {
    if (typeof history.onpushstate == "function") {
        history.onpushstate({state: state});
    }

    //Custom code here
    style_duolingo();

    return pushState.apply(history, arguments);
}
})(window.history);
Sign up to request clarification or add additional context in comments.

7 Comments

this is half right. It works when going from the main listing of practice exercises to the practice. It does not work when going from the end of a practice to continue, then to the next practice.
Perhaps we are missing something here. Can you fire the following code and look into browser console $('body').on('change', function(){console.warn('App changed')});
$('body').on('change', function(){console.warn('App changed')}); [<body class=​"global-en compact-enabled" lang=​"en" style=​"overflow:​ auto;​">​…​</body>​] VM1999:51 Tampermonkey script: wrote css change the last line is from my script. This is despite the fact that it does not actually change the CSS!
actually, even when it does change the CSS, the results look the same: $('body').on('change', function(){console.warn('App changed')}); [<body class=​"global-en compact-enabled" lang=​"en">​…​</body>​] e365420…-duolingo.js:3 Duolingo is hiring software engineers: https://www.duolingo.com/jobs /gcm-service-worker.js:1 GET https://www.duolingo.com/gcm-service-worker.js net::ERR_FILE_EXISTS VM6336:55 Tampermonkey script: wrote css change
the code was only to show you if changed log warning shows on every page change. I see that the in some cases URL changes, but not always. Did you try to run your function inside body change listener like this: $('body').on('change', function(){ style_duolingo() }); If this covers your other 50% of "working right" combine it with history pushstate
|
1

Use it like this:

jQ(document).ready(function(){

    jQ(window).bind('hashchange', function() {
        jQ('#start-button').css({"float": "left", "margin-right": "10em"});
    });

});

1 Comment

this seems like it should be the answer, but it in fact does not work.
1

Since you're only adjusting styling, you're better off using Stylish Chrome extension that allows you to tamper with css. You would then add

@-moz-document domain("www.duolingo.com") {
    #start-button {
        float: left;
        margin-right: 10em;
    }
}

Note @-moz-document follows userstyles convention and is importable into Chrome. There's actually a few published userstyles for duolingo already :)

1 Comment

I used to use stylish —I liked it a lot, but I've since switched to loading jquery in my pages through userscript by default, because it is much more flexible. The only reason I moved away from stylish was that at the time, you could not easily specify that rules should not match the gui elements stylish shows you in page when stylish the page. I understand (and think I can see in your example) that they did eventually fix that though.
0

There also seems to a plugin that allows the same if the hashchange event on window fails.

Comments

0

You can check for any url change by checking the url and seeing if that matches the previous url, every second. It might look like this:

var oldURL = window.location.url;
var newURL = oldURL;
window.setInterval(function(){
    newURL = window.location.url;
    if(oldURL !== newURL){
        //the URL has changed
        oldURL = newURL; //to prevent the above from continuously firing
    }
}, 1000);// checks every 1000 ms (1s)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.