pseudo-dom 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +134 -48
- package/browser/pseudo-dom.js +233 -126
- package/browser/pseudo-dom.min.js +1 -1
- package/dist/classes/PseudoEventListener.d.ts +25 -25
- package/dist/classes/PseudoEventListener.js +37 -34
- package/dist/classes/PseudoEventListener.min.js +1 -1
- package/dist/interfaces/PseudoEventTarget.d.ts +2 -2
- package/dist/services/ElementService.d.ts +1 -0
- package/dist/services/ElementService.js +11 -4
- package/dist/services/ElementService.min.js +1 -1
- package/dist/services/EventService.d.ts +16 -4
- package/dist/services/EventService.js +59 -31
- package/dist/services/EventService.min.js +1 -1
- package/dist/services/EventTargetService.d.ts +41 -9
- package/dist/services/EventTargetService.js +121 -52
- package/dist/services/EventTargetService.min.js +1 -1
- package/package.json +1 -1
|
@@ -18,6 +18,13 @@ const EventService_1 = require('../services/EventService')
|
|
|
18
18
|
* @property {boolean} isDefault
|
|
19
19
|
*/
|
|
20
20
|
class PseudoEventListener {
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} eventType The type of event this listens for
|
|
23
|
+
* @param {Object} [options] The capture, once and passive options
|
|
24
|
+
* @param {Function} handleEvent The function which is called with the event, already bound to what it should run as
|
|
25
|
+
* @param {Function} [originalCallback=handleEvent] The function (or object) which was given when registering, used to find this listener again
|
|
26
|
+
* @constructor
|
|
27
|
+
*/
|
|
21
28
|
constructor (eventType, {
|
|
22
29
|
capture = false,
|
|
23
30
|
once = false,
|
|
@@ -30,6 +37,7 @@ class PseudoEventListener {
|
|
|
30
37
|
}
|
|
31
38
|
this.eventType = ''
|
|
32
39
|
this.defaultListener = false
|
|
40
|
+
this.isRemoved = false
|
|
33
41
|
this.eventOptions = {
|
|
34
42
|
capture,
|
|
35
43
|
once,
|
|
@@ -47,6 +55,11 @@ class PseudoEventListener {
|
|
|
47
55
|
return this.originalCallback
|
|
48
56
|
}
|
|
49
57
|
|
|
58
|
+
/** Whether this listener listens in the capture phase (and at the target) rather than in the bubble phase. */
|
|
59
|
+
get capture () {
|
|
60
|
+
return this.eventOptions.capture
|
|
61
|
+
}
|
|
62
|
+
|
|
50
63
|
get isDefault () {
|
|
51
64
|
return this.defaultListener
|
|
52
65
|
}
|
|
@@ -55,6 +68,20 @@ class PseudoEventListener {
|
|
|
55
68
|
return this.eventOptions.once
|
|
56
69
|
}
|
|
57
70
|
|
|
71
|
+
/** Whether the listener promises not to prevent the default (preventDefault does nothing while it runs). */
|
|
72
|
+
get passive () {
|
|
73
|
+
return this.eventOptions.passive
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Whether this listener has been removed, a removed listener does not run even if the event already started. */
|
|
77
|
+
get removed () {
|
|
78
|
+
return this.isRemoved
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
set removed (removed) {
|
|
82
|
+
this.isRemoved = removed
|
|
83
|
+
}
|
|
84
|
+
|
|
58
85
|
/**
|
|
59
86
|
* @method
|
|
60
87
|
* @name PseudoEventListener#handleEvent
|
|
@@ -66,6 +93,7 @@ class PseudoEventListener {
|
|
|
66
93
|
}
|
|
67
94
|
|
|
68
95
|
/**
|
|
96
|
+
* A capture listener runs while the event travels down to the target.
|
|
69
97
|
* @method
|
|
70
98
|
* @name PseudoEventListener#doCapturePhase
|
|
71
99
|
* @param {PseudoEvent} event
|
|
@@ -76,6 +104,7 @@ class PseudoEventListener {
|
|
|
76
104
|
}
|
|
77
105
|
|
|
78
106
|
/**
|
|
107
|
+
* Every listener of the target itself runs, capture listeners first.
|
|
79
108
|
* @method
|
|
80
109
|
* @name PseudoEventListener#doTargetPhase
|
|
81
110
|
* @param {PseudoEvent} event
|
|
@@ -86,13 +115,14 @@ class PseudoEventListener {
|
|
|
86
115
|
}
|
|
87
116
|
|
|
88
117
|
/**
|
|
118
|
+
* A listener which is not a capture listener runs while the event travels back up (when it bubbles).
|
|
89
119
|
* @method
|
|
90
120
|
* @name PseudoEventListener#doBubblePhase
|
|
91
121
|
* @param {PseudoEvent} event
|
|
92
|
-
* @returns {boolean
|
|
122
|
+
* @returns {boolean}
|
|
93
123
|
*/
|
|
94
124
|
doBubblePhase (event) {
|
|
95
|
-
return event.eventPhase === EventService_1.EventService.BUBBLING_PHASE &&
|
|
125
|
+
return event.eventPhase === EventService_1.EventService.BUBBLING_PHASE && !this.eventOptions.capture
|
|
96
126
|
}
|
|
97
127
|
|
|
98
128
|
/**
|
|
@@ -106,43 +136,16 @@ class PseudoEventListener {
|
|
|
106
136
|
}
|
|
107
137
|
|
|
108
138
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* @returns {boolean|*}
|
|
113
|
-
*/
|
|
114
|
-
skipDefault (event) {
|
|
115
|
-
return this.isDefault && event.defaultPrevented
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* @method
|
|
120
|
-
* @name PseudoEventListener#stopPropagation
|
|
121
|
-
* @param {PseudoEvent} event
|
|
122
|
-
* @returns {boolean}
|
|
123
|
-
*/
|
|
124
|
-
stopPropagation (event) {
|
|
125
|
-
return !this.doTargetPhase(event) && event.inner.propagationStopped
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* @method
|
|
130
|
-
* @name PseudoEventListener#nonPassiveHalt
|
|
131
|
-
* @param {PseudoEvent} event
|
|
132
|
-
* @returns {boolean|*}
|
|
133
|
-
*/
|
|
134
|
-
nonPassiveHalt (event) {
|
|
135
|
-
return !this.eventOptions.passive && (this.skipDefault(event) || event.inner.immediatePropagationStopped || this.stopPropagation(event))
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
+
* Whether this listener should not run for the event as it is now (it was removed, or it is for another phase).
|
|
140
|
+
* Stopping propagation is handled by the dispatching, since it stops other targets and not the listeners of the
|
|
141
|
+
* current one.
|
|
139
142
|
* @method
|
|
140
143
|
* @name PseudoEventListener#rejectEvent
|
|
141
144
|
* @param {PseudoEvent} event
|
|
142
|
-
* @returns {
|
|
145
|
+
* @returns {boolean}
|
|
143
146
|
*/
|
|
144
147
|
rejectEvent (event) {
|
|
145
|
-
return this.
|
|
148
|
+
return this.isRemoved || this.skipPhase(event)
|
|
146
149
|
}
|
|
147
150
|
}
|
|
148
151
|
exports.default = PseudoEventListener
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const EventService_1=require("../services/EventService");class PseudoEventListener{constructor(e,{capture:t=!1,once:s=!1,passive:
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const EventService_1=require("../services/EventService");class PseudoEventListener{constructor(e,{capture:t=!1,once:s=!1,passive:r=!1}={},i,n=i){this.eventOptions={capture:!1,once:!1,passive:!1},this.eventType="",this.defaultListener=!1,this.isRemoved=!1,this.eventOptions={capture:t,once:s,passive:r},this.eventType=e,this.handler=i,this.originalCallback=n}get callback(){return this.originalCallback}get capture(){return this.eventOptions.capture}get isDefault(){return this.defaultListener}get once(){return this.eventOptions.once}get passive(){return this.eventOptions.passive}get removed(){return this.isRemoved}set removed(e){this.isRemoved=e}handleEvent(e){return this.handler(e)}doCapturePhase(e){return e.eventPhase===EventService_1.EventService.CAPTURING_PHASE&&this.eventOptions.capture}doTargetPhase(e){return e.eventPhase===EventService_1.EventService.AT_TARGET}doBubblePhase(e){return e.eventPhase===EventService_1.EventService.BUBBLING_PHASE&&!this.eventOptions.capture}skipPhase(e){return!this.doCapturePhase(e)&&!this.doTargetPhase(e)&&!this.doBubblePhase(e)}rejectEvent(e){return this.isRemoved||this.skipPhase(e)}}exports.default=PseudoEventListener;
|
|
@@ -35,12 +35,12 @@ export interface PseudoEventTarget {
|
|
|
35
35
|
* @param {string} type
|
|
36
36
|
* @param {function} callback
|
|
37
37
|
*/
|
|
38
|
-
removeEventListener(type: string, callback: Function): void;
|
|
38
|
+
removeEventListener(type: string, callback: Function, options?: listenerOptions | boolean): void;
|
|
39
39
|
/**
|
|
40
40
|
* Dispatches an event to this EventTarget.
|
|
41
41
|
* @param {Event|PseudoEvent} event
|
|
42
42
|
* @param {EventTarget|PseudoEventTarget} target
|
|
43
43
|
* @returns {boolean}
|
|
44
44
|
*/
|
|
45
|
-
dispatchEvent(event: PseudoEvent
|
|
45
|
+
dispatchEvent(event: PseudoEvent): boolean;
|
|
46
46
|
}
|
|
@@ -35,6 +35,7 @@ export declare class ElementService extends NodeService implements Partial<Pseud
|
|
|
35
35
|
private readonly attributeList;
|
|
36
36
|
private readonly propertyAttributes;
|
|
37
37
|
private readonly tokenList;
|
|
38
|
+
private defaultEventApplied;
|
|
38
39
|
/**
|
|
39
40
|
* @param {Object} [settings={}]
|
|
40
41
|
* @param {string} [settings.tagName=''] The name of the tag this element represents
|
|
@@ -16,6 +16,7 @@ Object.defineProperty(exports, '__esModule', {
|
|
|
16
16
|
value: true
|
|
17
17
|
})
|
|
18
18
|
exports.ElementService = void 0
|
|
19
|
+
const EventService_1 = require('./EventService')
|
|
19
20
|
const NodeService_1 = require('./NodeService')
|
|
20
21
|
const AttrService_1 = require('./AttrService')
|
|
21
22
|
const DOMTokenListService_1 = require('./DOMTokenListService')
|
|
@@ -52,6 +53,7 @@ class ElementService extends NodeService_1.NodeService {
|
|
|
52
53
|
children = []
|
|
53
54
|
} = {}) {
|
|
54
55
|
super()
|
|
56
|
+
this.defaultEventApplied = false
|
|
55
57
|
this.tokenList = new DOMTokenListService_1.DOMTokenListService()
|
|
56
58
|
this.tag = tagName
|
|
57
59
|
this.attributeList = attributes.concat([{
|
|
@@ -117,20 +119,25 @@ class ElementService extends NodeService_1.NodeService {
|
|
|
117
119
|
*/
|
|
118
120
|
applyDefaultEvent () {
|
|
119
121
|
let callback = event => undefined
|
|
122
|
+
if (this.defaultEventApplied) {
|
|
123
|
+
return callback
|
|
124
|
+
}
|
|
120
125
|
switch (this.tagName) {
|
|
121
|
-
case 'form':
|
|
122
|
-
this.addEventListener('submit', callback)
|
|
123
|
-
break
|
|
124
126
|
case 'button':
|
|
125
127
|
case 'input':
|
|
126
128
|
if (/^(submit|image)$/i.test(this.type || '')) {
|
|
129
|
+
// Clicking a submit button submits the form it is in: the form gets a submit event, which can be cancelled
|
|
127
130
|
callback = event => {
|
|
128
131
|
const forms = (0, getParentNodesFromAttribute_1.default)('tagName', 'form', this)
|
|
129
132
|
if (forms.length) {
|
|
130
|
-
forms[
|
|
133
|
+
forms[forms.length - 1].dispatchEvent(new EventService_1.EventService('submit', {
|
|
134
|
+
bubbles: true,
|
|
135
|
+
cancelable: true
|
|
136
|
+
}))
|
|
131
137
|
}
|
|
132
138
|
}
|
|
133
139
|
super.setDefaultEvent('click', callback)
|
|
140
|
+
this.defaultEventApplied = true
|
|
134
141
|
}
|
|
135
142
|
}
|
|
136
143
|
return callback
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.find.js"),require("core-js/modules/esnext.iterator.for-each.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js");var __importDefault=function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.ElementService=void 0;const NodeService_1=require("./NodeService"),AttrService_1=require("./AttrService"),DOMTokenListService_1=require("./DOMTokenListService"),NamedNodeMapService_1=require("./NamedNodeMapService"),getParentNodesFromAttribute_1=__importDefault(require("../functions/getParentNodesFromAttribute"));class ElementService extends NodeService_1.NodeService{constructor({tagName:e="",attributes:t=[],parent:r=null,children:i=[]}={}){super(),this.tokenList=new DOMTokenListService_1.DOMTokenListService,this.tag=e,this.attributeList=t.concat([{name:"className",value:""},{name:"id",value:""},{name:"innerHTML",value:""}]),this.propertyAttributes=this.attributeList.map(({name:e})=>e),this.attributeList.forEach(({name:e,value:t})=>{this[e]=t}),i.forEach(e=>{if(!e||"number"!=typeof e.nodeType)throw new TypeError("The children of an element must be nodes.");this.appendChild(e)}),r&&r.appendChild(this)}get tagName(){return this.tag}get nodeType(){return NodeService_1.NodeService.ELEMENT_NODE}get attributes(){return new NamedNodeMapService_1.NamedNodeMapService(this.attributeList.map(({name:e,value:t})=>new AttrService_1.AttrService(e,String(t),this)))}get classList(){return this.tokenList}get className(){return this.tokenList.value}set className(e){this.tokenList.value=e}applyDefaultEvent(){let e=e=>{};switch(this.tagName){case"
|
|
1
|
+
"use strict";require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.find.js"),require("core-js/modules/esnext.iterator.for-each.js"),require("core-js/modules/esnext.iterator.map.js"),require("core-js/modules/esnext.iterator.some.js");var __importDefault=function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.ElementService=void 0;const EventService_1=require("./EventService"),NodeService_1=require("./NodeService"),AttrService_1=require("./AttrService"),DOMTokenListService_1=require("./DOMTokenListService"),NamedNodeMapService_1=require("./NamedNodeMapService"),getParentNodesFromAttribute_1=__importDefault(require("../functions/getParentNodesFromAttribute"));class ElementService extends NodeService_1.NodeService{constructor({tagName:e="",attributes:t=[],parent:r=null,children:i=[]}={}){super(),this.defaultEventApplied=!1,this.tokenList=new DOMTokenListService_1.DOMTokenListService,this.tag=e,this.attributeList=t.concat([{name:"className",value:""},{name:"id",value:""},{name:"innerHTML",value:""}]),this.propertyAttributes=this.attributeList.map(({name:e})=>e),this.attributeList.forEach(({name:e,value:t})=>{this[e]=t}),i.forEach(e=>{if(!e||"number"!=typeof e.nodeType)throw new TypeError("The children of an element must be nodes.");this.appendChild(e)}),r&&r.appendChild(this)}get tagName(){return this.tag}get nodeType(){return NodeService_1.NodeService.ELEMENT_NODE}get attributes(){return new NamedNodeMapService_1.NamedNodeMapService(this.attributeList.map(({name:e,value:t})=>new AttrService_1.AttrService(e,String(t),this)))}get classList(){return this.tokenList}get className(){return this.tokenList.value}set className(e){this.tokenList.value=e}applyDefaultEvent(){let e=e=>{};if(this.defaultEventApplied)return e;switch(this.tagName){case"button":case"input":/^(submit|image)$/i.test(this.type||"")&&(e=e=>{const t=(0,getParentNodesFromAttribute_1.default)("tagName","form",this);t.length&&t[t.length-1].dispatchEvent(new EventService_1.EventService("submit",{bubbles:!0,cancelable:!0}))},super.setDefaultEvent("click",e),this.defaultEventApplied=!0)}return e}childInserted(e){"function"==typeof e.applyDefaultEvent&&e.applyDefaultEvent()}hasAttribute(e){return this.attributeList.some(({name:t})=>t===e)}setAttribute(e,t){const r=this.attributeList.find(({name:t})=>t===e);r?r.value=t:this.attributeList.push({name:e,value:t}),this.propertyAttributes.indexOf(e)>=0&&(this[e]=t)}getAttribute(e){const t=this.attributeList.find(({name:t})=>t===e);return t?t.value:null}removeAttribute(e){const t=this.attributeList.findIndex(({name:t})=>t===e);t>=0&&this.attributeList.splice(t,1)}}exports.ElementService=ElementService;
|
|
@@ -5,12 +5,24 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { PseudoEventTarget } from '../interfaces/PseudoEventTarget';
|
|
7
7
|
import { PseudoEvent } from '../interfaces/PseudoEvent';
|
|
8
|
+
/**
|
|
9
|
+
* The parts of an event which the dispatching of it (EventTargetService) needs to change or read. Not part of the DOM's
|
|
10
|
+
* Event, which is why they are kept apart from the event's own properties.
|
|
11
|
+
*/
|
|
8
12
|
export type EventInner = {
|
|
9
|
-
currentTarget: PseudoEventTarget;
|
|
13
|
+
currentTarget: PseudoEventTarget | null;
|
|
10
14
|
eventPhase: number;
|
|
11
15
|
target: PseudoEventTarget;
|
|
12
16
|
immediatePropagationStopped: boolean;
|
|
13
17
|
propagationStopped: boolean;
|
|
18
|
+
/** True while the event is being dispatched. */
|
|
19
|
+
dispatching: boolean;
|
|
20
|
+
/** True while a passive listener is running, in which preventDefault does nothing. */
|
|
21
|
+
inPassiveListener: boolean;
|
|
22
|
+
/** The targets the event travels through, the target first and the root last, set while dispatching. */
|
|
23
|
+
path: Array<PseudoEventTarget>;
|
|
24
|
+
/** Finish the dispatch: no phase, no current target, no path and the stop flags are cleared so the event can be dispatched again. */
|
|
25
|
+
finishDispatch: () => void;
|
|
14
26
|
};
|
|
15
27
|
/**
|
|
16
28
|
* Simulate the behaviour of the Event Class when there is no DOM available.
|
|
@@ -51,9 +63,9 @@ export declare class EventService implements PseudoEvent {
|
|
|
51
63
|
*
|
|
52
64
|
* @param {string} typeArg
|
|
53
65
|
* @param {Object} [eventOptions={}]
|
|
54
|
-
* @param {boolean} [eventOptions.bubbles=
|
|
55
|
-
* @param {boolean} [eventOptions.cancelable=
|
|
56
|
-
* @param {boolean} [eventOptions.composed=
|
|
66
|
+
* @param {boolean} [eventOptions.bubbles=false]
|
|
67
|
+
* @param {boolean} [eventOptions.cancelable=false]
|
|
68
|
+
* @param {boolean} [eventOptions.composed=false]
|
|
57
69
|
* @constructor
|
|
58
70
|
*/
|
|
59
71
|
constructor(typeArg?: string, { bubbles, cancelable, composed }?: {
|
|
@@ -5,18 +5,10 @@
|
|
|
5
5
|
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
6
6
|
* @version 1.0.0
|
|
7
7
|
*/
|
|
8
|
-
const __importDefault = void 0 && (void 0).__importDefault || function (mod) {
|
|
9
|
-
return mod && mod.__esModule
|
|
10
|
-
? mod
|
|
11
|
-
: {
|
|
12
|
-
default: mod
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
8
|
Object.defineProperty(exports, '__esModule', {
|
|
16
9
|
value: true
|
|
17
10
|
})
|
|
18
11
|
exports.EventService = void 0
|
|
19
|
-
const getParentNodes_1 = __importDefault(require('../functions/getParentNodes'))
|
|
20
12
|
/**
|
|
21
13
|
* Simulate the behaviour of the Event Class when there is no DOM available.
|
|
22
14
|
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
@@ -51,20 +43,20 @@ class EventService {
|
|
|
51
43
|
*
|
|
52
44
|
* @param {string} typeArg
|
|
53
45
|
* @param {Object} [eventOptions={}]
|
|
54
|
-
* @param {boolean} [eventOptions.bubbles=
|
|
55
|
-
* @param {boolean} [eventOptions.cancelable=
|
|
56
|
-
* @param {boolean} [eventOptions.composed=
|
|
46
|
+
* @param {boolean} [eventOptions.bubbles=false]
|
|
47
|
+
* @param {boolean} [eventOptions.cancelable=false]
|
|
48
|
+
* @param {boolean} [eventOptions.composed=false]
|
|
57
49
|
* @constructor
|
|
58
50
|
*/
|
|
59
51
|
constructor (typeArg = '', {
|
|
60
|
-
bubbles =
|
|
61
|
-
cancelable =
|
|
62
|
-
composed =
|
|
52
|
+
bubbles = false,
|
|
53
|
+
cancelable = false,
|
|
54
|
+
composed = false
|
|
63
55
|
} = {}) {
|
|
64
56
|
this.properties = {
|
|
65
|
-
bubbles:
|
|
66
|
-
cancelable:
|
|
67
|
-
composed:
|
|
57
|
+
bubbles: false,
|
|
58
|
+
cancelable: false,
|
|
59
|
+
composed: false,
|
|
68
60
|
currentTarget: null,
|
|
69
61
|
defaultPrevented: false,
|
|
70
62
|
immediatePropagationStopped: false,
|
|
@@ -73,7 +65,10 @@ class EventService {
|
|
|
73
65
|
target: null,
|
|
74
66
|
timeStamp: Math.floor(Date.now() / 1000),
|
|
75
67
|
type: '',
|
|
76
|
-
isTrusted: true
|
|
68
|
+
isTrusted: true,
|
|
69
|
+
dispatching: false,
|
|
70
|
+
inPassiveListener: false,
|
|
71
|
+
path: []
|
|
77
72
|
}
|
|
78
73
|
this.setReadOnlyProperties({
|
|
79
74
|
type: typeArg,
|
|
@@ -130,12 +125,21 @@ class EventService {
|
|
|
130
125
|
get inner () {
|
|
131
126
|
const self = this
|
|
132
127
|
return {
|
|
128
|
+
get currentTarget () {
|
|
129
|
+
return self.properties.currentTarget
|
|
130
|
+
},
|
|
133
131
|
set currentTarget (target) {
|
|
134
132
|
self.properties.currentTarget = target
|
|
135
133
|
},
|
|
134
|
+
get eventPhase () {
|
|
135
|
+
return self.properties.eventPhase
|
|
136
|
+
},
|
|
136
137
|
set eventPhase (phase) {
|
|
137
138
|
self.properties.eventPhase = phase
|
|
138
139
|
},
|
|
140
|
+
get target () {
|
|
141
|
+
return self.properties.target
|
|
142
|
+
},
|
|
139
143
|
set target (target) {
|
|
140
144
|
self.properties.target = target
|
|
141
145
|
},
|
|
@@ -144,6 +148,35 @@ class EventService {
|
|
|
144
148
|
},
|
|
145
149
|
get propagationStopped () {
|
|
146
150
|
return self.properties.propagationStopped
|
|
151
|
+
},
|
|
152
|
+
get dispatching () {
|
|
153
|
+
return self.properties.dispatching
|
|
154
|
+
},
|
|
155
|
+
set dispatching (dispatching) {
|
|
156
|
+
self.properties.dispatching = dispatching
|
|
157
|
+
},
|
|
158
|
+
get inPassiveListener () {
|
|
159
|
+
return self.properties.inPassiveListener
|
|
160
|
+
},
|
|
161
|
+
set inPassiveListener (passive) {
|
|
162
|
+
self.properties.inPassiveListener = passive
|
|
163
|
+
},
|
|
164
|
+
get path () {
|
|
165
|
+
return self.properties.path
|
|
166
|
+
},
|
|
167
|
+
set path (path) {
|
|
168
|
+
self.properties.path = path
|
|
169
|
+
},
|
|
170
|
+
finishDispatch () {
|
|
171
|
+
self.setReadOnlyProperties({
|
|
172
|
+
currentTarget: null,
|
|
173
|
+
eventPhase: EventService.NONE,
|
|
174
|
+
path: [],
|
|
175
|
+
dispatching: false,
|
|
176
|
+
inPassiveListener: false,
|
|
177
|
+
propagationStopped: false,
|
|
178
|
+
immediatePropagationStopped: false
|
|
179
|
+
})
|
|
147
180
|
}
|
|
148
181
|
}
|
|
149
182
|
}
|
|
@@ -154,16 +187,8 @@ class EventService {
|
|
|
154
187
|
* @returns {Array.<PseudoEventTarget>}
|
|
155
188
|
*/
|
|
156
189
|
composedPath () {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return (0, getParentNodes_1.default)(this.target)
|
|
160
|
-
case EventService.BUBBLING_PHASE:
|
|
161
|
-
return (0, getParentNodes_1.default)(this.target).slice().reverse()
|
|
162
|
-
case EventService.AT_TARGET:
|
|
163
|
-
return [this.target]
|
|
164
|
-
default:
|
|
165
|
-
return []
|
|
166
|
-
}
|
|
190
|
+
// While the event is being dispatched this is every target it travels through, the target first and the root last
|
|
191
|
+
return this.properties.dispatching ? this.properties.path.slice() : []
|
|
167
192
|
}
|
|
168
193
|
|
|
169
194
|
/**
|
|
@@ -172,9 +197,12 @@ class EventService {
|
|
|
172
197
|
* @returns {null}
|
|
173
198
|
*/
|
|
174
199
|
preventDefault () {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
200
|
+
// Only an event which can be cancelled can be prevented, and a passive listener cannot prevent the default
|
|
201
|
+
if (this.cancelable && !this.properties.inPassiveListener) {
|
|
202
|
+
this.setReadOnlyProperties({
|
|
203
|
+
defaultPrevented: true
|
|
204
|
+
})
|
|
205
|
+
}
|
|
178
206
|
return null
|
|
179
207
|
}
|
|
180
208
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.EventService=void 0;class EventService{constructor(e="",{bubbles:t=!1,cancelable:r=!1,composed:i=!1}={}){this.properties={bubbles:!1,cancelable:!1,composed:!1,currentTarget:null,defaultPrevented:!1,immediatePropagationStopped:!1,propagationStopped:!1,eventPhase:0,target:null,timeStamp:Math.floor(Date.now()/1e3),type:"",isTrusted:!0,dispatching:!1,inPassiveListener:!1,path:[]},this.setReadOnlyProperties({type:e,bubbles:t,cancelable:r,composed:i})}get bubbles(){return this.properties.bubbles}get cancelable(){return this.properties.cancelable}get composed(){return this.properties.composed}get currentTarget(){return this.properties.currentTarget}get defaultPrevented(){return this.properties.defaultPrevented}get eventPhase(){return this.properties.eventPhase}get isTrusted(){return this.properties.isTrusted}get target(){return this.properties.target}get timeStamp(){return this.properties.timeStamp}get type(){return this.properties.type}get inner(){const e=this;return{get currentTarget(){return e.properties.currentTarget},set currentTarget(t){e.properties.currentTarget=t},get eventPhase(){return e.properties.eventPhase},set eventPhase(t){e.properties.eventPhase=t},get target(){return e.properties.target},set target(t){e.properties.target=t},get immediatePropagationStopped(){return e.properties.immediatePropagationStopped},get propagationStopped(){return e.properties.propagationStopped},get dispatching(){return e.properties.dispatching},set dispatching(t){e.properties.dispatching=t},get inPassiveListener(){return e.properties.inPassiveListener},set inPassiveListener(t){e.properties.inPassiveListener=t},get path(){return e.properties.path},set path(t){e.properties.path=t},finishDispatch(){e.setReadOnlyProperties({currentTarget:null,eventPhase:EventService.NONE,path:[],dispatching:!1,inPassiveListener:!1,propagationStopped:!1,immediatePropagationStopped:!1})}}}composedPath(){return this.properties.dispatching?this.properties.path.slice():[]}preventDefault(){return this.cancelable&&!this.properties.inPassiveListener&&this.setReadOnlyProperties({defaultPrevented:!0}),null}stopImmediatePropagation(){return this.setReadOnlyProperties({immediatePropagationStopped:!0}),null}stopPropagation(){return this.setReadOnlyProperties({propagationStopped:!0}),null}setReadOnlyProperties(e={}){return this.properties=Object.assign({},this.properties,e),this}}exports.EventService=EventService,EventService.NONE=0,EventService.CAPTURING_PHASE=1,EventService.AT_TARGET=2,EventService.BUBBLING_PHASE=3;
|
|
@@ -7,6 +7,9 @@ import { EventService } from './EventService';
|
|
|
7
7
|
import { listenerOptions, PseudoEventTarget } from '../interfaces/PseudoEventTarget';
|
|
8
8
|
/**
|
|
9
9
|
* Simulate the behaviour of the EventTarget Class when there is no DOM available.
|
|
10
|
+
* Dispatching an event sends it through the tree the way the DOM does: down from the root to the target (capture
|
|
11
|
+
* listeners), to the target itself, then back up to the root (the listeners which are not capture listeners, when the
|
|
12
|
+
* event bubbles).
|
|
10
13
|
* @author Joshua Heagle <joshuaheagle@gmail.com>
|
|
11
14
|
* @class
|
|
12
15
|
* @property {Object.<string, Array.<PseudoEventListener>>} listeners
|
|
@@ -28,25 +31,54 @@ declare class EventTargetService implements PseudoEventTarget {
|
|
|
28
31
|
*/
|
|
29
32
|
private listenersFor;
|
|
30
33
|
/**
|
|
31
|
-
* Run
|
|
32
|
-
*
|
|
33
|
-
* and listeners
|
|
34
|
-
*
|
|
35
|
-
* @
|
|
34
|
+
* Run the listeners registered on this target for the type of the event which apply to the phase the event is in
|
|
35
|
+
* (at the target, the capture listeners run before the others). Listeners which are added while this runs do not run
|
|
36
|
+
* for this event, and listeners which are removed while it runs no longer do. Running stops as soon as immediate
|
|
37
|
+
* propagation is stopped. A listener which throws does not stop the others.
|
|
38
|
+
* @param {EventService} event The event, which is at a phase and has a current target
|
|
39
|
+
* @returns {Array<*>} The errors which the listeners threw
|
|
36
40
|
*/
|
|
37
41
|
private runEvents;
|
|
42
|
+
/**
|
|
43
|
+
* Take a listener out of the registered listeners, so that it does not run again.
|
|
44
|
+
* @param {string} type
|
|
45
|
+
* @param {PseudoEventListener} listener
|
|
46
|
+
*/
|
|
47
|
+
private removeListener;
|
|
38
48
|
/**
|
|
39
49
|
* Register the function to run when nothing else has prevented the default for this type of event.
|
|
40
50
|
* @param {string} type
|
|
41
51
|
* @param {Function} callback
|
|
42
52
|
*/
|
|
43
53
|
protected setDefaultEvent(type: string, callback: Function): void;
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
/**
|
|
55
|
+
* Registers an event handler of a specific event type. Adding the same handler again for the same type and phase does
|
|
56
|
+
* nothing, like the DOM.
|
|
57
|
+
* @param {string} type The type of event to listen for
|
|
58
|
+
* @param {Function|Object} callback The function to call (or an object with a handleEvent function)
|
|
59
|
+
* @param {Object|boolean} [useCapture=false] Listen while the event travels down to the target (true), or an object with capture, once and passive
|
|
60
|
+
*/
|
|
46
61
|
addEventListener(type: string, callback: Function | {
|
|
47
62
|
handleEvent: Function;
|
|
48
63
|
} | any, useCapture?: listenerOptions | boolean): void;
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Removes an event listener, the one which was added with the same type, handler and phase.
|
|
66
|
+
* @param {string} type The type of event
|
|
67
|
+
* @param {Function|Object} callback The handler which was added
|
|
68
|
+
* @param {Object|boolean} [options=false] Whether the listener was a capture listener (true), or an object with capture
|
|
69
|
+
*/
|
|
70
|
+
removeEventListener(type: string, callback: Function, options?: listenerOptions | boolean): void;
|
|
71
|
+
/**
|
|
72
|
+
* Dispatches an event to this target and through the tree: capture listeners of the ancestors from the root down,
|
|
73
|
+
* then the listeners of this target, then (when the event bubbles) the other listeners of the ancestors from the
|
|
74
|
+
* parent up to the root. stopPropagation() stops it reaching further targets, stopImmediatePropagation() also stops
|
|
75
|
+
* the remaining listeners of the current target. Afterwards, unless the default was prevented, the default action
|
|
76
|
+
* of this target (see setDefaultEvent) runs. The event can be dispatched again afterwards.
|
|
77
|
+
* @param {EventService} event The event to dispatch
|
|
78
|
+
* @returns {boolean} False when the event was cancelable and a listener prevented the default, otherwise true
|
|
79
|
+
* @throws {Error} When the event is already being dispatched, or (after the whole dispatch has finished) the error
|
|
80
|
+
* which a listener threw (an error with all of them in its errors property when several did)
|
|
81
|
+
*/
|
|
82
|
+
dispatchEvent(event: EventService): boolean;
|
|
51
83
|
}
|
|
52
84
|
export default EventTargetService;
|