How to use external ajax response in Chrome Plugin - javascript

I have a existing file ajax,js in my website that makes an ajax request and creates a global JSON object, searchResult using that response. Now I am creating a Chrome plugin, that requires this JSON Object inside it. I have a content script for the plugin viz. plugin.js and I want to include the object inside plugin.js file.
When I try to log window.searchResult from within plugin.js, it shows as undefined.
but when I use browser console, it shows the value as expected.
Please help me with this.

Problem
Chrome content scripts and the page's own scripts live in isolated worlds.
Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page.
Your code works in the console, since you execute it by default in the page's context. To see what the extension sees, you need to switch it.
Solution 1a
First, the generic solution (works even if you don't control the webpage)
There is a way around this, by injecting some code directly into the page's "world" (or properly called, context).
After injecting the code, your page-level script needs to communicate with the content script to pass the data. It's possible with custom DOM events (as, as you remember, DOM is shared). The page-level script sends an event with the data in the event's details.
Alternatively, you can just attach the data to some DOM node, say, an invisible <div>.
Solution 1b
Since you said it's your page, you can skip the inject-into-the-page step and have a listener ready in the page's own code.
The content script sends a custom event to request the data, and the page answers passes the data back as described in 1a.
Solution 2
In theory, you don't even need a content script.
You can use the "externally_connectable" mechanism to speak with the page directly.
Note though that the page has to initiate the conversation.

Related

Javascript script/dom dependency?

When helping someone with a website that is rather large and have many includes I hit a bug and couldn't understand it. It was something like this
<script src=...></script>
<div ...
<script>
alert('myscript');
</script>
This page worked fine until I use that section of html and used jquery to ajax the content in. It broke the code but I don't understand why. I seen my alert. I can see the script is being access via the browser network log. I see some of the results of the first script tag but its broken.
Why does order matter? I thought as long as the dom is ready and the script is executed everything should be fine. But in this case being ajaxed in breaks it. I couldn't spend much time but it was curious to see something was dependent on timing.
--edit--
Also I notice if the script is already included on the page ajaxing in the content it will run fine
Does anyone have any idea why ajaxing in content breaks? When its not ajaxed in its fine.
Based on what you say, I give the following assessment :
40% likely -- it is about script load. Dependencies within the ajaxed script to other scripts, variables you define on the page, or even DOM content that is supposedly loaded could be not loaded at the time the script is ajaxed and executed.
Try changing the order of the script tag on the page, putting the loading of the script inside a document ready event handler, or delaying the script execution with setTimeout or defer="defer" -- or if you are really cool create a boot loader that ensures every script is loaded and executed in the exact order you specify : by chaining sets of dependency free simultaneous loads, to sequences of dependent loads.
Script1 <---- depends on --- (Script 2.1, Script 2.2, Script 2.3 )
<--- depends on --- Script3.
So load 1 first, then all the 2. scripts, then 3.
40% likely -- it is about security model. The website where you are ajaxing it from, Where is that? What is its relation to the domain the page is on? Are you testing this on localhost ?If so there are more restrictions. What about on an actual server? Is the Access-Control-Allow-Origin header set appropriately on the ajax response?
20% likely -- it is a circular dependency between the script and the DOM. Say some event handler on element X closes on a scope that references element X. Then there will be a reference to X inside a reference to X so they can't both be garbage collected, so X will persist, cause a memory leak, and possibly create an unusable reference which could be breaking your code.
--edit--
Based on your comment about .html(...) I think .html or .load to run scripts is too messy, and may not even work at all. See .load() doesn't load scripts for a nice way to load scripts with ajax. Or you could jQuery.getScript(...).
Also I seem to remember having issues even with loading html nodes from plain HTML using ajax. It just seems too messy to me. If you want to transfer structured information across ajax, use JSON, then present that information on your side with javascript and HTML. So, don't grab the whole data + presentation, just grab the data, then do your own presentation on your side. It's much neater.

Avoid duplicate Javascript inside iframes

Here is a wireframe to ilustrate the structure of a legacy project that shows some performance issue:
For all dialogs (From jQuery UI) open a new iframe are created and all js from Home are re-downloaded and all objects are re-instanced. Can I create a reference from jQuery from Home to all new iframes and work in each iframe isolated scope?
For example:
[Home scope]
$("#some-el").data('foo', 'bar');
console.log($("#some-el").data('foo')); // results bar
[App1 scope]
//after defined in Home first run
console.log($("#some-el").data('foo')); // results undefined
PS: Remember this is a legacy architeture and all solutions must be consider this scenario.
I've encountered this situation before. One approach is to define some javascript that gets loaded into the iframes that just reroutes any function calls to top.functionCall() instead of containing their actual definition. It becomes very simple if all of your functions are under one namespace, like so:
Parent window js:
var namespace = (function () {
// all of your functions are in here as properties of namespace
})();
iframe window js:
var namespace = top.namespace;
One issue with this is any context sensitive functions (functions that rely or operate on the window object) will most likely break.
Actually, if all of these are hosted in the same place, the browser will NOT be downloading the files multiple times. Rather, it will be caching the first result, and then pulling from cache in the second. Iframes are treated as a separate context, so you won't need to worry about variable or form conflicts.
Assuming that downloading the same file twice is your primary concern, then you should be ok there.
An alternative design would be to use AJAX instead of iframed content - but having been where you are in working with legacy apps, I realize how hard that can be to do without real JSON / REST calls available. One thing I've done is changed the views inside the iframes to be "partials," returning only the necessary HTML contents without the HTML head etc., and loading them using $.load(). This gets complex as you will need to execute bindings post-load and carefully track form ID's etc., but it can be done.

Is there any way, other than to use eval/handleAs: "javascript" to dynamically fetch scripts (via XMLHttpRequest)

Here I have asked a question pertaining to exceptions raised when dynamically loading scripts via XMLHttpRequest (in other words when executed via eval)
In a related question, I wanted to know whether loading scripts dynamically as such is considered bad practice to begin with. In my particular case I have an HTML Canvas element, and rather than load all possible shapes, I want to fetch them dynamically, without reloading the page, and execute them on return. The problem I am having there is that if the code associated with that shape is incorrect, the error message displayed is not very useful (indicates location of eval statement, not incorrect statement). Is there another way to dynamically fetch code from the server and execute it, while better informing the location of the exception when it occurs.
If you want to load a script use a <script> element. If you want to dynamically load a script, create the <script> element dynamically.
var script = document.createElement('SCRIPT');
script.src = "<url to load>";
document.getElementsByTagName("HEAD")[0].appendChild(script);
It's not guaranteed to be synchronous the way eval with synchronous XHR is, but ideally you'd structure your code to take advantage of asynchony.
Adding to Mike's answer, if you want good debugger support including a script tag is probably the way to go, since that is what debuggers are used to working on. The main differences from eval that you need to be aware of are:
Eval runs in the scope of where its called while included script tags run in the global scope.
Eval is synchronous while included tags run asynchronously. (You will need to use something like JSONP and dojo.io.script if you need to run code after the script tag finishes).
If the scripts are fixed you can also consider debugging them by including their script tags and deploying them as you see fit.

using jquery on child frame without loading it again

is it possible to load and use jquery in the parent iframe page & inside the iframe whithout loading jquery twice,
meaning to load jquery just once in the page and using it in the ifrmae within.
Sure, just make sure the <iframe> isn't loading the jQuery script i.e. <script src="...."> then you can access the jQuery instance in the parent like so:
var $ = window.top.$;
Be sure to use the correct context using the second parameter:
$('img', document);
If this isn't possible you can't "prevent" a script from being downloaded and executed.
You can give the child frame a reference to the jQuery object from the parent frame, but you'd have to be very careful about using it because in various places, jQuery uses the document object of the context in which it was loaded, which will (of course) be the parent's document. In some places you can override that (for instance, when searching for elements via $() you can give a context in which to search as a second parameter), but it's likely to be more trouble than it's worth.
But re-loading jQuery shouldn't be an issue. It should come from cache. Granted, there may be an extra HTTP GET with an "unmodified" response, although by using proper cache headers when serving the jQuery file, you could avoid even that. (I haven't checked the cache headers of the various CDNs that host it.)

AJAX + dynamically adding java script function to the page

I am loading a portion of page using AJAX calls, which may contain script functions defined in them . Which are attached with the controls being loaded with different events. Now the problem is that when those events triggered i got the error "object not found" which indicate the function is not found/defined. While using Firebug i can see that the function is defined and available. So how can i make sure that browser can find the respective function.
I tried but either i am missing some thing or either its not working, Here is what i am doing
Page
--->Partial View A
----->Partial View B
Now Page Loads Partial A with Ajax Calls which further loads Partial B with Ajax Calls.Both Partial A & B contains few java script function that logically only associated with them not with master page.
The pages loads fine except the functions could not execute as "Object Not Found" comes in.
You should define functions using this syntax:
myFunction = function(foo) {}
not this syntax
function myFunction(foo) {}
The second form won't work when eval()'d (which is probably what's happening)
If you are using a framework or library you have to set a parameter in order to evaluate the script present in the response of the ajax request. It's usualy called evalScripts
evalScripts:true
You can also use the callbacks (success/error) of the request to trigger the events, so that it's easier to keep the code in one place and to avoid situations like this.
If you are using plain javasciprt and the XmlHttpObject, then you have to manually find all the script tags in your response and then eval() them.

Categories