Can you turn off the loading screen in Submodal? - javascript

We are using the enhanced sub-modal script (http://gabrito.com/files/subModal/) and would like to bypass the loading.html screen that comes up by default. Can this be turned off? Setting the value to "null" shows a "page not found" error before the actual page loads.

It's not hard, but the code is scattered all over the place in the Javascript source. You might want to use a more modern alternative instead (especially if you're already using a library on your site)
First of all, we strip out all instances of the gLoading variable - this means removing the setPopUpLoadingPage function and the src="'+gLoading+'" in the part where they build the HTML string to inject into the page. And finally, one last reference to gLoading exist in the hidePopWin function, to reset the iframe source back to the loading page when the modal is hidden.
Then finally we replace the line gPopFrame.src = url; in the showPopWin function with this:
if(gPopFrame.src != url){
gPopFrame.src = url;
}
To stop the iframe from reloading if it's the same source.
You can see a live demo of the new script here: http://www.jsfiddle.net/yijiang/T2u2Z/ and also grab a copy of it here: http://dl.dropbox.com/u/1722364/submodalsource.js

Related

Javascript: Text in arrays and multiple textareas

I'm trying to load a parent page into an object tag, and whilst I can get an alert to show I've got the code, I cannot get it into the <object> Any clues?
var page=parent.document.documentElement.innerHTML;
alert(page);
document.getElementById('close_skin').style.visibility="visible";
document.getElementById('show_skin').style.visibility="visible";
document.getElementById('show_skin').setAttribute("data",page);
Assuming I can get the code to appear, how can I "toggle" to a different set of styles? The parent uses ".xxx_fixed" classes, but the code in the object needs to use the ".xxx_float" classes that are also in the template CSS at top of page. (When I did it in another PERL program, it was easy just to rename the tags in the <body> from "class='xxx_fixed' " to "class='xxx_float' " (Can't do that so easily with global javascript replace as that would also rename the classes at top of code as well!)
I have just tried adding some script to the top of the var page object - which MAY work if I can get the code to appear ...
+'document.getElementById(\'icon_outer\').setAttribute(\'class\', \'icon_outer_float\')'
If you're interested as to the "why", the "fixed" keep menu / top bar fixed in one place when viewed in full screen browser, but the 'float' makes everything move in unison within the <object> "window" allowing viewer to pan around the template page like a static magnifying glass;
.menu_back_float{position:relative;top:0px;background-color:#f5eca4;min-height:520px;height:auto}
.menu_back_fixed{position:relative;top:35px;background-color:#f5eca4;min-height:550px;height:auto}
To load the parent page into an <object> element, you have to specify the URL of the page. To get the code and place it in a alert box, you can use jQuery's $.get() method (as long as you load it via a proxy domain), like this:
HTML:
// I'm just using W3Schools just to save time
<object data="http://www.w3schools.com/" width="1500" height="1200">
<embed src="http://www.w3schools.com/" width="1500" height="1200"></embed>
Your browser does not support the object tag.
</object>
JavaScript:
window.jQuery.get("http://www.yourdomain.com/?url=www.w3schools.com", function(response) {
window.alert(response);
}
For the second part of your question, you can use jQuery to change the name of the class from .xxx_fixed to .xxx_float:
function main() {
$('object').removeClass('xxx_fixed').addClass('xxx_float');
}
$(document).ready(main);
Hopefully I have answered your question correctly and thouroughly, and if I haven't, feel free to let me know so I can edit this.

How to switch between original DOM and the DOM changed by a Content script?

I'm making a Chrome Extension that changes the DOM of a page. But I would like to give the user an option to switch between the page before the changes and the changed page.
It's a little bit like Google translate where you can change between the orginal language and the translated message.
I could not find anything in my own searches.
I know JavaScript but not JQuery yet.
Thanks for the help.
You could save the entire body in a variable, then start overwriting things. If you want to switch back load up the old body.
You could save all the original DOM content to a variable before running the content script. You can do this by using the following code at the top of your content script:
var originalDOM = document.getElementsByTagName("*");
This saves the entire DOM in an array called originalDOM. The * acts a universal tag, requesting every tag in the document. You can read more about the .getElementsByTagName() API here.
You could try:
var html = document.getElementsByTagName("html")[0];
var page = html.innerHTML;
This will give you everything between the <html> tags.
After the content script is injected, run:
var newPage = html.innerHTML;
Now, whenever you want to switch between the pages, simply run:
html.innerHTML = page; //or newPage
You can read more about the .getElementsByTagName() API here

Most secure javascript JSON Inline technique

I'm using varnish+esi to return external json content from a RESTFul API.
This technique allows me to manage request and refresh data without using webserver resources for each request.
e.g:
<head>
....
<script>
var data = <esi:include src='apiurl/data'>;
</script>
...
After include the esi varnish will return:
var data = {attr:1, attr2:'martin'};
This works fine, but if the API returns an error, this technique will generate a parse error.
var data = <html><head><script>...api js here...</script></head><body><h1 ... api html ....
I solved this problem using a hidden div to parse and catch the error:
...
<b id=esi-data style=display:none;><esi:include src='apiurl/data'></b>
<script>
try{
var data = $.parseJSON($('#esi-data').html());
}catch{ alert('manage the error here');}
....
I've also tried using a script type text/esi, but the browser renders the html inside the script tag (wtf), e.g:
<script id=esi-data type='text/esi'><esi:include src='apiurl/data'></script>
Question:
Is there any why to wrap the tag and avoid the browser parse it ?
Let me expand upon the iframe suggestion I made in my comment—it's not quite what you think!
The approach is almost exactly the same as what you're doing already, but instead of using a normal HTML element like a div, you use an iframe.
<iframe id="esi-data" src="about:blank"><esi:include src="apiurl/data"></iframe>
var $iframe = $('#esi-data');
try {
var data = $.parseJSON($iframe.html());
} catch (e) { ... }
$iframe.remove();
#esi-data { display: none; }
How is this any different from your solution? Two ways:
The data/error page are truly hidden from your visitors. An iframe has an embedded content model, meaning that any content within the <iframe>…</iframe> tags gets completely replaced in the DOM—but you can still retrieve the original content using innerHTML.
It's valid HTML5… sort-of. In HTML5, markup inside iframe elements is treated as text. Sure, you're meant to be able to parse it as a fragment, and it's meant to contain only phrasing content (and no script elements!), but it's essentially just treated as text by the validator—and by browsers.
Scripts from the error page won't run. The content gets parsed as text and replaced in the DOM with another document—no chance for any script elements to be processed.
Take a look at it in action. If you comment out the line where I remove the iframe element and inspect the DOM, you can confirm that the HTML content is being replaced with an empty document. Also note that the embedded script tag never runs.
Important: this approach could still break if the third party added an iframe element into their error page for some reason. Unlikely as this may be, you can bulletproof the approach a little more by combining your technique with this one: surround the iframe with a hidden div that you remove when you're finished parsing.
Here I go with another attempt.
Although I believe you already have the possibly best solution for this, I could only imagine that you work around it with a fairly low-performance method of calling esi:insert in a separate HTML window, then retrieve the contents as if you were using AJAX on the server. Perhaps similar to this? Then check the contents you retrieved, maybe by using json_decode and on success generate an error JSON string.
The greatest downside I see to this is that I believe this would be very consuming and most likely even delays your requests as the separate page is called as if your server yourself was a client, parsed, then sent back.
I'd honestly stick to your current solution.
this is a rather tricky problem with no real elegant solution, if not with no solution at all
I asked you if it was an HTML(5) or XHTML(5) document, because in the later case a CDATA section can be used to wrap the content, changing slightly your solution to something like this :
...
<b id='esi-data' style='display:none;'>
<![CDATA[ <esi:include src='apiurl/data'> ]]>
</b>
<script>
try{
var data = $.parseJSON($('#esi-data').html());
}catch{ alert('manage the error here');}
....
Of crouse this solution works if :
you're using XHTML5 and
the error contains no CDATA section (because CDATA section nesting is impossible).
I don't know if switching from one serialization to the other is an option, but I wanted to clarify the intent of my question. It will hopefully help you out :).
Can't you simply change your API to return JSON { "error":"error_code_or_text" } on error? You can even do something meaningful in your interface to alert user about error if you do it that way.
<script>var data = 999;</script>
<script>
data = <esi:include src='apiurl/data'>;
</script>
<script>
if(data == 999) alert("there was an error");
</script>
If there is an error and "data" is not JSON, then a javascript error will be thrown. The next script block will pick that up.

How can you see which Javascript script generated a certain html line?

I have some crazy app done almost 100% by manipulating the DOM and I find myself in the unfortunate position of changing something in it. As there are probably around 100 different scripts that do God knows what, I have no clue in which file should I look to make my changes. So, I want to ask, is there a way (using Firebug maybe or something similar) to know where a specific piece of html was generated? I'm a C developer, so I'm not very good at this, it drives me crazy.
Are all the elements added at the page load, or partially in the response to the user input? (clicking etc.)
for stuff added with the response to your actions, you can use Firebug's "Break On Next" button in the "Script" tab. To active BON you have to click it, or, in just-shipped Firebug 1.10.0a8, use keyboard shortcut ALT-CTRL-B (useful when you have event listeners bound to mouse movements). Then, when any piece of JS is going to be executed in reaction to your click etc., you will hit a breakpoint.
for stuff added at page load time, you may use the trick of extending the native functions (this might sound crazy - yeah it is, don't do it in production!) like appendChild, insertBefore, replaceChild. Just insert the appropriate code at the very top of your main HTML file, so all the code below will "see" the change.
Unfortunately, this does not work in Firefox due to a bug. But works in Opera and I guess in Chrome as well.
When you extend the native function, you can inject any code before really adding the node to the page. For instance, call console.log or create a breakpoint, to inspect the current page state. You can try playing with breakpoints to see the available variables properties inside those function to adjust what you push to console.log.
For this code:
<!doctype html>
<html>
<head>
<script type="text/javascript">
// this should work in Firefox but it does not -- https://bugzilla.mozilla.org/show_bug.cgi?id=618379
// works at least in Opera, probably Chrome too
Node.prototype._appendChild = Node.prototype.appendChild;
Node.prototype.appendChild = function(child) {
console.log("appending " + child + " to " + this);
return this._appendChild(child); // call the original function with the original parameters
}
// this works in Firefox
document._createElement = document.createElement;
document.createElement = function(tagName){
console.log("creating " + tagName);
return this._createElement(tagName);
}
</script>
</head>
<body>
<script type="text/javascript">
var p = document.createElement("p");
p.appendChild( document.createTextNode("abc"));
document.body.appendChild(p);
</script>
</body>
</html>
Opera outputs:
creating p appendChild.html:14
appending [object Text] to [object HTMLParagraphElement] appendChild.html:7
appending [object HTMLParagraphElement] to [object HTMLBodyElement] appendChild.html:7
To overcome the weakness of Firefox (that you can't override appendChild), you may use the trick: place the code below instead in the top of your HTML
<script>
Node.prototype._appendChild = function(child) {
console.log("appending " + child + " to " + this);
return this.appendChild(child)
};
</script>
and then, use Fiddler proxy by creating auto-responders (WMV tutorial, 9.9 MB) where you manually replace all calls to .appendChild with ._appendChild (you can use Notepad++ for "find replace in all opened files"). Creating auto-responders and hand-tampering requests can be mundane, but it's extremely powerful. To quickly create auto-responder rule, load the page when Fiddler is active, then drag'n'drop files as in the picture below. For each file, right click and choose "Generate File" from menu (this will put a file on the desktop) or create a file by yourself in different location. (it's good to open Fiddler-generated files and remove response headers from them; BTW "Generate file" puts real contents only if the response header was 200, so make sure to load the page with CTRL-F5 to skip the cache).
In Chrome you can inspect an element and right click on it. This menu gives you some options to break when something below the element is changed or when it's own attributes change. Maybe one of those breakpoints will find what you are looking for?
Assuming you've got access to the raw (hopefully un-minified/obfuscated) JS files, maybe just search them for text strings related to DOM manipulation and/or attributes of the node you're trying to find the creation of? I'd try things like "appendChild" "createElement" and the node's ID/class names.
You could also set break points all over the script files, and step through them as the page loads to help you narrow down where to look. Might help to start by just "pausing" the JS execution and stepping through from the very beginning.
If you can share the code (a link to the live site would do fine) I'd be happy to take a look.
If you are using the jQuery framework in your javascript to make the DOM changes then you may find the fireQuery plugin for FireBug in the firefox browser may get you the information you need.
Example:
It adds additional information to the standard HTML view by superimposing additional jquery element information to the display to provide a deeper insight into how your javascript is amending the page content.
I hope that helps you out.

How to display html page from string

I generate some html content dynamically like:
var content = "<head><title>testtitle</title></head><body>testbody</body>";
Then I get myself a new tab with about:blank, and now I want to display my generated html in this tab. If the tab's contentDocument is newDoc, I thought I just do:
newDoc.documentElement.innerHTML = content;
However, that doesn't work. It seems to have no effect at all. In firebug it seems to work once but screws up firebug at the same time, so I can't verify, source view remains unchanged.
I then tried:
newDoc.getElementsByTagName("head")[0].innerHTML = headContent;
newDoc.body.innerHTML = bodyContent;
Which doesn't change the displayed empty page, also not in the source view, but if I alert newDoc.documentElement.innerHTML, it reflects the changes. It seems like this isn't the document that's displayed any more. Weird.
So my question: how do I do that? Specifically in a firefox extension, if that is important.
Is there maybe a href format with "text://..." instead of "file://..." or something?
Update:
It turns out that I can't only replace the full code this way, I can't even body.appendChild, but I'm sure I did that before, so I compared. Here I get my document this way:
var tab = getBrowser().addTab(); //make new tab
getBrowser().selectedTab = tab; //bring it to front
var browser = getBrowser().getBrowserForTab(tab); //get the window of the tab
var newDoc = browser.contentDocument;
Now I can do:
newDoc.location.href = url;
And this works, it loads the given page.
So I thought this is the correct document, but if I don't assign a url, but instead try to build the dom myself, it simply doesn't work.
If I do those changes to window.content.document after the tab is in front, it works. So how come these documents are different? If newDoc is the wrong one, how come assigning a location does anything?
Although I can get it to work now, I don't particularly like the solution of getting the document by bringing the tab to the front and then grabbing the window.content document, that feels like a hack and depends on timing.
I just found a nifty jQuery method that might accomplish this: http://api.jquery.com/html/#html2
I created a page with a button that calls the script:
$("html").html("<span>Hello <b>World</b></span>");
This replaces the entire page DOM.

Categories