0

Here's the plot, which is a True Story (a problem that exists for a real person, that is - me):

You are working on a large enterprise site, which includes a lot of JavaScript and specifically jQuery code you don't have any control of, and can't possibly change (good luck even finding out who wrote it, or why). Layers of authentication and authority are involved, so just pretend it's written in stone and you can't touch it.

Somewhere in this code, there is an event that scrolls the document to the top of the page after it has loaded. "OK, that sounds harmless" one might think - but it is now your task to scroll the page to a specific item based on a query string or anchor.

Everything works fine generally, but when you click a link that goes to example.com/list#item11, the browser works as expected and you go directly down to the item you want to link to...and then, whammo, the page instantly jumps back to the top of the page.

Now, you might say "well, that's what document.ready() is for!" ...to your horror, you find that the rogue event comes along anyway.

After Stack Overflow searching for an even later event to tie into, you find this gem:

$(document).ready(function(e) {
  $(window).load(function(e){ });
}

And surely, this will definitely work! Only, it does not. You try return false and e.preventDefault(), but that does nothing for you here.

All you can be sure of is that this rogue scrolling event occurs after your code runs, after the DOM is ready, and definitely after the window.load() event. You are sure of nothing else.

Can you assassinate this rogue event? Is there some mechanism to intercept scroll events and prevent them from occurring? Can you link into some event later event, like "the DOM is ready, the window is loaded, the page is settled, the children are in bed, and all other events are done being handled.... event()`"?

The only solutions I can imagine now are "give up - scrolling behavior on page load isn't going to work in your scenario", "use a timer and wait! then commit seppuku for being such a dirty hack!", and "ninja-assassination mission!" (since I don't know who wrote the offending code, I'd have to settle for killing their code instead of them - and I'm sure they had their reasons, or have already been assassinated... or at least waiting for the code to pass and do my thing).

Is there some Better Way, some hard to find function, some last resort that invokes the arcane Dark Lords of Reflection, or is it time to give up and solve the problem another way?

TLDR;

  1. How do you stop a disruptive scripted event - like scrolling - from occurring when you can't change the code that is causing it? Acceptable answers include how to make certain your code runs after - without using a timer hack! - and/or if your code always runs first how do you prevent the later code from messing up yours?

  2. It might be helpful to find out how the event is defined, and what events are firing, but I feel that this is a separate question and may not necessarily be required to fix the situation. For illustration purposes, assume there are thousands of active events and listeners spread out across dozens of minified script files. It may just be so hard to narrow down what exactly is happening as to be too much trouble to even try.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
BrianH
  • 2,140
  • 14
  • 20
  • 2
    There's several that remove event handlers, like [`unbind`, `off`, `undelegate`](http://api.jquery.com/category/events/event-handler-attachment/). You probably need to know exactly how it's being added or run before you karate fu it, though. – Jared Farrish Jan 21 '14 at 22:28
  • possible duplicate of [Listen to all javascript events](http://stackoverflow.com/questions/3489433/listen-to-all-javascript-events) – Fraser Jan 21 '14 at 22:29
  • 1
    @Fraser This question is a *bit* more specific than what you're suggesting... – Rob W Jan 21 '14 at 22:30
  • 1
    @Rob W - Don't vote to close then. It is the same question but just using flowery language to describe the simple problem of locating when/where an event is fired. – Fraser Jan 21 '14 at 22:31
  • 2
    Why use 50 words when 500 will do? – Joe Jan 21 '14 at 22:32
  • Sounds like you should introduce version control instead of worrying about dirty hacks. I really think you should find out why the first code was implemented an fix it if needed. Or we'll see the next guy after you in here posting this example with your added code. – Jonathan Jan 21 '14 at 22:33
  • If it was added with JQuery you can definitely kill it, [List All Events](http://stackoverflow.com/a/447106/2464634) on the window or document and destroy the offending listener. – Preston S Jan 21 '14 at 22:37
  • you can use the onscoll event to avoid a timer and maybe even the visual scrolling of the page. – dandavis Jan 21 '14 at 22:47
  • @JaredFarrish That is a fair point, I hadn't considered that how it was created might change what can be done to undo it. – BrianH Jan 22 '14 at 17:13
  • @Fraser While that question is useful, and the accepted answer may help in finding the event itself (I'll certainly be trying it!), it does not in any way address the actual killing - or prevention - itself, which is really the core goal I'm after. – BrianH Jan 22 '14 at 17:17
  • @Joe It's "which 50" that is the hard part; figuring out which 50 indeed will likely result from solving the problem! – BrianH Jan 22 '14 at 17:18
  • @Jonathan You are absolutely correct in the general case and at high levels - but the downside of large enterprises is indeed that you might never even be able to find the name of the supervisor of the division who employs the person responsible for code that is interacting with yours, much less change their code or their production methodology. Thus the difficulty I - and others - face: fixing a problem with code you can't change, even if you could find what code is the problem after all. – BrianH Jan 22 '14 at 17:21
  • @BrainDHall - you either remove the calling code or unsubscribe/replace/change the handler. There is no such concept as "killing an event". – Fraser Jan 22 '14 at 17:30

3 Answers3

2

The best solution will be to edit the source code where the ready event is declare.

if you can't, you can copy this code somewhere else and edit it.

if its totally not possible, then

you cannot unbind the ready event because that can cause problem.

you can override the window.scrollTop() function by its prototype

window.prototype.scrollTo2 = window.prototype.scrollTo;
window.prototype.scrollTo = function(){

  /*Look in the url if you have an hash tab*/
  // if yes return false
  //if not 
  window.prototype.scrollTo2()
};
Frederic Nault
  • 986
  • 9
  • 14
  • This is exactly the sort of thing that I thought might be possible, but hadn't considered even possible. +1 for that alone! This also highlights the importance of finding out just what sort of event might be causing the behavior, because if it is indeed scrollTo() this indeed kill it outright in a very targeted way! "I'll handle scroll bar events for this page, thank you - no touching!" – BrianH Jan 22 '14 at 17:25
  • Sadly, I tried: 'window.scrollTo = function(){ return false; }; window.scrollBy = function(){ return false; }; window.scrollByLines = function(){ return false; }; window.scrollByPages = function(){ return false; }; window.prototype.scrollTo = function(){ return false; }; window.prototype.scrollBy = function(){ return false; }; window.prototype.scrollByLines = function(){ return false; }; window.prototype.scrollByPages = function(){ return false; }; ', all to no avail. In the console this doesn't change the behavior at all :( – BrianH Jan 22 '14 at 18:32
  • change the prototype function not the function itselft – Frederic Nault Jan 24 '14 at 15:57
  • I tried both, just incase, but none work. I suspect it is a browser safety feature, I don't seem to be able to over-ride the functionality at all. – BrianH Jan 24 '14 at 17:03
  • Do you have the js link where the jump to top happend, I would like to take a look – Frederic Nault Jan 25 '14 at 13:01
1

Smack them with a timer if everything else fails:

$(document).ready(function() {
    window.setTimeout(function() {
        document.location = "#bottom";
    }, 200);
});

Live test case.

Ugly, but working.

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
  • It does indeed work, but it's exactly the ugliness I'm hoping to avoid :( It is certainly the simplest, and it might even end up the best - I just explicitly (in the question) want to find a different way. – BrianH Jan 22 '14 at 17:23
  • @BrianDHall wish I had better answer, but as it stands there's no real way to catch the specific code that scroll back to the top and kill it. – Shadow The GPT Wizard Jan 22 '14 at 17:27
  • You might be right, and this may indeed be the only real, working - if unpleasant - solution. It might actually be the only way to truly solve the problem with minimal side-effect, anyway! But, we will indeed see :) – BrianH Jan 22 '14 at 17:33
1

I would hook into the window.scrollTo prototype to try and catch the burglar in the act. If you know how it's done, it's easier to get rid of it.

If this rogue call is not embedded in too huge a pile of JQuery goo, it could even allow to trace the call to the original culprit, who would soon be smitten with great vengeance and furious anger.

kuroi neko
  • 8,479
  • 1
  • 19
  • 43