add Ox.TreeList, fix Ox.List bugs

This commit is contained in:
rlx 2011-02-07 18:57:05 +00:00
parent c31850f0c4
commit d7badfe326
3 changed files with 281 additions and 60 deletions

View file

@ -894,47 +894,48 @@ Lists
right: 0;
bottom: 0;
}
.OxTextList .OxBody .OxContent {
.OxTextList .OxContent {
//width: 100%;
}
.OxTextList .OxBody .OxItem {
.OxTextList .OxItem {
height: 16px;
cursor: default;
}
.OxTextList .OxBody .OxItem .OxCell {
.OxTextList .OxItem .OxCell {
float: left;
height: 14px;
padding: 1px 4px 1px 4px;
border-right: 1px solid;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.OxTextList .OxBody .OxItem .OxCell.OxEdit {
.OxTextList .OxItem .OxCell.OxEdit {
height: 16px;
padding: 0;
}
.OxTextList .OxBody .OxItem .OxCell > img {
.OxTextList .OxItem .OxCell > img {
width: 16px;
height: 16px;
margin: -1px 0 0 -4px;
}
.OxTextList .OxBody .OxItem .OxSpace {
.OxTextList .OxItem .OxSpace {
float: left;
width: 4px;
height: 16px;
}
.OxTextList .OxBody .OxItem .OxLine {
.OxTextList .OxItem .OxLine {
float: left;
width: 1px;
height: 16px;
}
.OxTextList .OxBody .OxItem.OxSelected .OxCell.OxClickable {
.OxTextList .OxItem.OxSelected .OxCell.OxClickable {
cursor: pointer;
}
.OxTextList .OxBody .OxItem.OxSelected .OxCell.OxEditable {
.OxTextList .OxItem.OxSelected .OxCell.OxEditable {
cursor: text;
}
.OxTextList .OxBody .OxItem.OxSelected.OxDrag .OxCell {
.OxTextList .OxItem.OxSelected.OxDrag .OxCell {
cursor: ns-resize;
}
.OxTextList .OxPage {
@ -943,6 +944,9 @@ Lists
.OxTextList.OxDrop .OxItem .OxCell {
color: green;
}
.OxTreeList .OxItem .OxCell {
border-right-width: 0
}
/*
================================================================================

View file

@ -238,13 +238,13 @@ Lists
border-color: rgb(24, 24, 24);
}
.OxThemeModern .OxTextList .OxBody .OxItem .OxCell {
border-right: 1px solid rgb(24, 24, 24);
border-right-color: rgb(24, 24, 24);
}
.OxThemeModern .OxTextList .OxItem.OxSelected .OxCell {
border-right: 1px solid rgb(40, 40, 40);
border-right-color: rgb(40, 40, 40);
}
.OxThemeModern .OxTextList .OxFocus .OxItem.OxSelected .OxCell {
border-right: 1px solid rgb(72, 72, 72);
border-right-color: rgb(72, 72, 72);
color: rgb(255, 255, 255);
}
.OxThemeModern .OxTextList .OxBody .OxItem .OxLine {

View file

@ -957,6 +957,10 @@ requires
// (to be implemented by widget)
};
that._leakSelf = function() { // fixme: remove
return self;
}
that.bindEvent = function() {
/***
binds a function to an event triggered by this object
@ -6512,7 +6516,6 @@ requires
clickTimeout: 0,
dragTimeout: 0,
format: {},
ids: [],
itemMargin: self.options.type == 'text' ? 0 : 8, // 2 x 4 px margin ... fixme: the 2x should be computed later
keyboardEvents: {
key_control_c: copyItems,
@ -6556,7 +6559,16 @@ requires
'key_' + (self.options.orientation == 'vertical' ? 'shift_down' : 'shift_right')
] = addNextToSelection;
}
if (self.options.orientation == 'both') {
if (self.options.orientation == 'vertical') {
$.extend(self.keyboardEvents, {
key_left: function() {
triggerToggleEvent(false);
},
key_right: function() {
triggerToggleEvent(true);
}
});
} else if (self.options.orientation == 'both') {
$.extend(self.keyboardEvents, {
key_down: selectBelow,
key_up: selectAbove
@ -6745,7 +6757,7 @@ requires
pos: findItemPosition(e)
};
$.extend(self.drag, {
id: self.ids[self.drag.pos],
id: self.$items[self.drag.pos].options('data')[self.options.unique],
startPos: self.drag.pos,
startY: e.clientY,
stopPos: self.drag.pos
@ -6779,14 +6791,16 @@ requires
});
that.triggerEvent('move', {
//id: id,
ids: self.ids
ids: $.map(self.$items, function($item) {
return $item.options('data')[self.options.unique];
})
//position: pos
});
}
function dragItem(pos, e) {
var $item = self.$items[pos],
id = self.ids[pos],
id = self.$items[pos].options('data')[self.options.unique],
startPos = pos,
startY = e.clientY,
stopPos = startPos,
@ -6824,7 +6838,9 @@ requires
});
that.triggerEvent('move', {
//id: id,
ids: self.ids
ids: $.map(self.$items, function($item) {
return $item.options('data')[self.options.unique];
})
//position: pos
});
}
@ -6960,8 +6976,8 @@ requires
function getPositionById(id) {
// fixme: is this really needed?
var pos = -1;
$.each(self.ids, function(i, v) {
if (v == id) {
$.each(self.$items, function(i, $item) {
if ($item.options('data')[self.options.unique] == id) {
pos = i;
return false;
}
@ -7038,9 +7054,9 @@ requires
}
function getSelectedIds() {
// fixme: is carring self.ids around the best way?
Ox.print('gSI', self.selected)
return $.map(self.selected, function(pos) {
return self.ids[pos];
return self.$items[pos].options('data')[self.options.unique];
});
}
@ -7097,7 +7113,6 @@ requires
self.$pages[page] = new Ox.ListPage().css(getPageCSS(page));
$.each(result.data.items, function(i, v) {
var pos = offset + i;
self.ids[pos] = v[self.options.unique]; // fixme: why not use self.$items[pos].options('id')?
self.$items[pos] = new Ox.ListItem({
construct: self.options.construct,
data: v,
@ -7226,6 +7241,7 @@ requires
addAllToSelection(pos);
}
} else if (!isSelected(pos)) {
Ox.print('select', pos)
select(pos);
} else if (self.selected.length > 1) {
// this could be the first click
@ -7274,7 +7290,7 @@ requires
self.clickTimeout = 0;
open();
}
} else if (self.options.min == 0) {
} else if (!$(e.target).hasClass('OxToggle') && self.options.min == 0) {
selectNone();
}
}
@ -7285,9 +7301,7 @@ requires
$item.detach()[insert](self.$items[stopPos].$element); // fixme: why do we need .$element here?
//Ox.print('moveItem', startPos, stopPos, insert, self.ids);
var $item = self.$items.splice(startPos, 1)[0];
id = self.ids.splice(startPos, 1)[0];
self.$items.splice(stopPos, 0, $item);
self.ids.splice(stopPos, 0, id);
self.$items.forEach(function($item, pos) {
$item.data({position: pos});
});
@ -7534,6 +7548,13 @@ requires
}, 100);
}
function triggerToggleEvent(expanded) {
that.triggerEvent('toggle', {
expanded: expanded,
ids: getSelectedIds()
});
}
function unloadPage(page) {
if (page < 0 || page >= self.pages) {
return;
@ -7553,6 +7574,33 @@ requires
unloadPage(page + 1)
}
function updatePages(pos, scroll) {
// only used if orientation is both
clear();
self.pageLength = self.pageLengthByRowLength[self.rowLength]
$.extend(self, {
listSize: getListSize(),
pages: Math.ceil(self.listLength / self.pageLength),
pageWidth: (self.options.itemWidth + self.itemMargin) * self.rowLength,
pageHeight: getPageHeight()
});
that.$content.css({
height: self.listSize + 'px'
});
self.page = getPageByPosition(pos);
//that.scrollTop(0);
that.$content.empty();
loadPages(self.page, function() {
scrollTo(scroll);
});
}
function updatePositions() {
self.$items.forEach(function(item, pos) {
item.data('position', pos);
});
}
function updateQuery(ids) { // fixme: shouldn't this be setQuery?
// ids are the selcected ids
// (in case list is loaded with selection)
@ -7585,27 +7633,6 @@ requires
}));
}
function updatePages(pos, scroll) {
// only used if orientation is both
clear();
self.pageLength = self.pageLengthByRowLength[self.rowLength]
$.extend(self, {
listSize: getListSize(),
pages: Math.ceil(self.listLength / self.pageLength),
pageWidth: (self.options.itemWidth + self.itemMargin) * self.rowLength,
pageHeight: getPageHeight()
});
that.$content.css({
height: self.listSize + 'px'
});
self.page = getPageByPosition(pos);
//that.scrollTop(0);
that.$content.empty();
loadPages(self.page, function() {
scrollTo(scroll);
});
}
function updateSort() {
if (self.listLength > 1) {
clear();
@ -7622,6 +7649,39 @@ requires
}
};
that.addItems = function(pos, items) {
var $items = [],
length = items.length;
self.selected.forEach(function(v, i) {
if (v >= pos) {
self.selected[i] += length;
}
});
items.forEach(function(item, i) {
var $item;
$items.push($item = new Ox.ListItem({
construct: self.options.construct,
data: item,
draggable: self.options.draggable,
position: pos + i,
unique: self.options.unique
}));
if (i == 0) {
if (pos == 0) {
$item.insertBefore(self.$items[0]);
} else {
$item.insertAfter(self.$items[pos - 1]);
}
} else {
$item.insertAfter($items[i - 1]);
}
});
self.options.items.splice.apply(self.options.items, $.merge([pos, 0], items));
self.$items.splice.apply(self.$items, $.merge([pos, 0], $items));
updatePositions();
Ox.print('s.o.i', self.options.items, 's.$i', $.map(self.$items, function(v) {return v.data()}))
}
that.clearCache = function() { // fixme: was used by TextList resizeColumn, now probably no longer necessary
self.$pages = [];
return that;
@ -7652,19 +7712,26 @@ requires
return that;
};
that.removeItems = function(pos, length) {
Ox.range(pos, pos + length).forEach(function(i) {
self.selected.indexOf(i) > -1 && deselect(i);
self.$items[i].remove();
});
self.options.items.splice(pos, length);
self.$items.splice(pos, length);
self.selected.forEach(function(v, i) {
if (v >= pos + length) {
self.selected[i] -= length;
}
});
updatePositions();
}
that.scrollToSelection = function() {
self.selected.length && scrollToPosition(self.selected[0]);
return that;
};
that.setId = function(oldId, newId) { // fixme: not used
var index = self.ids.indexOf(oldId);
if (index > -1) {
self.ids[index] = newId;
}
return that;
};
that.size = function() { // fixme: not a good function name
if (self.options.orientation == 'both') {
var rowLength = getRowLength(),
@ -7725,9 +7792,6 @@ requires
oldValue = data[key];
data[key] = value;
$item.options({data: data});
if (key == self.options.unique) {
self.ids[self.ids.indexOf(oldValue)] = value;
}
return that;
}
};
@ -7753,7 +7817,7 @@ requires
function constructItem(update) {
var $element = self.options.construct(self.options.data)
.addClass('OxItem')
.addClass('OxItem OxDeleteme' + self.options.data[self.options.unique])
.attr({
draggable: self.options.draggable
})
@ -8506,6 +8570,159 @@ requires
};
Ox.TreeList = function(options, self) {
var self = self || {},
that = new Ox.Element('div', self)
.defaults({
items: [],
max: -1,
min: 0,
selected: [],
width: 256
})
.options(options || {});
that.$element = new Ox.List({
construct: constructItem,
itemHeight: 16,
items: parseItems(),
itemWidth: self.options.width,
max: self.options.max,
min: self.options.min,
unique: 'id',
}, $.extend({}, self))
.addClass('OxTextList OxTreeList')
.css({
width: self.options.width + 'px'
})
.click(clickItem)
.bindEvent({
toggle: toggleItems
});
function clickItem(e) {
var $target = $(e.target),
$item, id, item;
if ($target.hasClass('OxToggle')) {
$item = $target.parent().parent();
id = $item.data('id');
item = getItemById(id);
toggleItem(item, !item.expanded)
}
}
function constructItem(data) {
var $item = $('<div>'),
padding = (data.level + !data.items) * 16 - 8;
if (data.level || !data.items) {
$('<div>')
.addClass('OxCell OxTarget')
.css({
width: padding + 'px',
})
.appendTo($item);
}
if (data.items) {
$('<div>')
.addClass('OxCell')
.css({
width: '8px',
})
.append(
// fixme: need Ox.Icon()
$('<img>')
.addClass('OxToggle')
.attr({
src: oxui.path + '/png/ox.ui.' + Ox.theme() + '/symbol' +
(data.expanded ? 'Collapse' : 'Expand') + '.png'
})
)
.appendTo($item);
}
$('<div>')
.addClass('OxCell OxTarget')
.css({
width: (self.options.width - padding - 32) + 'px'
})
.html(data.title)
.appendTo($item);
return $item;
}
function getItemById(id, items, level) {
var items = items || self.options.items,
level = level || 0,
ret = null;
$.each(items, function(i, item) {
if (item.id == id) {
ret = $.extend(item, {
level: level
});
return false;
}
if (item.items) {
ret = getItemById(id, item.items, level + 1);
if (ret) {
return false;
}
}
});
return ret;
}
function parseItems(items, level) {
var items = items || self.options.items,
level = level || 0,
ret = [];
items.forEach(function(item, i) {
var item_ = $.extend({
level: level
}, item, item.items ? {
items: !!item.expanded ?
parseItems(item.items, level + 1) : []
} : {});
ret.push(item_);
item.items && $.merge(ret, item_.items);
});
return ret;
}
function toggleItem(item, expanded) {
var $img, $item, pos;
item.expanded = expanded;
$.each(that.$element.find('.OxItem'), function(i, v) {
var $item = $(v);
if ($item.data('id') == item.id) {
$img = $item.find('img');
pos = $item.data('position');
return false;
}
})
$img.attr({
src: oxui.path + '/png/ox.ui.' + Ox.theme() + '/symbol' +
(item.expanded ? 'Collapse' : 'Expand') + '.png'
});
item.expanded ?
that.$element.addItems(pos + 1, parseItems(item.items, item.level + 1)) :
that.$element.removeItems(pos + 1, parseItems(item.items, item.level + 1).length);
}
function toggleItems(event, data) {
data.ids.forEach(function(id, i) {
var item = getItemById(id);
Ox.print('item', item, !!item.items, data.expanded != !!item.expanded)
if (item.items && data.expanded != !!item.expanded) {
Ox.print('ITEM', item)
toggleItem(item, data.expanded);
}
});
}
return that;
};
/*
============================================================================
Maps