import * as utils from '../utils'; export interface Options { enableLongPress: boolean; postMessageSyntax: string; enableEditPopup: boolean; createEditPopupSyntax?: string; destroyEditPopupSyntax?: string; } // longPressTouchStart and clearLongPressTimeout are turned into strings before being called. // Thus, they should not reference any other non-builtin functions. const longPressTouchStartFnString = `(onLongPress, longPressDelay) => { // if touchTimeout is set when ontouchstart is called it means the user has already touched // the screen once and this is the 2nd touch in this case we assume the user is trying // to zoom and we don't want to show the menu if (!!window.touchTimeout) { clearTimeout(window.touchTimeout); window.touchTimeout = null; } else { window.touchTimeout = setTimeout(() => { window.touchTimeout = null; onLongPress(); }, longPressDelay); } }`; const clearLongPressTimeoutFnString = `() => { if (window.touchTimeout) { clearTimeout(window.touchTimeout); window.touchTimeout = null; } }`; // Helper for createEventHandlingAttrs. Exported to facilitate testing. export const createEventHandlingListeners = (resourceId: string, options: Options, onClickAction: string|null) => { const eventHandlers = { ontouchstart: '', ontouchmove: '', ontouchend: '', ontouchcancel: '', onmouseenter: '', onmouseleave: '', onclick: '', }; if (options.enableLongPress) { const longPressHandler = `(() => ${options.postMessageSyntax}('longclick:${resourceId}'))`; const touchStart = `(${longPressTouchStartFnString})(${longPressHandler}, ${utils.longPressDelay}); `; const callClearLongPressTimeout = `(${clearLongPressTimeoutFnString})(); `; const touchCancel = callClearLongPressTimeout; const touchEnd = callClearLongPressTimeout; eventHandlers.ontouchstart += touchStart; eventHandlers.ontouchcancel += touchCancel; eventHandlers.ontouchmove += touchCancel; eventHandlers.ontouchend += touchEnd; } if (options.enableEditPopup) { const editPopupClick = `(() => ${options.postMessageSyntax}('edit:${resourceId}'))`; const createEditPopup = ` (${options.createEditPopupSyntax})(this, ${JSON.stringify(resourceId)}, ${editPopupClick}); `; eventHandlers.ontouchstart += createEditPopup; eventHandlers.onclick += createEditPopup; } if (onClickAction) { eventHandlers.onclick += onClickAction; } return eventHandlers; }; // Adds event-handling (e.g. long press) code to images and links. // resourceId is the ID of the image resource or link. const createEventHandlingAttrs = (resourceId: string, options: Options, onClickAction: string|null) => { const eventHandlers = createEventHandlingListeners(resourceId, options, onClickAction); // Build onfoo="listener" strings and add them to the result. let result = ''; for (const listenerType in eventHandlers) { const eventHandlersDict = eventHandlers as Record; // Only create code for non-empty listeners. if (eventHandlersDict[listenerType].length > 0) { const listener = eventHandlersDict[listenerType].replace(/["]/g, '"'); result += ` ${listenerType}="${listener}" `; } } return result; }; export default createEventHandlingAttrs;