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.

roberto tomás
  • 4,435
  • 5
  • 42
  • 71
  • Does this help? http://stackoverflow.com/questions/6390341/how-to-detect-url-change – Prophecies Feb 26 '16 at 15:18
  • What is the parameter for type that you are passing in your AJAX call? – Abhishek Dhanraj Shahdeo Mar 14 '16 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("");`? – Me.Name Mar 14 '16 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. – roberto tomás Mar 14 '16 at 12:47

5 Answers5

3

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);
Community
  • 1
  • 1
sulest
  • 1,006
  • 1
  • 10
  • 17
  • 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. – roberto tomás Mar 09 '16 at 22:11
  • 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')});` – sulest Mar 10 '16 at 12:23
  • `$('body').on('change', function(){console.warn('App changed')});` `[​…​​]` `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! – roberto tomás Mar 10 '16 at 15:20
  • actually, even when it does change the CSS, the results look the same: `$('body').on('change', function(){console.warn('App changed')});` `[​…​​]` `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` – roberto tomás Mar 10 '16 at 15:30
  • 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 – sulest Mar 10 '16 at 16:07
  • I think we have collectively managed to find 2 of them. Going directly to a practice page with a full page load triggers the onReady event for query, and my code worked for that. `pushState` changes also seem sometimes are used, and there the css works. But there is a 3rd time where even "onChange" isn't triggering... it makes me wonder if the Chrome browser caches some results? In any case there is still an event happening that, although CSS is applied (I see my log in the console), it's not styling the elem. — apparently it first triggers a detected event, then later renders the output. – roberto tomás Mar 10 '16 at 16:47
  • I've marked this as the answer and awarded the bounty on the basis of the fact that this was the best answer, and even if not complete, it did teach me something and improve my userscript. thank you. – roberto tomás Mar 14 '16 at 12:50
1

Use it like this:

jQ(document).ready(function(){

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

});
Atif Tariq
  • 2,650
  • 27
  • 34
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 :)

Oleg
  • 24,465
  • 8
  • 61
  • 91
  • 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. – roberto tomás Mar 14 '16 at 12:49
0

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

Prophecies
  • 723
  • 1
  • 7
  • 19
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)
Andrew
  • 1,322
  • 14
  • 20