I'm trying to convert a Play! 2.0 application into a Scalatra application. I've had some success, but there are 3 issues remaining, 1 of which has its own ticket.
1) I understand that src/main/webapp/WEB-INF/views and src/main/webapp/WEB-INF/layouts contain the layouts in a standard directory structure. I was not able to get this to work in a different heirarchy, though, e.g. if I have 2 servlets and wanted different views for them:
- WEB-INF
- servlet1
- views
- layouts
- servlet2
- views
- layouts
In the example I provided, I can't adequately reference anything not directly under WEB-INF/views or WEB-INF/layouts. Presumably, it's because I'm not declaring something in web.xml correctly?
// works
get("/") {
contentType = "text/html"
templateEngine.layout("/WEB-INF/views/app.jade")
}
// no worky
get("/") {
contentType = "text/html"
templateEngine.layout("/WEB-INF/servlet1/views/app.jade") // where servlet1/layouts/default.jade exists
}
2) What's up with templating? For this conversion to work, I need to be able to use Underscore templates in conjunction with whatever is available to me from Scalatra (Jade, Mustache, etc). I chose Jade because all the default examples use it.
I'm really running into two sub-issues here.
1) I can't seem to use Underscore templates with Jade, even though I have included the javascripts in this ticket. Maybe this works, maybe it doesn't. This is probably because....
2) My include statements look like tags instead of actually including the partial, so it's really hard to test the first sub-issue.
<!-- / Nav -->
<include>nav</include>
<!-- / Action1 -->
<include>action1</include>
<include>action2</include>
<!-- / Wireframe -->
<div id="default-region">
<script id="template-layout" type="text/template">
<div id="region-nav"></div>
<div id="region-content"></div>
</script>
</div>
<!-- / CSS and JavaScripts relative to Backbone app -->
<include>assets</include>
What the equivalent app.jade file looks like:
// Nav
include nav
// Action1
include action1
include action2
// Wireframe
div#default-region
script#template-layout(type="text/template")
div#region-nav
div#region-content
// CSS and JavaScripts relative to Backbone app
include assets
Any help would be appreciated!
You can structure your views differently or you have to provide a different filesystem configuration for your views. You can configure that by overriding getRenderContext.
You don't need to call templateEngine.layout, but instead use our helper methods.
For jade with a layout that becomes jade("my_view", "layout" -> "/WEB-INF/layouts/authenticated.jade")
As for including those tags, etc. perhaps you mean this?
Related
I have a Sample project with angular-datatables with CRUD operations. I looked at Project Scaffolding at grunt web, but I can't find anything about javascript templates that fit my needs...
I saw init.copyAndProcess that is something like I want, but I need few improves to this. First, I want templates with conditional sentences on my js file, like(pseudocode):
{if prop.selectAllButton}
//declare header render on Datatables in several lines of code{/if}
Also, there will be like 10 or 20 options, and it could grow with the number of columns or by creating virtual columns. So, I want the props object to be on a file, not to be prompts on cli.
The table is not rendered in angular way.
Thanks in advance.
Chi.
Now i see that my questions is a bit obvious to answer if I move out of grunt Scaffolding and use yeoman...
In yo file, I can read my configFile in the initializing phase, like:
initializing: function () {
this.pkg = require('../package.json');
this.dtconfig = require(this.options['config-file-location']);
},
Where 'config-file-location' is an argument of the cli.
Them, in the writing phase, I use dtconfig as parameter for copyTpl:
scripts: function () {
this.fs.copyTpl(
this.templatePath('main.js'),
this.destinationPath('app/scripts/main.js'),
{//Parameters
selectAllButton: this.dtconfig.selectAllButton
}
);
And them, in the templates/main.js file:
<% if (selectAllButton) { %>
//apply selectaAll header render for dt.
In a Sails.js application, how can I include javascript assets selectively?
For instance, if I have an admin page and admin.js lives inside the assets/js directory. How do I keep the admin.js from loading on the public index page?
I'm aware that I could move the js out to the public directory, and include the script in my admin view's template. But I'm still unable to include it after the assets.js() call inserts it's javascript. I need it to be inserted after the sails.io.js script is loaded.
Is there any way to selectively load scripts and still have access to the sails.io.js which is automatically included with the assets.js() function call? Is there a better paradigm for this kind of situation?
EDIT:
Since the release of SailsJS 0.9 and the restructuring of the asset management system, this question doesn't really apply anymore.
Sailsjs uses asset-rack to serve /assets. With the default layout page, sailsjs serves pages that look like (dummy2.js is included with an explicit < script >):
<html>
<head>
...
<script type="text/javascript" src="/assets/mixins/sails.io-d338eee765373b5d77fdd78f29d47900.js"></script>
<script type="text/javascript" src="/assets/js/dummy0-1cdb8d87a92a2d5a02b910c6227b3ca4.js"></script>
<script type="text/javascript" src="/assets/js/dummy1-8c1b254452f6908d682b9b149eb55d7e.js"></script>
</head>
<body>
...
<script src="/public/dummy2.js"></script>
...
</body>
</html>
So sailsjs does not concatenate files (at least not in development mode). sails.io (socket-io) is always included before /assets/js in layout, and before < script > on the page.
It looks like your admin.js is expecting a condition which sails.io has not yet set, perhaps its negotiating a transport with the server? Try waiting for the condition to be set.
In a Sails.js application, how can I include javascript assets selectively?
I selectively load js assets using a wrapper around assets.js(). This snippet uses Jade's "-" and "!{...}". EJS would instead use "<%...%>" and "<%=...%>"
<!-- JavaScript and stylesheets from your assets folder are included here -->
!{assets.css()}
-function selectAssets (assetsjs, files, ifInclude) {
- return assetsjs.split('\n').reduce(function (prev, curr, i) {
- var frag = curr.match(/src="\/assets\/js\/\w{1,}\-/);
- if(frag) {
- var file = frag[0].substring(16, frag[0].length - 1);
- if ((files.indexOf(file) === -1) == ifInclude) { return prev; }
- }
- return prev + curr + '\n';
- }, '');
-}
//!{assets.js()} this line is replaced by:
!{selectAssets(assets.js(), ['dummy1', 'dummy5', 'dummy6'], false)}
The above would not include /assets/js/dummy1.js, dummy5, dummy6 with the layout. If you wanted to include dummy1 and dummy5 on a particular page, you would place
!{selectAssets(assets.js(), ['dummy1', 'dummy5'], true)}
on that page.
Note: The code assumes file name don't contain "-". Its straighforward to generalize for css and templates. sails-io would be a special case for mixins.
I know this is a old question but since people are still looking for this.
Sails has a folder called tasks in the root after you create a new project.
The file you are looking for is
pipeline.js
That file holds a variable called jsFilesToInject
// Client-side javascript files to inject in order
// (uses Grunt-style wildcard/glob/splat expressions)
var jsFilesToInject = [
// Load sails.io before everything else
// 'js/dependencies/sails.io.js',
'js/sails.io.js'
// Dependencies like jQuery, or Angular are brought in here
'js/dependencies/**/*.js',
// All of the rest of your client-side js files
// will be injected here in no particular order.
'js/**/*.js'
];
Just put your script that you want loaded before sails.io.js.
This is relevant for sails 0.11.x
another way that is valid is to create a views/partials folder
and create a new file like mapScripts.ejs
drop the script tags there and in your view use
<% include ../partials/mapScripts %>
Yes, you put a condition in template. :)
or add another "block" for your js.
extends ../layout
block body
<h1>hello</h1>
block jsscripts
<scripts> ..... </script>
To answer part of your question about where included files are located.
In 0.10 version order of the files is set in file tasks/values/injectedFiles.js as I recall in previous versions it was determined in Gruntfile.js itself.
You can add reference of your custom file in tasks/pipeline.js
var jsFilesToInject = [
'js/dependencies/sails.io.js',
'js/dependencies/**/*.js',
'js/**/*.js',
'js/yourcustomFile.js'
];
I've started using bundling and minification included with the MVC4 Beta. I'm running into a few issues with it:
For one thing, if I use the classic <script src="Folder/js" type="text/javascript"/> bundling, it seems like I have to rename my files to make sure they're bundled in the proper order.
Let's say I have three javascript files: "ants.js", "bugs.js", "insects.js"
ants.js depends on bugs.js
bugs.js depends on insects.js
Default bundling seems to bundle them in alphabetical order.
To get them to bundle properly, I have to rename them to: "0.insects.js", "1.bugs.js", "2.ants.js"
That's really hackish and there has to be a cleaner way.
The next problem I'm having is debugging. I like to step through the javascript in my testing browsers, is there a way to turn off just the minification while in DEBUG mode?
EDIT: To be clear, I know I can create bundles and register them from C#, it just seems really ugly to have to do it that way.
To temporarily get non-minified output use this
public class NonMinifyingJavascript : IBundleTransform
{
public void Process(BundleContext context, BundleResponse bundle)
{
if(bundle == null)
{
throw new ArgumentNullException("bundle");
}
context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies();
foreach(FileInfo file in bundle.Files)
{
HttpContext.Current.Response.AddFileDependency(file.FullName);
}
bundle.ContentType = "text/javascript";
//base.Process(context, bundle);
}
}
If you wanted it based totally on a config setting, I imagine you could create an IBundle transform that delegates to this one or JsMinify depending on your config setting
In order to control the ordering of the javascript files you need to use the BundleFileSetOrdering
var javascriptBundle = new Bundle("~/site/js", new NonMinifyingJavascript());
//controls ordering for javascript files, otherwise they are processed in order of AddFile calls
var bootstrapOrdering = new BundleFileSetOrdering("bootstrap");
//The popover plugin requires the tooltip plugin
bootstrapOrdering.Files.Add("bootstrap-tooltip.js");
bootstrapOrdering.Files.Add("bootstrap-popover.js");
BundleTable.Bundles.FileSetOrderList.Add(bootstrapOrdering);
javascriptBundle.AddDirectory("~/Scripts", "bootstrap-*.js");
I use the MVC default NoTransform instead of the NonMinifyingJavascript proposed by chrisortman. As far as I know it does the same.
But still not optimal. Ideally I want a script tag for each idividual script file when I want to debug. This makes debugging a lot easier with VS11, which I like to use (one debugger so I can debug js and c# in one debug session).
So I created this little helper:
#helper RenderScriptTags(string virtualPath)
{
if (Minify /* some appsetting */)
{
<script src="#System.Web.Optimization.BundleTable.Bundles.ResolveBundleUrl(virtualPath)"></script>
}
else
{
foreach (var file in System.Web.Optimization.BundleResolver.Current.GetBundleContents(virtualPath))
{
<script src="#Url.Content(file)"></script>
}
}
}
#RenderScriptTags("~/libraries")
I have a single page app, so I have this in my main cshtml file, but it can easily be generalized by moving this to an htmlhelper extension method.
Works nice!
This code takes also into account the BundleFileSetOrdering if you have set one!
Might also take a look at RequestReduce. It bundles your scripts and CSS without any coding or configuration by looking at how they are laid out on your page and bundling according to that. It also allows you to turn off bundling and minification via web.config or for individual requests via a querystring param: RRFilter=disabled.
I ran into this same problem yesterday and couldn't find a good solution with the new System.Web.Optimization namespace. There were some broken MSDN links, so the fact that everything is in beta means it may change, but I digress...
You could always load the scripts differently during development than in production. Easy to do with an AppSetting:
#if (System.Configuration.
ConfigurationManager.AppSettings["BundleResources"] != null)
{
#* load the css & js using bundles *#
}
else
{
#* load the css & js files individually*#
}
You can then enable / disable the optimization stuff by commenting out an appsetting in web.config:
<appSettings>
...
<!--<add key="BundleResources" value="uhuh" />-->
...
</appSettings>
I will explain my idea behind this:
I use python for google app engine + js + css
the main project will be stored under the src folder like this:
\src
\app <--- here goes all the python app for gae
\javascript <--- my non-packed javascript files
\static_files <--- static files for gae
now the javascript dir looks like this
\javascript
\frameworks <--- maybe jQuery && jQueryUI
\models <--- js files
\controllers <--- js files
\views <--- HTML files!
app.js <--- the main app for js
compile.py <--- this is the file I will talk more
About compile.py:
This file will have 2 methods one for the min and other for the development javascript file;
When is run will do:
Join all the files with "js" extension;
The app.js contains a variable named "views" and is an object, like a hash; Then the compiler copy the contents of each file with "html" extension located in the "/javascript/views/" dir using this rule;
example: if we have a view like this "/views/login.html" then the "views" js var will have a property named "login"; views['login'] = '...content...';
example2: "/views/admin/sexyBitcy.html" then view['admin.sexyBitcy'] = '...content...' or whatever exists in that html file..;
Then this big file will be saved into the "/src/static_files/core.js"; if is minified will be saved as "/src/static_files/core.min.js";
The javascript will use dependenccy injection, or sort of it. (:
I will explain how it will work then:
the index.html that is loaded when you come into the site loads the core.js and the jquery.js;
the core.js will create the layout of the page, as SEO is not important for the most of the pages;
the core.js uses the controllers-models-views to create the layout of course; the html for the layout is inside the var "views"; will be a heavy variable of course!
Some code:
mvcInjector = new MVCInjector;
mvcInjector.mapView(views['login'], 'login', LoginController);
parent = $('#jscontent');
jquery
view = mvcInjector.instanceView('login', parent); // <--- this will create the contents of the views['login'] in the parent node "parent = $('#jscontent');" then will instance the LoginController that will map the "SkinParts" (like in FLEX if you know); what does it mean map the "SkinParts"? - when the user will click on a button an handler for that action is defined in the controller; ex.:
// LoginController
this.init = function(){
// map skin parts
this.mapSkinPart('email', 'input[name]="email"');
this.mapSkinPart('submit', 'input[name]="submit"');
// link skin parts to handlers
this.getSkinPart('submit').click = this.login;
}
// handlers
this.login = function(event){
// connect to the db
// some problems here the get the value as the "this" keyword references to the this of the controller class, I will work it around soon
alert('open window button1' + this.getSkinPart('email').value());
}
If something is not clear just say something, I will be happy to explain;
So the question remains: is this scalable, manageable and fast enough for a big RIA application build with javascript+jquery and maybe with jqueryUI?
Thanks ;)
I like your idea quit a bit.
I would think about loading html pages by ajax, if they are big and there are many of them...
Have a look on angular project, I hope, it could help you a lot. It's a kind of JS framework, designed to work together with jQuery. Well suitable for test driven development.
It uses html as templates, you can simply create your own controllers, use dependency injector, etc... Feel free to ask any question on mailing list.
Then, I must recommend JsTestDriver - really cool test runner for JS (so you can easily run unit tests in many browsers, during development - let's say after save...)
I am a web guy doing mostly Perl server-side stuff, and I'm slowly coming to a few conclusions.
It is far better to do most of your code via Javascript and toss data back and forth via AJAX than it is to hit submit and reload a mostly-identical page
I like jQuery because I like CSS, and it's fun to chain together big long and scary-to-others definitions
There's something to that templating stuff.
You want your HTML elements to look like your HTML elements, and it's easier to define that in HTML:
<div class="sidebar_elem">
TEXT
</div>
Than it is to cobble up the same in Javascript or jQuery:
( '<div/>' )
.attr('id' , 'sidebar_elem' + i )
.addclass( 'sidebar_elem' )
;
( '<a/>' )
.attr('href' , link_url )
.appendTo( '#sidebar_elem' + i )
;
This is to say that I am no longer a templating agnostic, but I don't know which templating tool to believe in. I have looked into some jQuery-based templating plugins, but I have yet to become happy with any of them, in part because the ones I've seen seem to want to put all that code into the page itself, which breaks the "Only markup goes into HTML files, only style goes into CSS files, only code goes into JS files" mantra I keep reciting.
So, I'm looking for a Javascript-based templating tool that would allow me to have my templates in an outside file so I can have one template change cover a series of web pages. If it's jQuery-based, that's great, less stuff I have to learn, but it isn't a deal-breaker.
There are several good ones out there:
Mustache.js
Pure.js
Json Template
If you want a jQuery version, Tempest looks good.
The 2 libs I know that do not mix template coding with HTML markups are chain.js and PURE
chain makes only DOM manipulations.
PURE uses a mix of DOM and innerHTML as the DOM alone can be slow to render bigger templates.
I'm the main contributor of PURE, and we created it to build a web app on the ajax model you describe.
Take a look at this one http://ejohn.org/blog/javascript-micro-templating/. Made by John Resig, creator of jQuery, this one doesn't even need jQuery, and it's freaking small. It also stores templates in script tag (Daniel's answer). Example template:
<script type="text/html" id="user_tmpl">
<% for ( var i = 0; i < users.length; i++ ) { %>
<li><%=users[i].name%></li>
<% } %>
</script>
Maybe you can load them using src attribute if you really need them to be in separate files, which I don't think is a wise idea, because it means additional roundtrip to the server. So at the end, for the sake of optimization, you can store them in separate files, but embed them server side in the page that needs them.
Since there is no well defined API and a best library for templating, I would suggest you choose one that is actively developed. Below, I briefly explained two libraries that are actively being developed.
jQuery team decided that jQuery Templates will no longer be actively developed or maintained, thus I would strongly suggest NOT using it. See this blog entry.
You can use JsRender in accordance with JsViews to take full functionality provided by jQuery Templates and even more like data linking. You can find demos for JsRender and JsViews. I would suggest using these libraries since they are actively being developed by jQuery UI team but be aware that they are still not even beta!
Mustache is another templating solution that is actively being developed and it simplifies templates by combining conditional tags and enumeration tags. It also provides strong features like inverted sections, partials and high order sections with simple syntax. Mustache is also one of the fastest templating solutions See blog by Brian Landau. I, personally, find mustache a good templating solution since it has a simple syntax and performs well.
How about EJS?
Example from their page:
"EJS combines data and a template to produce HTML."
Data:
{title: 'Cleaning Supplies', supplies: ['mop', 'broom', 'duster'] }
Template:
<ul>
<% for(var i=0; i<supplies.length; i++) {%>
<li><%= supplies[i] %></li>
<% } %>
</ul>
Result:
mop
broom
duster
You should check out google closure template. It's completely independent so you can use it with any lib you want. It's a templating tool written in java.
http://code.google.com/closure/templates/docs/helloworld_js.html
It allows you to create a template on the server, run a java "compiler" on it and the output is a javascript function that takes json as its parameter.
{namespace examples}
/**
* Greets a person using "Hello" by default.
* #param name The name of the person.
* #param? greetingWord Optional greeting word to use instead of "Hello".
*/
{template .helloName}
{if not $greetingWord}
Hello {$name}!
{else}
{$greetingWord} {$name}!
{/if}
{/template}
This will generate a function called examples.helloName that can be called like
Their format is very IDE friendly, I get all the HTML syntax highlighting when editing the templates
examples.helloName({name: 'Ana', greetingWord:"Howdy"});
You can call other templates from within templates, it automatically html escapes your data (unless you tell it not to), provides bidirection support.
Another great thing is the fact that the templating tool can also generate java code. So somebody writing an app that must support browsers with scripting disabled can generate the HTML on the server if necessary.
Last but not least, unlike other js templating systems (), the template is parsed on the server, so the client side only has to do the merging of the template and data, the parsing of the template is done as a build step on the server.
http://dev.sencha.com/deploy/dev/docs/?class=Ext.XTemplate is an example of a templating tool that runs completely on the client. There are two problems with this approach, the parsing of the template is done on the client and your html has to be embedded in a javascript string. However, some IDEs (Intellij) will highlight the HTML inside JS strings).
What about JAML Code?
http://github.com/edspencer/jaml
Similar to a few of the above but I believe is a bit more logical...
It is the concept of defining your templates via JSON / JavaScript and then using a function in JavaScript to pass arguments to your template which gets it rendered and returned as an element.
There are implementations around for the various JavaScript Frameworks that exist.
Try out this:
https://www.npmjs.com/package/jlate
use CDN:
<script src="https://cdn.jsdelivr.net/combine/npm/lodash,npm/jlate#0.0.2/jlate/JLate.min.js"></script>
I given below working example where you can replace github template url with your own template sample:
https://raw.githubusercontent.com/webphonix/JLate/main/test_project/template/weblate_loop.html
<div class="row">
<% _.each(names, function(n){ %>
<div class="col-md-6"><%- n.name %></div>
<% }) %>
</div>
var author = [{
name: "Guru"
},
{
name: "Gurudev"
},
{
name: "Test"
},
{
name: "Webphonix"
},
];
$$("#my_temp").jlate({
names: author
});
<script src="https://cdn.jsdelivr.net/combine/npm/lodash,npm/jlate#0.0.2/jlate/JLate.min.js"></script>
<div>
<jlate id="my_temp" src="https://raw.githubusercontent.com/webphonix/JLate/main/test_project/template/weblate_loop.html" type="template">
Loading...
</jlate>
</div>
Try JLate:
https://www.npmjs.com/package/jlate
use version 0.0.2 instead 0.0.1
use below cdn:
<script src="https://cdn.jsdelivr.net/combine/npm/lodash,npm/jlate#0.0.2/jlate/JLate.min.js"></script>
Use a script block.
<script id="someId" type="text/html">
<!-- your template here -->
</script>
and one of many JQuery plugins.
http://weblogs.asp.net/scottgu/archive/2010/05/07/jquery-templates-and-data-linking-and-microsoft-contributing-to-jquery.aspx
I have a templating engine called stencil.js, which I believe is pretty sweet. It works with jQuery via the jquery-haml DOM building engine.
Write your template (which you can put in an external file and decode as JSON):
["%div.sidebar_elem"
["%a", { href: { key:'link' } },
{ key: "text" }
]
]
And run it through stencil along with your data:
$("#parent").stencil(template, { link: "http://example.com", text: "Click me!" });
There are more examples at the stencil.js GitHub project, but I think it's just what you're looking for.
It could use a couple more utility methods, and some code for an unfinished data binding component is still in the master branch, so drop me a comment if you’re interested and I'll see if I can clean it up.
check out ibdom, and some background/history here: Recommended JavaScript HTML template library for JQuery?
Could always go with jQuery-Templates: http://api.jquery.com/category/plugins/templates/
What about http://www.enfusion-framework.org
Stuff like this:
<span template>Our telephone number is {phone}.</span>
<span session>You are logged in as {nickname}.</span>