Pass a value and print it in javascript - javascript

I'm trying to pass a lang variable in my js files.
Actually I have this:
<script src="assets/js/plugins.js?lang=en"></script>
In plugins.js, I have this:
var LIBS = {
// Chart libraries
validation: [
"assets/libs/validation/jquery.validation.min.js",
"assets/libs/validation/lang/xxxxxx.min.js"
],
...
};
How can I get the lang value passed to replace my xxxxxx by the lang en ?
Thanks.

try this in your plugin.js
var LIBS = {
// Chart libraries
validation: [
"assets/libs/validation/jquery.validation.min.js",
"assets/libs/validation/lang/xxxxxx.min.js"
]
};
LIBS.tmpValidation = LIBS.validation;
LIBS.validation = [];
LIBS.lang = "en";
Object.defineProperty(LIBS, "validation", {
get : function(){
var self = this;
return this.tmpValidation.map(function(item){
return item.replace(/xxxxxx/g, self.lang)
})
}
});
console.log(LIBS.validation);
You can now define your plugin in such a way that lang property is set to LIBS before invoking LIBS.validation

You can use a global variable.
Global variable:
I've used an object here to store settings, you could add more settings, if you wish
var settings = { lang:'en' };
Your other script (plugins.js):
var LIBS = {
// Chart libraries
validation: [
'assets/libs/validation/jquery.validation.min.js',
'assets/libs/validation/lang/' + settings.lang + '.min.js'
],
...
};
Here's a full example script that does precisely what I'm talking about above. I've got LIBS declared in the same script, but it could just as easily be included in plugins.js and declared below the setting of the global settings variable in this script instead...
Example Script:
<script>
var settings = { lang:'en' };
console.log(settings); // Show that the value has been set.
var LIBS = {
// Chart libraries
validation: [
'assets/libs/validation/jquery.validation.min.js',
'assets/libs/validation/lang/' + settings.lang + '.min.js'
]
};
// Show that LIBS has been set with the language setting from the global variable.
console.log(LIBS);
</script>
After you've run this, then you will see that the variable has been picked up and the second entry in the array is assets/libs/validation/lang/en.min.js
Or to be closer to your own example...
<script>
var settings = { lang:'en' };
console.log(settings); // Show that the value has been set.
</script>
<!-- Following line must come after the script above
this JS file can now access that global settings variable -->
<script src="plugins.js"></script>

try
var s = document.getElementsByTagName('script'),
ss = s[s.length-1];
lang = ss.src.match(/\?lang=(\w\w)/);
// sure... check it exists!
console.debug(lang[1]);
inside plugins.js

Related

Pass functions in a vm script context

Let's say I have a library module that looks like this:
module.exports = {
increment: function() {
count++;
}
}
And I'd like to use it in a dynamically generated script that looks like this:
(function() { lib.increment(); })();
by passing it in a sandbox:
var sandbox = {
count: 1
lib: require('./lib')
}
var script = new vm.Script('(function() { lib.increment() })();');
script.runInNewContext(sandbox);
The obvious problem I run into is that I on the one hand can't require "lib" because "count" is not defined in lib.js ; on the other hand if I define var count above the exports of the "lib.js" file, this new count variable will be affected instead of the one in the sandbox.
Here are the constraints that I would like to respect:
Use vm and not a eval() nor a require() on a generated file
Have "lib" defined in a external file
No modification of the automatically generated script, so no use of lib.increment.apply(context) or similar
The only solutions I've found so far is to prepend the lib functions in the generated script as a string, or to define them directly on the sandbox object, which I find to be a less desirable option.
There doesn't seem to be any way of passing a context of variables on the require call.
One way of accomplishing this is have your lib module be a function that takes in a context then returns the correct interface.
lib.js
module.exports = function(context) {
var count = context.count;
return {
increment: function() {
count++;
}
};
};
main.js
var sandbox = {
count: 1
};
sandbox.lib = require('./lib')(sandbox);
var script = new vm.Script('(function() { lib.increment() })();');
script.runInNewContext(sandbox);

gulp + nunjucks couldn't render templates

I'm trying to use nunjucks in my JS stack.
I have pre-compiled my templates with gulp-nunjucks:
gulp.task("build:tpl", function() {
var options = {
// ... empty for the moment
};
return gulp.src("src/text/*.txt", { base : path.join(__dirname, "src/text") } )
.pipe(nunjucks())
.pipe(concat("ui-template.js"))
.pipe(gulp.dest("js/tpl"));
});
Then I include ui-template with require JS for use:
/**
* setup UI
*
* "ui-colorchess.txt" is the main template
* it contains (nested) subtemplates (include "ui-history.txt" and so forth)
*/
UI.prototype.setup = function() {
var that = this;
// first we grab precompiled templates
require(["js/tpl/ui-template.js"], function() {
// ... into requirejs variables (or not)
// some context vars, just to provide an ID in HTML
var ctx = {
id : "colorchess-1",
otherStuff : 2
};
var env = new nunjucks.Environment(
new nunjucks.WebLoader("/js/tpl")
);
// it sucks here !
var c = env.render("ui-colorchess.txt", ctx);
console.log(c);
// try to assign result to a container
that.bounds.innerHTML = c;
// one more time... when it will work !
// var board = new Board("colorchess-board-" + that.key);
// board.firstDraw();
});
And I get an error in my console:
Uncaught Template render error: (ui-colorchess.txt)
TypeError: Cannot read property 'resolve' of undefined
Can anyone identify what's wrong?
Same issue described in sindresorhus/gulp-nunjucks#1.
If you want to concatenate the files, you have to set the name option:
var options = {
name: function (file) {
return file.relative;
}
};
I have solved the problem by doing the following:
renaming my templates in *.html
removing paths like "./subtemplate.txt" in my includes
setting configure("../html")
requiring correctily with requireJS

change language value in CKEditor

I'm trying to change a value of my language definition. I need to do this where the editor instances are created and under certain conditions.
I don't want to change the language file because that file is fine the way it is and also because other editors on the same website doesn't need that particular modification.
Can some one help me? I'm using CKEDITOR 3.6.1
$("form textarea").each(function()
{
var name = $(this).attr("name");
var instance = CKEDITOR.instances[name];
if(instance)
{
CKEDITOR.instances[name].destroy(true)
}
CKEDITOR.config.format_tags = 'h1;p';
CKEDITOR.config.format_p = { element : 'p', attributes : { 'class' : 'my_class' } };
//if(condition) CKEDITOR.config.lang.es.tag_h1 = "My special header";
//if(condition) CKEDITOR.lang.es.tag_h1 = "My special header";
CKEDITOR.replace(name);
});
Modify the code of the format plugin, by adding beforeInit function:
CKEDITOR.plugins.add( 'format', {
requires: 'richcombo',
beforeInit: function( editor ) {
editor.lang.format.tag_h1 = 'Moooooooo!';
},
init: function( editor ) {
...
In this function you can modify all the language entries as labels and stuff are generated, inserted and displayed in the init() below. You can use any kind of condition to change the lang entry here.
Another solution: harder but global. With this you can overwrite all plugins from one place, without touching source codes:
// Save the old CKEDITOR.plugins.load
var orgLoad = CKEDITOR.plugins.load;
// Overwrite CKEDITOR.plugins.load
CKEDITOR.plugins.load = function() {
// Save the old callback argument.
var oldCallback = arguments[ 1 ];
// Overwrite the old callback argument.
arguments[ 1 ] = function( plugins ) {
// Modify the plugin by adding beforeInit to the definition.
plugins.format.beforeInit = function( editor ) {
editor.lang.format.tag_h1 = 'Moooooooo!';
};
// Call the old callback.
oldCallback.call( this, plugins );
};
// Call old CKEDITOR.plugins.load
orgLoad.apply( this, arguments );
};

return value from js file

I have two js file in my html page . If the first one begins with :
(function($){
..
..
}(jQuery));
can I insert a var into function($,varname) , return it's value and use it in the other file?
You need a global variable for this. You can do this in one of a few ways. Let's assume we need to send the value "Bacon" to the other script.
(function($){
window.myScriptsExports = "Bacon";
}(jQuery));
// OR
var myScriptsExports = (function($){
// other code
return "Bacon";
// NO other code
}(jQuery));
// OR (not really recommended)
(function($){
// other code
$.myScriptsExports = "Bacon";
// other code
}(jQuery));
You can improve the code by using global namespace which goes like:
(function($,global){
var _obj = {};
_obj.property1 = 'Property1';
_obj.function1 = function() { console.log('Function 1');};
global.myObject = _obj;
}(jQuery,window));
//accessing
window.myObject.property1
//or
window.myObject.function1()
Supposing your function is synchrone, you may set a global function :
(function($){
..
var myvar = 666;
window.getMyVar = function() {
return myvar;
};
..
}(jQuery));
and you can use it from the other function if the second file is imported after this one :
(function($){
..
var myprevisouslysetvar = window.getMyVar();
..
}(jQuery));
Note that the files doesn't matter in javascript : your page would work the same (apart details if you have "use strict") with both files concatenated.

Trying to concatenate all my JS into one file and needing some JS framework/pattern type advice

Just in case it matters, I use ASP.NET 3.5 with VB.NET. I have nested MasterPages and UpdatePanels with Partial PostBacks. I include Modernizr 1.7 with YepNopeJs/IE Shim in my head section. Right before the closing body tag, I include my jQuery 1.6, jQuery UI 1.8.12, and this script.js I'm trying to build.
I'm thinking of using something like:
SITE = {
PAGES : { ... },
VARS : { ... },
HELPERS : { ... },
PLUGINS : { ... },
init : function() { ... }
};
SITE.init();
UPDATE
Ok with Levi's advice, I came up with this solution:
var SFAIC = {}; // Global namespace
SFAIC.common = { ... }; // Shared properties
SFAIC.common.fn = { ... }; // Shared functions
SFAIC.plugin = {
qtip: $.fn.qtip,
validate: $.fn.validate,
validator: $.fn.validator
};
SFAIC.init = function() { ... }; // Global initializer
$(document).ready(function() { SFAIC.init(); });
Then each page would have its own object literal like:
SFAIC.Main = {}; // Main.aspx
SFAIC.Main.someSection = { ... }; // Some Section's properties
SFAIC.Main.someSection.fn = { ... }; // Some Section's functions
SFAIC.Main.anotherSection = { ... }; // Another Section's properties
SFAIC.Main.anotherSection.fn = { ... }; // Another Section's functions
SFAIC.Main.init = function() { ... }; // Main.aspx's intializer
$(document).ready(function() { SFAIC.Main.init(); });
I recommend that you make a new object for section and a new function for each page/item.
However, the more scripts you add in this way, the harder it gets to manage the whole in an editor. Netbeans has a feature that lets you jump to parts of the object and helps manage this.
Example:
var lib = {}; // your library
//maybe you like the plural name plugins better. That's fine.
lib.plugin = {
//define plugins here
};
//maybe you like the plural name helpers better. That's fine too.
lib.helper = {
//define your helpers here
cycle: function() {
//code for the cycle plug-in
}
};
lib.account = {
//you could stick code that is general to all account pages here
};
lib.account.overview = function() {
//you could stick code that is specific to the account overview page here
//maybe you'd use the cycle plug-in to show their latest posts.
lib.plugin.cycle();
};
lib.account = {
//you could stick code that is general to all account pages here
};
lib.account.overview = function() {
//you could stick code that is specific to the account overview page here
//maybe you'd use the cycle plug-in to show their latest posts.
lib.plugin.cycle();
};
Then on the Account Overview page you'd call lib.account.overview().
For Production:
Use a package like closure, uglify or the one I mention at the end to package all your code into one file and send that.
For Development:
I would recommend for structure you use a asynchronous javascript loader like
require.js.
This means you have lot's of modules and you specifically state the dependancies.
For example you would have one main.js
// main.js
require([
"jquery.js",
"jquery.ui.js",
...
], function() {
// if the correct location is "mysite.com/foo/" then url will be "foo"
var url = window.location.pathname.match(/\/(\w+)\//)[1] || "mainpage";
require(url + ".js", function(pageObj) {
// ...
});
});
// foo.js
define({
pageStuff: ...
});
I recommend you read through the requireJS docs to understand their structuring system. It's one of the best I've found.
When it comes to optimising all javascript into one file you just use their builder. This should be part of your project deploy system.

Categories