Skip to content

Instantly share code, notes, and snippets.

@junyper
Created March 17, 2014 02:37
Show Gist options
  • Save junyper/9593039 to your computer and use it in GitHub Desktop.
Save junyper/9593039 to your computer and use it in GitHub Desktop.
App = Ember.Application.create()
App.Router.map ->
@route 'standards-list',
path: '/'
###### Routes #########
App.StandardsListRoute = Ember.Route.extend
model: ->
window.ENV.map (item) ->
standard = item.grading_standard
App.Standard.create
title: standard.title
grades: standard.data.map (data) ->
App.Grade.create
label: data[0]
value: data[1]
####### Models ######
App.Standard = Ember.Object.extend
title: null
ranges: null
selected: false #TODO: this seems like it belongs in the controller, but the ArrayController doesn't seem to be able to set controller properties.
App.Grade = Ember.Object.extend
label: null
value: 0
#TODO: these seem like they belong in the controller, but the ArrayController doesn't seem to be able to set controller properties.
min: -1
max: 1
color: 'transparent'
editable: false
####### Controllers #######
App.StandardsListController = Ember.ArrayController.extend
actions:
remove: (standard) ->
# TODO: ic-ajax
@removeObject(standard)
edit: (standard) ->
editable = @findBy 'editable', true
if editable? then editable.set 'editable', false
standard.set 'editable', true
add: ->
newStandard = App.Standard.create
title: 'New Standard'
grades: Ember.A [
App.Grade.create
selected: true
editable: true
value: .5
label: 'Pass'
App.Grade.create
editable: true
value: 0
label: 'Fail'
]
@addObject newStandard
@send 'edit', newStandard
App.StandardController = Ember.ObjectController.extend
setEditable: (->
@get('grades').setEach 'editable', @get('editable')
).observes('editable')
actions:
save: ->
# TODO: ic-ajax then:
@set('editable', false)
App.GradesListController = Ember.ArrayController.extend
updateGrades: ( ->
grades = @get('content')
@forEach (grade, index) ->
grade.setProperties
max: if grades[index-1]? then grades[index-1].get('value') else 1
min: if grades[index+1]? then grades[index+1].get('value') else -1
).on('init').observes('content', '@each.value')
updateColors: ( ->
length = @get('length')
@forEach (grade, i) ->
grade.set 'color', $.Color(
hue: 120 - (i/(length-1) * 120)
saturation: .7
lightness: .8
).toRgbaString()
).on('init').observes('length')
actions:
remove: (grade) ->
@removeObject(grade)
add: ->
newGrade = App.Grade.create
label: 'New'
value: .01
editable: true
@replaceContent @get('length')-1, 0, [newGrade]
@send 'select', newGrade
select: (grade) ->
selected = @findBy 'selected', true
if selected? then selected.set 'selected', false
grade.set 'selected', true
App.GradeController = Ember.ObjectController.extend
setSelected: (->
if not @get('editable') then @set 'selected', false
).observes('editable')
colorStyle: (->
"background-color: #{@get('color')}"
).property('color').readOnly()
readOnlyValue: (->
@get('min') == -1 or !@get('selected')
).property('min', 'selected').readOnly()
deleteable: (->
@get('min') > -1
).property('min').readOnly()
isValid: (-> # TODO: validate label
value = @get('value')
min = @get('min')
max = @get('max')
(min < value < max) or @get('min') == -1
).property('value', 'min', 'max').readOnly()
maxPercentage: (->
@get('max') * 100
).property('max').readOnly()
minPercentage: (->
@get('min') * 100
).property('min').readOnly()
percentage: ((key, value) ->
if arguments.length > 1
@set 'value', value/100
@get('value') * 100
).property('value')
######## Views #######
App.GradeView = Ember.View.extend
classNames: ['gs-grade']
tagName: 'tr'
classNameBindings: ['controller.isValid::error']
attributeBindings: ['tabindex']
tabindex: (->
-1 if @get('controller').get('editable')
).property('controller.editable')
focusIn: (evt) ->
controller = @get('controller')
controller.send 'select', controller
######## Components #######
App.FocusedInputComponent = Ember.TextField.extend
initFocus: (->
Ember.run.scheduleOnce 'afterRender', =>
@$()?.focus()
).on('didInsertElement')
Ember.Handlebars.helper 'focused-input', App.FocusedInputComponent
App.SpinnerInputComponent = Ember.TextField.extend
classNames: ['spinner-input']
initSpinner: (->
Ember.run.scheduleOnce 'afterRender', =>
@$()?.spinner @get('spinnerOptions')
).on('didInsertElement').observes('spinnerOptions')
spinnerOptions: (->
max: @get('max')
min: @get('min')
mouseWheel: false
).property('max', 'min')
Ember.Handlebars.helper 'spinner-input', App.SpinnerInputComponent
body {
padding: 20px;
}
.gs-btns {
float: right;
}
.gs-label {
min-width: 60px;
padding: 5px;
display: inline-block;
border-radius: 3px;
font-weight: bold;
text-align: center;
}
.gs-standard {
max-width: 400px;
border-top: 1px solid #eee;
margin: 40px 0;
padding: 10px;
}
.gs-standard-title {
font-weight: bold;
}
.gs-standard-editable {
background-color: #f4f8fa;
border-radius: 3px;
border-top: 0;
}
.gs-standard-editable .gs-grade:hover {
cursor: pointer;
}
.gs-standard input {
margin: 0;
}
.gs-value input {
width: 50px;
font-size: 1em;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Grading Standards</title>
<link href="http://getbootstrap.com/2.3.2/assets/css/bootstrap.css" rel="stylesheet" type="text/css" />
<link href="http://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.min.css" rel="stylesheet" type="text/css" />
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.min.js"></script>
<script src="http://code.jquery.com/color/jquery.color-2.1.0.min.js"></script>
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.2.1.js"></script>
<script src="http://builds.emberjs.com/tags/v1.4.0/ember.js"></script>
</head>
<body>
<script type="text/x-handlebars" data-template-name="standards-list">
<h2>Grading Standards</h2>
{{#each standard in model}}
{{ render "standard" standard }}
{{/each}}
<button {{ action "add" }} class="btn btn-default">
Add a Standard
</button>
</script>
<script type="text/x-handlebars" data-template-name="standard">
<section {{ bind-attr class=":gs-standard editable:gs-standard-editable:" }}>
<header>
{{#if editable}}
{{ focused-input value=title class="gs-standard-title"}}
{{else}}
<div class="gs-btns">
<button {{ action "edit" this }} class="btn btn-sm">
<i class="icon-edit"></i>
</button>
<button {{ action "remove" this }} class="btn btn-sm">
<i class="icon-trash"></i>
</button>
</div>
<h3>{{title}}</h3>
{{/if}}
</header>
<table {{ bind-attr class=":table :table-striped editable:table-hover:" }}>
<thead>
<tr>
<th>Grade</th>
<th>Minimum %</th>
{{#if editable}}
<th></th>
{{/if}}
</tr>
</thead>
{{ render "grades-list" grades }}
</table>
<footer>
{{#if editable}}
<button {{ action "save" }} class="btn btn-primary btn-large">
Save Standard
</button>
{{/if}}
</footer>
</section>
</script>
<script type="text/x-handlebars" data-template-name="grades-list">
{{#each grade in model}}
{{ render "grade" grade }}
{{/each}}
</script>
<script type="text/x-handlebars" data-template-name="grade">
<td>
<span class="gs-label" {{ bind-attr style=colorStyle }}>
{{#if selected}}
{{ focused-input value=label }}
{{else}}
{{label}}
{{/if}}
</span>
</td>
<td class="gs-value">
{{#unless readOnlyValue}}
{{spinner-input value=percentage min=minPercentage max=maxPercentage}}
{{else}}
{{percentage}}
{{/unless}}
</td>
{{#if editable}}
<td class="gs-grade-btns">
{{#if deleteable}}
<button {{ action "remove" this }} class="btn btn-sm" title="Remove this grade">
<i class="icon-trash"></i>
</button>
{{else}}
<button {{ action "add" bubbles=false }} class="btn btn-sm" title="Add a grade">
<i class="icon-plus"></i>
</button>
{{/if}}
</td>
{{/if}}
</script>
<script>ENV = [
{
"grading_standard": {
"data": [
[
"A",
0.925
],
[
"A-",
0.91
],
[
"B+",
0.875
],
[
"B",
0.823
],
[
"B-",
0.8
],
[
"C+",
0.778
],
[
"C",
0.74
],
[
"C-",
0.7
],
[
"D+",
0.67
],
[
"D",
0.64
],
[
"D-",
0.61
],
[
"F",
0
]
],
"title": "Lorem Ipsum Standard"
}
},
{
"grading_standard": {
"data": [
[
"4.0",
0.75
],
[
"3.0",
0.01
],
[
"M",
0
]
],
"title": "GPA 2"
}
}
];</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment