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.
@@ -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 && (event.bubbles || !this.eventOptions.capture)
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
- * @method
110
- * @name PseudoEventListener#skipDefault
111
- * @param {PseudoEvent} event
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 {*|boolean}
145
+ * @returns {boolean}
143
146
  */
144
147
  rejectEvent (event) {
145
- return this.nonPassiveHalt(event) || this.skipPhase(event)
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:n=!1}={},i,r=i){this.eventOptions={capture:!1,once:!1,passive:!1},this.eventType="",this.defaultListener=!1,this.eventOptions={capture:t,once:s,passive:n},this.eventType=e,this.handler=i,this.originalCallback=r}get callback(){return this.originalCallback}get isDefault(){return this.defaultListener}get once(){return this.eventOptions.once}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&&(e.bubbles||!this.eventOptions.capture)}skipPhase(e){return!this.doCapturePhase(e)&&!this.doTargetPhase(e)&&!this.doBubblePhase(e)}skipDefault(e){return this.isDefault&&e.defaultPrevented}stopPropagation(e){return!this.doTargetPhase(e)&&e.inner.propagationStopped}nonPassiveHalt(e){return!this.eventOptions.passive&&(this.skipDefault(e)||e.inner.immediatePropagationStopped||this.stopPropagation(e))}rejectEvent(e){return this.nonPassiveHalt(e)||this.skipPhase(e)}}exports.default=PseudoEventListener;
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, target: PseudoEventTarget): boolean;
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[0].submit()
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"form":this.addEventListener("submit",e);break;case"button":case"input":/^(submit|image)$/i.test(this.type||"")&&(e=e=>{const t=(0,getParentNodesFromAttribute_1.default)("tagName","form",this);t.length&&t[0].submit()},super.setDefaultEvent("click",e))}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;
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=true]
55
- * @param {boolean} [eventOptions.cancelable=true]
56
- * @param {boolean} [eventOptions.composed=true]
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=true]
55
- * @param {boolean} [eventOptions.cancelable=true]
56
- * @param {boolean} [eventOptions.composed=true]
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 = true,
61
- cancelable = true,
62
- composed = true
52
+ bubbles = false,
53
+ cancelable = false,
54
+ composed = false
63
55
  } = {}) {
64
56
  this.properties = {
65
- bubbles: true,
66
- cancelable: true,
67
- composed: true,
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
- switch (this.eventPhase) {
158
- case EventService.CAPTURING_PHASE:
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
- this.setReadOnlyProperties({
176
- defaultPrevented: true
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";var __importDefault=function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(exports,"__esModule",{value:!0}),exports.EventService=void 0;const getParentNodes_1=__importDefault(require("../functions/getParentNodes"));class EventService{constructor(e="",{bubbles:t=!0,cancelable:r=!0,composed:s=!0}={}){this.properties={bubbles:!0,cancelable:!0,composed:!0,currentTarget:null,defaultPrevented:!1,immediatePropagationStopped:!1,propagationStopped:!1,eventPhase:0,target:null,timeStamp:Math.floor(Date.now()/1e3),type:"",isTrusted:!0},this.setReadOnlyProperties({type:e,bubbles:t,cancelable:r,composed:s})}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{set currentTarget(t){e.properties.currentTarget=t},set eventPhase(t){e.properties.eventPhase=t},set target(t){e.properties.target=t},get immediatePropagationStopped(){return e.properties.immediatePropagationStopped},get propagationStopped(){return e.properties.propagationStopped}}}composedPath(){switch(this.eventPhase){case EventService.CAPTURING_PHASE:return(0,getParentNodes_1.default)(this.target);case EventService.BUBBLING_PHASE:return(0,getParentNodes_1.default)(this.target).slice().reverse();case EventService.AT_TARGET:return[this.target];default:return[]}}preventDefault(){return 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;
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 each of the listeners registered on this target for the type of the event.
32
- * Listeners which do not apply to the event's phase are skipped, running stops once immediate propagation is stopped,
33
- * and listeners added or removed while running do not change which ones run for this event.
34
- * @param {EventService} event
35
- * @returns {*} true when there was nothing registered, otherwise the last value returned from a handler (null when none ran)
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
- private runDefaultEvent;
45
- private startEvents;
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
- removeEventListener(type: string, callback: Function): void;
50
- dispatchEvent(event: EventService, target?: EventTargetService): boolean;
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;