Improve output: distinguish between failed assertions (failures) and unexpected exceptions (errors), and print a filtered stack trace for any exception.
This commit is contained in:
commit
4f2e303079
1839 changed files with 235630 additions and 0 deletions
425
webapp/web/src/selection/Selection.js
Normal file
425
webapp/web/src/selection/Selection.js
Normal file
|
@ -0,0 +1,425 @@
|
|||
/*
|
||||
Copyright (c) 2004-2006, The Dojo Foundation
|
||||
All Rights Reserved.
|
||||
|
||||
Licensed under the Academic Free License version 2.1 or above OR the
|
||||
modified BSD license. For more information on Dojo licensing, see:
|
||||
|
||||
http://dojotoolkit.org/community/licensing.shtml
|
||||
*/
|
||||
|
||||
dojo.provide("dojo.selection.Selection");
|
||||
dojo.require("dojo.lang.array");
|
||||
dojo.require("dojo.lang.func");
|
||||
dojo.require("dojo.math");
|
||||
|
||||
dojo.selection.Selection = function(items, isCollection) {
|
||||
this.items = [];
|
||||
this.selection = [];
|
||||
this._pivotItems = [];
|
||||
this.clearItems();
|
||||
|
||||
if(items) {
|
||||
if(isCollection) {
|
||||
this.setItemsCollection(items);
|
||||
} else {
|
||||
this.setItems(items);
|
||||
}
|
||||
}
|
||||
}
|
||||
dojo.lang.extend(dojo.selection.Selection, {
|
||||
items: null, // items to select from, order matters for growable selections
|
||||
|
||||
selection: null, // items selected, aren't stored in order (see sorted())
|
||||
lastSelected: null, // last item selected
|
||||
|
||||
allowImplicit: true, // if true, grow selection will start from 0th item when nothing is selected
|
||||
length: 0, // number of *selected* items
|
||||
|
||||
// if true, the selection is treated as an in-order and can grow by ranges, not just by single item
|
||||
isGrowable: true,
|
||||
|
||||
_pivotItems: null, // stack of pivot items
|
||||
_pivotItem: null, // item we grow selections from, top of stack
|
||||
|
||||
// event handlers
|
||||
onSelect: function(item) {},
|
||||
onDeselect: function(item) {},
|
||||
onSelectChange: function(item, selected) {},
|
||||
|
||||
_find: function(item, inSelection) {
|
||||
if(inSelection) {
|
||||
return dojo.lang.find(item, this.selection);
|
||||
} else {
|
||||
return dojo.lang.find(item, this.items);
|
||||
}
|
||||
},
|
||||
|
||||
isSelectable: function(item) {
|
||||
// user-customizable, will filter items through this
|
||||
return true;
|
||||
},
|
||||
|
||||
setItems: function(/* ... */) {
|
||||
this.clearItems();
|
||||
this.addItems.call(this, arguments);
|
||||
},
|
||||
|
||||
// this is in case you have an active collection array-like object
|
||||
// (i.e. getElementsByTagName collection) that manages its own order
|
||||
// and item list
|
||||
setItemsCollection: function(collection) {
|
||||
this.items = collection;
|
||||
},
|
||||
|
||||
addItems: function(/* ... */) {
|
||||
var args = dojo.lang.unnest(arguments);
|
||||
for(var i = 0; i < args.length; i++) {
|
||||
this.items.push(args[i]);
|
||||
}
|
||||
},
|
||||
|
||||
addItemsAt: function(item, before /* ... */) {
|
||||
if(this.items.length == 0) { // work for empy case
|
||||
return this.addItems(dojo.lang.toArray(arguments, 2));
|
||||
}
|
||||
|
||||
if(!this.isItem(item)) {
|
||||
item = this.items[item];
|
||||
}
|
||||
if(!item) { throw new Error("addItemsAt: item doesn't exist"); }
|
||||
var idx = this._find(item);
|
||||
if(idx > 0 && before) { idx--; }
|
||||
for(var i = 2; i < arguments.length; i++) {
|
||||
if(!this.isItem(arguments[i])) {
|
||||
this.items.splice(idx++, 0, arguments[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeItem: function(item) {
|
||||
// remove item
|
||||
var idx = this._find(item);
|
||||
if(idx > -1) {
|
||||
this.items.splice(idx, 1);
|
||||
}
|
||||
// remove from selection
|
||||
// FIXME: do we call deselect? I don't think so because this isn't how
|
||||
// you usually want to deselect an item. For example, if you deleted an
|
||||
// item, you don't really want to deselect it -- you want it gone. -DS
|
||||
idx = this._find(item, true);
|
||||
if(idx > -1) {
|
||||
this.selection.splice(idx, 1);
|
||||
}
|
||||
},
|
||||
|
||||
clearItems: function() {
|
||||
this.items = [];
|
||||
this.deselectAll();
|
||||
},
|
||||
|
||||
isItem: function(item) {
|
||||
return this._find(item) > -1;
|
||||
},
|
||||
|
||||
isSelected: function(item) {
|
||||
return this._find(item, true) > -1;
|
||||
},
|
||||
|
||||
/**
|
||||
* allows you to filter item in or out of the selection
|
||||
* depending on the current selection and action to be taken
|
||||
**/
|
||||
selectFilter: function(item, selection, add, grow) {
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* update -- manages selections, most selecting should be done here
|
||||
* item => item which may be added/grown to/only selected/deselected
|
||||
* add => behaves like ctrl in windows selection world
|
||||
* grow => behaves like shift
|
||||
* noToggle => if true, don't toggle selection on item
|
||||
**/
|
||||
update: function(item, add, grow, noToggle) {
|
||||
if(!this.isItem(item)) { return false; }
|
||||
|
||||
if(this.isGrowable && grow) {
|
||||
if(!this.isSelected(item)
|
||||
&& this.selectFilter(item, this.selection, false, true)) {
|
||||
this.grow(item);
|
||||
this.lastSelected = item;
|
||||
}
|
||||
} else if(add) {
|
||||
if(this.selectFilter(item, this.selection, true, false)) {
|
||||
if(noToggle) {
|
||||
if(this.select(item)) {
|
||||
this.lastSelected = item;
|
||||
}
|
||||
} else if(this.toggleSelected(item)) {
|
||||
this.lastSelected = item;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.deselectAll();
|
||||
this.select(item);
|
||||
}
|
||||
|
||||
this.length = this.selection.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Grow a selection.
|
||||
* toItem => which item to grow selection to
|
||||
* fromItem => which item to start the growth from (it won't be selected)
|
||||
*
|
||||
* Any items in (fromItem, lastSelected] that aren't part of
|
||||
* (fromItem, toItem] will be deselected
|
||||
**/
|
||||
grow: function(toItem, fromItem) {
|
||||
if(!this.isGrowable) { return; }
|
||||
|
||||
if(arguments.length == 1) {
|
||||
fromItem = this._pivotItem;
|
||||
if(!fromItem && this.allowImplicit) {
|
||||
fromItem = this.items[0];
|
||||
}
|
||||
}
|
||||
if(!toItem || !fromItem) { return false; }
|
||||
|
||||
var fromIdx = this._find(fromItem);
|
||||
|
||||
// get items to deselect (fromItem, lastSelected]
|
||||
var toDeselect = {};
|
||||
var lastIdx = -1;
|
||||
if(this.lastSelected) {
|
||||
lastIdx = this._find(this.lastSelected);
|
||||
var step = fromIdx < lastIdx ? -1 : 1;
|
||||
var range = dojo.math.range(lastIdx, fromIdx, step);
|
||||
for(var i = 0; i < range.length; i++) {
|
||||
toDeselect[range[i]] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// add selection (fromItem, toItem]
|
||||
var toIdx = this._find(toItem);
|
||||
var step = fromIdx < toIdx ? -1 : 1;
|
||||
var shrink = lastIdx >= 0 && step == 1 ? lastIdx < toIdx : lastIdx > toIdx;
|
||||
var range = dojo.math.range(toIdx, fromIdx, step);
|
||||
if(range.length) {
|
||||
for(var i = range.length-1; i >= 0; i--) {
|
||||
var item = this.items[range[i]];
|
||||
if(this.selectFilter(item, this.selection, false, true)) {
|
||||
if(this.select(item, true) || shrink) {
|
||||
this.lastSelected = item;
|
||||
}
|
||||
if(range[i] in toDeselect) {
|
||||
delete toDeselect[range[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.lastSelected = fromItem;
|
||||
}
|
||||
|
||||
// now deselect...
|
||||
for(var i in toDeselect) {
|
||||
if(this.items[i] == this.lastSelected) {
|
||||
//dojo.debug("oops!");
|
||||
}
|
||||
this.deselect(this.items[i]);
|
||||
}
|
||||
|
||||
// make sure everything is all kosher after selections+deselections
|
||||
this._updatePivot();
|
||||
},
|
||||
|
||||
/**
|
||||
* Grow selection upwards one item from lastSelected
|
||||
**/
|
||||
growUp: function() {
|
||||
if(!this.isGrowable) { return; }
|
||||
|
||||
var idx = this._find(this.lastSelected) - 1;
|
||||
while(idx >= 0) {
|
||||
if(this.selectFilter(this.items[idx], this.selection, false, true)) {
|
||||
this.grow(this.items[idx]);
|
||||
break;
|
||||
}
|
||||
idx--;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Grow selection downwards one item from lastSelected
|
||||
**/
|
||||
growDown: function() {
|
||||
if(!this.isGrowable) { return; }
|
||||
|
||||
var idx = this._find(this.lastSelected);
|
||||
if(idx < 0 && this.allowImplicit) {
|
||||
this.select(this.items[0]);
|
||||
idx = 0;
|
||||
}
|
||||
idx++;
|
||||
while(idx > 0 && idx < this.items.length) {
|
||||
if(this.selectFilter(this.items[idx], this.selection, false, true)) {
|
||||
this.grow(this.items[idx]);
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
},
|
||||
|
||||
toggleSelected: function(item, noPivot) {
|
||||
if(this.isItem(item)) {
|
||||
if(this.select(item, noPivot)) { return 1; }
|
||||
if(this.deselect(item)) { return -1; }
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
|
||||
select: function(item, noPivot) {
|
||||
if(this.isItem(item) && !this.isSelected(item)
|
||||
&& this.isSelectable(item)) {
|
||||
this.selection.push(item);
|
||||
this.lastSelected = item;
|
||||
this.onSelect(item);
|
||||
this.onSelectChange(item, true);
|
||||
if(!noPivot) {
|
||||
this._addPivot(item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
deselect: function(item) {
|
||||
var idx = this._find(item, true);
|
||||
if(idx > -1) {
|
||||
this.selection.splice(idx, 1);
|
||||
this.onDeselect(item);
|
||||
this.onSelectChange(item, false);
|
||||
if(item == this.lastSelected) {
|
||||
this.lastSelected = null;
|
||||
}
|
||||
|
||||
this._removePivot(item);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
selectAll: function() {
|
||||
for(var i = 0; i < this.items.length; i++) {
|
||||
this.select(this.items[i]);
|
||||
}
|
||||
},
|
||||
|
||||
deselectAll: function() {
|
||||
while(this.selection && this.selection.length) {
|
||||
this.deselect(this.selection[0]);
|
||||
}
|
||||
},
|
||||
|
||||
selectNext: function() {
|
||||
var idx = this._find(this.lastSelected);
|
||||
while(idx > -1 && ++idx < this.items.length) {
|
||||
if(this.isSelectable(this.items[idx])) {
|
||||
this.deselectAll();
|
||||
this.select(this.items[idx]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
selectPrevious: function() {
|
||||
//debugger;
|
||||
var idx = this._find(this.lastSelected);
|
||||
while(idx-- > 0) {
|
||||
if(this.isSelectable(this.items[idx])) {
|
||||
this.deselectAll();
|
||||
this.select(this.items[idx]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// select first selectable item
|
||||
selectFirst: function() {
|
||||
this.deselectAll();
|
||||
var idx = 0;
|
||||
while(this.items[idx] && !this.select(this.items[idx])) {
|
||||
idx++;
|
||||
}
|
||||
return this.items[idx] ? true : false;
|
||||
},
|
||||
|
||||
// select last selectable item
|
||||
selectLast: function() {
|
||||
this.deselectAll();
|
||||
var idx = this.items.length-1;
|
||||
while(this.items[idx] && !this.select(this.items[idx])) {
|
||||
idx--;
|
||||
}
|
||||
return this.items[idx] ? true : false;
|
||||
},
|
||||
|
||||
_addPivot: function(item, andClear) {
|
||||
this._pivotItem = item;
|
||||
if(andClear) {
|
||||
this._pivotItems = [item];
|
||||
} else {
|
||||
this._pivotItems.push(item);
|
||||
}
|
||||
},
|
||||
|
||||
_removePivot: function(item) {
|
||||
var i = dojo.lang.find(item, this._pivotItems);
|
||||
if(i > -1) {
|
||||
this._pivotItems.splice(i, 1);
|
||||
this._pivotItem = this._pivotItems[this._pivotItems.length-1];
|
||||
}
|
||||
|
||||
this._updatePivot();
|
||||
},
|
||||
|
||||
_updatePivot: function() {
|
||||
if(this._pivotItems.length == 0) {
|
||||
if(this.lastSelected) {
|
||||
this._addPivot(this.lastSelected);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
sorted: function() {
|
||||
return dojo.lang.toArray(this.selection).sort(
|
||||
dojo.lang.hitch(this, function(a, b) {
|
||||
var A = this._find(a), B = this._find(b);
|
||||
if(A > B) {
|
||||
return 1;
|
||||
} else if(A < B) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
// remove any items from the selection that are no longer in this.items
|
||||
updateSelected: function() {
|
||||
for(var i = 0; i < this.selection.length; i++) {
|
||||
if(this._find(this.selection[i]) < 0) {
|
||||
var removed = this.selection.splice(i, 1);
|
||||
|
||||
this._removePivot(removed[0]);
|
||||
}
|
||||
}
|
||||
|
||||
this.length = this.selection.length;
|
||||
}
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue