overleaf/services/web/public/js/ace/lib/event.js
2014-02-12 10:23:40 +00:00

355 lines
11 KiB
JavaScript
Executable file

/* ***** BEGIN LICENSE BLOCK *****
* Distributed under the BSD license:
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
"use strict";
var keys = require("./keys");
var useragent = require("./useragent");
var dom = require("./dom");
exports.addListener = function(elem, type, callback) {
if (elem.addEventListener) {
return elem.addEventListener(type, callback, false);
}
if (elem.attachEvent) {
var wrapper = function() {
callback.call(elem, window.event);
};
callback._wrapper = wrapper;
elem.attachEvent("on" + type, wrapper);
}
};
exports.removeListener = function(elem, type, callback) {
if (elem.removeEventListener) {
return elem.removeEventListener(type, callback, false);
}
if (elem.detachEvent) {
elem.detachEvent("on" + type, callback._wrapper || callback);
}
};
/*
* Prevents propagation and clobbers the default action of the passed event
*/
exports.stopEvent = function(e) {
exports.stopPropagation(e);
exports.preventDefault(e);
return false;
};
exports.stopPropagation = function(e) {
if (e.stopPropagation)
e.stopPropagation();
else
e.cancelBubble = true;
};
exports.preventDefault = function(e) {
if (e.preventDefault)
e.preventDefault();
else
e.returnValue = false;
};
/*
* @return {Number} 0 for left button, 1 for middle button, 2 for right button
*/
exports.getButton = function(e) {
if (e.type == "dblclick")
return 0;
if (e.type == "contextmenu" || (e.ctrlKey && useragent.isMac))
return 2;
// DOM Event
if (e.preventDefault) {
return e.button;
}
// old IE
else {
return {1:0, 2:2, 4:1}[e.button];
}
};
exports.capture = function(el, eventHandler, releaseCaptureHandler) {
function onMouseUp(e) {
eventHandler && eventHandler(e);
releaseCaptureHandler && releaseCaptureHandler(e);
exports.removeListener(document, "mousemove", eventHandler, true);
exports.removeListener(document, "mouseup", onMouseUp, true);
exports.removeListener(document, "dragstart", onMouseUp, true);
}
exports.addListener(document, "mousemove", eventHandler, true);
exports.addListener(document, "mouseup", onMouseUp, true);
exports.addListener(document, "dragstart", onMouseUp, true);
return onMouseUp;
};
exports.addMouseWheelListener = function(el, callback) {
if ("onmousewheel" in el) {
var factor = 8;
exports.addListener(el, "mousewheel", function(e) {
if (e.wheelDeltaX !== undefined) {
e.wheelX = -e.wheelDeltaX / factor;
e.wheelY = -e.wheelDeltaY / factor;
} else {
e.wheelX = 0;
e.wheelY = -e.wheelDelta / factor;
}
callback(e);
});
} else if ("onwheel" in el) {
exports.addListener(el, "wheel", function(e) {
e.wheelX = (e.deltaX || 0) * 5;
e.wheelY = (e.deltaY || 0) * 5;
callback(e);
});
} else {
exports.addListener(el, "DOMMouseScroll", function(e) {
if (e.axis && e.axis == e.HORIZONTAL_AXIS) {
e.wheelX = (e.detail || 0) * 5;
e.wheelY = 0;
} else {
e.wheelX = 0;
e.wheelY = (e.detail || 0) * 5;
}
callback(e);
});
}
};
exports.addMultiMouseDownListener = function(el, timeouts, eventHandler, callbackName) {
var clicks = 0;
var startX, startY, timer;
var eventNames = {
2: "dblclick",
3: "tripleclick",
4: "quadclick"
};
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 {
clicks = 1;
}
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);
if (clicks > 4)
clicks = 0;
else if (clicks > 1)
return eventHandler[callbackName](eventNames[clicks], e);
});
if (useragent.isOldIE) {
exports.addListener(el, "dblclick", function(e) {
clicks = 2;
if (timer)
clearTimeout(timer);
timer = setTimeout(function() {timer = null}, timeouts[clicks - 1] || 600);
eventHandler[callbackName]("mousedown", e);
eventHandler[callbackName](eventNames[clicks], e);
});
}
};
function normalizeCommandKeys(callback, e, keyCode) {
var hashId = 0;
if ((useragent.isOpera && !("KeyboardEvent" in window)) && useragent.isMac) {
hashId = 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0)
| (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0);
} else {
hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0)
| (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0);
}
if (!useragent.isMac && pressedKeys) {
if (pressedKeys[91] || pressedKeys[92])
hashId |= 8;
if (pressedKeys.altGr) {
if ((3 & hashId) != 3)
pressedKeys.altGr = 0
else
return;
}
if (keyCode === 18 || keyCode === 17) {
var location = e.location || e.keyLocation;
if (keyCode === 17 && location === 1) {
ts = e.timeStamp;
} else if (keyCode === 18 && hashId === 3 && location === 2) {
var dt = -ts;
ts = e.timeStamp;
dt += ts;
if (dt < 3)
pressedKeys.altGr = true;
}
}
}
if (keyCode in keys.MODIFIER_KEYS) {
switch (keys.MODIFIER_KEYS[keyCode]) {
case "Alt":
hashId = 2;
break;
case "Shift":
hashId = 4;
break;
case "Ctrl":
hashId = 1;
break;
default:
hashId = 8;
break;
}
keyCode = 0;
}
if (hashId & 8 && (keyCode === 91 || keyCode === 93)) {
keyCode = 0;
}
if (!hashId && keyCode === 13) {
if (e.location || e.keyLocation === 3) {
callback(e, hashId, -keyCode)
if (e.defaultPrevented)
return;
}
}
// If there is no hashId and the keyCode is not a function key, then
// we don't call the callback as we don't handle a command key here
// (it's a normal key/character input).
if (!hashId && !(keyCode in keys.FUNCTION_KEYS) && !(keyCode in keys.PRINTABLE_KEYS)) {
return false;
}
return callback(e, hashId, keyCode);
}
var pressedKeys = null;
var ts = 0;
exports.addCommandKeyListener = function(el, callback) {
var addListener = exports.addListener;
if (useragent.isOldGecko || (useragent.isOpera && !("KeyboardEvent" in window))) {
// Old versions of Gecko aka. Firefox < 4.0 didn't repeat the keydown
// event if the user pressed the key for a longer time. Instead, the
// keydown event was fired once and later on only the keypress event.
// To emulate the 'right' keydown behavior, the keyCode of the initial
// keyDown event is stored and in the following keypress events the
// stores keyCode is used to emulate a keyDown event.
var lastKeyDownKeyCode = null;
addListener(el, "keydown", function(e) {
lastKeyDownKeyCode = e.keyCode;
});
addListener(el, "keypress", function(e) {
return normalizeCommandKeys(callback, e, lastKeyDownKeyCode);
});
} else {
var lastDefaultPrevented = null;
addListener(el, "keydown", function(e) {
pressedKeys[e.keyCode] = true;
var result = normalizeCommandKeys(callback, e, e.keyCode);
lastDefaultPrevented = e.defaultPrevented;
return result;
});
addListener(el, "keypress", function(e) {
if (lastDefaultPrevented && (e.ctrlKey || e.altKey || e.shiftKey || e.metaKey)) {
exports.stopEvent(e);
lastDefaultPrevented = null;
}
});
addListener(el, "keyup", function(e) {
pressedKeys[e.keyCode] = null;
});
if (!pressedKeys) {
pressedKeys = Object.create(null);
addListener(window, "focus", function(e) {
pressedKeys = Object.create(null);
});
}
}
};
if (window.postMessage && !useragent.isOldIE) {
var postMessageId = 1;
exports.nextTick = function(callback, win) {
win = win || window;
var messageName = "zero-timeout-message-" + postMessageId;
exports.addListener(win, "message", function listener(e) {
if (e.data == messageName) {
exports.stopPropagation(e);
exports.removeListener(win, "message", listener);
callback();
}
});
win.postMessage(messageName, "*");
};
}
exports.nextFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame;
if (exports.nextFrame)
exports.nextFrame = exports.nextFrame.bind(window);
else
exports.nextFrame = function(callback) {
setTimeout(callback, 17);
};
});