javascript - How to make my userscript work on specific pages of a site that uses the history api? -


(this in continuation of this discussion)

i've been trying make script (for instagram) shows how many images out of total visible when viewing profile page (example profile). shows counter in upper right corner of screen , supports infinite scrolling.

here is:

// ==userscript== // @name        instagram - visible images counter // @name        instagram - visible images counter // @include     https://instagram.com/* // @grant       none // ==/userscript==  var p = document.getelementsbyclassname('-cx-private-postsgriditem__root'); var m = document.getelementsbyclassname('-cx-private-postsstatistic__count'); var ww = m[0].innerhtml.replace(/(\d+),(?=\d{3}(\d|$))/g, "$1");                       // regex strip thousand comma seperator posts number var z = (p.length/ww)*100; var counter = p.length+' / '+m[0].innerhtml +' ' +z.tofixed(1) + '%'; var div = document.createelement("div"); div.style.top = "1px"; div.style.right = "1px"; div.style.position = "fixed"; document.body.appendchild(div); div.id="mycounter"; mycounter = document.getelementbyid('mycounter'); mycounter.innerhtml = counter; mycounter.style.top = "1px"; mycounter.style.right = "1px"; mycounter.style.position = "fixed";  /// --------------------------------- /// mutation observer -monitors posts grid infinite scrolling event-  /// --------------------------------- var target1 = document.queryselector('.-cx-private-postsgrid__root'); var observer1 = new mutationobserver(function (mutations) {   mutations.foreach(function (mutation) {     p=document.getelementsbyclassname('-cx-private-postsgriditem__root');     m = document.getelementsbyclassname('-cx-private-postsstatistic__count');     ww = m[0].innerhtml.replace(/(\d+),(?=\d{3}(\d|$))/g, "$1");     z = (p.length/ww)*100;     counter = p.length+' / '+m[0].innerhtml +' ' +z.tofixed(1) + '%';         mycounter.innerhtml = counter;   }); }) var config = { attributes: true, childlist: true, characterdata: true } observer1.observe(target1, config); 

my script works ok, have issue:

instagram, after it's recent redesign -i think-, seems use single-page application workflow,
i.e fetches clicked link content , replaces current page it, , changes browser's current url, all without reloading page.

so, script works when open profile url in new tab.
it doesn't work when opening profile url in same tab while in timeline (https://instagram.com)).
in other words, doesn't work (after open https://instagram.com , login)
if click view profile url of user follow, eg. https://instagram.com/instagram/

how can fix this?

someone has kindly suggested these 3 ways:

  1. try event handler event fired instagram site pjax:end on github, example.
  2. use mutation observer waits profile-specific html element.
  3. or use setinterval check location.href periodically.*


so, i've been trying various approaches (including suggestions #2 , #3) no success.
(about suggestion #1: can't find element similar pjax:end).
so, what i've tried far:


  1. (based on suggestion #2) adding mutation observer check whether element shows 'posts count' element exists, , if yes, run code.

    var target0 = document.queryselector('.-cx-private-postsstatistic__count');  var observer0 = new mutationobserver(function (mutations) {   mutations.foreach(function (mutation) {             mycode();   }); })  var config0 = { attributes: true, childlist: true, characterdata: true }  observer0.observe(target0, config0); 

  1. (based on suggestion #3) checking location.href every 1 second whether current location profile (i.e. not timeline (https://instagram.com/). if true clear periodic function , run previous code.

    var interval = setinterval(testhref() , 1000);  function testhref(){     if (location.href != "https://instagram.com/")         clearinterval(interval);         mycode();    } 

  1. simply adding 1 sec delay on top of code (and changing @require rule apply on profile urls // @include https://instagram.com/*/), no success:

    settimeout(function() { }, 1000); 

  1. i've tried using waitforkeyelements utility function, detects , handles ajaxed content.
    thought it's easier implement way, working simple "wait until element exists" (i used main profile pic selector wait for, because couldn't find relevant ajax selector. didn't use jnode inside code).
    enclosed whole code in single function visiblecounter, , added waitforkeyelements line (see below), unfortunately doesn't work:

    waitforkeyelements (".-cx-private-profilepage__avatar", visiblecounter);           function visiblecounter(jnode){     mycode() } 

i solved using arrive.js library. provides events watch dom elements creation , removal. makes use of mutation observers internally. library not depend on jquery, can replace jquery elements in examples below pure javascript elements , work fine.

i quote comment author:

i've found mutationobserver api bit complex i've built library, arrive.js, provide simpler api listen elements creation/removal.

as 2 of uses:

watch elements creation:

use arrive event watch elements creation:

// watch creation of element satisfies selector ".test-elem" $(document).arrive(".test-elem", function() {     // 'this' refers newly created element     var $newelem = $(this); }); 

and

watch elements removal

use leave event watch elements removal. first arugument leave must not descendent or child selector i.e. cannot pass .page .test-elem, instead, pass .test-elem. it's because of limitation in mutationobserver's api.

// watch removal of element satisfies selector ".test-elem" $(".container-1").leave(".test-elem", function() {     var $removedelem = $(this); });  [1]: https://github.com/uzairfarooq/arrive 

and, complete script:

// ==userscript== // @name        instagram - visible images counter // @include     https://www.instagram.com/* // @grant       none // @require     https://code.jquery.com/jquery-3.0.0.min.js // @require     https://greasyfork.org/scripts/21927-arrive-js/code/arrivejs.js?version=139586 // ==/userscript==     function showcounter() {     var visiblecount = $( "a[href*='taken-by']" ).length;   // count of visible images     var totalstring = $("span:contains('posts')").eq(1).children().eq(0).html();    // 'total' value (it's string)     var total = totalstring.replace(/(\d+),(?=\d{3}(\d|$))/g, '$1');    // apply regex 'total' string strip thousand comma seperator     if (visiblecount > total){         visiblecount = total;     }     var visiblepercent = ((visiblecount / total) * 100).tofixed(1); // visible images percentage     var counter = visiblecount + ' / ' + totalstring + ' ' + visiblepercent + '%';     return counter; }     function creatediv(){     // creation of counter element     document.body.appendchild(div);     div.innerhtml = showcounter();      // initial display of counter     div.style.top = '1px';     div.style.right = '1px';     div.style.position = 'fixed'; }    function observer(){      /// ---------------------------------     /// mutation observer -monitors posts grid infinite scrolling event-.     /// ---------------------------------     observer1 = new mutationobserver(function(mutations) {         mutations.foreach(function(mutation) {             div.innerhtml = showcounter();                      // in each infinite scrolling event, re-calculate counter         });     }).observe($('article').children().eq(1).children()[0],     // target of observer         {             // attributes: true,             childlist: true,             // characterdata: true,         }); // config of observer  }       var div = document.createelement('div');    // global variable var observer1;                              // global variable  if (document.url !== 'https://www.instagram.com/' &&     document.url.indexof('https://www.instagram.com/p/') === -1 ){     creatediv();     observer(); }    $(document).arrive('article ._5axto', function() {      // 'article .5axto'     creatediv();     observer(); });    $(document).leave('article ._5axto', function() {     div.remove();     observer1.disconnect(); }); 

Comments

Popular posts from this blog

c# - Validate object ID from GET to POST -

node.js - Custom Model Validator SailsJS -

php - Find a regex to take part of Email -