Showing preview only (360K chars total). Download the full file or copy to clipboard to get everything.
Repository: fengyuanchen/pickerjs
Branch: master
Commit: a62e731aef20
Files: 91
Total size: 335.9 KB
Directory structure:
gitextract_tcbz06ub/
├── .babelrc
├── .editorconfig
├── .eslintrc
├── .gitattributes
├── .github/
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── ISSUE_TEMPLATE.md
│ └── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .stylelintrc
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dist/
│ ├── picker.common.js
│ ├── picker.css
│ ├── picker.esm.js
│ └── picker.js
├── docs/
│ ├── css/
│ │ ├── main.css
│ │ └── picker.css
│ ├── index.html
│ └── js/
│ ├── main.js
│ ├── picker.en-GB.js
│ ├── picker.en-US.js
│ ├── picker.js
│ ├── picker.pl-PL.js
│ └── picker.zh-CN.js
├── i18n/
│ ├── picker.en-GB.js
│ ├── picker.en-US.js
│ ├── picker.pl-PL.js
│ ├── picker.pt-BR.js
│ └── picker.zh-CN.js
├── package.json
├── postcss.config.js
├── rollup.config.js
├── src/
│ ├── css/
│ │ └── picker.css
│ ├── index.css
│ ├── index.js
│ └── js/
│ ├── constants.js
│ ├── defaults.js
│ ├── events.js
│ ├── handlers.js
│ ├── helpers.js
│ ├── methods.js
│ ├── picker.js
│ ├── template.js
│ └── utilities.js
├── test/
│ ├── .eslintrc
│ ├── helpers.js
│ ├── karma.conf.js
│ └── specs/
│ ├── Picker.spec.js
│ ├── events/
│ │ ├── hidden.spec.js
│ │ ├── hide.spec.js
│ │ ├── pick.spec.js
│ │ ├── show.spec.js
│ │ └── shown.spec.js
│ ├── methods/
│ │ ├── destroy.spec.js
│ │ ├── formatDate.spec.js
│ │ ├── getDate.spec.js
│ │ ├── hide.spec.js
│ │ ├── next.spec.js
│ │ ├── noConflict.spec.js
│ │ ├── parseDate.spec.js
│ │ ├── pick.spec.js
│ │ ├── prev.spec.js
│ │ ├── reset.spec.js
│ │ ├── setDate.spec.js
│ │ ├── setDefaults.spec.js
│ │ ├── show.spec.js
│ │ └── update.spec.js
│ └── options/
│ ├── container.spec.js
│ ├── controls.spec.js
│ ├── date.spec.js
│ ├── format.spec.js
│ ├── headers.spec.js
│ ├── hidden.spec.js
│ ├── hide.spec.js
│ ├── increment.spec.js
│ ├── inline.spec.js
│ ├── language.spec.js
│ ├── months.spec.js
│ ├── monthsShort.spec.js
│ ├── pick.spec.js
│ ├── rows.spec.js
│ ├── show.spec.js
│ ├── shown.spec.js
│ ├── text.spec.js
│ └── translate.spec.js
└── types/
└── index.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
]
],
"env": {
"test": {
"plugins": [
"istanbul"
]
}
}
}
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
================================================
FILE: .eslintrc
================================================
{
"extends": "airbnb-base",
"env": {
"browser": true
},
"root": true,
"rules": {
"no-param-reassign": "off",
"no-restricted-properties": "off",
"valid-jsdoc": ["error", {
"requireReturn": false
}]
}
}
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: .github/CODE_OF_CONDUCT.md
================================================
# Contributor Code of Conduct
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at https://www.contributor-covenant.org/version/1/0/0/code-of-conduct.html
================================================
FILE: .github/CONTRIBUTING.md
================================================
# Contributing to Picker.js
> Based on [Angular's contributing guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md).
We would love for you to contribute to Picker.js and help make it even better than it is today! As a contributor, here are the guidelines we would like you to follow:
- [Code of Conduct](#code-of-conduct)
- [Question or Problem](#question-or-problem)
- [Issues and Bugs](#issues-and-bugs)
- [Feature Requests](#feature-requests)
- [Submission Guidelines](#submission-guidelines)
- [Coding Rules](#coding-rules)
- [Commit Message Guidelines](#commit-message-guidelines)
## Code of Conduct
Help us keep Picker.js open and inclusive. Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md).
## Question or Problem
Do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [Stack Overflow](https://stackoverflow.com/questions/tagged/pickerjs) where the questions should be tagged with tag `pickerjs`.
Stack Overflow is a much better place to ask questions since:
- There are thousands of people willing to help on Stack Overflow.
- Questions and answers stay available for public viewing so your question / answer might help someone else.
- Stack Overflow's voting system assures that the best answers are prominently visible.
To save your and our time, we will systematically close all issues that are requests for general support and redirect people to Stack Overflow.
## Issues and Bugs
If you find a bug in the source code, you can help us by [submitting an issue](#submitting-an-issue) to our [GitHub Repository](https://github.com/fengyuanchen/pickerjs). Even better, you can [submit a Pull Request](#submitting-a-pull-request-pr) with a fix.
## Feature Requests
You can *request* a new feature by [submitting an issue](#submitting-an-issue) to our [GitHub Repository](https://github.com/fengyuanchen/pickerjs). If you would like to *implement* a new feature, please submit an issue with a proposal for your work first, to be sure that we can use it.
Please consider what kind of change it is:
- For a **Major Feature**, first open an issue and outline your proposal so that it can be discussed. This will also allow us to better coordinate our efforts, prevent duplication of work, and help you to craft the change so that it is successfully accepted into the project.
- **Small Features** can be crafted and directly [submitted as a Pull Request](#submitting-a-pull-request-pr).
## Submission Guidelines
### Submitting an Issue
Before you submit an issue, please search the [issue tracker](https://github.com/fengyuanchen/pickerjs/issues), maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available.
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using [CodePen](https://codepen.io/pen). Having a live, reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like:
- version of Picker.js used
- 3rd-party libraries and their versions
- and most importantly - a use-case that fails
A minimal reproduce scenario using [CodePen](https://codepen.io/pen) allows us to quickly confirm a bug (or point out coding problem) as well as confirm that we are fixing the right problem. If [CodePen](https://codepen.io/pen) is not a suitable way to demonstrate the problem (for example for issues related to our npm packaging), please create a standalone git repository demonstrating the problem.
We will be insisting on a minimal reproduce scenario in order to save maintainers time and ultimately be able to fix more bugs. Interestingly, from our experience users often find coding problems themselves while preparing a minimal reproduce scenario. We understand that sometimes it might be hard to extract essentials bits of code from a larger code-base but we really need to isolate the problem before we can fix it.
Unfortunately we are not able to investigate / fix bugs without a minimal reproduce scenario, so if we don't hear back from you we are going to close an issue that don't have enough info to be reproduced.
You can file new issues by filling out our [new issue form](https://github.com/fengyuanchen/pickerjs/issues/new).
### Submitting a Pull Request (PR)
Before you submit your Pull Request (PR) consider the following guidelines:
1. Search [GitHub](https://github.com/fengyuanchen/pickerjs/pulls) for an open or closed PR that relates to your submission. You don't want to duplicate effort.
1. Fork the **fengyuanchen/pickerjs** repo.
1. Make your changes in a new git branch:
```shell
git checkout -b my-fix-branch master
```
1. Create your patch, **including appropriate test cases**.
1. Follow our [Coding Rules](#coding-rules).
1. Run the full Picker.js test suite, and ensure that all tests pass.
1. Commit your changes using a descriptive commit message that follows our [Commit Message Guidelines](#commit-message-guidelines). Adherence to these guidelines is necessary because release notes are automatically generated from these messages.
```shell
git commit -a
```
Note: the optional commit `-a` command line option will automatically "add" and "rm" edited files.
1. Push your branch to GitHub:
```shell
git push origin my-fix-branch
```
1. In GitHub, send a pull request to `pickerjs:master`.
1. If we suggest changes then:
- Make the required updates.
- Re-run the Picker.js test suites to ensure tests are still passing.
- Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
```shell
git rebase master -i
git push -f
```
That's it! Thank you for your contribution!
#### After your pull request is merged
After your pull request is merged, you can safely delete your branch and pull the changes from the main (upstream) repository:
1. Delete the remote branch on GitHub either through the GitHub web UI or your local shell as follows:
```shell
git push origin --delete my-fix-branch
```
1. Check out the master branch:
```shell
git checkout master -f
```
1. Delete the local branch:
```shell
git branch -D my-fix-branch
```
1. Update your master with the latest upstream version:
```shell
git pull --ff upstream master
```
## Coding Rules
To ensure consistency throughout the source code, keep these rules in mind as you are working:
- All features or bug fixes **must be tested** by one or more specs (unit-tests).
- All public API methods **must be documented**.
- We follow [Airbnb's JavaScript Style Guide](https://github.com/airbnb/javascript).
## Commit Message Guidelines
### Commit Message Format
A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier to read on GitHub as well as in various git tools.
The footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
Here are some [samples](https://github.com/fengyuanchen/pickerjs/commits/master).
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
Must be one of the following:
- **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
- **docs**: Documentation only changes
- **feat**: A new feature
- **fix**: A bug fix
- **perf**: A code change that improves performance
- **refactor**: A code change that neither fixes a bug nor adds a feature
- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- **test**: Adding missing tests or correcting existing tests
### Scope
The scope could be anything specifying place of the commit change. For example `move`, `zoom`, `rotate`, etc...
### Subject
The subject contains succinct description of the change:
- Use the imperative, present tense: "change" not "changed" nor "changes".
- Don't capitalize first letter.
- No dot (.) at the end.
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!--
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
-->
## I'm submitting a...
<!-- Check one of the following options with "x" -->
<pre><code>
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report <!-- Please search GitHub for a similar issue or PR before submitting -->
[ ] Feature request
[ ] Documentation issue or request
</code></pre>
## Current behavior
<!-- Describe how the issue manifests. -->
## Expected behavior
<!-- Describe what the desired behavior would be. -->
## Minimal reproduction of the problem with instructions
<!--
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
https://codepen.io/pen or similar.
-->
## What is the motivation / use case for changing the behavior?
<!-- Describe the motivation or the concrete use case. -->
## Environment
<pre><code>
Picker.js version: X.Y.Z
<!-- Check whether this is still an issue in the most recent Picker.js version -->
Browser:
- [ ] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
Others:
<!-- Anything else relevant? -->
</code></pre>
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
## PR Checklist
Please check if your PR fulfills the following requirements:
- [ ] The commit message follows our [guidelines](https://github.com/fengyuanchen/pickerjs/blob/master/.github/CONTRIBUTING.md#commit-message-guidelines).
- [ ] Tests for the changes have been added (for bug fixes / features)
- [ ] Docs have been added / updated (for bug fixes / features)
## PR Type
What kind of change does this PR introduce?
<!-- Please check the one that applies to this PR using "x". -->
```
[ ] Bugfix
[ ] Feature
[ ] Code style update
[ ] Refactor
[ ] Build related changes
[ ] Documentation content changes
[ ] Other, Please describe:
```
## What is the current behavior?
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
Issue Number: N/A
## What is the new behavior?
## Does this PR introduce a breaking change?
```
[ ] Yes
[ ] No
```
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->
## Other information
================================================
FILE: .gitignore
================================================
*.map
coverage
node_modules
================================================
FILE: .stylelintrc
================================================
{
"extends": "stylelint-config-standard",
"plugins": [
"stylelint-order"
],
"rules": {
"no-descending-specificity": null,
"order/properties-alphabetical-order": true
}
}
================================================
FILE: .travis.yml
================================================
language: node_js
node_js: node
cache: npm
script:
- npm run lint
- npm run build
- npm test
after_success:
- npm run codecov
================================================
FILE: CHANGELOG.md
================================================
# Changelog
## 1.2.1 (Feb 18, 2019)
- Remove duplicate tokens (#22).
- Use the latest date to calculate the max day (#23).
## 1.2.0 (Dec 16, 2018)
- Add the `controls` option.
- Enhance the `text` option for defining the text content of the column headers.
## 1.1.0 (Dec 15, 2018)
- Add the `headers` option for customizing the column headers (#20).
## 1.0.0 (Oct 25, 2018)
- Fix wrong BC year detecting when the date string has a `-` before year digits (#17).
## 1.0.0-rc (Oct 23, 2018)
- Add polish localization (#13).
- Fix wrong maximum day when month change (#15, #16).
## 1.0.0-beta (Jun 18, 2018)
- Refactor the core code.
- Refactor the test code.
- Add type definitions file for TypeScript.
- Fix page scrolling issue in iOS browsers (#9).
## 0.2.0 (Feb 11, 2018)
- Enhance the `format` option to support no separator mode as `YYYYMMDD` (#7).
## 0.1.2 (Mar 11, 2017)
- Improved event handler for Pointer Events (#3).
## 0.1.1 (Oct 22, 2016)
- Fixed the issue of increment and decrement (#1).
## 0.1.0 (Jul 16, 2016)
- Supports 16 options: `container`, `date`, `format`, `increment`, `inline`, `language`, `months`, `monthsShort`, `translate`, `rows`, `text`, `show`, `shown`, `hide`, `hidden` and `pick`.
- Supports 12 methods: `show`, `hide`, `prev`, `next`, `pick`, `getDate`, `setDate`, `update`, `reset`, `parseDate`, `formatDate` and `destroy`.
- Supports 5 events: `show`, `shown`, `hide`, `hidden` and `pick`.
## 0.0.1 (Jun 1, 2016)
- Init.
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright 2016-present Chen Fengyuan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: README.md
================================================
# Picker.js
[](https://travis-ci.org/fengyuanchen/pickerjs) [](https://codecov.io/gh/fengyuanchen/pickerjs) [](https://www.npmjs.com/package/pickerjs) [](https://www.npmjs.com/package/pickerjs)
> JavaScript date time picker.
- [Website](https://fengyuanchen.github.io/pickerjs)
## Table of contents
- [Main](#main)
- [Getting started](#getting-started)
- [Options](#options)
- [Methods](#methods)
- [Events](#events)
- [No conflict](#no-conflict)
- [Browser support](#browser-support)
- [Versioning](#versioning)
- [License](#license)
## Main
```text
dist/
├── picker.css
├── picker.min.css (compressed)
├── picker.js (UMD)
├── picker.min.js (UMD, compressed)
├── picker.common.js (CommonJS, default)
└── picker.esm.js (ES Module)
```
## Getting started
### Installation
```shell
npm install pickerjs
```
Include files:
```html
<link href="/path/to/picker.css" rel="stylesheet">
<script src="/path/to/picker.js"></script>
```
### Usage
#### Syntax
```js
new Picker(element[, options])
```
- **element**
- Type: `HTMLElement`
- The target element for picking.
- **options** (optional)
- Type: `Object`
- The options for picking. Check out the available [options](#options).
#### Example
```html
<input type="text" id="input">
```
```js
var input = document.getElementById('input');
var picker = new Picker(input, {
format: 'YYYY/MM/DD HH:mm',
});
```
[⬆ Back to top](#table-of-contents)
## Options
You may set picker options with `new Picker(element, options)`.
If you want to change the global default options, You may use `Picker.setDefaults(options)`.
### container
- Type: `Element` or `Selector`
- Default: `null`
Define the container for putting the picker. If not present, the picker will be appended to the `document.body`.
```js
new Picker(element, {
container: document.querySelector('.picker-container'),
});
```
Or
```js
new Picker(element, {
container: '.picker-container',
});
```
### controls
- Type: `Boolean`
- Default: `false`
Indicate whether show the prev and next arrow controls on each column.
### date
- Type: `Date` or `String`
- Default: `null`
The initial date. If not present, use the current date.
```js
new Picker(element, {
date: new Date(2048, 9, 24, 5, 12),
});
```
Or
```js
new Picker(element, {
date: '2048-10-24 05:12',
});
```
### format
- Type: `String`
- Default: `'YYYY-MM-DD HH:mm'`
- Tokens:
- `YYYY`: 4 digits year with leading zero
- `YYY`: 3 digits year with leading zero
- `YY`: 2 digits year with leading zero and be converted to a year near 2000
- `Y`: Years with any number of digits and sign
- `MMMM`: Month name
- `MMM`: Short month name
- `MM`: Month number with leading zero
- `M`: Month number
- `DD`: Day of month with leading zero
- `D`: Day of month
- `HH`: Hours with leading zero
- `H`: Hours
- `mm`: Minutes with leading zero
- `m`: Minutes
- `ss`: Seconds with leading zero
- `s`: Seconds
- `SSS`: Milliseconds with leading zero
- `SS`: Milliseconds with leading zero
- `S`: Milliseconds
The date string format, also as the sorting order of date time columns.
```js
new Picker(element, {
date: '2048-10-24 05:12:02.056',
format: 'YYYY-MM-DD HH:mm:ss.SSS',
});
```
Or
```js
new Picker(element, {
date: 'Oct 24, 2048',
format: 'MMM D, YYYY',
});
```
### headers
- Type: `Boolean`
- Default: `false`
Indicate whether show the column headers. The text content of each header is defined in the `text` option.
### increment
- Type: `Number` or `Object`
- Default: `1`
Define the increment for each date time part.
```js
new Picker(element, {
increment: 10,
});
```
Or
```js
new Picker(element, {
increment: {
year: 1,
month: 1,
day: 1,
hour: 1,
minute: 10,
second: 10,
millisecond: 100,
},
});
```
### inline
- Type: `Boolean`
- Default: `false`
Enable inline mode.
### language
- Type: `String` (ISO language code)
- Default: `''`
Define the language.
> You should define the language first. Check out the [i18n](i18n) folder for more information.
### months
- Type: `Array`
- Default: `['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']`
Months' name.
### monthsShort
- Type: `Array`
- Default: `['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']`
Short months' name.
### rows
- Type: `Number`
- Default: `5`
Define the number of rows for showing.
### text
- Type: `Object`
- Default:
```js
{
title: 'Pick a date and time',
cancel: 'Cancel',
confirm: 'OK',
year: 'Year',
month: 'Month',
day: 'Day',
hour: 'Hour',
minute: 'Minute',
second: 'Second',
millisecond: 'Millisecond',
}
```
Define the title and button text of the picker.
### translate
- Type: `Function`
- Default:
```js
function (type, text) {
return text;
}
```
Translate date time text.
```js
new Picker(element, {
translate(type, text) {
const aliases = ['〇', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
return String(text).split('').map((n) => aliases[Number(n)]).join('');
},
});
```
### show
- Type: `Function`
- Default: `null`
The shortcut of the `show` event.
### shown
- Type: `Function`
- Default: `null`
The shortcut of the `shown` event.
### hide
- Type: `Function`
- Default: `null`
The shortcut of the `hide` event.
### hidden
- Type: `Function`
- Default: `null`
The shortcut of the `hidden` event.
### pick
- Type: `Function`
- Default: `null`
The shortcut of the `pick` event.
[⬆ Back to top](#table-of-contents)
## Methods
If a method doesn't need to return any value, it will return the picker instance (`this`) for chain composition.
### show()
Show the picker.
### hide()
Hide the picker.
### prev(type)
- **type**:
- Type: `String`
- Options: `'year'`, `'month'`, `'day'`, `'hour'`, `'minute'`, `'second'`, `'millisecond'`
- Date time type.
Pick the previous item.
### next(type)
- **type**: (the same as the `prev` method)
Pick the next item.
### pick()
Pick the current date to the target element.
### getDate([formatted])
- **formatted** (optional):
- Type: `Boolean`
- Format the date.
- (return value):
- Type: `Date` or `String`
Get the current date.
```js
const picker = new Picker(element, {
date: new Date(2048, 9, 24, 5, 12),
});
picker.getDate();
// > Sat Oct 24 2048 05:12:00 GMT+0800 (China Standard Time)
picker.getDate(true);
// > 2048-10-24 05:12
```
### setDate(date)
- **date**:
- Type: `Date`
- The new date.
Override the current date with a new date.
### update()
Update the picker with the current the element value / text.
### reset()
Reset the picker and the element value / text.
### parseDate(date)
- **date**:
- Type: `String`
- (return value):
- Type: `Date`
Parse a date string with the set date format.
```js
const picker = new Picker(element, options);
picker.parseDate('2048-10-24 05:12');
// > Sat Oct 24 2048 05:12:00 GMT+0800 (China Standard Time)
```
### formatDate(date)
- **date**:
- Type: `Date`
- (return value):
- Type: `String`
- The formatted date string.
Format a date object to a string with the set date format.
```js
const picker = new Picker(element, options);
picker.formatDate(new Date(2048, 9, 24, 5, 12));
// > 2048-10-24 05:12
```
### destroy()
Destroy the picker and remove the instance from the target element.
[⬆ Back to top](#table-of-contents)
## Events
### show
This event fires when a picker modal starts to show.
> Only available in non-inline mode.
### shown
This event fires when a picker modal has shown.
> Only available in non-inline mode.
### hide
This event fires when a picker modal starts to hide.
> Only available in non-inline mode.
### hidden
This event fires when a picker modal has hidden.
> Only available in non-inline mode.
### pick
This event fires when pick the current date to the target element.
> If the target element is an `<input>` or `<textarea>` element, then a `change` event will be triggered too.
[⬆ Back to top](#table-of-contents)
## No conflict
If you have to use other picker with the same namespace, just call the `Picker.noConflict` static method to revert to it.
```html
<script src="other-picker.js"></script>
<script src="picker.js"></script>
<script>
Picker.noConflict();
// Code that uses other `Picker` can follow here.
</script>
```
## Browser support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Opera (latest)
- Edge (latest)
- Internet Explorer 9+
## Versioning
Maintained under the [Semantic Versioning guidelines](https://semver.org).
## License
[MIT](https://opensource.org/licenses/MIT) © [Chen Fengyuan](https://chenfengyuan.com)
[⬆ Back to top](#table-of-contents)
================================================
FILE: dist/picker.common.js
================================================
/*!
* Picker.js v1.2.1
* https://fengyuanchen.github.io/pickerjs
*
* Copyright 2016-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2019-02-18T13:08:12.801Z
*/
'use strict';
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
}
var DEFAULTS = {
// Define the container for putting the picker.
container: null,
// Indicate whether show the prev and next arrow controls on each column.
controls: false,
// The initial date. If not present, use the current date.
date: null,
// The date string format, also as the sorting order for columns.
format: 'YYYY-MM-DD HH:mm',
// Indicate whether show the column headers.
headers: false,
// Define the increment for each date / time part.
increment: 1,
// Enable inline mode.
inline: false,
// Define the language. (An ISO language code).
language: '',
// Months' name.
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
// Shorter months' name.
monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
// Define the number of rows for showing.
rows: 5,
// Define the text of the picker.
text: {
title: 'Pick a date and time',
cancel: 'Cancel',
confirm: 'OK',
year: 'Year',
month: 'Month',
day: 'Day',
hour: 'Hour',
minute: 'Minute',
second: 'Second',
millisecond: 'Millisecond'
},
// Translate date / time text.
translate: function translate(type, text) {
return text;
},
// Shortcuts of custom events.
show: null,
shown: null,
hide: null,
hidden: null,
pick: null
};
var TEMPLATE = '<div class="picker" data-picker-action="hide" touch-action="none" tabindex="-1" role="dialog">' + '<div class="picker-dialog" role="document">' + '<div class="picker-header">' + '<h4 class="picker-title">{{ title }}</h4>' + '<button type="button" class="picker-close" data-picker-action="hide" aria-label="Close">×</button>' + '</div>' + '<div class="picker-body">' + '<div class="picker-grid"></div>' + '</div>' + '<div class="picker-footer">' + '<button type="button" class="picker-cancel" data-picker-action="hide">{{ cancel }}</button>' + '<button type="button" class="picker-confirm" data-picker-action="pick">{{ confirm }}</button>' + '</div>' + '</div>' + '</div>';
var IS_BROWSER = typeof window !== 'undefined';
var WINDOW = IS_BROWSER ? window : {};
var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false;
var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
var NAMESPACE = 'picker';
var LANGUAGES = {}; // Actions
var ACTION_HIDE = 'hide';
var ACTION_NEXT = 'next';
var ACTION_PICK = 'pick';
var ACTION_PREV = 'prev'; // Classes
var CLASS_OPEN = "".concat(NAMESPACE, "-open");
var CLASS_OPENED = "".concat(NAMESPACE, "-opened");
var CLASS_PICKED = "".concat(NAMESPACE, "-picked"); // Data keys
// Add namespace to avoid to conflict to some other libraries.
var DATA_ACTION = "".concat(NAMESPACE, "Action");
var DATA_TOKEN = 'token';
var DATA_TYPE = 'type';
var DATA_NAME = 'name';
var DATA_VALUE = 'value'; // Events
var EVENT_CLICK = 'click';
var EVENT_FOCUS = 'focus';
var EVENT_HIDDEN = 'hidden';
var EVENT_HIDE = 'hide';
var EVENT_KEY_DOWN = 'keydown';
var EVENT_PICK = 'pick';
var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';
var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';
var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup';
var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START;
var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE;
var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;
var EVENT_SHOW = 'show';
var EVENT_SHOWN = 'shown';
var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
var _Object$prototype = Object.prototype,
hasOwnProperty = _Object$prototype.hasOwnProperty,
toString = _Object$prototype.toString;
/**
* Detect the type of the given value.
* @param {*} value - The value to detect.
* @returns {string} Returns the type.
*/
function typeOf(value) {
return toString.call(value).slice(8, -1).toLowerCase();
}
/**
* Check if the given value is a string.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a string, else `false`.
*/
function isString(value) {
return typeof value === 'string';
}
/**
* Check if the given value is finite.
*/
var isFinite = Number.isFinite || WINDOW.isFinite;
/**
* Check if the given value is not a number.
*/
var isNaN = Number.isNaN || WINDOW.isNaN;
/**
* Check if the given value is a number.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a number, else `false`.
*/
function isNumber(value) {
return typeof value === 'number' && !isNaN(value);
}
/**
* Check if the given value is an object.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is an object, else `false`.
*/
function isObject(value) {
return _typeof(value) === 'object' && value !== null;
}
/**
* Check if the given value is a plain object.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a plain object, else `false`.
*/
function isPlainObject(value) {
if (!isObject(value)) {
return false;
}
try {
var _constructor = value.constructor;
var prototype = _constructor.prototype;
return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');
} catch (error) {
return false;
}
}
/**
* Check if the given value is a function.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a function, else `false`.
*/
function isFunction(value) {
return typeof value === 'function';
}
/**
* Check if the given value is a date.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a date, else `false`.
*/
function isDate(value) {
return typeOf(value) === 'date';
}
/**
* Check if the given value is a valid date.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a valid date, else `false`.
*/
function isValidDate(value) {
return isDate(value) && value.toString() !== 'Invalid Date';
}
/**
* Iterate the given data.
* @param {*} data - The data to iterate.
* @param {Function} callback - The process function for each element.
* @returns {*} The original data.
*/
function forEach(data, callback) {
if (data && isFunction(callback)) {
if (Array.isArray(data) || isNumber(data.length)
/* array-like */
) {
var length = data.length;
var i;
for (i = 0; i < length; i += 1) {
if (callback.call(data, data[i], i, data) === false) {
break;
}
}
} else if (isObject(data)) {
Object.keys(data).forEach(function (key) {
callback.call(data, data[key], key, data);
});
}
}
return data;
}
/**
* Recursively assigns own enumerable properties of source objects to the target object.
* @param {Object} target - The target object.
* @param {Object[]} sources - The source objects.
* @returns {Object} The target object.
*/
function deepAssign(target) {
for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
sources[_key - 1] = arguments[_key];
}
if (isObject(target) && sources.length > 0) {
sources.forEach(function (source) {
if (isObject(source)) {
Object.keys(source).forEach(function (key) {
if (isPlainObject(target[key]) && isPlainObject(source[key])) {
target[key] = deepAssign({}, target[key], source[key]);
} else {
target[key] = source[key];
}
});
}
});
}
return target;
}
/**
* Add classes to the given element.
* @param {Element} element - The target element.
* @param {string} value - The classes to be added.
*/
function addClass(element, value) {
if (!value) {
return;
}
if (isNumber(element.length)) {
forEach(element, function (elem) {
addClass(elem, value);
});
return;
}
if (element.classList) {
element.classList.add(value);
return;
}
var className = element.className.trim();
if (!className) {
element.className = value;
} else if (className.indexOf(value) < 0) {
element.className = "".concat(className, " ").concat(value);
}
}
/**
* Remove classes from the given element.
* @param {Element} element - The target element.
* @param {string} value - The classes to be removed.
*/
function removeClass(element, value) {
if (!value) {
return;
}
if (isNumber(element.length)) {
forEach(element, function (elem) {
removeClass(elem, value);
});
return;
}
if (element.classList) {
element.classList.remove(value);
return;
}
if (element.className.indexOf(value) >= 0) {
element.className = element.className.replace(value, '');
}
}
var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
/**
* Transform the given string from camelCase to kebab-case
* @param {string} value - The value to transform.
* @returns {string} The transformed value.
*/
function hyphenate(value) {
return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase();
}
/**
* Get data from the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to get.
* @returns {string} The data value.
*/
function getData(element, name) {
if (isObject(element[name])) {
return element[name];
}
if (element.dataset) {
return element.dataset[name];
}
return element.getAttribute("data-".concat(hyphenate(name)));
}
/**
* Set data to the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to set.
* @param {string} data - The data value.
*/
function setData(element, name, data) {
if (isObject(data)) {
element[name] = data;
} else if (element.dataset) {
element.dataset[name] = data;
} else {
element.setAttribute("data-".concat(hyphenate(name)), data);
}
}
/**
* Remove data from the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to remove.
*/
function removeData(element, name) {
if (isObject(element[name])) {
try {
delete element[name];
} catch (error) {
element[name] = undefined;
}
} else if (element.dataset) {
// #128 Safari not allows to delete dataset property
try {
delete element.dataset[name];
} catch (error) {
element.dataset[name] = undefined;
}
} else {
element.removeAttribute("data-".concat(hyphenate(name)));
}
}
var REGEXP_SPACES = /\s\s*/;
var onceSupported = function () {
var supported = false;
if (IS_BROWSER) {
var once = false;
var listener = function listener() {};
var options = Object.defineProperty({}, 'once', {
get: function get() {
supported = true;
return once;
},
/**
* This setter can fix a `TypeError` in strict mode
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}
* @param {boolean} value - The value to set
*/
set: function set(value) {
once = value;
}
});
WINDOW.addEventListener('test', listener, options);
WINDOW.removeEventListener('test', listener, options);
}
return supported;
}();
/**
* Remove event listener from the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Function} listener - The event listener.
* @param {Object} options - The event options.
*/
function removeListener(element, type, listener) {
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var handler = listener;
type.trim().split(REGEXP_SPACES).forEach(function (event) {
if (!onceSupported) {
var listeners = element.listeners;
if (listeners && listeners[event] && listeners[event][listener]) {
handler = listeners[event][listener];
delete listeners[event][listener];
if (Object.keys(listeners[event]).length === 0) {
delete listeners[event];
}
if (Object.keys(listeners).length === 0) {
delete element.listeners;
}
}
}
element.removeEventListener(event, handler, options);
});
}
/**
* Add event listener to the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Function} listener - The event listener.
* @param {Object} options - The event options.
*/
function addListener(element, type, listener) {
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var _handler = listener;
type.trim().split(REGEXP_SPACES).forEach(function (event) {
if (options.once && !onceSupported) {
var _element$listeners = element.listeners,
listeners = _element$listeners === void 0 ? {} : _element$listeners;
_handler = function handler() {
delete listeners[event][listener];
element.removeEventListener(event, _handler, options);
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
listener.apply(element, args);
};
if (!listeners[event]) {
listeners[event] = {};
}
if (listeners[event][listener]) {
element.removeEventListener(event, listeners[event][listener], options);
}
listeners[event][listener] = _handler;
element.listeners = listeners;
}
element.addEventListener(event, _handler, options);
});
}
/**
* Dispatch event on the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Object} data - The additional event data.
* @returns {boolean} Indicate if the event is default prevented or not.
*/
function dispatchEvent(element, type, data) {
var event; // Event and CustomEvent on IE9-11 are global objects, not constructors
if (isFunction(Event) && isFunction(CustomEvent)) {
event = new CustomEvent(type, {
detail: data,
bubbles: true,
cancelable: true
});
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(type, true, true, data);
}
return element.dispatchEvent(event);
}
/**
* Check if the given year is a leap year.
* @param {number} year - The year to check.
* @returns {boolean} Returns `true` if the given year is a leap year, else `false`.
*/
function isLeapYear(year) {
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
}
/**
* Get days number of the given month.
* @param {number} year - The target year.
* @param {number} month - The target month.
* @returns {number} Returns days number.
*/
function getDaysInMonth(year, month) {
return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
}
/**
* Add leading zeroes to the given value
* @param {number} value - The value to add.
* @param {number} [length=1] - The number of the leading zeroes.
* @returns {string} Returns converted value.
*/
function addLeadingZero(value) {
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var str = String(Math.abs(value));
var i = str.length;
var result = '';
if (value < 0) {
result += '-';
}
while (i < length) {
i += 1;
result += '0';
}
return result + str;
}
/**
* Map token to type name
* @param {string} token - The token to map.
* @returns {string} Returns mapped type name.
*/
function tokenToType(token) {
return {
Y: 'year',
M: 'month',
D: 'day',
H: 'hour',
m: 'minute',
s: 'second',
S: 'millisecond'
}[token.charAt(0)];
}
var REGEXP_TOKENS = /(Y|M|D|H|m|s|S)\1*/g;
/**
* Parse date format.
* @param {string} format - The format to parse.
* @returns {Object} Returns parsed format data.
*/
function parseFormat(format) {
var tokens = format.match(REGEXP_TOKENS);
if (!tokens) {
throw new Error('Invalid format.');
} // Remove duplicate tokens (#22)
tokens = tokens.filter(function (token, index) {
return tokens.indexOf(token) === index;
});
var result = {
tokens: tokens
};
tokens.forEach(function (token) {
result[tokenToType(token)] = token;
});
return result;
}
var events = {
bind: function bind() {
var element = this.element,
options = this.options,
grid = this.grid;
if (isFunction(options.show)) {
addListener(element, EVENT_SHOW, options.show);
}
if (isFunction(options.shown)) {
addListener(element, EVENT_SHOWN, options.shown);
}
if (isFunction(options.hide)) {
addListener(element, EVENT_HIDE, options.hide);
}
if (isFunction(options.hidden)) {
addListener(element, EVENT_HIDDEN, options.hidden);
}
if (isFunction(options.pick)) {
addListener(element, EVENT_PICK, options.pick);
}
addListener(element, EVENT_FOCUS, this.onFocus = this.focus.bind(this));
addListener(element, EVENT_CLICK, this.onFocus);
addListener(this.picker, EVENT_CLICK, this.onClick = this.click.bind(this));
addListener(grid, EVENT_WHEEL, this.onWheel = this.wheel.bind(this));
addListener(grid, EVENT_POINTER_DOWN, this.onPointerDown = this.pointerdown.bind(this));
addListener(document, EVENT_POINTER_MOVE, this.onPointerMove = this.pointermove.bind(this));
addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
},
unbind: function unbind() {
var element = this.element,
options = this.options,
grid = this.grid;
if (isFunction(options.show)) {
removeListener(element, EVENT_SHOW, options.show);
}
if (isFunction(options.shown)) {
removeListener(element, EVENT_SHOWN, options.shown);
}
if (isFunction(options.hide)) {
removeListener(element, EVENT_HIDE, options.hide);
}
if (isFunction(options.hidden)) {
removeListener(element, EVENT_HIDDEN, options.hidden);
}
if (isFunction(options.pick)) {
removeListener(element, EVENT_PICK, options.pick);
}
removeListener(element, EVENT_FOCUS, this.onFocus);
removeListener(element, EVENT_CLICK, this.onFocus);
removeListener(this.picker, EVENT_CLICK, this.onClick);
removeListener(grid, EVENT_WHEEL, this.onWheel);
removeListener(grid, EVENT_POINTER_DOWN, this.onPointerDown);
removeListener(document, EVENT_POINTER_MOVE, this.onPointerMove);
removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
}
};
var handlers = {
focus: function focus(event) {
event.target.blur();
this.show();
},
click: function click(event) {
var target = event.target;
var action = getData(target, DATA_ACTION);
switch (action) {
case ACTION_HIDE:
this.hide();
break;
case ACTION_PICK:
this.pick();
break;
case ACTION_PREV:
case ACTION_NEXT:
this[action](getData(target.parentElement, DATA_TYPE));
break;
default:
}
},
wheel: function wheel(event) {
var target = event.target;
if (target === this.grid) {
return;
}
event.preventDefault();
while (target.parentElement && target.parentElement !== this.grid) {
target = target.parentElement;
}
var type = getData(target, DATA_TYPE);
if (event.deltaY < 0) {
this.prev(type);
} else {
this.next(type);
}
},
pointerdown: function pointerdown(event) {
var target = event.target;
if (target === this.grid || getData(target, DATA_ACTION)) {
return;
} // This line is required for preventing page scrolling in iOS browsers
event.preventDefault();
while (target.parentElement && target.parentElement !== this.grid) {
target = target.parentElement;
}
var list = target.querySelector(".".concat(NAMESPACE, "-list"));
var itemHeight = list.firstElementChild.offsetHeight;
this.cell = {
elem: target,
list: list,
moveY: 0,
maxMoveY: itemHeight,
minMoveY: itemHeight / 2,
startY: event.changedTouches ? event.changedTouches[0].pageY : event.pageY,
type: getData(target, DATA_TYPE)
};
},
pointermove: function pointermove(event) {
var cell = this.cell;
if (!cell) {
return;
}
event.preventDefault();
var endY = event.changedTouches ? event.changedTouches[0].pageY : event.pageY;
var moveY = cell.moveY + (endY - cell.startY);
cell.startY = endY;
cell.moveY = moveY;
if (Math.abs(moveY) < cell.maxMoveY) {
cell.list.style.top = "".concat(moveY, "px");
return;
}
cell.list.style.top = 0;
cell.moveY = 0;
if (moveY >= cell.maxMoveY) {
this.prev(cell.type);
} else if (moveY <= -cell.maxMoveY) {
this.next(cell.type);
}
},
pointerup: function pointerup(event) {
var cell = this.cell;
if (!cell) {
return;
}
event.preventDefault();
cell.list.style.top = 0;
if (cell.moveY >= cell.minMoveY) {
this.prev(cell.type);
} else if (cell.moveY <= -cell.minMoveY) {
this.next(cell.type);
}
this.cell = null;
},
keydown: function keydown(event) {
if (this.shown && (event.key === 'Escape' || event.keyCode === 27)) {
this.hide();
}
}
};
var helpers = {
render: function render(type) {
var _this = this;
if (!type) {
this.format.tokens.forEach(function (token) {
return _this.render(tokenToType(token));
});
return;
}
var options = this.options;
var data = this.data[type];
var current = this.current(type);
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var base = 0;
if (isFinite(max)) {
base = min > 0 ? max : max + 1;
}
data.list.innerHTML = '';
data.current = current;
for (var i = 0; i < options.rows + 2; i += 1) {
var item = document.createElement('li');
var position = i - data.index;
var newValue = current + position * data.increment;
if (base) {
newValue %= base;
if (newValue < min) {
newValue += base;
}
}
item.textContent = options.translate(type, data.aliases ? data.aliases[newValue] : addLeadingZero(newValue + data.offset, data.digit));
setData(item, DATA_NAME, type);
setData(item, DATA_VALUE, newValue);
addClass(item, "".concat(NAMESPACE, "-item"));
if (position === 0) {
addClass(item, CLASS_PICKED);
data.item = item;
}
data.list.appendChild(item);
}
},
current: function current(type, value) {
var date = this.date;
var format = this.format;
var token = format[type];
switch (token.charAt(0)) {
case 'Y':
if (isNumber(value)) {
date.setFullYear(token.length === 2 ? 2000 + value : value);
if (format.month) {
this.render(tokenToType(format.month));
}
if (format.day) {
this.render(tokenToType(format.day));
}
}
return date.getFullYear();
case 'M':
if (isNumber(value)) {
date.setMonth(value, // The current day should not exceed its maximum day in current month
Math.min(date.getDate(), getDaysInMonth(date.getFullYear(), value)));
if (format.day) {
this.render(tokenToType(format.day));
}
}
return date.getMonth();
case 'D':
if (isNumber(value)) {
date.setDate(value);
}
return date.getDate();
case 'H':
if (isNumber(value)) {
date.setHours(value);
}
return date.getHours();
case 'm':
if (isNumber(value)) {
date.setMinutes(value);
}
return date.getMinutes();
case 's':
if (isNumber(value)) {
date.setSeconds(value);
}
return date.getSeconds();
case 'S':
if (isNumber(value)) {
date.setMilliseconds(value);
}
return date.getMilliseconds();
default:
}
return date;
},
getValue: function getValue() {
var element = this.element;
return this.isInput ? element.value : element.textContent;
},
setValue: function setValue(value) {
var element = this.element;
if (this.isInput) {
element.value = value;
} else if (this.options.container) {
element.textContent = value;
}
},
open: function open() {
var body = this.body;
body.style.overflow = 'hidden';
body.style.paddingRight = "".concat(this.scrollBarWidth + (parseFloat(this.initialBodyPaddingRight) || 0), "px");
},
close: function close() {
var body = this.body;
body.style.overflow = '';
body.style.paddingRight = this.initialBodyPaddingRight;
}
};
var methods = {
/**
* Show the picker.
* @param {boolean} [immediate=false] - Indicate if show the picker immediately or not.
* @returns {Picker} this
*/
show: function show() {
var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var element = this.element,
picker = this.picker;
if (this.inline || this.shown) {
return this;
}
if (dispatchEvent(element, EVENT_SHOW) === false) {
return this;
}
this.shown = true;
this.open();
addClass(picker, CLASS_OPEN);
var done = function done() {
dispatchEvent(element, EVENT_SHOWN);
};
if (!immediate) {
// Reflow to enable transition
// eslint-disable-next-line
picker.offsetWidth;
}
addClass(picker, CLASS_OPENED);
if (immediate) {
done();
} else {
setTimeout(done, 300);
}
return this;
},
/**
* Hide the picker.
* @param {boolean} [immediate=false] - Indicate if hide the picker immediately or not.
* @returns {Picker} this
*/
hide: function hide() {
var _this = this;
var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var element = this.element,
picker = this.picker;
if (this.inline || !this.shown) {
return this;
}
if (dispatchEvent(element, EVENT_HIDE) === false) {
return this;
}
this.shown = false;
removeClass(picker, CLASS_OPENED);
var done = function done() {
_this.close();
removeClass(picker, CLASS_OPEN);
dispatchEvent(element, EVENT_HIDDEN);
};
if (immediate) {
done();
} else {
setTimeout(done, 300);
}
return this;
},
/**
* Pick to the previous item.
* @param {string} type - The column type.
* @returns {Picker} this
*/
prev: function prev(type) {
var options = this.options;
var token = this.format[type];
var data = this.data[type];
var list = data.list;
var item = list.lastElementChild;
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var prev = data.item.previousElementSibling;
var value = Number(getData(list.firstElementChild, DATA_VALUE)) - data.increment;
if (value < min) {
value += max - min + 1;
}
item.textContent = options.translate(type, data.aliases ? data.aliases[value] : addLeadingZero(value + data.offset, token.length));
setData(item, DATA_VALUE, value);
if (prev) {
removeClass(data.item, CLASS_PICKED);
addClass(prev, CLASS_PICKED);
data.item = prev;
}
list.insertBefore(item, list.firstElementChild);
data.current = Number(getData(data.item, DATA_VALUE));
this.current(type, data.current);
if (this.inline && options.container) {
this.pick();
}
return this;
},
/**
* Pick to the next item.
* @param {String} type - The column type.
* @returns {Picker} this
*/
next: function next(type) {
var options = this.options;
var token = this.format[type];
var data = this.data[type];
var list = data.list;
var item = list.firstElementChild;
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var next = data.item.nextElementSibling;
var value = Number(getData(list.lastElementChild, DATA_VALUE)) + data.increment;
if (value > max) {
value -= max - min + 1;
}
item.textContent = options.translate(type, data.aliases ? data.aliases[value] : addLeadingZero(value + data.offset, token.length));
setData(item, DATA_VALUE, value);
list.appendChild(item);
if (next) {
removeClass(data.item, CLASS_PICKED);
addClass(next, CLASS_PICKED);
data.item = next;
}
data.current = Number(getData(data.item, DATA_VALUE));
this.current(type, data.current);
if (this.inline && options.container) {
this.pick();
}
return this;
},
// Pick the current date to the target element.
pick: function pick() {
var element = this.element;
if (dispatchEvent(element, EVENT_PICK) === false) {
return this;
}
var value = this.formatDate(this.date);
this.setValue(value);
if (this.isInput && dispatchEvent(element, 'change') === false) {
this.reset();
}
this.hide();
return this;
},
/**
* Get the current date.
* @param {boolean} [formatted=false] - Indicate if format the date or not.
* @return {Date|string} The output date.
*/
getDate: function getDate() {
var formatted = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var date = this.date;
return formatted ? this.formatDate(date) : new Date(date);
},
/**
* Override the current date with a new date.
* @param {Date|string} date - The date to set.
* @returns {Picker} this
*/
setDate: function setDate(date) {
if (date) {
this.date = this.parseDate(date);
this.render();
}
return this;
},
// Update the picker with the current element value / text.
update: function update() {
this.date = this.parseDate(this.getValue());
this.render();
return this;
},
// Reset the picker and element value / text.
reset: function reset() {
this.setValue(this.initialValue);
this.date = new Date(this.initialDate);
this.render();
return this;
},
/**
* Parse a date with the set date format.
* @param {Date|string} date - The date to parse.
* @returns {Date} The parsed date object.
*/
parseDate: function parseDate(date) {
var options = this.options,
format = this.format;
var digits = [];
if (isDate(date)) {
return new Date(date);
}
if (isString(date)) {
var groups = [].concat(_toConsumableArray(options.months), _toConsumableArray(options.monthsShort), ['\\d+']);
digits = date.match(new RegExp("(".concat(groups.join('|'), ")"), 'g')); // Parse `11111111` (YYYYMMDD) to ['1111', '11', '11']
if (digits && date.length === options.format.length && digits.length !== format.tokens.length) {
digits = format.tokens.map(function (token) {
return date.substr(options.format.indexOf(token), token.length);
});
}
if (!digits || digits.length !== format.tokens.length) {
return new Date();
}
}
var parsedDate = new Date();
digits.forEach(function (digit, i) {
var token = format.tokens[i];
var n = Number(digit);
switch (token) {
case 'YYYY':
case 'YYY':
case 'Y':
{
var index = date.indexOf(digit);
var isHyphen = date.substr(index - 1, 1) === '-';
var isBC = index > 1 && isHyphen && /\S/.test(date.substr(index - 2, 1)) || index === 1 && isHyphen;
parsedDate.setFullYear(isBC ? -n : n);
break;
}
case 'YY':
parsedDate.setFullYear(2000 + n);
break;
case 'MMMM':
parsedDate.setMonth(options.months.indexOf(digit));
break;
case 'MMM':
parsedDate.setMonth(options.monthsShort.indexOf(digit));
break;
case 'MM':
case 'M':
parsedDate.setMonth(n - 1);
break;
case 'DD':
case 'D':
parsedDate.setDate(n);
break;
case 'HH':
case 'H':
parsedDate.setHours(n);
break;
case 'mm':
case 'm':
parsedDate.setMinutes(n);
break;
case 'ss':
case 's':
parsedDate.setSeconds(n);
break;
case 'SSS':
case 'SS':
case 'S':
parsedDate.setMilliseconds(n);
break;
default:
}
});
return parsedDate;
},
/**
* Format a date object to a string with the set date format.
* @param {Date} date - The date to format.
* @return {string} THe formatted date.
*/
formatDate: function formatDate(date) {
var options = this.options,
format = this.format;
var formatted = '';
if (isValidDate(date)) {
var year = date.getFullYear();
var month = date.getMonth();
var day = date.getDate();
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
var milliseconds = date.getMilliseconds();
formatted = options.format;
format.tokens.forEach(function (token) {
var replacement = '';
switch (token) {
case 'YYYY':
case 'YYY':
case 'Y':
replacement = addLeadingZero(year, token.length);
break;
case 'YY':
replacement = addLeadingZero(year % 100, 2);
break;
case 'MMMM':
replacement = options.months[month];
break;
case 'MMM':
replacement = options.monthsShort[month];
break;
case 'MM':
case 'M':
replacement = addLeadingZero(month + 1, token.length);
break;
case 'DD':
case 'D':
replacement = addLeadingZero(day, token.length);
break;
case 'HH':
case 'H':
replacement = addLeadingZero(hours, token.length);
break;
case 'mm':
case 'm':
replacement = addLeadingZero(minutes, token.length);
break;
case 'ss':
case 's':
replacement = addLeadingZero(seconds, token.length);
break;
case 'SSS':
case 'SS':
case 'S':
replacement = addLeadingZero(milliseconds, token.length);
break;
default:
}
formatted = formatted.replace(token, replacement);
});
}
return formatted;
},
// Destroy the picker and remove the instance from the target element.
destroy: function destroy() {
var element = this.element,
picker = this.picker;
if (!getData(element, NAMESPACE)) {
return this;
}
this.hide(true);
this.unbind();
removeData(element, NAMESPACE);
picker.parentNode.removeChild(picker);
return this;
}
};
var REGEXP_DELIMITER = /\{\{\s*(\w+)\s*\}\}/g;
var REGEXP_INPUTS = /input|textarea/i;
var AnotherPicker = WINDOW.Picker;
var Picker =
/*#__PURE__*/
function () {
/**
* Create a new Picker.
* @param {Element} element - The target element for picking.
* @param {Object} [options={}] - The configuration options.
*/
function Picker(element) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Picker);
if (!element || element.nodeType !== 1) {
throw new Error('The first argument is required and must be an element.');
}
this.element = element;
this.options = deepAssign({}, DEFAULTS, LANGUAGES[options.language], isPlainObject(options) && options);
this.shown = false;
this.init();
}
_createClass(Picker, [{
key: "init",
value: function init() {
var _this = this;
var element = this.element;
if (getData(element, NAMESPACE)) {
return;
}
setData(element, NAMESPACE, this);
var options = this.options;
var isInput = REGEXP_INPUTS.test(element.tagName);
var inline = options.inline && (options.container || !isInput);
var template = document.createElement('div');
template.insertAdjacentHTML('afterbegin', TEMPLATE.replace(REGEXP_DELIMITER, function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return options.text[args[1]];
}));
var picker = template.getElementsByClassName(NAMESPACE)[0];
var grid = picker.getElementsByClassName("".concat(NAMESPACE, "-grid"))[0];
var container = options.container;
if (isString(container)) {
container = document.querySelector(container);
}
if (inline) {
addClass(picker, CLASS_OPEN);
addClass(picker, CLASS_OPENED);
if (!container) {
container = element;
}
} else {
var ownerDocument = element.ownerDocument;
var body = ownerDocument.body || ownerDocument.documentElement;
this.body = body;
this.scrollBarWidth = WINDOW.innerWidth - ownerDocument.documentElement.clientWidth;
this.initialBodyPaddingRight = WINDOW.getComputedStyle(body).paddingRight;
addClass(picker, "".concat(NAMESPACE, "-fixed"));
if (!container) {
container = document.body;
}
}
this.isInput = isInput;
this.inline = inline;
this.container = container;
this.picker = picker;
this.grid = grid;
this.cell = null;
this.format = parseFormat(options.format);
var initialValue = this.getValue();
var date = this.parseDate(options.date || initialValue);
this.date = date;
this.initialDate = new Date(date);
this.initialValue = initialValue;
this.data = {};
var rows = Number(options.rows);
if (!(rows % 2)) {
rows += 1;
}
options.rows = rows || 5;
addClass(grid, "".concat(NAMESPACE, "-").concat(options.rows > 1 ? 'multiple' : 'single'));
if (options.controls) {
addClass(grid, "".concat(NAMESPACE, "-controls"));
}
var headers = options.headers,
increment = options.increment;
if (headers) {
addClass(grid, "".concat(NAMESPACE, "-headers")); // TODO: Drop the `headers` option's object support in v2.
headers = isPlainObject(headers) ? headers : options.text;
}
if (!isPlainObject(increment)) {
increment = {
year: increment,
month: increment,
day: increment,
hour: increment,
minute: increment,
second: increment,
millisecond: increment
};
}
this.format.tokens.forEach(function (token) {
var type = tokenToType(token);
var cell = document.createElement('div');
var cellBody = document.createElement('div');
var list = document.createElement('ul');
var data = {
digit: token.length,
increment: Math.abs(Number(increment[type])) || 1,
list: list,
max: Infinity,
min: -Infinity,
index: Math.floor((options.rows + 2) / 2),
offset: 0
};
switch (token.charAt(0)) {
case 'Y':
if (data.digit === 2) {
data.max = 99;
data.min = 0;
}
break;
case 'M':
data.max = 11;
data.min = 0;
data.offset = 1;
if (data.digit === 3) {
data.aliases = options.monthsShort;
} else if (data.digit === 4) {
data.aliases = options.months;
}
break;
case 'D':
// XXX: Use the latest date to calculate the max day (#23)
data.max = function () {
return getDaysInMonth(_this.date.getFullYear(), _this.date.getMonth());
};
data.min = 1;
break;
case 'H':
data.max = 23;
data.min = 0;
break;
case 'm':
data.max = 59;
data.min = 0;
break;
case 's':
data.max = 59;
data.min = 0;
break;
case 'S':
data.max = 999;
data.min = 0;
break;
default:
}
setData(cell, DATA_TYPE, type);
setData(cell, DATA_TOKEN, token);
if (headers) {
var cellHeader = document.createElement('div');
addClass(cellHeader, "".concat(NAMESPACE, "-cell__header"));
cellHeader.textContent = headers[type] || type[0].toUpperCase() + type.substr(1);
cell.appendChild(cellHeader);
}
if (options.controls) {
var prev = document.createElement('div');
addClass(prev, "".concat(NAMESPACE, "-cell__control"));
addClass(prev, "".concat(NAMESPACE, "-cell__control--prev"));
setData(prev, DATA_ACTION, ACTION_PREV);
cell.appendChild(prev);
}
addClass(list, "".concat(NAMESPACE, "-list"));
addClass(cellBody, "".concat(NAMESPACE, "-cell__body"));
addClass(cell, "".concat(NAMESPACE, "-cell"));
addClass(cell, "".concat(NAMESPACE, "-").concat(type, "s"));
cellBody.appendChild(list);
cell.appendChild(cellBody);
if (options.controls) {
var next = document.createElement('div');
addClass(next, "".concat(NAMESPACE, "-cell__control"));
addClass(next, "".concat(NAMESPACE, "-cell__control--next"));
setData(next, DATA_ACTION, ACTION_NEXT);
cell.appendChild(next);
}
grid.appendChild(cell);
_this.data[type] = data;
_this.render(type);
});
if (inline) {
container.innerHTML = '';
}
container.appendChild(picker);
this.bind();
}
/**
* Get the no conflict picker class.
* @returns {Picker} The picker class.
*/
}], [{
key: "noConflict",
value: function noConflict() {
WINDOW.Picker = AnotherPicker;
return Picker;
}
/**
* Change the default options.
* @param {Object} options - The new default options.
*/
}, {
key: "setDefaults",
value: function setDefaults(options) {
deepAssign(DEFAULTS, LANGUAGES[options.language], isPlainObject(options) && options);
}
}]);
return Picker;
}();
deepAssign(Picker.prototype, events, handlers, helpers, methods);
Picker.languages = LANGUAGES;
module.exports = Picker;
================================================
FILE: dist/picker.css
================================================
/*!
* Picker.js v1.2.1
* https://fengyuanchen.github.io/pickerjs
*
* Copyright 2016-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2019-02-18T13:08:09.658Z
*/
:root {
--gray: #999;
--blue: #0074d9;
--color: #333;
--background-color: #fff;
--border: 1px solid #eee;
}
.picker {
background-color: rgba(0, 0, 0, 0.5);
color: #333;
color: var(--color);
direction: ltr;
display: none;
font-size: 1rem;
line-height: 1.5;
overflow: hidden;
-ms-touch-action: none;
touch-action: none;
-webkit-transition: opacity 0.15s;
transition: opacity 0.15s;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.picker-fixed {
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
z-index: 1986;
}
.picker-fixed > .picker-dialog {
bottom: -100%;
left: 0;
max-height: 100%;
position: absolute;
right: 0;
-webkit-transition: bottom 0.3s;
transition: bottom 0.3s;
}
.picker-fixed .picker-header {
display: block;
}
.picker-fixed .picker-footer {
display: table;
}
.picker-open {
display: block;
opacity: 0;
}
.picker-opened {
opacity: 1;
}
.picker-opened > .picker-dialog {
bottom: 0;
}
.picker-dialog {
background-color: #fff;
background-color: var(--background-color);
border: 1px solid #eee;
border: var(--border);
}
.picker-header {
border-bottom: 1px solid #eee;
border-bottom: var(--border);
display: none;
padding: 0.875rem 1.25rem;
position: relative;
}
.picker-title {
font-size: 1.125rem;
font-weight: 500;
line-height: 1.25rem;
margin: 0;
}
.picker-close {
background-color: transparent;
border-width: 0;
color: #999;
color: var(--gray);
cursor: pointer;
font-size: 1.75rem;
height: 3rem;
opacity: 0.75;
padding: 0;
position: absolute;
right: 0;
top: 0;
width: 3rem;
}
.picker-close:focus,
.picker-close:hover {
opacity: 1;
outline: none;
}
.picker-body {
overflow: hidden;
}
.picker-grid {
display: table;
table-layout: fixed;
width: 100%;
}
.picker-cell {
display: table-cell;
position: relative;
}
.picker-cell::before,
.picker-cell::after {
content: '';
display: block;
left: 0;
position: absolute;
right: 0;
z-index: 3;
}
.picker-cell::before {
background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.05)));
background-image: linear-gradient(to top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.05));
bottom: 50%;
margin-bottom: 1rem;
top: 0;
}
.picker-cell::after {
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.05)));
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.05));
bottom: 0;
margin-top: 1rem;
top: 50%;
}
.picker-cell + .picker-cell {
border-left: 1px solid #eee;
border-left: var(--border);
}
.picker-headers .picker-cell::before {
margin-bottom: 0;
}
.picker-headers .picker-cell::after {
margin-top: 2rem;
}
.picker-single:not(.picker-controls):not(.picker-headers) .picker-cell::before,
.picker-single:not(.picker-controls):not(.picker-headers) .picker-cell::after {
display: none;
}
.picker-cell__header {
color: #999;
color: var(--gray);
font-size: 0.875rem;
font-weight: 500;
line-height: 1.5rem;
margin: 0;
overflow: hidden;
padding: 0.25rem 0.5rem;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
}
.picker-cell__control {
cursor: pointer;
height: 2rem;
padding: 0.25rem 0.5rem;
position: relative;
z-index: 4;
}
.picker-cell__control::before {
border: 0 solid #ccc;
content: '';
display: block;
height: 0.5rem;
left: 50%;
position: absolute;
top: 50%;
-webkit-transform: translate(-50%, -50%) rotate(-45deg);
-ms-transform: translate(-50%, -50%) rotate(-45deg);
transform: translate(-50%, -50%) rotate(-45deg);
width: 0.5rem;
}
.picker-cell__control:hover::before {
border-color: var(--primary);
}
.picker-cell__control--prev::before {
border-right-width: 1px;
border-top-width: 1px;
margin-top: 2px;
}
.picker-cell__control--next::before {
border-bottom-width: 1px;
border-left-width: 1px;
margin-bottom: 2px;
}
.picker-cell__body {
overflow: hidden;
position: relative;
}
.picker-cell__body::before,
.picker-cell__body::after {
content: '';
height: 2rem;
left: 0;
position: absolute;
right: 0;
z-index: 1;
}
.picker-cell__body::before {
background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(255, 255, 255, 0)), to(rgba(255, 255, 255, 1)));
background-image: linear-gradient(to top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
top: 0;
}
.picker-cell__body::after {
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0)), to(rgba(255, 255, 255, 1)));
background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
bottom: 0;
}
.picker-single .picker-cell__body::before,
.picker-single .picker-cell__body::after {
display: none;
}
.picker-list {
list-style: none;
margin: -2rem 0;
padding: 0;
position: relative;
}
.picker-item {
color: #999;
color: var(--gray);
padding: 0.25rem 0.5rem;
text-align: center;
white-space: nowrap;
}
.picker-picked {
color: #0074d9;
color: var(--blue);
font-size: 1.125em;
line-height: 1.5rem;
}
.picker-footer {
border-top: 1px solid #eee;
border-top: var(--border);
display: none;
width: 100%;
}
.picker-cancel,
.picker-confirm {
background-color: transparent;
border-width: 0;
cursor: pointer;
display: table-cell;
font-size: 1rem;
padding: 0.75rem 1rem;
width: 50%;
}
.picker-cancel:focus,
.picker-cancel:hover,
.picker-confirm:focus,
.picker-confirm:hover {
background-color: #fcfcfc;
outline: none;
}
.picker-confirm {
color: #0074d9;
color: var(--blue);
}
================================================
FILE: dist/picker.esm.js
================================================
/*!
* Picker.js v1.2.1
* https://fengyuanchen.github.io/pickerjs
*
* Copyright 2016-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2019-02-18T13:08:12.801Z
*/
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
}
var DEFAULTS = {
// Define the container for putting the picker.
container: null,
// Indicate whether show the prev and next arrow controls on each column.
controls: false,
// The initial date. If not present, use the current date.
date: null,
// The date string format, also as the sorting order for columns.
format: 'YYYY-MM-DD HH:mm',
// Indicate whether show the column headers.
headers: false,
// Define the increment for each date / time part.
increment: 1,
// Enable inline mode.
inline: false,
// Define the language. (An ISO language code).
language: '',
// Months' name.
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
// Shorter months' name.
monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
// Define the number of rows for showing.
rows: 5,
// Define the text of the picker.
text: {
title: 'Pick a date and time',
cancel: 'Cancel',
confirm: 'OK',
year: 'Year',
month: 'Month',
day: 'Day',
hour: 'Hour',
minute: 'Minute',
second: 'Second',
millisecond: 'Millisecond'
},
// Translate date / time text.
translate: function translate(type, text) {
return text;
},
// Shortcuts of custom events.
show: null,
shown: null,
hide: null,
hidden: null,
pick: null
};
var TEMPLATE = '<div class="picker" data-picker-action="hide" touch-action="none" tabindex="-1" role="dialog">' + '<div class="picker-dialog" role="document">' + '<div class="picker-header">' + '<h4 class="picker-title">{{ title }}</h4>' + '<button type="button" class="picker-close" data-picker-action="hide" aria-label="Close">×</button>' + '</div>' + '<div class="picker-body">' + '<div class="picker-grid"></div>' + '</div>' + '<div class="picker-footer">' + '<button type="button" class="picker-cancel" data-picker-action="hide">{{ cancel }}</button>' + '<button type="button" class="picker-confirm" data-picker-action="pick">{{ confirm }}</button>' + '</div>' + '</div>' + '</div>';
var IS_BROWSER = typeof window !== 'undefined';
var WINDOW = IS_BROWSER ? window : {};
var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false;
var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
var NAMESPACE = 'picker';
var LANGUAGES = {}; // Actions
var ACTION_HIDE = 'hide';
var ACTION_NEXT = 'next';
var ACTION_PICK = 'pick';
var ACTION_PREV = 'prev'; // Classes
var CLASS_OPEN = "".concat(NAMESPACE, "-open");
var CLASS_OPENED = "".concat(NAMESPACE, "-opened");
var CLASS_PICKED = "".concat(NAMESPACE, "-picked"); // Data keys
// Add namespace to avoid to conflict to some other libraries.
var DATA_ACTION = "".concat(NAMESPACE, "Action");
var DATA_TOKEN = 'token';
var DATA_TYPE = 'type';
var DATA_NAME = 'name';
var DATA_VALUE = 'value'; // Events
var EVENT_CLICK = 'click';
var EVENT_FOCUS = 'focus';
var EVENT_HIDDEN = 'hidden';
var EVENT_HIDE = 'hide';
var EVENT_KEY_DOWN = 'keydown';
var EVENT_PICK = 'pick';
var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';
var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';
var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup';
var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START;
var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE;
var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;
var EVENT_SHOW = 'show';
var EVENT_SHOWN = 'shown';
var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
var _Object$prototype = Object.prototype,
hasOwnProperty = _Object$prototype.hasOwnProperty,
toString = _Object$prototype.toString;
/**
* Detect the type of the given value.
* @param {*} value - The value to detect.
* @returns {string} Returns the type.
*/
function typeOf(value) {
return toString.call(value).slice(8, -1).toLowerCase();
}
/**
* Check if the given value is a string.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a string, else `false`.
*/
function isString(value) {
return typeof value === 'string';
}
/**
* Check if the given value is finite.
*/
var isFinite = Number.isFinite || WINDOW.isFinite;
/**
* Check if the given value is not a number.
*/
var isNaN = Number.isNaN || WINDOW.isNaN;
/**
* Check if the given value is a number.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a number, else `false`.
*/
function isNumber(value) {
return typeof value === 'number' && !isNaN(value);
}
/**
* Check if the given value is an object.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is an object, else `false`.
*/
function isObject(value) {
return _typeof(value) === 'object' && value !== null;
}
/**
* Check if the given value is a plain object.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a plain object, else `false`.
*/
function isPlainObject(value) {
if (!isObject(value)) {
return false;
}
try {
var _constructor = value.constructor;
var prototype = _constructor.prototype;
return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');
} catch (error) {
return false;
}
}
/**
* Check if the given value is a function.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a function, else `false`.
*/
function isFunction(value) {
return typeof value === 'function';
}
/**
* Check if the given value is a date.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a date, else `false`.
*/
function isDate(value) {
return typeOf(value) === 'date';
}
/**
* Check if the given value is a valid date.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a valid date, else `false`.
*/
function isValidDate(value) {
return isDate(value) && value.toString() !== 'Invalid Date';
}
/**
* Iterate the given data.
* @param {*} data - The data to iterate.
* @param {Function} callback - The process function for each element.
* @returns {*} The original data.
*/
function forEach(data, callback) {
if (data && isFunction(callback)) {
if (Array.isArray(data) || isNumber(data.length)
/* array-like */
) {
var length = data.length;
var i;
for (i = 0; i < length; i += 1) {
if (callback.call(data, data[i], i, data) === false) {
break;
}
}
} else if (isObject(data)) {
Object.keys(data).forEach(function (key) {
callback.call(data, data[key], key, data);
});
}
}
return data;
}
/**
* Recursively assigns own enumerable properties of source objects to the target object.
* @param {Object} target - The target object.
* @param {Object[]} sources - The source objects.
* @returns {Object} The target object.
*/
function deepAssign(target) {
for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
sources[_key - 1] = arguments[_key];
}
if (isObject(target) && sources.length > 0) {
sources.forEach(function (source) {
if (isObject(source)) {
Object.keys(source).forEach(function (key) {
if (isPlainObject(target[key]) && isPlainObject(source[key])) {
target[key] = deepAssign({}, target[key], source[key]);
} else {
target[key] = source[key];
}
});
}
});
}
return target;
}
/**
* Add classes to the given element.
* @param {Element} element - The target element.
* @param {string} value - The classes to be added.
*/
function addClass(element, value) {
if (!value) {
return;
}
if (isNumber(element.length)) {
forEach(element, function (elem) {
addClass(elem, value);
});
return;
}
if (element.classList) {
element.classList.add(value);
return;
}
var className = element.className.trim();
if (!className) {
element.className = value;
} else if (className.indexOf(value) < 0) {
element.className = "".concat(className, " ").concat(value);
}
}
/**
* Remove classes from the given element.
* @param {Element} element - The target element.
* @param {string} value - The classes to be removed.
*/
function removeClass(element, value) {
if (!value) {
return;
}
if (isNumber(element.length)) {
forEach(element, function (elem) {
removeClass(elem, value);
});
return;
}
if (element.classList) {
element.classList.remove(value);
return;
}
if (element.className.indexOf(value) >= 0) {
element.className = element.className.replace(value, '');
}
}
var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
/**
* Transform the given string from camelCase to kebab-case
* @param {string} value - The value to transform.
* @returns {string} The transformed value.
*/
function hyphenate(value) {
return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase();
}
/**
* Get data from the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to get.
* @returns {string} The data value.
*/
function getData(element, name) {
if (isObject(element[name])) {
return element[name];
}
if (element.dataset) {
return element.dataset[name];
}
return element.getAttribute("data-".concat(hyphenate(name)));
}
/**
* Set data to the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to set.
* @param {string} data - The data value.
*/
function setData(element, name, data) {
if (isObject(data)) {
element[name] = data;
} else if (element.dataset) {
element.dataset[name] = data;
} else {
element.setAttribute("data-".concat(hyphenate(name)), data);
}
}
/**
* Remove data from the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to remove.
*/
function removeData(element, name) {
if (isObject(element[name])) {
try {
delete element[name];
} catch (error) {
element[name] = undefined;
}
} else if (element.dataset) {
// #128 Safari not allows to delete dataset property
try {
delete element.dataset[name];
} catch (error) {
element.dataset[name] = undefined;
}
} else {
element.removeAttribute("data-".concat(hyphenate(name)));
}
}
var REGEXP_SPACES = /\s\s*/;
var onceSupported = function () {
var supported = false;
if (IS_BROWSER) {
var once = false;
var listener = function listener() {};
var options = Object.defineProperty({}, 'once', {
get: function get() {
supported = true;
return once;
},
/**
* This setter can fix a `TypeError` in strict mode
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}
* @param {boolean} value - The value to set
*/
set: function set(value) {
once = value;
}
});
WINDOW.addEventListener('test', listener, options);
WINDOW.removeEventListener('test', listener, options);
}
return supported;
}();
/**
* Remove event listener from the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Function} listener - The event listener.
* @param {Object} options - The event options.
*/
function removeListener(element, type, listener) {
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var handler = listener;
type.trim().split(REGEXP_SPACES).forEach(function (event) {
if (!onceSupported) {
var listeners = element.listeners;
if (listeners && listeners[event] && listeners[event][listener]) {
handler = listeners[event][listener];
delete listeners[event][listener];
if (Object.keys(listeners[event]).length === 0) {
delete listeners[event];
}
if (Object.keys(listeners).length === 0) {
delete element.listeners;
}
}
}
element.removeEventListener(event, handler, options);
});
}
/**
* Add event listener to the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Function} listener - The event listener.
* @param {Object} options - The event options.
*/
function addListener(element, type, listener) {
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var _handler = listener;
type.trim().split(REGEXP_SPACES).forEach(function (event) {
if (options.once && !onceSupported) {
var _element$listeners = element.listeners,
listeners = _element$listeners === void 0 ? {} : _element$listeners;
_handler = function handler() {
delete listeners[event][listener];
element.removeEventListener(event, _handler, options);
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
listener.apply(element, args);
};
if (!listeners[event]) {
listeners[event] = {};
}
if (listeners[event][listener]) {
element.removeEventListener(event, listeners[event][listener], options);
}
listeners[event][listener] = _handler;
element.listeners = listeners;
}
element.addEventListener(event, _handler, options);
});
}
/**
* Dispatch event on the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Object} data - The additional event data.
* @returns {boolean} Indicate if the event is default prevented or not.
*/
function dispatchEvent(element, type, data) {
var event; // Event and CustomEvent on IE9-11 are global objects, not constructors
if (isFunction(Event) && isFunction(CustomEvent)) {
event = new CustomEvent(type, {
detail: data,
bubbles: true,
cancelable: true
});
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(type, true, true, data);
}
return element.dispatchEvent(event);
}
/**
* Check if the given year is a leap year.
* @param {number} year - The year to check.
* @returns {boolean} Returns `true` if the given year is a leap year, else `false`.
*/
function isLeapYear(year) {
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
}
/**
* Get days number of the given month.
* @param {number} year - The target year.
* @param {number} month - The target month.
* @returns {number} Returns days number.
*/
function getDaysInMonth(year, month) {
return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
}
/**
* Add leading zeroes to the given value
* @param {number} value - The value to add.
* @param {number} [length=1] - The number of the leading zeroes.
* @returns {string} Returns converted value.
*/
function addLeadingZero(value) {
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var str = String(Math.abs(value));
var i = str.length;
var result = '';
if (value < 0) {
result += '-';
}
while (i < length) {
i += 1;
result += '0';
}
return result + str;
}
/**
* Map token to type name
* @param {string} token - The token to map.
* @returns {string} Returns mapped type name.
*/
function tokenToType(token) {
return {
Y: 'year',
M: 'month',
D: 'day',
H: 'hour',
m: 'minute',
s: 'second',
S: 'millisecond'
}[token.charAt(0)];
}
var REGEXP_TOKENS = /(Y|M|D|H|m|s|S)\1*/g;
/**
* Parse date format.
* @param {string} format - The format to parse.
* @returns {Object} Returns parsed format data.
*/
function parseFormat(format) {
var tokens = format.match(REGEXP_TOKENS);
if (!tokens) {
throw new Error('Invalid format.');
} // Remove duplicate tokens (#22)
tokens = tokens.filter(function (token, index) {
return tokens.indexOf(token) === index;
});
var result = {
tokens: tokens
};
tokens.forEach(function (token) {
result[tokenToType(token)] = token;
});
return result;
}
var events = {
bind: function bind() {
var element = this.element,
options = this.options,
grid = this.grid;
if (isFunction(options.show)) {
addListener(element, EVENT_SHOW, options.show);
}
if (isFunction(options.shown)) {
addListener(element, EVENT_SHOWN, options.shown);
}
if (isFunction(options.hide)) {
addListener(element, EVENT_HIDE, options.hide);
}
if (isFunction(options.hidden)) {
addListener(element, EVENT_HIDDEN, options.hidden);
}
if (isFunction(options.pick)) {
addListener(element, EVENT_PICK, options.pick);
}
addListener(element, EVENT_FOCUS, this.onFocus = this.focus.bind(this));
addListener(element, EVENT_CLICK, this.onFocus);
addListener(this.picker, EVENT_CLICK, this.onClick = this.click.bind(this));
addListener(grid, EVENT_WHEEL, this.onWheel = this.wheel.bind(this));
addListener(grid, EVENT_POINTER_DOWN, this.onPointerDown = this.pointerdown.bind(this));
addListener(document, EVENT_POINTER_MOVE, this.onPointerMove = this.pointermove.bind(this));
addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
},
unbind: function unbind() {
var element = this.element,
options = this.options,
grid = this.grid;
if (isFunction(options.show)) {
removeListener(element, EVENT_SHOW, options.show);
}
if (isFunction(options.shown)) {
removeListener(element, EVENT_SHOWN, options.shown);
}
if (isFunction(options.hide)) {
removeListener(element, EVENT_HIDE, options.hide);
}
if (isFunction(options.hidden)) {
removeListener(element, EVENT_HIDDEN, options.hidden);
}
if (isFunction(options.pick)) {
removeListener(element, EVENT_PICK, options.pick);
}
removeListener(element, EVENT_FOCUS, this.onFocus);
removeListener(element, EVENT_CLICK, this.onFocus);
removeListener(this.picker, EVENT_CLICK, this.onClick);
removeListener(grid, EVENT_WHEEL, this.onWheel);
removeListener(grid, EVENT_POINTER_DOWN, this.onPointerDown);
removeListener(document, EVENT_POINTER_MOVE, this.onPointerMove);
removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
}
};
var handlers = {
focus: function focus(event) {
event.target.blur();
this.show();
},
click: function click(event) {
var target = event.target;
var action = getData(target, DATA_ACTION);
switch (action) {
case ACTION_HIDE:
this.hide();
break;
case ACTION_PICK:
this.pick();
break;
case ACTION_PREV:
case ACTION_NEXT:
this[action](getData(target.parentElement, DATA_TYPE));
break;
default:
}
},
wheel: function wheel(event) {
var target = event.target;
if (target === this.grid) {
return;
}
event.preventDefault();
while (target.parentElement && target.parentElement !== this.grid) {
target = target.parentElement;
}
var type = getData(target, DATA_TYPE);
if (event.deltaY < 0) {
this.prev(type);
} else {
this.next(type);
}
},
pointerdown: function pointerdown(event) {
var target = event.target;
if (target === this.grid || getData(target, DATA_ACTION)) {
return;
} // This line is required for preventing page scrolling in iOS browsers
event.preventDefault();
while (target.parentElement && target.parentElement !== this.grid) {
target = target.parentElement;
}
var list = target.querySelector(".".concat(NAMESPACE, "-list"));
var itemHeight = list.firstElementChild.offsetHeight;
this.cell = {
elem: target,
list: list,
moveY: 0,
maxMoveY: itemHeight,
minMoveY: itemHeight / 2,
startY: event.changedTouches ? event.changedTouches[0].pageY : event.pageY,
type: getData(target, DATA_TYPE)
};
},
pointermove: function pointermove(event) {
var cell = this.cell;
if (!cell) {
return;
}
event.preventDefault();
var endY = event.changedTouches ? event.changedTouches[0].pageY : event.pageY;
var moveY = cell.moveY + (endY - cell.startY);
cell.startY = endY;
cell.moveY = moveY;
if (Math.abs(moveY) < cell.maxMoveY) {
cell.list.style.top = "".concat(moveY, "px");
return;
}
cell.list.style.top = 0;
cell.moveY = 0;
if (moveY >= cell.maxMoveY) {
this.prev(cell.type);
} else if (moveY <= -cell.maxMoveY) {
this.next(cell.type);
}
},
pointerup: function pointerup(event) {
var cell = this.cell;
if (!cell) {
return;
}
event.preventDefault();
cell.list.style.top = 0;
if (cell.moveY >= cell.minMoveY) {
this.prev(cell.type);
} else if (cell.moveY <= -cell.minMoveY) {
this.next(cell.type);
}
this.cell = null;
},
keydown: function keydown(event) {
if (this.shown && (event.key === 'Escape' || event.keyCode === 27)) {
this.hide();
}
}
};
var helpers = {
render: function render(type) {
var _this = this;
if (!type) {
this.format.tokens.forEach(function (token) {
return _this.render(tokenToType(token));
});
return;
}
var options = this.options;
var data = this.data[type];
var current = this.current(type);
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var base = 0;
if (isFinite(max)) {
base = min > 0 ? max : max + 1;
}
data.list.innerHTML = '';
data.current = current;
for (var i = 0; i < options.rows + 2; i += 1) {
var item = document.createElement('li');
var position = i - data.index;
var newValue = current + position * data.increment;
if (base) {
newValue %= base;
if (newValue < min) {
newValue += base;
}
}
item.textContent = options.translate(type, data.aliases ? data.aliases[newValue] : addLeadingZero(newValue + data.offset, data.digit));
setData(item, DATA_NAME, type);
setData(item, DATA_VALUE, newValue);
addClass(item, "".concat(NAMESPACE, "-item"));
if (position === 0) {
addClass(item, CLASS_PICKED);
data.item = item;
}
data.list.appendChild(item);
}
},
current: function current(type, value) {
var date = this.date;
var format = this.format;
var token = format[type];
switch (token.charAt(0)) {
case 'Y':
if (isNumber(value)) {
date.setFullYear(token.length === 2 ? 2000 + value : value);
if (format.month) {
this.render(tokenToType(format.month));
}
if (format.day) {
this.render(tokenToType(format.day));
}
}
return date.getFullYear();
case 'M':
if (isNumber(value)) {
date.setMonth(value, // The current day should not exceed its maximum day in current month
Math.min(date.getDate(), getDaysInMonth(date.getFullYear(), value)));
if (format.day) {
this.render(tokenToType(format.day));
}
}
return date.getMonth();
case 'D':
if (isNumber(value)) {
date.setDate(value);
}
return date.getDate();
case 'H':
if (isNumber(value)) {
date.setHours(value);
}
return date.getHours();
case 'm':
if (isNumber(value)) {
date.setMinutes(value);
}
return date.getMinutes();
case 's':
if (isNumber(value)) {
date.setSeconds(value);
}
return date.getSeconds();
case 'S':
if (isNumber(value)) {
date.setMilliseconds(value);
}
return date.getMilliseconds();
default:
}
return date;
},
getValue: function getValue() {
var element = this.element;
return this.isInput ? element.value : element.textContent;
},
setValue: function setValue(value) {
var element = this.element;
if (this.isInput) {
element.value = value;
} else if (this.options.container) {
element.textContent = value;
}
},
open: function open() {
var body = this.body;
body.style.overflow = 'hidden';
body.style.paddingRight = "".concat(this.scrollBarWidth + (parseFloat(this.initialBodyPaddingRight) || 0), "px");
},
close: function close() {
var body = this.body;
body.style.overflow = '';
body.style.paddingRight = this.initialBodyPaddingRight;
}
};
var methods = {
/**
* Show the picker.
* @param {boolean} [immediate=false] - Indicate if show the picker immediately or not.
* @returns {Picker} this
*/
show: function show() {
var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var element = this.element,
picker = this.picker;
if (this.inline || this.shown) {
return this;
}
if (dispatchEvent(element, EVENT_SHOW) === false) {
return this;
}
this.shown = true;
this.open();
addClass(picker, CLASS_OPEN);
var done = function done() {
dispatchEvent(element, EVENT_SHOWN);
};
if (!immediate) {
// Reflow to enable transition
// eslint-disable-next-line
picker.offsetWidth;
}
addClass(picker, CLASS_OPENED);
if (immediate) {
done();
} else {
setTimeout(done, 300);
}
return this;
},
/**
* Hide the picker.
* @param {boolean} [immediate=false] - Indicate if hide the picker immediately or not.
* @returns {Picker} this
*/
hide: function hide() {
var _this = this;
var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var element = this.element,
picker = this.picker;
if (this.inline || !this.shown) {
return this;
}
if (dispatchEvent(element, EVENT_HIDE) === false) {
return this;
}
this.shown = false;
removeClass(picker, CLASS_OPENED);
var done = function done() {
_this.close();
removeClass(picker, CLASS_OPEN);
dispatchEvent(element, EVENT_HIDDEN);
};
if (immediate) {
done();
} else {
setTimeout(done, 300);
}
return this;
},
/**
* Pick to the previous item.
* @param {string} type - The column type.
* @returns {Picker} this
*/
prev: function prev(type) {
var options = this.options;
var token = this.format[type];
var data = this.data[type];
var list = data.list;
var item = list.lastElementChild;
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var prev = data.item.previousElementSibling;
var value = Number(getData(list.firstElementChild, DATA_VALUE)) - data.increment;
if (value < min) {
value += max - min + 1;
}
item.textContent = options.translate(type, data.aliases ? data.aliases[value] : addLeadingZero(value + data.offset, token.length));
setData(item, DATA_VALUE, value);
if (prev) {
removeClass(data.item, CLASS_PICKED);
addClass(prev, CLASS_PICKED);
data.item = prev;
}
list.insertBefore(item, list.firstElementChild);
data.current = Number(getData(data.item, DATA_VALUE));
this.current(type, data.current);
if (this.inline && options.container) {
this.pick();
}
return this;
},
/**
* Pick to the next item.
* @param {String} type - The column type.
* @returns {Picker} this
*/
next: function next(type) {
var options = this.options;
var token = this.format[type];
var data = this.data[type];
var list = data.list;
var item = list.firstElementChild;
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var next = data.item.nextElementSibling;
var value = Number(getData(list.lastElementChild, DATA_VALUE)) + data.increment;
if (value > max) {
value -= max - min + 1;
}
item.textContent = options.translate(type, data.aliases ? data.aliases[value] : addLeadingZero(value + data.offset, token.length));
setData(item, DATA_VALUE, value);
list.appendChild(item);
if (next) {
removeClass(data.item, CLASS_PICKED);
addClass(next, CLASS_PICKED);
data.item = next;
}
data.current = Number(getData(data.item, DATA_VALUE));
this.current(type, data.current);
if (this.inline && options.container) {
this.pick();
}
return this;
},
// Pick the current date to the target element.
pick: function pick() {
var element = this.element;
if (dispatchEvent(element, EVENT_PICK) === false) {
return this;
}
var value = this.formatDate(this.date);
this.setValue(value);
if (this.isInput && dispatchEvent(element, 'change') === false) {
this.reset();
}
this.hide();
return this;
},
/**
* Get the current date.
* @param {boolean} [formatted=false] - Indicate if format the date or not.
* @return {Date|string} The output date.
*/
getDate: function getDate() {
var formatted = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var date = this.date;
return formatted ? this.formatDate(date) : new Date(date);
},
/**
* Override the current date with a new date.
* @param {Date|string} date - The date to set.
* @returns {Picker} this
*/
setDate: function setDate(date) {
if (date) {
this.date = this.parseDate(date);
this.render();
}
return this;
},
// Update the picker with the current element value / text.
update: function update() {
this.date = this.parseDate(this.getValue());
this.render();
return this;
},
// Reset the picker and element value / text.
reset: function reset() {
this.setValue(this.initialValue);
this.date = new Date(this.initialDate);
this.render();
return this;
},
/**
* Parse a date with the set date format.
* @param {Date|string} date - The date to parse.
* @returns {Date} The parsed date object.
*/
parseDate: function parseDate(date) {
var options = this.options,
format = this.format;
var digits = [];
if (isDate(date)) {
return new Date(date);
}
if (isString(date)) {
var groups = [].concat(_toConsumableArray(options.months), _toConsumableArray(options.monthsShort), ['\\d+']);
digits = date.match(new RegExp("(".concat(groups.join('|'), ")"), 'g')); // Parse `11111111` (YYYYMMDD) to ['1111', '11', '11']
if (digits && date.length === options.format.length && digits.length !== format.tokens.length) {
digits = format.tokens.map(function (token) {
return date.substr(options.format.indexOf(token), token.length);
});
}
if (!digits || digits.length !== format.tokens.length) {
return new Date();
}
}
var parsedDate = new Date();
digits.forEach(function (digit, i) {
var token = format.tokens[i];
var n = Number(digit);
switch (token) {
case 'YYYY':
case 'YYY':
case 'Y':
{
var index = date.indexOf(digit);
var isHyphen = date.substr(index - 1, 1) === '-';
var isBC = index > 1 && isHyphen && /\S/.test(date.substr(index - 2, 1)) || index === 1 && isHyphen;
parsedDate.setFullYear(isBC ? -n : n);
break;
}
case 'YY':
parsedDate.setFullYear(2000 + n);
break;
case 'MMMM':
parsedDate.setMonth(options.months.indexOf(digit));
break;
case 'MMM':
parsedDate.setMonth(options.monthsShort.indexOf(digit));
break;
case 'MM':
case 'M':
parsedDate.setMonth(n - 1);
break;
case 'DD':
case 'D':
parsedDate.setDate(n);
break;
case 'HH':
case 'H':
parsedDate.setHours(n);
break;
case 'mm':
case 'm':
parsedDate.setMinutes(n);
break;
case 'ss':
case 's':
parsedDate.setSeconds(n);
break;
case 'SSS':
case 'SS':
case 'S':
parsedDate.setMilliseconds(n);
break;
default:
}
});
return parsedDate;
},
/**
* Format a date object to a string with the set date format.
* @param {Date} date - The date to format.
* @return {string} THe formatted date.
*/
formatDate: function formatDate(date) {
var options = this.options,
format = this.format;
var formatted = '';
if (isValidDate(date)) {
var year = date.getFullYear();
var month = date.getMonth();
var day = date.getDate();
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
var milliseconds = date.getMilliseconds();
formatted = options.format;
format.tokens.forEach(function (token) {
var replacement = '';
switch (token) {
case 'YYYY':
case 'YYY':
case 'Y':
replacement = addLeadingZero(year, token.length);
break;
case 'YY':
replacement = addLeadingZero(year % 100, 2);
break;
case 'MMMM':
replacement = options.months[month];
break;
case 'MMM':
replacement = options.monthsShort[month];
break;
case 'MM':
case 'M':
replacement = addLeadingZero(month + 1, token.length);
break;
case 'DD':
case 'D':
replacement = addLeadingZero(day, token.length);
break;
case 'HH':
case 'H':
replacement = addLeadingZero(hours, token.length);
break;
case 'mm':
case 'm':
replacement = addLeadingZero(minutes, token.length);
break;
case 'ss':
case 's':
replacement = addLeadingZero(seconds, token.length);
break;
case 'SSS':
case 'SS':
case 'S':
replacement = addLeadingZero(milliseconds, token.length);
break;
default:
}
formatted = formatted.replace(token, replacement);
});
}
return formatted;
},
// Destroy the picker and remove the instance from the target element.
destroy: function destroy() {
var element = this.element,
picker = this.picker;
if (!getData(element, NAMESPACE)) {
return this;
}
this.hide(true);
this.unbind();
removeData(element, NAMESPACE);
picker.parentNode.removeChild(picker);
return this;
}
};
var REGEXP_DELIMITER = /\{\{\s*(\w+)\s*\}\}/g;
var REGEXP_INPUTS = /input|textarea/i;
var AnotherPicker = WINDOW.Picker;
var Picker =
/*#__PURE__*/
function () {
/**
* Create a new Picker.
* @param {Element} element - The target element for picking.
* @param {Object} [options={}] - The configuration options.
*/
function Picker(element) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Picker);
if (!element || element.nodeType !== 1) {
throw new Error('The first argument is required and must be an element.');
}
this.element = element;
this.options = deepAssign({}, DEFAULTS, LANGUAGES[options.language], isPlainObject(options) && options);
this.shown = false;
this.init();
}
_createClass(Picker, [{
key: "init",
value: function init() {
var _this = this;
var element = this.element;
if (getData(element, NAMESPACE)) {
return;
}
setData(element, NAMESPACE, this);
var options = this.options;
var isInput = REGEXP_INPUTS.test(element.tagName);
var inline = options.inline && (options.container || !isInput);
var template = document.createElement('div');
template.insertAdjacentHTML('afterbegin', TEMPLATE.replace(REGEXP_DELIMITER, function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return options.text[args[1]];
}));
var picker = template.getElementsByClassName(NAMESPACE)[0];
var grid = picker.getElementsByClassName("".concat(NAMESPACE, "-grid"))[0];
var container = options.container;
if (isString(container)) {
container = document.querySelector(container);
}
if (inline) {
addClass(picker, CLASS_OPEN);
addClass(picker, CLASS_OPENED);
if (!container) {
container = element;
}
} else {
var ownerDocument = element.ownerDocument;
var body = ownerDocument.body || ownerDocument.documentElement;
this.body = body;
this.scrollBarWidth = WINDOW.innerWidth - ownerDocument.documentElement.clientWidth;
this.initialBodyPaddingRight = WINDOW.getComputedStyle(body).paddingRight;
addClass(picker, "".concat(NAMESPACE, "-fixed"));
if (!container) {
container = document.body;
}
}
this.isInput = isInput;
this.inline = inline;
this.container = container;
this.picker = picker;
this.grid = grid;
this.cell = null;
this.format = parseFormat(options.format);
var initialValue = this.getValue();
var date = this.parseDate(options.date || initialValue);
this.date = date;
this.initialDate = new Date(date);
this.initialValue = initialValue;
this.data = {};
var rows = Number(options.rows);
if (!(rows % 2)) {
rows += 1;
}
options.rows = rows || 5;
addClass(grid, "".concat(NAMESPACE, "-").concat(options.rows > 1 ? 'multiple' : 'single'));
if (options.controls) {
addClass(grid, "".concat(NAMESPACE, "-controls"));
}
var headers = options.headers,
increment = options.increment;
if (headers) {
addClass(grid, "".concat(NAMESPACE, "-headers")); // TODO: Drop the `headers` option's object support in v2.
headers = isPlainObject(headers) ? headers : options.text;
}
if (!isPlainObject(increment)) {
increment = {
year: increment,
month: increment,
day: increment,
hour: increment,
minute: increment,
second: increment,
millisecond: increment
};
}
this.format.tokens.forEach(function (token) {
var type = tokenToType(token);
var cell = document.createElement('div');
var cellBody = document.createElement('div');
var list = document.createElement('ul');
var data = {
digit: token.length,
increment: Math.abs(Number(increment[type])) || 1,
list: list,
max: Infinity,
min: -Infinity,
index: Math.floor((options.rows + 2) / 2),
offset: 0
};
switch (token.charAt(0)) {
case 'Y':
if (data.digit === 2) {
data.max = 99;
data.min = 0;
}
break;
case 'M':
data.max = 11;
data.min = 0;
data.offset = 1;
if (data.digit === 3) {
data.aliases = options.monthsShort;
} else if (data.digit === 4) {
data.aliases = options.months;
}
break;
case 'D':
// XXX: Use the latest date to calculate the max day (#23)
data.max = function () {
return getDaysInMonth(_this.date.getFullYear(), _this.date.getMonth());
};
data.min = 1;
break;
case 'H':
data.max = 23;
data.min = 0;
break;
case 'm':
data.max = 59;
data.min = 0;
break;
case 's':
data.max = 59;
data.min = 0;
break;
case 'S':
data.max = 999;
data.min = 0;
break;
default:
}
setData(cell, DATA_TYPE, type);
setData(cell, DATA_TOKEN, token);
if (headers) {
var cellHeader = document.createElement('div');
addClass(cellHeader, "".concat(NAMESPACE, "-cell__header"));
cellHeader.textContent = headers[type] || type[0].toUpperCase() + type.substr(1);
cell.appendChild(cellHeader);
}
if (options.controls) {
var prev = document.createElement('div');
addClass(prev, "".concat(NAMESPACE, "-cell__control"));
addClass(prev, "".concat(NAMESPACE, "-cell__control--prev"));
setData(prev, DATA_ACTION, ACTION_PREV);
cell.appendChild(prev);
}
addClass(list, "".concat(NAMESPACE, "-list"));
addClass(cellBody, "".concat(NAMESPACE, "-cell__body"));
addClass(cell, "".concat(NAMESPACE, "-cell"));
addClass(cell, "".concat(NAMESPACE, "-").concat(type, "s"));
cellBody.appendChild(list);
cell.appendChild(cellBody);
if (options.controls) {
var next = document.createElement('div');
addClass(next, "".concat(NAMESPACE, "-cell__control"));
addClass(next, "".concat(NAMESPACE, "-cell__control--next"));
setData(next, DATA_ACTION, ACTION_NEXT);
cell.appendChild(next);
}
grid.appendChild(cell);
_this.data[type] = data;
_this.render(type);
});
if (inline) {
container.innerHTML = '';
}
container.appendChild(picker);
this.bind();
}
/**
* Get the no conflict picker class.
* @returns {Picker} The picker class.
*/
}], [{
key: "noConflict",
value: function noConflict() {
WINDOW.Picker = AnotherPicker;
return Picker;
}
/**
* Change the default options.
* @param {Object} options - The new default options.
*/
}, {
key: "setDefaults",
value: function setDefaults(options) {
deepAssign(DEFAULTS, LANGUAGES[options.language], isPlainObject(options) && options);
}
}]);
return Picker;
}();
deepAssign(Picker.prototype, events, handlers, helpers, methods);
Picker.languages = LANGUAGES;
export default Picker;
================================================
FILE: dist/picker.js
================================================
/*!
* Picker.js v1.2.1
* https://fengyuanchen.github.io/pickerjs
*
* Copyright 2016-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2019-02-18T13:08:12.801Z
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = global || self, global.Picker = factory());
}(this, function () { 'use strict';
function _typeof(obj) {
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
_typeof = function (obj) {
return typeof obj;
};
} else {
_typeof = function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
}
return _typeof(obj);
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) {
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
return arr2;
}
}
function _iterableToArray(iter) {
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance");
}
var DEFAULTS = {
// Define the container for putting the picker.
container: null,
// Indicate whether show the prev and next arrow controls on each column.
controls: false,
// The initial date. If not present, use the current date.
date: null,
// The date string format, also as the sorting order for columns.
format: 'YYYY-MM-DD HH:mm',
// Indicate whether show the column headers.
headers: false,
// Define the increment for each date / time part.
increment: 1,
// Enable inline mode.
inline: false,
// Define the language. (An ISO language code).
language: '',
// Months' name.
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
// Shorter months' name.
monthsShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
// Define the number of rows for showing.
rows: 5,
// Define the text of the picker.
text: {
title: 'Pick a date and time',
cancel: 'Cancel',
confirm: 'OK',
year: 'Year',
month: 'Month',
day: 'Day',
hour: 'Hour',
minute: 'Minute',
second: 'Second',
millisecond: 'Millisecond'
},
// Translate date / time text.
translate: function translate(type, text) {
return text;
},
// Shortcuts of custom events.
show: null,
shown: null,
hide: null,
hidden: null,
pick: null
};
var TEMPLATE = '<div class="picker" data-picker-action="hide" touch-action="none" tabindex="-1" role="dialog">' + '<div class="picker-dialog" role="document">' + '<div class="picker-header">' + '<h4 class="picker-title">{{ title }}</h4>' + '<button type="button" class="picker-close" data-picker-action="hide" aria-label="Close">×</button>' + '</div>' + '<div class="picker-body">' + '<div class="picker-grid"></div>' + '</div>' + '<div class="picker-footer">' + '<button type="button" class="picker-cancel" data-picker-action="hide">{{ cancel }}</button>' + '<button type="button" class="picker-confirm" data-picker-action="pick">{{ confirm }}</button>' + '</div>' + '</div>' + '</div>';
var IS_BROWSER = typeof window !== 'undefined';
var WINDOW = IS_BROWSER ? window : {};
var IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.documentElement : false;
var HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
var NAMESPACE = 'picker';
var LANGUAGES = {}; // Actions
var ACTION_HIDE = 'hide';
var ACTION_NEXT = 'next';
var ACTION_PICK = 'pick';
var ACTION_PREV = 'prev'; // Classes
var CLASS_OPEN = "".concat(NAMESPACE, "-open");
var CLASS_OPENED = "".concat(NAMESPACE, "-opened");
var CLASS_PICKED = "".concat(NAMESPACE, "-picked"); // Data keys
// Add namespace to avoid to conflict to some other libraries.
var DATA_ACTION = "".concat(NAMESPACE, "Action");
var DATA_TOKEN = 'token';
var DATA_TYPE = 'type';
var DATA_NAME = 'name';
var DATA_VALUE = 'value'; // Events
var EVENT_CLICK = 'click';
var EVENT_FOCUS = 'focus';
var EVENT_HIDDEN = 'hidden';
var EVENT_HIDE = 'hide';
var EVENT_KEY_DOWN = 'keydown';
var EVENT_PICK = 'pick';
var EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';
var EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';
var EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mouseup';
var EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOUCH_START;
var EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOUCH_MOVE;
var EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' : EVENT_TOUCH_END;
var EVENT_SHOW = 'show';
var EVENT_SHOWN = 'shown';
var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
var _Object$prototype = Object.prototype,
hasOwnProperty = _Object$prototype.hasOwnProperty,
toString = _Object$prototype.toString;
/**
* Detect the type of the given value.
* @param {*} value - The value to detect.
* @returns {string} Returns the type.
*/
function typeOf(value) {
return toString.call(value).slice(8, -1).toLowerCase();
}
/**
* Check if the given value is a string.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a string, else `false`.
*/
function isString(value) {
return typeof value === 'string';
}
/**
* Check if the given value is finite.
*/
var isFinite = Number.isFinite || WINDOW.isFinite;
/**
* Check if the given value is not a number.
*/
var isNaN = Number.isNaN || WINDOW.isNaN;
/**
* Check if the given value is a number.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a number, else `false`.
*/
function isNumber(value) {
return typeof value === 'number' && !isNaN(value);
}
/**
* Check if the given value is an object.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is an object, else `false`.
*/
function isObject(value) {
return _typeof(value) === 'object' && value !== null;
}
/**
* Check if the given value is a plain object.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a plain object, else `false`.
*/
function isPlainObject(value) {
if (!isObject(value)) {
return false;
}
try {
var _constructor = value.constructor;
var prototype = _constructor.prototype;
return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');
} catch (error) {
return false;
}
}
/**
* Check if the given value is a function.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a function, else `false`.
*/
function isFunction(value) {
return typeof value === 'function';
}
/**
* Check if the given value is a date.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a date, else `false`.
*/
function isDate(value) {
return typeOf(value) === 'date';
}
/**
* Check if the given value is a valid date.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is a valid date, else `false`.
*/
function isValidDate(value) {
return isDate(value) && value.toString() !== 'Invalid Date';
}
/**
* Iterate the given data.
* @param {*} data - The data to iterate.
* @param {Function} callback - The process function for each element.
* @returns {*} The original data.
*/
function forEach(data, callback) {
if (data && isFunction(callback)) {
if (Array.isArray(data) || isNumber(data.length)
/* array-like */
) {
var length = data.length;
var i;
for (i = 0; i < length; i += 1) {
if (callback.call(data, data[i], i, data) === false) {
break;
}
}
} else if (isObject(data)) {
Object.keys(data).forEach(function (key) {
callback.call(data, data[key], key, data);
});
}
}
return data;
}
/**
* Recursively assigns own enumerable properties of source objects to the target object.
* @param {Object} target - The target object.
* @param {Object[]} sources - The source objects.
* @returns {Object} The target object.
*/
function deepAssign(target) {
for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
sources[_key - 1] = arguments[_key];
}
if (isObject(target) && sources.length > 0) {
sources.forEach(function (source) {
if (isObject(source)) {
Object.keys(source).forEach(function (key) {
if (isPlainObject(target[key]) && isPlainObject(source[key])) {
target[key] = deepAssign({}, target[key], source[key]);
} else {
target[key] = source[key];
}
});
}
});
}
return target;
}
/**
* Add classes to the given element.
* @param {Element} element - The target element.
* @param {string} value - The classes to be added.
*/
function addClass(element, value) {
if (!value) {
return;
}
if (isNumber(element.length)) {
forEach(element, function (elem) {
addClass(elem, value);
});
return;
}
if (element.classList) {
element.classList.add(value);
return;
}
var className = element.className.trim();
if (!className) {
element.className = value;
} else if (className.indexOf(value) < 0) {
element.className = "".concat(className, " ").concat(value);
}
}
/**
* Remove classes from the given element.
* @param {Element} element - The target element.
* @param {string} value - The classes to be removed.
*/
function removeClass(element, value) {
if (!value) {
return;
}
if (isNumber(element.length)) {
forEach(element, function (elem) {
removeClass(elem, value);
});
return;
}
if (element.classList) {
element.classList.remove(value);
return;
}
if (element.className.indexOf(value) >= 0) {
element.className = element.className.replace(value, '');
}
}
var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
/**
* Transform the given string from camelCase to kebab-case
* @param {string} value - The value to transform.
* @returns {string} The transformed value.
*/
function hyphenate(value) {
return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase();
}
/**
* Get data from the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to get.
* @returns {string} The data value.
*/
function getData(element, name) {
if (isObject(element[name])) {
return element[name];
}
if (element.dataset) {
return element.dataset[name];
}
return element.getAttribute("data-".concat(hyphenate(name)));
}
/**
* Set data to the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to set.
* @param {string} data - The data value.
*/
function setData(element, name, data) {
if (isObject(data)) {
element[name] = data;
} else if (element.dataset) {
element.dataset[name] = data;
} else {
element.setAttribute("data-".concat(hyphenate(name)), data);
}
}
/**
* Remove data from the given element.
* @param {Element} element - The target element.
* @param {string} name - The data key to remove.
*/
function removeData(element, name) {
if (isObject(element[name])) {
try {
delete element[name];
} catch (error) {
element[name] = undefined;
}
} else if (element.dataset) {
// #128 Safari not allows to delete dataset property
try {
delete element.dataset[name];
} catch (error) {
element.dataset[name] = undefined;
}
} else {
element.removeAttribute("data-".concat(hyphenate(name)));
}
}
var REGEXP_SPACES = /\s\s*/;
var onceSupported = function () {
var supported = false;
if (IS_BROWSER) {
var once = false;
var listener = function listener() {};
var options = Object.defineProperty({}, 'once', {
get: function get() {
supported = true;
return once;
},
/**
* This setter can fix a `TypeError` in strict mode
* {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}
* @param {boolean} value - The value to set
*/
set: function set(value) {
once = value;
}
});
WINDOW.addEventListener('test', listener, options);
WINDOW.removeEventListener('test', listener, options);
}
return supported;
}();
/**
* Remove event listener from the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Function} listener - The event listener.
* @param {Object} options - The event options.
*/
function removeListener(element, type, listener) {
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var handler = listener;
type.trim().split(REGEXP_SPACES).forEach(function (event) {
if (!onceSupported) {
var listeners = element.listeners;
if (listeners && listeners[event] && listeners[event][listener]) {
handler = listeners[event][listener];
delete listeners[event][listener];
if (Object.keys(listeners[event]).length === 0) {
delete listeners[event];
}
if (Object.keys(listeners).length === 0) {
delete element.listeners;
}
}
}
element.removeEventListener(event, handler, options);
});
}
/**
* Add event listener to the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Function} listener - The event listener.
* @param {Object} options - The event options.
*/
function addListener(element, type, listener) {
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var _handler = listener;
type.trim().split(REGEXP_SPACES).forEach(function (event) {
if (options.once && !onceSupported) {
var _element$listeners = element.listeners,
listeners = _element$listeners === void 0 ? {} : _element$listeners;
_handler = function handler() {
delete listeners[event][listener];
element.removeEventListener(event, _handler, options);
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
listener.apply(element, args);
};
if (!listeners[event]) {
listeners[event] = {};
}
if (listeners[event][listener]) {
element.removeEventListener(event, listeners[event][listener], options);
}
listeners[event][listener] = _handler;
element.listeners = listeners;
}
element.addEventListener(event, _handler, options);
});
}
/**
* Dispatch event on the target element.
* @param {Element} element - The event target.
* @param {string} type - The event type(s).
* @param {Object} data - The additional event data.
* @returns {boolean} Indicate if the event is default prevented or not.
*/
function dispatchEvent(element, type, data) {
var event; // Event and CustomEvent on IE9-11 are global objects, not constructors
if (isFunction(Event) && isFunction(CustomEvent)) {
event = new CustomEvent(type, {
detail: data,
bubbles: true,
cancelable: true
});
} else {
event = document.createEvent('CustomEvent');
event.initCustomEvent(type, true, true, data);
}
return element.dispatchEvent(event);
}
/**
* Check if the given year is a leap year.
* @param {number} year - The year to check.
* @returns {boolean} Returns `true` if the given year is a leap year, else `false`.
*/
function isLeapYear(year) {
return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
}
/**
* Get days number of the given month.
* @param {number} year - The target year.
* @param {number} month - The target month.
* @returns {number} Returns days number.
*/
function getDaysInMonth(year, month) {
return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
}
/**
* Add leading zeroes to the given value
* @param {number} value - The value to add.
* @param {number} [length=1] - The number of the leading zeroes.
* @returns {string} Returns converted value.
*/
function addLeadingZero(value) {
var length = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
var str = String(Math.abs(value));
var i = str.length;
var result = '';
if (value < 0) {
result += '-';
}
while (i < length) {
i += 1;
result += '0';
}
return result + str;
}
/**
* Map token to type name
* @param {string} token - The token to map.
* @returns {string} Returns mapped type name.
*/
function tokenToType(token) {
return {
Y: 'year',
M: 'month',
D: 'day',
H: 'hour',
m: 'minute',
s: 'second',
S: 'millisecond'
}[token.charAt(0)];
}
var REGEXP_TOKENS = /(Y|M|D|H|m|s|S)\1*/g;
/**
* Parse date format.
* @param {string} format - The format to parse.
* @returns {Object} Returns parsed format data.
*/
function parseFormat(format) {
var tokens = format.match(REGEXP_TOKENS);
if (!tokens) {
throw new Error('Invalid format.');
} // Remove duplicate tokens (#22)
tokens = tokens.filter(function (token, index) {
return tokens.indexOf(token) === index;
});
var result = {
tokens: tokens
};
tokens.forEach(function (token) {
result[tokenToType(token)] = token;
});
return result;
}
var events = {
bind: function bind() {
var element = this.element,
options = this.options,
grid = this.grid;
if (isFunction(options.show)) {
addListener(element, EVENT_SHOW, options.show);
}
if (isFunction(options.shown)) {
addListener(element, EVENT_SHOWN, options.shown);
}
if (isFunction(options.hide)) {
addListener(element, EVENT_HIDE, options.hide);
}
if (isFunction(options.hidden)) {
addListener(element, EVENT_HIDDEN, options.hidden);
}
if (isFunction(options.pick)) {
addListener(element, EVENT_PICK, options.pick);
}
addListener(element, EVENT_FOCUS, this.onFocus = this.focus.bind(this));
addListener(element, EVENT_CLICK, this.onFocus);
addListener(this.picker, EVENT_CLICK, this.onClick = this.click.bind(this));
addListener(grid, EVENT_WHEEL, this.onWheel = this.wheel.bind(this));
addListener(grid, EVENT_POINTER_DOWN, this.onPointerDown = this.pointerdown.bind(this));
addListener(document, EVENT_POINTER_MOVE, this.onPointerMove = this.pointermove.bind(this));
addListener(document, EVENT_POINTER_UP, this.onPointerUp = this.pointerup.bind(this));
addListener(document, EVENT_KEY_DOWN, this.onKeyDown = this.keydown.bind(this));
},
unbind: function unbind() {
var element = this.element,
options = this.options,
grid = this.grid;
if (isFunction(options.show)) {
removeListener(element, EVENT_SHOW, options.show);
}
if (isFunction(options.shown)) {
removeListener(element, EVENT_SHOWN, options.shown);
}
if (isFunction(options.hide)) {
removeListener(element, EVENT_HIDE, options.hide);
}
if (isFunction(options.hidden)) {
removeListener(element, EVENT_HIDDEN, options.hidden);
}
if (isFunction(options.pick)) {
removeListener(element, EVENT_PICK, options.pick);
}
removeListener(element, EVENT_FOCUS, this.onFocus);
removeListener(element, EVENT_CLICK, this.onFocus);
removeListener(this.picker, EVENT_CLICK, this.onClick);
removeListener(grid, EVENT_WHEEL, this.onWheel);
removeListener(grid, EVENT_POINTER_DOWN, this.onPointerDown);
removeListener(document, EVENT_POINTER_MOVE, this.onPointerMove);
removeListener(document, EVENT_POINTER_UP, this.onPointerUp);
removeListener(document, EVENT_KEY_DOWN, this.onKeyDown);
}
};
var handlers = {
focus: function focus(event) {
event.target.blur();
this.show();
},
click: function click(event) {
var target = event.target;
var action = getData(target, DATA_ACTION);
switch (action) {
case ACTION_HIDE:
this.hide();
break;
case ACTION_PICK:
this.pick();
break;
case ACTION_PREV:
case ACTION_NEXT:
this[action](getData(target.parentElement, DATA_TYPE));
break;
default:
}
},
wheel: function wheel(event) {
var target = event.target;
if (target === this.grid) {
return;
}
event.preventDefault();
while (target.parentElement && target.parentElement !== this.grid) {
target = target.parentElement;
}
var type = getData(target, DATA_TYPE);
if (event.deltaY < 0) {
this.prev(type);
} else {
this.next(type);
}
},
pointerdown: function pointerdown(event) {
var target = event.target;
if (target === this.grid || getData(target, DATA_ACTION)) {
return;
} // This line is required for preventing page scrolling in iOS browsers
event.preventDefault();
while (target.parentElement && target.parentElement !== this.grid) {
target = target.parentElement;
}
var list = target.querySelector(".".concat(NAMESPACE, "-list"));
var itemHeight = list.firstElementChild.offsetHeight;
this.cell = {
elem: target,
list: list,
moveY: 0,
maxMoveY: itemHeight,
minMoveY: itemHeight / 2,
startY: event.changedTouches ? event.changedTouches[0].pageY : event.pageY,
type: getData(target, DATA_TYPE)
};
},
pointermove: function pointermove(event) {
var cell = this.cell;
if (!cell) {
return;
}
event.preventDefault();
var endY = event.changedTouches ? event.changedTouches[0].pageY : event.pageY;
var moveY = cell.moveY + (endY - cell.startY);
cell.startY = endY;
cell.moveY = moveY;
if (Math.abs(moveY) < cell.maxMoveY) {
cell.list.style.top = "".concat(moveY, "px");
return;
}
cell.list.style.top = 0;
cell.moveY = 0;
if (moveY >= cell.maxMoveY) {
this.prev(cell.type);
} else if (moveY <= -cell.maxMoveY) {
this.next(cell.type);
}
},
pointerup: function pointerup(event) {
var cell = this.cell;
if (!cell) {
return;
}
event.preventDefault();
cell.list.style.top = 0;
if (cell.moveY >= cell.minMoveY) {
this.prev(cell.type);
} else if (cell.moveY <= -cell.minMoveY) {
this.next(cell.type);
}
this.cell = null;
},
keydown: function keydown(event) {
if (this.shown && (event.key === 'Escape' || event.keyCode === 27)) {
this.hide();
}
}
};
var helpers = {
render: function render(type) {
var _this = this;
if (!type) {
this.format.tokens.forEach(function (token) {
return _this.render(tokenToType(token));
});
return;
}
var options = this.options;
var data = this.data[type];
var current = this.current(type);
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var base = 0;
if (isFinite(max)) {
base = min > 0 ? max : max + 1;
}
data.list.innerHTML = '';
data.current = current;
for (var i = 0; i < options.rows + 2; i += 1) {
var item = document.createElement('li');
var position = i - data.index;
var newValue = current + position * data.increment;
if (base) {
newValue %= base;
if (newValue < min) {
newValue += base;
}
}
item.textContent = options.translate(type, data.aliases ? data.aliases[newValue] : addLeadingZero(newValue + data.offset, data.digit));
setData(item, DATA_NAME, type);
setData(item, DATA_VALUE, newValue);
addClass(item, "".concat(NAMESPACE, "-item"));
if (position === 0) {
addClass(item, CLASS_PICKED);
data.item = item;
}
data.list.appendChild(item);
}
},
current: function current(type, value) {
var date = this.date;
var format = this.format;
var token = format[type];
switch (token.charAt(0)) {
case 'Y':
if (isNumber(value)) {
date.setFullYear(token.length === 2 ? 2000 + value : value);
if (format.month) {
this.render(tokenToType(format.month));
}
if (format.day) {
this.render(tokenToType(format.day));
}
}
return date.getFullYear();
case 'M':
if (isNumber(value)) {
date.setMonth(value, // The current day should not exceed its maximum day in current month
Math.min(date.getDate(), getDaysInMonth(date.getFullYear(), value)));
if (format.day) {
this.render(tokenToType(format.day));
}
}
return date.getMonth();
case 'D':
if (isNumber(value)) {
date.setDate(value);
}
return date.getDate();
case 'H':
if (isNumber(value)) {
date.setHours(value);
}
return date.getHours();
case 'm':
if (isNumber(value)) {
date.setMinutes(value);
}
return date.getMinutes();
case 's':
if (isNumber(value)) {
date.setSeconds(value);
}
return date.getSeconds();
case 'S':
if (isNumber(value)) {
date.setMilliseconds(value);
}
return date.getMilliseconds();
default:
}
return date;
},
getValue: function getValue() {
var element = this.element;
return this.isInput ? element.value : element.textContent;
},
setValue: function setValue(value) {
var element = this.element;
if (this.isInput) {
element.value = value;
} else if (this.options.container) {
element.textContent = value;
}
},
open: function open() {
var body = this.body;
body.style.overflow = 'hidden';
body.style.paddingRight = "".concat(this.scrollBarWidth + (parseFloat(this.initialBodyPaddingRight) || 0), "px");
},
close: function close() {
var body = this.body;
body.style.overflow = '';
body.style.paddingRight = this.initialBodyPaddingRight;
}
};
var methods = {
/**
* Show the picker.
* @param {boolean} [immediate=false] - Indicate if show the picker immediately or not.
* @returns {Picker} this
*/
show: function show() {
var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var element = this.element,
picker = this.picker;
if (this.inline || this.shown) {
return this;
}
if (dispatchEvent(element, EVENT_SHOW) === false) {
return this;
}
this.shown = true;
this.open();
addClass(picker, CLASS_OPEN);
var done = function done() {
dispatchEvent(element, EVENT_SHOWN);
};
if (!immediate) {
// Reflow to enable transition
// eslint-disable-next-line
picker.offsetWidth;
}
addClass(picker, CLASS_OPENED);
if (immediate) {
done();
} else {
setTimeout(done, 300);
}
return this;
},
/**
* Hide the picker.
* @param {boolean} [immediate=false] - Indicate if hide the picker immediately or not.
* @returns {Picker} this
*/
hide: function hide() {
var _this = this;
var immediate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var element = this.element,
picker = this.picker;
if (this.inline || !this.shown) {
return this;
}
if (dispatchEvent(element, EVENT_HIDE) === false) {
return this;
}
this.shown = false;
removeClass(picker, CLASS_OPENED);
var done = function done() {
_this.close();
removeClass(picker, CLASS_OPEN);
dispatchEvent(element, EVENT_HIDDEN);
};
if (immediate) {
done();
} else {
setTimeout(done, 300);
}
return this;
},
/**
* Pick to the previous item.
* @param {string} type - The column type.
* @returns {Picker} this
*/
prev: function prev(type) {
var options = this.options;
var token = this.format[type];
var data = this.data[type];
var list = data.list;
var item = list.lastElementChild;
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var prev = data.item.previousElementSibling;
var value = Number(getData(list.firstElementChild, DATA_VALUE)) - data.increment;
if (value < min) {
value += max - min + 1;
}
item.textContent = options.translate(type, data.aliases ? data.aliases[value] : addLeadingZero(value + data.offset, token.length));
setData(item, DATA_VALUE, value);
if (prev) {
removeClass(data.item, CLASS_PICKED);
addClass(prev, CLASS_PICKED);
data.item = prev;
}
list.insertBefore(item, list.firstElementChild);
data.current = Number(getData(data.item, DATA_VALUE));
this.current(type, data.current);
if (this.inline && options.container) {
this.pick();
}
return this;
},
/**
* Pick to the next item.
* @param {String} type - The column type.
* @returns {Picker} this
*/
next: function next(type) {
var options = this.options;
var token = this.format[type];
var data = this.data[type];
var list = data.list;
var item = list.firstElementChild;
var max = isFunction(data.max) ? data.max() : data.max;
var min = isFunction(data.min) ? data.min() : data.min;
var next = data.item.nextElementSibling;
var value = Number(getData(list.lastElementChild, DATA_VALUE)) + data.increment;
if (value > max) {
value -= max - min + 1;
}
item.textContent = options.translate(type, data.aliases ? data.aliases[value] : addLeadingZero(value + data.offset, token.length));
setData(item, DATA_VALUE, value);
list.appendChild(item);
if (next) {
removeClass(data.item, CLASS_PICKED);
addClass(next, CLASS_PICKED);
data.item = next;
}
data.current = Number(getData(data.item, DATA_VALUE));
this.current(type, data.current);
if (this.inline && options.container) {
this.pick();
}
return this;
},
// Pick the current date to the target element.
pick: function pick() {
var element = this.element;
if (dispatchEvent(element, EVENT_PICK) === false) {
return this;
}
var value = this.formatDate(this.date);
this.setValue(value);
if (this.isInput && dispatchEvent(element, 'change') === false) {
this.reset();
}
this.hide();
return this;
},
/**
* Get the current date.
* @param {boolean} [formatted=false] - Indicate if format the date or not.
* @return {Date|string} The output date.
*/
getDate: function getDate() {
var formatted = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var date = this.date;
return formatted ? this.formatDate(date) : new Date(date);
},
/**
* Override the current date with a new date.
* @param {Date|string} date - The date to set.
* @returns {Picker} this
*/
setDate: function setDate(date) {
if (date) {
this.date = this.parseDate(date);
this.render();
}
return this;
},
// Update the picker with the current element value / text.
update: function update() {
this.date = this.parseDate(this.getValue());
this.render();
return this;
},
// Reset the picker and element value / text.
reset: function reset() {
this.setValue(this.initialValue);
this.date = new Date(this.initialDate);
this.render();
return this;
},
/**
* Parse a date with the set date format.
* @param {Date|string} date - The date to parse.
* @returns {Date} The parsed date object.
*/
parseDate: function parseDate(date) {
var options = this.options,
format = this.format;
var digits = [];
if (isDate(date)) {
return new Date(date);
}
if (isString(date)) {
var groups = [].concat(_toConsumableArray(options.months), _toConsumableArray(options.monthsShort), ['\\d+']);
digits = date.match(new RegExp("(".concat(groups.join('|'), ")"), 'g')); // Parse `11111111` (YYYYMMDD) to ['1111', '11', '11']
if (digits && date.length === options.format.length && digits.length !== format.tokens.length) {
digits = format.tokens.map(function (token) {
return date.substr(options.format.indexOf(token), token.length);
});
}
if (!digits || digits.length !== format.tokens.length) {
return new Date();
}
}
var parsedDate = new Date();
digits.forEach(function (digit, i) {
var token = format.tokens[i];
var n = Number(digit);
switch (token) {
case 'YYYY':
case 'YYY':
case 'Y':
{
var index = date.indexOf(digit);
var isHyphen = date.substr(index - 1, 1) === '-';
var isBC = index > 1 && isHyphen && /\S/.test(date.substr(index - 2, 1)) || index === 1 && isHyphen;
parsedDate.setFullYear(isBC ? -n : n);
break;
}
case 'YY':
parsedDate.setFullYear(2000 + n);
break;
case 'MMMM':
parsedDate.setMonth(options.months.indexOf(digit));
break;
case 'MMM':
parsedDate.setMonth(options.monthsShort.indexOf(digit));
break;
case 'MM':
case 'M':
parsedDate.setMonth(n - 1);
break;
case 'DD':
case 'D':
parsedDate.setDate(n);
break;
case 'HH':
case 'H':
parsedDate.setHours(n);
break;
case 'mm':
case 'm':
parsedDate.setMinutes(n);
break;
case 'ss':
case 's':
parsedDate.setSeconds(n);
break;
case 'SSS':
case 'SS':
case 'S':
parsedDate.setMilliseconds(n);
break;
default:
}
});
return parsedDate;
},
/**
* Format a date object to a string with the set date format.
* @param {Date} date - The date to format.
* @return {string} THe formatted date.
*/
formatDate: function formatDate(date) {
var options = this.options,
format = this.format;
var formatted = '';
if (isValidDate(date)) {
var year = date.getFullYear();
var month = date.getMonth();
var day = date.getDate();
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
var milliseconds = date.getMilliseconds();
formatted = options.format;
format.tokens.forEach(function (token) {
var replacement = '';
switch (token) {
case 'YYYY':
case 'YYY':
case 'Y':
replacement = addLeadingZero(year, token.length);
break;
case 'YY':
replacement = addLeadingZero(year % 100, 2);
break;
case 'MMMM':
replacement = options.months[month];
break;
case 'MMM':
replacement = options.monthsShort[month];
break;
case 'MM':
case 'M':
replacement = addLeadingZero(month + 1, token.length);
break;
case 'DD':
case 'D':
replacement = addLeadingZero(day, token.length);
break;
case 'HH':
case 'H':
replacement = addLeadingZero(hours, token.length);
break;
case 'mm':
case 'm':
replacement = addLeadingZero(minutes, token.length);
break;
case 'ss':
case 's':
replacement = addLeadingZero(seconds, token.length);
break;
case 'SSS':
case 'SS':
case 'S':
replacement = addLeadingZero(milliseconds, token.length);
break;
default:
}
formatted = formatted.replace(token, replacement);
});
}
return formatted;
},
// Destroy the picker and remove the instance from the target element.
destroy: function destroy() {
var element = this.element,
picker = this.picker;
if (!getData(element, NAMESPACE)) {
return this;
}
this.hide(true);
this.unbind();
removeData(element, NAMESPACE);
picker.parentNode.removeChild(picker);
return this;
}
};
var REGEXP_DELIMITER = /\{\{\s*(\w+)\s*\}\}/g;
var REGEXP_INPUTS = /input|textarea/i;
var AnotherPicker = WINDOW.Picker;
var Picker =
/*#__PURE__*/
function () {
/**
* Create a new Picker.
* @param {Element} element - The target element for picking.
* @param {Object} [options={}] - The configuration options.
*/
function Picker(element) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Picker);
if (!element || element.nodeType !== 1) {
throw new Error('The first argument is required and must be an element.');
}
this.element = element;
this.options = deepAssign({}, DEFAULTS, LANGUAGES[options.language], isPlainObject(options) && options);
this.shown = false;
this.init();
}
_createClass(Picker, [{
key: "init",
value: function init() {
var _this = this;
var element = this.element;
if (getData(element, NAMESPACE)) {
return;
}
setData(element, NAMESPACE, this);
var options = this.options;
var isInput = REGEXP_INPUTS.test(element.tagName);
var inline = options.inline && (options.container || !isInput);
var template = document.createElement('div');
template.insertAdjacentHTML('afterbegin', TEMPLATE.replace(REGEXP_DELIMITER, function () {
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return options.text[args[1]];
}));
var picker = template.getElementsByClassName(NAMESPACE)[0];
var grid = picker.getElementsByClassName("".concat(NAMESPACE, "-grid"))[0];
var container = options.container;
if (isString(container)) {
container = document.querySelector(container);
}
if (inline) {
addClass(picker, CLASS_OPEN);
addClass(picker, CLASS_OPENED);
if (!container) {
container = element;
}
} else {
var ownerDocument = element.ownerDocument;
var body = ownerDocument.body || ownerDocument.documentElement;
this.body = body;
this.scrollBarWidth = WINDOW.innerWidth - ownerDocument.documentElement.clientWidth;
this.initialBodyPaddingRight = WINDOW.getComputedStyle(body).paddingRight;
addClass(picker, "".concat(NAMESPACE, "-fixed"));
if (!container) {
container = document.body;
}
}
this.isInput = isInput;
this.inline = inline;
this.container = container;
this.picker = picker;
this.grid = grid;
this.cell = null;
this.format = parseFormat(options.format);
var initialValue = this.getValue();
var date = this.parseDate(options.date || initialValue);
this.date = date;
this.initialDate = new Date(date);
this.initialValue = initialValue;
this.data = {};
var rows = Number(options.rows);
if (!(rows % 2)) {
rows += 1;
}
options.rows = rows || 5;
addClass(grid, "".concat(NAMESPACE, "-").concat(options.rows > 1 ? 'multiple' : 'single'));
if (options.controls) {
addClass(grid, "".concat(NAMESPACE, "-controls"));
}
var headers = options.headers,
increment = options.increment;
if (headers) {
addClass(grid, "".concat(NAMESPACE, "-headers")); // TODO: Drop the `headers` option's object support in v2.
headers = isPlainObject(headers) ? headers : options.text;
}
if (!isPlainObject(increment)) {
increment = {
year: increment,
month: increment,
day: increment,
hour: increment,
minute: increment,
second: increment,
millisecond: increment
};
}
this.format.tokens.forEach(function (token) {
var type = tokenToType(token);
var cell = document.createElement('div');
var cellBody = document.createElement('div');
var list = document.createElement('ul');
var data = {
digit: token.length,
increment: Math.abs(Number(increment[type])) || 1,
list: list,
max: Infinity,
min: -Infinity,
index: Math.floor((options.rows + 2) / 2),
offset: 0
};
switch (token.charAt(0)) {
case 'Y':
if (data.digit === 2) {
data.max = 99;
data.min = 0;
}
break;
case 'M':
data.max = 11;
data.min = 0;
data.offset = 1;
if (data.digit === 3) {
data.aliases = options.monthsShort;
} else if (data.digit === 4) {
data.aliases = options.months;
}
break;
case 'D':
// XXX: Use the latest date to calculate the max day (#23)
data.max = function () {
return getDaysInMonth(_this.date.getFullYear(), _this.date.getMonth());
};
data.min = 1;
break;
case 'H':
data.max = 23;
data.min = 0;
break;
case 'm':
data.max = 59;
data.min = 0;
break;
case 's':
data.max = 59;
data.min = 0;
break;
case 'S':
data.max = 999;
data.min = 0;
break;
default:
}
setData(cell, DATA_TYPE, type);
setData(cell, DATA_TOKEN, token);
if (headers) {
var cellHeader = document.createElement('div');
addClass(cellHeader, "".concat(NAMESPACE, "-cell__header"));
cellHeader.textContent = headers[type] || type[0].toUpperCase() + type.substr(1);
cell.appendChild(cellHeader);
}
if (options.controls) {
var prev = document.createElement('div');
addClass(prev, "".concat(NAMESPACE, "-cell__control"));
addClass(prev, "".concat(NAMESPACE, "-cell__control--prev"));
setData(prev, DATA_ACTION, ACTION_PREV);
cell.appendChild(prev);
}
addClass(list, "".concat(NAMESPACE, "-list"));
addClass(cellBody, "".concat(NAMESPACE, "-cell__body"));
addClass(cell, "".concat(NAMESPACE, "-cell"));
addClass(cell, "".concat(NAMESPACE, "-").concat(type, "s"));
cellBody.appendChild(list);
cell.appendChild(cellBody);
if (options.controls) {
var next = document.createElement('div');
addClass(next, "".concat(NAMESPACE, "-cell__control"));
addClass(next, "".concat(NAMESPACE, "-cell__control--next"));
setData(next, DATA_ACTION, ACTION_NEXT);
cell.appendChild(next);
}
grid.appendChild(cell);
_this.data[type] = data;
_this.render(type);
});
if (inline) {
container.innerHTML = '';
}
container.appendChild(picker);
this.bind();
}
/**
* Get the no conflict picker class.
* @returns {Picker} The picker class.
*/
}], [{
key: "noConflict",
value: function noConflict() {
WINDOW.Picker = AnotherPicker;
return Picker;
}
/**
* Change the default options.
* @param {Object} options - The new default options.
*/
}, {
key: "setDefaults",
value: function setDefaults(options) {
deepAssign(DEFAULTS, LANGUAGES[options.language], isPlainObject(options) && options);
}
}]);
return Picker;
}();
deepAssign(Picker.prototype, events, handlers, helpers, methods);
Picker.languages = LANGUAGES;
return Picker;
}));
================================================
FILE: docs/css/main.css
================================================
.carbonads {
border: 1px solid #ccc;
border-radius: 0.25rem;
font-size: 0.875rem;
overflow: hidden;
padding: 1rem;
}
.carbon-wrap {
overflow: hidden;
}
.carbon-img {
clear: left;
display: block;
float: left;
}
.carbon-text,
.carbon-poweredby {
display: block;
margin-left: 140px;
}
.carbon-text,
.carbon-text:hover,
.carbon-text:focus {
color: #fff;
text-decoration: none;
}
.carbon-poweredby,
.carbon-poweredby:hover,
.carbon-poweredby:focus {
color: #ddd;
text-decoration: none;
}
@media (min-width: 768px) {
.carbonads {
float: right;
margin-bottom: -1rem;
margin-top: -1rem;
max-width: 360px;
}
}
.footer {
font-size: 0.875rem;
}
.heart {
color: #ddd;
display: block;
height: 2rem;
line-height: 2rem;
margin-bottom: 0;
margin-top: 1rem;
position: relative;
text-align: center;
width: 100%;
}
.heart:hover {
color: #ff4136;
}
.heart::before {
border-top: 1px solid #eee;
content: " ";
display: block;
height: 0;
left: 0;
position: absolute;
right: 0;
top: 50%;
}
.heart::after {
background-color: #fff;
content: "♥";
padding-left: 0.5rem;
padding-right: 0.5rem;
position: relative;
z-index: 1;
}
.docs-picker-container {
border: 1px dashed #eee;
display: none;
margin: 0.5rem auto;
min-height: 40px;
position: relative;
}
.docs-picker-container::before {
color: #ccc;
content: 'Container for inline picker';
font-size: 12px;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
z-index: -1;
}
.docs-options .form-check {
margin-bottom: 0;
}
.docs-options .input-group {
margin-bottom: 0.5rem;
}
.docs-options .input-group-prepend .input-group-text {
min-width: 6rem;
}
.docs-methods > .input-group,
.docs-methods > .btn-group,
.docs-methods > .btn {
margin-bottom: 0.5rem;
}
.js-super-picker-container .picker-years {
width: 28%;
}
================================================
FILE: docs/css/picker.css
================================================
/*!
* Picker.js v1.2.1
* https://fengyuanchen.github.io/pickerjs
*
* Copyright 2016-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2019-02-18T13:08:09.658Z
*/
:root {
--gray: #999;
--blue: #0074d9;
--color: #333;
--background-color: #fff;
--border: 1px solid #eee;
}
.picker {
background-color: rgba(0, 0, 0, 0.5);
color: #333;
color: var(--color);
direction: ltr;
display: none;
font-size: 1rem;
line-height: 1.5;
overflow: hidden;
-ms-touch-action: none;
touch-action: none;
-webkit-transition: opacity 0.15s;
transition: opacity 0.15s;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.picker-fixed {
bottom: 0;
left: 0;
position: fixed;
right: 0;
top: 0;
z-index: 1986;
}
.picker-fixed > .picker-dialog {
bottom: -100%;
left: 0;
max-height: 100%;
position: absolute;
right: 0;
-webkit-transition: bottom 0.3s;
transition: bottom 0.3s;
}
.picker-fixed .picker-header {
display: block;
}
.picker-fixed .picker-footer {
display: table;
}
.picker-open {
display: block;
opacity: 0;
}
.picker-opened {
opacity: 1;
}
.picker-opened > .picker-dialog {
bottom: 0;
}
.picker-dialog {
background-color: #fff;
background-color: var(--background-color);
border: 1px solid #eee;
border: var(--border);
}
.picker-header {
border-bottom: 1px solid #eee;
border-bottom: var(--border);
display: none;
padding: 0.875rem 1.25rem;
position: relative;
}
.picker-title {
font-size: 1.125rem;
font-weight: 500;
line-height: 1.25rem;
margin: 0;
}
.picker-close {
background-color: transparent;
border-width: 0;
color: #999;
color: var(--gray);
cursor: pointer;
font-size: 1.75rem;
height: 3rem;
opacity: 0.75;
padding: 0;
position: absolute;
right: 0;
top: 0;
width: 3rem;
}
.picker-close:focus,
.picker-close:hover {
opacity: 1;
outline: none;
}
.picker-body {
overflow: hidden;
}
.picker-grid {
display: table;
table-layout: fixed;
width: 100%;
}
.picker-cell {
display: table-cell;
position: relative;
}
.picker-cell::before,
.picker-cell::after {
content: '';
display: block;
left: 0;
position: absolute;
right: 0;
z-index: 3;
}
.picker-cell::before {
background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.05)));
background-image: linear-gradient(to top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.05));
bottom: 50%;
margin-bottom: 1rem;
top: 0;
}
.picker-cell::after {
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0)), to(rgba(0, 0, 0, 0.05)));
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.05));
bottom: 0;
margin-top: 1rem;
top: 50%;
}
.picker-cell + .picker-cell {
border-left: 1px solid #eee;
border-left: var(--border);
}
.picker-headers .picker-cell::before {
margin-bottom: 0;
}
.picker-headers .picker-cell::after {
margin-top: 2rem;
}
.picker-single:not(.picker-controls):not(.picker-headers) .picker-cell::before,
.picker-single:not(.picker-controls):not(.picker-headers) .picker-cell::after {
display: none;
}
.picker-cell__header {
color: #999;
color: var(--gray);
font-size: 0.875rem;
font-weight: 500;
line-height: 1.5rem;
margin: 0;
overflow: hidden;
padding: 0.25rem 0.5rem;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
}
.picker-cell__control {
cursor: pointer;
height: 2rem;
padding: 0.25rem 0.5rem;
position: relative;
z-index: 4;
}
.picker-cell__control::before {
border: 0 solid #ccc;
content: '';
display: block;
height: 0.5rem;
left: 50%;
position: absolute;
top: 50%;
-webkit-transform: translate(-50%, -50%) rotate(-45deg);
-ms-transform: translate(-50%, -50%) rotate(-45deg);
transform: translate(-50%, -50%) rotate(-45deg);
width: 0.5rem;
}
.picker-cell__control:hover::before {
border-color: var(--primary);
}
.picker-cell__control--prev::before {
border-right-width: 1px;
border-top-width: 1px;
margin-top: 2px;
}
.picker-cell__control--next::before {
border-bottom-width: 1px;
border-left-width: 1px;
margin-bottom: 2px;
}
.picker-cell__body {
overflow: hidden;
position: relative;
}
.picker-cell__body::before,
.picker-cell__body::after {
content: '';
height: 2rem;
left: 0;
position: absolute;
right: 0;
z-index: 1;
}
.picker-cell__body::before {
background-image: -webkit-gradient(linear, left bottom, left top, from(rgba(255, 255, 255, 0)), to(rgba(255, 255, 255, 1)));
background-image: linear-gradient(to top, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
top: 0;
}
.picker-cell__body::after {
background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0)), to(rgba(255, 255, 255, 1)));
background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
bottom: 0;
}
.picker-single .picker-cell__body::before,
.picker-single .picker-cell__body::after {
display: none;
}
.picker-list {
list-style: none;
margin: -2rem 0;
padding: 0;
position: relative;
}
.picker-item {
color: #999;
color: var(--gray);
padding: 0.25rem 0.5rem;
text-align: center;
white-space: nowrap;
}
.picker-picked {
color: #0074d9;
color: var(--blue);
font-size: 1.125em;
line-height: 1.5rem;
}
.picker-footer {
border-top: 1px solid #eee;
border-top: var(--border);
display: none;
width: 100%;
}
.picker-cancel,
.picker-confirm {
background-color: transparent;
border-width: 0;
cursor: pointer;
display: table-cell;
font-size: 1rem;
padding: 0.75rem 1rem;
width: 50%;
}
.picker-cancel:focus,
.picker-cancel:hover,
.picker-confirm:focus,
.picker-confirm:hover {
background-color: #fcfcfc;
outline: none;
}
.picker-confirm {
color: #0074d9;
color: var(--blue);
}
================================================
FILE: docs/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="JavaScript date time picker.">
<meta name="author" content="Chen Fengyuan">
<title>Picker.js</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://unpkg.com/highlightjs@9.12.0/styles/github.css">
<link rel="stylesheet" href="css/picker.css">
<link rel="stylesheet" href="css/main.css">
</head>
<body>
<!--[if lt IE 9]>
<div class="alert alert-warning alert-dismissible fade show m-0 rounded-0" role="alert">
You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<![endif]-->
<!-- Header -->
<header class="navbar navbar-light navbar-expand-md">
<div class="container">
<a class="navbar-brand" href="./">Picker.js</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar-collapse" aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbar-collapse" role="navigation">
<nav class="nav navbar-nav">
<a class="nav-link" href="https://github.com/fengyuanchen/pickerjs/blob/master/README.md">Docs</a>
<a class="nav-link" href="https://github.com/fengyuanchen/pickerjs">GitHub</a>
<a class="nav-link" href="https://fengyuanchen.github.io">Explore</a>
<a class="nav-link" href="https://chenfengyuan.com">About</a>
</nav>
</div>
</nav>
</header>
<!-- Jumbotron -->
<div class="jumbotron bg-primary text-white rounded-0">
<div class="container">
<div class="row">
<div class="col-md">
<h1>Picker.js <small class="h6">v1.2.1</small></h1>
<p class="lead">JavaScript date time picker.</p>
</div>
<div class="col-md">
<div class="carbonads">
<script id="_carbonads_js" src="https://cdn.carbonads.com/carbon.js?serve=CKYI55Q7&placement=fengyuanchengithubio" async></script>
</div>
</div>
</div>
</div>
</div>
<!-- Content -->
<div class="container">
<h1>Overview</h1>
<hr>
<div class="row">
<div class="col-sm-6 col-md-4">
<h3>Demo</h3>
<hr>
<div class="docs-picker">
<input type="text" class="form-control docs-date" name="date" placeholder="Pick a date and time">
<div class="docs-picker-container"></div>
</div>
<br>
</div>
<div class="col-sm-6 col-md-4">
<h3>Options</h3>
<hr>
<div class="docs-options">
<ul class="list-group mb-2">
<li class="list-group-item">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="container" name="container">
<label class="form-check-label" for="container">container</label>
</div>
</li>
<li class="list-group-item">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="controls" name="controls">
<label class="form-check-label" for="controls">controls</label>
</div>
</li>
<li class="list-group-item">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="headers" name="headers">
<label class="form-check-label" for="headers">headers</label>
</div>
</li>
<li class="list-group-item">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="inline" name="inline">
<label class="form-check-label" for="inline">inline</label>
</div>
</li>
</ul>
<div class="input-group">
<span class="input-group-prepend">
<label class="input-group-text" for="date">date</label>
</span>
<input type="text" class="form-control" id="date" name="date" placeholder="null">
</div>
<div class="input-group">
<span class="input-group-prepend">
<label class="input-group-text" for="format">format</label>
</span>
<input type="text" class="form-control" id="format" name="format" value="YYYY-MM-DD HH:mm" placeholder="YYYY-MM-DD HH:mm">
</div>
<div class="input-group">
<span class="input-group-prepend">
<label class="input-group-text" for="language">language</label>
</span>
<select class="form-control" id="language" name="language">
<option value="">(Default)</option>
<option value="en-US">en-US</option>
<option value="en-GB">en-GB</option>
<option value="pl-PL">pl-PL</option>
<option value="zh-CN">zh-CN</option>
</select>
</div>
<div class="input-group">
<span class="input-group-prepend">
<label class="input-group-text" for="rows">rows</label>
</span>
<select class="form-control" id="rows" name="rows">
<option value="1">1</option>
<option value="3">3</option>
<option value="5" selected>5</option>
<option value="7">7</option>
<option value="9">9</option>
</select>
</div>
</div>
<br>
</div>
<div class="col-sm-6 col-md-4">
<h3>Methods</h3>
<hr>
<div class="docs-methods">
<div class="input-group">
<div class="input-group-prepend">
<button type="button" class="btn btn-primary" data-method="getDate" data-related-target="#putDate">Get Date</button>
</div>
<input type="text" class="form-control" id="putDate">
</div>
<div class="input-group">
<div class="input-group-prepend">
<button type="button" class="btn btn-primary" data-args="[true]" data-method="getDate" data-related-target="#putDateFormatted">Get Date (formatted)</button>
</div>
<input type="text" class="form-control" id="putDateFormatted">
</div>
<button type="button" class="btn btn-block btn-primary" data-method="show">Show</button>
<button type="button" class="btn btn-block btn-primary" data-method="pick">Pick</button>
<button type="button" class="btn btn-block btn-primary" data-method="update">Update</button>
<button type="button" class="btn btn-block btn-primary" data-method="reset">Reset</button>
<button type="button" class="btn btn-block btn-danger" data-method="destroy">Destroy</button>
</div>
</div>
</div>
<h1>Examples</h1>
<hr>
<div class="card mb-4">
<h4 class="card-header">Date Picker</h4>
<div class="card-body">
<h6>Demo</h6>
<input type="text" class="form-control js-date-picker" value="Oct 24, 2048">
<br>
<h6>HTML</h6>
<pre class="html"><code>
<input type="text" class="form-control js-date-picker" value="Oct 24, 2048">
</code></pre>
<h6>JavaScript</h6>
<pre class="js"><code>new Picker(document.querySelector('.js-date-picker'), {
format: 'MMM D, YYYY',
text: {
title: 'Pick a date',
},
});</code></pre>
</div>
</div>
<div class="card mb-4">
<h4 class="card-header">Time Picker</h4>
<div class="card-body">
<h6>Demo</h6>
<input type="text" class="form-control js-time-picker" value="02:56">
<br>
<h6>HTML</h6>
<pre class="html"><code>
<input type="text" class="form-control js-time-picker" value="02:56">
</code></pre>
<h6>JavaScript</h6>
<pre class="js"><code>new Picker(document.querySelector('.js-time-picker'), {
format: 'HH:mm',
headers: true,
text: {
title: 'Pick a time',
},
});</code></pre>
</div>
</div>
<div class="card mb-4">
<h4 class="card-header">Full Picker</h4>
<div class="card-body">
<h6>Demo</h6>
<input type="text" class="form-control js-full-picker" value="2048-10-24 05:12:02.056">
<br>
<h6>HTML</h6>
<pre class="html"><code>
<input type="text" class="form-control js-full-picker" value="2048-10-24 05:12:02.056">
</code></pre>
<h6>JavaScript</h6>
<pre class="js"><code>new Picker(document.querySelector('.js-full-picker'), {
controls: true,
format: 'YYYY-MM-DD HH:mm:ss.SSS',
headers: true,
});</code></pre>
</div>
</div>
<div class="card mb-4">
<h4 class="card-header">Month Picker</h4>
<div class="card-body">
<h6>Demo</h6>
<input type="text" class="form-control js-month-picker" value="November">
<br>
<h6>HTML</h6>
<pre class="html"><code>
<input type="text" class="form-control js-month-picker" value="November">
</code></pre>
<h6>JavaScript</h6>
<pre class="js"><code>new Picker(document.querySelector('.js-month-picker'), {
format: 'MMMM',
text: {
title: 'Pick a month',
},
});</code></pre>
</div>
</div>
<div class="card mb-4">
<h4 class="card-header">Inline Picker</h4>
<div class="card-body">
<h6>Demo</h6>
<div class="js-inline-picker">2048-10-24 05:12</div>
<br>
<h6>HTML</h6>
<pre class="html"><code>
<div class="js-inline-picker">2048-10-24 05:12</div>
</code></pre>
<h6>JavaScript</h6>
<pre class="js"><code>new Picker(document.querySelector('.js-inline-picker'), {
controls: true,
inline: true,
});</code></pre>
</div>
</div>
<div class="card mb-4">
<h4 class="card-header">Mini Picker</h4>
<div class="card-body">
<h6>Demo</h6>
<input type="text" class="form-control sr-only js-mini-picker">
<div class="js-mini-picker-container"></div>
<br>
<h6>HTML</h6>
<pre class="html"><code>
<input type="text" class="form-control sr-only js-mini-picker">
<div class="js-mini-picker-container"></div>
</code></pre>
<h6>JavaScript</h6>
<pre class="js"><code>new Picker(document.querySelector('.js-mini-picker'), {
container: '.js-mini-picker-container',
inline: true,
rows: 1,
});</code></pre>
</div>
</div>
<div class="card mb-4">
<h4 class="card-header">Super Picker / I18n</h4>
<div class="card-body">
<h6>Demo</h6>
<input type="text" class="form-control js-super-picker" value="2020年2月20日2时20分">
<div class="js-super-picker-container"></div>
<br>
<h6>HTML</h6>
<pre class="html"><code>
<input type="text" class="form-control js-super-picker" value="2020年2月20日2时20分">
<div class="js-super-picker-container"></div>
</code></pre>
<h6>CSS</h6>
<pre class="css"><code>.js-super-picker-container .picker-years {
width: 28%;
}</code></pre>
<h6>JavaScript</h6>
<pre class="js"><code>new Picker(document.querySelector('.js-super-picker'), {
container: '.js-super-picker-container',
format: 'YYYY年M月D日H时m分',
increment: {
minute: 10,
},
text: {
title: '选择日期时间',
cancel: '取消',
confirm: '确认',
},
translate(type, text) {
const suffixes = {
year: '年',
month: '月',
day: '日',
hour: '时',
minute: '分',
};
return Number(text) + suffixes[type];
},
});</code></pre>
</div>
</div>
</div>
<!-- Footer -->
<footer class="footer">
<div class="container">
<p class="heart"></p>
<nav class="nav flex-wrap justify-content-center mb-3">
<a class="nav-link" href="https://github.com/fengyuanchen/pickerjs">GitHub</a>
<a class="nav-link" href="https://github.com/fengyuanchen/pickerjs/releases">Releases</a>
<a class="nav-link" href="https://github.com/fengyuanchen/pickerjs/blob/master/LICENSE">License</a>
<a class="nav-link" href="https://chenfengyuan.com">About</a>
</nav>
</div>
</footer>
<!-- Scripts -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js"></script>
<script src="https://unpkg.com/highlightjs@9.12.0/highlight.pack.js"></script>
<script src="https://fengyuanchen.github.io/shared/google-analytics.js"></script>
<script src="js/picker.js"></script>
<script src="js/picker.en-US.js"></script>
<script src="js/picker.en-GB.js"></script>
<script src="js/picker.pl-PL.js"></script>
<script src="js/picker.zh-CN.js"></script>
<script src="js/main.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</body>
</html>
================================================
FILE: docs/js/main.js
================================================
window.onload = function () {
'use strict';
var Picker = window.Picker;
var input = document.querySelector('.docs-date');
var pickerContainer = document.querySelector('.docs-picker-container');
var options = {
show: function (e) {
console.log(e.type);
},
shown: function (e) {
console.log(e.type);
},
hide: function (e) {
console.log(e.type);
},
hidden: function (e) {
console.log(e.type);
},
pick: function (e) {
console.log(e.type);
}
};
var picker = new Picker(input, options);
console.log(picker);
input.addEventListener('change', function (e) {
console.log(e.type);
}, false);
input.addEventListener('show', function (e) {
console.log(e.type);
}, false);
input.addEventListener('shown', function (e) {
console.log(e.type);
}, false);
input.addEventListener('hide', function (e) {
console.log(e.type);
}, false);
input.addEventListener('hidden', function (e) {
console.log(e.type);
}, false);
input.addEventListener('pick', function (e) {
console.log(e.type);
}, false);
document.querySelector('.docs-options').addEventListener('change', function (e) {
if (!picker) {
return;
}
var target = e.target;
var type = target.type;
var name = target.name;
var value = type === 'checkbox' ? target.checked : target.value;
var relatedElement;
switch (name) {
case 'container':
if (value) {
value = pickerContainer;
pickerContainer.style.display = 'block';
} else {
pickerContainer.style.display = 'none';
}
break;
case 'inline':
relatedElement = document.querySelector('input[name="container"]');
if (!relatedElement.checked) {
relatedElement.click();
}
break;
case 'language':
relatedElement = document.querySelector('input[name="format"]');
setTimeout(function () {
relatedElement.placeholder = relatedElement.value = picker.options.format;
}, 0);
break;
// No default
}
options[name] = value;
picker.destroy();
picker = new Picker(input, options);
}, false);
document.querySelector('.docs-methods').addEventListener('click', function (e) {
if (!picker) {
return;
}
var target = e.target;
var method = target.getAttribute('data-method');
var relatedTarget;
var result;
if (method) {
result = picker[method].apply(picker, JSON.parse(target.getAttribute('data-args')));
relatedTarget = target.getAttribute('data-related-target');
if (relatedTarget) {
document.querySelector(relatedTarget).value = result;
}
if (method === 'destroy') {
picker = null;
}
}
});
// Examples
// --------------------------------------------------
new Picker(document.querySelector('.js-date-picker'), {
format: 'MMM D, YYYY',
text: {
title: 'Pick a date',
},
});
new Picker(document.querySelector('.js-time-picker'), {
format: 'HH:mm',
headers: true,
text: {
ti
gitextract_tcbz06ub/
├── .babelrc
├── .editorconfig
├── .eslintrc
├── .gitattributes
├── .github/
│ ├── CODE_OF_CONDUCT.md
│ ├── CONTRIBUTING.md
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ └── feature_request.md
│ ├── ISSUE_TEMPLATE.md
│ └── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .stylelintrc
├── .travis.yml
├── CHANGELOG.md
├── LICENSE
├── README.md
├── dist/
│ ├── picker.common.js
│ ├── picker.css
│ ├── picker.esm.js
│ └── picker.js
├── docs/
│ ├── css/
│ │ ├── main.css
│ │ └── picker.css
│ ├── index.html
│ └── js/
│ ├── main.js
│ ├── picker.en-GB.js
│ ├── picker.en-US.js
│ ├── picker.js
│ ├── picker.pl-PL.js
│ └── picker.zh-CN.js
├── i18n/
│ ├── picker.en-GB.js
│ ├── picker.en-US.js
│ ├── picker.pl-PL.js
│ ├── picker.pt-BR.js
│ └── picker.zh-CN.js
├── package.json
├── postcss.config.js
├── rollup.config.js
├── src/
│ ├── css/
│ │ └── picker.css
│ ├── index.css
│ ├── index.js
│ └── js/
│ ├── constants.js
│ ├── defaults.js
│ ├── events.js
│ ├── handlers.js
│ ├── helpers.js
│ ├── methods.js
│ ├── picker.js
│ ├── template.js
│ └── utilities.js
├── test/
│ ├── .eslintrc
│ ├── helpers.js
│ ├── karma.conf.js
│ └── specs/
│ ├── Picker.spec.js
│ ├── events/
│ │ ├── hidden.spec.js
│ │ ├── hide.spec.js
│ │ ├── pick.spec.js
│ │ ├── show.spec.js
│ │ └── shown.spec.js
│ ├── methods/
│ │ ├── destroy.spec.js
│ │ ├── formatDate.spec.js
│ │ ├── getDate.spec.js
│ │ ├── hide.spec.js
│ │ ├── next.spec.js
│ │ ├── noConflict.spec.js
│ │ ├── parseDate.spec.js
│ │ ├── pick.spec.js
│ │ ├── prev.spec.js
│ │ ├── reset.spec.js
│ │ ├── setDate.spec.js
│ │ ├── setDefaults.spec.js
│ │ ├── show.spec.js
│ │ └── update.spec.js
│ └── options/
│ ├── container.spec.js
│ ├── controls.spec.js
│ ├── date.spec.js
│ ├── format.spec.js
│ ├── headers.spec.js
│ ├── hidden.spec.js
│ ├── hide.spec.js
│ ├── increment.spec.js
│ ├── inline.spec.js
│ ├── language.spec.js
│ ├── months.spec.js
│ ├── monthsShort.spec.js
│ ├── pick.spec.js
│ ├── rows.spec.js
│ ├── show.spec.js
│ ├── shown.spec.js
│ ├── text.spec.js
│ └── translate.spec.js
└── types/
└── index.d.ts
SYMBOL INDEX (262 symbols across 25 files)
FILE: dist/picker.common.js
function _typeof (line 13) | function _typeof(obj) {
function _classCallCheck (line 27) | function _classCallCheck(instance, Constructor) {
function _defineProperties (line 33) | function _defineProperties(target, props) {
function _createClass (line 43) | function _createClass(Constructor, protoProps, staticProps) {
function _toConsumableArray (line 49) | function _toConsumableArray(arr) {
function _arrayWithoutHoles (line 53) | function _arrayWithoutHoles(arr) {
function _iterableToArray (line 61) | function _iterableToArray(iter) {
function _nonIterableSpread (line 65) | function _nonIterableSpread() {
function typeOf (line 167) | function typeOf(value) {
function isString (line 176) | function isString(value) {
function isNumber (line 195) | function isNumber(value) {
function isObject (line 204) | function isObject(value) {
function isPlainObject (line 213) | function isPlainObject(value) {
function isFunction (line 232) | function isFunction(value) {
function isDate (line 241) | function isDate(value) {
function isValidDate (line 250) | function isValidDate(value) {
function forEach (line 260) | function forEach(data, callback) {
function deepAssign (line 289) | function deepAssign(target) {
function addClass (line 316) | function addClass(element, value) {
function removeClass (line 347) | function removeClass(element, value) {
function hyphenate (line 375) | function hyphenate(value) {
function getData (line 385) | function getData(element, name) {
function setData (line 403) | function setData(element, name, data) {
function removeData (line 418) | function removeData(element, name) {
function removeListener (line 476) | function removeListener(element, type, listener) {
function addListener (line 508) | function addListener(element, type, listener) {
function dispatchEvent (line 550) | function dispatchEvent(element, type, data) {
function isLeapYear (line 572) | function isLeapYear(year) {
function getDaysInMonth (line 582) | function getDaysInMonth(year, month) {
function addLeadingZero (line 592) | function addLeadingZero(value) {
function tokenToType (line 615) | function tokenToType(token) {
function parseFormat (line 633) | function parseFormat(format) {
function Picker (line 1422) | function Picker(element) {
FILE: dist/picker.esm.js
function _typeof (line 11) | function _typeof(obj) {
function _classCallCheck (line 25) | function _classCallCheck(instance, Constructor) {
function _defineProperties (line 31) | function _defineProperties(target, props) {
function _createClass (line 41) | function _createClass(Constructor, protoProps, staticProps) {
function _toConsumableArray (line 47) | function _toConsumableArray(arr) {
function _arrayWithoutHoles (line 51) | function _arrayWithoutHoles(arr) {
function _iterableToArray (line 59) | function _iterableToArray(iter) {
function _nonIterableSpread (line 63) | function _nonIterableSpread() {
function typeOf (line 165) | function typeOf(value) {
function isString (line 174) | function isString(value) {
function isNumber (line 193) | function isNumber(value) {
function isObject (line 202) | function isObject(value) {
function isPlainObject (line 211) | function isPlainObject(value) {
function isFunction (line 230) | function isFunction(value) {
function isDate (line 239) | function isDate(value) {
function isValidDate (line 248) | function isValidDate(value) {
function forEach (line 258) | function forEach(data, callback) {
function deepAssign (line 287) | function deepAssign(target) {
function addClass (line 314) | function addClass(element, value) {
function removeClass (line 345) | function removeClass(element, value) {
function hyphenate (line 373) | function hyphenate(value) {
function getData (line 383) | function getData(element, name) {
function setData (line 401) | function setData(element, name, data) {
function removeData (line 416) | function removeData(element, name) {
function removeListener (line 474) | function removeListener(element, type, listener) {
function addListener (line 506) | function addListener(element, type, listener) {
function dispatchEvent (line 548) | function dispatchEvent(element, type, data) {
function isLeapYear (line 570) | function isLeapYear(year) {
function getDaysInMonth (line 580) | function getDaysInMonth(year, month) {
function addLeadingZero (line 590) | function addLeadingZero(value) {
function tokenToType (line 613) | function tokenToType(token) {
function parseFormat (line 631) | function parseFormat(format) {
function Picker (line 1420) | function Picker(element) {
FILE: dist/picker.js
function _typeof (line 17) | function _typeof(obj) {
function _classCallCheck (line 31) | function _classCallCheck(instance, Constructor) {
function _defineProperties (line 37) | function _defineProperties(target, props) {
function _createClass (line 47) | function _createClass(Constructor, protoProps, staticProps) {
function _toConsumableArray (line 53) | function _toConsumableArray(arr) {
function _arrayWithoutHoles (line 57) | function _arrayWithoutHoles(arr) {
function _iterableToArray (line 65) | function _iterableToArray(iter) {
function _nonIterableSpread (line 69) | function _nonIterableSpread() {
function typeOf (line 171) | function typeOf(value) {
function isString (line 180) | function isString(value) {
function isNumber (line 199) | function isNumber(value) {
function isObject (line 208) | function isObject(value) {
function isPlainObject (line 217) | function isPlainObject(value) {
function isFunction (line 236) | function isFunction(value) {
function isDate (line 245) | function isDate(value) {
function isValidDate (line 254) | function isValidDate(value) {
function forEach (line 264) | function forEach(data, callback) {
function deepAssign (line 293) | function deepAssign(target) {
function addClass (line 320) | function addClass(element, value) {
function removeClass (line 351) | function removeClass(element, value) {
function hyphenate (line 379) | function hyphenate(value) {
function getData (line 389) | function getData(element, name) {
function setData (line 407) | function setData(element, name, data) {
function removeData (line 422) | function removeData(element, name) {
function removeListener (line 480) | function removeListener(element, type, listener) {
function addListener (line 512) | function addListener(element, type, listener) {
function dispatchEvent (line 554) | function dispatchEvent(element, type, data) {
function isLeapYear (line 576) | function isLeapYear(year) {
function getDaysInMonth (line 586) | function getDaysInMonth(year, month) {
function addLeadingZero (line 596) | function addLeadingZero(value) {
function tokenToType (line 619) | function tokenToType(token) {
function parseFormat (line 637) | function parseFormat(format) {
function Picker (line 1426) | function Picker(element) {
FILE: docs/js/main.js
method translate (line 177) | translate(type, text) {
FILE: docs/js/picker.js
function _typeof (line 17) | function _typeof(obj) {
function _classCallCheck (line 31) | function _classCallCheck(instance, Constructor) {
function _defineProperties (line 37) | function _defineProperties(target, props) {
function _createClass (line 47) | function _createClass(Constructor, protoProps, staticProps) {
function _toConsumableArray (line 53) | function _toConsumableArray(arr) {
function _arrayWithoutHoles (line 57) | function _arrayWithoutHoles(arr) {
function _iterableToArray (line 65) | function _iterableToArray(iter) {
function _nonIterableSpread (line 69) | function _nonIterableSpread() {
function typeOf (line 171) | function typeOf(value) {
function isString (line 180) | function isString(value) {
function isNumber (line 199) | function isNumber(value) {
function isObject (line 208) | function isObject(value) {
function isPlainObject (line 217) | function isPlainObject(value) {
function isFunction (line 236) | function isFunction(value) {
function isDate (line 245) | function isDate(value) {
function isValidDate (line 254) | function isValidDate(value) {
function forEach (line 264) | function forEach(data, callback) {
function deepAssign (line 293) | function deepAssign(target) {
function addClass (line 320) | function addClass(element, value) {
function removeClass (line 351) | function removeClass(element, value) {
function hyphenate (line 379) | function hyphenate(value) {
function getData (line 389) | function getData(element, name) {
function setData (line 407) | function setData(element, name, data) {
function removeData (line 422) | function removeData(element, name) {
function removeListener (line 480) | function removeListener(element, type, listener) {
function addListener (line 512) | function addListener(element, type, listener) {
function dispatchEvent (line 554) | function dispatchEvent(element, type, data) {
function isLeapYear (line 576) | function isLeapYear(year) {
function getDaysInMonth (line 586) | function getDaysInMonth(year, month) {
function addLeadingZero (line 596) | function addLeadingZero(value) {
function tokenToType (line 619) | function tokenToType(token) {
function parseFormat (line 637) | function parseFormat(format) {
function Picker (line 1426) | function Picker(element) {
FILE: src/js/constants.js
constant IS_BROWSER (line 1) | const IS_BROWSER = typeof window !== 'undefined';
constant WINDOW (line 2) | const WINDOW = IS_BROWSER ? window : {};
constant IS_TOUCH_DEVICE (line 3) | const IS_TOUCH_DEVICE = IS_BROWSER ? 'ontouchstart' in WINDOW.document.d...
constant HAS_POINTER_EVENT (line 4) | const HAS_POINTER_EVENT = IS_BROWSER ? 'PointerEvent' in WINDOW : false;
constant NAMESPACE (line 5) | const NAMESPACE = 'picker';
constant LANGUAGES (line 6) | const LANGUAGES = {};
constant ACTION_HIDE (line 9) | const ACTION_HIDE = 'hide';
constant ACTION_NEXT (line 10) | const ACTION_NEXT = 'next';
constant ACTION_PICK (line 11) | const ACTION_PICK = 'pick';
constant ACTION_PREV (line 12) | const ACTION_PREV = 'prev';
constant CLASS_OPEN (line 15) | const CLASS_OPEN = `${NAMESPACE}-open`;
constant CLASS_OPENED (line 16) | const CLASS_OPENED = `${NAMESPACE}-opened`;
constant CLASS_PICKED (line 17) | const CLASS_PICKED = `${NAMESPACE}-picked`;
constant DATA_ACTION (line 21) | const DATA_ACTION = `${NAMESPACE}Action`;
constant DATA_TOKEN (line 22) | const DATA_TOKEN = 'token';
constant DATA_TYPE (line 23) | const DATA_TYPE = 'type';
constant DATA_NAME (line 24) | const DATA_NAME = 'name';
constant DATA_VALUE (line 25) | const DATA_VALUE = 'value';
constant EVENT_CLICK (line 28) | const EVENT_CLICK = 'click';
constant EVENT_FOCUS (line 29) | const EVENT_FOCUS = 'focus';
constant EVENT_HIDDEN (line 30) | const EVENT_HIDDEN = 'hidden';
constant EVENT_HIDE (line 31) | const EVENT_HIDE = 'hide';
constant EVENT_KEY_DOWN (line 32) | const EVENT_KEY_DOWN = 'keydown';
constant EVENT_PICK (line 33) | const EVENT_PICK = 'pick';
constant EVENT_TOUCH_START (line 34) | const EVENT_TOUCH_START = IS_TOUCH_DEVICE ? 'touchstart' : 'mousedown';
constant EVENT_TOUCH_MOVE (line 35) | const EVENT_TOUCH_MOVE = IS_TOUCH_DEVICE ? 'touchmove' : 'mousemove';
constant EVENT_TOUCH_END (line 36) | const EVENT_TOUCH_END = IS_TOUCH_DEVICE ? 'touchend touchcancel' : 'mous...
constant EVENT_POINTER_DOWN (line 37) | const EVENT_POINTER_DOWN = HAS_POINTER_EVENT ? 'pointerdown' : EVENT_TOU...
constant EVENT_POINTER_MOVE (line 38) | const EVENT_POINTER_MOVE = HAS_POINTER_EVENT ? 'pointermove' : EVENT_TOU...
constant EVENT_POINTER_UP (line 39) | const EVENT_POINTER_UP = HAS_POINTER_EVENT ? 'pointerup pointercancel' :...
constant EVENT_SHOW (line 40) | const EVENT_SHOW = 'show';
constant EVENT_SHOWN (line 41) | const EVENT_SHOWN = 'shown';
constant EVENT_WHEEL (line 42) | const EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
FILE: src/js/defaults.js
method translate (line 76) | translate(type, text) {
FILE: src/js/events.js
method bind (line 22) | bind() {
method unbind (line 55) | unbind() {
FILE: src/js/handlers.js
method focus (line 13) | focus(event) {
method click (line 18) | click(event) {
method wheel (line 40) | wheel(event) {
method pointerdown (line 62) | pointerdown(event) {
method pointermove (line 90) | pointermove(event) {
method pointerup (line 120) | pointerup(event) {
method keydown (line 139) | keydown(event) {
FILE: src/js/helpers.js
method render (line 19) | render(type) {
method current (line 68) | current(type, value) {
method getValue (line 146) | getValue() {
method setValue (line 152) | setValue(value) {
method open (line 162) | open() {
method close (line 169) | close() {
FILE: src/js/methods.js
method show (line 33) | show(immediate = false) {
method hide (line 74) | hide(immediate = false) {
method prev (line 108) | prev(type) {
method next (line 150) | next(type) {
method pick (line 188) | pick() {
method getDate (line 213) | getDate(formatted = false) {
method setDate (line 224) | setDate(date) {
method update (line 234) | update() {
method reset (line 242) | reset() {
method parseDate (line 255) | parseDate(date) {
method formatDate (line 360) | formatDate(date) {
method destroy (line 439) | destroy() {
FILE: src/js/picker.js
constant REGEXP_DELIMITER (line 31) | const REGEXP_DELIMITER = /\{\{\s*(\w+)\s*\}\}/g;
constant REGEXP_INPUTS (line 32) | const REGEXP_INPUTS = /input|textarea/i;
class Picker (line 35) | class Picker {
method constructor (line 41) | constructor(element, options = {}) {
method init (line 57) | init() {
method noConflict (line 274) | static noConflict() {
method setDefaults (line 283) | static setDefaults(options) {
FILE: src/js/utilities.js
function typeOf (line 13) | function typeOf(value) {
function isString (line 22) | function isString(value) {
function isNumber (line 41) | function isNumber(value) {
function isObject (line 50) | function isObject(value) {
function isPlainObject (line 59) | function isPlainObject(value) {
function isFunction (line 79) | function isFunction(value) {
function isDate (line 88) | function isDate(value) {
function isValidDate (line 97) | function isValidDate(value) {
function forEach (line 107) | function forEach(data, callback) {
function deepAssign (line 134) | function deepAssign(target, ...sources) {
function hasClass (line 158) | function hasClass(element, value) {
function addClass (line 169) | function addClass(element, value) {
function removeClass (line 200) | function removeClass(element, value) {
function toggleClass (line 228) | function toggleClass(element, value, added) {
constant REGEXP_HYPHENATE (line 248) | const REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
function hyphenate (line 255) | function hyphenate(value) {
function getData (line 265) | function getData(element, name) {
function setData (line 283) | function setData(element, name, data) {
function removeData (line 298) | function removeData(element, name) {
constant REGEXP_SPACES (line 317) | const REGEXP_SPACES = /\s\s*/;
method get (line 325) | get() {
method set (line 335) | set(value) {
function removeListener (line 354) | function removeListener(element, type, listener, options = {}) {
function addListener (line 386) | function addListener(element, type, listener, options = {}) {
function dispatchEvent (line 422) | function dispatchEvent(element, type, data) {
function isLeapYear (line 445) | function isLeapYear(year) {
function getDaysInMonth (line 455) | function getDaysInMonth(year, month) {
function addLeadingZero (line 465) | function addLeadingZero(value, length = 1) {
function tokenToType (line 487) | function tokenToType(token) {
constant REGEXP_TOKENS (line 499) | const REGEXP_TOKENS = /(Y|M|D|H|m|s|S)\1*/g;
function parseFormat (line 506) | function parseFormat(format) {
FILE: test/specs/events/hidden.spec.js
method shown (line 5) | shown() {
FILE: test/specs/events/hide.spec.js
method shown (line 5) | shown() {
method shown (line 21) | shown() {
method hidden (line 32) | hidden() {
FILE: test/specs/events/show.spec.js
method shown (line 5) | shown() {
method shown (line 20) | shown() {
FILE: test/specs/methods/hide.spec.js
method shown (line 5) | shown() {
method shown (line 19) | shown() {
FILE: test/specs/methods/show.spec.js
method shown (line 5) | shown() {
method shown (line 19) | shown() {
FILE: test/specs/options/hidden.spec.js
method shown (line 12) | shown() {
method hidden (line 16) | hidden(event) {
FILE: test/specs/options/hide.spec.js
method shown (line 12) | shown() {
method hide (line 16) | hide(event) {
method shown (line 28) | shown() {
method hide (line 38) | hide(event) {
method hidden (line 42) | hidden() {
FILE: test/specs/options/pick.spec.js
method pick (line 12) | pick(event) {
FILE: test/specs/options/show.spec.js
method show (line 12) | show(event) {
method shown (line 16) | shown() {
method hidden (line 20) | hidden() {
method show (line 31) | show(event) {
method shown (line 40) | shown() {
FILE: test/specs/options/shown.spec.js
method shown (line 12) | shown(event) {
FILE: test/specs/options/translate.spec.js
method translate (line 5) | translate(type, text) {
FILE: types/index.d.ts
type HeadersOptions (line 2) | interface HeadersOptions {
type IncrementOptions (line 12) | interface IncrementOptions {
type TextOptions (line 22) | interface TextOptions extends HeadersOptions {
type Options (line 28) | interface Options {
class Picker (line 50) | class Picker {
Condensed preview — 91 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (364K chars).
[
{
"path": ".babelrc",
"chars": 185,
"preview": "{\n \"presets\": [\n [\n \"@babel/preset-env\",\n {\n \"modules\": false\n }\n ]\n ],\n \"env\": {\n \"te"
},
{
"path": ".editorconfig",
"chars": 147,
"preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 2\nindent_style = space\ninsert_final_newline = true\ntrim_"
},
{
"path": ".eslintrc",
"chars": 239,
"preview": "{\n \"extends\": \"airbnb-base\",\n \"env\": {\n \"browser\": true\n },\n \"root\": true,\n \"rules\": {\n \"no-param-reassign\": "
},
{
"path": ".gitattributes",
"chars": 66,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto\n"
},
{
"path": ".github/CODE_OF_CONDUCT.md",
"chars": 1407,
"preview": "# Contributor Code of Conduct\n\nAs contributors and maintainers of this project, we pledge to respect all people who cont"
},
{
"path": ".github/CONTRIBUTING.md",
"chars": 9417,
"preview": "# Contributing to Picker.js\n\n> Based on [Angular's contributing guidelines](https://github.com/angular/angular/blob/mast"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 834,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the b"
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 595,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Is your fea"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 1415,
"preview": "<!--\nPLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.\n\nISSUES MISSING IMPORTANT INFOR"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 1055,
"preview": "## PR Checklist\n\nPlease check if your PR fulfills the following requirements:\n\n- [ ] The commit message follows our [gui"
},
{
"path": ".gitignore",
"chars": 28,
"preview": "*.map\ncoverage\nnode_modules\n"
},
{
"path": ".stylelintrc",
"chars": 192,
"preview": "{\n \"extends\": \"stylelint-config-standard\",\n \"plugins\": [\n \"stylelint-order\"\n ],\n \"rules\": {\n \"no-descending-sp"
},
{
"path": ".travis.yml",
"chars": 134,
"preview": "language: node_js\nnode_js: node\ncache: npm\nscript:\n - npm run lint\n - npm run build\n - npm test\nafter_success:\n - np"
},
{
"path": "CHANGELOG.md",
"chars": 1479,
"preview": "# Changelog\n\n## 1.2.1 (Feb 18, 2019)\n\n- Remove duplicate tokens (#22).\n- Use the latest date to calculate the max day (#"
},
{
"path": "LICENSE",
"chars": 1084,
"preview": "The MIT License (MIT)\n\nCopyright 2016-present Chen Fengyuan\n\nPermission is hereby granted, free of charge, to any person"
},
{
"path": "README.md",
"chars": 9082,
"preview": "# Picker.js\n\n[](https://travis-ci.org/fengyuanch"
},
{
"path": "dist/picker.common.js",
"chars": 45355,
"preview": "/*!\n * Picker.js v1.2.1\n * https://fengyuanchen.github.io/pickerjs\n *\n * Copyright 2016-present Chen Fengyuan\n * Release"
},
{
"path": "dist/picker.css",
"chars": 5914,
"preview": "/*!\n * Picker.js v1.2.1\n * https://fengyuanchen.github.io/pickerjs\n *\n * Copyright 2016-present Chen Fengyuan\n * Release"
},
{
"path": "dist/picker.esm.js",
"chars": 45338,
"preview": "/*!\n * Picker.js v1.2.1\n * https://fengyuanchen.github.io/pickerjs\n *\n * Copyright 2016-present Chen Fengyuan\n * Release"
},
{
"path": "dist/picker.js",
"chars": 48406,
"preview": "/*!\n * Picker.js v1.2.1\n * https://fengyuanchen.github.io/pickerjs\n *\n * Copyright 2016-present Chen Fengyuan\n * Release"
},
{
"path": "docs/css/main.css",
"chars": 1911,
"preview": ".carbonads {\n border: 1px solid #ccc;\n border-radius: 0.25rem;\n font-size: 0.875rem;\n overflow: hidden;\n padding: 1"
},
{
"path": "docs/css/picker.css",
"chars": 5914,
"preview": "/*!\n * Picker.js v1.2.1\n * https://fengyuanchen.github.io/pickerjs\n *\n * Copyright 2016-present Chen Fengyuan\n * Release"
},
{
"path": "docs/index.html",
"chars": 13652,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\">"
},
{
"path": "docs/js/main.js",
"chars": 4197,
"preview": "window.onload = function () {\n 'use strict';\n\n var Picker = window.Picker;\n var input = document.querySelector('.docs"
},
{
"path": "docs/js/picker.en-GB.js",
"chars": 368,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "docs/js/picker.en-US.js",
"chars": 368,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "docs/js/picker.js",
"chars": 48406,
"preview": "/*!\n * Picker.js v1.2.1\n * https://fengyuanchen.github.io/pickerjs\n *\n * Copyright 2016-present Chen Fengyuan\n * Release"
},
{
"path": "docs/js/picker.pl-PL.js",
"chars": 851,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "docs/js/picker.zh-CN.js",
"chars": 887,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "i18n/picker.en-GB.js",
"chars": 368,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "i18n/picker.en-US.js",
"chars": 368,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "i18n/picker.pl-PL.js",
"chars": 851,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "i18n/picker.pt-BR.js",
"chars": 1011,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "i18n/picker.zh-CN.js",
"chars": 887,
"preview": "(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory("
},
{
"path": "package.json",
"chars": 3815,
"preview": "{\n \"name\": \"pickerjs\",\n \"version\": \"1.2.1\",\n \"description\": \"JavaScript date time picker.\",\n \"main\": \"dist/picker.co"
},
{
"path": "postcss.config.js",
"chars": 342,
"preview": "const rollupConfig = require('./rollup.config');\n\nmodule.exports = {\n plugins: {\n 'postcss-import': {},\n 'postcss"
},
{
"path": "rollup.config.js",
"chars": 822,
"preview": "const babel = require('rollup-plugin-babel');\nconst changeCase = require('change-case');\nconst createBanner = require('c"
},
{
"path": "src/css/picker.css",
"chars": 4529,
"preview": ":root {\n --gray: #999;\n --blue: #0074d9;\n --color: #333;\n --background-color: #fff;\n --border: 1px solid #eee;\n}\n\n."
},
{
"path": "src/index.css",
"chars": 28,
"preview": "@import './css/picker.css';\n"
},
{
"path": "src/index.js",
"chars": 58,
"preview": "import Picker from './js/picker';\n\nexport default Picker;\n"
},
{
"path": "src/js/constants.js",
"chars": 1804,
"preview": "export const IS_BROWSER = typeof window !== 'undefined';\nexport const WINDOW = IS_BROWSER ? window : {};\nexport const IS"
},
{
"path": "src/js/defaults.js",
"chars": 1516,
"preview": "export default {\n // Define the container for putting the picker.\n container: null,\n\n // Indicate whether show the pr"
},
{
"path": "src/js/events.js",
"chars": 2614,
"preview": "import {\n EVENT_CLICK,\n EVENT_FOCUS,\n EVENT_HIDDEN,\n EVENT_HIDE,\n EVENT_KEY_DOWN,\n EVENT_PICK,\n EVENT_POINTER_DOW"
},
{
"path": "src/js/handlers.js",
"chars": 2835,
"preview": "import {\n ACTION_HIDE,\n ACTION_NEXT,\n ACTION_PICK,\n ACTION_PREV,\n DATA_ACTION,\n DATA_TYPE,\n NAMESPACE,\n} from './"
},
{
"path": "src/js/helpers.js",
"chars": 3717,
"preview": "import {\n CLASS_PICKED,\n DATA_NAME,\n DATA_VALUE,\n NAMESPACE,\n} from './constants';\nimport {\n addClass,\n addLeading"
},
{
"path": "src/js/methods.js",
"chars": 10191,
"preview": "import {\n CLASS_OPEN,\n CLASS_OPENED,\n CLASS_PICKED,\n DATA_VALUE,\n EVENT_HIDDEN,\n EVENT_HIDE,\n EVENT_PICK,\n EVENT"
},
{
"path": "src/js/picker.js",
"chars": 7240,
"preview": "import DEFAULTS from './defaults';\nimport TEMPLATE from './template';\nimport events from './events';\nimport handlers fro"
},
{
"path": "src/js/template.js",
"chars": 787,
"preview": "export default (\n '<div class=\"picker\" data-picker-action=\"hide\" touch-action=\"none\" tabindex=\"-1\" role=\"dialog\">'\n "
},
{
"path": "src/js/utilities.js",
"chars": 13224,
"preview": "import {\n IS_BROWSER,\n WINDOW,\n} from './constants';\n\nconst { hasOwnProperty, toString } = Object.prototype;\n\n/**\n * D"
},
{
"path": "test/.eslintrc",
"chars": 170,
"preview": "{\n \"env\": {\n \"mocha\": true\n },\n \"globals\": {\n \"Picker\": true,\n \"expect\": true\n },\n \"rules\": {\n \"no-new\""
},
{
"path": "test/helpers.js",
"chars": 327,
"preview": "window.createContainer = () => {\n const container = document.createElement('div');\n\n document.body.appendChild(contain"
},
{
"path": "test/karma.conf.js",
"chars": 991,
"preview": "const puppeteer = require('puppeteer');\nconst rollupConfig = require('../rollup.config');\n\nprocess.env.CHROME_BIN = pupp"
},
{
"path": "test/specs/Picker.spec.js",
"chars": 328,
"preview": "describe('Picker', () => {\n it('should be a class (function)', () => {\n expect(Picker).to.be.a('function');\n });\n\n "
},
{
"path": "test/specs/events/hidden.spec.js",
"chars": 372,
"preview": "describe('hidden (event)', () => {\n it('should trigger the `hidden` event', (done) => {\n const input = window.create"
},
{
"path": "test/specs/events/hide.spec.js",
"chars": 883,
"preview": "describe('hide (event)', () => {\n it('should trigger the `hide` event', (done) => {\n const input = window.createInpu"
},
{
"path": "test/specs/events/pick.spec.js",
"chars": 469,
"preview": "describe('pick (event)', () => {\n it('should trigger the `pick` event', () => {\n const input = window.createInput();"
},
{
"path": "test/specs/events/show.spec.js",
"chars": 778,
"preview": "describe('show (event)', () => {\n it('should trigger the `show` event', () => {\n const input = window.createInput();"
},
{
"path": "test/specs/events/shown.spec.js",
"chars": 331,
"preview": "describe('shown (event)', () => {\n it('should trigger the `shown` event', (done) => {\n const input = window.createIn"
},
{
"path": "test/specs/methods/destroy.spec.js",
"chars": 485,
"preview": "describe('destroy (method)', () => {\n it('should destroy the picker correctly', () => {\n const container = window.cr"
},
{
"path": "test/specs/methods/formatDate.spec.js",
"chars": 334,
"preview": "describe('formatDate (method)', () => {\n it('should format the given date correctly', () => {\n const input = window."
},
{
"path": "test/specs/methods/getDate.spec.js",
"chars": 544,
"preview": "describe('getDate (method)', () => {\n it('should get a date object', () => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/methods/hide.spec.js",
"chars": 661,
"preview": "describe('hide (method)', () => {\n it('should hide the picker', (done) => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/methods/next.spec.js",
"chars": 848,
"preview": "describe('next (method)', () => {\n it('should switch to the next date item', () => {\n const input = window.createInp"
},
{
"path": "test/specs/methods/noConflict.spec.js",
"chars": 434,
"preview": "describe('noConflict', () => {\n it('should be a static method', () => {\n expect(Picker.noConflict).to.be.a('function"
},
{
"path": "test/specs/methods/parseDate.spec.js",
"chars": 279,
"preview": "describe('parseDate (method)', () => {\n it('should parse date correctly', () => {\n const input = window.createInput("
},
{
"path": "test/specs/methods/pick.spec.js",
"chars": 294,
"preview": "describe('pick (method)', () => {\n it('should pick the date to the input element', () => {\n const input = window.cre"
},
{
"path": "test/specs/methods/prev.spec.js",
"chars": 851,
"preview": "describe('prev (method)', () => {\n it('should switch to the previous date item', () => {\n const input = window.creat"
},
{
"path": "test/specs/methods/reset.spec.js",
"chars": 551,
"preview": "describe('reset (method)', () => {\n it('should reset the value of the input element', () => {\n const input = window."
},
{
"path": "test/specs/methods/setDate.spec.js",
"chars": 444,
"preview": "describe('setDate (method)', () => {\n it('should set date correctly', () => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/methods/setDefaults.spec.js",
"chars": 654,
"preview": "describe('setDefaults', () => {\n it('should be a static method', () => {\n expect(Picker.setDefaults).to.be.a('functi"
},
{
"path": "test/specs/methods/show.spec.js",
"chars": 626,
"preview": "describe('show (method)', () => {\n it('should show the picker', (done) => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/methods/update.spec.js",
"chars": 344,
"preview": "describe('update (method)', () => {\n it('should update the picker when the value of the input element changed', () => {"
},
{
"path": "test/specs/options/container.spec.js",
"chars": 1090,
"preview": "describe('container (option)', () => {\n it('should be `null` by default', () => {\n const input = window.createInput("
},
{
"path": "test/specs/options/controls.spec.js",
"chars": 1349,
"preview": "describe('controls (option)', () => {\n it('should be `false` by default', () => {\n const input = window.createInput("
},
{
"path": "test/specs/options/date.spec.js",
"chars": 709,
"preview": "describe('date (option)', () => {\n it('should be `null` by default', () => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/options/format.spec.js",
"chars": 7288,
"preview": "describe('format (option)', () => {\n it('should match the given format', () => {\n const input = window.createInput()"
},
{
"path": "test/specs/options/headers.spec.js",
"chars": 1882,
"preview": "describe('headers (option)', () => {\n it('should be `false` by default', () => {\n const input = window.createInput()"
},
{
"path": "test/specs/options/hidden.spec.js",
"chars": 534,
"preview": "describe('hidden (option)', () => {\n it('should be `null` be default', () => {\n const input = window.createInput();\n"
},
{
"path": "test/specs/options/hide.spec.js",
"chars": 1026,
"preview": "describe('hide (option)', () => {\n it('should be `null` be default', () => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/options/increment.spec.js",
"chars": 3378,
"preview": "describe('increment (option)', () => {\n it('should be `1` by default', () => {\n const input = window.createInput();\n"
},
{
"path": "test/specs/options/inline.spec.js",
"chars": 735,
"preview": "describe('inline (option)', () => {\n it('should be `false` by default', () => {\n const input = window.createInput();"
},
{
"path": "test/specs/options/language.spec.js",
"chars": 463,
"preview": "describe('language (option)', () => {\n it('should be empty by default', () => {\n const input = window.createInput();"
},
{
"path": "test/specs/options/months.spec.js",
"chars": 480,
"preview": "describe('months (option)', () => {\n it('should use the given months', () => {\n const input = window.createInput();\n"
},
{
"path": "test/specs/options/monthsShort.spec.js",
"chars": 495,
"preview": "describe('monthsShort (option)', () => {\n it('should use the given short months', () => {\n const input = window.crea"
},
{
"path": "test/specs/options/pick.spec.js",
"chars": 555,
"preview": "describe('pick (option)', () => {\n it('should be `null` be default', () => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/options/rows.spec.js",
"chars": 1312,
"preview": "describe('rows (option)', () => {\n it('should be `5` by default', () => {\n const input = window.createInput();\n c"
},
{
"path": "test/specs/options/show.spec.js",
"chars": 981,
"preview": "describe('show (option)', () => {\n it('should be `null` be default', () => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/options/shown.spec.js",
"chars": 503,
"preview": "describe('shown (option)', () => {\n it('should be `null` be default', () => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/options/text.spec.js",
"chars": 1031,
"preview": "describe('text (option)', () => {\n it('should match the given text', () => {\n const input = window.createInput();\n "
},
{
"path": "test/specs/options/translate.spec.js",
"chars": 556,
"preview": "describe('translate (option)', () => {\n it('should translate the date correctly', () => {\n const input = window.crea"
},
{
"path": "types/index.d.ts",
"chars": 1673,
"preview": "declare namespace Picker {\n export interface HeadersOptions {\n year?: string;\n month?: string;\n day?: string;\n"
}
]
About this extraction
This page contains the full source code of the fengyuanchen/pickerjs GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 91 files (335.9 KB), approximately 88.8k tokens, and a symbol index with 262 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.