Issue Details (XML | Word | Printable)

Key: CODEBASE-216
Type: New Feature New Feature
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Jonathan Rochkind
Reporter: Jonathan Rochkind
Votes: 0
Watchers: 0
Operations

Clone this issue
If you were logged in you would be able to see more operations.
Blacklight Plugin

Allow code to add JS, CSS, and other HTML head content, in a loosely coupled way

Created: 29/Apr/10 11:47 AM   Updated: 03/May/10 02:22 PM
Return to search
Issue 13 of 28 issue(s)
<< Previous | CODEBASE-216 | Next >>
Component/s: None
Affects Version/s: 2.4
Fix Version/s: 2.5


 Description  « Hide
There are a variety of cases where code living in one place would like to add or modify the JS, CSS, or other head content included in the the HTML blacklight renders. We want it to be able to do so in a "loosely coupled" way, without having to be too tightly coupled to _exactly_ what the current BL HTML is, so it can keep working if the HTML change; so code in a plugin can do this and work if people use a custom BL layout; so code in Blacklight core can keep working even if people chagne their views; etc.

Examples include:
1. Blacklight core code wants to add certain head content to only a particular action. (Coudl be certain JS that only applies to that action; could be advertisement of RSS feed only in #index action)_

2. Local implementer wants to add their own CSS, possibly replacing BL CSS. It should be possible to do this cleanly without having to over-ride large swaths of BL core, and without even having to write a custom layout if you are not ready for that yet or don't need it yet.

3. An extra BL plugin (advanced search?) has views that require certain JS files to be included. This plugin needs to be able to specify that the JS files should be included whenever the certain views are used -- and this should work without needing to assume too much about _exactly_ what the ultimate BL installations views will look like.


PROPOSED SOLUTION

(can be seen in http://github.com/projectblacklight/blacklight/tree/html_head_param )

A Blacklight controller contains instance variables that hold desired HEAD content. These instance variables can be "loaded" with content at the controller-level, or by a view. In the case of the 'controller level', a before_filter is usually the best way to do this -- before_filters can be added to an existing controller in blacklight_config.rb or any other initializer, which will be useful for #2 and possibly #3 above. In the case of a view that wants to assure it's own html head content can be included, this can easily be done using a "capture" block if necessary.

While a single instance variable containing an array of actual HTML content would be sufficient for this, the cases of JS and CSS specifically are going to be common enough that it seemed appropriate to add support specifically for that.

I started out adding these variables/methods to hold head content only in CatalogController, but realized that ALL BL controllers need this logic, because there are certain default CSS/JS that should apply to all controllers, and that it should be possible to chagne for all controllers in a DRY fashion (as for case #2) above. So it ended up in ApplicationController.

See ApplicationController#stylesheet_links, #javascript_includes, and #extra_head_content for the places the content to be added to html head is stored. Also see ApplicationController#default_html_head, set up as a before_filter on all BL controllers, which establishes the initial set of default BL js and css.

The BL layout then calls ApplicationHelper#render_head_content, which takes this information stored in these controller instance variables, and actually renders the head content. NOTE WELL: ANY custom layout should call ApplicationHelper#render_head_content in it's <head> section. By doing this, the custom layout will be compatible with any future plugins (like 'advanced search'), or possibly future parts of blacklight core, that expect to be able to add things to html HEAD. Requriing simply this one helper call to be in a custom layout is a nice easy short clear requirement for 'compatibility'.

Here are the instructions from the rdoc in Application#render_head_content, that show how you can use this setup in various situations such as #1-3 above to modify html <head> as desired.

(doesn't format very readably in JIRA, just see comments above #render_head_content at: http://github.com/projectblacklight/blacklight/blob/html_head_param/app/helpers/application_helper.rb )

<pre>
##
  # This method should be included in any Blacklight layout, including
  # custom ones. It will output results of #render_js_includes,
  # #render_stylesheet_includes, and all the content of
  # current_controller#extra_head_content.
  #
  # Uses controller methods #extra_head_content, #javascript_includes,
  # and #stylesheet_links to find content. Tolerates it if those
  # methods don't exist, silently skipping.
  #
  # By a layout outputting this in html HEAD, it provides an easy way for
  # local config or extra plugins to add HEAD content.
  #
  # Add your own css or remove the defaults by simply editing
  # controller.stylesheet_links, controller.javascript_includes,
  # or controller.extra_head_content. Eg:
  #
  # in an initialzer or other startup file (plugin init.rb?):
  #
  # == Apply to all actions in all controllers:
  #
  # ApplicationController.before_filter do |controller|
  # # remove default jquery-ui theme.
  # controller.stylesheet_links.each do |args|
  # args.delete_if {|a| a =~ /^|\/jquery-ui-[\d.]+\.custom\.css$/ }
  # end
  #
  # # add in a different jquery-ui theme, or any other css or what have you
  # controller.stylesheet_links << 'my_css.css'
  #
  # controller.javascript_includes << "my_local_behaviors.js"
  #
  # controller.extra_head_content << '<link rel="something" href="something">'
  # end
  #
  # == Apply to a particular action in a particular controller:
  #
  # CatalogController.before_filter :only => :show |controller|
  # controller.extra_head_content << '<link rel="something" href="something">'
  # end
  #
  # == Or in a view file that wants to add certain header content? no problem:
  #
  # <% stylesheet_links << "mystylesheet.css" %>
  # <% javascript_includes << "my_js.js" %>
  # <% extra_head_content << capture do %>
  # <%= tag :link, { :href => some_method_for_something, :rel => "alternate" } %>
  # <% end %>
</pre>




 All   Comments   Change History      Sort Order: Ascending order - Click to sort in descending order
Jonathan Rochkind added a comment - 03/May/10 02:22 PM
committed