From 6d1d26ab545fbc886ed87de409594dae73f87ded Mon Sep 17 00:00:00 2001 From: Artem Stepanyuk Date: Sat, 12 Dec 2020 16:09:12 +0300 Subject: [PATCH] Version 1.4.1 --- build/knockstrap.js | 1010 +++++++++++++++++++++++++++++++++++++++ build/knockstrap.min.js | 2 + 2 files changed, 1012 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..9c8b801 --- /dev/null +++ b/build/knockstrap.js @@ -0,0 +1,1010 @@ +/*! knockstrap 1.4.1 http://faulknercs.github.io/Knockstrap/ | (c) 2013-2020 Artem Stepanyuk | http://www.opensource.org/licenses/mit-license */ + +(function (factory) { + 'use strict'; + + if (typeof ko !== 'undefined' && typeof jQuery !== 'undefined') { + //global knockout and jQuery references already present, so use these regardless of whether this module has been included in CommonJS/AMD + factory(ko, jQuery); + } else 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(['knockout', 'jquery'], factory); + } else { + throw new Error('Could not locate current context reference to knockout and jQuery in order to load 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 = ko.toJS; + + // 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'] = '
\n' + + '
'; + + templates['alertInner'] = '\n' + + '

'; + + templates['carousel'] = '\n' + + '\n' + + '\n' + + '\n' + + '\n' + + ''; + + templates['carouselContent'] = '
'; + + templates['carouselControls'] = '\n' + + ' \n' + + '\n' + + '\n' + + ' \n' + + ''; + + templates['carouselIndicators'] = '\n' + + ''; + + templates['modal'] = ''; + + templates['modalBody'] = '
\n' + + '
'; + + templates['modalFooter'] = '\n' + + '\n' + + '\n' + + ''; + + templates['modalHeader'] = '\n' + + '

\n' + + ''; + + templates['pager'] = '\n' + + ''; + + templates['pagination'] = ''; + + templates['progress'] = '\n' + + '
\n' + + ' \n' + + ' % \n' + + ' \n' + + '
\n' + + ''; + + + // 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 === (typeof Node !== 'undefined' && Node.ELEMENT_NODE || 1)) { + template = userTemplate; + data = value.data || { message: value.message }; + + // ola lawal added this code to removeclassess for resulable alerts using hide show (issue #29) + $element.removeClass("alert-info alert-danger alert-success "); + + $element.addClass('alert fade in').addClass('alert-' + (ko.unwrap(value.type) || 'info')); + } else if (element.nodeType === (typeof Node !== 'undefined' && 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 bootstrap 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(!$checkbox.prop('disabled')) { + if (ko.unwrap(value) instanceof Array) { + var index = ko.utils.arrayIndexOf(ko.unwrap(value), (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 = ko.utils.arrayIndexOf(value, el.value) !== -1; + $(el).parent().toggleClass('active', isChecked); + el.checked = isChecked; + }); + } else { + isChecked = ko.utils.arrayIndexOf(value, $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); + } + } + }; + + // Knockout doesn't allow to use 'css: className' and 'css: { 'class-name': boolValue }' bindings on same element + // This binding can be used together with 'css: { 'class-name': boolValue }' + // Inspired by https://github.com/knockout/knockout/wiki/Bindings---class + var previousClassKey = '__ko__previousClassValue__'; + + ko.bindingHandlers['class'] = { + update: function (element, valueAccessor) { + if (element[previousClassKey]) { + ko.utils.toggleDomNodeCssClass(element, element[previousClassKey], false); + } + + var value = ko.unwrap(valueAccessor()); + ko.utils.toggleDomNodeCssClass(element, value, true); + element[previousClassKey] = value; + } + }; + ko.bindingHandlers.modal = { + defaults: { + css: 'modal fade', + dialogCss: '', + attributes: { + role: 'dialog' + }, + + events: { + shown: 'shown.bs.modal', + hidden: 'hidden.bs.modal' + }, + + 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, + events = $.extend({}, defaults.events, ko.toJS(value.events)), + options = ko.utils.extend({ show: $element.data().show || false }, ko.toJS(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(events.shown, 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(events.hidden, 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'); + } + } + }; + ko.bindingHandlers.pagination = { + defaults: { + maxPages: 5, + + pageSize: 10, + + directions: true, + + boundary: true, + + text: { + first: 'First', + last: 'Last', + back: '«', + forward: '»' + } + }, + + init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + var value = $.extend(true, {}, ko.bindingHandlers.pagination.defaults, valueAccessor()); + + if (!ko.isObservable(value.currentPage)) { + throw new TypeError('currentPage should be observable'); + } + + if (!$.isNumeric(value.currentPage())) { + value.currentPage(1); + } + + var model = new Pagination(value); + + ko.renderTemplate('pagination', bindingContext.createChildContext(model), { templateEngine: ko.stringTemplateEngine.instance }, element); + + return { controlsDescendantBindings: true }; + } + }; + + ko.bindingHandlers.pager = { + defaults: { + pageSize: 10, + + text: { + back: '←', + forward: '→' + } + }, + + init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { + var value = $.extend(true, {}, ko.bindingHandlers.pager.defaults, valueAccessor()); + + if (!ko.isObservable(value.currentPage)) { + throw new TypeError('currentPage should be observable'); + } + + if (!$.isNumeric(value.currentPage())) { + value.currentPage(1); + } + + var model = new Pager(value); + + ko.renderTemplate('pager', bindingContext.createChildContext(model), { templateEngine: ko.stringTemplateEngine.instance }, element); + + return { controlsDescendantBindings: true }; + } + }; + + function Pager(data) { + var self = this; + + self.isAligned = data.isAligned; + + self.currentPage = data.currentPage; + + self.totalCount = data.totalCount; + + self.pageSize = data.pageSize; + + self.text = data.text; + + self.pagesCount = ko.computed(function () { + var total = ko.unwrap(self.totalCount), + pageSize = ko.unwrap(self.pageSize); + + return Math.max(Math.ceil(total / pageSize), 1); + }); + + self.isBackDisabled = ko.computed(function () { + return self.currentPage() === 1; + }); + + self.isForwardDisabled = ko.computed(function () { + return self.currentPage() === self.pagesCount(); + }); + + self.goBack = function() { + if (self.isBackDisabled()) { + return; + } + + var current = self.currentPage(); + self.currentPage(current - 1); + }; + + self.goForward = function() { + if (self.isForwardDisabled()) { + return; + } + + var current = self.currentPage(); + self.currentPage(current + 1); + }; + } + + function Pagination(data) { + var self = this; + + Pager.call(self, data); + + var getStartPage = function () { + var maxPages = +ko.unwrap(self.maxPages); + + return ((Math.ceil(self.currentPage() / maxPages) - 1) * maxPages) + 1; + }; + + var getLastPage = function (startPage) { + var maxPages = +ko.unwrap(self.maxPages); + + return Math.min(startPage + maxPages - 1, self.pagesCount()); + }; + + self.maxPages = data.maxPages; + + self.boundary = data.boundary; + + self.directions = data.directions; + + self.text = data.text; + + self.pages = ko.computed(function () { + var pages = []; + + var startPage = getStartPage(), + endPage = getLastPage(startPage); + + for (var pageNumber = startPage; pageNumber <= endPage; pageNumber++) { + pages.push(new Page(pageNumber, pageNumber, pageNumber === self.currentPage())); + } + + if (startPage > 1) { + pages.unshift(new Page(startPage - 1, '...')); + } + + if (endPage < self.pagesCount()) { + pages.push(new Page(endPage + 1, '...')); + } + + return pages; + }); + + self.selectPage = function (page) { + self.currentPage(page.number); + }; + + self.goFirst = function() { + if (self.isBackDisabled()) { + return; + } + + self.currentPage(1); + }; + + self.goLast = function () { + if (self.isForwardDisabled()) { + return; + } + + self.currentPage(self.pagesCount()); + }; + } + + // page model + function Page(number, text, isActive) { + this.number = number; + + this.text = text || number; + + this.isActive = !!isActive; + } + + 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); + + var renderPopoverTemplate = function (eventObject) { + + if (eventObject && eventObject.type === 'inserted') { + $element.off('shown.bs.popover'); + } + + var template = ko.unwrap(value.template), + internalModel; + + if(typeof template === 'string') { + internalModel = { + $$popoverTemplate: $.extend({ + name: value.template, + data: value.data + }, value.templateOptions) + }; + + } else { + internalModel = { + $$popoverTemplate: value.template + }; + } + + var childContext = bindingContext.createChildContext(bindingContext.$rawData, null, function(context) { + ko.utils.extend(context, internalModel); + }); + + ko.applyBindingsToDescendants(childContext, 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'), + position = (popoverMethods.options && popoverMethods.options.placement) || 'right', + offset = popoverMethods.getCalculatedOffset(position, popoverMethods.getPosition(), $popover.outerWidth(), $popover.outerHeight()); + + popoverMethods.applyPlacement(offset, position); + }; + + // 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 inserted.bs.popover', renderPopoverTemplate); + } + + options.content = '
'; + options.html = true; + } + + var popoverData = $element.data('bs.popover'); + + if (!popoverData) { + $element.popover(options); + + $element.on('shown.bs.popover inserted.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); + if(popoverData.tip().is(":visible") && popoverData.options.content) { + $element.popover('show'); + } + } + } + }; + + 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; + + if(unwrappedValue instanceof Array) { + model = unwrappedValue.map(function(val) { + return normalize(val); + }); + } else { + model = [normalize(value)]; + } + + ko.renderTemplate('progress', model, { templateEngine: ko.stringTemplateEngine.instance }, element); + + $element.addClass(defs.css); + + return { controlsDescendantBindings: true }; + }, + }; + + function normalize(value) { + var unwrappedValue = ko.unwrap(value); + + if (typeof unwrappedValue === 'number') { + return new ProgressBar({ value: value }); + } else if (typeof ko.unwrap(unwrappedValue.value) === 'number') { + return new ProgressBar(unwrappedValue); + } else { + throw new Error('progress binding can accept only numbers or objects with "value" number property'); + } + } + + function ProgressBar(data) { + var self = this; + + $.extend(self, ko.bindingHandlers.progress.defaults, data); + + self.barWidth = ko.computed(function() { + return ko.unwrap(self.value) + '%'; + }); + + self.barType = ko.computed(function() { + var type = ko.unwrap(self.type); + + return type ? 'progress-bar-' + type : ''; + }); + } + // 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(); + + // we shouldn't change value for disables buttons + if (!radio.prop('disabled')) { + value(newValue); + } + }, 0); + }); + }, + + update: function (element, valueAccessor) { + var tempValue = ko.unwrap(valueAccessor()), + value = tempValue !== null && tempValue !== undefined ? tempValue : '', + $radioButton = $(element).find('input[value="' + value.toString().replace(/"/g, '\\"') + '"]'), + $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..ddc8580 --- /dev/null +++ b/build/knockstrap.min.js @@ -0,0 +1,2 @@ +/*! knockstrap 1.4.1 http://faulknercs.github.io/Knockstrap/ | (c) 2013-2020 Artem Stepanyuk | http://www.opensource.org/licenses/mit-license */ +!function(a){"use strict";if("undefined"!=typeof ko&&"undefined"!=typeof jQuery)a(ko,jQuery);else if("function"==typeof require&&"object"==typeof exports&&"object"==typeof module)a(require("knockout"),require("jquery"));else{if("function"!=typeof define||!define.amd)throw new Error("Could not locate current context reference to knockout and jQuery in order to load Knockstrap");define(["knockout","jquery"],a)}}(function(a,b){"use strict";function c(b){var c=this;c.isAligned=b.isAligned,c.currentPage=b.currentPage,c.totalCount=b.totalCount,c.pageSize=b.pageSize,c.text=b.text,c.pagesCount=a.computed(function(){var b=a.unwrap(c.totalCount),d=a.unwrap(c.pageSize);return Math.max(Math.ceil(b/d),1)}),c.isBackDisabled=a.computed(function(){return 1===c.currentPage()}),c.isForwardDisabled=a.computed(function(){return c.currentPage()===c.pagesCount()}),c.goBack=function(){if(!c.isBackDisabled()){var a=c.currentPage();c.currentPage(a-1)}},c.goForward=function(){if(!c.isForwardDisabled()){var a=c.currentPage();c.currentPage(a+1)}}}function d(b){var d=this;c.call(d,b);var f=function(){var b=+a.unwrap(d.maxPages);return(Math.ceil(d.currentPage()/b)-1)*b+1},g=function(b){var c=+a.unwrap(d.maxPages);return Math.min(b+c-1,d.pagesCount())};d.maxPages=b.maxPages,d.boundary=b.boundary,d.directions=b.directions,d.text=b.text,d.pages=a.computed(function(){for(var a=[],b=f(),c=g(b),h=b;c>=h;h++)a.push(new e(h,h,h===d.currentPage()));return b>1&&a.unshift(new e(b-1,"...")),c\n',b.alertInner='\n

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

\n',b.pager='\n',b.pagination='',b.progress='\n
\n \n % \n \n
\n',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]:void(b.data[this.templateName][a]=c)},this.text=function(a){return 0===arguments.length?b[this.templateName]:void(b[this.templateName]=a)}},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===("undefined"!=typeof Node&&Node.ELEMENT_NODE||1))h=m,i=k.data||{message:k.message},j.removeClass("alert-info alert-danger alert-success "),j.addClass("alert fade in").addClass("alert-"+(a.unwrap(k.type)||"info"));else{if(c.nodeType!==("undefined"!=typeof Node&&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:i.id?c.id=a.unwrap(i.id):c.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(!e.prop("disabled"))if(a.unwrap(f)instanceof Array){var i=a.utils.arrayIndexOf(a.unwrap(f),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(c,d){e=-1!==a.utils.arrayIndexOf(g,d.value),b(d).parent().toggleClass("active",e),d.checked=e}):(e=-1!==a.utils.arrayIndexOf(g,f.val()),f.toggleClass("active",e),f.find("input").prop("checked",e)):(e=!!g,f.prop("checked",e),f.parent().toggleClass("active",e))}};var h="__ko__previousClassValue__";a.bindingHandlers["class"]={update:function(b,c){b[h]&&a.utils.toggleDomNodeCssClass(b,b[h],!1);var d=a.unwrap(c());a.utils.toggleDomNodeCssClass(b,d,!0),b[h]=d}},a.bindingHandlers.modal={defaults:{css:"modal fade",dialogCss:"",attributes:{role:"dialog"},events:{shown:"shown.bs.modal",hidden:"hidden.bs.modal"},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=b.extend({},j.events,a.toJS(i.events)),l=a.utils.extend({show:h.data().show||!1},a.toJS(i.options)),m=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.");(l.keyboard||"undefined"==typeof l.keyboard)&&h.attr("tabindex",-1);var n={dialogCss:i.dialogCss||j.dialogCss,headerTemplate:m(j.headerTemplate,a.unwrap(i.header)),bodyTemplate:m(j.bodyTemplate,a.unwrap(i.body)),footerTemplate:i.footer?m(j.footerTemplate,a.unwrap(i.footer)):null};return a.renderTemplate("modal",g.createChildContext(n),{templateEngine:a.stringTemplateEngine.instance},c),h.addClass(j.css).attr(j.attributes),h.modal(l),h.on(k.shown,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(k.hidden,function(){i.visible(!1)}),l.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")}},a.bindingHandlers.pagination={defaults:{maxPages:5,pageSize:10,directions:!0,boundary:!0,text:{first:"First",last:"Last",back:"«",forward:"»"}},init:function(c,e,f,g,h){var i=b.extend(!0,{},a.bindingHandlers.pagination.defaults,e());if(!a.isObservable(i.currentPage))throw new TypeError("currentPage should be observable");b.isNumeric(i.currentPage())||i.currentPage(1);var j=new d(i);return a.renderTemplate("pagination",h.createChildContext(j),{templateEngine:a.stringTemplateEngine.instance},c),{controlsDescendantBindings:!0}}},a.bindingHandlers.pager={defaults:{pageSize:10,text:{back:"←",forward:"→"}},init:function(d,e,f,g,h){var i=b.extend(!0,{},a.bindingHandlers.pager.defaults,e());if(!a.isObservable(i.currentPage))throw new TypeError("currentPage should be observable");b.isNumeric(i.currentPage())||i.currentPage(1);var j=new c(i);return a.renderTemplate("pager",h.createChildContext(j),{templateEngine:a.stringTemplateEngine.instance},d),{controlsDescendantBindings:!0}}};var i="__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(c,d,e,f,g){var h=b(c),j=a.unwrap(d()),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(c,i),m=function(c){c&&"inserted"===c.type&&h.off("shown.bs.popover");var d,e=a.unwrap(j.template);d="string"==typeof e?{$$popoverTemplate:b.extend({name:j.template,data:j.data},j.templateOptions)}:{$$popoverTemplate:j.template};var f=g.createChildContext(g.$rawData,null,function(b){a.utils.extend(b,d)});a.applyBindingsToDescendants(f,document.getElementById(l));var i=b("#"+l).parents(".popover"),k=h.data("bs.popover"),m=k.options&&k.options.placement||"right",n=k.getCalculatedOffset(m,k.getPosition(),i.outerWidth(),i.outerHeight());k.applyPlacement(n,m)};l||(l=a.utils.uniqueId("ks-popover-"),a.utils.domData.set(c,i,l),h.on("shown.bs.popover inserted.bs.popover",m)),k.content='
',k.html=!0}var n=h.data("bs.popover");n?(a.utils.extend(n.options,k),n.tip().is(":visible")&&n.options.content&&h.popover("show")):(h.popover(k),h.on("shown.bs.popover inserted.bs.popover",function(){(k.container?b(k.container):h.parent()).one("click",'[data-dismiss="popover"]',function(){h.popover("hide")})}))}},a.bindingHandlers.progress={defaults:{css:"progress",text:"",textHidden:!0,striped:!1,type:"",animated:!1},init:function(c,d){var e,g=b(c),h=d(),i=a.unwrap(h),j=a.bindingHandlers.progress.defaults;return e=i instanceof Array?i.map(function(a){return f(a)}):[f(h)],a.renderTemplate("progress",e,{templateEngine:a.stringTemplateEngine.instance},c),g.addClass(j.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();c.prop("disabled")||e(f)},0)})},update:function(c,d){var e,f=a.unwrap(d()),g=null!==f&&void 0!==f?f:"",h=b(c).find('input[value="'+g.toString().replace(/"/g,'\\"')+'"]');h.length?(e=h.parent(),e.siblings().removeClass("active"),e.addClass("active"),h.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