Tuesday, 8 July 2014

Bootswatches from OSGi fragment

I've only just started using the Bootstrap4XPages plugin.
Obviously one of the first things you want to do is change all the pretty colours, and bootswatches are the easiest way to do this.
Note: In this article use the terms OSGi Bundle and OSGi plugin (or bundle and plugin) interchangeably. they are the same thing.However OSGi fragment is slightly different as you will see.

Bootswatches

To activate a bootswatch you just need to include a css file. Usually you just download it, put it in your NSF resources, and then reference it from your own theme or directly on a page.
Note: This is still probably the easiest way to do it! But I like plugins so I'm doing it the hard way :)

The current bootswatches on the bootswatch website are for bootstrap 3.2.0, however the bootstrap for Xpages plugin I have is still at 3.1.1 so I downloaded the bootswatch from the bootswatch github repository tagged at 3.1.1.
 
Looking through the OpenNTF project for Bootstrap, I saw a comment from Phil Riand about the potential to supply these bootstrap themes as a OSGi fragment.

I have done OSGi bundles I have never done a OSGi fragment, so I was curious just as a matter of  expanding my knowledge.
The full explanation is at the bottom of this post, I figure most people reading this are thinking "yeah yeah just give me the codez", so if you are interested in how the OSGi fragment part works, read on after the good stuff..

I have only done this for bootswatches for version 3.1.1 but this could be done for any version.

This method using the OSGi fragment means that these css files are installed once on the server / client and all served up from the fragment via the bootstrap plugin.

If you run 'tell http osgi ss bootstrap' you can see the relationship between the plugin and the fragment


Check out the source code on my github fork of the bootstrap 4 xpages project


First Install the fragment using the update site. Note it depends on the Bootstrap4XPages plugin
NOTE: I haven't tested the update site yet, it's 12:30am I have to go to bed I'll do more testing tomorrow night

Here are 2 ways to use the bootswatch OSGi fragment


1) Create your own theme in your NSF e.g. 'myapp.theme' which extends bootstrapv3.1.1
within it put a resource tag which points to the relevant css file, using the resource provider url, note the yellow highlighted part is where the bootswatch name is, see the next picture for the bootswatches that are available.



 2) Use (or extend) the themes that I have created in the fragment.
Here i am Extending:

 Here I am using


How does the OSGi fragment work?

OSGi fragments are not plugins in their own right, they attach themselves (like a head crab) to a host plugin.
During the resolving of the parent plugin, it looks for any fragment bundles that wish to be part of the parent bundle. If everything that the fragment bundles depends on is available, then the fragment bundle is accepted as part of the parent bundle, and to the outside world, they are one and the same thing.
The fragment has a Manifest.MF file just like a normal plugin, however this has slightly different entries, and specifies the host plugin that it would like to attach itself to.
Instead of a plugin.xml they have a fragment.xml , and the necessary extensions can be put in this fragment.xml. You can see in the source code I have put an extension for the StyleKitFactory in the fragment.xml file, and during resolving of the parent bundle this will be treated like the plugin.xml file.
You can create a fragment project in eclipse from the Plug-in development perspective, under
File -> New -> Other -> Plugin Developmen -> Fragment Project.

So how does the css get served up? 

Warning following details may not be 100% accurate, take as a guide to explore the source code only!
The extension library that we all know and love has a resource provider which basically says:
If anyone asks for resources with a path that starts with '/xsp/.ibmxspres/.extlib/' then I will provide the resources. 
There is minification and aggregation stuff in there which I haven't learned how to use yet, (so my bundle fragment clearly isn't optimised for production but it is a start!)
You can see in the source code for the main org.openntf.xsp.bootstrap plugin there is a class called BootstrapLoader.

When the Bootstrap plugin is Activated, it registers this BootstrapLoader with the Extension Library's resource provider, and it roughly says:
If anyone asks for resources with a path that starts with '/xsp/.ibmxspres/.extlib/bootstrap' then I can provide the resources.
If you look in the BootstrapLoader's getResourceURL method, you can see that it is configured to intercept resources starting with 'bootstrap', and then look for them within the bootstrap bundle's 'resources/web/extlib/' folder.

So, in our bootswatch fragment bundle, we also have this folder structure, and place our css files in there. When the bootstrap loader looks for resources it will also look in the same directory in the fragment bundle!

Conclusion!
It still is far from perfect, is seems to render differently when runtime javascript/css compression optimization is on, so I need to look into it further, next step is to learn a bit more about the minifier  / aggregation stuff.
Whilst this code/fragment is not quite ready for broad release, you can see what's going on, and hopefully I will get some feedback on some final steps to get it ready for either it's own OpenNTF project or acceptance into the Bootstrap4XPages project


5 comments:

  1. Plugin developers might argue that adding the resources to every application is the "hard way" ;-) But I'm sure we'll all benefit fromt he effort you're putting in.

    On resource aggregation I had similar problems with relative URLs when using Font Awesome. Not sure if the comments on this blog post might help http://xpagetips.blogspot.co.uk/2013/08/five-minutes-to-font-awesome-icons.html. I use a theme and set the relevant stylesheet as rendered based upon context.getProperty('xsp.resources.aggregate').equals('false') or ('true')

    ReplyDelete
  2. Great post Gregor! Bootstrap 3.2 support is coming. The build is ready, just need to wait for IBM to clear it. See also my fork at https://github.com/markleusink/Bootstrap4XPages-1

    On the resource aggregation issue: when a new build of the plugin is created, it replaces the relative links in the CSS files by absolute links. That might also be a good way to do it in your fragment.

    The plugin project contains a Maven POM file to do the build, but that requires a parent POM file and libraries that I don't have access to as a non-IBM-er. So I created a Grunt task to do the replacements. Let me know if you want to have them.

    ReplyDelete
    Replies
    1. Thanks Mark, that would be great to have the grunt task I will have a look and see if I can apply it to these css files.
      I will redo the fragment for 3.2.0 bootswatches

      What do think about the location of this bootswatch project? should it be it's own standalone OpenNTF project? or is it likely to include with the main bootstrap plugin

      Delete
  3. One more thing: I also added a base theme to the new release that loads all the Bootstrap resources, except the Bootstrap CSS file. When it's out, I'd recommend to extend that (bootstrapv3_base) so you don't run into any conflicts with the standard CSS and don't load an additional unnecessary CSS file.

    ReplyDelete
    Replies
    1. fantastic that makes sense I will extend that one

      Delete