Replacing <img> icons with an <icon> tag

288 views
Skip to first unread message

Tom Fennelly

unread,
Jun 27, 2014, 11:51:08 AM6/27/14
to jenkin...@googlegroups.com
Hi.

There's the "Refreshing the Jenkins UI" thread that's been going.  I decided to split out a new thread for this because the other thread has long since become a bit unwieldy.

So I've been playing around with trying to replace raw <img> tags in Jenkins with a new <l:icon> tag.  I did a version that also included doing the actual icons with <div>s + CSS, but after talking to Stephen Connolly I went back and more-or-less started from scratch again.  This time, we dropped the goal of introducing CSS based icons (for now only... that will be in a followup I hope) and instead just concentrated on creating a jelly tag for doing icons.


The new <l:icon> tag in this branch is basically the same as an <img>.  In terms of porting existing scripts to use it, all you need to do is rename "<img " to "<l:icon " (/lib/layout namespace).  In this form (<l:icon src"path-to-icon-image" ... />), the tag simple renders the icon <img> using the 'src' attribute value provided on the icon tag.  This makes it easy to do a basic migration.  

This on it's own is useful (a single point of control for rendering icon images), but of course we also want to get away from using image urls  in the markup and move towards a CSS based approach (with divs etc).  To help us get there, this new <l:icon> tag supports a 'class' attribute.  We purposely chose this attribute name because it matches how we intend using it's value i.e. basically as a CSS class selector... it's value is a set of space separated icon class specs and it will map directly to CSS etc.  Note that the 'class' attribute takes precedence over the 'src' attribute.  In any case, it would not really make sense to specify both.

The following are a few examples of how you'd specify core Jenkins icons, comparing doing it the current way (using <img>s) and the newer proposed way (using <l:icon>s):

<img><l:icon> (using the 'class' attribute)
<img src="${imagesURL}/48x48/warning.png" height="48" width="48" /><l:icon class="icon-warning icon-xlg"/>
<img src="${imagesURL}/32x32/clipboard.png" width="32" height="32" /><l:icon class="icon-clipboard icon-lg"/>
<img src="${imagesURL}/48x48/${it.icon}" width="48" height="48" /><l:icon class="${h.toNormalizedIconNameClass(it.icon)} icon-xlg" />
<img src="${imagesURL}/24x24/grey_anime.gif" alt="" height="24" width="24"/><l:icon class="icon-grey-anime icon-md"/>

Of course you can also just rename the <img> tag to <l:icon> and that will work too e.g. <l:icon src="${imagesURL}/48x48/warning.png" height="48" width="48" />.

As I already said, the 'class' attribute specifies a class spec for the icon you want to use.  "icon-warning icon-xlg" is the extra-large warning icon, while "icon-warning icon-sm" is the small version of the same icon.  The current version of the <l:icon> tag relies on a lookup to convert the class spec to the actual image url.  See the IconSet class if you want more details on that.

The next thing I'm going to look at will be how will this work for Plugins i.e. how will plugins be able to define their own set of icons.  My current thinking is that each plugin will be able to define it's own CSS/Less file for it's icon-set.  So, taking the git plugin as an example, it's logo icon might be done as follows:

Small:<l:icon class="icon-git-logo icon-sm"/>
Medium:<l:icon class="icon-git-logo icon-md"/>
Large:<l:icon class="icon-git-logo icon-lg"/> 

Of course this relies on the plugin author making sure to pick class names that don't clash with other plugins.  That should not be a problem if we follow a simple convention of "icon-[plugin-name]-XXX".

Obviously we don't want Jenkins to be loading potentially 100s of CSS files, so that's where I think Less might come into the picture i.e. use Less to build a single css file for all the installed plugins.  Maybe this could be built into the plugin/update-centre components i.e. each time a plugin is installed or uninstalled we run Less to create the new CSS.  Using a preprocessor like Less should (I think !! ) also mean we can still resolve relative paths (e.g. to a background-image) after preprocessing is complete.

That's it for now... please send feedback :)

Regards,

Tom.

Stephen Connolly

unread,
Jun 27, 2014, 12:22:13 PM6/27/14
to jenkin...@googlegroups.com
I think we are still missing something in letting people backport this to older plugins. So from what I can see in its current incarnation we'd be waiting for plugins to pick up this version of core.

I think there is not much to go to get there. The big blocker in my mind is that you have h.toNormalizedIconNameClass which is a function that would only be present in newer versions of core. 

I think until people see how they can use this in a plugin that works on older and newer versions of core it will be harder to gain traction.

The big win is when every plugin can be updated without forcing all users to update to a newer version of jenkins "just to get the icons using the tag".


--
You received this message because you are subscribed to the Google Groups "Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jenkinsci-de...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tom Fennelly

unread,
Jun 28, 2014, 5:58:51 AM6/28/14
to jenkin...@googlegroups.com
On Friday, June 27, 2014 5:22:13 PM UTC+1, Stephen Connolly wrote:
I think we are still missing something in letting people backport this to older plugins. So from what I can see in its current incarnation we'd be waiting for plugins to pick up this version of core.

Ah yes... I forgot to mention that in the email.  As part of the plugin support, we will provide a "shim" plugin.  This plugin will define what is, in effect, a "proxy" type jelly tag (so something like <icon-shim >) that will check the version of the underlying Jenkins installation.  If the underlying Jenkins is a version that supports the <icon> tag then, <icon-shim> just delegates to that tag... mapping across all the attributes (both tags would have the same "interface").  If the underlying version is an older version that does not support the <icon> tag, then <icon-shim> should just render the icon <img> directly i.e. as icon <img> markup is done today.  You and I also talked about doing a pre-release of this shim plugin.
 
I think there is not much to go to get there. The big blocker in my mind is that you have h.toNormalizedIconNameClass which is a function that would only be present in newer versions of core. 

Right... maybe I shouldn't have used that in the examples :)  In the same way that plugins will not be able to use the new core <icon> tag, then they will also not be able to use anything like h.toNormalizedIconNameClass.  We need to provide alternatives via the shim plugin.
 

I think until people see how they can use this in a plugin that works on older and newer versions of core it will be harder to gain traction.

Agreed... this is the next step... the shim plugin + porting of one of the existing plugins to use it and demo it working on a new and old Jenkins.
 

Tom Fennelly

unread,
Jun 30, 2014, 6:35:00 PM6/30/14
to jenkin...@googlegroups.com
So... the whole idea of the shim plugin got me thinking a bit i.e. was there an alternative that might be a bit easier to manage.  I was wondering why not just put the <icon> tag in a simple taglib of it's own (Vs putting it in Jenkins Core + requiring the shim etc).  

I quickly ran the idea by Kohsuke and he seemed to think it was a reasonable enough idea and maybe was worth a general discussion of it's own i.e. best practices for introducing new layout tags.  So, I just created a separate thread for that: https://groups.google.com/forum/?hl=en#!topic/jenkinsci-dev/YiR-u6wz6lI

Tom Fennelly

unread,
Jul 21, 2014, 10:05:11 AM7/21/14
to jenkin...@googlegroups.com
I was holding off on posting this but decided to post anyway so as to get feedback if possible.

Here's an up-to-date Jenkins core branch containing the new <l:icon> tag + the "shim" plugin (to allow plugins use the tag but still maintain compatibility with older versions of Jenkins):
Here's a branch of the Credentials plugin using the shim:
At present, the shim plugin is in the Jenkins core repo (ui-ext/icon/shim-plugin):
  1. Should it stay there, or must all plugins be in a repo of their own?  
  2. If it stays there, how should it be versioned i.e. in line with Jenkins core or independently?



On Friday, June 27, 2014 5:22:13 PM UTC+1, Stephen Connolly wrote:

Tom Fennelly

unread,
Jul 24, 2014, 10:46:59 AM7/24/14
to jenkin...@googlegroups.com
There a PR for this now: https://github.com/jenkinsci/jenkins/pull/1336

Hopefully we can get it in or just decide to not do it at all... it's been dragging on way too long.
Reply all
Reply to author
Forward
0 new messages