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) }))