/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Ajax.org Code Editor (ACE). * * The Initial Developer of the Original Code is * Ajax.org B.V. * Portions created by the Initial Developer are Copyright (C) 2010 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Fabian Jakobs * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** 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(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; }; exports.getDocumentX = function(e) { if (e.clientX) { return e.clientX + dom.getPageScrollLeft(); } else { return e.pageX; } }; exports.getDocumentY = function(e) { if (e.clientY) { return e.clientY + dom.getPageScrollTop(); } else { return e.pageY; } }; /** * @return {Number} 0 for left button, 1 for middle button, 2 for right button */ exports.getButton = function(e) { if (e.type == "dblclick") return 0; else if (e.type == "contextmenu") return 2; // DOM Event if (e.preventDefault) { return e.button; } // old IE else { return {1:0, 2:2, 4:1}[e.button]; } }; if (document.documentElement.setCapture) { exports.capture = function(el, eventHandler, releaseCaptureHandler) { function onMouseMove(e) { eventHandler(e); return exports.stopPropagation(e); } var called = false; function onReleaseCapture(e) { eventHandler(e); if (!called) { called = true; releaseCaptureHandler(e); } exports.removeListener(el, "mousemove", eventHandler); exports.removeListener(el, "mouseup", onReleaseCapture); exports.removeListener(el, "losecapture", onReleaseCapture); 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 onMouseMove(e) { eventHandler(e); e.stopPropagation(); } function onMouseUp(e) { eventHandler && eventHandler(e); releaseCaptureHandler && releaseCaptureHandler(e); document.removeEventListener("mousemove", onMouseMove, true); document.removeEventListener("mouseup", onMouseUp, true); e.stopPropagation(); } document.addEventListener("mousemove", onMouseMove, true); document.addEventListener("mouseup", onMouseUp, true); }; } exports.addMouseWheelListener = function(el, callback) { var max = 0; var listener = function(e) { if (e.wheelDelta !== undefined) { // some versions of Safari (e.g. 5.0.5) report insanely high // scroll values. These browsers require a higher factor if (Math.abs(e.wheelDeltaY) > max) max = Math.abs(e.wheelDeltaY); if (max > 5000) var factor = 400; else var factor = 8; if (e.wheelDeltaX !== undefined) { e.wheelX = -e.wheelDeltaX / factor; e.wheelY = -e.wheelDeltaY / factor; } else { e.wheelX = 0; e.wheelY = -e.wheelDelta / factor; } } else { 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.addListener(el, "DOMMouseScroll", listener); exports.addListener(el, "mousewheel", listener); }; exports.addMultiMouseDownListener = function(el, button, count, timeout, callback) { var clicks = 0; var startX, startY; var listener = function(e) { clicks += 1; if (clicks == 1) { startX = e.clientX; startY = e.clientY; setTimeout(function() { clicks = 0; }, timeout || 600); } var isButton = exports.getButton(e) == button; if (!isButton || Math.abs(e.clientX - startX) > 5 || Math.abs(e.clientY - startY) > 5) clicks = 0; if (clicks == count) { clicks = 0; callback(e); } if (isButton) return exports.preventDefault(e); }; exports.addListener(el, "mousedown", listener); useragent.isOldIE && exports.addListener(el, "dblclick", listener); }; function normalizeCommandKeys(callback, e, keyCode) { var hashId = 0; if (useragent.isOpera && 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 (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 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); } exports.addCommandKeyListener = function(el, callback) { var addListener = exports.addListener; if (useragent.isOldGecko || useragent.isOpera) { // 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 lastDown = null; addListener(el, "keydown", function(e) { lastDown = e.keyIdentifier || e.keyCode; return normalizeCommandKeys(callback, e, e.keyCode); }); } }; if (window.postMessage) { 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, "*"); }; } else { exports.nextTick = function(callback, win) { win = win || window; window.setTimeout(callback, 0); }; } });