├── docs ├── README.md ├── _config.yml ├── demo.gif ├── snapshot.png ├── snapshot_tel.png ├── snapshot_number.png └── README.cn.md ├── demo └── transfer │ ├── angular │ ├── app │ │ ├── app.component.styl │ │ ├── app.module.ts │ │ └── app.component.ts │ └── index.ts │ ├── vanilla │ ├── index.js │ └── app.js │ ├── vue │ ├── index.js │ └── app.js │ ├── react │ ├── index.js │ └── app.js │ ├── README.md │ ├── index.template.html │ └── styles.styl ├── .gitignore ├── vendor ├── angular │ ├── index.ts │ ├── keyboard │ │ ├── numeric-keyboard.woff │ │ ├── keyboard.component.styl │ │ └── keyboard.component.ts │ ├── input │ │ ├── input.component.styl │ │ └── input.component.ts │ └── module.ts ├── react │ ├── index.js │ ├── keyboard.js │ └── input.js ├── vanilla │ ├── index.js │ ├── keyboard.js │ └── input.js └── vue │ ├── index.js │ ├── keyboard.js │ └── input.js ├── lib ├── styles │ ├── numeric-keyboard.woff │ ├── input.styl │ └── keyboard.styl ├── layouts │ ├── index.js │ ├── tel.js │ └── number.js ├── utils │ ├── attribute.js │ ├── string.js │ ├── animate.js │ ├── type.js │ └── vdom.js ├── keys.js ├── keyboard.js └── input.js ├── test ├── spec │ ├── keyboardSpec.js │ ├── vdom │ │ ├── vtextSpec.js │ │ ├── diffPatchSpec.js │ │ ├── createElementSpec.js │ │ ├── vcomponentSpec.js │ │ ├── componentSpec.js │ │ ├── vnodeSpec.js │ │ ├── patchSpec.js │ │ └── diffSpec.js │ └── inputSpec.js └── karma.conf.js ├── .eslintrc.json ├── tsconfig.json ├── .travis.yml ├── babel.conf.js ├── LICENSE ├── webpack.conf.demo.js ├── webpack.conf.dev.js ├── package.json ├── webpack.conf.build.js ├── README.md └── dist └── numeric_keyboard.angular.js /docs/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /demo/transfer/angular/app/app.component.styl: -------------------------------------------------------------------------------- 1 | @require '../../styles.styl' 2 | -------------------------------------------------------------------------------- /docs/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viclm/numeric-keyboard/HEAD/docs/demo.gif -------------------------------------------------------------------------------- /docs/snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viclm/numeric-keyboard/HEAD/docs/snapshot.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .*.swp 3 | .DS_Store 4 | .vscode 5 | npm-debug.log 6 | yarn-error.log 7 | -------------------------------------------------------------------------------- /docs/snapshot_tel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viclm/numeric-keyboard/HEAD/docs/snapshot_tel.png -------------------------------------------------------------------------------- /docs/snapshot_number.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viclm/numeric-keyboard/HEAD/docs/snapshot_number.png -------------------------------------------------------------------------------- /demo/transfer/vanilla/index.js: -------------------------------------------------------------------------------- 1 | import App from './app.js' 2 | 3 | new App(document.querySelector('#app')) 4 | -------------------------------------------------------------------------------- /vendor/angular/index.ts: -------------------------------------------------------------------------------- 1 | import * as Keys from 'lib/keys.js' 2 | 3 | export * from './module' 4 | export { Keys } 5 | -------------------------------------------------------------------------------- /lib/styles/numeric-keyboard.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viclm/numeric-keyboard/HEAD/lib/styles/numeric-keyboard.woff -------------------------------------------------------------------------------- /lib/layouts/index.js: -------------------------------------------------------------------------------- 1 | import number from './number.js' 2 | import tel from './tel.js' 3 | 4 | export default { 5 | number, 6 | tel 7 | } 8 | -------------------------------------------------------------------------------- /vendor/angular/keyboard/numeric-keyboard.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/viclm/numeric-keyboard/HEAD/vendor/angular/keyboard/numeric-keyboard.woff -------------------------------------------------------------------------------- /vendor/react/index.js: -------------------------------------------------------------------------------- 1 | import * as Keys from 'lib/keys.js' 2 | 3 | export * from './keyboard.js' 4 | export * from './input.js' 5 | export { Keys } 6 | -------------------------------------------------------------------------------- /vendor/vanilla/index.js: -------------------------------------------------------------------------------- 1 | import * as Keys from 'lib/keys.js' 2 | 3 | export * from './keyboard.js' 4 | export * from './input.js' 5 | export { Keys } 6 | -------------------------------------------------------------------------------- /vendor/vue/index.js: -------------------------------------------------------------------------------- 1 | import * as Keys from 'lib/keys.js' 2 | 3 | export * from './keyboard.js' 4 | export * from './input.js' 5 | export { Keys } 6 | -------------------------------------------------------------------------------- /demo/transfer/vue/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './app.js' 3 | 4 | new Vue({ 5 | el: '#app', 6 | render: h => h(App) 7 | }) 8 | 9 | -------------------------------------------------------------------------------- /lib/utils/attribute.js: -------------------------------------------------------------------------------- 1 | export const coerceBooleanProperty = function coerceBooleanProperty(value) { 2 | return value != null && `${value}` !== 'false' 3 | } 4 | -------------------------------------------------------------------------------- /demo/transfer/react/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './app.js' 4 | 5 | ReactDOM.render( 6 | React.createElement(App), 7 | document.getElementById('app') 8 | ) 9 | -------------------------------------------------------------------------------- /vendor/angular/keyboard/keyboard.component.styl: -------------------------------------------------------------------------------- 1 | @require '../../../lib/styles/keyboard.styl' 2 | 3 | :host 4 | width 100% 5 | height 100% 6 | 7 | :host .numeric-keyboard 8 | width inherit 9 | height inherit 10 | -------------------------------------------------------------------------------- /test/spec/keyboardSpec.js: -------------------------------------------------------------------------------- 1 | import { Mixins } from 'lib/keyboard' 2 | 3 | describe('keyboard mixins', () => { 4 | it('a dispatch method is required to dispatch a custom event', () => { 5 | expect(Mixins.dispatch).toThrowError() 6 | }) 7 | }) 8 | -------------------------------------------------------------------------------- /lib/utils/string.js: -------------------------------------------------------------------------------- 1 | export const capitalize = function capitalize(str) { 2 | return str.charAt(0).toUpperCase() + str.substring(1) 3 | } 4 | 5 | export const toString = function toString(obj) { 6 | if (Object(obj) === obj) { 7 | return Object.prototype.toString.call(obj) 8 | } 9 | return obj == null ? '' : obj.toString() 10 | } 11 | -------------------------------------------------------------------------------- /test/spec/vdom/vtextSpec.js: -------------------------------------------------------------------------------- 1 | import { VText } from 'lib/utils/vdom.js' 2 | 3 | describe('vtext', () => { 4 | 5 | it('render', () => { 6 | const vtext = new VText('foo') 7 | const element = vtext.render() 8 | 9 | expect(element).toEqual(jasmine.any(Text)) 10 | expect(element.nodeValue).toBe('foo') 11 | }) 12 | 13 | }) 14 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | 4 | "parserOptions": { 5 | "ecmaVersion": 2018, 6 | "sourceType": "module", 7 | "ecmaFeatures": { 8 | "jsx": true 9 | } 10 | }, 11 | 12 | "env": { 13 | "browser": true, 14 | "jasmine": true 15 | }, 16 | 17 | "extends": [ "eslint:recommended" ], 18 | 19 | "rules": { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "emitDecoratorMetadata": true, 5 | "experimentalDecorators": true, 6 | "lib": ["ES2015", "DOM"], 7 | "target": "ES5", 8 | "paths": { 9 | "lib/*": ["./lib/*"], 10 | "numeric-keyboard": ["./vendor/angular"] 11 | } 12 | }, 13 | "include": ["vendor/angular/*"] 14 | } 15 | -------------------------------------------------------------------------------- /vendor/angular/input/input.component.styl: -------------------------------------------------------------------------------- 1 | @import '../../../lib/styles/input.styl' 2 | 3 | :host 4 | display inline-block 5 | background #fff 6 | width 12em 7 | height 1.2em 8 | padding 2px 9 | text-align left 10 | 11 | :host .numeric-input 12 | display block 13 | background transparent 14 | width 100% 15 | height 100% 16 | padding 0 17 | text-align inherit 18 | -------------------------------------------------------------------------------- /lib/keys.js: -------------------------------------------------------------------------------- 1 | export const ZERO = '0' 2 | export const ONE = '1' 3 | export const TWO = '2' 4 | export const THREE = '3' 5 | export const FOUR = '4' 6 | export const FIVE = '5' 7 | export const SIX = '6' 8 | export const SEVEN = '7' 9 | export const EIGHT = '8' 10 | export const NINE = '9' 11 | export const DOT = '.' 12 | export const DEL = 'del' 13 | export const ENTER = 'enter' 14 | export const ESC = 'esc' 15 | export const BLANK = '' 16 | -------------------------------------------------------------------------------- /demo/transfer/angular/index.ts: -------------------------------------------------------------------------------- 1 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 2 | import 'core-js/es7/reflect' 3 | // Zone JS is required by default for Angular itself. 4 | import 'zone.js/dist/zone' 5 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic' 6 | import { AppModule } from './app/app.module' 7 | import '../styles.styl' 8 | 9 | platformBrowserDynamic().bootstrapModule(AppModule) 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: "lts/*" 4 | 5 | branches: 6 | only: master 7 | 8 | notifications: 9 | email: false 10 | 11 | matrix: 12 | include: 13 | - os: linux 14 | dist: trusty 15 | sudo: required 16 | addons: 17 | chrome: stable 18 | before_script: 19 | - "export DISPLAY=:99.0" 20 | - "sh -e /etc/init.d/xvfb start" 21 | - sleep 3 22 | - os: osx 23 | osx_image: xcode8.3 24 | -------------------------------------------------------------------------------- /vendor/angular/module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core' 2 | import { CommonModule } from '@angular/common' 3 | import { NumericKeyboard } from './keyboard/keyboard.component' 4 | import { NumericInput } from './input/input.component' 5 | 6 | @NgModule({ 7 | declarations: [ NumericKeyboard, NumericInput ], 8 | entryComponents: [ NumericKeyboard ], 9 | imports: [ CommonModule ], 10 | exports: [ NumericKeyboard, NumericInput ] 11 | }) 12 | export class NumericKeyboardModule {} 13 | -------------------------------------------------------------------------------- /demo/transfer/angular/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { NumericKeyboardModule } from 'numeric-keyboard'; 4 | 5 | import { App, Password } from './app.component'; 6 | 7 | 8 | @NgModule({ 9 | declarations: [ 10 | App, 11 | Password 12 | ], 13 | imports: [ 14 | BrowserModule, 15 | NumericKeyboardModule 16 | ], 17 | providers: [], 18 | bootstrap: [App] 19 | }) 20 | export class AppModule {} 21 | -------------------------------------------------------------------------------- /lib/utils/animate.js: -------------------------------------------------------------------------------- 1 | const requestAnimationFrame = window.requestAnimationFrame || window.setTimeout 2 | 3 | export const animate = function animate(iterable, done = () => {}, frames = 60) { 4 | let running = true 5 | let frame = 0 6 | 7 | const closure = timestamp => { 8 | if (!running) { return } 9 | iterable(timestamp, ++frame, frames) 10 | if (frame < frames) { 11 | requestAnimationFrame(closure, 0) 12 | } 13 | else { 14 | done() 15 | } 16 | } 17 | 18 | requestAnimationFrame(closure, 0) 19 | 20 | return () => { running = false } 21 | } 22 | -------------------------------------------------------------------------------- /test/spec/vdom/diffPatchSpec.js: -------------------------------------------------------------------------------- 1 | import { VNode, diffAndPatch } from 'lib/utils/vdom.js' 2 | 3 | describe('diff and patch', () => { 4 | 5 | it('props', () => { 6 | const oldTree = new VNode('div', { id: 'foo', className: 'bar' }) 7 | const element = oldTree.render() 8 | 9 | expect(element.getAttribute('id')).toBe('foo') 10 | expect(element.getAttribute('class')).toBe('bar') 11 | 12 | const newTree = new VNode('div', { className: 'qux' }) 13 | diffAndPatch(element, oldTree, newTree) 14 | 15 | expect(element.getAttribute('id')).toBeNull() 16 | expect(element.getAttribute('class')).toBe('qux') 17 | }) 18 | 19 | }) 20 | -------------------------------------------------------------------------------- /babel.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (vendor) { 2 | const presets = [ 3 | ['@babel/preset-env', { 4 | 'targets': { 5 | 'browsers': ['iOS >= 8', 'Android >= 4'] 6 | }, 7 | useBuiltIns: 'usage' 8 | }] 9 | ] 10 | 11 | if (vendor === 'vue') { 12 | presets.push('@vue/babel-preset-jsx') 13 | } 14 | 15 | const plugins = ['@babel/plugin-transform-runtime'] 16 | 17 | if (vendor === 'react') { 18 | plugins.push('@babel/plugin-transform-react-jsx') 19 | } 20 | else if (vendor === 'vanilla') { 21 | plugins.push(['@babel/plugin-transform-react-jsx', { pragma: 'createElement' }]) 22 | } 23 | 24 | return { presets, plugins } 25 | } 26 | -------------------------------------------------------------------------------- /lib/utils/type.js: -------------------------------------------------------------------------------- 1 | const RType = /[a-z]+(?=])/i 2 | 3 | export const typeofConstructor = function typeofConstructor(data) { 4 | return eval(Object.prototype.toString.call(data).match(RType)[0]) 5 | } 6 | 7 | export const isPlainObject = function isPlainObject(obj) { 8 | if (!obj || Object.prototype.toString.call(obj) !== '[object Object]') { 9 | return false 10 | } 11 | const proto = Object.getPrototypeOf(obj) 12 | return proto == null || proto.hasOwnProperty('constructor') && proto.constructor === Object.prototype.constructor 13 | } 14 | 15 | export const isEmptyObject = function isEmptyObject(obj) { 16 | for (let name in obj) { 17 | return false 18 | } 19 | return true 20 | } 21 | -------------------------------------------------------------------------------- /demo/transfer/README.md: -------------------------------------------------------------------------------- 1 | # Transfer App 2 | 3 | A transfer application for demonstrating the usage of numeric keyboard. 4 | 5 | All you need to do is fill in the amount and confirm your password. 6 | 7 | ## Run the development version 8 | 9 | ```shell 10 | yarn dev 11 | ``` 12 | 13 | http://localhost:4040/vanilla.html 14 | 15 | http://localhost:4040/react.html 16 | 17 | http://localhost:4040/vue.html 18 | 19 | http://localhost:4040/angular.html 20 | 21 | ## Run the publish version 22 | 23 | ```shell 24 | yarn start 25 | ``` 26 | 27 | http://localhost:4141/vanilla.html 28 | 29 | http://localhost:4141/react.html 30 | 31 | http://localhost:4141/vue.html 32 | 33 | http://localhost:4141/angular.html 34 | -------------------------------------------------------------------------------- /lib/layouts/tel.js: -------------------------------------------------------------------------------- 1 | import * as Keys from '../keys.js' 2 | 3 | export default [ 4 | [ 5 | { 6 | key: Keys.ONE 7 | }, 8 | { 9 | key: Keys.TWO 10 | }, 11 | { 12 | key: Keys.THREE 13 | }, 14 | ], 15 | [ 16 | { 17 | key: Keys.FOUR 18 | }, 19 | { 20 | key: Keys.FIVE 21 | }, 22 | { 23 | key: Keys.SIX 24 | }, 25 | ], 26 | [ 27 | { 28 | key: Keys.SEVEN 29 | }, 30 | { 31 | key: Keys.EIGHT 32 | }, 33 | { 34 | key: Keys.NINE 35 | }, 36 | ], 37 | [ 38 | { 39 | key: Keys.DEL 40 | }, 41 | { 42 | key: Keys.ZERO 43 | }, 44 | { 45 | key: Keys.ENTER 46 | }, 47 | ], 48 | ] 49 | -------------------------------------------------------------------------------- /lib/layouts/number.js: -------------------------------------------------------------------------------- 1 | import * as Keys from '../keys.js' 2 | 3 | export default [ 4 | [ 5 | { 6 | key: Keys.ONE 7 | }, 8 | { 9 | key: Keys.TWO 10 | }, 11 | { 12 | key: Keys.THREE 13 | }, 14 | { 15 | key: Keys.DEL, 16 | rowspan: 2, 17 | }, 18 | ], 19 | [ 20 | { 21 | key: Keys.FOUR 22 | }, 23 | { 24 | key: Keys.FIVE 25 | }, 26 | { 27 | key: Keys.SIX 28 | }, 29 | ], 30 | [ 31 | { 32 | key: Keys.SEVEN 33 | }, 34 | { 35 | key: Keys.EIGHT 36 | }, 37 | { 38 | key: Keys.NINE 39 | }, 40 | { 41 | key: Keys.ENTER, 42 | rowspan: 2, 43 | }, 44 | ], 45 | [ 46 | { 47 | key: Keys.DOT 48 | }, 49 | { 50 | key: Keys.ZERO 51 | }, 52 | { 53 | key: Keys.ESC 54 | }, 55 | ], 56 | ] 57 | -------------------------------------------------------------------------------- /test/spec/vdom/createElementSpec.js: -------------------------------------------------------------------------------- 1 | import { createElement, VText, VNode, VComponent, Component } from 'lib/utils/vdom.js' 2 | 3 | describe('createElement', () => { 4 | 5 | // @TODO add tag validation 6 | xit('vtext', () => { 7 | const vtree = createElement('foo') 8 | 9 | expect(vtree).toEqual(jasmine.any(VText)) 10 | }) 11 | 12 | it('vnode', () => { 13 | const vtree = createElement('div') 14 | 15 | expect(vtree).toEqual(jasmine.any(VNode)) 16 | }) 17 | 18 | it('vnode with props and children', () => { 19 | const vtree = createElement('div', { id: 'foo' }, 'bar', createElement('span')) 20 | 21 | expect(vtree.props.id).toBe('foo') 22 | expect(vtree.children).toEqual([jasmine.any(VText), jasmine.any(VNode)]) 23 | }) 24 | 25 | it('vcomponent', () => { 26 | class C extends Component {} 27 | const vtree = createElement(C) 28 | 29 | expect(vtree).toEqual(jasmine.any(VComponent)) 30 | }) 31 | 32 | }) 33 | -------------------------------------------------------------------------------- /demo/transfer/index.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Numeric keyboard 6 | 19 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 刘明 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/styles/input.styl: -------------------------------------------------------------------------------- 1 | .numeric-input 2 | display inline-block 3 | background white 4 | width 12em 5 | height 1.2em 6 | padding 2px 7 | text-align left 8 | 9 | &.readonly, &.disabled 10 | opacity 0.5 11 | pointer-events none 12 | 13 | & > div 14 | position relative 15 | overflow hidden 16 | height 100% 17 | 18 | .numeric-input-placeholder 19 | color #757575 20 | 21 | .numeric-input-text 22 | width 10000% 23 | 24 | // span 25 | // display table-cell 26 | // vertical-align middle 27 | 28 | .numeric-input-cursor 29 | pointer-events none 30 | position absolute 31 | left 0 32 | top 0 33 | width 1px 34 | height 100% 35 | animation numeric-input-cursor 1s infinite 36 | 37 | @keyframes numeric-input-cursor { 38 | from { 39 | opacity 1 40 | } 41 | to { 42 | opacity 0 43 | } 44 | } 45 | 46 | .numeric-keyboard-actionsheet 47 | position: fixed 48 | bottom: 0 49 | left: 0 50 | width: 100% 51 | height: 36% 52 | 53 | & > div:first-child 54 | height 100% 55 | 56 | & > div:last-child 57 | position: absolute 58 | top: 0 59 | right: 0 60 | bottom: 0 61 | left: 0 62 | transform: translateY(100%) 63 | box-shadow: 0 -2px 4px 0 #cfd4da 64 | -------------------------------------------------------------------------------- /lib/keyboard.js: -------------------------------------------------------------------------------- 1 | import { ENTER } from './keys.js' 2 | import Layouts from './layouts/index.js' 3 | 4 | export const Options = { 5 | layout: 'number', 6 | entertext: 'enter' 7 | } 8 | 9 | export const Mixins = { 10 | init(options) { 11 | const { layout } = options 12 | 13 | let resolvedLayout 14 | if (typeof layout === 'string') { 15 | resolvedLayout = Layouts[layout] 16 | if (!Array.isArray(resolvedLayout)) { 17 | throw new Error(`${layout} is not a build-in layout.`) 18 | } 19 | } 20 | else { 21 | resolvedLayout = layout 22 | if (!Array.isArray(resolvedLayout) || !resolvedLayout.every(i => Array.isArray(i))) { 23 | throw new Error(`custom layout must be a two-dimensional array.`) 24 | } 25 | } 26 | 27 | this.kp = options 28 | this.ks = { resolvedLayout } 29 | }, 30 | 31 | destroy() { 32 | 33 | }, 34 | 35 | set(key, value) { 36 | this.ks[key] = value 37 | }, 38 | 39 | onTouchend(key) { 40 | this.dispatch('press', key) 41 | if (key === ENTER) { 42 | this.dispatch('enterpress') 43 | } 44 | }, 45 | 46 | dispatch(/* event, payload */) { 47 | throw new Error('dispatch method must be overrided!') 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /lib/styles/keyboard.styl: -------------------------------------------------------------------------------- 1 | @font-face 2 | font-family numeric-keyboard 3 | src url('numeric-keyboard.woff') format('woff') 4 | font-weight normal 5 | font-style normal 6 | 7 | .numeric-keyboard 8 | width 100% 9 | height 100% 10 | background #cfd4da 11 | table-layout fixed 12 | border-collapse separate 13 | border-spacing 1px 14 | font-size 2em 15 | text-align center 16 | 17 | .numeric-keyboard-key 18 | touch-action manipulation 19 | transition background 0.5s 20 | color #000000 21 | background #ffffff 22 | &:active 23 | background #929ca8 24 | &[data-key=""] 25 | pointer-events none 26 | &[data-key=enter] 27 | color #ffffff 28 | background #007aff 29 | &[data-key=enter]:active 30 | background #0051a8 31 | &[data-icon]::before 32 | content attr(data-icon) 33 | &[data-icon=del]::before, 34 | &[data-icon=esc]::before 35 | font-family numeric-keyboard !important 36 | speak none 37 | font-style normal 38 | font-weight normal 39 | font-variant normal 40 | text-transform none 41 | line-height 1 42 | 43 | letter-spacing 0 44 | -webkit-font-feature-settings "liga" 45 | font-feature-settings "liga" 46 | -webkit-font-variant-ligatures discretionary-ligatures 47 | font-variant-ligatures discretionary-ligatures 48 | 49 | -webkit-font-smoothing antialiased 50 | -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpackConfigs = require('../webpack.conf.build.js') 3 | 4 | const webpackConfig = webpackConfigs[0] 5 | 6 | delete webpackConfig.entry 7 | delete webpackConfig.output 8 | webpackConfig.devtool = 'inline-source-map' 9 | 10 | const browsers = [] 11 | if (process.env.TRAVIS) { 12 | if (process.env.TRAVIS_OS_NAME === 'linux') { 13 | browsers.push('Chrome') 14 | } 15 | else if (process.env.TRAVIS_OS_NAME === 'osx') { 16 | browsers.push('Safari') 17 | } 18 | } 19 | else { 20 | browsers.push('ChromeHeadless') 21 | } 22 | 23 | module.exports = function(config) { 24 | config.set({ 25 | frameworks: ['jasmine'], 26 | files: [ 27 | 'spec/**/*Spec.js' 28 | ], 29 | exclude: [ 30 | '**/*.swp' 31 | ], 32 | preprocessors: { 33 | 'spec/**/*Spec.js': ['webpack', 'sourcemap'] 34 | }, 35 | webpack: webpackConfig, 36 | webpackMiddleware: { 37 | stats: 'errors-only' 38 | }, 39 | browsers: browsers, 40 | customLaunchers: { 41 | ChromeHeadless: { 42 | base: 'Chrome', 43 | flags: [ 44 | '--no-sandbox', 45 | '--headless', 46 | '--disable-gpu', 47 | '--remote-debugging-port=9222', 48 | ], 49 | }, 50 | }, 51 | concurrency: Infinity, 52 | port: 4242, 53 | singleRun: process.env.TRAVIS, 54 | autoWatch: !process.env.TRAVIS 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /vendor/react/keyboard.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { capitalize } from 'lib/utils/string' 3 | import { Options, Mixins } from 'lib/keyboard.js' 4 | import { ENTER } from 'lib/keys.js' 5 | import 'lib/styles/keyboard.styl' 6 | 7 | class Parent extends React.Component {} 8 | Object.assign(Parent.prototype, Mixins) 9 | 10 | export class NumericKeyboard extends Parent { 11 | constructor(props) { 12 | super(props) 13 | this.init(props) 14 | } 15 | 16 | onTouchend(key, event) { 17 | super.onTouchend(key, event) 18 | event.nativeEvent.stopImmediatePropagation() 19 | } 20 | 21 | dispatch(event, payload) { 22 | const callback = this.props[`on${capitalize(event)}`] 23 | if (callback) { 24 | callback(payload) 25 | } 26 | } 27 | 28 | render() { 29 | return ( 30 | 31 | 32 | {this.ks.resolvedLayout.map((r, i) => 33 | 34 | {r.map(c => 35 | 44 | )} 45 | 46 | )} 47 | 48 |
this.onTouchend(c.key, e)} > 43 |
49 | ) 50 | } 51 | } 52 | 53 | NumericKeyboard.defaultProps = Options 54 | -------------------------------------------------------------------------------- /vendor/vanilla/keyboard.js: -------------------------------------------------------------------------------- 1 | import { Component, createElement } from 'lib/utils/vdom' // eslint-disable-line no-unused-vars 2 | import { capitalize } from 'lib/utils/string' 3 | import { Options, Mixins } from 'lib/keyboard.js' 4 | import { ENTER } from 'lib/keys.js' 5 | import 'lib/styles/keyboard.styl' 6 | 7 | class Parent extends Component {} 8 | Object.assign(Parent.prototype, Mixins) 9 | 10 | export class NumericKeyboard extends Parent { 11 | constructor(props) { 12 | super(props) 13 | this.init(this.props) 14 | } 15 | 16 | onTouchend(key, event) { 17 | super.onTouchend(key, event) 18 | event.stopPropagation() 19 | } 20 | 21 | dispatch(event, payload) { 22 | const callback = this.props[`on${capitalize(event)}`] 23 | if (callback) { 24 | callback(payload) 25 | } 26 | } 27 | 28 | render() { 29 | return ( 30 | 31 | 32 | {this.ks.resolvedLayout.map((r, i) => 33 | 34 | {r.map(c => 35 | 44 | )} 45 | 46 | )} 47 | 48 |
this.onTouchend(c.key, e)} > 43 |
49 | ) 50 | } 51 | } 52 | 53 | NumericKeyboard.defaultProps = Options 54 | -------------------------------------------------------------------------------- /vendor/vue/keyboard.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { typeofConstructor } from 'lib/utils/type.js' 3 | import { Options, Mixins } from 'lib/keyboard.js' 4 | import { ENTER } from 'lib/keys.js' 5 | import 'lib/styles/keyboard.styl' 6 | 7 | export const NumericKeyboard = Vue.extend({ 8 | 9 | mixins: [{ methods: Mixins }], 10 | 11 | props: (() => { 12 | let props = {} 13 | for (let name in Options) { 14 | props[name] = { default: Options[name], type: [typeofConstructor(Options[name]), String, Number, Boolean, Array, Object, Date, Function] } 15 | } 16 | return props 17 | })(), 18 | 19 | data() { 20 | return { 21 | ks: null 22 | } 23 | }, 24 | 25 | methods: { 26 | dispatch(event, payload) { 27 | this.$emit(event, payload) 28 | } 29 | }, 30 | 31 | created() { 32 | this.init(this._props) 33 | }, 34 | 35 | beforeDestroy() { 36 | this.destroy() 37 | }, 38 | 39 | render() { 40 | return ( 41 | 42 | 43 | {this.ks.resolvedLayout.map((r, i) => 44 | 45 | {r.map(c => 46 | 55 | )} 56 | 57 | )} 58 | 59 |
this.onTouchend(c.key, e)} > 54 |
60 | ) 61 | } 62 | 63 | }) 64 | -------------------------------------------------------------------------------- /vendor/angular/keyboard/keyboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output, OnInit, OnDestroy } from '@angular/core' 2 | import { Options, Mixins } from 'lib/keyboard' 3 | import { ENTER } from 'lib/keys.js' 4 | 5 | const template = ` 6 | 7 | 8 | 16 | 17 |
15 |
18 | ` 19 | 20 | class Parent {} 21 | Parent.prototype = Mixins 22 | 23 | @Component({ 24 | selector: 'numeric-keyboard', 25 | template: template, 26 | styleUrls: [ './keyboard.component.styl' ] 27 | }) 28 | export class NumericKeyboard extends Parent implements OnInit, OnDestroy { 29 | @Input() layout: string | { key: number | string }[][] = Options.layout 30 | @Input() entertext: string = Options.entertext 31 | 32 | @Output() press = new EventEmitter() 33 | @Output() enterpress = new EventEmitter() 34 | 35 | public kp: any 36 | public ks: any 37 | 38 | ngOnInit() { 39 | Mixins.init.call(this, { 40 | layout: this.layout, 41 | entertext: this.entertext 42 | }) 43 | } 44 | 45 | ngOnDestroy() { 46 | Mixins.destroy.call(this) 47 | } 48 | 49 | dispatch(event: string, payload?: number | string) { 50 | switch (event) { 51 | case 'press': 52 | this.press.emit(payload) 53 | break 54 | case 'enterpress': 55 | this.enterpress.emit() 56 | break 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /test/spec/vdom/vcomponentSpec.js: -------------------------------------------------------------------------------- 1 | import { VComponent, Component, createElement } from 'lib/utils/vdom.js' 2 | 3 | describe('vcomponet', () => { 4 | 5 | it('render', () => { 6 | class C extends Component { 7 | render() { 8 | return createElement('div', { id: this.props.id }) 9 | } 10 | } 11 | 12 | const vcomponent = new VComponent(C, { id: 'foo' }) 13 | const element = vcomponent.render() 14 | 15 | expect(element).toEqual(jasmine.any(HTMLDivElement)) 16 | expect(element.getAttribute('id')).toBe('foo') 17 | }) 18 | 19 | it('render - with events', () => { 20 | class C extends Component { 21 | onTouchend() { 22 | this.props.onTouchend.call() 23 | } 24 | 25 | render() { 26 | return createElement('div', { onTouchend: this.onTouchend.bind(this) }) 27 | } 28 | } 29 | 30 | const touchendHandler = jasmine.createSpy() 31 | const vcomponent = new VComponent(C, { onTouchend: touchendHandler }) 32 | const element = vcomponent.render() 33 | 34 | expect(touchendHandler).not.toHaveBeenCalled() 35 | 36 | element.dispatchEvent(new Event('touchend')) 37 | 38 | expect(touchendHandler).toHaveBeenCalledTimes(1) 39 | }) 40 | 41 | it('update', () => { 42 | class C extends Component { 43 | render() { 44 | return createElement('section', { id: this.props.id }) 45 | } 46 | } 47 | 48 | const vcomponent = new VComponent(C, { id: 'foo' }) 49 | const element = vcomponent.render() 50 | 51 | expect(element.getAttribute('id')).toBe('foo') 52 | 53 | vcomponent.update({ id: 'bar' }) 54 | 55 | expect(element.getAttribute('id')).toBe('bar') 56 | 57 | vcomponent.update({ id: 'qux' }) 58 | 59 | expect(element.getAttribute('id')).toBe('qux') 60 | }) 61 | 62 | }) 63 | -------------------------------------------------------------------------------- /webpack.conf.demo.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const HtmlWebpackPlugin = require('html-webpack-plugin') 3 | const babelConfig = require('./babel.conf.js') 4 | 5 | function factory(vendor) { 6 | 7 | return { 8 | mode: 'development', 9 | entry: `./demo/transfer/${vendor}/index`, 10 | output: { 11 | filename: `transfer.${vendor}.js` 12 | }, 13 | resolve: { 14 | alias: { 15 | 'vue': 'vue/dist/vue.common.js', 16 | 'numeric-keyboard': path.resolve(__dirname, `./dist/numeric_keyboard.${vendor}.js`) 17 | }, 18 | extensions: ['.ts', '.js'] 19 | }, 20 | module: { 21 | rules: [ 22 | { 23 | test: /\.ts$/, 24 | exclude: /node_modules|dist/, 25 | use: ['awesome-typescript-loader', 'angular2-template-loader'] 26 | }, 27 | { 28 | test: /\.js$/, 29 | exclude: /node_modules|dist/, 30 | use: [{ loader: 'babel-loader', options: babelConfig(vendor) }] 31 | }, 32 | { 33 | test: /\.component.styl$/, 34 | exclude: /node_modules/, 35 | use: ['to-string-loader', 'css-loader', 'stylus-loader'] 36 | }, 37 | { 38 | test: /\/\w+(?!\.component\.)\.styl$/, 39 | exclude: /node_modules/, 40 | use: ['style-loader', 'css-loader', 'stylus-loader'] 41 | }, 42 | { 43 | test: /\.woff$/, 44 | exclude: /node_modules/, 45 | use: ['url-loader'] 46 | } 47 | ] 48 | }, 49 | devtool: 'eval', 50 | devServer: { 51 | host: '0.0.0.0', 52 | port: 4141, 53 | stats: 'minimal' 54 | }, 55 | plugins: [ 56 | new HtmlWebpackPlugin({ 57 | filename: `${vendor}.html`, 58 | template: 'demo/transfer/index.template.html', 59 | meta: { vendor } 60 | }) 61 | ] 62 | } 63 | 64 | } 65 | 66 | module.exports = ['vanilla', 'react', 'vue', 'angular'].map(vendor => factory(vendor)) 67 | -------------------------------------------------------------------------------- /webpack.conf.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const HtmlWebpackPlugin = require('html-webpack-plugin') 3 | const babelConfig = require('./babel.conf.js') 4 | 5 | function factory(vendor) { 6 | 7 | return { 8 | mode: 'development', 9 | entry: `./demo/transfer/${vendor}/index`, 10 | output: { 11 | filename: `transfer.${vendor}.js` 12 | }, 13 | resolve: { 14 | alias: { 15 | 'vue': 'vue/dist/vue.common.js', 16 | 'lib': path.resolve(__dirname, './lib'), 17 | 'numeric-keyboard': path.resolve(__dirname, `./vendor/${vendor}`) 18 | }, 19 | extensions: ['.ts', '.js'] 20 | }, 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.ts$/, 25 | exclude: /node_modules|dist/, 26 | use: ['awesome-typescript-loader', 'angular2-template-loader'] 27 | }, 28 | { 29 | test: /\.js$/, 30 | exclude: /node_modules/, 31 | use: [{ loader: 'babel-loader', options: babelConfig(vendor) }, 'eslint-loader'] 32 | }, 33 | { 34 | test: /\.component.styl$/, 35 | exclude: /node_modules/, 36 | use: ['to-string-loader', 'css-loader', 'stylus-loader'] 37 | }, 38 | { 39 | test: /\/\w+(?!\.component\.)\.styl$/, 40 | exclude: /node_modules/, 41 | use: ['style-loader', 'css-loader', 'stylus-loader'] 42 | }, 43 | { 44 | test: /\.woff$/, 45 | exclude: /node_modules/, 46 | use: ['url-loader'] 47 | } 48 | ] 49 | }, 50 | devtool: 'eval', 51 | devServer: { 52 | host: '0.0.0.0', 53 | port: 4040, 54 | stats: 'minimal' 55 | }, 56 | plugins: [ 57 | new HtmlWebpackPlugin({ 58 | filename: `${vendor}.html`, 59 | template: 'demo/transfer/index.template.html', 60 | meta: { vendor } 61 | }) 62 | ] 63 | } 64 | 65 | } 66 | 67 | module.exports = ['vanilla', 'react', 'vue', 'angular'].map(vendor => factory(vendor)) 68 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "numeric-keyboard", 3 | "version": "0.7.0", 4 | "description": "Numeric keyboard for mobile browsers", 5 | "repository": "viclm/numeric-keyboard", 6 | "license": "MIT", 7 | "scripts": { 8 | "test": "karma start test/karma.conf.js", 9 | "dev": "webpack-dev-server --config webpack.conf.dev.js", 10 | "start": "webpack-dev-server --config webpack.conf.demo.js", 11 | "build": "webpack --config webpack.conf.build.js --hide-modules --progress" 12 | }, 13 | "devDependencies": { 14 | "@angular/common": "^7.2.7", 15 | "@angular/compiler": "^7.2.7", 16 | "@angular/core": "^7.2.7", 17 | "@angular/platform-browser": "^7.2.7", 18 | "@angular/platform-browser-dynamic": "^7.2.7", 19 | "@babel/core": "^7.2.2", 20 | "@babel/plugin-transform-react-jsx": "^7.2.0", 21 | "@babel/plugin-transform-runtime": "^7.2.0", 22 | "@babel/preset-env": "^7.2.3", 23 | "@babel/runtime": "^7.2.0", 24 | "@types/node": "^10.12.18", 25 | "@vue/babel-helper-vue-jsx-merge-props": "^1.0.0-beta.2", 26 | "@vue/babel-preset-jsx": "^1.0.0-beta.2", 27 | "angular2-template-loader": "^0.6.2", 28 | "awesome-typescript-loader": "^5.2.1", 29 | "babel-loader": "^8.0.5", 30 | "core-js": "^2.6.5", 31 | "css-loader": "^2.1.0", 32 | "eslint": "^5.12.0", 33 | "eslint-loader": "^2.1.1", 34 | "eslint-plugin-html": "^5.0.0", 35 | "html-loader": "^0.5.5", 36 | "html-webpack-plugin": "^3.2.0", 37 | "jasmine-core": "^3.3.0", 38 | "karma": "^3.1.4", 39 | "karma-chrome-launcher": "^2.2.0", 40 | "karma-jasmine": "^2.0.1", 41 | "karma-safari-launcher": "^1.0.0", 42 | "karma-sourcemap-loader": "^0.3.7", 43 | "karma-webpack": "^3.0.5", 44 | "react": "^16.7.0", 45 | "react-dom": "^16.7.0", 46 | "rxjs": "^6.3.3", 47 | "style-loader": "^0.23.1", 48 | "stylus": "^0.54.5", 49 | "stylus-loader": "^3.0.2", 50 | "to-string-loader": "^1.1.5", 51 | "typescript": "^3.2.2", 52 | "url-loader": "^1.1.2", 53 | "vue": "^2.5.21", 54 | "webpack": "^4.28.3", 55 | "webpack-cli": "^3.2.1", 56 | "webpack-dev-server": "^3.1.14", 57 | "zone.js": "^0.8.29" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /demo/transfer/styles.styl: -------------------------------------------------------------------------------- 1 | * 2 | margin 0 3 | padding 0 4 | 5 | body 6 | padding 0.2rem 7 | font-size 0.24rem 8 | 9 | header 10 | text-align center 11 | 12 | form 13 | margin 0.8rem 0 0.2rem 0 14 | font-size 0.36rem 15 | label 16 | display block 17 | 18 | .input 19 | margin 0.1rem 0 0.4rem 0 20 | border-bottom 1px solid #cfd4da 21 | display flex 22 | align-items center 23 | font-weight bold 24 | 25 | &::before 26 | content '$' 27 | margin-right 0.1rem 28 | font-size 0.6rem 29 | 30 | .numeric-input 31 | flex 1 32 | width 0 33 | height 1rem 34 | line-height 1rem 35 | font-size 1rem 36 | 37 | input[type=submit] 38 | outline none 39 | border none 40 | width 100% 41 | height 0.72rem 42 | line-height 0.72rem 43 | font-size inherit 44 | background #007aff 45 | color white 46 | &[disabled] 47 | opacity 0.5 48 | 49 | footer 50 | text-align center 51 | color gray 52 | 53 | 54 | 55 | 56 | 57 | .password 58 | position fixed 59 | left 0 60 | right 0 61 | top 0 62 | bottom 0 63 | background alpha(black, 0.2) 64 | 65 | .dialog 66 | position absolute 67 | left 0 68 | bottom 0 69 | box-shadow 0 -2px 4px 0 #cfd4da 70 | width 100% 71 | text-align center 72 | background white 73 | animation password-slide-up 0.5s 74 | 75 | h2 76 | padding 0.1rem 0 77 | 78 | .input 79 | margin 0.4rem auto 1rem auto 80 | border 1px solid #cfd4da 81 | display flex 82 | width 6rem 83 | span 84 | border-right 1px solid #cfd4da 85 | display flex 86 | justify-content center 87 | align-items center 88 | width 1rem 89 | height 1rem 90 | &:last-child 91 | border-right none 92 | &.fill::before 93 | content '' 94 | border-radius 0.3rem 95 | display block 96 | width 0.3rem 97 | height 0.3rem 98 | background black 99 | 100 | .numeric-keyboard 101 | height 4rem 102 | 103 | @keyframes password-slide-up { 104 | from { 105 | transform translateY(100%) 106 | } 107 | to { 108 | transform translateY(0) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /webpack.conf.build.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const babelConfig = require('./babel.conf.js') 3 | 4 | function factory(vendor) { 5 | 6 | return { 7 | mode: 'none', 8 | entry: `./vendor/${vendor}/index`, 9 | output: { 10 | path: path.resolve(__dirname, 'dist'), 11 | filename: `numeric_keyboard.${vendor}.js`, 12 | library: 'NumericKeyboard', 13 | libraryTarget: 'umd2', 14 | umdNamedDefine: true 15 | }, 16 | resolve: { 17 | alias: { 18 | lib: path.resolve(__dirname, './lib') 19 | }, 20 | extensions: ['.ts', '.js'] 21 | }, 22 | externals: { 23 | 'vue': { 24 | root: 'Vue', 25 | commonjs: 'vue', 26 | commonjs2: 'vue', 27 | amd: 'vue' 28 | }, 29 | 'react': { 30 | root: 'React', 31 | commonjs2: 'react', 32 | commonjs: 'react', 33 | amd: 'react' 34 | }, 35 | 'react-dom': { 36 | root: 'ReactDOM', 37 | commonjs2: 'react-dom', 38 | commonjs: 'react-dom', 39 | amd: 'react-dom' 40 | }, 41 | '@angular/core': { 42 | root: 'ng', 43 | commonjs2: '@angular/core', 44 | commonjs: '@angular/core', 45 | amd: '@angular/core' 46 | }, 47 | '@angular/common': { 48 | root: 'ng', 49 | commonjs2: '@angular/common', 50 | commonjs: '@angular/common', 51 | amd: '@angular/common' 52 | } 53 | }, 54 | module: { 55 | rules: [ 56 | { 57 | test: /\.ts$/, 58 | exclude: /node_modules|dist/, 59 | use: ['awesome-typescript-loader', 'angular2-template-loader'] 60 | }, 61 | { 62 | test: /\.js$/, 63 | exclude: /node_modules/, 64 | use: [{ loader: 'babel-loader', options: babelConfig(vendor) }, 'eslint-loader'] 65 | }, 66 | { 67 | test: /\.component.styl$/, 68 | exclude: /node_modules/, 69 | use: ['to-string-loader', 'css-loader', 'stylus-loader'] 70 | }, 71 | { 72 | test: /\/\w+(?!\.component\.)\.styl$/, 73 | exclude: /node_modules/, 74 | use: ['style-loader', 'css-loader', 'stylus-loader'] 75 | }, 76 | { 77 | test: /\.woff$/, 78 | exclude: /node_modules/, 79 | use: ['url-loader'] 80 | } 81 | ] 82 | }, 83 | devtool: false 84 | } 85 | } 86 | 87 | module.exports = ['vanilla', 'react', 'vue', 'angular'].map(vendor => factory(vendor)) 88 | -------------------------------------------------------------------------------- /vendor/vanilla/input.js: -------------------------------------------------------------------------------- 1 | import { Component, createElement } from 'lib/utils/vdom.js' // eslint-disable-line no-unused-vars 2 | import { capitalize } from 'lib/utils/string.js' 3 | import { Options, Mixins } from 'lib/input.js' 4 | import { NumericKeyboard } from './keyboard.js' // eslint-disable-line no-unused-vars 5 | import 'lib/styles/input.styl' 6 | 7 | class Parent extends Component {} 8 | Object.assign(Parent.prototype, Mixins) 9 | 10 | export class NumericInput extends Parent { 11 | 12 | constructor(props) { 13 | super(props) 14 | this.init(this.props) 15 | this.state = this.ks 16 | } 17 | 18 | mounted(element) { 19 | this.onMounted(element) 20 | } 21 | 22 | updated() { 23 | this.onUpdated() 24 | } 25 | 26 | setProps(nextProps) { 27 | if (nextProps.value !== this.props.value && nextProps.value !== this.ks.value) { 28 | const rawValue = nextProps.value.toString().split('') 29 | const cursorPos = rawValue.length 30 | this.set('rawValue', rawValue) 31 | this.set('cursorPos', cursorPos) 32 | } 33 | super.setProps(nextProps) 34 | } 35 | 36 | set(key, value) { 37 | super.set(key, value) 38 | this.setState({ [key]: value }) 39 | } 40 | 41 | createKeyboard(el, options, events, callback) { 42 | for (let event in events) { 43 | options[`on${capitalize(event)}`] = events[event] 44 | } 45 | const keyboard = new NumericKeyboard(options) 46 | keyboard.mount() 47 | el.appendChild(keyboard._element) 48 | callback(keyboard) 49 | } 50 | 51 | destroyKeyboard(el, keyboard) { 52 | keyboard.destroy() 53 | } 54 | 55 | dispatch(event, payload) { 56 | const callback = this.props[`on${capitalize(event)}`] 57 | if (callback) { 58 | callback(payload) 59 | } 60 | } 61 | 62 | render() { 63 | let className = 'numeric-input' 64 | if (this.kp.readonly) { 65 | className += ' readonly' 66 | } 67 | if (this.kp.disabled) { 68 | className += ' disabled' 69 | } 70 | 71 | return ( 72 |
73 |
74 |
{this.ks.rawValue.map((c, i) => {c})}
75 | {this.ks.rawValue.length === 0 &&
{this.kp.placeholder}
} 76 | {this.ks.cursorActive &&
} 77 |
78 |
79 | ) 80 | } 81 | 82 | } 83 | 84 | NumericInput.defaultProps = Options 85 | -------------------------------------------------------------------------------- /vendor/vue/input.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { typeofConstructor } from 'lib/utils/type.js' 3 | import { Options, Mixins } from 'lib/input.js' 4 | import { NumericKeyboard } from './keyboard.js' 5 | import 'lib/styles/input.styl' 6 | 7 | export const NumericInput = Vue.extend({ 8 | 9 | mixins: [{ methods: Mixins }], 10 | 11 | props: (() => { 12 | let props = {} 13 | for (let name in Options) { 14 | props[name] = { default: Options[name], type: [typeofConstructor(Options[name]), String, Number, Boolean, Array, Object, Date, Function] } 15 | } 16 | return props 17 | })(), 18 | 19 | data() { 20 | return { 21 | ks: null 22 | } 23 | }, 24 | 25 | watch: { 26 | value(newValue) { 27 | if (newValue === this.ks.value) { return } 28 | const rawValue = newValue.toString().split('') 29 | const cursorPos = rawValue.length 30 | this.set('rawValue', rawValue) 31 | this.set('cursorPos', cursorPos) 32 | } 33 | }, 34 | 35 | methods: { 36 | onFocus(e) { 37 | Mixins.onFocus.call(this, e) 38 | this.$forceUpdate() 39 | }, 40 | 41 | dispatch(event, payload) { 42 | this.$emit(event, payload) 43 | }, 44 | 45 | createKeyboard(el, options, events, callback) { 46 | const keyboard = new Vue({ 47 | render: h => h(NumericKeyboard, { 48 | props: options, 49 | on: events 50 | }) 51 | }) 52 | keyboard.$mount() 53 | el.appendChild(keyboard.$el) 54 | callback(keyboard) 55 | }, 56 | 57 | destroyKeyboard(el, keyboard) { 58 | keyboard.$destroy() 59 | } 60 | }, 61 | 62 | created() { 63 | this.init(this._props) 64 | }, 65 | 66 | mounted() { 67 | this.onMounted(this.$el) 68 | }, 69 | 70 | updated() { 71 | this.onUpdated() 72 | }, 73 | 74 | beforeDestroy() { 75 | this.destroy() 76 | }, 77 | 78 | render() { 79 | let className = 'numeric-input' 80 | if (this.kp.readonly) { 81 | className += ' readonly' 82 | } 83 | if (this.kp.disabled) { 84 | className += ' disabled' 85 | } 86 | 87 | return ( 88 |
89 |
90 |
{this.ks.rawValue.map((c, i) => {c})}
91 | {this.ks.rawValue.length === 0 &&
{this.kp.placeholder}
} 92 | {this.ks.cursorActive &&
} 93 |
94 |
95 | ) 96 | } 97 | 98 | }) 99 | -------------------------------------------------------------------------------- /vendor/react/input.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import { capitalize } from 'lib/utils/string.js' 4 | import { Options, Mixins } from 'lib/input.js' 5 | import { NumericKeyboard } from './keyboard.js' // eslint-disable-line no-unused-vars 6 | import 'lib/styles/input.styl' 7 | 8 | class Parent extends React.Component {} 9 | Object.assign(Parent.prototype, Mixins) 10 | 11 | export class NumericInput extends Parent { 12 | 13 | constructor(props) { 14 | super(props) 15 | this.init(props) 16 | this.state = this.ks 17 | } 18 | 19 | componentDidMount() { 20 | this.onMounted(ReactDOM.findDOMNode(this)) 21 | } 22 | 23 | componentWillUnmount() { 24 | this.destroy() 25 | } 26 | 27 | shouldComponentUpdate(nextProps) { 28 | if (nextProps.value !== this.props.value && nextProps.value !== this.ks.value) { 29 | const rawValue = nextProps.value.toString().split('') 30 | const cursorPos = rawValue.length 31 | this.set('rawValue', rawValue) 32 | this.set('cursorPos', cursorPos) 33 | return false 34 | } 35 | return true 36 | } 37 | 38 | componentDidUpdate() { 39 | this.onUpdated() 40 | } 41 | 42 | set(key, value) { 43 | super.set(key, value) 44 | this.setState({ [key]: value }) 45 | } 46 | 47 | createKeyboard(el, options, events, callback) { 48 | for (let event in events) { 49 | options[`on${capitalize(event)}`] = events[event] 50 | } 51 | ReactDOM.render( instance && callback(instance)} {...options} />, el) 52 | } 53 | 54 | destroyKeyboard(el) { 55 | ReactDOM.unmountComponentAtNode(el) 56 | } 57 | 58 | dispatch(event, payload) { 59 | const callback = this.props[`on${capitalize(event)}`] 60 | if (callback) { 61 | callback(payload) 62 | } 63 | } 64 | 65 | render() { 66 | let className = 'numeric-input' 67 | if (this.kp.readonly) { 68 | className += ' readonly' 69 | } 70 | if (this.kp.disabled) { 71 | className += ' disabled' 72 | } 73 | 74 | return ( 75 |
76 |
77 |
{this.ks.rawValue.map((c, i) => {c})}
78 | {this.ks.rawValue.length === 0 &&
{this.kp.placeholder}
} 79 | {this.ks.cursorActive &&
} 80 |
81 |
82 | ) 83 | } 84 | 85 | } 86 | 87 | NumericInput.defaultProps = Options 88 | -------------------------------------------------------------------------------- /test/spec/vdom/componentSpec.js: -------------------------------------------------------------------------------- 1 | import { Component, createElement } from 'lib/utils/vdom.js' 2 | 3 | describe('component', () => { 4 | 5 | it('mount() trigger first render', () => { 6 | class C extends Component { 7 | mounted() {} 8 | render() { 9 | return createElement('p') 10 | } 11 | } 12 | 13 | const c = new C 14 | 15 | spyOn(c, 'mounted') 16 | 17 | expect(c._element).toBeNull() 18 | expect(c.mounted).not.toHaveBeenCalled() 19 | 20 | c.mount() 21 | 22 | expect(c._element).toEqual(jasmine.any(HTMLParagraphElement)) 23 | expect(c.mounted).toHaveBeenCalledTimes(1) 24 | }) 25 | 26 | it('setProps() trigger rerender', () => { 27 | class C extends Component { 28 | mounted() {} 29 | updated() {} 30 | render() { 31 | return createElement('p', null, [this.props.text]) 32 | } 33 | } 34 | 35 | const c = new C({ text: 'foo' }) 36 | 37 | spyOn(c, 'mounted') 38 | spyOn(c, 'updated') 39 | spyOn(c, 'render').and.callThrough() 40 | 41 | expect(c.updated).not.toHaveBeenCalled() 42 | 43 | c.mount() 44 | 45 | expect(c.render).toHaveBeenCalledTimes(1) 46 | expect(c._element.firstChild.nodeValue).toBe('foo') 47 | expect(c.updated).toHaveBeenCalledTimes(0) 48 | 49 | c.setProps({ text: 'bar' }) 50 | 51 | expect(c.render).toHaveBeenCalledTimes(2) 52 | expect(c._element.firstChild.nodeValue).toBe('bar') 53 | expect(c.updated).toHaveBeenCalledTimes(1) 54 | expect(c.mounted).toHaveBeenCalledTimes(1) 55 | }) 56 | 57 | it('setState() trigger rerender async', (done) => { 58 | class C extends Component { 59 | constructor(props) { 60 | super(props) 61 | this.state = { text: 'foo' } 62 | } 63 | mounted() {} 64 | updated() {} 65 | render() { 66 | return createElement('p', null, [this.state.text]) 67 | } 68 | } 69 | 70 | const c = new C 71 | 72 | spyOn(c, 'mounted') 73 | spyOn(c, 'updated') 74 | spyOn(c, 'render').and.callThrough() 75 | 76 | c.mount() 77 | 78 | expect(c.render).toHaveBeenCalledTimes(1) 79 | expect(c._element.firstChild.nodeValue).toBe('foo') 80 | 81 | c.setState({ text: 'bar' }) 82 | c.setState({ text: 'barz' }) 83 | 84 | expect(c.render).toHaveBeenCalledTimes(1) 85 | expect(c._element.firstChild.nodeValue).toBe('foo') 86 | expect(c.updated).not.toHaveBeenCalled() 87 | 88 | setTimeout(() => { 89 | expect(c.render).toHaveBeenCalledTimes(2) 90 | expect(c._element.firstChild.nodeValue).toBe('barz') 91 | expect(c.updated).toHaveBeenCalledTimes(1) 92 | expect(c.mounted).toHaveBeenCalledTimes(1) 93 | done() 94 | }, 200) 95 | }) 96 | 97 | }) 98 | -------------------------------------------------------------------------------- /demo/transfer/vue/app.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { NumericKeyboard, NumericInput, Keys } from 'numeric-keyboard' 3 | import '../styles.styl' 4 | 5 | const PasswordLayout = [ 6 | [ 7 | { 8 | key: Keys.ONE 9 | }, 10 | { 11 | key: Keys.TWO 12 | }, 13 | { 14 | key: Keys.THREE 15 | }, 16 | ], 17 | [ 18 | { 19 | key: Keys.FOUR 20 | }, 21 | { 22 | key: Keys.FIVE 23 | }, 24 | { 25 | key: Keys.SIX 26 | }, 27 | ], 28 | [ 29 | { 30 | key: Keys.SEVEN 31 | }, 32 | { 33 | key: Keys.EIGHT 34 | }, 35 | { 36 | key: Keys.NINE 37 | }, 38 | ], 39 | [ 40 | { 41 | key: Keys.BLANK 42 | }, 43 | { 44 | key: Keys.ZERO 45 | }, 46 | { 47 | key: Keys.DEL 48 | }, 49 | ], 50 | ] 51 | 52 | const Password = Vue.extend({ 53 | components: { 54 | 'v-numeric-keyboard': NumericKeyboard 55 | }, 56 | 57 | data() { 58 | return { 59 | PasswordLayout, 60 | password: '' 61 | } 62 | }, 63 | 64 | methods: { 65 | press(key) { 66 | if (key === Keys.DEL) { 67 | this.password = this.password.slice(0, -1) 68 | } 69 | else { 70 | this.password = this.password + key 71 | if (this.password.length === 6) { 72 | setTimeout(() => this.$emit('confirm', this.password), 100) 73 | } 74 | } 75 | } 76 | }, 77 | 78 | template: ` 79 |
80 |
81 |

Conform password

82 |
83 | 84 |
85 | 86 |
87 |
88 | ` 89 | 90 | }) 91 | 92 | export default Vue.extend({ 93 | components: { 94 | 'v-numeric-input': NumericInput, 95 | 'v-password': Password 96 | }, 97 | 98 | data() { 99 | return { 100 | amount: '', 101 | shouldOpenPassword: false 102 | } 103 | }, 104 | 105 | methods: { 106 | confirmAmount() { 107 | if (this.amount) { 108 | this.shouldOpenPassword = true 109 | } 110 | }, 111 | 112 | confirmPassword(password) { 113 | this.shouldOpenPassword = false 114 | setTimeout(() => alert(`Amount: ${this.amount}\nPassword: ${password}`), 200) 115 | } 116 | }, 117 | 118 | template: ` 119 |
120 |
121 |

Transfer to Arthur

122 |
123 |
124 | 125 |
126 | 127 |
128 | 129 |
130 |
131 |

Power by Numeric Keyboard

132 |
133 | 134 |
135 | ` 136 | }) 137 | -------------------------------------------------------------------------------- /demo/transfer/angular/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Output } from '@angular/core' 2 | import { Keys } from 'numeric-keyboard' 3 | 4 | const PasswordLayout = [ 5 | [ 6 | { 7 | key: Keys.ONE 8 | }, 9 | { 10 | key: Keys.TWO 11 | }, 12 | { 13 | key: Keys.THREE 14 | }, 15 | ], 16 | [ 17 | { 18 | key: Keys.FOUR 19 | }, 20 | { 21 | key: Keys.FIVE 22 | }, 23 | { 24 | key: Keys.SIX 25 | }, 26 | ], 27 | [ 28 | { 29 | key: Keys.SEVEN 30 | }, 31 | { 32 | key: Keys.EIGHT 33 | }, 34 | { 35 | key: Keys.NINE 36 | }, 37 | ], 38 | [ 39 | { 40 | key: Keys.BLANK 41 | }, 42 | { 43 | key: Keys.ZERO 44 | }, 45 | { 46 | key: Keys.DEL 47 | }, 48 | ], 49 | ] 50 | 51 | const PasswordTemplate = ` 52 |
53 |
54 |

Conform password

55 |
56 | 57 |
58 | 59 |
60 |
61 | ` 62 | 63 | @Component({ 64 | selector: 'password', 65 | template: PasswordTemplate, 66 | styleUrls: [ './app.component.styl' ] 67 | }) 68 | export class Password { 69 | @Output() confirm = new EventEmitter() 70 | 71 | public PasswordLayout: any = PasswordLayout 72 | public password: string = '' 73 | 74 | press(key) { 75 | if (key === Keys.DEL) { 76 | this.password = this.password.slice(0, -1) 77 | } 78 | else { 79 | this.password = this.password + key 80 | if (this.password.length === 6) { 81 | setTimeout(() => this.confirm.emit(this.password), 100) 82 | } 83 | } 84 | } 85 | } 86 | 87 | const AppTemplate = ` 88 |
89 |
90 |

Transfer to Arthur

91 |
92 |
93 | 94 |
95 | 96 |
97 | 98 |
99 |
100 |

Power by Numeric Keyboard

101 |
102 | 103 |
104 | ` 105 | 106 | @Component({ 107 | selector: '#app', 108 | template: AppTemplate, 109 | styleUrls: [ './app.component.styl' ] 110 | }) 111 | export class App { 112 | public amount: string | number = '' 113 | public shouldOpenPassword: boolean = false 114 | 115 | confirmAmount(e) { 116 | if (e) { 117 | e.preventDefault() 118 | } 119 | if (this.amount) { 120 | this.shouldOpenPassword = true 121 | } 122 | } 123 | 124 | confirmPassword(password) { 125 | this.shouldOpenPassword = false 126 | setTimeout(() => alert(`Amount: ${this.amount}\nPassword: ${password}`), 200) 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /demo/transfer/react/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { NumericKeyboard, NumericInput, Keys } from 'numeric-keyboard' // eslint-disable-line no-unused-vars 3 | import '../styles.styl' 4 | 5 | const PasswordLayout = [ 6 | [ 7 | { 8 | key: Keys.ONE 9 | }, 10 | { 11 | key: Keys.TWO 12 | }, 13 | { 14 | key: Keys.THREE 15 | }, 16 | ], 17 | [ 18 | { 19 | key: Keys.FOUR 20 | }, 21 | { 22 | key: Keys.FIVE 23 | }, 24 | { 25 | key: Keys.SIX 26 | }, 27 | ], 28 | [ 29 | { 30 | key: Keys.SEVEN 31 | }, 32 | { 33 | key: Keys.EIGHT 34 | }, 35 | { 36 | key: Keys.NINE 37 | }, 38 | ], 39 | [ 40 | { 41 | key: Keys.BLANK 42 | }, 43 | { 44 | key: Keys.ZERO 45 | }, 46 | { 47 | key: Keys.DEL 48 | }, 49 | ], 50 | ] 51 | 52 | class Password extends React.Component { // eslint-disable-line no-unused-vars 53 | constructor() { 54 | super() 55 | this.state = { 56 | password: '' 57 | } 58 | } 59 | 60 | press(key) { 61 | if (key === Keys.DEL) { 62 | this.setState(state => ({ password: state.password.slice(0, -1) })) 63 | } 64 | else { 65 | this.setState(state => ({ password: state.password + key }), () => { 66 | if (this.state.password.length === 6) { 67 | setTimeout(() => this.props.onConfirm.call(null, this.state.password), 100) 68 | } 69 | }) 70 | } 71 | } 72 | 73 | render() { 74 | return
75 |
76 |

Conform password

77 |
78 | {[1, 2, 3, 4, 5, 6].map(n => n > this.state.password.length ? : )} 79 |
80 | 81 |
82 |
83 | } 84 | } 85 | 86 | export default class App extends React.Component { 87 | constructor() { 88 | super() 89 | this.state = { 90 | amount: '', 91 | shouldOpenPassword: false 92 | } 93 | } 94 | 95 | inputAmout(amount) { 96 | this.setState({ amount: amount }) 97 | } 98 | 99 | confirmAmount(e) { 100 | if (e) { 101 | e.preventDefault() 102 | } 103 | if (this.state.amount) { 104 | this.setState({ shouldOpenPassword: true }) 105 | } 106 | } 107 | 108 | confirmPassword(password) { 109 | this.setState({ shouldOpenPassword: false }) 110 | setTimeout(() => alert(`Amount: ${this.state.amount}\nPassword: ${password}`), 200) 111 | } 112 | 113 | render() { 114 | return
115 |
116 |

Transfer to Arthur

117 |
118 |
119 | 120 |
121 | 122 |
123 | 124 |
125 |
126 |

Power by Numeric Keyboard

127 |
128 | { this.state.shouldOpenPassword && } 129 |
130 | } 131 | } 132 | -------------------------------------------------------------------------------- /test/spec/vdom/vnodeSpec.js: -------------------------------------------------------------------------------- 1 | import { VText, VNode } from 'lib/utils/vdom.js' 2 | 3 | describe('vnode', () => { 4 | 5 | it('render', () => { 6 | const vnode = new VNode('div') 7 | const element = vnode.render() 8 | 9 | expect(element).toEqual(jasmine.any(HTMLDivElement)) 10 | }) 11 | 12 | it('render props', () => { 13 | const vnode = new VNode('div', { id: 'foo', htmlFor: 'bar', className: 'baz', qux: 'quux', obj: {} }) 14 | const element = vnode.render() 15 | 16 | expect(element.getAttribute('id')).toBe('foo') 17 | expect(element.getAttribute('for')).toBe('bar') 18 | expect(element.getAttribute('class')).toBe('baz') 19 | expect(element.getAttribute('qux')).toBe('quux') 20 | expect(element.getAttribute('obj')).toBe('[object Object]') 21 | 22 | expect(element.getAttribute('htmlFor')).toBeNull() 23 | expect(element.getAttribute('className')).toBeNull() 24 | }) 25 | 26 | it('render styles', () => { 27 | const vnode = new VNode('div', { style: { color: 'white', backgroundColor: 'black' } }) 28 | const element = vnode.render() 29 | 30 | expect(element.style.color).toBe('white') 31 | expect(element.style.backgroundColor).toBe('black') 32 | }) 33 | 34 | it('render events', () => { 35 | const start = jasmine.createSpy('touchstart') 36 | const end = jasmine.createSpy('touchend') 37 | 38 | const vnode = new VNode('div', { onTouchstart: start, ontouchend: end }) 39 | const element = vnode.render() 40 | 41 | expect(element.getAttribute('onTouchstart')).toBeNull() 42 | expect(element.getAttribute('ontouchend')).toBe('[object Function]') 43 | 44 | expect(start).not.toHaveBeenCalled() 45 | 46 | element.dispatchEvent(new Event('touchstart')) 47 | // dispatch a touchend event will raise a exception as the unlegal code specified by the ontouchend property will run 48 | // element.dispatchEvent(new Event('touchend')) 49 | 50 | expect(start).toHaveBeenCalledTimes(1) 51 | }) 52 | 53 | it('render single child', () => { 54 | const vnode = new VNode('div', null, new VNode('span')) 55 | const element = vnode.render() 56 | 57 | expect(element.childNodes.length).toBe(1) 58 | expect(element.firstChild).toEqual(jasmine.any(HTMLSpanElement)) 59 | }) 60 | 61 | it('render children', () => { 62 | const vnode = new VNode('div', null, 'foo', new VNode('span', null, new VText('bar'), 1)) 63 | const element = vnode.render() 64 | 65 | expect(element.childNodes.length).toBe(2) 66 | expect(element.firstChild).toEqual(jasmine.any(Text)) 67 | expect(element.lastChild).toEqual(jasmine.any(HTMLSpanElement)) 68 | expect(element.lastChild.firstChild.nodeValue).toBe('bar') 69 | expect(element.lastChild.lastChild.nodeValue).toBe('1') 70 | expect(element.lastChild.innerHTML).toBe('bar1') 71 | }) 72 | 73 | it('update', function () { 74 | const start = jasmine.createSpy('touchstart') 75 | const end = jasmine.createSpy('touchend') 76 | 77 | const vnode = new VNode('div', { id: 'foo', style: { color: 'white' }, onTouchstart: start }) 78 | const updateProps = { id: null, className: 'bar', style: { color: null, backgroundColor: 'black' }, onTouchstart: null, onTouchend: end } 79 | 80 | const element = vnode.render() 81 | vnode.update(updateProps) 82 | 83 | expect(element.getAttribute('id')).toBeNull() 84 | expect(element.getAttribute('class')).toBe('bar') 85 | expect(element.style.color).toBe('') 86 | expect(element.style.backgroundColor).toBe('black') 87 | 88 | element.dispatchEvent(new Event('touchstart')) 89 | element.dispatchEvent(new Event('touchend')) 90 | 91 | expect(start).toHaveBeenCalledTimes(0) 92 | expect(end).toHaveBeenCalledTimes(1) 93 | }) 94 | 95 | }) 96 | -------------------------------------------------------------------------------- /demo/transfer/vanilla/app.js: -------------------------------------------------------------------------------- 1 | import { NumericKeyboard, NumericInput, Keys } from 'numeric-keyboard' 2 | import '../styles.styl' 3 | 4 | const PasswordLayout = [ 5 | [ 6 | { 7 | key: Keys.ONE 8 | }, 9 | { 10 | key: Keys.TWO 11 | }, 12 | { 13 | key: Keys.THREE 14 | }, 15 | ], 16 | [ 17 | { 18 | key: Keys.FOUR 19 | }, 20 | { 21 | key: Keys.FIVE 22 | }, 23 | { 24 | key: Keys.SIX 25 | }, 26 | ], 27 | [ 28 | { 29 | key: Keys.SEVEN 30 | }, 31 | { 32 | key: Keys.EIGHT 33 | }, 34 | { 35 | key: Keys.NINE 36 | }, 37 | ], 38 | [ 39 | { 40 | key: Keys.BLANK 41 | }, 42 | { 43 | key: Keys.ZERO 44 | }, 45 | { 46 | key: Keys.DEL 47 | }, 48 | ], 49 | ] 50 | 51 | const PasswordTemplate = ` 52 |
53 |
54 |

Conform password

55 |
56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 |
64 |
65 |
66 | ` 67 | 68 | class Password { 69 | constructor(el, options) { 70 | this.el = el 71 | this.options = options 72 | this.password = '' 73 | 74 | this.render() 75 | } 76 | 77 | press(key) { 78 | if (key === Keys.DEL) { 79 | this.password = this.password.slice(0, -1) 80 | } 81 | else { 82 | this.password = this.password + key 83 | } 84 | 85 | Array.prototype.slice.call(this.el.querySelectorAll('.input span')).forEach((el, n) => { 86 | if (n < this.password.length) { 87 | el.setAttribute('class', 'fill') 88 | } 89 | else { 90 | el.removeAttribute('class') 91 | } 92 | }) 93 | 94 | if (this.password.length === 6) { 95 | setTimeout(() => this.options.onConfirm.call(null, this.password), 100) 96 | } 97 | } 98 | 99 | render() { 100 | this.el.outerHTML = PasswordTemplate 101 | this.el = document.querySelector('.password') 102 | 103 | new NumericKeyboard({ 104 | layout: PasswordLayout, 105 | onPress: this.press.bind(this) 106 | }).mount('.keyboard') 107 | } 108 | } 109 | 110 | const AppTemplate = ` 111 |
112 |
113 |

Transfer to Arthur

114 |
115 |
116 | 117 |
118 | 119 |
120 |
121 |

Power by Numeric Keyboard

122 |
123 |
124 | ` 125 | 126 | export default class App { 127 | constructor(el, options) { 128 | this.el = el 129 | this.options = options 130 | this.amount = '' 131 | 132 | this.render() 133 | } 134 | 135 | inputAmount(amount) { 136 | this.amount = amount 137 | this.el.querySelector('input[type=submit]').disabled = !amount 138 | } 139 | 140 | confirmAmount(e) { 141 | if (e) { 142 | e.preventDefault() 143 | } 144 | if (this.amount) { 145 | const elPassword = document.createElement('div') 146 | this.el.appendChild(elPassword) 147 | new Password(elPassword, { onConfirm: this.confirmPassword.bind(this) }) 148 | } 149 | } 150 | 151 | confirmPassword(password) { 152 | this.el.removeChild(this.el.querySelector('.password')) 153 | setTimeout(() => alert(`Amount: ${this.amount}\nPassword: ${password}`), 200) 154 | } 155 | 156 | render() { 157 | this.el.outerHTML = AppTemplate 158 | this.el = document.querySelector('.app') 159 | 160 | new NumericInput({ 161 | type: 'number', 162 | autofocus: true, 163 | entertext: 'Confirm', 164 | format: '^(?:\\d+(?:\\.\\d{0,2})?)?$', 165 | onInput: this.inputAmount.bind(this), 166 | onEnterpress: this.confirmAmount.bind(this) 167 | }).mount('.input div') 168 | 169 | this.el.querySelector('form').addEventListener('submit', this.confirmAmount.bind(this), false) 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /test/spec/vdom/patchSpec.js: -------------------------------------------------------------------------------- 1 | import { VNode, Diff, Patch } from 'lib/utils/vdom.js' 2 | 3 | describe('patch', () => { 4 | 5 | it('props', () => { 6 | const oldTree = new VNode('div', { id: 'foo', className: 'bar' }) 7 | const element = oldTree.render() 8 | 9 | expect(element.getAttribute('id')).toBe('foo') 10 | expect(element.getAttribute('class')).toBe('bar') 11 | 12 | const newTree = new VNode('div', { className: 'qux' }) 13 | const diffs = new Diff(oldTree, newTree).patches 14 | new Patch(element, diffs) 15 | 16 | expect(element.getAttribute('id')).toBeNull() 17 | expect(element.getAttribute('class')).toBe('qux') 18 | }) 19 | 20 | it('styles', () => { 21 | const oldTree = new VNode('div', { style: { color: 'white' } }) 22 | const element = oldTree.render() 23 | 24 | expect(element.style.color).toBe('white') 25 | 26 | const newTree = new VNode('div', { style: { color: null, backgroundColor: 'black' } }) 27 | const diffs = new Diff(oldTree, newTree).patches 28 | new Patch(element, diffs) 29 | 30 | expect(element.style.color).toBe('') 31 | expect(element.style.backgroundColor).toBe('black') 32 | }) 33 | 34 | it('events', () => { 35 | const start = jasmine.createSpy('touchstart') 36 | const end = jasmine.createSpy('touchend') 37 | const move = jasmine.createSpy('touchmove') 38 | 39 | const oldTree = new VNode('div', { onTouchstart: start, onTouchend: end }) 40 | const element = oldTree.render() 41 | 42 | element.dispatchEvent(new Event('touchstart')) 43 | element.dispatchEvent(new Event('touchend')) 44 | element.dispatchEvent(new Event('touchmove')) 45 | 46 | expect(start).toHaveBeenCalledTimes(1) 47 | expect(end).toHaveBeenCalledTimes(1) 48 | expect(move).not.toHaveBeenCalled() 49 | 50 | const newTree = new VNode('div', { onTouchmove: move }) 51 | const diffs = new Diff(oldTree, newTree).patches 52 | new Patch(element, diffs) 53 | 54 | element.dispatchEvent(new Event('touchstart')) 55 | element.dispatchEvent(new Event('touchend')) 56 | element.dispatchEvent(new Event('touchmove')) 57 | 58 | expect(start).toHaveBeenCalledTimes(1) 59 | expect(end).toHaveBeenCalledTimes(1) 60 | expect(move).toHaveBeenCalledTimes(1) 61 | }) 62 | 63 | it('replace text', () => { 64 | const oldTree = new VNode('div', null, 'foo') 65 | const element = oldTree.render() 66 | 67 | expect(element.firstChild.nodeValue).toBe('foo') 68 | 69 | const newTree = new VNode('div', null, 'bar') 70 | const diffs = new Diff(oldTree, newTree).patches 71 | new Patch(element, diffs) 72 | 73 | expect(element.firstChild.nodeValue).toBe('bar') 74 | }) 75 | 76 | it('replace node', () => { 77 | const oldTree = new VNode('div', null, new VNode('div')) 78 | const element = oldTree.render() 79 | 80 | expect(element.firstChild).toEqual(jasmine.any(HTMLDivElement)) 81 | 82 | const newTree = new VNode('div', null, new VNode('span')) 83 | const diffs = new Diff(oldTree, newTree).patches 84 | new Patch(element, diffs) 85 | 86 | expect(element.firstChild).toEqual(jasmine.any(HTMLSpanElement)) 87 | }) 88 | 89 | it('reorder', () => { 90 | const oldTree = new VNode('div', null, new VNode('span', {id: 'foo'}), new VNode('span', {id: 'bar'})) 91 | const element = oldTree.render() 92 | 93 | expect(element.firstChild.getAttribute('id')).toBe('foo') 94 | expect(element.lastChild.getAttribute('id')).toBe('bar') 95 | 96 | const newTree = new VNode('div', null, new VNode('span', {id: 'bar'}), new VNode('span', {id: 'foo'})) 97 | const diffs = new Diff(oldTree, newTree).patches 98 | new Patch(element, diffs) 99 | 100 | expect(element.firstChild.getAttribute('id')).toBe('bar') 101 | expect(element.lastChild.getAttribute('id')).toBe('foo') 102 | }) 103 | 104 | it('reorder with key', () => { 105 | const oldTree = new VNode('div', null, new VNode('span', {id: 'foo', key: 'foo'}), new VNode('span', {id: 'bar', key: 'bar'})) 106 | const element = oldTree.render() 107 | 108 | expect(element.firstChild.getAttribute('id')).toBe('foo') 109 | expect(element.lastChild.getAttribute('id')).toBe('bar') 110 | 111 | const newTree = new VNode('div', null, new VNode('span', {id: 'bar', key: 'bar'}), new VNode('span', {id: 'foo', key: 'foo'})) 112 | const diffs = new Diff(oldTree, newTree).patches 113 | new Patch(element, diffs) 114 | 115 | expect(element.firstChild.getAttribute('id')).toBe('bar') 116 | expect(element.lastChild.getAttribute('id')).toBe('foo') 117 | }) 118 | 119 | }) 120 | -------------------------------------------------------------------------------- /vendor/angular/input/input.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output, OnInit, OnDestroy, AfterViewInit, AfterViewChecked, 2 | ElementRef, ApplicationRef, ComponentFactoryResolver, Injector, EmbeddedViewRef } from '@angular/core' 3 | import { coerceBooleanProperty } from 'lib/utils/attribute.js' 4 | import { Options, Mixins } from 'lib/input' 5 | import { NumericKeyboard } from '../keyboard/keyboard.component' 6 | 7 | const template = ` 8 |
9 |
10 |
{{c}}
11 |
{{kp.placeholder}}
12 |
13 |
14 |
15 | ` 16 | 17 | class Parent {} 18 | Parent.prototype = Mixins 19 | Parent.prototype.constructor = Parent 20 | 21 | @Component({ 22 | selector: 'numeric-input', 23 | template: template, 24 | styleUrls: [ './input.component.styl' ] 25 | }) 26 | export class NumericInput extends Parent implements OnInit, OnDestroy, AfterViewInit, AfterViewChecked { 27 | private _autofocus: boolean = Options.autofocus 28 | private _disabled: boolean = Options.disabled 29 | private _readonly: boolean = Options.readonly 30 | private _value: number | string = Options.value 31 | 32 | @Input() 33 | get autofocus() { return this._autofocus } 34 | set autofocus(value: any) { this._autofocus = coerceBooleanProperty(value) } 35 | 36 | @Input() 37 | get disabled() { return this._disabled } 38 | set disabled(value: any) { this._disabled = coerceBooleanProperty(value) } 39 | 40 | @Input() 41 | get readonly() { return this._readonly } 42 | set readonly(value: any) { this._readonly = coerceBooleanProperty(value) } 43 | 44 | @Input() 45 | get ngModel() { return this._value } 46 | set ngModel(value: any) { 47 | if (this.ks && this.ks.value !== value) { 48 | const rawValue = value.toString().split('') 49 | const cursorPos = rawValue.length 50 | Mixins.set.call(this, 'rawValue', rawValue) 51 | Mixins.set.call(this, 'cursorPos', cursorPos) 52 | } 53 | this._value = value 54 | } 55 | 56 | @Input() type: string = Options.type 57 | @Input() value: number | string = Options.value 58 | @Input() maxlength: number = Options.maxlength 59 | @Input() name: string = Options.name 60 | @Input() placeholder: string = Options.placeholder 61 | @Input() format: string | { (val: string): boolean } = Options.format 62 | @Input() layout: string | { key: number | string }[][] = Options.layout 63 | @Input() entertext: string = Options.entertext 64 | 65 | @Output() focus = new EventEmitter() 66 | @Output() blur = new EventEmitter() 67 | @Output() enterpress = new EventEmitter() 68 | @Output() ngModelChange = new EventEmitter() 69 | 70 | public kp 71 | public ks 72 | 73 | constructor( 74 | private element: ElementRef, 75 | private appRef: ApplicationRef, 76 | private componentFactoryResolver: ComponentFactoryResolver, 77 | private injector: Injector) { 78 | super() 79 | } 80 | 81 | ngOnInit() { 82 | let resolvedOptions = {} 83 | for (let key in Options) { 84 | resolvedOptions[key] = this[key] 85 | } 86 | Mixins.init.call(this, resolvedOptions) 87 | } 88 | 89 | ngOnDestroy() { 90 | Mixins.destroy.call(this) 91 | } 92 | 93 | ngAfterViewInit() { 94 | Mixins.onMounted.call(this, this.element.nativeElement.querySelector('.numeric-input')) 95 | } 96 | 97 | ngAfterViewChecked() { 98 | Mixins.onUpdated.call(this) 99 | } 100 | 101 | trackByIndex(index) { 102 | return index 103 | } 104 | 105 | onFocus(event) { 106 | Mixins.onFocus.call(this, event) 107 | } 108 | 109 | dispatch(event: string, payload?: number | string) { 110 | switch (event) { 111 | case 'focus': 112 | this.focus.emit() 113 | break 114 | case 'blur': 115 | this.blur.emit() 116 | break 117 | case 'enterpress': 118 | this.enterpress.emit() 119 | break 120 | case 'input': 121 | this.ngModelChange.emit(payload) 122 | break 123 | } 124 | } 125 | 126 | createKeyboard(el, options, events, callback) { 127 | const componentRef = this.componentFactoryResolver 128 | .resolveComponentFactory(NumericKeyboard) 129 | .create(this.injector) 130 | 131 | Object.assign(componentRef.instance, options) 132 | 133 | componentRef.instance.ngOnInit() 134 | 135 | for (let event in events) { 136 | componentRef.instance[event].subscribe(events[event]) 137 | } 138 | 139 | this.appRef.attachView(componentRef.hostView) 140 | el.appendChild((componentRef.hostView as EmbeddedViewRef).rootNodes[0] as HTMLElement) 141 | 142 | callback(componentRef) 143 | } 144 | 145 | destroyKeyboard(el, keyboard) { 146 | keyboard.destroy() 147 | this.appRef.detachView(keyboard.hostView) 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /test/spec/vdom/diffSpec.js: -------------------------------------------------------------------------------- 1 | import { Component, VText, VNode, VComponent, Diff, PatchType } from 'lib/utils/vdom.js' 2 | 3 | describe('diff', () => { 4 | 5 | it('vtext and vtext, same', () => { 6 | const oldNode = new VText('foo') 7 | const newNode = new VText('foo') 8 | const diffs = new Diff(oldNode, newNode).patches 9 | 10 | expect(diffs[0]).toBeUndefined() 11 | }) 12 | 13 | it('vtext and vtext, different', () => { 14 | const oldNode = new VText('foo') 15 | const newNode = new VText('bar') 16 | const diffs = new Diff(oldNode, newNode).patches 17 | 18 | expect(diffs[0]).toEqual([{type: PatchType.REPLACE, oldNode, newNode}]) 19 | }) 20 | 21 | it('vnode vs vnode, same', () => { 22 | const oldNode = new VNode('div') 23 | const newNode = new VNode('div') 24 | const diffs = new Diff(oldNode, newNode).patches 25 | 26 | expect(diffs[0]).toBeUndefined() 27 | }) 28 | 29 | it('vnode vs vnode, different tagName', () => { 30 | const oldNode = new VNode('div') 31 | const newNode = new VNode('span') 32 | const diffs = new Diff(oldNode, newNode).patches 33 | 34 | expect(diffs[0]).toEqual([{type: PatchType.REPLACE, oldNode, newNode}]) 35 | }) 36 | 37 | it('vnode vs vnode, different props', () => { 38 | let oldNode, newNode, diffs 39 | 40 | oldNode = new VNode('div') 41 | newNode = new VNode('div', {classname: 'bar'}) 42 | diffs = new Diff(oldNode, newNode).patches 43 | 44 | expect(diffs[0]).toEqual([{type: PatchType.PROPS, oldNode, newNode, props: {classname: 'bar'}}]) 45 | 46 | oldNode = new VNode('div', {classname: 'bar'}) 47 | newNode = new VNode('div') 48 | diffs = new Diff(oldNode, newNode).patches 49 | 50 | expect(diffs[0]).toEqual([{type: PatchType.PROPS, oldNode, newNode, props: {classname: null}}]) 51 | 52 | oldNode = new VNode('div', {classname: 'bar'}) 53 | newNode = new VNode('div', {classname: 'foo'}) 54 | diffs = new Diff(oldNode, newNode).patches 55 | 56 | expect(diffs[0]).toEqual([{type: PatchType.PROPS, oldNode, newNode, props: {classname: 'foo'}}]) 57 | 58 | oldNode = new VNode('div', {classname: 'bar'}) 59 | newNode = new VNode('div', {classname: 'foo', id: 'qux'}) 60 | diffs = new Diff(oldNode, newNode).patches 61 | 62 | expect(diffs[0]).toEqual([{type: PatchType.PROPS, oldNode, newNode, props: {classname: 'foo', id: 'qux'}}]) 63 | 64 | oldNode = new VNode('div', { style: { color: 'white' } }) 65 | newNode = new VNode('div', { style: { color: null, backgroundColor: 'black' } }) 66 | diffs = new Diff(oldNode, newNode).patches 67 | 68 | expect(diffs[0]).toEqual([{type: PatchType.PROPS, oldNode, newNode, props: { style: { color: null, backgroundColor: 'black' } }}]) 69 | }) 70 | 71 | it('vnode vs vnode, different children', () => { 72 | let oldNode, newNode, diffs 73 | 74 | oldNode = new VNode('div') 75 | newNode = new VNode('div', null, 'foo') 76 | diffs = new Diff(oldNode, newNode).patches 77 | 78 | expect(diffs[0]).toEqual([{type: PatchType.REORDER, move: [{type: PatchType.INSERT, node: jasmine.any(VText), index: 0}]}]) 79 | 80 | oldNode = new VNode('div', null, 'foo') 81 | newNode = new VNode('div') 82 | diffs = new Diff(oldNode, newNode).patches 83 | 84 | expect(diffs[0]).toEqual([{type: PatchType.REORDER, move: [{type: PatchType.REMOVE, node: jasmine.any(VText), index: 0}]}]) 85 | 86 | oldNode = new VNode('div', null, 'foo') 87 | newNode = new VNode('div', null, 'bar') 88 | diffs = new Diff(oldNode, newNode).patches 89 | 90 | expect(diffs[0][0].type).toBe(PatchType.REORDER) 91 | expect(diffs[0][0].move.length).toBe(2) 92 | expect(diffs[0][0].move[0]).toEqual({type: PatchType.REMOVE, node: jasmine.any(VText), index: 0}) 93 | expect(diffs[0][0].move[1]).toEqual({type: PatchType.INSERT, node: jasmine.any(VText), index: 0}) 94 | 95 | oldNode = new VNode('div', null, new VNode('span', {key: 'foo'}), new VNode('span', {key: 'bar'})) 96 | newNode = new VNode('div', null, new VNode('span', {key: 'bar'}), new VNode('span', {key: 'foo'})) 97 | diffs = new Diff(oldNode, newNode).patches 98 | 99 | expect(diffs[0][0].type).toBe(PatchType.REORDER) 100 | expect(diffs[0][0].move.length).toBe(2) 101 | expect(diffs[0][0].move[0]).toEqual({type: PatchType.INSERT, node: jasmine.any(VNode), index: 0}) 102 | expect(diffs[0][0].move[1]).toEqual({type: PatchType.REMOVE, node: jasmine.any(VNode), index: 2}) 103 | }) 104 | 105 | it('vcomponent and vcomponent, same', () => { 106 | class C extends Component {} 107 | const oldNode = new VComponent(C) 108 | const newNode = new VComponent(C) 109 | const diffs = new Diff(oldNode, newNode).patches 110 | 111 | expect(diffs[0]).toBeUndefined() 112 | }) 113 | 114 | it('vcomponent vs vcomponent, different class', function () { 115 | class C1 extends Component {} 116 | class C2 extends Component {} 117 | const oldNode = new VComponent(C1) 118 | const newNode = new VComponent(C2) 119 | const diffs = new Diff(oldNode, newNode).patches 120 | 121 | expect(diffs[0]).toEqual([{type: PatchType.REPLACE, oldNode, newNode}]) 122 | }) 123 | 124 | it('vcomponent vs vcomponent, different props', function () { 125 | class C extends Component {} 126 | const oldNode = new VComponent(C, {foo: 'foo'}) 127 | const newNode = new VComponent(C, {bar: 'bar'}) 128 | const diffs = new Diff(oldNode, newNode).patches 129 | 130 | expect(diffs[0]).toEqual([{type: PatchType.PROPS, oldNode, newNode, props: {foo: null, bar: 'bar'}}]) 131 | }) 132 | 133 | it('vtext vs vnode vs vcomponent', function () { 134 | const vtext = new VText('foo') 135 | const vnode = new VNode('div') 136 | const vcomponent = new VComponent(class C extends Component {}) 137 | 138 | const diffsTN = new Diff(vtext, vnode).patches 139 | const diffsTC = new Diff(vtext, vcomponent).patches 140 | const diffsNC = new Diff(vnode, vcomponent).patches 141 | 142 | expect(diffsTN[0]).toEqual([{type: PatchType.REPLACE, oldNode: vtext, newNode: vnode}]) 143 | expect(diffsTC[0]).toEqual([{type: PatchType.REPLACE, oldNode: vtext, newNode: vcomponent}]) 144 | expect(diffsNC[0]).toEqual([{type: PatchType.REPLACE, oldNode: vnode, newNode: vcomponent}]) 145 | }) 146 | 147 | 148 | }) 149 | -------------------------------------------------------------------------------- /test/spec/inputSpec.js: -------------------------------------------------------------------------------- 1 | import { Options, Mixins } from 'lib/input.js' 2 | import * as Keys from 'lib/keys.js' 3 | 4 | describe('input mixins', () => { 5 | 6 | const createComponent = (options) => { 7 | const component = Object.create(Mixins) 8 | component.dispatch = jasmine.createSpy() 9 | component.init(Object.assign({}, Options, options)) 10 | return component 11 | } 12 | 13 | it('built-in number charactor', () => { 14 | const component = createComponent({type: 'text'}) 15 | 16 | expect(component.ks.rawValue).toEqual([]) 17 | expect(component.ks.cursorPos).toBe(0) 18 | expect(component.dispatch).not.toHaveBeenCalled() 19 | 20 | ;[ 21 | Keys.ZERO, Keys.ONE, Keys.TWO, Keys.THREE, Keys.FOUR, 22 | Keys.FIVE, Keys.SIX, Keys.SEVEN, Keys.EIGHT, Keys.NINE 23 | ].forEach((key, index) => { 24 | const rawValue = Array(index + 2).join('*').split('').map((n, i) => (i).toString()) 25 | component.input(key) 26 | expect(component.ks.rawValue).toEqual(rawValue) 27 | expect(component.ks.cursorPos).toBe(index + 1) 28 | expect(component.dispatch).toHaveBeenCalledWith('input', rawValue.join('')) 29 | }) 30 | 31 | expect(component.dispatch).toHaveBeenCalledWith('input', '0123456789') 32 | expect(component.dispatch).toHaveBeenCalledTimes(10) 33 | }) 34 | 35 | it('built-in control charactor', () => { 36 | let component = createComponent({type: 'text'}) 37 | 38 | // input event be triggered only when content changes 39 | component.input(Keys.BLANK) 40 | expect(component.ks.rawValue).toEqual([]) 41 | expect(component.ks.cursorPos).toBe(0) 42 | expect(component.dispatch).not.toHaveBeenCalled() 43 | 44 | component.input(Keys.ESC) 45 | expect(component.ks.rawValue).toEqual([]) 46 | expect(component.ks.cursorPos).toBe(0) 47 | expect(component.dispatch).not.toHaveBeenCalled() 48 | 49 | component.input(Keys.ENTER) 50 | expect(component.ks.rawValue).toEqual([]) 51 | expect(component.ks.cursorPos).toBe(0) 52 | expect(component.dispatch).toHaveBeenCalledWith('enterpress') 53 | expect(component.dispatch).toHaveBeenCalledTimes(1) 54 | 55 | component.input(Keys.DOT) 56 | expect(component.ks.rawValue).toEqual(['.']) 57 | expect(component.ks.cursorPos).toBe(1) 58 | expect(component.dispatch).toHaveBeenCalledWith('input', '.') 59 | expect(component.dispatch).toHaveBeenCalledTimes(2) 60 | 61 | component.input(Keys.DEL) 62 | expect(component.ks.rawValue).toEqual([]) 63 | expect(component.ks.cursorPos).toBe(0) 64 | expect(component.dispatch).toHaveBeenCalledWith('input', '') 65 | expect(component.dispatch).toHaveBeenCalledTimes(3) 66 | 67 | component.input(Keys.DEL) 68 | expect(component.ks.rawValue).toEqual([]) 69 | expect(component.ks.cursorPos).toBe(0) 70 | expect(component.dispatch).toHaveBeenCalledWith('input', '') 71 | expect(component.dispatch).toHaveBeenCalledTimes(3) 72 | }) 73 | 74 | it('custom charactor', () => { 75 | const component = createComponent({type: 'text'}) 76 | 77 | component.input('0') 78 | expect(component.ks.rawValue).toEqual(['0']) 79 | expect(component.ks.cursorPos).toBe(1) 80 | expect(component.dispatch).toHaveBeenCalledWith('input', '0') 81 | expect(component.dispatch).toHaveBeenCalledTimes(1) 82 | 83 | component.input('X') 84 | expect(component.ks.rawValue).toEqual(['0', 'X']) 85 | expect(component.ks.cursorPos).toBe(2) 86 | expect(component.dispatch).toHaveBeenCalledWith('input', '0X') 87 | expect(component.dispatch).toHaveBeenCalledTimes(2) 88 | }) 89 | 90 | it('input number', () => { 91 | let component = createComponent({type: 'number'}) 92 | 93 | // leading zeros is legal, but is not octal 94 | component.input(Keys.ZERO) 95 | expect(component.ks.rawValue).toEqual(['0']) 96 | expect(component.ks.cursorPos).toBe(1) 97 | expect(component.dispatch).toHaveBeenCalledWith('input', 0) 98 | expect(component.dispatch).toHaveBeenCalledTimes(1) 99 | 100 | component.input(Keys.ONE) 101 | expect(component.ks.rawValue).toEqual(['0', '1']) 102 | expect(component.ks.cursorPos).toBe(2) 103 | expect(component.dispatch).toHaveBeenCalledWith('input', 1) 104 | expect(component.dispatch).toHaveBeenCalledTimes(2) 105 | 106 | component.input(Keys.TWO) 107 | expect(component.ks.rawValue).toEqual(['0', '1', '2']) 108 | expect(component.ks.cursorPos).toBe(3) 109 | expect(component.dispatch).toHaveBeenCalledWith('input', 12) 110 | expect(component.dispatch).toHaveBeenCalledTimes(3) 111 | 112 | component.input('X') 113 | expect(component.ks.rawValue).toEqual(['0', '1', '2']) 114 | expect(component.ks.cursorPos).toBe(3) 115 | expect(component.dispatch).toHaveBeenCalledWith('input', 12) 116 | expect(component.dispatch).toHaveBeenCalledTimes(3) 117 | }) 118 | 119 | it('input number with decimal point', () => { 120 | let component = createComponent({type: 'number'}) 121 | 122 | // double decimal point is a obvious mistake which should be blocked 123 | // leading decimal point is legal, so there is no need to padding zero 124 | component.input(Keys.DOT) 125 | expect(component.ks.rawValue).toEqual(['.']) 126 | expect(component.ks.cursorPos).toBe(1) 127 | expect(component.dispatch).toHaveBeenCalledTimes(1) 128 | 129 | component.input(Keys.ONE) 130 | expect(component.ks.rawValue).toEqual(['.', '1']) 131 | expect(component.ks.cursorPos).toBe(2) 132 | expect(component.dispatch).toHaveBeenCalledWith('input', 0.1) 133 | expect(component.dispatch).toHaveBeenCalledTimes(2) 134 | 135 | component.input(Keys.DOT) 136 | expect(component.ks.rawValue).toEqual(['.', '1']) 137 | expect(component.ks.cursorPos).toBe(2) 138 | expect(component.dispatch).toHaveBeenCalledTimes(2) 139 | }) 140 | 141 | it('input tel', () => { 142 | let component = createComponent({type: 'tel'}) 143 | 144 | component.input(Keys.DOT) 145 | expect(component.ks.rawValue).toEqual([]) 146 | expect(component.ks.cursorPos).toBe(0) 147 | expect(component.dispatch).not.toHaveBeenCalled() 148 | 149 | component.input('X') 150 | expect(component.ks.rawValue).toEqual([]) 151 | expect(component.ks.cursorPos).toBe(0) 152 | expect(component.dispatch).not.toHaveBeenCalled() 153 | 154 | component.input(Keys.ZERO) 155 | expect(component.ks.rawValue).toEqual(['0']) 156 | expect(component.ks.cursorPos).toBe(1) 157 | expect(component.dispatch).toHaveBeenCalledWith('input', '0') 158 | expect(component.dispatch).toHaveBeenCalledTimes(1) 159 | }) 160 | 161 | }) 162 | -------------------------------------------------------------------------------- /docs/README.cn.md: -------------------------------------------------------------------------------- 1 | # 数字键盘 2 | 3 | [![Build Status](https://travis-ci.org/viclm/numeric-keyboard.svg?branch=master)](https://travis-ci.org/viclm/numeric-keyboard) 4 | [![npm package](https://img.shields.io/npm/v/numeric-keyboard.svg)](https://www.npmjs.org/package/numeric-keyboard) 5 | 6 | 用于手机浏览器的虚拟的可自定义数字键盘,它包含一个可以调起虚拟自定义数字键盘的文本框,支持大部分的 HTML5 标准属性和光标操作。 7 | 同时,虚拟键盘本身可以单独和其他自定义输入界面一起使用,比如互联网金融场景常见的数字验证码输入方格。 8 | 9 | 数字键盘有多个版本:**原生 JavaScript**、**React**、**Angular** 和 **Vue**。 10 | 11 | > 对于 **React**、**Angular** and **Vue**,仅支持最新版本的实现。 12 | 13 | ![snapshot](https://raw.githubusercontent.com/viclm/numeric-keyboard/master/docs/demo.gif) 14 | 15 | ## 目录 16 | 17 | - [安装](#安装) 18 | - [使用](#使用) 19 | - [键盘](#键盘) 20 | - [贡献](#贡献) 21 | - [许可证](#许可证) 22 | 23 | ## 安装 24 | 25 | 通过 **Yarn** 安装 26 | ```shell 27 | yarn add numeric-keyboard 28 | ``` 29 | 30 | 配置 **Webpack** 使用恰当的版本 31 | ```javascript 32 | resolve: { 33 | alias: { 34 | // 以 **Vue** 为例 35 | 'numeric-keyboard$': 'numeric-keyboard/dist/numeric_keyboard.vue.js' 36 | } 37 | }, 38 | ``` 39 | 40 | 41 | ## 使用 42 | 43 | #### Vanilla JavaScript 44 | ```javascript 45 | import { NumericInput } from 'numeric-keyboard' 46 | new NumericInput({ 47 | type: 'number', 48 | placeholder: 'touch to input', 49 | onInput(value) { 50 | ... 51 | } 52 | }).mount('.input') 53 | ``` 54 | 55 | #### React 56 | ```jsx 57 | import { NumericInput } from 'numeric-keyboard' 58 | class App extends React.Component { 59 | input(val) { 60 | ... 61 | }, 62 | render() { 63 | return
64 | 65 | 66 |
67 | } 68 | } 69 | ``` 70 | 71 | #### Angular 72 | ```typescript 73 | import { Component } from '@angular/core'; 74 | @Component({ 75 | selector: 'app-root', 76 | template: ` 77 |
78 | 79 | 80 |
81 | `, 82 | }) 83 | export class AppComponent { 84 | public amount: number | string = '' 85 | } 86 | ``` 87 | 88 | #### Vue 89 | ```vue 90 | 96 | 97 | 110 | 111 | ``` 112 | 113 | ### 选项/属性 114 | 115 | 虚拟文本框用以替换原生的输入框,所以它支持大部分标准属性,详情可参看 HTML 标准文档。 116 | 117 | ```javascript 118 | // 只支持两种输入类型:number 和 tel,默认唤起对应布局的键盘 119 | type: { 120 | type: String, 121 | default: 'number' 122 | }, 123 | autofocus: { 124 | type: Boolean, 125 | default: false 126 | }, 127 | disabled: { 128 | type: Boolean, 129 | default: false 130 | }, 131 | maxlength: { 132 | type: Number 133 | }, 134 | name: { 135 | type: String 136 | }, 137 | placeholder: { 138 | type: String 139 | }, 140 | readonly: { 141 | type: Boolean, 142 | default: false 143 | }, 144 | value: { 145 | type: [String, Number] 146 | }, 147 | // 使用一个正则表达式或者函数限制输入内容 148 | format: { 149 | type: [String, Function] 150 | }, 151 | // 自定义键盘布局 152 | layout: { 153 | type: [String, Array], 154 | default: 'number' 155 | }, 156 | // 自定义键盘确认键文案,图标可使用 Iconfont 157 | entertext: { 158 | type: String, 159 | default: 'enter' 160 | } 161 | ``` 162 | 163 | ### 回调函数/事件 164 | 165 | #### `input` 166 | 当输入发生改变时会触发 `input` 事件,和原生输入框元素触发的事件不同,响应函数的第一个参数并不是事件对象,而是输入框内文本的值。当使用原生 **JavaScript** 版本时,使用 `onInput()` 回调函数代替 `input` 事件。 167 | 168 | #### `enterpress` 169 | 当按下键盘确认键时会触发 `enterpress` 事件。 170 | 171 | 172 | ## 键盘 173 | 174 | 虚拟数字键盘本身是一个独立的可插拔组件,可自定义布局,通常它需要和一个输入界面一起使用。 175 | 176 | ### 使用 177 | 178 | #### Vanilla JavaScript 179 | ```javascript 180 | import { NumericKeyboard } from 'numeric-keyboard' 181 | new NumericKeyboard('.keyboard', { 182 | layout: 'tel', 183 | onPress(key) { 184 | ... 185 | } 186 | }) 187 | ``` 188 | 189 | #### React 190 | ```jsx 191 | import { NumericKeyboard } from 'numeric-keyboard' 192 | class App extends React.Component { 193 | press(key) { 194 | ... 195 | } 196 | render() { 197 | return
198 | 199 |
200 | } 201 | } 202 | ``` 203 | 204 | #### Angular 205 | ```typescript 206 | import { Component } from '@angular/core'; 207 | @Component({ 208 | selector: 'app-root', 209 | template: ` 210 |
211 | 212 |
213 | `, 214 | }) 215 | export class AppComponent { 216 | press(key) { 217 | ... 218 | } 219 | } 220 | ``` 221 | 222 | #### Vue 223 | ```vue 224 | 229 | 230 | 243 | ``` 244 | 245 | ### 选项/属性 246 | 247 | ```javascript 248 | // 修改键盘的布局 249 | layout: { 250 | type: [String, Array], 251 | default: 'number' 252 | }, 253 | // 自定义确认键文案,图标可使用 Iconfont 254 | entertext: { 255 | type: String, 256 | default: 'enter' 257 | } 258 | ``` 259 | 260 | #### `layout` 261 | 有两种内置的布局: **number** 和 **tel** 对应两种标准输入类型。 262 | 你可以自定义任何布局样式,数字键盘使用一个二维数组构建了一种表格布局,支持单元格合并。 263 | 264 | ##### number 布局 265 | ![number layout](https://raw.githubusercontent.com/viclm/numeric-keyboard/master/docs/snapshot_number.png) 266 | 267 | ##### tel 布局 268 | ![tel layout](https://raw.githubusercontent.com/viclm/numeric-keyboard/master/docs/snapshot_tel.png) 269 | 270 | ##### 自定义布局 271 | ```javascript 272 | // 内置 number 布局代码示例 273 | import { keys } from 'numeric-keyboard' 274 | [ 275 | [ 276 | { 277 | key: keys.ONE 278 | }, 279 | { 280 | key: keys.TWO 281 | }, 282 | { 283 | key: keys.THREE 284 | }, 285 | { 286 | key: keys.DEL, 287 | rowspan: 2, 288 | }, 289 | ], 290 | [ 291 | { 292 | key: keys.FOUR 293 | }, 294 | { 295 | key: keys.FIVE 296 | }, 297 | { 298 | key: keys.SIX 299 | }, 300 | ], 301 | [ 302 | { 303 | key: keys.SEVEN 304 | }, 305 | { 306 | key: keys.EIGHT 307 | }, 308 | { 309 | key: keys.NINE 310 | }, 311 | { 312 | key: keys.ENTER, 313 | rowspan: 2, 314 | }, 315 | ], 316 | [ 317 | { 318 | key: keys.DOT 319 | }, 320 | { 321 | key: keys.ZERO 322 | }, 323 | { 324 | key: keys.ESC 325 | }, 326 | ], 327 | ] 328 | ``` 329 | 330 | ### 回调函数/事件 331 | 332 | #### `press` 333 | 点击键盘按键时会触发 `press` 事件,响应函数的参数是刚刚点击过的按键。当使用原生 **JavaScript** 版本时,使用 `onPress()` 回调函数代替 `press` 事件。 334 | 335 | #### `enterpress` 336 | 当按下键盘确认键时会触发 `enterpress` 事件。 337 | 338 | 339 | ## 贡献 340 | 欢迎一起参与开发,规范正在制定中... 341 | 342 | 343 | ## 许可证 344 | Licensed under the MIT license. 345 | -------------------------------------------------------------------------------- /lib/input.js: -------------------------------------------------------------------------------- 1 | import * as Keys from './keys.js' 2 | import { animate } from './utils/animate.js' 3 | 4 | const RNumber = /^\d*(?:\.\d*)?$/ 5 | const RTel = /^\d*$/ 6 | 7 | const KeyboardCenter = (function () { 8 | 9 | let activeInput 10 | 11 | return { 12 | register(input) { 13 | this.unregister() 14 | activeInput = input 15 | document.addEventListener('touchend', this.unregister, false) 16 | }, 17 | unregister(e) { 18 | if (!activeInput) { 19 | return 20 | } 21 | if (e && (activeInput.ks.inputElement.contains(e.target) || activeInput.ks.keyboardElement.contains(e.target))) { 22 | return 23 | } 24 | activeInput.closeKeyboard() 25 | activeInput = null 26 | document.removeEventListener('touchend', this.unregister, false) 27 | } 28 | } 29 | 30 | })() 31 | 32 | export const Options = { 33 | type: 'number', 34 | value: '', 35 | autofocus: false, 36 | disabled: false, 37 | readonly: false, 38 | maxlength: Infinity, 39 | name: '', 40 | placeholder: '', 41 | format: '^', 42 | layout: 'number', 43 | entertext: 'enter' 44 | } 45 | 46 | export const Mixins = { 47 | 48 | init(options) { 49 | let formatFn = options.format 50 | if (typeof formatFn === 'string') { 51 | formatFn = (rformat => (val => rformat.test(val)))(new RegExp(options.format)) 52 | } 53 | 54 | const value = options.value 55 | const rawValue = value.toString().split('') 56 | const cursorPos = rawValue.length 57 | 58 | this.kp = options 59 | this.ks = { 60 | formatFn, 61 | value, 62 | rawValue, 63 | cursorPos, 64 | cursorColor: null, 65 | cursorActive: false, 66 | keyboard: null, 67 | inputElement: null, 68 | keyboardElement: null 69 | } 70 | }, 71 | 72 | destroy() { 73 | KeyboardCenter.unregister() 74 | }, 75 | 76 | set(key, value) { 77 | this.ks[key] = value 78 | }, 79 | 80 | onMounted(el) { 81 | this.set('inputElement', el) 82 | this.set('cursorColor', window.getComputedStyle(el).getPropertyValue('color')) 83 | 84 | if (this.kp.autofocus && !this.kp.readonly && !this.kp.disabled) { 85 | setTimeout(() => this.openKeyboard(), 500) 86 | } 87 | }, 88 | 89 | onUpdated() { 90 | this.moveCursor() 91 | }, 92 | 93 | onFocus(e) { 94 | e.stopPropagation() 95 | this.openKeyboard() 96 | const cursorPos = +e.target.dataset.index 97 | this.set('cursorPos', isNaN(cursorPos) ? this.ks.rawValue.length : cursorPos) 98 | }, 99 | 100 | input(key) { 101 | const { type, maxlength } = this.kp 102 | const { rawValue, cursorPos, formatFn } = this.ks 103 | 104 | const input = key => { 105 | const isAdd = typeof key !== 'undefined' 106 | const newRawValue = rawValue.slice() 107 | if (isAdd) { 108 | newRawValue.splice(cursorPos, 0, key) 109 | } 110 | else { 111 | newRawValue.splice(cursorPos - 1, 1) 112 | } 113 | 114 | let newValue = newRawValue.join('') 115 | 116 | if (formatFn(newValue)) { 117 | if (type === 'number') { 118 | if (!RNumber.test(newValue)) { return } 119 | newValue = parseFloat(newValue, 10) 120 | if (isNaN(newValue)) { 121 | newValue = '' 122 | } 123 | } 124 | else if (newValue.length > maxlength || type === 'tel' && !RTel.test(newValue)) { return } 125 | 126 | this.set('value', newValue) 127 | this.set('rawValue', newRawValue) 128 | this.set('cursorPos', isAdd ? cursorPos + 1 : cursorPos - 1) 129 | this.dispatch('input', newValue) 130 | } 131 | } 132 | 133 | switch (key) { 134 | case Keys.BLANK: 135 | break 136 | case Keys.ESC: 137 | this.closeKeyboard() 138 | break 139 | case Keys.ENTER: 140 | this.closeKeyboard() 141 | this.dispatch('enterpress') 142 | break 143 | case Keys.DEL: 144 | if (cursorPos > 0) { 145 | input() 146 | } 147 | break 148 | case Keys.DOT : 149 | case Keys.ZERO : 150 | case Keys.ONE : 151 | case Keys.TWO : 152 | case Keys.THREE : 153 | case Keys.FOUR : 154 | case Keys.FIVE : 155 | case Keys.SIX : 156 | case Keys.SEVEN : 157 | case Keys.EIGHT : 158 | case Keys.NINE : 159 | default: 160 | input(key) 161 | break 162 | } 163 | }, 164 | 165 | moveCursor() { 166 | if (!this.ks.cursorActive) { 167 | return 168 | } 169 | 170 | const elCursor = this.ks.inputElement.querySelector('.numeric-input-cursor') 171 | const elText = this.ks.inputElement.querySelector('.numeric-input-text') 172 | const elCharactor = elText.querySelector(`span:nth-child(${this.ks.cursorPos})`) 173 | 174 | if (!elCharactor) { 175 | elCursor.style.transform = 'translateX(0)' 176 | elText.style.transform = 'translateX(0)' 177 | return 178 | } 179 | 180 | const cursorOffset = elCharactor.offsetLeft + elCharactor.offsetWidth 181 | const maxVisibleWidth = elText.parentNode.offsetWidth 182 | elCursor.style.transform = `translateX(${Math.min(maxVisibleWidth - 1, cursorOffset)}px)` 183 | elText.style.transform = `translateX(${Math.min(0, maxVisibleWidth - cursorOffset)}px)` 184 | }, 185 | 186 | openKeyboard() { 187 | if (this.ks.keyboard) { return } 188 | 189 | const elContainer = document.createElement('div') 190 | const elShadow = document.createElement('div') 191 | const elKeyboard = document.createElement('div') 192 | elContainer.className = 'numeric-keyboard-actionsheet' 193 | elContainer.appendChild(elShadow) 194 | elContainer.appendChild(elKeyboard) 195 | document.body.appendChild(elContainer) 196 | 197 | this.createKeyboard( 198 | elKeyboard, 199 | { 200 | layout: this.kp.layout || this.kp.type, 201 | entertext: this.kp.entertext 202 | }, 203 | { 204 | press: this.input.bind(this) 205 | }, 206 | keyboard => this.set('keyboard', keyboard) 207 | ) 208 | 209 | animate((timestamp, frame, frames) => { 210 | elKeyboard.style.transform = `translateY(${(frames - frame) / frames * 100}%)` 211 | }, () => {}, 10) 212 | 213 | this.set('keyboardElement', elKeyboard) 214 | this.set('cursorActive', true) 215 | this.set('cursorPos', this.ks.rawValue.length) 216 | 217 | this.dispatch('focus') 218 | KeyboardCenter.register(this) 219 | }, 220 | 221 | closeKeyboard() { 222 | if (!this.ks.keyboard) { return } 223 | 224 | const keyboard = this.ks.keyboard 225 | const elKeyboard = this.ks.keyboardElement 226 | 227 | animate((timestamp, frame, frames) => { 228 | elKeyboard.style.transform = `translateY(${frame / frames * 100}%)` 229 | }, () => { 230 | setTimeout(() => { 231 | this.destroyKeyboard(elKeyboard, keyboard) 232 | document.body.removeChild(elKeyboard.parentNode) 233 | }, 300) 234 | }, 10) 235 | 236 | this.set('keyboard', null) 237 | this.set('keyboardElement', null) 238 | this.set('cursorActive', false) 239 | this.set('cursorPos', 0) 240 | 241 | this.dispatch('blur') 242 | KeyboardCenter.unregister() 243 | }, 244 | 245 | createKeyboard(/* el, options, events, callback */) { 246 | throw new Error('createKeyboard method must be overrided!') 247 | }, 248 | 249 | destroyKeyboard(/* el, keyboard */) { 250 | throw new Error('destroyKeyboard method must be overrided!') 251 | }, 252 | 253 | dispatch(/* event, payload */) { 254 | throw new Error('dispatch method must be overrided!') 255 | } 256 | 257 | } 258 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Numeric Keyboard 2 | 3 | [![Build Status](https://travis-ci.org/viclm/numeric-keyboard.svg?branch=master)](https://travis-ci.org/viclm/numeric-keyboard) 4 | [![npm package](https://img.shields.io/npm/v/numeric-keyboard.svg)](https://www.npmjs.org/package/numeric-keyboard) 5 | 6 | A custom virtual numeric keyboard works in mobile browsers. It contains a virtual input box which would invoke the numeric keyboard instead of system keyboard, the virtual input box supports many html5 standard properties and also has a nice cursor to make it behaves like native input element as much as possible. 7 | Besides, the numeric keyboard is a pluggable component can be used together with other input interfaces. 8 | 9 | The numeric keyboard is created respectively for **Vanilla JavaScript**, **React**, **Angular** and **Vue**. 10 | 11 | > for **React**, **Angular** and **Vue**, only the latest version is supported. 12 | 13 | :cn: [中文说明](https://github.com/viclm/numeric-keyboard/blob/master/docs/README.cn.md) :cn: :cn: :cn: :cn: 14 | 15 | ![snapshot](https://raw.githubusercontent.com/viclm/numeric-keyboard/master/docs/demo.gif) 16 | 17 | ## Table of contents 18 | 19 | - [Install](#install) 20 | - [Usage](#usage) 21 | - [Keyboard](#keyboard) 22 | - [Contributing](#contributing) 23 | - [License](#license) 24 | 25 | ## Install 26 | 27 | You can install it via **Yarn** 28 | ```shell 29 | yarn add numeric-keyboard 30 | ``` 31 | 32 | Config **Webpack** to use the right version 33 | ```javascript 34 | resolve: { 35 | alias: { 36 | // use Vue component for example 37 | 'numeric-keyboard$': 'numeric-keyboard/dist/numeric_keyboard.vue.js' 38 | } 39 | }, 40 | ``` 41 | 42 | 43 | ## Usage 44 | 45 | #### Vanilla JavaScript 46 | ```javascript 47 | import { NumericInput } from 'numeric-keyboard' 48 | new NumericInput({ 49 | type: 'number', 50 | placeholder: 'touch to input', 51 | onInput(value) { 52 | ... 53 | } 54 | }).mount('.input') 55 | ``` 56 | 57 | #### React 58 | ```jsx 59 | import { NumericInput } from 'numeric-keyboard' 60 | class App extends React.Component { 61 | input(val) { 62 | ... 63 | }, 64 | render() { 65 | return
66 | 67 | 68 |
69 | } 70 | } 71 | ``` 72 | 73 | #### Angular 74 | ```typescript 75 | import { Component } from '@angular/core'; 76 | @Component({ 77 | selector: 'app-root', 78 | template: ` 79 |
80 | 81 | 82 |
83 | `, 84 | }) 85 | export class AppComponent { 86 | public amount: number | string = '' 87 | } 88 | ``` 89 | 90 | #### Vue 91 | ```vue 92 | 98 | 99 | 112 | 113 | ``` 114 | 115 | ### Options/Props 116 | 117 | As a substitute for native input element, the input box supports most of the standard attributes, you can refer the HTML spec for details. 118 | 119 | ```javascript 120 | // There are only two types: number and tel, the corresponding layout of keyboard would be invoked by default. 121 | type: { 122 | type:String, 123 | default: 'number' 124 | }, 125 | autofocus: { 126 | type: Boolean, 127 | default: false 128 | }, 129 | disabled: { 130 | type: Boolean, 131 | default: false 132 | }, 133 | maxlength: { 134 | type: Number 135 | }, 136 | name: { 137 | type: String 138 | }, 139 | placeholder: { 140 | type: String 141 | }, 142 | readonly: { 143 | type: Boolean, 144 | default: false 145 | }, 146 | value: { 147 | type: [String, Number] 148 | }, 149 | // Passs a regexp string or function to limit the input. 150 | format: { 151 | type: [String, Function] 152 | }, 153 | // change the layout of keyboard 154 | layout: { 155 | type: [String, Array], 156 | default: 'number' 157 | }, 158 | // change the label of keyboard enter key, use iconfont for icon. 159 | entertext: { 160 | type: String, 161 | default: 'enter' 162 | } 163 | ``` 164 | 165 | ### Callback/Events 166 | 167 | #### `input` 168 | The `input` event is emitted when the value of input changes. The first argument for the callback is the value of the input box rather than an event object from a native input element. A `onInput()` callback is used in vanilla javascript version. 169 | 170 | #### `enterpress` 171 | The `enterpress` event is emitted when the enter key of keyboard is pressed. 172 | 173 | 174 | ## Keyboard 175 | 176 | The keyboard is a pluggable component which supports custom layout. In order to be able to work properly in a real scene, it usually needs to match an output interface. 177 | 178 | ### Usage 179 | 180 | #### Vanilla JavaScript 181 | ```javascript 182 | import { NumericKeyboard } from 'numeric-keyboard' 183 | new NumericKeyboard('.keyboard', { 184 | layout: 'tel', 185 | onPress(key) { 186 | ... 187 | } 188 | }) 189 | ``` 190 | 191 | #### React 192 | ```jsx 193 | import { NumericKeyboard } from 'numeric-keyboard' 194 | class App extends React.Component { 195 | press(key) { 196 | ... 197 | } 198 | render() { 199 | return
200 | 201 |
202 | } 203 | } 204 | ``` 205 | 206 | #### Angular 207 | ```typescript 208 | import { Component } from '@angular/core'; 209 | @Component({ 210 | selector: 'app-root', 211 | template: ` 212 |
213 | 214 |
215 | `, 216 | }) 217 | export class AppComponent { 218 | press(key) { 219 | ... 220 | } 221 | } 222 | ``` 223 | 224 | #### Vue 225 | ```vue 226 | 231 | 232 | 245 | ``` 246 | 247 | ### Options/Props 248 | 249 | ```javascript 250 | // change the layout of keyboard 251 | layout: { 252 | type: [String, Array], 253 | default: 'number' 254 | }, 255 | // change the label of keyboard enter key, use iconfont for icon. 256 | entertext: { 257 | type: String, 258 | default: 'enter' 259 | } 260 | ``` 261 | 262 | #### `layout` 263 | There are two built-in layouts called **number** and **tel** which can be used as a replacement of system keyboard. 264 | You can still rearrange all the keys to create your own layout. The layout object is a two-dimension array which constructs a table layout, you can make table-specific operations like merging cells. 265 | 266 | ##### number layout 267 | ![number layout](https://raw.githubusercontent.com/viclm/numeric-keyboard/master/docs/snapshot_number.png) 268 | 269 | ##### tel layout 270 | ![tel layout](https://raw.githubusercontent.com/viclm/numeric-keyboard/master/docs/snapshot_tel.png) 271 | 272 | ##### custom layout 273 | ```javascript 274 | // code sample for the build-in number layout 275 | import { keys } from 'numeric-keyboard' 276 | [ 277 | [ 278 | { 279 | key: keys.ONE 280 | }, 281 | { 282 | key: keys.TWO 283 | }, 284 | { 285 | key: keys.THREE 286 | }, 287 | { 288 | key: keys.DEL, 289 | rowspan: 2, 290 | }, 291 | ], 292 | [ 293 | { 294 | key: keys.FOUR 295 | }, 296 | { 297 | key: keys.FIVE 298 | }, 299 | { 300 | key: keys.SIX 301 | }, 302 | ], 303 | [ 304 | { 305 | key: keys.SEVEN 306 | }, 307 | { 308 | key: keys.EIGHT 309 | }, 310 | { 311 | key: keys.NINE 312 | }, 313 | { 314 | key: keys.ENTER, 315 | rowspan: 2, 316 | }, 317 | ], 318 | [ 319 | { 320 | key: keys.DOT 321 | }, 322 | { 323 | key: keys.ZERO 324 | }, 325 | { 326 | key: keys.ESC 327 | }, 328 | ], 329 | ] 330 | ``` 331 | 332 | ### Callbacks/Events 333 | 334 | #### `press` 335 | the `press` event is emitted with a key code when the key is pressed. The argument for the callback is the key just pressed. A `onPress()` callback is used in vanilla javascript version. 336 | 337 | #### `enterpress` 338 | The `enterpress` event is emitted when the enter key of keyboard is pressed. 339 | 340 | 341 | ## Contributing 342 | Welcome to contributing, the guidelines are being drafted. 343 | 344 | 345 | ## License 346 | Licensed under the MIT license. 347 | -------------------------------------------------------------------------------- /lib/utils/vdom.js: -------------------------------------------------------------------------------- 1 | import { toString } from './string.js' 2 | import { isPlainObject, isEmptyObject } from './type.js' 3 | 4 | const REventProperty = /^on(?=[A-Z])/ 5 | 6 | const HTMLAttrFix = { 7 | className: 'class', 8 | htmlFor: 'for' 9 | } 10 | 11 | const PatchType = { 12 | INSERT: 'insert', 13 | PROPS: 'props', 14 | REMOVE: 'remove', 15 | REORDER: 'reorder', 16 | REPLACE: 'replace' 17 | } 18 | 19 | class VText { 20 | constructor(text) { 21 | this.text = text 22 | } 23 | 24 | destroy() { 25 | } 26 | 27 | key(index) { 28 | this.key = this.text || index 29 | } 30 | 31 | render() { 32 | return document.createTextNode(this.text) 33 | } 34 | 35 | update() { 36 | } 37 | 38 | transition() { 39 | } 40 | } 41 | 42 | class VNode { 43 | constructor(tagName, props, ...children) { 44 | this.tagName = tagName 45 | this.props = props || {} 46 | this.children = this.resolveChildren(children) 47 | 48 | this._element = null 49 | this._events = {} 50 | } 51 | 52 | destroy() { 53 | for (let event in this._events) { 54 | let handlers = this._events[event] 55 | for (let i = 0 ; i < handlers.length ; i++) { 56 | this._element.removeEventListener(event, handlers[i]) 57 | } 58 | delete this._events[event] 59 | } 60 | } 61 | 62 | key(index) { 63 | this.key = this.props['key'] || index 64 | } 65 | 66 | resolveProps(props) { 67 | let attributes = {} 68 | let styles = {} 69 | let events = {} 70 | for (let name in props) { 71 | if (REventProperty.test(name)) { 72 | events[name.slice(2).toLowerCase()] = props[name] 73 | } 74 | else if (name === 'style') { 75 | styles = props[name] 76 | } 77 | else { 78 | attributes[HTMLAttrFix[name] || name] = props[name] 79 | } 80 | } 81 | return { attributes, styles, events } 82 | } 83 | 84 | resolveChildren(children) { 85 | const resolvedChildren = [] 86 | for (let i = 0 ; i < children.length ; i++) { 87 | let child = children[i] 88 | if (!child) { continue } 89 | if (Array.isArray(child)) { 90 | child.unshift(1) 91 | child.unshift(i) 92 | Array.prototype.splice.apply(children, child) 93 | i-- 94 | } 95 | else { 96 | if (Object(child) !== child) { 97 | child = new VText(child) 98 | } 99 | child.key(i) 100 | resolvedChildren.push(child) 101 | } 102 | } 103 | return resolvedChildren 104 | } 105 | 106 | addEvent(event, handler) { 107 | const handlers = this._events[event] || [] 108 | if (handler == null) { 109 | for (let i = 0 ; i < handlers.length ; i++) { 110 | this._element.removeEventListener(event, handlers[i]) 111 | } 112 | delete this._events[event] 113 | } 114 | else { 115 | this._element.addEventListener(event, handler, false) 116 | this._events[event] = handlers.concat(handler) 117 | } 118 | } 119 | 120 | render() { 121 | const { attributes, styles, events } = this.resolveProps(this.props) 122 | const element = this._element = document.createElement(this.tagName) 123 | for (let name in attributes) { 124 | attributes[name] != null && element.setAttribute(name, toString(attributes[name])) 125 | } 126 | for (let name in styles) { 127 | element.style[name] = styles[name] 128 | } 129 | for (let name in events) { 130 | this.addEvent(name, events[name]) 131 | } 132 | for (let i = 0 ; i < this.children.length ; i++) { 133 | element.appendChild(this.children[i].render()) 134 | } 135 | return element 136 | } 137 | 138 | update(props) { 139 | const { attributes, styles, events } = this.resolveProps(props) 140 | for (let name in attributes) { 141 | let value = attributes[name] 142 | if (value == null) { 143 | this._element.removeAttribute(name) 144 | } 145 | else { 146 | this._element.setAttribute(name, toString(value)) 147 | } 148 | } 149 | for (let name in styles) { 150 | this._element.style[name] = styles[name] 151 | } 152 | for (let name in events) { 153 | this.addEvent(name, events[name]) 154 | } 155 | } 156 | 157 | transition(vnode) { 158 | vnode._element = this._element 159 | } 160 | 161 | } 162 | 163 | class VComponent { 164 | constructor(component, props = {}) { 165 | this.component = component 166 | this.props = props 167 | 168 | this._component = null 169 | } 170 | 171 | destroy() { 172 | this._component.destroy() 173 | } 174 | 175 | key(index) { 176 | this.key = this.props['key'] || index 177 | } 178 | 179 | render() { 180 | const component = this._component = new this.component(this.props) 181 | component.mount() 182 | return component._element 183 | } 184 | 185 | update(props) { 186 | this._component.setProps(props) 187 | } 188 | 189 | transition(vcomponent) { 190 | vcomponent._component = this._component 191 | } 192 | } 193 | 194 | class Diff { 195 | 196 | constructor(a, b) { 197 | this.index = -1 198 | this.patches = {} 199 | this.walk(a, b) 200 | } 201 | 202 | walk(a, b) { 203 | if (!a || !b) { return } 204 | 205 | const patch = [], index = ++this.index 206 | 207 | try { 208 | 209 | if (a.constructor !== b.constructor) { 210 | patch.push({ type: PatchType.REPLACE, oldNode: a, newNode: b }) 211 | return 212 | } 213 | 214 | if (a.constructor === VText) { 215 | if (a.text !== b.text) { 216 | patch.push({ type: PatchType.REPLACE, oldNode: a, newNode: b }) 217 | } 218 | return 219 | } 220 | 221 | if (a.constructor === VNode) { 222 | if (a.tagName !== b.tagName) { 223 | patch.push({ type: PatchType.REPLACE, oldNode: a, newNode: b }) 224 | return 225 | } 226 | 227 | const diffProps = this.diffProps(a.props, b.props) 228 | if (diffProps) { 229 | patch.push({ type: PatchType.PROPS, props: diffProps, oldNode: a, newNode: b }) 230 | } 231 | 232 | const diffChildren = this.diffChildren(a.children, b.children) 233 | if (diffChildren.move.length) { 234 | patch.push({ type: PatchType.REORDER, move: diffChildren.move }) 235 | } 236 | 237 | for (let i = 0 ; i < b.children.length ; i++) { 238 | this.walk(diffChildren.children[i], b.children[i]) 239 | } 240 | 241 | return 242 | } 243 | 244 | if (a.constructor === VComponent) { 245 | if (a.component !== b.component) { 246 | patch.push({ type: PatchType.REPLACE, oldNode: a, newNode: b }) 247 | return 248 | } 249 | 250 | const diffProps = this.diffProps(a.props, b.props) 251 | if (diffProps) { 252 | patch.push({type: PatchType.PROPS, props: diffProps, oldNode: a, newNode: b}) 253 | } 254 | } 255 | 256 | } 257 | catch (e) { throw e } 258 | finally { 259 | if (patch.length) { this.patches[index] = patch } 260 | } 261 | 262 | } 263 | 264 | diffProps(oldProps, newProps) { 265 | const diffProps = {} 266 | 267 | for (let name in oldProps) { 268 | let oldValue = oldProps[name] 269 | let newValue = newProps[name] 270 | 271 | if (!(name in newProps)) { 272 | diffProps[name] = null 273 | } 274 | else if (isPlainObject(oldValue) && isPlainObject(newValue)) { 275 | const dp = this.diffProps(oldValue, newValue) 276 | if (dp) { 277 | diffProps[name] = newValue 278 | } 279 | } 280 | else if (typeof oldValue === 'function' && typeof newValue === 'function') { 281 | if (oldValue !== newValue && oldValue.toString() !== newValue.toString()) { 282 | diffProps[name] = newValue 283 | } 284 | } 285 | else if (oldValue !== newValue) { 286 | diffProps[name] = newValue 287 | } 288 | } 289 | 290 | for (let name in newProps) { 291 | if (!(name in oldProps)) { 292 | diffProps[name] = newProps[name] 293 | } 294 | } 295 | 296 | return !isEmptyObject(diffProps) && diffProps 297 | } 298 | 299 | diffChildren(oldChildren, newChildren) { 300 | function getIndex(list) { 301 | const hash = {} 302 | for (let i = 0 ; i < list.length ; i++) { 303 | hash[list[i].key] = i 304 | } 305 | return hash 306 | } 307 | const oldIndex = getIndex(oldChildren) 308 | const newIndex = getIndex(newChildren) 309 | 310 | const transChildren = [], children = [], move = [] 311 | 312 | for (let i = 0 ; i < oldChildren.length ; i++) { 313 | let node = oldChildren[i] 314 | if (newIndex[node.key] > -1) { 315 | transChildren.push(newChildren[newIndex[node.key]]) 316 | } 317 | else { 318 | move.push({ type: PatchType.REMOVE, node, index: i }) 319 | } 320 | } 321 | 322 | let i = 0, j = 0 323 | 324 | for (; i < newChildren.length ; i++) { 325 | let node = newChildren[i] 326 | if (transChildren[j] && transChildren[j].key === node.key) { 327 | children[i] = oldChildren[oldIndex[node.key]] 328 | j++ 329 | } 330 | else { 331 | move.push({ type: PatchType.INSERT, node, index: i }) 332 | } 333 | } 334 | 335 | while (transChildren[j]) { 336 | move.push({ type: PatchType.REMOVE, node: transChildren[j], index: i }) 337 | j++ 338 | } 339 | 340 | return { move, children } 341 | } 342 | } 343 | 344 | class Patch { 345 | constructor(node, patches) { 346 | this.root = node 347 | this.patches = patches 348 | this.patchesRemaining = Object.keys(patches).length 349 | this.index = -1 350 | this.walk(node) 351 | } 352 | 353 | walk(node) { 354 | var index = ++this.index 355 | var patch = this.patches[index] 356 | if (patch) { 357 | this.applyPatch(node, patch) 358 | this.patchesRemaining-- 359 | } 360 | 361 | if (this.patchesRemaining > 0 && (this.root === node || node.nodeType === 1 && !node.__component)) { 362 | const childNodes = node.childNodes 363 | for (let i = 0 ; i < childNodes.length ; i++) { 364 | if (this.walk(childNodes[i])) { break } 365 | } 366 | } 367 | 368 | return this.patchesRemaining === 0 369 | } 370 | 371 | applyPatch(node, patches) { 372 | for (let i = 0 ; i < patches.length ; i++) { 373 | let patch = patches[i] 374 | switch (patch.type) { 375 | case PatchType.PROPS: 376 | this.patchProps(node, patch) 377 | break 378 | case PatchType.REPLACE: 379 | this.patchReplace(node, patch) 380 | break 381 | case PatchType.REORDER: 382 | this.patchReorder(node, patch) 383 | break 384 | } 385 | } 386 | } 387 | 388 | patchProps(node, patch) { 389 | patch.oldNode.transition(patch.newNode) 390 | patch.oldNode.update(patch.props) 391 | } 392 | 393 | patchReplace(node, patch) { 394 | patch.oldNode.destroy() 395 | node.parentNode.replaceChild(patch.newNode.render(), node) 396 | } 397 | 398 | patchReorder(node, patch) { 399 | const childNodes = node.childNodes 400 | const move = patch.move 401 | const domActions = [] 402 | 403 | for (let i = 0 ; i < move.length ; i++) { 404 | let patch = move[i] 405 | // if (patch.type === PatchType.REMOVE) { 406 | // patch.node.destroy() 407 | // domActions.push({ method: 'removeChild', args: [childNodes[patch.index]] }) 408 | // } 409 | // else if (patch.type === PatchType.INSERT) { 410 | // domActions.push({ method: 'insertBefore', args: [patch.node.render(), childNodes[patch.index]] }) 411 | // } 412 | if (patch.type === PatchType.REMOVE) { 413 | patch.node.destroy() 414 | node.removeChild(childNodes[patch.index]) 415 | } 416 | else if (patch.type === PatchType.INSERT) { 417 | node.insertBefore(patch.node.render(), node.childNodes[patch.index]) 418 | } 419 | } 420 | 421 | for (let i = 0 ; i < domActions.length ; i++) { 422 | node[domActions[i].method].apply(node, domActions[i].args) 423 | } 424 | } 425 | } 426 | 427 | 428 | function createElement(type, props, ...children) { 429 | if (typeof type === 'string') { 430 | return new VNode(type, props, ...children) 431 | } 432 | else if (Object.getPrototypeOf(type) === Component) { 433 | return new VComponent(type, props) 434 | } 435 | else { 436 | return new VText(type) 437 | } 438 | } 439 | 440 | function diffAndPatch(element, oldTree, newTree) { 441 | const patches = new Diff(oldTree, newTree).patches 442 | new Patch(element, patches) 443 | } 444 | 445 | class Component { 446 | constructor(props) { 447 | this.props = Object.assign({}, this.constructor.defaultProps, props) 448 | this.state = {} 449 | 450 | this._events = {} 451 | this._vtree = null 452 | this._element = null 453 | this._renderTimer = null 454 | } 455 | 456 | destroy() { 457 | } 458 | 459 | mount(selector) { 460 | function renderDOM(vtree) { 461 | const element = vtree.render() 462 | if (vtree.children) { 463 | for (let i = 0 ; i < vtree.children.length ; i++) { 464 | renderDOM(vtree.children[i]) 465 | } 466 | } 467 | return element 468 | } 469 | 470 | this._vtree = this.render() 471 | this._element = renderDOM(this._vtree) 472 | this._element.component = 'component' 473 | 474 | if (selector) { 475 | const element = document.querySelector(selector) 476 | element.parentNode.replaceChild(this._element, element) 477 | } 478 | 479 | this.mounted(this._element) 480 | } 481 | 482 | mounted() { 483 | } 484 | 485 | setProps(props) { 486 | Object.assign(this.props, props) 487 | 488 | diffAndPatch(this._element, this._vtree, this._vtree = this.render()) 489 | 490 | this.updated() 491 | } 492 | 493 | setState(state) { 494 | Object.assign(this.state, state) 495 | 496 | if (this._renderTimer) { return } 497 | 498 | this._renderTimer = setTimeout(() => { 499 | diffAndPatch(this._element, this._vtree, this._vtree = this.render()) 500 | this._renderTimer = null 501 | this.updated() 502 | }, 100) 503 | } 504 | 505 | updated() { 506 | } 507 | 508 | render() { 509 | return createElement(new VText('')) 510 | } 511 | } 512 | 513 | 514 | export { createElement, diffAndPatch, Component, VText, VNode, VComponent, Diff, Patch, PatchType } 515 | -------------------------------------------------------------------------------- /dist/numeric_keyboard.angular.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(require("@angular/core"), require("@angular/common")); 4 | else if(typeof define === 'function' && define.amd) 5 | define("NumericKeyboard", ["@angular/core", "@angular/common"], factory); 6 | else if(typeof exports === 'object') 7 | exports["NumericKeyboard"] = factory(require("@angular/core"), require("@angular/common")); 8 | else 9 | root["NumericKeyboard"] = factory(root["ng"], root["ng"]); 10 | })(window, function(__WEBPACK_EXTERNAL_MODULE__3__, __WEBPACK_EXTERNAL_MODULE__4__) { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 50 | /******/ } 51 | /******/ }; 52 | /******/ 53 | /******/ // define __esModule on exports 54 | /******/ __webpack_require__.r = function(exports) { 55 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 56 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 57 | /******/ } 58 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 59 | /******/ }; 60 | /******/ 61 | /******/ // create a fake namespace object 62 | /******/ // mode & 1: value is a module id, require it 63 | /******/ // mode & 2: merge all properties of value into the ns 64 | /******/ // mode & 4: return value when already ns object 65 | /******/ // mode & 8|1: behave like require 66 | /******/ __webpack_require__.t = function(value, mode) { 67 | /******/ if(mode & 1) value = __webpack_require__(value); 68 | /******/ if(mode & 8) return value; 69 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 70 | /******/ var ns = Object.create(null); 71 | /******/ __webpack_require__.r(ns); 72 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 73 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 74 | /******/ return ns; 75 | /******/ }; 76 | /******/ 77 | /******/ // getDefaultExport function for compatibility with non-harmony modules 78 | /******/ __webpack_require__.n = function(module) { 79 | /******/ var getter = module && module.__esModule ? 80 | /******/ function getDefault() { return module['default']; } : 81 | /******/ function getModuleExports() { return module; }; 82 | /******/ __webpack_require__.d(getter, 'a', getter); 83 | /******/ return getter; 84 | /******/ }; 85 | /******/ 86 | /******/ // Object.prototype.hasOwnProperty.call 87 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 88 | /******/ 89 | /******/ // __webpack_public_path__ 90 | /******/ __webpack_require__.p = ""; 91 | /******/ 92 | /******/ 93 | /******/ // Load entry module and return exports 94 | /******/ return __webpack_require__(__webpack_require__.s = 0); 95 | /******/ }) 96 | /************************************************************************/ 97 | /******/ ([ 98 | /* 0 */ 99 | /***/ (function(module, exports, __webpack_require__) { 100 | 101 | "use strict"; 102 | 103 | function __export(m) { 104 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; 105 | } 106 | Object.defineProperty(exports, "__esModule", { value: true }); 107 | var Keys = __webpack_require__(1); 108 | exports.Keys = Keys; 109 | __export(__webpack_require__(2)); 110 | 111 | 112 | /***/ }), 113 | /* 1 */ 114 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 115 | 116 | "use strict"; 117 | __webpack_require__.r(__webpack_exports__); 118 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ZERO", function() { return ZERO; }); 119 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ONE", function() { return ONE; }); 120 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "TWO", function() { return TWO; }); 121 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "THREE", function() { return THREE; }); 122 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FOUR", function() { return FOUR; }); 123 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "FIVE", function() { return FIVE; }); 124 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SIX", function() { return SIX; }); 125 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "SEVEN", function() { return SEVEN; }); 126 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EIGHT", function() { return EIGHT; }); 127 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NINE", function() { return NINE; }); 128 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DOT", function() { return DOT; }); 129 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "DEL", function() { return DEL; }); 130 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ENTER", function() { return ENTER; }); 131 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ESC", function() { return ESC; }); 132 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "BLANK", function() { return BLANK; }); 133 | var ZERO = '0'; 134 | var ONE = '1'; 135 | var TWO = '2'; 136 | var THREE = '3'; 137 | var FOUR = '4'; 138 | var FIVE = '5'; 139 | var SIX = '6'; 140 | var SEVEN = '7'; 141 | var EIGHT = '8'; 142 | var NINE = '9'; 143 | var DOT = '.'; 144 | var DEL = 'del'; 145 | var ENTER = 'enter'; 146 | var ESC = 'esc'; 147 | var BLANK = ''; 148 | 149 | /***/ }), 150 | /* 2 */ 151 | /***/ (function(module, exports, __webpack_require__) { 152 | 153 | "use strict"; 154 | 155 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 156 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 157 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 158 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 159 | return c > 3 && r && Object.defineProperty(target, key, r), r; 160 | }; 161 | Object.defineProperty(exports, "__esModule", { value: true }); 162 | var core_1 = __webpack_require__(3); 163 | var common_1 = __webpack_require__(4); 164 | var keyboard_component_1 = __webpack_require__(5); 165 | var input_component_1 = __webpack_require__(15); 166 | var NumericKeyboardModule = /** @class */ (function () { 167 | function NumericKeyboardModule() { 168 | } 169 | NumericKeyboardModule = __decorate([ 170 | core_1.NgModule({ 171 | declarations: [keyboard_component_1.NumericKeyboard, input_component_1.NumericInput], 172 | entryComponents: [keyboard_component_1.NumericKeyboard], 173 | imports: [common_1.CommonModule], 174 | exports: [keyboard_component_1.NumericKeyboard, input_component_1.NumericInput] 175 | }) 176 | ], NumericKeyboardModule); 177 | return NumericKeyboardModule; 178 | }()); 179 | exports.NumericKeyboardModule = NumericKeyboardModule; 180 | 181 | 182 | /***/ }), 183 | /* 3 */ 184 | /***/ (function(module, exports) { 185 | 186 | module.exports = __WEBPACK_EXTERNAL_MODULE__3__; 187 | 188 | /***/ }), 189 | /* 4 */ 190 | /***/ (function(module, exports) { 191 | 192 | module.exports = __WEBPACK_EXTERNAL_MODULE__4__; 193 | 194 | /***/ }), 195 | /* 5 */ 196 | /***/ (function(module, exports, __webpack_require__) { 197 | 198 | "use strict"; 199 | 200 | var __extends = (this && this.__extends) || (function () { 201 | var extendStatics = function (d, b) { 202 | extendStatics = Object.setPrototypeOf || 203 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 204 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 205 | return extendStatics(d, b); 206 | }; 207 | return function (d, b) { 208 | extendStatics(d, b); 209 | function __() { this.constructor = d; } 210 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 211 | }; 212 | })(); 213 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 214 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 215 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 216 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 217 | return c > 3 && r && Object.defineProperty(target, key, r), r; 218 | }; 219 | var __metadata = (this && this.__metadata) || function (k, v) { 220 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 221 | }; 222 | Object.defineProperty(exports, "__esModule", { value: true }); 223 | var core_1 = __webpack_require__(3); 224 | var keyboard_1 = __webpack_require__(6); 225 | var template = "\n\n \n \n \n
\n
\n"; 226 | var Parent = /** @class */ (function () { 227 | function Parent() { 228 | } 229 | return Parent; 230 | }()); 231 | Parent.prototype = keyboard_1.Mixins; 232 | var NumericKeyboard = /** @class */ (function (_super) { 233 | __extends(NumericKeyboard, _super); 234 | function NumericKeyboard() { 235 | var _this = _super !== null && _super.apply(this, arguments) || this; 236 | _this.layout = keyboard_1.Options.layout; 237 | _this.entertext = keyboard_1.Options.entertext; 238 | _this.press = new core_1.EventEmitter(); 239 | _this.enterpress = new core_1.EventEmitter(); 240 | return _this; 241 | } 242 | NumericKeyboard.prototype.ngOnInit = function () { 243 | keyboard_1.Mixins.init.call(this, { 244 | layout: this.layout, 245 | entertext: this.entertext 246 | }); 247 | }; 248 | NumericKeyboard.prototype.ngOnDestroy = function () { 249 | keyboard_1.Mixins.destroy.call(this); 250 | }; 251 | NumericKeyboard.prototype.dispatch = function (event, payload) { 252 | switch (event) { 253 | case 'press': 254 | this.press.emit(payload); 255 | break; 256 | case 'enterpress': 257 | this.enterpress.emit(); 258 | break; 259 | } 260 | }; 261 | __decorate([ 262 | core_1.Input(), 263 | __metadata("design:type", Object) 264 | ], NumericKeyboard.prototype, "layout", void 0); 265 | __decorate([ 266 | core_1.Input(), 267 | __metadata("design:type", String) 268 | ], NumericKeyboard.prototype, "entertext", void 0); 269 | __decorate([ 270 | core_1.Output(), 271 | __metadata("design:type", Object) 272 | ], NumericKeyboard.prototype, "press", void 0); 273 | __decorate([ 274 | core_1.Output(), 275 | __metadata("design:type", Object) 276 | ], NumericKeyboard.prototype, "enterpress", void 0); 277 | NumericKeyboard = __decorate([ 278 | core_1.Component({ 279 | selector: 'numeric-keyboard', 280 | template: template, 281 | styles: [__webpack_require__(10)] 282 | }) 283 | ], NumericKeyboard); 284 | return NumericKeyboard; 285 | }(Parent)); 286 | exports.NumericKeyboard = NumericKeyboard; 287 | 288 | 289 | /***/ }), 290 | /* 6 */ 291 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 292 | 293 | "use strict"; 294 | __webpack_require__.r(__webpack_exports__); 295 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Options", function() { return Options; }); 296 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mixins", function() { return Mixins; }); 297 | /* harmony import */ var _keys_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); 298 | /* harmony import */ var _layouts_index_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7); 299 | 300 | 301 | var Options = { 302 | layout: 'number', 303 | entertext: 'enter' 304 | }; 305 | var Mixins = { 306 | init: function init(options) { 307 | var layout = options.layout; 308 | var resolvedLayout; 309 | 310 | if (typeof layout === 'string') { 311 | resolvedLayout = _layouts_index_js__WEBPACK_IMPORTED_MODULE_1__["default"][layout]; 312 | 313 | if (!Array.isArray(resolvedLayout)) { 314 | throw new Error("".concat(layout, " is not a build-in layout.")); 315 | } 316 | } else { 317 | resolvedLayout = layout; 318 | 319 | if (!Array.isArray(resolvedLayout) || !resolvedLayout.every(function (i) { 320 | return Array.isArray(i); 321 | })) { 322 | throw new Error("custom layout must be a two-dimensional array."); 323 | } 324 | } 325 | 326 | this.kp = options; 327 | this.ks = { 328 | resolvedLayout: resolvedLayout 329 | }; 330 | }, 331 | destroy: function destroy() {}, 332 | set: function set(key, value) { 333 | this.ks[key] = value; 334 | }, 335 | onTouchend: function onTouchend(key) { 336 | this.dispatch('press', key); 337 | 338 | if (key === _keys_js__WEBPACK_IMPORTED_MODULE_0__["ENTER"]) { 339 | this.dispatch('enterpress'); 340 | } 341 | }, 342 | dispatch: function dispatch() 343 | /* event, payload */ 344 | { 345 | throw new Error('dispatch method must be overrided!'); 346 | } 347 | }; 348 | 349 | /***/ }), 350 | /* 7 */ 351 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 352 | 353 | "use strict"; 354 | __webpack_require__.r(__webpack_exports__); 355 | /* harmony import */ var _number_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8); 356 | /* harmony import */ var _tel_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9); 357 | 358 | 359 | /* harmony default export */ __webpack_exports__["default"] = ({ 360 | number: _number_js__WEBPACK_IMPORTED_MODULE_0__["default"], 361 | tel: _tel_js__WEBPACK_IMPORTED_MODULE_1__["default"] 362 | }); 363 | 364 | /***/ }), 365 | /* 8 */ 366 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 367 | 368 | "use strict"; 369 | __webpack_require__.r(__webpack_exports__); 370 | /* harmony import */ var _keys_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); 371 | 372 | /* harmony default export */ __webpack_exports__["default"] = ([[{ 373 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["ONE"] 374 | }, { 375 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["TWO"] 376 | }, { 377 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["THREE"] 378 | }, { 379 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["DEL"], 380 | rowspan: 2 381 | }], [{ 382 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["FOUR"] 383 | }, { 384 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["FIVE"] 385 | }, { 386 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["SIX"] 387 | }], [{ 388 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["SEVEN"] 389 | }, { 390 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["EIGHT"] 391 | }, { 392 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["NINE"] 393 | }, { 394 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["ENTER"], 395 | rowspan: 2 396 | }], [{ 397 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["DOT"] 398 | }, { 399 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["ZERO"] 400 | }, { 401 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["ESC"] 402 | }]]); 403 | 404 | /***/ }), 405 | /* 9 */ 406 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 407 | 408 | "use strict"; 409 | __webpack_require__.r(__webpack_exports__); 410 | /* harmony import */ var _keys_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); 411 | 412 | /* harmony default export */ __webpack_exports__["default"] = ([[{ 413 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["ONE"] 414 | }, { 415 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["TWO"] 416 | }, { 417 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["THREE"] 418 | }], [{ 419 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["FOUR"] 420 | }, { 421 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["FIVE"] 422 | }, { 423 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["SIX"] 424 | }], [{ 425 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["SEVEN"] 426 | }, { 427 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["EIGHT"] 428 | }, { 429 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["NINE"] 430 | }], [{ 431 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["DEL"] 432 | }, { 433 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["ZERO"] 434 | }, { 435 | key: _keys_js__WEBPACK_IMPORTED_MODULE_0__["ENTER"] 436 | }]]); 437 | 438 | /***/ }), 439 | /* 10 */ 440 | /***/ (function(module, exports, __webpack_require__) { 441 | 442 | 443 | var result = __webpack_require__(11); 444 | 445 | if (typeof result === "string") { 446 | module.exports = result; 447 | } else { 448 | module.exports = result.toString(); 449 | } 450 | 451 | 452 | /***/ }), 453 | /* 11 */ 454 | /***/ (function(module, exports, __webpack_require__) { 455 | 456 | exports = module.exports = __webpack_require__(12)(false); 457 | // Imports 458 | var urlEscape = __webpack_require__(13); 459 | var ___CSS_LOADER_URL___0___ = urlEscape(__webpack_require__(14)); 460 | 461 | // Module 462 | exports.push([module.i, "@font-face {\n font-family: numeric-keyboard;\n src: url(" + ___CSS_LOADER_URL___0___ + ") format('woff');\n font-weight: normal;\n font-style: normal;\n}\n.numeric-keyboard {\n width: 100%;\n height: 100%;\n background: #cfd4da;\n table-layout: fixed;\n border-collapse: separate;\n border-spacing: 1px;\n font-size: 2em;\n text-align: center;\n}\n.numeric-keyboard-key {\n touch-action: manipulation;\n transition: background 0.5s;\n color: #000;\n background: #fff;\n}\n.numeric-keyboard-key:active {\n background: #929ca8;\n}\n.numeric-keyboard-key[data-key=\"\"] {\n pointer-events: none;\n}\n.numeric-keyboard-key[data-key=enter] {\n color: #fff;\n background: #007aff;\n}\n.numeric-keyboard-key[data-key=enter]:active {\n background: #0051a8;\n}\n.numeric-keyboard-key[data-icon]::before {\n content: attr(data-icon);\n}\n.numeric-keyboard-key[data-icon=del]::before,\n.numeric-keyboard-key[data-icon=esc]::before {\n font-family: numeric-keyboard !important;\n speak: none;\n font-style: normal;\n font-weight: normal;\n font-variant: normal;\n text-transform: none;\n line-height: 1;\n letter-spacing: 0;\n -webkit-font-feature-settings: \"liga\";\n font-feature-settings: \"liga\";\n -webkit-font-variant-ligatures: discretionary-ligatures;\n font-variant-ligatures: discretionary-ligatures;\n -webkit-font-smoothing: antialiased;\n}\n:host {\n width: 100%;\n height: 100%;\n}\n:host .numeric-keyboard {\n width: inherit;\n height: inherit;\n}\n", ""]); 463 | 464 | 465 | 466 | /***/ }), 467 | /* 12 */ 468 | /***/ (function(module, exports, __webpack_require__) { 469 | 470 | "use strict"; 471 | 472 | 473 | /* 474 | MIT License http://www.opensource.org/licenses/mit-license.php 475 | Author Tobias Koppers @sokra 476 | */ 477 | // css base code, injected by the css-loader 478 | module.exports = function (useSourceMap) { 479 | var list = []; // return the list of modules as css string 480 | 481 | list.toString = function toString() { 482 | return this.map(function (item) { 483 | var content = cssWithMappingToString(item, useSourceMap); 484 | 485 | if (item[2]) { 486 | return '@media ' + item[2] + '{' + content + '}'; 487 | } else { 488 | return content; 489 | } 490 | }).join(''); 491 | }; // import a list of modules into the list 492 | 493 | 494 | list.i = function (modules, mediaQuery) { 495 | if (typeof modules === 'string') { 496 | modules = [[null, modules, '']]; 497 | } 498 | 499 | var alreadyImportedModules = {}; 500 | 501 | for (var i = 0; i < this.length; i++) { 502 | var id = this[i][0]; 503 | 504 | if (id != null) { 505 | alreadyImportedModules[id] = true; 506 | } 507 | } 508 | 509 | for (i = 0; i < modules.length; i++) { 510 | var item = modules[i]; // skip already imported module 511 | // this implementation is not 100% perfect for weird media query combinations 512 | // when a module is imported multiple times with different media queries. 513 | // I hope this will never occur (Hey this way we have smaller bundles) 514 | 515 | if (item[0] == null || !alreadyImportedModules[item[0]]) { 516 | if (mediaQuery && !item[2]) { 517 | item[2] = mediaQuery; 518 | } else if (mediaQuery) { 519 | item[2] = '(' + item[2] + ') and (' + mediaQuery + ')'; 520 | } 521 | 522 | list.push(item); 523 | } 524 | } 525 | }; 526 | 527 | return list; 528 | }; 529 | 530 | function cssWithMappingToString(item, useSourceMap) { 531 | var content = item[1] || ''; 532 | var cssMapping = item[3]; 533 | 534 | if (!cssMapping) { 535 | return content; 536 | } 537 | 538 | if (useSourceMap && typeof btoa === 'function') { 539 | var sourceMapping = toComment(cssMapping); 540 | var sourceURLs = cssMapping.sources.map(function (source) { 541 | return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'; 542 | }); 543 | return [content].concat(sourceURLs).concat([sourceMapping]).join('\n'); 544 | } 545 | 546 | return [content].join('\n'); 547 | } // Adapted from convert-source-map (MIT) 548 | 549 | 550 | function toComment(sourceMap) { 551 | // eslint-disable-next-line no-undef 552 | var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))); 553 | var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64; 554 | return '/*# ' + data + ' */'; 555 | } 556 | 557 | /***/ }), 558 | /* 13 */ 559 | /***/ (function(module, exports, __webpack_require__) { 560 | 561 | "use strict"; 562 | 563 | 564 | module.exports = function escape(url, needQuotes) { 565 | if (typeof url !== 'string') { 566 | return url; 567 | } // If url is already wrapped in quotes, remove them 568 | 569 | 570 | if (/^['"].*['"]$/.test(url)) { 571 | url = url.slice(1, -1); 572 | } // Should url be wrapped? 573 | // See https://drafts.csswg.org/css-values-3/#urls 574 | 575 | 576 | if (/["'() \t\n]/.test(url) || needQuotes) { 577 | return '"' + url.replace(/"/g, '\\"').replace(/\n/g, '\\n') + '"'; 578 | } 579 | 580 | return url; 581 | }; 582 | 583 | /***/ }), 584 | /* 14 */ 585 | /***/ (function(module, exports) { 586 | 587 | module.exports = "data:font/woff;base64,d09GRgABAAAAAAfsAAwAAAAAB5wAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABHAAAAHIAAABy2arcWE9TLzIAAAGQAAAAYAAAAGAPEgWBY21hcAAAAfAAAABsAAAAbOm3AapnYXNwAAACXAAAAAgAAAAIAAAAEGdseWYAAAJkAAACfAAAAnw0f1YEaGVhZAAABOAAAAA2AAAANg8HzfloaGVhAAAFGAAAACQAAAAkB8IDzWhtdHgAAAU8AAAAMAAAADAOAABgbG9jYQAABWwAAAAaAAAAGgKeAfxtYXhwAAAFiAAAACAAAAAgAB4ATm5hbWUAAAWoAAACIgAAAiI2PD88cG9zdAAAB8wAAAAgAAAAIAADAAAAAQAAAAoAHgAsAAFsYXRuAAgABAAAAAAAAAABAAAAAWxpZ2EACAAAAAEAAAABAAQABAAAAAEACgAAAAEADAADABYAIgAuAAEAAwAFAAYACwABAAQACQADAAYABwABAAQACgADAAgABAABAAQACgACAAsAAAADA1UBkAAFAAACmQLMAAAAjwKZAswAAAHrADMBCQAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAEAAAOkCA8D/wABAA8AAQAAAAAEAAAAAAAAAAAAAACAAAAAAAAMAAAADAAAAHAABAAMAAAAcAAMAAQAAABwABABQAAAAEAAQAAMAAAABACAAZQBsAHPpAv/9//8AAAAAACAAYwBsAHPpAP/9//8AAf/j/6H/m/+VFwkAAwABAAAAAAAAAAAAAAAAAAAAAAABAAH//wAPAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAAAAAAAAAACAAA3OQEAAAAAAQAAAAAAAAAAAAIAADc5AQAAAAADAGAAgAOgAwAAGwA8AEgAAAEhIgYHDgExDgEVFBYXMBYXHgEzITI2NRE0JiMTFAYHDgEjISImLwEuATU0Nj8BPgE3PgEzITIWFx4BFRElNycHJwcXBxc3FzcDFv62RlsrK2UICAgIVzk5T0QBSjpQUDpqEA8PJxX+tjE+KqsDBQUDphIkFBQpFwFKFScPDxD++X8df38df38df38dAwBUKytqCRUMDBYIXjk5SFQ6AWg6UP4OFigPEBEvLLIDCwcHCwOsEyINDg0PDxAmFv6Ysn8df34dfn4dfn8dAAAAABEAAABSBAADLgADAAgADAAQABQAGAAcACEAJgArADAANQA6AD8AQwBIAEsAACUhESEBIREhERMzFSM3MxUjNzMVIzczFSM3MxUjJTMVIzU7ARUjNTsBFSM1OwEVIzU7ARUjNTsBFSM1ATMVIzUhMxUjJSEVITUFBycEAPwABAD8LAOo/FiEV1eSWFiSWFiSWFiTV1f9bVhYk1dXklhYklhYk1dXklhY/TNYWAK+WFj91AHy/g4BbnV11gJY/dQCAP4AATNYWFhYWFhYWFjqV1dXV1dXV1dXV1dX/txYWFhYWFj5WFgAAAABAAAAAAAAAAAAAgAANzkBAAAAAAEAAAABAAAtcRXTXw889QALBAAAAAAA1fTE5wAAAADV9MTnAAAAAAQAAy4AAAAIAAIAAAAAAAAAAQAAA8D/wAAABAAAAAAABAAAAQAAAAAAAAAAAAAAAAAAAAwEAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAABgBAAAAAAAAAAAAAAAAAoAFAAeACgAMgA8AEYAUADAATQBPgAAAAEAAAAMAEwAEQAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAOAK4AAQAAAAAAAQAUAAAAAQAAAAAAAgAHANUAAQAAAAAAAwAUAF0AAQAAAAAABAAUAOoAAQAAAAAABQALADwAAQAAAAAABgAUAJkAAQAAAAAACgAaASYAAwABBAkAAQAoABQAAwABBAkAAgAOANwAAwABBAkAAwAoAHEAAwABBAkABAAoAP4AAwABBAkABQAWAEcAAwABBAkABgAoAK0AAwABBAkACgA0AUB2dWUtbnVtZXJpYy1rZXlib2FyZAB2AHUAZQAtAG4AdQBtAGUAcgBpAGMALQBrAGUAeQBiAG8AYQByAGRWZXJzaW9uIDEuMABWAGUAcgBzAGkAbwBuACAAMQAuADB2dWUtbnVtZXJpYy1rZXlib2FyZAB2AHUAZQAtAG4AdQBtAGUAcgBpAGMALQBrAGUAeQBiAG8AYQByAGR2dWUtbnVtZXJpYy1rZXlib2FyZAB2AHUAZQAtAG4AdQBtAGUAcgBpAGMALQBrAGUAeQBiAG8AYQByAGRSZWd1bGFyAFIAZQBnAHUAbABhAHJ2dWUtbnVtZXJpYy1rZXlib2FyZAB2AHUAZQAtAG4AdQBtAGUAcgBpAGMALQBrAGUAeQBiAG8AYQByAGRGb250IGdlbmVyYXRlZCBieSBJY29Nb29uLgBGAG8AbgB0ACAAZwBlAG4AZQByAGEAdABlAGQAIABiAHkAIABJAGMAbwBNAG8AbwBuAC4AAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" 588 | 589 | /***/ }), 590 | /* 15 */ 591 | /***/ (function(module, exports, __webpack_require__) { 592 | 593 | "use strict"; 594 | 595 | var __extends = (this && this.__extends) || (function () { 596 | var extendStatics = function (d, b) { 597 | extendStatics = Object.setPrototypeOf || 598 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 599 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 600 | return extendStatics(d, b); 601 | }; 602 | return function (d, b) { 603 | extendStatics(d, b); 604 | function __() { this.constructor = d; } 605 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 606 | }; 607 | })(); 608 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 609 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 610 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 611 | else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; 612 | return c > 3 && r && Object.defineProperty(target, key, r), r; 613 | }; 614 | var __metadata = (this && this.__metadata) || function (k, v) { 615 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 616 | }; 617 | Object.defineProperty(exports, "__esModule", { value: true }); 618 | var core_1 = __webpack_require__(3); 619 | var attribute_js_1 = __webpack_require__(16); 620 | var input_1 = __webpack_require__(17); 621 | var keyboard_component_1 = __webpack_require__(5); 622 | var template = "\n
\n
\n
{{c}}
\n
{{kp.placeholder}}
\n
\n
\n
\n"; 623 | var Parent = /** @class */ (function () { 624 | function Parent() { 625 | } 626 | return Parent; 627 | }()); 628 | Parent.prototype = input_1.Mixins; 629 | Parent.prototype.constructor = Parent; 630 | var NumericInput = /** @class */ (function (_super) { 631 | __extends(NumericInput, _super); 632 | function NumericInput(element, appRef, componentFactoryResolver, injector) { 633 | var _this = _super.call(this) || this; 634 | _this.element = element; 635 | _this.appRef = appRef; 636 | _this.componentFactoryResolver = componentFactoryResolver; 637 | _this.injector = injector; 638 | _this._autofocus = input_1.Options.autofocus; 639 | _this._disabled = input_1.Options.disabled; 640 | _this._readonly = input_1.Options.readonly; 641 | _this._value = input_1.Options.value; 642 | _this.type = input_1.Options.type; 643 | _this.value = input_1.Options.value; 644 | _this.maxlength = input_1.Options.maxlength; 645 | _this.name = input_1.Options.name; 646 | _this.placeholder = input_1.Options.placeholder; 647 | _this.format = input_1.Options.format; 648 | _this.layout = input_1.Options.layout; 649 | _this.entertext = input_1.Options.entertext; 650 | _this.focus = new core_1.EventEmitter(); 651 | _this.blur = new core_1.EventEmitter(); 652 | _this.enterpress = new core_1.EventEmitter(); 653 | _this.ngModelChange = new core_1.EventEmitter(); 654 | return _this; 655 | } 656 | Object.defineProperty(NumericInput.prototype, "autofocus", { 657 | get: function () { return this._autofocus; }, 658 | set: function (value) { this._autofocus = attribute_js_1.coerceBooleanProperty(value); }, 659 | enumerable: true, 660 | configurable: true 661 | }); 662 | Object.defineProperty(NumericInput.prototype, "disabled", { 663 | get: function () { return this._disabled; }, 664 | set: function (value) { this._disabled = attribute_js_1.coerceBooleanProperty(value); }, 665 | enumerable: true, 666 | configurable: true 667 | }); 668 | Object.defineProperty(NumericInput.prototype, "readonly", { 669 | get: function () { return this._readonly; }, 670 | set: function (value) { this._readonly = attribute_js_1.coerceBooleanProperty(value); }, 671 | enumerable: true, 672 | configurable: true 673 | }); 674 | Object.defineProperty(NumericInput.prototype, "ngModel", { 675 | get: function () { return this._value; }, 676 | set: function (value) { 677 | if (this.ks && this.ks.value !== value) { 678 | var rawValue = value.toString().split(''); 679 | var cursorPos = rawValue.length; 680 | input_1.Mixins.set.call(this, 'rawValue', rawValue); 681 | input_1.Mixins.set.call(this, 'cursorPos', cursorPos); 682 | } 683 | this._value = value; 684 | }, 685 | enumerable: true, 686 | configurable: true 687 | }); 688 | NumericInput.prototype.ngOnInit = function () { 689 | var resolvedOptions = {}; 690 | for (var key in input_1.Options) { 691 | resolvedOptions[key] = this[key]; 692 | } 693 | input_1.Mixins.init.call(this, resolvedOptions); 694 | }; 695 | NumericInput.prototype.ngOnDestroy = function () { 696 | input_1.Mixins.destroy.call(this); 697 | }; 698 | NumericInput.prototype.ngAfterViewInit = function () { 699 | input_1.Mixins.onMounted.call(this, this.element.nativeElement.querySelector('.numeric-input')); 700 | }; 701 | NumericInput.prototype.ngAfterViewChecked = function () { 702 | input_1.Mixins.onUpdated.call(this); 703 | }; 704 | NumericInput.prototype.trackByIndex = function (index) { 705 | return index; 706 | }; 707 | NumericInput.prototype.onFocus = function (event) { 708 | input_1.Mixins.onFocus.call(this, event); 709 | }; 710 | NumericInput.prototype.dispatch = function (event, payload) { 711 | switch (event) { 712 | case 'focus': 713 | this.focus.emit(); 714 | break; 715 | case 'blur': 716 | this.blur.emit(); 717 | break; 718 | case 'enterpress': 719 | this.enterpress.emit(); 720 | break; 721 | case 'input': 722 | this.ngModelChange.emit(payload); 723 | break; 724 | } 725 | }; 726 | NumericInput.prototype.createKeyboard = function (el, options, events, callback) { 727 | var componentRef = this.componentFactoryResolver 728 | .resolveComponentFactory(keyboard_component_1.NumericKeyboard) 729 | .create(this.injector); 730 | Object.assign(componentRef.instance, options); 731 | componentRef.instance.ngOnInit(); 732 | for (var event_1 in events) { 733 | componentRef.instance[event_1].subscribe(events[event_1]); 734 | } 735 | this.appRef.attachView(componentRef.hostView); 736 | el.appendChild(componentRef.hostView.rootNodes[0]); 737 | callback(componentRef); 738 | }; 739 | NumericInput.prototype.destroyKeyboard = function (el, keyboard) { 740 | keyboard.destroy(); 741 | this.appRef.detachView(keyboard.hostView); 742 | }; 743 | __decorate([ 744 | core_1.Input(), 745 | __metadata("design:type", Object), 746 | __metadata("design:paramtypes", [Object]) 747 | ], NumericInput.prototype, "autofocus", null); 748 | __decorate([ 749 | core_1.Input(), 750 | __metadata("design:type", Object), 751 | __metadata("design:paramtypes", [Object]) 752 | ], NumericInput.prototype, "disabled", null); 753 | __decorate([ 754 | core_1.Input(), 755 | __metadata("design:type", Object), 756 | __metadata("design:paramtypes", [Object]) 757 | ], NumericInput.prototype, "readonly", null); 758 | __decorate([ 759 | core_1.Input(), 760 | __metadata("design:type", Object), 761 | __metadata("design:paramtypes", [Object]) 762 | ], NumericInput.prototype, "ngModel", null); 763 | __decorate([ 764 | core_1.Input(), 765 | __metadata("design:type", String) 766 | ], NumericInput.prototype, "type", void 0); 767 | __decorate([ 768 | core_1.Input(), 769 | __metadata("design:type", Object) 770 | ], NumericInput.prototype, "value", void 0); 771 | __decorate([ 772 | core_1.Input(), 773 | __metadata("design:type", Number) 774 | ], NumericInput.prototype, "maxlength", void 0); 775 | __decorate([ 776 | core_1.Input(), 777 | __metadata("design:type", String) 778 | ], NumericInput.prototype, "name", void 0); 779 | __decorate([ 780 | core_1.Input(), 781 | __metadata("design:type", String) 782 | ], NumericInput.prototype, "placeholder", void 0); 783 | __decorate([ 784 | core_1.Input(), 785 | __metadata("design:type", Object) 786 | ], NumericInput.prototype, "format", void 0); 787 | __decorate([ 788 | core_1.Input(), 789 | __metadata("design:type", Object) 790 | ], NumericInput.prototype, "layout", void 0); 791 | __decorate([ 792 | core_1.Input(), 793 | __metadata("design:type", String) 794 | ], NumericInput.prototype, "entertext", void 0); 795 | __decorate([ 796 | core_1.Output(), 797 | __metadata("design:type", Object) 798 | ], NumericInput.prototype, "focus", void 0); 799 | __decorate([ 800 | core_1.Output(), 801 | __metadata("design:type", Object) 802 | ], NumericInput.prototype, "blur", void 0); 803 | __decorate([ 804 | core_1.Output(), 805 | __metadata("design:type", Object) 806 | ], NumericInput.prototype, "enterpress", void 0); 807 | __decorate([ 808 | core_1.Output(), 809 | __metadata("design:type", Object) 810 | ], NumericInput.prototype, "ngModelChange", void 0); 811 | NumericInput = __decorate([ 812 | core_1.Component({ 813 | selector: 'numeric-input', 814 | template: template, 815 | styles: [__webpack_require__(72)] 816 | }), 817 | __metadata("design:paramtypes", [core_1.ElementRef, 818 | core_1.ApplicationRef, 819 | core_1.ComponentFactoryResolver, 820 | core_1.Injector]) 821 | ], NumericInput); 822 | return NumericInput; 823 | }(Parent)); 824 | exports.NumericInput = NumericInput; 825 | 826 | 827 | /***/ }), 828 | /* 16 */ 829 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 830 | 831 | "use strict"; 832 | __webpack_require__.r(__webpack_exports__); 833 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "coerceBooleanProperty", function() { return coerceBooleanProperty; }); 834 | var coerceBooleanProperty = function coerceBooleanProperty(value) { 835 | return value != null && "".concat(value) !== 'false'; 836 | }; 837 | 838 | /***/ }), 839 | /* 17 */ 840 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 841 | 842 | "use strict"; 843 | __webpack_require__.r(__webpack_exports__); 844 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Options", function() { return Options; }); 845 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mixins", function() { return Mixins; }); 846 | /* harmony import */ var core_js_modules_es6_regexp_to_string__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(18); 847 | /* harmony import */ var core_js_modules_es6_regexp_to_string__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es6_regexp_to_string__WEBPACK_IMPORTED_MODULE_0__); 848 | /* harmony import */ var core_js_modules_es6_regexp_split__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(39); 849 | /* harmony import */ var core_js_modules_es6_regexp_split__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es6_regexp_split__WEBPACK_IMPORTED_MODULE_1__); 850 | /* harmony import */ var core_js_modules_es6_regexp_constructor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(57); 851 | /* harmony import */ var core_js_modules_es6_regexp_constructor__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es6_regexp_constructor__WEBPACK_IMPORTED_MODULE_2__); 852 | /* harmony import */ var _keys_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(1); 853 | /* harmony import */ var _utils_animate_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(71); 854 | 855 | 856 | 857 | 858 | 859 | var RNumber = /^\d*(?:\.\d*)?$/; 860 | var RTel = /^\d*$/; 861 | 862 | var KeyboardCenter = function () { 863 | var activeInput; 864 | return { 865 | register: function register(input) { 866 | this.unregister(); 867 | activeInput = input; 868 | document.addEventListener('touchend', this.unregister, false); 869 | }, 870 | unregister: function unregister(e) { 871 | if (!activeInput) { 872 | return; 873 | } 874 | 875 | if (e && (activeInput.ks.inputElement.contains(e.target) || activeInput.ks.keyboardElement.contains(e.target))) { 876 | return; 877 | } 878 | 879 | activeInput.closeKeyboard(); 880 | activeInput = null; 881 | document.removeEventListener('touchend', this.unregister, false); 882 | } 883 | }; 884 | }(); 885 | 886 | var Options = { 887 | type: 'number', 888 | value: '', 889 | autofocus: false, 890 | disabled: false, 891 | readonly: false, 892 | maxlength: Infinity, 893 | name: '', 894 | placeholder: '', 895 | format: '^', 896 | layout: 'number', 897 | entertext: 'enter' 898 | }; 899 | var Mixins = { 900 | init: function init(options) { 901 | var formatFn = options.format; 902 | 903 | if (typeof formatFn === 'string') { 904 | formatFn = function (rformat) { 905 | return function (val) { 906 | return rformat.test(val); 907 | }; 908 | }(new RegExp(options.format)); 909 | } 910 | 911 | var value = options.value; 912 | var rawValue = value.toString().split(''); 913 | var cursorPos = rawValue.length; 914 | this.kp = options; 915 | this.ks = { 916 | formatFn: formatFn, 917 | value: value, 918 | rawValue: rawValue, 919 | cursorPos: cursorPos, 920 | cursorColor: null, 921 | cursorActive: false, 922 | keyboard: null, 923 | inputElement: null, 924 | keyboardElement: null 925 | }; 926 | }, 927 | destroy: function destroy() { 928 | KeyboardCenter.unregister(); 929 | }, 930 | set: function set(key, value) { 931 | this.ks[key] = value; 932 | }, 933 | onMounted: function onMounted(el) { 934 | var _this = this; 935 | 936 | this.set('inputElement', el); 937 | this.set('cursorColor', window.getComputedStyle(el).getPropertyValue('color')); 938 | 939 | if (this.kp.autofocus && !this.kp.readonly && !this.kp.disabled) { 940 | setTimeout(function () { 941 | return _this.openKeyboard(); 942 | }, 500); 943 | } 944 | }, 945 | onUpdated: function onUpdated() { 946 | this.moveCursor(); 947 | }, 948 | onFocus: function onFocus(e) { 949 | e.stopPropagation(); 950 | this.openKeyboard(); 951 | var cursorPos = +e.target.dataset.index; 952 | this.set('cursorPos', isNaN(cursorPos) ? this.ks.rawValue.length : cursorPos); 953 | }, 954 | input: function input(key) { 955 | var _this2 = this; 956 | 957 | var _this$kp = this.kp, 958 | type = _this$kp.type, 959 | maxlength = _this$kp.maxlength; 960 | var _this$ks = this.ks, 961 | rawValue = _this$ks.rawValue, 962 | cursorPos = _this$ks.cursorPos, 963 | formatFn = _this$ks.formatFn; 964 | 965 | var input = function input(key) { 966 | var isAdd = typeof key !== 'undefined'; 967 | var newRawValue = rawValue.slice(); 968 | 969 | if (isAdd) { 970 | newRawValue.splice(cursorPos, 0, key); 971 | } else { 972 | newRawValue.splice(cursorPos - 1, 1); 973 | } 974 | 975 | var newValue = newRawValue.join(''); 976 | 977 | if (formatFn(newValue)) { 978 | if (type === 'number') { 979 | if (!RNumber.test(newValue)) { 980 | return; 981 | } 982 | 983 | newValue = parseFloat(newValue, 10); 984 | 985 | if (isNaN(newValue)) { 986 | newValue = ''; 987 | } 988 | } else if (newValue.length > maxlength || type === 'tel' && !RTel.test(newValue)) { 989 | return; 990 | } 991 | 992 | _this2.set('value', newValue); 993 | 994 | _this2.set('rawValue', newRawValue); 995 | 996 | _this2.set('cursorPos', isAdd ? cursorPos + 1 : cursorPos - 1); 997 | 998 | _this2.dispatch('input', newValue); 999 | } 1000 | }; 1001 | 1002 | switch (key) { 1003 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["BLANK"]: 1004 | break; 1005 | 1006 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["ESC"]: 1007 | this.closeKeyboard(); 1008 | break; 1009 | 1010 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["ENTER"]: 1011 | this.closeKeyboard(); 1012 | this.dispatch('enterpress'); 1013 | break; 1014 | 1015 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["DEL"]: 1016 | if (cursorPos > 0) { 1017 | input(); 1018 | } 1019 | 1020 | break; 1021 | 1022 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["DOT"]: 1023 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["ZERO"]: 1024 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["ONE"]: 1025 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["TWO"]: 1026 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["THREE"]: 1027 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["FOUR"]: 1028 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["FIVE"]: 1029 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["SIX"]: 1030 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["SEVEN"]: 1031 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["EIGHT"]: 1032 | case _keys_js__WEBPACK_IMPORTED_MODULE_3__["NINE"]: 1033 | default: 1034 | input(key); 1035 | break; 1036 | } 1037 | }, 1038 | moveCursor: function moveCursor() { 1039 | if (!this.ks.cursorActive) { 1040 | return; 1041 | } 1042 | 1043 | var elCursor = this.ks.inputElement.querySelector('.numeric-input-cursor'); 1044 | var elText = this.ks.inputElement.querySelector('.numeric-input-text'); 1045 | var elCharactor = elText.querySelector("span:nth-child(".concat(this.ks.cursorPos, ")")); 1046 | 1047 | if (!elCharactor) { 1048 | elCursor.style.transform = 'translateX(0)'; 1049 | elText.style.transform = 'translateX(0)'; 1050 | return; 1051 | } 1052 | 1053 | var cursorOffset = elCharactor.offsetLeft + elCharactor.offsetWidth; 1054 | var maxVisibleWidth = elText.parentNode.offsetWidth; 1055 | elCursor.style.transform = "translateX(".concat(Math.min(maxVisibleWidth - 1, cursorOffset), "px)"); 1056 | elText.style.transform = "translateX(".concat(Math.min(0, maxVisibleWidth - cursorOffset), "px)"); 1057 | }, 1058 | openKeyboard: function openKeyboard() { 1059 | var _this3 = this; 1060 | 1061 | if (this.ks.keyboard) { 1062 | return; 1063 | } 1064 | 1065 | var elContainer = document.createElement('div'); 1066 | var elShadow = document.createElement('div'); 1067 | var elKeyboard = document.createElement('div'); 1068 | elContainer.className = 'numeric-keyboard-actionsheet'; 1069 | elContainer.appendChild(elShadow); 1070 | elContainer.appendChild(elKeyboard); 1071 | document.body.appendChild(elContainer); 1072 | this.createKeyboard(elKeyboard, { 1073 | layout: this.kp.layout || this.kp.type, 1074 | entertext: this.kp.entertext 1075 | }, { 1076 | press: this.input.bind(this) 1077 | }, function (keyboard) { 1078 | return _this3.set('keyboard', keyboard); 1079 | }); 1080 | Object(_utils_animate_js__WEBPACK_IMPORTED_MODULE_4__["animate"])(function (timestamp, frame, frames) { 1081 | elKeyboard.style.transform = "translateY(".concat((frames - frame) / frames * 100, "%)"); 1082 | }, function () {}, 10); 1083 | this.set('keyboardElement', elKeyboard); 1084 | this.set('cursorActive', true); 1085 | this.set('cursorPos', this.ks.rawValue.length); 1086 | this.dispatch('focus'); 1087 | KeyboardCenter.register(this); 1088 | }, 1089 | closeKeyboard: function closeKeyboard() { 1090 | var _this4 = this; 1091 | 1092 | if (!this.ks.keyboard) { 1093 | return; 1094 | } 1095 | 1096 | var keyboard = this.ks.keyboard; 1097 | var elKeyboard = this.ks.keyboardElement; 1098 | Object(_utils_animate_js__WEBPACK_IMPORTED_MODULE_4__["animate"])(function (timestamp, frame, frames) { 1099 | elKeyboard.style.transform = "translateY(".concat(frame / frames * 100, "%)"); 1100 | }, function () { 1101 | setTimeout(function () { 1102 | _this4.destroyKeyboard(elKeyboard, keyboard); 1103 | 1104 | document.body.removeChild(elKeyboard.parentNode); 1105 | }, 300); 1106 | }, 10); 1107 | this.set('keyboard', null); 1108 | this.set('keyboardElement', null); 1109 | this.set('cursorActive', false); 1110 | this.set('cursorPos', 0); 1111 | this.dispatch('blur'); 1112 | KeyboardCenter.unregister(); 1113 | }, 1114 | createKeyboard: function createKeyboard() 1115 | /* el, options, events, callback */ 1116 | { 1117 | throw new Error('createKeyboard method must be overrided!'); 1118 | }, 1119 | destroyKeyboard: function destroyKeyboard() 1120 | /* el, keyboard */ 1121 | { 1122 | throw new Error('destroyKeyboard method must be overrided!'); 1123 | }, 1124 | dispatch: function dispatch() 1125 | /* event, payload */ 1126 | { 1127 | throw new Error('dispatch method must be overrided!'); 1128 | } 1129 | }; 1130 | 1131 | /***/ }), 1132 | /* 18 */ 1133 | /***/ (function(module, exports, __webpack_require__) { 1134 | 1135 | "use strict"; 1136 | 1137 | __webpack_require__(19); 1138 | var anObject = __webpack_require__(23); 1139 | var $flags = __webpack_require__(29); 1140 | var DESCRIPTORS = __webpack_require__(20); 1141 | var TO_STRING = 'toString'; 1142 | var $toString = /./[TO_STRING]; 1143 | 1144 | var define = function (fn) { 1145 | __webpack_require__(30)(RegExp.prototype, TO_STRING, fn, true); 1146 | }; 1147 | 1148 | // 21.2.5.14 RegExp.prototype.toString() 1149 | if (__webpack_require__(21)(function () { return $toString.call({ source: 'a', flags: 'b' }) != '/a/b'; })) { 1150 | define(function toString() { 1151 | var R = anObject(this); 1152 | return '/'.concat(R.source, '/', 1153 | 'flags' in R ? R.flags : !DESCRIPTORS && R instanceof RegExp ? $flags.call(R) : undefined); 1154 | }); 1155 | // FF44- RegExp#toString has a wrong name 1156 | } else if ($toString.name != TO_STRING) { 1157 | define(function toString() { 1158 | return $toString.call(this); 1159 | }); 1160 | } 1161 | 1162 | 1163 | /***/ }), 1164 | /* 19 */ 1165 | /***/ (function(module, exports, __webpack_require__) { 1166 | 1167 | // 21.2.5.3 get RegExp.prototype.flags() 1168 | if (__webpack_require__(20) && /./g.flags != 'g') __webpack_require__(22).f(RegExp.prototype, 'flags', { 1169 | configurable: true, 1170 | get: __webpack_require__(29) 1171 | }); 1172 | 1173 | 1174 | /***/ }), 1175 | /* 20 */ 1176 | /***/ (function(module, exports, __webpack_require__) { 1177 | 1178 | // Thank's IE8 for his funny defineProperty 1179 | module.exports = !__webpack_require__(21)(function () { 1180 | return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7; 1181 | }); 1182 | 1183 | 1184 | /***/ }), 1185 | /* 21 */ 1186 | /***/ (function(module, exports) { 1187 | 1188 | module.exports = function (exec) { 1189 | try { 1190 | return !!exec(); 1191 | } catch (e) { 1192 | return true; 1193 | } 1194 | }; 1195 | 1196 | 1197 | /***/ }), 1198 | /* 22 */ 1199 | /***/ (function(module, exports, __webpack_require__) { 1200 | 1201 | var anObject = __webpack_require__(23); 1202 | var IE8_DOM_DEFINE = __webpack_require__(25); 1203 | var toPrimitive = __webpack_require__(28); 1204 | var dP = Object.defineProperty; 1205 | 1206 | exports.f = __webpack_require__(20) ? Object.defineProperty : function defineProperty(O, P, Attributes) { 1207 | anObject(O); 1208 | P = toPrimitive(P, true); 1209 | anObject(Attributes); 1210 | if (IE8_DOM_DEFINE) try { 1211 | return dP(O, P, Attributes); 1212 | } catch (e) { /* empty */ } 1213 | if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!'); 1214 | if ('value' in Attributes) O[P] = Attributes.value; 1215 | return O; 1216 | }; 1217 | 1218 | 1219 | /***/ }), 1220 | /* 23 */ 1221 | /***/ (function(module, exports, __webpack_require__) { 1222 | 1223 | var isObject = __webpack_require__(24); 1224 | module.exports = function (it) { 1225 | if (!isObject(it)) throw TypeError(it + ' is not an object!'); 1226 | return it; 1227 | }; 1228 | 1229 | 1230 | /***/ }), 1231 | /* 24 */ 1232 | /***/ (function(module, exports) { 1233 | 1234 | module.exports = function (it) { 1235 | return typeof it === 'object' ? it !== null : typeof it === 'function'; 1236 | }; 1237 | 1238 | 1239 | /***/ }), 1240 | /* 25 */ 1241 | /***/ (function(module, exports, __webpack_require__) { 1242 | 1243 | module.exports = !__webpack_require__(20) && !__webpack_require__(21)(function () { 1244 | return Object.defineProperty(__webpack_require__(26)('div'), 'a', { get: function () { return 7; } }).a != 7; 1245 | }); 1246 | 1247 | 1248 | /***/ }), 1249 | /* 26 */ 1250 | /***/ (function(module, exports, __webpack_require__) { 1251 | 1252 | var isObject = __webpack_require__(24); 1253 | var document = __webpack_require__(27).document; 1254 | // typeof document.createElement is 'object' in old IE 1255 | var is = isObject(document) && isObject(document.createElement); 1256 | module.exports = function (it) { 1257 | return is ? document.createElement(it) : {}; 1258 | }; 1259 | 1260 | 1261 | /***/ }), 1262 | /* 27 */ 1263 | /***/ (function(module, exports) { 1264 | 1265 | // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 1266 | var global = module.exports = typeof window != 'undefined' && window.Math == Math 1267 | ? window : typeof self != 'undefined' && self.Math == Math ? self 1268 | // eslint-disable-next-line no-new-func 1269 | : Function('return this')(); 1270 | if (typeof __g == 'number') __g = global; // eslint-disable-line no-undef 1271 | 1272 | 1273 | /***/ }), 1274 | /* 28 */ 1275 | /***/ (function(module, exports, __webpack_require__) { 1276 | 1277 | // 7.1.1 ToPrimitive(input [, PreferredType]) 1278 | var isObject = __webpack_require__(24); 1279 | // instead of the ES6 spec version, we didn't implement @@toPrimitive case 1280 | // and the second argument - flag - preferred type is a string 1281 | module.exports = function (it, S) { 1282 | if (!isObject(it)) return it; 1283 | var fn, val; 1284 | if (S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val; 1285 | if (typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it))) return val; 1286 | if (!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it))) return val; 1287 | throw TypeError("Can't convert object to primitive value"); 1288 | }; 1289 | 1290 | 1291 | /***/ }), 1292 | /* 29 */ 1293 | /***/ (function(module, exports, __webpack_require__) { 1294 | 1295 | "use strict"; 1296 | 1297 | // 21.2.5.3 get RegExp.prototype.flags 1298 | var anObject = __webpack_require__(23); 1299 | module.exports = function () { 1300 | var that = anObject(this); 1301 | var result = ''; 1302 | if (that.global) result += 'g'; 1303 | if (that.ignoreCase) result += 'i'; 1304 | if (that.multiline) result += 'm'; 1305 | if (that.unicode) result += 'u'; 1306 | if (that.sticky) result += 'y'; 1307 | return result; 1308 | }; 1309 | 1310 | 1311 | /***/ }), 1312 | /* 30 */ 1313 | /***/ (function(module, exports, __webpack_require__) { 1314 | 1315 | var global = __webpack_require__(27); 1316 | var hide = __webpack_require__(31); 1317 | var has = __webpack_require__(33); 1318 | var SRC = __webpack_require__(34)('src'); 1319 | var $toString = __webpack_require__(35); 1320 | var TO_STRING = 'toString'; 1321 | var TPL = ('' + $toString).split(TO_STRING); 1322 | 1323 | __webpack_require__(37).inspectSource = function (it) { 1324 | return $toString.call(it); 1325 | }; 1326 | 1327 | (module.exports = function (O, key, val, safe) { 1328 | var isFunction = typeof val == 'function'; 1329 | if (isFunction) has(val, 'name') || hide(val, 'name', key); 1330 | if (O[key] === val) return; 1331 | if (isFunction) has(val, SRC) || hide(val, SRC, O[key] ? '' + O[key] : TPL.join(String(key))); 1332 | if (O === global) { 1333 | O[key] = val; 1334 | } else if (!safe) { 1335 | delete O[key]; 1336 | hide(O, key, val); 1337 | } else if (O[key]) { 1338 | O[key] = val; 1339 | } else { 1340 | hide(O, key, val); 1341 | } 1342 | // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative 1343 | })(Function.prototype, TO_STRING, function toString() { 1344 | return typeof this == 'function' && this[SRC] || $toString.call(this); 1345 | }); 1346 | 1347 | 1348 | /***/ }), 1349 | /* 31 */ 1350 | /***/ (function(module, exports, __webpack_require__) { 1351 | 1352 | var dP = __webpack_require__(22); 1353 | var createDesc = __webpack_require__(32); 1354 | module.exports = __webpack_require__(20) ? function (object, key, value) { 1355 | return dP.f(object, key, createDesc(1, value)); 1356 | } : function (object, key, value) { 1357 | object[key] = value; 1358 | return object; 1359 | }; 1360 | 1361 | 1362 | /***/ }), 1363 | /* 32 */ 1364 | /***/ (function(module, exports) { 1365 | 1366 | module.exports = function (bitmap, value) { 1367 | return { 1368 | enumerable: !(bitmap & 1), 1369 | configurable: !(bitmap & 2), 1370 | writable: !(bitmap & 4), 1371 | value: value 1372 | }; 1373 | }; 1374 | 1375 | 1376 | /***/ }), 1377 | /* 33 */ 1378 | /***/ (function(module, exports) { 1379 | 1380 | var hasOwnProperty = {}.hasOwnProperty; 1381 | module.exports = function (it, key) { 1382 | return hasOwnProperty.call(it, key); 1383 | }; 1384 | 1385 | 1386 | /***/ }), 1387 | /* 34 */ 1388 | /***/ (function(module, exports) { 1389 | 1390 | var id = 0; 1391 | var px = Math.random(); 1392 | module.exports = function (key) { 1393 | return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); 1394 | }; 1395 | 1396 | 1397 | /***/ }), 1398 | /* 35 */ 1399 | /***/ (function(module, exports, __webpack_require__) { 1400 | 1401 | module.exports = __webpack_require__(36)('native-function-to-string', Function.toString); 1402 | 1403 | 1404 | /***/ }), 1405 | /* 36 */ 1406 | /***/ (function(module, exports, __webpack_require__) { 1407 | 1408 | var core = __webpack_require__(37); 1409 | var global = __webpack_require__(27); 1410 | var SHARED = '__core-js_shared__'; 1411 | var store = global[SHARED] || (global[SHARED] = {}); 1412 | 1413 | (module.exports = function (key, value) { 1414 | return store[key] || (store[key] = value !== undefined ? value : {}); 1415 | })('versions', []).push({ 1416 | version: core.version, 1417 | mode: __webpack_require__(38) ? 'pure' : 'global', 1418 | copyright: '© 2019 Denis Pushkarev (zloirock.ru)' 1419 | }); 1420 | 1421 | 1422 | /***/ }), 1423 | /* 37 */ 1424 | /***/ (function(module, exports) { 1425 | 1426 | var core = module.exports = { version: '2.6.5' }; 1427 | if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef 1428 | 1429 | 1430 | /***/ }), 1431 | /* 38 */ 1432 | /***/ (function(module, exports) { 1433 | 1434 | module.exports = false; 1435 | 1436 | 1437 | /***/ }), 1438 | /* 39 */ 1439 | /***/ (function(module, exports, __webpack_require__) { 1440 | 1441 | "use strict"; 1442 | 1443 | 1444 | var isRegExp = __webpack_require__(40); 1445 | var anObject = __webpack_require__(23); 1446 | var speciesConstructor = __webpack_require__(43); 1447 | var advanceStringIndex = __webpack_require__(45); 1448 | var toLength = __webpack_require__(49); 1449 | var callRegExpExec = __webpack_require__(50); 1450 | var regexpExec = __webpack_require__(52); 1451 | var fails = __webpack_require__(21); 1452 | var $min = Math.min; 1453 | var $push = [].push; 1454 | var $SPLIT = 'split'; 1455 | var LENGTH = 'length'; 1456 | var LAST_INDEX = 'lastIndex'; 1457 | var MAX_UINT32 = 0xffffffff; 1458 | 1459 | // babel-minify transpiles RegExp('x', 'y') -> /x/y and it causes SyntaxError 1460 | var SUPPORTS_Y = !fails(function () { RegExp(MAX_UINT32, 'y'); }); 1461 | 1462 | // @@split logic 1463 | __webpack_require__(53)('split', 2, function (defined, SPLIT, $split, maybeCallNative) { 1464 | var internalSplit; 1465 | if ( 1466 | 'abbc'[$SPLIT](/(b)*/)[1] == 'c' || 1467 | 'test'[$SPLIT](/(?:)/, -1)[LENGTH] != 4 || 1468 | 'ab'[$SPLIT](/(?:ab)*/)[LENGTH] != 2 || 1469 | '.'[$SPLIT](/(.?)(.?)/)[LENGTH] != 4 || 1470 | '.'[$SPLIT](/()()/)[LENGTH] > 1 || 1471 | ''[$SPLIT](/.?/)[LENGTH] 1472 | ) { 1473 | // based on es5-shim implementation, need to rework it 1474 | internalSplit = function (separator, limit) { 1475 | var string = String(this); 1476 | if (separator === undefined && limit === 0) return []; 1477 | // If `separator` is not a regex, use native split 1478 | if (!isRegExp(separator)) return $split.call(string, separator, limit); 1479 | var output = []; 1480 | var flags = (separator.ignoreCase ? 'i' : '') + 1481 | (separator.multiline ? 'm' : '') + 1482 | (separator.unicode ? 'u' : '') + 1483 | (separator.sticky ? 'y' : ''); 1484 | var lastLastIndex = 0; 1485 | var splitLimit = limit === undefined ? MAX_UINT32 : limit >>> 0; 1486 | // Make `global` and avoid `lastIndex` issues by working with a copy 1487 | var separatorCopy = new RegExp(separator.source, flags + 'g'); 1488 | var match, lastIndex, lastLength; 1489 | while (match = regexpExec.call(separatorCopy, string)) { 1490 | lastIndex = separatorCopy[LAST_INDEX]; 1491 | if (lastIndex > lastLastIndex) { 1492 | output.push(string.slice(lastLastIndex, match.index)); 1493 | if (match[LENGTH] > 1 && match.index < string[LENGTH]) $push.apply(output, match.slice(1)); 1494 | lastLength = match[0][LENGTH]; 1495 | lastLastIndex = lastIndex; 1496 | if (output[LENGTH] >= splitLimit) break; 1497 | } 1498 | if (separatorCopy[LAST_INDEX] === match.index) separatorCopy[LAST_INDEX]++; // Avoid an infinite loop 1499 | } 1500 | if (lastLastIndex === string[LENGTH]) { 1501 | if (lastLength || !separatorCopy.test('')) output.push(''); 1502 | } else output.push(string.slice(lastLastIndex)); 1503 | return output[LENGTH] > splitLimit ? output.slice(0, splitLimit) : output; 1504 | }; 1505 | // Chakra, V8 1506 | } else if ('0'[$SPLIT](undefined, 0)[LENGTH]) { 1507 | internalSplit = function (separator, limit) { 1508 | return separator === undefined && limit === 0 ? [] : $split.call(this, separator, limit); 1509 | }; 1510 | } else { 1511 | internalSplit = $split; 1512 | } 1513 | 1514 | return [ 1515 | // `String.prototype.split` method 1516 | // https://tc39.github.io/ecma262/#sec-string.prototype.split 1517 | function split(separator, limit) { 1518 | var O = defined(this); 1519 | var splitter = separator == undefined ? undefined : separator[SPLIT]; 1520 | return splitter !== undefined 1521 | ? splitter.call(separator, O, limit) 1522 | : internalSplit.call(String(O), separator, limit); 1523 | }, 1524 | // `RegExp.prototype[@@split]` method 1525 | // https://tc39.github.io/ecma262/#sec-regexp.prototype-@@split 1526 | // 1527 | // NOTE: This cannot be properly polyfilled in engines that don't support 1528 | // the 'y' flag. 1529 | function (regexp, limit) { 1530 | var res = maybeCallNative(internalSplit, regexp, this, limit, internalSplit !== $split); 1531 | if (res.done) return res.value; 1532 | 1533 | var rx = anObject(regexp); 1534 | var S = String(this); 1535 | var C = speciesConstructor(rx, RegExp); 1536 | 1537 | var unicodeMatching = rx.unicode; 1538 | var flags = (rx.ignoreCase ? 'i' : '') + 1539 | (rx.multiline ? 'm' : '') + 1540 | (rx.unicode ? 'u' : '') + 1541 | (SUPPORTS_Y ? 'y' : 'g'); 1542 | 1543 | // ^(? + rx + ) is needed, in combination with some S slicing, to 1544 | // simulate the 'y' flag. 1545 | var splitter = new C(SUPPORTS_Y ? rx : '^(?:' + rx.source + ')', flags); 1546 | var lim = limit === undefined ? MAX_UINT32 : limit >>> 0; 1547 | if (lim === 0) return []; 1548 | if (S.length === 0) return callRegExpExec(splitter, S) === null ? [S] : []; 1549 | var p = 0; 1550 | var q = 0; 1551 | var A = []; 1552 | while (q < S.length) { 1553 | splitter.lastIndex = SUPPORTS_Y ? q : 0; 1554 | var z = callRegExpExec(splitter, SUPPORTS_Y ? S : S.slice(q)); 1555 | var e; 1556 | if ( 1557 | z === null || 1558 | (e = $min(toLength(splitter.lastIndex + (SUPPORTS_Y ? 0 : q)), S.length)) === p 1559 | ) { 1560 | q = advanceStringIndex(S, q, unicodeMatching); 1561 | } else { 1562 | A.push(S.slice(p, q)); 1563 | if (A.length === lim) return A; 1564 | for (var i = 1; i <= z.length - 1; i++) { 1565 | A.push(z[i]); 1566 | if (A.length === lim) return A; 1567 | } 1568 | q = p = e; 1569 | } 1570 | } 1571 | A.push(S.slice(p)); 1572 | return A; 1573 | } 1574 | ]; 1575 | }); 1576 | 1577 | 1578 | /***/ }), 1579 | /* 40 */ 1580 | /***/ (function(module, exports, __webpack_require__) { 1581 | 1582 | // 7.2.8 IsRegExp(argument) 1583 | var isObject = __webpack_require__(24); 1584 | var cof = __webpack_require__(41); 1585 | var MATCH = __webpack_require__(42)('match'); 1586 | module.exports = function (it) { 1587 | var isRegExp; 1588 | return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : cof(it) == 'RegExp'); 1589 | }; 1590 | 1591 | 1592 | /***/ }), 1593 | /* 41 */ 1594 | /***/ (function(module, exports) { 1595 | 1596 | var toString = {}.toString; 1597 | 1598 | module.exports = function (it) { 1599 | return toString.call(it).slice(8, -1); 1600 | }; 1601 | 1602 | 1603 | /***/ }), 1604 | /* 42 */ 1605 | /***/ (function(module, exports, __webpack_require__) { 1606 | 1607 | var store = __webpack_require__(36)('wks'); 1608 | var uid = __webpack_require__(34); 1609 | var Symbol = __webpack_require__(27).Symbol; 1610 | var USE_SYMBOL = typeof Symbol == 'function'; 1611 | 1612 | var $exports = module.exports = function (name) { 1613 | return store[name] || (store[name] = 1614 | USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); 1615 | }; 1616 | 1617 | $exports.store = store; 1618 | 1619 | 1620 | /***/ }), 1621 | /* 43 */ 1622 | /***/ (function(module, exports, __webpack_require__) { 1623 | 1624 | // 7.3.20 SpeciesConstructor(O, defaultConstructor) 1625 | var anObject = __webpack_require__(23); 1626 | var aFunction = __webpack_require__(44); 1627 | var SPECIES = __webpack_require__(42)('species'); 1628 | module.exports = function (O, D) { 1629 | var C = anObject(O).constructor; 1630 | var S; 1631 | return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? D : aFunction(S); 1632 | }; 1633 | 1634 | 1635 | /***/ }), 1636 | /* 44 */ 1637 | /***/ (function(module, exports) { 1638 | 1639 | module.exports = function (it) { 1640 | if (typeof it != 'function') throw TypeError(it + ' is not a function!'); 1641 | return it; 1642 | }; 1643 | 1644 | 1645 | /***/ }), 1646 | /* 45 */ 1647 | /***/ (function(module, exports, __webpack_require__) { 1648 | 1649 | "use strict"; 1650 | 1651 | var at = __webpack_require__(46)(true); 1652 | 1653 | // `AdvanceStringIndex` abstract operation 1654 | // https://tc39.github.io/ecma262/#sec-advancestringindex 1655 | module.exports = function (S, index, unicode) { 1656 | return index + (unicode ? at(S, index).length : 1); 1657 | }; 1658 | 1659 | 1660 | /***/ }), 1661 | /* 46 */ 1662 | /***/ (function(module, exports, __webpack_require__) { 1663 | 1664 | var toInteger = __webpack_require__(47); 1665 | var defined = __webpack_require__(48); 1666 | // true -> String#at 1667 | // false -> String#codePointAt 1668 | module.exports = function (TO_STRING) { 1669 | return function (that, pos) { 1670 | var s = String(defined(that)); 1671 | var i = toInteger(pos); 1672 | var l = s.length; 1673 | var a, b; 1674 | if (i < 0 || i >= l) return TO_STRING ? '' : undefined; 1675 | a = s.charCodeAt(i); 1676 | return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff 1677 | ? TO_STRING ? s.charAt(i) : a 1678 | : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000; 1679 | }; 1680 | }; 1681 | 1682 | 1683 | /***/ }), 1684 | /* 47 */ 1685 | /***/ (function(module, exports) { 1686 | 1687 | // 7.1.4 ToInteger 1688 | var ceil = Math.ceil; 1689 | var floor = Math.floor; 1690 | module.exports = function (it) { 1691 | return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); 1692 | }; 1693 | 1694 | 1695 | /***/ }), 1696 | /* 48 */ 1697 | /***/ (function(module, exports) { 1698 | 1699 | // 7.2.1 RequireObjectCoercible(argument) 1700 | module.exports = function (it) { 1701 | if (it == undefined) throw TypeError("Can't call method on " + it); 1702 | return it; 1703 | }; 1704 | 1705 | 1706 | /***/ }), 1707 | /* 49 */ 1708 | /***/ (function(module, exports, __webpack_require__) { 1709 | 1710 | // 7.1.15 ToLength 1711 | var toInteger = __webpack_require__(47); 1712 | var min = Math.min; 1713 | module.exports = function (it) { 1714 | return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 1715 | }; 1716 | 1717 | 1718 | /***/ }), 1719 | /* 50 */ 1720 | /***/ (function(module, exports, __webpack_require__) { 1721 | 1722 | "use strict"; 1723 | 1724 | 1725 | var classof = __webpack_require__(51); 1726 | var builtinExec = RegExp.prototype.exec; 1727 | 1728 | // `RegExpExec` abstract operation 1729 | // https://tc39.github.io/ecma262/#sec-regexpexec 1730 | module.exports = function (R, S) { 1731 | var exec = R.exec; 1732 | if (typeof exec === 'function') { 1733 | var result = exec.call(R, S); 1734 | if (typeof result !== 'object') { 1735 | throw new TypeError('RegExp exec method returned something other than an Object or null'); 1736 | } 1737 | return result; 1738 | } 1739 | if (classof(R) !== 'RegExp') { 1740 | throw new TypeError('RegExp#exec called on incompatible receiver'); 1741 | } 1742 | return builtinExec.call(R, S); 1743 | }; 1744 | 1745 | 1746 | /***/ }), 1747 | /* 51 */ 1748 | /***/ (function(module, exports, __webpack_require__) { 1749 | 1750 | // getting tag from 19.1.3.6 Object.prototype.toString() 1751 | var cof = __webpack_require__(41); 1752 | var TAG = __webpack_require__(42)('toStringTag'); 1753 | // ES3 wrong here 1754 | var ARG = cof(function () { return arguments; }()) == 'Arguments'; 1755 | 1756 | // fallback for IE11 Script Access Denied error 1757 | var tryGet = function (it, key) { 1758 | try { 1759 | return it[key]; 1760 | } catch (e) { /* empty */ } 1761 | }; 1762 | 1763 | module.exports = function (it) { 1764 | var O, T, B; 1765 | return it === undefined ? 'Undefined' : it === null ? 'Null' 1766 | // @@toStringTag case 1767 | : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T 1768 | // builtinTag case 1769 | : ARG ? cof(O) 1770 | // ES3 arguments fallback 1771 | : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B; 1772 | }; 1773 | 1774 | 1775 | /***/ }), 1776 | /* 52 */ 1777 | /***/ (function(module, exports, __webpack_require__) { 1778 | 1779 | "use strict"; 1780 | 1781 | 1782 | var regexpFlags = __webpack_require__(29); 1783 | 1784 | var nativeExec = RegExp.prototype.exec; 1785 | // This always refers to the native implementation, because the 1786 | // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js, 1787 | // which loads this file before patching the method. 1788 | var nativeReplace = String.prototype.replace; 1789 | 1790 | var patchedExec = nativeExec; 1791 | 1792 | var LAST_INDEX = 'lastIndex'; 1793 | 1794 | var UPDATES_LAST_INDEX_WRONG = (function () { 1795 | var re1 = /a/, 1796 | re2 = /b*/g; 1797 | nativeExec.call(re1, 'a'); 1798 | nativeExec.call(re2, 'a'); 1799 | return re1[LAST_INDEX] !== 0 || re2[LAST_INDEX] !== 0; 1800 | })(); 1801 | 1802 | // nonparticipating capturing group, copied from es5-shim's String#split patch. 1803 | var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined; 1804 | 1805 | var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED; 1806 | 1807 | if (PATCH) { 1808 | patchedExec = function exec(str) { 1809 | var re = this; 1810 | var lastIndex, reCopy, match, i; 1811 | 1812 | if (NPCG_INCLUDED) { 1813 | reCopy = new RegExp('^' + re.source + '$(?!\\s)', regexpFlags.call(re)); 1814 | } 1815 | if (UPDATES_LAST_INDEX_WRONG) lastIndex = re[LAST_INDEX]; 1816 | 1817 | match = nativeExec.call(re, str); 1818 | 1819 | if (UPDATES_LAST_INDEX_WRONG && match) { 1820 | re[LAST_INDEX] = re.global ? match.index + match[0].length : lastIndex; 1821 | } 1822 | if (NPCG_INCLUDED && match && match.length > 1) { 1823 | // Fix browsers whose `exec` methods don't consistently return `undefined` 1824 | // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/ 1825 | // eslint-disable-next-line no-loop-func 1826 | nativeReplace.call(match[0], reCopy, function () { 1827 | for (i = 1; i < arguments.length - 2; i++) { 1828 | if (arguments[i] === undefined) match[i] = undefined; 1829 | } 1830 | }); 1831 | } 1832 | 1833 | return match; 1834 | }; 1835 | } 1836 | 1837 | module.exports = patchedExec; 1838 | 1839 | 1840 | /***/ }), 1841 | /* 53 */ 1842 | /***/ (function(module, exports, __webpack_require__) { 1843 | 1844 | "use strict"; 1845 | 1846 | __webpack_require__(54); 1847 | var redefine = __webpack_require__(30); 1848 | var hide = __webpack_require__(31); 1849 | var fails = __webpack_require__(21); 1850 | var defined = __webpack_require__(48); 1851 | var wks = __webpack_require__(42); 1852 | var regexpExec = __webpack_require__(52); 1853 | 1854 | var SPECIES = wks('species'); 1855 | 1856 | var REPLACE_SUPPORTS_NAMED_GROUPS = !fails(function () { 1857 | // #replace needs built-in support for named groups. 1858 | // #match works fine because it just return the exec results, even if it has 1859 | // a "grops" property. 1860 | var re = /./; 1861 | re.exec = function () { 1862 | var result = []; 1863 | result.groups = { a: '7' }; 1864 | return result; 1865 | }; 1866 | return ''.replace(re, '$') !== '7'; 1867 | }); 1868 | 1869 | var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = (function () { 1870 | // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec 1871 | var re = /(?:)/; 1872 | var originalExec = re.exec; 1873 | re.exec = function () { return originalExec.apply(this, arguments); }; 1874 | var result = 'ab'.split(re); 1875 | return result.length === 2 && result[0] === 'a' && result[1] === 'b'; 1876 | })(); 1877 | 1878 | module.exports = function (KEY, length, exec) { 1879 | var SYMBOL = wks(KEY); 1880 | 1881 | var DELEGATES_TO_SYMBOL = !fails(function () { 1882 | // String methods call symbol-named RegEp methods 1883 | var O = {}; 1884 | O[SYMBOL] = function () { return 7; }; 1885 | return ''[KEY](O) != 7; 1886 | }); 1887 | 1888 | var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL ? !fails(function () { 1889 | // Symbol-named RegExp methods call .exec 1890 | var execCalled = false; 1891 | var re = /a/; 1892 | re.exec = function () { execCalled = true; return null; }; 1893 | if (KEY === 'split') { 1894 | // RegExp[@@split] doesn't call the regex's exec method, but first creates 1895 | // a new one. We need to return the patched regex when creating the new one. 1896 | re.constructor = {}; 1897 | re.constructor[SPECIES] = function () { return re; }; 1898 | } 1899 | re[SYMBOL](''); 1900 | return !execCalled; 1901 | }) : undefined; 1902 | 1903 | if ( 1904 | !DELEGATES_TO_SYMBOL || 1905 | !DELEGATES_TO_EXEC || 1906 | (KEY === 'replace' && !REPLACE_SUPPORTS_NAMED_GROUPS) || 1907 | (KEY === 'split' && !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC) 1908 | ) { 1909 | var nativeRegExpMethod = /./[SYMBOL]; 1910 | var fns = exec( 1911 | defined, 1912 | SYMBOL, 1913 | ''[KEY], 1914 | function maybeCallNative(nativeMethod, regexp, str, arg2, forceStringMethod) { 1915 | if (regexp.exec === regexpExec) { 1916 | if (DELEGATES_TO_SYMBOL && !forceStringMethod) { 1917 | // The native String method already delegates to @@method (this 1918 | // polyfilled function), leasing to infinite recursion. 1919 | // We avoid it by directly calling the native @@method method. 1920 | return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) }; 1921 | } 1922 | return { done: true, value: nativeMethod.call(str, regexp, arg2) }; 1923 | } 1924 | return { done: false }; 1925 | } 1926 | ); 1927 | var strfn = fns[0]; 1928 | var rxfn = fns[1]; 1929 | 1930 | redefine(String.prototype, KEY, strfn); 1931 | hide(RegExp.prototype, SYMBOL, length == 2 1932 | // 21.2.5.8 RegExp.prototype[@@replace](string, replaceValue) 1933 | // 21.2.5.11 RegExp.prototype[@@split](string, limit) 1934 | ? function (string, arg) { return rxfn.call(string, this, arg); } 1935 | // 21.2.5.6 RegExp.prototype[@@match](string) 1936 | // 21.2.5.9 RegExp.prototype[@@search](string) 1937 | : function (string) { return rxfn.call(string, this); } 1938 | ); 1939 | } 1940 | }; 1941 | 1942 | 1943 | /***/ }), 1944 | /* 54 */ 1945 | /***/ (function(module, exports, __webpack_require__) { 1946 | 1947 | "use strict"; 1948 | 1949 | var regexpExec = __webpack_require__(52); 1950 | __webpack_require__(55)({ 1951 | target: 'RegExp', 1952 | proto: true, 1953 | forced: regexpExec !== /./.exec 1954 | }, { 1955 | exec: regexpExec 1956 | }); 1957 | 1958 | 1959 | /***/ }), 1960 | /* 55 */ 1961 | /***/ (function(module, exports, __webpack_require__) { 1962 | 1963 | var global = __webpack_require__(27); 1964 | var core = __webpack_require__(37); 1965 | var hide = __webpack_require__(31); 1966 | var redefine = __webpack_require__(30); 1967 | var ctx = __webpack_require__(56); 1968 | var PROTOTYPE = 'prototype'; 1969 | 1970 | var $export = function (type, name, source) { 1971 | var IS_FORCED = type & $export.F; 1972 | var IS_GLOBAL = type & $export.G; 1973 | var IS_STATIC = type & $export.S; 1974 | var IS_PROTO = type & $export.P; 1975 | var IS_BIND = type & $export.B; 1976 | var target = IS_GLOBAL ? global : IS_STATIC ? global[name] || (global[name] = {}) : (global[name] || {})[PROTOTYPE]; 1977 | var exports = IS_GLOBAL ? core : core[name] || (core[name] = {}); 1978 | var expProto = exports[PROTOTYPE] || (exports[PROTOTYPE] = {}); 1979 | var key, own, out, exp; 1980 | if (IS_GLOBAL) source = name; 1981 | for (key in source) { 1982 | // contains in native 1983 | own = !IS_FORCED && target && target[key] !== undefined; 1984 | // export native or passed 1985 | out = (own ? target : source)[key]; 1986 | // bind timers to global for call from export context 1987 | exp = IS_BIND && own ? ctx(out, global) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; 1988 | // extend global 1989 | if (target) redefine(target, key, out, type & $export.U); 1990 | // export 1991 | if (exports[key] != out) hide(exports, key, exp); 1992 | if (IS_PROTO && expProto[key] != out) expProto[key] = out; 1993 | } 1994 | }; 1995 | global.core = core; 1996 | // type bitmap 1997 | $export.F = 1; // forced 1998 | $export.G = 2; // global 1999 | $export.S = 4; // static 2000 | $export.P = 8; // proto 2001 | $export.B = 16; // bind 2002 | $export.W = 32; // wrap 2003 | $export.U = 64; // safe 2004 | $export.R = 128; // real proto method for `library` 2005 | module.exports = $export; 2006 | 2007 | 2008 | /***/ }), 2009 | /* 56 */ 2010 | /***/ (function(module, exports, __webpack_require__) { 2011 | 2012 | // optional / simple context binding 2013 | var aFunction = __webpack_require__(44); 2014 | module.exports = function (fn, that, length) { 2015 | aFunction(fn); 2016 | if (that === undefined) return fn; 2017 | switch (length) { 2018 | case 1: return function (a) { 2019 | return fn.call(that, a); 2020 | }; 2021 | case 2: return function (a, b) { 2022 | return fn.call(that, a, b); 2023 | }; 2024 | case 3: return function (a, b, c) { 2025 | return fn.call(that, a, b, c); 2026 | }; 2027 | } 2028 | return function (/* ...args */) { 2029 | return fn.apply(that, arguments); 2030 | }; 2031 | }; 2032 | 2033 | 2034 | /***/ }), 2035 | /* 57 */ 2036 | /***/ (function(module, exports, __webpack_require__) { 2037 | 2038 | var global = __webpack_require__(27); 2039 | var inheritIfRequired = __webpack_require__(58); 2040 | var dP = __webpack_require__(22).f; 2041 | var gOPN = __webpack_require__(64).f; 2042 | var isRegExp = __webpack_require__(40); 2043 | var $flags = __webpack_require__(29); 2044 | var $RegExp = global.RegExp; 2045 | var Base = $RegExp; 2046 | var proto = $RegExp.prototype; 2047 | var re1 = /a/g; 2048 | var re2 = /a/g; 2049 | // "new" creates a new object, old webkit buggy here 2050 | var CORRECT_NEW = new $RegExp(re1) !== re1; 2051 | 2052 | if (__webpack_require__(20) && (!CORRECT_NEW || __webpack_require__(21)(function () { 2053 | re2[__webpack_require__(42)('match')] = false; 2054 | // RegExp constructor can alter flags and IsRegExp works correct with @@match 2055 | return $RegExp(re1) != re1 || $RegExp(re2) == re2 || $RegExp(re1, 'i') != '/a/i'; 2056 | }))) { 2057 | $RegExp = function RegExp(p, f) { 2058 | var tiRE = this instanceof $RegExp; 2059 | var piRE = isRegExp(p); 2060 | var fiU = f === undefined; 2061 | return !tiRE && piRE && p.constructor === $RegExp && fiU ? p 2062 | : inheritIfRequired(CORRECT_NEW 2063 | ? new Base(piRE && !fiU ? p.source : p, f) 2064 | : Base((piRE = p instanceof $RegExp) ? p.source : p, piRE && fiU ? $flags.call(p) : f) 2065 | , tiRE ? this : proto, $RegExp); 2066 | }; 2067 | var proxy = function (key) { 2068 | key in $RegExp || dP($RegExp, key, { 2069 | configurable: true, 2070 | get: function () { return Base[key]; }, 2071 | set: function (it) { Base[key] = it; } 2072 | }); 2073 | }; 2074 | for (var keys = gOPN(Base), i = 0; keys.length > i;) proxy(keys[i++]); 2075 | proto.constructor = $RegExp; 2076 | $RegExp.prototype = proto; 2077 | __webpack_require__(30)(global, 'RegExp', $RegExp); 2078 | } 2079 | 2080 | __webpack_require__(70)('RegExp'); 2081 | 2082 | 2083 | /***/ }), 2084 | /* 58 */ 2085 | /***/ (function(module, exports, __webpack_require__) { 2086 | 2087 | var isObject = __webpack_require__(24); 2088 | var setPrototypeOf = __webpack_require__(59).set; 2089 | module.exports = function (that, target, C) { 2090 | var S = target.constructor; 2091 | var P; 2092 | if (S !== C && typeof S == 'function' && (P = S.prototype) !== C.prototype && isObject(P) && setPrototypeOf) { 2093 | setPrototypeOf(that, P); 2094 | } return that; 2095 | }; 2096 | 2097 | 2098 | /***/ }), 2099 | /* 59 */ 2100 | /***/ (function(module, exports, __webpack_require__) { 2101 | 2102 | // Works with __proto__ only. Old v8 can't work with null proto objects. 2103 | /* eslint-disable no-proto */ 2104 | var isObject = __webpack_require__(24); 2105 | var anObject = __webpack_require__(23); 2106 | var check = function (O, proto) { 2107 | anObject(O); 2108 | if (!isObject(proto) && proto !== null) throw TypeError(proto + ": can't set as prototype!"); 2109 | }; 2110 | module.exports = { 2111 | set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line 2112 | function (test, buggy, set) { 2113 | try { 2114 | set = __webpack_require__(56)(Function.call, __webpack_require__(60).f(Object.prototype, '__proto__').set, 2); 2115 | set(test, []); 2116 | buggy = !(test instanceof Array); 2117 | } catch (e) { buggy = true; } 2118 | return function setPrototypeOf(O, proto) { 2119 | check(O, proto); 2120 | if (buggy) O.__proto__ = proto; 2121 | else set(O, proto); 2122 | return O; 2123 | }; 2124 | }({}, false) : undefined), 2125 | check: check 2126 | }; 2127 | 2128 | 2129 | /***/ }), 2130 | /* 60 */ 2131 | /***/ (function(module, exports, __webpack_require__) { 2132 | 2133 | var pIE = __webpack_require__(61); 2134 | var createDesc = __webpack_require__(32); 2135 | var toIObject = __webpack_require__(62); 2136 | var toPrimitive = __webpack_require__(28); 2137 | var has = __webpack_require__(33); 2138 | var IE8_DOM_DEFINE = __webpack_require__(25); 2139 | var gOPD = Object.getOwnPropertyDescriptor; 2140 | 2141 | exports.f = __webpack_require__(20) ? gOPD : function getOwnPropertyDescriptor(O, P) { 2142 | O = toIObject(O); 2143 | P = toPrimitive(P, true); 2144 | if (IE8_DOM_DEFINE) try { 2145 | return gOPD(O, P); 2146 | } catch (e) { /* empty */ } 2147 | if (has(O, P)) return createDesc(!pIE.f.call(O, P), O[P]); 2148 | }; 2149 | 2150 | 2151 | /***/ }), 2152 | /* 61 */ 2153 | /***/ (function(module, exports) { 2154 | 2155 | exports.f = {}.propertyIsEnumerable; 2156 | 2157 | 2158 | /***/ }), 2159 | /* 62 */ 2160 | /***/ (function(module, exports, __webpack_require__) { 2161 | 2162 | // to indexed object, toObject with fallback for non-array-like ES3 strings 2163 | var IObject = __webpack_require__(63); 2164 | var defined = __webpack_require__(48); 2165 | module.exports = function (it) { 2166 | return IObject(defined(it)); 2167 | }; 2168 | 2169 | 2170 | /***/ }), 2171 | /* 63 */ 2172 | /***/ (function(module, exports, __webpack_require__) { 2173 | 2174 | // fallback for non-array-like ES3 and non-enumerable old V8 strings 2175 | var cof = __webpack_require__(41); 2176 | // eslint-disable-next-line no-prototype-builtins 2177 | module.exports = Object('z').propertyIsEnumerable(0) ? Object : function (it) { 2178 | return cof(it) == 'String' ? it.split('') : Object(it); 2179 | }; 2180 | 2181 | 2182 | /***/ }), 2183 | /* 64 */ 2184 | /***/ (function(module, exports, __webpack_require__) { 2185 | 2186 | // 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O) 2187 | var $keys = __webpack_require__(65); 2188 | var hiddenKeys = __webpack_require__(69).concat('length', 'prototype'); 2189 | 2190 | exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) { 2191 | return $keys(O, hiddenKeys); 2192 | }; 2193 | 2194 | 2195 | /***/ }), 2196 | /* 65 */ 2197 | /***/ (function(module, exports, __webpack_require__) { 2198 | 2199 | var has = __webpack_require__(33); 2200 | var toIObject = __webpack_require__(62); 2201 | var arrayIndexOf = __webpack_require__(66)(false); 2202 | var IE_PROTO = __webpack_require__(68)('IE_PROTO'); 2203 | 2204 | module.exports = function (object, names) { 2205 | var O = toIObject(object); 2206 | var i = 0; 2207 | var result = []; 2208 | var key; 2209 | for (key in O) if (key != IE_PROTO) has(O, key) && result.push(key); 2210 | // Don't enum bug & hidden keys 2211 | while (names.length > i) if (has(O, key = names[i++])) { 2212 | ~arrayIndexOf(result, key) || result.push(key); 2213 | } 2214 | return result; 2215 | }; 2216 | 2217 | 2218 | /***/ }), 2219 | /* 66 */ 2220 | /***/ (function(module, exports, __webpack_require__) { 2221 | 2222 | // false -> Array#indexOf 2223 | // true -> Array#includes 2224 | var toIObject = __webpack_require__(62); 2225 | var toLength = __webpack_require__(49); 2226 | var toAbsoluteIndex = __webpack_require__(67); 2227 | module.exports = function (IS_INCLUDES) { 2228 | return function ($this, el, fromIndex) { 2229 | var O = toIObject($this); 2230 | var length = toLength(O.length); 2231 | var index = toAbsoluteIndex(fromIndex, length); 2232 | var value; 2233 | // Array#includes uses SameValueZero equality algorithm 2234 | // eslint-disable-next-line no-self-compare 2235 | if (IS_INCLUDES && el != el) while (length > index) { 2236 | value = O[index++]; 2237 | // eslint-disable-next-line no-self-compare 2238 | if (value != value) return true; 2239 | // Array#indexOf ignores holes, Array#includes - not 2240 | } else for (;length > index; index++) if (IS_INCLUDES || index in O) { 2241 | if (O[index] === el) return IS_INCLUDES || index || 0; 2242 | } return !IS_INCLUDES && -1; 2243 | }; 2244 | }; 2245 | 2246 | 2247 | /***/ }), 2248 | /* 67 */ 2249 | /***/ (function(module, exports, __webpack_require__) { 2250 | 2251 | var toInteger = __webpack_require__(47); 2252 | var max = Math.max; 2253 | var min = Math.min; 2254 | module.exports = function (index, length) { 2255 | index = toInteger(index); 2256 | return index < 0 ? max(index + length, 0) : min(index, length); 2257 | }; 2258 | 2259 | 2260 | /***/ }), 2261 | /* 68 */ 2262 | /***/ (function(module, exports, __webpack_require__) { 2263 | 2264 | var shared = __webpack_require__(36)('keys'); 2265 | var uid = __webpack_require__(34); 2266 | module.exports = function (key) { 2267 | return shared[key] || (shared[key] = uid(key)); 2268 | }; 2269 | 2270 | 2271 | /***/ }), 2272 | /* 69 */ 2273 | /***/ (function(module, exports) { 2274 | 2275 | // IE 8- don't enum bug keys 2276 | module.exports = ( 2277 | 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf' 2278 | ).split(','); 2279 | 2280 | 2281 | /***/ }), 2282 | /* 70 */ 2283 | /***/ (function(module, exports, __webpack_require__) { 2284 | 2285 | "use strict"; 2286 | 2287 | var global = __webpack_require__(27); 2288 | var dP = __webpack_require__(22); 2289 | var DESCRIPTORS = __webpack_require__(20); 2290 | var SPECIES = __webpack_require__(42)('species'); 2291 | 2292 | module.exports = function (KEY) { 2293 | var C = global[KEY]; 2294 | if (DESCRIPTORS && C && !C[SPECIES]) dP.f(C, SPECIES, { 2295 | configurable: true, 2296 | get: function () { return this; } 2297 | }); 2298 | }; 2299 | 2300 | 2301 | /***/ }), 2302 | /* 71 */ 2303 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 2304 | 2305 | "use strict"; 2306 | __webpack_require__.r(__webpack_exports__); 2307 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "animate", function() { return animate; }); 2308 | var requestAnimationFrame = window.requestAnimationFrame || window.setTimeout; 2309 | var animate = function animate(iterable) { 2310 | var done = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {}; 2311 | var frames = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 60; 2312 | var running = true; 2313 | var frame = 0; 2314 | 2315 | var closure = function closure(timestamp) { 2316 | if (!running) { 2317 | return; 2318 | } 2319 | 2320 | iterable(timestamp, ++frame, frames); 2321 | 2322 | if (frame < frames) { 2323 | requestAnimationFrame(closure, 0); 2324 | } else { 2325 | done(); 2326 | } 2327 | }; 2328 | 2329 | requestAnimationFrame(closure, 0); 2330 | return function () { 2331 | running = false; 2332 | }; 2333 | }; 2334 | 2335 | /***/ }), 2336 | /* 72 */ 2337 | /***/ (function(module, exports, __webpack_require__) { 2338 | 2339 | 2340 | var result = __webpack_require__(73); 2341 | 2342 | if (typeof result === "string") { 2343 | module.exports = result; 2344 | } else { 2345 | module.exports = result.toString(); 2346 | } 2347 | 2348 | 2349 | /***/ }), 2350 | /* 73 */ 2351 | /***/ (function(module, exports, __webpack_require__) { 2352 | 2353 | exports = module.exports = __webpack_require__(12)(false); 2354 | // Module 2355 | exports.push([module.i, ".numeric-input {\n display: inline-block;\n background: #fff;\n width: 12em;\n height: 1.2em;\n padding: 2px;\n text-align: left;\n}\n.numeric-input.readonly,\n.numeric-input.disabled {\n opacity: 0.5;\n pointer-events: none;\n}\n.numeric-input > div {\n position: relative;\n overflow: hidden;\n height: 100%;\n}\n.numeric-input-placeholder {\n color: #757575;\n}\n.numeric-input-text {\n width: 10000%;\n}\n.numeric-input-cursor {\n pointer-events: none;\n position: absolute;\n left: 0;\n top: 0;\n width: 1px;\n height: 100%;\n animation: numeric-input-cursor 1s infinite;\n}\n.numeric-keyboard-actionsheet {\n position: fixed;\n bottom: 0;\n left: 0;\n width: 100%;\n height: 36%;\n}\n.numeric-keyboard-actionsheet > div:first-child {\n height: 100%;\n}\n.numeric-keyboard-actionsheet > div:last-child {\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n transform: translateY(100%);\n box-shadow: 0 -2px 4px 0 #cfd4da;\n}\n@-moz-keyframes numeric-input-cursor {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n@-webkit-keyframes numeric-input-cursor {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n@-o-keyframes numeric-input-cursor {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n@keyframes numeric-input-cursor {\n from {\n opacity: 1;\n }\n to {\n opacity: 0;\n }\n}\n:host {\n display: inline-block;\n background: #fff;\n width: 12em;\n height: 1.2em;\n padding: 2px;\n text-align: left;\n}\n:host .numeric-input {\n display: block;\n background: transparent;\n width: 100%;\n height: 100%;\n padding: 0;\n text-align: inherit;\n}\n", ""]); 2356 | 2357 | 2358 | 2359 | /***/ }) 2360 | /******/ ]); 2361 | }); --------------------------------------------------------------------------------