Skip to content

Commit 914c1f5

Browse files
committed
feat(host event interceptor): technique for intercepting and exposing onevents for the components
Via this.rb.events.host object, see readme.md for more info.
1 parent 73994f9 commit 914c1f5

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

README.md

+22
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ $ yarn add @rapid-build-ui/rb-base
2424
* [API](#api) (creates this.rb object that contains a set of common helper objects):
2525
* [this.rb.elms](#thisrbelms)
2626
* [this.rb.events](#thisrbevents)
27+
* [this.rb.events.host](#thisrbeventshost)
2728
* [this.rb.view](#thisrbview)
2829

2930
* [Callbacks](#callbacks-optional):
@@ -95,6 +96,27 @@ export class RbPopover extends RbBase() {
9596
* forces events to be set to empty {}
9697

9798

99+
### this.rb.events.host
100+
* Properties
101+
* events :object (readonly, hashmap of active host events)
102+
* Methods
103+
* add([event types]) :void
104+
* usually ran in component constructor
105+
* event types example: ['click', 'focus']
106+
* examples:
107+
* this.rb.events.host.add(['click']);
108+
* this.rb.events.add(this, 'click', this.rb.events.host.run);
109+
* remove([event types]) :void
110+
* event types example: ['click', 'focus']
111+
* removeAll() :void
112+
* run(event) :any (event :object)
113+
* runs event that was added via add()
114+
* supports promises (see isPending())
115+
* example: this.rb.events.host.run(event)
116+
* isPending(event) :boolean (event :object | string)
117+
* returns true if function returned a promise and it's pending
118+
119+
98120
### this.rb.view
99121
* Properties
100122
* isReady :boolean (readonly, will be true when view is ready)

src/client/scripts/private/mixins/base.js

+3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ const Base = (BaseElm = HTMLElement) => class extends withComponent(BaseElm) {
2020
disconnectedCallback() { // :void
2121
super.disconnectedCallback && super.disconnectedCallback();
2222
this.rb.events.removeAll({ force: true });
23+
this.rb.events.host.removeAll();
24+
this.rb.elms = {};
2325
// console.log(`${this.localName} disconnected:`, this.rb.events.events);
26+
// console.log(`${this.localName} disconnected:`, this.rb.events.host.events);
2427
}
2528

2629
/* @skatejs/renderer-lit-html

src/client/scripts/private/services/event.js

+62
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
- this.rb.events.emit(elm, 'event' [, { detail: any } ]); :boolean
1313
********************************************************************************/
1414
import Guid from '../../public/services/guid.js';
15+
import Type from '../../public/services/type.js';
1516

1617
/* Event Helpers
1718
****************/
@@ -107,6 +108,14 @@ const EventHelper = {
107108

108109
// bound functions are prefixed with 'bound '
109110
return callback.name.replace(/^bound /, '');
111+
},
112+
setHostEvent(hostEvents, evt, func, opts={}) { // :void
113+
hostEvents[evt] = {
114+
pending: false,
115+
func: func.bind(this) // by default bind to rb-component
116+
}
117+
if (!opts.clear) return;
118+
this[opts.onEvt] = null; // nullify when onevent is declared in html
110119
}
111120
};
112121

@@ -116,6 +125,7 @@ const EventService = function() { // :object (this = rb-component)
116125
/* Private
117126
**********/
118127
let _events = {};
128+
let _hostEvents = {};
119129

120130
/* Public
121131
*********/
@@ -175,6 +185,58 @@ const EventService = function() { // :object (this = rb-component)
175185
const evtOpts = Object.assign({}, EventHelper.customEvtDefaults, opts);
176186
const evtObj = new CustomEvent(evt, evtOpts);
177187
return target.dispatchEvent(evtObj);
188+
},
189+
/* Host Events
190+
**************/
191+
host: {
192+
get events() { // :object (readonly: hashmap of host events)
193+
return _hostEvents;
194+
},
195+
add: (events=[]) => { // :void (usually ran in component constructor)
196+
if (!events.length) return; // ex: ['click','focus']
197+
for (const evt of events) {
198+
const onEvt = `on${evt}`; // ex: onclick
199+
if (this.hasAttribute(onEvt))
200+
EventHelper.setHostEvent.call(this, _hostEvents, evt, this[onEvt], {
201+
onEvt,
202+
clear: true
203+
});
204+
// dynamic getters and setters
205+
Object.defineProperty(this, onEvt, {
206+
get() { // :object
207+
return _hostEvents[evt];
208+
},
209+
set(func) {
210+
EventHelper.setHostEvent.call(this, _hostEvents, evt, func);
211+
}
212+
});
213+
}
214+
},
215+
remove: (events=[]) => { // :void
216+
if (!events.length) return;
217+
for (const evt of events)
218+
delete _hostEvents[evt];
219+
},
220+
removeAll: () => { // :void
221+
_hostEvents = {};
222+
},
223+
run: async evt => { // :any (evt :object<event>)
224+
const hostEvent = _hostEvents[evt.type];
225+
if (!hostEvent) return;
226+
if (hostEvent.pending) return;
227+
if (!Type.is.function(hostEvent.func)) return;
228+
hostEvent.pending = true;
229+
const result = await hostEvent.func(evt);
230+
hostEvent.pending = false;
231+
return result;
232+
},
233+
isPending: evt => { // :boolean (evt :object<event> | string<eventType>)
234+
if (!evt) return false;
235+
if (Type.is.object(evt)) evt = evt.type;
236+
const hostEvent = _hostEvents[evt];
237+
if (!hostEvent) return false;
238+
return hostEvent.pending;
239+
}
178240
}
179241
};
180242
};

0 commit comments

Comments
 (0)