Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More event props improvements #9

Merged
merged 8 commits into from
Nov 20, 2017
Merged

More event props improvements #9

merged 8 commits into from
Nov 20, 2017

Conversation

cornerman
Copy link
Contributor

No description provided.

@@ -10,5 +10,5 @@ trait ErrorEventProps[EP[_ <: DomEvent], DomEvent, DomErrorEvent <: DomEvent] {
/**
* Script to be run when an error occurs when the file is being loaded
*/
lazy val onError: EP[DomErrorEvent] = eventProp("onerror")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oopsie. Good catch

/**
* Fires when the browser window is resized
*/
lazy val onResize: EP[DomUIEvent] = eventProp("resize")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you want to move onResize to this trait? Is it somehow conceptually different from other events in WindowEventProps? Looking at MDN this event seems to be window-specific by nature.


Looking at onLoad and onScroll, I see that they can be applied to elements as well. It would be nice to update the comments on those to not be window-specific and to link to https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onload and https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onscroll

Copy link
Contributor Author

@cornerman cornerman Nov 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason is that I want to separate event handlers that are exclusive to Window, Document, Element and HTMLElement. All three of them implement GlobalEventHandlers. And, for example the event handler onResize is a GlobalEventHandler and therefore not exclusive to Window (eventhough the resize event only exists on Window).

But here they differ:

  • Window additionally implements WindowEventHandlers and its own event handlers, which more or less corresponds to our WindowEventProps (these properties are not available on Document or Element).
  • Document also adds some own event handlers. We currently do not have event properties for those.
  • Element has two event handler of its own. We currently do not have event properties for those.
  • HTMLElement adds the clipboard and touch events. The clipboard events are defined in our ClipboardEventProps, we do not have touch events.

Maybe, we can also make it more clear somehow, which EventProps traits belong to which EventTarget?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will update the comments


/**
* The click event is raised when the user clicks on an element. The click
* event will occur after the mousedown and mouseup events.
*
* MDN
*/
lazy val onClick: EP[DomMouseEvent] = eventProp("click")
lazy val onClick: EP[DomMouseEvent with DomHtmlElementTargetEvent] = eventProp("click")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect we can indeed do this, but is there any formal indication that such events will only happen on elements and not e.g. text nodes or SVG elements?

Copy link
Contributor Author

@cornerman cornerman Nov 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, i think you are right! MDN actually only says the target type is Element.

Then, I was probably also wrong to make onBlur and onFocus in FormEventProps be an HTMLElementTargetEvent, as they are also only defined for target Element. Right?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think we should start out being somewhat conservative in this kind of thing, I'd be happy with dom.Element where MDN says so. If we start relying on "conveniently incorrect" types the eventual withdrawal will be painful... I'm still hoping that the other approach I mentioned in a comment on this issue in outwatch will work better for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds right, I will update those event props to having target of type dom.Element. We can always revisit if there is new information.

@cornerman cornerman force-pushed the cleanup-events branch 2 times, most recently from 9d0149a to 6d9f28d Compare November 17, 2017 14:18
@@ -6,6 +6,6 @@ import scala.scalajs.js

/** Represents an event for which we know what exact type the `target` is. */
@js.native
trait ElementTargetEvent[+E <: dom.html.Element] extends dom.Event {
trait TypedTargetEvent[+E <: dom.EventTarget] extends dom.Event {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


/**
* The click event is raised when the user clicks on an element. The click
* event will occur after the mousedown and mouseup events.
*
* MDN
*/
lazy val onClick: EP[DomMouseEvent] = eventProp("click")
lazy val onClick: EP[DomMouseEvent with DomHtmlElementTargetEvent] = eventProp("click")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think we should start out being somewhat conservative in this kind of thing, I'd be happy with dom.Element where MDN says so. If we start relying on "conveniently incorrect" types the eventual withdrawal will be painful... I'm still hoping that the other approach I mentioned in a comment on this issue in outwatch will work better for this.

trait EventPropsInWindow[EP[_ <: dom.Event]] extends EventPropsInGlobal[EP] with WindowEventProps[EP] { this: generic.builders.EventPropBuilder[EP, dom.Event] => }
trait EventPropsInDocument[EP[_ <: dom.Event]] extends EventPropsInGlobal[EP] with ClipboardEventProps[EP] { this: generic.builders.EventPropBuilder[EP, dom.Event] => }
trait EventPropsInElement[EP[_ <: dom.Event]] extends EventPropsInGlobal[EP] { this: generic.builders.EventPropBuilder[EP, dom.Event] => }
trait EventPropsInHTMLElement[EP[_ <: dom.Event]] extends EventPropsInGlobal[EP] with ClipboardEventProps[EP] { this: generic.builders.EventPropBuilder[EP, dom.Event] => }
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm... I'm not sure if these new traits should reside in SDT. I don't really see a good way to use more than one of those traits at a time in a typical consuming library. I mean, the names would conflict, and you'd need to instantiate way more eventprop objects than needed... right? Maybe I'm missing something?

I'm guessing #13 is related here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I would like sdt to bring those type as they tell me which event properties are applicable to which underlying EventTarget type.

My plan is to have the following three usages:

  • trait DomEventProps extends EventPropsInHTMLElement[EmitterBuilder] with EventPropBuilder[EmitterBuilder, dom.Event] for normal usage within tags as it is now, like: input(onChange --> sink).
  • object WindowEvents extends EventPropsInWindow[Observable] with EventPropBuilder[Observable, dom.Event] for registering window events via an observable: WindowEvents.onStorage.map(ev => ...).
  • object DocumentEvents extends EventPropsInDocument[Observable] with EventPropBuilder[Observable, dom.Event] for registering document events via an observable: DocumentEvents.onLoad.map(ev => ...).

The latter two can be build by creating an observable from the callback we have when registering an event with (Window|Document).attachEventListener(eventKey, callback)

Copy link
Owner

@raquo raquo Nov 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh that's a nice pattern! I myself was using node.events(onClick) pattern because I don't want each node to extend a trait with a hundred vals, even if they're lazy. But for document / window this looks reasonable.

Let's keep all those traits then.


I'm assuming you named the new traits ...InX as opposed to X... because EventPropsInWindow would otherwise conflict with WindowEventProps? Should we maybe rename the original WindowEventProps to WindowOnlyEventProps or something like that? Would look nicer and would also sort of better match Javascript's stuff:

https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers
https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly! Sure, we can rename them; I wasn't too happy with this ...In... :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

node.events(onClick)

With regards to outwatch/outwatch#93, that approach would work much better with the currentTarget-event.

@@ -19,7 +22,7 @@ import com.raquo.domtypes.generic.builders.EventPropBuilder
* DOM InputEvent https://developer.mozilla.org/en-US/docs/Web/API/InputEvent
* Note: This type is not implemented in scala-js-dom
*/
trait FormEventProps[EP[_ <: DomEvent], DomEvent, DomFocusEvent <: DomEvent, DomInputEvent <: DomEvent, DomHtmlElementTargetEvent <: DomEvent, DomFormElementTargetEvent <: DomEvent, DomInputElementTargetEvent <: DomEvent] { this: EventPropBuilder[EP, DomEvent] =>
trait FormEventProps[EP[_ <: DomEvent], DomEvent, DomFocusEvent <: DomEvent, DomInputEvent <: DomEvent, DomElementTargetEvent <: DomEvent, DomHtmlElementTargetEvent <: DomEvent, DomFormElementTargetEvent <: DomEvent, DomInputElementTargetEvent <: DomEvent] { this: EventPropBuilder[EP, DomEvent] =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not completely sure about the target types anymore. Why does MDN often say target: Element, but then in the description gives a more concrete type on which elements the event can occur?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, conventional JS ideology is largely "let's try to run this and see what we get", so I don't imagine JS devs care all that much about what types are specified. There are also potentially some differences in what is specified in the DOM standard and what is actually implemented in browsers, but I'd think those are minimal by now. I think it's mostly just that JS users largely don't care about minor typing details like this.

For the submit event MDN says "Note that submit is fired only on the form element, not the button or submit input. (Forms are submitted, not buttons.)", and I've verified this behavior manually in a couple browsers, so I'm confident enough to put Form as the type of target for such an event.

@raquo raquo merged commit 7a7ecb2 into master Nov 20, 2017
@raquo raquo deleted the cleanup-events branch November 20, 2017 00:21
@raquo
Copy link
Owner

raquo commented Nov 20, 2017

@cornerman Thanks for working on this! I've just released v0.4

@cornerman
Copy link
Contributor Author

Great! I think, it should be ready now for outwatch. Thank you so much for all your effort!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants