Skip to content

Instantly share code, notes, and snippets.

@alisdair
Last active April 24, 2016 13:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alisdair/c6ed5222d5fbe42507599e48bfe1946b to your computer and use it in GitHub Desktop.
Save alisdair/c6ed5222d5fbe42507599e48bfe1946b to your computer and use it in GitHub Desktop.
Allocations
import Ember from 'ember';
function clamp(min, max, number) {
return Math.min(Math.max(number, min), max);
}
const clampPercent = clamp.bind(undefined, 0, 100);
export default Ember.Controller.extend({
appName: 'Ember Twiddle',
init() {
this.set('allocations', [
Ember.Object.create({
label: 'A',
value: 65
}), Ember.Object.create({
label: 'B',
value: 35
})
]);
},
canAdd: Ember.computed.lt('allocations.length', 8),
validSum: Ember.computed.equal('allocationSum', 100),
allocationValues: Ember.computed('allocations.@each.value', function() {
return this.get('allocations').map(a => parseInt(a.get('value')));
}),
allocationSum: Ember.computed.sum('allocationValues'),
actions: {
addAllocation() {
let allocations = this.get('allocations');
let last = allocations.get('lastObject');
let next = Ember.Object.create({
label: String.fromCharCode(last.label.charCodeAt(0) + 1),
value: last.get('value')
});
allocations.pushObject(next);
this.send('fixAllocations');
},
removeAllocation(allocation) {
this.get('allocations').removeObject(allocation);
this.send('fixAllocations');
},
fixAllocations() {
let allocations = this.get('allocations');
let adjust = 100 / this.get('allocationSum');
allocations.forEach(a => {
a.set('value', Math.round(a.get('value') * adjust))
});
let sum = this.get('allocationSum');
if (sum !== 100) {
let delta = 100 - sum;
let [a] = allocations;
a.set('value', a.get('value') + delta);
}
},
changeAllocation(index, event) {
let value = clampPercent(event.target.value);
let allocations = this.get('allocations');
Ember.set(allocations[index], 'value', value);
if (allocations.length === 2) {
Ember.set(allocations[(index + 1) % 2], 'value', 100 - value);
}
}
}
});
import Ember from 'ember';
export function and(params/*, hash*/) {
return params.every(param => !!param);
}
export default Ember.Helper.helper(and);
import Ember from 'ember';
export function equal(params/*, hash*/) {
return params[0] === params[1];
}
export default Ember.Helper.helper(equal);
import Ember from 'ember';
export function gt(params/*, hash*/) {
return params[0] > params[1];
}
export default Ember.Helper.helper(gt);
import Ember from 'ember';
export function subtract(params/*, hash*/) {
return params[0] - params[1];
}
export default Ember.Helper.helper(subtract);
* {
box-sizing: border-box;
}
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 16px;
}
.label {
background: #999;
border-radius: 5px;
color: white;
padding: 0.5rem;
text-align: center;
}
:nth-child(1) > .label {
background: #F44336;
}
:nth-child(2) > .label {
background: #0288D1;
}
:nth-child(3) > .label {
background: #FF9800;
}
:nth-child(4) > .label {
background: #4CAF50;
}
:nth-child(5) > .label {
background: #FF78A6;
}
:nth-child(6) > .label {
background: #00BCD4;
}
:nth-child(7) > .label {
background: #673AB7;
}
:nth-child(8) > .label {
background: #795548;
}
.mrg-h-sm {
margin-left: 8px;
margin-right: 8px;
}
.mrg-v-sm {
margin-top: 8px;
margin-bottom: 8px;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.text-error {
color: #d22;
}
.w-1 {
width: 2rem;
}
.w-3 {
width: 3.5rem;
}
.w-12 {
width: 20rem;
}
.btn {
background: #eee;
border: 2px solid #ccc;
border-radius: 2px;
color: #222;
cursor: pointer;
font-size: 1rem;
padding: .5rem 1rem;
text-decoration: none;
text-align: center;
}
.btn:hover, .btn:focus, .btn:active {
background: #ddd;
}
.btn-blue {
background: #3ae;
border-color: #29e;
color: white;
}
.btn-blue:hover, .btn-blue:focus, .btn-blue:active {
background-color: #18c;
}
.btn-green {
background: #2a7;
border-color: #2b8;
color: white;
}
.btn-green:hover, .btn-green:focus, .btn-green:active {
background-color: #186;
}
input {
border: thin solid #ccc;
font-size: 1rem;
padding: .5rem;
width: 100%;
}
input[type=range] {
border: none;
padding-left: 0;
padding-right: 0;
margin: 0;
}
.flex {
display: flex;
align-items: center;
}
.flex > * {
flex-shrink: 0;
}
{{#each allocations as |allocation i|}}
<div class="flex mrg-v-sm">
<span class="w-1 label">{{allocation.label}}</span>
<div class="w-12 mrg-h-sm">
{{input
type="range"
min=0
max=100
tabindex=1
value=allocation.value
input=(action "changeAllocation" i)}}
</div>
<div class="w-3">
{{input
type="number"
min=0
max=100
tabindex=2
value=allocation.value
input=(action "changeAllocation" i)}}
</div>
{{#if (and (gt i 1) (equal i (subtract allocations.length 1)))}}
<div class="w-3 mrg-h-sm">
<button class="btn" {{action "removeAllocation" allocation}}>
</button>
</div>
{{/if}}
</div>
{{/each}}
<div class="flex mrg-v-sm">
<div class="w-1"></div>
<div class="w-12 mrg-h-sm text-right">Total:</div>
<div class="w-3 text-center {{unless validSum "text-error"}}">
{{allocationSum}}%
</div>
<div class="mrg-h-sm">
{{#unless validSum}}
<button class="btn btn-green" {{action "fixAllocations"}}>
Fix?
</button>
{{else if canAdd}}
<button class="btn btn-blue" {{action "addAllocation"}}>
Add
</button>
{{/unless}}
</div>
</div>
{
"version": "0.7.2",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.4.4/ember.debug.js",
"ember-data": "https://cdnjs.cloudflare.com/ajax/libs/ember-data.js/2.4.3/ember-data.js",
"ember-template-compiler": "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.4.4/ember-template-compiler.js"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment