summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/jquery-ui.js298
1 files changed, 225 insertions, 73 deletions
diff --git a/lib/jquery-ui.js b/lib/jquery-ui.js
index 4939d009..8777e4fe 100644
--- a/lib/jquery-ui.js
+++ b/lib/jquery-ui.js
@@ -159,30 +159,41 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
var self = this;
this.items = $(this.options.filter, this.element);
- this.element.addClass("ui-selectable");
+ this.element.addClass("ui-selectable ui-widget");
//Set the currentFocus to the first item
- this.currentFocus = this.items.eq(0);
+ this.currentFocus = this.items.eq(0).attr('tabindex', 0);
//Refresh item positions
- this.refresh();
+ this.refresh(1);
//Disable text selection
this.element.disableSelection();
//Prepare caret selection
- if(this.options.lasso) this._mouseInit();
+ if(this.options.lasso) {
+
+ // we need to move the lasso options onto the root options for the mouse clas
+ if(this.options.lasso !== true) {
+ $.extend(this.options, this.options.lasso);
+ }
+
+ this._mouseInit();
+ }
this.element
.bind('mousedown.selectable', function(event) {
+ if(self.options.disabled)
+ return;
+
var item = self._targetIsItem(event.target);
if (!item) return;
-
+
// If item is part of current selection and current
// selection is multiple, return and allow mouseup
// to fire (Windows gets this right too, OSX doesn't)
- if(self._selection.length > 1 && $(item).hasClass(self.options.selectedClass)) {
+ if(self._selection.length > 1 && $(item).hasClass('ui-selected')) {
return (self._listenForMouseUp = 1);
}
@@ -210,36 +221,36 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
}
})
.bind('focus.selectable', function() {
- self.currentFocus.addClass('ui-focused');
+ if(!self.options.disabled) self.currentFocus.addClass('ui-state-focus');
})
.bind('blur.selectable', function() {
- self.currentFocus.removeClass('ui-focused');
+ if(!self.options.disabled) self.currentFocus.removeClass('ui-state-focus');
})
.bind('keydown.selectable', function(event) {
- if(!self.options.keyboard)
+ if(!self.options.keyboard || self.options.disabled)
return;
if(self._trigger('beforeselect', event) === false)
return true;
if(event.keyCode == $.ui.keyCode.DOWN) {
- self.options.smart ? self.selectClosest('down', event) : self.selectNext(event);
+ self.options.closest ? self.selectClosest('down', event) : self.next(event);
event.preventDefault();
}
if(event.keyCode == $.ui.keyCode.RIGHT) {
- self.options.smart ? self.selectClosest('right', event) : self.selectNext(event);
+ self.options.closest ? self.selectClosest('right', event) : self.next(event);
event.preventDefault();
}
if(event.keyCode == $.ui.keyCode.UP) {
- self.options.smart ? self.selectClosest('up', event) : self.selectPrevious(event);
+ self.options.closest ? self.selectClosest('up', event) : self.previous(event);
event.preventDefault();
}
if(event.keyCode == $.ui.keyCode.LEFT) {
- self.options.smart ? self.selectClosest('left', event) : self.selectPrevious(event);
+ self.options.closest ? self.selectClosest('left', event) : self.previous(event);
event.preventDefault();
}
@@ -260,7 +271,7 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
overlap = 10000,
selfOffset = this.currentFocus.data('selectable-item');
- $(this.options.filter, this.element).not(this.currentFocus).filter(':visible').each(function() {
+ this.items.not(this.currentFocus).filter(':visible').each(function() {
var $this = $(this),
offset = $this.data('selectable-item'),
@@ -303,13 +314,23 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
});
- return current[1] ? this._select(event, current[1]) : false;
+ // if nothing close is found, bail
+ if(!current[1])
+ return false;
+
+ //We need to find the index of the current, and the index of the new one to call selectAdjacent
+ // - calling _select doesn't work, since it's only for mouse interaction (no ctrl focus move!)
+ var currentIndex = this.items.index(this.currentFocus[0]);
+ var newIndex = this.items.index(current[1]);
+
+ return this._selectAdjacent(event, newIndex - currentIndex);
},
destroy: function() {
+ this.items.removeClass("ui-selectable-item ui-selected ui-state-active");
this.element
- .removeClass("ui-selectable ui-selectable-disabled")
+ .removeClass("ui-selectable ui-selectable-disabled ui-widget")
.removeData("selectable")
.unbind(".selectable");
this._mouseDestroy();
@@ -318,11 +339,11 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
_mouseCapture: function(event) {
//If the item we start dragging on is a selectable, we bail (if keyboard is used)
this.clickedOnItem = this._targetIsItem(event.target);
- return !this.options.keyboard || !this.clickedOnItem;
+ return true; // TODO: this starts the lasso on items as well - we might want to introduce an option to disable this
},
_mouseStart: function(event) {
-
+
var self = this, o = this.options;
this.opos = [event.pageX, event.pageY];
@@ -330,10 +351,13 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
return;
//Cache positions
- this.refresh();
+ this.refresh(1);
//Trigger start event
this._trigger("start", event, this._uiHash());
+
+ //Save the current selection as previous
+ this._previousSelection = this._selection.slice();
// append and position helper (lasso)
$('body').append(this.helper);
@@ -347,12 +371,12 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
});
//Tell the intersection that some start selected
- this.items.filter('.'+this.options.selectedClass).each(function() {
- if(event.metaKey) {
- if(this != self.clickedOnItem) $.data(this, "selectable-item").startSelected = true;
- } else self._removeFromSelection($(this), event);
- });
-
+ for (var i = this._selection.length - 1; i >= 0; i--){
+ if(event.metaKey || event.ctrlKey) {
+ if(this != self.clickedOnItem) $(this._selection[i]).data("selectable-item").startSelected = true;
+ } else self._removeFromSelection($(this._selection[i]), event);
+ };
+
},
_mouseDrag: function(event) {
@@ -395,7 +419,41 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
},
_mouseStop: function(event) {
- this._trigger("stop", event, this._uiHash());
+
+ var newlySelected = [],
+ newlyDeselected = [];
+
+ // Find out the delta of the newly selected items
+ for (var i=0; i < this._selection.length; i++) {
+ var wasAlreadyPartOfPreviousSelection = false;
+ for (var j=0; j < this._previousSelection.length; j++) {
+ if(this._selection[i][0] == this._previousSelection[j][0])
+ wasAlreadyPartOfPreviousSelection = true;
+ };
+ if(!wasAlreadyPartOfPreviousSelection) newlySelected.push(this._selection[i]);
+ };
+
+ // Find out the delta of the newly unselected items
+ for (var i = this._previousSelection.length - 1; i >= 0; i--){
+ if(!this._previousSelection[i].data('selectable-item').selected) newlyDeselected.push(this._previousSelection[i]);
+ };
+
+
+ // Transform both deltas into jQuery objects
+ newlySelected = $($.map(newlySelected, function(i) { return i[0]; }));
+ newlyDeselected = $($.map(newlyDeselected, function(i) { return i[0]; }));
+
+ var uiHash = $.extend(this._uiHash(), {
+ added: newlySelected || [],
+ removed: newlyDeselected || []
+ });
+ this._trigger("stop", event, uiHash);
+
+ // Trigger change event if anything has changed
+ if((newlySelected && newlySelected.length) || (newlyDeselected && newlyDeselected.length)) {
+ this._trigger('change', event, uiHash);
+ }
+
this.helper.remove();
return false;
},
@@ -407,23 +465,63 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
_selection: [],
+ _endSelection: function(event, newlySelected) {
+
+ //Only trigger the 'deselect' event if items have been removed from the selection
+ var newlyDeselected = this._triggerDeselection(event);
+
+ //Only trigger 'select' event if items have been added to the selection
+ if(newlySelected && newlySelected.length)
+ this._trigger('select', event, this._uiHash(newlySelected, 'added'));
+
+ // Trigger change event if anything has changed
+ if((newlySelected && newlySelected.length) || (newlyDeselected && newlyDeselected.length)) {
+ var uiHash = $.extend(this._uiHash(), {
+ added: newlySelected || [],
+ removed: newlyDeselected || []
+ });
+ this._trigger('change', event, uiHash);
+ }
+
+ },
+
+ _triggerDeselection: function(event) {
+
+ var triggerItems = [];
+
+ for (var i = this._previousSelection.length - 1; i >= 0; i--){
+ var data = this._previousSelection[i].data('selectable-item');
+ if(!data || !data.selected) triggerItems.push(this._previousSelection[i]);
+ };
+
+ this._previousSelection = [];
+ triggerItems = $($.map(triggerItems, function(i) { return i[0]; }));
+ if(triggerItems.length) this._trigger('deselect', event, this._uiHash(triggerItems, 'removed'));
+
+ return triggerItems;
+
+ },
+
_clearSelection: function(triggerEvent) {
var triggerItems = [];
for (var i = this._selection.length - 1; i >= 0; i--){
if(triggerEvent && this._selection[i].data('selectable-item').selected) triggerItems.push(this._selection[i]);
- this._selection[i].removeClass(this.options.selectedClass);
+ this._selection[i].removeClass('ui-selected ui-state-active');
this._selection[i].data('selectable-item').selected = false;
};
+ this._previousSelection = this._selection.slice();
this._selection = [];
- if(triggerEvent) this._trigger('unselect', triggerEvent, this._uiHash($($.map(triggerItems, function(i) { return i[0]; })), 'removed'));
+ if(triggerEvent && triggerItems.length) this._trigger('deselect', triggerEvent, this._uiHash($($.map(triggerItems, function(i) { return i[0]; })), 'removed'));
},
_toggleSelection: function(item, event) {
- item.data('selectable-item').selected ? this._removeFromSelection(item, event) : this._addToSelection(item);
+ var selected = item.data('selectable-item').selected;
+ selected ? this._removeFromSelection(item, event) : this._addToSelection(item);
+ return !selected;
},
_addToSelection: function(item, triggerEvent) {
@@ -433,7 +531,7 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
this._selection.push(item);
this.latestSelection = item;
- item.addClass(this.options.selectedClass);
+ item.addClass('ui-selected ui-state-active');
item.data('selectable-item').selected = true;
if(triggerEvent) {
@@ -448,10 +546,10 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
for (var i=0; i < this._selection.length; i++) {
if (this._selection[i][0] == item[0]) {
- this._selection[i].removeClass(this.options.selectedClass);
+ this._selection[i].removeClass('ui-selected ui-state-active');
this._selection[i].data('selectable-item').selected = false;
this._selection.splice(i,1);
- if(triggerEvent) this._trigger('unselect', triggerEvent, this._uiHash($(item), 'removed'));
+ if(triggerEvent) this._trigger('deselect', triggerEvent, this._uiHash($(item), 'removed'));
break;
}
};
@@ -462,10 +560,10 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
var newlySelected = [];
- if (event.shiftKey && this.options.multiple) {
+ if (event && event.shiftKey) {
//Clear the previous selection to make room for a shift selection
- this._clearSelection(event);
+ this._clearSelection();
var index = this.items.index(this.latestWithoutModifier[0]) > this.items.index(this.currentFocus[0]) ? -1 : 1;
var i = this.latestWithoutModifier.data('selectable-item').selected ? this.items.eq(this.items.index(this.latestWithoutModifier[0])+index) : this.latestWithoutModifier;
@@ -479,10 +577,11 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
} else {
- if (event.metaKey) {
- this._toggleSelection(this.currentFocus, event);
+ if (event && (event.metaKey || event.ctrlKey)) {
+ var withMetaIsNewlySelected = this._toggleSelection(this.currentFocus, event);
+ if(withMetaIsNewlySelected) newlySelected.push(this.currentFocus);
} else {
- this._clearSelection(event);
+ this._clearSelection();
newlySelected.push(this._addToSelection(this.currentFocus));
this.latestWithoutModifier = this.currentFocus;
}
@@ -497,7 +596,7 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
var newlySelected = [];
- if (event.shiftKey && this.options.multiple) {
+ if (event && event.shiftKey) {
if (this.currentFocus.data('selectable-item').selected) {
this._removeFromSelection(this.previousFocus, event);
@@ -519,7 +618,7 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
} else {
//If the CTRL or Apple/Win key is pressed, only set focus
- if (event.metaKey)
+ if (event && (event.metaKey || event.ctrlKey))
return;
this._clearSelection(event);
@@ -528,24 +627,24 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
}
- return $($.map(newlySelected, function(i) { return i[0]; }));
+ return $($.map(newlySelected, function(i) { if(i) return i[0]; }));
},
_select: function(event, item) {
//Set the current selection to the previous/next item
- this.previousFocus = this.currentFocus;
- this.currentFocus = $(item);
+ this.previousFocus = this.currentFocus.attr('tabindex', -1);
+ this.currentFocus = $(item).attr('tabindex', 0);
- this.previousFocus.removeClass('ui-focused');
- this.currentFocus.addClass('ui-focused');
+ this.previousFocus.removeClass('ui-state-focus');
+ this.currentFocus.addClass('ui-state-focus');
//Set and update the selection
var newlySelected = this._updateSelectionMouse(event);
- //Trigger select event
- if(newlySelected && newlySelected.length) this._trigger('select', event, this._uiHash(newlySelected, 'added'));
+ // Ending the selection does a diff and then triggers appropriate events
+ this._endSelection(event, newlySelected);
},
@@ -557,54 +656,118 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
if (!item.length) return;
//Set the current selection to the previous/next item
- this.previousFocus = this.currentFocus;
- this.currentFocus = item;
+ this.previousFocus = this.currentFocus.attr('tabindex', -1);
+ this.currentFocus = item.attr('tabindex', 0);
- this.previousFocus.removeClass('ui-focused');
- this.currentFocus.addClass('ui-focused');
+ this.previousFocus.removeClass('ui-state-focus');
+ this.currentFocus.addClass('ui-state-focus');
//Set and update the selection
+ this._previousSelection = this._selection.slice();
var newlySelected = this._updateSelection(event, index);
- //Trigger select event
- if(newlySelected && newlySelected.length) this._trigger('select', event, this._uiHash(newlySelected, 'added'));
+ // Ending the selection does a diff and then triggers appropriate events
+ this._endSelection(event, newlySelected);
},
- selectPrevious: function(event) {
+ previous: function(event) {
this._selectAdjacent(event, -1);
},
- selectNext: function(event) {
+ next: function(event) {
this._selectAdjacent(event, 1);
},
- refresh: function() {
+ refresh: function(fromInside) {
- var o = this.options;
+ var o = this.options, self = this;
this.items = $(o.filter, this.element);
+ this.items.addClass('ui-selectable-item');
this.items.each(function() {
+
var $this = $(this);
var pos = $this.offset();
+
+ if(self.currentFocus && self.currentFocus[0] != this)
+ $this.attr('tabindex', -1);
+
$.data(this, "selectable-item", {
left: pos.left,
top: pos.top,
right: pos.left + $this.width(),
bottom: pos.top + $this.height(),
startSelected: false,
- selected: $this.hasClass(o.selectedClass)
+ selected: $this.hasClass('ui-selected')
});
});
+
+
+ if(!fromInside) {
+ this._previousSelection = this._selection.slice();
+ this._selection = [];
+ for (var i=0; i < this._previousSelection.length; i++) {
+ if(this._previousSelection[i][0].parentNode) this._selection.push(this._previousSelection[i]);
+ };
+
+ this._endSelection();
+ }
+
},
select: function(item) {
- //TODO
+
+ if(!isNaN(parseInt(item)))
+ item = this.items.get(item);
+
+ item = $(item, this.element);
+ if(!item.length) return;
+
+ // clear the current selection
+ this._clearSelection();
+
+ // select all found
+ var newlySelected = [], self = this;
+ item.each(function(i) {
+ if(i == 0) { //Setting the focus on the first item in the list
+ self.previousFocus = self.currentFocus.attr('tabindex', -1);
+ self.currentFocus = $(this).attr('tabindex', 0);
+ self.previousFocus.removeClass('ui-state-focus');
+ self.currentFocus.addClass('ui-state-focus');
+ }
+ newlySelected.push(self._addToSelection($(this)));
+ });
+
+ // Ending the selection does a diff and then triggers appropriate events
+ this._endSelection(event, $($.map(newlySelected, function(i) { return i[0]; })));
+
},
deselect: function(item) {
- if(!item) this._clearSelection(true);
- //TODO: Deselect single elements
+
+ // if no item was specified, deselect all
+ if(!item)
+ this._clearSelection(true);
+
+ if(!isNaN(parseInt(item)))
+ item = this.items.get(item);
+
+ item = $(item, this.element);
+ if(!item.length) return;
+
+ //store the current selection
+ this._previousSelection = this._selection.slice();
+
+ // deselect all found
+ var self = this;
+ item.each(function() {
+ self._removeFromSelection($(this));
+ });
+
+ // Ending the selection does a diff and then triggers appropriate events
+ this._endSelection(event);
+
},
_uiHash: function(items, specialKey) {
@@ -621,15 +784,7 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
$.extend($.ui.selectable, {
defaults: {
-
- //TODO: Figure out how to move these defaults out
- cancel: ":input,option",
- delay: 0,
- distance: 1,
- appendTo: 'body',
-
- multiple: true,
- smart: true,
+ closest: true,
filter: '> *',
keyboard: true,
@@ -639,10 +794,7 @@ jQuery.effects||(function(d){d.effects={version:"1.7.2",save:function(g,h){for(v
distance: 1,
tolerance: 'touch',
appendTo: 'body'
- },
-
- //Should we really delete that?
- selectedClass: 'ui-state-selected'
+ }
}
});