50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Knockstrap [](https://travis-ci.org/faulknercs/Knockstrap)
2 | ==========
3 |
4 | ## ⚠️ Bootstrap versions support ⚠️
5 |
6 | __If you need Bootstrap 4 support, you may use [KnockstrapPlus](https://github.com/CloudNimble/KnockstrapPlus) fork. Also, you can try to search for more forks [here](https://github.com/faulknercs/Knockstrap/network).__
7 |
8 | I highly appreciate all contributions and feedback, but I don't use Bootstrap nor Knockout anymore, so I don't have any plans to continue development of this project.
9 | This repository is not going to be updated for Bootstrap 4 (and further) and will continue work only with Bootstrap 3. But I continue merging patches with bugfixes for Bootstrap 3 if any appears.
10 |
11 | ### Description
12 |
13 | Knockstrap is binding library for Knockout.js, which provides bindings to Twitter Bootstrap 3 widgets
14 |
15 | #### Supported widgets:
16 |
17 | - Modal
18 | - Tooltip
19 | - Popover
20 | - Alert
21 | - Progress
22 | - Toggle button
23 | - Radio button
24 | - Checkbox button
25 | - Carousel
26 | - Pagination
27 | - Pager
28 |
29 | [Download](https://github.com/faulknercs/Knockstrap/releases/download/v1.4.1/knockstrap-1.4.1.zip)
30 |
31 | [Documentation/Examples](http://faulknercs.github.io/Knockstrap/)
32 |
33 | ### Dependencies
34 |
35 | - jQuery (Any compatible with Bootstrap 3 version)
36 | - Twitter Bootstrap 3 (CSS and JavaScript)
37 | - Knockout.js (>=2.3.0)
38 |
39 | ### Packages
40 |
41 | [NuGet](http://www.nuget.org/packages/Knockstrap/) | [Bower](http://bower.io/search/?q=knockstrap) | [npm](https://www.npmjs.org/package/knockstrap)
42 |
43 | ### CDN
44 |
45 | [jsDelivr](https://cdn.jsdelivr.net/npm/knockstrap@1.4.1/build/knockstrap.js)
46 |
47 | ### Building
48 | #### Building using grunt:
49 |
50 | Install node.js and grunt plugin.
51 |
52 | Install all grunt plugins:
53 |
54 | npm install
55 |
56 | Then you can build project with:
57 |
58 | grunt
59 |
60 | Also, you can specify custom build and temp directories:
61 |
62 | grunt -buildPath=D:/custom/build -tempPath=D:/custom/temp
63 |
64 | To build examples use:
65 |
66 | grunt examples
67 |
68 | Also, you can specify custom examples directory:
69 |
70 | grunt -examplesPath=D:/custom/examples
71 |
72 | To run unit-tests, use:
73 |
74 | grunt jasmine
75 |
76 | To run building, tests and minification, use:
77 |
78 | grunt release
79 |
80 | ### License: [MIT License](http://www.opensource.org/licenses/mit-license.php)
--------------------------------------------------------------------------------
/src/templates/templatesWrapper.js:
--------------------------------------------------------------------------------
1 | // inspired by http://www.knockmeout.net/2011/10/ko-13-preview-part-3-template-sources.html
2 | (function () {
3 | // storage of string templates for all instances of stringTemplateEngine
4 | // @include compiledTemplates.js
5 |
6 | // create new template source to provide storing string templates in storage
7 | ko.templateSources.stringTemplate = function (template) {
8 | this.templateName = template;
9 |
10 | this.data = function (key, value) {
11 | templates.data = templates.data || {};
12 | templates.data[this.templateName] = templates.data[this.templateName] || {};
13 |
14 | if (arguments.length === 1) {
15 | return templates.data[this.templateName][key];
16 | }
17 |
18 | templates.data[this.templateName][key] = value;
19 | };
20 |
21 | this.text = function (value) {
22 | if (arguments.length === 0) {
23 | return templates[this.templateName];
24 | }
25 |
26 | templates[this.templateName] = value;
27 | };
28 | };
29 |
30 | // create modified template engine, which uses new string template source
31 | ko.stringTemplateEngine = function () {
32 | this.allowTemplateRewriting = false;
33 | };
34 |
35 | ko.stringTemplateEngine.prototype = new ko.nativeTemplateEngine();
36 | ko.stringTemplateEngine.prototype.constructor = ko.stringTemplateEngine;
37 |
38 | ko.stringTemplateEngine.prototype.makeTemplateSource = function (template) {
39 | return new ko.templateSources.stringTemplate(template);
40 | };
41 |
42 | ko.stringTemplateEngine.prototype.getTemplate = function (name) {
43 | return templates[name];
44 | };
45 |
46 | ko.stringTemplateEngine.prototype.addTemplate = function (name, template) {
47 | if (arguments.length < 2) {
48 | throw new Error('template is not provided');
49 | }
50 |
51 | templates[name] = template;
52 | };
53 |
54 | ko.stringTemplateEngine.prototype.removeTemplate = function (name) {
55 | if (!name) {
56 | throw new Error('template name is not provided');
57 | }
58 |
59 | delete templates[name];
60 | };
61 |
62 | ko.stringTemplateEngine.prototype.isTemplateExist = function (name) {
63 | return !!templates[name];
64 | };
65 |
66 | ko.stringTemplateEngine.instance = new ko.stringTemplateEngine();
67 | })();
68 |
--------------------------------------------------------------------------------
/tests/stringTemplateEngineBehaviors.js:
--------------------------------------------------------------------------------
1 | describe('String Template Engine', function () {
2 | this.prepareTestElement('');
3 |
4 | beforeEach(function() {
5 | this.engine = new ko.stringTemplateEngine();
6 | });
7 |
8 | it('Should "ko.stringTemplateEngine.instance" exist and be an instanse of ko.stringTemplateEngine', function() {
9 | expect(ko.stringTemplateEngine.instance).toBeDefined();
10 | expect(ko.stringTemplateEngine.instance).toEqual(jasmine.any(ko.stringTemplateEngine));
11 | });
12 |
13 | it('Should add new string template to string template engine', function() {
14 | this.engine.addTemplate('test', 'text');
15 |
16 | expect(this.engine.isTemplateExist('test')).toBeTruthy();
17 | });
18 |
19 | it('Should get added template from string template engine', function () {
20 | this.engine.addTemplate('test', 'text');
21 |
22 | expect(this.engine.getTemplate('test')).toEqual('text');
23 | });
24 |
25 | it('Should remove template from template engine', function () {
26 | this.engine.addTemplate('test', 'text');
27 |
28 | expect(this.engine.isTemplateExist('test')).toBeTruthy();
29 | this.engine.removeTemplate('test');
30 | expect(this.engine.isTemplateExist('test')).toBeFalsy();
31 | });
32 |
33 | it('Should render element with added string template', function () {
34 | this.engine.addTemplate('test', 'test text');
35 |
36 | var vm = {
37 | templ: { name: 'test', templateEngine: this.engine }
38 | };
39 |
40 | ko.applyBindings(vm, this.testElement[0]);
41 |
42 | expect(this.testElement).toContainText('test text');
43 | });
44 |
45 | it('Should not render element with string template engine', function () {
46 | this.engine.addTemplate('test', 'string template engine');
47 | this.testElement.after('');
48 |
49 | var vm = {
50 | templ: { name: 'test' }
51 | };
52 |
53 | ko.applyBindings(vm, this.testElement[0]);
54 |
55 | expect(this.testElement).not.toContainText('string template engine');
56 | $('#test-template').remove();
57 | });
58 |
59 | it('Should throw exception, if trying to remove template without name', function () {
60 | expect(function() {
61 | this.engine.removeTemplate();
62 | }).toThrow();
63 | });
64 |
65 | it('Should throw exception, if trying to add undefined template', function () {
66 | expect(function () {
67 | this.engine.addTemplate('test');
68 | }).toThrow();
69 | });
70 | });
--------------------------------------------------------------------------------
/tests/runner.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Knockstrap Tests Runner
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/src/bindings/checkboxBinding.js:
--------------------------------------------------------------------------------
1 | // Knockout checked binding doesn't work with Bootstrap checkboxes
2 | ko.bindingHandlers.checkbox = {
3 | init: function (element, valueAccessor) {
4 | var $element = $(element),
5 | handler = function (e) {
6 | // we need to handle change event after bootstrap will handle its event
7 | // to prevent incorrect changing of checkbox state
8 | setTimeout(function() {
9 | var $checkbox = $(e.target),
10 | value = valueAccessor(),
11 | data = $checkbox.val(),
12 | isChecked = $checkbox.parent().hasClass('active');
13 |
14 | if(!$checkbox.prop('disabled')) {
15 | if (ko.unwrap(value) instanceof Array) {
16 | var index = ko.utils.arrayIndexOf(ko.unwrap(value), (data));
17 |
18 | if (isChecked && (index === -1)) {
19 | value.push(data);
20 | } else if (!isChecked && (index !== -1)) {
21 | value.splice(index, 1);
22 | }
23 | } else {
24 | value(isChecked);
25 | }
26 | }
27 | }, 0);
28 | };
29 |
30 | if ($element.attr('data-toggle') === 'buttons' && $element.find('input:checkbox').length) {
31 |
32 | if (!(ko.unwrap(valueAccessor()) instanceof Array)) {
33 | throw new Error('checkbox binding should be used only with array or observableArray values in this case');
34 | }
35 |
36 | $element.on('change', 'input:checkbox', handler);
37 | } else if ($element.attr('type') === 'checkbox') {
38 |
39 | if (!ko.isObservable(valueAccessor())) {
40 | throw new Error('checkbox binding should be used only with observable values in this case');
41 | }
42 |
43 | $element.on('change', handler);
44 | } else {
45 | throw new Error('checkbox binding should be used only with bootstrap checkboxes');
46 | }
47 | },
48 |
49 | update: function (element, valueAccessor) {
50 | var $element = $(element),
51 | value = ko.unwrap(valueAccessor()),
52 | isChecked;
53 |
54 | if (value instanceof Array) {
55 | if ($element.attr('data-toggle') === 'buttons') {
56 | $element.find('input:checkbox').each(function (index, el) {
57 | isChecked = ko.utils.arrayIndexOf(value, el.value) !== -1;
58 | $(el).parent().toggleClass('active', isChecked);
59 | el.checked = isChecked;
60 | });
61 | } else {
62 | isChecked = ko.utils.arrayIndexOf(value, $element.val()) !== -1;
63 | $element.toggleClass('active', isChecked);
64 | $element.find('input').prop('checked', isChecked);
65 | }
66 | } else {
67 | isChecked = !!value;
68 | $element.prop('checked', isChecked);
69 | $element.parent().toggleClass('active', isChecked);
70 | }
71 | }
72 | };
73 |
--------------------------------------------------------------------------------
/examples-src/htmlParts/bindingExamples/classExample.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Class
4 |
5 |
6 | This binding adds or removes one or more CSS classes to the associated DOM element.
7 | Can be used, when you need to use Knockout css binding with static and dynamic classes simultaneously.
8 | In this case, you may use css binding for static classes and class binding for dynamic classes.
9 |
10 |
11 |
Examples
12 |
13 |
14 |
15 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum nec pharetra eros.
16 | Sed luctus vitae ligula viverra porttitor. Vestibulum porttitor egestas lacus.
17 |
76 | Uses Bootstrap 3 options. If any option is not specified, uses default value. See Bootstrap documentation.
77 | All of the options can be observables. Also option's object can be observable too.
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/src/bindings/modalBinding.js:
--------------------------------------------------------------------------------
1 | ko.bindingHandlers.modal = {
2 | defaults: {
3 | css: 'modal fade',
4 | dialogCss: '',
5 | attributes: {
6 | role: 'dialog'
7 | },
8 |
9 | events: {
10 | shown: 'shown.bs.modal',
11 | hidden: 'hidden.bs.modal'
12 | },
13 |
14 | headerTemplate: {
15 | name: 'modalHeader',
16 | templateEngine: ko.stringTemplateEngine.instance
17 | },
18 |
19 | bodyTemplate: {
20 | name: 'modalBody',
21 | templateEngine: ko.stringTemplateEngine.instance
22 | },
23 |
24 | footerTemplate: {
25 | name: 'modalFooter',
26 | templateEngine: ko.stringTemplateEngine.instance,
27 | data: {
28 | closeLabel: 'Close',
29 | primaryLabel: 'Ok'
30 | }
31 | }
32 | },
33 |
34 | init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
35 | var $element = $(element),
36 | value = valueAccessor(),
37 | defaults = ko.bindingHandlers.modal.defaults,
38 | events = $.extend({}, defaults.events, ko.toJS(value.events)),
39 | options = ko.utils.extend({ show: $element.data().show || false }, ko.toJS(value.options)),
40 | extendDefaults = function (defs, val) {
41 | var extended = {
42 | name: defs.name,
43 | data: defs.data,
44 | };
45 |
46 | // reassign to not overwrite default content of data property
47 | extended = $.extend(true, {}, extended, val);
48 | if (!val || !val.name) {
49 | extended.templateEngine = defs.templateEngine;
50 | }
51 |
52 | return extended;
53 | };
54 |
55 | if (!value.header || !value.body) {
56 | throw new Error('header and body options are required for modal binding.');
57 | }
58 |
59 | // fix for not working escape button
60 | if (options.keyboard || typeof options.keyboard === 'undefined') {
61 | $element.attr('tabindex', -1);
62 | }
63 |
64 | var model = {
65 | dialogCss: value.dialogCss || defaults.dialogCss,
66 | headerTemplate: extendDefaults(defaults.headerTemplate, ko.unwrap(value.header)),
67 | bodyTemplate: extendDefaults(defaults.bodyTemplate, ko.unwrap(value.body)),
68 | footerTemplate: value.footer ? extendDefaults(defaults.footerTemplate, ko.unwrap(value.footer)) : null
69 | };
70 |
71 | ko.renderTemplate('modal', bindingContext.createChildContext(model), { templateEngine: ko.stringTemplateEngine.instance }, element);
72 |
73 | $element.addClass(defaults.css).attr(defaults.attributes);
74 | $element.modal(options);
75 |
76 | $element.on(events.shown, function () {
77 | if (typeof value.visible !== 'undefined' && typeof value.visible === 'function' && !ko.isComputed(value.visible)) {
78 | value.visible(true);
79 | }
80 |
81 | $(this).find("[autofocus]:first").focus();
82 | });
83 |
84 | if (typeof value.visible !== 'undefined' && typeof value.visible === 'function' && !ko.isComputed(value.visible)) {
85 | $element.on(events.hidden, function() {
86 | value.visible(false);
87 | });
88 |
89 | // if we need to show modal after initialization, we need also set visible property to true
90 | if (options.show) {
91 | value.visible(true);
92 | }
93 | }
94 |
95 | return { controlsDescendantBindings: true };
96 | },
97 |
98 | update: function (element, valueAccessor) {
99 | var value = valueAccessor();
100 |
101 | if (typeof value.visible !== 'undefined') {
102 | $(element).modal(!ko.unwrap(value.visible) ? 'hide' : 'show');
103 | }
104 | }
105 | };
--------------------------------------------------------------------------------
/tests/bindings/alertBindingBehaviors.js:
--------------------------------------------------------------------------------
1 | describe('Binding: alert', function () {
2 | this.prepareTestElement('');
3 |
4 | beforeEach(function () {
5 | this.testElement.after('');
6 | });
7 |
8 | afterEach(function () {
9 | $('#test-template').remove();
10 | });
11 |
12 | it('Should add "alert" class to target element', function () {
13 | var vm = {
14 | value: { message: '' }
15 | };
16 |
17 | ko.applyBindings(vm, this.testElement[0]);
18 |
19 | expect(this.testElement).toHaveClass('alert');
20 | });
21 |
22 | it('Should render alert with given message text', function() {
23 | var vm = {
24 | value: { message: 'test text' }
25 | };
26 |
27 | ko.applyBindings(vm, this.testElement[0]);
28 |
29 | expect(this.testElement).toContainText('test text');
30 | });
31 |
32 | it('Should render alert with class according to given type', function () {
33 | var vm = {
34 | value: { message: 'text', type: 'info' }
35 | };
36 |
37 | ko.applyBindings(vm, this.testElement[0]);
38 |
39 | expect(this.testElement).toHaveClass('alert-info');
40 | });
41 |
42 | it('Should change alert type class according to changes of type property', function () {
43 | var vm = {
44 | value: { message: 'text', type: ko.observable('info') }
45 | };
46 |
47 | ko.applyBindings(vm, this.testElement[0]);
48 |
49 | vm.value.type('danger');
50 | expect(this.testElement).toHaveClass('alert-danger');
51 | vm.value.type('custom');
52 | expect(this.testElement).toHaveClass('alert-custom');
53 | });
54 |
55 | it('Should render alert with given template id and data', function () {
56 | var vm = {
57 | value: { template: 'test-template', data: { label: 'test text' } }
58 | };
59 |
60 | ko.applyBindings(vm, this.testElement[0]);
61 |
62 | expect(this.testElement).toContainElement('.test-template');
63 | expect(this.testElement.find('.test-template')).toContainText('test text');
64 | });
65 |
66 | it('Should change template values according to obsrvables changing', function () {
67 | var vm = {
68 | value: { template: 'test-template', data: { label: ko.observable('test text') } }
69 | };
70 |
71 | ko.applyBindings(vm, this.testElement[0]);
72 |
73 | expect(this.testElement.find('.test-template')).toContainText('test text');
74 | vm.value.data.label('new text');
75 | expect(this.testElement.find('.test-template')).toContainText('new text');
76 | });
77 |
78 | it('Should change template if template option changes', function () {
79 | var vm = {
80 | value: { template: ko.observable('test-template'), data: { label: 'test text' } }
81 | };
82 |
83 | this.testElement.after('');
84 |
85 | ko.applyBindings(vm, this.testElement[0]);
86 |
87 | expect(this.testElement).toContainElement('.test-template');
88 | vm.value.template('test-template-2');
89 | expect(this.testElement).toContainElement('.test-template-2');
90 |
91 | $('#test-template-2').remove();
92 | });
93 |
94 | it('Should creates alert for virtual elements', function () {
95 | var vm = {
96 | value: { message: 'test text' }
97 | };
98 |
99 | // change test element to ko virtual elements for this spec
100 | this.testElement = this.testElement.removeAttr('data-bind').html('');
101 |
102 | ko.applyBindings(vm, this.testElement[0]);
103 |
104 | expect(this.testElement).toContainElement('.alert');
105 | expect(this.testElement).toContainText('test text');
106 | });
107 | });
--------------------------------------------------------------------------------
/src/bindings/popoverBinding.js:
--------------------------------------------------------------------------------
1 | var popoverDomDataTemplateKey = '__popoverTemplateKey__';
2 |
3 | ko.bindingHandlers.popover = {
4 |
5 | init: function (element) {
6 | var $element = $(element);
7 |
8 | ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
9 | if ($element.data('bs.popover')) {
10 | $element.popover('destroy');
11 | }
12 | });
13 | },
14 |
15 | update: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
16 | var $element = $(element),
17 | value = ko.unwrap(valueAccessor()),
18 | options = (!value.options && !value.template ? ko.utils.unwrapProperties(value) : ko.utils.unwrapProperties(value.options)) || {};
19 |
20 | if (value.template) {
21 | // use unwrap to track dependency from template, if it is observable
22 | ko.unwrap(value.template);
23 |
24 | var id = ko.utils.domData.get(element, popoverDomDataTemplateKey);
25 |
26 | var renderPopoverTemplate = function (eventObject) {
27 |
28 | if (eventObject && eventObject.type === 'inserted') {
29 | $element.off('shown.bs.popover');
30 | }
31 |
32 | var template = ko.unwrap(value.template),
33 | internalModel;
34 |
35 | if(typeof template === 'string') {
36 | internalModel = {
37 | $$popoverTemplate: $.extend({
38 | name: value.template,
39 | data: value.data
40 | }, value.templateOptions)
41 | };
42 |
43 | } else {
44 | internalModel = {
45 | $$popoverTemplate: value.template
46 | };
47 | }
48 |
49 | var childContext = bindingContext.createChildContext(bindingContext.$rawData, null, function(context) {
50 | ko.utils.extend(context, internalModel);
51 | });
52 |
53 | ko.applyBindingsToDescendants(childContext, document.getElementById(id));
54 |
55 | // bootstrap's popover calculates position before template renders,
56 | // so we recalculate position, using bootstrap methods
57 | var $popover = $('#' + id).parents('.popover'),
58 | popoverMethods = $element.data('bs.popover'),
59 | position = (popoverMethods.options && popoverMethods.options.placement) || 'right',
60 | offset = popoverMethods.getCalculatedOffset(position, popoverMethods.getPosition(), $popover.outerWidth(), $popover.outerHeight());
61 |
62 | popoverMethods.applyPlacement(offset, position);
63 | };
64 |
65 | // if there is no generated id - popover executes first time for this element
66 | if (!id) {
67 | id = ko.utils.uniqueId('ks-popover-');
68 | ko.utils.domData.set(element, popoverDomDataTemplateKey, id);
69 |
70 | // place template rendering after popover is shown, because we don't have root element for template before that
71 | $element.on('shown.bs.popover inserted.bs.popover', renderPopoverTemplate);
72 | }
73 |
74 | options.content = '
Text of alert message. Doesn't used if data property is specified.
59 |
60 |
61 |
type
62 |
Type: string, can be observable (default: 'info')
63 |
64 | Type of alert message. Possible values are 'info', 'warning', 'danger', 'success'.
65 | To specify your own type you should define css-styles for this type.
66 | For exmaple, for type 'my-custom-type', you shoud provide css class 'alert-my-custom-type'.
67 |
68 |
69 |
70 |
template
71 |
Type: string, can be observable (default: 'alertTemplate')
72 |
73 | Name of template for alert content. Default template:
74 |
Data for template. If this option is specified, message option will be ignored.
84 |
For default template, you should provide message property (or, if it will not provided via data, message option of binding will be used).
85 |
86 |
87 |
templateOptions
88 |
Type: object
89 |
Contains options for template.
90 |
91 | They are: templateEngine, afterRender, beforeRender and afterAdd.
92 | Please, see Knockout documentation for details.
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/CHANGELOG.txt:
--------------------------------------------------------------------------------
1 | v1.4.1
2 | -Fixed issue with appearing popover when binding is dynamically changed when popover is hidden
3 | -Fixed issue with numeric 0 value for radio buttons
4 | -Fixed issue with updating popver placement when template is used
5 |
6 | v1.4.0
7 | -Added support of stacked progress-bars for progress binding
8 | -Added support of custom event names for modal binding (so if you override events of modal, you still would be able to use modal binding)
9 | -Added support of usage of all template options with popover binding
10 | -Added possibility to use object with template options for popover binding's template property
11 | -Fixed issue with clickable disabled checkboxes in checkbox binding
12 | -Fixed not updating popover when its data was dynamically changed while popover is opened
13 | -Fixed issue with not disabled controls in pagination binding for cases, when pagesCount is zero
14 | -Fixed issue with numeric values in radio binding
15 | -Removed Bootstrap dependency from nuspec, since there is a lot of different packages with Bootstrap
16 | -Removed jamjs repository link since it is closed now
17 |
18 | v1.3.2
19 | -Fixed changing of selected radio button, when it is disabled
20 | -Fixed changing of selected checkbox, when it is disabled
21 |
22 | v1.3.1
23 | -Fixed not working close button in popover, when bootstrap 3.3.5 used
24 | -Removed unwrapProperties implementation as ko.toJS do the same. ko.utils.unwrapProperties still available as alias for ko.toJS
25 | -Prioritised loading reference to knockout and jQuery from global context. It fixes cases, when knockout and jQuery are loaded from cdn and knockstarp is loaded via 'require'
26 |
27 | v1.3.0
28 | -Added pagination binding
29 | -Added pager binding
30 | -Added class binding
31 | -Updated bower dependencies with official knockout package
32 | -Updated to use anonymous module when exporting via AMD
33 | -Fixed alert and checkbox binding to work in ie8
34 | -Fixed carousel binding to add "active" class to first indicator after loading
35 | -Fixed radioBinding using value with quote
36 | -Fixed the previous css class is not removed from alert element
37 | -Popover now subscribes to the bootstrap 3.3.5 event inserted.bs.popover if available
38 | -Changed grunt-templates-concat to grunt-html-convert in build process, because grunt-templates-concat was removed from npm repo for unknown reasons.
39 |
40 | v1.2.1
41 | -Fixed issue with submitting forms with toggle buttons
42 | -Fixed attemting to set visible property for computed value for modal binding
43 | -Updated docs to work via https
44 |
45 | v1.2.0
46 | -Changed dependency name from jQuery to official jquery
47 | -Added dialogCss property to modal binding
48 |
49 | v1.1.0
50 | -Added possibility to use popover binding with other bindings on same element and with other bindings on child elements
51 | -Added support of close button via 'data-dismiss="popover"' for popover binding
52 | -Made visible property optional for modal binding
53 | -Added possibility of using observable header, body and footer properties to modal binding
54 | -Added possibility to obtain added templates from stringTemplateEngine
55 | -Added possibility to provide different options for progress-bar in progress binding
56 | -Added possibility to change default css and attributes of root element for modal, progress and carousel bindings
57 |
58 | v1.0.0
59 | -Fixed popover positioning, when template is used
60 | -Fixed not changing template, when popover is opened
61 | -Added possibility to add new string-based templates dynamically
62 | -Added possibility to change default template engine for default templates of Knockstrap bindings
63 | -Rewrote stringTemplateEngine implementation
64 | -Added tests for stringTemplateEngine
65 | -Added possibility to change default template engine for header, footer and body in modal binding
66 | -Added possibility to pass modal options via data-attributes
67 | -Reorganized and updated documentation
68 | -Added travis-ci support
69 |
70 | v0.4.0
71 | -Added unit tests via jasmine for all bindings and utility functions
72 | -Added throwing exception, when binding is used with incompatible values
73 | -Added unchecking of buttons for radio binding, when no buttons have passed value
74 | -Fixed checkboxes don't have 'checked' property set to true, when they are clicked for checkbox binding
75 | -Made 'footer' property optional for modal binding
76 | -Fixed carousel binding bugs
77 | -Removed close callback from alert binding ('close.bs.alert' event from bootstrap can be used instead)
78 | -Updated alert binding default template: now it require only 'message' property, 'type' property doesn't depend on template data
79 | -Updated unwrapPoperties function: now if you pass not objects, it returns them without transformation into objects.
80 | -Added nuget package manager support
81 |
82 | v0.3.0
83 | -Added checkbox binding
84 | -Added carousel binding
85 | -Changed bindings documentation
86 | -Updated uniqueId function: now it will generate separate sequences for different prefixes
87 | -Updated radio binding: now it will support dynamically added buttons
88 | -Added short notation for popover binding
89 | -Added bower and jam package managers support
90 |
91 | v0.2.0
92 | -Added radio binding
93 | -Added toggle binding
94 | -Dividing examples into separate files
95 | -Added sources for examples
96 | -Small fixes
97 |
98 | v0.1.0
99 | -First version
--------------------------------------------------------------------------------
/examples-src/htmlParts/stringTemplateEngineExamples.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
String Template Engine
4 |
5 |
Knockstrap provides implementation of Knockout-compatible stringTemplateEngine, which can use strings as html templates.
6 |
7 | For developers, constructor of engine available via ko.stringTemplateEngine.
8 | Also it contains instance property, so it isn't necessary to create your own.
9 | It can be used everywhere, where Knockout's nativeTemplateEngine is acceptable.
10 |
11 |
Template engine contains storage of templates, which is shared between all instances.
12 |
13 |
API
14 |
stringTemplateEngine contains:
15 |
16 |
17 |
18 | addTemplate(name, template)
19 |
20 |
21 |
Adds new template with given name to engine storage
22 |
23 |
24 |
25 |
26 |
name
27 |
Type: string
28 |
29 | Name of new template. If template already exists - it will be overwritten.
30 |
31 |
32 |
33 |
template
34 |
Type: string
35 |
36 | Body of template. May contain any html.
37 |
38 |
39 |
40 |
41 |
42 | removeTemplate(name)
43 |
44 |
45 |
Removes template with given name from engine storage
46 |
47 |
48 |
49 |
50 |
name
51 |
Type: string
52 |
53 | Name of template for deleting. If template doesn't exist - nothing happens.
54 |
55 |
56 |
57 |
58 |
59 | getTemplate(name)
60 |
61 |
62 |
Returns template with given name from engine storage or returns undefined, if there is no template
63 |
64 |
65 |
66 |
67 |
name
68 |
Type: string
69 |
70 | Name of template.
71 |
72 |
73 |
74 |
75 |
76 | isTemplateExist(name)
77 |
78 |
79 |
Return true, if template with given name was saved in engine storage. Otherwise - false.
45 | Observable value is set in true, when button is toggled, otherwise, value is set in false. This binding is two-way,
46 | if observable value changes, 'active' class will be set to element.
47 |
48 |
49 |
50 |
51 |
52 |
Radio buttons
53 |
Two-way binding to Bootstrap radio buttons. Default Knockout checked binding doesn't work with Bootstrap's buttons, so you can use this binding
117 | Observable value is set to value of chosen radiobutton. Initially, when no radio button is toggled, observable value is undefined.
118 | This binding is two-way. For correct work all radio buttons should have value attribute.
119 |
120 |
121 |
122 |
123 |
124 |
Checkbox buttons
125 |
Two-way binding to Bootstrap checkbox buttons. Default Knockout checked binding doesn't work with Bootstrap's buttons, so you can use this binding
222 | Array, contains selected values or boolean, which is set to true or false, depending of checkbox state.
223 | This binding is two-way, if array values changed, corresponding checkbox is set up, if value is deleted from array, otherwise, it is set down.
224 | For boolean case, if observable value changes, corrseponding checkbox is set up, if value is true, otherwise, it is set down.
225 |
114 | Template binding for single carousel item, uses options from Knockout template binding.
115 | Please, see Knockout documentation for details.
116 |
117 |
Default values of item template:
118 |
119 |
120 |
121 |
name
122 |
Type: string, can be observable (default: 'carouselContent')
123 |
Name of single item temlate for carousel. Default template:
124 |
125 |
<div data-bind="text: content"></div>
126 |
127 |
128 |
129 |
data
130 |
Type: array, can be observable
131 |
132 | Items for carousel. Each item will be passed to content template. Each item should contains src, altproperties.
133 | For default template item should contain content property.
134 |
135 |
136 |
137 |
138 |
converter
139 |
Type: function
140 |
Function, which applies for each item and returning data object for template. Default function just return item itself.
141 |
142 |
143 |
144 |
145 |
146 |
indicators
147 |
Type: object, can be observable
148 |
149 | Template binding for carousel indicators, uses options from Knockout template binding.
150 | Please, see Knockout documentation for details.
151 |
152 |
Default values of indicators object:
153 |
154 |
155 |
156 |
name
157 |
Type: string, can be observable (default: 'carouselIndicators')
158 |
Name of controls temlate for carousel. Default template:
Data for indicators template. For default template, it should contains id and items properties.
171 |
172 |
173 |
174 |
dataConverter
175 |
Type: function
176 |
Function, which creates data object for indicators template. Accepts binding value as parameter. Will be ignored, if data property is specified. Default function:
Data for controls template. For default template, it should contains id property.
222 |
223 |
224 |
225 |
dataConverter
226 |
Type: function
227 |
Function, which creates data object for controls template. Accepts binding value as parameter. Will be ignored, if data property is specified. Default function:
246 | Default values for carousel binding located in ko.bindingHandlers.carousel.defaults object.
247 | It contains default css for root element of carousel and default values for controls, indicators and item templtates.
248 | Can be changed before ko.applyBindigs() is called.
249 |
Progress value in percents. Values greater than 100, assumed equal to 100
92 |
93 |
94 |
95 |
type
96 |
Type: string, can be observable (default: none)
97 |
98 | Type of progress bar. Possible values are 'info', 'warning', 'danger', 'success'.
99 | To specify your own type you should define css-styles for it.
100 | For exmaple, for type 'my-custom-type', you shoud provide css class 'progress-bar-custom-type'.
101 |
102 |
103 |
104 |
105 |
text
106 |
Type: string, can be observable (default: empty string)
107 |
Text on progress bar after percents
108 |
109 |
110 |
111 |
textHidden
112 |
Type: boolean, can be observable (default: true)
113 |
Hides percents of progress and text on progress bar, if true, otherwise hides.
114 |
115 |
116 |
117 |
striped
118 |
Type: boolean, can be observable (default: false)
119 |
Adds stripes to progress bar, if true. Work only in Bootstrap >= 3.2.0
120 |
121 |
122 |
123 |
animated
124 |
Type: boolean, can be observable (default: false)
125 |
Animates stripes on progress bar, if true. Work only in Bootstrap >= 3.2.0
126 |
127 |
128 |
129 |
130 |
Short notation
131 |
Examples
132 |
If you only need use progress value, you can use short notation of binding, which uses only number as model.
Array of data-objects for progress bar. Each element in array should contain options for progress bar in full or short notation
285 |
286 |
287 |
288 |
289 |
Default values
290 |
291 | Default values for progress binding located in ko.bindingHandlers.progress.defaults object.
292 | It contains default css for root element of progress-bar and default values for its options.
293 | Can be changed before ko.applyBindigs() is called.
294 |
146 | Bootstrap options for modal. If any option is not specified, it uses default values (except show, it default value is false in comparing with Bootstrap).
147 | Also, can be specified via data-attributes.
148 | Please, see Bootstrap documentation for details.
149 |
150 |
151 |
152 |
153 |
visible
154 |
Type: boolean, can be observable (default: false)
155 |
Shows modal, if true, otherwise hides modal. By default is false.
156 |
Can be omitted in order to use Bootstrap's attributes for showing or closing modal.
157 |
158 |
159 |
160 |
dialogCss
161 |
Type: string, can be observable (default: undefined)
162 |
Used to add classes to modal-dialog element. For example, it can accept modal-lg value for large modal or modal-sm for small.
Data for footer template. For default template, data object contains:
244 |
245 |
246 |
247 |
action
248 |
Type: function
249 |
250 | Function, which will be called, when user clicks on primary button.
251 | If this property is omitted for default template, primary button wouldn't render.
252 |
253 |
254 |
255 |
256 |
257 |
primaryLabel
258 |
Type: string, can be observable (default: 'Ok')
259 |
Text for primary button in default template.
260 |
261 |
262 |
263 |
closeLabel
264 |
Type: string, can be observable (default: 'Close')
265 |
Text for closing button in default template.
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
events
274 |
Type: object, can be observable
275 |
276 | Names of Bootstrap events, which are used by binding.
277 | Some bootstrap plugins change them, so you can pass new events to binding.
278 |
279 |
Default values of events object:
280 |
281 |
282 |
283 |
shown
284 |
Type: string, can be observable (default: 'shown.bs.modal')
285 |
Name of Bootstrap event, which fired when the modal has been made visible to the user
286 |
287 |
288 |
hidden
289 |
Type: string, can be observable (default: 'hidden.bs.modal')
290 |
Name of Bootstrap event, which fired when the modal has finished being hidden from the user
291 |
292 |
293 |
294 |
295 |
296 |
297 |
Default values
298 |
299 | Default values for modal binding located in ko.bindingHandlers.modal.defaults object.
300 | It contains default css and attributes for root element of modal and default values for header, body and footer.
301 | Can be changed before ko.applyBindigs() is called.
302 |