How can I make internationalization changes js file for alert, without passing value through template.
I have 'messages' & messages.es-ES file in conf folder.
Years ago I have similar problem in an older version of play framework (2.2.x), that I had solved by writing a twirl template like this:
#()
#import play.api.Play.current
var myI18n = (function() {
var messages = #Html("{" + Messages.messages.flatMap(_._2).map(mess => s""""${mess._1}":"${mess._2}"""").mkString(", ") + "}")
return {
getMessage: function (key) {
if(messages.hasOwnProperty(key)) {
return messages[key];
}
else return key;
}
};
});
In this way, i build at runtime a js file with my messages library and with a basic function for retrieving.
Then I expose an action who returns this (obiviusly need cache by locale):
public static Result javascriptRoutes() {
response().setContentType("text/javascript");
return ok(views.html.i18n.render());
}
and include in pages:
<script type="text/javascript" src="#controllers.routes.I18nJs.javascriptRoutes()"></script>
Finally, I can retrieve the value of messages key with a sample myI18n().getMessage("my.message.key")
var val = 3;
var code = "var a = 5; if (a >= val) { console.log(a + ' >= ' + val); a; } else { console.log(a + ' < 3 ' + val); val; }";
console.log(eval(code));
This is the scenario where an alternative to eval() is required.
The Server can send any kind of JS code which could be run on a particular block.
Do not use eval(code) or new Function(code) as both are basically the same thing and should be blocked by CSP.
Just return your content from the server as content-type: text/javascript then get it into your page with a <script> block or import.
On the server you would have something like (pseudo code, as I don't know what tech stack you're on):
[Route("serverActionReturningCode")]
public string ActionReturningCode()
{
// return the content as JS
Response.Headers.Add("content-type", "text/javascript");
// build the response object as JS
return "window.latestResult = {" +
"a: '" + a + "', " +
"b: '" + b + "', " +
"generatedCode: function() { ... }" +
"};";
}
Then in your page:
<script src="serverActionReturningCode"></script>
<script>
// Now the script above has run and set window.latestResult
console.log('a', window.latestResult.a);
console.log('b', window.latestResult.b);
console.log('function output', window.latestResult.generatedCode());
</script>
This will let you dynamically generate JS functions on the server.
However, if you can avoid the functions and just need to pass values it is a lot simpler to use JSON instead.
It seems to be like there is no way other than to live with eval or change the entire design of the application. Even if we look for any other alternatives, it's going to be the change in the name and syntax. But the security issues are going to be the same. Its the design of the application that JS CodeGen tool in the server will generate JS code snippets and send it via JSON in certain fields which has to be picked and executed in the front-end. But in this design, we can assure one thing that the JS code is generated only at the design time of the user and not at the runtime.
Thanks for your help.
You can do it like this. Using Eval() is not recommended.
function looseJsonParse(obj){
return Function('"use strict";return (' + obj + ')')();
}
console.log(looseJsonParse(
"{a:(4-1), b:function(){}, c:new Date()}"
))
Refer this MDN article https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
to dig more into it.
Trying to create a firefox addon that accesses the browser cookies. Following googled tutorials I've written the following function but looks like the Services.jsm is not accessible?
Components.utils.import("resource://gre/modules/Services.jsm");
var myExtension = {
myListener: function(evt) {
//I get here
alert("Received from web page: " +
evt.target.getAttribute("attribute1") + "/" +
evt.target.getAttribute("attribute2"));
//I dont see anything dumped
let enum = Services.cookies.getCookiesFromHost("example.com");
while (enum.hasMoreElements()) {
var cookie = e.getNext().QueryInterface(Ci.nsICookie2);
dump(cookie.host + ";" + cookie.name + "=" + cookie.value + "\n");
}
}
}
document.addEventListener("MyExtensionEvent", function(e) { myExtension.myListener(e); }, false, true);
Thanks #Shakur I didn't catch that e and yep you're right it needs to be fixed to enum.
I'm not familiar with cookie service, I would have to read up on it but you're on right track.
This is because you have not defined Ci you use Ci in the while loop. You can replace Ci with Components.interfaces and it should fix it up. :) If you want to use the C* short forms it is typically done by adding to the top: const {Cc:classes, Cu:utils, Ci:interfaces, Cr:results, CC: Constructor} = Components as seen in this example here: https://codereview.stackexchange.com/questions/56821/improvements-to-nsizipreader-and-nsiscriptableinputstream/56824#56824
I consider myself a very experienced node.js developer.
Yet I still wonder if there is a better way to write the following code so I don't get the pyramid of doom... Now I went easy on you, I have some code that my pyramid gets as high as 20 floors, no kidding; and that's WITH using async.js !!!
The problem is really that I have many dependencies on previews variables so everything must be nested.
The guy that wrote the book "Async Javascript, build more responsive Apps with less code" explains that he would put the functions at the root scope, which sure, would get rid of the pyramid, but now you would have a whole bunch of high scope variables (possibly even global, depending at the scope you declare them at) and this pollution can result in some pretty nasty bugs (this could cause var conflicts with other scripts if set at global space (sure you could use self invoking functions, more yachhh... or even worse, since we are dealing with async, variable overrides...). In fact, the beauty of closure is pretty mush out the door.
What he recommend is doing something like:
function checkPassword(username, passwordGuess, callback) {
var passwordHash;
var queryStr = 'SELECT * FROM user WHERE username = ?';
db.query(selectUser, username, queryCallback);
function queryCallback(err, result) {
if (err) throw err;
passwordHash = result['password_hash'];
hash(passwordGuess, hashCallback);
}
function hashCallback(passwordGuessHash) {
callback(passwordHash === passwordGuessHash);
}
}
again, not a clean approach IMHO.
So, if you look at my code (again, this is just a snippet, I get much bigger nests in other places) you will often see my code getting further and further apart from the left; and that's with using things like waterfall and async forEach...
here is a small example:
ms.async.eachSeries(arrWords, function (key, asyncCallback) {
pg.connect(pgconn.dbserver('galaxy'), function (err, pgClient, pgCB) {
statement = "SELECT * FROM localization_strings WHERE local_id = 10 AND string_key = '" + key[0] + "'";
pgClient.query(statement, function (err, result) {
if (pgconn.handleError(err, pgCB, pgClient)) return;
// if key doesn't exist go ahead and insert it
if (result.rows.length == 0) {
statement = "SELECT nextval('last_resource_bundle_string_id')";
pgClient.query(statement, function (err, result) {
if (pgconn.handleError(err, pgCB, pgClient)) return;
var insertIdOffset = parseInt(result.rows[0].nextval);
statement = "INSERT INTO localization_strings (resource_bundle_string_id, string_key, string_revision, string_text,modified_date,local_id, bundle_id) VALUES ";
statement += " (" + insertIdOffset + ",'" + key[0] + "'," + 0 + ",'" + englishDictionary[key[0]] + "'," + 0 + ",10,20)";
ms.log(statement);
pgClient.query(statement, function (err, result) {
if (pgconn.handleError(err, pgCB, pgClient)) return;
pgCB();
asyncCallback();
});
});
}
pgCB();
asyncCallback();
});
});
});
On my deep scripts I counted over 25 closing parenthesis, CRAZY, and all while remembering where to call my last callBack so async continues to next iteration...
Is there a solution to this problem? Or it is just the natrure of the beast?
As Mithon said in his answer, promises can make this code much clearer and help to reduce duplication. Let's say that you create two wrapper functions that return promises, corresponding to the two database operations you're performing, connectToDb and queryDb. Then your code can be written as something like:
ms.async.eachSeries(arrWords, function (key, asyncCallback) {
var stepState = {};
connectToDb('galaxy').then(function(connection) {
// Store the connection objects in stepState
stepState.pgClient = connection.pgClient;
stepState.pgCB = connection.pgCB;
// Send our first query across the connection
var statement = "SELECT * FROM localization_strings WHERE local_id = 10 AND string_key = '" + key[0] + "'";
return queryDb(stepState.pgClient, statement);
}).then(function (result) {
// If the result is empty, we need to send another 2-query sequence
if (result.rows.length == 0) {
var statement = "SELECT nextval('last_resource_bundle_string_id')";
return queryDb(stepState.pgClient, statement).then(function(result) {
var insertIdOffset = parseInt(result.rows[0].nextval);
var statement = "INSERT INTO localization_strings (resource_bundle_string_id, string_key, string_revision, string_text,modified_date,local_id, bundle_id) VALUES ";
statement += " (" + insertIdOffset + ",'" + key[0] + "'," + 0 + ",'" + englishDictionary[key[0]] + "'," + 0 + ",10,20)";
ms.log(statement);
return queryDb(stepState.pgClient, statement);
});
}
}).then(function (result) {
// Continue to the next step
stepState.pgCB();
asyncCallback();
}).fail(function (error) {
// Handle a database error from any operation in this step...
});
});
It's still complex, but the complexity is more manageable. Adding a new database operation to every "step" no longer requires a new level of indentation. Also notice that all error handling is done in one place, rather than having to add an if (pgconn.handleError(...)) line every time you perform a database operation.
Update: As requested, here's how you might go about defining the two wrapper functions. I'll assume that you're using kriskowal/q as your promise library:
function connectToDb(dbName) {
var deferred = Q.defer();
pg.connect(pgconn.dbserver(dbName), function (err, pgClient, pgCB) {
if (err) {
deferred.reject(err)
} else {
deferred.resolve({pgClient: pgClient, pgCB: pgCB})
}
});
return deferred.promise;
}
You can use this pattern to create a wrapper around any function that takes a single-use callback.
The queryDb is even more straightforward because its callback gives you either a single error value or a single result value, which means that you can use q's built-in makeNodeResolver utility method to resolve or reject the deferred:
function queryDb(pgClient, statement) {
var deferred = Q.defer();
pgClient.query(statement, deferred.makeNodeResolver());
return deferred.promise;
}
For more information on promises, check out my book: Async JavaScript, published by PragProg.
The problem to this sort of thing is promises. If you haven't heard of them, I suggest reading up on kriskowal's q.
Now, I don't know if the db.query returns a promise or not. If it doesn't you might be able to find a db-wrapper that does or a different db library. If that is not an option, you may "promisify" the db-library you're using. See Howto use promises with Node, and especially the section "Wrapping a function that takes a Node-style callback".
Best of luck! :)
The simplest way to combat the async pyramid of hell is to segregate your async callbacks into smaller functions that you can place outside your main loop. Chances are you can at least break some of your callbacks into more maintainable functions that can be used elsewhere in your code base, but the question you're asking is a bit vague and can be solved in a large number of ways.
Also, you should consider what Stuart mentioned in his answer and try to combine some of your queries together. I'm more concerned that you have 20+ nested calls which would indicate something seriously erroneous in your callback structure so I'd look at your code first before anything else.
Consider rewriting your code to have less back-and-forth with the database. The rule of thumb I use to estimate an app's performance under heavy load is that every async call will add two seconds to the response (one for the request, and one for the reply).
For example, is there maybe a way you could offload this logic to the database? Or a way to "SELECT nextval('last_resource_bundle_string_id')" at the same time as you "SELECT * FROM localization_strings WHERE local_id = 10 AND string_key = '" + key[0] + "'" (perhaps a stored procedure)?
I break each level of the pyramid of doom into a function and chain them one to the other. I think it is a lot easier to follow. In the example above i'd do it as follows.
ms.async.eachSeries(arrWords, function (key, asyncCallback) {
var pgCB;
var pgClient;
var connect = function () {
pg.connect(pgconn.dbserver('galaxy'), function (err, _pgClient, _pgCB) {
pgClient = _pgClient;
pgCB = _pgCB;
findKey();
});
};
var findKey = function () {
statement = "SELECT * FROM localization_strings WHERE local_id = 10 AND string_key = '" + key[0] + "'";
pgClient.query(statement, function (err, result) {
if (pgconn.handleError(err, pgCB, pgClient))
return;
// if key doesn't exist go ahead and insert it
if (result.rows.length == 0) {
getId();
return;
}
pgCB();
asyncCallback();
});
};
var getId = function () {
statement = "SELECT nextval('last_resource_bundle_string_id')";
pgClient.query(statement, function (err, result) {
if (pgconn.handleError(err, pgCB, pgClient))
return;
insertKey();
});
};
var insertKey = function () {
var insertIdOffset = parseInt(result.rows[0].nextval);
statement = "INSERT INTO localization_strings (resource_bundle_string_id, string_key, string_revision, string_text,modified_date,local_id, bundle_id) VALUES ";
statement += " (" + insertIdOffset + ",'" + key[0] + "'," + 0 + ",'" + englishDictionary[key[0]] + "'," + 0 + ",10,20)";
ms.log(statement);
pgClient.query(statement, function (err, result) {
if (pgconn.handleError(err, pgCB, pgClient))
return;
pgCB();
asyncCallback();
});
};
connect();
});
I have been searching for many hours over several days for this answer and though there are many topics on how to include files in a project (also here at Stack Overflow), I have not yet found THE solution to my problem.
I'm working on a project where I want to include one single object at a time, from many different files (I do not want to include the files themselves, only their content). All the object in all the files have the same name, only the content is different.
It is important that I do not get a SCRIPT tag in the head section of the page as all the content from the files will have the same names. None of the files will have functions anyways, only one single object, that will need to be loaded one at the time and then discarded when the next element is loaded.
The objects will hold the data that will be shown on the page and they will be called from the menu by an 'onclick' event.
function setMenu() // The menu is being build.
{
var html = '';
html += '<table border="0">';
for (var i = 0; i<menu.pages.length; i++)
{
html += '<tr class="menuPunkt"><td width="5"></td><td onclick="pageName(this)">'+ menu.pages[i] +'</td><td width="5"></td></tr>';
}
// menu is a global object containing elements such as an array with
// all the pages that needs to be shown and styling for the menu.
html += '</table>';
document.getElementById("menu").innerHTML = html;
style.setMenu(); // The menu is being positioned and styled.
}
Now, when I click on a menu item the pageName function is triggered and I'm sending the HTML element to the function as well, it is here that I want the content from my external file to be loaded into a local variable and used to display content on the page.
The answer I want is "How to load the external obj into the function where I need it?" (It may be an external file, but only in the term of not being included in the head section of the project). I'm still loading the the file from my own local library.
function pageName(elm) // The element that I clicked is elm.
{
var page = info.innerHTML; // I need only the innerHTML from the element.
var file = 'sites/' + page + '.js'; // The file to be loaded is created.
var obj = ?? // Here I somehow want the object from the external file to be loaded.
// Before doing stuff the the obj.
style.content();
}
The content from the external file could look like this:
// The src for the external page: 'sites/page.js'
var obj = new Object()
{
obj.innerHTML = 'Text to be shown';
obj.style = 'Not important for problem at hand';
obj.otherStuff = ' --||-- ';
}
Any help will be appreciated,
Molle
Using the following function, you can download the external js file in an ajax way and execute the contents of the file. Please note, however, that the external file will be evaluated in the global scope, and the use of the eval is NOT recommended. The function was adopted from this question.
function strapJS(jsUrl) {
var jsReq = (window.XMLHttpRequest) ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
if (jsReq === null) {
console.log("Error: XMLHttpRequest could not be initiated.");
}
jsReq.onload = function () {
try {
eval(jsReq.responseText);
} catch (e) {
console.log("Error: The script file contains errors." + e);
}
};
try {
jsReq.open("GET", jsUrl, true);
jsReq.send(null);
} catch (e) {
console.log("Error: Cannot retrieving data." + e);
}
}
JSFiddle here
Edit: 1
After some refactoring, I came up with this:
function StrapJs(scriptStr, jsObjName) {
var self = this;
self.ScriptStr = scriptStr;
self.ReturnedVal = null;
function _init() {
eval(self.ScriptStr);
self.ReturnedVal = eval(jsObjName);
}
_init();
}
You can then get the script string any way you want and just instantiate a new StrapJs object with the script string and name of the object to return inside the script string. The ReturnedVal property of the StrapJs object will then contain the object you are after.
Example usage:
var extJS = "var obj = " +
"{ " +
" innerHTML : 'Text to be shown', " +
" style : 'Not important for problem at hand', " +
" otherStuff : ' --||-- ' " +
"}; ";
var extJS2 = "var obj = " +
"{ " +
" innerHTML : 'Text to be shown 2', " +
" style : 'Not important for problem at hand 2', " +
" otherStuff : ' --||-- 2' " +
"}; ";
var strapJS = new StrapJs(extJS, 'obj');
var strapJS2 = new StrapJs(extJS2, 'obj');
console.log(strapJS.ReturnedVal.innerHTML);
console.log(strapJS2.ReturnedVal.innerHTML);
See it in action on this fiddle