A discussion on CanJS's extensions and browser quirk fixes

@matthewp and @chrisbitme had a long convo that started with CanJS’s support of:

<img src="{{url}}"/>

If url was null, we would prevent browsers (like old versions of IE) from making a network request when src="".

Eventually, this resulted in the following discussion topics:

1.A What do we consider broken browser behavior? What about unspecified behaviors? Is something like <img src="{{url}}"/> broken browser behavior?
1.B Should we fix broken browser behavior going forward.
1.C How should we fix it.

This discussion then shifted to how something like react might fix it by creating a <compat-image> tag. This prompted another discussion topic:

2. Should we simplify/reduce CanJS’s “extension” areas? CanJS has the following extension areas:

  • components Component.extend({tag: "drag-able"}) -> <drag-able>
  • custom attrs / tags viewCallbacks.attr("draggable", handler) -> <div draggable>
  • custom dom-attr domAttr["dragging"] = { ... } -> <div dragging:from="value"/>
  • custom events domEvent.addEvent( { ... } ) -> <div on:drag="handler()"/>

Here are my thoughts:

1.A What do we consider broken browser behavior? What about unspecified behaviors? Is something like broken browser behavior?

I think any behavior that most modern browsers do that’s reasonable, that a few older, or backward browsers get wrong should be considered broken behavior.

1.B Should we fix broken browser behavior going forward?

I think we should.

1.C How should we fix it?

In places we can polyfill the “correct” behavior, we should polyfill it and provide a polyfill that can be loaded as a configuration / super dependency by the module loader (or as a script tag before CanJS loads).

In places we can’t, I still think CanJS should fix it whatever way possible.

2. Should we simplify/reduce CanJS’s “extension” areas?

I’m split on this. I think mixins like date-picker in <input date-picker> are great. But I’m willing to sacrifice them to make <date-picker> the standard approach. But the custom attr hook will still exist because can-stache-bindings still exists. We can hide it.

This leaves Component, dom-attr and dom-event. I still prefer using a focused attribute mixin:

<input type='checkbox' focused:from="shouldBeFocused"/>

versus having a bunch of custom elements:

<focused-input-checkbox focused:from="shouldBeFocused">

I think these custom attributes should be imported specifically into the template:

<can-import from="can-dom-attr-focused" value:to="scope.attributes.focused"/>
<input type='checkbox' focused:from="shouldBeFocused"/>

NOTE: this is similar to what we have planned for can-dom-events

Finally, React makes it easy to make wrapping elements. We should probably do the same. The following shows updateFrom which is similar to React’s object spread:

Component.extend({
  "tag": "focused-input".
  view: `<input this:updateFrom="inputAttributes"/>`
  ViewModel: {
    get inputAttributes() {
      var attrs = this.get();
      delete attrs.focused;
      return attrs;
    }
  }
})