Yelotofu

Yelotofu ~ “In building standards compliant sites we are creating a better Web for the future.”

jQuery: Textarea maxlength

Tags: , , , , ,

Being able to restrict the maximum length of user input from the interface directly is very convenient and practical in use. We do this a lot with input elements. Unfortunately textarea elements do not natively support the maxlength attribute. This attribute was finally added in HTML5 but at the time of writing Chrome is the only browser supporting it.

Naturally many have used JavaScript to rectify this problem and I'd be doing the same here. The difference is we won't be putting anything special in the markup but will simply use the maxlength attribute within our textarea as if it's native — like so:

HTML

 
<textarea cols="30" rows="5" maxlength="10"></textarea>
 

This is looking good for HTML5 compatibility. And here's the magic:

jQuery

jQuery(function($) {
 
  // ignore these keys
  var ignore = [8,9,13,33,34,35,36,37,38,39,40,46];
 
  // use keypress instead of keydown as that's the only
  // place keystrokes could be canceled in Opera
  var eventName = 'keypress';
 
  // handle textareas with maxlength attribute
  $('textarea[maxlength]')
 
    // this is where the magic happens
    .live(eventName, function(event) {
      var self = $(this),
          maxlength = self.attr('maxlength'),
          code = $.data(this, 'keycode');
 
      // check if maxlength has a value.
      // The value must be greater than 0
      if (maxlength && maxlength > 0) {
 
        // continue with this keystroke if maxlength
        // not reached or one of the ignored keys were pressed.
        return ( self.val().length < maxlength
                 || $.inArray(code, ignore) !== -1 );
 
      }
    })
 
    // store keyCode from keydown event for later use
    .live('keydown', function(event) {
      $.data(this, 'keycode', event.keyCode || event.which);
    });
 
});

See live example.

This code could probably be enhanced further by triggering custom events when the maximum length is reached or include a character counter of some sort within the keypress handler. Your imagination is the limit!

Tip: getting values from an options list

Tags: , , , ,

So, if you've ever converted an options list into a single array of values you might have intuitively done this:

var select = $('#mySelectElement')[0];
var values = new Array();
for (var i=0; i < select.length; i++) {
  values.push(select.options[i].value);
}

Pretty boring aye?

There is a snazzier (is that a word?) alternative, which is to use jQuery.map:

var select = $('#mySelectElement')[0];
var values = $.map(select.options, function(n) {
    return n.value;
});

OK, only one line saving but doesn't that feel good?!?

Happy Birthday Google Chrome!

Tags: , ,

Wow, it's been a year already? Time certainly flies when you're having fun! It seems the Google Chrome team have been hard at work! They've finally made a version of Google Chrome for Mac and Linux which you could download from the Dev channel.

Had a quick test and found Print and Application shortcuts haven't been implemented yet. Chrome also died on me a few times unexpectedly (doesn't seem to cope too well with our QUnit test pages). Overall I like the minimal interface and speedier JavaScript response times. It could only get better!

Zend Server CE and Snow Leopard Problem

Tags: , ,

There's a compatibility issue with the Java Bridge in Zend Server CE which results in failure of the ZendServer admin interface. A temporary fix could be found at http://forums.zend.com/viewtopic.php?f=44&t=1115

I found this out the hard way - reinstalled and digged the internals before realizing it was a compatibility issue. I hope the Zend guys fix this soon!

Oh, I'm on Zend Server CE 4.0.5

Labs: UI inlineEdit

Tags: , , , , , , ,

After my last tutorial on building a simple inlineEdit plugin I converted the concepts into a UI widget. It's now sitting in labs for you to use, pick apart and devour:

http://jquery-ui.googlecode.com/svn/branches/labs/inlineedit/demo.html

If you inspect the source code you will notice the structure is quite different. It's actually pretty much the same functionality wise but I have separated each piece into smaller chunks. This makes it easier to extend in future (I plan to write more on ways to extend UI widgets in another post).

Here's a quick peek at the features:

  • Basic inline editing - click, edit, save
  • Ability to save on pressing ENTER key
  • Cancel by un-focussing the input or clicking cancel
  • ThemeRoller ready
  • Customisable empty placeholder
  • Save and Cancel callbacks
  • Cancelable Save callback (so you could script a cancel action)

As usual please feedback and help improve this widget either by commenting here or on the InlineEdit design & planning page

Enjoy!

Tip: Obtaining Request Parameters in Zend_View

I found it virtually impossible to obtain GET or POST request parameters in Zend_View without resorting to accessing the $_GET or $_POST variables. Directly accessing these variables within Zend_View is bad practice so it's been suppressed on purpose to keep processing where it should be - within the Controller. However it is possible to get hold of these variables properly and that is to pass them from the Controller.

Example. You have a query string that looks like this ?keyword=test and want to show it in your view, here's what to do:

MyController.php

 
public function indexAction() {
  $this->view->request = $this->getRequest();
}
 

my-controller/index.phtml

 
The keyword is <?= $this->request->keyword ?>
 

Thanks!

jQuery Inline Edit tutorial

Tags: , , , , ,

A friend recently asked me to review his edit-in-place code which turned out to be a modification of the one found at http://docs.jquery.com/Tutorials:Edit_in_Place_with_Ajax. Reading the tutorial on that page I asked myself how I would do this differently? Defining a global setClickable() function and then calling $('#editInPlace").click() is totally uncool, essentially limiting yourself to one edit-in-place area per page.

Since the concept of edit-in-place is so simple and the implementation should be likewise I want to try and tackle this as a tutorial by going through concepts and teaching to build from scratch.

The concept

There's a piece of text on a page, e.g. a heading or paragraph, looking plain and un-interesting. When you hover over it however a visual highlight, usually pale yellow, indicates that it's something special - an editable region. You then click on the text and it magically transforms into an editable box with save and cancel buttons tagged at the end. On clicking either save or cancel the editable box transforms back into its original form with text updated if saved.

The build

What we want to do is put these concepts into code whilst building something that's re-usable. A plugin will do the trick! Let's call our plugin inlineEdit.

We are only 3 steps away from achieving our goal! Follow along...

Step 1: Getting the basics right

The basic functionality consists of a static text element (span, div etc...) that can transforms into an input element on click. And on hover the text element will highlight to indicate special interactions.

Here's our first pass: Basic Interaction

Code explanation: Our plugin accepts a CSS class name defined in a stylesheet which is used to toggle the text element's classname - a class defining a background-color typically #ffC is sufficient for this. On clicking we replace the entire contents of the original text element with an input element and pass the original content into the input as its value. For now changes are saved when the input loses focus.

Step 2: Save, Cancel & Callbacks

As you may notice above we saved on blur and there is no way of canceling changes. Let's improve the interaction by adding a save button. This is important as you'd want to do something with the changes or allow a user to manually cancel. Every application does something different at the saving stage so we'll simply define a save callback and let the implementer decide what to do on save, be it Ajax post or what not. The save action is also cancelable by returning false inside the callback.

Here is our second pass: Save, cancel and callbacks

Step 3: Finishing Off

Our plugin is nearly there. Just a few nice finishing touches remaining. We want to give the user ability to change the button label and pass an initial value. Also to make the plugin more re-usable we want to move the core plugin code out to a separate file and reference it instead. To set the stage for further improvements in the future we also split the code into two distinct clauses.

Final result: Live Demo and source code is here

Usage

Now to use this brand spanking new plugin we simply apply it to any DOM element like so:

HTML

<span class="editable">Hello World!</span>

JavaScript - Basic

$(function() {
  $('.editable').inlineEdit();
});

JavaScript - Customised button label with save callback

$(function() {
  $('.editable').inlineEdit({
    buttonText: 'Add',
    save: function(e, data) {
      return confirm('Change name to '+ data.value +'?');
    }
  });
});

Feedback welcome - if you happen to improve upon this code base please share-a-like!

Enjoy!

Update 26-Aug-09: Added placeholder for cases when text is empty; changed label option to buttonText to minimise confusion.

Update 18-Oct-09 Fixed bug in setting initial value via script.

Update 17-Jan-10 Moved code to http://github.com/caphun/jquery.inlineedit. I will continue to improve this plugin from there. Feel free to fork it!

jQuery UI Spinner update

Tags: , , ,

Sorry for no news these past few months. It's been very hectic since the new family addition back in Dec which I managed to keep low key. ;) I feel so guilty now for neglecting this blog and my readers (don't think I have any regulars anyway so I guess nothing missed!), but hey priorities are priorities!

Right, the reason for this post is that there has been some recent exciting updates to the spinner which I would love to get feedback on from the public. Thanks to Brant Burnett, the Spinner has been re-invigorated and looks set to become a kick ass component in the making!

We've added a bunch of new features and updates including:

  • support for jquery 1.3.2
  • support for ThemeRoller
  • spinning hexidecimals and other numbering systems
  • ability to auto-hide buttons and show on hover with customizable speeds
  • better keyboard interaction - you could now use PgUp/PgDn to setup up/down in a large increment set by options

We also have a lot more in the works, such as:

  • ability to spin time and date
  • segment spinning based on formatter
  • HTML5 support
  • and more...

If interested, check out the latest demo

We're still in the planning / development stage so any features you see now or currently being planned may not necessarily land in the final release. It all depends on what you want - collectively that is! So if there is something you really think should be added please shout in the dev mailing list or on the UI planning wiki.

Looking forward to some feedback.

Thanks!

jQuery UI 1.7 released

Tags: , , ,

Today marks the release of jQuery UI 1.6 1.7. Kudos to UI team members who've done a fantastic job!

I'm pretty excited not only because I'm now part of this fantastic team but also with where UI is headed and how it has progressed thus far. UI is still pretty young compared to other UI libraries so there is much to learn from the likes of Dojo, ExtJS and YUI - all great frameworks in their own right.

1.7 see's a total refactor of the UI CSS Framework and ThemeRoller v2. This must be by far the greatest visible improvement in this version of UI. Though it is but one part of the hard work put into this release.

For full details on this release see the official release announcement.

Cross browser equal height that works

Tags: , ,

Note: This article was first posted to the Lemon Digital Blog.

Since its dawn, CSS has been plagued with the lack of a bullet proof technic to produce equal height columns, boxes and grids. The fortunate few have been able to avoid this problem by "designing for the Web" — no crazy fonts; no equal height.

For those unfortunate millions, it isn't so cut 'n' dry. Many designers continue to create vertically aligned and beautifully designed mock-ups in PhotoShop fully expecting the end result to look the same on the Web (and quite rightly so); if not, at least the columns should remain at equal height in all scenarios!

Thankfully display:table-cell and display:inline-block come to the rescue. Like magic, these change the characteristics of any block level element in amazing ways giving elements table-cell like behaviour; The latter even allows proper element tiling in an orderly fashion. If you come from the hybrid-layout era you'd know how convenient tables for layout were. These two CSS properties give the best of both worlds - better markup semantics with grid-like features.

This sounds like fancy stuff but really, it is quite simple. Code always speaks louder than words so here's an example to get the juices going: Working with cells in CSS

Now, let me take you through the code once you've had a gander through the source code...

 
.grid { display: table; }
.grid li { display: table-cell; }
 

These two lines are all we need to change a list into a table row. But here's the catch — this only works in Mozilla, Opera and Safari browsers; as usual IE is the odd one out. The forthcoming IE8 will support these display values but for now we have to hack our way to a solution that really works. Here's where things get interesting.

To get equal height in IE we turn to inline-block. IE has some buggy CSS support. inline-block only works in IE if we duplicate it with an inline call afterwards, like so:

.grid {
  width: 100%;
  height: 1%;
}
.grid li {
  display: inline-block;
  vertical-align: top;
  height: 100%;
}
.grid li {
  display: inline;
  width: 24.9%;
}

In the above we're specifying a width of 24.9% — this value will be different depending on the number of cells in a row. Our example has four, so in theory it should be 25%. This weird value is just evidence how bad IE's support is when it comes to CSS.

Finally to produce equal height columns we increase the bottom padding to a very high value to overcome the varying content height:

 
/* equal column height hack - for IE6 &amp; IE7 only */
.grid {
  voice-family: "\"}\"";
  voice-family: inherit;
  overflow: hidden;
}
.grid li {
  voice-family: "\"}\"";
  voice-family: inherit;
  padding-bottom: 9999px;
  margin-bottom: -9999px;
}

That's it! Pretty simple if it wasn't for IE! ;)

Here are two more examples based on the concepts talked about in this article:

Further reading:

Go crazy!

« Previous Entries