Can you execute contained JavaScript in browsers? - javascript

I want to be able to run JavaScript on my webpage and guarantee that it can be stopped cleanly without causing problems. You could think of it as running JavaScript as if it was contained in an iFrame but allow it to modify and interact with the root DOM. That way if I remove the iFrame, the JS dies.
Use Case/Justification
I want to turn any webpage into a weird mutant SPA. That means taking the traditional HTML, CSS, and JavaScript and then handling page switching myself. To propperly switch pages avoiding artifacts from previously executing JS I'd need to make sure one page's JS doesn't interact with the next page's JS. Ideally, to switch a page it would follow this general formula:
Load HTML and CSS with a framework like Ember.js
Load all linked JavaScript in a contained environment but with the ability to modify the root DOM
When the user clicks a link, stop all running JavaScript and return to step 1.
My Thoughts
I've run tests actually loading a webpage in a full-screen iframe (like this) which achieves the level of containment that I want when executing the JavaScript, but it has serious performance penalties. I want the contained JavaScript, with a minimal performance penalty.
One thought I had was after downloading JavaScript, replacing the actual code dynamically. I would change the code to instead of referencing the Window, referencing the Window.parent.
I'm not attached to the idea of using iFrames, but it just seems like it is the closest thing to a "container" that you can get in JavaScript/the browser. I'd love alternatives.
Related?
github.com/codeschool/javascript-sandbox
instantclick.io/
shadow DOM?
Mini-Followup:
Would it be feasible to build an app like this which would allow for proper handling of both JS life cycles and page switches?

You can't unload a script once it has been loaded. But you can encapsulate some script in an object, and create or destroy this object.
For instance:
var Robot = function(){
return{
sayHello : function(){
alert("Hello!");
},
doSomethingElse : function(){
alert("I'm doing something else");
}
}
}
robot = new Robot();
robot.sayHello(); // Actually alerts "Hello!"
robot = null; // the robot is destroyed.
In your case, if you load a script via ajax, say this piece of script in an object :
{
sayHello : function(){
alert("Hello!");
},
doSomethingElse : function(){
alert("I'm doing something else");
}
}
you can then encapsulate this script in a function :
var Robot = null,
robot = null;
$.get('scriptURL', function(ajaxedScriptObject){
Robot = function(){ return ajaxedScriptObject; };
createRobot();
})
function createRobot(){
robot = new Robot();
sayHello();
destroyRobot();
}
function sayHello(){
robot.sayHello(); // Should alert "Hello!" :)
}
function destroyRobot(){
robot = null;
}

Related

Rewrite browser JS code to transform global definitions into window properties

I support a very old PHP web framework that uses server-side rendering. I decided to implement Vue for the rendering of some modules, so I compiled a hello world app and realized deployment wouldn't be so simple.
The framework works as a giant SPA, with each module being rendered using the html output of a body() function. The output is replaced in the client's DOM without reloading the page itself.
<script> tags are banned for security reasons and will be sanitized from the resulting html. The only way to deliver JS to the client is by using an eval_js() function.
The problem is rather simple. I need to safely load JS code several times in the same DOM. I cannot load it as-is after app compilation, because from the second time onwards the code is executed (every time a user visits a module, or performs an action) the code will attempt to re-define global variables and kill the whole client.
The solution is also rather simple, just rewrite the JS code such that every global definition is transformed into a window property. This way, even if the same piece of code gets executed several times in the same DOM, it will simply replace window properties rather than attempting to re-define variables.
In example, the following input:
function Yr(t){
const b = t.prototype.hasOwnProperty;
this._init(b);
}
var hOe = sg(uOe, fOe, dOe, !1, null, "e687eb20", null, null);
const vOe = {
name: "AmmFilters",
components: {
AmmOptionSelect: pOe
}
};
new Yr({...}).$mount("#app");
Would be rewritten into:
window.Yr = function(t){
const b = t.prototype.hasOwnProperty;
this._init(b);
}
window.hOe = sg(window.uOe, window.fOe, window.dOe, !1, null, "e687eb20", null, null);
window.vOe = {
name: "AmmFilters",
components: {
AmmOptionSelect: window.pOe
}
}
new window.Yr({...}).$mount("#app");
I initially considered to write my own parser, but then realized that ES6+ syntax is no child's play. The code I will attempt to rewrite is optimized & obfuscated which means it will have all sort of complex syntax and I must be careful not to turn scoped definitions into window properties.
Any ideas on a tool that already performs this task? The resulting JS code should have no difference from the original, as global scoped variables end up in the window object anyway.
I believe it would be a fairly useful tool for various use cases, so thought about asking before attempting to reinvent the wheel.

Chrome extensions - modify script before execution

I'm kinda new to this chrome-extensions stuff, and i'm trying to modify a script before it is executed.
Example:
<script type="text/javascript">
function() {
var count = 10;
countDown = setInterval(function() {
if(count == 0) {
// do Stuff
}
count--;
}, 1000);
}
</script>
My goal is to either remove this script from the site (before it is executed) and inject my own (i already did the injection-part) or modify it (for example set count to 20 so it takes 20 seconds).
I've already tried a lot of things but i just can't find a good way.
Hope you can help me :)
It's going to be pretty difficult to hijack that part on the fly, but at least you can stop the timer.
All you need to do is to call
clearInterval(countDown);
..in the right context.
At this point the extension architecture and the concept of isolated worlds come into play.
The only part of the extension that can interact with the webpage is a content script. But then, the content script lives in a separate context:
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. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.
But you need to access the page's JavaScript. There's a way, by injecting your code into the page as a <script> tag:
var script = document.createElement('script');
script.textContent = "clearInterval(countDown);";
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

Run greasemonkey script after javascript

I'm trying to modify a variable - which is created in javascript - and run a function to change some visual stuff on a page. But my greasemonkey script is - i guess - running before the javascript, i'm getting an error says function is not defined.
How can I force to run my script after the javascript runs?
Actually what I'm trying to do is very simple. There is a variable called cursort, what I want to do is change that to "data-price" and sort the list again using updateSort(). Here is the code:
var cursort = "data-price";
updateSort();
I had to do something similar, there was a object defined at the end of the page that I wanted to just cancel out, so it's functions wouldn't run (it captured link clicks and ran some stuff).
In the page it was defined like this:
var someObj = { ... }
I made a greasemonkey script (after much trial/error) that looked like this.
window.addEventListener ("load", runAfter, false);
function runAfter() {
unsafeWindow.someObj = null;
}
Now clicking on the links does not trigger all the other actions that were in someObj.
Maybe you can do something like that?

Manage javascript include files

Currently we have an extensive web-based office application written in PHP, javascript to manage various processes (billing, ordering, user management, reporting, subscription management, article managementm, warehousing etc.)
The application uses iframes to load pages that perform various functions within the main application interface. From the main page tabs are created so you can access all open pages if needed. Each page has their own javascript include-files, css etc to perform complex tasks. All iframed-pages (around 600) are on the same domain/host.
Since many people describe using iframes as 'evil', I was examining on how I could convert the application into using divs only.
The quesions I have are:
1) in a situation where there are no iframes anymore, do I need to include every used javascript files on the main start page? Or is it possible to dynamically load javascript files into the memory depending on which page you access? (inluding new function declarations etc.)
2) Can these include-files be removed completely out of the memory when someone closes a page? (in this case a div). This to avoid possible conflicts between function names & variables of different files and also not to burden the browser's memory usage.
3) Or perhaps iframes are not that 'evil' afterall, and this is a correct way for using iframes?
thanks for the advise
chees
Patrick
have you tried any code or just asking?
you can use jquery (see here)
$.getScript("ajax/test.js", function(data, textStatus, jqxhr) {
console.log(data); //data returned
console.log(textStatus); //success
console.log(jqxhr.status); //200
console.log('Load was performed.');
});
As long as your javascript is modular, you can unload it whenever you want.
In case you don't know, in Javascript functions are objects. And with objects you can do this:
var a = {b:10, c:20, d:30}; //Some memory is allocated for object a
a = null; //Object a will be deleted, and no longer need any memory
How can you use that to handle functions? Here's easiest explanation:
var myFunction = function(a,b,c) {
alert(a+b+c);
}; //Here we have a function stored in memory
myFunction = null; //And now we don't
You can make whole libraries of functions this way and then remove them with one operation. Example:
var MyMath = {};
MyMath.abs = function(a) {
return (a<0)?-a:a;
};
MyMath.min = function(a,b) {
return a>b?b:a;
}; //MyMath uses some memory.
alert(MyMath.min(5,10));
MyMath = null; //Now it does not
So, wrap all of your libraries into objects, and unload those objects whenever you need.
Added:
When your browser sees some new Javascript code - it executes it all at once. It also does save it in memory, but never uses it again (basically it is stored the same way hello is stored in <div>hello</div>). Therefore the best solution would be:
1) Add <script> tags dynamically to load desired Javascript files on demand. It will look something like:
if (MyMathLibrary == null || MyMathLibrary == undefined) {
createScriptElementForMathLibrary();
}
alert(MyMathLibrary.calculateEnthropyOfTheUniverse());
2) Whenever you no longer need the library, you just do MyMathLibrary = null. You can also delete it from DOM at this point, it won't do any harm, as I said, it is no more than invisible div at this point.
But honestly, are you sure this is worth the bother? People nowadays write 3D shooters purely in Javascript and computers come with 4-16 GB of memory. Also, it's common practice to first make a working program and bother with optimizations only if it lags. Otherwise it is likely that you will spend a month of work for something no user will ever notice.

Create Multiple Instances Of Same Script

I am currently building a website that uses windows to load in new content via ajax. These windows are allowed to contain the same page as in another window using the same javascript. Currently I assign a unique id to the new window which it then stores for later use.
Once the code is loaded in, all the ids in that window are converted by adding on to them a unique_id. ie "box" becomes "box_win1". I then send this id to the javascript by assigning it to a variable so it can be used in document.ready function.
The pseudo code for the window is like the following:
document.ready{
var temp_id=id+1;
$("#mybox" + temp_id).val("abc")
//run some startup stuff
}
I am just wondering is there a better way to do this. As I find if I open to many new windows all at once the temp_id conflicts and goes to the wrong window.
I would like to some how create an instance of the code but I am not sure how. I cannot use global functions however as that may cause naming conflicts.
put this into a function
function callMe (){
var temp_id=id+1;
$("#mybox" + temp_id).val("abc")
//run some startup stuff
}
you can use callMe() anywhere then

Categories