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

Support blocks with mixins #310

Closed
daaku opened this issue Aug 28, 2011 · 9 comments
Closed

Support blocks with mixins #310

daaku opened this issue Aug 28, 2011 · 9 comments

Comments

@daaku
Copy link
Contributor

daaku commented Aug 28, 2011

It would be pretty awesome to have support for blocks in mixins. There are some simple use cases which would be a great start:

mixin dialog(action, header, body, buttons)
  form.dialog(action=action)
    .dialog-hd
      #{header}
      a.close X
    .dialog-bd #{body}
    if buttons
      .dialog-buttons #{buttons}


mixin dialog(action='/answer')
  block header
    h2 What is the answer?
      span.sub To life, the universe and everything else
  block body
    label Your answer:
    input(name='answer')
  block buttons
    input(type='submit')

It would be even more powerful if blocks could also be passed context and used along with iteration. This could enable some powerful UI abstractions that hide repetitive detail:

mixin grocery(items, each)
  ui.grocery
    each item in items
      li.grocery-item
        #{each(item)}
        a.remove X
  a.add-grocery Add item

items = [{ name: 'tomato', id: 1 }, { name: 'milk', id: 2 }]
grocery(items)
  block each(item)
    a(href='/item/' + item.id)= item.name
@tj
Copy link
Contributor

tj commented Aug 29, 2011

I'll have to revisit this when I implement blocks for template inheritance (if/when), I dont mind the idea, though I think template inheritance will get around a lot of this, I suppose then a template would essentially be a mixin, so maybe if we make that abstraction they can both act the same with some behaviour like this

@daaku
Copy link
Contributor Author

daaku commented Aug 30, 2011

Thanks for the ack. I've used template inheritance in Jinja a little, and while it's nice for the top level layouts, I think blocks in mixins will be more useful for "widget" type abstractions where composition works better. Jinja enables something like this with call support in macros but it's limited to one block (without doing some tricky/ugly things). I'll welcome blocks either way though :)

@tj
Copy link
Contributor

tj commented Aug 30, 2011

yeah true, they kinda compliment each other, definitely something we can play around with a bit. I'd like to get the mixins more powerful like Stylus mixins

@Charuru
Copy link

Charuru commented Dec 1, 2011

yeah this would be really nice.

@cjoudrey
Copy link

cjoudrey commented Dec 4, 2011

👍

Another use case:

mixin form_tag(action, method, content)
  form(action=action, method=method)
    #{content}
    input(name='utf8', type='hidden', value='✓')
    input(name='authenticity_token', type='hidden', value='f755bb0ed134b76c432144748a6d4b7a7ddf2b71')

mixin form_tag('/search', 'GET')
  block content
    | Form contents

@csuwildcat
Copy link

Yeah, this would pretty much be the holy grail for me.

@jasonkuhrt
Copy link

This would be hugely useful IMO. Tonnes of use cases can be handled by this pattern (that are otherwise not possible) in the context of ui containers/widgets etc.

@tj
Copy link
Contributor

tj commented Apr 18, 2012

it's almost like a shadow dom haha

@jasonkuhrt
Copy link

(All this markup comes from: http://vanyarose.com/works/at-the-bottom-of-the-hill)


I think Jade needs to approach a mashup of mixin + extends. I.e. extends allows for:

(Note the following is markup for a "panel", one of many)

// soundtrack.jade
extends index

block head
  header
    h1.title!= panel.label
    span.audio-player-control.play
    span.audio-player-control.pause
  progress(max=100)

block content
  ul.audio-player-tracks
    each track in panel.medias
      li.audio-player-track.audio-track(data-formats=JSON.stringify(track.file_type),
      data-name  = track.file_name,
      data-files = JSON.stringify(track.full_file_name),
      data-src-root = "#{content_url}/#{track.path}/",
      data-src   = "#{track.full_path}")= track.file_name

Here is another panel:

// video.jade
extends index

block content
    each video in panel.medias
        video.sublime.movie-player(width="280", height=panel.media_height, preload="none")
            each video_format in video
                // There are multiple formats for each video
                source(src="#{content_url}/#{video_format.full_path}")

So I want to be able to invoke multiple extends in a single file, and with arguments.

Without the ability for a mixins to receive blocks or extends to occur multiple times in a file here is the result when I want/need to consolidate my panels into a single file:

  • no DSL
  • not DRY
  • harder to read
include ../mixins/lists

.major-section: div.panels

  .column.column-1
    .panel.poster: img( src="#{work.urls.main}/poster_280.jpg" )

    .panel.screenings.multi-list
      header: h1.title Screenings
      .content
        each screenings_by_type in work.screenings
          h2= screenings_by_type.type
          mixin basic_list(screenings_by_type.showings, ["year","name"], ["festival-year","festival-name"])

    .panel.contact.multi-list
      header: h1.title Contact
      .content
        each contact_group in work.contact
          h2= t(contact_group.type)
          each contact in contact_group.contacts
            address
              div: a(href=contact.website)= contact.name
              div: a(href=contact.email)= contact.email
              div: span.phone= contact.phone


  .column.column-2

    .panel.synopsis: div.content
      h1= work.title
      p!= work.synopsis

    .panel.details.term-list
      header: h1.title Details
      .content
        dl
          each field in details_fields
            .ds
              dt= t(field)
              if Array.isArray(work.details[field])
                if typeof work.details[field][0] == "object"
                  each company in work.details[field]
                    dd: a(href=company.website)= company.name
                else
                  dd= work.details[field].join(", ")
              else
                dd= work.details[field]

    .panel.details.term-list
      header: h1.title Principal Cast
      .content
        mixin definition_list(work.principal_cast, {term:"role",desc:"person"})


  .column.column-3

    .panel.directors-statement
      header: h1.title Director's statement
      .content!= work.directors_statement

    .panel.details.term-list
      header: h1.title Principal Crew
      .content
        mixin definition_list(work.principal_crew, {term:"role",desc:"person"}, true)


  .column.column-4

    .panel.videos.raw
      header: h1.title Moving image
      .content
        each video in work.videos
          video.sublime.movie-player(width="280", height=video.height, preload="none")
            source(src="#{work.urls.videos}/#{video.name}.mp4")
            source(src="#{work.urls.videos}/#{video.name}.webm")

    .panel.stills.raw
      header: h1.title Stills
      .content
        each still_id in work.stills
          img( src="#{work.urls.stills}/#{still_id}.jpg" )

@tj tj closed this as completed in ae8e8b7 Apr 18, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants