As was foretold, we've added advertisements to the forums! If you have questions, or if you encounter any bugs, please visit this thread: https://forums.penny-arcade.com/discussion/240191/forum-advertisement-faq-and-reports-thread/

Complex HTML Question

RendRend Registered User regular
edited January 2010 in Help / Advice Forum
Alright guys, this is a puzzler to me.

I am making a popup/iframe which will be on a web page. I need the same cascading stylesheets to apply to both, but the iframe/popup will only know about them through the parent page.

IE. I need to be able to dynamically link .css in an iframe/popup based on the linked .css in the page that it's coming from. Is this possible? If so, how do I do it?

I can only use standard HTML and javascript- no php, ajax, etc etc.

Rend on

Posts

  • Jimmy KingJimmy King Registered User regular
    edited January 2010
    This should work.

    Javascript should be able to look at the query string paramters or the path on the URL. I'd just stick the base name of the css (or some mapping/obfuscation if you're really worried about it) in the path or query string to the popup. Then the javascript in the popup can look at that to load the correct css.

    Something like on the following link to actually load the css: http://www.webmasterworld.com/forum91/374.htm

    Jimmy King on
  • RendRend Registered User regular
    edited January 2010
    That helps a bit, but I'm not necessarily going to know which css are linked on the parent page. Part of the problem is finding the linked css that I don't necessarily know about.

    I don't control the parent page, just the iframe.

    Rend on
  • Jimmy KingJimmy King Registered User regular
    edited January 2010
    Ah, yeah, that does change things a bit. No way to have whoever manages the parent page include that? Obviously I don't know how their end is set up. I assume somewhere a URL must be getting entered in be it somewhere in the markup directly or a CMS system or whatever and so you can tell them "instead of linking to http://www.example.com/mypage.html in the iframe, link to http://www.example.com/mypage.html?css=blargh.css" or whatever.

    Unfortunately, as far as I know, iframes cannot inherit css from the parent so it has to be specifically told in some manner. The above is the most obvious.

    My next solution would be a mapping of page -> css. I assume you can look at the referrer in javascript. Then you use a hash to map the referrer to a css. This is assuming you have a set of known referrers that is not going to change, though, so it may not be viable at all. It's also more clumsy to deal with for adding pages that will load the iframe.

    Jimmy King on
  • RendRend Registered User regular
    edited January 2010
    Jimmy King wrote: »
    Ah, yeah, that does change things a bit. No way to have whoever manages the parent page include that? Obviously I don't know how their end is set up. I assume somewhere a URL must be getting entered in be it somewhere in the markup directly or a CMS system or whatever and so you can tell them "instead of linking to http://www.example.com/mypage.html in the iframe, link to http://www.example.com/mypage.html?css=blargh.css" or whatever.

    Unfortunately, as far as I know, iframes cannot inherit css from the parent so it has to be specifically told in some manner. The above is the most obvious.

    My next solution would be a mapping of page -> css. I assume you can look at the referrer in javascript. Then you use a hash to map the referrer to a css. This is assuming you have a set of known referrers that is not going to change, though, so it may not be viable at all. It's also more clumsy to deal with for adding pages that will load the iframe.

    The solution has to be minor on the part of the parent page. Though I dont control it I can influence it, the less intrusive the solution the better, and also the simpler. ideally it should be able to be implemented by someone who doesn't know how to write html.

    Rend on
  • Jimmy KingJimmy King Registered User regular
    edited January 2010
    Yeah, I've got no ideas that won't require them to do anything at all. It would probably be possible to provide them with an external javascript that modifies the links appropriately, but then they still need to edit the html to tell it to load the .js file.

    Jimmy King on
  • RendRend Registered User regular
    edited January 2010
    It's alright to have them edit the html, it's just the less technical the better. There's no real set in stone requirements for this particular thing, but the best it could be would be anything that happens on the parent page would be easy and intuitive.

    I have no idea if that's possible, but it's fine if it gets a bit more technical, just as long as it's not needlessly so.

    Rend on
  • SkyCaptainSkyCaptain IndianaRegistered User regular
    edited January 2010
    Can't you just add the css reference in the popup page the same way the parent page gets the css?

    SkyCaptain on
    The RPG Bestiary - Dangerous foes and legendary monsters for D&D 4th Edition
  • flatlinegraphicsflatlinegraphics Registered User regular
    edited January 2010
    this is going to be an ugly ugly hack, no matter what. since an iframe is technically a new window, the included page has no DOM relationship to the parent. since it is a completely different page, you cannot even use parent or document (as they will refer to linked page, and not the holder page). if you can supply them with a js script, that would probably be best. that way, you can run jquery and ajax everything else in.

    something like this may work:
    provide the client with a code snippet like this:
    <script src="http://yoursite.com/builder.js"&gt;
    <script>build();</script>

    your builder script would then link jquery and start writing dynamically to the page, including something that zero's out styles. once you do this, you should have complete control, and even be able to use ajax functions.

    basically, you are looking to launch a xss attack... may be another thing to look into.

    flatlinegraphics on
  • TejsTejs Registered User regular
    edited January 2010
    Rend wrote: »
    Alright guys, this is a puzzler to me.

    I am making a popup/iframe which will be on a web page. I need the same cascading stylesheets to apply to both, but the iframe/popup will only know about them through the parent page.

    IE. I need to be able to dynamically link .css in an iframe/popup based on the linked .css in the page that it's coming from. Is this possible? If so, how do I do it?

    I can only use standard HTML and javascript- no php, ajax, etc etc.

    I can only hope this won't be used for some nefarious reason - I can't think offhand why would you would want to go this path VS using a different solution. With this solution, whoever owns the parent page needs to add 1) IFrame Reference, 2) External JavaScript file, 3) Host Said Javascript file.

    Parent Page:
    <html>
    	<head>
    		<link href="parentCss.css" type="text/css" rel="stylesheet" id="myLink" />
    		<script type="text/javascript" language="javascript" src="switchCss.js"></script>
    	</head>
    	<body>
    		<span class="Style">This is text</span><br>
    		<iframe id="myFrame" src="iFrame.html" /><br>
    	</body>
    </html>
    

    Iframe Page
    <html>
    	<head id="headElement">
    		<script type="text/javascript" language="javascript">
    			function addCss(cssName)
    			{
    				var fileref=document.createElement("link");
    				fileref.setAttribute("rel", "stylesheet");
    				fileref.setAttribute("type", "text/css");
    				fileref.setAttribute("href", cssName);
    
    				var head = document.getElementById('headElement');
    
    				if(head != null)
    				{
    					head.appendChild(fileref);
    				}
    			}
    		</script>
    	</head>
    	<body>
    		<span class="Style">Text</span>
    		<input type="button" onclick="parent.communicate(addCss);" value="Add Css">
    	</body>
    </html>
    

    Parent JavaScript
    function communicate(callback)
    {
    	var cssLink = document.getElementById('myLink');
    
    	if(cssLink != null)
    	{
    		callback(cssLink.getAttribute('href'));
    	}
    }
    

    CssFile
    .Style { color: blue; }
    

    This example uses a button click on the iframe to load the parent CSS into the iframe CSS store. Switching the event to onload would do it automatically. I've only tested this on internet explorer, so your results may vary.

    Tejs on
  • RendRend Registered User regular
    edited January 2010
    No, no nefariousness here, but your solution intrigues me. I don't completely understand the whole thing off the bat, but maybe if you explain it in a bit more detail I'll have a more complete grasp of what's going on.

    What I see happening is the parent page is hosting a script, which the iframe is calling? I was not aware that could happen, that's the case?

    Also, is this solution capable of loading multiple CSS with one runthrough? You said you could do it on load instead of on click, which is likely what will need to happen, also, would that present any problems?

    Rend on
  • GanluanGanluan Registered User regular
    edited January 2010
    I haven't tried it, but I'm not sure Tejs' solution works on browsers other than IE or if the HTTP requests are handled differently by the web server.

    Ganluan on
  • PracticalProblemSolverPracticalProblemSolver Registered User regular
    edited January 2010
    Assuming the parent pages are something that can be added as needed(not dynamically generated) here's some pseudo code:

    switch referral
    case 'bob.com':
    use_css('bob.com/blue.css');
    case 'jane.com':
    use_css('jane.com/red.css');


    I'm curious as to why you're doing this, sounds nefarious to me.

    PracticalProblemSolver on
  • RendRend Registered User regular
    edited January 2010
    Well, it's most definitely not :p

    What's going on here is that I need a way to make the iframe look and feel the same as the parent page, but when the parent page is not something I designed or upkeep or anything. The reason for that is I'm trying to design something that will be capable of being used across multiple different pages/sites, so the css may be radically different on each one. As such, instead of manually adding the css to the iframe, it would be vastly preferable to have some sort of way to automate it, based on the css that was already there.

    Rend on
  • TejsTejs Registered User regular
    edited January 2010
    Rend wrote: »
    No, no nefariousness here, but your solution intrigues me. I don't completely understand the whole thing off the bat, but maybe if you explain it in a bit more detail I'll have a more complete grasp of what's going on.

    What I see happening is the parent page is hosting a script, which the iframe is calling? I was not aware that could happen, that's the case?

    Also, is this solution capable of loading multiple CSS with one runthrough? You said you could do it on load instead of on click, which is likely what will need to happen, also, would that present any problems?

    Sure, I'll explain as best I can. The action of loading the CSS and attaching it to the iframe occurs after some event in the page lifecycle. We can't do it when the parent page is loading, because the iframe will not have loaded yet.

    So we hook into an event on the iframe to start the process. In this situation, I've attached to the onclick event of the button. If it was supposed to be automatic, you would attach to the onload or onready event of the iframe's lifecycle.

    What I do is pass a callback to the parent javascript and pass back the names of the parent css files. The parent javascript is only concerned with figuring out the names of the CSS files it has loaded. If there were multiple files, you just need to pass back to the callback the appropriate names.

    Then, on the iframe where the callback is specified (in this case, addCss), I put together link tags with those names and reference them on the iframe, which then tells the browser to download those files and link them to the iframe document - that applies the css styles to the iframe.

    I don't believe any of the javascript I used was not browser compatible - I believe parent.<anything> is a valid reference for FF, Chrome, or IE.

    Tejs on
  • PracticalProblemSolverPracticalProblemSolver Registered User regular
    edited January 2010
    This is your iframe:
    <html>
    <head>
    <script language="javascript" type="text/javascript">
                            function addCss(cssName)
                            {
                                    var fileref=document.createElement("link");
                                    fileref.setAttribute("rel", "stylesheet");
                                    fileref.setAttribute("type", "text/css");
                                    fileref.setAttribute("href", cssName);
                                    document.getElementsByTagName("head")[0].appendChild(fileref)
                            }
                           </script>
    </head>
    
    <body style="background-color:;">
    
    <script language="javascript" type="text/javascript">
    switch(parent.location.host)
    {
      case 'wang.com':
        addCss('wang.com/wang.css');
        break;
      case 'hoohoo.com':
        addCss('hoohoo.com/hh.css');
        break;
    }
                    </script>
    </body>
    </html>
    

    you owe me fifty bucks.

    PracticalProblemSolver on
  • TejsTejs Registered User regular
    edited January 2010
    I've actually been thinking about how to simplify my earlier solution today and think I have a good candidate. Assume the same CSS file from my last example. Now, you only need to worry about inserting your iframe into the parent page.

    Parent Code (note no external JavaScript file)
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html>
    	<head>
    		<link rel="stylesheet" type="text/css" href="cssData.css" />
    	</head>
    	<body>
    		<span class="Style">This is my text styled.</span>
    		<br/>
    		<br/>		
    		<iframe src="iframe.html" />
    	</body>
    </html>
    

    And the Iframe (I've modified it to automatically call the loadCss function).
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html>
    	<head>
    		<script type="text/javascript" language="javascript">
    			function loadCss()
    			{
    				var parentLinks = parent.document.getElementsByTagName('head')[0];
    				var selfHeader = document.getElementsByTagName('head')[0];
    
    				if(parentLinks == undefined)
    					return;
    
    				var cssLinks = parentLinks.getElementsByTagName('link');
    				
    				for(var j = 0; j < cssLinks.length; j++)
    				{
    					if(cssLinks[j].getAttribute('type').indexOf('text/css') > -1)
    					{
    						var newLink = createLink(cssLinks[j].getAttribute('href'));
    
    						if(selfHeader != undefined)
    							selfHeader.appendChild(newLink);
    					}
    				}
    			}
    
    			function createLink(fileName)
    			{
    				var linkElement = document.createElement('link');
    				linkElement.setAttribute('rel', 'stylesheet');
    				linkElement.setAttribute('type', 'text/css');
    				linkElement.setAttribute('href', fileName);
    
    				return linkElement;
    			}
    		</script>
    	</head>
    	<body onload="loadCss();">
    		<span class="Style">This is my text styled.</span>
    	</body>
    </html>
    

    In IE8, Chrome, and FF3, the iframe has the styles of the parent frame.

    Tejs on
  • RendRend Registered User regular
    edited January 2010
    Tejs wrote: »
    I've actually been thinking about how to simplify my earlier solution today and think I have a good candidate. Assume the same CSS file from my last example. Now, you only need to worry about inserting your iframe into the parent page.


    In IE8, Chrome, and FF3, the iframe has the styles of the parent frame.

    Yeah yeah I can see that, actually I was just writing something up that is surprisingly similar. When you showed the example above about the parent uploading the javascript I started drafting one up that used getelementsbytagname(link) to automatically parse out all the links that might be relevant on the parent page.

    My only question remains that, how far back can you go before you hit compatibility issues?

    Rend on
  • Jimmy KingJimmy King Registered User regular
    edited January 2010
    Oh, that's pretty cool Tejs. I had thought about a solution like that. I'm not a front end guy and assumed Javascript in the iFrame wouldn't be able to parse the dom tree of the parent page.

    Jimmy King on
  • RendRend Registered User regular
    edited January 2010
    Jimmy King wrote: »
    Oh, that's pretty cool Tejs. I had thought about a solution like that. I'm not a front end guy and assumed Javascript in the iFrame wouldn't be able to parse the dom tree of the parent page.

    That was basically also my worry.

    Rend on
  • TejsTejs Registered User regular
    edited January 2010
    Jimmy King wrote: »
    Oh, that's pretty cool Tejs. I had thought about a solution like that. I'm not a front end guy and assumed Javascript in the iFrame wouldn't be able to parse the dom tree of the parent page.

    I'm technically not a front end guy either... it just happens to have some overlap with ASP.NET =D

    As for backwards compatibility, use Spoon - Browser Sandbox. It's a neat site that lets you emulate browser editions. It's useful when I need to troubleshoot the god forsaken IE6 incompatibilities that exist everywhere. I got that link from one of the UI designers at work.

    Tejs on
  • SeguerSeguer of the Void Sydney, AustraliaRegistered User regular
    edited January 2010
    Rend wrote: »
    Jimmy King wrote: »
    Oh, that's pretty cool Tejs. I had thought about a solution like that. I'm not a front end guy and assumed Javascript in the iFrame wouldn't be able to parse the dom tree of the parent page.

    That was basically also my worry.

    You might want to recheck this. I don't think it can work across domains, which it sounds like your solution requires.

    If both the parent page and the iframe src are on the same domain, it can work (hell, then you can do parent. anything).

    Seguer on
  • RendRend Registered User regular
    edited January 2010
    Seguer wrote: »
    Rend wrote: »
    Jimmy King wrote: »
    Oh, that's pretty cool Tejs. I had thought about a solution like that. I'm not a front end guy and assumed Javascript in the iFrame wouldn't be able to parse the dom tree of the parent page.

    That was basically also my worry.

    You might want to recheck this. I don't think it can work across domains, which it sounds like your solution requires.

    If both the parent page and the iframe src are on the same domain, it can work (hell, then you can do parent. anything).

    Actually I'm fairly sure they would be on the same domain, so that wouldn't be an issue.

    Rend on
  • TejsTejs Registered User regular
    edited January 2010
    Seguer wrote: »
    Rend wrote: »
    Jimmy King wrote: »
    Oh, that's pretty cool Tejs. I had thought about a solution like that. I'm not a front end guy and assumed Javascript in the iFrame wouldn't be able to parse the dom tree of the parent page.

    That was basically also my worry.

    You might want to recheck this. I don't think it can work across domains, which it sounds like your solution requires.

    If both the parent page and the iframe src are on the same domain, it can work (hell, then you can do parent. anything).

    That's a good point. It obviously never came up when I was making my test files =D

    Tejs on
Sign In or Register to comment.