posthtml / posthtml-expressions

Use variables, JS-like expressions, and even markup-powered logic in your HTML.
Other
123 stars 20 forks source link

[Feature Request] : Filters #60

Open cossssmin opened 4 years ago

cossssmin commented 4 years ago

Would be awesome if posthtml-expressions offered support for filters, like Nunjucks does.

So you could do stuff like:

locals: { greeting: 'hello there' }
<p>
  {{ greeting | capitalize }}
</p>
<p>
  Hello there
</p>

...or:

<div>{{ [1,2,3] | first }}</div>
<div>1</div>
anikethsaha commented 4 years ago

I am +1 for this. Just a question, does any other template lang provides similar features ?

cossssmin commented 4 years ago

It would be even better if you could register your own filters.

So the plugin would come with built-in fitlters, but you could pass in a filters option:

require('posthtml-expressions')({
  filters: {
    upper: (str) => str.toUpperCase(),
    trim:  (str) => str.trim(),
    join: (array, separator) => array.join(separator)
  }
})
cossssmin commented 4 years ago

I am +1 for this. Just a question, does any other template lang provides similar features ?

Besides Nunjucks and Jinja (which the former is inspired from), Liquid also has this. There might be others that I don't know of...

anikethsaha commented 4 years ago

Seems like a good feature to add !

Scrum commented 4 years ago

@cossssmin I like this idea and approach, there is a true feeling that we are creating our own Jinja or Django template

cossssmin commented 4 years ago

Glad to hear it! 😊

Now, regarding development, I haven't looked into it, and I have a feeling it'll be pretty complicated (for me, at least) to get it working with that {{ variable | filterName }} syntax. Can you help with that?

For starters maybe we could do a <filter name="filterName"> tag, which you could use like so:

<filter name="uppercase">lorem ipsum</filter>

Result:

LOREM IPSUM

I can totally help with writing the built-in filters that it would include, I guess we could decide on what to port over from Liquid and Nunjucks?

Speaking about built-in filters, these will definitely not cover all needs, so I think the filters option mentioned above would be really, really useful.

Scrum commented 4 years ago

<filter name="filterName"> it seems very cumbersome considering that there may be several filters - it will clog HTML

{{ variable | filterName }} - I will make sketches in this direction, but most likely tomorrow))

cossssmin commented 4 years ago

Forgot about multiple filters, so this needs to be taken into account.

For example:

{{ "foo\nbar" | striptags(true) | escape | nl2br }}

I think the <filter name=""> tag might still be useful:

Thoughts?

Scrum commented 4 years ago

Thoughts?

So far vague

simple

<filter name="">string</filter>

nested 1

<filter name=""><filter name="">string</filter></filter>

nested 2

<filter name="">string<filter name="">string</filter></filter>

I think the filter to the line will be better

@anikethsaha @voischev What do you think ?

cossssmin commented 4 years ago

Yep, I get someone could do that, but you wouldn't have to if we have both {{ var | filterName }} and the <filter> tag. You use the inline one on objects/strings, but for something like this you'd still need a tag, I think:

<filter name="capitalize">
  <section>
    <article>
      <h1>article title</h1>
      <p>lorem ipsum dolor sit amet</p>
    </article>
  </section>
</filter>

Result:

<section>
  <article>
    <h1>Article title</h1>
    <p>Lorem ipsum dolor sit amet</p>
  </article>
</section>

I think this is also why Jinja (docs) Nunjucks (docs) have a filter block. This way, you can apply a filter not just to your own markup, but to stuff that you include with posthtml-include or with posthtml-modules :)

anikethsaha commented 4 years ago

i think , <filter> can have more control over the HTML I guess. (not sure though)

I think we can have PoC for either or both so that we can discuss it with the implementation with just the built-in ones!

cossssmin commented 4 years ago

i think , <filter> can have more control over the HTML I guess. (not sure though)

I think both are useful, as there are situations where you can't use the tag, and vice-versa - remember the @{{ }} + <raw> discussion we had? 🙂

anikethsaha commented 4 years ago

yes, seems like we need both ! 👍

anikethsaha commented 4 years ago

let's start with the tag just for the sake of simplicity ? or with the other one !

Scrum commented 4 years ago

Ok, let's try with tags,

  1. what will the filter chain look like?
  2. In what order to apply?
  3. Ignoring applied filters?
<filter name="capitalize | striptags(true) | escape | nl2br">
  <h1></h1>
  <filter name="!escape"><p></p></filter> // ignore filter escape ?
</filter>

left to right or right to left?

or

<filter name="capitalize">
  <filter name="striptags(true)">
    <filter name="escape">
      <h1></h1>
    </filter>
    <filter name="!capitalize"> // ignore filter capitalize
      <p></p>
    </filter>
  </filter>
</filter>

top to bottom or bottom to top?

cossssmin commented 4 years ago

My feedback:

  1. If we go for the first one (multiple filters split by |), the second one would also be possible. I think it would be awesome to be able to call multiple filters on a block with a single filter tag, so I'm all for the first approach 👍

  2. I would say in order of appearance. So, apply the first filter in the attribute, then the next, and so on. I'm not saying LTR or RTL, as that might depend on the user's language and some editors support RTL. In order of appearance would also make it top to bottom or outside to inside, when nesting filters - I suppose this would be easier, instead of going up the tree?

  3. Really cool idea, didn't think of that! Would be very useful for opting out of applying some filter. I can imagine a loop block where you have several filters that format content, and you need to do it in an alternating fashion - so instead of doing double the work (applying another filter to undo the ~previous~ parent one; might not even be possible), it actually does less work. +1 for this!