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

View file

@ -238,13 +238,13 @@ Lists
border-color: rgb(24, 24, 24); border-color: rgb(24, 24, 24);
} }
.OxThemeModern .OxTextList .OxBody .OxItem .OxCell { .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 { .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 { .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); color: rgb(255, 255, 255);
} }
.OxThemeModern .OxTextList .OxBody .OxItem .OxLine { .OxThemeModern .OxTextList .OxBody .OxItem .OxLine {

View file

@ -957,6 +957,10 @@ requires
// (to be implemented by widget) // (to be implemented by widget)
}; };
that._leakSelf = function() { // fixme: remove
return self;
}
that.bindEvent = function() { that.bindEvent = function() {
/*** /***
binds a function to an event triggered by this object binds a function to an event triggered by this object
@ -6512,7 +6516,6 @@ requires
clickTimeout: 0, clickTimeout: 0,
dragTimeout: 0, dragTimeout: 0,
format: {}, format: {},
ids: [],
itemMargin: self.options.type == 'text' ? 0 : 8, // 2 x 4 px margin ... fixme: the 2x should be computed later itemMargin: self.options.type == 'text' ? 0 : 8, // 2 x 4 px margin ... fixme: the 2x should be computed later
keyboardEvents: { keyboardEvents: {
key_control_c: copyItems, key_control_c: copyItems,
@ -6556,7 +6559,16 @@ requires
'key_' + (self.options.orientation == 'vertical' ? 'shift_down' : 'shift_right') 'key_' + (self.options.orientation == 'vertical' ? 'shift_down' : 'shift_right')
] = addNextToSelection; ] = 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, { $.extend(self.keyboardEvents, {
key_down: selectBelow, key_down: selectBelow,
key_up: selectAbove key_up: selectAbove
@ -6745,7 +6757,7 @@ requires
pos: findItemPosition(e) pos: findItemPosition(e)
}; };
$.extend(self.drag, { $.extend(self.drag, {
id: self.ids[self.drag.pos], id: self.$items[self.drag.pos].options('data')[self.options.unique],
startPos: self.drag.pos, startPos: self.drag.pos,
startY: e.clientY, startY: e.clientY,
stopPos: self.drag.pos stopPos: self.drag.pos
@ -6779,14 +6791,16 @@ requires
}); });
that.triggerEvent('move', { that.triggerEvent('move', {
//id: id, //id: id,
ids: self.ids ids: $.map(self.$items, function($item) {
return $item.options('data')[self.options.unique];
})
//position: pos //position: pos
}); });
} }
function dragItem(pos, e) { function dragItem(pos, e) {
var $item = self.$items[pos], var $item = self.$items[pos],
id = self.ids[pos], id = self.$items[pos].options('data')[self.options.unique],
startPos = pos, startPos = pos,
startY = e.clientY, startY = e.clientY,
stopPos = startPos, stopPos = startPos,
@ -6824,7 +6838,9 @@ requires
}); });
that.triggerEvent('move', { that.triggerEvent('move', {
//id: id, //id: id,
ids: self.ids ids: $.map(self.$items, function($item) {
return $item.options('data')[self.options.unique];
})
//position: pos //position: pos
}); });
} }
@ -6960,8 +6976,8 @@ requires
function getPositionById(id) { function getPositionById(id) {
// fixme: is this really needed? // fixme: is this really needed?
var pos = -1; var pos = -1;
$.each(self.ids, function(i, v) { $.each(self.$items, function(i, $item) {
if (v == id) { if ($item.options('data')[self.options.unique] == id) {
pos = i; pos = i;
return false; return false;
} }
@ -7038,9 +7054,9 @@ requires
} }
function getSelectedIds() { function getSelectedIds() {
// fixme: is carring self.ids around the best way? Ox.print('gSI', self.selected)
return $.map(self.selected, function(pos) { 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)); self.$pages[page] = new Ox.ListPage().css(getPageCSS(page));
$.each(result.data.items, function(i, v) { $.each(result.data.items, function(i, v) {
var pos = offset + i; 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({ self.$items[pos] = new Ox.ListItem({
construct: self.options.construct, construct: self.options.construct,
data: v, data: v,
@ -7226,6 +7241,7 @@ requires
addAllToSelection(pos); addAllToSelection(pos);
} }
} else if (!isSelected(pos)) { } else if (!isSelected(pos)) {
Ox.print('select', pos)
select(pos); select(pos);
} else if (self.selected.length > 1) { } else if (self.selected.length > 1) {
// this could be the first click // this could be the first click
@ -7274,7 +7290,7 @@ requires
self.clickTimeout = 0; self.clickTimeout = 0;
open(); open();
} }
} else if (self.options.min == 0) { } else if (!$(e.target).hasClass('OxToggle') && self.options.min == 0) {
selectNone(); selectNone();
} }
} }
@ -7285,9 +7301,7 @@ requires
$item.detach()[insert](self.$items[stopPos].$element); // fixme: why do we need .$element here? $item.detach()[insert](self.$items[stopPos].$element); // fixme: why do we need .$element here?
//Ox.print('moveItem', startPos, stopPos, insert, self.ids); //Ox.print('moveItem', startPos, stopPos, insert, self.ids);
var $item = self.$items.splice(startPos, 1)[0]; var $item = self.$items.splice(startPos, 1)[0];
id = self.ids.splice(startPos, 1)[0];
self.$items.splice(stopPos, 0, $item); self.$items.splice(stopPos, 0, $item);
self.ids.splice(stopPos, 0, id);
self.$items.forEach(function($item, pos) { self.$items.forEach(function($item, pos) {
$item.data({position: pos}); $item.data({position: pos});
}); });
@ -7534,6 +7548,13 @@ requires
}, 100); }, 100);
} }
function triggerToggleEvent(expanded) {
that.triggerEvent('toggle', {
expanded: expanded,
ids: getSelectedIds()
});
}
function unloadPage(page) { function unloadPage(page) {
if (page < 0 || page >= self.pages) { if (page < 0 || page >= self.pages) {
return; return;
@ -7553,6 +7574,33 @@ requires
unloadPage(page + 1) 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? function updateQuery(ids) { // fixme: shouldn't this be setQuery?
// ids are the selcected ids // ids are the selcected ids
// (in case list is loaded with selection) // (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() { function updateSort() {
if (self.listLength > 1) { if (self.listLength > 1) {
clear(); 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 that.clearCache = function() { // fixme: was used by TextList resizeColumn, now probably no longer necessary
self.$pages = []; self.$pages = [];
return that; return that;
@ -7652,19 +7712,26 @@ requires
return that; 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() { that.scrollToSelection = function() {
self.selected.length && scrollToPosition(self.selected[0]); self.selected.length && scrollToPosition(self.selected[0]);
return that; 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 that.size = function() { // fixme: not a good function name
if (self.options.orientation == 'both') { if (self.options.orientation == 'both') {
var rowLength = getRowLength(), var rowLength = getRowLength(),
@ -7725,9 +7792,6 @@ requires
oldValue = data[key]; oldValue = data[key];
data[key] = value; data[key] = value;
$item.options({data: data}); $item.options({data: data});
if (key == self.options.unique) {
self.ids[self.ids.indexOf(oldValue)] = value;
}
return that; return that;
} }
}; };
@ -7753,7 +7817,7 @@ requires
function constructItem(update) { function constructItem(update) {
var $element = self.options.construct(self.options.data) var $element = self.options.construct(self.options.data)
.addClass('OxItem') .addClass('OxItem OxDeleteme' + self.options.data[self.options.unique])
.attr({ .attr({
draggable: self.options.draggable 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 Maps