From f8811f2d8714f02ad6d71fa9e464826104ca3803 Mon Sep 17 00:00:00 2001 From: Artem Stepanyuk Date: Thu, 19 Mar 2015 19:14:40 +0300 Subject: [PATCH] Version 1.2.1 --- build/knockstrap.js | 655 ++++++++++++++++++++++++++++++++++++++++ build/knockstrap.min.js | 2 + 2 files changed, 657 insertions(+) create mode 100644 build/knockstrap.js create mode 100644 build/knockstrap.min.js diff --git a/build/knockstrap.js b/build/knockstrap.js new file mode 100644 index 0000000..b365b39 --- /dev/null +++ b/build/knockstrap.js @@ -0,0 +1,655 @@ +/*! knockstrap 1.2.1 | (c) 2014 Artem Stepanyuk | http://www.opensource.org/licenses/mit-license */ + +(function (moduleName, factory) { + 'use strict'; + + if (typeof require === 'function' && typeof exports === 'object' && typeof module === 'object') { + // CommonJS/Node.js + factory(require('knockout'), require('jquery')); + } else if (typeof define === 'function' && define.amd) { + // AMD + define(moduleName, ['knockout', 'jquery'], factory); + } else { + factory(ko, $); + } + +})('knockstrap', function (ko, $) { + 'use strict'; + + ko.utils.uniqueId = (function () { + + var prefixesCounts = { + 'ks-unique-': 0 + }; + + return function (prefix) { + prefix = prefix || 'ks-unique-'; + + if (!prefixesCounts[prefix]) { + prefixesCounts[prefix] = 0; + } + + return prefix + prefixesCounts[prefix]++; + }; + })(); + ko.utils.unwrapProperties = function (wrappedProperies) { + + if (wrappedProperies === null || typeof wrappedProperies !== 'object') { + return wrappedProperies; + } + + var options = {}; + + ko.utils.objectForEach(wrappedProperies, function (propertyName, propertyValue) { + options[propertyName] = ko.unwrap(propertyValue); + }); + + return options; + }; + + // inspired by http://www.knockmeout.net/2011/10/ko-13-preview-part-3-template-sources.html + (function () { + // storage of string templates for all instances of stringTemplateEngine + var templates = {}; + + templates.alert="
"; + templates.alertInner="

"; + templates.carousel="
"; + templates.carouselContent="
"; + templates.carouselControls=" "; + templates.carouselIndicators="
"; + templates.modal="
"; + templates.modalBody="
"; + templates.modalFooter=" "; + templates.modalHeader="

"; + templates.progress="
%
"; + + + // create new template source to provide storing string templates in storage + ko.templateSources.stringTemplate = function (template) { + this.templateName = template; + + this.data = function (key, value) { + templates.data = templates.data || {}; + templates.data[this.templateName] = templates.data[this.templateName] || {}; + + if (arguments.length === 1) { + return templates.data[this.templateName][key]; + } + + templates.data[this.templateName][key] = value; + }; + + this.text = function (value) { + if (arguments.length === 0) { + return templates[this.templateName]; + } + + templates[this.templateName] = value; + }; + }; + + // create modified template engine, which uses new string template source + ko.stringTemplateEngine = function () { + this.allowTemplateRewriting = false; + }; + + ko.stringTemplateEngine.prototype = new ko.nativeTemplateEngine(); + ko.stringTemplateEngine.prototype.constructor = ko.stringTemplateEngine; + + ko.stringTemplateEngine.prototype.makeTemplateSource = function (template) { + return new ko.templateSources.stringTemplate(template); + }; + + ko.stringTemplateEngine.prototype.getTemplate = function (name) { + return templates[name]; + }; + + ko.stringTemplateEngine.prototype.addTemplate = function (name, template) { + if (arguments.length < 2) { + throw new Error('template is not provided'); + } + + templates[name] = template; + }; + + ko.stringTemplateEngine.prototype.removeTemplate = function (name) { + if (!name) { + throw new Error('template name is not provided'); + } + + delete templates[name]; + }; + + ko.stringTemplateEngine.prototype.isTemplateExist = function (name) { + return !!templates[name]; + }; + + ko.stringTemplateEngine.instance = new ko.stringTemplateEngine(); + })(); + + + ko.bindingHandlers.alert = { + init: function () { + return { controlsDescendantBindings: true }; + }, + + update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + var $element = $(element), + value = valueAccessor(), + usedTemplateEngine = !value.template ? ko.stringTemplateEngine.instance : null, + userTemplate = ko.unwrap(value.template) || 'alertInner', + template, data; + + // for compatibility with ie8, use '1' and '8' values for node types + if (element.nodeType === (Node.ELEMENT_NODE || 1)) { + template = userTemplate; + data = value.data || { message: value.message }; + + $element.addClass('alert fade in').addClass('alert-' + (ko.unwrap(value.type) || 'info')); + } else if (element.nodeType === (Node.COMMENT_NODE || 8)) { + template = 'alert'; + data = { + innerTemplate: { + name: userTemplate , + data: value.data || { message: value.message }, + templateEngine: usedTemplateEngine + }, + type: 'alert-' + (ko.unwrap(value.type) || 'info') + }; + } else { + throw new Error('alert binding should be used with dom elements or ko virtual elements'); + } + + ko.renderTemplate(template, bindingContext.createChildContext(data), ko.utils.extend({ templateEngine: usedTemplateEngine }, value.templateOptions), element); + } + }; + + ko.virtualElements.allowedBindings.alert = true; + ko.bindingHandlers.carousel = { + + defaults: { + css: 'carousel slide', + + controlsTemplate: { + name: 'carouselControls', + templateEngine: ko.stringTemplateEngine.instance, + dataConverter: function(value) { + return { + id: ko.computed(function() { + return '#' + ko.unwrap(value.id); + }) + }; + } + }, + + indicatorsTemplate: { + name: 'carouselIndicators', + templateEngine: ko.stringTemplateEngine.instance, + dataConverter: function(value) { + return { + id: ko.computed(function() { + return '#' + ko.unwrap(value.id); + }), + + items: value.content.data + }; + } + }, + + itemTemplate: { + name: 'carouselContent', + templateEngine: ko.stringTemplateEngine.instance, + + converter: function (item) { + return item; + } + } + }, + + init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + var $element = $(element), + value = valueAccessor(), + defaults = ko.bindingHandlers.carousel.defaults, + extendDefaults = function(defs, type) { + var extended = { + name: defs.name, + data: (value[type] && (value[type].data || value[type].dataConverter && value[type].dataConverter(value))) || defs.dataConverter(value), + }; + + extended = $.extend(true, {}, extended, value[type]); + if (!value[type] || !value[type].name) { + extended.templateEngine = defs.templateEngine; + } + + return extended; + }; + + if (!value.content) { + throw new Error('content option is required for carousel binding'); + } + + // get carousel id from 'id' attribute, or from binding options, or generate it + if (element.id) { + value.id = element.id; + } else if (value.id) { + element.id = ko.unwrap(value.id); + } else { + element.id = value.id = ko.utils.uniqueId('ks-carousel-'); + } + + var model = { + id: value.id, + controlsTemplate: extendDefaults(defaults.controlsTemplate, 'controls'), + indicatorsTemplate: extendDefaults(defaults.indicatorsTemplate, 'indicators'), + + items: value.content.data, + converter: value.content.converter || defaults.itemTemplate.converter, + itemTemplateName: value.content.name || defaults.itemTemplate.name, + templateEngine: !value.content.name ? defaults.itemTemplate.templateEngine : null, + afterRender: value.content.afterRender, + afterAdd: value.content.afterAdd, + beforeRemove: value.content.beforeRemove + }; + + ko.renderTemplate('carousel', bindingContext.createChildContext(model), { templateEngine: ko.stringTemplateEngine.instance }, element); + + $element.addClass(defaults.css); + + return { controlsDescendantBindings: true }; + }, + + update: function (element, valueAccessor) { + var value = valueAccessor(), + options = ko.unwrap(value.options); + + $(element).carousel(options); + } + }; + // Knockout checked binding doesn't work with Bootstrap checkboxes + ko.bindingHandlers.checkbox = { + init: function (element, valueAccessor) { + var $element = $(element), + handler = function (e) { + // we need to handle change event after bootsrap will handle its event + // to prevent incorrect changing of checkbox state + setTimeout(function() { + var $checkbox = $(e.target), + value = valueAccessor(), + data = $checkbox.val(), + isChecked = $checkbox.parent().hasClass('active'); + + if (ko.unwrap(value) instanceof Array) { + var index = ko.unwrap(value).indexOf(data); + + if (isChecked && (index === -1)) { + value.push(data); + } else if (!isChecked && (index !== -1)) { + value.splice(index, 1); + } + } else { + value(isChecked); + } + }, 0); + }; + + if ($element.attr('data-toggle') === 'buttons' && $element.find('input:checkbox').length) { + + if (!(ko.unwrap(valueAccessor()) instanceof Array)) { + throw new Error('checkbox binding should be used only with array or observableArray values in this case'); + } + + $element.on('change', 'input:checkbox', handler); + } else if ($element.attr('type') === 'checkbox') { + + if (!ko.isObservable(valueAccessor())) { + throw new Error('checkbox binding should be used only with observable values in this case'); + } + + $element.on('change', handler); + } else { + throw new Error('checkbox binding should be used only with bootstrap checkboxes'); + } + }, + + update: function (element, valueAccessor) { + var $element = $(element), + value = ko.unwrap(valueAccessor()), + isChecked; + + if (value instanceof Array) { + if ($element.attr('data-toggle') === 'buttons') { + $element.find('input:checkbox').each(function (index, el) { + isChecked = value.indexOf(el.value) !== -1; + $(el).parent().toggleClass('active', isChecked); + el.checked = isChecked; + }); + } else { + isChecked = value.indexOf($element.val()) !== -1; + $element.toggleClass('active', isChecked); + $element.find('input').prop('checked', isChecked); + } + } else { + isChecked = !!value; + $element.prop('checked', isChecked); + $element.parent().toggleClass('active', isChecked); + } + } + }; + ko.bindingHandlers.modal = { + defaults: { + css: 'modal fade', + dialogCss: '', + attributes: { + role: 'dialog' + }, + + headerTemplate: { + name: 'modalHeader', + templateEngine: ko.stringTemplateEngine.instance + }, + + bodyTemplate: { + name: 'modalBody', + templateEngine: ko.stringTemplateEngine.instance + }, + + footerTemplate: { + name: 'modalFooter', + templateEngine: ko.stringTemplateEngine.instance, + data: { + closeLabel: 'Close', + primaryLabel: 'Ok' + } + } + }, + + init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + var $element = $(element), + value = valueAccessor(), + defaults = ko.bindingHandlers.modal.defaults, + options = ko.utils.extend({ show: $element.data().show || false }, ko.utils.unwrapProperties(value.options)), + extendDefaults = function (defs, val) { + var extended = { + name: defs.name, + data: defs.data, + }; + + // reassign to not overwrite default content of data property + extended = $.extend(true, {}, extended, val); + if (!val || !val.name) { + extended.templateEngine = defs.templateEngine; + } + + return extended; + }; + + if (!value.header || !value.body) { + throw new Error('header and body options are required for modal binding.'); + } + + // fix for not working escape button + if (options.keyboard || typeof options.keyboard === 'undefined') { + $element.attr('tabindex', -1); + } + + var model = { + dialogCss: value.dialogCss || defaults.dialogCss, + headerTemplate: extendDefaults(defaults.headerTemplate, ko.unwrap(value.header)), + bodyTemplate: extendDefaults(defaults.bodyTemplate, ko.unwrap(value.body)), + footerTemplate: value.footer ? extendDefaults(defaults.footerTemplate, ko.unwrap(value.footer)) : null + }; + + ko.renderTemplate('modal', bindingContext.createChildContext(model), { templateEngine: ko.stringTemplateEngine.instance }, element); + + $element.addClass(defaults.css).attr(defaults.attributes); + $element.modal(options); + + $element.on('shown.bs.modal', function () { + if (typeof value.visible !== 'undefined' && typeof value.visible === 'function' && !ko.isComputed(value.visible)) { + value.visible(true); + } + + $(this).find("[autofocus]:first").focus(); + }); + + if (typeof value.visible !== 'undefined' && typeof value.visible === 'function' && !ko.isComputed(value.visible)) { + $element.on('hidden.bs.modal', function() { + value.visible(false); + }); + + // if we need to show modal after initialization, we need also set visible property to true + if (options.show) { + value.visible(true); + } + } + + return { controlsDescendantBindings: true }; + }, + + update: function (element, valueAccessor) { + var value = valueAccessor(); + + if (typeof value.visible !== 'undefined') { + $(element).modal(!ko.unwrap(value.visible) ? 'hide' : 'show'); + } + } + }; + var popoverDomDataTemplateKey = '__popoverTemplateKey__'; + + ko.bindingHandlers.popover = { + + init: function (element) { + var $element = $(element); + + ko.utils.domNodeDisposal.addDisposeCallback(element, function () { + if ($element.data('bs.popover')) { + $element.popover('destroy'); + } + }); + }, + + update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + var $element = $(element), + value = ko.unwrap(valueAccessor()), + options = (!value.options && !value.template ? ko.utils.unwrapProperties(value) : ko.utils.unwrapProperties(value.options)) || {}; + + if (value.template) { + // use unwrap to track dependency from template, if it is observable + ko.unwrap(value.template); + + var id = ko.utils.domData.get(element, popoverDomDataTemplateKey), + data = ko.unwrap(value.data); + + var renderPopoverTemplate = function () { + // use unwrap again to get correct template value instead of old value from closure + // this works for observable template property + ko.renderTemplate(ko.unwrap(value.template), bindingContext.createChildContext(data), value.templateOptions, document.getElementById(id)); + + // bootstrap's popover calculates position before template renders, + // so we recalculate position, using bootstrap methods + var $popover = $('#' + id).parents('.popover'), + popoverMethods = $element.data('bs.popover'), + offset = popoverMethods.getCalculatedOffset(options.placement || 'right', popoverMethods.getPosition(), $popover.outerWidth(), $popover.outerHeight()); + + popoverMethods.applyPlacement(offset, options.placement || 'right'); + }; + + // if there is no generated id - popover executes first time for this element + if (!id) { + id = ko.utils.uniqueId('ks-popover-'); + ko.utils.domData.set(element, popoverDomDataTemplateKey, id); + + // place template rendering after popover is shown, because we don't have root element for template before that + $element.on('shown.bs.popover', renderPopoverTemplate); + } + + options.content = '
'; + options.html = true; + + // support rerendering of template, if observable changes, when popover is opened + if ($('#' + id).is(':visible')) { + renderPopoverTemplate(); + } + } + + var popoverData = $element.data('bs.popover'); + + if (!popoverData) { + $element.popover(options); + + $element.on('shown.bs.popover', function () { + (options.container ? $(options.container) : $element.parent()).one('click', '[data-dismiss="popover"]', function () { + $element.popover('hide'); + }); + }); + } else { + ko.utils.extend(popoverData.options, options); + } + } + }; + ko.bindingHandlers.progress = { + defaults: { + css: 'progress', + text: '', + textHidden: true, + striped: false, + type: '', + animated: false + }, + + init: function (element, valueAccessor) { + var $element = $(element), + value = valueAccessor(), + unwrappedValue = ko.unwrap(value), + defs = ko.bindingHandlers.progress.defaults, + model = $.extend({}, defs, unwrappedValue); + + if (typeof unwrappedValue === 'number') { + model.value = value; + + model.barWidth = ko.computed(function() { + return ko.unwrap(value) + '%'; + }); + } else if (typeof ko.unwrap(unwrappedValue.value) === 'number') { + model.barWidth = ko.computed(function() { + return ko.unwrap(unwrappedValue.value) + '%'; + }); + } else { + throw new Error('progress binding can accept only numbers or objects with "value" number propertie'); + } + + model.innerCss = ko.computed(function () { + var values = ko.utils.unwrapProperties(unwrappedValue), + css = ''; + + if (values.animated) { + css += 'active '; + } + + if (values.striped) { + css += 'progress-bar-striped '; + } + + if (values.type) { + css += 'progress-bar-' + values.type; + } + + return css; + }); + + ko.renderTemplate('progress', model, { templateEngine: ko.stringTemplateEngine.instance }, element); + + $element.addClass(defs.css); + + return { controlsDescendantBindings: true }; + }, + }; + + // Knockout checked binding doesn't work with Bootstrap radio-buttons + ko.bindingHandlers.radio = { + init: function (element, valueAccessor) { + + if (!ko.isObservable(valueAccessor())) { + throw new Error('radio binding should be used only with observable values'); + } + + $(element).on('change', 'input:radio', function (e) { + // we need to handle change event after bootsrap will handle its event + // to prevent incorrect changing of radio button styles + setTimeout(function() { + var radio = $(e.target), + value = valueAccessor(), + newValue = radio.val(); + + value(newValue); + }, 0); + }); + }, + + update: function (element, valueAccessor) { + var $radioButton = $(element).find('input[value="' + ko.unwrap(valueAccessor()) + '"]'), + $radioButtonWrapper; + + if ($radioButton.length) { + $radioButtonWrapper = $radioButton.parent(); + + $radioButtonWrapper.siblings().removeClass('active'); + $radioButtonWrapper.addClass('active'); + + $radioButton.prop('checked', true); + } else { + $radioButtonWrapper = $(element).find('.active'); + $radioButtonWrapper.removeClass('active'); + $radioButtonWrapper.find('input').prop('checked', false); + } + } + }; + ko.bindingHandlers.toggle = { + init: function (element, valueAccessor) { + var value = valueAccessor(); + + if (!ko.isObservable(value)) { + throw new Error('toggle binding should be used only with observable values'); + } + + $(element).on('click', function (event) { + event.preventDefault(); + + var previousValue = ko.unwrap(value); + value(!previousValue); + }); + }, + + update: function (element, valueAccessor) { + ko.utils.toggleDomNodeCssClass(element, 'active', ko.unwrap(valueAccessor())); + } + }; + + ko.bindingHandlers.tooltip = { + init: function (element) { + var $element = $(element); + + ko.utils.domNodeDisposal.addDisposeCallback(element, function () { + if ($element.data('bs.tooltip')) { + $element.tooltip('destroy'); + } + }); + }, + + update: function (element, valueAccessor) { + var $element = $(element), + value = ko.unwrap(valueAccessor()), + options = ko.utils.unwrapProperties(value); + + var tooltipData = $element.data('bs.tooltip'); + + if (!tooltipData) { + $element.tooltip(options); + } else { + ko.utils.extend(tooltipData.options, options); + } + } + }; + +}); diff --git a/build/knockstrap.min.js b/build/knockstrap.min.js new file mode 100644 index 0000000..d7e2fe4 --- /dev/null +++ b/build/knockstrap.min.js @@ -0,0 +1,2 @@ +/*! knockstrap 1.2.1 | (c) 2014 Artem Stepanyuk | http://www.opensource.org/licenses/mit-license */ +!function(a,b){"use strict";"function"==typeof require&&"object"==typeof exports&&"object"==typeof module?b(require("knockout"),require("jquery")):"function"==typeof define&&define.amd?define(a,["knockout","jquery"],b):b(ko,$)}("knockstrap",function(a,b){"use strict";a.utils.uniqueId=function(){var a={"ks-unique-":0};return function(b){return b=b||"ks-unique-",a[b]||(a[b]=0),b+a[b]++}}(),a.utils.unwrapProperties=function(b){if(null===b||"object"!=typeof b)return b;var c={};return a.utils.objectForEach(b,function(b,d){c[b]=a.unwrap(d)}),c},function(){var b={};b.alert='
',b.alertInner='

',b.carousel=' ',b.carouselContent='
',b.carouselControls=' ',b.carouselIndicators=' ',b.modal='',b.modalBody='
',b.modalFooter=' ',b.modalHeader='

',b.progress='
%
',a.templateSources.stringTemplate=function(a){this.templateName=a,this.data=function(a,c){return b.data=b.data||{},b.data[this.templateName]=b.data[this.templateName]||{},1===arguments.length?b.data[this.templateName][a]:(b.data[this.templateName][a]=c,void 0)},this.text=function(a){return 0===arguments.length?b[this.templateName]:(b[this.templateName]=a,void 0)}},a.stringTemplateEngine=function(){this.allowTemplateRewriting=!1},a.stringTemplateEngine.prototype=new a.nativeTemplateEngine,a.stringTemplateEngine.prototype.constructor=a.stringTemplateEngine,a.stringTemplateEngine.prototype.makeTemplateSource=function(b){return new a.templateSources.stringTemplate(b)},a.stringTemplateEngine.prototype.getTemplate=function(a){return b[a]},a.stringTemplateEngine.prototype.addTemplate=function(a,c){if(arguments.length<2)throw new Error("template is not provided");b[a]=c},a.stringTemplateEngine.prototype.removeTemplate=function(a){if(!a)throw new Error("template name is not provided");delete b[a]},a.stringTemplateEngine.prototype.isTemplateExist=function(a){return!!b[a]},a.stringTemplateEngine.instance=new a.stringTemplateEngine}(),a.bindingHandlers.alert={init:function(){return{controlsDescendantBindings:!0}},update:function(c,d,e,f,g){var h,i,j=b(c),k=d(),l=k.template?null:a.stringTemplateEngine.instance,m=a.unwrap(k.template)||"alertInner";if(c.nodeType===(Node.ELEMENT_NODE||1))h=m,i=k.data||{message:k.message},j.addClass("alert fade in").addClass("alert-"+(a.unwrap(k.type)||"info"));else{if(c.nodeType!==(Node.COMMENT_NODE||8))throw new Error("alert binding should be used with dom elements or ko virtual elements");h="alert",i={innerTemplate:{name:m,data:k.data||{message:k.message},templateEngine:l},type:"alert-"+(a.unwrap(k.type)||"info")}}a.renderTemplate(h,g.createChildContext(i),a.utils.extend({templateEngine:l},k.templateOptions),c)}},a.virtualElements.allowedBindings.alert=!0,a.bindingHandlers.carousel={defaults:{css:"carousel slide",controlsTemplate:{name:"carouselControls",templateEngine:a.stringTemplateEngine.instance,dataConverter:function(b){return{id:a.computed(function(){return"#"+a.unwrap(b.id)})}}},indicatorsTemplate:{name:"carouselIndicators",templateEngine:a.stringTemplateEngine.instance,dataConverter:function(b){return{id:a.computed(function(){return"#"+a.unwrap(b.id)}),items:b.content.data}}},itemTemplate:{name:"carouselContent",templateEngine:a.stringTemplateEngine.instance,converter:function(a){return a}}},init:function(c,d,e,f,g){var h=b(c),i=d(),j=a.bindingHandlers.carousel.defaults,k=function(a,c){var d={name:a.name,data:i[c]&&(i[c].data||i[c].dataConverter&&i[c].dataConverter(i))||a.dataConverter(i)};return d=b.extend(!0,{},d,i[c]),i[c]&&i[c].name||(d.templateEngine=a.templateEngine),d};if(!i.content)throw new Error("content option is required for carousel binding");c.id?i.id=c.id:c.id=i.id?a.unwrap(i.id):i.id=a.utils.uniqueId("ks-carousel-");var l={id:i.id,controlsTemplate:k(j.controlsTemplate,"controls"),indicatorsTemplate:k(j.indicatorsTemplate,"indicators"),items:i.content.data,converter:i.content.converter||j.itemTemplate.converter,itemTemplateName:i.content.name||j.itemTemplate.name,templateEngine:i.content.name?null:j.itemTemplate.templateEngine,afterRender:i.content.afterRender,afterAdd:i.content.afterAdd,beforeRemove:i.content.beforeRemove};return a.renderTemplate("carousel",g.createChildContext(l),{templateEngine:a.stringTemplateEngine.instance},c),h.addClass(j.css),{controlsDescendantBindings:!0}},update:function(c,d){var e=d(),f=a.unwrap(e.options);b(c).carousel(f)}},a.bindingHandlers.checkbox={init:function(c,d){var e=b(c),f=function(c){setTimeout(function(){var e=b(c.target),f=d(),g=e.val(),h=e.parent().hasClass("active");if(a.unwrap(f)instanceof Array){var i=a.unwrap(f).indexOf(g);h&&-1===i?f.push(g):h||-1===i||f.splice(i,1)}else f(h)},0)};if("buttons"===e.attr("data-toggle")&&e.find("input:checkbox").length){if(!(a.unwrap(d())instanceof Array))throw new Error("checkbox binding should be used only with array or observableArray values in this case");e.on("change","input:checkbox",f)}else{if("checkbox"!==e.attr("type"))throw new Error("checkbox binding should be used only with bootstrap checkboxes");if(!a.isObservable(d()))throw new Error("checkbox binding should be used only with observable values in this case");e.on("change",f)}},update:function(c,d){var e,f=b(c),g=a.unwrap(d());g instanceof Array?"buttons"===f.attr("data-toggle")?f.find("input:checkbox").each(function(a,c){e=-1!==g.indexOf(c.value),b(c).parent().toggleClass("active",e),c.checked=e}):(e=-1!==g.indexOf(f.val()),f.toggleClass("active",e),f.find("input").prop("checked",e)):(e=!!g,f.prop("checked",e),f.parent().toggleClass("active",e))}},a.bindingHandlers.modal={defaults:{css:"modal fade",dialogCss:"",attributes:{role:"dialog"},headerTemplate:{name:"modalHeader",templateEngine:a.stringTemplateEngine.instance},bodyTemplate:{name:"modalBody",templateEngine:a.stringTemplateEngine.instance},footerTemplate:{name:"modalFooter",templateEngine:a.stringTemplateEngine.instance,data:{closeLabel:"Close",primaryLabel:"Ok"}}},init:function(c,d,e,f,g){var h=b(c),i=d(),j=a.bindingHandlers.modal.defaults,k=a.utils.extend({show:h.data().show||!1},a.utils.unwrapProperties(i.options)),l=function(a,c){var d={name:a.name,data:a.data};return d=b.extend(!0,{},d,c),c&&c.name||(d.templateEngine=a.templateEngine),d};if(!i.header||!i.body)throw new Error("header and body options are required for modal binding.");(k.keyboard||"undefined"==typeof k.keyboard)&&h.attr("tabindex",-1);var m={dialogCss:i.dialogCss||j.dialogCss,headerTemplate:l(j.headerTemplate,a.unwrap(i.header)),bodyTemplate:l(j.bodyTemplate,a.unwrap(i.body)),footerTemplate:i.footer?l(j.footerTemplate,a.unwrap(i.footer)):null};return a.renderTemplate("modal",g.createChildContext(m),{templateEngine:a.stringTemplateEngine.instance},c),h.addClass(j.css).attr(j.attributes),h.modal(k),h.on("shown.bs.modal",function(){"undefined"==typeof i.visible||"function"!=typeof i.visible||a.isComputed(i.visible)||i.visible(!0),b(this).find("[autofocus]:first").focus()}),"undefined"==typeof i.visible||"function"!=typeof i.visible||a.isComputed(i.visible)||(h.on("hidden.bs.modal",function(){i.visible(!1)}),k.show&&i.visible(!0)),{controlsDescendantBindings:!0}},update:function(c,d){var e=d();"undefined"!=typeof e.visible&&b(c).modal(a.unwrap(e.visible)?"show":"hide")}};var c="__popoverTemplateKey__";a.bindingHandlers.popover={init:function(c){var d=b(c);a.utils.domNodeDisposal.addDisposeCallback(c,function(){d.data("bs.popover")&&d.popover("destroy")})},update:function(d,e,f,g,h){var i=b(d),j=a.unwrap(e()),k=(j.options||j.template?a.utils.unwrapProperties(j.options):a.utils.unwrapProperties(j))||{};if(j.template){a.unwrap(j.template);var l=a.utils.domData.get(d,c),m=a.unwrap(j.data),n=function(){a.renderTemplate(a.unwrap(j.template),h.createChildContext(m),j.templateOptions,document.getElementById(l));var c=b("#"+l).parents(".popover"),d=i.data("bs.popover"),e=d.getCalculatedOffset(k.placement||"right",d.getPosition(),c.outerWidth(),c.outerHeight());d.applyPlacement(e,k.placement||"right")};l||(l=a.utils.uniqueId("ks-popover-"),a.utils.domData.set(d,c,l),i.on("shown.bs.popover",n)),k.content='
',k.html=!0,b("#"+l).is(":visible")&&n()}var o=i.data("bs.popover");o?a.utils.extend(o.options,k):(i.popover(k),i.on("shown.bs.popover",function(){(k.container?b(k.container):i.parent()).one("click",'[data-dismiss="popover"]',function(){i.popover("hide")})}))}},a.bindingHandlers.progress={defaults:{css:"progress",text:"",textHidden:!0,striped:!1,type:"",animated:!1},init:function(c,d){var e=b(c),f=d(),g=a.unwrap(f),h=a.bindingHandlers.progress.defaults,i=b.extend({},h,g);if("number"==typeof g)i.value=f,i.barWidth=a.computed(function(){return a.unwrap(f)+"%"});else{if("number"!=typeof a.unwrap(g.value))throw new Error('progress binding can accept only numbers or objects with "value" number propertie');i.barWidth=a.computed(function(){return a.unwrap(g.value)+"%"})}return i.innerCss=a.computed(function(){var b=a.utils.unwrapProperties(g),c="";return b.animated&&(c+="active "),b.striped&&(c+="progress-bar-striped "),b.type&&(c+="progress-bar-"+b.type),c}),a.renderTemplate("progress",i,{templateEngine:a.stringTemplateEngine.instance},c),e.addClass(h.css),{controlsDescendantBindings:!0}}},a.bindingHandlers.radio={init:function(c,d){if(!a.isObservable(d()))throw new Error("radio binding should be used only with observable values");b(c).on("change","input:radio",function(a){setTimeout(function(){var c=b(a.target),e=d(),f=c.val();e(f)},0)})},update:function(c,d){var e,f=b(c).find('input[value="'+a.unwrap(d())+'"]');f.length?(e=f.parent(),e.siblings().removeClass("active"),e.addClass("active"),f.prop("checked",!0)):(e=b(c).find(".active"),e.removeClass("active"),e.find("input").prop("checked",!1))}},a.bindingHandlers.toggle={init:function(c,d){var e=d();if(!a.isObservable(e))throw new Error("toggle binding should be used only with observable values");b(c).on("click",function(b){b.preventDefault();var c=a.unwrap(e);e(!c)})},update:function(b,c){a.utils.toggleDomNodeCssClass(b,"active",a.unwrap(c()))}},a.bindingHandlers.tooltip={init:function(c){var d=b(c);a.utils.domNodeDisposal.addDisposeCallback(c,function(){d.data("bs.tooltip")&&d.tooltip("destroy")})},update:function(c,d){var e=b(c),f=a.unwrap(d()),g=a.utils.unwrapProperties(f),h=e.data("bs.tooltip");h?a.utils.extend(h.options,g):e.tooltip(g)}}}); \ No newline at end of file