Simon Palmer’s blog

August 30, 2010

Customers as advocates

Filed under: Uncategorized — simonpalmer @ 2:32 pm

Bit of a shameless plug, but I really like the work that’s coming out of our social media team.  GoRecommend started as a tactical integration point so our customers could track, and to some extent guide, where their brands ended up in Facebook following shopper taking a survey about customer experience.

The positioning of a brand is a delicate process which is jealously guarded and heavily invested by companies who care about how they present themselves to the world – which is pretty much every company.  The fact that, driven by loyalty, and perhaps unfettered by it, shoppers can question, criticise, re-position, evangelise, advocate your brand in a selection of forums with enormous networked readership means that the power balance between companies and their customers has changed.  This scares the willies out of most marketing departments and is the sort of discontinuous change that, unless embraced, could spell disaster.

On the other hand, what if you could properly embrace it?  What if you could understand and watch what people are saying?  Done badly it is Orwellian interference, done well it is game-changing connection to your audience and customers.

Enter GoRecommend.  We’re at the friendly fun end of understanding what shoppers are saying about brands.  We provide the infrastructure to make a positive message easy and a negative message contextual and beneficial – after all how can a brand improve unless it listens to its critics?  We’ve extended out beyond Facebook and into Twitter and email and are getting a huge amount of market traction from our customers who are excited and slightly bewildered by the implications of social media.

Come take a look…

http://gorecommend.net/

Advertisements

August 11, 2010

How do you add a comment field to a list in Sharepoint 2003?

Filed under: Sharepoint — simonpalmer @ 4:57 pm

I want to add a field to a list on a Sharepoint 2003 meeting site which allows for multiple comments against an item, including who posted the comment and when.  Should be easy, right?  Well it is, but there are a couple of things you need to do and it’s not exactly obvious.

I was expecting that a comment field would be a specific type, since there are multiple comments by different authors against a single list item, so a one-to-many relationship between list item and comment – at least that’s what the techy wonk in me was saying.  When I couldn’t find that I was baffled and spent a long time reading the Sharepoint help and Googling and StackOverflowing, all to no avail.

Turns out the solution is far simpler…
1) switch on versioning for your list
2) create yourself a multi-line text field on your list
3) call it “Comments”
4) show it in your favourite view

The versioning is what gives the impression of a one-to-many on the comments and there is some styling on the standard item view which shows the versions as a comment trail, which is nice.  I suppose versioning is a one-to-many on the list item ID, which is equivalent for my purposes.

Seems like a silly simple set of steps now I know it, but was frustrating while I didn’t know it and if this page gets crawled by Google then the obvious search will yield a result for the next poor individual.

August 9, 2010

OnStartups, HubSpot, MadMen etc.

Filed under: Uncategorized — simonpalmer @ 4:41 pm

I read this OnStartups post with interest and tried to figure out my mixed emotions.  Here were my emotions:

Envy… frustration… annoyance… realisation… blog libido

So here I am blogging about it.

I recently joined a great company just outside Toronto (locally referred to as TO) and one of the first issues I face is getting a handle on where from, and how, we can attract talent into our business.  We have a great proposition, a great workplace atmosphere, a great customer list and a great set of backers.  Still, we struggle to attract technical talent from the pool available in the GTA (Greater Toronto Area for those of you outside Canada).

The GTA contains a large number of potential people and some great schools (Waterloo, UofT, Ryerson, McMaster to name but a few) turning out bright grads, docs etc.  It also contains some very different working and living environments, from Waterloo/Kitchener in the West to Markham in the East and Richmond Hill and Thornhill in the North.  And then there’s downtown Toronto, which is a vibrant international city with a diverse cultural and intellectual mix.

Basically there’s something for everyone, and you would think that in an environment like that a company like ours ought to find it easy to attract talent.  But we don’t.  In fact it is devilishly difficult to get a good stream of people into the front of our recruitment pipeline and I have been looking at why.

At this point I need to say that we are in West Mississauga (click for a Google map) which is not in Toronto. The GTA also has the worst traffic of any city I have lived in – by a long margin.  There isn’t really an alternative to a car for a lot of journeys and Toronto also sits on a major Canadian artery running East-West across the country, HWY 401.  Put this all together and if you are travelling into TO with the rush hour traffic, or out again, you can set aside a minimum of an hour in the car each way, and much more if there is any sort of traffic congestion, such as roadworks or accidents.  There are always roadworks and accidents.  I can’t understate how bad the traffic can be.

So, after a number of conversations with local recruiters I was in the process of accepting the obvious, which is that our location is the reason why we can’t mine the rich seam of talent that clearly exists around us.  I was also looking at the feasibility of an office downtown or in the K-W area to drop ourselves into the middle of the melting pot.  This is risky and expensive if it doesn’t work, so I’m not apologizing for thinking carefully about it.

As I did so I realised I was looking at location in the wrong way, it isn’t the cause any more than salary, package, working environment or technology choices are the cause.  In fact all location does is place another constraint, just like all those others, on the sorts of people who may be interested in working for us as a business.

Then the OnStartups blog post emerged and my cycle of emotions kicked in and this is where I got to.

I reject the notion that all good tech companies must, by definition, be staffed by young people, and that you have to create a workplace which panders to their very specific social needs.  In fact, those exact same people grow into mature adults with kids and a different set of needs.  As that happens none of their talent goes away – in fact it is augmented with experience and broader skills which make them more valuable, not less.  Why do they have to go from a loft downtown to a scrapheap in the suburbs?

So I wondered, what does the adult version of that set of (non-)policies in the OnStartups post look like?  I ask partly because this is a tier of the workforce that these sorts of businesses are clearly ignoring and partly because I am a crotchety old 40-something who resents the notion that all the talent exists below a tree-line which ends at 29, and I secretly harbor the notion that they are actually a bunch of  lazy and self-possessed children who have had very easy lives and think that the world owes them something.  Plus none of them have yet proven much.

If we can’t attract the kids to Mississauga because they are drinking beer and playing foosball downtown, then what about them in 5 years time when they have succumb to their girl/boy/friends and have moved out to a house with a minivan, a dog, a school round the corner, a back yard and 2 years of 3 hours sleep a night?  They are the same talented people but they don’t work as long and they care about a more structured set of policies on vacation, working hours, etc.

They may also have been dumped unceremoniously out of Utopia.com because the fancy office couldn’t be paid for out of revenues and their financiers called in their warrants when the hockey sticks turned out to be wooden spoons.  So they are more realistic and perhaps less productive – but they carry all the skills and talent, and they can’t all be managers.

I wonder what an ideal workplace and set of policies looks like for them…. (being provocative)… I want to create a “post-juvenile culture”

  1. Vacation policy = closed for Christmas
    …and 2 weeks in August
  2. We care which 37.5 hours a week you work
    …because we think you should spend quality time with your kids, because they’ll be happier and you’ll be happier, more loyal and will work harder while you are here – plus experience tells us that you’ll probably do better if you are mostly here – which aligns with the Agile manifesto which we espouse in reality, not in theory.  And we also know that a motivated, but otherwise committed, person like you will do whatever is necessary to make yourself, and us, a success.
  3. Extreme filtering
    If you want to know what’s going on in the heads of management come and ask.  We don’t want to blur your very busy, and slightly shortened, day with a load of irrelevant information for decisions in which, ultimately, you are unlikely to have much say.  It’s not because we are trying to hide anything, and where legally permissible we’ll fully disclose.  Instead it’s because there is always a strata of information which matches your role and makes you more effective, and a whole load of other stuff which is largely irrelevant to you – and we understand that and see it as part of our role to protect you from it
  4. Some doors policy
    We acknowledge that there are moments when you deserve some privacy to talk about things which are important to you.  As management we face this every day and don’t want you to feel like you have to air your dirty laundry with us as we sit between two developers.
  5. Free breakfast
    You probably squeaked out of the house with no time to grab a bite, come and have it on us at your desk
  6. Free beer
    Once a month at a bar/restaurant.  We’ll help you organize a babysitter and either a DD or a taxi home.  Please don’t drink in the office and drive home.
  7. Partnership with a local crèche and daycare
    We understand that the biggest challenge you face with young kids is what to do with them while you maintain some momentum in your career and how you deal with finding good quality care that you can both trust and afford.  You may not have a fancy office and a really great healthcare plan, but we’ll help with childcare costs – especially beyond the hours that the providers normally offer.  That means you don’t have to feel like you have to rush away at 2.30pm to drive the 45 minutes to daycare to pick up the kids while you do two conference calls on your earpiece in the car and wonder how long it’ll be before it becomes a career limiting issue.
  8. Social media policy = whatever
    Really, we care as little as you do
  9. Dress code = be respectful
    We are a professional organization and you are a professional person, your attire should reflect that.  We also have customers in the building on occasions with whom you will have worked very hard to establish the professional credentials of yourselves and our business.  We know you would not jeopardize all that hard work by dressing inappropriately.

That’s as far as I got before I realised that it was compelling enough to make a very nice workplace proposition in its own right.  I’m actively pressing this agenda with the people we think we would like to attract.  I’m also pursuing it internally to see how practical we think it would be for us as a business – we have to balance this agenda against our commercial business objectives – which are always missing from this sort of discussion.  I like it because it doesn’t necessarily mean we have to get a loft downtown to attract the talent – some of it is probably living within 20 minutes in the car, we just have to find it.

March 21, 2010

*Really* simple S3 persistence from Grails

Filed under: code, Grails — simonpalmer @ 10:16 pm

I recently posted about really simple file upload in my app and once I had that working I moved onto my next problem, which was in two parts, 1) making the persistence location flexible – and scalable – and 2) providing a public url to the images.

Taking the second problem first, I thought I was going to need to find some clever way of mapping a URI to a folder on the server and I investigated about 25 ways of doing that in tomcat, jetty, apache, and anywhere else I thought might work. There are solutions, but they normally mean an additional web server and subdomain, or some such configuration, to serve static content. There is also a grails plugin for serving static images. All of this felt like a lot of infrastructure and complexity, not to mention server load, which runs against my basic “do it elsewhere, not on the server” philosophy.

For the first issue (scalable persistence) I looked at where in the standard AWS AMI I was using I could place content and the choices are limited because I wanted sub-folders for each of my users and giving rights to processes on the server instance to create folders was also looking like a lot of non-standard config.

In steps Amazon S3. The solution is really very simple. Sign up for an AWS S3 account, create a bucket with a unique name for the app, add buckets for each user (they already have a UID to identify them) and back the asynchronous upload with a simple write to S3 from my controller. If you make the assets publicly readable then you can expose them through the regular s3.amazonaws.com url and you don’t need any other server infrastructure for your static file serving (*jumps up and down with glee*). Of course, there’s a Grails plugin for S3, so that’s where I started, and before I go much further I should say that I think that does the job very thoroughly and you should try that before you take my hack – at the very least download the code and study it closely, it is well written.

But… I didn’t want to involve my database and my file system in the upload process and I never anticipate needing a background process for doing the upload to the buckets, so it was breaking my self-imposed KISS rules.

So, “how hard could it be”? Here’s how.

First it is a good idea to grab the Jets3t library, which is brilliant. I found the install all a bit weird, but there is a jar file in the jets3t-XXX/applets folder – at least there was in the download I grabbed – and you basically need to stick that in your lib folder under your Grails app. If you are using the STS Eclipse plug-in you’ll need to add the jar as an external library to your project properties to have it compile, run, work, etc.

It’s a good idea to write a Grails Service for this, so you start by doing that

grails create-service AmazonS3

And here’s the code for the service… this is admittedly very simplistic and it needs some error handling, but you’ll figure that out…

import org.jets3t.service.S3Service
import org.jets3t.service.security.AWSCredentials
import org.jets3t.service.impl.rest.httpclient.RestS3Service
import org.jets3t.service.model.S3Bucket
import org.jets3t.service.model.S3Object
import org.jets3t.service.acl.AccessControlList

class AmazonS3Service {
	
	static String accessKey="PUTYOUROWNONEINHERE"
	static String secretKey="PUTYOUROWNONEINHERE"
	static RestS3Service s3 = new RestS3Service(new AWSCredentials(accessKey, secretKey))
        boolean transactional = false
	String rootBucketPath="yourbucket/subbucket/whatever/"
	String defaultBucketLocation=S3Bucket.LOCATION_EUROPE
	
	Map mimeExtensionMap = [
			"png" : "image/png",
			"jpg": "image/jpeg",
			"gif": "image/gif",
			"tiff": "image/tiff",
			"pdf": "application/pdf",
			"mpeg": "video/mpeg",
			"mp4": "video/mp4",
			"mov": "video/quicktime",
			"wmv": "video/x-ms-wmv",
			"html": "text/html",
			"xml": "text/xml",
			"mp3": "audio/mpeg",
			"flv": "application/octet-stream"
	]
	
	S3Bucket makeBucket(uid)
	{
		S3Bucket bucket = s3.getOrCreateBucket((rootBucketPath + uid), defaultBucketLocation)
		bucket.setAcl AccessControlList.REST_CANNED_PUBLIC_READ
		return bucket
	}
	
	void put(inputstream, name, uid, ext, length)
	{
		if (mimeExtensionMap.containsKey(ext.toLowerCase()))
		{
			String mime = mimeExtensionMap[ext.toLowerCase()]; 
			S3Bucket bucket = makeBucket(uid)
			S3Object up = new S3Object()
			up.setAcl AccessControlList.REST_CANNED_PUBLIC_READ
			up.setContentLength length
			up.setContentType mime
			up.setDataInputStream inputstream
			up.setKey name
			up.setBucketName bucket.getName()
			s3.putObject bucket, up
		}
	}
	void putXML(text, name, uid)
	{
		String mime = mimeExtensionMap["xml"]; 
		S3Bucket bucket = makeBucket(uid)
		S3Object up = new S3Object(bucket, name, text)
		up.setAcl AccessControlList.REST_CANNED_PUBLIC_READ
		up.setContentLength text.length()
		up.setContentType mime
		s3.putObject bucket, up
	}
}

This gives you a single API entry point (well, two, put and putXML) and will give you read-only assets on your S3 bucket that follow this sort of path…

yourbucket/subbucket/whatever/an-identifier-of-your-coice/image1.jpg
yourbucket/subbucket/whatever/an-identifier-of-your-coice/image2.jpg
yourbucket/subbucket/whatever/an-identifier-of-your-coice/image3.jpg
yourbucket/subbucket/whatever/82757c2a-cfa9-49bf-89fa-9efdaf9bf418/image1.jpg
yourbucket/subbucket/whatever/82757c2a-cfa9-49bf-89fa-9efdaf9bf418/image2.jpg
yourbucket/subbucket/whatever/82757c2a-cfa9-49bf-89fa-9efdaf9bf418/image3.jpg

These can then be got at via urls which reference these buckets via the normal s3 url…


To call this from a controller used to manage the asynchronous file upload you just need to know about one thing, which is how to get from a Spring MultipartFile to something which the JetS3t API can consume.

def amazonS3Service;
def uploadfile = {

	if(request.method == 'POST') 
	{

		Iterator itr = request.getFileNames();

		String vloc = "";
		while(itr.hasNext()) 
		{
			MultipartFile mpFile = request.getFile(itr.next());
			if (!mpFile.isEmpty()) 
			{
				// success
				String _file = mpFile.getOriginalFilename().replace(" ", "_");
				vloc += h.uid + "/" + _file;
				String ext = _file.substring(_file.lastIndexOf(".")+1);
				amazonS3Service.put (mpFile.getInputStream(), _file, h.uid, ext, mpFile.getSize())

			}
		}

		render vloc
	}
}

Basically mpFile.getInputStream() will give something which can be sent directly to S3 without being persisted to the local file system – which is what pretty much every other example I came across does. A couple of things to point out at this point, first is that h.uid is not visible in this code, it is just a unique value I ascribe to each user in my system and you should choose your own. It forms the rightmost bucket name in my S3 key structure. Second is that I use the file name as the key and I modify it to replace the spaces with underscores to avoid any nasty problems with filenames.

Eh voila, you have static image persistence to an almost infinitely scalable server infrastructure (at reasonable cost) and serving via the cloud. Normal caveats apply, and this is far from perfect code, but it works and I hope it helps you get started.

March 12, 2010

*Really* simple Mail service for authsmtp in Grails

Filed under: code, Grails — simonpalmer @ 2:37 pm

OK, after A MONTH of trying to figure out how to get the Grails mail plugin to talk to authsmtp, and *utterly* failing, in a puddle of tears this afternoon at my 1,745th attempt at finding out anything about this on the web, I went into deep hack mode and cracked it in 15 minutes flat.

The answer… write my own f*!%$ing email service.

If you can bear to read to the end I have a bigger Grails lesson, but here’s the solution for any poor person who may be following me down this path.

First off, why AuthSMTP.com? Well, in a production envronment, for a real world application which is going to be generating email in response to user actions (such as notifications), then your gmail account will not cut it and your local ISP will almost certainly block the IP address of your server – especially if you deploy into the cloud at either Google or AWS. That means you have to have a real SMTP host to take care of the relaying and send. AuthSMTP is one of many out there, but their pricing policy is reasonable and they are production strength. I have used them for personal accounts for POP3 and they have been good, although their technical support demonstrated the worst sort of brainless responses possible and was deeply disappointing.

So, following the mantra which got me here, of “how hard can it be?”, here’s the answer…

First off go to your grails prompt and create a service with a name of your choice using

grails create-service Mymail

Next in the scaffolded code, put the following – I decided that I would just use old fashioned Java since I sort of felt I know what I was doing and I am still not comfortable enough with Groovy that I would risk chasing my own stupid errors for another month.

import java.util.Properties;
import javax.mail.internet.*;
import javax.mail.*;

class MymailService 
{
    boolean transactional = false

    public boolean sendMessage(String to, String msgSubject, String msgText) 
    {
		String host = "mail.authsmtp.com";
		String username = "ac99999"; // your authsmtp username
		String password = "xxxxxxxxxx" // your authsmtp password
		String from = "no-reply@yourdomain.com";
		
		Properties props = System.getProperties();
		props.put("mail.smtp.host", host);
		props.put("mail.smtp.user", username);
		props.put("mail.smtp.password", password);
		props.put("mail.smtp.port", "2525"); // thish is the port recommended by authsmtp
		props.put("mail.smtp.auth", "true");
				
		Session session = Session.getDefaultInstance(props, null);
		MimeMessage message = new MimeMessage(session);
		message.setFrom(new InternetAddress(from));
		
		InternetAddress to_address = new InternetAddress(to);
		message.addRecipient(Message.RecipientType.TO, to_address);
		
		message.setSubject(msgSubject);
		message.setText(msgText);
		Transport transport = session.getTransport("smtp");
		transport.connect(host, username, password);
		transport.sendMessage(message, message.getAllRecipients());
		transport.close();
		return true;
	}
}

It’s worst fault is that the thread waits for a response form the server and I confess the error handling could be added improved, and OK, you can’t attach files and you can’t send to multiple recipients, although adding that would be really simple, and you can’t do back-flips and set properties on the fly and blah blah. BUT… you can send a basic message from one email address to another, which I am betting is what 99% of automatically generated email does.

Now for the lesson, and look away if you have already been baptised by a Grails evangelist. The conclusion I am quickly coming to is that all the benefit I got on the swings of a rapid start with Grails I have more than lost on the ugly, nasty, dizzying, vomity, downright dangerous roundabout of debugging it when something doesn’t work.

Even having gone as far as downloading and installing the STS Eclipse IDE – which remains the slowest piece of software on my desktop by a factor of 5 – and figuring out how to actually debug a session, stepping through the code I found myself in a completely impenetrable marass of codeless call stacks as deep as the mariana trench. It remains about as bad a development experience as I have had in the 20-some years I’ve been doing it. The only worse thing is the silent fail of a Javascript library as the browser refuses it. It’s about time the browser was replaced with something better, but that’s a whole other rant.

March 5, 2010

*Really* simple asynchronous file upload in Grails

Filed under: code, Grails — simonpalmer @ 4:11 pm

I spent ages trying to decide which was the best way for me to implement file upload in my grails app. What I wanted was the ability for a user to select an image from their local machine and for it to be uploaded into a tag on my page. The biggest issue I faced was that the upload button, and in fact the whole DIV that contained the image and other stuff, is generated at runtime. The other mandatory condition was that it had to happen asynchronously and without re-loading the page.

I tried out 3 or 4 solutions, including several grails plug-ins (google for “grails file upload” and you’ll find them), several ajax javascript solutions, which I have now lost, and a couple of Flash uploader implementations. The trouble with all of them was a combination of complexity and size. In the end I found a really simple alternative which seems to work just fine and builds on adding the Grails UI plugin into my application.

My solution was in two parts, first was to give myself the ability to have a modal dialog box on my page and second was to utilise the Yahoo GUI library to make an asynchronous connection back to the server.

The modal dialog came directly from the Grails UI plugin, which has a very rich set of excellent features and I recommend it. Installing that plugin gave me a dialog box, which was as simple as including a resource reference and a GSP tag in a hidden div on my page…

        <gui:resources components="['dialog']"/>
        <div>
            <gui:dialog
                id="dlgFileUpload"
                title="Upload Image"
                draggable="false"
                modal="true"
                buttons="[[text:'Upload', handler: 'onUploadButtonClick', isDefault: true],[text:'Cancel', handler: 'function() {this.cancel();}', isDefault: false]]">
                <form action="uploadfile" enctype="multipart/form-data" method="post" id="uploadForm">
                <input type="file" name="testFile"/>
                </form>
            </gui:dialog>
        </div>

The important thing to notice in here is that the dialog box contains a form which defines the multipart enctype, the method as POST. The action refers to the code in my Grails controller which handled persistence of the file. The gui:resources tag is exploded by Grails into a set of script includes for the Yahoo UI libraries. This is important because the YUI library is very large and there are many interdependencies, and this single tag hides all that, which is a major time saver.

The other thing that the Grails UI plugin gave me was the whole of the YUI library, so the next bit was to write some code to handle the file upload itself. Rather than lots of fancy components I realised that I could just use the YAHOO.util.Connect object to make an asynchronous call back to the server, in much that same way that I might otherwise have used an XMLHTTPRequest object in Javascript. Because the whole YUI library is included with the plugin I already had the code. To get at the Connect object I had to include the appropriate script because the gui:resources tag seemed not to add it as a dependence…

        <script type="text/javascript" src="/js/yui/2.7.0/utilities/utilities.js" ></script>

From that point it was a simple matter of writing a function to handle the click on the upload button in my dialog which made the request back to the server, and handled the response…

        function onUploadButtonClick(e)
        {
            var uploadHandler =
            {
                upload: function(o)
                {
                    refreshActiveImage(o.responseText);
                    setDirty();
                    hideWaitCursor();
                }
            };
            showWaitCursor();
            //the second argument of setForm is crucial,
            //which tells Connection Manager this is an file upload form
            YAHOO.util.Connect.setForm('uploadForm', true);
            YAHOO.util.Connect.asyncRequest('POST', 'uploadfile', uploadHandler);
            this.cancel();
        }

The important thinhg to notice in here is that the setForm call requires the second argument to be set to true so it recognises the form settings for the POST. Otherwise, the two lines of code invoking YAHOO connect do everything you need to send a file back to the server.

My server side code processes the multipart file upload and persists the file into Amazon S3 (see my other post about that). I then render the file as a virtual location relative to the current page back into my page so I can simply update the src property of the right IMG tag on my page – that’s what refreshActiveImage(o.responseText); does.

Eh voila! A common plug-in, a great utility library, some really basic Javascript and a form and I have the simplest file upload I could imagine.

March 2, 2010

Hallelujah. Code formatting in my wordpress blog!

Filed under: code — simonpalmer @ 10:15 pm

How did I not know about the Sourcecode tags? I have spent years trying to figure out how to post nice looking code to my blog and was misled by all the plug-in nonsense which only applies if you are hosting your own wordpress instance – which I’m not. Here is the link to the docs for formatting source code in your wordpress.org or wordpress.com hosted blog.

I’m a bit disappointed that there is not an HTML language definition, but that’s OK, I write XHTML in any case so XML works just fine.

function makeRooms(edit)
{
	var t = getTag("roomsBody", "div");
	if (t != null)
	{
		var div = "<div id='rooms'>";
		
		//if (rooms === undefined) rooms = [];
		for (var i = 0; i &lt; rooms.length; i++)
		{
			if (edit)
			{
				div += makeRoomDivEdit(rooms[i], imgpath, i);
			}
			else
			{
				div += makeRoomDiv(rooms[i], imgpath);
			}
		}
		div += &quot;</div>";
		if (edit) div += "<a style='padding:5px;' class='instruction' href='addRoom()'>Add Room</a>";
		t.innerHTML = div;
	}
}

Styling grails-ui elements

Filed under: code, Grails — simonpalmer @ 10:05 pm

The grails-ui plugin has a very rich feature set, being based on the Yahoo’s YUI library.  I have been trying to avoid it, but eventually I have caved and I need a modal dialog box for my web page.  I say caved because I think that it is not an intuitive element of a web application and there are enough cross-browser coding issues to make the introduction of a modal window on a web page a bit of a nightmare.  Of course that’s all taken care of by libraries such as YUI, but they come at a price; there’s a lot of code to download.

Anyhow, I caved and decided I would install the ui plugin to my project and use the dialog box.  It still feels like a bit of a sledgehammer to crack my little nut, but it works and it is not as buggy as the modal DIV I started writing myself.

The trouble is that out of the box you get none of the default styling from the YUI skins.  According to the grails documentation it should be sufficient to enclose your dialog in a tag and set the class of that tag to refer to the YUI skins…

    <body>
        <div class="yui-skin-sam">
            <gui:dialog blah blah></gui:dialog>
        </div>
    </body>

However, this doesn’t work. And neither does this…

    <body class="yui-skin-sam">
        <div>
            <gui:dialog blah blah></gui:dialog>
        </div>
    </body>

In fact the only way I could get this to work was by adding the “yui-skin-sam” class reference to the body tag in layout/main.gsp.

But that comes with a set of problems of its own, not least of which is that styling the body tag in the main layout means that every generated page gets that styling. If, like me, you had gone to some lengths to define your own styling, that is a real pain because the chance of you not having weird clashes in styles – and yui-skin-sam not overriding them – is almost nil for any semi-serious web app.

So, some words to the wise:

  • If you are starting out on your new shiny Grails app, and you want to style it yourself, imply a namespace in your style names when you are making them by prefixing them all with a code.
  • If you think you might want some exoteric UI feature from the grails UI plug-in – and you almost certainly will – then install it early and declare the style class on the main layout body tag from the start. That way you won’t have a lot of re-factoring of style code to do later.

January 30, 2010

Textpad syntax file for Grails GSP

Filed under: Grails — simonpalmer @ 4:39 pm

Since I couldn’t find one on Textpad’s list, or anywhere else on the web, and nobody on Stackoverflow had one either, I thought I would write myself a syntax hilighting file for Grails GSP.

Here it is for anyone else who might find it useful. Because WordPress don’t allow upload of the .syn file extension I have renamed it gsp.pdf. Right-click on the link save it to your hard disk and rename to .syn file to have it work. It needs to go into your samples folder underneath your Textpad install location.

I have been building it as I have gone along, so it is likely to be incomplete. However, it has most of the commonly used tags so it works for me. I based it on an existing HTML template which also has reasonably support for Javascript, so it is a pretty good general Grails View syntax hilighter.

This seems particularly important for Grails since the IDE’s available are pretty bad (or expensive) and it sort of works better to have a favourite text editor in the mix as your primary editor. I have also added some of the common grails commands to Textpad and it is starting to function as a pretty good alternative to the STS Eclipse plug-in which Spring provide – which isn’t worth it in my opinion.

I have another one I am building for Groovy which I’ll post just as soon as I get it in a state where it does what I feel is the minimum to get by.

January 7, 2010

Back on Stack

Filed under: stackoverflow — simonpalmer @ 9:26 pm

I am back using Stackoverflow after falling out of love with it. I went back for a specific reason, which was entirely the right reason, namely that I had a difficult technical problem that I could not find any solution for. You can see the post which took me back here.

I got some great responses, although none of them led me to a real answer. I ended up logging a bug at Adobe about the issue. Lord knows what will happen to that and I still have a broken Flex socket server, but the experience was good enough that I have overcome my objections and re-joined the Stackoverflow community.

It is easy to spend (read waste) too much time there chasing rep points, and generally in response to questions that the posters ought really to be able to figure out for themselves. And my criticisms remain the same as they were, I have just got over them. Mostly.

There is a definite increase in the sorts of questions which start “I downloaded this code from the internet”, followed by “I have no idea what this bit does, but I changed it and now it doesn’t work”, followed by “can you tell me why”. Basically I think this is lazy and dangerous and I hope these ar students rather than professional programmers. Stackoverflow encourages this sort of behaviour because someone – probably in pursuit of rep points – will normally take the time to post an answer, sometimes a very good answer.

I’m not bothered about the rep any more, although it remains a nice idea and a very good way to get people hookes for long enough to see the real value underneath it. The self-regulation seems to be working reasonably well too and the excesses of the early days are all but gone and there are fewer people trying to be the SO police than there were – although that remains a problem.

So back on and getting and adding value. SO is now part of my technical infrastructure, which I suppose means it is succeeding.

« Newer PostsOlder Posts »

Blog at WordPress.com.