mirror of
https://github.com/google/blockly.git
synced 2026-01-04 15:40:08 +01:00
* fix(build): Restore erroneously-deleted filter function This was deleted in PR #7406 as it was mainly being used to filter core/ vs. test/mocha/ deps into separate deps files - but it turns out also to be used for filtering error messages too. Oops. * refactor(tests): Migrate advanced compilation test to ES Modules * refactor(build): Migrate main.js to TypeScript This turns out to be pretty straight forward, even if it would cause crashing if one actually tried to import this module instead of just feeding it to Closure Compiler. * chore(build): Remove goog.declareModuleId calls Replace goog.declareModuleId calls with a comment recording the former module ID for posterity (or at least until we decide how to reformat the renamings file. * chore(tests): Delete closure/goog/* For the moment we still need something to serve as base.js for the benefit of closure-make-deps, so we keep a vestigial base.js around, containing only the @provideGoog declaration. * refactor(build): Remove vestigial base.js By changing slightly the command line arguments to closure-make-deps and closure-calculate-chunks the need to have any base.js is eliminated. * chore: Typo fix for PR #7415
245 lines
6.6 KiB
TypeScript
245 lines
6.6 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2021 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
// Former goog.module ID: Blockly.browserEvents
|
|
|
|
import * as Touch from './touch.js';
|
|
import * as userAgent from './utils/useragent.js';
|
|
|
|
/**
|
|
* Blockly opaque event data used to unbind events when using
|
|
* `bind` and `conditionalBind`.
|
|
*/
|
|
export type Data = [EventTarget, string, (e: Event) => void][];
|
|
|
|
/**
|
|
* The multiplier for scroll wheel deltas using the line delta mode.
|
|
* See https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
|
|
* for more information on deltaMode.
|
|
*/
|
|
const LINE_MODE_MULTIPLIER = 40;
|
|
|
|
/**
|
|
* The multiplier for scroll wheel deltas using the page delta mode.
|
|
* See https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode
|
|
* for more information on deltaMode.
|
|
*/
|
|
const PAGE_MODE_MULTIPLIER = 125;
|
|
|
|
/**
|
|
* Bind an event handler that can be ignored if it is not part of the active
|
|
* touch stream.
|
|
* Use this for events that either start or continue a multi-part gesture (e.g.
|
|
* mousedown or mousemove, which may be part of a drag or click).
|
|
*
|
|
* @param node Node upon which to listen.
|
|
* @param name Event name to listen to (e.g. 'mousedown').
|
|
* @param thisObject The value of 'this' in the function.
|
|
* @param func Function to call when event is triggered.
|
|
* @param opt_noCaptureIdentifier True if triggering on this event should not
|
|
* block execution of other event handlers on this touch or other
|
|
* simultaneous touches. False by default.
|
|
* @returns Opaque data that can be passed to unbindEvent_.
|
|
*/
|
|
export function conditionalBind(
|
|
node: EventTarget,
|
|
name: string,
|
|
thisObject: Object | null,
|
|
func: Function,
|
|
opt_noCaptureIdentifier?: boolean,
|
|
): Data {
|
|
/**
|
|
*
|
|
* @param e
|
|
*/
|
|
function wrapFunc(e: Event) {
|
|
const captureIdentifier = !opt_noCaptureIdentifier;
|
|
|
|
if (!(captureIdentifier && !Touch.shouldHandleEvent(e))) {
|
|
if (thisObject) {
|
|
func.call(thisObject, e);
|
|
} else {
|
|
func(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
const bindData: Data = [];
|
|
if (name in Touch.TOUCH_MAP) {
|
|
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
|
|
const type = Touch.TOUCH_MAP[name][i];
|
|
node.addEventListener(type, wrapFunc, false);
|
|
bindData.push([node, type, wrapFunc]);
|
|
}
|
|
} else {
|
|
node.addEventListener(name, wrapFunc, false);
|
|
bindData.push([node, name, wrapFunc]);
|
|
}
|
|
return bindData;
|
|
}
|
|
|
|
/**
|
|
* Bind an event handler that should be called regardless of whether it is part
|
|
* of the active touch stream.
|
|
* Use this for events that are not part of a multi-part gesture (e.g.
|
|
* mouseover for tooltips).
|
|
*
|
|
* @param node Node upon which to listen.
|
|
* @param name Event name to listen to (e.g. 'mousedown').
|
|
* @param thisObject The value of 'this' in the function.
|
|
* @param func Function to call when event is triggered.
|
|
* @returns Opaque data that can be passed to unbindEvent_.
|
|
*/
|
|
export function bind(
|
|
node: EventTarget,
|
|
name: string,
|
|
thisObject: Object | null,
|
|
func: Function,
|
|
): Data {
|
|
/**
|
|
*
|
|
* @param e
|
|
*/
|
|
function wrapFunc(e: Event) {
|
|
if (thisObject) {
|
|
func.call(thisObject, e);
|
|
} else {
|
|
func(e);
|
|
}
|
|
}
|
|
|
|
const bindData: Data = [];
|
|
if (name in Touch.TOUCH_MAP) {
|
|
for (let i = 0; i < Touch.TOUCH_MAP[name].length; i++) {
|
|
const type = Touch.TOUCH_MAP[name][i];
|
|
node.addEventListener(type, wrapFunc, false);
|
|
bindData.push([node, type, wrapFunc]);
|
|
}
|
|
} else {
|
|
node.addEventListener(name, wrapFunc, false);
|
|
bindData.push([node, name, wrapFunc]);
|
|
}
|
|
return bindData;
|
|
}
|
|
|
|
/**
|
|
* Unbind one or more events event from a function call.
|
|
*
|
|
* @param bindData Opaque data from bindEvent_.
|
|
* This list is emptied during the course of calling this function.
|
|
* @returns The function call.
|
|
*/
|
|
export function unbind(bindData: Data): (e: Event) => void {
|
|
// Accessing an element of the last property of the array is unsafe if the
|
|
// bindData is an empty array. But that should never happen because developers
|
|
// should only pass Data from bind or conditionalBind.
|
|
const callback = bindData[bindData.length - 1][2];
|
|
while (bindData.length) {
|
|
const [node, name, func] = bindData.pop()!;
|
|
node.removeEventListener(name, func, false);
|
|
}
|
|
return callback;
|
|
}
|
|
|
|
/**
|
|
* Returns true if this event is targeting a text input widget?
|
|
*
|
|
* @param e An event.
|
|
* @returns True if text input.
|
|
*/
|
|
export function isTargetInput(e: Event): boolean {
|
|
if (e.target instanceof HTMLElement) {
|
|
if (
|
|
e.target.isContentEditable ||
|
|
e.target.getAttribute('data-is-text-input') === 'true'
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
if (e.target instanceof HTMLInputElement) {
|
|
const target = e.target;
|
|
return (
|
|
target.type === 'text' ||
|
|
target.type === 'number' ||
|
|
target.type === 'email' ||
|
|
target.type === 'password' ||
|
|
target.type === 'search' ||
|
|
target.type === 'tel' ||
|
|
target.type === 'url'
|
|
);
|
|
}
|
|
|
|
if (e.target instanceof HTMLTextAreaElement) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns true this event is a right-click.
|
|
*
|
|
* @param e Mouse event.
|
|
* @returns True if right-click.
|
|
*/
|
|
export function isRightButton(e: MouseEvent): boolean {
|
|
if (e.ctrlKey && userAgent.MAC) {
|
|
// Control-clicking on Mac OS X is treated as a right-click.
|
|
// WebKit on Mac OS X fails to change button to 2 (but Gecko does).
|
|
return true;
|
|
}
|
|
return e.button === 2;
|
|
}
|
|
|
|
/**
|
|
* Returns the converted coordinates of the given mouse event.
|
|
* The origin (0,0) is the top-left corner of the Blockly SVG.
|
|
*
|
|
* @param e Mouse event.
|
|
* @param svg SVG element.
|
|
* @param matrix Inverted screen CTM to use.
|
|
* @returns Object with .x and .y properties.
|
|
*/
|
|
export function mouseToSvg(
|
|
e: MouseEvent,
|
|
svg: SVGSVGElement,
|
|
matrix: SVGMatrix | null,
|
|
): SVGPoint {
|
|
const svgPoint = svg.createSVGPoint();
|
|
svgPoint.x = e.clientX;
|
|
svgPoint.y = e.clientY;
|
|
|
|
if (!matrix) {
|
|
matrix = svg.getScreenCTM()!.inverse();
|
|
}
|
|
return svgPoint.matrixTransform(matrix);
|
|
}
|
|
|
|
/**
|
|
* Returns the scroll delta of a mouse event in pixel units.
|
|
*
|
|
* @param e Mouse event.
|
|
* @returns Scroll delta object with .x and .y properties.
|
|
*/
|
|
export function getScrollDeltaPixels(e: WheelEvent): {x: number; y: number} {
|
|
switch (e.deltaMode) {
|
|
case 0x00: // Pixel mode.
|
|
default:
|
|
return {x: e.deltaX, y: e.deltaY};
|
|
case 0x01: // Line mode.
|
|
return {
|
|
x: e.deltaX * LINE_MODE_MULTIPLIER,
|
|
y: e.deltaY * LINE_MODE_MULTIPLIER,
|
|
};
|
|
case 0x02: // Page mode.
|
|
return {
|
|
x: e.deltaX * PAGE_MODE_MULTIPLIER,
|
|
y: e.deltaY * PAGE_MODE_MULTIPLIER,
|
|
};
|
|
}
|
|
}
|