├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── dist ├── virtual-keyboard.module.d.ts ├── key-press.interface.metadata.json ├── key-press.interface.d.ts ├── key-press.interface.js ├── key-press.interface.js.map ├── index.js.map ├── index.d.ts ├── index.metadata.json ├── index.js ├── virtual-keyboard.service.metadata.json ├── virtual-keyboard.module.js.map ├── virtual-keyboard.service.d.ts ├── virtual-keyboard-key.component.d.ts ├── virtual-keyboard.service.js.map ├── virtual-keyboard.directive.d.ts ├── layouts.d.ts ├── virtual-keyboard-key.component.metadata.json ├── virtual-keyboard.module.metadata.json ├── virtual-keyboard-key.component.js.map ├── layouts.metadata.json ├── virtual-keyboard.directive.metadata.json ├── virtual-keyboard.directive.js.map ├── virtual-keyboard.module.js ├── virtual-keyboard.component.metadata.json ├── virtual-keyboard.service.js ├── virtual-keyboard.component.d.ts ├── layouts.js.map ├── layouts.js ├── virtual-keyboard-key.component.js ├── virtual-keyboard.component.js.map ├── virtual-keyboard.directive.js ├── virtual-keyboard.component.js ├── ng-virtual-keyboard.umd.js └── ng-virtual-keyboard.umd.js.map ├── app ├── favicon.png ├── app.component.scss ├── main.ts ├── webpack.config.js ├── app.component.ts ├── app.component.html └── index.html ├── docs ├── favicon.png └── index.html ├── execute.sh ├── src ├── key-press.interface.ts ├── index.ts ├── virtual-keyboard.module.ts ├── virtual-keyboard.service.ts ├── virtual-keyboard-key.component.ts ├── layouts.ts ├── virtual-keyboard.directive.ts └── virtual-keyboard.component.ts ├── .idea ├── misc.xml ├── vcs.xml ├── jsLibraryMappings.xml ├── modules.xml ├── ng-virtual-keyboard.iml └── inspectionProfiles │ └── Project_Default.xml ├── docker-compose.yml ├── .eslintrc.json ├── CHANGELOG.md ├── Jenkinsfile ├── LICENSE ├── webpack.config.js ├── tsconfig.json ├── tsconfig.ngc.json ├── package.json ├── README.md └── .gitignore /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @by-pinja/architects 2 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.module.d.ts: -------------------------------------------------------------------------------- 1 | export declare class NgVirtualKeyboardModule { 2 | } 3 | -------------------------------------------------------------------------------- /app/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/by-pinja/ng-virtual-keyboard/HEAD/app/favicon.png -------------------------------------------------------------------------------- /docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/by-pinja/ng-virtual-keyboard/HEAD/docs/favicon.png -------------------------------------------------------------------------------- /execute.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker run -it --rm -w /app -v ${PWD}/:/app node:12-alpine3.14 "$@" 3 | -------------------------------------------------------------------------------- /dist/key-press.interface.metadata.json: -------------------------------------------------------------------------------- 1 | [{"__symbolic":"module","version":4,"metadata":{"KeyPressInterface":{"__symbolic":"interface"}}}] -------------------------------------------------------------------------------- /src/key-press.interface.ts: -------------------------------------------------------------------------------- 1 | export interface KeyPressInterface { 2 | special: boolean; 3 | keyValue: string; 4 | key: string; 5 | } 6 | -------------------------------------------------------------------------------- /dist/key-press.interface.d.ts: -------------------------------------------------------------------------------- 1 | export interface KeyPressInterface { 2 | special: boolean; 3 | keyValue: string; 4 | key: string; 5 | } 6 | -------------------------------------------------------------------------------- /dist/key-press.interface.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | //# sourceMappingURL=key-press.interface.js.map -------------------------------------------------------------------------------- /dist/key-press.interface.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"key-press.interface.js","sourceRoot":"","sources":["../src/key-press.interface.ts"],"names":[],"mappings":""} -------------------------------------------------------------------------------- /dist/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,2EAA0E;AAIxE,qCAJO,uDAA0B,CAIP;AAH5B,qEAAoE;AAIlE,kCAJO,iDAAuB,CAIP"} -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import { NgVirtualKeyboardDirective } from './virtual-keyboard.directive'; 2 | import { NgVirtualKeyboardModule } from './virtual-keyboard.module'; 3 | export { NgVirtualKeyboardDirective, NgVirtualKeyboardModule }; 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { NgVirtualKeyboardDirective } from './virtual-keyboard.directive'; 2 | import { NgVirtualKeyboardModule } from './virtual-keyboard.module'; 3 | 4 | export { 5 | NgVirtualKeyboardDirective, 6 | NgVirtualKeyboardModule 7 | } 8 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.7' 2 | 3 | services: 4 | example: 5 | image: node:12-alpine3.14 6 | command: [sh, -cx, "yarn install ; yarn run start"] 7 | ports: 8 | - '4200:4200' 9 | working_dir: /app 10 | volumes: 11 | - ./:/app 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | | Q | A 2 | | ---------------- | ----- 3 | | Bug report? | yes/no 4 | | Feature request? | yes/no 5 | | BC Break report? | yes/no 6 | | RFC? | yes/no 7 | | Library version | x.y.z 8 | 9 | 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /dist/index.metadata.json: -------------------------------------------------------------------------------- 1 | [{"__symbolic":"module","version":4,"metadata":{"NgVirtualKeyboardDirective":{"__symbolic":"reference","module":"./virtual-keyboard.directive","name":"NgVirtualKeyboardDirective","line":4,"character":2},"NgVirtualKeyboardModule":{"__symbolic":"reference","module":"./virtual-keyboard.module","name":"NgVirtualKeyboardModule","line":5,"character":2}}}] -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "parser": "@typescript-eslint/parser", 7 | "parserOptions": { 8 | "ecmaVersion": 12, 9 | "sourceType": "module" 10 | }, 11 | "plugins": [ 12 | "@typescript-eslint" 13 | ], 14 | "rules": { 15 | "quotes": [ 16 | "error", 17 | "single" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /dist/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | var virtual_keyboard_directive_1 = require("./virtual-keyboard.directive"); 4 | exports.NgVirtualKeyboardDirective = virtual_keyboard_directive_1.NgVirtualKeyboardDirective; 5 | var virtual_keyboard_module_1 = require("./virtual-keyboard.module"); 6 | exports.NgVirtualKeyboardModule = virtual_keyboard_module_1.NgVirtualKeyboardModule; 7 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /dist/virtual-keyboard.service.metadata.json: -------------------------------------------------------------------------------- 1 | [{"__symbolic":"module","version":4,"metadata":{"VirtualKeyboardService":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Injectable","line":3,"character":1}}],"members":{"setShift":[{"__symbolic":"method"}],"setCapsLock":[{"__symbolic":"method"}],"toggleShift":[{"__symbolic":"method"}],"toggleCapsLock":[{"__symbolic":"method"}],"setCaretPosition":[{"__symbolic":"method"}],"reset":[{"__symbolic":"method"}]}}}}] -------------------------------------------------------------------------------- /.idea/ng-virtual-keyboard.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/app.component.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | height: 100%; 4 | min-height: 100%; 5 | padding: .5em 1em; 6 | font-family: Roboto, "Helvetica Neue", sans-serif; 7 | flex: 1; 8 | } 9 | 10 | h1, h2, h3, h4, p { 11 | margin: 0 0 .38em; 12 | } 13 | 14 | h2 { 15 | margin-top: .76em; 16 | } 17 | 18 | h4 { 19 | margin-top: .38em; 20 | } 21 | 22 | pre { 23 | border-left: 6px solid #505050; 24 | padding: .38em .76em; 25 | margin: 0 0 .38em .76em; 26 | } 27 | 28 | .text-right { 29 | text-align: right; 30 | } 31 | 32 | .badges { 33 | a { 34 | margin-right: .38em; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.module.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"virtual-keyboard.module.js","sourceRoot":"","sources":["../src/virtual-keyboard.module.ts"],"names":[],"mappings":";;;;;;;;AAAA,sCAAyC;AACzC,0CAA+C;AAC/C,wCAAkE;AAClE,8CAAoG;AACpG,oDAAwD;AAExD,2EAA0E;AAC1E,2EAAwE;AACxE,mFAA+E;AAC/E,uEAAoE;AA6BpE;IAAA;IAAuC,CAAC;IAA3B,uBAAuB;QA3BnC,eAAQ,CAAC;YACR,YAAY,EAAE;gBACZ,uDAA0B;gBAC1B,qDAAwB;gBACxB,4DAA2B;aAC5B;YACD,SAAS,EAAE;gBACT,iDAAsB;aACvB;YACD,OAAO,EAAE;gBACP,qBAAY;gBACZ,mBAAW;gBACX,2BAAmB;gBACnB,8BAAgB;gBAChB,0BAAe;gBACf,0BAAe;gBACf,wBAAa;gBACb,yBAAc;aACf;YACD,eAAe,EAAE;gBACf,qDAAwB;aACzB;YACD,OAAO,EAAE;gBACP,uDAA0B;aAC3B;SACF,CAAC;OAEW,uBAAuB,CAAI;IAAD,8BAAC;CAAA,AAAxC,IAAwC;AAA3B,0DAAuB"} -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | | Q | A 2 | | ------------- | --- 3 | | Branch? | master for new features / tags for bug fixes 4 | | Bug fix? | yes/no 5 | | New feature? | yes/no 6 | | BC breaks? | yes/no 7 | | Deprecations? | yes/no 8 | | Fixed tickets | #... 9 | | License | MIT 10 | 11 | 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [0.12.0] 9 | 10 | ### Changed 11 | 12 | - Migrated to Angular 8 13 | 14 | ## [0.11.0] 15 | 16 | ### Added 17 | 18 | - Added support for keyboard closing event 19 | 20 | ## [0.10.0] 21 | 22 | Accidental release, same as 0.9.1 23 | 24 | ## [0.9.1] 25 | 26 | ### Fixed 27 | 28 | - Fix bug with backspace not updating model 29 | 30 | ## [0.9.0] 31 | 32 | ### Changed 33 | 34 | - Migrated to Angular 7 35 | - Support for Node 12 36 | 37 | ## [0.8.0] 38 | 39 | Start of changelog documentation 40 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | library 'jenkins-ptcs-library@3.1.0' 2 | 3 | podTemplate(label: pod.label, 4 | containers: pod.templates + [ 5 | containerTemplate(name: 'node', image: 'node:12-alpine3.14', ttyEnabled: true, command: '/bin/sh -c', args: 'cat') 6 | ] 7 | ) { 8 | node(pod.label) { 9 | stage('Checkout') { 10 | checkout scm 11 | } 12 | container('node') { 13 | stage('Build') { 14 | sh """ 15 | yarn install 16 | yarn run build 17 | """ 18 | } 19 | stage('Lint') { 20 | sh """ 21 | yarn lint 22 | """ 23 | } 24 | stage('Publish') { 25 | if ("${env.TAG_NAME}".contains("-")) 26 | { 27 | publishTagToNpm("./", "--tag beta") 28 | } 29 | else { 30 | publishTagToNpm() 31 | } 32 | 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Protacon 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 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.service.d.ts: -------------------------------------------------------------------------------- 1 | import { ReplaySubject } from 'rxjs/internal/ReplaySubject'; 2 | export declare class VirtualKeyboardService { 3 | shift$: ReplaySubject; 4 | capsLock$: ReplaySubject; 5 | caretPosition$: ReplaySubject; 6 | private capsLock; 7 | private shift; 8 | /** 9 | * Setter for Shift value, note that this also sets CapsLock value. 10 | * 11 | * @param {boolean} value 12 | */ 13 | setShift(value: boolean): void; 14 | /** 15 | * Setter for CapsLock value 16 | * 17 | * @param {boolean} value 18 | */ 19 | setCapsLock(value: boolean): void; 20 | /** 21 | * Toggle for Shift, note that this also toggles CapsLock 22 | */ 23 | toggleShift(): void; 24 | /** 25 | * Toggle for CapsLock 26 | */ 27 | toggleCapsLock(): void; 28 | /** 29 | * Setter for caret position value. 30 | * 31 | * @param {number} position 32 | */ 33 | setCaretPosition(position: number): void; 34 | /** 35 | * Method to reset Shift and CapsLock values to default ones. 36 | */ 37 | reset(): void; 38 | } 39 | -------------------------------------------------------------------------------- /dist/virtual-keyboard-key.component.d.ts: -------------------------------------------------------------------------------- 1 | import { OnInit, EventEmitter } from '@angular/core'; 2 | import { KeyPressInterface } from './key-press.interface'; 3 | export declare class VirtualKeyboardKeyComponent implements OnInit { 4 | key: string; 5 | disabled: boolean; 6 | keyPress: EventEmitter; 7 | special: boolean; 8 | spacer: boolean; 9 | flexValue: string; 10 | keyValue: string; 11 | icon: string; 12 | text: string; 13 | /** 14 | * Constructor of the class. 15 | */ 16 | constructor(); 17 | /** 18 | * On init life cycle hook, within this we'll initialize following properties: 19 | * - special 20 | * - keyValue 21 | * - flexValue 22 | */ 23 | ngOnInit(): void; 24 | /** 25 | * Method to check if key is disabled or not. 26 | * 27 | * @returns {boolean} 28 | */ 29 | isDisabled(): boolean; 30 | /** 31 | * Method to handle actual "key" press from virtual keyboard. 32 | * 1) Key is "Special", process special key event 33 | * 2) Key is "Normal", append this key value to input 34 | */ 35 | onKeyPress(): void; 36 | } 37 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | let path = require('path'); 2 | let webpack = require('webpack'); 3 | 4 | module.exports = { 5 | entry: { 6 | '@protacon/ng-virtual-keyboard': path.join(__dirname, 'src', 'index.ts'), 7 | }, 8 | resolve: { 9 | extensions: [ 10 | '.ts', 11 | '.js', 12 | '.json', 13 | '.css', 14 | '.html', 15 | ], 16 | }, 17 | /* 18 | resolveLoader: { 19 | root: path.join(__dirname, 'node_modules'), 20 | }, 21 | */ 22 | output: { 23 | path: path.join(__dirname, 'dist'), 24 | filename: 'ng-virtual-keyboard.umd.js', 25 | library: [ 26 | 'ng-virtual-keyboard', 27 | ], 28 | libraryTarget: 'umd', 29 | }, 30 | externals: [ 31 | /^rxjs\//, //.... any other way? rx.umd.min.js does work? 32 | /^@angular\//, 33 | ], 34 | devtool: 'source-map', 35 | module: { 36 | rules: [ 37 | { // Support for .ts files. 38 | test: /\.ts$/, 39 | use: [ 40 | { 41 | loader: 'ts-loader', 42 | }, 43 | { 44 | loader: 'angular2-template-loader', 45 | }, 46 | ], 47 | }, 48 | ], 49 | }, 50 | }; 51 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es5", "es6", "dom"], 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "sourceMap": true, 10 | "pretty": true, 11 | "allowUnreachableCode": true, 12 | "allowUnusedLabels": true, 13 | "noImplicitAny": false, 14 | "noImplicitReturns": false, 15 | "noImplicitUseStrict": false, 16 | "allowSyntheticDefaultImports": true, 17 | "suppressExcessPropertyErrors": true, 18 | "suppressImplicitAnyIndexErrors": true, 19 | "skipDefaultLibCheck": true, 20 | "noEmitHelpers": false, 21 | "isolatedModules": false, 22 | "strictNullChecks": false, 23 | "outDir": "dist", 24 | "baseUrl": "src", 25 | "paths": { 26 | "ProtaconSolutions/ng-virtual-keyboard": ["./index"] 27 | } 28 | }, 29 | "files": [ 30 | "src/index.ts" 31 | ], 32 | "exclude": [ 33 | "node_modules" 34 | ], 35 | "compileOnSave": false, 36 | "buildOnSave": false, 37 | "angularCompilerOptions": { 38 | "strictMetadataEmit": true, 39 | "skipTemplateCodegen": true 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tsconfig.ngc.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es5", "es6", "dom"], 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "declaration": true, 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "sourceMap": true, 11 | "pretty": true, 12 | "allowUnreachableCode": true, 13 | "allowUnusedLabels": true, 14 | "noImplicitAny": false, 15 | "noImplicitReturns": false, 16 | "noImplicitUseStrict": false, 17 | "allowSyntheticDefaultImports": true, 18 | "suppressExcessPropertyErrors": true, 19 | "suppressImplicitAnyIndexErrors": true, 20 | "skipDefaultLibCheck": true, 21 | "noEmitHelpers": false, 22 | "isolatedModules": false, 23 | "strictNullChecks": false, 24 | "outDir": "dist", 25 | "baseUrl": "src", 26 | "paths": { 27 | "ProtaconSolutions/ng-virtual-keyboard": ["./index"] 28 | } 29 | }, 30 | "files": [ 31 | "src/index.ts" 32 | ], 33 | "exclude": [ 34 | "node_modules" 35 | ], 36 | "compileOnSave": false, 37 | "buildOnSave": false, 38 | "angularCompilerOptions": { 39 | "strictMetadataEmit": true, 40 | "skipTemplateCodegen": true 41 | } 42 | } -------------------------------------------------------------------------------- /src/virtual-keyboard.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { ReactiveFormsModule, FormsModule } from '@angular/forms'; 4 | import { MatButtonModule, MatDialogModule, MatIconModule, MatInputModule } from '@angular/material'; 5 | import { FlexLayoutModule } from '@angular/flex-layout'; 6 | 7 | import { NgVirtualKeyboardDirective } from './virtual-keyboard.directive'; 8 | import { VirtualKeyboardComponent } from './virtual-keyboard.component'; 9 | import { VirtualKeyboardKeyComponent } from './virtual-keyboard-key.component'; 10 | import { VirtualKeyboardService } from './virtual-keyboard.service'; 11 | 12 | @NgModule({ 13 | declarations: [ 14 | NgVirtualKeyboardDirective, 15 | VirtualKeyboardComponent, 16 | VirtualKeyboardKeyComponent, 17 | ], 18 | providers: [ 19 | VirtualKeyboardService, 20 | ], 21 | imports: [ 22 | CommonModule, 23 | FormsModule, 24 | ReactiveFormsModule, 25 | FlexLayoutModule, 26 | MatButtonModule, 27 | MatDialogModule, 28 | MatIconModule, 29 | MatInputModule, 30 | ], 31 | entryComponents: [ 32 | VirtualKeyboardComponent, 33 | ], 34 | exports: [ 35 | NgVirtualKeyboardDirective, 36 | ] 37 | }) 38 | 39 | export class NgVirtualKeyboardModule { } 40 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.service.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"virtual-keyboard.service.js","sourceRoot":"","sources":["../src/virtual-keyboard.service.ts"],"names":[],"mappings":";;;;;;;;AAAA,sCAA2C;AAC3C,6DAA4D;AAG5D;IADA;QAES,WAAM,GAA2B,IAAI,6BAAa,CAAC,CAAC,CAAC,CAAC;QACtD,cAAS,GAA2B,IAAI,6BAAa,CAAC,CAAC,CAAC,CAAC;QACzD,mBAAc,GAA0B,IAAI,6BAAa,CAAC,CAAC,CAAC,CAAC;QAE5D,aAAQ,GAAG,KAAK,CAAC;QACjB,UAAK,GAAG,KAAK,CAAC;IAyDxB,CAAC;IAvDC;;;;OAIG;IACI,yCAAQ,GAAf,UAAgB,KAAc;QAC5B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE7B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED;;;;OAIG;IACI,4CAAW,GAAlB,UAAmB,KAAc;QAC/B,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACI,4CAAW,GAAlB;QACE,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAE7B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED;;OAEG;IACI,+CAAc,GAArB;QACE,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED;;;;OAIG;IACI,iDAAgB,GAAvB,UAAwB,QAAgB;QACtC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACI,sCAAK,GAAZ;QACE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IA9DU,sBAAsB;QADlC,iBAAU,EAAE;OACA,sBAAsB,CA+DlC;IAAD,6BAAC;CAAA,AA/DD,IA+DC;AA/DY,wDAAsB"} -------------------------------------------------------------------------------- /dist/virtual-keyboard.directive.d.ts: -------------------------------------------------------------------------------- 1 | import { ElementRef, EventEmitter } from '@angular/core'; 2 | import { MatDialog } from '@angular/material'; 3 | import { KeyboardLayout } from './layouts'; 4 | export declare class NgVirtualKeyboardDirective { 5 | private element; 6 | private dialog; 7 | private opened; 8 | private focus; 9 | layout: KeyboardLayout | string; 10 | placeholder: string; 11 | type: string; 12 | keyboardClose: EventEmitter; 13 | onWindowBlur(): void; 14 | onWindowFocus(): void; 15 | onFocus(): void; 16 | onClick(): void; 17 | /** 18 | * Constructor of the class. 19 | * 20 | * @param {ElementRef} element 21 | * @param {MatDialog} dialog 22 | */ 23 | constructor(element: ElementRef, dialog: MatDialog); 24 | /** 25 | * Method to open virtual keyboard 26 | */ 27 | private openKeyboard; 28 | /** 29 | * Getter for used keyboard layout. 30 | * 31 | * @returns {KeyboardLayout} 32 | */ 33 | private getLayout; 34 | /** 35 | * Getter for used placeholder for virtual keyboard input field. 36 | * 37 | * @returns {string} 38 | */ 39 | private getPlaceHolder; 40 | /** 41 | * Getter for used type for virtual keyboard input field. 42 | * 43 | * @return {string} 44 | */ 45 | private getType; 46 | } 47 | -------------------------------------------------------------------------------- /app/main.ts: -------------------------------------------------------------------------------- 1 | // polyfills, comment the following out for debugging purpose 2 | import 'core-js/es6'; 3 | import 'core-js/es7/reflect'; 4 | import 'zone.js/dist/zone'; 5 | 6 | // The browser platform with a compiler 7 | import { NgModule } from '@angular/core'; 8 | import { FormsModule } from '@angular/forms'; 9 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 10 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 11 | import { BrowserModule } from '@angular/platform-browser'; 12 | import { MatInputModule } from '@angular/material'; 13 | import { FlexLayoutModule } from '@angular/flex-layout'; 14 | 15 | import 'hammerjs'; 16 | import '@angular/material/prebuilt-themes/deeppurple-amber.css'; 17 | 18 | //noinspection TypeScriptCheckImport 19 | import { NgVirtualKeyboardModule } from '@protacon/ng-virtual-keyboard'; 20 | 21 | import { AppComponent } from './app.component'; 22 | 23 | @NgModule({ 24 | imports: [ 25 | BrowserModule, 26 | BrowserAnimationsModule, 27 | FormsModule, 28 | MatInputModule, 29 | FlexLayoutModule, 30 | NgVirtualKeyboardModule, 31 | ], 32 | declarations: [ 33 | AppComponent, 34 | ], 35 | bootstrap: [ 36 | AppComponent, 37 | ], 38 | }) 39 | 40 | export class AppModule { } 41 | 42 | // Compile and launch the module 43 | platformBrowserDynamic() 44 | .bootstrapModule(AppModule) 45 | .then(() => { }) 46 | .catch((error) => console.error(error)); 47 | -------------------------------------------------------------------------------- /dist/layouts.d.ts: -------------------------------------------------------------------------------- 1 | export declare type KeyboardLayout = Array>; 2 | export declare const alphanumericKeyboard: KeyboardLayout; 3 | export declare const alphanumericNordicKeyboard: KeyboardLayout; 4 | export declare const extendedKeyboard: KeyboardLayout; 5 | export declare const extendedNordicKeyboard: KeyboardLayout; 6 | export declare const numericKeyboard: KeyboardLayout; 7 | export declare const phoneKeyboard: KeyboardLayout; 8 | export declare const specialKeys: Array; 9 | export declare const specialKeyIcons: { 10 | Enter: string; 11 | Backspace: string; 12 | Escape: string; 13 | SpaceBar: string; 14 | Shift: string; 15 | }; 16 | export declare const specialKeyTexts: { 17 | CapsLock: string; 18 | }; 19 | export declare const notDisabledSpecialKeys: string[]; 20 | /** 21 | * Helper function to determine if given key is 'Spacer' or not. 22 | * 23 | * @param {string} key 24 | * @returns {boolean} 25 | */ 26 | export declare function isSpacer(key: string): boolean; 27 | /** 28 | * Helper function to determine if given key is special or not. 29 | * 30 | * @param {string} key 31 | * @returns {boolean} 32 | */ 33 | export declare function isSpecial(key: string): boolean; 34 | /** 35 | * Function to change specified layout to CapsLock layout. 36 | * 37 | * @param {KeyboardLayout} layout 38 | * @param {boolean} caps 39 | * @returns {KeyboardLayout} 40 | */ 41 | export declare function keyboardCapsLockLayout(layout: KeyboardLayout, caps: boolean): KeyboardLayout; 42 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /dist/virtual-keyboard-key.component.metadata.json: -------------------------------------------------------------------------------- 1 | [{"__symbolic":"module","version":4,"metadata":{"VirtualKeyboardKeyComponent":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Component","line":5,"character":1},"arguments":[{"selector":"virtual-keyboard-key","template":"\n \n {{ keyValue }}\n \n \n {{ icon }}\n \n {{ text }}\n \n \n ","styles":["\n .mat-button,\n .mat-icon-button,\n .mat-raised-button {\n min-width: 64px;\n min-height: 64px;\n padding: 0;\n margin: 2px;\n font-size: 32px;\n line-height: 32px;\n }\n \n .mat-button.spacer,\n .mat-icon-button.spacer,\n .mat-raised-button.spacer {\n background-color: transparent;\n }\n "]}]}],"members":{"key":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input","line":46,"character":3}}]}],"disabled":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input","line":47,"character":3}}]}],"keyPress":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output","line":48,"character":3}}]}],"__ctor__":[{"__symbolic":"constructor"}],"ngOnInit":[{"__symbolic":"method"}],"isDisabled":[{"__symbolic":"method"}],"onKeyPress":[{"__symbolic":"method"}]}}}}] -------------------------------------------------------------------------------- /src/virtual-keyboard.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { ReplaySubject } from 'rxjs/internal/ReplaySubject'; 3 | 4 | @Injectable() 5 | export class VirtualKeyboardService { 6 | public shift$: ReplaySubject = new ReplaySubject(1); 7 | public capsLock$: ReplaySubject = new ReplaySubject(1); 8 | public caretPosition$: ReplaySubject = new ReplaySubject(1); 9 | 10 | private capsLock = false; 11 | private shift = false; 12 | 13 | /** 14 | * Setter for Shift value, note that this also sets CapsLock value. 15 | * 16 | * @param {boolean} value 17 | */ 18 | public setShift(value: boolean) { 19 | this.shift = value; 20 | this.shift$.next(this.shift); 21 | 22 | this.setCapsLock(this.shift); 23 | } 24 | 25 | /** 26 | * Setter for CapsLock value 27 | * 28 | * @param {boolean} value 29 | */ 30 | public setCapsLock(value: boolean) { 31 | this.capsLock = value; 32 | this.capsLock$.next(value); 33 | } 34 | 35 | /** 36 | * Toggle for Shift, note that this also toggles CapsLock 37 | */ 38 | public toggleShift(): void { 39 | this.shift = !this.shift; 40 | this.shift$.next(this.shift); 41 | 42 | this.setCapsLock(this.shift); 43 | } 44 | 45 | /** 46 | * Toggle for CapsLock 47 | */ 48 | public toggleCapsLock() { 49 | this.capsLock = !this.capsLock; 50 | this.capsLock$.next(this.capsLock); 51 | } 52 | 53 | /** 54 | * Setter for caret position value. 55 | * 56 | * @param {number} position 57 | */ 58 | public setCaretPosition(position: number) { 59 | this.caretPosition$.next(position); 60 | } 61 | 62 | /** 63 | * Method to reset Shift and CapsLock values to default ones. 64 | */ 65 | public reset() { 66 | this.setShift(false); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.module.metadata.json: -------------------------------------------------------------------------------- 1 | [{"__symbolic":"module","version":4,"metadata":{"NgVirtualKeyboardModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":11,"character":1},"arguments":[{"declarations":[{"__symbolic":"reference","module":"./virtual-keyboard.directive","name":"NgVirtualKeyboardDirective","line":13,"character":4},{"__symbolic":"reference","module":"./virtual-keyboard.component","name":"VirtualKeyboardComponent","line":14,"character":4},{"__symbolic":"reference","module":"./virtual-keyboard-key.component","name":"VirtualKeyboardKeyComponent","line":15,"character":4}],"providers":[{"__symbolic":"reference","module":"./virtual-keyboard.service","name":"VirtualKeyboardService","line":18,"character":4}],"imports":[{"__symbolic":"reference","module":"@angular/common","name":"CommonModule","line":21,"character":4},{"__symbolic":"reference","module":"@angular/forms","name":"FormsModule","line":22,"character":4},{"__symbolic":"reference","module":"@angular/forms","name":"ReactiveFormsModule","line":23,"character":4},{"__symbolic":"reference","module":"@angular/flex-layout","name":"FlexLayoutModule","line":24,"character":4},{"__symbolic":"reference","module":"@angular/material","name":"MatButtonModule","line":25,"character":4},{"__symbolic":"reference","module":"@angular/material","name":"MatDialogModule","line":26,"character":4},{"__symbolic":"reference","module":"@angular/material","name":"MatIconModule","line":27,"character":4},{"__symbolic":"reference","module":"@angular/material","name":"MatInputModule","line":28,"character":4}],"entryComponents":[{"__symbolic":"reference","module":"./virtual-keyboard.component","name":"VirtualKeyboardComponent","line":31,"character":4}],"exports":[{"__symbolic":"reference","module":"./virtual-keyboard.directive","name":"NgVirtualKeyboardDirective","line":34,"character":4}]}]}]}}}] -------------------------------------------------------------------------------- /dist/virtual-keyboard-key.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"virtual-keyboard-key.component.js","sourceRoot":"","sources":["../src/virtual-keyboard-key.component.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,sCAA+E;AAG/E,qCAA0G;AA0C1G;IAYE;;OAEG;IACH;QAZU,aAAQ,GAAG,IAAI,mBAAY,EAAqB,CAAC;QAEpD,YAAO,GAAG,KAAK,CAAC;QAChB,WAAM,GAAG,KAAK,CAAC;IASC,CAAC;IAExB;;;;;OAKG;IACI,8CAAQ,GAAf;QACE,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,GAAG,GAAG,CAAC,CAAC;QAEZ,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE;YACvB,IAAI,CAAC,MAAM,GAAG,kBAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,CAAC,OAAO,GAAG,mBAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAEnC,IAAM,OAAO,GAAG,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAE3D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;YAE3B,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE;gBACd,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpC,GAAG,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;aAC5B;SACF;aAAM;YACL,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC;SAC1B;QAED,IAAI,IAAI,CAAC,OAAO,EAAE;YAChB,IAAI,yBAAe,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;gBACjD,IAAI,CAAC,IAAI,GAAG,yBAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;aAC5C;iBAAM,IAAI,yBAAe,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;gBACxD,IAAI,CAAC,IAAI,GAAG,yBAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;aAC5C;SACF;QAED,IAAI,CAAC,SAAS,GAAM,UAAU,GAAG,EAAE,GAAG,GAAG,OAAI,CAAC;IAChD,CAAC;IAED;;;;OAIG;IACI,gDAAU,GAAjB;QACE,IAAI,IAAI,CAAC,MAAM,EAAE;YACf,OAAO,IAAI,CAAC;SACb;aAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,gCAAsB,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE;YAChF,OAAO,KAAK,CAAC;SACd;aAAM;YACL,OAAO,IAAI,CAAC,QAAQ,CAAC;SACtB;IACH,CAAC;IAED;;;;OAIG;IACI,gDAAU,GAAjB;QACE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAC,CAAC,CAAC;IACtF,CAAC;IA3EQ;QAAR,YAAK,EAAE;;4DAAa;IACZ;QAAR,YAAK,EAAE;;iEAAmB;IACjB;QAAT,aAAM,EAAE;;iEAAkD;IAHhD,2BAA2B;QAxCvC,gBAAS,CAAC;YACT,QAAQ,EAAE,sBAAsB;YAChC,QAAQ,EAAE,8ZAiBT;YACD,MAAM,EAAE,CAAC,qWAiBR,CAAC;SACH,CAAC;;OAEW,2BAA2B,CA6EvC;IAAD,kCAAC;CAAA,AA7ED,IA6EC;AA7EY,kEAA2B"} -------------------------------------------------------------------------------- /dist/layouts.metadata.json: -------------------------------------------------------------------------------- 1 | [{"__symbolic":"module","version":4,"metadata":{"KeyboardLayout":{"__symbolic":"interface"},"alphanumericKeyboard":[["1","2","3","4","5","6","7","8","9","0","Backspace:2"],["q","w","e","r","t","y","u","i","o","p","CapsLock:2"],["a","s","d","f","g","h","j","k","l","Spacer","Shift:2"],["z","x","c","v","b","n","m","Spacer:5"]],"alphanumericNordicKeyboard":[["1","2","3","4","5","6","7","8","9","0","Spacer","Backspace:2"],["q","w","e","r","t","y","u","i","o","p","å","CapsLock:2"],["a","s","d","f","g","h","j","k","l","ö","ä","Shift:2"],["z","x","c","v","b","n","m","Spacer:6"]],"extendedKeyboard":[["1","2","3","4","5","6","7","8","9","0","Backspace:2"],["q","w","e","r","t","y","u","i","o","p","CapsLock:2"],["a","s","d","f","g","h","j","k","l","Spacer","Shift:2"],["z","x","c","v","b","n","m",",",".","-","_","+"],["Spacer","@","SpaceBar:7","#","Spacer:2"]],"extendedNordicKeyboard":[["1","2","3","4","5","6","7","8","9","0","+","Backspace:2"],["q","w","e","r","t","y","u","i","o","p","å","CapsLock:2"],["a","s","d","f","g","h","j","k","l","ö","ä","Shift:2"],["z","x","c","v","b","n","m",",",".","-","_","Spacer:2"],["Spacer","@","SpaceBar:7","#","Spacer:3"]],"numericKeyboard":[["1","2","3","Backspace:2"],["4","5","6","Spacer:2"],["7","8","9","Spacer:2"],["Spacer","0","Spacer:3"]],"phoneKeyboard":[["1","2","3","Backspace:2"],["4","5","6","Spacer:2"],["7","8","9","Spacer:2"],["-","0","+","Spacer:2"]],"specialKeys":["Enter","Backspace","Escape","CapsLock","SpaceBar","Spacer","Shift"],"specialKeyIcons":{"Enter":"keyboard_return","Backspace":"backspace","Escape":"close","SpaceBar":"space_bar","Shift":"keyboard_capslock"},"specialKeyTexts":{"CapsLock":"Caps"},"notDisabledSpecialKeys":["Enter","Backspace","Escape"],"isSpacer":{"__symbolic":"function"},"isSpecial":{"__symbolic":"function"},"keyboardCapsLockLayout":{"__symbolic":"function","parameters":["layout","caps"],"value":{"__symbolic":"call","expression":{"__symbolic":"select","expression":{"__symbolic":"reference","name":"layout"},"member":"map"},"arguments":[{"__symbolic":"error","message":"Lambda not supported","line":114,"character":20}]}}}}] -------------------------------------------------------------------------------- /dist/virtual-keyboard.directive.metadata.json: -------------------------------------------------------------------------------- 1 | [{"__symbolic":"module","version":4,"metadata":{"NgVirtualKeyboardDirective":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Directive","line":14,"character":1},"arguments":[{"selector":"[ng-virtual-keyboard]"}]}],"members":{"layout":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input","line":22,"character":3},"arguments":["ng-virtual-keyboard-layout"]}]}],"placeholder":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input","line":23,"character":3},"arguments":["ng-virtual-keyboard-placeholder"]}]}],"type":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Input","line":24,"character":3},"arguments":["ng-virtual-keyboard-type"]}]}],"keyboardClose":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Output","line":25,"character":3},"arguments":["ng-virtual-keyboard-close"]}]}],"onWindowBlur":[{"__symbolic":"method","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"HostListener","line":27,"character":3},"arguments":["window:blur"]}]}],"onWindowFocus":[{"__symbolic":"method","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"HostListener","line":32,"character":3},"arguments":["window:focus"]}]}],"onFocus":[{"__symbolic":"method","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"HostListener","line":39,"character":3},"arguments":["focus"]}]}],"onClick":[{"__symbolic":"method","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"HostListener","line":44,"character":3},"arguments":["click"]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/core","name":"ElementRef","line":56,"character":21},{"__symbolic":"reference","module":"@angular/material","name":"MatDialog","line":57,"character":20}]}],"openKeyboard":[{"__symbolic":"method"}],"getLayout":[{"__symbolic":"method"}],"getPlaceHolder":[{"__symbolic":"method"}],"getType":[{"__symbolic":"method"}]}}}}] -------------------------------------------------------------------------------- /app/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | 4 | const _root = path.resolve(__dirname, '..'); 5 | 6 | function root(args) { 7 | args = Array.prototype.slice.call(arguments, 0); 8 | 9 | return path.join.apply(path, [_root].concat(args)); 10 | } 11 | 12 | const config = { 13 | resolve: { 14 | extensions: [ 15 | '.ts', 16 | '.webpack.js', 17 | '.web.js', 18 | '.js', 19 | ], 20 | alias: { 21 | '@protacon/ng-virtual-keyboard': '../src/index.ts', 22 | } 23 | }, 24 | devtool: 'source-map', 25 | entry: './app/main.ts', 26 | module: { 27 | rules: [ 28 | { 29 | test: /\.ts$/, 30 | use: [ 31 | { 32 | loader: 'ts-loader', 33 | }, 34 | { 35 | loader: 'angular2-template-loader', 36 | }, 37 | ], 38 | }, 39 | { 40 | test: /\.css$/, 41 | use: [ 42 | { 43 | loader: 'style-loader', 44 | }, 45 | { 46 | loader: 'css-loader', 47 | }, 48 | ], 49 | }, 50 | { 51 | test: /\.html$/, 52 | use: [ 53 | { 54 | loader: 'raw-loader', 55 | }, 56 | ], 57 | }, 58 | { 59 | test: /\.scss$/, 60 | use: [ 61 | { 62 | loader: 'raw-loader', 63 | }, 64 | { 65 | loader: 'sass-loader', 66 | }, 67 | ], 68 | }, 69 | ], 70 | }, 71 | plugins: [ 72 | new webpack.ContextReplacementPlugin( 73 | // The (\\|\/) piece accounts for path separators in *nix and Windows 74 | /angular(\\|\/)core(\\|\/)@angular/, 75 | root('./src'), // location of your src 76 | {} // a map of your routes 77 | ), 78 | ], 79 | output: { 80 | path: `${__dirname}/build/`, 81 | publicPath: '/build/', 82 | filename: 'app.js' 83 | }, 84 | optimization: { 85 | minimize: false 86 | } 87 | }; 88 | 89 | if (process.env.NODE_ENV === 'prod') { 90 | config.optimization.minimize = true; 91 | 92 | config.module.rules.push({ 93 | test: /\.ts$/, 94 | use: [ 95 | { 96 | loader: 'strip-loader?strip[]=debug,strip[]=console.log', 97 | }, 98 | ], 99 | }); 100 | } 101 | 102 | module.exports = config; 103 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.directive.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"virtual-keyboard.directive.js","sourceRoot":"","sources":["../src/virtual-keyboard.directive.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/virtual-keyboard.module.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | 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; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | Object.defineProperty(exports, "__esModule", { value: true }); 9 | var core_1 = require("@angular/core"); 10 | var common_1 = require("@angular/common"); 11 | var forms_1 = require("@angular/forms"); 12 | var material_1 = require("@angular/material"); 13 | var flex_layout_1 = require("@angular/flex-layout"); 14 | var virtual_keyboard_directive_1 = require("./virtual-keyboard.directive"); 15 | var virtual_keyboard_component_1 = require("./virtual-keyboard.component"); 16 | var virtual_keyboard_key_component_1 = require("./virtual-keyboard-key.component"); 17 | var virtual_keyboard_service_1 = require("./virtual-keyboard.service"); 18 | var NgVirtualKeyboardModule = /** @class */ (function () { 19 | function NgVirtualKeyboardModule() { 20 | } 21 | NgVirtualKeyboardModule = __decorate([ 22 | core_1.NgModule({ 23 | declarations: [ 24 | virtual_keyboard_directive_1.NgVirtualKeyboardDirective, 25 | virtual_keyboard_component_1.VirtualKeyboardComponent, 26 | virtual_keyboard_key_component_1.VirtualKeyboardKeyComponent, 27 | ], 28 | providers: [ 29 | virtual_keyboard_service_1.VirtualKeyboardService, 30 | ], 31 | imports: [ 32 | common_1.CommonModule, 33 | forms_1.FormsModule, 34 | forms_1.ReactiveFormsModule, 35 | flex_layout_1.FlexLayoutModule, 36 | material_1.MatButtonModule, 37 | material_1.MatDialogModule, 38 | material_1.MatIconModule, 39 | material_1.MatInputModule, 40 | ], 41 | entryComponents: [ 42 | virtual_keyboard_component_1.VirtualKeyboardComponent, 43 | ], 44 | exports: [ 45 | virtual_keyboard_directive_1.NgVirtualKeyboardDirective, 46 | ] 47 | }) 48 | ], NgVirtualKeyboardModule); 49 | return NgVirtualKeyboardModule; 50 | }()); 51 | exports.NgVirtualKeyboardModule = NgVirtualKeyboardModule; 52 | //# sourceMappingURL=virtual-keyboard.module.js.map -------------------------------------------------------------------------------- /dist/virtual-keyboard.component.metadata.json: -------------------------------------------------------------------------------- 1 | [{"__symbolic":"module","version":4,"metadata":{"VirtualKeyboardComponent":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"Component","line":7,"character":1},"arguments":[{"selector":"virtual-keyboard","template":"\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n ","styles":["\n .close {\n position: relative;\n float: right;\n top: -16px;\n right: 0;\n margin-bottom: -40px;\n }\n \n .mat-input-container {\n margin: -16px 0;\n font-size: 32px;\n }\n \n .mat-input-element:disabled {\n color: currentColor;\n }\n\n :host /deep/ .mat-input-placeholder {\n top: 10px !important;\n font-size: 24px !important;\n }\n "]}]}],"members":{"keyboardInput":[{"__symbolic":"property","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"ViewChild","line":69,"character":3},"arguments":["keyboardInput",{"static":true}]}]}],"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"reference","module":"@angular/material","name":"MatDialogRef","line":114,"character":22,"arguments":[{"__symbolic":"reference","name":"VirtualKeyboardComponent"}]},{"__symbolic":"reference","module":"./virtual-keyboard.service","name":"VirtualKeyboardService","line":115,"character":36}]}],"ngOnInit":[{"__symbolic":"method"}],"ngOnDestroy":[{"__symbolic":"method"}],"close":[{"__symbolic":"method"}],"updateCaretPosition":[{"__symbolic":"method"}],"keyPress":[{"__symbolic":"method"}],"checkDisabled":[{"__symbolic":"method"}],"handleNormalKey":[{"__symbolic":"method"}],"handleSpecialKey":[{"__symbolic":"method"}],"dispatchEvents":[{"__symbolic":"method"}]}}}}] -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@protacon/ng-virtual-keyboard", 3 | "version": "0.12.0", 4 | "description": "Virtual Keyboard for Angular applications", 5 | "main": "dist/ng-virtual-keyboard.umd.js", 6 | "module": "dist/index.js", 7 | "typings": "dist/index.d.ts", 8 | "scripts": { 9 | "start": "cross-env NODE_ENV=dev webpack serve --progress --mode production --port 4200 --host 0.0.0.0 --content-base app --config app/webpack.config --open", 10 | "lint": "eslint 'src/**/*.ts' 'app/**/*.ts'", 11 | "clean": "rimraf dist", 12 | "build": "npm-run-all --serial clean build:ngc build:umd build:app build:gh-pages", 13 | "build:ngc": "ngc -p tsconfig.ngc.json", 14 | "build:umd": "cross-env NODE_ENV=prod webpack --progress --mode production", 15 | "build:app": "cross-env NODE_ENV=prod webpack --progress --mode production --config app/webpack.config", 16 | "build:gh-pages": "cp app/index.html docs && cp app/favicon.png docs && cp -r app/build docs" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/protacon/ng-virtual-keyboard.git" 21 | }, 22 | "keywords": [ 23 | "Angular" 24 | ], 25 | "author": "Protacon", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/protacon/ng-virtual-keyboard/issues" 29 | }, 30 | "homepage": "https://github.com/protacon/ng-virtual-keyboard#readme", 31 | "prefer-stable": true, 32 | "dependencies": { 33 | "@angular/animations": "^8.2.0", 34 | "@angular/cdk": "^8.2.0", 35 | "@angular/flex-layout": "^8.0.0-beta.27", 36 | "@angular/material": "^8.2.0", 37 | "hammerjs": "^2.0.0" 38 | }, 39 | "devDependencies": { 40 | "@angular/common": "^8.2.0", 41 | "@angular/compiler": "^8.2.0", 42 | "@angular/compiler-cli": "^8.2.0", 43 | "@angular/core": "^8.2.0", 44 | "@angular/forms": "^8.2.0", 45 | "@angular/platform-browser": "^8.2.0", 46 | "@angular/platform-browser-dynamic": "^8.2.0", 47 | "@angular/router": "^8.2.0", 48 | "@types/node": "^7.10.7", 49 | "@typescript-eslint/eslint-plugin": "^4.29.0", 50 | "@typescript-eslint/parser": "^4.29.0", 51 | "angular2-template-loader": "^0.6.2", 52 | "core-js": "^2.6.9", 53 | "cross-env": "^5.2.1", 54 | "css-loader": "^1.0.0", 55 | "eslint": "^7.32.0", 56 | "node-sass": "^4.12.0", 57 | "npm-run-all": "^4.1.5", 58 | "raw-loader": "^1.0.0", 59 | "rimraf": "^2.7.1", 60 | "rxjs": "^6.5.3", 61 | "rxjs-compat": "^6.5.3", 62 | "sass-loader": "^6.0.3", 63 | "strip-loader": "^0.1.2", 64 | "style-loader": "^0.16.1", 65 | "ts-loader": "^4.4.2", 66 | "typescript": "~3.4.0", 67 | "webpack": "^4.0.0", 68 | "webpack-cli": "^4.7.2", 69 | "webpack-dev-server": "^3.11.1", 70 | "zone.js": "^0.9.1" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ng-virtual-keyboard 2 | [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) 3 | [![npm version](https://badge.fury.io/js/%40protacon%2Fng-virtual-keyboard.svg)](https://badge.fury.io/js/%40protacon%2Fng-virtual-keyboard) 4 | [![npm](https://img.shields.io/npm/dm/@protacon/ng-virtual-keyboard.svg)](https://www.npmjs.com/package/@protacon/ng-virtual-keyboard) 5 | [![Dependency Status](https://david-dm.org/protacon/ng-virtual-keyboard.svg)](https://david-dm.org/protacon/ng-virtual-keyboard) 6 | [![devDependency Status](https://david-dm.org/protacon/ng-virtual-keyboard/dev-status.svg)](https://david-dm.org/protacon/ng-virtual-keyboard#info=devDependencies) 7 | 8 | ## What is this? 9 | Virtual Keyboard for Angular applications 10 | 11 | [See CHANGELOG.md](CHANGELOG.md) 12 | 13 | ## Install 14 | ### Step 1: Install @protacon/ng-virtual-keyboard 15 | ```bash 16 | $ npm install --save @protacon/ng-virtual-keyboard 17 | ``` 18 | 19 | ### Step 2: Import the module 20 | Add `NgVirtualKeyboardModule` as an import in your app's root NgModule. 21 | ```typescript 22 | import { NgVirtualKeyboardModule } from '@protacon/ng-virtual-keyboard'; 23 | 24 | @NgModule({ 25 | ... 26 | imports: [ 27 | ... 28 | NgVirtualKeyboardModule, 29 | ], 30 | ... 31 | }) 32 | export class AppModule { } 33 | ``` 34 | 35 | ## Usage 36 | Simple usage example 37 | ```html 38 | 44 | ``` 45 | 46 | | Attribute | Description | 47 | | --- | --- | 48 | | `ng-virtual-keyboard` | Required to initialize Virtual Keyboard to specified input | 49 | | `ng-virtual-keyboard-layout` | Used layout on keyboard, following keyboards are defaults that you can use `alphanumeric, alphanumericNordic, extended, extendedNordic, numeric, phone` | 50 | | `ng-virtual-keyboard-placeholder` | Override placeholder text, if input has not any - or you want to override input placeholder value | 51 | | `ng-virtual-keyboard-close` | Listener for keyboard closing event | 52 | 53 | ## Demo 54 | https://by-pinja.github.io/ng-virtual-keyboard/ 55 | 56 | ## Local development 57 | 58 | For easier local development, Docker can be used for compiling and testing the 59 | keyboard. To run virtual keyboard from local docker environment, execute following: 60 | 61 | ```bash 62 | docker-compose up 63 | ``` 64 | 65 | After this is ready, navigate to [http://localhost:4200/](http://localhost:4200/) 66 | 67 | To avoid installing node etc. locally, `execute.sh` can be used 68 | to exceute command with current version of supported container. 69 | 70 | Lint example: 71 | 72 | ```bash 73 | bash execute.sh yarn lint 74 | ``` 75 | 76 | Basically this is just a shorthand for `docker run -it --rm -w /app -v ${PWD}/:/app node:12-alpine3.14 "$@"` 77 | 78 | ## License 79 | [The MIT License (MIT)](LICENSE) 80 | 81 | Copyright (c) 2017 Protacon 82 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.service.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | 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; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | Object.defineProperty(exports, "__esModule", { value: true }); 9 | var core_1 = require("@angular/core"); 10 | var ReplaySubject_1 = require("rxjs/internal/ReplaySubject"); 11 | var VirtualKeyboardService = /** @class */ (function () { 12 | function VirtualKeyboardService() { 13 | this.shift$ = new ReplaySubject_1.ReplaySubject(1); 14 | this.capsLock$ = new ReplaySubject_1.ReplaySubject(1); 15 | this.caretPosition$ = new ReplaySubject_1.ReplaySubject(1); 16 | this.capsLock = false; 17 | this.shift = false; 18 | } 19 | /** 20 | * Setter for Shift value, note that this also sets CapsLock value. 21 | * 22 | * @param {boolean} value 23 | */ 24 | VirtualKeyboardService.prototype.setShift = function (value) { 25 | this.shift = value; 26 | this.shift$.next(this.shift); 27 | this.setCapsLock(this.shift); 28 | }; 29 | /** 30 | * Setter for CapsLock value 31 | * 32 | * @param {boolean} value 33 | */ 34 | VirtualKeyboardService.prototype.setCapsLock = function (value) { 35 | this.capsLock = value; 36 | this.capsLock$.next(value); 37 | }; 38 | /** 39 | * Toggle for Shift, note that this also toggles CapsLock 40 | */ 41 | VirtualKeyboardService.prototype.toggleShift = function () { 42 | this.shift = !this.shift; 43 | this.shift$.next(this.shift); 44 | this.setCapsLock(this.shift); 45 | }; 46 | /** 47 | * Toggle for CapsLock 48 | */ 49 | VirtualKeyboardService.prototype.toggleCapsLock = function () { 50 | this.capsLock = !this.capsLock; 51 | this.capsLock$.next(this.capsLock); 52 | }; 53 | /** 54 | * Setter for caret position value. 55 | * 56 | * @param {number} position 57 | */ 58 | VirtualKeyboardService.prototype.setCaretPosition = function (position) { 59 | this.caretPosition$.next(position); 60 | }; 61 | /** 62 | * Method to reset Shift and CapsLock values to default ones. 63 | */ 64 | VirtualKeyboardService.prototype.reset = function () { 65 | this.setShift(false); 66 | }; 67 | VirtualKeyboardService = __decorate([ 68 | core_1.Injectable() 69 | ], VirtualKeyboardService); 70 | return VirtualKeyboardService; 71 | }()); 72 | exports.VirtualKeyboardService = VirtualKeyboardService; 73 | //# sourceMappingURL=virtual-keyboard.service.js.map -------------------------------------------------------------------------------- /app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ViewEncapsulation } from '@angular/core' 2 | 3 | @Component({ 4 | selector: 'my-app', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.scss'], 7 | encapsulation: ViewEncapsulation.None 8 | }) 9 | 10 | export class AppComponent { 11 | public layouts = [ 12 | { 13 | name: 'Alphanumeric', 14 | layout: 'alphanumeric', 15 | placeholder: 'placeholder 1', 16 | placeholderCustom: 'custom placeholder 1', 17 | }, 18 | { 19 | name: 'Alphanumeric - Nordic', 20 | layout: 'alphanumericNordic', 21 | placeholder: 'placeholder 2', 22 | placeholderCustom: 'custom placeholder 2', 23 | }, 24 | { 25 | name: 'Extended', 26 | layout: 'extended', 27 | placeholder: 'placeholder 3', 28 | placeholderCustom: 'custom placeholder 3', 29 | }, 30 | { 31 | name: 'Extended - Nordic', 32 | layout: 'extendedNordic', 33 | placeholder: 'placeholder 4', 34 | placeholderCustom: 'custom placeholder 4', 35 | }, 36 | { 37 | name: 'Numeric', 38 | layout: 'numeric', 39 | placeholder: 'placeholder 5', 40 | placeholderCustom: 'custom placeholder 5', 41 | }, 42 | { 43 | name: 'Phone', 44 | layout: 'phone', 45 | placeholder: 'placeholder 6', 46 | placeholderCustom: 'custom placeholder 6', 47 | }, 48 | ]; 49 | 50 | public badges = [ 51 | { 52 | img: 'https://img.shields.io/badge/license-MIT-blue.svg', 53 | link: 'https://github.com/protacon/ng-virtual-keyboard/blob/master/LICENSE', 54 | }, 55 | { 56 | img: 'https://badge.fury.io/js/%40protacon%2Fng-virtual-keyboard.svg', 57 | link: 'https://badge.fury.io/js/%40protacon%2Fng-virtual-keyboard', 58 | }, 59 | { 60 | img: 'https://travis-ci.org/protacon/ng-virtual-keyboard.png?branch=master', 61 | link: 'https://travis-ci.org/protacon/ng-virtual-keyboard', 62 | }, 63 | { 64 | img: 'https://codecov.io/gh/protacon/ng-virtual-keyboard/branch/master/graph/badge.svg', 65 | link: 'https://codecov.io/gh/protacon/ng-virtual-keyboard', 66 | }, 67 | { 68 | img: 'https://david-dm.org/protacon/ng-virtual-keyboard.svg', 69 | link: 'https://david-dm.org/protacon/ng-virtual-keyboard', 70 | }, 71 | { 72 | img: 'https://david-dm.org/protacon/ng-virtual-keyboard/dev-status.svg', 73 | link: 'https://david-dm.org/protacon/ng-virtual-keyboard#info=devDependencies', 74 | }, 75 | ]; 76 | 77 | public customLayout = [ 78 | ['a', 'b:2', 'Backspace:3'], 79 | ['c:1.33', 'd:1.67', 'Shift:3'], 80 | ]; 81 | 82 | public invalid = false; 83 | 84 | get customLayoutValue() { 85 | return JSON.stringify(this.customLayout, null, 2); 86 | } 87 | 88 | set customLayoutValue(value) { 89 | try { 90 | this.customLayout = JSON.parse(value); 91 | 92 | this.invalid = false; 93 | } catch (error) { 94 | this.invalid = true; 95 | } 96 | } 97 | 98 | onClose() { 99 | console.log('Keyboard was closed'); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/virtual-keyboard-key.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core'; 2 | 3 | import { KeyPressInterface } from './key-press.interface'; 4 | import { isSpacer, isSpecial, notDisabledSpecialKeys, specialKeyIcons, specialKeyTexts } from './layouts'; 5 | 6 | @Component({ 7 | selector: 'virtual-keyboard-key', 8 | template: ` 9 | 25 | `, 26 | styles: [` 27 | .mat-button, 28 | .mat-icon-button, 29 | .mat-raised-button { 30 | min-width: 64px; 31 | min-height: 64px; 32 | padding: 0; 33 | margin: 2px; 34 | font-size: 32px; 35 | line-height: 32px; 36 | } 37 | 38 | .mat-button.spacer, 39 | .mat-icon-button.spacer, 40 | .mat-raised-button.spacer { 41 | background-color: transparent; 42 | } 43 | `] 44 | }) 45 | 46 | export class VirtualKeyboardKeyComponent implements OnInit { 47 | @Input() key: string; 48 | @Input() disabled: boolean; 49 | @Output() keyPress = new EventEmitter(); 50 | 51 | public special = false; 52 | public spacer = false; 53 | public flexValue: string; 54 | public keyValue: string; 55 | public icon: string; 56 | public text: string; 57 | 58 | /** 59 | * Constructor of the class. 60 | */ 61 | public constructor() { } 62 | 63 | /** 64 | * On init life cycle hook, within this we'll initialize following properties: 65 | * - special 66 | * - keyValue 67 | * - flexValue 68 | */ 69 | public ngOnInit(): void { 70 | let multiplier = 1; 71 | let fix = 0; 72 | 73 | if (this.key.length > 1) { 74 | this.spacer = isSpacer(this.key); 75 | this.special = isSpecial(this.key); 76 | 77 | const matches = /^(\w+)(:(\d+(\.\d+)?))?$/g.exec(this.key); 78 | 79 | this.keyValue = matches[1]; 80 | 81 | if (matches[3]) { 82 | multiplier = parseFloat(matches[3]); 83 | fix = (multiplier - 1) * 4; 84 | } 85 | } else { 86 | this.keyValue = this.key; 87 | } 88 | 89 | if (this.special) { 90 | if (specialKeyIcons.hasOwnProperty(this.keyValue)) { 91 | this.icon = specialKeyIcons[this.keyValue]; 92 | } else if (specialKeyTexts.hasOwnProperty(this.keyValue)) { 93 | this.text = specialKeyTexts[this.keyValue]; 94 | } 95 | } 96 | 97 | this.flexValue = `${multiplier * 64 + fix}px`; 98 | } 99 | 100 | /** 101 | * Method to check if key is disabled or not. 102 | * 103 | * @returns {boolean} 104 | */ 105 | public isDisabled(): boolean { 106 | if (this.spacer) { 107 | return true; 108 | } else if (this.disabled && notDisabledSpecialKeys.indexOf(this.keyValue) !== -1) { 109 | return false; 110 | } else { 111 | return this.disabled; 112 | } 113 | } 114 | 115 | /** 116 | * Method to handle actual "key" press from virtual keyboard. 117 | * 1) Key is "Special", process special key event 118 | * 2) Key is "Normal", append this key value to input 119 | */ 120 | public onKeyPress(): void { 121 | this.keyPress.emit({special: this.special, keyValue: this.keyValue, key: this.key}); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.component.d.ts: -------------------------------------------------------------------------------- 1 | import { ElementRef, OnDestroy, OnInit } from '@angular/core'; 2 | import { MatDialogRef } from '@angular/material'; 3 | import { KeyboardLayout } from './layouts'; 4 | import { VirtualKeyboardService } from './virtual-keyboard.service'; 5 | import { KeyPressInterface } from './key-press.interface'; 6 | export declare class VirtualKeyboardComponent implements OnInit, OnDestroy { 7 | dialogRef: MatDialogRef; 8 | private virtualKeyboardService; 9 | keyboardInput: ElementRef; 10 | inputElement: ElementRef; 11 | layout: KeyboardLayout; 12 | placeholder: string; 13 | type: string; 14 | disabled: boolean; 15 | maxLength: number | string; 16 | private caretPosition; 17 | private shift; 18 | /** 19 | * Helper method to set cursor in input to correct place. 20 | * 21 | * @param {HTMLInputElement|HTMLTextAreaElement} input 22 | * @param {number} start 23 | * @param {number} end 24 | */ 25 | private static setSelectionRange; 26 | /** 27 | * Constructor of the class. 28 | * 29 | * @param {MatDialogRef} dialogRef 30 | * @param {VirtualKeyboardService} virtualKeyboardService 31 | */ 32 | constructor(dialogRef: MatDialogRef, virtualKeyboardService: VirtualKeyboardService); 33 | /** 34 | * On init life cycle hook, this will do following: 35 | * 1) Set focus to virtual keyboard input field 36 | * 2) Subscribe to following 37 | * 2.1) Shift key, this is needed in keyboard event dispatches 38 | * 2.2) CapsLock key, this will change keyboard layout 39 | * 2.3) Caret position in virtual keyboard input 40 | * 3) Reset of possible previously tracked caret position 41 | */ 42 | ngOnInit(): void; 43 | /** 44 | * On destroy life cycle hook, in this we want to reset virtual keyboard service states on following: 45 | * - Shift 46 | * - CapsLock 47 | */ 48 | ngOnDestroy(): void; 49 | /** 50 | * Method to close virtual keyboard dialog 51 | */ 52 | close(): void; 53 | /** 54 | * Method to update caret position. This is called on click event in virtual keyboard input element. 55 | */ 56 | updateCaretPosition(): void; 57 | /** 58 | * Method to handle actual "key" press from virtual keyboard. 59 | * 1) Key is "Special", process special key event 60 | * 2) Key is "Normal" 61 | * - Append this key value to input 62 | * - Dispatch DOM events to input element 63 | * - Toggle Shift key if it's pressed 64 | * 65 | * @param {KeyPressInterface} event 66 | */ 67 | keyPress(event: KeyPressInterface): void; 68 | /** 69 | * Method to check is virtual keyboard input is disabled. 70 | */ 71 | private checkDisabled; 72 | /** 73 | * Method to handle "normal" key press event, this will add specified character to input value. 74 | * 75 | * @param {string} keyValue 76 | */ 77 | private handleNormalKey; 78 | /** 79 | * Method to handle "Special" key press events. 80 | * 1) Enter 81 | * 2) Escape, close virtual keyboard 82 | * 3) Backspace, remove last character from input value 83 | * 4) CapsLock, toggle current layout state 84 | * 6) Shift, toggle current layout state 85 | * 5) SpaceBar 86 | */ 87 | private handleSpecialKey; 88 | /** 89 | * Method to dispatch necessary keyboard events to current input element. 90 | * 91 | * @see https://w3c.github.io/uievents/tools/key-event-viewer.html 92 | * 93 | * @param {KeyPressInterface} event 94 | */ 95 | private dispatchEvents; 96 | } 97 | -------------------------------------------------------------------------------- /dist/layouts.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"layouts.js","sourceRoot":"","sources":["../src/layouts.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /dist/layouts.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.alphanumericKeyboard = [ 4 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Backspace:2'], 5 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'CapsLock:2'], 6 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'Spacer', 'Shift:2'], 7 | ['z', 'x', 'c', 'v', 'b', 'n', 'm', 'Spacer:5'], 8 | ]; 9 | exports.alphanumericNordicKeyboard = [ 10 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Spacer', 'Backspace:2'], 11 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'CapsLock:2'], 12 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'Shift:2'], 13 | ['z', 'x', 'c', 'v', 'b', 'n', 'm', 'Spacer:6'], 14 | ]; 15 | exports.extendedKeyboard = [ 16 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Backspace:2'], 17 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'CapsLock:2'], 18 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'Spacer', 'Shift:2'], 19 | ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', '_', '+'], 20 | ['Spacer', '@', 'SpaceBar:7', '#', 'Spacer:2'], 21 | ]; 22 | exports.extendedNordicKeyboard = [ 23 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', 'Backspace:2'], 24 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'CapsLock:2'], 25 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'Shift:2'], 26 | ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', '_', 'Spacer:2'], 27 | ['Spacer', '@', 'SpaceBar:7', '#', 'Spacer:3'], 28 | ]; 29 | exports.numericKeyboard = [ 30 | ['1', '2', '3', 'Backspace:2'], 31 | ['4', '5', '6', 'Spacer:2'], 32 | ['7', '8', '9', 'Spacer:2'], 33 | ['Spacer', '0', 'Spacer:3'], 34 | ]; 35 | exports.phoneKeyboard = [ 36 | ['1', '2', '3', 'Backspace:2'], 37 | ['4', '5', '6', 'Spacer:2'], 38 | ['7', '8', '9', 'Spacer:2'], 39 | ['-', '0', '+', 'Spacer:2'], 40 | ]; 41 | exports.specialKeys = [ 42 | 'Enter', 43 | 'Backspace', 44 | 'Escape', 45 | 'CapsLock', 46 | 'SpaceBar', 47 | 'Spacer', 48 | 'Shift', 49 | ]; 50 | exports.specialKeyIcons = { 51 | Enter: 'keyboard_return', 52 | Backspace: 'backspace', 53 | Escape: 'close', 54 | SpaceBar: 'space_bar', 55 | Shift: 'keyboard_capslock' 56 | }; 57 | exports.specialKeyTexts = { 58 | CapsLock: 'Caps' 59 | }; 60 | exports.notDisabledSpecialKeys = [ 61 | 'Enter', 62 | 'Backspace', 63 | 'Escape', 64 | ]; 65 | /** 66 | * Helper function to determine if given key is 'Spacer' or not. 67 | * 68 | * @param {string} key 69 | * @returns {boolean} 70 | */ 71 | function isSpacer(key) { 72 | if (key.length > 1) { 73 | return /^Spacer(:(\d+(\.\d+)?))?$/g.test(key); 74 | } 75 | return false; 76 | } 77 | exports.isSpacer = isSpacer; 78 | /** 79 | * Helper function to determine if given key is special or not. 80 | * 81 | * @param {string} key 82 | * @returns {boolean} 83 | */ 84 | function isSpecial(key) { 85 | if (key.length > 1) { 86 | return !!exports.specialKeys.filter(function (specialKey) { 87 | var pattern = new RegExp("^(" + specialKey + ")(:(\\d+(\\.\\d+)?))?$", 'g'); 88 | return pattern.test(key); 89 | }).length; 90 | } 91 | return false; 92 | } 93 | exports.isSpecial = isSpecial; 94 | /** 95 | * Function to change specified layout to CapsLock layout. 96 | * 97 | * @param {KeyboardLayout} layout 98 | * @param {boolean} caps 99 | * @returns {KeyboardLayout} 100 | */ 101 | function keyboardCapsLockLayout(layout, caps) { 102 | return layout.map(function (row) { 103 | return row.map(function (key) { 104 | return isSpecial(key) ? key : (caps ? key.toUpperCase() : key.toLowerCase()); 105 | }); 106 | }); 107 | } 108 | exports.keyboardCapsLockLayout = keyboardCapsLockLayout; 109 | //# sourceMappingURL=layouts.js.map -------------------------------------------------------------------------------- /src/layouts.ts: -------------------------------------------------------------------------------- 1 | export type KeyboardLayout = Array>; 2 | 3 | export const alphanumericKeyboard: KeyboardLayout = [ 4 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Backspace:2'], 5 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'CapsLock:2'], 6 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'Spacer', 'Shift:2'], 7 | ['z', 'x', 'c', 'v', 'b', 'n', 'm', 'Spacer:5'], 8 | ]; 9 | 10 | export const alphanumericNordicKeyboard: KeyboardLayout = [ 11 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Spacer', 'Backspace:2'], 12 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'CapsLock:2'], 13 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'Shift:2'], 14 | ['z', 'x', 'c', 'v', 'b', 'n', 'm', 'Spacer:6'], 15 | ]; 16 | 17 | export const extendedKeyboard: KeyboardLayout = [ 18 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Backspace:2'], 19 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'CapsLock:2'], 20 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'Spacer', 'Shift:2'], 21 | ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', '_', '+'], 22 | ['Spacer', '@', 'SpaceBar:7', '#', 'Spacer:2'], 23 | ]; 24 | 25 | export const extendedNordicKeyboard: KeyboardLayout = [ 26 | ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', 'Backspace:2'], 27 | ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'CapsLock:2'], 28 | ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'Shift:2'], 29 | ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', '_', 'Spacer:2'], 30 | ['Spacer', '@', 'SpaceBar:7', '#', 'Spacer:3'], 31 | ]; 32 | 33 | export const numericKeyboard: KeyboardLayout = [ 34 | ['1', '2', '3', 'Backspace:2'], 35 | ['4', '5', '6', 'Spacer:2'], 36 | ['7', '8', '9', 'Spacer:2'], 37 | ['Spacer', '0', 'Spacer:3'], 38 | ]; 39 | 40 | export const phoneKeyboard: KeyboardLayout = [ 41 | ['1', '2', '3', 'Backspace:2'], 42 | ['4', '5', '6', 'Spacer:2'], 43 | ['7', '8', '9', 'Spacer:2'], 44 | ['-', '0', '+', 'Spacer:2'], 45 | ]; 46 | 47 | export const specialKeys: Array = [ 48 | 'Enter', 49 | 'Backspace', 50 | 'Escape', 51 | 'CapsLock', 52 | 'SpaceBar', 53 | 'Spacer', 54 | 'Shift', 55 | ]; 56 | 57 | export const specialKeyIcons = { 58 | Enter: 'keyboard_return', 59 | Backspace: 'backspace', 60 | Escape: 'close', 61 | SpaceBar: 'space_bar', 62 | Shift: 'keyboard_capslock' 63 | }; 64 | 65 | export const specialKeyTexts = { 66 | CapsLock: 'Caps' 67 | }; 68 | 69 | export const notDisabledSpecialKeys = [ 70 | 'Enter', 71 | 'Backspace', 72 | 'Escape', 73 | ]; 74 | 75 | /** 76 | * Helper function to determine if given key is 'Spacer' or not. 77 | * 78 | * @param {string} key 79 | * @returns {boolean} 80 | */ 81 | export function isSpacer(key: string): boolean { 82 | if (key.length > 1) { 83 | return /^Spacer(:(\d+(\.\d+)?))?$/g.test(key); 84 | } 85 | 86 | return false; 87 | } 88 | 89 | /** 90 | * Helper function to determine if given key is special or not. 91 | * 92 | * @param {string} key 93 | * @returns {boolean} 94 | */ 95 | export function isSpecial(key: string): boolean { 96 | if (key.length > 1) { 97 | return !!specialKeys.filter(specialKey => { 98 | const pattern = new RegExp(`^(${specialKey})(:(\\d+(\\.\\d+)?))?$`, 'g'); 99 | 100 | return pattern.test(key); 101 | }).length; 102 | } 103 | 104 | return false; 105 | } 106 | 107 | /** 108 | * Function to change specified layout to CapsLock layout. 109 | * 110 | * @param {KeyboardLayout} layout 111 | * @param {boolean} caps 112 | * @returns {KeyboardLayout} 113 | */ 114 | export function keyboardCapsLockLayout(layout: KeyboardLayout, caps: boolean): KeyboardLayout { 115 | return layout.map((row: Array): Array => { 116 | return row.map((key: string): string => { 117 | return isSpecial(key) ? key : (caps ? key.toUpperCase() : key.toLowerCase()); 118 | }); 119 | }); 120 | } 121 | -------------------------------------------------------------------------------- /src/virtual-keyboard.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive, ElementRef, EventEmitter, HostListener, Input, Output } from '@angular/core'; 2 | import { MatDialog, MatDialogRef } from '@angular/material'; 3 | 4 | import { VirtualKeyboardComponent } from './virtual-keyboard.component'; 5 | import { 6 | alphanumericKeyboard, 7 | alphanumericNordicKeyboard, 8 | extendedKeyboard, 9 | extendedNordicKeyboard, 10 | KeyboardLayout, 11 | numericKeyboard, 12 | phoneKeyboard 13 | } from './layouts'; 14 | 15 | @Directive({ 16 | selector: '[ng-virtual-keyboard]' 17 | }) 18 | 19 | export class NgVirtualKeyboardDirective { 20 | private opened = false; 21 | private focus = true; 22 | 23 | @Input('ng-virtual-keyboard-layout') layout: KeyboardLayout | string; 24 | @Input('ng-virtual-keyboard-placeholder') placeholder: string; 25 | @Input('ng-virtual-keyboard-type') type: string; 26 | @Output('ng-virtual-keyboard-close') keyboardClose: EventEmitter; 27 | 28 | @HostListener('window:blur') 29 | onWindowBlur() { 30 | this.focus = false; 31 | } 32 | 33 | @HostListener('window:focus') 34 | onWindowFocus() { 35 | setTimeout(() => { 36 | this.focus = true; 37 | }, 0); 38 | } 39 | 40 | @HostListener('focus') 41 | onFocus() { 42 | this.openKeyboard(); 43 | } 44 | 45 | @HostListener('click') 46 | onClick() { 47 | this.openKeyboard(); 48 | } 49 | 50 | /** 51 | * Constructor of the class. 52 | * 53 | * @param {ElementRef} element 54 | * @param {MatDialog} dialog 55 | */ 56 | public constructor( 57 | private element: ElementRef, 58 | private dialog: MatDialog, 59 | ) { 60 | this.keyboardClose = new EventEmitter(); 61 | } 62 | 63 | /** 64 | * Method to open virtual keyboard 65 | */ 66 | private openKeyboard() { 67 | if (!this.opened && this.focus) { 68 | this.opened = true; 69 | 70 | let dialogRef: MatDialogRef; 71 | 72 | dialogRef = this.dialog.open(VirtualKeyboardComponent); 73 | dialogRef.componentInstance.inputElement = this.element; 74 | dialogRef.componentInstance.layout = this.getLayout(); 75 | dialogRef.componentInstance.placeholder = this.getPlaceHolder(); 76 | dialogRef.componentInstance.type = this.getType(); 77 | 78 | dialogRef 79 | .afterClosed() 80 | .subscribe(() => { 81 | this.keyboardClose.emit(); 82 | setTimeout(() => { 83 | this.opened = false; 84 | }, 0); 85 | }); 86 | } 87 | } 88 | 89 | /** 90 | * Getter for used keyboard layout. 91 | * 92 | * @returns {KeyboardLayout} 93 | */ 94 | private getLayout(): KeyboardLayout { 95 | let layout; 96 | 97 | switch (this.layout) { 98 | case 'alphanumeric': 99 | layout = alphanumericKeyboard; 100 | break; 101 | case 'alphanumericNordic': 102 | layout = alphanumericNordicKeyboard; 103 | break; 104 | case 'extended': 105 | layout = extendedKeyboard; 106 | break; 107 | case 'extendedNordic': 108 | layout = extendedNordicKeyboard; 109 | break; 110 | case 'numeric': 111 | layout = numericKeyboard; 112 | break; 113 | case 'phone': 114 | layout = phoneKeyboard; 115 | break; 116 | default: 117 | layout = this.layout; 118 | break; 119 | } 120 | 121 | return layout; 122 | } 123 | 124 | /** 125 | * Getter for used placeholder for virtual keyboard input field. 126 | * 127 | * @returns {string} 128 | */ 129 | private getPlaceHolder(): string { 130 | return this.placeholder ? this.placeholder : this.element.nativeElement.placeholder; 131 | } 132 | 133 | /** 134 | * Getter for used type for virtual keyboard input field. 135 | * 136 | * @return {string} 137 | */ 138 | private getType(): string { 139 | return this.type ? this.type : this.element.nativeElement.type; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /dist/virtual-keyboard-key.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | 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; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | var core_1 = require("@angular/core"); 13 | var layouts_1 = require("./layouts"); 14 | var VirtualKeyboardKeyComponent = /** @class */ (function () { 15 | /** 16 | * Constructor of the class. 17 | */ 18 | function VirtualKeyboardKeyComponent() { 19 | this.keyPress = new core_1.EventEmitter(); 20 | this.special = false; 21 | this.spacer = false; 22 | } 23 | /** 24 | * On init life cycle hook, within this we'll initialize following properties: 25 | * - special 26 | * - keyValue 27 | * - flexValue 28 | */ 29 | VirtualKeyboardKeyComponent.prototype.ngOnInit = function () { 30 | var multiplier = 1; 31 | var fix = 0; 32 | if (this.key.length > 1) { 33 | this.spacer = layouts_1.isSpacer(this.key); 34 | this.special = layouts_1.isSpecial(this.key); 35 | var matches = /^(\w+)(:(\d+(\.\d+)?))?$/g.exec(this.key); 36 | this.keyValue = matches[1]; 37 | if (matches[3]) { 38 | multiplier = parseFloat(matches[3]); 39 | fix = (multiplier - 1) * 4; 40 | } 41 | } 42 | else { 43 | this.keyValue = this.key; 44 | } 45 | if (this.special) { 46 | if (layouts_1.specialKeyIcons.hasOwnProperty(this.keyValue)) { 47 | this.icon = layouts_1.specialKeyIcons[this.keyValue]; 48 | } 49 | else if (layouts_1.specialKeyTexts.hasOwnProperty(this.keyValue)) { 50 | this.text = layouts_1.specialKeyTexts[this.keyValue]; 51 | } 52 | } 53 | this.flexValue = multiplier * 64 + fix + "px"; 54 | }; 55 | /** 56 | * Method to check if key is disabled or not. 57 | * 58 | * @returns {boolean} 59 | */ 60 | VirtualKeyboardKeyComponent.prototype.isDisabled = function () { 61 | if (this.spacer) { 62 | return true; 63 | } 64 | else if (this.disabled && layouts_1.notDisabledSpecialKeys.indexOf(this.keyValue) !== -1) { 65 | return false; 66 | } 67 | else { 68 | return this.disabled; 69 | } 70 | }; 71 | /** 72 | * Method to handle actual "key" press from virtual keyboard. 73 | * 1) Key is "Special", process special key event 74 | * 2) Key is "Normal", append this key value to input 75 | */ 76 | VirtualKeyboardKeyComponent.prototype.onKeyPress = function () { 77 | this.keyPress.emit({ special: this.special, keyValue: this.keyValue, key: this.key }); 78 | }; 79 | __decorate([ 80 | core_1.Input(), 81 | __metadata("design:type", String) 82 | ], VirtualKeyboardKeyComponent.prototype, "key", void 0); 83 | __decorate([ 84 | core_1.Input(), 85 | __metadata("design:type", Boolean) 86 | ], VirtualKeyboardKeyComponent.prototype, "disabled", void 0); 87 | __decorate([ 88 | core_1.Output(), 89 | __metadata("design:type", Object) 90 | ], VirtualKeyboardKeyComponent.prototype, "keyPress", void 0); 91 | VirtualKeyboardKeyComponent = __decorate([ 92 | core_1.Component({ 93 | selector: 'virtual-keyboard-key', 94 | template: "\n \n {{ keyValue }}\n \n \n {{ icon }}\n \n {{ text }}\n \n \n ", 95 | styles: ["\n .mat-button,\n .mat-icon-button,\n .mat-raised-button {\n min-width: 64px;\n min-height: 64px;\n padding: 0;\n margin: 2px;\n font-size: 32px;\n line-height: 32px;\n }\n \n .mat-button.spacer,\n .mat-icon-button.spacer,\n .mat-raised-button.spacer {\n background-color: transparent;\n }\n "] 96 | }), 97 | __metadata("design:paramtypes", []) 98 | ], VirtualKeyboardKeyComponent); 99 | return VirtualKeyboardKeyComponent; 100 | }()); 101 | exports.VirtualKeyboardKeyComponent = VirtualKeyboardKeyComponent; 102 | //# sourceMappingURL=virtual-keyboard-key.component.js.map -------------------------------------------------------------------------------- /dist/virtual-keyboard.component.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"virtual-keyboard.component.js","sourceRoot":"","sources":["../src/virtual-keyboard.component.ts"],"names":[],"mappings":"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"} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | ### macOS template 4 | *.DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | ### Vim template 31 | # swap 32 | [._]*.s[a-v][a-z] 33 | [._]*.sw[a-p] 34 | [._]s[a-v][a-z] 35 | [._]sw[a-p] 36 | # session 37 | Session.vim 38 | # temporary 39 | .netrwhist 40 | *~ 41 | # auto-generated tag files 42 | tags 43 | ### Emacs template 44 | # -*- mode: gitignore; -*- 45 | \#*\# 46 | /.emacs.desktop 47 | /.emacs.desktop.lock 48 | *.elc 49 | auto-save-list 50 | tramp 51 | .\#* 52 | 53 | # Org-mode 54 | .org-id-locations 55 | *_archive 56 | 57 | # flymake-mode 58 | *_flymake.* 59 | 60 | # eshell files 61 | /eshell/history 62 | /eshell/lastdir 63 | 64 | # elpa packages 65 | /elpa/ 66 | 67 | # reftex files 68 | *.rel 69 | 70 | # AUCTeX auto folder 71 | /auto/ 72 | 73 | # cask packages 74 | .cask/ 75 | 76 | # Flycheck 77 | flycheck_*.el 78 | 79 | # server auth directory 80 | /server/ 81 | 82 | # projectiles files 83 | .projectile 84 | 85 | # directory configuration 86 | .dir-locals.el 87 | ### Windows template 88 | # Windows thumbnail cache files 89 | Thumbs.db 90 | ehthumbs.db 91 | ehthumbs_vista.db 92 | 93 | # Folder config file 94 | Desktop.ini 95 | 96 | # Recycle Bin used on file shares 97 | $RECYCLE.BIN/ 98 | 99 | # Windows Installer files 100 | *.cab 101 | *.msi 102 | *.msm 103 | *.msp 104 | 105 | # Windows shortcuts 106 | *.lnk 107 | ### NetBeans template 108 | nbproject/private/ 109 | nbbuild/ 110 | nbdist/ 111 | .nb-gradle/ 112 | ### NotepadPP template 113 | # Notepad++ backups # 114 | *.bak 115 | ### VisualStudioCode template 116 | .vscode/* 117 | !.vscode/settings.json 118 | !.vscode/tasks.json 119 | !.vscode/launch.json 120 | !.vscode/extensions.json 121 | ### SublimeText template 122 | # cache files for sublime text 123 | *.tmlanguage.cache 124 | *.tmPreferences.cache 125 | *.stTheme.cache 126 | 127 | # workspace files are user-specific 128 | *.sublime-workspace 129 | 130 | # project files should be checked into the repository, unless a significant 131 | # proportion of contributors will probably not be using SublimeText 132 | # *.sublime-project 133 | 134 | # sftp configuration file 135 | sftp-config.json 136 | 137 | # Package control specific files 138 | Package Control.last-run 139 | Package Control.ca-list 140 | Package Control.ca-bundle 141 | Package Control.system-ca-bundle 142 | Package Control.cache/ 143 | Package Control.ca-certs/ 144 | Package Control.merged-ca-bundle 145 | Package Control.user-ca-bundle 146 | oscrypto-ca-bundle.crt 147 | bh_unicode_properties.cache 148 | 149 | # Sublime-github package stores a github token in this file 150 | # https://packagecontrol.io/packages/sublime-github 151 | GitHub.sublime-settings 152 | ### JetBrains template 153 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 154 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 155 | .idea 156 | 157 | ## File-based project format: 158 | *.iws 159 | 160 | ## Plugin-specific files: 161 | 162 | # IntelliJ 163 | /out/ 164 | 165 | # mpeltonen/sbt-idea plugin 166 | .idea_modules/ 167 | 168 | # JIRA plugin 169 | atlassian-ide-plugin.xml 170 | 171 | # Crashlytics plugin (for Android Studio and IntelliJ) 172 | com_crashlytics_export_strings.xml 173 | crashlytics.properties 174 | crashlytics-build.properties 175 | fabric.properties 176 | ### TextMate template 177 | *.tmproj 178 | *.tmproject 179 | tmtags 180 | ### Linux template 181 | 182 | # temporary files which can be created if a process still has a handle open of a deleted file 183 | .fuse_hidden* 184 | 185 | # KDE directory preferences 186 | .directory 187 | 188 | # Linux trash folder which might appear on any partition or disk 189 | .Trash-* 190 | 191 | # .nfs files are created when an open file is removed but is still being accessed 192 | .nfs* 193 | ### Eclipse template 194 | 195 | .metadata 196 | bin/ 197 | tmp/ 198 | *.tmp 199 | *.swp 200 | *~.nib 201 | local.properties 202 | .settings/ 203 | .loadpath 204 | .recommenders 205 | 206 | # Eclipse Core 207 | .project 208 | 209 | # External tool builders 210 | .externalToolBuilders/ 211 | 212 | # Locally stored "Eclipse launch configurations" 213 | *.launch 214 | 215 | # PyDev specific (Python IDE for Eclipse) 216 | *.pydevproject 217 | 218 | # CDT-specific (C/C++ Development Tooling) 219 | .cproject 220 | 221 | # JDT-specific (Eclipse Java Development Tools) 222 | .classpath 223 | 224 | # Java annotation processor (APT) 225 | .factorypath 226 | 227 | # PDT-specific (PHP Development Tools) 228 | .buildpath 229 | 230 | # sbteclipse plugin 231 | .target 232 | 233 | # Tern plugin 234 | .tern-project 235 | 236 | # TeXlipse plugin 237 | .texlipse 238 | 239 | # STS (Spring Tool Suite) 240 | .springBeans 241 | 242 | # Code Recommenders 243 | .recommenders/ 244 | 245 | # Scala IDE specific (Scala & Java development for Eclipse) 246 | .cache-main 247 | .scala_dependencies 248 | .worksheet 249 | -------------------------------------------------------------------------------- /app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

@protacon/ng-virtual-keyboard

5 | 6 |
7 | 8 |
9 |
10 | 11 |
12 |

What is this?

13 | 14 |

15 | Virtual Keyboard for Angular applications. 16 |

17 |
18 | 19 |
20 |

Install

21 | 22 |

Step 1: Install @protacon/ng-virtual-keyboard

23 | 24 |
 25 | $ npm install --save @protacon/ng-virtual-keyboard
26 | 27 |

Step 2: Import the module

28 | 29 |

30 | Add NgVirtualKeyboardModule as an import in your app's root NgModule. 31 |

32 | 33 |
 34 | import {{ '{' }} NgVirtualKeyboardModule {{ '}' }} from '@protacon/ng-virtual-keyboard';
 35 | 
 36 | @NgModule({{ '{' }}
 37 |   ...
 38 |   imports: [
 39 |     ...
 40 |     NgVirtualKeyboardModule,
 41 |   ],
 42 |   ...
 43 | {{ '}' }})
 44 | export class AppModule {{ '{' }} {{ '}' }}
45 |
46 | 47 |
48 |

Usage

49 | 50 |

51 | Simple usage example 52 |

53 | 54 |
 55 | <input type="text" value=""
 56 |   ng-virtual-keyboard
 57 |   ng-virtual-keyboard-layout="alphanumeric"
 58 |   ng-virtual-keyboard-placeholder="Custom placeholder text"
 59 |   (ng-virtual-keyboard-close)="onClose()"
 60 | />
61 |
62 | 63 |
64 |

Demos

65 | 66 |
67 |
68 |

69 | Layout/Info 70 |

71 |
72 | 73 | 74 | Minimal 75 | 76 | 77 | 78 | With placeholder 79 | 80 | 81 | 82 | With custom placeholder 83 | 84 | 85 | 86 | With maxlength="5" 87 | 88 | 89 | 90 | Type Password 91 | 92 |
93 | 94 |
95 |
96 | {{ layout.name }} 97 | 98 | 99 | 105 | 106 | 107 | 108 | 114 | 115 | 116 | 117 | 124 | 125 | 126 | 127 | 133 | 134 | 135 | 136 | 144 | 145 |
146 |
147 | 148 |
149 | Custom Layout 150 | 151 | 152 | 158 | 159 |
160 | 161 |
162 | Custom layout definition 163 | 164 | 165 | 166 | 167 | 168 | Given layout is not valid JSON - use Array<Array<string>> format 169 | 170 | 171 |
172 |
173 |
174 |
175 | -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Virtual Keyboard for Angular applications 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 118 | 119 | 120 | 121 | 122 | Fork me on GitHub 123 | 124 | 125 | 126 | 127 |
128 |
Loading...
129 |
130 | 131 | 138 | 139 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Virtual Keyboard for Angular applications 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 118 | 119 | 120 | 121 | 122 | Fork me on GitHub 123 | 124 | 125 | 126 | 127 |
128 |
Loading...
129 |
130 | 131 | 138 | 139 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.directive.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | 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; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | var core_1 = require("@angular/core"); 13 | var material_1 = require("@angular/material"); 14 | var virtual_keyboard_component_1 = require("./virtual-keyboard.component"); 15 | var layouts_1 = require("./layouts"); 16 | var NgVirtualKeyboardDirective = /** @class */ (function () { 17 | /** 18 | * Constructor of the class. 19 | * 20 | * @param {ElementRef} element 21 | * @param {MatDialog} dialog 22 | */ 23 | function NgVirtualKeyboardDirective(element, dialog) { 24 | this.element = element; 25 | this.dialog = dialog; 26 | this.opened = false; 27 | this.focus = true; 28 | this.keyboardClose = new core_1.EventEmitter(); 29 | } 30 | NgVirtualKeyboardDirective.prototype.onWindowBlur = function () { 31 | this.focus = false; 32 | }; 33 | NgVirtualKeyboardDirective.prototype.onWindowFocus = function () { 34 | var _this = this; 35 | setTimeout(function () { 36 | _this.focus = true; 37 | }, 0); 38 | }; 39 | NgVirtualKeyboardDirective.prototype.onFocus = function () { 40 | this.openKeyboard(); 41 | }; 42 | NgVirtualKeyboardDirective.prototype.onClick = function () { 43 | this.openKeyboard(); 44 | }; 45 | /** 46 | * Method to open virtual keyboard 47 | */ 48 | NgVirtualKeyboardDirective.prototype.openKeyboard = function () { 49 | var _this = this; 50 | if (!this.opened && this.focus) { 51 | this.opened = true; 52 | var dialogRef = void 0; 53 | dialogRef = this.dialog.open(virtual_keyboard_component_1.VirtualKeyboardComponent); 54 | dialogRef.componentInstance.inputElement = this.element; 55 | dialogRef.componentInstance.layout = this.getLayout(); 56 | dialogRef.componentInstance.placeholder = this.getPlaceHolder(); 57 | dialogRef.componentInstance.type = this.getType(); 58 | dialogRef 59 | .afterClosed() 60 | .subscribe(function () { 61 | _this.keyboardClose.emit(); 62 | setTimeout(function () { 63 | _this.opened = false; 64 | }, 0); 65 | }); 66 | } 67 | }; 68 | /** 69 | * Getter for used keyboard layout. 70 | * 71 | * @returns {KeyboardLayout} 72 | */ 73 | NgVirtualKeyboardDirective.prototype.getLayout = function () { 74 | var layout; 75 | switch (this.layout) { 76 | case 'alphanumeric': 77 | layout = layouts_1.alphanumericKeyboard; 78 | break; 79 | case 'alphanumericNordic': 80 | layout = layouts_1.alphanumericNordicKeyboard; 81 | break; 82 | case 'extended': 83 | layout = layouts_1.extendedKeyboard; 84 | break; 85 | case 'extendedNordic': 86 | layout = layouts_1.extendedNordicKeyboard; 87 | break; 88 | case 'numeric': 89 | layout = layouts_1.numericKeyboard; 90 | break; 91 | case 'phone': 92 | layout = layouts_1.phoneKeyboard; 93 | break; 94 | default: 95 | layout = this.layout; 96 | break; 97 | } 98 | return layout; 99 | }; 100 | /** 101 | * Getter for used placeholder for virtual keyboard input field. 102 | * 103 | * @returns {string} 104 | */ 105 | NgVirtualKeyboardDirective.prototype.getPlaceHolder = function () { 106 | return this.placeholder ? this.placeholder : this.element.nativeElement.placeholder; 107 | }; 108 | /** 109 | * Getter for used type for virtual keyboard input field. 110 | * 111 | * @return {string} 112 | */ 113 | NgVirtualKeyboardDirective.prototype.getType = function () { 114 | return this.type ? this.type : this.element.nativeElement.type; 115 | }; 116 | __decorate([ 117 | core_1.Input('ng-virtual-keyboard-layout'), 118 | __metadata("design:type", Object) 119 | ], NgVirtualKeyboardDirective.prototype, "layout", void 0); 120 | __decorate([ 121 | core_1.Input('ng-virtual-keyboard-placeholder'), 122 | __metadata("design:type", String) 123 | ], NgVirtualKeyboardDirective.prototype, "placeholder", void 0); 124 | __decorate([ 125 | core_1.Input('ng-virtual-keyboard-type'), 126 | __metadata("design:type", String) 127 | ], NgVirtualKeyboardDirective.prototype, "type", void 0); 128 | __decorate([ 129 | core_1.Output('ng-virtual-keyboard-close'), 130 | __metadata("design:type", core_1.EventEmitter) 131 | ], NgVirtualKeyboardDirective.prototype, "keyboardClose", void 0); 132 | __decorate([ 133 | core_1.HostListener('window:blur'), 134 | __metadata("design:type", Function), 135 | __metadata("design:paramtypes", []), 136 | __metadata("design:returntype", void 0) 137 | ], NgVirtualKeyboardDirective.prototype, "onWindowBlur", null); 138 | __decorate([ 139 | core_1.HostListener('window:focus'), 140 | __metadata("design:type", Function), 141 | __metadata("design:paramtypes", []), 142 | __metadata("design:returntype", void 0) 143 | ], NgVirtualKeyboardDirective.prototype, "onWindowFocus", null); 144 | __decorate([ 145 | core_1.HostListener('focus'), 146 | __metadata("design:type", Function), 147 | __metadata("design:paramtypes", []), 148 | __metadata("design:returntype", void 0) 149 | ], NgVirtualKeyboardDirective.prototype, "onFocus", null); 150 | __decorate([ 151 | core_1.HostListener('click'), 152 | __metadata("design:type", Function), 153 | __metadata("design:paramtypes", []), 154 | __metadata("design:returntype", void 0) 155 | ], NgVirtualKeyboardDirective.prototype, "onClick", null); 156 | NgVirtualKeyboardDirective = __decorate([ 157 | core_1.Directive({ 158 | selector: '[ng-virtual-keyboard]' 159 | }), 160 | __metadata("design:paramtypes", [core_1.ElementRef, 161 | material_1.MatDialog]) 162 | ], NgVirtualKeyboardDirective); 163 | return NgVirtualKeyboardDirective; 164 | }()); 165 | exports.NgVirtualKeyboardDirective = NgVirtualKeyboardDirective; 166 | //# sourceMappingURL=virtual-keyboard.directive.js.map -------------------------------------------------------------------------------- /src/virtual-keyboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; 2 | import { MatDialogRef } from '@angular/material'; 3 | 4 | import { keyboardCapsLockLayout, KeyboardLayout } from './layouts'; 5 | import { VirtualKeyboardService } from './virtual-keyboard.service'; 6 | import { KeyPressInterface } from './key-press.interface'; 7 | 8 | @Component({ 9 | selector: 'virtual-keyboard', 10 | template: ` 11 |
12 |
13 | 14 | 19 | 20 | 27 | 28 | 29 |
33 | 40 |
41 |
42 |
43 | `, 44 | styles: [` 45 | .close { 46 | position: relative; 47 | float: right; 48 | top: -16px; 49 | right: 0; 50 | margin-bottom: -40px; 51 | } 52 | 53 | .mat-input-container { 54 | margin: -16px 0; 55 | font-size: 32px; 56 | } 57 | 58 | .mat-input-element:disabled { 59 | color: currentColor; 60 | } 61 | 62 | :host /deep/ .mat-input-placeholder { 63 | top: 10px !important; 64 | font-size: 24px !important; 65 | } 66 | `] 67 | }) 68 | 69 | export class VirtualKeyboardComponent implements OnInit, OnDestroy { 70 | @ViewChild('keyboardInput', { static: true }) keyboardInput: ElementRef; 71 | 72 | public inputElement: ElementRef; 73 | public layout: KeyboardLayout; 74 | public placeholder: string; 75 | public type: string; 76 | public disabled: boolean; 77 | public maxLength: number | string; 78 | 79 | private caretPosition: number; 80 | private shift = false; 81 | 82 | /** 83 | * Helper method to set cursor in input to correct place. 84 | * 85 | * @param {HTMLInputElement|HTMLTextAreaElement} input 86 | * @param {number} start 87 | * @param {number} end 88 | */ 89 | private static setSelectionRange( 90 | input: any, 91 | start: number, 92 | end: number 93 | ): void { 94 | if (input.setSelectionRange) { 95 | input.focus(); 96 | input.setSelectionRange(start, end); 97 | 98 | } else if (input.createTextRange) { 99 | const range = input.createTextRange(); 100 | 101 | range.collapse(true); 102 | range.moveEnd('character', end); 103 | range.moveStart('character', start); 104 | range.select(); 105 | } 106 | } 107 | 108 | /** 109 | * Constructor of the class. 110 | * 111 | * @param {MatDialogRef} dialogRef 112 | * @param {VirtualKeyboardService} virtualKeyboardService 113 | */ 114 | public constructor( 115 | public dialogRef: MatDialogRef, 116 | private virtualKeyboardService: VirtualKeyboardService 117 | ) { } 118 | 119 | /** 120 | * On init life cycle hook, this will do following: 121 | * 1) Set focus to virtual keyboard input field 122 | * 2) Subscribe to following 123 | * 2.1) Shift key, this is needed in keyboard event dispatches 124 | * 2.2) CapsLock key, this will change keyboard layout 125 | * 2.3) Caret position in virtual keyboard input 126 | * 3) Reset of possible previously tracked caret position 127 | */ 128 | public ngOnInit(): void { 129 | setTimeout(() => { 130 | this.keyboardInput.nativeElement.focus(); 131 | }, 0); 132 | 133 | this.virtualKeyboardService.shift$.subscribe((shift: boolean) => { 134 | this.shift = shift; 135 | }); 136 | 137 | this.virtualKeyboardService.capsLock$.subscribe((capsLock: boolean) => { 138 | this.layout = keyboardCapsLockLayout(this.layout, capsLock); 139 | }); 140 | 141 | this.virtualKeyboardService.caretPosition$.subscribe((caretPosition: number) => { 142 | this.caretPosition = caretPosition; 143 | 144 | setTimeout(() => { 145 | VirtualKeyboardComponent.setSelectionRange(this.keyboardInput.nativeElement, caretPosition, caretPosition); 146 | }, 0); 147 | }); 148 | 149 | if (this.inputElement.nativeElement.value.length) { 150 | this.virtualKeyboardService.setCaretPosition(this.inputElement.nativeElement.value.length); 151 | } 152 | 153 | this.maxLength = this.inputElement.nativeElement.maxLength > 0 ? this.inputElement.nativeElement.maxLength : ''; 154 | 155 | this.checkDisabled(); 156 | } 157 | 158 | /** 159 | * On destroy life cycle hook, in this we want to reset virtual keyboard service states on following: 160 | * - Shift 161 | * - CapsLock 162 | */ 163 | public ngOnDestroy(): void { 164 | this.virtualKeyboardService.reset(); 165 | } 166 | 167 | /** 168 | * Method to close virtual keyboard dialog 169 | */ 170 | public close(): void { 171 | this.dialogRef.close(); 172 | } 173 | 174 | /** 175 | * Method to update caret position. This is called on click event in virtual keyboard input element. 176 | */ 177 | public updateCaretPosition(): void { 178 | this.virtualKeyboardService.setCaretPosition(this.keyboardInput.nativeElement.selectionStart); 179 | } 180 | 181 | /** 182 | * Method to handle actual "key" press from virtual keyboard. 183 | * 1) Key is "Special", process special key event 184 | * 2) Key is "Normal" 185 | * - Append this key value to input 186 | * - Dispatch DOM events to input element 187 | * - Toggle Shift key if it's pressed 188 | * 189 | * @param {KeyPressInterface} event 190 | */ 191 | public keyPress(event: KeyPressInterface): void { 192 | if (event.special) { 193 | this.handleSpecialKey(event); 194 | } else { 195 | this.handleNormalKey(event.keyValue); 196 | 197 | this.dispatchEvents(event); 198 | 199 | // Toggle shift if it's activated 200 | if (this.shift) { 201 | this.virtualKeyboardService.toggleShift(); 202 | } 203 | } 204 | 205 | this.checkDisabled(); 206 | } 207 | 208 | /** 209 | * Method to check is virtual keyboard input is disabled. 210 | */ 211 | private checkDisabled(): void { 212 | const maxLength = this.inputElement.nativeElement.maxLength; 213 | const valueLength = this.inputElement.nativeElement.value.length; 214 | 215 | this.disabled = maxLength > 0 && valueLength >= maxLength; 216 | } 217 | 218 | /** 219 | * Method to handle "normal" key press event, this will add specified character to input value. 220 | * 221 | * @param {string} keyValue 222 | */ 223 | private handleNormalKey(keyValue: string): void { 224 | let value = ''; 225 | 226 | // We have caret position, so attach character to specified position 227 | if (!isNaN(this.caretPosition)) { 228 | value = [ 229 | this.inputElement.nativeElement.value.slice(0, this.caretPosition), 230 | keyValue, 231 | this.inputElement.nativeElement.value.slice(this.caretPosition) 232 | ].join(''); 233 | 234 | // Update caret position 235 | this.virtualKeyboardService.setCaretPosition(this.caretPosition + 1); 236 | } else { 237 | value = `${this.inputElement.nativeElement.value}${keyValue}`; 238 | } 239 | 240 | // And finally set new value to input 241 | this.inputElement.nativeElement.value = value; 242 | } 243 | 244 | /** 245 | * Method to handle "Special" key press events. 246 | * 1) Enter 247 | * 2) Escape, close virtual keyboard 248 | * 3) Backspace, remove last character from input value 249 | * 4) CapsLock, toggle current layout state 250 | * 6) Shift, toggle current layout state 251 | * 5) SpaceBar 252 | */ 253 | private handleSpecialKey(event: KeyPressInterface): void { 254 | switch (event.keyValue) { 255 | case 'Enter': 256 | this.close(); 257 | break; 258 | case 'Escape': 259 | this.close(); 260 | break; 261 | case 'Backspace': 262 | const currentValue = this.inputElement.nativeElement.value; 263 | 264 | // We have a caret position, so we need to remove char from that position 265 | if (!isNaN(this.caretPosition)) { 266 | // And current position must > 0 267 | if (this.caretPosition > 0) { 268 | const start = currentValue.slice(0, this.caretPosition - 1); 269 | const end = currentValue.slice(this.caretPosition); 270 | 271 | this.inputElement.nativeElement.value = `${start}${end}`; 272 | 273 | // Update caret position 274 | this.virtualKeyboardService.setCaretPosition(this.caretPosition - 1); 275 | } 276 | } else { 277 | this.inputElement.nativeElement.value = currentValue.substring(0, currentValue.length - 1); 278 | } 279 | 280 | this.dispatchEvents(event); 281 | // Set focus to keyboard input 282 | this.keyboardInput.nativeElement.focus(); 283 | break; 284 | case 'CapsLock': 285 | this.virtualKeyboardService.toggleCapsLock(); 286 | break; 287 | case 'Shift': 288 | this.virtualKeyboardService.toggleShift(); 289 | break; 290 | case 'SpaceBar': 291 | this.handleNormalKey(' '); 292 | break; 293 | } 294 | } 295 | 296 | /** 297 | * Method to dispatch necessary keyboard events to current input element. 298 | * 299 | * @see https://w3c.github.io/uievents/tools/key-event-viewer.html 300 | * 301 | * @param {KeyPressInterface} event 302 | */ 303 | private dispatchEvents(event: KeyPressInterface) { 304 | const eventInit: KeyboardEventInit = { 305 | bubbles: true, 306 | cancelable: true, 307 | shiftKey: this.shift, 308 | key: event.keyValue, 309 | code: `Key${event.keyValue.toUpperCase()}}`, 310 | location: 0 311 | }; 312 | 313 | // Simulate all needed events on base element 314 | this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keydown', eventInit)); 315 | this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keypress', eventInit)); 316 | this.inputElement.nativeElement.dispatchEvent(new Event('input', { bubbles: true })); 317 | this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keyup', eventInit)); 318 | 319 | // And set focus to input 320 | this.keyboardInput.nativeElement.focus(); 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /dist/virtual-keyboard.component.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { 3 | var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; 4 | if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); 5 | 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; 6 | return c > 3 && r && Object.defineProperty(target, key, r), r; 7 | }; 8 | var __metadata = (this && this.__metadata) || function (k, v) { 9 | if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); 10 | }; 11 | Object.defineProperty(exports, "__esModule", { value: true }); 12 | var core_1 = require("@angular/core"); 13 | var material_1 = require("@angular/material"); 14 | var layouts_1 = require("./layouts"); 15 | var virtual_keyboard_service_1 = require("./virtual-keyboard.service"); 16 | var VirtualKeyboardComponent = /** @class */ (function () { 17 | /** 18 | * Constructor of the class. 19 | * 20 | * @param {MatDialogRef} dialogRef 21 | * @param {VirtualKeyboardService} virtualKeyboardService 22 | */ 23 | function VirtualKeyboardComponent(dialogRef, virtualKeyboardService) { 24 | this.dialogRef = dialogRef; 25 | this.virtualKeyboardService = virtualKeyboardService; 26 | this.shift = false; 27 | } 28 | VirtualKeyboardComponent_1 = VirtualKeyboardComponent; 29 | /** 30 | * Helper method to set cursor in input to correct place. 31 | * 32 | * @param {HTMLInputElement|HTMLTextAreaElement} input 33 | * @param {number} start 34 | * @param {number} end 35 | */ 36 | VirtualKeyboardComponent.setSelectionRange = function (input, start, end) { 37 | if (input.setSelectionRange) { 38 | input.focus(); 39 | input.setSelectionRange(start, end); 40 | } 41 | else if (input.createTextRange) { 42 | var range = input.createTextRange(); 43 | range.collapse(true); 44 | range.moveEnd('character', end); 45 | range.moveStart('character', start); 46 | range.select(); 47 | } 48 | }; 49 | /** 50 | * On init life cycle hook, this will do following: 51 | * 1) Set focus to virtual keyboard input field 52 | * 2) Subscribe to following 53 | * 2.1) Shift key, this is needed in keyboard event dispatches 54 | * 2.2) CapsLock key, this will change keyboard layout 55 | * 2.3) Caret position in virtual keyboard input 56 | * 3) Reset of possible previously tracked caret position 57 | */ 58 | VirtualKeyboardComponent.prototype.ngOnInit = function () { 59 | var _this = this; 60 | setTimeout(function () { 61 | _this.keyboardInput.nativeElement.focus(); 62 | }, 0); 63 | this.virtualKeyboardService.shift$.subscribe(function (shift) { 64 | _this.shift = shift; 65 | }); 66 | this.virtualKeyboardService.capsLock$.subscribe(function (capsLock) { 67 | _this.layout = layouts_1.keyboardCapsLockLayout(_this.layout, capsLock); 68 | }); 69 | this.virtualKeyboardService.caretPosition$.subscribe(function (caretPosition) { 70 | _this.caretPosition = caretPosition; 71 | setTimeout(function () { 72 | VirtualKeyboardComponent_1.setSelectionRange(_this.keyboardInput.nativeElement, caretPosition, caretPosition); 73 | }, 0); 74 | }); 75 | if (this.inputElement.nativeElement.value.length) { 76 | this.virtualKeyboardService.setCaretPosition(this.inputElement.nativeElement.value.length); 77 | } 78 | this.maxLength = this.inputElement.nativeElement.maxLength > 0 ? this.inputElement.nativeElement.maxLength : ''; 79 | this.checkDisabled(); 80 | }; 81 | /** 82 | * On destroy life cycle hook, in this we want to reset virtual keyboard service states on following: 83 | * - Shift 84 | * - CapsLock 85 | */ 86 | VirtualKeyboardComponent.prototype.ngOnDestroy = function () { 87 | this.virtualKeyboardService.reset(); 88 | }; 89 | /** 90 | * Method to close virtual keyboard dialog 91 | */ 92 | VirtualKeyboardComponent.prototype.close = function () { 93 | this.dialogRef.close(); 94 | }; 95 | /** 96 | * Method to update caret position. This is called on click event in virtual keyboard input element. 97 | */ 98 | VirtualKeyboardComponent.prototype.updateCaretPosition = function () { 99 | this.virtualKeyboardService.setCaretPosition(this.keyboardInput.nativeElement.selectionStart); 100 | }; 101 | /** 102 | * Method to handle actual "key" press from virtual keyboard. 103 | * 1) Key is "Special", process special key event 104 | * 2) Key is "Normal" 105 | * - Append this key value to input 106 | * - Dispatch DOM events to input element 107 | * - Toggle Shift key if it's pressed 108 | * 109 | * @param {KeyPressInterface} event 110 | */ 111 | VirtualKeyboardComponent.prototype.keyPress = function (event) { 112 | if (event.special) { 113 | this.handleSpecialKey(event); 114 | } 115 | else { 116 | this.handleNormalKey(event.keyValue); 117 | this.dispatchEvents(event); 118 | // Toggle shift if it's activated 119 | if (this.shift) { 120 | this.virtualKeyboardService.toggleShift(); 121 | } 122 | } 123 | this.checkDisabled(); 124 | }; 125 | /** 126 | * Method to check is virtual keyboard input is disabled. 127 | */ 128 | VirtualKeyboardComponent.prototype.checkDisabled = function () { 129 | var maxLength = this.inputElement.nativeElement.maxLength; 130 | var valueLength = this.inputElement.nativeElement.value.length; 131 | this.disabled = maxLength > 0 && valueLength >= maxLength; 132 | }; 133 | /** 134 | * Method to handle "normal" key press event, this will add specified character to input value. 135 | * 136 | * @param {string} keyValue 137 | */ 138 | VirtualKeyboardComponent.prototype.handleNormalKey = function (keyValue) { 139 | var value = ''; 140 | // We have caret position, so attach character to specified position 141 | if (!isNaN(this.caretPosition)) { 142 | value = [ 143 | this.inputElement.nativeElement.value.slice(0, this.caretPosition), 144 | keyValue, 145 | this.inputElement.nativeElement.value.slice(this.caretPosition) 146 | ].join(''); 147 | // Update caret position 148 | this.virtualKeyboardService.setCaretPosition(this.caretPosition + 1); 149 | } 150 | else { 151 | value = "" + this.inputElement.nativeElement.value + keyValue; 152 | } 153 | // And finally set new value to input 154 | this.inputElement.nativeElement.value = value; 155 | }; 156 | /** 157 | * Method to handle "Special" key press events. 158 | * 1) Enter 159 | * 2) Escape, close virtual keyboard 160 | * 3) Backspace, remove last character from input value 161 | * 4) CapsLock, toggle current layout state 162 | * 6) Shift, toggle current layout state 163 | * 5) SpaceBar 164 | */ 165 | VirtualKeyboardComponent.prototype.handleSpecialKey = function (event) { 166 | switch (event.keyValue) { 167 | case 'Enter': 168 | this.close(); 169 | break; 170 | case 'Escape': 171 | this.close(); 172 | break; 173 | case 'Backspace': 174 | var currentValue = this.inputElement.nativeElement.value; 175 | // We have a caret position, so we need to remove char from that position 176 | if (!isNaN(this.caretPosition)) { 177 | // And current position must > 0 178 | if (this.caretPosition > 0) { 179 | var start = currentValue.slice(0, this.caretPosition - 1); 180 | var end = currentValue.slice(this.caretPosition); 181 | this.inputElement.nativeElement.value = "" + start + end; 182 | // Update caret position 183 | this.virtualKeyboardService.setCaretPosition(this.caretPosition - 1); 184 | } 185 | } 186 | else { 187 | this.inputElement.nativeElement.value = currentValue.substring(0, currentValue.length - 1); 188 | } 189 | this.dispatchEvents(event); 190 | // Set focus to keyboard input 191 | this.keyboardInput.nativeElement.focus(); 192 | break; 193 | case 'CapsLock': 194 | this.virtualKeyboardService.toggleCapsLock(); 195 | break; 196 | case 'Shift': 197 | this.virtualKeyboardService.toggleShift(); 198 | break; 199 | case 'SpaceBar': 200 | this.handleNormalKey(' '); 201 | break; 202 | } 203 | }; 204 | /** 205 | * Method to dispatch necessary keyboard events to current input element. 206 | * 207 | * @see https://w3c.github.io/uievents/tools/key-event-viewer.html 208 | * 209 | * @param {KeyPressInterface} event 210 | */ 211 | VirtualKeyboardComponent.prototype.dispatchEvents = function (event) { 212 | var eventInit = { 213 | bubbles: true, 214 | cancelable: true, 215 | shiftKey: this.shift, 216 | key: event.keyValue, 217 | code: "Key" + event.keyValue.toUpperCase() + "}", 218 | location: 0 219 | }; 220 | // Simulate all needed events on base element 221 | this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keydown', eventInit)); 222 | this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keypress', eventInit)); 223 | this.inputElement.nativeElement.dispatchEvent(new Event('input', { bubbles: true })); 224 | this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keyup', eventInit)); 225 | // And set focus to input 226 | this.keyboardInput.nativeElement.focus(); 227 | }; 228 | var VirtualKeyboardComponent_1; 229 | __decorate([ 230 | core_1.ViewChild('keyboardInput', { static: true }), 231 | __metadata("design:type", core_1.ElementRef) 232 | ], VirtualKeyboardComponent.prototype, "keyboardInput", void 0); 233 | VirtualKeyboardComponent = VirtualKeyboardComponent_1 = __decorate([ 234 | core_1.Component({ 235 | selector: 'virtual-keyboard', 236 | template: "\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n ", 237 | styles: ["\n .close {\n position: relative;\n float: right;\n top: -16px;\n right: 0;\n margin-bottom: -40px;\n }\n \n .mat-input-container {\n margin: -16px 0;\n font-size: 32px;\n }\n \n .mat-input-element:disabled {\n color: currentColor;\n }\n\n :host /deep/ .mat-input-placeholder {\n top: 10px !important;\n font-size: 24px !important;\n }\n "] 238 | }), 239 | __metadata("design:paramtypes", [material_1.MatDialogRef, 240 | virtual_keyboard_service_1.VirtualKeyboardService]) 241 | ], VirtualKeyboardComponent); 242 | return VirtualKeyboardComponent; 243 | }()); 244 | exports.VirtualKeyboardComponent = VirtualKeyboardComponent; 245 | //# sourceMappingURL=virtual-keyboard.component.js.map -------------------------------------------------------------------------------- /dist/ng-virtual-keyboard.umd.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("@angular/core"),require("@angular/material"),require("rxjs/internal/ReplaySubject"),require("@angular/common"),require("@angular/forms"),require("@angular/flex-layout")):"function"==typeof define&&define.amd?define(["@angular/core","@angular/material","rxjs/internal/ReplaySubject","@angular/common","@angular/forms","@angular/flex-layout"],t):"object"==typeof exports?exports["ng-virtual-keyboard"]=t(require("@angular/core"),require("@angular/material"),require("rxjs/internal/ReplaySubject"),require("@angular/common"),require("@angular/forms"),require("@angular/flex-layout")):e["ng-virtual-keyboard"]=t(e["@angular/core"],e["@angular/material"],e["rxjs/internal/ReplaySubject"],e["@angular/common"],e["@angular/forms"],e["@angular/flex-layout"])}(window,(function(e,t,n,i,o,a){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=6)}([function(t,n){t.exports=e},function(e,n){e.exports=t},function(e,t,n){"use strict";function i(e){return e.length>1&&!!t.specialKeys.filter((function(t){return new RegExp("^("+t+")(:(\\d+(\\.\\d+)?))?$","g").test(e)})).length}Object.defineProperty(t,"__esModule",{value:!0}),t.alphanumericKeyboard=[["1","2","3","4","5","6","7","8","9","0","Backspace:2"],["q","w","e","r","t","y","u","i","o","p","CapsLock:2"],["a","s","d","f","g","h","j","k","l","Spacer","Shift:2"],["z","x","c","v","b","n","m","Spacer:5"]],t.alphanumericNordicKeyboard=[["1","2","3","4","5","6","7","8","9","0","Spacer","Backspace:2"],["q","w","e","r","t","y","u","i","o","p","å","CapsLock:2"],["a","s","d","f","g","h","j","k","l","ö","ä","Shift:2"],["z","x","c","v","b","n","m","Spacer:6"]],t.extendedKeyboard=[["1","2","3","4","5","6","7","8","9","0","Backspace:2"],["q","w","e","r","t","y","u","i","o","p","CapsLock:2"],["a","s","d","f","g","h","j","k","l","Spacer","Shift:2"],["z","x","c","v","b","n","m",",",".","-","_","+"],["Spacer","@","SpaceBar:7","#","Spacer:2"]],t.extendedNordicKeyboard=[["1","2","3","4","5","6","7","8","9","0","+","Backspace:2"],["q","w","e","r","t","y","u","i","o","p","å","CapsLock:2"],["a","s","d","f","g","h","j","k","l","ö","ä","Shift:2"],["z","x","c","v","b","n","m",",",".","-","_","Spacer:2"],["Spacer","@","SpaceBar:7","#","Spacer:3"]],t.numericKeyboard=[["1","2","3","Backspace:2"],["4","5","6","Spacer:2"],["7","8","9","Spacer:2"],["Spacer","0","Spacer:3"]],t.phoneKeyboard=[["1","2","3","Backspace:2"],["4","5","6","Spacer:2"],["7","8","9","Spacer:2"],["-","0","+","Spacer:2"]],t.specialKeys=["Enter","Backspace","Escape","CapsLock","SpaceBar","Spacer","Shift"],t.specialKeyIcons={Enter:"keyboard_return",Backspace:"backspace",Escape:"close",SpaceBar:"space_bar",Shift:"keyboard_capslock"},t.specialKeyTexts={CapsLock:"Caps"},t.notDisabledSpecialKeys=["Enter","Backspace","Escape"],t.isSpacer=function(e){return e.length>1&&/^Spacer(:(\d+(\.\d+)?))?$/g.test(e)},t.isSpecial=i,t.keyboardCapsLockLayout=function(e,t){return e.map((function(e){return e.map((function(e){return i(e)?e:t?e.toUpperCase():e.toLowerCase()}))}))}},function(e,t,n){"use strict";var i=this&&this.__decorate||function(e,t,n,i){var o,a=arguments.length,r=a<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(r=(a<3?o(r):a>3?o(t,n,r):o(t,n))||r);return a>3&&r&&Object.defineProperty(t,n,r),r},o=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)};Object.defineProperty(t,"__esModule",{value:!0});var a=n(0),r=n(1),s=n(4),c=n(2),l=function(){function e(e,t){this.element=e,this.dialog=t,this.opened=!1,this.focus=!0,this.keyboardClose=new a.EventEmitter}return e.prototype.onWindowBlur=function(){this.focus=!1},e.prototype.onWindowFocus=function(){var e=this;setTimeout((function(){e.focus=!0}),0)},e.prototype.onFocus=function(){this.openKeyboard()},e.prototype.onClick=function(){this.openKeyboard()},e.prototype.openKeyboard=function(){var e=this;if(!this.opened&&this.focus){this.opened=!0;var t=void 0;(t=this.dialog.open(s.VirtualKeyboardComponent)).componentInstance.inputElement=this.element,t.componentInstance.layout=this.getLayout(),t.componentInstance.placeholder=this.getPlaceHolder(),t.componentInstance.type=this.getType(),t.afterClosed().subscribe((function(){e.keyboardClose.emit(),setTimeout((function(){e.opened=!1}),0)}))}},e.prototype.getLayout=function(){var e;switch(this.layout){case"alphanumeric":e=c.alphanumericKeyboard;break;case"alphanumericNordic":e=c.alphanumericNordicKeyboard;break;case"extended":e=c.extendedKeyboard;break;case"extendedNordic":e=c.extendedNordicKeyboard;break;case"numeric":e=c.numericKeyboard;break;case"phone":e=c.phoneKeyboard;break;default:e=this.layout}return e},e.prototype.getPlaceHolder=function(){return this.placeholder?this.placeholder:this.element.nativeElement.placeholder},e.prototype.getType=function(){return this.type?this.type:this.element.nativeElement.type},i([a.Input("ng-virtual-keyboard-layout"),o("design:type",Object)],e.prototype,"layout",void 0),i([a.Input("ng-virtual-keyboard-placeholder"),o("design:type",String)],e.prototype,"placeholder",void 0),i([a.Input("ng-virtual-keyboard-type"),o("design:type",String)],e.prototype,"type",void 0),i([a.Output("ng-virtual-keyboard-close"),o("design:type",a.EventEmitter)],e.prototype,"keyboardClose",void 0),i([a.HostListener("window:blur"),o("design:type",Function),o("design:paramtypes",[]),o("design:returntype",void 0)],e.prototype,"onWindowBlur",null),i([a.HostListener("window:focus"),o("design:type",Function),o("design:paramtypes",[]),o("design:returntype",void 0)],e.prototype,"onWindowFocus",null),i([a.HostListener("focus"),o("design:type",Function),o("design:paramtypes",[]),o("design:returntype",void 0)],e.prototype,"onFocus",null),i([a.HostListener("click"),o("design:type",Function),o("design:paramtypes",[]),o("design:returntype",void 0)],e.prototype,"onClick",null),e=i([a.Directive({selector:"[ng-virtual-keyboard]"}),o("design:paramtypes",[a.ElementRef,r.MatDialog])],e)}();t.NgVirtualKeyboardDirective=l},function(e,t,n){"use strict";var i=this&&this.__decorate||function(e,t,n,i){var o,a=arguments.length,r=a<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(r=(a<3?o(r):a>3?o(t,n,r):o(t,n))||r);return a>3&&r&&Object.defineProperty(t,n,r),r},o=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)};Object.defineProperty(t,"__esModule",{value:!0});var a=n(0),r=n(1),s=n(2),c=n(5),l=function(){function e(e,t){this.dialogRef=e,this.virtualKeyboardService=t,this.shift=!1}var t;return t=e,e.setSelectionRange=function(e,t,n){if(e.setSelectionRange)e.focus(),e.setSelectionRange(t,n);else if(e.createTextRange){var i=e.createTextRange();i.collapse(!0),i.moveEnd("character",n),i.moveStart("character",t),i.select()}},e.prototype.ngOnInit=function(){var e=this;setTimeout((function(){e.keyboardInput.nativeElement.focus()}),0),this.virtualKeyboardService.shift$.subscribe((function(t){e.shift=t})),this.virtualKeyboardService.capsLock$.subscribe((function(t){e.layout=s.keyboardCapsLockLayout(e.layout,t)})),this.virtualKeyboardService.caretPosition$.subscribe((function(n){e.caretPosition=n,setTimeout((function(){t.setSelectionRange(e.keyboardInput.nativeElement,n,n)}),0)})),this.inputElement.nativeElement.value.length&&this.virtualKeyboardService.setCaretPosition(this.inputElement.nativeElement.value.length),this.maxLength=this.inputElement.nativeElement.maxLength>0?this.inputElement.nativeElement.maxLength:"",this.checkDisabled()},e.prototype.ngOnDestroy=function(){this.virtualKeyboardService.reset()},e.prototype.close=function(){this.dialogRef.close()},e.prototype.updateCaretPosition=function(){this.virtualKeyboardService.setCaretPosition(this.keyboardInput.nativeElement.selectionStart)},e.prototype.keyPress=function(e){e.special?this.handleSpecialKey(e):(this.handleNormalKey(e.keyValue),this.dispatchEvents(e),this.shift&&this.virtualKeyboardService.toggleShift()),this.checkDisabled()},e.prototype.checkDisabled=function(){var e=this.inputElement.nativeElement.maxLength,t=this.inputElement.nativeElement.value.length;this.disabled=e>0&&t>=e},e.prototype.handleNormalKey=function(e){var t="";isNaN(this.caretPosition)?t=""+this.inputElement.nativeElement.value+e:(t=[this.inputElement.nativeElement.value.slice(0,this.caretPosition),e,this.inputElement.nativeElement.value.slice(this.caretPosition)].join(""),this.virtualKeyboardService.setCaretPosition(this.caretPosition+1)),this.inputElement.nativeElement.value=t},e.prototype.handleSpecialKey=function(e){switch(e.keyValue){case"Enter":case"Escape":this.close();break;case"Backspace":var t=this.inputElement.nativeElement.value;if(isNaN(this.caretPosition))this.inputElement.nativeElement.value=t.substring(0,t.length-1);else if(this.caretPosition>0){var n=t.slice(0,this.caretPosition-1),i=t.slice(this.caretPosition);this.inputElement.nativeElement.value=""+n+i,this.virtualKeyboardService.setCaretPosition(this.caretPosition-1)}this.dispatchEvents(e),this.keyboardInput.nativeElement.focus();break;case"CapsLock":this.virtualKeyboardService.toggleCapsLock();break;case"Shift":this.virtualKeyboardService.toggleShift();break;case"SpaceBar":this.handleNormalKey(" ")}},e.prototype.dispatchEvents=function(e){var t={bubbles:!0,cancelable:!0,shiftKey:this.shift,key:e.keyValue,code:"Key"+e.keyValue.toUpperCase()+"}",location:0};this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent("keydown",t)),this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent("keypress",t)),this.inputElement.nativeElement.dispatchEvent(new Event("input",{bubbles:!0})),this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent("keyup",t)),this.keyboardInput.nativeElement.focus()},i([a.ViewChild("keyboardInput",{static:!0}),o("design:type",a.ElementRef)],e.prototype,"keyboardInput",void 0),e=t=i([a.Component({selector:"virtual-keyboard",template:'\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n ',styles:["\n .close {\n position: relative;\n float: right;\n top: -16px;\n right: 0;\n margin-bottom: -40px;\n }\n \n .mat-input-container {\n margin: -16px 0;\n font-size: 32px;\n }\n \n .mat-input-element:disabled {\n color: currentColor;\n }\n\n :host /deep/ .mat-input-placeholder {\n top: 10px !important;\n font-size: 24px !important;\n }\n "]}),o("design:paramtypes",[r.MatDialogRef,c.VirtualKeyboardService])],e)}();t.VirtualKeyboardComponent=l},function(e,t,n){"use strict";var i=this&&this.__decorate||function(e,t,n,i){var o,a=arguments.length,r=a<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(r=(a<3?o(r):a>3?o(t,n,r):o(t,n))||r);return a>3&&r&&Object.defineProperty(t,n,r),r};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(7),r=function(){function e(){this.shift$=new a.ReplaySubject(1),this.capsLock$=new a.ReplaySubject(1),this.caretPosition$=new a.ReplaySubject(1),this.capsLock=!1,this.shift=!1}return e.prototype.setShift=function(e){this.shift=e,this.shift$.next(this.shift),this.setCapsLock(this.shift)},e.prototype.setCapsLock=function(e){this.capsLock=e,this.capsLock$.next(e)},e.prototype.toggleShift=function(){this.shift=!this.shift,this.shift$.next(this.shift),this.setCapsLock(this.shift)},e.prototype.toggleCapsLock=function(){this.capsLock=!this.capsLock,this.capsLock$.next(this.capsLock)},e.prototype.setCaretPosition=function(e){this.caretPosition$.next(e)},e.prototype.reset=function(){this.setShift(!1)},e=i([o.Injectable()],e)}();t.VirtualKeyboardService=r},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=n(3);t.NgVirtualKeyboardDirective=i.NgVirtualKeyboardDirective;var o=n(8);t.NgVirtualKeyboardModule=o.NgVirtualKeyboardModule},function(e,t){e.exports=n},function(e,t,n){"use strict";var i=this&&this.__decorate||function(e,t,n,i){var o,a=arguments.length,r=a<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(r=(a<3?o(r):a>3?o(t,n,r):o(t,n))||r);return a>3&&r&&Object.defineProperty(t,n,r),r};Object.defineProperty(t,"__esModule",{value:!0});var o=n(0),a=n(9),r=n(10),s=n(1),c=n(11),l=n(3),p=n(4),u=n(12),d=n(5),y=function(){function e(){}return e=i([o.NgModule({declarations:[l.NgVirtualKeyboardDirective,p.VirtualKeyboardComponent,u.VirtualKeyboardKeyComponent],providers:[d.VirtualKeyboardService],imports:[a.CommonModule,r.FormsModule,r.ReactiveFormsModule,c.FlexLayoutModule,s.MatButtonModule,s.MatDialogModule,s.MatIconModule,s.MatInputModule],entryComponents:[p.VirtualKeyboardComponent],exports:[l.NgVirtualKeyboardDirective]})],e)}();t.NgVirtualKeyboardModule=y},function(e,t){e.exports=i},function(e,t){e.exports=o},function(e,t){e.exports=a},function(e,t,n){"use strict";var i=this&&this.__decorate||function(e,t,n,i){var o,a=arguments.length,r=a<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,n,i);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(r=(a<3?o(r):a>3?o(t,n,r):o(t,n))||r);return a>3&&r&&Object.defineProperty(t,n,r),r},o=this&&this.__metadata||function(e,t){if("object"==typeof Reflect&&"function"==typeof Reflect.metadata)return Reflect.metadata(e,t)};Object.defineProperty(t,"__esModule",{value:!0});var a=n(0),r=n(2),s=function(){function e(){this.keyPress=new a.EventEmitter,this.special=!1,this.spacer=!1}return e.prototype.ngOnInit=function(){var e=1,t=0;if(this.key.length>1){this.spacer=r.isSpacer(this.key),this.special=r.isSpecial(this.key);var n=/^(\w+)(:(\d+(\.\d+)?))?$/g.exec(this.key);this.keyValue=n[1],n[3]&&(t=4*((e=parseFloat(n[3]))-1))}else this.keyValue=this.key;this.special&&(r.specialKeyIcons.hasOwnProperty(this.keyValue)?this.icon=r.specialKeyIcons[this.keyValue]:r.specialKeyTexts.hasOwnProperty(this.keyValue)&&(this.text=r.specialKeyTexts[this.keyValue])),this.flexValue=64*e+t+"px"},e.prototype.isDisabled=function(){return!!this.spacer||(!this.disabled||-1===r.notDisabledSpecialKeys.indexOf(this.keyValue))&&this.disabled},e.prototype.onKeyPress=function(){this.keyPress.emit({special:this.special,keyValue:this.keyValue,key:this.key})},i([a.Input(),o("design:type",String)],e.prototype,"key",void 0),i([a.Input(),o("design:type",Boolean)],e.prototype,"disabled",void 0),i([a.Output(),o("design:type",Object)],e.prototype,"keyPress",void 0),e=i([a.Component({selector:"virtual-keyboard-key",template:'\n \n {{ keyValue }}\n \n \n {{ icon }}\n \n {{ text }}\n \n \n ',styles:["\n .mat-button,\n .mat-icon-button,\n .mat-raised-button {\n min-width: 64px;\n min-height: 64px;\n padding: 0;\n margin: 2px;\n font-size: 32px;\n line-height: 32px;\n }\n \n .mat-button.spacer,\n .mat-icon-button.spacer,\n .mat-raised-button.spacer {\n background-color: transparent;\n }\n "]}),o("design:paramtypes",[])],e)}();t.VirtualKeyboardKeyComponent=s}])})); 2 | //# sourceMappingURL=ng-virtual-keyboard.umd.js.map -------------------------------------------------------------------------------- /dist/ng-virtual-keyboard.umd.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://ng-virtual-keyboard/webpack/universalModuleDefinition","webpack://ng-virtual-keyboard/webpack/bootstrap","webpack://ng-virtual-keyboard/external \"@angular/core\"","webpack://ng-virtual-keyboard/external \"@angular/material\"","webpack://ng-virtual-keyboard/./src/layouts.ts","webpack://ng-virtual-keyboard/./src/virtual-keyboard.directive.ts","webpack://ng-virtual-keyboard/./src/virtual-keyboard.component.ts","webpack://ng-virtual-keyboard/./src/virtual-keyboard.service.ts","webpack://ng-virtual-keyboard/./src/index.ts","webpack://ng-virtual-keyboard/external \"rxjs/internal/ReplaySubject\"","webpack://ng-virtual-keyboard/./src/virtual-keyboard.module.ts","webpack://ng-virtual-keyboard/external \"@angular/common\"","webpack://ng-virtual-keyboard/external \"@angular/forms\"","webpack://ng-virtual-keyboard/external \"@angular/flex-layout\"","webpack://ng-virtual-keyboard/./src/virtual-keyboard-key.component.ts"],"names":["root","factory","exports","module","require","define","amd","window","__WEBPACK_EXTERNAL_MODULE__0__","__WEBPACK_EXTERNAL_MODULE__1__","__WEBPACK_EXTERNAL_MODULE__7__","__WEBPACK_EXTERNAL_MODULE__9__","__WEBPACK_EXTERNAL_MODULE__10__","__WEBPACK_EXTERNAL_MODULE__11__","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","isSpecial","length","specialKeys","filter","specialKey","RegExp","test","alphanumericKeyboard","alphanumericNordicKeyboard","extendedKeyboard","extendedNordicKeyboard","numericKeyboard","phoneKeyboard","specialKeyIcons","Enter","Backspace","Escape","SpaceBar","Shift","specialKeyTexts","CapsLock","notDisabledSpecialKeys","layout","caps","map","row","toUpperCase","toLowerCase","element","dialog","opened","focus","this","keyboardClose","EventEmitter","onWindowBlur","onWindowFocus","setTimeout","onFocus","openKeyboard","onClick","dialogRef","open","VirtualKeyboardComponent","componentInstance","inputElement","getLayout","placeholder","getPlaceHolder","type","getType","afterClosed","subscribe","emit","nativeElement","Input","Output","HostListener","NgVirtualKeyboardDirective","Directive","selector","ElementRef","MatDialog","virtualKeyboardService","shift","setSelectionRange","input","start","end","createTextRange","range","collapse","moveEnd","moveStart","select","ngOnInit","keyboardInput","shift$","capsLock$","capsLock","keyboardCapsLockLayout","caretPosition$","caretPosition","setCaretPosition","maxLength","checkDisabled","ngOnDestroy","reset","close","updateCaretPosition","selectionStart","keyPress","event","special","handleSpecialKey","handleNormalKey","keyValue","dispatchEvents","toggleShift","valueLength","disabled","isNaN","slice","join","currentValue","substring","toggleCapsLock","eventInit","bubbles","cancelable","shiftKey","code","location","dispatchEvent","KeyboardEvent","Event","ViewChild","static","Component","template","styles","MatDialogRef","VirtualKeyboardService","ReplaySubject","setShift","next","setCapsLock","position","Injectable","NgVirtualKeyboardModule","NgModule","declarations","VirtualKeyboardKeyComponent","providers","imports","CommonModule","FormsModule","ReactiveFormsModule","FlexLayoutModule","MatButtonModule","MatDialogModule","MatIconModule","MatInputModule","entryComponents","spacer","multiplier","fix","isSpacer","matches","exec","parseFloat","icon","text","flexValue","isDisabled","indexOf","onKeyPress"],"mappings":"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","file":"ng-virtual-keyboard.umd.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"@angular/core\"), require(\"@angular/material\"), require(\"rxjs/internal/ReplaySubject\"), require(\"@angular/common\"), require(\"@angular/forms\"), require(\"@angular/flex-layout\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"@angular/core\", \"@angular/material\", \"rxjs/internal/ReplaySubject\", \"@angular/common\", \"@angular/forms\", \"@angular/flex-layout\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ng-virtual-keyboard\"] = factory(require(\"@angular/core\"), require(\"@angular/material\"), require(\"rxjs/internal/ReplaySubject\"), require(\"@angular/common\"), require(\"@angular/forms\"), require(\"@angular/flex-layout\"));\n\telse\n\t\troot[\"ng-virtual-keyboard\"] = factory(root[\"@angular/core\"], root[\"@angular/material\"], root[\"rxjs/internal/ReplaySubject\"], root[\"@angular/common\"], root[\"@angular/forms\"], root[\"@angular/flex-layout\"]);\n})(window, function(__WEBPACK_EXTERNAL_MODULE__0__, __WEBPACK_EXTERNAL_MODULE__1__, __WEBPACK_EXTERNAL_MODULE__7__, __WEBPACK_EXTERNAL_MODULE__9__, __WEBPACK_EXTERNAL_MODULE__10__, __WEBPACK_EXTERNAL_MODULE__11__) {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 6);\n","module.exports = __WEBPACK_EXTERNAL_MODULE__0__;","module.exports = __WEBPACK_EXTERNAL_MODULE__1__;","export type KeyboardLayout = Array>;\n\nexport const alphanumericKeyboard: KeyboardLayout = [\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Backspace:2'],\n ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'CapsLock:2'],\n ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'Spacer', 'Shift:2'],\n ['z', 'x', 'c', 'v', 'b', 'n', 'm', 'Spacer:5'],\n];\n\nexport const alphanumericNordicKeyboard: KeyboardLayout = [\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Spacer', 'Backspace:2'],\n ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'CapsLock:2'],\n ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'Shift:2'],\n ['z', 'x', 'c', 'v', 'b', 'n', 'm', 'Spacer:6'],\n];\n\nexport const extendedKeyboard: KeyboardLayout = [\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'Backspace:2'],\n ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'CapsLock:2'],\n ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'Spacer', 'Shift:2'],\n ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', '_', '+'],\n ['Spacer', '@', 'SpaceBar:7', '#', 'Spacer:2'],\n];\n\nexport const extendedNordicKeyboard: KeyboardLayout = [\n ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', 'Backspace:2'],\n ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'å', 'CapsLock:2'],\n ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä', 'Shift:2'],\n ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '-', '_', 'Spacer:2'],\n ['Spacer', '@', 'SpaceBar:7', '#', 'Spacer:3'],\n];\n\nexport const numericKeyboard: KeyboardLayout = [\n ['1', '2', '3', 'Backspace:2'],\n ['4', '5', '6', 'Spacer:2'],\n ['7', '8', '9', 'Spacer:2'],\n ['Spacer', '0', 'Spacer:3'],\n];\n\nexport const phoneKeyboard: KeyboardLayout = [\n ['1', '2', '3', 'Backspace:2'],\n ['4', '5', '6', 'Spacer:2'],\n ['7', '8', '9', 'Spacer:2'],\n ['-', '0', '+', 'Spacer:2'],\n];\n\nexport const specialKeys: Array = [\n 'Enter',\n 'Backspace',\n 'Escape',\n 'CapsLock',\n 'SpaceBar',\n 'Spacer',\n 'Shift',\n];\n\nexport const specialKeyIcons = {\n Enter: 'keyboard_return',\n Backspace: 'backspace',\n Escape: 'close',\n SpaceBar: 'space_bar',\n Shift: 'keyboard_capslock'\n};\n\nexport const specialKeyTexts = {\n CapsLock: 'Caps'\n};\n\nexport const notDisabledSpecialKeys = [\n 'Enter',\n 'Backspace',\n 'Escape',\n];\n\n/**\n * Helper function to determine if given key is 'Spacer' or not.\n *\n * @param {string} key\n * @returns {boolean}\n */\nexport function isSpacer(key: string): boolean {\n if (key.length > 1) {\n return /^Spacer(:(\\d+(\\.\\d+)?))?$/g.test(key);\n }\n\n return false;\n}\n\n/**\n * Helper function to determine if given key is special or not.\n *\n * @param {string} key\n * @returns {boolean}\n */\nexport function isSpecial(key: string): boolean {\n if (key.length > 1) {\n return !!specialKeys.filter(specialKey => {\n const pattern = new RegExp(`^(${specialKey})(:(\\\\d+(\\\\.\\\\d+)?))?$`, 'g');\n\n return pattern.test(key);\n }).length;\n }\n\n return false;\n}\n\n/**\n * Function to change specified layout to CapsLock layout.\n *\n * @param {KeyboardLayout} layout\n * @param {boolean} caps\n * @returns {KeyboardLayout}\n */\nexport function keyboardCapsLockLayout(layout: KeyboardLayout, caps: boolean): KeyboardLayout {\n return layout.map((row: Array): Array => {\n return row.map((key: string): string => {\n return isSpecial(key) ? key : (caps ? key.toUpperCase() : key.toLowerCase());\n });\n });\n}\n","import { Directive, ElementRef, EventEmitter, HostListener, Input, Output } from '@angular/core';\nimport { MatDialog, MatDialogRef } from '@angular/material';\n\nimport { VirtualKeyboardComponent } from './virtual-keyboard.component';\nimport {\n alphanumericKeyboard,\n alphanumericNordicKeyboard,\n extendedKeyboard,\n extendedNordicKeyboard,\n KeyboardLayout,\n numericKeyboard,\n phoneKeyboard\n} from './layouts';\n\n@Directive({\n selector: '[ng-virtual-keyboard]'\n})\n\nexport class NgVirtualKeyboardDirective {\n private opened = false;\n private focus = true;\n\n @Input('ng-virtual-keyboard-layout') layout: KeyboardLayout | string;\n @Input('ng-virtual-keyboard-placeholder') placeholder: string;\n @Input('ng-virtual-keyboard-type') type: string;\n @Output('ng-virtual-keyboard-close') keyboardClose: EventEmitter;\n\n @HostListener('window:blur')\n onWindowBlur() {\n this.focus = false;\n }\n\n @HostListener('window:focus')\n onWindowFocus() {\n setTimeout(() => {\n this.focus = true;\n }, 0);\n }\n\n @HostListener('focus')\n onFocus() {\n this.openKeyboard();\n }\n\n @HostListener('click')\n onClick() {\n this.openKeyboard();\n }\n\n /**\n * Constructor of the class.\n *\n * @param {ElementRef} element\n * @param {MatDialog} dialog\n */\n public constructor(\n private element: ElementRef,\n private dialog: MatDialog,\n ) { \n this.keyboardClose = new EventEmitter();\n }\n\n /**\n * Method to open virtual keyboard\n */\n private openKeyboard() {\n if (!this.opened && this.focus) {\n this.opened = true;\n\n let dialogRef: MatDialogRef;\n\n dialogRef = this.dialog.open(VirtualKeyboardComponent);\n dialogRef.componentInstance.inputElement = this.element;\n dialogRef.componentInstance.layout = this.getLayout();\n dialogRef.componentInstance.placeholder = this.getPlaceHolder();\n dialogRef.componentInstance.type = this.getType();\n\n dialogRef\n .afterClosed()\n .subscribe(() => {\n this.keyboardClose.emit();\n setTimeout(() => {\n this.opened = false;\n }, 0);\n });\n }\n }\n\n /**\n * Getter for used keyboard layout.\n *\n * @returns {KeyboardLayout}\n */\n private getLayout(): KeyboardLayout {\n let layout;\n\n switch (this.layout) {\n case 'alphanumeric':\n layout = alphanumericKeyboard;\n break;\n case 'alphanumericNordic':\n layout = alphanumericNordicKeyboard;\n break;\n case 'extended':\n layout = extendedKeyboard;\n break;\n case 'extendedNordic':\n layout = extendedNordicKeyboard;\n break;\n case 'numeric':\n layout = numericKeyboard;\n break;\n case 'phone':\n layout = phoneKeyboard;\n break;\n default:\n layout = this.layout;\n break;\n }\n\n return layout;\n }\n\n /**\n * Getter for used placeholder for virtual keyboard input field.\n *\n * @returns {string}\n */\n private getPlaceHolder(): string {\n return this.placeholder ? this.placeholder : this.element.nativeElement.placeholder;\n }\n\n /**\n * Getter for used type for virtual keyboard input field.\n * \n * @return {string}\n */\n private getType(): string {\n return this.type ? this.type : this.element.nativeElement.type;\n }\n}\n","import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';\nimport { MatDialogRef } from '@angular/material';\n\nimport { keyboardCapsLockLayout, KeyboardLayout } from './layouts';\nimport { VirtualKeyboardService } from './virtual-keyboard.service';\nimport { KeyPressInterface } from './key-press.interface';\n\n@Component({\n selector: 'virtual-keyboard',\n template: `\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n `,\n styles: [`\n .close {\n position: relative;\n float: right;\n top: -16px;\n right: 0;\n margin-bottom: -40px;\n }\n \n .mat-input-container {\n margin: -16px 0;\n font-size: 32px;\n }\n \n .mat-input-element:disabled {\n color: currentColor;\n }\n\n :host /deep/ .mat-input-placeholder {\n top: 10px !important;\n font-size: 24px !important;\n }\n `]\n})\n\nexport class VirtualKeyboardComponent implements OnInit, OnDestroy {\n @ViewChild('keyboardInput', { static: true }) keyboardInput: ElementRef;\n\n public inputElement: ElementRef;\n public layout: KeyboardLayout;\n public placeholder: string;\n public type: string;\n public disabled: boolean;\n public maxLength: number | string;\n\n private caretPosition: number;\n private shift = false;\n\n /**\n * Helper method to set cursor in input to correct place.\n *\n * @param {HTMLInputElement|HTMLTextAreaElement} input\n * @param {number} start\n * @param {number} end\n */\n private static setSelectionRange(\n input: any,\n start: number,\n end: number\n ): void {\n if (input.setSelectionRange) {\n input.focus();\n input.setSelectionRange(start, end);\n\n } else if (input.createTextRange) {\n const range = input.createTextRange();\n\n range.collapse(true);\n range.moveEnd('character', end);\n range.moveStart('character', start);\n range.select();\n }\n }\n\n /**\n * Constructor of the class.\n *\n * @param {MatDialogRef} dialogRef\n * @param {VirtualKeyboardService} virtualKeyboardService\n */\n public constructor(\n public dialogRef: MatDialogRef,\n private virtualKeyboardService: VirtualKeyboardService\n ) { }\n\n /**\n * On init life cycle hook, this will do following:\n * 1) Set focus to virtual keyboard input field\n * 2) Subscribe to following\n * 2.1) Shift key, this is needed in keyboard event dispatches\n * 2.2) CapsLock key, this will change keyboard layout\n * 2.3) Caret position in virtual keyboard input\n * 3) Reset of possible previously tracked caret position\n */\n public ngOnInit(): void {\n setTimeout(() => {\n this.keyboardInput.nativeElement.focus();\n }, 0);\n\n this.virtualKeyboardService.shift$.subscribe((shift: boolean) => {\n this.shift = shift;\n });\n\n this.virtualKeyboardService.capsLock$.subscribe((capsLock: boolean) => {\n this.layout = keyboardCapsLockLayout(this.layout, capsLock);\n });\n\n this.virtualKeyboardService.caretPosition$.subscribe((caretPosition: number) => {\n this.caretPosition = caretPosition;\n\n setTimeout(() => {\n VirtualKeyboardComponent.setSelectionRange(this.keyboardInput.nativeElement, caretPosition, caretPosition);\n }, 0);\n });\n\n if (this.inputElement.nativeElement.value.length) {\n this.virtualKeyboardService.setCaretPosition(this.inputElement.nativeElement.value.length);\n }\n\n this.maxLength = this.inputElement.nativeElement.maxLength > 0 ? this.inputElement.nativeElement.maxLength : '';\n\n this.checkDisabled();\n }\n\n /**\n * On destroy life cycle hook, in this we want to reset virtual keyboard service states on following:\n * - Shift\n * - CapsLock\n */\n public ngOnDestroy(): void {\n this.virtualKeyboardService.reset();\n }\n\n /**\n * Method to close virtual keyboard dialog\n */\n public close(): void {\n this.dialogRef.close();\n }\n\n /**\n * Method to update caret position. This is called on click event in virtual keyboard input element.\n */\n public updateCaretPosition(): void {\n this.virtualKeyboardService.setCaretPosition(this.keyboardInput.nativeElement.selectionStart);\n }\n\n /**\n * Method to handle actual \"key\" press from virtual keyboard.\n * 1) Key is \"Special\", process special key event\n * 2) Key is \"Normal\"\n * - Append this key value to input\n * - Dispatch DOM events to input element\n * - Toggle Shift key if it's pressed\n *\n * @param {KeyPressInterface} event\n */\n public keyPress(event: KeyPressInterface): void {\n if (event.special) {\n this.handleSpecialKey(event);\n } else {\n this.handleNormalKey(event.keyValue);\n\n this.dispatchEvents(event);\n\n // Toggle shift if it's activated\n if (this.shift) {\n this.virtualKeyboardService.toggleShift();\n }\n }\n\n this.checkDisabled();\n }\n\n /**\n * Method to check is virtual keyboard input is disabled.\n */\n private checkDisabled(): void {\n const maxLength = this.inputElement.nativeElement.maxLength;\n const valueLength = this.inputElement.nativeElement.value.length;\n\n this.disabled = maxLength > 0 && valueLength >= maxLength;\n }\n\n /**\n * Method to handle \"normal\" key press event, this will add specified character to input value.\n *\n * @param {string} keyValue\n */\n private handleNormalKey(keyValue: string): void {\n let value = '';\n\n // We have caret position, so attach character to specified position\n if (!isNaN(this.caretPosition)) {\n value = [\n this.inputElement.nativeElement.value.slice(0, this.caretPosition),\n keyValue,\n this.inputElement.nativeElement.value.slice(this.caretPosition)\n ].join('');\n\n // Update caret position\n this.virtualKeyboardService.setCaretPosition(this.caretPosition + 1);\n } else {\n value = `${this.inputElement.nativeElement.value}${keyValue}`;\n }\n\n // And finally set new value to input\n this.inputElement.nativeElement.value = value;\n }\n\n /**\n * Method to handle \"Special\" key press events.\n * 1) Enter\n * 2) Escape, close virtual keyboard\n * 3) Backspace, remove last character from input value\n * 4) CapsLock, toggle current layout state\n * 6) Shift, toggle current layout state\n * 5) SpaceBar\n */\n private handleSpecialKey(event: KeyPressInterface): void {\n switch (event.keyValue) {\n case 'Enter':\n this.close();\n break;\n case 'Escape':\n this.close();\n break;\n case 'Backspace':\n const currentValue = this.inputElement.nativeElement.value;\n\n // We have a caret position, so we need to remove char from that position\n if (!isNaN(this.caretPosition)) {\n // And current position must > 0\n if (this.caretPosition > 0) {\n const start = currentValue.slice(0, this.caretPosition - 1);\n const end = currentValue.slice(this.caretPosition);\n\n this.inputElement.nativeElement.value = `${start}${end}`;\n\n // Update caret position\n this.virtualKeyboardService.setCaretPosition(this.caretPosition - 1);\n }\n } else {\n this.inputElement.nativeElement.value = currentValue.substring(0, currentValue.length - 1);\n }\n\n this.dispatchEvents(event);\n // Set focus to keyboard input\n this.keyboardInput.nativeElement.focus();\n break;\n case 'CapsLock':\n this.virtualKeyboardService.toggleCapsLock();\n break;\n case 'Shift':\n this.virtualKeyboardService.toggleShift();\n break;\n case 'SpaceBar':\n this.handleNormalKey(' ');\n break;\n }\n }\n\n /**\n * Method to dispatch necessary keyboard events to current input element.\n *\n * @see https://w3c.github.io/uievents/tools/key-event-viewer.html\n *\n * @param {KeyPressInterface} event\n */\n private dispatchEvents(event: KeyPressInterface) {\n const eventInit: KeyboardEventInit = {\n bubbles: true,\n cancelable: true,\n shiftKey: this.shift,\n key: event.keyValue,\n code: `Key${event.keyValue.toUpperCase()}}`,\n location: 0\n };\n\n // Simulate all needed events on base element\n this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keydown', eventInit));\n this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keypress', eventInit));\n this.inputElement.nativeElement.dispatchEvent(new Event('input', { bubbles: true }));\n this.inputElement.nativeElement.dispatchEvent(new KeyboardEvent('keyup', eventInit));\n\n // And set focus to input\n this.keyboardInput.nativeElement.focus();\n }\n}\n","import { Injectable } from '@angular/core';\nimport { ReplaySubject } from 'rxjs/internal/ReplaySubject';\n\n@Injectable()\nexport class VirtualKeyboardService {\n public shift$: ReplaySubject = new ReplaySubject(1);\n public capsLock$: ReplaySubject = new ReplaySubject(1);\n public caretPosition$: ReplaySubject = new ReplaySubject(1);\n\n private capsLock = false;\n private shift = false;\n\n /**\n * Setter for Shift value, note that this also sets CapsLock value.\n *\n * @param {boolean} value\n */\n public setShift(value: boolean) {\n this.shift = value;\n this.shift$.next(this.shift);\n\n this.setCapsLock(this.shift);\n }\n\n /**\n * Setter for CapsLock value\n *\n * @param {boolean} value\n */\n public setCapsLock(value: boolean) {\n this.capsLock = value;\n this.capsLock$.next(value);\n }\n\n /**\n * Toggle for Shift, note that this also toggles CapsLock\n */\n public toggleShift(): void {\n this.shift = !this.shift;\n this.shift$.next(this.shift);\n\n this.setCapsLock(this.shift);\n }\n\n /**\n * Toggle for CapsLock\n */\n public toggleCapsLock() {\n this.capsLock = !this.capsLock;\n this.capsLock$.next(this.capsLock);\n }\n\n /**\n * Setter for caret position value.\n *\n * @param {number} position\n */\n public setCaretPosition(position: number) {\n this.caretPosition$.next(position);\n }\n\n /**\n * Method to reset Shift and CapsLock values to default ones.\n */\n public reset() {\n this.setShift(false);\n }\n}\n","import { NgVirtualKeyboardDirective } from './virtual-keyboard.directive';\nimport { NgVirtualKeyboardModule } from './virtual-keyboard.module';\n\nexport {\n NgVirtualKeyboardDirective,\n NgVirtualKeyboardModule\n}\n","module.exports = __WEBPACK_EXTERNAL_MODULE__7__;","import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { ReactiveFormsModule, FormsModule } from '@angular/forms';\nimport { MatButtonModule, MatDialogModule, MatIconModule, MatInputModule } from '@angular/material';\nimport { FlexLayoutModule } from '@angular/flex-layout';\n\nimport { NgVirtualKeyboardDirective } from './virtual-keyboard.directive';\nimport { VirtualKeyboardComponent } from './virtual-keyboard.component';\nimport { VirtualKeyboardKeyComponent } from './virtual-keyboard-key.component';\nimport { VirtualKeyboardService } from './virtual-keyboard.service';\n\n@NgModule({\n declarations: [\n NgVirtualKeyboardDirective,\n VirtualKeyboardComponent,\n VirtualKeyboardKeyComponent,\n ],\n providers: [\n VirtualKeyboardService,\n ],\n imports: [\n CommonModule,\n FormsModule,\n ReactiveFormsModule,\n FlexLayoutModule,\n MatButtonModule,\n MatDialogModule,\n MatIconModule,\n MatInputModule,\n ],\n entryComponents: [\n VirtualKeyboardComponent,\n ],\n exports: [\n NgVirtualKeyboardDirective,\n ]\n})\n\nexport class NgVirtualKeyboardModule { }\n","module.exports = __WEBPACK_EXTERNAL_MODULE__9__;","module.exports = __WEBPACK_EXTERNAL_MODULE__10__;","module.exports = __WEBPACK_EXTERNAL_MODULE__11__;","import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';\n\nimport { KeyPressInterface } from './key-press.interface';\nimport { isSpacer, isSpecial, notDisabledSpecialKeys, specialKeyIcons, specialKeyTexts } from './layouts';\n\n@Component({\n selector: 'virtual-keyboard-key',\n template: `\n \n {{ keyValue }}\n \n \n {{ icon }}\n \n {{ text }}\n \n \n `,\n styles: [`\n .mat-button,\n .mat-icon-button,\n .mat-raised-button {\n min-width: 64px;\n min-height: 64px;\n padding: 0;\n margin: 2px;\n font-size: 32px;\n line-height: 32px;\n }\n \n .mat-button.spacer,\n .mat-icon-button.spacer,\n .mat-raised-button.spacer {\n background-color: transparent;\n }\n `]\n})\n\nexport class VirtualKeyboardKeyComponent implements OnInit {\n @Input() key: string;\n @Input() disabled: boolean;\n @Output() keyPress = new EventEmitter();\n\n public special = false;\n public spacer = false;\n public flexValue: string;\n public keyValue: string;\n public icon: string;\n public text: string;\n\n /**\n * Constructor of the class.\n */\n public constructor() { }\n\n /**\n * On init life cycle hook, within this we'll initialize following properties:\n * - special\n * - keyValue\n * - flexValue\n */\n public ngOnInit(): void {\n let multiplier = 1;\n let fix = 0;\n\n if (this.key.length > 1) {\n this.spacer = isSpacer(this.key);\n this.special = isSpecial(this.key);\n\n const matches = /^(\\w+)(:(\\d+(\\.\\d+)?))?$/g.exec(this.key);\n\n this.keyValue = matches[1];\n\n if (matches[3]) {\n multiplier = parseFloat(matches[3]);\n fix = (multiplier - 1) * 4;\n }\n } else {\n this.keyValue = this.key;\n }\n\n if (this.special) {\n if (specialKeyIcons.hasOwnProperty(this.keyValue)) {\n this.icon = specialKeyIcons[this.keyValue];\n } else if (specialKeyTexts.hasOwnProperty(this.keyValue)) {\n this.text = specialKeyTexts[this.keyValue];\n }\n }\n\n this.flexValue = `${multiplier * 64 + fix}px`;\n }\n\n /**\n * Method to check if key is disabled or not.\n *\n * @returns {boolean}\n */\n public isDisabled(): boolean {\n if (this.spacer) {\n return true;\n } else if (this.disabled && notDisabledSpecialKeys.indexOf(this.keyValue) !== -1) {\n return false;\n } else {\n return this.disabled;\n }\n }\n\n /**\n * Method to handle actual \"key\" press from virtual keyboard.\n * 1) Key is \"Special\", process special key event\n * 2) Key is \"Normal\", append this key value to input\n */\n public onKeyPress(): void {\n this.keyPress.emit({special: this.special, keyValue: this.keyValue, key: this.key});\n }\n}\n"],"sourceRoot":""} --------------------------------------------------------------------------------