Improved slider behaviour and fixed prefix handling
diff --git a/dev/js/src/menu/item.js b/dev/js/src/menu/item.js
index b8e8808..8278d17 100644
--- a/dev/js/src/menu/item.js
+++ b/dev/js/src/menu/item.js
@@ -122,10 +122,50 @@
    * @param {string} Prefix string for highlights
    */
   highlight : function (prefix) {
+
+    // The prefix already matches
+    if (this._prefix === prefix)
+      return;
+
+    // There is a prefix but it doesn't match
+    if (this._prefix !== null) {
+      this.lowlight();
+    }
+
     var children = this.element().childNodes;
     for (var i = children.length -1; i >= 0; i--) {
       this._highlight(children[i], prefix);
     };
+
+    this._prefix = prefix;
+  },
+
+  /**
+   * Remove highlight of the menu item
+   */
+  lowlight : function () {
+    if (this._prefix === null)
+      return;
+
+    var e = this.element();
+    
+    var marks = e.getElementsByTagName("mark");
+    for (var i = marks.length - 1; i >= 0; i--) {
+      // Create text node clone
+      var x = document.createTextNode(
+	marks[i].firstChild.nodeValue
+      );
+      
+      // Replace with content
+      marks[i].parentNode.replaceChild(
+	x,
+	marks[i]
+      );
+    };
+
+    // Remove consecutive textnodes
+    e.normalize();
+    this._prefix = null;
   },
 
   // Highlight a certain substring of the menu item
@@ -176,30 +216,6 @@
     };
   },
 
-  /**
-   * Remove highlight of the menu item
-   */
-  lowlight : function () {
-    var e = this.element();
-    
-    var marks = e.getElementsByTagName("mark");
-    for (var i = marks.length - 1; i >= 0; i--) {
-      // Create text node clone
-      var x = document.createTextNode(
-	marks[i].firstChild.nodeValue
-      );
-      
-      // Replace with content
-      marks[i].parentNode.replaceChild(
-	x,
-	marks[i]
-      );
-    };
-
-    // Remove consecutive textnodes
-    e.normalize();
-  },
-
   // Initialize menu item
   _init : function (params) {
     
@@ -212,6 +228,7 @@
       this._action = params[1];
 
     this._lcField = ' ' + this.content().textContent.toLowerCase();
+    this._highlight = null;
 
     return this;
   },
diff --git a/dev/js/src/menu/slider.js b/dev/js/src/menu/slider.js
index c35f284..d71bae1 100644
--- a/dev/js/src/menu/slider.js
+++ b/dev/js/src/menu/slider.js
@@ -1,14 +1,33 @@
 define({
 
   /**
-   * Create new prefix object.
+   * Create new slider object.
+   * The slider will only be used by mouse - touch support
+   * shouldn't be necessary.
    */
   create : function (menu) {
     return Object.create(this)._init(menu);
   },
 
-  _mousemove : function (e) {
-    var relativePos = e.clientY - this._event.init;
+  length : function (i) {
+    if (arguments.length === 0)
+      return this._length;
+    if (i == this._length)
+      return;
+    this._length = i;
+    this._initSize();
+  },
+
+  limit : function (i) {
+    if (arguments.length === 0)
+      return this._limit;
+    if (i == this._limit)
+      return;
+    this._limit = i;
+    this._initSize();
+  },
+
+  movetoRel : function (relativePos) {
     var diffHeight = (this._rulerHeight - this._sliderHeight);
     var relativeOffset = (relativePos / diffHeight);
 
@@ -16,34 +35,38 @@
     if (off !== undefined) {
       this._menu.screen(off);
     };
-
-    e.halt();
-
-    // Support touch!
   },
 
-  _mouseup : function (e) {
-    this._element.classList.remove('active');
-    window.removeEventListener('mousemove', this._event.mov);
-    window.removeEventListener('mouseup', this._event.up);
+  movetoAbs : function (absPos) {
+    var absOffset = (absPos / this._rulerHeight);
+
+    var off = this.offset(parseInt(absOffset * (this._screens + 1)));
+    if (off !== undefined) {
+      this._menu.screen(off);
+    };
   },
 
-  _mousedown : function (e) {
-    // Bind drag handler
-    var ev = this._event;
-    ev.init = e.clientY - (this._step * this._offset);
-    ev.mov = this._mousemove.bind(this);
-    ev.up = this._mouseup.bind(this);
+  offset : function (off) {
+    if (arguments.length === 0)
+      return this._offset;
 
-    this._rulerHeight  = this._element.clientHeight; // offsetHeight?
-    this._sliderHeight = this._slider.clientHeight;  // offsetHeight?
+    if (off > this._screens) {
+      off = this._screens;
+    }
+    else if (off < 0) {
+      off = 0;
+    };
 
-    this._element.classList.add('active');
+    if (off === this._offset)
+      return undefined;
 
-    window.addEventListener('mousemove', ev.mov);
-    window.addEventListener('mouseup', ev.up);
+    this._offset = off;
+    this._slider.style.top = (this._step * off) + '%';
+    return off;
+  },
 
-    e.halt();
+  element : function () {
+    return this._element;
   },
 
   // Initialize prefix object
@@ -61,51 +84,78 @@
       document.createElement('span')
     );
 
-    this._element.appendChild(document.createElement('div'))
-    // Do not mark the menu on mousedown
-    .addEventListener('mousedown', function (e) {
-      e.halt()
-    });
+    this._ruler = this._element.appendChild(document.createElement('div'));
 
-    // TODO: Support touch!
+    // Do not mark the menu on mousedown
+    this._ruler.addEventListener('mousedown', function (e) {
+      e.halt()
+    }, false);
+
+    // Move the slider to the click position
+    this._ruler.addEventListener('click', this._mouseclick.bind(this), false);
+
     this._slider.addEventListener('mousedown', this._mousedown.bind(this), false);
 
     return this;
   },
 
   _initSize : function () {
+    if (this._length <= this._limit) {
+      this._element.style.display = 'none';
+      return;
+    }
+    else {
+      this._element.style.display = 'block';
+    };
+
     this._height = ((this._limit / this._length) * 100);
     this._screens = this._length - this._limit;
     this._step = (100 - this._height) / this._screens;
-  },
-
-  show : function (i) {
     this._slider.style.height = this._height + '%';
   },
 
-  length : function (i) {
-    this._length = i;
-    this._initSize();
+  _initClientHeight : function () {
+    this._rulerHeight  = this._element.clientHeight; // offsetHeight?
+    this._sliderHeight = this._slider.clientHeight;  // offsetHeight?
   },
 
-  limit : function (i) {
-    this._limit = i;
-    this._initSize();
+  _mousemove : function (e) {
+    this.movetoRel(e.clientY - this._event.init);
+    e.halt();
+    // Support touch!
   },
 
-  offset : function (off) {
-    if (arguments.length === 0)
-      return this._offset;
-
-    if (off === this._offset || off > this._screens || off < 0)
-      return undefined;
-
-    this._offset = off;
-    this._slider.style.top = (this._step * off) + '%';
-    return off;
+  _mouseup : function (e) {
+    this._element.classList.remove('active');
+    window.removeEventListener('mousemove', this._event.mov);
+    window.removeEventListener('mouseup', this._event.up);
+    this._menu.focus();
   },
 
-  element : function () {
-    return this._element;
+  _mousedown : function (e) {
+    // Bind drag handler
+    var ev = this._event;
+    ev.init = e.clientY - (this._step * this._offset);
+    ev.mov = this._mousemove.bind(this);
+    ev.up = this._mouseup.bind(this);
+
+    // TODO: This may not be necessary all the time
+    this._initClientHeight();
+
+    this._element.classList.add('active');
+
+    window.addEventListener('mousemove', ev.mov);
+    window.addEventListener('mouseup', ev.up);
+
+    e.halt();
+  },
+
+  _mouseclick : function (e) {
+    this._initClientHeight();
+
+    this.movetoAbs(
+      e.clientY - this._ruler.getClientRects()[0].top
+    );
+    e.halt();
   }
 });