Skip to content
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

Explicit block definition #1271

Closed
buschtoens opened this issue Oct 25, 2013 · 5 comments
Closed

Explicit block definition #1271

buschtoens opened this issue Oct 25, 2013 · 5 comments

Comments

@buschtoens
Copy link

Currently all three block statements (block, append, prepend) implicitly define a new block, if they can't already find a block with the same name in the extended layout.

This is problematic, when using blocks in a single file without a layout (and for includes, but that's another topic).

#test
  block test
    p 1

prepend test
  p 0
append test
  p 2
<!-- expected output -->
<div id="test">
  <p>0</p>
  <p>1</p>
  <p>2</p>
</div>

<!-- actual output -->
<div id="test">
  <p>1</p>
</div>
<p>1</p>
<p>1</p>

This is caused by the ambigious use of the block name statement. On the one hand block test could create a new block in its current place, on the other hand it could replace all other occurences.

Apparently it does all together. Because changing block test to append test (which is short for block prepare test) leads to this rather funny result.

<div id="test">
  <p>1</p>
</div>
<p>0</p>
<p>1</p>
<p>0</p>
<p>2</p>
<p>1</p>

IMHO blocks should get more explicit and so I made up my mind on this. (I'm rather sorry that this is somewhat f a cross-breed of a bug report and a Google Groups post.)

h1 The new block interface

h2 Block definitions, appending and prepending

// There now is only *one* way to define a block.
// (i.e. `append` and `prepend` are additional only and don't define blocks)
#only-nums
  block i-can-haz-alphanum
    // This definition can optionally have child nodes.
    p 1

// Blocks can be defined multiple times.
// They can also have different contents.
// Block defintions don't replace one another's content, like before.
// (optional)
#nums-and-an-a
  block i-can-haz-alphanum
    p a

// `block append` and `block prepend` still work as expected.
// The provided content is appended or prepended to all matched block definitions.
// However, `append` and `prepend` don't define blocks themselves.
// They are much like `mixin`s. They are there for the engine, but cannot be seen in the HTML.
block append i-can-haz-alphanum
  p 2

// `append` and `prepend` shorthands too still work as expected.
prepend i-can-haz-alphanum
  p 0

h2 Replacing

#dialogue
block dialogue
  p Bonjour!
prepend dialogue
  p Salut!
append dialogue
  p Au revoir.

// The `replace` mode has to be accessed explicitly.
// It replaces the original content and all appends and prepends that have happened before.
block replace dialogue
  p Luke, I am your father.

// Of course there's a shorthand.
replace dialogue
  p Nooo...

// Further appends and prepends still work.
prepend dialogue
  p Luke, I am your father.
append dialogue
  p Oh yes, I did a paternity test.
<h1>The new block interface</h1>

<h2>Block definitions, appending and prepending</h2>

<div id="only-nums">
  <p>0</p>
  <p>1</p>
  <p>2</p>
</div>

<div id="nums-and-an-a">
  <p>0</p>
  <p>a</p>
  <p>2</p>
</div>

<h2>Replacing</h2>

<div id="dialogue">
  <p>Luke, I am your father.</p>
  <p>Nooo...</p>
  <p>Oh yes, I did a paternity test.</p>
</div>

I would implement this myself and make a PR, but I'm not familiar enough with Jade's internal engine to be able to safely do it all alone and not produce 20 new bugs by the way. Yet I think, that this shouldn't be too much of a change in the code. append, prepend and replace become something like a mixin (as in not yielding output) and the block engine gets a little twist so that multiple blocks of the same name are allowed.

I find this much more predictable than the original interface and would like to hear your thoughts on this.

@buschtoens
Copy link
Author

tldr, proposed changes are:

  • block my-block is the only way to define a block. It does not replace any content. No ambiguity.
  • append my-block and prepend my-block only do what they are meant to do. They don't implicitly create new block definitions. They only add content to all block defintions, that are called my-block.
  • replace my-block is the only way to replace the contents of all block defintions, that are called my-block. No accidental overwrites anymore.

(Of course block append my-block, block prepend my-block and block replace my-block work too)

These changes make the block engine usable in single flat Jade files and will very likely eliminate a nasty bug with includes in combination with layouts.

@thomas-riccardi
Copy link

In light of the multiple issues discussed, the block feature obviously needs more explicit behavior.

append and prepend should indeed not yield, as I described in #997 (comment).

I like the idea of block replace: we explicitly say "I want to replace/implement the block named name". (I hesitate between replace and implement, since default values for block seem to not be the usual case: in many cases the extended layout just defines placeholders to yield something defined later.)

Implicitly defining a block as it's done today mixes two notions: defining where to yield the content if we are not in the root level of an extending .jade (btw what happens if this extending .jade is also used by another extends?), and maybe replacing a previously defined block. This is confusing.

This may however limit the possibilities with includes: we could maybe imagine a use-case where an include is both used in an extending and an extended .jade, but I'm not sure it's really an issue, as it's probably not possible today due to the multiple issues around this.

Also, why resetting appended and prepended values when replacing a block? If we want to avoid implicit behaviors we could have block replace and block reset: this way replace works as block today: we don't reset the previously appended and prepended values.

Finally, why multiple block with the same name? This creates new unexpected behaviors: we can define different default values, but we cannot modify only one of them, the replace, append and prepend will modify all of them. If you want multiple yield points for the same block maybe add a block yield feature, this way we explicit the behavior, and we refuse children for this one.

Anyway, these changes are breaking changes: we break the main usage of block, this will have to be dealt with as the Jade project is use by many. Maybe use a different name than block?
However I still think we should change the behavior of append and prepend, it will break some cases, but not the main ones, and it will fix real issues.

@buschtoens
Copy link
Author

Maybe we really need block replace name and block implement name. The first replaces the content and all appends & prepends. The latter only replaces the content, that was set by block name or by further block implement name calls.

All block operations (block append name, block prepend name, block replace name, block implement name) do not yield (in place). They are treated like null nodes, mixin defintions or something like that.

block name is now the only way to define a point where the contents of a block will be yielded. This statement can be nested into other blocks. Circular nestings should throw.
block name optionally takes child nodes, which implement content for only this one yielding point. Child nodes can be other block defintions or block operations.

block yield name seems interesting at first, but is not neccessary, if block name is explicitly used for defining blocks and not for replacing them.

p.friend
  block friend
    | Tobi

p.friend
  block friend
    | Meowingtons

p.no-friend
  block friend

prepend friend
  | I like

append friend
  | . He's ony of my best friends.
<p class="friend">I like Tobi. He's one of my best friends.</p>
<p class="friend">I like Meowingtons. He's one of my best friends.</p>
<p class="no-friend">I like . He's one of my best friends.</p>

@sintaxi
Copy link

sintaxi commented Nov 2, 2013

+1 for more explicit behaviour in blocks

@TimothyGu
Copy link
Member

In short, you cannot append a block in the same file. EOD. If you want to append a block, then use extends. See also #1267.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants