Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Attaching change notifier for window.location

I need to trigger a function whenever window.location.href changes but I'm running into problems. I went over the source for various watch polyfills, but I can't quite follow what was going on with the code.

if (!Object.prototype.watch) {
  Object.defineProperty(Object.prototype, "watch", {
    enumerable: false
    , configurable: true
    , writable: false
    , value: function (prop, handler) {
      var
        oldval = this[prop]
        , newval = oldval
        , getter = function () {
          return newval;
        }
        , setter = function (val) {
          oldval = newval;
          return newval = handler.call(this, prop, oldval, val);
        }
        ;
      if (delete this[prop]) { // can't watch constants
        Object.defineProperty(this, prop, {
          get: getter
          , set: setter
          , enumerable: true
          , configurable: true
        });
      }
    }
  });
}

Obviously, I don't know much about the internals of JS or reflection in general. Here is a method that works for title:

var observer = new window.MutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    change({title: mutation.target.textContent});
  });
});

observer.observe(document.querySelector('head > title'),
  { subtree: true, characterData: true, childList: true });

But I can't specify Location via a query selector and I'm pretty sure it would need to implement the node class for observer to work.

like image 314
Indolering Avatar asked Oct 20 '25 13:10

Indolering


2 Answers

In non-Firefox browsers, you cannot set a watcher on location.href. I needed to set the watcher on location.pathway, location.hash, and location.search instead.

It is also better to just reuse a function instead of writing the same one out twice. I was able to shave it down to just this:

if (!Object.prototype.watch) { //don't overwrite gecko watch function
  Object.prototype.watch = function(prop, handler) {
    var oldval = this[prop], newval = oldval,
      getter = function() {
        return newval;
      },
      setter = function(val) {
        oldval = newval;
        return newval = handler.call(this, prop, oldval, val);
      };
    if (delete this[prop]) {
      Object.defineProperty(this, prop, {
        get: getter,
        set: setter
      });
    }
  };
}
like image 130
Indolering Avatar answered Oct 23 '25 07:10

Indolering


This is a little bit of a hack, but not much more than anything else I have seen and it will work pretty much equally in all modern browsers.

var myTitle = document.title;
var myLocation = window.location.href;

setInterval(function() {
    if (myTitle != document.title || myLocation != window.location.href)
    {
        // Do something here;

        myTitle = document.title;
        myLocation = window.location.href;         
    }
}, 100);

It simply polls the properties in short intervals. To short to be visible for the user but it should also not have much CPU overhead.

like image 35
ced-b Avatar answered Oct 23 '25 06:10

ced-b



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!