add Ox.TreeList, fix Ox.List bugs
This commit is contained in:
parent
c31850f0c4
commit
d7badfe326
3 changed files with 281 additions and 60 deletions
|
@ -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
|
||||
}
|
||||
|
||||
/*
|
||||
================================================================================
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue