Improve visualization of the slider and optimize navigation in menus
diff --git a/dev/js/spec/menuSpec.js b/dev/js/spec/menuSpec.js
index 2b3fcf3..7577c2f 100644
--- a/dev/js/spec/menuSpec.js
+++ b/dev/js/spec/menuSpec.js
@@ -395,7 +395,7 @@
it('should be visible', function () {
var menu = KorAP.HintMenu.create("cnx/", list);
- expect(menu.unshow()).toBe(undefined);
+ expect(menu.removeItems()).toBe(undefined);
menu.limit(3);
expect(menu.show()).toBe(true);
@@ -767,10 +767,22 @@
});
- it('should choose prefix with failing prefix', function () {
+ it('should choose prefix with failing prefix (1)', function () {
var menu = KorAP.HintMenu.create("cnx/", list);
menu.limit(2);
expect(menu.prefix("exit").show()).toBe(true);
+ expect(menu.element().querySelector('li')).toBe(null);
+ expect(menu.shownItem(0)).toBeUndefined();
+ expect(menu._prefix.active()).toBe(true);
+ });
+
+
+ it('should choose prefix with failing prefix (2)', function () {
+ var menu = KorAP.HintMenu.create("cnx/", list);
+ menu.limit(2);
+ expect(menu.show()).toBe(true);
+ expect(menu.prefix("exit").show()).toBe(true);
+ expect(menu.element().querySelector('li')).toBe(null);
expect(menu.shownItem(0)).toBeUndefined();
expect(menu._prefix.active()).toBe(true);
});
diff --git a/dev/js/src/menu.js b/dev/js/src/menu.js
index 7b2f779..abe2a15 100644
--- a/dev/js/src/menu.js
+++ b/dev/js/src/menu.js
@@ -5,13 +5,9 @@
*/
/*
* TODO: space is not a valid prefix!
- * TODO: Prefix should be case sensitive!
* TODO: What is _pos and what is position?
* TODO: What is the difference between position
* and _active?
- * TODO: next and prev should use an optimized version of _screen
- * TODO: On next and prev the viewport should move
- * to the active item.
* TODO: Ignore keys with function key combinations (other than shift)
* TODO: Show the slider briefly on move (whenever screen is called).
*/
@@ -57,7 +53,7 @@
// Initialize list
_init : function (itemClass, prefixClass, lengthFieldClass, params) {
- var that = this;
+
this._itemClass = itemClass || defaultItemClass;
// Add prefix object
@@ -98,27 +94,21 @@
// Arrow keys
e.addEventListener(
'keydown',
- function (ev) {
- that._keydown(ev)
- },
+ this._keydown.bind(this),
false
);
// Strings
e.addEventListener(
'keypress',
- function (ev) {
- that._keypress(ev)
- },
+ this._keypress.bind(this),
false
);
// Mousewheel
e.addEventListener(
'wheel',
- function (ev) {
- that._mousewheel(ev)
- },
+ this._mousewheel.bind(this),
false
);
@@ -311,7 +301,7 @@
// Add characters to prefix
_keypress : function (e) {
e.halt();
- var c = String.fromCharCode(_codeFromEvent(e)); // .toLowerCase();
+ var c = String.fromCharCode(_codeFromEvent(e));
// Add prefix
this._prefix.add(c);
@@ -333,29 +323,6 @@
if (this._offset === nr)
return;
- // OPTIMIZE!!!
-
- // TODO: This is just an optimization of screen
- /*
- if (this.position >= (this.limit() + this._offset) {
- this._removeFirst();
- this._offset++;
- this._append(this._list[this.position]);
- this._slider.offset(this._offset);
- }
- else if (this.position < this._offset) {
-
- this._removeLast();
- this._offset--;
- this._prepend(this._list[this.position]);
- // set the slider to the new offset
- this._slider.offset(this._offset);
- }
- */
-
-
- this.unshow();
- this._offset = nr;
this._showItems(nr);
},
@@ -412,7 +379,7 @@
// show menu based on initial offset
this._unmark(); // Unmark everything that was marked before
- this.unshow(); // Delete everything that is shown
+ this.removeItems();
// Initialize the list
if (!this._initList()) {
@@ -498,7 +465,7 @@
hide : function () {
this.active = false;
this._unmark();
- this.unshow();
+ this.removeItems();
this._element.style.opacity = 0;
this._prefix.clear();
this.onHide();
@@ -542,7 +509,7 @@
/**
* Delete all visible items from the menu element
*/
- unshow : function () {
+ removeItems : function () {
var child;
// Remove all children
@@ -646,19 +613,15 @@
return;
}
else {
- this._offset = 0;
this.position = 0;
newItem = this.liveItem(0);
this._active = 0;
- this._unmark();
- this.unshow();
this._showItems(0);
};
}
// The next element is after the viewport - roll down
else if (this.position >= (this.limit() + this._offset)) {
-
this.screen(this.position - this.limit() + 1);
}
@@ -697,23 +660,25 @@
// Activate prefix
var prefix = this._prefix;
- this._offset = this.liveLength() - this.limit();
+ var offset = this.liveLength() - this.limit();
+ // this._offset = this.liveLength() - this.limit();
// Normalize offset
- this._offset = this._offset < 0 ? 0 : this._offset;
+ // this._offset = this._offset < 0 ? 0 : this._offset;
+ offset = offset < 0 ? 0 : offset;
this.position = this.liveLength() - 1;
if (prefix.isSet() && !prefix.active()) {
this.position++;
prefix.active(true);
+ this._offset = offset;
return;
}
else {
newItem = this.liveItem(this.position);
this._unmark();
- this.unshow();
- this._showItems(this._offset);
+ this._showItems(offset);
};
}
@@ -775,24 +740,44 @@
// Append Items that should be shown
_showItems : function (off) {
- // Use list
- var shown = 0;
- var i;
+ // optimization: scroll down one step
+ if (this._offset === (off - 1)) {
+ this._offset = off;
+ this._removeFirst();
+ var pos = this._offset + this.limit() - 1;
+ this._append(this._list[pos]);
+ }
- for (i in this._list) {
+ // optimization: scroll up one step
+ else if (this._offset === (off + 1)) {
+ this._offset = off;
+ this._removeLast();
+ this._prepend(this._list[this._offset]);
+ }
+ else {
+ this._offset = off;
- // Don't show - it's before offset
- shown++;
- if (shown <= off)
- continue;
+ // Remove all items
+ this.removeItems();
- var itemNr = this._list[i];
- var item = this.item(itemNr);
- this._append(itemNr);
+ // Use list
+ var shown = 0;
+ var i;
- // this._offset))
- if (shown >= (this.limit() + off))
- break;
+ for (i in this._list) {
+
+ // Don't show - it's before offset
+ shown++;
+ if (shown <= off)
+ continue;
+
+ var itemNr = this._list[i];
+ var item = this.item(itemNr);
+ this._append(itemNr);
+
+ if (shown >= (this.limit() + off))
+ break;
+ };
};
// set the slider to the new offset
@@ -805,8 +790,10 @@
var item = this.item(i);
// Highlight based on prefix
- if (this.prefix().length > 0)
+ if (this.prefix().length > 0) {
item.highlight(this.prefix().toLowerCase());
+ };
+
// Append element
this.element().appendChild(item.element());
@@ -818,8 +805,9 @@
var item = this.item(i);
// Highlight based on prefix
- if (this.prefix().length > 0)
+ if (this.prefix().length > 0) {
item.highlight(this.prefix().toLowerCase());
+ };
var e = this.element();
// Append element after lengthField/prefix/slider
@@ -832,7 +820,7 @@
// Remove the HTML node from the first item
_removeFirst : function () {
- this.item(this._list[this._offset]).lowlight();
+ // this.item(this._list[this._offset]).lowlight();
// leave lengthField/prefix/slider
this._element.removeChild(this._element.children[3]);
},
@@ -840,7 +828,7 @@
// Remove the HTML node from the last item
_removeLast : function () {
- this.item(this._list[this._offset + this.limit() - 1]).lowlight();
+ // this.item(this._list[this._offset + this.limit() - 1]).lowlight();
this._element.removeChild(this._element.lastChild);
}
};
diff --git a/dev/js/src/menu/slider.js b/dev/js/src/menu/slider.js
index d71bae1..0b0aed0 100644
--- a/dev/js/src/menu/slider.js
+++ b/dev/js/src/menu/slider.js
@@ -27,6 +27,22 @@
this._initSize();
},
+ active : function (bool) {
+ if (arguments.length === 1) {
+ if (bool) {
+ if (!this._active) {
+ this._element.classList.add('active');
+ this._active = true;
+ };
+ }
+ else if (this._active) {
+ this._element.classList.remove('active');
+ this._active = false;
+ }
+ };
+ return this._active;
+ },
+
movetoRel : function (relativePos) {
var diffHeight = (this._rulerHeight - this._sliderHeight);
var relativeOffset = (relativePos / diffHeight);
@@ -62,6 +78,7 @@
this._offset = off;
this._slider.style.top = (this._step * off) + '%';
+
return off;
},
@@ -76,6 +93,7 @@
this._offset = 0;
this._event = {};
+ this._active = false;
this._element = document.createElement('div');
this._element.setAttribute('class', 'ruler');
@@ -126,7 +144,7 @@
},
_mouseup : function (e) {
- this._element.classList.remove('active');
+ this.active(false);
window.removeEventListener('mousemove', this._event.mov);
window.removeEventListener('mouseup', this._event.up);
this._menu.focus();
@@ -142,7 +160,7 @@
// TODO: This may not be necessary all the time
this._initClientHeight();
- this._element.classList.add('active');
+ this.active(true);
window.addEventListener('mousemove', ev.mov);
window.addEventListener('mouseup', ev.up);
diff --git a/dev/scss/header/menu.scss b/dev/scss/header/menu.scss
index 582e543..070f26b 100644
--- a/dev/scss/header/menu.scss
+++ b/dev/scss/header/menu.scss
@@ -53,6 +53,7 @@
ul.menu:hover > div.ruler,
ul.menu > div.ruler.active {
+ transition: opacity .1s ease;
opacity: 1;
}
@@ -73,6 +74,8 @@
height: 100%;
opacity: 0;
cursor: pointer;
+ transition: opacity .5s ease 1s;
+
> span {
position: absolute;
@include choose-active;