From c29a8c9fda590d24d39f9a5fa11cf29e2675a2ec Mon Sep 17 00:00:00 2001
From: rlx <0x0073@0x2620.org>
Date: Tue, 11 Jan 2011 06:17:45 +0000
Subject: [PATCH] some improvements to lists (editable, sortable)
---
build/css/ox.ui.css | 33 ++++--
build/js/ox.ui.js | 243 +++++++++++++++++++++++++++++++++++++-------
2 files changed, 233 insertions(+), 43 deletions(-)
diff --git a/build/css/ox.ui.css b/build/css/ox.ui.css
index 1db30c30..b0283693 100644
--- a/build/css/ox.ui.css
+++ b/build/css/ox.ui.css
@@ -22,6 +22,10 @@ div, input, textarea {
font-family: Lucida Grande, Segoe UI, DejaVu Sans, Arial;
font-size: 11px;
}
+img {
+ -moz-user-drag: none;
+ -webkit-user-drag: none;
+}
td {
padding: 0;
}
@@ -243,6 +247,16 @@ input.OxMedium {
-moz-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 {
height: 10px;
padding: 0 4px 0 4px;
@@ -422,12 +436,18 @@ OxInput
*/
div.OxInput {
height: 16px;
- -moz-border-radius: 8px;
- -webkit-border-radius: 8px;
}
div.OxInput.OxMedium {
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 {
float: left;
padding: 0 6px 0 6px;
@@ -763,11 +783,6 @@ Lists
//-webkit-user-select: text;
}
-.OxTextList .OxCell {
- float: left;
- height: 12px;
- padding: 2px 4px 2px 4px;
-}
.OxTextList .OxBar {
//z-index: 10;
//-moz-box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.75);
@@ -879,6 +894,10 @@ Lists
overflow: hidden;
white-space: nowrap;
}
+.OxTextList .OxBody .OxItem .OxCell.OxEdit {
+ height: 16px;
+ padding: 0;
+}
.OxTextList .OxBody .OxItem .OxCell > img {
width: 16px;
height: 16px;
diff --git a/build/js/ox.ui.js b/build/js/ox.ui.js
index 6fc41c50..47ffe4cf 100644
--- a/build/js/ox.ui.js
+++ b/build/js/ox.ui.js
@@ -225,7 +225,7 @@ requires
that.api.api(function(result) {
$.each(result.data.actions, function(i, action) {
that.api[action] = function(data, callback) {
- if (arguments.length == 1) {
+ if (arguments.length == 1 && Ox.isFunction(data)) {
callback = data;
data = {};
}
@@ -702,7 +702,7 @@ requires
function callback(data) {
delete requests[options.id];
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) {
@@ -2554,6 +2554,7 @@ requires
overlap: 'none',
placeholder: '',
serialize: null,
+ style: 'rounded',
textAlign: 'left',
type: 'text',
validate: null,
@@ -2561,7 +2562,7 @@ requires
width: 128
})
.options(options)
- .addClass('OxInput OxMedium')
+ .addClass('OxInput OxMedium Ox' + Ox.toTitleCase(self.options.style))
.bindEvent($.extend(self.options.type == 'textarea' ? {} : {
key_enter: submit
}, {
@@ -2658,7 +2659,7 @@ requires
}
self.$input = $('')
- .addClass('OxInput OxMedium')
+ .addClass('OxInput OxMedium Ox' + Ox.toTitleCase(self.options.style))
.attr({
disabled: self.options.disabled ? 'disabled' : '',
type: self.options.type == 'password' ? 'password' : 'text'
@@ -2676,7 +2677,9 @@ requires
if (self.hasPasswordPlaceholder) {
self.$input.hide();
self.$placeholder = $('')
- .addClass('OxInput OxMedium OxPlaceholder')
+ .addClass('OxInput OxMedium Ox' +
+ Ox.toTitleCase(self.options.style) +
+ ' OxPlaceholder')
.attr({
type: 'text'
})
@@ -2942,6 +2945,7 @@ requires
$document.unbind('keydown', keypress);
$document.unbind('keypress', keypress);
}
+ //that.triggerEvent('blur', {});
}
function cancel() {
@@ -3029,10 +3033,11 @@ requires
}
function getInputWidth() {
- return self.options.width - 14 -
+ return self.options.width -
(self.options.arrows ? 32 : 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) {
@@ -3150,6 +3155,7 @@ requires
that.focus = function() {
self.$input.focus();
cursor(0, self.$input.val().length);
+ return that;
};
that.value = function() {
@@ -5781,6 +5787,7 @@ requires
that = new Ox.Element({}, self)
.defaults({
centerSelection: false,
+ draggable: true,
id: '',
item: function() {},
keys: [],
@@ -5802,6 +5809,7 @@ requires
that.$element = new Ox.List({
centered: self.options.centered,
construct: constructItem,
+ draggable: self.options.draggable,
id: self.options.id,
itemHeight: self.itemHeight,
itemWidth: self.itemWidth,
@@ -5834,9 +5842,9 @@ requires
{height: 8, width: 5},
ratio = data.width / data.height;
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,
- 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.print('IconItem', options, self)
+ //Ox.print('IconItem', options, self)
var self = self || {},
that = new Ox.Element({}, self)
@@ -6051,6 +6059,7 @@ requires
.defaults({
centered: false,
construct: function() {},
+ draggable: false,
format: [],
itemHeight: 16,
itemWidth: 16,
@@ -6062,20 +6071,22 @@ requires
request: function() {}, // (data, callback), without data returns {items, size etc.}
selected: [],
sort: [],
+ sortable: false,
type: 'text',
unique: ''
})
.options(options || {})
.scroll(scroll);
- that.$content.mousedown(mousedown);
+ that.$content.mousedown(mousedown).mouseup(mouseup);
$.extend(self, {
$items: [],
$pages: [],
clickTimeout: 0,
+ dragTimeout: 0,
format: {},
- ids: {},
+ ids: [],
itemMargin: self.options.type == 'text' ? 0 : 8, // 2 x 4 px margin ... fixme: the 2x should be computed later
keyboardEvents: {
key_end: scrollToFirst,
@@ -6104,11 +6115,19 @@ requires
key_control_shift_a: selectNone
});
}
- self.keyboardEvents['key_' + (self.options.orientation == 'vertical' ? 'up' : 'left')] = selectPrevious;
- self.keyboardEvents['key_' + (self.options.orientation == 'vertical' ? 'down' : 'right')] = selectNext;
+ self.keyboardEvents[
+ 'key_' + (self.options.orientation == 'vertical' ? 'up' : 'left')
+ ] = selectPrevious;
+ self.keyboardEvents[
+ 'key_' + (self.options.orientation == 'vertical' ? 'down' : 'right')
+ ] = selectNext;
if (self.options.max == -1) {
- self.keyboardEvents['key_' + (self.options.orientation == 'vertical' ? 'shift_up' : 'shift_left')] = addPreviousToSelection;
- self.keyboardEvents['key_' + (self.options.orientation == 'vertical' ? 'shift_down' : 'shift_right')] = addNextToSelection;
+ self.keyboardEvents[
+ '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') {
$.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
];
}
+ if (self.options.draggable) {
+ that.bind({
+ dragstart: function(e) {
+ Ox.print('DRAGSTART', e);
+ }
+ });
+ }
updateQuery(self.options.selected);
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() {
Ox.print('emptyFirstPage', self.$pages);
self.$pages[0] && self.$pages[0].find('.OxEmpty').remove();
@@ -6485,11 +6595,12 @@ requires
self.$items[pos] = new Ox.ListItem({
construct: self.options.construct,
data: v,
+ draggable: self.options.draggable,
format: self.options.format,
id: v[self.options.unique],
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)) {
Ox.print('pos', pos, 'isSelected')
self.$items[pos].addClass('OxSelected');
@@ -6523,7 +6634,7 @@ requires
}
function mousedown(e) {
- Ox.print('click')
+ Ox.print('mousedown')
var $item = findItem(e),
pos,
deselectTimeout = false;
@@ -6554,6 +6665,14 @@ requires
select(pos);
}
}, 250);
+ if (self.options.sortable) {
+ self.dragTimeout = setTimeout(function() {
+ if (self.dragTimeout) {
+ dragItem(pos, e);
+ self.dragTimeout = 0;
+ }
+ }, 250);
+ }
} else {
// dblclick
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() {
that.triggerEvent('open', {
ids: getSelectedIds()
@@ -6895,6 +7022,8 @@ requires
self.preview = false;
};
+ that.findItem = findItem; // fixme: not pretty, exporting for TextList, to make edit work
+
that.reload = function() {
Ox.print('---------------- list reload, page', self.page)
var page = self.page;
@@ -6966,6 +7095,7 @@ requires
.defaults({
construct: function() {},
data: {},
+ draggable: false,
format: [],
id: '',
position: 0
@@ -6990,6 +7120,7 @@ requires
that.$element = self.options.construct(self.data)
.addClass('OxItem')
.attr({
+ draggable: self.options.draggable,
id: self.options.id
})
.data('position', self.options.position);
@@ -7112,6 +7243,7 @@ requires
request: self.options.request,
selected: self.options.selected,
sort: self.options.sort,
+ sortable: self.options.sortable,
type: 'text',
unique: self.unique
}, $.extend({}, self)) // pass event handler
@@ -7127,6 +7259,9 @@ requires
that.$head && that.$head.scrollLeft(scrollLeft);
}
})
+ .bind({
+ mousedown: mousedown
+ })
.bindEvent({
select: function(event, data) {
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) {
Ox.print('clickColumn', id);
var i = getColumnIndexById(id),
@@ -7355,25 +7538,12 @@ requires
}
function getColumnIndexById(id) {
- var pos = -1;
- $.each(self.options.columns, function(i, v) {
- if (v.id == id) {
- pos = i;
- return false;
- }
- });
- return pos;
+ // fixme: use ox.js function
+ return Ox.getPositionById(self.options.columns, id);
}
function getColumnPositionById(id) {
- var pos = -1;
- $.each(self.visibleColumns, function(i, v) {
- if (v.id == id) {
- pos = i;
- return false;
- }
- });
- return pos;
+ return Ox.getPositionById(self.visibleColumns, id);
}
function getItemWidth() {
@@ -7400,8 +7570,8 @@ requires
var $v = $(v);
$v.children(startClassName).detach()[insert]($v.children(stopClassName));
});
- column = self.visibleColumns.splice(startPos, 1)[0],
- width = self.columnWidths.splice(startPos, 1)[0];
+ var 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);
}
@@ -8965,6 +9135,7 @@ requires
title: [],
})
.options($.extend(options, {
+ foo: Ox.print(options, self.defaults.keyboard),
keyboard: parseKeyboard(options.keyboard || self.defaults.keyboard),
title: Ox.makeArray(options.title || self.defaults.title)
}))