Sunday, August 26, 2012

CSS Recipe for Making Elements Fill Their Container Height

A common desire when designing Web sites is to have a columnar layout, with something along the lines of a sidebar that is visually distinct from the main content, but which fully consumes the space.  This can be surprisingly difficult to implement consistently, and leaves many designers reaching for a background image on the container, even if only solid colors are required.  A more flexible solution is available using CSS and HTML alone (not even JavaScript is required)

Quick Disclaimer

Honestly my single biggest reason for this workaround is that I loathe having to open up a graphics editor for something like this, particularly to only perform a slight adjustment   I'm also neurotic enough that I want the static resources associated with a site to be truly relevant, so that even one file that is conceptually redundant irks me.  This workaround isn't pristine as it throws an element in the HTML which is solely for design purposes, though at this point I'm also increasingly viewing the DOM as the optimal place to pollute in little ways in the interest of keeping other more complicated aspects simple and organized. This solution is also limited to some scenarios.

Also as a quick note I'm writing this in HTML but I'm not doing it in any way orderly since I'm just typing into blogger, so inspect the elements rather than reading the source.

The Problem

Pretend for a moment that this container is a full document body as displayed in a browser
And you want to put another container in it, we'll use a sidebar since it's relevant:
Sidebar Content
But that's no good, so we set the height of the sidebar to be the full height of the container using height:100% and making sure the container is position:relative:
Sidebar Content

Looks good...until

Sidebar Content that is really long and no longer fits in the size that the container was originally assigned to and ends up spilling out of the edge
Now here's where the imagination kicks in, that's broken because the content jumps out of the background (and you can pretend you'd scroll down to view that area that is outside of the container). But not to worry...CSS has you covered, change the height:100% to min-height:100%...then the container will always be at least the full height but will expand to hold its contents.
Sidebar Content that is really long and no longer fits in the size that the container was originally assigned to and ends up spilling out of the edge
Problem solved, and you picked up a new CSS trick. More realistically though the main container will also be sized by percentage so it can scale to fit the visitor's screen (otherwise that's another issue), so we'll add some content to that area and change the height to a relative one.
Sidebar Content
Main content with all sorts of interesting facts that are normally longer than the sidebar content.
Argh...back to square one.

The Solution

So I went back and forth with this issue for a little bit like probably most people have that tried to solve it with CSS alone. Every solution seemed to break when either the sidebar or the content area was larger, or when things happened like the page scrolling. Finally one day I had the forehead smacking realization (and this is where it gets slightly kludgy) why not just do both? Not ideal, but for me still preferable to a background image. When we last left the code it was left in a state where the sidebar would grow to hold the contents, but would not consistently fill the content area. This is more relevant from the DOM perspective as it flows properly, so we can leave that one alone...but then add a second element behind that one that consistently fills the container. For that you need to use an alternate positioning type: the often maligned "absolute" positioning, and in this case combined with constraint based positioning (alternate sizing options would also work). Adding a sibling element beneath the sidebar on the z-index within the same position:relative parent element...with absolute positioning, the same width as the sidebar, and a 0 value for in this case, top, right, and bottom to have it fill up the entire right side.
Sidebar Content
Main content with all sorts of interesting facts that are normally longer than the sidebar content.
So that now checks out...now the other way around:
Sidebar Content that is really long and no longer fits in the size that the container was originally assigned to and ends up spilling out of the edge
Main content with all sorts of interesting facts that are normally longer than the sidebar content.

(Again pretending you would scroll down to see that part overlapping the "window"). And...perfect(ish). So long as your DOM is in decent shape this works like a charm and has been put through the paces on several sites and seems to be quirk-proof in major browsers. This could also be handled by JavaScript on page load. Overall a slightly more complicated solution than a background image and may not be for everyone...but it is likely more maintainable and is also arguably more conceptually accurate than attaching the primary visual representation of one element to a resource associated with another element.

Quick Amendment

I realized after I wrote this that it is missing another piece: that container should expand to hold the sidebar if needed now that it has a relative height. Since the sidebar is presently floated it's not expanding the container. This can be solved by the typical clearfix workaround.

Sidebar Content that is really long and no longer fits in the size that the container was originally assigned to and ends up spilling out of the edge
Main content with all sorts of interesting facts that are normally longer than the sidebar content.

Saturday, August 18, 2012

JavaScript: More than a Scripting Language?

With the help of HTML5 and modern Web development, JavaScript is finally getting regarded as a real programming language.  But is JavaScript really equipped to handle all of its new responsibilities?

Background

JavaScript/ECMAScript has spent most of its life being written by people who learned just enough of it to create simple scripts, and those scripts were then copied and pasted by those who normally didn't know more than how to set variables in those scripts.  Thanks to things like AJAX, jQuery, and modern Web browsers JavaScript is now more powerful, easier to work with, and an essential part of any modern Web application.

There is a relatively new trend of powerful JavaScript libraries and frameworks to create complete applications in JavaScript and allow for MVC style development in the client.  Node.js has even moved this to the server side.

Why JavaScript Rocks

Node.js is a particularly interesting case because JavaScript was chosen not out of a desire to move JavaScript to the server, but because JavaScript had the qualities that were desired: most notably painless support for asynchronous programming.  To be honest, I've been meaning to tinker with Node for a while now, but it keeps getting preempted on my list of technologies to explore.

JavaScript has a lightweight syntax and has evolved to handle asynchronous evented programming better than most languages.  Its dynamic typing, prototypal inheritance, and first class functions can allow for rapid implementation of complex functionality.  JavaScript almost certainly allows for some of the most rapid development of any popular language available (from a language perspective, the platform as a whole is still relatively sparse).

JavaScript is dynamite!...

It can destroy your requirements faster than most anything else...but it can also take your foot along with it.  The most maligned feature of JavaScript is the global namespace.  Rather than go into the features individually, I'll instead use the global namespace as a symbol for the limitations of JavaScript: it allows for faster, worry-free development at the cost of structure.  JavaScript was, as the name suggests, created to be a scripting language written in relatively short snippets to glue other pieces together within a host environment.  The prototypal inheritance and general dynamism further support this: a script could be written to evolve as it executes rather than being designed before hand.  The immense productivity provided comes with an immense danger of writing tangled, co-incidental code particularly if you mix in some temporal concerns due to asynchronicity.

Should you use JavaScript

Whether to use JavaScript can be reduced to the structure vs flexibility debate that flickers around dynamic vs static languages.  From my perspective that question leads to a human factor.  Structure is always needed for a maintainable system and so the variable factor becomes how much of that structure is provided by the language (and supported by tools) vs how much is required to be maintained by developer discipline.  JavaScript is a particularly dynamic language, and therefore places particular onus on the developers to code in away that allows for the application to be maintainable.  As a project and its associated team size grows larger this is likely to become increasingly difficult.  

JavaScript is a great language for small pieces of functionality.  It also provides an attractive and viable option to produce small applications.  As the size of the application grows, however, the dynamism is likely to get increasingly difficult to manage.  JavaScript is therefore best used in manageable chunks within a larger infrastructure.  A single piece of functionality or the analog of the functionality provided by a small mobile app, essentially a single namespace/package, would be a good constraint for the extent of a JavaScript library's reach.   In that context JavaScript is very good at what it does and it should certainly be used (or CoffeeScript).  

The Future

One of the elephants in the room still remains things like prototypal inheritance and first class functions: those JavaScript features that are alien for most developers.  This has led to many people trying to jam JavaScript to behave more conventionally.  Prototypal inheritance is not something that has any momentum, and as much as I hope for wider adoption of first class functions and techniques like high order functions, I think much of that is too abstract to be as digestible as something like object orientation.  The present JavaScript space is a very exciting one and it will provide a lot of useful fodder for the future.  There seem to be fundamental issues with JavaScript, however, and whether it is able to evolve thoroughly and quickly enough to increase its reach beyond small packages and reach a wider audience of developers is still uncertain.  Most importantly the primary focus of JavaScript must remain to continue to serve its present function as well as it does now, which may always be at odds with extending its role.  

Sunday, August 12, 2012

Using Spring Form Binding When the View Resolver Doesn't Support It

Spring form binding is a convenient way to get valid data objects from a user in Spring MVC. If you need to use a View technology other than JSP, however, things may not just work, so here's some information that may fill in the gaps.

The situation

The particular situation I encountered involves using Freemarker for a template language.  Above and beyond just Freemarker I'm also using Spring Surf, so the standard solution (covered below) doesn't apply.  This post covers a direct usable solution that works in a technology agnostic way (aside from Spring) and should at least provide information for other solutions.  

Standard solution and what's going on

The standard means of setting up Freemarker (and other View technologies) for Spring form binding is to add some settings to the view resolver configuration.  Something along the lines of:

<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
   <property name="exposeSpringMacroHelpers"><value>true</value></property>
   <property name="exposeRequestAttributes"><value>true</value></property>
   <property name="exposeSessionAttributes"><value>true</value></property>
</bean>

where the first property does the needed set-up for form binding (the other two merge request and session info into the model).  Tracking this down through the source code this setting is ultimately passed from the view resolver to the AbstractTemplateView (source) which adds a RequestContext to the model (and does the request & session merging).

Re-using that behavior

Unfortunately this is normally re-used through inheritance, and in the case of Spring Surf neither the relevant view resolver nor the AbstractTemplateView class are in the used hierarchy.  It could also be argued that this functionality shouldn't really be handled by the view resolver at all since it is more of an application concern, though I'd see both sides of the possible argument having pretty even weight.  I'd certainly argue that one way or the other it should be made more modular: for speed I resorted to the cut and paste route.

A sensible place to get the Model set up as needed for the View to hook in to it would be right in between when the Controller is done doing it's work and before the View resolver does its resolving.  In Spring this can be done with the postHandle hook of a HandlerInterceptor.  For consistency I've borrowed the same properties/flags as the AbstractTemplateView.  An additional caveat due to being moved before the View resolver is that every request will be intercepted, even those that aren't relevant and possibly don't have a Model such as those handled by a MessageConverter.  An additional null check takes care of that.

A sample interceptor would then be something like (season to taste):

public class RequestContextInterceptor extends HandlerInterceptorAdapter implements ApplicationContextAware {
  private ApplicationContext applicationContext;

  private boolean exposeSpringMacroHelpers = true;
  private boolean exposeRequestAttributes = true;
  private boolean exposeSessionAttribute = true;

  public static final String MODEL_KEY = "springMacroRequestContext";

  public void setExposeSpringMacroHelpers(boolean exposeSpringMacroHelpers) {
    this.exposeSpringMacroHelpers = exposeSpringMacroHelpers;
  }
//...Other setters

  @Override
  public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

  //When using mesage converters or other non model requests
  if (modelAndView == null) return;

  if (exposeSpringMacroHelpers) {
    if (!modelAndView.getModel().containsKey(MODEL_KEY)) {
     //Throw together a usable RequestContext...seems to require ApplicationContextAware-ness
      modelAndView.addObject(MODEL_KEY, new RequestContext(request, response,((WebApplicationContext) applicationContext).getServletContext(), modelAndView.getModel()));
    }
  }

  if (exposeRequestAttributes) {
    //...Code stolen from AbstractTemplateView
  }
  //..Session code stolen from AbstractTemplate View
}

  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.applicationContext = applicationContext;
  }
}

This can then be wired in to Spring:

    <mvc:interceptors>        
        <bean class="com.example.handlerinterceptors.RequestContextInterceptor">
          <property name="exposeSpringMacroHelpers" value="true"/>
          <property name="exposeRequestAttributes" value="true"/>
        </bean>
    </mvc:interceptors>

To avoid conflicts, disable the settings in the view resolver configuration.

For Freemarker there is also a form binding library that is normally automatically exposed for use.  Rather than muck around with getting that working and also because I like to be able to easily reference the source for that file, I opted to just download and use the file as a normal Freemarker import.

And there you have it: guidelines for a usable solution that is more portable than the out-of-box offering or at least some guidance that may help lead whee you need to go.  


Saturday, August 11, 2012

Bouncing Google Play apps onto a Kindle Fire

I'm going to add to the long list of Internet articles that describe installing apps from Google Play (f.k.a. Google Market) onto a Kindle Fire with my adopted approach (which requires another Android device).  This is nothing too interesting but does the trick the minimal effort.

Kindle Fire Notes

I got my Kindle Fire as a gift this past Christmas.  It is a nice little tablet that comes loaded with a version of Android which has been customized by Amazon and does not have the Google framework or applications, and installation of these are not officially supported.  If you are considering purchasing one and stumbled across this post to weigh your options: from my perspective the Fire is a good choice if you're particularly interested in the Amazon-centric offerings (obviously), but you'd be better off with one of the other options for an all-around product (particularly with some of the new offerings in the same price range).  I personally don't use the Fire for much more than reading and at some point I may also tinker with the Amazon flavored Android SDK so Fire fits the bill for me.

Rooting (not required)

You can fairly easily get root access to a Fire and install the Google Framework and Play and any other Android software, there are plenty of sites with instructions.  You could also wipe the device and install a more standard Android distribution.  If you're just looking to install some apps though, it's easier to just install those apps using sideload-style direct installation (my Fire is rooted but Play didn't work immediately and I haven't had a need to spend any time fixing it).

Instructions (the significant part)

Installing most apps is as simple as running the apk package on the device.  The big obstacle is that most apks are only served through stores, so the trick is to get them positioned where the Fire can grab them without a cumbersome process.  I like to keep my devices as self-sufficient as possible and on the day I was looking to install software I was far too lazy to take the walk to my car to retrieve the needed cable to connect my Fire to my computer, so this is also a PC-less method with no cables required.

Step 1. Install app on Android device (on the source device)

Self-explanatory, I have an Android phone with Play install so install the app as you normal would.

Step 2. Stage the downloaded apk in an accessible location (source device)

Getting to the .apk

First you need a way to access the apk and then track it down.  Like most other sites I'll recommend ES File Explorer for a file manager.  I started to poke around to find the file system path to the app I was looking for, but with ES you don't even need to that.  After it is opened bring up the menu and goto Manager->App Manager which will list the installed Apps.  Backup the app you want to bounce to the Kindle and keep track of the directory where the backup will be stored.

Staging the .apk

A simple way to get the package on to the Fire is using a cloud drive/backup type of solution.  Dropbox is a nice widely supported one, which also has an option to download its apk directly so it can be easily installed on to a Kindle Fire with no fuss.  Install Dropbox on to both devices.  Navigate to the directory where you created the backup on the source device in ES File Explorer and bring up the context menu (tap and hold) on the file you want to transfer.  Select "Share" and then "Dropbox" to upload the file to your Dropbox account.

Step 3. Install the apk on the Kindle Fire

You can now just navigate to the file using Dropbox on the Kindle Fire and run the apk to install the application.  So long as the application is compatible (and dependencies are met) there should be no issues and the app is ready for action.

Conclusion

This is yet another recipe for installing apps not available through the Amazon Appstore onto a Kindle Fire.  Very straightforward but could be useful for anyone, like me, who doesn't normally plug their Android devices into their computers.  Another big advantage to the cable-less approach is that this can be easily done asynchronously: if there is an app you'll want to install it can be staged at any time using the source device, and then installed on the Fire any time thereafter.  This is particularly relevant since without Play itself installed on the Fire updates will require being bounced also.  Hopefully this can be of assistance to anyone who is looking for those handful of apps for their Fire that just aren't available on the Amazon Appstore.