jQueryUI buttonsets have a UX problem

jQueryUI is much less popular these days, but it is still used widely. Other UI frameworks have solved many of the shortcomings with it, but switching over to Bootstrap or some other UI framework isn’t always the best option. One thing I have noticed is the buttonsets which can be used to style checkboxes and radio buttons are problematic.  Especially so if you are using a custom (not glossy) theme! It simply isn’t clear what state the buttons are in sometimes.

See the default widget demos for an example:

Icons can help with this but the jQueryUI icons are another sore spot of the framework, and implementing even those icons on buttonsets to indicate button state can be a bit tricky.

A very little custom css seems to go a long way though!

I tested this on a few different OSes and browsers just in case the unicode icon thing might be a problem but it seemed to work well. Even if that were an issue, using a custom font or other content in the content value should work.

Flattr this!

jquery ‘otherable’ widget

HTML select boxes are limited in their usefulness. Often, for quickly filling in forms I need something like a select, but with an other option that allows me to specify the other value. There are various ways I have seen this solved, but I have one I have worked out that I like quite a bit.

Here is a simplistic demo of a transforming select/text input on jsBin

Other ways you could solve it:

  1. Have a separate value to capture the other value. Bonus if you only show that field after ‘other’ value has been chosen, and hide it and clear it if they re-chose with the select… it can be a bit of a chore to keep it all strait and you have to deal with two distinct parameters on the back end as well.
  2. No select, rather some sort of autocomplete on a text input. Works! And only 1 value to deal with on backend, keeping APIs simple. But, not as friendly for users. Free recall is more work with lower accuracy. Plus you probably want to avoid keyboard use on mobile when possible if you are going for speed.
  3. Complicated custom select widget using JavaScript. These can work, and can look nice, but the code for them is bloated and fragile. HTML select works pretty well on mobile. Attempted JavaScript mimics tend not to.

 

Flattr this!

Spreadsheet exports

Spreadsheets as a data export format are just horrible, but clients seem to consistently request it. ButIDontWannaItJustFeels…ComeON!! don’t you know we have a beautiful REST JSON API?!

Sigh…

Okay so at least there is Apache POI to help out.

I made a couple simple utility methods that take a Map of data and either turns it into a spreadsheet or fills in a spreadsheet that you feed it. Not enough code to make into a github project or plugin, but a Gist? yeah sure – here ya go! Maybe you’ll find it useful.

https://gist.github.com/aeischeid/373f9bf68f179027b3f5

As is, it outputs .xls files and you could use the output to render a spreadsheet file. You can also easily make this .xlsx but it requires including a couple more large POI jars.

 

Flattr this!

Crowdfunding Open Source

I know various people who sing the praises of Apple’s OSes in part because of the quantity and quality of apps. Or conversely criticize Linux or to a lesser degree Android because of the lack thereof. I get the pragmatic appeal they are making. But then, referring to the apps, they say things to the effect of, “where I can PAY money to keep them going”, and they lose me a little bit.

Is the utopia of open source yet maintained quality software somehow out of reach, or out of reach on specifically on open platforms maybe, as this type of thinking seems to imply? I don’t think it is, but I am not certain how to explain its overall lack of realization. This isn’t to say open source stuff is bad. It isn’t! I use it almost exclusively, and manage to be mostly productive and not frustrated with it! But, generally speaking, open source options often either don’t exist, are missing some features, or are lacking some polish compared with proprietary options. Even if that is not mostly true it is true often enough to maintain that impression among most people I know who have an opinion on the topic.

I have been glad to see more crowdfunding and such for open source projects. The donation model isn’t new of course, but the ways to do it have certainly expanded and the popularity of crowdfunding in general has exploded. Personally I try to contribute funds for projects that I use, but I always struggle to decide how much money throw in the hat. Should I contribute what I would guess a license for similar software might cost, based on how frequently I use – or would potentially use – it, or based on how much I want to see this missing piece of functionality added to the ecosystem?

With crowdfunding gaining popularity and becoming easier to initiate I have been hoping to see more quality and increasing options emerging on Linux, and that is happening, but it seems slower to happen than I would expect honestly. Maybe another way to say it is that it simply isn’t terribly clear whether there has been an increase in the pace of general development or the willingness to stick around and maintain and refine a project. And if there has, it’s not to the degree I would have expected now that the crowdfunding option has emerged the way it has.

One possible cause is that somehow crowdfunding doesn’t yet feel as legitimate as it should to the type of people who typically fund software development. Many, if not most, people who pay for software licenses barely understand the distinction between open source and closed source software, so in part a failure to jump on the crowdfunding bandwagon isn’t surprising, however, I know a number of tech savvy OS X and PC users who have the philosophy of “I want to financially support developers of good/useful software”, but sometimes it seems like they are only interested in doing that through the license/closed source model, and not so much via the crowdfund/open source model. Like somehow the later isn’t sustainable or doesn’t qualify as legitimate support somehow. Maybe my perception is just off on that, but if not then I wonder what causes/perpetuates that, and I wonder what can be done to get over that and get us closer to software utopia.

Flattr this!

Firefox Propaganda

Overall I think people don’t understand propaganda well, and this leads to the perpetuation of bad journalism among other things. I could go on about that, but suffice it to say there is propaganda out there in the tech press and other places concerning web browsers. I don’t really get the reasoning behind why there is propaganda regarding web browser software… A little, just not well enough to articulate or go into here. Anyway may as well add my voice to the noise.

Reasons I continue to use Firefox as my primary browser.

  1. It is decent software that is constantly improving. On the whole, in numerous practical benchmarks and measures it compares well with Chrome, IE and Safari. Meaning there is no obvious or sweeping practical reasons that serve as justification to sacrifice ideologically superior software.
  2. Ideologically superior software?! Firefox is open source AND the only major browser with development driven by an open community facilitated by a non-profit organization. Consider why companies like Google, Microsoft and Apple may want you to use their browser; why they even make web browser software at all… They do not have your interests in mind, at least not primarily. Their primary interests are necessarily those of the businesses and shareholders who profit from you in some form or another. The fact that their source code is open or that their development happens within public view doesn’t diminish the significance of this fact.
  3. The focus of Mozilla being the interest of their users leads to innovative and interesting projects that stand to directly improve the experience of web users.
    1. Rust: a new language that focuses on concurrency and memory safety. This has more potential to benefit users than the languages and platforms advanced by the other browser vendors. Dart, Go, Swift, .NET, etc. They are all interesting, and not bad or anything, but their primary directions and focuses all seem to revolve around solving business and development problems rather than end user problems specifically.
    2. ASM.JS: making code, especially gaming code, blazing fast in the browser. This vastly expands the scope of products that could be delivered though the web browser reducing the reliance on particular OS’s or vendor specific app stores to deliver such products and services.
    3. FirefoxOS: a whole mobile OS that uses the web platform as the development framework and the web itself as the app distribution model! Mobile OS’s have notoriously delivered a relatively poor web experience preferring ‘Native’ Apps and the App Store model for distribution each for various reasons, but some aspects of this model are inferior and detrimental to users experience comparatively speaking.
    4. Shumway, Firefox’s Sync and WebRTC implementations, PDF.js, OculusRift/3D support, etc…
  4. The focus of Mozilla being the interest of their users leads to standards that tend to center around the benefit to web users and developers in general rather than specific features or functionality that some company or companies perceive as important for their products/users/developers.
  5. A few particular features that may or may not be replicated in options or add ons for other browsers:
    1. Firefox Sync: Passwords, history, bookmarks, settings, etc shared between devices, including mobile versions, in a way that remains completely private! Actually, it looks like Chrome supports a form of this now, but it is opt in. By default Google will be able to see all your data unencrypted. (and that makes sense according to their business model, so I wouldn’t expect that to change.)
    2. Just in time tab loading: I like to have my browser open with tabs in state it was when I closed it. This is convenient for me. However there is usually no need to load the content, and start playing videos or whatever might be on those tabs, until I switch to it for the first time. Besides avoiding annoying videos starting to play on some unfocused tab the just in time option keeps memory, battery, and network uses lower in many cases while improving the start-up experience. It is a small thing that makes a significant difference. Apart from some technical challenge that makes it much more difficult than it would seem to be I genuinely can’t see why the other browsers wouldn’t decide to implement this.
    3. Firefox Hello/built in WebRTC tool: The new chat feature bundled with Firefox just floors me. No sign in or pre-agreed upon shared service is necessary between you and whomever you want to video chat with! Just share a link and go!

Recently there was a post going around about switching back to Firefox from Chrome. Even though it is in favor of Firefox in this instance it is this sort of ‘journalism’ that I find disappointing.

Flattr this!

Grails datePicker magic

Been working much more on the frontend side of web development lately, but found a nice trick in Grails that seemed good to throw out there.

Maybe this is documented somewhere and I just always missed it. I knew the datePicker tag in gsp’s worked nicely for binding to domainClass objects through dataBinding, but didn’t know it could also be used as a super convenient way to get a date object in a controller. This is in grails 2.3 line BTW.

Example:

My use case was a simple report that needed to be run for a given month.

in the gsp:

	
		
		
	

Sweet. That is a really quick way to generate the HTML I want.

Now, here is the really slick part I didn’t know about. In the controller I can access the params.report object and it will be a Date!

def report() {
	def forwardMonth = params.report.toCalendar()
	forwardMonth.roll(Calendar.MONTH, 1)
	forwardMonth  = forwardMonth.getTime()
	flash.message = "${params.report.toString()} -- ${forwardMonth.toString()}"
	...

Flattr this!

Touch Monitors Are On My Wishlist

I think I want touch screen monitors for my work and home desktops. I might be one of the few who still uses a desktop, but my quirky thoughts on the coming obsolescence of laptops as a form factor can be saved for another time.

The appeal of touch monitors is not to replace my mouse or keyboard, but rather to do the things they aren’t terribly great at. For example when I want to re position my cursor from my browser on one monitor to a specific location in my text editor on another, neither the mouse nor the keyboard are able to do this with the level of efficiency that a touch screen enables. To illustrate what I mean it helps to detail the steps a bit.

With the mouse I first have to find the cursor. This is normally not so difficult and there are even tools to help, but it is a task none-the-less. It gets a little worse if the window currently in focus doesn’t have the mouse within its space. Usually what happens is I wiggle my mouse or finger on the track pad and find the movement with my eye. With dual monitor setups this is yet less trivial.  Step two involves navigating the pointer to the next location. Step three is clicking to place the cursor. Step four is placing my hands back on the keyboard to start typing.

With a keyboard there are so many options for keyboard shortcuts and paths to accomplish the task that whatever steps I chose someone could just say, ‘well my [secret hidden] way is much simpler’ and probably be right, but a typical person like myself in a typical scenario as I often find myself in might use alt+tab to select a new window to focus from the list of open windows, and either press that multiple times until they land on the one they want or use arrow keys. In Ubuntu this method uses icons and I have to remember which icon belongs to the program window I want to focus on (text editor). Add two more little steps if I happen to have two text editor windows open so that I pick the right one. Once I get the right window in focus. I hunt down the blinking cursor with my eye and move the cursor with the arrow keys (or in my case nimble well trained fingers with lots of keyboard keys in combination that are faster than using only arrow keys.) to the desired location.

With a touchscreen I could simply reach up and touch the place on the screen I want the cursor to now be at, put my hand back on the keyboard and start typing.

And there are probably infinite combinations of using all three interaction avenues to accomplish the task depending on if it involves multiple windows of the same application, minimized or hidden windows, scrolling to window content that is out of view, tabs within the application, windows on other virtual desktops, etc.

Anyway long boring bit about HCI, but point of it is that I think touch is here to stay because it is a intuitive and useful way of interacting with computers. It has been overplayed so much that I kinda hate bringing up how effortlessly my kids use a tablet, but seriously, they do, and observing them on it is part of why I am thinking about this. Personally I don’t think touch interaction will replace keyboard, mice, or track pads on platforms where those already dominate. Touch screens will merely compliment them very nicely. And as cool as other interaction methods such as eye tracking, voice recognition, or body gesture readers are conceptually, for the near future at least, I see those as only being practically applicable for niche cases whereas touch seems beneficial in many more scenarios. My take away from all these thoughts is probably nothing all that revelatory or novel. It is simply that it doesn’t matter what sort of device you are designing your application GUI for anymore, you need to consider if, where, and how to make it touch friendly because, even if your particular platform doesn’t have touch capabilities now, I guess the odds that it will in the future are increasing rapidly.

trying out zsh and oh-my-zsh on ubuntu

Using the terminal all day I figured I should ‘sharpen the axe’ a bit. I have played around with configuring bash, but mostly I don’t know what I am doing in that .bashrc file. I tried a few ways to get the terminal tab titles to be something shorter so they would actually be usefull for example. no luck there. Tried customizing the prompt to include git status if I was in a git repo. Got that one to sorta work, but screwed up some other stuff in the process…

Noticed zsh is a alternative that has a vocal fan base, thought I’d see if it lived up to the hype. I’ve been using it for a couple months now but so far I think I like it, and I am sure I have only scratched the surface of what it is capable of. which was probably true of bash as well…

Anyway, installing isn’t to hard, but not very obvious so I thought I would document how I did it to see if anyone wanted to chime in on how I did it wrong, or possibly would find it usefull.

First install zsh package from Software Centere or using apt-get install zsh
Use bash terminal one last time to install oh-my-zsh (https://github.com/robbyrussell/oh-my-zsh)
open edit>profile preferences in the terminal menu
on the second tab ‘Title and Command’ check ‘Run custom command instead of my shell’ and enter ‘zsh’ in the text input.
Restart Terminal
Viola!

edit .zshrc as desired.

Grails and Spine.js decoupled development setup

Using Grails as the API server for a spine app and Spine.js as a front end framework has been going well. My Spine app has up till now lived in the web-apps directory of my Grails app. After living with this arrangement for a while I started to realize how separating the two even further would have many all-around advantages. Decoupling code makes new projects easier to manage by isolating versioning, testing, deployment/release for example.

In production environments this sort of setup isn’t all that uncommon, you let Apache or something like it serve static image, js or css files and use mod_jk or some proxy setup to pass the rest on to Java app server like Tomcat.

My setup is a little different in that I want to serve html and js and have to make sure all relative links still work for ajax API requests, and locally there is a cross domain issue if you try to simply work from files in the browser and make calls to Grails running on Tomcat

Long story short; to get my decoupled dev setup here is what I did:

  1. Install Apache
  2. Get it running
  3. Set up virtualhost that will proxy appropriate requests to Grails (need mod_proxy_http)
  4. Add alias definitions for Spine apps

Steps one and two are relatively standard stuff. On Ubuntu it is trivially easy. (sudo apt-get install apache2)

Step 3 was new to me. Searching turned up a good starting point on that, but simply proxy isn’t what I really needed. That brings us to step 4. I needed some interceptors (Alias’) for my spine apps, so that relative links still played nice. For example, I wanted ‘http://localhost/grailsApp/spineApp/’ to direct to my Spine app, while links within the spine app like ‘../api/book/5’ were handled by Grails. an old forum post contained the nugget I was looking for.

Basicially this is what I needed inside of my virtualhost block:

ProxyPass /grailsApp/spineApp !
Alias /grailsApp/spineApp /path/to/spineApp/on/fileSystem

ProxyRequests Off
ProxyPreserveHost On

ProxyPass /grailsApp http://127.0.0.1:8080/grailsApp
ProxyPassReverse /grailsAPp http://127.0.0.1:8080/grailsApp

Grails config will have to change to handle redirects and such in grails controllers, that setting is normally in grails-app/conf/Config.groovy

environments {
development {
grails.serverURL = "http://localhost/grailsApp"
...

Flattr this!

Customized Grails Controller for REST

Update: new code https://gist.github.com/4152409

Grails can do RESTfull easily enough, but I wanted a restful API from grails without throwing out grails scaffolding, So I decided to customize Grails’ controller template.

grails install-templates

then in [app-name]/src/templates/scaffolding/Controller.groovy

import org.springframework.dao.DataIntegrityViolationException
import grails.converters.XML
import grails.converters.JSON

class ${className}Controller {

	static allowedMethods = [list:'GET',
		show:'GET',
		edit:['GET', 'POST'],
		save:'POST',
		update:['POST','PUT'],
		delete:['POST','DELETE']
	]

	def index() {
		redirect(action: "list", params: params)
	}

	def list() {
		params.max = Math.min(params.max ? params.int('max') : 50, 200)
		def list = ${className}.list(params)
		def listObject = [${propertyName}List: list, ${propertyName}Total: ${className}.count()]
		withFormat {
			html listObject
			json { render list as JSON }
			xml { render listObject as XML }
		}
	}

	def create() {
		[${propertyName}: new ${className}(params)]
	}

	def save() {
		def ${propertyName} = new ${className}(params)
		if (!${propertyName}.save(flush: true)) {
			withFormat {
				html {render(view: "create", model: [${propertyName}: ${propertyName}])}
				json {
					response.status = 403
					render ${propertyName}.errors as JSON
				}
				xml {
					response.status =403
					render ${propertyName}.errors as XML
				}
			}
			return
		}
		flash.message = message(code: 'default.created.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
		withFormat {
			html {
				redirect(action: "show", id: ${propertyName}.id)
			}
			json {
				response.status = 201
				render ${propertyName} as JSON
			}
			xml {
				response.status = 201
				render ${propertyName}.id
			}
		}
	}

	def show() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}
		def object = [${propertyName}: ${propertyName}]
		withFormat {
			html {object}
			json { render object as JSON }
			xml { render object as XML }
		}
	}

	def edit() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
			redirect(action: "list")
			return
		}
		[${propertyName}: ${propertyName}]
	}

	def update() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action:"list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}

		if (params.version) {
			def version = params.version.toLong()
			if (${propertyName}.version > version) {
				${propertyName}.errors.rejectValue("version", "default.optimistic.locking.failure",
						  [message(code: '${domainClass.propertyName}.label', default: '${className}')] as Object[],
						  "Another user has updated this ${className} while you were editing")
				withFormat {
					html {render(view: "edit", model: [${propertyName}: ${propertyName}])}
					json { response.sendError(409) }
					xml { response.sendError(409) }
				}
				return
			}
		}

		${propertyName}.properties = params

		if (!${propertyName}.save(flush: true)) {
			withFormat {
				html {render(view: "edit", model: [${propertyName}: ${propertyName}])}
				json {
					response.status = 403
					render ${propertyName}.errors as JSON
				}
				xml {
					response.status = 403
					render ${propertyName}.errors as XML
				}
			}
			return
		}
		withFormat {
			html {
				flash.message = message(code: 'default.updated.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), ${propertyName}.id])
				redirect(action: "show", id: ${propertyName}.id)
			}
			json {
				response.status = 204
				render ${propertyName} as JSON
			}
			xml {
				response.status = 204
				render ''
			}
		}
	}

	def delete() {
		def ${propertyName} = ${className}.get(params.id)
		if (!${propertyName}) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.found.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json { response.sendError(404) }
				xml { response.sendError(404) }
			}
			return
		}
		try {
			${propertyName}.delete(flush: true)
			withFormat {
				html {
					flash.message = message(code: 'default.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "list")
				}
				json {
					response.status = 204
					render ''
				}
				xml {
					response.status = 204
					render ''
				}
			}
		}
		catch (DataIntegrityViolationException e) {
			withFormat {
				html {
					flash.message = message(code: 'default.not.deleted.message', args: [message(code: '${domainClass.propertyName}.label', default: '${className}'), params.id])
					redirect(action: "show", id: params.id)
				}
				json { response.sendError(500) }
				xml { response.sendError(500) }
			}
		}
	}

}

then modify your UrlMappings.groovy file to look something like this:

class UrlMappings {

	static mappings = {
		"/$controller/$action?/$id?"{
			constraints {
			// apply constraints here
			}
		}
		name api0: "/api/$controller/$id"(parseRequest:true){
			action = [GET: "show", PUT: "update", DELETE: "delete"]
			constraints {
				id(matches:/\d+/)
			}
		}

		name api1: "/api/$controller"(parseRequest:true){
			action = [GET: "list", POST: "save"]
		}
	}
}

I found the JSON Restful plugin a while after I already did most of this, so that is another way to go. Other than it having some issues in grails 2 right now it looks like a really good option, but one thing I like about my approach is that if you want to customize your API in fine detail you can do so. You can always generate individual controllers and modify them of course. Another option is registering custom marshallers. The simple example for customizing your JSON output without changing any controller code would be doing something like this in your Bootstrap.groovy

import grails.converters.JSON
class BootStrap {
  def init = {servletContext ->;
    JSON.registerObjectMarshaller(Person) {
      def returnArray = [:]
      returnArray['name'] = it.name
      returnArray['addrs'] = it.addresses
      return returnArray
    }
    ...
  }

...

Flattr this!