I am trying do some modification to an greasemonkey userscript to implement a feature I need. The code is like
showAddress:function(addrString,type)
{
this.addrBox=$('<div id="batchPublish"></div>')
.append('<div id="batchHeader"></div>')
.append('<div id="batchContent" style="float:left;clear:both"></div>');
.........
var batchContent=this.addrBox.find('#batchContent')
.append('<pre width="300" style="text-align:left" id="batchedlink"></pre>');
this.addrBox.find('#batchedlink').css({'width':'500px','height':'250px','overflow':'auto','word-wrap': 'break-word'})
.append(addrString);
$.blockUI({message:this.addrBox,css:{width:"520px",height:"300px"}}); }
Basically this code writes data to html. What I want to implement is to have "addrString" written to an iframe embedded. Now It's in the "pre" tag. I have tried many approaches but still no luck. Iframe was always empty.
I am completely a novice in javascript and unclear whether this is possible.
Thank you for the help.
Since you are adding the iFrame in the same domain, then you can manipulate its contents like this:
(See it in action at jsBin.)
$("#batchContent").append ('<iframe id="batchedlink"></iframe>');
/*--- Compensate for a bug in IE and FF, Dynamically added iFrame needs
some time to become "DOM-able".
*/
setTimeout ( function () {
var iframeBody = $("#batchedlink").contents ().find ("body");
iframeBody.append (addrString);
},
333
);
NOTE:
For a Chrome userscript, you apparently don't need the timer delay. But for FF and IE 8 (the other 2 browsers I double-checked), a dynamically added iFrame is not manipulable until after it has "settled" for some reason. This seems to take about 200 mS.
A statically loaded iFrame does not have this lag, see the jsBin demo.
Sort of hard to tell exactly what you're asking -- but if you want to know whether or not you can append DOM elements to an iFrame, the answer is "no".
Related
I use the following code to dynamically create an iframe.
var iframe_jquery = $("<iframe>")
.addClass("foo")
.appendTo(container); // container is a jQuery object containing a <div> which already exists
Then, I want to access its contentWindow, but it's null:
var iframe = iframe_jquery.get(0);
if (iframe){ // iFrame exists
console.log(iframe.contentWindow); // Prints "null"
var doc = iframe.contentWindow.document; // NullpointerException
}
So I thought: "Maybe the iframe isn't ready yet?" So I tried:
iframe_jquery.ready(function(){
var iframe = iframe_jquery.get(0);
console.log(iframe.contentWindow); // Prints "null"
var doc = iframe.contentWindow.document; // NullpointerException
});
Same result.
What's wrong?
I had this problem last week while playing with iframes (building an rtf editor), and yeah it's not ready yet.
I thought if I put it in a .ready(), it would work, but .ready() is when the DOM is ready, not when the iframe has loaded its contents, so I ended up wrapping my code with jQuery .load().
So try this:
$(function () {
$("#myiframe").load(function () {
frames["myframe"].document.body.innerHTML = htmlValue;
});
});
Hope this helps
The problem is that your <iframe> won't be "real" until it's really added to the actual DOM for the page. Here is a fiddle to demonstrate..
Depending on the browser, accessing the document or an <iframe> may vary.
Here is an example of how to handle it:
if (iframe.contentDocument) // FF Chrome
doc = iframe.contentDocument;
else if ( iframe.contentWindow ) // IE
doc = iframe.contentWindow.document;
You can also make a function that will be executed when the iframe has finished loading by setting it's onload attribute.
Bookmarklet version
Just out of curiosity I thought I'd put this together. Remembering that iframes and load events don't play well together on different browsers (mainly older, falling apart, should-be-dead browsers)... plus not being entirely sure how jQuery gets around this problem... my brain decided that this would be better supported (whether it is or not is neither here nor there):
$(function(){
/// bind a listener for the bespoke iframeload event
$(window).bind('iframeload', function(){
/// access the contents of the iframe using jQuery notation
iframe.show().contents().find('body').html('hello');
});
/// create your iframe
var iframe = $('<iframe />')
/// by forcing our iframe to evaluate javascript in the path, we know when it's ready
.attr('src', 'javascript:(function(){try{p=window.parent;p.jQuery(p).trigger(\'iframeload\');}catch(ee){};})();')
/// insert the iframe into the live DOM
.appendTo('body');
});
The reason for taking this approach is that it is normally far better to trigger your load event from inside the iframe itself. But this means having a proper document loaded in to the iframe, so for dynamic iframes this is a little tedious. This is kind of a mixture between having a document loaded, and not.
The above works on everything I have tested so far - and yes you are correct - it is a little ridiculous, non-future-proof and propably other things that have negative connotations ;)
One positive thing I'll say about this post is that introduces the use of .contents() to access the document of the iframe, which is at least a little bit useful...
I am simply trying to change the SRC attribute of an image via javascript like so:
document.getElementById('fooImage').src = img;
Where img is a variable that has a link to the file.
In all other browsers (Chrome, Firefox, Safari) this works. In IE (7+) this also works too sometimes.
Using IE's built-in developer tools, I can see that the image's SRC tag is set. Is there something else in the locals window that could help me debug why the image doesn't actually show on screen?
I've also tried using jQuery to do this and same outcome:
$("#fooImage").attr("src", img);
An ideas?
In debugging this I would hard code it first...
document.getElementById('fooImage').src = "myimage.png";
I've used the following in my website and it works like this...
var imgCounter = document.getElementById('formtimer');
imgCounter.src = "graphics/odometers/1.png";
Some other things to check:
Make sure your ID= tag is not in the <DIV section but inside the <IMG section... for example <div class="style1"><img src="yourpicture" id="someid">. If `id='someid' is in the div tag then you can't change the picture / the picture won't show up.
are you using window.onload?, body onload? the proper way to use the first is..
window.onload = function () { YourFunctionHere(); };
Try a different test image. I had issues in the past with showing png's, I changed it to a gif or jpg and it worked. I don't understand how that was "way back" but it doesn't seem to be an issue anymore but hey... something to try.
try a full url
using https?
try sticking the image somewhere else in your program and see what happens.
try adding this to your HTML (put your website in place of mine - lookup BASE href on google for more info)
<BASE href="http://perrycs/" />
Make sure the image isn't hidden behind a layer (I know it works in some browsers)
tell us the website so we can check it out and get more info to help you in debugging this, seeing context (surrounding code) helps...
Given that it works in other browsers, searching on this topic it seems that often the problem is how IE caches images (ref. Epascarello's comment). Your code is the same as what I have - it works fine except in IE10.
I too, faced this conundrum. Then discovered that it works in 'Page Inspector', so after some digging discovered that (in Internet Explorer) by going to Tools.Internet Options.Advanced
uncheck the 'Disable script debugging (Internet Explorer)' and the one below it.
I found that with IE9 after changing an image.src with
var strVar="C:Users/x/Desktop/caution.png"
image.src=strVar
and calling an alert(image.src) I would get something like this n the alertbox:
file:///C:Users/x/Desktop/"C:Users/x/Desktop/caution.png"
So I tried
image.src=strVar.replace(/\"/g,"")
to remove qoutemarks
and it worked!
alert(image.src)
file:///C:Users/x/Desktop/caution.png
I'm having problems with debugging DOM changes introduced by some JavaScript code I'm running. Somewhere in the code an element's class is changed, and I'm trying to pinpoint where exactly. Unfortunately, the new class name is so generic that searching through all the JS code gives too many results to be a viable option.
I've tried debugging a bit with Firebug, but despite the nice "Break on Attribute Change" feature, I can't get it to work in a way I would want. The Firebug demo works correctly, but it's a post load situation.
The problem seems to be that I want to watch for mutations before the page is fully loaded. I assume that the changes occur somewhere in $(document).ready(), so it's in the DOM, but I can't select elements for UI breakpoints as would be the case with the demo (after page load).
Is there some way to debug this kind of situation other than grepping/going through the code by hand?
I propose that you remove the target element where its classname is changed. With some luck, you may be able to generate an error in the JavaScript code, so you will find where is your problem.
Otherwise, if it's done by JQuery (addClass), you may want to modify the JQuery code itself just to figure out the callstack.
The code would look like this (make sure this code is the first code called after JQuery inclusion):
(function () {
var addClass = jQuery.fn.addClass;
jQuery.fn.addClass = function (value) {
for (var i = 0, l = this.length; i < l; i++) {
// Here you put your method to start the debugger if you get your right element
if (this[i].id === "abc") {
debugger;
}
}
addClass(value);
}
})();
Hope that helps.
This answer may sound pretty lame, but I honestly think the best solution for bugs like this is "deconstructing" your program. Just make a copy of the entire project, then rip it apart. Take out chunks of code one by one. Turn function calls into stub functions or whatever to keep things running. Find the minimal amount of code that triggers the bug. Then the solution should be obvious.
Have you considered adding a mutation event? The event I think you want, DOMAttrModified, is not supported in webkit, so you might have to test with Firefox or Opera. In fact it is deprecated in DOM level 3.
There are two jQuery plugins for mutation events here (documentation) and here but since you want to do this before page load they might not be the answer.
You are probably best writing your own JavaScript bind for this event - there is an example in the answer to is there an alternative to DOMAttrModified that will work in webkit
I hope this helps.
If you want to use the "Break on Attribute Change" feature to debug, you can do the following:
Comment out all JS in the page (which is hopefully all in the head) except for the base jQuery load.
Load the page and set your watch points.
Add a button, which fires the JS, to the HTML. Or, optionally fire it from the console.
Trigger the JS load/fire. Hopefully your watch and break points will fire as desired.
For example, suppose your page loads/has:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js" type="text/javascript"></script>
<script src="/Library_X.js" type="text/javascript"></script>
<script src="/MyJS.js" type="text/javascript"></script>
Then you could run this code in the console after setting the watch points:
function addJS_Node (text, s_URL)
{
var scriptNode = document.createElement ('script');
scriptNode.type = "text/javascript";
if (text) scriptNode.textContent = text;
if (s_URL) scriptNode.src = s_URL;
document.head.appendChild (scriptNode);
}
addJS_Node (null, '/Library_X.js');
//-- Possible pause here.
addJS_Node (null, '/MyJS.js');
// etc.
Or temporarily code a button that fires the same JS, into the page's HTML.
It seems this is a known problem and has been asked several times before here in SO however I do not see anything specific to jQTouch so I thought I would give it a try.
jQT will dynamically load pages when a link is clicked. In this page I would like to include something like
<script>
$.include('javascriptfile.js', function() {alert('do something with results of this file to an already existing div element');};
</script>
The $.include is a jquery plugin I found that mimics the $.load with a few more smarts added to it. Tested to work on FF but not in Chrome or most importantly, Safari.
The alert is never displayed. FireBug never shows the javascript even being loaded. If I put an alert before the $.include I still do not see anything.
I have tried an onclick/ontap event that would then run this code that was included in the head tag, no luck.
Edit: I am using the r148 revision of jQT. This was working prior to moving to this version, i believe.
Did you try to add the javascript file using one of these two methods:
Static Way:
<script type="text/javascript">
function staticLoadScript(url){
document.write('<script src="', url, '" type="text/JavaScript"><\/script>');
}
staticLoadScript("javascriptfile.js");
modifyDivFn(processFnInFile());
</script>
Dynamic way:
<script type="text/javascript">
function dhtmlLoadScript(url){
var e = document.createElement("script");
e.src = url;
e.type="text/javascript";
document.getElementsByTagName("head")[0].appendChild(e);
}
onload = function(){
dhtmlLoadScript("javascriptfile.js");
modifyDivFn(processFnInFile());
}
</script>
After the include you can call a function that does the processing you want (that being processFnInFile()) which result will be passed to modifyDivFn (and modify the div you want.) You could do this in one function, just to illustrate the idea.
Source: Dynamically Loading Javascript Files
Well Geries, I appreciate your help but ultimately the answer required a drastic rethinking of how I was using JQTouch. The solution was to move everything to an onclick event and make all the hrefs link to #. This might be what you were talking about Geries.
In the onclick function I do the logic, preloading, loading of the page through my own GET through jquery, then use the public object jQT.goTo(div, transition). This seems to get around the WebKit bugs or whatever I was running into and this now owrks on FireFox, Chrome, Safari, iPhone, and the lot.
I do run into a few animation issues with JQT but I think these are known issues that I hope Stark and the gang at JQTouch are working on.
OK, every other browser works fine with the method I have coded so far but for some reason Internet Explorer will not work. I have spent hours of time (more time than actually developing the feature!) on compatibility and am close to giving up!
I have a forum and one of its neat features is the WYSIWYG editor. For that, I essentially have an IFrame that acts as the document:
<iframe name="writer" src="/scripts/blank.html" class="writer"></iframe>
This is the current state of the JavaScript (constantly updated):
function initEditor()
{
w = frames['writer']
wc = g('writerCopy')
if(w == null) return
frames['writer'].document.designMode = 'on'
frames['writer'].document.body.innerHTML = styleSheet+wc.value
frames['writer'].focus()
}
It works partially now, but fails on the line:
frames['writer'].document.body.innerHTML = styleSheet+wc.value
in Internet Explorer with "'frames.writer.document.body' is null or not an object".
I'm not even sure IE supports that designMode.
And, .contentDocument is only IE8, IE7 and less uses .contentWindow.document, but iframe windows are part of the frames-collection.
try this, should be crossbrowser:
<iframe name="writer"></iframe>
frames["writer"].document.body.innerHTML = "some html...";
You need to point your iframe to a dummy document for IE. Just create a file blank.html with the following:
<html><body></body></html>
and set <iframe src="blank.html" ... >
Then you can go about referencing frame.document.body.innerHTML = '...' to your hearts content.
BTW that is a terrible title to a question.
Evidently IE8 does not make frame elements available until the entire parent page has loaded. Also note, you can write to the frame before the parent page loads, but this will overwrite the frame and prevent it from being loaded.
The easy solution is to move the InitEditor() call from inside the body to here:
<body onload="InitEditor()">
Perhaps the iframe isn't loaded yet. I can duplicate your "'frames.writer.document.body' is null or not an object" error. I added a setTimeout around it and it then worked for me.
setTimeout(function () {
frames['writer'].document.body.innerHTML = "some text";
}, 200);
Have you activated IE's debugging facilities?
Am I missing something here? shouldn't you use something like:
window.frames[nameOrNumberOfFrame]...
See also in MSDN:
This collection contains only window
objects and does not provide access to
the corresponding frame and iframe
objects. To access these objects, use
the all collection for the document
containing the objects.
In the end I used frames['frameName'].document.write('someText') but only if the other method fails.