-
Notifications
You must be signed in to change notification settings - Fork 177
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
A way for attributes to contain expressions without triggering browser errors or false loading #833
Conversation
Here is a couple of examples: https://codepen.io/dmitrysharabin/pen/gOoqOzj |
There is an issue I don't know how to address yet: I can't preserve an attribute case. E.g., I tried to add different attributes with letters in different cases to elements inside and outside a Mavo app, and it looks like browsers convert attributes to lower case automatically? Am I right? @LeaVerou Are you aware of any way to bypass it? |
It looks like I am. 😭 |
awkward hack: define another attribute that converts its indicated
attribute from hyphenated to camel case; e.g. mv-camelcase-view-box
would become viewBox.
…On 4/19/2022 9:08 AM, Dmitry Sharabin wrote:
I tried to add different attributes with letters in different
cases to elements inside and outside a Mavo app, and it looks like
browsers convert attributes to lower case automatically? Am I right?
It looks like I am. 😭
https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute#lower_casing
—
Reply to this email directly, view it on GitHub
<#833 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAIWSXUMRDHEZAGOSNIW2XDVF2V5XANCNFSM5TWYYJYQ>.
You are receiving this because you are subscribed to this
thread.Message ID: ***@***.***>
|
actually, here is another possible approach: apparently there is a
specified list of tag adjustments that you could perform automatically
*if the node with the attributes is an svg node* which I suspect can be
checked somehow.
https://html.spec.whatwg.org/multipage/parsing.html#adjust-svg-attributes
search for "adjust svg attributes" in this doc if the anchor fails.
…On 4/19/2022 9:08 AM, Dmitry Sharabin wrote:
I tried to add different attributes with letters in different
cases to elements inside and outside a Mavo app, and it looks like
browsers convert attributes to lower case automatically? Am I right?
It looks like I am. 😭
https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute#lower_casing
—
Reply to this email directly, view it on GitHub
<#833 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAIWSXUMRDHEZAGOSNIW2XDVF2V5XANCNFSM5TWYYJYQ>.
You are receiving this because you are subscribed to this
thread.Message ID: ***@***.***>
|
Oh I'm glad you're working on this. Due to the way Mavo resolves expressions, substituting gradually, I imagine (without having seen the code) that this solution may still produce errors when the expressions depend on other expressions, e.g.: <input type=number value="[foo]">
<span property="foo" value="[bar]"></span>
<span property="bar" value="3"></span> |
In the SVG Path Builder we won't be able to get rid of the error caused by this code:
Do you mean trigger browser errors? The following code works without errors (I updated the pen). :) But I'm almost 100% sure I could miss some use cases. <input type=number mv-attr-value="[foo]" />
<span property="foo" mv-value="bar"></span>
<span property="bar">3</span> |
That's interesting. Thanks, David. 🙏🏻 I was thinking of the approach you suggested and wondering: do we really need this at the core? If the casing issue becomes a problem for authors, we can add a plugin that will make the |
Why not? Can't we specify |
Ah, yes. You are absolutely right—lowercase attributes are not even an issue. They work perfectly fine. Stupid me. 🤦♂️ Now I need to figure out why Thank you. I'll continue my investigation then. |
…ithout triggering browser errors or false loading
85c212b
to
d378d55
Compare
…at are part of the value, not only the value itself
d378d55
to
e7e3786
Compare
Thanks to David, we know that browsers adjust SVG attributes that are not all lowercase. That means that when there is an expression inside the value of an attribute (e.g., inside The We can conclude that the casing issue causes loss of functionality. So I decided to follow David's suggestion and adjust those kinds of attributes manually. And it worked. Yay! I updated the demo so that it showcases different use cases. I believe this PR is ready for review. 🤞🏻 |
Are you using the correct namespace for these attributes? I wonder if that's why |
Hmm. That's a good question. I don't know. I definitely need to figure it out. |
Here are some results of my research concerning SVG, its elements, attributes, and namespaces:
Suppose we have (mind the attribute case): <svg viewbox="0 0 100 100">
...
</svg> In DevTools, we see (mind the attribute case): After inspecting the
element.setAttribute(o.attribute, value); with this one: if (element.namespaceURI === "http://www.w3.org/2000/svg") {
element.setAttributeNS(element.namespaceURI, o.attribute, value);
}
else {
element.setAttribute(o.attribute, value);
} Then I inspected <svg
viewbox="-50 -50 50 50"
mv-attr-viewBox="[list(0, 0, 100, 100)]">
...
</svg> In DevTools we have and As we can see, the browser adjusted the fallback attribute (as expected), and the one added by Mavo has the To conclude, So, unfortunately I couldn't find the way to make |
I believe I wonder if something like this would work: https://codepen.io/leaverou/pen/ZEvPPaP?editors=1111 |
Whoa! That's cool!!! Thanks for the new knowledge. Re:context. Got it. Totally agree. I will take that into account. |
Huge thank you to @LeaVerou for the idea!
Done! |
If I get your comment correctly, now it should work (after some fixes I made to the code): https://codepen.io/dmitrysharabin/pen/mdpgBvy |
@LeaVerou, I would also be grateful if you give this PR another look. I believe the feature it adds to Mavo might be very beneficial. We might make this feature experimental. |
Definitely on the same page here, a non-deterministic scenario would be very much not ideal 😂
I think overall I like having Regardless of what we decide, we definitely will need to update the documentation to be very clear and explicit about how this works |
…the corresponding objects)
src/expressions.js
Outdated
let attributes = $$(node.attributes); | ||
|
||
// Iterate only over mv-attr-foo with expressions | ||
for (let attribute of attributes.filter(attribute => attribute.name.startsWith("mv-attr-") && syntax.test(attribute.value))) { | ||
let name = attribute.name.replace("mv-attr-", ""); | ||
let ignorable = attributes.find(attribute => attribute.name === name); | ||
|
||
if (ignorable) { | ||
// Ignore expressions in foo, if any, since mv-attr-foo has priority | ||
ignore ??= new Set(); | ||
ignore.add(ignorable.name); | ||
} | ||
} | ||
|
||
attributes.forEach(attribute => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LeaVerou, thank you so much for your hint—expressions.js
is indeed the appropriate place for this logic. Sorry for requesting your review one more time. 🙈
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this may be complicating things a bit. I just pushed a commit that tries to simplify the logic, but I haven't tested it, so you'd need to do that.
Also, we don't need to apply syntax.test()
here, the values of mv-attr-*
, like directives, are always expressions. If you haven't designed it like that, you should.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I re-designed the mv-attr-*
feature to work as mv-value
. Because of the wrong design decision, I wrote way too complicated logic. I knew that mv-attr-foo
doesn't make sense if it's not an expression, but I chose the wrong path to implement it. Thank you for pointing this out. 🙏🏻
src/domexpression.js
Outdated
this.attribute = Mavo.getProperAttributeCase(this.element, this.attribute); | ||
} | ||
|
||
this.fallback = this.fallback || Mavo.Primitive.getValue(this.element, {attribute: this.attribute}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.fallback = this.fallback || Mavo.Primitive.getValue(this.element, {attribute: this.attribute}); | |
this.fallback ||= Mavo.Primitive.getValue(this.element, {attribute: this.attribute}); |
(also do we need ||
or ??
here?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume that some falsy values (e.g., 0
) might be perfectly valid fallbacks, and we don't want to replace them with any other value. So, I'm leaning towards ??=
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, left some minor comments
src/expressions.js
Outdated
@@ -183,11 +183,11 @@ var _ = Mavo.Expressions = $.Class({ | |||
}, | |||
|
|||
extract: function(node, attribute, path, syntax = Mavo.Expression.Syntax.default) { | |||
if (attribute && _.skip.indexOf(attribute.name) > -1) { | |||
if (_.skip.includes(attribute?.name)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we remove this entirely now that _.skip
is taken into account in traverse()
? As far as our own codebase is concerned, that seems ok, but not sure if any plugins call extract()
and depend on this behavior
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question. I searched for extract(
in our repo with plugins and found no mentions. Neither could I find this in my repos. I'm unsure if we have any other plugins we might break. We can try to commit to this change and see what might happen. 🤓
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm ready to remove it as soon as we decide to do that. I commented this block out, and everything still works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done!
Now, I'm ready to request your review one more time. Thanks a ton for your patience and excellent ideas! 🙏🏻
src/domexpression.js
Outdated
this.attribute = this.attribute.replace("mv-attr-", ""); | ||
|
||
if ([SVG_NAMESPACE_URI, MATHML_NAMESPACE_URI].includes(this.element.namespaceURI)) { | ||
this.attribute = Mavo.getProperAttributeCase(this.element, this.attribute); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just dawned on me: do we also need to do this in XHTML documents (with an actual XML MIME type)? If so, it would require a different check (not a blocker, we can fix later).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably we should. Our users will push us to do this in any case. 😅
|
||
this.fallback ??= Mavo.Primitive.getValue(this.element, {attribute: this.attribute}); | ||
let expression = this.element.getAttribute(this.originalAttribute); | ||
this.element.removeAttribute(this.originalAttribute); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seems to be a lot of repetition between this and the preceding block implementing mv-value
. I'll push a commit to address it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, please check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoa! Cool! It's working with this beautiful piece of code. 🥳 Thank you!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is done then?
I think so! 🤞 |
@LeaVerou, thanks a ton for your help! We made this awesome feature happen. Yay! 🥳 |
I think the natural use case for foo= mv-attr-foo= is when you want to give the browser something to work with until the expression in mv-attr-foo is evaluated, but that once that happens mv-attr-foo should dominate. |
This is exactly how it’s designed and implemented. I’m glad we are all on the same page. |
Having considered further, I can see an argument for order of attributes, because that's how html works, right? So once the expression is evaluated. we could apply the standard order of attributes rules to decide if it overrides the foo attribute. |
@karger, do you mind filing a separate issue so we can discuss it there, not in the merged PR? There is always room for improvements we don't want to skip. :) |
Closes #475.
I believe this feature is a nice to have in the upcoming release. I tested it on several examples, including SVG Path Builder. It looks like it's working. :)
I liked the idea of using the
mv-attr-*
family of attributes for the feature, so I went that way.Since I'm not 100% sure that I do everything correctly, let's consider this PR as the first step. :)