some improvements to lists (editable, sortable)

This commit is contained in:
rlx 2011-01-11 06:17:45 +00:00
parent 02a687cf77
commit 8255a4dbd3
2 changed files with 233 additions and 43 deletions

View File

@ -22,6 +22,10 @@ div, input, textarea {
font-family: Lucida Grande, Segoe UI, DejaVu Sans, Arial; font-family: Lucida Grande, Segoe UI, DejaVu Sans, Arial;
font-size: 11px; font-size: 11px;
} }
img {
-moz-user-drag: none;
-webkit-user-drag: none;
}
td { td {
padding: 0; padding: 0;
} }
@ -243,6 +247,16 @@ input.OxMedium {
-moz-border-radius: 8px; -moz-border-radius: 8px;
-webkit-border-radius: 8px; -webkit-border-radius: 8px;
} }
input.OxMedium.OxRounded {
padding: 0 6px 0 6px;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
}
input.OxMedium.OxSquare {
padding: 0 2px 0 2px;
-moz-border-radius: 0;
-webkit-border-radius: 0;
}
input.OxSmall { input.OxSmall {
height: 10px; height: 10px;
padding: 0 4px 0 4px; padding: 0 4px 0 4px;
@ -422,12 +436,18 @@ OxInput
*/ */
div.OxInput { div.OxInput {
height: 16px; height: 16px;
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
} }
div.OxInput.OxMedium { div.OxInput.OxMedium {
height: 16px; height: 16px;
} }
div.OxInput.OxRounded {
-moz-border-radius: 8px;
-webkit-border-radius: 8px;
}
div.OxInput.OxSquare {
-moz-border-radius: 0;
-webkit-border-radius: 0;
}
div.OxInput > .OxInputLabel { div.OxInput > .OxInputLabel {
float: left; float: left;
padding: 0 6px 0 6px; padding: 0 6px 0 6px;
@ -763,11 +783,6 @@ Lists
//-webkit-user-select: text; //-webkit-user-select: text;
} }
.OxTextList .OxCell {
float: left;
height: 12px;
padding: 2px 4px 2px 4px;
}
.OxTextList .OxBar { .OxTextList .OxBar {
//z-index: 10; //z-index: 10;
//-moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.75); //-moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.75);
@ -879,6 +894,10 @@ Lists
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
} }
.OxTextList .OxBody .OxItem .OxCell.OxEdit {
height: 16px;
padding: 0;
}
.OxTextList .OxBody .OxItem .OxCell > img { .OxTextList .OxBody .OxItem .OxCell > img {
width: 16px; width: 16px;
height: 16px; height: 16px;

View File

@ -225,7 +225,7 @@ requires
that.api.api(function(result) { that.api.api(function(result) {
$.each(result.data.actions, function(i, action) { $.each(result.data.actions, function(i, action) {
that.api[action] = function(data, callback) { that.api[action] = function(data, callback) {
if (arguments.length == 1) { if (arguments.length == 1 && Ox.isFunction(data)) {
callback = data; callback = data;
data = {}; data = {};
} }
@ -702,7 +702,7 @@ requires
function callback(data) { function callback(data) {
delete requests[options.id]; delete requests[options.id];
Ox.length(requests) == 0 && $body.trigger('requestStop'); Ox.length(requests) == 0 && $body.trigger('requestStop');
options.callback(data); // fixme: doesn't work if callback hasn't been passed options.callback && options.callback(data);
} }
function debug(request) { function debug(request) {
@ -2554,6 +2554,7 @@ requires
overlap: 'none', overlap: 'none',
placeholder: '', placeholder: '',
serialize: null, serialize: null,
style: 'rounded',
textAlign: 'left', textAlign: 'left',
type: 'text', type: 'text',
validate: null, validate: null,
@ -2561,7 +2562,7 @@ requires
width: 128 width: 128
}) })
.options(options) .options(options)
.addClass('OxInput OxMedium') .addClass('OxInput OxMedium Ox' + Ox.toTitleCase(self.options.style))
.bindEvent($.extend(self.options.type == 'textarea' ? {} : { .bindEvent($.extend(self.options.type == 'textarea' ? {} : {
key_enter: submit key_enter: submit
}, { }, {
@ -2658,7 +2659,7 @@ requires
} }
self.$input = $('<input>') self.$input = $('<input>')
.addClass('OxInput OxMedium') .addClass('OxInput OxMedium Ox' + Ox.toTitleCase(self.options.style))
.attr({ .attr({
disabled: self.options.disabled ? 'disabled' : '', disabled: self.options.disabled ? 'disabled' : '',
type: self.options.type == 'password' ? 'password' : 'text' type: self.options.type == 'password' ? 'password' : 'text'
@ -2676,7 +2677,9 @@ requires
if (self.hasPasswordPlaceholder) { if (self.hasPasswordPlaceholder) {
self.$input.hide(); self.$input.hide();
self.$placeholder = $('<input>') self.$placeholder = $('<input>')
.addClass('OxInput OxMedium OxPlaceholder') .addClass('OxInput OxMedium Ox' +
Ox.toTitleCase(self.options.style) +
' OxPlaceholder')
.attr({ .attr({
type: 'text' type: 'text'
}) })
@ -2942,6 +2945,7 @@ requires
$document.unbind('keydown', keypress); $document.unbind('keydown', keypress);
$document.unbind('keypress', keypress); $document.unbind('keypress', keypress);
} }
//that.triggerEvent('blur', {});
} }
function cancel() { function cancel() {
@ -3029,10 +3033,11 @@ requires
} }
function getInputWidth() { function getInputWidth() {
return self.options.width - 14 - return self.options.width -
(self.options.arrows ? 32 : 0) - (self.options.arrows ? 32 : 0) -
(self.options.clear ? 16 : 0) - (self.options.clear ? 16 : 0) -
(self.options.label ? self.options.labelWidth : 0); (self.options.label ? self.options.labelWidth : 0) -
(self.options.style == 'rounded' ? 14 : 6);
} }
function keypress(event) { function keypress(event) {
@ -3150,6 +3155,7 @@ requires
that.focus = function() { that.focus = function() {
self.$input.focus(); self.$input.focus();
cursor(0, self.$input.val().length); cursor(0, self.$input.val().length);
return that;
}; };
that.value = function() { that.value = function() {
@ -5781,6 +5787,7 @@ requires
that = new Ox.Element({}, self) that = new Ox.Element({}, self)
.defaults({ .defaults({
centerSelection: false, centerSelection: false,
draggable: true,
id: '', id: '',
item: function() {}, item: function() {},
keys: [], keys: [],
@ -5802,6 +5809,7 @@ requires
that.$element = new Ox.List({ that.$element = new Ox.List({
centered: self.options.centered, centered: self.options.centered,
construct: constructItem, construct: constructItem,
draggable: self.options.draggable,
id: self.options.id, id: self.options.id,
itemHeight: self.itemHeight, itemHeight: self.itemHeight,
itemWidth: self.itemWidth, itemWidth: self.itemWidth,
@ -5834,9 +5842,9 @@ requires
{height: 8, width: 5}, {height: 8, width: 5},
ratio = data.width / data.height; ratio = data.width / data.height;
return new Ox.IconItem($.extend(data, { return new Ox.IconItem($.extend(data, {
height: self.options.size / (ratio <= 1 ? 1 : ratio), height: Math.round(self.options.size / (ratio <= 1 ? 1 : ratio)),
size: self.options.size, size: self.options.size,
width: self.options.size * (ratio >= 1 ? 1 : ratio) width: Math.round(self.options.size * (ratio >= 1 ? 1 : ratio))
})); }));
} }
@ -5890,7 +5898,7 @@ requires
Ox.IconItem = function(options, self) { Ox.IconItem = function(options, self) {
Ox.print('IconItem', options, self) //Ox.print('IconItem', options, self)
var self = self || {}, var self = self || {},
that = new Ox.Element({}, self) that = new Ox.Element({}, self)
@ -6051,6 +6059,7 @@ requires
.defaults({ .defaults({
centered: false, centered: false,
construct: function() {}, construct: function() {},
draggable: false,
format: [], format: [],
itemHeight: 16, itemHeight: 16,
itemWidth: 16, itemWidth: 16,
@ -6062,20 +6071,22 @@ requires
request: function() {}, // (data, callback), without data returns {items, size etc.} request: function() {}, // (data, callback), without data returns {items, size etc.}
selected: [], selected: [],
sort: [], sort: [],
sortable: false,
type: 'text', type: 'text',
unique: '' unique: ''
}) })
.options(options || {}) .options(options || {})
.scroll(scroll); .scroll(scroll);
that.$content.mousedown(mousedown); that.$content.mousedown(mousedown).mouseup(mouseup);
$.extend(self, { $.extend(self, {
$items: [], $items: [],
$pages: [], $pages: [],
clickTimeout: 0, clickTimeout: 0,
dragTimeout: 0,
format: {}, format: {},
ids: {}, 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_end: scrollToFirst, key_end: scrollToFirst,
@ -6104,11 +6115,19 @@ requires
key_control_shift_a: selectNone key_control_shift_a: selectNone
}); });
} }
self.keyboardEvents['key_' + (self.options.orientation == 'vertical' ? 'up' : 'left')] = selectPrevious; self.keyboardEvents[
self.keyboardEvents['key_' + (self.options.orientation == 'vertical' ? 'down' : 'right')] = selectNext; 'key_' + (self.options.orientation == 'vertical' ? 'up' : 'left')
] = selectPrevious;
self.keyboardEvents[
'key_' + (self.options.orientation == 'vertical' ? 'down' : 'right')
] = selectNext;
if (self.options.max == -1) { if (self.options.max == -1) {
self.keyboardEvents['key_' + (self.options.orientation == 'vertical' ? 'shift_up' : 'shift_left')] = addPreviousToSelection; self.keyboardEvents[
self.keyboardEvents['key_' + (self.options.orientation == 'vertical' ? 'shift_down' : 'shift_right')] = addNextToSelection; 'key_' + (self.options.orientation == 'vertical' ? 'shift_up' : 'shift_left')
] = addPreviousToSelection;
self.keyboardEvents[
'key_' + (self.options.orientation == 'vertical' ? 'shift_down' : 'shift_right')
] = addNextToSelection;
} }
if (self.options.orientation == 'both') { if (self.options.orientation == 'both') {
$.extend(self.keyboardEvents, { $.extend(self.keyboardEvents, {
@ -6125,6 +6144,13 @@ requires
0, 60, 60, 60, 60, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68, 72, 76, 60 0, 60, 60, 60, 60, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68, 72, 76, 60
]; ];
} }
if (self.options.draggable) {
that.bind({
dragstart: function(e) {
Ox.print('DRAGSTART', e);
}
});
}
updateQuery(self.options.selected); updateQuery(self.options.selected);
that.bindEvent(self.keyboardEvents); that.bindEvent(self.keyboardEvents);
@ -6249,6 +6275,90 @@ requires
} }
} }
function dragItem(pos, e) {
var $item = self.$items[pos],
id = self.ids[pos],
startPos = pos,
startY = e.clientY,
stopPos = startPos,
offsets = $.map(self.$items, function($item, pos) {
return (pos - startPos) * 16 - e.offsetY + 8;
});
Ox.print('dragItem', e);
Ox.print(e.offsetY, offsets)
$item.addClass('OxDrag') // fixme: why does the class not work?
.css({
cursor: 'move',
opacity: 0.5
});
$window.mousemove(function(e) {
var clientY = e.clientY - that.offset()['top'],
offset = clientY % 16,
position = Ox.limit(parseInt(clientY / 16), 0, self.$items.length - 1);
if (position < pos) {
stopPos = position + (offset > 8 ? 1 : 0);
} else if (position > pos) {
stopPos = position - (offset <= 8 ? 1 : 0);
}
if (stopPos != pos) {
moveItem(pos, stopPos);
pos = stopPos;
}
});
$window.one('mouseup', function() {
dropItem(id, pos);
$window.unbind('mousemove');
});
}
function moveItem(startPos, stopPos) {
var $item = self.$items[startPos],
insert = startPos < stopPos ? 'insertAfter' : 'insertBefore';
$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});
});
self.selected = [stopPos];
Ox.print('ids', self.ids);
}
function dropItem(id, pos) {
var $item = self.$items[pos];
$item.removeClass('OxDrag')
.css({
cursor: 'pointer',
opacity: 1
});
that.triggerEvent('sort', {
ids: self.ids
});
/*
Ox.print('dropColumn', id, pos)
var startPos = getColumnPositionById(id),
stopPos = pos,
$title = that.$titles.splice(startPos, 1)[0],
column = self.visibleColumns.splice(startPos, 1)[0],
width = self.columnWidths.splice(startPos, 1)[0];
self.visibleColumns.splice(stopPos, 0, column);
self.columnWidths.splice(stopPos, 0, width);
that.$head.$content.empty();
constructHead();
Ox.print('s.vC', self.visibleColumns)
$('.OxColumn' + Ox.toTitleCase(id)).css({
opacity: 1
});
that.$titles[stopPos].removeClass('OxDrag').css({
cursor: 'pointer'
});
that.$body.clearCache();
*/
}
function emptyFirstPage() { function emptyFirstPage() {
Ox.print('emptyFirstPage', self.$pages); Ox.print('emptyFirstPage', self.$pages);
self.$pages[0] && self.$pages[0].find('.OxEmpty').remove(); self.$pages[0] && self.$pages[0].find('.OxEmpty').remove();
@ -6485,11 +6595,12 @@ requires
self.$items[pos] = new Ox.ListItem({ self.$items[pos] = new Ox.ListItem({
construct: self.options.construct, construct: self.options.construct,
data: v, data: v,
draggable: self.options.draggable,
format: self.options.format, format: self.options.format,
id: v[self.options.unique], id: v[self.options.unique],
position: pos position: pos
}); });
self.ids[pos] = v[self.options.unique]; self.ids[pos] = v[self.options.unique]; // fixme: why not use self.$items[pos].options('id')?
if (isSelected(pos)) { if (isSelected(pos)) {
Ox.print('pos', pos, 'isSelected') Ox.print('pos', pos, 'isSelected')
self.$items[pos].addClass('OxSelected'); self.$items[pos].addClass('OxSelected');
@ -6523,7 +6634,7 @@ requires
} }
function mousedown(e) { function mousedown(e) {
Ox.print('click') Ox.print('mousedown')
var $item = findItem(e), var $item = findItem(e),
pos, pos,
deselectTimeout = false; deselectTimeout = false;
@ -6554,6 +6665,14 @@ requires
select(pos); select(pos);
} }
}, 250); }, 250);
if (self.options.sortable) {
self.dragTimeout = setTimeout(function() {
if (self.dragTimeout) {
dragItem(pos, e);
self.dragTimeout = 0;
}
}, 250);
}
} else { } else {
// dblclick // dblclick
clearTimeout(self.clickTimeout); clearTimeout(self.clickTimeout);
@ -6565,6 +6684,14 @@ requires
} }
} }
function mouseup(e) {
Ox.print('mouseup')
if (self.dragTimeout) {
clearTimeout(self.dragTimeout);
self.dragTimeout = 0;
}
}
function open() { function open() {
that.triggerEvent('open', { that.triggerEvent('open', {
ids: getSelectedIds() ids: getSelectedIds()
@ -6895,6 +7022,8 @@ requires
self.preview = false; self.preview = false;
}; };
that.findItem = findItem; // fixme: not pretty, exporting for TextList, to make edit work
that.reload = function() { that.reload = function() {
Ox.print('---------------- list reload, page', self.page) Ox.print('---------------- list reload, page', self.page)
var page = self.page; var page = self.page;
@ -6966,6 +7095,7 @@ requires
.defaults({ .defaults({
construct: function() {}, construct: function() {},
data: {}, data: {},
draggable: false,
format: [], format: [],
id: '', id: '',
position: 0 position: 0
@ -6990,6 +7120,7 @@ requires
that.$element = self.options.construct(self.data) that.$element = self.options.construct(self.data)
.addClass('OxItem') .addClass('OxItem')
.attr({ .attr({
draggable: self.options.draggable,
id: self.options.id id: self.options.id
}) })
.data('position', self.options.position); .data('position', self.options.position);
@ -7112,6 +7243,7 @@ requires
request: self.options.request, request: self.options.request,
selected: self.options.selected, selected: self.options.selected,
sort: self.options.sort, sort: self.options.sort,
sortable: self.options.sortable,
type: 'text', type: 'text',
unique: self.unique unique: self.unique
}, $.extend({}, self)) // pass event handler }, $.extend({}, self)) // pass event handler
@ -7127,6 +7259,9 @@ requires
that.$head && that.$head.scrollLeft(scrollLeft); that.$head && that.$head.scrollLeft(scrollLeft);
} }
}) })
.bind({
mousedown: mousedown
})
.bindEvent({ .bindEvent({
select: function(event, data) { select: function(event, data) {
self.options.selected = data.ids; self.options.selected = data.ids;
@ -7186,6 +7321,54 @@ requires
} }
} }
function mousedown(e) {
var $cell = $(e.target),
$input,
$item = that.$body.findItem(e),
columnId,
columnIndex,
html, width;
if ($item && $item.hasClass('OxSelected')) {
columnId = $cell.attr('class')
.split('OxColumn')[1].split(' ')[0].toLowerCase();
columnIndex = getColumnIndexById(columnId);
if (self.options.columns[columnIndex].editable) {
html = $cell.html();
width = self.options.columns[columnIndex].width;
$cell.empty()
.addClass('OxEdit')
.css({
width: width + 'px'
});
$input = Ox.Input({
style: 'square',
value: html,
width: width
})
.bindEvent({
blur: submit,
submit: submit
})
.appendTo($cell)
.focus();
}
}
function submit() {
var value = $input.value();
$cell.empty()
.removeClass('OxEdit')
.css({
width: (width - 8) + 'px'
})
.html(value)
that.triggerEvent('edit', {
id: $item.attr('id'),
key: columnId,
value: value
});
}
}
function clickColumn(id) { function clickColumn(id) {
Ox.print('clickColumn', id); Ox.print('clickColumn', id);
var i = getColumnIndexById(id), var i = getColumnIndexById(id),
@ -7355,25 +7538,12 @@ requires
} }
function getColumnIndexById(id) { function getColumnIndexById(id) {
var pos = -1; // fixme: use ox.js function
$.each(self.options.columns, function(i, v) { return Ox.getPositionById(self.options.columns, id);
if (v.id == id) {
pos = i;
return false;
}
});
return pos;
} }
function getColumnPositionById(id) { function getColumnPositionById(id) {
var pos = -1; return Ox.getPositionById(self.visibleColumns, id);
$.each(self.visibleColumns, function(i, v) {
if (v.id == id) {
pos = i;
return false;
}
});
return pos;
} }
function getItemWidth() { function getItemWidth() {
@ -7400,8 +7570,8 @@ requires
var $v = $(v); var $v = $(v);
$v.children(startClassName).detach()[insert]($v.children(stopClassName)); $v.children(startClassName).detach()[insert]($v.children(stopClassName));
}); });
column = self.visibleColumns.splice(startPos, 1)[0], var column = self.visibleColumns.splice(startPos, 1)[0],
width = self.columnWidths.splice(startPos, 1)[0]; width = self.columnWidths.splice(startPos, 1)[0];
self.visibleColumns.splice(stopPos, 0, column); self.visibleColumns.splice(stopPos, 0, column);
self.columnWidths.splice(stopPos, 0, width); self.columnWidths.splice(stopPos, 0, width);
} }
@ -8965,6 +9135,7 @@ requires
title: [], title: [],
}) })
.options($.extend(options, { .options($.extend(options, {
foo: Ox.print(options, self.defaults.keyboard),
keyboard: parseKeyboard(options.keyboard || self.defaults.keyboard), keyboard: parseKeyboard(options.keyboard || self.defaults.keyboard),
title: Ox.makeArray(options.title || self.defaults.title) title: Ox.makeArray(options.title || self.defaults.title)
})) }))