├── .github ├── FUNDING.yml └── workflows │ └── comment-issue.yml ├── .gitignore ├── .travis.yml ├── .editorconfig ├── autoform-bs-datepicker.html ├── package.js ├── LICENSE ├── .versions ├── README.md ├── autoform-bs-datepicker.js └── .jshintrc /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [StorytellerCZ, jankapunkt] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .build* 3 | .npm* 4 | .meteor* 5 | smart.lock 6 | nbproject* 7 | /packages/ 8 | .idea/ 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "22" 4 | before_install: 5 | - "curl -L http://git.io/ejPSng | /bin/sh" 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | trim_trailing_whitespace = true 9 | charset = utf-8 10 | 11 | [*.js] 12 | max_line_length = 80 13 | indent_brace_style = 1TBS 14 | spaces_around_operators = true 15 | quote_type = auto -------------------------------------------------------------------------------- /autoform-bs-datepicker.html: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: 'aldeed:autoform-bs-datepicker', 3 | summary: 'Custom bootstrap-datepicker input type for AutoForm', 4 | version: '2.1.0', 5 | git: 'https://github.com/aldeed/meteor-autoform-bs-datepicker.git' 6 | }); 7 | 8 | Package.onUse(function(api) { 9 | api.versionsFrom('2.16'); 10 | api.use('templating@1.0.0 || 1.4.4'); 11 | api.use('blaze@2.0.0 || 2.9.0 || 3.0.1'); 12 | api.use('aldeed:autoform@6.0.0 || 7.1.0 || 8.0.0'); 13 | api.addFiles([ 14 | 'autoform-bs-datepicker.html', 15 | 'autoform-bs-datepicker.js' 16 | ], 'client'); 17 | }); 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2017 Eric Dobbertin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /.versions: -------------------------------------------------------------------------------- 1 | aldeed:autoform@6.0.0 2 | aldeed:autoform-bs-datepicker@2.0.2 3 | babel-compiler@7.10.5 4 | babel-runtime@1.5.1 5 | base64@1.0.12 6 | blaze@2.1.5 7 | blaze-tools@1.0.10 8 | boilerplate-generator@1.7.2 9 | caching-compiler@1.2.2 10 | caching-html-compiler@1.0.4 11 | callback-hook@1.5.1 12 | check@1.4.1 13 | ddp@1.4.1 14 | ddp-client@2.6.2 15 | ddp-common@1.4.1 16 | ddp-server@2.7.1 17 | deps@1.0.12 18 | diff-sequence@1.1.2 19 | dynamic-import@0.7.3 20 | ecmascript@0.16.8 21 | ecmascript-runtime@0.8.1 22 | ecmascript-runtime-client@0.12.1 23 | ecmascript-runtime-server@0.11.0 24 | ejson@1.1.3 25 | fetch@0.1.4 26 | html-tools@1.0.11 27 | htmljs@1.0.11 28 | id-map@1.1.1 29 | inter-process-messaging@0.1.1 30 | jquery@1.11.6 31 | livedata@1.0.18 32 | logging@1.3.4 33 | meteor@1.11.5 34 | modern-browsers@0.1.10 35 | modules@0.20.0 36 | modules-runtime@0.13.1 37 | momentjs:moment@2.10.6 38 | mongo-id@1.0.8 39 | observe-sequence@1.0.16 40 | promise@0.12.2 41 | random@1.2.1 42 | react-fast-refresh@0.2.8 43 | reactive-dict@1.3.1 44 | reactive-var@1.0.12 45 | reload@1.3.1 46 | retry@1.1.0 47 | routepolicy@1.1.1 48 | socket-stream-client@0.5.2 49 | spacebars@1.0.9 50 | spacebars-compiler@1.1.0 51 | templating@1.1.7 52 | templating-tools@1.1.1 53 | tracker@1.3.3 54 | typescript@4.9.5 55 | ui@1.0.9 56 | underscore@1.6.1 57 | webapp@1.13.8 58 | webapp-hashing@1.1.1 59 | -------------------------------------------------------------------------------- /.github/workflows/comment-issue.yml: -------------------------------------------------------------------------------- 1 | name: Add immediate comment on new issues 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | jobs: 8 | createComment: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Create Comment 12 | uses: peter-evans/create-or-update-comment@v1.4.2 13 | with: 14 | issue-number: ${{ github.event.issue.number }} 15 | body: | 16 | Thank you for submitting this issue! 17 | 18 | We, the Members of Meteor Community Packages take every issue seriously. 19 | Our goal is to provide long-term lifecycles for packages and keep up 20 | with the newest changes in Meteor and the overall NodeJs/JavaScript ecosystem. 21 | 22 | However, we contribute to these packages mostly in our free time. 23 | Therefore, we can't guarantee your issues to be solved within certain time. 24 | 25 | If you think this issue is trivial to solve, don't hesitate to submit 26 | a pull request, too! We will accompany you in the process with reviews and hints 27 | on how to get development set up. 28 | 29 | Please also consider sponsoring the maintainers of the package. 30 | If you don't know who is currently maintaining this package, just leave a comment 31 | and we'll let you know 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | aldeed:autoform-bs-datepicker 2 | ========================= 3 | 4 | An add-on Meteor package for [aldeed:autoform](https://github.com/aldeed/meteor-autoform). Provides a single custom input type, "bootstrap-datepicker", which renders an input using the [bootstrap-datepicker](http://bootstrap-datepicker.readthedocs.org/en/release/index.html) plugin. 5 | 6 | ## Prerequisites 7 | 8 | Bootstrap and the plugin library must be installed separately. 9 | 10 | In a Meteor app directory, enter: 11 | 12 | ``` 13 | $ meteor add twbs:bootstrap 14 | $ meteor add rajit:bootstrap3-datepicker 15 | $ meteor add aldeed:autoform 16 | ``` 17 | 18 | ## Installation 19 | 20 | In a Meteor app directory, enter: 21 | 22 | ``` 23 | $ meteor add aldeed:autoform-bs-datepicker 24 | ``` 25 | 26 | ## Usage 27 | 28 | Specify "bootstrap-datepicker" for the `type` attribute of any input. This can be done in a number of ways: 29 | 30 | In the schema, which will then work with a `quickForm` or `afQuickFields`: 31 | 32 | ```js 33 | { 34 | date: { 35 | type: Date, 36 | autoform: { 37 | type: "bootstrap-datepicker", 38 | datePickerOptions: { 39 | autoclose: true 40 | } 41 | } 42 | } 43 | } 44 | ``` 45 | Options for the bs-datepicker plugin can be found [here](https://bootstrap-datepicker.readthedocs.org/en/latest/options.html). 46 | 47 | Or on the `afFieldInput` component or any component that passes along attributes to `afFieldInput`: 48 | 49 | ```js 50 | {{> afQuickField name="typeTest" type="bootstrap-datepicker"}} 51 | 52 | {{> afFormGroup name="typeTest" type="bootstrap-datepicker"}} 53 | 54 | {{> afFieldInput name="typeTest" type="bootstrap-datepicker"}} 55 | ``` 56 | 57 | ## Automatic Type Conversions 58 | 59 | This input type is intended to be used with `type: Date` schema keys, but it also works with other schema types. Here's a list: 60 | 61 | * `Date`: Value is stored as a `Date` object representing midnight in the UTC timezone on the morning of the selected date. 62 | * `String`: Value is stored as a string representation of the selected date in ISO format, e.g., "2014-11-25". 63 | * `Number`: Value is stored as the result of calling `getTime()` on the `Date` object (representing midnight in the UTC timezone on the morning of the selected date). 64 | * `Array`: If the schema expects an array of `Date` or `String` or `Number`, the value is converted to a one-item array and stored. 65 | 66 | To provide bootstrap-datepicker options, set a `datePickerOptions` attribute equal to a helper that returns the options object. Most of the `data-date` attributes that the plugin recognizes should also work. 67 | 68 | ## Customizing Appearance 69 | 70 | To easily add an input group add-on after the field, just provide the classes for the span in a `buttonClasses` attribute: 71 | 72 | ```js 73 | {{> afFieldInput name="typeTest" type="bootstrap-datepicker" buttonClasses="glyphicon glyphicon-calendar"}} 74 | ``` 75 | 76 | If you want to customize the appearance of the input more, for example to use input group add-ons both before and after the field, use the [aldeed:template-extension](https://atmospherejs.com/aldeed/template-extension) package to replace the "afBootstrapDatepicker" template, like this: 77 | 78 | ```html 79 | 87 | ``` 88 | 89 | ```js 90 | Template.dpReplacement.replaces("afBootstrapDatepicker"); 91 | ``` 92 | 93 | ## Demo 94 | 95 | [Live](http://autoform.meteor.com/types) 96 | 97 | ## Contributing 98 | 99 | Anyone is welcome to contribute. Fork, make your changes, and then submit a pull request. 100 | -------------------------------------------------------------------------------- /autoform-bs-datepicker.js: -------------------------------------------------------------------------------- 1 | /* global AutoForm, $ */ 2 | 3 | AutoForm.addInputType('bootstrap-datepicker', { 4 | template: 'afBootstrapDatepicker', 5 | valueOut: function () { 6 | var val; 7 | if (this.val()) { 8 | val = this.datepicker('getUTCDate'); 9 | } 10 | return (val instanceof Date) ? val : this.val(); 11 | }, 12 | valueConverters: { 13 | string: function (val) { 14 | return (val instanceof Date) ? AutoForm.valueConverters.dateToDateStringUTC(val) : val; 15 | }, 16 | stringArray: function (val) { 17 | if (val instanceof Date) { 18 | return [AutoForm.valueConverters.dateToDateStringUTC(val)]; 19 | } 20 | return val; 21 | }, 22 | number: function (val) { 23 | return (val instanceof Date) ? val.getTime() : val; 24 | }, 25 | numberArray: function (val) { 26 | if (val instanceof Date) { 27 | return [val.getTime()]; 28 | } 29 | return val; 30 | }, 31 | dateArray: function (val) { 32 | var valArray = this.datepicker('getUTCDates'); 33 | if (allArrayItemsAreDates(valArray)) return valArray; 34 | return val; 35 | }, 36 | }, 37 | }); 38 | 39 | Template.afBootstrapDatepicker.helpers({ 40 | atts: function addFormControlAtts() { 41 | var atts = { ...this.atts }; 42 | // Add bootstrap class 43 | atts = AutoForm.Utility.addClass(atts, 'form-control'); 44 | delete atts.datePickerOptions; 45 | return atts; 46 | } 47 | }); 48 | 49 | Template.afBootstrapDatepicker.onRendered(function onRendered() { 50 | var $input = this.data.atts.buttonClasses ? this.$('.input-group.date') : this.$('input'); 51 | var data = this.data; 52 | 53 | // instanciate datepicker 54 | $input.datepicker(data.atts.datePickerOptions); 55 | 56 | // set and reactively update values 57 | var previousValue; 58 | this.autorun(function () { 59 | var data = Template.currentData(); 60 | var nextValue = data.value; 61 | 62 | // set field value 63 | if (String(previousValue) !== String(nextValue)) { 64 | if (typeof nextValue === 'string' && AutoForm.Utility.isValidDateString(nextValue)) { 65 | nextValue = utcToLocal(new Date(nextValue + 'T00:00:00.000Z')); 66 | } 67 | 68 | if (nextValue instanceof Date) { 69 | $input.datepicker('setUTCDate', nextValue); 70 | } else if (typeof nextValue === 'string') { 71 | $input.datepicker('update', nextValue); 72 | } 73 | 74 | if (Array.isArray(nextValue)) { 75 | if (allArrayItemsAreDates(nextValue)) { 76 | $input.datepicker('setUTCDates', nextValue); 77 | } else if (allArrayItemsAreValidDateStrings(nextValue)) { 78 | var nextUTCDates = nextValue.map(function (dateString) { 79 | return utcToLocal(new Date(dateString + 'T00:00:00.000Z')); 80 | }); 81 | $input.datepicker('setUTCDates', nextUTCDates); 82 | } else { 83 | $input.datepicker('update', nextValue); 84 | } 85 | } 86 | 87 | previousValue = nextValue; 88 | } 89 | 90 | // set start date if there's a min in the schema 91 | if (data.min instanceof Date) { 92 | // datepicker plugin expects local Date object, 93 | // so convert UTC Date object to local 94 | var startDate = utcToLocal(data.min); 95 | $input.datepicker('setStartDate', startDate); 96 | } 97 | 98 | // set end date if there's a max in the schema 99 | if (data.max instanceof Date) { 100 | // datepicker plugin expects local Date object, 101 | // so convert UTC Date object to local 102 | var endDate = utcToLocal(data.max); 103 | $input.datepicker('setEndDate', endDate); 104 | } 105 | }); 106 | }); 107 | 108 | Template.afBootstrapDatepicker.onDestroyed(function () { 109 | var $input = this.data.atts.buttonClasses ? this.$('.input-group.date') : this.$('input'); 110 | $input.datepicker('remove'); 111 | }); 112 | 113 | function utcToLocal(utcDate) { 114 | var localDateObj = new Date(); 115 | localDateObj.setDate(utcDate.getUTCDate()); 116 | localDateObj.setMonth(utcDate.getUTCMonth()); 117 | localDateObj.setFullYear(utcDate.getUTCFullYear()); 118 | localDateObj.setHours(0); 119 | localDateObj.setMinutes(0); 120 | localDateObj.setSeconds(0); 121 | localDateObj.setMilliseconds(0); 122 | return localDateObj; 123 | } 124 | 125 | function allArrayItemsAreDates(items) { 126 | var nonDates = items.filter(function(val) { return !(val instanceof Date); }); 127 | return nonDates.length === 0; 128 | } 129 | 130 | function allArrayItemsAreValidDateStrings(items) { 131 | var nonValid = items.filter(function(val) { 132 | return !(typeof val === 'string' && AutoForm.Utility.isValidDateString(val)); 133 | }); 134 | return nonValid.length === 0; 135 | } 136 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | //.jshintrc 2 | { 3 | // JSHint Meteor Configuration File 4 | // Match the Meteor Style Guide 5 | // 6 | // By @raix with contributions from @aldeed and @awatson1978 7 | // Source https://github.com/raix/Meteor-jshintrc 8 | // 9 | // See http://jshint.com/docs/ for more details 10 | 11 | "maxerr" : 50, // {int} Maximum error before stopping 12 | 13 | // Enforcing 14 | "bitwise" : true, // true: Prohibit bitwise operators (&, |, ^, etc.) 15 | "camelcase" : true, // true: Identifiers must be in camelCase 16 | "curly" : true, // true: Require {} for every new block or scope 17 | "eqeqeq" : true, // true: Require triple equals (===) for comparison 18 | "forin" : true, // true: Require filtering for..in loops with obj.hasOwnProperty() 19 | "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` 20 | "indent" : 2, // {int} Number of spaces to use for indentation 21 | "latedef" : false, // true: Require variables/functions to be defined before being used 22 | "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` 23 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` 24 | "noempty" : true, // true: Prohibit use of empty blocks 25 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) 26 | "plusplus" : false, // true: Prohibit use of `++` & `--` 27 | "quotmark" : false, // Quotation mark consistency: 28 | // false : do nothing (default) 29 | // true : ensure whatever is used is consistent 30 | // "single" : require single quotes 31 | // "double" : require double quotes 32 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks) 33 | "unused" : true, // true: Require all defined variables be used 34 | "strict" : false, // true: Requires all functions run in ES5 Strict Mode 35 | "trailing" : true, // true: Prohibit trailing whitespaces 36 | "maxparams" : false, // {int} Max number of formal params allowed per function 37 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions) 38 | "maxstatements" : false, // {int} Max number statements per function 39 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function 40 | "maxlen" : 80, // {int} Max number of characters per line 41 | 42 | // Relaxing 43 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) 44 | "boss" : false, // true: Tolerate assignments where comparisons would be expected 45 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. 46 | "eqnull" : false, // true: Tolerate use of `== null` 47 | "es5" : true, // true: Allow ES5 syntax (ex: getters and setters) 48 | "esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`) 49 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features) 50 | // (ex: `for each`, multiple try/catch, function expression…) 51 | "evil" : false, // true: Tolerate use of `eval` and `new Function()` 52 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs 53 | "funcscope" : false, // true: Tolerate defining variables inside control statements" 54 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict') 55 | "iterator" : false, // true: Tolerate using the `__iterator__` property 56 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block 57 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings 58 | "laxcomma" : false, // true: Tolerate comma-first style coding 59 | "loopfunc" : false, // true: Tolerate functions being defined in loops 60 | "multistr" : false, // true: Tolerate multi-line strings 61 | "proto" : false, // true: Tolerate using the `__proto__` property 62 | "scripturl" : false, // true: Tolerate script-targeted URLs 63 | "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment 64 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` 65 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation 66 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` 67 | "validthis" : false, // true: Tolerate using this in a non-constructor function 68 | 69 | // Environments 70 | "browser" : true, // Web Browser (window, document, etc) 71 | "couch" : false, // CouchDB 72 | "devel" : true, // Development/debugging (alert, confirm, etc) 73 | "dojo" : false, // Dojo Toolkit 74 | "jquery" : false, // jQuery 75 | "mootools" : false, // MooTools 76 | "node" : false, // Node.js 77 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) 78 | "prototypejs" : false, // Prototype and Scriptaculous 79 | "rhino" : false, // Rhino 80 | "worker" : false, // Web Workers 81 | "wsh" : false, // Windows Scripting Host 82 | "yui" : false, // Yahoo User Interface 83 | //"meteor" : false, // Meteor.js 84 | 85 | // Legacy 86 | "nomen" : false, // true: Prohibit dangling `_` in variables 87 | "onevar" : false, // true: Allow only one `var` statement per function 88 | "passfail" : false, // true: Stop on first error 89 | "white" : false, // true: Check against strict whitespace and indentation rules 90 | 91 | // Custom Globals 92 | "predef" : [ 93 | "Meteor", 94 | "Accounts", 95 | "Session", 96 | "Template", 97 | "check", 98 | "Match", 99 | "Deps", 100 | "EJSON", 101 | "Email", 102 | "Package", 103 | "Tinytest", 104 | "Npm", 105 | "Assets", 106 | "Packages", 107 | "process", 108 | "LocalCollection", 109 | "_", 110 | "Random", 111 | "HTTP" 112 | ] // additional predefined global variables 113 | } 114 | --------------------------------------------------------------------------------