1

I'm trying to enhance a GUI of one of our tools, but I'm failing miserably. The UI consists of a body with multiple iFrames from which I want to select one and change the content a bit.

The problem is that when using my selector frame = $("iframe[src*='/vs/virt.jsp']"); it looks like it can't find the element.

Here's the code (doesn't do anything else than log):

// ==UserScript==
// @name UI Tweaks
// @version 0.2
// @description Does stuff
// @match https://*.local/vs/*
// @run-at          document-end
// @grant none
// @require http://code.jquery.com/jquery-latest.js
// ==/UserScript==


console.log(window.location);
console.log("before");
console.log($());
frame = $("iframe[src*='/vs/virt.jsp']");
console.log(frame.attr("id"));
console.log("after");

When running this on the page I get two page loads and it shows the location object, before and after. But the frame object is totally empty.

However, when running the same thing in Chrome developer console after the page has loaded I get the elements I'm looking for.

I've tried different ways to only load the script after page load etc, but it still does not work.

Update:

I added:

// @require     https://gist.github.com/raw/2625891/waitForKeyElements.js

Then tried this:

waitForKeyElements (
    "iframe[src*='/vs/virt.jsp']",
    test()
);

function test(){
    frame = $("iframe[src*='/vs/virt.jsp']");
    console.log(frame.attr("id"));
}

Still the same result. Worth noting is that I use Tampermonkey, but perhaps it's the same?

Edit 2:

function timer() {
  frame = $("iframe[src*='/vs/virt.jsp']");
    console.log(frame.attr("id"));
    setTimeout(timer, 1000);
}

timer();

It keeps outputting "undefined" whereas if I try it in Chrome developer console I get the object. It's like Tampermonkey does not have access?

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
PatrikJ
  • 2,327
  • 3
  • 24
  • 35
  • 1
    `$("iframe[iframe[src*='/vs/virt.jsp']");` that's a typo in the question, right, that's not actual code? – Jaromanda X Oct 15 '15 at 12:02
  • It's a typo. Correcting it now. Thanks for the observation! – PatrikJ Oct 15 '15 at 12:11
  • 1
    The iframe element is probably created later. Try using `waitForKeyElements` or `MutationObserver`. – wOxxOm Oct 15 '15 at 14:00
  • Will do and reporting back – PatrikJ Oct 16 '15 at 14:33
  • Tried waitForKeyElements. MutationObserver looks like it's above my skill grade. :) – PatrikJ Oct 16 '15 at 14:53
  • @PatrikJ, `test()` in your new code isn't a *callback* but an immediate function *call*. Remove the `()`. Also, with `@grant none` the script runs in the context of the webpage, so you might have two conflicting jQuery libraries if the webpage uses its own. Remove `@grant none`. And rework the code to use `@grant unsafeWindow` but only if needed. – wOxxOm Oct 16 '15 at 19:29

1 Answers1

2

Since your iFrame is on the same domain as your main page, it's relatively straightforward to target iframe changes using waitForKeyElements(). It was designed with that possibility in mind.
Pass a valid iFrame selector as the 4th parameter.

For example:

  1. Go to this jsFiddle page. It dynamically creates an iframe with the id tstIframe, and it looks like:

            Initial state

  2. When you click the button it adds a line of text to the iframe -- in a div with the class comment.

  3. Suppose we want to process that text, then this script will do that:

    // ==UserScript==
    // @name        Dynamic iframe content manipulator
    // @match       http://fiddle.jshell.net/5zqfthx7/*
    // @require     http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
    // @require     https://gist.github.com/raw/2625891/waitForKeyElements.js
    // @grant       GM_addStyle
    // ==/UserScript==
    /*- The @grant directive is needed to work around a design change
        introduced in GM 1.0.   It restores the sandbox.
    */
    waitForKeyElements (
        ".comment",
        styleComment,
        false,
        "#tstIframe"
    );
    
    function styleComment (jNode) {
        jNode.css ("background", "lime");
    }
    
  4. When you install that script, reload the page and press the button, you will see each new line getting colored, like so:

            Script in action


Notes:

  1. Do not use @noframes in this case. Tampermonkey does not properly apply it in this kind of iframe manipulation -- especially if the iframe has no src.
  2. When using @require, always use a @grant other than none, unless you know exactly how the page's JS and the script's will interact and conflict.
  3. Additional options are available on Firefox. Chrome still has finicky/limited iframe support.
  4. Finally, since your iFrame has a src, you can often just script for it as if it was the only page. Tune your @match,etc., directives to fire on the iframe and maybe wrap the code in an if (self !== top) {... } structure.
    See this answer for example.
Community
  • 1
  • 1
Brock Adams
  • 90,639
  • 22
  • 233
  • 295