diff --git a/package.json b/package.json index b186a6cb..549247d5 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "aria-query": "5.3.0", "chalk": "^4.1.0", "dom-accessibility-api": "^0.5.9", + "lodash": "^4.17.21", "lz-string": "^1.5.0", "pretty-format": "^27.0.2" }, diff --git a/src/__tests__/fake-timers.js b/src/__tests__/fake-timers.js index 6cf7ca5f..293ecfb7 100644 --- a/src/__tests__/fake-timers.js +++ b/src/__tests__/fake-timers.js @@ -60,9 +60,9 @@ test('times out after 1000ms by default', async () => { jest.useRealTimers() // NOTE: this assertion ensures that the timeout runs in the declared (fake) clock // while in real time the time was only a fraction since the real clock is only bound by the CPU. - // So 20ms is really just an approximation on how long the CPU needs to execute our code. + // So 80ms is really just an approximation on how long the CPU needs to execute our code. // If people want to timeout in real time they should rely on their test runners. - expect(performance.now() - startReal).toBeLessThanOrEqual(20) + expect(performance.now() - startReal).toBeLessThanOrEqual(80) }) test('recursive timers do not cause issues', async () => { diff --git a/src/event-map.js b/src/event-map.js index 08676759..485dd620 100644 --- a/src/event-map.js +++ b/src/event-map.js @@ -1,3 +1,6 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import _ from 'lodash' +import {valiateByAttr} from './life-cycle' export const eventMap = { // Clipboard Events copy: { @@ -112,10 +115,24 @@ export const eventMap = { dragOver: { EventType: 'DragEvent', defaultInit: {bubbles: true, cancelable: true, composed: true}, + cond: conditionObj => { + const shouldTrueAttrArr = ['dragover'] + const shouldFalseAttrArr = ['defaultprevented'] + if (valiateByAttr(conditionObj, [], shouldFalseAttrArr)) { + return true + } + if (valiateByAttr(conditionObj, shouldTrueAttrArr, [])) { + return true + } + return false + }, }, dragStart: { EventType: 'DragEvent', defaultInit: {bubbles: true, cancelable: true, composed: true}, + before: (config = {}) => { + return _.pick(config, ['dragstart', 'defaultprevented']) + }, }, drop: { EventType: 'DragEvent', diff --git a/src/events.js b/src/events.js index b964f305..e25b9198 100644 --- a/src/events.js +++ b/src/events.js @@ -1,8 +1,17 @@ import {getConfig} from './config' import {getWindowFromNode} from './helpers' import {eventMap, eventAliasMap} from './event-map' +import {beforeFn} from './life-cycle' +const NodeEventMap = new Map() -function fireEvent(element, event) { +function fireEvent( + element, + event, + cond = () => { + return true + }, + before, +) { return getConfig().eventWrapper(() => { if (!event) { throw new Error( @@ -14,7 +23,21 @@ function fireEvent(element, event) { `Unable to fire a "${event.type}" event - please provide a DOM element.`, ) } - return element.dispatchEvent(event) + const CloneConditionValue = NodeEventMap.get(element) + const condition = beforeFn(CloneConditionValue, event, before) + if (cond && typeof cond == 'function') { + if (cond(condition)) { + element.dispatchEvent(event) + } + } + if (event.defaultPrevented) { + condition.defaultprevented = true + } + NodeEventMap.set(element, condition) + if (event.cancelable && event.defaultPrevented) { + return false + } + return true }) } @@ -93,12 +116,14 @@ function createEvent( } Object.keys(eventMap).forEach(key => { - const {EventType, defaultInit} = eventMap[key] + const {EventType, defaultInit, cond, before} = eventMap[key] const eventName = key.toLowerCase() createEvent[key] = (node, init) => createEvent(eventName, node, init, {EventType, defaultInit}) - fireEvent[key] = (node, init) => fireEvent(node, createEvent[key](node, init)) + fireEvent[key] = (node, init) => { + return fireEvent(node, createEvent[key](node, init), cond, before) + } }) // function written after some investigation here: diff --git a/src/life-cycle.js b/src/life-cycle.js new file mode 100644 index 00000000..57429de8 --- /dev/null +++ b/src/life-cycle.js @@ -0,0 +1,53 @@ +/** + * @description before->cond->dispatch + */ + +export const beforeFn = ( + initValue, + event, + before = config => { + return config + }, +) => { + let ConditionValue = initValue + if (before && typeof before == 'function') { + ConditionValue = before(ConditionValue) + } + if (!ConditionValue) { + ConditionValue = { + [`${event.type}`]: true, + } + } + if (ConditionValue) { + ConditionValue = { + ...ConditionValue, + [`${event.type}`]: true, + } + } + return ConditionValue +} + +/** + * @description judge attr exist about condition + * @param {*} element + * @param {*} AttrObj + * @returns + */ +export function valiateByAttr(element, AttrTrueObj, AttrFalseObj) { + if (!element) { + return false + } + let trueFlag = true + for (const i in AttrTrueObj) { + if (element[`${AttrTrueObj[i]}`]) { + trueFlag = false + } + } + let falseFlag = true + for (const i in AttrFalseObj) { + if (element[`${AttrFalseObj[i]}`]) { + falseFlag = false + } + } + return trueFlag && falseFlag +}