PDA

View Full Version : [1.1.x]Extended ContentPanel with writable/printable Iframes



hendricd
10 Sep 2007, 3:15 PM
Thought I'd share something I whipped up for a current project:

I needed to modify/render full-page content in an IFrame-ContentPanel (in CSS isolation). Emails actually.

This adds .setContent, .print(yes!), .getHostWindow, .getHostDocument to IFrame panels. It also permits UpdateManager updates to the IFrames.document as well (no, not the same as setting the iframes.src property! ). This makes an iframe act just like any other 'updateable' container to the ContentPanel.



Ext.ux.ContentPanel = function(el,config,content){

config || (config={});
content = content || config.content || false;
config.content = null;

Ext.ux.ContentPanel.superclass.constructor.call(this,el,config /*,content - not yet, later on */);

this._isIframe = this.el && this.el.dom? this.el.dom.tagName=="IFRAME":false;

if(this._isIframe){
this.el.dom.name || (this.el.dom.name = this.el.dom.id);
this.el.update = this.setContent.createDelegate(this);
var r= function(el, response, updateManager, callback){

this.setContent(response.responseText, updateManager.loadScripts);
if(callback){callback();}
};

this.el.getUpdateManager().setRenderer({render:r.createDelegate(this)});

}
if(content){
this.setContent.defer(100,this,[content]);//allow the frame to quiesce if autoCreated
}
};

Ext.extend(Ext.ux.ContentPanel,Ext.ContentPanel,
{_isIframe: false,
setContent:function(content,loadScripts,callback){
loadScripts = loadScripts || this.el.getUpdateManager().loadScripts || false;

if(this._isIframe || this.getEl().dom.tagName=="IFRAME"){

content || (content='');

var doc = this.getHostDocument();
doc.open();
doc.write(loadScripts===true?
content:content.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, ""));
doc.close();
}else{
Ext.ux.ContentPanel.superclass.setContent.call(this,content,loadScripts );

}
if(callback)callback();

},
getHostDocument:function(){
return this.getHostWindow().document;
},
getHostWindow:function(){
var el=this.getEl().dom;
if(this._isIframe || el.tagName=="IFRAME"){

return (el.contentWindow||window.frames[el.name]);
}
return window;
},
print:function(noPrompt){
if(!this._isIframe)return;
if(this.getHostWindow().print){
this.getHostWindow().print();
} else {
var wbo = '<OBJECT ID="BO1" WIDTH=0 HEIGHT=0 CLASSID="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"></OBJECT>';
this.getHostDocument().body.insertAdjacentHTML('beforeEnd', wbo);
BO1.ExecWB(6, noPrompt?1:2);//Use a 1 vs. a 2 for a prompting dialog box
BO1.outerHTML = "";
}

},
destroy:function(){
if(this._isIframe){
var iFrame = this.getEl().dom;
if(iFrame && iFrame.src) {
iFrame.src = 'javascript:false';
}

}
}

});

This also means you can query (Ext.select) on the Iframe.document's DOM using Ext in the parent window without loading the Ext framework in the Iframe:


var el = Ext.DomHelper.append(document.body,{tag: 'iframe', frameBorder: 0, src: ''});
layout.beginUpdate();
var uxPanel=layout.regions['center'].add(new Ext.ux.ContentPanel(el,{title: 'Photo Album' , fitToFrame:true, closable:true}));
layout.endUpdate();
uxPanel.load({
url:'getPhotos.php?just=mine',
callback:function(){
Ext.select('img',true,uxPanel.getHostDocument().body).hide(true); //fade out all the iframe's images
Ext.Msg.confirm('Your Photos are Ready!','Would you like to print your ugly photos?',
function(but){if(but=='yes')uxPanel.print()});
},
text: "Loading...",
timeout: 30,
scripts:true,
scope:uxPanel
},uxPanel);

The same cannot be said for Ext.get; however.

[tags: iframe contentpanel]

Update: A newer (replacement) solution has been developed for Iframes in ContentPanels here (http://extjs.com/forum/showthread.php?t=16590).

bhaidaya
13 Sep 2007, 8:00 AM
Wow, can't wait to try this out... been having trouble with this very issue...

gelleneu
14 Sep 2007, 11:40 PM
I tried the example, and the Ext.select / uxPanel.getHostDocument function in the callback method hides all my images OUTSIDE the Iframe... The content of the IFrame is not changed...:(

hendricd
15 Sep 2007, 4:23 AM
Can you post your panel's load statement and callback ?

You'll need to pass uxPanel.getHostDocument() in the third parameter of the select.

DigitalSkyline
21 Sep 2007, 4:05 PM
I'm using your extension... very cool of you to share! I'm wondering what would be the best way to access the iframe document's dom elements. In one instance I need to write to a div (I have the ID) and in another instance I'd like to get the html contents of the iframe.

I'll be experimenting in the meanwhile...

galdaka
22 Sep 2007, 4:25 AM
Live example please!!

Thanks in advance,

hendricd
23 Sep 2007, 6:33 AM
@DigitalSkyline - I have had success with Ext.select as in:


Ext.select('#yourdiv',true,uxPanel.getHostDocument())

when querying Iframe nodes. you might might try combining the results with Ext.Fly [but haven't tested that yet] to do what you want. Or you could do something like:


uxPanel.getHostDocument().getElementById('yourdiv') and access the iframe's DOM the old-fashioned way and 'innerHTML' the heck out of it.

I have devised a dynamic JS Loader for Ext that would permit 'Ext-izing' Iframes and popup windows without embedding script commands into the content. Then, you would be able to use Ext methods to access these embedded DOMS at will. The JS-Loader details can be found here (http://extjs.com/forum/showthread.php?p=63349#post63349), but I'll be ux'ing this class and a more thorough example of how to do that in the next couple of weeks. (hint: the globalEval method is the key ;) )

tvlgiao
23 Sep 2007, 8:24 AM
Hi hendricd,

one problem I can see is that the content inside iframe is not behaved as XHTML.
you can see the attached snapshot, the font size in iframe is bigger than normal indicates that.

I tested on Firefox 2.x

Thanks for any advice.

Giao

hendricd
24 Sep 2007, 8:09 AM
@tvlgiao - yes, you have to remember that an iframe is another browser context and does not share any of the stylesheets of it's parent context (operating in CSS and javascript isolation). You'll need to write your desired stylesheets into the iframe's document head section and/or include the necessary <link style> tags in there as well.

galdaka
24 Sep 2007, 11:57 AM
Sorry any example for test your results?

Thanks in advance,

DigitalSkyline
24 Sep 2007, 3:06 PM
This didn't work:


Ext.select('#yourdiv',true,uxPanel.getHostDocument()).innerHTML = "write this content";

but this did:


uxPanel.getHostDocument().getElementById('yourdiv').innerHTML = "write this content";





I have devised a dynamic JS Loader for Ext that would permit 'Ext-izing' Iframes and popup windows without embedding script commands into the content. Then, you would be able to use Ext methods to access these embedded DOMS at will. The JS-Loader details can be found here (http://extjs.com/forum/showthread.php?p=63349#post63349), but I'll be ux'ing this class and a more thorough example of how to do that in the next couple of weeks. (hint: the globalEval method is the key ;) )

Sounds interesting...


I have another question, I've tried to use the uxPanel.refresh(); to reload the iframe source but it seems to have no effect.... any ideas?

hendricd
24 Sep 2007, 8:34 PM
@DigitalSkyline - I dont [think] Composite element collections permit access to properties in that fashion. Does this work in your case ?



Ext.select('#yourdiv',true,uxPanel.getHostDocument()).each(function(el){el.innerHTML = "write this content";});


RE:
I have another question, I've tried to use the uxPanel.refresh(); to reload the iframe source but it seems to have no effect.... any ideas?

I'd like to see some more of your trial use case, but it could be I need to extend the 'update' emulation a bit more for UpdateManager in that scenario.

Keep it coming.. :-?

@Galdaka - not sure what your looking for here. I will be posting a more thorough demonstration site in the next few weeks, but the example provided acts like any other Contentpanel.

galdaka
24 Sep 2007, 10:25 PM
@Galdaka - not sure what your looking for here. I will be posting a more thorough demonstration site in the next few weeks, but the example provided acts like any other Contentpanel.

Thanks, I hope your live example for testing the results.

hendricd
29 Oct 2007, 6:50 PM
A newer solution has been developed for Iframes in ContentPanels here (http://extjs.com/forum/showthread.php?t=16590).