Bootstrap buttons for spa
Bootstrap 2.3.2
Knockout 3.0.0rc
HTML
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-3.0.0rc.js"></script>
<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="#">Button samples</a>
<!--/.nav-collapse -->
</div>
</div>
</div>
<h3>Samples</h3>
<hr/>
<h4>Vertical Group</h4>
<div class="row-fluid">
<div data-toggle="buttons-radio" class="btn-group btn-group-vertical cvy" style="width:100px; margin:10px;">
<button type="button" class="btn btn-primary btn-block ">Session Start</button>
<button type="button" class="btn btn-danger btn-block active ">Stop</button>
</div>
<div data-toggle="buttons-radio" class="btn-group btn-group-vertical cvy" style="width:100px; margin:10px;">
<button type="button" class="btn btn-success btn-block ">Session Start</button>
<button type="button" class="btn btn-danger btn-block active ">Stop</button>
</div>
</div>
<h4>Horizontal Group</h4>
<div class='row-fluid'>
<div data-toggle="buttons-radio" class="btn-group cvy " style="width:150px; margin:10px;">
<button type="button" class="btn btn-primary ">Session Start</button>
<button type="button" class="btn btn-danger active ">Stop</button>
</div>
<div data-toggle="buttons-radio" class="btn-group cvy" style="width:200px; margin:10px;">
<button type="button" class="btn btn-success ">Session Start</button>
<button type="button" class="btn btn-danger active ">Stop</button>
...
CSS
span {
color: #a00;
}
.cvy .btn:active, .cvy .btn.active {
color: #ffffff;
background-color: #757575 !important;
}
.cvy .btn.disabled, .cvy .btn[disabled] {
background-color: #CECECE !important;
}
/* btn-danger - active color change */
/*
.cvy .btn-danger:active, .cvy .btn-danger.active, .cvy .btn-danger.disabled, .cvy .btn-danger[disabled] {
color: #ffffff;
background-color: #757575 !important;
}
*/
/* btn-primary - active color change */
/*
.cvy .btn-primary:active, .cvy .btn-primary.active, .cvy .btn-primary.disabled, .cvy .btn-primary[disabled] {
color: #ffffff;
background-color: #757575 !important;
}
*/
/* btn-success */
/*
.cvy .btn-success:active, .cvy .btn-success.active, .cvy .btn-success.disabled, .cvy .btn-success[disabled] {
color: #ffffff;
background-color: #757575 !important;
}
*/
JavaScript
ko.bindingHandlers.radio = {
init: function (element, valueAccessor, allBindings, data, context) {
var observable = valueAccessor();
if (!ko.isWriteableObservable(observable)) {
throw "You must pass an observable or writable computed";
}
$(element).on('click', '.btn', function () { // use delegate click handler vs click handler for each btn
var $btn = $(this),
disabled = $btn.hasClass('disabled'),
radioValue;
if (!disabled) {
radioValue = $btn.data("value") || $btn.attr("value") || $btn.text();
observable(radioValue);
}
});
},
update: function (element, valueAccessor, allBindings, data, context) {
var observable = valueAccessor(),
options = allBindings(),
disabled = ko.unwrap(options.disabled) || false;
$(".btn", element).each(function () {
var $btn = $(this),
radioValue = $btn.data("value") || $btn.attr("value") || $btn.text();
$btn.toggleClass("active", isTextMatch(observable, radioValue))
.toggleClass('disabled', disabled);
});
function isTextMatch(a, b) {
var src = ko.unwrap(a) || '',
target = ko.unwrap(b) || '';
return src.toLowerCase() === target.toLowerCase();
}
}
};
ViewModel = function () {
this.paceMode = ko.observable('Instructor');
this.correctness = ko.observable('Show');
this.session = ko.observable('Stop');
this.disable = ko.observable(true);
this.allowChange = ko.observable('No');
};
ko.applyBindings(new ViewModel()); // This makes Knockout get to work