I have a Grails plugin which I’m using as basically a container for some shared static resources that will be used by various other Grails projects in-house (CSS, JS files, etc). The idea of using a plugin was just to share these things — the plugin doesn’t really do anything else very interesting. What is the best way to directly reference resources inside the plugin? I’d rather not create custom taglibs, since I’m not really adding any functionality here; I just want access to the resources inside the plugin — something like this, e.g., to reference a CSS file from a GSP:
<g:link rel="stylesheet" url="${resource(dir:'css', file:'mycss.css',
plugin:'myplugin')}"/>
Does this idea violate the concept of plugins, where only certain aspects of it should be exposed, and the rest is a black box? Alternative approaches to sharing static resources among related Grails projects are also welcome, in case I’m headed down an insane, wrong-headed path by even trying this. :)
First, in Grails, a plugin is not considered a black box. To the contrary, all the code is exposed; if you really want to make it a black box, then you should use another plugin, Binary Artifacts.
Secondly, your approach is very sensible. To access plugin resources, I would have created a taglib like:
def res = { attrs ->
attrs.dir=pluginContextPath
//Do whatever you want here
out << g.resource(attrs)
}
and call it the same way as <g:resource>. That way, you don’t even have to expose your plugin’s resources path. The Nimble plugin is using this approach.
Also you might have a look at the Grails Resources plugin, which is trying to handle the nightmare of static resource dependencies among Grails plugins and projects. I have never used it, but for sure in my next Grails project, I will integrate it (BTW, it will be included into Grails 1.4).
Related
I have Liferay 7.2
I want to customize the html of the layout of the widget Documents AND Media
I tried to create a hook to document and media but it seems that is not the right way.
How can i do that?
First, the fact that you're talking about a hook tells me that you're coming from Liferay 6 or earlier. Forget the old module types ("war-style modules"), embrace the new "jar-style modules" or "OSGi modules", which leverage the OSGi methods and mechanisms in the foundation. The new module type that comes closest to the functionality of hooks would be a "module fragment".
Alternatively, if you want to create one module that overrides the JSPs of more than one other module (or overrides JSPs as a side effect to its main purpose), you may want to look into "JSP Bags".
Still, both methods are discouraged and should be taken as a last resort, according to Liferay's "Introduction to Customizing JSPs".
The preferred method would be to use Dynamic Includes (albeit they only work if the target portlet has been written to include inclusion points) or Portlet Filters (which basically allow you to programmatically edit the request to and response from the standard Portlet classes and JSPs).
Still, if you're aiming to replace most of the JSPs of the standard document and media widget (keep in mind: Widgets are still Portlets, they just have been renamed in the frontend), a module fragment still seems to the best way forward.
To identify the correct module, here are the necessary steps. I'll show it using the DLAdmin portlet from the control panel as an example:
Identify the portlet you want to edit: Look into the HTML using the DOM inspector of your browser. Look for section tags with IDs like <section class="portlet" id="portlet_com_liferay_document_library_web_portlet_DLAdminPortlet"> around the area of interest.
Now translate that ID into a package path with portlet class: com.liferay.document.library.web.portlet.DLAdminPortlet. Search for that class in the Liferay github repository. (Go there, press T, enter the class name, find its Java class source file. In case of multiple hits, you need to check the package path, too.)
Once you opened the source file, go back up in the file tree to the parent folder of the src folder. There's a bnd.bnd file. Take a look into it, it will tell you the Bundle-SymbolicName.
Use the Liferay IDE or Blade CLI (depending on your development environment) to create a module fragment for the module identified by the Bundle-SymbolicName.
The idea is not new, like Wordpress, Oxwall : a platform created by some guru guy that allowing other dev guys to add new apps (like forum, blog, market-place, whatever) into the platform easily. By easy, we mean either just install new plugin by upload or less user friendly coding new plugin without changing the core code.
Actually, we have a working solution with angular1 but quite clumsy, that's it, multiple stand-alone ng-app within a website, like:
domain.com/forum-spa
domain.com/dating-app-spa
..etc..
Good thing about it is quite straightforward to implement, not much to worry about lazy-loading. But we are not happy with that approach for many reasons.
Angular2 is really close. We hope it can bring a better solution for building a large web platform
iframe
custom components that are added at build time that are added depending on user data like explained in Angular 2 dynamic tabs with user-click chosen components
This approach is compatible with the offline template compiler
There is also a more flexible way that supports user-provided component templates How to realize website with hundreds of pages in Angular2
This approach is not compatible with the offline template compiler and requires the Angular parser and compiler to be included in the build output.
Right now, I am using <%- assets.js() %> to include all the javascript files on all pages. So, it means all the functions will be initialized on all pages.
I am wondering how can I disable a javascript file on a specific web page? Or, if there is a way to include some of the javascript files on a specific web page but not all the javascript files.
The trouble with the auto-loading is that it's really hard to dictate the ordering of the source files in any meaningful way-- it really comes down to how you've structured the front-end.
In v0.8.x (the version you're working with, from what I can tell), you can use the config/assets.js to control the ordering of folders that get loaded in. This is not ideal, but is a decent workaround that my team used on several projects.
In v0.9, we've removed rigging/asset-rack in favor of tight integration Grunt, which has a large community and some really cool and well maintained packages for most types of asset bundling, etc.
In any case, here are the different approaches you can investigate for serving assets in the new version of Sails.js:
Treat it just like anything else
In your layout.ejs file, create <link /> and <script></script> tags to link in your css and javascript files like you would normally.
Use AMD (Require.JS)
I think lots of folks would say this is actually the best option. Require is a pretty powerful tool. And I'm mostly in agreement-- if you're working with front-end javascript that could be coming from anywhere, and is going to be extended by other developers who may be using a different framework, AMD is a great way to make sure you stay safe. If you're using Require, each js file is its own module, and declares its own dependencies, so asset dependency management becomes a thing of the past. Then in production mode, there are a couple of different options to compile and minify your CSS and JS. You can even dynamically load templates and CSS from JS with Require, which is pretty neat. AMD/RequireJS is a hands-down winner if you're interested in loading some or all of your assets asynchronously. It's also an all-client-side solution, which is pretty cool.
The only downside in my mind is the complexity. If you have control over the framework being used, you really shouldn't have to manually enter dependencies for each file-- it can figure that out itself (see https://github.com/balderdashy/mast/blob/2.x/lib/raise.js)
Use Grunt
When you make a new project with sails new foo in Sails v0.9, a file called Gruntfile.js is created. It has lots of stuff in it, a lot of which isn't being used by default. You can do almost anything with Grunt, but in particular, you'll want to look at how it's set up to copy files from assets/* to .tmp/public/.
sails new foo --linker (Sails v0.9 only)
Linker is a lot like what asset-rack/rigging does currently. It creates the same Gruntfile as #3 above, but utilizes more of the contents. It will auto-link files in the order you specify. Instead of view partials (e.g. <%= %>), the scriptlinker plugin allows you to customize the delimiters where js, css, and templates will be injected. By default, the Gruntfile is set up to use JST precompiled templates, but again, you can set it up however you like.
Hope that helps guys, and best of luck!
-Mike
PS- v0.9 is coming out very very soon, I've just been working through tests and issues to make sure we're 100% there. If you'd like to try it out, check out:
https://gist.github.com/mikermcneil/5930330
The lead for Sailsjs replied to this issue (though it was about selecting CSS files):
"For now, you can (a) bring in all styles all the time and make only the relevant ones apply (b) use another tool (like Grunt) to bundle assets like you would in a vanilla node.js project or (c) link the stylesheets manually (put them in your public folder)."
See: choosing assets sailsjs
Similar, more complex questions have been asked in the Google group:
https://groups.google.com/forum/#!topic/sailsjs/yt9EpJlfzXA
Considering the above, you may want to have a separate layout.ejs for each page. You can specify the layout.ejs you want for each page with
res.view({ layout: "different_layout" })
The layout.ejs would (a) not call assets.js() but have < script > for all the js files needed, or (b) call assets.js() to serve all the common js files in ./assets/js plus < script > to serve the page dependant ones residing elsewhere.
I have a wrapper around assets.js() that allows you to include all assets except for specified files. You can also use it to include only specific assets elsewhere. So you could load your common assets in layout and include other assets only on pages where they are required.
See my answer to How can I include javascript assets selectively in SailsJS?
I'm developing enterprise web application which is using JSF with Eclipse IDE. But i'n not experienced at JSF web application architect, just not familiar with name classes ,projects,packages,web pages, template pages etc.. , is it possible to name packages like following:
CompanyName.systemName.controller (there would be controllers in it )
CompanyName.systemName.Model (there would be managed beans and other things in it )
even how to choose best structure for my project(mean Architecture of folders,classes,packages,web pages, template pages etc). if anyone has an idea ? i'd be glad if have sample project.
thanks
Those are fine package names. Some people like to group packages by purpose:
org.mycompany.myapp.controller
org.mycompany.myapp.dao
org.mycompany.myapp.service
etc...
For larger applications, I like to group them by feature:
org.mycompany.myapp.billing
org.mycompany.myapp.signup
org.mycompany.myapp.webservices
etc...
As for folder structure, a good Maven archetype can be very helpful. Here's a web page that gives a good walkthrough of setting up a few types of JSF projects using Maven archetypes: http://www.javaserverfaces.org/get-started
If you look from architecture point of view, your JSF application should mirror very much like any other well architected Java-Web application.
For packaging I like to break first by functionality (like core, gui) and then by business unit level.
Something like:
com.comp.core.db.beans
com.comp.extension.ui.extension //If my application is going to give extension point for others to implement, extend the functionality.
com.comp.core.ui.controller
On a similar note pages, config files can be broken into separate logical units.
In Community 4.0.a, I'm posting my custom activities in the repo following this: http://wiki.alfresco.com/wiki/3.0_Activities_Developer_Guide
I have defined my own activity type, with custom bundles and pagelink to display custom needs in the activity dashlet.
But I face an issue, I need to specialize the output based on the activity-type in a similar way of what is done already in activity-list.get.js in the specialize() function.
I can't hack the js cause I'm packaging things in my own amp for Share.
What is the best way to do it? Is there some kind of extension point or do I need to override completely the dashlet?
The old way (3.x) to change the behaviour of a webscript controller is to copy the code and overwrite the Javascript by placing it under web-extension: alfresco/web-extension/site-webscripts/org/alfresco/components/dashlets/activity-list.get.js. There you can modify the specialize() function or whatever you need to do.
All files you place in the alfresco/web-extension/site-webscripts folder will replace original files in the share.war WEB-INF/classes/alfresco/site-webscripts classpath. Best practice is to place your customizations in the tomcat/shared/classes/alfresco/web-extension folder so you don't need to modify the WAR file.
Alfresco 4.0 provides a new way to change the javascript controllers of a webscript. You can add additional Javascript code that will run after the original code. This is preferable because you don't need to change original code and you can upgrade more easily later. To use it you need to get familiar with the new Share extension modules concept. See David Draper's Blog for more info on that.