A set of UI elements styled using Twitter Boostrap toolkit to use with Ember.js
JavaScript Ruby
Switch branches/tags
Nothing to show
Pull request Compare This branch is 4 commits ahead, 180 commits behind emberjs-addons:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
generators
packages
sample
tests
.gitignore
.travis.yml
Assetfile
Gemfile
Gemfile.lock
LICENSE
README.md
Rakefile
VERSION
config.ru

README.md

Ember Bootstrap Travis

Ember Bootstrap is set of UI elements styled using Twitter Bootstrap (currently version 2) toolkit to use with Ember.js. The ultimate goal is to provide all elements from the Bootstrap toolkit.

Is this thing even usable?

Nope, not yet. So either fork, do your magic and send pull request or move along.

What's implemented so far?

Views

  • Buttons - Bootstrap.Button
  • Modal panes - Bootstrap.ModalPane
  • Nav lists - Bootstrap.NavList
  • Pills - Bootstrap.Pills
  • Tabs (header) - Bootstrap.Tabs
  • Alert messages - Bootstrap.AlertMessage
  • Block alert messages - Bootstrap.BlockAlertMessage
  • Progress bars - Bootstrap.ProgressBar
  • Badges - Bootstrap.Badge
  • Labels - Bootstrap.Label
  • Wells - Bootstrap.Well
  • Badges - Bootstrap.Badge
  • Labels - Bootstrap.Label
  • Wells - Bootstrap.Well

Forms

  • Text Field - Bootstrap.Forms.TextField
  • Text Area - Bootstrap.Forms.TextArea

Handlebar Helpers

Some initial carousel helpers have been added to the helpers folder. Please test these out and add your own to the collection.

See https://github.com/luan/ember-formbuilder/tree/master/packages/ember-formbuilder/lib/formbuilder/helpers for inspiration ;)

Great guide to helpers here: http://techblog.fundinggates.com/blog/2012/08/ember-handlebars-helpers-bound-and-unbound/

And here: http://handlebarsjs.com/block_helpers.html

You could, of course, use a library like underscore.js or SproutCore's runtime library to make this look a bit prettier. Using SproutCore's runtime:

Handlebars.registerHelper 'list', (context, block) ->
  inner = context.map( (item) ->
    "<li>" + block(item) + "</li>"
  }).join("\n")
  "<ul>#{inner}</ul>"

Handlebars provides the final hash as options.hash. This makes it easier to accept a variable number of parameters, while also accepting an optional Hash. If the template provides no hash arguments, Handlebars will automatically pass an empty object ({}), so you don't need to check for the existance of hash arguments.

Handlebars.registerHelper('list', function(context, options) {
  var attrs = SC.keys(options.hash).map(function(key) {
    key + '="' + options.hash[key] + '"';
  }).join(" ");

  return "<ul " + attrs + ">" + context.map(function(item) {
    return "<li>" + options.fn(item) + "</li>";
  }).join("\n") + "</ul>";
});
``

Hash arguments provide a powerful way to offer a number of optional parameters to a block helper without the complexity caused by positional arguments.

Let’s dissect this: registerHelper takes two arguments: the name of the helper, and the helper function. The helper function takes the argument (i18nKey) and an options hash. It returns a string, which will be safely HTML-escaped by Ember.

To have your helper take optional arguments (e.g. {{t greeting World}}), CoffeeScript splats are very useful:

```coffeescript
Ember.Handlebars.registerHelper 't', (i18nKey, args..., options) ->
  Ember.String.loc(i18nKey, args)

Helper options can be accessed through options.hash, e.g. options.hash.lang for {{t greeting lang="en"}}

Ember.Handlebars.registerHelper "cancel", (text, options) ->
  ember_assert "The cancel helper only takes a single argument", arguments.length <= 2

  unless options
    options = text
    unless options.hash.text
      text = Ember.FormBuilder.STRINGS?[@objectName]?.cancel or 'Cancel'

  options.hash.preserveContext = false
  options.hash.form = this
  options.hash.text = text

  Ember.Handlebars.helpers.view.call this, 'Ember.FormBuilder.Cancel', options

Looks like this generic helper could be VERY useful :)

// Register a Handlebars helper that instantiates `view`.
// The view will have its `content` property bound to the
// helper argument.
App.registerViewHelper = function(name, view) {
  Ember.Handlebars.registerHelper(name, function(property, options) {
    options.hash.contentBinding = property;
    return Ember.Handlebars.helpers.view.call(this, view, options);
  });
};

And this one:

// Return a view that formats `content` through the function `fn`.
inlineFormatter = function(fn) {
  return Ember.View.extend({
    tagName: 'span',

    template: Ember.Handlebars.compile('{{view.formattedContent}}'),

    formattedContent: (function() {
      if (this.get('content') != null) {
        return fn(this.get('content'));
      }
    }).property('content')
  });
};

Now, for example, register a {{capitalize}} helper like this:

App.registerViewHelper('capitalize', inlineFormatter(function(content) {
  return content.charAt(0).toUpperCase() + content.slice(1);
}));

WOW!!!

We need to add some nice Bootstrap helpers to wrap all these views!!!

Usage

Bootstrap.Button

Button class automatically provides necessary classes (.btn) and binds type property to class (for example .btn-info for info type) and if button is disabled disabled class.

<script type="text/x-handlebars">
  {{view Bootstrap.Button type=info disabled=true}}Hello{{/view}}
</script>

Bootstrap.ModalPane

Bootstrap.ModalPane.popup({
  heading: "Sample modal pane",
  message: "Sample message...",
  primary: "OK",
  secondary: "Cancel",
  showBackdrop: true,
  callback: function(opts, event) {
    if (opts.primary) {
     // primary button was pressed
    } else if (opts.secondary) {
      // secondary button was pressed
    } else {
      // close was pressed
    }
  }
});

Bootstrap.NavList

<script type="text/x-handlebars">
  {{view Bootstrap.NavList
      contentBinding="SampleApp.navController.content"
      selectionBinding="SampleApp.navController.selection"}}
</script>

Bootstrap.Tabs

<script type="text/x-handlebars">
  {{view Bootstrap.Tabs
      contentBinding="SampleApp.tabsController.content"
      selectionBinding="SampleApp.tabsController.selection"}}
</script>

Bootstrap.Pills

<script type="text/x-handlebars">
  {{view Bootstrap.Pills
      contentBinding="SampleApp.pillsController.content"
      selectionBinding="SampleApp.pillsController.selection"}}
</script>

Bootstrap.AlertMessage

<script type="text/x-handlebars">
  {{view Bootstrap.AlertMessage type="success" message="You did it!"}}
</script>

Bootstrap.ProgressBar

<script type="text/x-handlebars">
  {{view Bootstrap.ProgressBar isStriped=true isAnimated=true 
      progressBinding="SampleApp.progressController.progress"}}
</script>

Bootstrap.Label

<script type="text/x-handlebars">
  {{view Bootstrap.Label type="important" content="Important"}}
</script>

Bootstrap.Badge

<script type="text/x-handlebars">
  {{view Bootstrap.Badge type="success" contentBinding="SampleApp.TodoController.completed"}}
</script>

Bootstrap.Well

<script type="text/x-handlebars">
  {{view Bootstrap.Well content="Important note about Ember and Bootstrap" }}
</script>

Bootstrap.Breadcrumbs

<script type="text/x-handlebars">
  {{view Bootstrap.Breadcrumbs contentBinding="SampleApp.breadcrumbsController.content" }}
</script>

Bootstrap.Pager

<script type="text/x-handlebars">
  {{view Bootstrap.Pager contentBinding="SampleApp.pagerController.content" }}
</script>

Bootstrap.Pagination

<script type="text/x-handlebars">
  {{view Bootstrap.Pagination contentBinding="SampleApp.paginationController.content" selectionBinding="SampleApp.paginationController.selection" }}
</script>

Bootstrap.Forms.TextField

<script type="text/x-handlebars">
  {{view EmBootstrap.TextField valueBinding="myObject.content" label="content"}}
</script>

Bootstrap.Forms.TextArea

<script type="text/x-handlebars">
  {{view EmBootstrap.TextArea valueBinding="myObject.content" label="content"}}
</script>

Bootstrap.Forms.Actions

<script type="text/x-handlebars">
{{view Bootstrap.Forms.Actions contentBinding="SampleApp.myFormController.actions" }}
</script>

Bootstrap.Forms.Checkbox

TODO: Needs fix.

<script type="text/x-handlebars">
{{view Bootstrap.Forms.Checkbox valueBinding="myObject.content" content="content" }}
</script>

Bootstrap.Forms.Radio

TODO: Needs fix.

<script type="text/x-handlebars">
{{view Bootstrap.Forms.Radio valueBinding="myObject.content" label="content" }}
</script>

Bootstrap.Form

<script type="text/x-handlebars">
{{view Bootstrap.Form type="inline" contentBinding="inlineForm" }}
</script>

Bootstrap.Forms.SearchQuery

<script type="text/x-handlebars">
{{view Bootstrap.SearchQuery contentBinding="queryField" }}
</script>

Bootstrap.Address

<script type="text/x-handlebars">
{{view Bootstrap.Address adrItemsBinding="content.items" title="content.title"}}
</script>

Bootstrap.HelpTxt

<script type="text/x-handlebars">
{{view Bootstrap.HelpTxt type="inline" content="Type your name"}}
</script>

Bootstrap.Table

<script type="text/x-handlebars">
{{view Bootstrap.Table type="striped" contentBinding="myController.tableContent"}}
</script>

Bootstrap.Text

<script type="text/x-handlebars">
{{view Bootstrap.Text type="warn" content="I'm warning you"}}
</script>

Bootstrap.Thumbnails

<script type="text/x-handlebars">
{{view Bootstrap.Thumbnails size="2" contentBinding="thumbnails"}}
</script>

Bootstrap.Thumbnail

<script type="text/x-handlebars">
{{view Bootstrap.Thumbnail size="2" contentBinding="myLittle.thumbnail"}}
</script>

Bootstrap.ImgThumbnail

<script type="text/x-handlebars">
{{view Bootstrap.ImgThumbnail size="2" contentBinding="myLittle.imgThumbnail"}}
</script>

Topbar

Sample Topbar HTML

<body>
  <div class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
      <div class="container">
        <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
          <span class="icon-bar"></span>
        </button>
        <a class="brand" href="http://twitter.github.io/bootstrap/examples/starter-template.html#">Project name</a>
        <div class="nav-collapse collapse">
          <ul class="nav">
            <li class="active"><a href="http://twitter.github.io/bootstrap/examples/starter-template.html#">Home</a></li>
            <li><a href="http://twitter.github.io/bootstrap/examples/starter-template.html#about">About</a></li>
            <li><a href="http://twitter.github.io/bootstrap/examples/starter-template.html#contact">Contact</a></li>
          </ul>
        </div>
      </div>
    </div>
  </div>
...
</body>

It should be easy to add a form, fx for user login or search ;)

Sticky footer

Taken from the example page

The styling

html,
body {
  height: 100%;
  /* The html and body elements cannot have any padding or margin. */
}

/* Wrapper for page content to push down footer */
#wrap {
  min-height: 100%;
  height: auto !important;
  height: 100%;
  /* Negative indent footer by it's height */
  margin: 0 auto -60px;
}

/* Set the fixed height of the footer here */
#push,
#footer {
  height: 60px;
}
#footer {
  background-color: #f5f5f5;
}

/* Lastly, apply responsive CSS fixes as necessary */
@media (max-width: 767px) {
  #footer {
    margin-left: -20px;
    margin-right: -20px;
    padding-left: 20px;
    padding-right: 20px;
  }
}

And the HTML

<body>
  <div id="wrap">
    <div class="container">
      <div class="page-header">
        <h1>Sticky footer</h1>
      </div>
      <p class="lead">Pin a fixed-height footer to the bottom of the viewport in desktop browsers with this custom HTML and CSS.</p>
      <p>Use <a href="http://twitter.github.io/bootstrap/examples/sticky-footer-navbar.html">the sticky footer</a> with a fixed navbar if need be, too.</p>
    </div>
    <div id="push"></div>
  </div>
  <div id="footer">
    <div class="container">
      <p class="muted credit">Example courtesy <a href="http://martinbean.co.uk/">Martin Bean</a> and <a href="http://ryanfait.com/sticky-footer/">Ryan Fait</a>.</p>
    </div>
  </div>
</body>  

Carousel

See carousel example

    /* Carousel base class */
    .carousel {
      margin-bottom: 60px;
    }

    .carousel .container {
      position: relative;
      z-index: 9;
    }

    .carousel-control {
      height: 80px;
      margin-top: 0;
      font-size: 120px;
      text-shadow: 0 1px 1px rgba(0,0,0,.4);
      background-color: transparent;
      border: 0;
      z-index: 10;
    }

    .carousel .item {
      height: 500px;
    }
    .carousel img {
      position: absolute;
      top: 0;
      left: 0;
      min-width: 100%;
      height: 500px;
    }

    .carousel-caption {
      background-color: transparent;
      position: static;
      max-width: 550px;
      padding: 0 20px;
      margin-top: 200px;
    }
    .carousel-caption h1,
    .carousel-caption .lead {
      margin: 0;
      line-height: 1.25;
      color: #fff;
      text-shadow: 0 1px 1px rgba(0,0,0,.4);
    }
    .carousel-caption .btn {
      margin-top: 10px;
    }

Additionally, the sample carousel contains some responsive styling for larger screen sizes ;)

And here the sample HTML:

<div id="myCarousel" class="carousel slide">
  <div class="carousel-inner">
    <div class="item active">
      <img src="./carousel_files/slide-01.jpg" alt="">
      <div class="container">
        <div class="carousel-caption">
          <h1>Example headline.</h1>
          <p class="lead">Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
          <a class="btn btn-large btn-primary" href="http://twitter.github.io/bootstrap/examples/carousel.html#">Sign up today</a>
        </div>
      </div>
    </div>
    <div class="item">
      <img src="./carousel_files/slide-02.jpg" alt="">
      <div class="container">
        <div class="carousel-caption">
          <h1>Another example headline.</h1>
          <p class="lead">Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
          <a class="btn btn-large btn-primary" href="http://twitter.github.io/bootstrap/examples/carousel.html#">Learn more</a>
        </div>
      </div>
    </div>
    <div class="item">
      <img src="./carousel_files/slide-03.jpg" alt="">
      <div class="container">
        <div class="carousel-caption">
          <h1>One more for good measure.</h1>
          <p class="lead">Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
          <a class="btn btn-large btn-primary" href="http://twitter.github.io/bootstrap/examples/carousel.html#">Browse gallery</a>
        </div>
      </div>
    </div>
  </div>
  <a class="left carousel-control" href="http://twitter.github.io/bootstrap/examples/carousel.html#myCarousel" data-slide="prev">‹</a>
  <a class="right carousel-control" href="http://twitter.github.io/bootstrap/examples/carousel.html#myCarousel" data-slide="next">›</a>
</div>
<script type="text/x-handlebars">
{{view Bootstrap.Carousel contentBinding="myLovely.carousel"}}
</script>
<script type="text/x-handlebars">
{{view Bootstrap.CarouselItem activeBinding="item.active" contentBinding="item.content"}}
</script>

Unit Tests

To run unit tests, run bundle exec rackup from the root directory and visit http://localhost:9292/tests/index.html?package=ember-bootstrap.

License

MIT License. Copyright 2012 Jiri Zajpt, Damien Mathieu, Franck Verrot

Authors & contributors