Commit
Avoid allocating an array each pass through and support String subclasses like SafeBuffers
- Loading branch information
There are no files selected for viewing
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
|
@@ -127,9 +127,11 @@ def tag_options(options, escape = true) | ||
options.each_pair do |key, value| | options.each_pair do |key, value| | ||
if key.to_s == 'data' && value.is_a?(Hash) | if key.to_s == 'data' && value.is_a?(Hash) | ||
value.each do |k, v| | value.each do |k, v| | ||
This comment has been minimized.
Sorry, something went wrong. |
|||
final_v = [String, Symbol].include?(v.class) ? v : v.to_json | if !v.is_a?(String) && !v.is_a?(Symbol) | ||
final_v = html_escape(final_v) if escape | v = v.to_json | ||
This comment has been minimized.
Sorry, something went wrong.
fxn
Member
|
|||
attrs << %(data-#{k.to_s.dasherize}="#{final_v}") | end | ||
v = html_escape(v) if escape | |||
attrs << %(data-#{k.to_s.dasherize}="#{v}") | |||
end | end | ||
elsif BOOLEAN_ATTRIBUTES.include?(key) | elsif BOOLEAN_ATTRIBUTES.include?(key) | ||
attrs << %(#{key}="#{key}") if value | attrs << %(#{key}="#{key}") if value | ||
|
11 comments
on commit 2f9e880
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.
You know, if you see that feature, and you know jQuery's .data, the first thought you have is that the feature has been programmed so that they play nicely. And that is not the case. I believe the user has to be warned.
The user has to know when is this useful, why does the feature render JSON for some data types and not others (???), and how to use it in real scenarios with real examples involving modern JavaScript APIs.
If everything matched and was transparent, this documentation would be much shorter.
A warning like "Careful, strings are just passed by. In particular they may be misinterpreted if they happen to contain JSON literals, so you should need to do this and that". Or, "Careful, this JSONifies structures, but in general you will need to handle types manually. In Prototype you would do this... in jQuery you would do that...". Only covering data- APIs, not bare JavaScript.
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.
Everything matches and is transparent to HTML5 spec (that is, everything is a string, and we convert non-stringlikes into JSON strings).
The gotcha is really with jQuery. If Rails documentation provided jQuery-specific examples, and jQuery changes how it decides to JSON-eval, Rails would also have to change its documentation. I think it's best to keep the documentation agnostic, with at most a sentence to urge users to check the documentation of their JavaScript library when using library-specific APIs.
Don't get me wrong, I agree that there are gotchas, but I think the confusion lies with jQuery, not necessarily Rails. If Rails needs to provide more documentation, though, it 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.
That's good, but I think it is not enough.
First, the provided documentation does not explain well what does this new feature do. It has only a vague "HTML5 data-* attributes can be set with a single +data+ key and a hash value of sub-attributes. Sub-attribute keys will be dasherized." No mention to what is JSONified and what not.
Second, the documentation should warn users that you can't directly use that with jQuery's new data interface, and that if you want to (which is what everyone will want to do), the recommended way is X.
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.
A quick look at jQuery:
<a data-escaped-true=""true"" data-true="true" />
<script>
$('a').data('escaped-true') // "\"true\"" (instead of "true")
$('a').data('true') // true
</script>
Their documentation is here: http://api.jquery.com/jQuery.data/#jQuery-data2
Without digging into the jQuery source, I'm not sure if it's even possible to escape JSON objects from being eval'd (that is, a quoted string isn't eval'd, so the string jQuery returns is surrounded by extra quotation marks). jQuery also doesn't camelCase the key names, as JavaScript does for the DOMStringMap object that .dataset returns. This all seems pretty jQuery-specific to me, but I'm happy to help with more documentation if necessary.
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.
All right. At least I'd document with more detail what does the feature do. The user needs to know that most stuff is JSONfied.
There are gotchas here for sure, dataset gives you a 1 from the string attribute value "1". But I can't find by now how to pass the string "1". The specs mention an algorithm to extract the value from a name in a DOMStringMap but I can't find it. Does anybody know where's that covered?
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.
dataset gives you a 1 from the string attribute value "1".
Are you sure? In WebKit:
<a data-number="1" />
>> document.getElementsByTagName('a')[0].dataset.number
=> "1"
I'm pretty sure a DOMStringMap dataset
is supposed to return strings, or, according to spec, DOMStrings:
http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#domstringmap.
I'll throw together a documentation patch for the JSON bit if no one else wants to take a stab at 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.
I saw some posts with integers like http://html5doctor.com/html5-custom-data-attributes/ (search for "leaves = 47"), but a post is a post, and the draft seems clear.
The code that converts the value in the new .data function in jQuery is:
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
if ( data === undefined && this[0].nodeType === 1 ) {
data = this[0].getAttribute( "data-" + key );
if ( typeof data === "string" ) {
try {
data = data === "true" ? true :
data === "false" ? false :
data === "null" ? null :
!jQuery.isNaN( data ) ? parseFloat( data ) :
rbrace.test( data ) ? jQuery.parseJSON( data ) :
data;
} catch( e ) {}
} else {
data = undefined;
}
}
where rbrace looks for object and array literals:
/^(?:\{.*\}|\[.*\])$/;
So the gotcha is in jQuery itself and don't see a way to pass the string "true" or "1". I mean, directly. As a workaround you could pass a dummy array with one string or some trick like that for example. Except for this inherent limitation, passing stuff with the idiom you just added is useful for that .data function. And seems the natural consumer to me in the general case, given the JSON encodings/decodings. For simple values any bare .dataset access works of course.
Cool. Thanks for the thread.
Would you like to complete the description of the feature then, to explain that it does with different datatypes?
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.
Sure thing. I'll get a patch together later today.
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.
For jQuery, if you want to get the strings "true" or "1" out instead of the interpreted values, you can just use attr('data-whatever') instead of data('whatever').
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.
Yeah. Problem is you need to know that in advance in the JavaScript side, as with the singleton array trick. The contract of .data is almost there, it is almost a generic contract for passing values of different datatypes. Except for this edge case.
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.
Excellent, documentation is now http://github.com/rails/rails/compare/4120e95...de3603c
I've added it to the CHANGELOG as well.
Good tweaks, thanks. This could also be further optimized by calling
value.each_pair
instead.