pseudo-dom 0.1.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.
Files changed (41) hide show
  1. package/README.md +626 -116
  2. package/browser/pseudo-dom.js +849 -407
  3. package/browser/pseudo-dom.min.js +1 -1
  4. package/dist/classes/PseudoEventListener.d.ts +25 -25
  5. package/dist/classes/PseudoEventListener.js +37 -34
  6. package/dist/classes/PseudoEventListener.min.js +1 -1
  7. package/dist/classes/PseudoHTMLDocument.d.ts +2 -2
  8. package/dist/classes/PseudoHTMLDocument.js +10 -21
  9. package/dist/classes/PseudoHTMLDocument.min.js +1 -1
  10. package/dist/classes/PseudoNodeList.js +14 -8
  11. package/dist/classes/PseudoNodeList.min.js +1 -1
  12. package/dist/factories/generateNode.d.ts +2 -10
  13. package/dist/factories/generateNode.js +9 -42
  14. package/dist/factories/generateNode.min.js +1 -1
  15. package/dist/functions/getParentNodes.d.ts +8 -6
  16. package/dist/functions/getParentNodes.js +16 -9
  17. package/dist/functions/getParentNodes.min.js +1 -1
  18. package/dist/functions/getParentNodesFromAttribute.d.ts +7 -7
  19. package/dist/functions/getParentNodesFromAttribute.js +21 -1
  20. package/dist/functions/getParentNodesFromAttribute.min.js +1 -1
  21. package/dist/functions.d.ts +1 -1
  22. package/dist/interfaces/PseudoEventTarget.d.ts +2 -2
  23. package/dist/services/DocumentFragmentService.d.ts +9 -0
  24. package/dist/services/DocumentFragmentService.js +16 -1
  25. package/dist/services/DocumentFragmentService.min.js +1 -1
  26. package/dist/services/DocumentService.d.ts +8 -0
  27. package/dist/services/DocumentService.js +15 -1
  28. package/dist/services/DocumentService.min.js +1 -1
  29. package/dist/services/ElementService.d.ts +6 -6
  30. package/dist/services/ElementService.js +28 -17
  31. package/dist/services/ElementService.min.js +1 -1
  32. package/dist/services/EventService.d.ts +16 -4
  33. package/dist/services/EventService.js +59 -31
  34. package/dist/services/EventService.min.js +1 -1
  35. package/dist/services/EventTargetService.d.ts +41 -9
  36. package/dist/services/EventTargetService.js +121 -52
  37. package/dist/services/EventTargetService.min.js +1 -1
  38. package/dist/services/NodeService.d.ts +31 -16
  39. package/dist/services/NodeService.js +90 -33
  40. package/dist/services/NodeService.min.js +1 -1
  41. package/package.json +2 -2
@@ -35,12 +35,13 @@ 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
41
42
  * @param {Array<{name: string, value: *}>} [settings.attributes=[]] The attributes (also assigned as properties) to start with
42
- * @param {PseudoNode|null} [settings.parent=null] The parent node
43
- * @param {Array} [settings.children=[]] The values or nodes to start as children
43
+ * @param {PseudoNode|null} [settings.parent=null] The node to add this element to as its last child
44
+ * @param {Array<PseudoNode>} [settings.children=[]] The nodes to start as children
44
45
  * @constructor
45
46
  */
46
47
  constructor({ tagName, attributes, parent, children }?: {
@@ -61,11 +62,10 @@ export declare class ElementService extends NodeService implements Partial<Pseud
61
62
  */
62
63
  applyDefaultEvent(): Function;
63
64
  /**
64
- *
65
- * @param {PseudoNode|ElementService} childElement
66
- * @returns {PseudoNode}
65
+ * An element which is added as a child gets its default events (for example a submit button submits its form).
66
+ * @param {NodeService} child The node which was inserted
67
67
  */
68
- appendChild(childElement: ElementService): PseudoNode;
68
+ protected childInserted(child: NodeService): void;
69
69
  /**
70
70
  * Check whether the element has an attribute by that name.
71
71
  * @param {string} attributeName
@@ -16,8 +16,7 @@ Object.defineProperty(exports, '__esModule', {
16
16
  value: true
17
17
  })
18
18
  exports.ElementService = void 0
19
- const generateNodeList_1 = __importDefault(require('../factories/generateNodeList'))
20
- const TreeLinker_1 = require('collect-your-stuff/dist/collections/linked-tree-list/TreeLinker')
19
+ const EventService_1 = require('./EventService')
21
20
  const NodeService_1 = require('./NodeService')
22
21
  const AttrService_1 = require('./AttrService')
23
22
  const DOMTokenListService_1 = require('./DOMTokenListService')
@@ -43,8 +42,8 @@ class ElementService extends NodeService_1.NodeService {
43
42
  * @param {Object} [settings={}]
44
43
  * @param {string} [settings.tagName=''] The name of the tag this element represents
45
44
  * @param {Array<{name: string, value: *}>} [settings.attributes=[]] The attributes (also assigned as properties) to start with
46
- * @param {PseudoNode|null} [settings.parent=null] The parent node
47
- * @param {Array} [settings.children=[]] The values or nodes to start as children
45
+ * @param {PseudoNode|null} [settings.parent=null] The node to add this element to as its last child
46
+ * @param {Array<PseudoNode>} [settings.children=[]] The nodes to start as children
48
47
  * @constructor
49
48
  */
50
49
  constructor ({
@@ -54,9 +53,8 @@ class ElementService extends NodeService_1.NodeService {
54
53
  children = []
55
54
  } = {}) {
56
55
  super()
56
+ this.defaultEventApplied = false
57
57
  this.tokenList = new DOMTokenListService_1.DOMTokenListService()
58
- this.parent = parent
59
- this.children = (0, generateNodeList_1.default)(TreeLinker_1.TreeLinker.fromArray(children).head)
60
58
  this.tag = tagName
61
59
  this.attributeList = attributes.concat([{
62
60
  name: 'className',
@@ -77,6 +75,15 @@ class ElementService extends NodeService_1.NodeService {
77
75
  }) => {
78
76
  this[name] = value
79
77
  })
78
+ children.forEach(child => {
79
+ if (!child || typeof child.nodeType !== 'number') {
80
+ throw new TypeError('The children of an element must be nodes.')
81
+ }
82
+ this.appendChild(child)
83
+ })
84
+ if (parent) {
85
+ parent.appendChild(this)
86
+ }
80
87
  }
81
88
 
82
89
  get tagName () {
@@ -112,34 +119,38 @@ class ElementService extends NodeService_1.NodeService {
112
119
  */
113
120
  applyDefaultEvent () {
114
121
  let callback = event => undefined
122
+ if (this.defaultEventApplied) {
123
+ return callback
124
+ }
115
125
  switch (this.tagName) {
116
- case 'form':
117
- this.addEventListener('submit', callback)
118
- break
119
126
  case 'button':
120
127
  case 'input':
121
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
122
130
  callback = event => {
123
131
  const forms = (0, getParentNodesFromAttribute_1.default)('tagName', 'form', this)
124
132
  if (forms.length) {
125
- forms[0].submit()
133
+ forms[forms.length - 1].dispatchEvent(new EventService_1.EventService('submit', {
134
+ bubbles: true,
135
+ cancelable: true
136
+ }))
126
137
  }
127
138
  }
128
139
  super.setDefaultEvent('click', callback)
140
+ this.defaultEventApplied = true
129
141
  }
130
142
  }
131
143
  return callback
132
144
  }
133
145
 
134
146
  /**
135
- *
136
- * @param {PseudoNode|ElementService} childElement
137
- * @returns {PseudoNode}
147
+ * An element which is added as a child gets its default events (for example a submit button submits its form).
148
+ * @param {NodeService} child The node which was inserted
138
149
  */
139
- appendChild (childElement) {
140
- super.appendChild(childElement)
141
- childElement.applyDefaultEvent()
142
- return childElement
150
+ childInserted (child) {
151
+ if (typeof child.applyDefaultEvent === 'function') {
152
+ child.applyDefaultEvent()
153
+ }
143
154
  }
144
155
 
145
156
  /**
@@ -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 generateNodeList_1=__importDefault(require("../factories/generateNodeList")),TreeLinker_1=require("collect-your-stuff/dist/collections/linked-tree-list/TreeLinker"),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.parent=r,this.children=(0,generateNodeList_1.default)(TreeLinker_1.TreeLinker.fromArray(i).head),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})}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}appendChild(e){return super.appendChild(e),e.applyDefaultEvent(),e}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;