better mouse events, fix bug where position would become zero while dragging on small timeline, and add shift-drag ratio-conserving resize to dialogs

This commit is contained in:
rlx 2011-01-16 19:02:29 +00:00
parent deaf77ef5c
commit 24263a3e17

View file

@ -940,13 +940,67 @@ requires
that.$element = $('<' + (self.options.element || 'div') + '/>', {
data: {
ox: that.id
}
},
mousedown: mousedown
});
$elements[that.id] = that;
wrapjQuery();
})();
// private
function mousedown(e) {
/*
better mouse events
on mousedown:
trigger mousedown
within 250 msec:
mouseup: trigger anyclick ("click" would collide with click events of certain widgets)
mouseup + mousedown: trigger doubleclick
after 250 msec:
mouseup + no mousedown within 250 msec: trigger singleclick
no mouseup within 250 msec: trigger dragstart
mousemove: trigger drag
mouseup: trigger dragend
*/
if (!self.mouseTimeout) {
// first mousedown
that.triggerEvent('mousedown', e);
self.mouseup = false;
self.mouseTimeout = setTimeout(function() {
self.mouseTimeout = 0;
if (self.mouseup) {
// singleclick
that.triggerEvent('singleclick', e);
} else {
// drag
that.triggerEvent('dragstart', e);
$window.unbind('mouseup', mouseup)
.mousemove(mousemove)
.one('mouseup', function(e) {
$window.unbind('mousemove', mousemove);
that.triggerEvent('dragend', e);
});
}
}, 250);
} else {
// second mousedown
clearTimeout(self.mouseTimeout);
self.mouseTimeout = 0;
that.triggerEvent('doubleclick');
}
$window.one('mouseup', mouseup);
function mousemove(e) {
that.triggerEvent('drag', e);
}
function mouseup(e) {
if (!self.mouseup) { // fixme: shouldn't be necessary, bound only once
that.triggerEvent('anyclick', e);
self.mouseup = true;
}
}
}
function wrapjQuery() {
$.each(oxui.jQueryFunctions, function(i, fn) {
that[fn] = function() {
@ -1108,11 +1162,15 @@ requires
*/
if (Ox.isObject(arguments[0])) {
$.each(arguments[0], function(event, data) {
if (['mousedown', 'anyclick', 'singleclick', 'doubleclick', 'dragstart', 'drag', 'dragend'].indexOf(event) == -1) {
Ox.print(that.id, self.options.id, 'trigger', event, data);
}
self.$eventHandler.trigger('ox_' + event, data);
});
} else {
if (['mousedown', 'anyclick', 'singleclick', 'doubleclick', 'dragstart', 'drag', 'dragend'].indexOf(arguments[0]) == -1) {
Ox.print(that.id, self.options ? self.options.id : '', 'trigger', arguments[0], arguments[1] || {});
}
self.$eventHandler.trigger('ox_' + arguments[0], arguments[1] || {});
}
return that;
@ -1460,8 +1518,12 @@ requires
Ox.print('dragging', e)
})
*/
.mousedown(dragStart)
.dblclick(toggle)
.bindEvent({
doubleclick: toggle,
dragstart: dragstart,
drag: drag,
dragend: dragend
})
.append($('<div>').addClass('OxSpace'))
.append($('<div>').addClass('OxLine'))
.append($('<div>').addClass('OxSpace'));
@ -1470,16 +1532,23 @@ requires
clientXY: self.options.orientation == 'horizontal' ? 'clientY' : 'clientX',
dimensions: oxui.getDimensions(self.options.orientation), // fixme: should orientation be the opposite orientation here?
edges: oxui.getEdges(self.options.orientation),
leftOrTop: self.options.edge == 'left' || self.options.edge == 'top',
startPos: 0,
startSize: 0
leftOrTop: self.options.edge == 'left' || self.options.edge == 'top'
});
function drag(e) {
var d = e[self.clientXY] - self.startPos
function dragstart(event, e) {
if (self.options.resizable && !self.options.collapsed) {
self.drag = {
startPos: e[self.clientXY],
startSize: self.options.size
}
}
}
function drag(event, e) {
var d = e[self.clientXY] - self.drag.startPos
size = self.options.size;
self.options.size = Ox.limit(
self.startSize + d * (self.leftOrTop ? 1 : -1),
self.drag.startSize + d * (self.leftOrTop ? 1 : -1),
self.options.resize[0],
self.options.resize[self.options.resize.length - 1]
);
@ -1509,25 +1578,17 @@ requires
}
}
function dragStart(e) {
if (self.options.resizable && !self.options.collapsed) {
self.startPos = e[self.clientXY];
self.startSize = self.options.size;
//Ox.print('startSize', self.startSize)
$window.mousemove(drag);
$window.one('mouseup', dragStop);
}
}
function dragStop() {
self.options.size != self.startSize && triggerEvents('resizeend');
$window.unbind('mousemove');
function dragend() {
self.options.size != self.drag.startSize && triggerEvents('resizeend');
}
function toggle() {
if (self.options.collapsible) {
// fixme: silly, pass a parameter
self.options.parent.toggle(self.leftOrTop ? 0 : self.options.parent.options('elements').length - 1);
self.options.parent.toggle(
self.leftOrTop ? 0 :
self.options.parent.options('elements').length - 1
);
self.options.collapsed = !self.options.collapsed;
}
/*
@ -1650,8 +1711,11 @@ requires
.addClass('OxTitleBar')
.appendTo(that);
self.options.movable && that.$titlebar
.mousedown(drag)
.dblclick(center);
.dblclick(center)
.bindEvent({
dragstart: dragstart,
drag: drag
});
that.$title = new Ox.Element()
.addClass('OxTitle')
@ -1690,37 +1754,97 @@ requires
});
}
function drag(event) {
var bodyWidth = $body.width(),
bodyHeight = $document.height(),
elementWidth = that.width(),
offset = that.offset(),
x = event.clientX,
y = event.clientY;
$window.mousemove(function(event) {
function dragstart(event, e) {
self.drag = {
bodyWidth: $body.width(),
bodyHeight: $document.height(),
elementWidth: that.width(),
offset: that.offset(),
x: e.clientX,
y: e.clientY
};
that.css({
margin: 0
});
}
function drag(event, e) {
var left = Ox.limit(
offset.left - x + event.clientX,
24 - elementWidth, bodyWidth - 24
//0, documentWidth - elementWidth
self.drag.offset.left - self.drag.x + e.clientX,
24 - self.drag.elementWidth, self.drag.bodyWidth - 24
//0, self.drag.documentWidth - self.drag.elementWidth
),
top = Ox.limit(
offset.top - y + event.clientY,
24, bodyHeight - 24
//24, documentHeight - elementHeight
self.drag.offset.top - self.drag.y + e.clientY,
24, self.drag.bodyHeight - 24
//24, self.drag.documentHeight - self.drag.elementHeight
);
that.css({
left: left + 'px',
top: top + 'px'
});
}
function dragstartResize(event, e) {
self.drag = {
documentWidth: $document.width(),
documentHeight: $document.height(),
elementWidth: that.width(),
elementHeight: that.height(),
offset: that.offset(),
x: e.clientX,
y: e.clientY
};
$.extend(self.drag, {
ratio: self.drag.elementWidth / self.drag.elementHeight
});
$window.one('mouseup', function() {
$window.unbind('mousemove');
that.css({
left: self.drag.offset.left,
top: self.drag.offset.top,
margin: 0
});
}
function dragResize(event, e) {
if (!e.shiftKey) {
self.drag.ratio = self.options.width / self.options.height;
}
self.options.width = Ox.limit(
self.drag.elementWidth - self.drag.x + e.clientX,
self.options.minWidth,
Math.min(
self.drag.documentWidth,
self.drag.documentWidth - self.drag.offset.left
)
);
self.options.height = Ox.limit(
self.drag.elementHeight - self.drag.y + e.clientY,
self.options.minHeight,
Math.min(
self.drag.documentHeight,
self.drag.documentHeight - self.drag.offset.top
)
);
if (e.shiftKey) {
self.options.height = Ox.limit(
self.options.width / self.drag.ratio,
self.options.minHeight,
Math.min(
self.drag.documentHeight,
self.drag.documentHeight - self.drag.offset.top
)
);
self.options.width = self.options.height * self.drag.ratio;
}
that.width(self.options.width);
that.height(self.options.height);
that.$content.height(self.options.height - 48 - 2 * self.options.padding); // fixme: this should happen automatically
}
function dragendResize(event, e) {
triggerResizeEvent();
}
function getButtonById(id) {
var ret = null;
//Ox.print('that.$buttons', that.$buttons, id)
@ -1764,8 +1888,12 @@ requires
if (self.options.resizable) {
that.$resize = new Ox.Element()
.addClass('OxResize')
.mousedown(resize)
.dblclick(reset)
.bindEvent({
dragstart: dragstartResize,
drag: dragResize,
dragend: dragendResize
})
.appendTo(that.$buttonsbar);
}
//Ox.print('--- two', self.options.buttons[1]);
@ -1803,38 +1931,6 @@ requires
triggerResizeEvent();
}
function resize(event) { // fixme: reserved jquery string?
var documentWidth = $document.width(),
documentHeight = $document.height(),
elementWidth = that.width(),
elementHeight = that.height(),
offset = that.offset(),
x = event.clientX,
y = event.clientY;
$window.mousemove(function(event) {
that.css({
left: offset.left,
top: offset.top,
margin: 0
});
self.options.width = Ox.limit(
elementWidth - x + event.clientX,
self.options.minWidth, Math.min(documentWidth, documentWidth - offset.left)
);
self.options.height = Ox.limit(
elementHeight - y + event.clientY,
self.options.minHeight, documentHeight - offset.top
);
that.width(self.options.width);
that.height(self.options.height);
that.$content.height(self.options.height - 48 - 2 * self.options.padding); // fixme: this should happen automatically
triggerResizeEvent();
});
$window.one('mouseup', function() {
$window.unbind('mousemove');
});
}
function triggerResizeEvent() {
that.triggerEvent('resize', {
width: self.options.width,
@ -7561,27 +7657,28 @@ requires
that.$titles = [];
self.columnOffsets = [];
$.each(self.visibleColumns, function(i, v) {
var $order, $resize, $left, $center, $right, timeout = 0;
var $order, $resize, $left, $center, $right;
offset += self.columnWidths[i];
self.columnOffsets[i] = offset - self.columnWidths[i] / 2;
that.$titles[i] = $('<div>')
that.$titles[i] = new Ox.Element()
.addClass('OxTitle OxColumn' + Ox.toTitleCase(v.id))
.css({
width: (self.columnWidths[i] - 9) + 'px',
textAlign: v.align
})
.html(v.title)
.mousedown(function(e) {
timeout = setTimeout(function() {
self.options.columnsMovable && dragColumn(v.id, e);
timeout = 0;
}, 250);
})
.mouseup(function() {
if (timeout) {
clearTimeout(timeout);
timeout = 0;
.bindEvent({
anyclick: function(event, e) {
clickColumn(v.id);
},
dragstart: function(event, e) {
dragstartColumn(v.id, e);
},
drag: function(event, e) {
dragColumn(v.id, e);
},
dragend: function(event, e) {
dragendColumn(v.id, e);
}
})
.appendTo(that.$head.$content.$element);
@ -7594,11 +7691,28 @@ requires
$(this).prev().trigger('click')
})
.appendTo(that.$head.$content.$element);
$resize = $('<div>')
Ox.print('okok')
$resize = new Ox.Element()
.addClass('OxResize')
.appendTo(that.$head.$content.$element);
Ox.print('nono')
if (self.options.columnsResizable) {
$resize.addClass('OxResizable')
.bindEvent({
doubleclick: function(event, e) {
resetColumn(v.id, e);
},
dragstart: function(event, e) {
dragstartResize(v.id, e);
},
drag: function(event, e) {
dragResize(v.id, e);
},
dragend: function(event, e) {
dragendResize(v.id, e);
}
});
/*
// fixme: make these their own named functions
.mousedown(function(e) {
var startWidth = self.columnWidths[i],
@ -7634,10 +7748,11 @@ requires
width: width
});
});
*/
}
$left = $('<div>').addClass('OxLeft').appendTo($resize);
$center = $('<div>').addClass('OxCenter').appendTo($resize);
$right = $('<div>').addClass('OxRight').appendTo($resize);
$left = $('<div>').addClass('OxLeft').appendTo($resize.$element);
$center = $('<div>').addClass('OxCenter').appendTo($resize.$element);
$right = $('<div>').addClass('OxRight').appendTo($resize.$element);
});
that.$head.$content.css({
width: (Ox.sum(self.columnWidths) + 2) + 'px'
@ -7689,64 +7804,83 @@ requires
return $item;
}
function dragColumn(id, e) {
var startX = e.clientX,
startPos = getColumnPositionById(id),
pos = startPos,
stopPos = startPos,
offsets = $.map(self.visibleColumns, function(v, i) {
return self.columnOffsets[i] - self.columnOffsets[startPos]
function dragstartColumn(id, e) {
self.drag = {
startX: e.clientX,
startPos: getColumnPositionById(id)
}
$.extend(self.drag, {
stopPos: self.drag.startPos,
offsets: $.map(self.visibleColumns, function(v, i) {
return self.columnOffsets[i] - self.columnOffsets[self.drag.startPos]
})
});
$('.OxColumn' + Ox.toTitleCase(id)).css({
opacity: 0.25
});
that.$titles[startPos].addClass('OxDrag').css({ // fixme: why does the class not work?
that.$titles[self.drag.startPos].addClass('OxDrag').css({ // fixme: why does the class not work?
cursor: 'move'
});
//Ox.print('offsets', offsets)
$window.mousemove(function(e) {
var d = e.clientX - startX;
$.each(offsets, function(i, v) {
if (d < 0 && d < v) {
stopPos = i;
return false;
} else if (d > 0 && d > v) {
stopPos = i;
}
});
if (stopPos != pos) {
pos = stopPos;
moveColumn(id, pos);
}
});
$window.one('mouseup', function() {
dropColumn(id, pos);
$window.unbind('mousemove');
});
}
function dropColumn(id, pos) {
//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);
function dragColumn(id, e) {
var d = e.clientX - self.drag.startX,
pos = self.drag.stopPos;
$.each(self.drag.offsets, function(i, v) {
if (d < 0 && d < v) {
self.drag.stopPos = i;
return false;
} else if (d > 0 && d > v) {
self.drag.stopPos = i;
}
});
if (self.drag.stopPos != pos) {
moveColumn(id, self.drag.stopPos);
}
}
function dragendColumn(id, e) {
var column = self.visibleColumns.splice(self.drag.stopPos, 1)[0],
width = self.columnWidths.splice(self.drag.stopPos, 1)[0];
self.visibleColumns.splice(self.drag.stopPos, 0, column);
self.columnWidths.splice(self.drag.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({
that.$titles[self.drag.stopPos].removeClass('OxDrag').css({
cursor: 'pointer'
});
that.$body.clearCache();
triggerColumnChangeEvent();
}
function dragstartResize(id, e) {
var pos = getColumnPositionById(id);
self.drag = {
startX: e.clientX,
startWidth: self.columnWidths[pos]
};
}
function dragResize(id, e) {
var width = Ox.limit(
self.drag.startWidth - self.drag.startX + e.clientX,
self.options.columnWidth[0],
self.options.columnWidth[1]
);
resizeColumn(id, width);
}
function dragendResize(id, e) {
var pos = getColumnPositionById(id);
that.triggerEvent('columnresize', {
id: id,
width: self.columnWidths[pos]
});
}
function getCell(id, key) {
Ox.print('getCell', id, key)
var $item = getItem(id);
@ -7841,8 +7975,13 @@ requires
//that.$body.clearCache();
}
function resize() {
function resetColumn(id) {
var width = self.defaultColumnWidths[getColumnIndexById(id)];
resizeColumn(id, width);
that.triggerEvent('columnresize', {
id: id,
width: width
});
}
function resizeColumn(id, width) {
@ -7862,7 +8001,6 @@ requires
width: (width - (self.options.columnsVisible ? 9 : 8)) + 'px'
});
setWidth();
//that.$body.clearCache();
}
function setWidth() {
@ -10011,9 +10149,13 @@ requires
})
.options(options || {})
.addClass('OxTimelineLarge')
.mousedown(mousedown)
.mouseleave(mouseleave)
.mousemove(mousemove);
.mousemove(mousemove)
.bindEvent({
anyclick: click,
dragstart: dragstart,
drag: drag
});
$.extend(self, {
$cuts: [],
@ -10079,35 +10221,27 @@ requires
setWidth();
setPosition();
function mousedown(e) {
var mousemove = false,
x = e.clientX;
$window.mousemove(function(e) {
mousemove = true;
self.options.position = Ox.limit(
self.options.position + (x - e.clientX) / self.fps,
0, self.options.duration
);
x = e.clientX;
setPosition();
that.triggerEvent('change', {
position: self.options.position
});
});
$window.one('mouseup', function() {
$window.unbind('mousemove');
if (!mousemove) {
function click(event, e) {
self.options.position = Ox.limit(
self.options.position + (e.clientX - that.$element.offset().left - self.center) / self.fps,
0, self.options.duration
);
setPosition();
triggerChangeEvent();
}
that.triggerEvent('change', {
position: self.options.position
});
});
e.preventDefault();
function dragstart(event, e) {
self.drag = {x: e.clientX};
}
function drag(event, e) {
self.options.position = Ox.limit(
self.options.position + (self.drag.x - e.clientX) / self.fps,
0, self.options.duration
);
self.drag.x = e.clientX;
setPosition();
triggerChangeEvent();
}
function mouseleave(e) {
@ -10168,6 +10302,12 @@ requires
setMarker();
}
function triggerChangeEvent() {
that.triggerEvent('change', {
position: self.options.position
});
}
function updateTooltip() {
var position = self.options.position + (self.clientX - that.offset().left - self.center) / self.fps;
if (position >= 0 && position <= self.options.duration) {
@ -10217,7 +10357,12 @@ requires
.addClass('OxTimelineSmall')
.mousedown(mousedown)
.mouseleave(mouseleave)
.mousemove(mousemove);
.mousemove(mousemove)
.bindEvent({
drag: function(event, e) {
mousedown(e);
}
});
$.extend(self, {
$images: [],
@ -10290,6 +10435,7 @@ requires
if (self.hasSubtitles) {
self.subtitlesImageURL = getSubtitlesImageURL();
self.$subtitles[i] = $('<img>')
.addClass('OxTimelineSmallSubtitles')
.attr({
src: self.subtitlesImageURL
})
@ -10376,41 +10522,34 @@ requires
}
function mousedown(e) {
if ($(e.target).is('img')) {
var $target = $(e.target);
if (
$target.hasClass('OxTimelineSmallImage') ||
$target.hasClass('OxTimelineSmallSubtitles')
) {
self.options.position = getPosition(e);
setPosition();
that.triggerEvent('change', {
position: self.options.position
});
}
$window.mousemove(function(e) {
if ($(e.target).is('img')) {
self.options.position = getPosition(e);
setPosition();
that.triggerEvent('change', {
position: self.options.position
});
}
});
$window.one('mouseup', function() {
$window.unbind('mousemove');
})
e.preventDefault();
}
function mouseleave(e) {
self.$tooltip.hide();
self.$tooltip && self.$tooltip.hide();
}
function mousemove(e) {
var $target = $(e.target),
position,
subtitle;
if ($target.is('img')) {
//FIXME: this might still be broken in opera according to http://acko.net/blog/mouse-handling-and-absolute-positions-in-javascript
if (
$target.hasClass('OxTimelineSmallImage') ||
$target.hasClass('OxTimelineSmallSubtitles')
) {
position = getPosition(e),
subtitle = getSubtitle(position);
//Ox.print('position', position, e)
self.$tooltip = new Ox.Tooltip({
title: subtitle ?
'<span class=\'OxBright\'>' +
@ -10422,6 +10561,8 @@ requires
textAlign: 'center'
})
.show(e.clientX, e.clientY);
} else {
self.$tooltip && self.$tooltip.hide();
}
}