Added arrow hotkeys to Draggable and Resizable

Which means better control over the post notes placement for all the
keyboard lovers.
This commit is contained in:
Marcin Kurczewski 2015-02-22 18:56:35 +01:00
parent 90406b1278
commit b416868aa7
4 changed files with 121 additions and 22 deletions

View file

@ -224,12 +224,17 @@
} }
.post-note { .post-note {
outline: 0;
pointer-events: auto; pointer-events: auto;
position: absolute; position: absolute;
background: rgba(255, 255, 255, 0.3); background: rgba(255, 255, 255, 0.3);
border: 1px solid rgba(0, 0, 0, 0.3); border: 1px solid rgba(0, 0, 0, 0.3);
font-size: 12pt; font-size: 12pt;
} }
.post-note:focus {
border-color: rgba(255, 0, 0, 0.3);
background-color: rgba(255, 225, 225, 0.3);
}
.post-note .text-wrapper { .post-note .text-wrapper {
position: absolute; position: absolute;
display: none; display: none;

View file

@ -2,75 +2,137 @@ var App = App || {};
App.Util = App.Util || {}; App.Util = App.Util || {};
App.Util.Draggable = function(jQuery) { App.Util.Draggable = function(jQuery) {
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT = 39;
var KEY_DOWN = 40;
function relativeDragStrategy($element) { function relativeDragStrategy($element) {
var $parent = $element.parent(); var $parent = $element.parent();
var delta; var delta;
var x = $element.offset().left - $parent.offset().left;
var y = $element.offset().top - $parent.offset().top;
var getPosition = function() {
return {x: x, y: y};
};
var setPosition = function(newX, newY) {
x = newX;
y = newY;
var screenX = Math.min(Math.max(newX, 0), $parent.outerWidth() - $element.outerWidth());
var screenY = Math.min(Math.max(newY, 0), $parent.outerHeight() - $element.outerHeight());
screenX *= 100.0 / $parent.outerWidth();
screenY *= 100.0 / $parent.outerHeight();
$element.css({
left: screenX + '%',
top: screenY + '%'});
};
return { return {
click: function(e) { mouseClicked: function(e) {
delta = { delta = {
x: $element.offset().left - e.clientX, x: $element.offset().left - e.clientX,
y: $element.offset().top - e.clientY, y: $element.offset().top - e.clientY,
}; };
}, },
update: function(e) { mouseMoved: function(e) {
var x = e.clientX + delta.x - $parent.offset().left; setPosition(
var y = e.clientY + delta.y - $parent.offset().top; e.clientX + delta.x - $parent.offset().left,
x = Math.min(Math.max(x, 0), $parent.outerWidth() - $element.outerWidth()); e.clientY + delta.y - $parent.offset().top);
y = Math.min(Math.max(y, 0), $parent.outerHeight() - $element.outerHeight());
x *= 100.0 / $parent.outerWidth();
y *= 100.0 / $parent.outerHeight();
$element.css({
left: x + '%',
top: y + '%'});
}, },
getPosition: getPosition,
setPosition: setPosition,
}; };
} }
function absoluteDragStrategy($element) { function absoluteDragStrategy($element) {
var delta; var delta;
var x = $element.offset().left;
var y = $element.offset().top;
var getPosition = function() {
return {x: x, y: y};
};
var setPosition = function(newX, newY) {
x = newX;
y = newY;
$element.css({
left: x + 'px',
top: y + 'px'});
};
return { return {
click: function(e) { mouseClicked: function(e) {
delta = { delta = {
x: $element.position().left - e.clientX, x: $element.position().left - e.clientX,
y: $element.position().top - e.clientY, y: $element.position().top - e.clientY,
}; };
}, },
update: function(e) { mouseMoved: function(e) {
var x = e.clientX + delta.x; setPosition(e.clientX + delta.x, e.clientY + delta.y);
var y = e.clientY + delta.y;
$element.css({
left: x + 'px',
top: y + 'px'});
}, },
getPosition: getPosition,
setPosition: setPosition,
}; };
} }
function makeDraggable($element, dragStrategy) { function makeDraggable($element, dragStrategy) {
var strategy = dragStrategy($element); var strategy = dragStrategy($element);
$element.data('drag-strategy', strategy);
$element.addClass('draggable'); $element.addClass('draggable');
$element.mousedown(function(e) { $element.mousedown(function(e) {
if (e.target !== $element.get(0)) { if (e.target !== $element.get(0)) {
return; return;
} }
e.preventDefault(); e.preventDefault();
$element.focus();
$element.addClass('dragging'); $element.addClass('dragging');
strategy.click(e); strategy.mouseClicked(e);
jQuery(window).bind('mousemove.elemmove', function(e) { jQuery(window).bind('mousemove.elemmove', function(e) {
strategy.update(e); strategy.mouseMoved(e);
}).bind('mouseup.elemmove', function(e) { }).bind('mouseup.elemmove', function(e) {
e.preventDefault(); e.preventDefault();
strategy.update(e); strategy.mouseMoved(e);
$element.removeClass('dragging'); $element.removeClass('dragging');
jQuery(window).unbind('mousemove.elemmove'); jQuery(window).unbind('mousemove.elemmove');
jQuery(window).unbind('mouseup.elemmove'); jQuery(window).unbind('mouseup.elemmove');
}); });
}); });
$element.keydown(function(e) {
var position = strategy.getPosition();
var oldPosition = {x: position.x, y: position.y};
if (e.shiftKey) {
return;
}
var delta = e.ctrlKey ? 10 : 1;
if (e.which === KEY_LEFT) {
position.x -= delta;
} else if (e.which === KEY_RIGHT) {
position.x += delta;
} else if (e.which === KEY_UP) {
position.y -= delta;
} else if (e.which === KEY_DOWN) {
position.y += delta;
}
if (position.x !== oldPosition.x || position.y !== oldPosition.y) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
strategy.setPosition(position.x, position.y);
}
});
} }
return { return {

View file

@ -2,6 +2,11 @@ var App = App || {};
App.Util = App.Util || {}; App.Util = App.Util || {};
App.Util.Resizable = function(jQuery) { App.Util.Resizable = function(jQuery) {
var KEY_LEFT = 37;
var KEY_UP = 38;
var KEY_RIGHT = 39;
var KEY_DOWN = 40;
function relativeResizeStrategy($element) { function relativeResizeStrategy($element) {
var $parent = $element.parent(); var $parent = $element.parent();
var delta; var delta;
@ -51,6 +56,7 @@ App.Util.Resizable = function(jQuery) {
$resizer.mousedown(function(e) { $resizer.mousedown(function(e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
$element.focus();
$element.addClass('resizing'); $element.addClass('resizing');
strategy.mouseClicked(e); strategy.mouseClicked(e);
@ -65,6 +71,32 @@ App.Util.Resizable = function(jQuery) {
jQuery(window).unbind('mouseup.elemsize'); jQuery(window).unbind('mouseup.elemsize');
}); });
}); });
$element.keydown(function(e) {
var size = strategy.getSize();
var oldSize = {width: size.width, height: size.height};
if (!e.shiftKey) {
return;
}
var delta = e.ctrlKey ? 10 : 1;
if (e.which === KEY_LEFT) {
size.width -= delta;
} else if (e.which === KEY_RIGHT) {
size.width += delta;
} else if (e.which === KEY_UP) {
size.height -= delta;
} else if (e.which === KEY_DOWN) {
size.height += delta;
}
if (size.width !== oldSize.width || size.height !== oldSize.height) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
strategy.setSize(size.width, size.height);
}
});
} }
return { return {

View file

@ -1,6 +1,6 @@
<div class="post-notes"> <div class="post-notes">
<% _.each(notes, function(note) { %> <% _.each(notes, function(note) { %>
<div class="post-note" <div tabindex="0" class="post-note"
style="left: <%= note.left %>%; style="left: <%= note.left %>%;
top: <%= note.top %>%; top: <%= note.top %>%;
width: <%= note.width %>%; width: <%= note.width %>%;