What is this window["obvInit"] ({...}) doing in a script? - javascript

I'm attempting to extract some information from Medium URLs and I notice that each page has the entire post contents stored in JSON format. The content looks like this on the page:
<script>// <![CDATA[
window["obvInit"]({"value":{"id":"e389ba1d8f57","versionId":"1b74...
How do I easily extract this JSON from the page? What does the preface of window["obvInit"] before the JSON mean? Can I call the function obvInit in my Chrome console and get the JSON output somehow?

What this does is call a function. It's probably (but not necesarrily) been declared like function obvInit(...){...} on the global window namespace. Now for your problem: You can easily extract the passed object by overwriting the function like this:
var _oldObvInit = window.obvInit;
window.obvInit = function(){
console.log(arguments[0]); //use this to extract the object
console.log(JSON.stringify(arguments[0])); //use this to extract JSON
return _oldObvInit.apply(window, arguments);
}
Put this before the script tag you've posted here and after the declaration of the function obvInit.
A bit context: inside every javascript function there's an implicit variable arguments which stores the arguments to the function as an array. And apply calls a function, sets the context (this) and takes the arguments as an array. Exactly what you need to wrap it.

This is a technique known as JSONP. Basically, since some older browsers don't have great support for cross-origin AJAX using XMLHttpRequest, you can insert a <script> tag into the page that gets the resource you want, except wrapped like this:
functionName({ /* ...data... */ });
So it calls a function known as functionName with the data as an argument. You would provide this function in your own code before inserting that script, like so:
function functionName(data) {
// use the data
}
window["obvInit"]() is equivalent to window.obvInit() which is equivalent to calling a function defined as obvInit at the global level.
As scripts are not subject to the same-origin policy, you can now get JSON-like data from any domain that will return it in this format.

Related

can I merge these 2 functions into one? (in the name of cleaner scripts...)

Built a website on Google App Script (for ref its on michelmoalem.com).
On page load I populate several vars with verious text blobs read from docs stored on google drive (CV, Biography etc) I use a pair of functions for each blob - on the JS script that - the first one (in this example loadEditor) runs the function getDocContent from the main code page (server side script) and on success feeds the resulting blob to the second function (loadCvData) that populates the var (cvEditing) with the aquired text.
function loadEditor(fetchResults){
google.script.run
.withSuccessHandler(loadCvData)
.getDocContent('16rvULQudFCcdJOb32Qk7qqfOfWmTxJ7MPuQ_fZJhaf4');
}
function (fetchResults2){
cvEditing=fetchResults2;
}
what I was wondering is how to populate the var within the first function eliminating the need for this 2 step solution...?
Perhaps:
function loadEditor(fetchResults){
google.script.run
.withSuccessHandler(function(data){loadCvData(data);let cvEditing=fetchResults;})
.getDocContent('16rvULQudFCcdJOb32Qk7qqfOfWmTxJ7MPuQ_fZJhaf4');
}
Explanation:
You need the success handler in order to handle data coming from server-side via google.script.run and use it client-side, that's how Apps Script works. At most you can use an anonymous function in the success handler, instead of calling another function, but that's it.

Overriding core JS commands?

I'm trying to modify/limit/prevent access to certain JS commands of my browser. For example commands like navigator.clipboard; However, I'm not sure how to approach this.
Is it possible to override these commands with user-defined javascript injected in the page, or do i have to edit the browser's javascript compiler and re-compile it from source for this?
I'm not really familiar with browsers and want to save time by knowing a general direction to follow. Thanks
First of all navigator.clipboard is not a function, but here is an example using the read function of navigator.clipboard:
navigator.clipboard.read = function (originalFunction) {
return function (yourParamsYouWantForThisFunction) {
// Do Stuff you wanna do before the real call. For example:
console.log(yourParamsYouWantForThisFunction);
// Call the original function
return originalFunction.call();
};
}(navigator.clipboard.read); // Pass the original function reference as a parameter
You may wonder, why there are two function statements:
The first one is there, so that we can pass the original function at runtime. If we would not do that, we would not be able to access the original navigator.clipboard.read function.
The second function is the actual function, that you will be using later, when you call navigator.clipboard.read().

I'm struggling to call this unusually structured Javascript function from XUL

(function(aLeftPane) { ... }) ("History").
The complete function is here: pastebin.com
I haven't been able to get my head round how the contents of the seconds set of brackets gets passed into the functions in the first set.
I want to make the hard-coded "History" into a variable. I've tried wrapping the whole thing in a more regular function, but I haven't been able to pass parameters to it successfully.
The XUL that calls the function currently looks like this: oncommand="madeUpWrapperName('history');"
(function(aLeftPane) { ... }) ("History")
Is not an unusually structured function, it's a common pattern to encapsulate code in JS. What it does is declare an anonymous function and then immediately call it. It is used very often by libraries to create the lib entry point and cleanly separate private from public code without polluting the global namespace.
In your case, you actually want to unwrap the function :
function unwrapped(aLeftPane)
{
/**
* Select left panel in Library.
*
* #param aBrowser Browser object in selected tab.
...
}
then, in your xul or somewhere else:
oncommand="unwrapped('History');"

getScript Local Load Instead of Global?

From what I have read JQuery's getScript function loads the script file in a global context using a function called 'global eval'. Is there a particular setting or method to change this so it will instead load within the function I am calling it from?
If I do the following code name returns undefined as its not loading the script in the local context.
function callscript(){
var name='fred';
getScript(abc.js);
}
//abc.js:
alert(name);
I believe I have found the solution using a regular JQuery ajax call. The trick is you set the datatype to 'text' as otherwise if its script or if use getScript or the alternative .get() it will auto run the script inside and place it in the global context.
function abc(){
var msg="ciao";
$.ajax({
url: 'themes/_default/system/message.js',
success: function(data){
eval(data);
},
dataType: "text"
});
}
//message.js
(function() {
alert(msg);
})();
This alerts 'ciao' as expected :)
Before anyone says anything yes I'm using eval but its perfectly fine in this situation.
As you already noticed, there's nothing in the docs regarding this. I double checked the source code and found that the underlying call has no options for you to pass to override this behavior.
// http://code.jquery.com/jquery-1.9.1.js
...
getScript: function( url, callback ) {
return jQuery.get( url, undefined, callback, "script" );
},
...
As far as I can tell, loading a script asynchronously into a local scope is not possible with jQuery. jQuery's API doesn't give you any other means to configure its usage like this.
I am still investigating how it might be possible using some other technique.
Ok i know this is 2017, 4 years later, but it seems jQuery team never bothered to address this issue, well sort of. I had the same problem and i think this is the solution, the actual intended way of using getScript in a local context. What I noticed was that there is no way that code could be easily eval'd in a local context against your code, which jQuery has no idea how it is going. I haven't gone deeper, but if you look at the jQuery source, how it is injecting the script into the document, it's genius, it avoids eval altogether. The script it therefore ran as if it's a file that was imported through script tag. Without further ado...
I have decided to do the vice-versa of the situation, it better explains what's going on. You can then reverse it to that example in question.
If you noticed getScript actually sends a unique ID to the server in the query string. I don't know why they didn't mention this in documentation. Use that to identify returned scripts. But you have to do something in the backend...
let imports;
$.getScript("scripts.php?file=abc.js", (data, textStatus, jqXHR) => {
window[jqXHR.getResponseHeader('X-scriptID')](imports);
alert (imports.name);
});
abc.js:
imports.name = 'fred';
backend wraps whatever script we are getting scripts.php:
// code that gets the file from file system into var $output
$output = file_get_contents($_REQUEST['file']);
// generate a unique script function name, sort of a namespace
$scriptID = "__script" . $_REQUEST['_'];
// wrap the script in a function a pass the imports variable
// (remember it was defined in js before this request) we will attach
// things we want to become local on to this object in script file
$output = "window.".$scriptID."=function(imports) { ".$output." };";
// set the script id so we can find this script in js
header ("X-scriptID: " . $scriptID);
// return the output
echo $output;
What going is that the js requests a script through getScript, but it doesn't request directly to the file it uses a php script to fetch the contents of the file. I am doing this so that i can modify the returned data and attach headers that are used to id the returned script (this is large app in mind here where a lot of scripts are requested this way).
When getScript runs the returned script in the browser as usual, the actual content of the script are not ran, just a declaration of the wrapper function with a unique name __script1237863498 or something like (the number was given by getScript upon requisition of that script earlier), attached to the global window object.
Then js uses that response to run the wrapper function and inject properties into the imports object... which become local to the requesting whatever's scope.
I don't know jQuery implementation, but the reason name is returning undefined is because name is a private property of the callscript object. To negate this, you could declare the variable outside of the function call:
var name = ''; //Declare name outside of the function
function callscript(){
name='fred';
getScript('abc.js'); //Shouldn't it be $.getScript? and argument should be passed as a string
}
//abc.js:
console.log(name) //Returns undefined
callscript(); //Call the script
console.log(name); //Returns "fred"
// global.js
var global1 = "I'm a global!";
// other js-file
function testGlobal () {
alert(global1);
}

send data to JS file without using global variables

I need to send data in a HTML page to a script file that is loaded in that page. The simplest way i can think of is to use a global variable which is defined in the page and accessed in the script file.
We all know global state is bad, so i started thinking about the options available for passing data from HTML page to script file without using global state. I cant find (or think of) any.
I am curious whether this is possible. Any ideas?
It really depends what you're doing. In general, I wouldn't advise this methodology, but it's something to consider depending on your circumstances. For the sake of this example, I'll assume you're using jQuery (if not, replace the document.ready with whatever you want to use for onDOMReadyStateChange monitoring).
In the HTML:
<script type='text/json-data' id='some_data_set'>
{ 'foo': 'bar', 'baz': 1 }
</script>
In the JavaScript:
$(function() {
var myData = JSON.parse($('script#some_data_set').html());
// YOUR CODE GOES HERE
});
Nope. All the javascript scope starts from a global level, therefore you must have at least one global reference to your data.
Let's say you wanted to store a list of products and events:
var myGlobalData = { "products":<products>, "events":<events> };
Where <products> and <events> are two different data blocks.
If you're paranoid on global objects, you can simply delete the reference point (thus it's contents) after you finished using it, as follows:
delete window.myGlobalData;
One option is to scope your data. For example, in JS file you can define an object like:
var processor = {
function setData(o) { // do stuff
}
};
Then in your HTML you know that the data is scoped to the processor. So you can do something like:
processor.setData({someData});

Categories