-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ Add support for setting event handlers from templates
- Loading branch information
Showing
3 changed files
with
122 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2581,15 +2581,45 @@ Renderer.setMethod(function applyElementOptions(element, options, for_sync_rende | |
} | ||
|
||
if (options.hooks?.length) { | ||
let event_handlers = []; | ||
|
||
for (let hook of options.hooks) { | ||
if (hook.name === 'ref') { | ||
const name = hook.name; | ||
|
||
if (name === 'ref') { | ||
let value = this.parseRuntimeExpression(hook.value); | ||
|
||
if (value) { | ||
value.value = element; | ||
} | ||
|
||
continue; | ||
} | ||
|
||
switch (name) { | ||
case 'click': | ||
case 'focus': | ||
case 'hover': | ||
case 'blur': | ||
case 'change': | ||
case 'input': | ||
case 'keydown': | ||
case 'keyup': | ||
case 'keypress': | ||
if (hook.value?.$expression) { | ||
event_handlers.push({ | ||
type : name, | ||
expression: hook.value?.$expression, | ||
}); | ||
} | ||
break; | ||
} | ||
} | ||
|
||
if (event_handlers.length) { | ||
attachEventHandlers(element, event_handlers); | ||
this.registerElementInstance(element); | ||
} | ||
} | ||
|
||
// If the element body is rendered using reference variables, | ||
|
@@ -2628,6 +2658,21 @@ Renderer.setMethod(function applyElementOptions(element, options, for_sync_rende | |
} | ||
}); | ||
|
||
/** | ||
* Attach event handlers | ||
* | ||
* @author Jelle De Loecker <[email protected]> | ||
* @since 2.4.0 | ||
* @version 2.4.0 | ||
* | ||
* @param {HTMLElement} element | ||
* @param {Object[]} handlers | ||
*/ | ||
const attachEventHandlers = (element, handlers) => { | ||
element[Hawkejs.EVENT_HANDLERS] = handlers; | ||
Hawkejs.Element.Element.ensureEventHandlers(element, handlers); | ||
}; | ||
|
||
/** | ||
* Attach reactive references | ||
* | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,8 @@ let has_premature_undried_elements, | |
|
||
const CURRENT_RENDER = Symbol('current_render'), | ||
STATE_DEFINITION = Symbol('state_definition'), | ||
STATE_VALUES = Symbol('state_values'); | ||
STATE_VALUES = Symbol('state_values'), | ||
ADDED_EVENT_LISTENERS = Symbol('added_event_listeners'); | ||
|
||
let custom_stylesheet_handler; | ||
|
||
|
@@ -474,16 +475,9 @@ Element.setStatic(function unDry(obj, force) { | |
} | ||
} | ||
|
||
if (obj.assigned_data) { | ||
element.assigned_data = obj.assigned_data; | ||
} | ||
|
||
if (obj.renderer) { | ||
element.hawkejs_renderer = obj.renderer; | ||
} | ||
|
||
// Make it empty, or else it'll set it again later | ||
obj = {}; | ||
} | ||
} | ||
|
||
|
@@ -546,6 +540,11 @@ Element.setStatic(function unDry(obj, force) { | |
element[STATE_VALUES] = obj.state_values; | ||
} | ||
|
||
if (obj.event_handlers?.length) { | ||
element[Hawkejs.EVENT_HANDLERS] = obj.event_handlers; | ||
Element.ensureEventHandlers(element, obj.event_handlers); | ||
} | ||
|
||
// Delay this so the object is fully undried | ||
Element.sceneReady(function() { | ||
if (typeof element.undried == 'function') { | ||
|
@@ -556,6 +555,57 @@ Element.setStatic(function unDry(obj, force) { | |
return element; | ||
}); | ||
|
||
/** | ||
* Make sure the event handlers will be added to the given element | ||
* | ||
* @author Jelle De Loecker <[email protected]> | ||
* @since 2.4.0 | ||
* @version 2.4.0 | ||
* | ||
* @param {HTMLElement} element | ||
* @param {Object[]} event_handlers | ||
* @param {boolean} force | ||
*/ | ||
Element.setStatic(function ensureEventHandlers(element, event_handlers, force = false) { | ||
|
||
if (!element || !event_handlers?.length || element[ADDED_EVENT_LISTENERS]) { | ||
return; | ||
} | ||
|
||
if (element.is_custom_hawkejs_element && !force && !element.isConnected()) { | ||
return; | ||
} | ||
|
||
element[ADDED_EVENT_LISTENERS] = true; | ||
|
||
for (let handler of event_handlers) { | ||
element.addEventListener(handler.type, e => { | ||
doHawkejsEventHandler(element, handler, e); | ||
}); | ||
} | ||
}); | ||
|
||
/** | ||
* Actually perform the given event handler | ||
* | ||
* @author Jelle De Loecker <[email protected]> | ||
* @since 2.4.0 | ||
* @version 2.4.0 | ||
* | ||
* @param {HTMLElement} element | ||
* @param {Object} handler | ||
* @param {Event} event | ||
*/ | ||
const doHawkejsEventHandler = (element, handler, event) => { | ||
|
||
let renderer = Element.prototype.ensureHawkejsRenderer.call(element); | ||
let variables = Hawkejs.Variables.cast(element[Hawkejs.VARIABLES], renderer); | ||
|
||
variables.set('$event', event); | ||
|
||
renderer.parseExpression(handler.expression, variables); | ||
}; | ||
|
||
/** | ||
* Make sure contents are rendered before doing this parent getter/method | ||
* | ||
|
@@ -1678,10 +1728,18 @@ Element.setMethod(function toDry() { | |
} | ||
} | ||
|
||
value = { | ||
hawkejs_id : this.hawkejs_id, | ||
assigned_data : this.assigned_data, | ||
variables : this[Hawkejs.VARIABLES], | ||
reactive : this[Hawkejs.REACTIVE_VALUES], | ||
instructions : this[Hawkejs.RENDER_INSTRUCTION], | ||
state_values : this[STATE_VALUES], | ||
event_handlers : this[Hawkejs.EVENT_HANDLERS], | ||
}; | ||
|
||
if (serialize_all) { | ||
value = { | ||
hawkejs_id : this.hawkejs_id, | ||
assigned_data : this.assigned_data, | ||
tagName : this.tagName, | ||
attributes : this.attributes, | ||
dataset : this.dataset, | ||
|
@@ -1690,19 +1748,7 @@ Element.setMethod(function toDry() { | |
cssText : this.style.cssText, | ||
innerHTML : this.innerHTML, | ||
renderer : this.hawkejs_renderer, | ||
variables : this[Hawkejs.VARIABLES], | ||
reactive : this[Hawkejs.REACTIVE_VALUES], | ||
instructions : this[Hawkejs.RENDER_INSTRUCTION], | ||
state_values : this[STATE_VALUES], | ||
}; | ||
} else { | ||
value = { | ||
hawkejs_id : this.hawkejs_id, | ||
assigned_data : this.assigned_data, | ||
variables : this[Hawkejs.VARIABLES], | ||
reactive : this[Hawkejs.REACTIVE_VALUES], | ||
instructions : this[Hawkejs.RENDER_INSTRUCTION], | ||
state_values : this[STATE_VALUES], | ||
...value | ||
}; | ||
} | ||
|
||
|
@@ -2332,6 +2378,12 @@ Element.setMethod(function connectedCallback() { | |
that.emit('rendered', {bubbles: false}); | ||
} | ||
|
||
let event_handlers = that[Hawkejs.EVENT_HANDLERS]; | ||
|
||
if (event_handlers) { | ||
Element.ensureEventHandlers(that, event_handlers, true); | ||
} | ||
|
||
if (has_template && that[Hawkejs.CREATED_MANUALLY] && that[Hawkejs.RENDER_CONTENT] && !that.has_rendered) { | ||
|
||
let rendering = that[Hawkejs.RENDER_CONTENT](); | ||
|