Closed pyykkis closed 12 years ago
I assume the goal is to have micro-string-templates as alternative to pure Javascript functions.
Darn.... this kind of kills one of main points of Transparency :)
Can we think of something "cleaner" solution here? I believe we could come up with a syntax which is not that closely bound to individual DOM elements (text, html, class, have special append) etc.
Here is my proposal of alternative approach which would behave like above but little more "streamlined" - e.g. the attribute name resolution for directive object content would be little cleaner
Complex directives
If value is a string it is treated as a text template (no HTML), like current data
directives : { foobar : "Mikko was here" }
If value is a function treat is a dynamic directive (the current implementation)
data : { mydirective : function(elem) { return "foobar"; }, mytemplatebindid : "foobar" }
If value is an object treat is a "complex" directive which gives additional formatting and targetting options. This would allow setting individual attribute directives, setting HTML escaping flag, setting content generator function and post procesing function
input : {
// Complex directive
mydirective : {
// Set to false to mimic manipulate innerHTML() instead of innerText(),
// Safety - default is true
escape : false,
// Directive content for individual attributes
// as attribute name -> attribute directives mapping.
// Attributes can be data-like direct string
// or follow diretive processing rules as function
attributes : {
// Set CSS class
"class" : "my-css-class",
// Mutate existing style declarating by suffixing new style
style : function(attr) { return attr + " display:none;"},
// Mutate exisitng id attribute by reading the current data
// and passing in its id attribute content
id : function(attr) { return "mikko-id-prefix-" + this.id; }
},
// Return text payload,
// now as unescaped HTML as set above.
// Run after attributes processing above.
// If null/undefined is returned then do not
// touch element content.
// If false is returned remove element.
// On empty string clear the element contents.
content : function(elem) {
return "<b>BOLD and the beautiful</b>";
}
}
}
First goal is to make directives more consistent with normal rendering, i.e., getting rid of @
syntax. Second goal is to provide powerful enough semantics, so that directives can be written as side-effect free functions.
Directives are always functions, never strings. At the moment, they can only return strings. I'm proposing they could return either string or object.
By all means, I'm not going to going to provide string-based micro templating. I agree append:
and prepend:
keywords might need more consideration. Otherwise, I'm feeling the proposed approach is a lot cleaner than the current implementation.
Please see the comparisons below.
<!-- template -->
<div id="container">
<a class="name"></a>
</div>
data = [
id: 1, name: "foo"
, id: 2, name: "bar"
]
# Current implementation.
# Ugly, as selecting the element and assigning to attribute are mixed together.
directives =
'name@href': () -> "www.example.com/#{@id}"
# New implementation.
directives =
name: () -> href: "www.example.com/#{@id}"
With current implementation, there's another ugly thing, if one needs to set multiple attributes and/or value. Given the same data and template than above, here's an example underlining the issue.
# Current implementation. Ugly, as directive function is not pure,
# but instead have side effects in addition to return value.
# Additionally, it's not obvious what the return value does
# (it's set as a text value of the element).
directives =
name: (e) ->
$(e).attr('href', "www.example.com/#{@id}")
"Hello #{name}!"
# New implementation.
# A pure function without side-effects and self-explanatory functionality
directives =
name: () ->
href: "www.example.com/#{@id}"
text: "Hello #{name}!"
# New implementation, rendering unescaped html content
directives =
name: () ->
href: "www.example.com/#{@id}"
html: "<b>Hello #{name}!</b>"
Thanks @miohtama for the review and feedback. I'm closing this and creating a new ticket for the functional approach on append/prepend you proposed, it's just awesome.
I'm planning to implement a new API for directives. Main motivation is to clarify and harmonize the functionality. This issue invalidates the issues https://github.com/leonidas/transparency/issues/21 https://github.com/leonidas/transparency/issues/22
New API extends functionality by providing
append
andprepend
, whilereplace
remains as a default. Additionally,index
is added as a new parameter for directives, which makes adding line counts oreven
andodd
classes a breeze.Principles:
@
symbols and semantic confusion due to mixing element selection and attribute assignment.string
, it get assigned to the matching elements as text content. This provides backward compatibility and simplicity for the most common scenario.object
, i.e., key-value pairs. Keys can be eithertext
,html
or any attribute name, e.g.,class
,src
orhref
. Values can be either type ofstring
, or objects. If the value is an object, it's expected to be either{append: "value"}
or{prepend: "value"}
, providing the obvious functionality.Examples:
Waiting for comments until Monday.