TomsterMail
The latest build of Ember.
by alexspeller
HTML
<script src="http://ember.alexspeller.com/handlebars-1.0.0.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.1.0/moment.min.js"></script>
<script src="http://ember.alexspeller.com/ember-latest.js"></script>
<script type="text/x-handlebars" data-template-name="application">
<div class='url'>URL: {{target.url}}</div>
<aside>
<ul>
<li><h2>Mailboxes</h2></li>
{{#each}}
<li>
{{#linkTo 'mailbox' this}}
<span class="count">
{{messages.length}}
</span>
{{name}}
{{/linkTo}}
</li>
{{/each}}
</ul>
</aside>
<section class='main'>
{{outlet}}
</section>
</script>
<script type="text/x-handlebars" data-template-name="index">
<section class="index">
<h1>TomsterMail</h1>
<span class='tomster'></span>
</section>
</script>
<script type="text/x-handlebars" data-template-name="mailbox">
<div class='filterbar'>
{{view App.FilterView valueBinding=filter}}
</div>
<table>
<tr>
{{#linkTo "mailbox" this sort="date" tagName="th"}}Date{{/linkTo}}
{{#linkTo "mailbox" this sort="subject" tagName="th"}}Subject{{/linkTo}}
{{#linkTo "mailbox" this sort="from" tagName="th"}}From{{/linkTo}}
{{#linkTo "mailbox" this sort="to" tagName="th"}}To{{/linkTo}}
</tr>
{{#each arrangedContent}}
{{#linkTo 'mail' this tagName=tr}}
<td>{{date date}}</td>
<td>{{view.isActive}}{{subject}}</td>
<td>{{from}}</td>
<td>{{to}}</td>
{{/linkTo}}
{{/each}}
</table>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="mailbox/index">
<section class="mailbox-index">
Select an email
...
CSS
body {
font-family: sans-serif;
color: #333;
}
h1 {
font-size: 2em;
margin-bottom: 1em;
}
h2 {
margin-bottom: 1em;
}
h4 {
font-size: 1.5em;
margin-bottom: 1em;
font-weight: bold;
}
.loading {
position: absolute;
top: 50%;
bottom: 50%;
left: 50%;
right: 50%;
width: 100px;
height: 50px;
color: white;
background-color: rgba(0,0,0,0.5);
margin-left: -50px;
margin-top: -25px;
border-radius: 10px;
text-align: center;
line-height: 50px;
}
aside {
float: left;
background-color: #9cb5d1;
width: 180px;
height: 430px;
border: 1px solid #ccc;
border-right-color: #333;
}
aside h2 {
text-transform: uppercase;
font-size: 0.7em;
font-weight: bold;
letter-spacing: 0.2em;
text-shadow: 1px 1px 0px #eee;
padding: 15px;
margin-bottom: 0;
}
aside a {
color: #333;
text-decoration: none;
display: block;
padding: 15px;
}
aside a.active {
background: linear-gradient(to bottom, #7db9e8 0%,#267dc9 99%);
color: white;
text-shadow: 1px 1px 0px #666;
}
span.count {
float: right;
background-color: #505f71;
color: white;
padding: 0.5em 1em;
border-radius: 40%;
font-size: 0.6em;
position: relative;
top: -3px;
font-weight: bold;
}
section.main {
height: 430px;
border: 1px solid #ccc;
margin-left: 180px;
}
section .index {
padding-top: 5em;
text-align: center;
height: 100%;
}
table {
width: 99%;
border-bottom: 1px solid #999;
border-collapse: collapse;
}
td, th {
padding: 0.5em;
}
th {
font-weight: bold;
font-size: 0.8em;
}
th.active:after {
content: " ▲";
}
th.active.desc:after {
content: " ▼";
}
tr {
border-bottom: 1px solid #ccc;
cursor: pointer;
}
td a {
text-decoration: none;
color: #333;
}
tr.active {
background: linear-gradient(to bottom, #7db9e8 0%,#267dc9 99%);
color: white;
text-shadow: 1px 1px 0px #666;
}
section .mailbox-index {
padding-top: 5em;
text-align: center;
color: #eee;
font-style: italic;
}
section...
CoffeeScript
Ember.FEATURES['query-params'] = true
window.App = Ember.Application.create
LOG_TRANSITIONS: true
#############
# Route Map #
#############
App.Router.map ->
@resource 'mailbox', path: '/:id', queryParams: ['sort', 'filter'], ->
@resource 'mail', path: '/:index'
#####################
# Route definitions #
#####################
App.ApplicationRoute = Em.Route.extend
model: ->
Mailbox.find()
App.MailboxRoute = Em.Route.extend
model: (params) ->
Mailbox.find params.id
serialize: (mailbox) ->
id: mailbox.id
setupController: (controller, context, queryParams) ->
@_super controller, context
controller.set 'sort', queryParams.sort
controller.set 'filter', queryParams.filter
App.MailRoute = Em.Route.extend
model: (params) ->
@modelFor('mailbox').messages[params.index]
serialize: (mail) ->
index: @modelFor('mailbox').messages.indexOf(mail)
# Just defining a route called LoadingRoute is enough to make ember
# enter this route when a promise is returned from any routes 'model'
# hook. The 'loading' template will be rendered in the application
# outlet with the LoadingView view #by default, although this can
# be overriden with the renderTemplate hook if desired
App.LoadingRoute = Em.Route.extend()
###############
# Controllers #
###############
App.MailboxController = Em.ObjectController.extend
arrangedContent: (->
if Em.isEmpty @get('filter')
filtered = @get('messages') || []
else
filtered = (@get('messages') || []).filter (message) =>
new RegExp(RegExp.quote(@get('filter').toLowerCase())).test(message.subject.toLowerCase())
Em.ArrayProxy.create content: (filtered).sort (a, b) =>
if a[@get('sort')] < b[@get('sort')] then -1
else if a[@get('sort')] > b[@get('sort')] then 1
else 0
).property 'messages.[]', 'sort', 'filter'
filterDidChange: (->
Em.run.debounce @, 'transitionFilter', 500
).observes 'filter'
transitionFilter: ->
string =...