'This' in phonegap - javascript

What is 'this' in phonegap? I am working on an app where I have local javascript packed with the app and remote javascript pulled from a server. I am using coffeescript to generate all the javascript.
Both files are being included in the app's index header, generated through haml as such:
%script{:src=>"javascripts/file1.js"}
%script{:src=>"http://192.168.5.205:3000/assets/file2.js"}
file1.js.coffee:
#myObj1 = property: true
file2.js.coffee:
#myObj2 = property: true
myObj1 is available globally and can be referenced as just myObj1, but myObj2 is only available via document.myObj2 and can not be referenced as simply myObj2. What is happening?

Well, if you say this:
#myObj2 = property: true
and you have to reference myObj2 as document.myObj2 everywhere else, then this must be document when file2.js.coffee is executed. This sort of thing can happen if your code is executed through $(document).ready() or similar means (for example: http://jsfiddle.net/ambiguous/6DFK9/).
If you want something to be global, then you really should be explicit about it and use window:
# in file1.js.coffee:
window.myObj1 = property: true
# in file2.js.coffee:
window.myObj2 = property: true
That way you don't have to worry about the calling context and more importantly, your intent will be explicit and you won't have to puzzle over what this is or supposed to be in six months when you're trying to fix bugs. Say what you mean: if you want it global, put it in window.

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.

How to access c# variables from a JavaScript file?

I have a C# file that pulls various config settings from different config files. A JavaScript application I'm writing needs some of those settings to run. I'm having trouble bringing the C# variables into the js file. Not sure what is the best approach. They need to end up as a JS object on the page. Would adding them to a JSon object in the C# file & calling that from the JS file work? Not even sure how to do that to be honest. Any help appreciated.
You can just declare a global variable in one of your root pages (say, _layout.cshtml):
<script>
var settings = {
foo: #(IsFoo ? "true", "false"),
bar: #SomeNumber,
baz: "#ImportantString"
}
</script>
Or, if you're writing a Web API, you can just add a /settings endpoint you can query like so (Assuming you're using jQuery):
$.get("/settings", response => {
// Store the `response` in a global variable.
});
If it's an independent javascript project and .net is more of an API, you need to make an API call which will send you those config settings.
If your javascript is part of .net MVC application, i.e., you are adding your javascript through an tag at then end of a .cshtml/.aspx file, you can easily pass it through a global variable, but even then the C# code need to pass those values through Modal to the .cshtml/aspx file.
what you can do is:
var pageConfig = pageConfig || {};
pageconfig.settings = #Html.Raw(Model.Settings); // This model object is part of the C# code and my assumption is that Settings will have array of configurations.
This can also be done globally, depending upon how the C# code is written.
Assuming that when you say 'various config settings' you're referring to .NET's ApplicationSettings (defined in Visual Studio's Properties > Settings), we've done something similar, in a generic manner, as follows:
public void WriteSettings(TextWriter writer)
{
// Declare the nameSpace for the DLL you want to pull settings from
var nameSpace = "foo.Bar"
ApplicationSettingsBase properties = (System.Configuration.ApplicationSettingsBase)Activator.CreateInstance(nameSpace, string.Format("{0}.Properties.Settings", nameSpace)).Unwrap();
foreach (SettingsProperty property in properties.Properties)
{
writer.Write(string.Format("{0}=\"{1}\", property.Name, properties[property.Name]);
}
}
I've ignored a few issues in your case:
I've not bothered trying to deal with non-strings; consider looking at property.PropertyType and casting your values appropriately
I've wrapped this in a function that accepts a TextWriter; you can pass this method Response.Output

Unable to refer javascript array from another javascript file

I am trying to create a chart using highcharts in which i am not able to fetch data which i store in another js file.
My main.js file has all the code for creating chart. It has the section of series.
series: [{
name: 'Desktops',
data: '/data/desktop.js',
tooltip: {
valueDecimals: 2
}
}]
Here i want to refer data from another js file. The name of file is desktop.js and it has just the below array
var desktopData = [[1475272800000, 117759], [1475359200000, 106147], [1475445600000, 147747], [1475532000000, 302031], [1475618400000, 520539], [1475704800000, 245353], [1475791200000, 180376], [1475877600000, 78819], [1475964000000, 90466], [1476050400000, 257822], [1476136800000, 284465], [1476223200000, 242898], [1476309600000, 297186], [1476396000000, 268069], [1476482400000, 183149], [1476568800000, 410442], [1476655200000, 1117798], [1476741600000, 1274668], [1476828000000, 1331799], [1476914400000, 1230213], [1477000800000, 888251], [1477087200000, 572050], [1477173600000, 931144], [1477260000000, 1556641], [1477346400000, 1526736], [1477432800000, 1310133], [1477519200000, 1207422], [1477605600000, 785556], [1477692000000, 487264], [1477778400000, 787714], [1477868400000, 942663]];
How can i refer array defined in another file?
Do you use any type of the framework? To load JS file in another file, you need to require it somehow, either by using AMD, ES imports or any other way (be it synchronous or asynchronous).
If you are just adding the files to the HTML (using script tags), then the only thing you have to do is to make sure that the files are loaded (DOMContentLoaded event) and then, you have to attach the data to a global scope.
Global scope in the browsers is called a window and every time when you use variable that was not declared in your scope by var it means that the JS is searching for it in the global scope. In order to assign something to a global scope you can just omit var or explicitely assign it like this:
window.desktopData = [];
// And then in another file, assuming that the data is ready
var myData = window.desktopData
Please also remember that including files in <script> tags usually means that they will block your browser and the order of the files matters (at least when you want to rely on the fact of one file already loaded before another file). I'd suggest using some kind of import system then:
http://requirejs.org/docs/whyamd.html

How to parse and load javascript object?

I have one js files . I load it using other javascrupt file using eval() function. I have seen eval is slow and with some other limtation. Since i need to store my JS file object in cache and use it anytime i need after apllication starts. I dont want to do eval() everytime.
Is there anyway to do it in simple way.
var evalObj;
if(evalObj) {
console.log('eval object already evaluated');
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level, categoryName, message);
}
else {
evalObj = eval(fs.readFileSync('./myJSFile', 'utf8'));
console.log('re evaluating object ..' );
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level,message);
}
myJSFile
var _sigmaAlarmHandler_ =function(args)
{
var args = Array.prototype.slice.call(arguments);
args.unshift();
console.log('Alarm : ', args);
}
Either the conditional eval is not working.
In node.js you can simple require your js-file:
var obj = require('./myJSFile');
obj.foo();
./myJSFile.js:
exports.foo = function() {
console.log('foo');
}
This file becomes a module with exported functions, that you need.
It loads once, then every require reuse already loaded module.
If it is not commonjs-compliant (i.e. using module.exports will not work), then you can run it in its own vm:
var vm = require('vm');
vm.runInNewContext(jscode,{/*globalvars*/});
where the second parameter is an object with global vars made available in the context in which the jscode is run. So if the second param is, say, {a:1,b:"foo"} then your jscode will run with the global variable a set to 1 and the global variable b set to "foo".
The jscode itself is a string that you load from a file or elsewhere.
Think of vm.runInNewContext() as "practice safe eval". Well, relatively safe, you can still do some dangerous stuff if you pass in particular vars, like process or file etc.
I used this for the declarative part of cansecurity http://github.com/deitch/cansecurity for nodejs
You can view the sample in the file lib/declarative.js
Here is the API for vm http://nodejs.org/api/vm.html
There are options to run in the same context, etc. But that is very risky.
When you actually run the code, using your example above:
_myfunctionInJSFile_(layouts.FormatDate(startTime), threadName, level,message);
you are looking to pass in 4 params: startTime, threadName, level, message and execute the function. The issue is that you cannot run the function on the current context. You need the function to be defined and run in the file. So you should have something like:
vm.runInNewContext(jscode,{startTime:layouts.FormatDate(startTime),threadName:threadName,level:level,message:message});
And then the jscode should look like
function _myfunctionInJSFile(startTime,threadName,level,message) {
// do whatever you need to do
}
// EXECUTE IT - the above vars are set by the global context provide in vm.runInNewContext
_myfunctionInJSFile(startTime,threadName,level,message);
If you prefer to define the function and have it loaded and run in this context, then just use the commonjs format.
I think i have found the answer for this.
Since my application is running in node js which uses v8 engine platform. When the application starts v8 engine caches all the code/configuration and can be used anytime.
Similarly in my code i will pre-load the JS code using eval and i will do it only once. So on next call i will return only the loaded JS code. Here i need to modify the code to load once.
But main point we have look is that in future if any body has similar requirement they can cache their JS codes using eval (thanks to v8 engine) and use it till your application is running.

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