How do I use helpers with Dust.js on a local environment? - javascript

I'm programming using dust-full.js from the linkedIn fork (2.5.1). I'm trying to use helpers for conditionals, but I can't seem to get it to work. Right now, I'm using my local machine (I have no intention at the moment to include a server backend, but it may be where this project goes). I currently test my code on my Dropbox public folder. All non-helper code has worked.
The code in question:
{?quote temp="4"}
Once you have chosen the best answer{#if cond="{temp} > 1"}s{/if}, please select the "Submit" button.
{:else}
Choose the best answer{#if cond="{temp} > 1"}s{/if}, then select the "Submit" button.
{/quote}
I have previously added the dust-full.js distribution and helpers like so:
<script src="script/dust-full.js" type="text/javascript"></script>
<script src="script/dust-helpers.min.js" type="text/javascript"></script>
I saw in other threads and on the dust.js tutorial that one needed to "require" the helpers. Using code like this:
var dust = require('dustjs-linkedin');
dust.helper = require('dustjs-helpers');
However, when I include this, I get the console error: "ReferenceError: require is not defined." I assume that this is because "require" is usually used/included in node.js, but I honestly don't know. I would prefer not to include node.js, as I don't know it and I'm not interested in learning additional libraries. However, I do not know how to evaluate helpers.
I have four questions:
Are there any obvious bugs in the code I've provided?
Are dust.js helpers only available using when using server-side scripting?
(Assuming the answer to 2 is "No") Can helpers be used only with dust-full.js and dust-helpers.js?
(Assuming the answer to 3 is "No") How does one use helpers only using client-side scripting?

Using require to load the helpers is for a server environment like Node. You should be able to do exactly what you've done to load the helpers-- just include them after the main dust script and they'll be automatically added to the dust object.
What you've done looks correct, so is it possible that you've used the wrong path to your dust-helpers Javascript file?
Here is a snippet showing the {#gt} helper working. (The {#if} helper is deprecated, so you'll get warnings in the console when you use it-- but {#gt} does exactly what you want.)
<div id="output"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dustjs-linkedin/2.5.1/dust-full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dustjs-helpers/1.5.0/dust-helpers.min.js"></script>
<script>
var tmpl = dust.compile('Hello World! Choose the best answer{#gt key=temp value=1}s{/gt}', "test"),
context = { "temp": 4 };
dust.loadSource(tmpl);
dust.render("test", context, function(err, out) {
document.getElementById("output").textContent = out;
});
</script>

Related

Can you share code between multiple grafana scripted dashboards?

I have created a couple of scripted dashboards for Grafana. I'm about to create another. There are all kinds of utility functions that I created and copied from script to script. I would much rather employ good programming practice and import the code rather than copy-paste.
Can that be done? If so, how would one do it?
Yes, this can be done.
This link suggests that SystemJS.import() can be used, although I have not tried it.
This github repo provides a detailed example using a different technique.
Although its not mentioned in the slim Grafana scripted dashboard doc, some version of lodash.com (commit to include lodash) and jquery seem to be available to all scripted dashboards.
The owner of this repo, anryko, has figured out how to use these two libraries to reference your own utility scripts like you're talking about.
All scripted dashboards have a main script; getdash.sh is anryko's main script, as seen by the dash URL on the README.md:
http://grafanaIP/dashboard/script/getdash.js
If you look at the end of getdash.sh, you'll see this line that references code in other user(you)-provided scripts:
var dash = getDashApp(datasources, getDashConf());
For example:
the code for getDashConf() is in this separate .js file
the code for getDashApp() is in this other separate .js file.
Here is the part where getdash.js uses jquery and lodash to load the source files:
// loadScripts :: [scriptSourceStr] -> Promise([jQuery.getScript Result])
var loadScripts = function loadScripts (scriptSrcs) {
var gettingScripts = _.map(scriptSrcs, function (src) {
return $.getScript(src);
});
return Promise.all(gettingScripts);
};
Here is the lodash doc for the above _.map.
The function scriptedDashboard() (also in getdash.js) calls the above loadScripts(), passing it the paths to the source files like this:
loadScripts([
'public/app/getdash/getdash.app.js',
'public/app/getdash/getdash.conf.js'
]).then(function () {
To be honest, I haven't yet looked further under the covers to see how all this makes the utility code 'reference-able.'

IPython: Adding Javascript scripts to IPython notebook

As a part of a project, I need to embedd some javascripts inside an IPython module.
This is what I want to do:
from IPython.display import display,Javascript
Javascript('echo("sdfds");',lib='/home/student/Gl.js')
My Gl.js looks like this
function echo(a){
alert(a);
}
Is there some way so that I can embed "Gl.js" and other such external scripts inside the notebook, such that I dont have to include them as 'lib' argument everytime I try to execute some Javascript code which requires to that library.
As a very short-term solution, you can make use of the IPython display() and HTML() functions to inject some JavaScript into the page.
from IPython.display import display, HTML
js = "<script>alert('Hello World!');</script>"
display(HTML(js))
Although I do not recommend this over the official custom.js method, I do sometimes find it useful to quickly test something or to dynamically generate a small JavaScript snippet.
Embedding D3 in an IPython Notebook
https://blog.thedataincubator.com/2015/08/embedding-d3-in-an-ipython-notebook/
To summarize the code.
Import the script:
%%javascript
require.config({
paths: {
d3: '//cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.min'
}
});
Add an element like this:
%%javascript
element.append("<div id='chart1'></div>");
Or this:
from IPython.display import Javascript
#runs arbitrary javascript, client-side
Javascript("""
window.vizObj={};
""".format(df.to_json()))
IPython Notebook: Javascript/Python Bi-directional Communication
http://jakevdp.github.io/blog/2013/06/01/ipython-notebook-javascript-python-communication/
A more extensive post explaining how to access Python variables in JavaScript and vice versa.
I've been fighting with this problem for several days now, here's something that looks like it works; buyer beware though, this is a minimal working solution and it's neither pretty nor optimal - a nicer solution would be very welcome!
First, in .ipython/<profile>/static/custom/myScript.js, we do some require.js magic:
define(function(){
var foo = function(){
console.log('bar');
}
return {
foo : foo
}
});
Copy this pattern for as many functions as you like. Then, in .ipython/<profile>/static/custom/custom.js, drag those out into something persistent:
$([IPython.events]).on('notebook_loaded.Notebook', function(){
require(['custom/myScript'], function(custom){
window.foo = custom.foo;
} );
});
Yes, I am a horrible person for throwing stuff on the window object, namespace things as you deem appropriate. But now in the notebook, a cell like
%%javascript
foo();
should do exactly what it looks like it should, without the user having to explicitly import your JS. I would love to see a simpler solution for this (plz devs can we plz have $.getScript('/static/custom/util.js'); in custom.js to load up a bunch of global JS functions) - but this is the best I've got for now. This singing and dancing aside, HUGE ups to the IPython notebook team, this is an awesome platform!
Not out of the box by installing a package, at least for now.
The way to do it is to use custom.js and jQuery getScript to inject the js into the notebook.
I explicitly stay vague on how to do it, as it is a dev feature changing from time to time.
What you should know is that the static folder in user profile is merged with webserver static assets allowing you to access any file that are in this folder by asking for the right url.
Also this question has been asked a few hours ago on IPython weekly video "lab meeting" broadcasted live and disponible on youtube (you might have a longer answer), I've opened discussion with the author of the question here
For some reason, I have problems with IPython.display.Javascript. Here is my alternative, which can handle both importing external .js files and running custom code:
from IPython.display import display, HTML
def javascript(*st,file=None):
if len(st) == 1 and file is None:
s = st[0]
elif len(st) == 0 and file is not None:
s = open(file).read()
else:
raise ValueError('Pass either a string or file=.')
display(HTML("<script type='text/javascript'>" + s + "</script>"))
Usage is as follows:
javascript('alert("hi")')
javascript(file='Gl.js')
javascript('echo("sdfds")')
You can use IJavascript (a Javascript kernel for Jupyter notebooks).
I was interested in calling JavaScript from a Jupyter code (Python) cell to process strings, and have the processed string output in the (same) code cell output; thanks to Inject/execute JS code to IPython notebook and forbid its further execution on page reload and Why cannot python call Javascript() from within a python function? now I have this example:
from IPython.display import display, Javascript, Markdown as md, HTML
def js_convert_str_html(instring_str):
js_convert = """
<div id="_my_special_div"></div>
<script>
var myinputstring = '{0}';
function do_convert_str_html(instr) {{
return instr.toUpperCase();
}}
document.getElementById("_my_special_div").textContent = do_convert_str_html(myinputstring);
</script>
""".format(instring_str)
return HTML(js_convert)
jsobj = js_convert_str_html("hello world")
display(jsobj)
Note that the JavaScript-processed string does not get returned to Python per se; rather, the JavaScript itself creates its own div, and adds the result of the string conversion to it.

How can I combine my JavaScript files and still have my callbacks wait for a ready state?

I have lots of functions and event handlers that are split across multiple javascript files which are included on different pages throughout my site.
For performance reasons I want to combine all of those files into 1 file that is global across the site.
The problem is I will have event handlers called on elements that won't necessarily exist and same function names.
This is an example of a typical javascript file...
$(document).ready(function(){
$('#blah').keypress(function(e){
if (e.which == 13) {
checkMap();
return false;
}
});
});
function checkMap() {
// code
}
function loadMap() {
// code
}
I would need to seperate this code into an object that is called on that specific page.
My thoughts are I could re-write it like this:
(function($) {
$.homepage = {
checkMap: function(){
// code
},
loadMap: function(){
//code
}
};
})(jQuery);
And then on the page that requires it I could call $.homepage.checkMap() etc.
But then how would I declare event handlers like document.ready without containing it in it's own function?
First of all: Depending on how much code you have, you should consider, if serving all your code in one file is really a good idea. It's okay to save http-requests, but if you load a huge chunk of code, from which you use 5% on a single page, you might be better of by keeping those js files separated (especially in mobile environments!).
Remember, you can let the browser cache those files. Depending on how frequent your code changes, and how much of the source changes, you might want to separate your code into stable core-functionality and additional .js packages for special purposes. This way you might be better off traffic- and maintainance-wise.
Encapsulating your functions into different objects is a good idea to prevent unnecessary function-hoisting and global namespace pollution.
Finally you can prevent calling needless event handlers by either:
Introducing some kind of pagetype which helps you decide calling only the necessary functions.
or
checking for the existence of certain elements like this if( $("specialelement").length > 0 ){ callhandlers}
to speed up your JS, you could use the Google Closure Compiler. It minifies and optimizes your code.
I think that all you need is a namespace for you application. A namespace is a simple JSON object that could look like this:
var myApp = {
homepage : {
showHeader : function(){},
hideHeader : function(){},
animationDelay : 3400,
start : function(){} // the function that start the entire homepage logic
},
about : {
....
}
}
You can split it in more files:
MyApp will contain the myApp = { } object, maybe with some useful utilities like object.create or what have you.
Homepage.js will contain myApp.homepage = { ... } with all the methods of your homepage page.
The list goes on and on with the rest of the pages.
Think of it as packages. You don't need to use $ as the main object.
<script src="myapp.js"></script>
<script src="homepage.js"></script>
<-....->
<script>
myApp.homepage.start();
</script>
Would be the way I would use the homepage object.
When compressing with YUI, you should have:
<script src="scripts.min.js"></script>
<script>
myApp.homepage.start();
</script>
Just to make sure I've understood you correctly, you have one js file with all your code, but you want to still be in control of what is executed on a certain page?
If that is the case, then the Terrific JS framework could interest you. It allows you to apply javascript functionality to a module. A module is a component on your webpage, like the navigation, header, a currency converter. Terrific JS scans the dom and executes the js for the modules it finds so you don't have to worry about execution. Terrific JS requires OOCSS naming conventions to identify modules. It's no quick solution to your problem but it will help if you're willing to take the time. Here are some more links you may find useful:
Hello World Example:
http://jsfiddle.net/brunschgi/uzjSM/
Blogpost on using:
http://thomas.junghans.co.za/blog/2011/10/14/using-terrificjs-in-your-website/
I would use something like YUI compressor to merge all files into one min.js file that is minified. If you are looking for performance both merging and minifiying is the way to go. http://developer.yahoo.com/yui/compressor/
Example:
Javascript input files: jquery.js, ads.js support.js
run yui with jquery.js, ads.js, support.js output it into min.js
Javascript output files: min.js
then use min.js in your html code.

Javascript and jQuery file structure

I have created a sizable application javascript and jQuery. However my file structure is getting a bit messy!
At the moment I have one large JS file with a if ($('#myDiv').length > 0) { test at the top to only execute the code on the correct page, is this good practice?
There is also a mixture of plain JS functions and jQuery extensions in the same file e.g $.fn.myFunction = function(e) {.
I also have a few bits of code that look like this:
function Product() {
this.sku = '';
this.name = '';
this.price = '';
}
var myProduct = new Product;
Basket = new Object;
My question is for pointers on good practice regarding javascript and jQuery projects.
The code if ($('#myDiv').length > 0) { is not good practice. Instead, make your page specific JS as functions and execute them in the corresponding page . Like this:
var T01 = function(){
// JS specific to Template 01
};
var T02 = function(){
// JS specific to Template 02
};
HTML head of Template 01:
<script type="text/javascript"> $(T01); </script>
Consistency is the golden rule.
You can discuss design patterns back and forth, but if you want to have easily maintainable code where new people can come in and get an overview fairly quickly, the most important part, whatever design patterns you chose, is to have a consistent code base.
It is also the hardest thing to do - keeping your codebase clean and consistent is probably the hardest thing you can do as a programmer, and especially as a team.
Of course the first tip I can give you is to separate the jQuery extensions in their own source files. You can always serve everything together with a minification tool, so you should not worry about performance.
About the code youo mention, it could be simplified to
var Product = {
sku: '',
name: '',
price: ''
}
var myProduct = objectCopy(Product);
var Basket = {};
provided you write a simple objectCopy function which loops through the object own properties and just copies them to a new object (you can make a shallow or a deep copy, according to your needs).
Finally, if you think your code is starting to get messy, you may want to learn some patterns to organize JS code, like the module pattern. Alternatively, if you are familiar with doing this on the backend, you may want to organize your application following the MVC pattern. personal advertisement - I have written myself a tiny library which helps organize your code in this fashion. There are also many other libraries for the same task, often adding other functionality as well.
If you follow the MVC pattern, your page will actually correspond to some action in some controller, and you could just start it with a call like
<script>someController.someAction()</script>
in the head of your document, hence removing the need for the manual check for #myDiv. If you use my library MCV, it will be enough to declare your body like
<body class="mcv:controller/action">
and start the application with
$(document).ready(function() {
mcv.autostart();
});
Yes it's good practice to put as much of your code into a seperate JS file as this could then be compressed before transmission and hence speed up download time. However no you should not have code that looks like
if ($('#myDiv').length > 0) {
on every page. Split your JS code up into manageable functions and call those as-and-when you need to.
I don't see a problem with mixing JS and jQuery functions up in the same file.

How to use javascript namespaces correctly in a View / PartialView

i've been playing with MVC for a while now, but since the project i'm on is starting to get wind in its sails more and more people are added to it. Since i'm in charge of hacking around to find out some "best practice", i'm especially wary about the possible misuses of javascript and would like to find out what would be the best way to have our views and partial views play nicely with javascript.
For the moment, we're having code that looks like this (only simplified for example's sake)
<script type="text/javascript">
function DisableInputsForSubmit() {
if ($('#IsDisabled').is(':checked')) {
$('#Parameters :input').attr('disabled', true);
} else {
$('#Parameters :input').removeAttr('disabled');
}
}
</script>
<%=Html.SubmitButton("submit", Html.ResourceText("submit"), New With {.class = "button", .onclick = "DisableInputsForSubmit(); if ($('#EditParameters').validate().form()) {SetContentArea(GetHtmlDisplay('SaveParameters', 'Area', 'Controller'), $('#Parameters').serialize());} return false;"})%><%=Html.ResourceIcon("Save")%>
Here, we're saving a form and posting it to the server, but we disable inputs we don't want to validate if a checkbox is checked.
a bit of context
Please ignore the Html.Resource* bits, it's the resource management
helpers
The SetContentArea method wraps ajax calls, and GetHtmlDisplay
resolves url regarding an area,
controller and action
We've got combres installed that takes care of compressing, minifying
and serving third-parties libraries and what i've clearly identified as reusable javascript
My problem is that if somebody else defines a function DisableInputsForSubmit at another level (let's say the master page, or in another javascript file), problems may arise.
Lots of videos on the web (Resig on the design of jQuery, or Douglas Crockford for his talk at Google about the good parts of javascript) talk about using the namespaces in your libraries/frameworks.
So far so good, but in this case, it looks a bit overkill. What is the recommended way to go? Should i:
Create a whole framework inside a namespace, and reference it globally in the application? Looks like a lot of work for something so tiny as this method
Create a skeleton framework, and use local javascript in my views/partials, eventually promoting parts of the inline javascript to framework status, depending on the usage we have? In this case, how can i cleanly isolate the inline javascript from other views/partials?
Don't worry and rely on UI testing to catch the problem if it ever happens?
As a matter of fact, i think that even the JS code i've written that is in a separate file will benefit from your answers :)
As a matter of safety/best practice, you should always use the module pattern. If you also use event handlers rather than shoving javascript into the onclick attribute, you don't have to worry about naming conflicts and your js is easier to read:
<script type="text/javascript">
(function() {
// your button selector may be different
$("input[type='submit'].button").click(function(ev) {
DisableInputsForSubmit();
if ($('#EditParameters').validate().form()) {
SetContentArea(GetHtmlDisplay('SaveParameters', 'Area','Controller'), $('#Parameters').serialize());
}
ev.preventDefault();
});
function DisableInputsForSubmit() {
if ($('#IsDisabled').is(':checked')) {
$('#Parameters :input').attr('disabled', true);
} else {
$('#Parameters :input').removeAttr('disabled');
}
}
})();
</script>
This is trivially easy to extract into an external file if you decide to.
Edit in response to comment:
To make a function re-usable, I would just use a namespace, yes. Something like this:
(function() {
MyNS = MyNS || {};
MyNS.DisableInputsForSubmit = function() {
//yada yada
}
})();

Categories

Resources