Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if a frame is loaded using javascript? - not onload, not iframe

The problem: Older knowledgebase software that, for whatever reason, has links that are broken. It is a series of nested frames. Some point to the correct target, some do not, and many are just broken. It makes using the knowledgebase cumbersome when it doesn't work smoothly

What I'm trying to acomplish: I want to determine when the specific frame has loaded and then parse the frame's document replacing the anchor tags with correct hrefs and targets.

Resources and limitations: I have access to some of the .aspx pages. The one I'm targeting now contains a framset which loads the knowledgebase document. The src of this frame however does not appear to be an actual .aspx page (physical file) - unsure how it is generated and unsure how the documents are stored. I see the src listed but can't find it on the webserver to which I have access.

Basic info: Pages are loaded using .aspx (I don't understand parts of this well and don't have access to anything much deeper). The .aspx page has a frameset that gets built when the page is loaded.

Sample Framset code from the .aspx file:

    <FRAMESET id="FrameSetMainView" runat="server" border="0" framespacing="0" frameborder="0">
    <!-- This frame set is defined and generated in the code -->
    </FRAMESET>

I've tried adding onload in the FRAMESET tag (this causes the page to error when trying to load). The frameset takes over the body so I can't add inline script to the bottom of the page to make it run after loading either.

Additionally, b/c of the age of the product - it is forced into compatibility mode. So IE7 equivalent support has to be used. (no addeventlistener option)

Current Strategy: What I think I can get working, but feels gimicky as all be - adding script into the <head>. Something along the lines of:

    <SCRIPT>
    function load(){
        var frameset = window.frames;
        if(frameset.length > 0){ // frames have loaded - commence replacement

        }else{ // frames not loaded
            setTimeout(load,1000); // wait 1 sec, try again
        }
    }

    load();
    </SCRIPT>

Other solutions?

like image 789
lusteri Avatar asked Apr 14 '16 21:04

lusteri


1 Answers

Use the onreadystatechange event

Yes, there is reliable way to solve this problem without resorting to timers or other ticks. When the page loads assign a handler to each frame "onreadystatechange" event. And you must also call it once to ensure that it is applied to frames which have already loaded. The code below was tested in IE compatibility modes 5,7,8,9,10 and worked as expected (fails in IE11). It was also tested with slow loading frames without problem.

References:

  • Microsoft - onreadystatechange event
  • Microsoft - Specifying legacy document modes
  • w3.org - Frameset Document Type Definition

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=7" />
  <title>Demo</title>
  <script type="text/javascript">
    window.onload = function() {
      for (var i = 0; i < window.frames.length; i++) {

        (function(frame) {

          // called whenever a frame is loaded or reloaded
          frame.onreadystatechange = function() {
            if (frame.readyState === 'complete') {
              updateLinks(frame);
            }
          }

          // call once to apply to already loaded frames
          frame.onreadystatechange();

        })(window.frames[i].frameElement);
      }
    }

     // modify the links within the frame
    function updateLinks(frame) {
      var i, links, doc;
      doc = frame.contentDocument || frame.contentWindow.document;
      links = doc.getElementsByTagName('A');
      for (i = 0; i < links.length; i++) {
        // modify the links here
        links[i].href += '?time=' + (new Date()).getTime();
      }
      console.info('modified ' + links.length + ' links in frame ' + frame.src);
    }
  </script>
</head>
<frameset cols="*,*">
  <frame src="frameLeft.html">
    <frame src="frameRight.html">
</frameset>

</html>
like image 63
Roberto Avatar answered Sep 24 '22 14:09

Roberto