Postprocess *.js files with grails - grails

I am wondering of there is any possibility of postprocessing *.js files so that every gsp expression can be evaluated.
for example i can write the following code directly in the gsp page:
<script type="text/javascript">
$.post("${createLink(controller:'mycontroller',action:'myaction')} " , {"id":id},function(){});
</script>
And the expression ${createLink} is evaluated by grails.
But i would like to also use ${createLink()} in *.js files which are not processed by grails.
Maybe it is possible to use the resource plugin to postprocess every *.js file and evaluate gsp expressions?
Of course i could wrap all my js code in a separate gsp page but it does not seem like an elegant solution.
Any help would be appreciated.

Either of this should work for you
http://grails.org/plugin/gsp-arse (standalone)
http://grails.org/plugin/gsp-resources (It works with resources plugin)

Another option is to do something similar to store the url in a variable
<script type="text/javascript">
var url = "${createLink(controller:'mycontroller',action:'myaction')}";
</script>
Then you can use all the ajax calls you want and still only have the url set once.

Use a JS Hash in your GSP file to save what matters
<r:script>
var linkobject={
mylink:'${createLink(controller:"mycontroller",action:"myaction")}',
 linkA : '${params.id}',
    linkB: '${g.createLink(action: "getThreats")}',
    linkC: '${g.createLink(action: "addThreat")}',
    linkD: '${g.resource(dir: 'images/icons', file: 'folder.png')}'
 
}
</r:script>
Then, Consume that JS hash in your JavaScript file to get what you need:
$.post(linkobject.mylink , {"id":linkobject.linkA},function(){});

Related

Thymeleaf put a dynamic parameter inside script tag

With thymeleaf and following code
<script th:src="#{/js/init.js}"></script>
I would like to make it like following in order to avoid browser caching for this file
<script th:src="#{/js/init.js?${minute}}"></script>
${minute} will be current time minute.
Try:
<script th:src="#{/js/init.js(minute=${minute})}"></script>
Reference: Standard URL Syntax
I solve the question by use the following, it's a bit longer than expected.
<script th:src="#{/js/init.js(minute=${#dates.format(#dates.createNow(), 'mm')})}"></script>
If you just want to provide versioned static files, you might try spring resource versioning. One possible solution using configuration only is described here https://stackoverflow.com/a/49040930.

Rollup external paths with iife

I found next code fragment on the Rollup api page.
If I would be using iife instead of amd.
How would Rollup define this in the bundle?
Or would it expect a preceding <script> tag containing that external code? If the latter would be true: Is there a way to produce a bundle with JS code which dynamically loads JS files through absolute URLs?
Try it. You'll see it generates code like this:
(function (d3) {
'use strict';
d3.selectAll('p').style('color', 'purple');
}(d3));
In other words yes, it expects there to be a <script> tag on the page that defines d3.
Is there a way to produce a bundle with JS code which dynamically loads JS files through absolute URLs?
That's exactly what the amd output is. You just need to have an AMD module loader such as require.js or curl.js on the page.

Bundling and concatenation with gulp-useref Durandal and ASP.NET MVC

I have a Durandal 2 app based on ASP.NET MVC 5 and Web API, with the initial Index.cshtml (on HomeController) being served through the MVC router. From then on it's all regular html views being handled by the Durandal router.
Anyway, I'm trying to use gulp-useref to concatenate all css and js files. I've got everything working and gulp-useref drops the newly concatenated files and an index.cshtml with the updated script and stylesheet references in a dist folder.
Of course, for the application to work I need the updated index.cshtml back in Views/Home/. I have created a "copy" task with gulp that does just that; it overwrites the original index.cshtml and fixes the paths to the concatenated js and css files.
That works as well, but since useref removes the html comments that mark the spot where it should insert the references to the concatenated files, the process is not repeatable.
Let me illustrate with some code.
In my Index.cshtml I have:
<html>
<head></head>
<body>
<!-- build:js js/lib.js-->
<script src="/bower_components/numeral/languages.js"></script>
<script src="/scripts/bootstrap.js"></script>
<script src="/scripts/typeahead.js"></script>
<script src="/scripts/knockout-bootstrap.js"></script>
<script src="/scripts/knockout-extenders.js"></script>
<!-- endbuild -->
</body>
</html>
This is where gulp-useref will place the updated script reference so it will end up looking like this:
<html>
<head></head>
<body>
<script src="/js/lib.js"></script>
</body>
</html>
As you can see, useref removes the html comments so if I overwrite the original index.cshtml with this file, useref will not know where to place the updated script tag. And if I don't overwrite the original index.cshtml, the application will not be using the concatenated files.
I'm new to gulp so I might be going at this in the completely wrong way, but how can I make sure that my /Views/Home/index.cshtml uses the concatenated files in an automated manner?
Or, alternatively, is there a better approach for what I'm trying to do, namely, get everything ready for deployment?
Here are my relevant gulp tasks, for reference:
gulp.task("optimize-for-deployment", function () {
var assets = $.useref.assets({ searchPath: "./" });
var cssFilter = $.filter("**/*.css");
var jsFilter = $.filter("**/*.js");
return gulp
.src(config.index)
.pipe($.plumber())
.pipe(assets)
.pipe(cssFilter)
.pipe($.csso())
.pipe(cssFilter.restore())
.pipe(jsFilter)
.pipe($.uglify())
.pipe(jsFilter.restore())
.pipe(assets.restore())
.pipe($.useref())
.pipe(gulp.dest(config.appDist));
});
// copy the updated index.cshtml to Views/Home/
gulp.task("copy-for-deployment", ["optimize-for-deployment"], function () {
return gulp.src(config.appDist + "index.cshtml")
.pipe($.replacePath(/js\/lib.js/, "/app/dist/js/lib.js"))
.pipe($.replacePath(/style\/app.css/, "/app/dist/style/app.css"))
.pipe(gulp.dest(config.indexLocation));
});
Don't know if this is 'better' approach or the best solution but you could use something like a template for your index file. So you would have an Index-template.cshtml with al your html comments which you use to create your Index.cshtml every time in your gulp tasks.
This way you can overwrite your Index.cshtml and keep your template with al your html comments.
I am new to .net mvc and trying to do the exact thing Sergi. If you modified the default view location scheme to include your dist folder (How to change default view location scheme in ASP.NET MVC?), would .net know to include the dist folder and compile those .cshtml files?

CKEditor - move skins folder somewhere else

I'm using CKEditor for the first time and trying to do something that I thought would be very simple to do but so far I've had no success.
Essentially I want to place the editor.js, config.js and styles.js in a scripts folder but want the "Skins" folder that contains the css and images to appear within a separate "Styles" folder.
The application consists of a simple view that displays the editor on load.
The code to display the editor is a follows:
angular.element(document).ready(function () {
CKEDITOR.config.contentsCss = '/Styles/CKEditor/';
CKEDITOR.replace('editor');
});
The HTML within my view is as follows:
#section scripts
{
<script src="~/Scripts/ckeditor.js" type="text/javascript"></script>
<script src="~/Scripts/angular.js"></script>
<script src="~/Scripts/Main.js" type="text/javascript"></script>
}
<h2>Index</h2>
<textarea id="editor" name="editor"></textarea>
This is an MVC application and the scripts are rendered at the end of the body within the layout view.
The editor will not display in any browser. As I understand it setting the contentsCss property should do the trick.
If I place the skins beneath my script folder it works fine. I can see in the generated source that it is adding a link to the header pointing to /Scripts/Skins/moono..., but I want it to add a reference to /Styles/Skins/moono...
Is what I am trying to do feasable and if so what am I missing here? I was expecting this to be simple.
As a work around I could just add some routing rules that redirects the relevant request to a different location, but I'd rather get to the bottom of the issue before I do this.
Further information:
My application is an ASP.net 4.5/MVC 4 app.
I'm referencing angular because I'll be using that once I've sorted this issue. I have tried removing all references to angular but the problem still persists.
I've tried setting the contentsCss property in the following ways:
Directly using CKEDITOR.config.contentsCss
Within the config.js file. The sample assigns an anonymous function to CKEDITOR.editorConfig and in there you can manipulate congif entries.
Passing a config parameter when calling the "replace" method on the CKEditor object.
I've tried manipulating the contentsCss property both before and after the call to replace.
I'm using the latest version of CKEditor (4.2)
Thanks to #Richard Deeming, I've found the answer.
I'm using the default moono style, so I needed to set the CKEDITOR.config.skin property as follows:
CKEDITOR.config.skin = 'moono,/Styles/CKEditor/Skins/moono/'
My final code now looks like this:
angular.element(document).ready(function () {
CKEDITOR.config.skin = 'moono,/Styles/CKEditor/Skins/moono/';
CKEDITOR.replace('editor');
});
You have to set the url to the actual folder containing the skin itself (I thought CKEditor might append skins/mooono itself but it doesn't).
I also found that you must include the final '/' from the URL.
Looking at the documentation, you need to specify the path as part of the skin name:
CKEDITOR.skinName = 'CKeditor,/Styles/CKeditor/';

Moving unobtrusive javascript out of html.erb file

I have a html.erb file in one of my views. The file is pretty big and has about 2/3 javascript code and just 1/3 html. I dont like this file being too cluttered. The javascript part is mostly event handlers and usage of jquery UI components like date pickers, dialogs etc for the corresponding html elements in the page. I would like to separate the javascript part from the html part.
Can I move the javascript to a separate js.erb file and use it like a partial? What is the advantage of this?
How would I move the javascript to a static .js file when I use rails API like I18n.() and <%= form_authenticity_token %>. Should I pass them every time to the wrapping javascript function? Is there a better way to do this?
If I move javascript out of the html.erb file will it help in caching/rendering of html.erb page?
Interested to find out if there are any re-usable patterns
Sample code on the html.erb file:
<% content_for :javascript do %>
<script type="text/javascript">
$(document).ready(function()
{
$('#create_segment_dialog').dialog({
title: "<%= I18n.t("segment.create_segment_title") %>",
// lots of javascript
}
</script>
<%end %>
//HTML starts here
<div id="right-column">
My 2c, but I know there are differing opinions on this:
Try and separate out as much of your JS code into a function or functions and put them into JS files in your asset pipeline. Take advantage of the move to break your JS into re-usable components that could be used by other methods/controllers.
This means you get all the benefits of the asset pipeline for the JS you move there:
Caching & fingerprinting your JS assets
Minification & compression support to save bandwidth
Minification to obfuscate your code if that is something you want
Concatenation of JS files to reduce the number of requests a browser has to make
Possibility to serve the assets from another location (CDN, web tier vs app tier)
Improved DRYness if that JavaScript is used by other methods/controllers
The drawback? As you've pointed out, any Rails variables have to be passed in as parameters to the functions.
Moving your JavaScript to a .js.erb partial is an option, but if this code is very specific to a particular method or controller then it is not necessarily improving DRYness - it may make your code a little more readable, by separating HTML and JS.

Resources