load images from javascript - grails

In my Grails app, I have a dir web-app/images/carousel/slides that contains files such as:
foo.png
foo.thumbnail.png
bar.png
bar.thumbnail.png
My app is using the resources Grails plugin, and the main images are loaded in a GSP using one of it's tags:
<r:img file="carousel/slides/foo.png"/>
which generates:
<img src="/myapp/static/images/carousel/slides/foo.png">
I attempt to load the thumbnail images from JavaScript by constucting a path such as /myapp/static/images/carousel/slides/foo.thumbnail.png. But when I attempt to display one of these images, I get a 404.
Similarly, if enter the following path in the browser's address bar
http://localhost:8080/myapp/static/images/carousel/slides/foo.png
the image displays correctly, but if I enter
http://localhost:8080/myapp/static/images/carousel/slides/foo.thumbnail.png
I get a 404. Why are my thumbnail images not available at the same path at runtime, given that they're in the same source directory? I suspect the answer has something to do with the fact that the main images are loaded using the resources framework whereas I attempt to load the thumbnails from JavaScript.

You mostly answered your own question: if you don't reference the images using resources in some way, then they don't get processed.
Your best bet is to create a resources module that contains a list of all the images. The add this resource to the page.
// grails-app/conf/CarouselResource.groovy
modules = {
carousel {
resource url:'/images/carousel/foo.jpg'
resource url:'/images/carousel/foo.thumbnail.jpg'
...
}
}
then in your GSP
<r:require module="carousel"/>
Now, the module description is a DSL, so you might be able to use some sort of file loop to automatically add all the files, but I'm not 100% sure how. You also might try something like '/images/carousel/**', but the docs don't say if that would work or not.
Also, I should mention, if you use any of the caching-based resources plugins, this won't help. You will then need to manually call r.img() and set it within your JavaScript, something like this (if it works):
<r:script>
var images = [
'${r.img(...)}'
];
</r:script>
This is because the URLs generated using, for example, cached-resources, are often hashes of the file content to allow for long-term caching. They usually are only indirectly related to the original filename.
Update based on comment below:
To load a common JS remotely, but include the images, you could do something like this. Realize, I don't know your carousel code, and you will almost certainly have to modify the carousel library to handle these changes.
<r:script>
window.carouselImages = [
{
image: '${r.external(url:'images/carousel/image1.jpg'}.encodeAsJavaScript();}',
thumbnail: '${r.external(url:'images/carousel/image1.thumbnail.jpg'}.encodeAsJavaScript();}'
},
...
];
</r:script>
<r:resource url="js/carousel.js"/>
Then in carousel.js you reference window.carouselImages to get your array of images. It also should be possible it flip the order, and use some method within carousel.js to add images, like this:
<r:script>
carousel.addImage('${r.external(url:'images/carousel/image1.jpg'}.encodeAsJavaScript();}', '${r.external(url:'images/carousel/image1.thumbnail.jpg'}.encodeAsJavaScript();}');
...
</r:script>
You can improve this by looping over the file list instead of encoding each image explicitly (and example was given in the JIRA I posted below).
Finally, if you aren't going to use any of the caching or file manipulation plugins (so the files always end up at the same URL), you could just simply loop over the files from within the controller or a service method, calling r.img() on each one. This would ensure that they are copied to the static directory. The return value from r.img() can be ignored.

You can use HTML5's data-* Attribute
<element data-*="somevalue">
Here is an example if your image is located at /grails-app/assets/images:
In page (i.e. index.gsp) you have to add the following:
And from the javascript all you have to do is:
<script>
var calImg = document.getElementById('calendar-icon').getAttribute('data-calendaricon');
</script>
Pretty straightforward, moreover it is a clean approach :)

Related

How can I reference a script that is in my pages directory?

I'm trying to keep a good practice of keeping context together and in that regard, I like how Razor Pages forces you to place your view models next to its view. I'd like to do this with script files as well.
For example, if script is a bit large and is only used on this particular page, it may not be the cleanest thing to have it in a render section in the cshtml. Instead, I'd want to place it into its own .js file. But to keep the project easy to navigate for team members, I'd like to place that .js file in the same folder next to its view and view model. I'm not sure how to link that file, or if I even can. If I give src a path to the file, it is not found. Assuming that's because wwwroot is the only folder setup to host static files.
Suggestions?
You can add an option to the StaticFilesProvider in your Configure method:
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(),"Pages")), RequestPath="/Pages"
});
See the documentation on Static Files in ASP.NET Core: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-2.1

Generate URL of resources that are handled by Grails AssetPipeline

I need to access a local JSON file. Since Grails 2.4 implements the AssetPipeline plugin by default, I saved my local JSON file at:
/grails-app/assets/javascript/vendor/me/json/local.json
Now what I need is to generate a URL to this JSON file, to be used as a function parameter on my JavaScript's $.getJSON() . I've tried using:
var URL.local = ""${ raw(asset.assetPath(src: "local.json")) }";
but it generates an invalid link:
console.log(URL.local);
// prints /project/assets/local.json
// instead of /project/assets/vendor/me/json/local.json
I also encountered the same scenario with images that are handled by AssetPipeline1.9.9— that are supposed to be inserted dynamically on the page. How can I generate the URL pointing this resource? I know, I can always provide a static String for the URL, but it seems there would be a more proper solution.
EDIT
I was asked if I could move the local JSON file directly under the assets/javascript root directory instead of placing it under a subdirectory to for an easier solution. I prefer not to, for organization purposes.
Have you tried asset.assetPath(src: "/me/json/local.json")
The assets plugin looks in all of the immediate children of assets/. Your local.json file would need to be placed in /project/assets/foo/ for your current code to pick it up.
Check out the relevant documentation here which contains an example.
The first level deep within the assets folder is simply used for organization purposes and can contain folders of any name you wish. File types also don't need to be in any specific folder. These folders are omitted from the URL mappings and relative path calculations.

Rails: How to access images in Javascript?

i'm pretty new to Rails and have a little question:
How can i access images in Javascript? SCSS, ERB, ... have methods like "image_path", but i didn't find something similar for Javascript.
I need it to specify the image URLs for the firefly plugin:
$.firefly({images : ['???/1.jpg', '???/2.jpg'],total : 40});
if your image in /app/assets/images/ you can simply use
/assets/1.jpg
Similarly in css, you can use
url(/assets/1.jpg)
You can follow same thing when using in javascript.
$.firefly({images : ['/assets/1.jpg', '/assets/2.jpg'],total : 40});
Note: The above methods will cause problem when your rails app is in sub-directory. In that case use relative path. Asset pre-compilation will compile all assets in public/assets directory. so your structure may be like:
public
-assets
--images
---1.png
--javascripts
--stylesheets
---style.css
so from style.css, you can use relative path like ../images/1.png
When I needed to do this, I inserted the whatever image was required on the page under a div#class and set that class as hidden in my css. Then, in javascript, I could access the image from that div.
May not be ideal solution, but couldn't think of anything else because of asset pipeline.
Also, try accessing image from ./assets/image_name.jpg

Best practices to develop and maintaing code for complex JQuery/JQueryUI based applications

I'm working on my first very complex JQuery based application.
A single web page can contain hundreds of JQuery related code for example to JQueryUI dialogs.
Now I want to organize code in separated files.
For example I'm moving all initialization dialogs code $("#dialog-xxx").dialog({...}) in separated files and due to reuse I wrap them on single function call like
dialogs.js
function initDialog_1() {
$("#dialog-1").dialog({});
}
function initDialog_2() {
$("#dialog-2").dialog({});
}
This simplifies function code and make caller page clear
$(function() {
// do some init stuff
initDialog_1();
initTooltip_2();
});
Is this the correct pattern?
Are you using more efficient techniques?
I know that splitting code in many js files introduces an ugly band-bandwidth usage so.
Does exist some good practice or tool to 'join' files for production environments?
I imagine some tool that does more work than simply minimize and/or compress JS code.
Some suggestions I might add:
keep all your variables in a globally available, multi-structured object, something like: MyVars = { dialogs: {}, tooltips: {} } and then use that across all your scripts
use call or apply methods for dynamically calling custom function names,if you perhaps want to keep the above object lightweight
For tidying things up, you could read this: http://betterexplained.com/articles/speed-up-your-javascript-load-time
This sounds fairly okay too me. Just two notes:
Use descriptive method names. "initDialog_1" doesn't tell you anything about the dialog it initializes.
While keeping JS code split into several files eases development it harms the felt performance of your interface. You could merge all files into one during build/deployment/runtime of your app. How to do it best heavily depends on your environment though.
I'm working on something fairly complex in JS right now, and have been wondering the same thing. I looked at various "module" implementations but while they look "cool" they don't seem to offer much value.
My plan at this point is to continue referencing lots of script files from my .html page (the plan is to only have one .html page, or very few).
Then when I'm building the release version, I'll write a very simple tool to fit into my build process, which will discover all the scripts I reference from the .html pages and concatenate them into one file, and replace the multiple <script> elements with a single one, so that only one request is necessary in the "release" version.
This will allow the compression to work across all the script text instead of on each separate file (like doing tar followed by gzip) and should make a difference to the script download time (though I should stress I haven't actually implemented it yet).
You usually want to keep all of your javascript inside one file. Less HTTP requests is usually better. If you take a look at the jQuery source, you'll notice that every function and property is right there in the jQuery global object:
jQuery.fn = jQuery.prototype = {
init: function(){ ... },
animate: function() { ... },
each: function() { ... },
// etc
}
However, the pattern you seem to be interested seems similar to the "module" pattern. The YUI framework uses this pattern, and allows developers to "require" different components of the library from the core module via HTTP request. You can read more about YUI here:
http://developer.yahoo.com/yui/3/yui/

Actionscript - combining AS2 assets into a single SWF

I have a flash project that I'm trying to export as a single SWF. There's a main SWF file that loads about 6 other SWFs, and both the main and the child SWFs reference other external assets (images, sounds, etc). I'd like to package everything as a single .swf file so I don't have to tote the other assets around with the .swf.
All the coding is done in the timeline, but the assets haven't been imported into the Flash Authoring environment and I don't have time to do that right now (there are too many references to them everywhere). I'm hoping that there's just an option I'm missing that allows this sort of packaged export, but I haven't found anything like that.
I don't have access to Flex or mxmlc (and as the AS is timeline-based, they wouldn't necessarily help me). Any thoughts?
Thanks!
PS...if there's no way of doing exactly what I'm saying, I could deal with having all the assets in a "assets" folder or something like that, so I'd just be toting around main.swf and an assets folder. The problem here is that all the references to the assets assume that they're in the same folder as the main.swf file, so everything's assumed to be local...is there a way to change the scope of all external references in Flash (so, for example, all local references in the code are actually searched in /assets)?
You might be able to decompile your swfs into XML with swfmill/mtasc and use a fancy XSLT to recombine them and recompile with swfmill/mtasc.
If that doesn't work and if you're using MovieClip.loadMovie or MovieClipLoader.loadMovie you can overload their methods and intercept the url:
var realLoadMovie:Function = MovieClip.prototype.loadMovie;
MovieClip.prototype.loadMovie = function(url:String, method:String) {
return realLoadMovie("assets/" + url, method);
}
var test:MovieClip = createEmptyMovieClip("testclip", getNextHighestDepth());
test.loadMovie("test.swf");
You'll need to do some additional string parsing if the urls have a resource-type prefix such as file://
There's a base parameter you can add when you embed the swf, just like align, scale, etc. If base is set, all relative urls will be prefixed with whatever path you define (well, almost all; videos and file reference objects being the exception here).
Other than that, I'd go with nikaji's solution.
HI Justin,
It sounds like you need to look into using shared libraries. Check out:
http://kb.adobe.com/selfservice/viewContent.do?externalId=tn_14767

Resources