Bootstrap.js file in both parent and iframe - javascript

I am creating a web app using bootstrap by twitter. The app contains of a page which loads up another page of the same domain in an iframe. Now my problem is, if the page that I am loading in iframe also contains bootstrap.js file it starts conflicting with the app.
For example, my app has a accordion (collapse) http://twitter.github.com/bootstrap/javascript.html#collapse built using the data attributes.
Once a page with bootstrap.js is loaded the collapse event starts getting fired twice.So something like
<head>//Bootstrap css and js files included</head>
<body>
<div>
//Collapsible Menu #1
</div>
<iframe>
<head>
//BootStrap.js script from same location as parent
</head>
<body>
// Another Collapsible Menu #2
</body>
` </head>
</iframe>
</body>
Here when I try to click on Menu #1, the code of Bootstrap.js gets triggered twice which ends ups in showing and then hiding the menu.
But my problem is not just limited to the menu. I need to be able to use bootstrap.js in my app and also allow pages which already contain bootstrap.js to be loaded inside the iframe.
Is there a way around this or am I doing something wrong?

found the problem.. it was very specific for my app. The way it was working was - there was an included JS file to trigger the app inside the "target" webpage. The JS file would not remove everything from the page and build an iframe to put load the content of the "target" inside iframe. Now in this case, I had BootstrapJS running before the app.js file which in turn resulted in getting executed in the "parent" frame and then when the app loads it was getting reloaded causing the conflict (or multiple events due to multiple inclusion).

I had the same issue in IE9 only.
I was opening an instance of my website in an IFRAME dialog. Meaning that there was 2 instances of Bootstrap, like above.
When I moused out of the IFRAME it resized the underlying layout to match that of the width of the smaller one in the IFRAME.
To get round it I had to disable the opening pages bootstrap-responsive.js stylesheet using javascript. You can then turn it back on, when you close the IFRAME dialog.
if(navigator.userAgent.indexOf("Trident/5")>-1){
window.parent.document.getElementById("responsiveCSS").sheet.disabled = true;
}
Horrible hack, I know.

Related

'document.getElementById' only works on index.html

Ultimate goal is to cycle through photos on a blog page. Seems like 'document.getElementById().src' would be a good approach.
Problem: To make sure the javascript code is successfully linking to the blog page, I tried testing with this in my script.js file:
document.getElementById('testID').innerHTML = "Running test";
and this in my .html file:
<div id="testID"></div>
But, the text "Running Test" does not show up on the blog page. However, when running this same exact test in my index.html page, it does work. Both .html files load the same script file along with jQuery. I don't understand why it works in one html file and not the other.
NEW FINDING:
This line of code now works on the blog page when I remove it from inside
$(document).ready(function(){ ... });
Why would that be?
The Javascript in the current page can only access HTML elements that are in pages that are currently loaded into the browser.
More specifically, document.getElementById() ONLY searches the current web page's document for matching elements. It does not search any other pages and certainly does not search other files on your server that are not loaded into the browser. "current web page" means the HTML loaded from the current URL in the browser bar.
When a web page is no longer visible in the browser window (e.g it's been replaced by some other page), it is gone and no longer reachable by any Javascript. In some specific cases, you can access document loaded into other tabs or other frames (subject to same-origin security rules and requires a different method of access).
In addition, no changes to a web page are persistent in the browser. As soon as a web page is no longer loaded into an active browser window, it is gone and reloading it again will load the original, unmodified version of that document.
If you want the same code from one page to run in another page, then you must include that same code in the other page. You can want, you can share a reference to the code by putting the code into its own page and then using a <script src="xxx.js"> tag in each page to cause the same code to get loaded into each page.
If interpret Question correctly, try using .load()
$("#container").load("/blog/blog_1.html #testID")

My main Index page embeds 2 other pages using Angular UI-Router; how can I get the Javascript file I'm loading in the Index to reach all 3 pages?

Using UI-Router the main page loads 2 other pages within them.
Index --> loads CSS and JS (including "application.js") with a <ui-view> to Navigation
Navigation page --> has navigation HTML with another <ui-view> to Content
Content
So basically Index > Navigation > Content
The Index is loading "application.js" with <script src="application.js"> at the bottom of the page. it contains all the page functionality.
It's loading successfully as I put an alert in the window.load function to make sure.... but what I'm finding is that I think the code in there is not reaching the other 2 embedded pages
The code works successfully if I put all the code and combine them together from the Index, Navigation, and Content into one single page. But not when separated but embedded together.
I tried putting:
<script src="~/assets/js/application.js"></script>
at the bottom of the Layout and Content but still didn't work..I'm guessing because technically it's loading as one page? but it's not really one page?...
HOWEVER if I copy and paste everything within application.js into the Layout and Content.. it WILL work.
That's such a crappy way of doing it though. How can I get this to work properly?

Activating Zurb Foundation's Joyride in an iFrame, from Chrome Extension content script

I am building a Chrome extension that creates an iFrame inside any HTML page (i.e. any page being viewed in the browser window).
The iFrame is "injected" into the HTML page by the Chrome extension's content script. The resulting HTML looks like this:
<html>
<head>..</head>
<body>..</body>
<iframe id="myIframe">...</iframe>
</html>
After the content script adds the iFrame to the main page's DOM it goes on to populate the iframe with content by manipulating its own DOM. I use the Zurb CSS to style the iframe content.
And this all works fine.
I am now trying to add the Zurb Joyride to the content of the iframe, and it is this that I cannot get to work.
My manifest's content_scripts declaration looks like this:
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["js/externalJS/jquery-2.1.4.min.js",
"js/externalJS/foundation.min.js",
"js/content_script.js"],
"run_at": "document_end"
}],
I suspect the iframe itself needs to have access to the Zurb scripts, so as well as foundation.min.js being loaded by the manifest as part of the extension, my content script also adds the relevant tags inside the iframe (by manipulating the DOM). My understanding is that the key elements within the iframe are:
tags for Zurb JS files
An object to attach the joyride to (id="testjoyride")
The joyride content itself
The initialisation call to foundation()
And so, with this in mind, I have the manifest's web_accessible_resources declaration looking like this:
"web_accessible_resources": [
"js/externalJS/jquery-2.1.4.min.js",
"js/externalJS/vendor/modernizr.js",
"js/externalJS/vendor/fastclick.js",
"js/externalJS/foundation.min.js",
"css/foundation.css",
"css/app.css"
],
And then use the content script to build up the following HTML inside the iframe:
<iframe id="myIframe">
<html>
<head>
<!-- the foundation style sheet (which works fine already) -->
<link type="text/css" rel="stylesheet" href="chrome-extension://extension_id/css/foundation.css">
<!-- the first two scripts -->
<script src="chrome-extension://extension_id/js/externalJS/vendor/modernizr.js"></script>
<script src="chrome-extension://extension_id/js/externalJS/jquery-2.1.4.min.js"></script>
</head>
<body>
<!-- a test object to attach the joyride too -->
<input type="submit" id="testjoyride">
<!-- now the rest of the iframe content -->
... content ...
<!-- the other two scripts -->
<script src="chrome-extension://extension_id/js/externalJS/vendor/fastclick.js"></script>
<script src="chrome-extension://extension_id/js/externalJS/foundation.min.js"></script>
<!-- default joyride code from foundation.zurb.com -->
<ol class="joyride-list" data-joyride="">
<li data-id="testjoyride" data-class="custom so-awesome" data-text="Next" data-prev-text="Prev">
<h4>Stop #1</h4>
</li>
<li data-button="end" data-prev-text="Prev">
<h4>Stop #3</h4>
</li>
</ol>
</body>
</html>
</iframe>
Then, finally, when all of the above content is attached to the iframe (and the iframe, of course, is attached to the parent page's DOM) I call foundation(), from the content_script.
I think I need to call it like this:
$(window.frames.myIframe.contentWindow.document).foundation('joyride', 'start');
i.e. passing in the document object of the iframe, not the parent page **
So I do all of that, and nothing happens. The joyride does not appear, nor does the HTML get transformed into the auto-generated output (as described here).
I have created a test case in a simple HTML page and it worked fine, I tried to move that test page into an iframe and the joyride stopped working. I therefore suspect, although without much confidence, that the issues lies with the iframe, not the Chrome extension.
** Note, I place this call right at the end of all the DOM manipulation. After I have added the new HTML I've created to the iframe's DOM, and after creating all my listeners etc. So I'm confident the scripts and the joyrides should be "there" by that point. However, if I stick an alert() just before the call to foundation('joyride','start'), the alert displays with an empty iframe behind it, and only after I dismiss the alert does the iframe populate. Whether that's important, or just a strange effect of the alert, I don't know.
Thanks to some helpful comments, I managed to get this working. The exact same solution got QTip2 working as well. So this is a solution for:
Third party javascript packages (specifically, JQuery, Foundation Zurb Joyride, and QTip2)...
... injected programmatically by a Chrome Extension...
... into an iFrame - that has itself been injected, by the Chrome Extension, into the user's current webpage
I will do my best to describe it below. I am self-taught and still a newbie, so my apologies for any confusing terminology or divergences from best practice.
Solution Overview
I ended up with three levels to my Chrome Extension:
A background script, controlling the extension (fairly inconsequential to this specific problem, but worth mentioning for completeness).
A content script, that receives commands from the background script and programmatically injects an iframe, the iframe HTML content, and the 3rd partly JS packages into the user's webpage.
An "iframe script", which is a custom JS script that is injected into the iframe along with the 3rd party packages. This iframe script can send/receive messages to/from the content script, whilst at the same time having access to the 3rd party JS packages - Zurb Joyride & QTips
The Manifest
Although the content script (content_script.js) controls all of the injection, it never actually runs any of the 3rd party JS packages itself. They are run by the user's webpage. Therefore my manifest's content_scripts declaration looks like this:
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["js/content_script.js"],
"run_at": "document_end"
}],
Because the web page needs to access the 3rd party scripts, it must be given permission. It also needs access to our custom iframe script:
"web_accessible_resources": [
"js/iframe_script.js",
"js/externalJS/jquery-2.1.4.min.js",
"js/externalJS/jquery.qtip.min.js",
"js/externalJS/vendor/modernizr.js",
"js/externalJS/vendor/fastclick.js",
"js/externalJS/foundation.min.js",
"css/foundation.css",
"css/jquery.qtip.min.css"
],
Content Script: Inject Joyride HTML into the iframe
The content script creates an iframe element (id="myIframe") and appends it to the user's webpage. It then goes on to programatically fill it with content.
Some of that content will become the anchors for the joyride: HTML elements with their ids set to joyrideStop1, joyrideStop2, etc:
iframeContentHTML += <i class="fi-info brandSpielIcon" id="joyrideStop1"></i>
And the content script also builds up the joyride HTML, as per the Zurb docs, at the bottom of the iframe body.
joyrideHTML += '<ol class="joyride-list" data-joyride>';
joyrideHTML += ' <li data-id="joyrideStop1" data-text="Next (1 of 5)" data-prev-text="Prev" class="customJoyride">';
joyrideHTML += ' <h4>Title</h4>';
joyrideHTML += ' <p>Content</p>';
joyrideHTML += ' </li>';
...
My custom CSS class is simply:
.customJoyRide .joyride-nub {
visibility: hidden;
}
This makes the little pointy arrow on the joyride tooltip disappear. I had significant problems trying to get the joyride to display nicely inside the small iframe. Ideally I would like them to anchor to elements inside the iframe, but display as though they are part of the main page. In the end this seemed either too hard or impossible, so I just removed the nub and dodged the issue. This is a display issue, and only a problem for small iframes, so not a core part of this solution.
Content Script: Inject JS into the iframe
To get Joyride to work, we need to inject the 3rd party scripts and the custom iframe_script.js into the iframe. This is an example of the code from content_script.js for one of the 3rd party scripts:
// Inject foundation script into iframe body
var foundationScript = document.createElement('script');
foundationScript.src = chrome.extension.getURL('js/externalJS/foundation.min.js');
window.frames.myIframe.contentWindow.document.body.appendChild(foundationScript);
NB. This part of the solution corrects one of my original mistakes. The scripts do not seem to initialise if you simply append text to innerHTML like so: body.innerHTML += '<script src=".."></script>;'
So I repeat the above code for all the scripts. In the iframe head I put:
jquery.qtipmin.css
modernizr.js
jquery-2.1.4.min.js
And at the bottom of the iframe body I put:
fastclick.js
foundation.min.js
jquery.qtip.min.js
iframe_script.js.
In that order.
Iframe Script: initialise
When iframe_script.js initialises, I immediately get it to add a message listener (so the content script can communicate with it) and then send a message to the content script telling it it's ready (the content script already has its own message listener set up, the code for which is not detailed here):
(function initialise(){
// Listen for messages from the content script
window.addEventListener("message", contentScriptMessage_listener, false);
// Tell the content script we're ready to go
window.parent.postMessage({sender: 'iframe_script',
subject: 'iframeScriptHasInitialised'}, '*');
})();
NB. I struggled to make sure the iframe's listener was set up before my content_script sent its first message to the iframe. In the end this solution (waiting for a message back from the iframe) seemed to work best, although I suspect there may be a better way
Content Script: tell the iframe to activate the joyride
Now that the content script knows the iframe listeners are ready, it can tell it to activate the Zurb joyride (and/or the QTips). I do this by sending a message back to the iframe.
window.frames.myIframe.contentWindow.postMessage({
sender: 'content_script',
subject: 'pleaseActivateJoyride'}, '*');
Obviously it would be simpler to activate the joyride directly from the iframe script, without all these messages bouncing back and forth. But that's the whole point: it's the content script that knows whether or not the joyride should even be displayed, let alone all the other config details. Keeping control with the content script (and, ultimately, with the background script) makes for a much tidier implementation over all.
Iframe Script: activate Joyride
My iframe script's message handler receives the message from the content script and calls this function:
function activateJoyride(){
$(document).foundation({
joyride: {
... configuration ...
}
});
$(document).foundation('joyride', 'start');
}
NB. I have an outstanding issue here. This can sometimes run before JQuery is loaded, resulting in an error ("$ is not declared"). I have played with window.setTimeout in an effort to resolve this, and it works nearly all the time... but it's not 100%
And that's it!
There's a matching activate function for the QTips, with the appropriate content injected into the iframe earlier. Just like with the joyride, I struggled with the rendering of the Qtips inside the small iframe. QTip2 is more powerful and the docs suggest there are solutions.

Load External javascript, but HTTP request repeatedly for one file javascript

I have problem when load external html into specific <div>. Here is the problem :
I have html files, "index.html" and "problem.html".
In problem.html I use skrollr to animate content.
When I click the "open" button in index.html, I use jquery load() method to load problem.html into specific in index.html.
The content was loading, but slowly.
When I check using firebug, I see many request skrollr.min.js. Why do I get skrollr.min.js and other file repeatedly?
When I refresh the page, load the menu and see at the firebug there are so many get skrollr.min.js and file that are called.
You could try to load the Page via iframe to see if it's faster. Just set the innerHTML of your container to
<iframe src="http://yourdomain.com/problem.html"></iframe>
when he clicked the Button.

jquery "listview" and charts

I have some troubles with display charts (jquery Charts) into a web.
I have two pages (1.html and 2.html). The first contain a listview that links with the second page. The 2.html displays the chart. Here is the problem: When page 2 is launched through page 1, the chart doesn't appear!! But if I reload the page 2.. so the chart appears!
If I work with an only page using "href=#page" references the chart works fine and it's displayed, but my intention is to have different html files, one of them with the listview and the other one with the chart. Is it possible?
I have tested many types of jquery charts and all of them had the same behavior.
Any idea?
thanks for all,
Best Regards.
Here the files:
1.html ----
<head>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
</head>
<body>
<div data-demo-html="true">
<ul data-role="listview" data-inset="true">
<li>Chart</li>
</ul>
</div>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js">/script>
</body>
2.html with the code into the reference (jqwidgets - chart_bar)
To understand this situation you need to understand how jQuery Mobile works. It uses ajax to load other pages.
First page is loaded normally. Its HEAD and BODY is loaded into the DOM, and they are there to await other content. When second page is loaded, only its BODY content is loaded into the DOM.
The most realistic solution would be to move all of your javascript into the original first HTML. Collect everything and put it inside a single js file, into a HEAD. Initialize it after jQuery Mobile has been loaded. I would also use that same index.js file and initialize it inside a HEAD of every possible other page.
Now you can ask me WHY?
Phonegap like jQuery Mobile is buggy, and sooner or later there's going to be an error and your app will fail (including loaded DOM) if your every js content is inside a single HTML file. DOM could be erased and Phonegap will refresh your current page. If that page don't have javascript that it will not work until it is restarted.
I've listed other ways to fix this problem (with examples) in my answer here: Why I have to put all the script to index.html in jquery mobile.

Categories

Resources