Skip to content

Commit

Permalink
Merge pull request #1599 from danyaPostfactum/nativednd
Browse files Browse the repository at this point in the history
Use native HTML5 Drag'n'Drop for text.
  • Loading branch information
lennartcl committed Sep 20, 2013
2 parents 2ae8a96 + 8a841df commit ee95161
Show file tree
Hide file tree
Showing 10 changed files with 513 additions and 289 deletions.
27 changes: 23 additions & 4 deletions lib/ace/css/editor.css
Expand Up @@ -5,6 +5,10 @@
font-size: 12px;
line-height: normal;
color: black;
-ms-user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
}

.ace_scroller {
Expand All @@ -23,6 +27,25 @@
cursor: text;
}

.ace_dragging, .ace_dragging * {
cursor: default !important;
}

.ace_dragging .ace_scroller:before{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
content: '';
background: rgba(0, 0, 0, 0.01);
z-index: 1000;
}

.ace_selecting, .ace_selecting * {
cursor: text !important;
}

.ace_gutter {
position: absolute;
overflow : hidden;
Expand Down Expand Up @@ -258,10 +281,6 @@
background-position: center center, top left;
}

.ace_editor.ace_dragging .ace_content {
cursor: move;
}

.ace_gutter-tooltip {
background-color: #FFF;
background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.1));
Expand Down
2 changes: 1 addition & 1 deletion lib/ace/edit_session.js
Expand Up @@ -1327,7 +1327,7 @@ var EditSession = function(text, mode) {
}
}

this.insert(toRange.start, text);
toRange.end = this.insert(toRange.start, text);
if (folds.length) {
var oldStart = fromRange.start;
var newStart = toRange.start;
Expand Down
5 changes: 3 additions & 2 deletions lib/ace/editor.js
Expand Up @@ -1559,8 +1559,8 @@ var Editor = function(renderer, session) {
* @returns {Range} The new range where the text was moved to.
* @related EditSession.moveText
**/
this.moveText = function(range, toPosition) {
return this.session.moveText(range, toPosition);
this.moveText = function(range, toPosition, copy) {
return this.session.moveText(range, toPosition, copy);
};

/**
Expand Down Expand Up @@ -2403,6 +2403,7 @@ config.defineOptions(Editor.prototype, "editor", {

scrollSpeed: "$mouseHandler",
dragDelay: "$mouseHandler",
dragEnabled: "$mouseHandler",
focusTimout: "$mouseHandler",

firstLineNumber: "session",
Expand Down
77 changes: 28 additions & 49 deletions lib/ace/lib/event.js
Expand Up @@ -41,7 +41,7 @@ exports.addListener = function(elem, type, callback) {
}
if (elem.attachEvent) {
var wrapper = function() {
callback(window.event);
callback.call(elem, window.event);
};
callback._wrapper = wrapper;
elem.attachEvent("on" + type, wrapper);
Expand Down Expand Up @@ -99,44 +99,22 @@ exports.getButton = function(e) {
}
};

if (document.documentElement.setCapture) {
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
var called = false;
function onReleaseCapture(e) {
eventHandler(e);
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
function onMouseUp(e) {
eventHandler && eventHandler(e);
releaseCaptureHandler && releaseCaptureHandler(e);

if (!called) {
called = true;
releaseCaptureHandler(e);
}

exports.removeListener(el, "mousemove", eventHandler);
exports.removeListener(el, "mouseup", onReleaseCapture);
exports.removeListener(el, "losecapture", onReleaseCapture);
exports.removeListener(document, "mousemove", eventHandler, true);
exports.removeListener(document, "mouseup", onMouseUp, true);
exports.removeListener(document, "dragstart", onMouseUp, true);

el.releaseCapture();
}

exports.addListener(el, "mousemove", eventHandler);
exports.addListener(el, "mouseup", onReleaseCapture);
exports.addListener(el, "losecapture", onReleaseCapture);
el.setCapture();
};
}
else {
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
function onMouseUp(e) {
eventHandler && eventHandler(e);
releaseCaptureHandler && releaseCaptureHandler(e);

document.removeEventListener("mousemove", eventHandler, true);
document.removeEventListener("mouseup", onMouseUp, true);
}
exports.stopPropagation(e);
}

document.addEventListener("mousemove", eventHandler, true);
document.addEventListener("mouseup", onMouseUp, true);
};
}
exports.addListener(document, "mousemove", eventHandler, true);
exports.addListener(document, "mouseup", onMouseUp, true);
exports.addListener(document, "dragstart", onMouseUp, true);
};

exports.addMouseWheelListener = function(el, callback) {
if ("onmousewheel" in el) {
Expand Down Expand Up @@ -183,21 +161,22 @@ exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbac
exports.addListener(el, "mousedown", function(e) {
if (exports.getButton(e) != 0) {
clicks = 0;
} else if (e.detail > 1) {
clicks++;
if (clicks > 4)
clicks = 1;
} else {
var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5;

if (!timer || isNewClick)
clicks = 0;

clicks += 1;

if (timer)
clearTimeout(timer)
timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600);
clicks = 1;
}
if (clicks == 1) {
startX = e.clientX;
startY = e.clientY;
if (useragent.isIE) {
var isNewClick = Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5;
if (isNewClick) {
clicks = 1;
}
if (clicks == 1) {
startX = e.clientX;
startY = e.clientY;
}
}

eventHandler[callbackName]("mousedown", e);
Expand Down
3 changes: 2 additions & 1 deletion lib/ace/mouse/default_gutter_handler.js
Expand Up @@ -57,7 +57,8 @@ function GutterHandler(mouseHandler) {
}
mouseHandler.$clickSelection = editor.selection.getLineRange(row);
}
mouseHandler.captureMouse(e, "selectByLines");
mouseHandler.setState("selectByLines");
mouseHandler.captureMouse(e);
return e.preventDefault();
});

Expand Down
118 changes: 28 additions & 90 deletions lib/ace/mouse/default_handlers.js
Expand Up @@ -32,6 +32,7 @@ define(function(require, exports, module) {
"use strict";

var dom = require("../lib/dom");
var event = require("../lib/event");
var useragent = require("../lib/useragent");

var DRAG_OFFSET = 0; // pixels
Expand All @@ -46,8 +47,8 @@ function DefaultHandlers(mouseHandler) {
editor.setDefaultHandler("quadclick", this.onQuadClick.bind(mouseHandler));
editor.setDefaultHandler("mousewheel", this.onMouseWheel.bind(mouseHandler));

var exports = ["select", "startSelect", "drag", "dragEnd", "dragWait",
"dragWaitEnd", "startDrag", "focusWait"];
var exports = ["select", "startSelect", "selectEnd", "selectAllEnd", "selectByWordsEnd",
"selectByLinesEnd", "dragWait", "dragWaitEnd", "focusWait"];

exports.forEach(function(x) {
mouseHandler[x] = this[x];
Expand Down Expand Up @@ -85,9 +86,10 @@ function DefaultHandlers(mouseHandler) {
if (inSelection && !editor.isFocused()) {
editor.focus();
if (this.$focusTimout && !this.$clickSelection && !editor.inMultiSelectMode) {
this.mousedownEvent.time = (new Date()).getTime();
this.setState("focusWait");
this.captureMouse(ev);
return ev.preventDefault();
return;
}
}

Expand All @@ -97,22 +99,29 @@ function DefaultHandlers(mouseHandler) {
this.startSelect(pos);
} else if (inSelection) {
this.mousedownEvent.time = (new Date()).getTime();
this.setState("dragWait");
this.startSelect(pos);
}

this.captureMouse(ev);
return ev.preventDefault();
};

this.startSelect = function(pos) {
pos = pos || this.editor.renderer.screenToTextCoordinates(this.x, this.y);
if (this.mousedownEvent.getShiftKey()) {
this.editor.selection.selectToPosition(pos);
}
else if (!this.$clickSelection) {
this.editor.moveCursorToPosition(pos);
this.editor.selection.clearSelection();
var editor = this.editor;
// allow double/triple click handlers to change selection
setTimeout(function(){
if (this.mousedownEvent.getShiftKey()) {
editor.selection.selectToPosition(pos);
}
else if (!this.$clickSelection) {
editor.moveCursorToPosition(pos);
editor.selection.clearSelection();
}
}.bind(this), 0);
if (editor.container.setCapture) {
editor.container.setCapture();
}
editor.setStyle("ace_selecting");
this.setState("select");
};

Expand Down Expand Up @@ -171,32 +180,14 @@ function DefaultHandlers(mouseHandler) {
editor.renderer.scrollCursorIntoView();
};

this.startDrag = function() {
var editor = this.editor;
this.setState("drag");
this.dragRange = editor.getSelectionRange();
var style = editor.getSelectionStyle();
this.dragSelectionMarker = editor.session.addMarker(this.dragRange, "ace_selection", style);
editor.clearSelection();
dom.addCssClass(editor.container, "ace_dragging");
if (!this.$dragKeybinding) {
this.$dragKeybinding = {
handleKeyboard: function(data, hashId, keyString, keyCode) {
if (keyString == "esc")
return {command: this.command};
},
command: {
exec: function(editor) {
var self = editor.$mouseHandler;
self.dragCursor = null;
self.dragEnd();
self.startSelect();
}
}
}
this.selectEnd =
this.selectAllEnd =
this.selectByWordsEnd =
this.selectByLinesEnd = function() {
this.editor.unsetStyle("ace_selecting");
if (this.editor.container.releaseCapture) {
this.editor.container.releaseCapture();
}

editor.keyBinding.addKeyboardHandler(this.$dragKeybinding);
};

this.focusWait = function() {
Expand All @@ -207,59 +198,6 @@ function DefaultHandlers(mouseHandler) {
this.startSelect(this.mousedownEvent.getDocumentPosition());
};

this.dragWait = function(e) {
var distance = calcDistance(this.mousedownEvent.x, this.mousedownEvent.y, this.x, this.y);
var time = (new Date()).getTime();
var editor = this.editor;

if (distance > DRAG_OFFSET) {
this.startSelect(this.mousedownEvent.getDocumentPosition());
} else if (time - this.mousedownEvent.time > editor.$mouseHandler.$dragDelay) {
this.startDrag();
}
};

this.dragWaitEnd = function(e) {
this.mousedownEvent.domEvent = e;
this.startSelect();
};

this.drag = function() {
var editor = this.editor;
this.dragCursor = editor.renderer.screenToTextCoordinates(this.x, this.y);
editor.moveCursorToPosition(this.dragCursor);
editor.renderer.scrollCursorIntoView();
};

this.dragEnd = function(e) {
var editor = this.editor;
var dragCursor = this.dragCursor;
var dragRange = this.dragRange;
dom.removeCssClass(editor.container, "ace_dragging");
editor.session.removeMarker(this.dragSelectionMarker);
editor.keyBinding.removeKeyboardHandler(this.$dragKeybinding);

if (!dragCursor)
return;

editor.clearSelection();
if (e && (e.ctrlKey || e.altKey)) {
var session = editor.session;
var newRange = dragRange;
newRange.end = session.insert(dragCursor, session.getTextRange(dragRange));
newRange.start = dragCursor;
} else if (dragRange.contains(dragCursor.row, dragCursor.column)) {
return;
} else {
var newRange = editor.moveText(dragRange, dragCursor);
}

if (!newRange)
return;

editor.selection.setSelectionRange(newRange);
};

this.onDoubleClick = function(ev) {
var pos = ev.getDocumentPosition();
var editor = this.editor;
Expand Down Expand Up @@ -293,7 +231,7 @@ function DefaultHandlers(mouseHandler) {

editor.selectAll();
this.$clickSelection = editor.getSelectionRange();
this.setState("null");
this.setState("selectAll");
};

this.onMouseWheel = function(ev) {
Expand Down

0 comments on commit ee95161

Please sign in to comment.