Skip to content

Instantly share code, notes, and snippets.

@clydet
Created September 2, 2014 05:22
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 clydet/6159866fffcb900a669d to your computer and use it in GitHub Desktop.
Save clydet/6159866fffcb900a669d to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="http://jashkenas.github.io/underscore/underscore-min.js"></script>
<script src="http://jashkenas.github.io/backbone/backbone.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<script id="jsbin-javascript">
var Bounds;
new (Bounds = (function() {
function Bounds(seedArray) {
this.ranges = seedArray;
this.errors = [];
};
Bounds.prototype.updateBoundName = function(index, name) {
this.ranges[index].name = name;
};
Bounds.prototype.adjustBound = function(index, bound, value){
var ranges, error;
ranges = this.getRanges();
if (!value.match(/^(?:0|[1-9][0-9]?|100)$/)){
this.errors.push(value + " is not a valid value (0 - 100)");
return
}
//DRY fix this
if (bound == 'lower'){
if (value > ranges[index].upper){
this.errors.push("lower bound (" + value + ") may not exceed upper bound (" + ranges[index].upper + ")");
} else {
var delta = ranges[index].lower - value;
ranges[index].size += delta;
if(delta >= ranges[index - 1].size){
while(delta > 0){
delta = delta - ranges[--index].size;
if (delta >= 0)
ranges.splice(index, 1);
else
ranges[index].size = Math.abs(delta)
}
} else {
ranges[index - 1].size -= delta;
}
}
} else {
if (value < ranges[index].lower){
this.errors.push("lower bound (" + ranges[index].lower + ") may not exceed upper bound (" + value + ")");
} else {
var delta = value - ranges[index].upper;
ranges[index].size += delta;
if(delta >= ranges[index + 1].size){
index++;
while(delta > 0){
delta = delta - ranges[index].size;
if (delta >= 0)
ranges.splice(index, 1);
else
ranges[index].size = Math.abs(delta)
}
} else {
ranges[index + 1].size -= delta;
}
}
}
this.ranges = _.map(ranges, function(entry) {return {"index": entry.index, "name": entry.name, "size": entry.size}});
};
Bounds.prototype.addBound = function(name){
if (!_.some(this.ranges, function(entry){return entry.size == 0;})){
this.ranges.push({
"index": this.ranges.length,
"name": "New range",
"size": 0
})
}
};
Bounds.prototype.removeBound = function(index){
if (this.ranges.length == 1){
this.ranges[0].name = 'New range'
return;
}
if (index > 0){
this.ranges[index - 1].size += this.ranges[index].size;
} else {
this.ranges[index + 1].size += this.ranges[index].size;
}
this.ranges.splice(index, 1);
};
Bounds.prototype.getRanges = function(){
var ranges = [];
var size = 0;
for (var i = 0; i < this.ranges.length; i++){
ranges.push(_.extend(this.ranges[i], {"lower": size, "upper": (size += this.ranges[i].size)}));
}
return ranges;
};
return Bounds;
})());
(function($){
var RangeView = Backbone.View.extend({
el: $('body'),
events: {
'click button#add': 'addRange',
'click button#save': 'saveRanges',
'click button#reset': 'initialize',
'click button.remove': 'removeRange',
'change input[type="text"]': 'updateName',
'change input[type="number"]': 'updateRanges'
},
initialState: [
{
"index": 0,
"name": "Low",
"size": 34
},
{
"index": 1,
"name": "Medium",
"size": 33
},
{
"index": 2,
"name": "High",
"size": 33
}
],
initialize: function(){
this.bounds = new Bounds(JSON.parse(JSON.stringify(this.initialState)));
this.render();
},
render: function(){
$(this.el).empty()
.append("<button id='add'>Add range</button>")
.append("<button id='save'>Save</button>")
.append("<button id='reset'>Reset</button>")
.append("<div class='errors'/>")
.append("<table><tr><td>Name</td><td>Range</td></tr></table>");
this.displayRanges();
this.displayErrors();
},
addRange: function(){
this.bounds.addBound();
this.render();
},
saveRanges: function(){
var output = JSON.stringify(this.bounds.getRanges());
console.log(output);
},
removeRange: function(e){
var index = $(e.currentTarget).closest('[data-order]').data('order');
this.bounds.removeBound(index);
this.render();
},
updateName: function(e){
var target, index;
target = $(e.currentTarget);
index = target.closest('[data-order]').data('order');
this.bounds.updateBoundName(index, target.val());
},
updateRanges: function(e){
var target, value, bound, index;
target = $(e.currentTarget)
value = target.val()
bound = target.data('bound')
index = target.closest('[data-order]').data('order')
this.bounds.adjustBound(index, bound, value);
this.render();
},
displayRanges: function(){
var ranges = this.bounds.getRanges();
_.each(ranges, function(range){
var disableLower, disableUpper;
disableLower = (range.lower == 0) ? 'readonly' : '';
disableUpper = (range.upper == 100) ? 'readonly' : '';
$('table').append('<tr data-order="' + range.index + '"><td><input type="text" value="' + range.name + '"/></td><td><input data-bound="lower" type="number" step="1" min="0" max="100" value="' + range.lower + '" ' + disableLower + '/><input data-bound="upper" type="number" step="1" min="0" max="100" value="' + range.upper + '" ' + disableUpper + '/><button class="remove">remove</button></td></tr>')
});
},
displayErrors: function(){
var error;
while(this.bounds.errors.length > 0) {
error = this.bounds.errors.pop();
$('.errors').append(error).append('<br/>');
}
}
});
var rangeView = new RangeView();
})(jQuery);
</script>
<script id="jsbin-source-html" type="text/html"><!DOCTYPE html>
<html>
<head>
<script src="//code.jquery.com/jquery-2.1.1.min.js"><\/script>
<script src="//jashkenas.github.io/underscore/underscore-min.js"><\/script>
<script src="//jashkenas.github.io/backbone/backbone.js"><\/script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
</body>
</html></script>
<script id="jsbin-source-javascript" type="text/javascript">var Bounds;
new (Bounds = (function() {
function Bounds(seedArray) {
this.ranges = seedArray;
this.errors = [];
};
Bounds.prototype.updateBoundName = function(index, name) {
this.ranges[index].name = name;
};
Bounds.prototype.adjustBound = function(index, bound, value){
var ranges, error;
ranges = this.getRanges();
if (!value.match(/^(?:0|[1-9][0-9]?|100)$/)){
this.errors.push(value + " is not a valid value (0 - 100)");
return
}
//DRY fix this
if (bound == 'lower'){
if (value > ranges[index].upper){
this.errors.push("lower bound (" + value + ") may not exceed upper bound (" + ranges[index].upper + ")");
} else {
var delta = ranges[index].lower - value;
ranges[index].size += delta;
if(delta >= ranges[index - 1].size){
while(delta > 0){
delta = delta - ranges[--index].size;
if (delta >= 0)
ranges.splice(index, 1);
else
ranges[index].size = Math.abs(delta)
}
} else {
ranges[index - 1].size -= delta;
}
}
} else {
if (value < ranges[index].lower){
this.errors.push("lower bound (" + ranges[index].lower + ") may not exceed upper bound (" + value + ")");
} else {
var delta = value - ranges[index].upper;
ranges[index].size += delta;
if(delta >= ranges[index + 1].size){
index++;
while(delta > 0){
delta = delta - ranges[index].size;
if (delta >= 0)
ranges.splice(index, 1);
else
ranges[index].size = Math.abs(delta)
}
} else {
ranges[index + 1].size -= delta;
}
}
}
this.ranges = _.map(ranges, function(entry) {return {"index": entry.index, "name": entry.name, "size": entry.size}});
};
Bounds.prototype.addBound = function(name){
if (!_.some(this.ranges, function(entry){return entry.size == 0;})){
this.ranges.push({
"index": this.ranges.length,
"name": "New range",
"size": 0
})
}
};
Bounds.prototype.removeBound = function(index){
if (this.ranges.length == 1){
this.ranges[0].name = 'New range'
return;
}
if (index > 0){
this.ranges[index - 1].size += this.ranges[index].size;
} else {
this.ranges[index + 1].size += this.ranges[index].size;
}
this.ranges.splice(index, 1);
};
Bounds.prototype.getRanges = function(){
var ranges = [];
var size = 0;
for (var i = 0; i < this.ranges.length; i++){
ranges.push(_.extend(this.ranges[i], {"lower": size, "upper": (size += this.ranges[i].size)}));
}
return ranges;
};
return Bounds;
})());
(function($){
var RangeView = Backbone.View.extend({
el: $('body'),
events: {
'click button#add': 'addRange',
'click button#save': 'saveRanges',
'click button#reset': 'initialize',
'click button.remove': 'removeRange',
'change input[type="text"]': 'updateName',
'change input[type="number"]': 'updateRanges'
},
initialState: [
{
"index": 0,
"name": "Low",
"size": 34
},
{
"index": 1,
"name": "Medium",
"size": 33
},
{
"index": 2,
"name": "High",
"size": 33
}
],
initialize: function(){
this.bounds = new Bounds(JSON.parse(JSON.stringify(this.initialState)));
this.render();
},
render: function(){
$(this.el).empty()
.append("<button id='add'>Add range</button>")
.append("<button id='save'>Save</button>")
.append("<button id='reset'>Reset</button>")
.append("<div class='errors'/>")
.append("<table><tr><td>Name</td><td>Range</td></tr></table>");
this.displayRanges();
this.displayErrors();
},
addRange: function(){
this.bounds.addBound();
this.render();
},
saveRanges: function(){
var output = JSON.stringify(this.bounds.getRanges());
console.log(output);
},
removeRange: function(e){
var index = $(e.currentTarget).closest('[data-order]').data('order');
this.bounds.removeBound(index);
this.render();
},
updateName: function(e){
var target, index;
target = $(e.currentTarget);
index = target.closest('[data-order]').data('order');
this.bounds.updateBoundName(index, target.val());
},
updateRanges: function(e){
var target, value, bound, index;
target = $(e.currentTarget)
value = target.val()
bound = target.data('bound')
index = target.closest('[data-order]').data('order')
this.bounds.adjustBound(index, bound, value);
this.render();
},
displayRanges: function(){
var ranges = this.bounds.getRanges();
_.each(ranges, function(range){
var disableLower, disableUpper;
disableLower = (range.lower == 0) ? 'readonly' : '';
disableUpper = (range.upper == 100) ? 'readonly' : '';
$('table').append('<tr data-order="' + range.index + '"><td><input type="text" value="' + range.name + '"/></td><td><input data-bound="lower" type="number" step="1" min="0" max="100" value="' + range.lower + '" ' + disableLower + '/><input data-bound="upper" type="number" step="1" min="0" max="100" value="' + range.upper + '" ' + disableUpper + '/><button class="remove">remove</button></td></tr>')
});
},
displayErrors: function(){
var error;
while(this.bounds.errors.length > 0) {
error = this.bounds.errors.pop();
$('.errors').append(error).append('<br/>');
}
}
});
var rangeView = new RangeView();
})(jQuery);</script></body>
</html>
var Bounds;
new (Bounds = (function() {
function Bounds(seedArray) {
this.ranges = seedArray;
this.errors = [];
};
Bounds.prototype.updateBoundName = function(index, name) {
this.ranges[index].name = name;
};
Bounds.prototype.adjustBound = function(index, bound, value){
var ranges, error;
ranges = this.getRanges();
if (!value.match(/^(?:0|[1-9][0-9]?|100)$/)){
this.errors.push(value + " is not a valid value (0 - 100)");
return
}
//DRY fix this
if (bound == 'lower'){
if (value > ranges[index].upper){
this.errors.push("lower bound (" + value + ") may not exceed upper bound (" + ranges[index].upper + ")");
} else {
var delta = ranges[index].lower - value;
ranges[index].size += delta;
if(delta >= ranges[index - 1].size){
while(delta > 0){
delta = delta - ranges[--index].size;
if (delta >= 0)
ranges.splice(index, 1);
else
ranges[index].size = Math.abs(delta)
}
} else {
ranges[index - 1].size -= delta;
}
}
} else {
if (value < ranges[index].lower){
this.errors.push("lower bound (" + ranges[index].lower + ") may not exceed upper bound (" + value + ")");
} else {
var delta = value - ranges[index].upper;
ranges[index].size += delta;
if(delta >= ranges[index + 1].size){
index++;
while(delta > 0){
delta = delta - ranges[index].size;
if (delta >= 0)
ranges.splice(index, 1);
else
ranges[index].size = Math.abs(delta)
}
} else {
ranges[index + 1].size -= delta;
}
}
}
this.ranges = _.map(ranges, function(entry) {return {"index": entry.index, "name": entry.name, "size": entry.size}});
};
Bounds.prototype.addBound = function(name){
if (!_.some(this.ranges, function(entry){return entry.size == 0;})){
this.ranges.push({
"index": this.ranges.length,
"name": "New range",
"size": 0
})
}
};
Bounds.prototype.removeBound = function(index){
if (this.ranges.length == 1){
this.ranges[0].name = 'New range'
return;
}
if (index > 0){
this.ranges[index - 1].size += this.ranges[index].size;
} else {
this.ranges[index + 1].size += this.ranges[index].size;
}
this.ranges.splice(index, 1);
};
Bounds.prototype.getRanges = function(){
var ranges = [];
var size = 0;
for (var i = 0; i < this.ranges.length; i++){
ranges.push(_.extend(this.ranges[i], {"lower": size, "upper": (size += this.ranges[i].size)}));
}
return ranges;
};
return Bounds;
})());
(function($){
var RangeView = Backbone.View.extend({
el: $('body'),
events: {
'click button#add': 'addRange',
'click button#save': 'saveRanges',
'click button#reset': 'initialize',
'click button.remove': 'removeRange',
'change input[type="text"]': 'updateName',
'change input[type="number"]': 'updateRanges'
},
initialState: [
{
"index": 0,
"name": "Low",
"size": 34
},
{
"index": 1,
"name": "Medium",
"size": 33
},
{
"index": 2,
"name": "High",
"size": 33
}
],
initialize: function(){
this.bounds = new Bounds(JSON.parse(JSON.stringify(this.initialState)));
this.render();
},
render: function(){
$(this.el).empty()
.append("<button id='add'>Add range</button>")
.append("<button id='save'>Save</button>")
.append("<button id='reset'>Reset</button>")
.append("<div class='errors'/>")
.append("<table><tr><td>Name</td><td>Range</td></tr></table>");
this.displayRanges();
this.displayErrors();
},
addRange: function(){
this.bounds.addBound();
this.render();
},
saveRanges: function(){
var output = JSON.stringify(this.bounds.getRanges());
console.log(output);
},
removeRange: function(e){
var index = $(e.currentTarget).closest('[data-order]').data('order');
this.bounds.removeBound(index);
this.render();
},
updateName: function(e){
var target, index;
target = $(e.currentTarget);
index = target.closest('[data-order]').data('order');
this.bounds.updateBoundName(index, target.val());
},
updateRanges: function(e){
var target, value, bound, index;
target = $(e.currentTarget)
value = target.val()
bound = target.data('bound')
index = target.closest('[data-order]').data('order')
this.bounds.adjustBound(index, bound, value);
this.render();
},
displayRanges: function(){
var ranges = this.bounds.getRanges();
_.each(ranges, function(range){
var disableLower, disableUpper;
disableLower = (range.lower == 0) ? 'readonly' : '';
disableUpper = (range.upper == 100) ? 'readonly' : '';
$('table').append('<tr data-order="' + range.index + '"><td><input type="text" value="' + range.name + '"/></td><td><input data-bound="lower" type="number" step="1" min="0" max="100" value="' + range.lower + '" ' + disableLower + '/><input data-bound="upper" type="number" step="1" min="0" max="100" value="' + range.upper + '" ' + disableUpper + '/><button class="remove">remove</button></td></tr>')
});
},
displayErrors: function(){
var error;
while(this.bounds.errors.length > 0) {
error = this.bounds.errors.pop();
$('.errors').append(error).append('<br/>');
}
}
});
var rangeView = new RangeView();
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment