diff --git a/dist/js/bundle.js b/dist/js/bundle.js index 8041f1d..348f7b0 100644 --- a/dist/js/bundle.js +++ b/dist/js/bundle.js @@ -1,2 +1,2 @@ -!function e(t,n,i){function o(l,s){if(!n[l]){if(!t[l]){var u="function"==typeof require&&require;if(!s&&u)return u(l,!0);if(a)return a(l,!0);var c=new Error("Cannot find module '"+l+"'");throw c.code="MODULE_NOT_FOUND",c}var r=n[l]={exports:{}};t[l][0].call(r.exports,(function(e){return o(t[l][1][e]||e)}),r,r.exports,e,t,n,i)}return n[l].exports}for(var a="function"==typeof require&&require,l=0;l0&&void 0!==arguments[0]?arguments[0]:1,t=this.value,n=this.selectionStartPosition,i=t.slice(0,n);if(""!==i){var o=t.slice(n),a=i.length-e,l=i.slice(0,a)+o,s=n-e;this.value=l,this.selectionPosition=s,this.inputEventHandler()}}},{key:"replaceValue",value:function(e){this.removeValue(),this.insertValue(e),this.inputEventHandler()}},{key:"clear",value:function(){this.value="",this.focus()}},{key:"validation",value:function(){var e=this.selectionStartPosition,t=this.value.replace(/[^0-9+*#]/g,""),n=e+t.length-this.value.length;this.value=t,this.selectionPosition=n}},{key:"inputEventHandler",value:function(){this.validation(),""===this.value?(console.log("value empty"),this.config.onValueEmpty()):(console.log("value non empty"),this.config.onValueNonEmpty())}},{key:"skeleton",get:function(){var e=document.createElement("input");return e.id=this.id,e.className="input-element",e.name="number",e.type="text",e.autofocus=!0,e.inputMode="none",e.autocomplete="off",e.addEventListener("input",this.inputEventHandler.bind(this)),e}},{key:"querySelector",get:function(){return document.getElementById(this.id)}},{key:"id",get:function(){return"input-"+this.config.namespace}},{key:"selectionStartPosition",get:function(){return this.makeSureFocused(),this.querySelector.selectionStart}},{key:"selectionEndPosition",get:function(){return this.makeSureFocused(),this.querySelector.selectionEnd}},{key:"selectionPosition",set:function(e){this.makeSureFocused(),this.querySelector.selectionStart=e,this.querySelector.selectionEnd=e}},{key:"focused",get:function(){return document.activeElement===this.querySelector}},{key:"value",get:function(){return this.querySelector.value},set:function(e){this.querySelector.value=e}}]),e}();n.default=o},{}],3:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});n.default=[{namespace:"one",ariaLabel:"One",title:"1"},{namespace:"two",ariaLabel:"Two",title:"2",subtitle:"ABC"},{namespace:"three",ariaLabel:"Three",title:"3",subtitle:"DEF"},{namespace:"four",ariaLabel:"Four",title:"4",subtitle:"GHI"},{namespace:"five",ariaLabel:"Five",title:"5",subtitle:"JKL"},{namespace:"six",ariaLabel:"Six",title:"6",subtitle:"MNO"},{namespace:"seven",ariaLabel:"Seven",title:"7",subtitle:"PQRS"},{namespace:"eight",ariaLabel:"Eight",title:"8",subtitle:"TUV"},{namespace:"nine",ariaLabel:"Nine",title:"9",subtitle:"WXYZ"},{namespace:"star",ariaLabel:"Star",title:"*"},{namespace:"zero",ariaLabel:"Zero",title:"0",subtitle:"+"},{namespace:"hash",ariaLabel:"Hash",title:"#"}]},{}],4:[function(e,t,n){"use strict";var i=function(){function e(e,t){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:1,t=this.value,n=this.selectionStartPosition,i=t.slice(0,n);if(""!==i){var o=t.slice(n),a=i.length-e,l=i.slice(0,a)+o,s=n-e;this.value=l,this.selectionPosition=s,this.inputEventHandler()}}},{key:"replaceValue",value:function(e){this.removeValue(),this.insertValue(e),this.inputEventHandler()}},{key:"clear",value:function(){this.value="",this.focus()}},{key:"validation",value:function(){var e=this.selectionStartPosition,t=this.value.replace(/[^0-9+*#]/g,""),n=e+t.length-this.value.length;this.value=t,this.selectionPosition=n}},{key:"inputEventHandler",value:function(){this.validation(),""===this.value?(console.log("value empty"),this.config.onValueEmpty()):(console.log("value non empty"),this.config.onValueNonEmpty())}},{key:"skeleton",get:function(){var e=document.createElement("input");return e.id=this.id,e.className="input-element",e.name="number",e.type="text",e.autofocus=!0,e.inputMode="none",e.autocomplete="off",e.addEventListener("input",this.inputEventHandler.bind(this)),e}},{key:"querySelector",get:function(){return document.getElementById(this.id)}},{key:"id",get:function(){return"input-"+this.config.namespace}},{key:"selectionStartPosition",get:function(){return this.makeSureFocused(),this.querySelector.selectionStart}},{key:"selectionEndPosition",get:function(){return this.makeSureFocused(),this.querySelector.selectionEnd}},{key:"selectionPosition",set:function(e){this.makeSureFocused(),this.querySelector.selectionStart=e,this.querySelector.selectionEnd=e}},{key:"focused",get:function(){return document.activeElement===this.querySelector}},{key:"value",get:function(){return this.querySelector.value},set:function(e){this.querySelector.value=e}}]),e}();n.default=o},{}],3:[function(e,t,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0});n.default=[{namespace:"one",ariaLabel:"One",title:"1"},{namespace:"two",ariaLabel:"Two",title:"2",subtitle:"ABC"},{namespace:"three",ariaLabel:"Three",title:"3",subtitle:"DEF"},{namespace:"four",ariaLabel:"Four",title:"4",subtitle:"GHI"},{namespace:"five",ariaLabel:"Five",title:"5",subtitle:"JKL"},{namespace:"six",ariaLabel:"Six",title:"6",subtitle:"MNO"},{namespace:"seven",ariaLabel:"Seven",title:"7",subtitle:"PQRS"},{namespace:"eight",ariaLabel:"Eight",title:"8",subtitle:"TUV"},{namespace:"nine",ariaLabel:"Nine",title:"9",subtitle:"WXYZ"},{namespace:"star",ariaLabel:"Star",title:"*"},{namespace:"zero",ariaLabel:"Zero",title:"0",subtitle:"+"},{namespace:"hash",ariaLabel:"Hash",title:"#"}]},{}],4:[function(e,t,n){"use strict";var i=function(){function e(e,t){for(var n=0;n {\n this.config.onLongPress!(this.config.subtitle!);\n },\n onPressStart: () => {\n this.config.onClick(this.config.title);\n },\n onLongPressCancel: this.config.onLongPressCancel,\n });\n }\n\n /**\n *\n * Apply click event listener on button element\n *\n * @param button\n *\n */\n addClickEventListener(button: HTMLButtonElement) {\n button.addEventListener('click', () => {\n this.config.onClick(this.config.title);\n });\n }\n\n /**\n *\n * If onLongPress callback is exist in config apply long press event\n * Else apply click event listener on button\n *\n * @param button\n *\n */\n configureButtonEvents(button: HTMLButtonElement) {\n if (this.config.onLongPress !== undefined) {\n // apply long press event\n this.applyLongPressEvent(button);\n } else {\n // add click event listener\n this.addClickEventListener(button);\n }\n }\n\n /**\n *\n * Dialpad button tile element\n *\n */\n get titleElement(): HTMLElement {\n const title = document.createElement('h1');\n title.classList.add('dialpad-btn__title');\n title.innerText = this.config.title;\n return title;\n }\n\n /**\n *\n * Dialpad button subtile\n *\n */\n get subtitleElement(): HTMLElement {\n const subtitle = document.createElement('p');\n subtitle.classList.add('dialpad-btn__subtitle');\n subtitle.innerText = this.config.subtitle ?? '';\n return subtitle;\n }\n\n /**\n *\n * Unique id for dialpad button\n *\n */\n get id() {\n return `dialpad-btn-${this.config.namespace}`;\n }\n\n /**\n *\n * Dialpad button query selector for dom manipulation\n *\n */\n get querySelector(): HTMLButtonElement {\n return document.getElementById(this.id)! as HTMLButtonElement;\n }\n\n /**\n *\n * Appends dialpad button to a specified parent element.\n *\n * @param parentElement\n *\n */\n build(parentElement: HTMLElement) {\n parentElement.appendChild(this.skeleton);\n }\n}\n","import { InputElementConfig } from './types';\r\n\r\n/**\r\n *\r\n * Input Element\r\n *\r\n */\r\nexport default class InputElement {\r\n // input element config\r\n private config: InputElementConfig;\r\n\r\n /**\r\n *\r\n * construct InputElement instance\r\n *\r\n */\r\n constructor(config: InputElementConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n *\r\n * input element skeleton\r\n *\r\n */\r\n private get skeleton(): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.id = this.id;\r\n input.className = 'input-element';\r\n input.name = 'number';\r\n input.type = 'text';\r\n input.autofocus = true;\r\n input.inputMode = 'none';\r\n input.autocomplete = 'off';\r\n\r\n // add input event listener\r\n input.addEventListener('input', this.inputEventHandler.bind(this));\r\n\r\n return input;\r\n }\r\n\r\n /**\r\n *\r\n * Input element query selector for dom manipulation\r\n *\r\n */\r\n get querySelector(): HTMLInputElement {\r\n return document.getElementById(this.id) as HTMLInputElement;\r\n }\r\n\r\n /**\r\n *\r\n * Unique id for input element\r\n *\r\n * @returns {string}\r\n *\r\n */\r\n get id(): string {\r\n return `input-${this.config.namespace}`;\r\n }\r\n\r\n /**\r\n *\r\n * Appends input element to a specified parent element.\r\n *\r\n * @param parentElement\r\n *\r\n */\r\n build(parentElement: HTMLElement) {\r\n parentElement.appendChild(this.skeleton);\r\n }\r\n\r\n /**\r\n *\r\n * Make sure input element is focused\r\n *\r\n */\r\n makeSureFocused() {\r\n if (!this.focused) {\r\n this.focus();\r\n }\r\n }\r\n\r\n /**\r\n *\r\n * Get input element selection start position\r\n *\r\n */\r\n get selectionStartPosition(): number {\r\n // make sure the input is focused\r\n this.makeSureFocused();\r\n return this.querySelector.selectionStart!;\r\n }\r\n\r\n /**\r\n *\r\n * Get input element caret end position\r\n *\r\n */\r\n get selectionEndPosition(): number {\r\n // make sure the input is focused\r\n this.makeSureFocused();\r\n return this.querySelector.selectionEnd!;\r\n }\r\n\r\n /**\r\n *\r\n * Set input element selection start and end positions\r\n *\r\n * @param position - desired caret position index value\r\n *\r\n */\r\n set selectionPosition(position: number) {\r\n // make sure the input is focused\r\n this.makeSureFocused();\r\n\r\n // set selection\r\n this.querySelector.selectionStart = position;\r\n this.querySelector.selectionEnd = position;\r\n }\r\n\r\n /**\r\n *\r\n * To check whether the input element is focused or not\r\n *\r\n */\r\n get focused(): boolean {\r\n return document.activeElement === this.querySelector;\r\n }\r\n\r\n /**\r\n *\r\n * To get input element value\r\n *\r\n */\r\n get value(): string {\r\n return this.querySelector.value;\r\n }\r\n\r\n /**\r\n *\r\n * To set input element value\r\n *\r\n * @param value - The value to set\r\n *\r\n */\r\n set value(value: string) {\r\n this.querySelector.value = value;\r\n }\r\n\r\n /**\r\n *\r\n * Focus input element\r\n *\r\n */\r\n focus() {\r\n this.querySelector.focus();\r\n }\r\n\r\n /**\r\n *\r\n * Insert a value at the caret position\r\n *\r\n * @param value - The value to be inserted\r\n *\r\n */\r\n // eslint-disable-next-line class-methods-use-this\r\n insertValue(value: string) {\r\n // capture current state\r\n const currentValue = this.value;\r\n const { selectionStartPosition, selectionEndPosition } = this;\r\n\r\n // prepare updated state\r\n let updatedValue;\r\n\r\n if (selectionStartPosition !== selectionEndPosition) {\r\n // if input selection start value is not equal to selection end position\r\n // it means input value is selected, in this case remove selected value\r\n // and insert new value at the selection start (caret) position\r\n updatedValue =\r\n currentValue.slice(0, selectionStartPosition) +\r\n value +\r\n currentValue.slice(selectionEndPosition);\r\n } else {\r\n // else input selection start value is same as selection end value\r\n // insert new value at selection start (caret) position\r\n updatedValue =\r\n currentValue.slice(0, selectionStartPosition) +\r\n value +\r\n currentValue.slice(selectionStartPosition);\r\n }\r\n const updatedCaretPosition = selectionStartPosition + value.length;\r\n\r\n // update state\r\n this.value = updatedValue;\r\n this.selectionPosition = updatedCaretPosition;\r\n }\r\n\r\n /**\r\n *\r\n * Remove characters from the value starting at the caret position\r\n *\r\n * @param count - The number of characters, default value is 1\r\n *\r\n */\r\n removeValue(count: number = 1) {\r\n // capture current state\r\n const currentValue = this.value;\r\n const currentCaretPosition = this.selectionStartPosition;\r\n\r\n // prepare updated state\r\n const beforeCaretValue = currentValue.slice(0, currentCaretPosition);\r\n\r\n // if before caret value is empty do nothing\r\n if (beforeCaretValue !== '') {\r\n const afterCaretValue = currentValue.slice(currentCaretPosition);\r\n const endIndex = beforeCaretValue.length - count;\r\n const updatedValue =\r\n beforeCaretValue.slice(0, endIndex) + afterCaretValue;\r\n const updatedCaretPosition = currentCaretPosition - count;\r\n\r\n // update state\r\n this.value = updatedValue;\r\n this.selectionPosition = updatedCaretPosition;\r\n\r\n // check empty or not\r\n this.inputEventHandler();\r\n }\r\n }\r\n\r\n /**\r\n *\r\n * @param value - The value to be replaced current last value\r\n *\r\n */\r\n replaceValue(value: string) {\r\n this.removeValue();\r\n this.insertValue(value);\r\n this.inputEventHandler();\r\n }\r\n\r\n /**\r\n *\r\n * Clear the value of input element\r\n *\r\n */\r\n clear() {\r\n this.value = '';\r\n this.focus();\r\n }\r\n\r\n /**\r\n *\r\n * Remove unwanted symbols and allow only digits, +, *, and #\r\n *\r\n */\r\n validation() {\r\n // prepare updated state\r\n const caretPositionBeforeRemoveUnwantedChars = this.selectionStartPosition;\r\n const updatedValueAfterRemoveUnwantedChars = this.value.replace(\r\n /[^0-9+*#]/g,\r\n ''\r\n );\r\n const updatedCaretPosition =\r\n caretPositionBeforeRemoveUnwantedChars +\r\n updatedValueAfterRemoveUnwantedChars.length -\r\n this.value.length;\r\n\r\n // update state\r\n this.value = updatedValueAfterRemoveUnwantedChars;\r\n this.selectionPosition = updatedCaretPosition;\r\n }\r\n\r\n /**\r\n *\r\n * `input` event handler\r\n *\r\n */\r\n private inputEventHandler() {\r\n // Remove unwanted symbols and allow only digits, +, *, and #\r\n this.validation();\r\n\r\n // check whether the value is empty or not, and act accordingly.\r\n if (this.value === '') {\r\n // eslint-disable-next-line no-console\r\n console.log('value empty');\r\n this.config.onValueEmpty();\r\n } else {\r\n // eslint-disable-next-line no-console\r\n console.log('value non empty');\r\n this.config.onValueNonEmpty();\r\n }\r\n }\r\n}\r\n","import { KeypadButtonData } from './types';\n\n/**\n *\n * Keypad buttons data\n *\n */\nconst KEYPAD_BUTTONS_DATA: Array = [\n {\n namespace: 'one',\n ariaLabel: 'One',\n title: '1',\n },\n {\n namespace: 'two',\n ariaLabel: 'Two',\n title: '2',\n subtitle: 'ABC',\n },\n {\n namespace: 'three',\n ariaLabel: 'Three',\n title: '3',\n subtitle: 'DEF',\n },\n {\n namespace: 'four',\n ariaLabel: 'Four',\n title: '4',\n subtitle: 'GHI',\n },\n {\n namespace: 'five',\n ariaLabel: 'Five',\n title: '5',\n subtitle: 'JKL',\n },\n {\n namespace: 'six',\n ariaLabel: 'Six',\n title: '6',\n subtitle: 'MNO',\n },\n {\n namespace: 'seven',\n ariaLabel: 'Seven',\n title: '7',\n subtitle: 'PQRS',\n },\n {\n namespace: 'eight',\n ariaLabel: 'Eight',\n title: '8',\n subtitle: 'TUV',\n },\n {\n namespace: 'nine',\n ariaLabel: 'Nine',\n title: '9',\n subtitle: 'WXYZ',\n },\n {\n namespace: 'star',\n ariaLabel: 'Star',\n title: '*',\n },\n {\n namespace: 'zero',\n ariaLabel: 'Zero',\n title: '0',\n subtitle: '+',\n },\n {\n namespace: 'hash',\n ariaLabel: 'Hash',\n title: '#',\n },\n];\n\nexport default KEYPAD_BUTTONS_DATA;\n","import DialpadButton from '../components/buttons/buttons';\nimport LongPressEvent from '../utilities/longPress';\nimport KEYPAD_BUTTONS_DATA from './data';\nimport { KeypadButtonData, KeypadConfig } from './types';\n\n/**\n *\n * Keypad\n *\n */\nexport default class Keypad {\n // keypad config\n private config: KeypadConfig;\n\n /**\n *\n * construct Keypad instance\n *\n */\n constructor(config: KeypadConfig) {\n this.config = config;\n }\n\n /**\n *\n * Keypad skeleton\n *\n */\n private get skeleton(): HTMLDivElement {\n const keypad = document.createElement('div');\n keypad.id = this.id;\n keypad.classList.add('keypad');\n\n // append digits buttons\n KEYPAD_BUTTONS_DATA.forEach((config: KeypadButtonData) => {\n // create button instance\n const btn = new DialpadButton({\n namespace: config.namespace,\n ariaLabel: config.ariaLabel,\n title: config.title,\n subtitle: config.subtitle,\n onClick: this.config.onKeypadBtnClick,\n onLongPress:\n config.title === '0' ? this.config.onZeroBtnLongPress : undefined,\n onLongPressCancel:\n config.title === '0'\n ? this.config.onZeroBtnLongPressCancel\n : undefined,\n });\n\n // append button\n btn.build(keypad);\n });\n\n // append dummy element\n keypad.appendChild(document.createElement('span'));\n\n // append call button\n keypad.appendChild(this.callButton);\n\n // append backspace button\n keypad.appendChild(this.backspaceButton);\n\n return keypad;\n }\n\n // eslint-disable-next-line class-methods-use-this\n getMaterialIcon(iconName: string) {\n const iconElement = document.createElement('span');\n iconElement.className = 'material-symbols-outlined';\n iconElement.innerText = iconName;\n return iconElement;\n }\n\n /**\n *\n * Keypad call button\n *\n */\n private get callButton(): HTMLElement {\n const callBtn = document.createElement('button');\n callBtn.classList.add('keypad__call-btn');\n callBtn.setAttribute('aria-label', 'call button');\n\n // append call icon\n callBtn.appendChild(this.getMaterialIcon('call'));\n\n // add click event listener\n callBtn.addEventListener('click', this.config.onCallBtnClick);\n\n return callBtn;\n }\n\n /**\n *\n * Keypad backspace button\n *\n */\n private get backspaceButton(): HTMLElement {\n const backspaceBtn = document.createElement('button');\n backspaceBtn.classList.add('keypad__backspace-btn');\n backspaceBtn.setAttribute('aria-label', 'Backspace button');\n backspaceBtn.disabled = true;\n\n // append backspace icon\n backspaceBtn.appendChild(this.getMaterialIcon('backspace'));\n\n // add click event listener\n backspaceBtn.addEventListener('click', this.config.onBackspaceBtnClick);\n\n // apply long press event\n LongPressEvent.apply({\n target: backspaceBtn,\n onLongPressCallback: this.config.onBackspaceBtnLongPress,\n });\n\n return backspaceBtn;\n }\n\n /**\n *\n * To get backspace button element for dom manipulations\n *\n */\n get backspaceButtonElement(): HTMLButtonElement {\n return this.querySelector.querySelector(\n '.keypad__backspace-btn'\n ) as HTMLButtonElement;\n }\n\n /**\n *\n * Unique id for keypad\n *\n */\n get id() {\n return `keypad-${this.config.namespace}`;\n }\n\n /**\n *\n * Keypad query selector for dom manipulation\n *\n */\n get querySelector(): HTMLDivElement {\n return document.getElementById(this.id)! as HTMLDivElement;\n }\n\n /**\n *\n * Appends keypad to a specified parent element.\n *\n * @param parentElement\n *\n */\n build(parentElement: HTMLElement) {\n parentElement.appendChild(this.skeleton);\n }\n\n /**\n *\n * Enable backspace button\n *\n */\n enableBackspaceButton() {\n this.backspaceButtonElement.disabled = false;\n }\n\n /**\n *\n * Disable backspace button\n *\n */\n disableBackspaceButton() {\n this.backspaceButtonElement.disabled = true;\n }\n}\n","import Dialpad from './pages/dialpad';\n\nwindow.onload = () => {\n // create dialpad instance\n const dialpad = new Dialpad({ namespace: 'demo' });\n\n // build dialpad\n dialpad.build(document.body);\n};\n","import InputElement from '../components/forms/inputs';\nimport Keypad from '../layout/keypad';\nimport DialpadConfig from './types';\n\n/**\n *\n * Dialpad Page\n *\n */\nexport default class Dialpad {\n // dialpad configuration\n private config: DialpadConfig;\n\n // input field instance\n private inputField!: InputElement;\n\n // keypad instance\n private keypad!: Keypad;\n\n // recent call number\n private recentCallOnNumber?: string;\n\n /**\n *\n * construct Dialpad instance\n *\n */\n constructor(config: DialpadConfig) {\n this.config = config;\n }\n\n /**\n *\n * page skeleton\n *\n * @returns {HTMLDivElement}\n *\n */\n private skeleton(): HTMLElement {\n const dialpad = document.createElement('section');\n dialpad.id = this.id;\n dialpad.className = 'dialpad';\n\n // build input field\n this.inputFieldLayout.build(dialpad);\n\n // build keypad layout\n this.keypadLayout.build(dialpad);\n\n // append copyright text\n dialpad.appendChild(this.copyrightText);\n\n return dialpad;\n }\n\n /**\n *\n * To get Input Element\n *\n */\n private get inputFieldLayout(): InputElement {\n this.inputField = new InputElement({\n namespace: this.config.namespace,\n onValueEmpty: () => {\n // eslint-disable-next-line no-console\n console.log('disable backspace button');\n this.keypad.disableBackspaceButton();\n },\n onValueNonEmpty: () => {\n // eslint-disable-next-line no-console\n console.log('enable backspace button');\n this.keypad.enableBackspaceButton();\n },\n });\n return this.inputField;\n }\n\n /**\n *\n * To get Keypad Layout\n *\n */\n private get keypadLayout() {\n this.keypad = new Keypad({\n namespace: this.config.namespace,\n onKeypadBtnClick: (value: string) => {\n // eslint-disable-next-line no-console\n console.log('clicked on button', value);\n\n // insert value\n this.inputField.insertValue(value);\n this.keypad.enableBackspaceButton();\n },\n onZeroBtnLongPress: (value: string) => {\n // eslint-disable-next-line no-console\n console.log('long pressed on zero button');\n\n // insert zero button subtitle value `+`\n this.inputField.replaceValue(value);\n },\n onZeroBtnLongPressCancel: () => {\n // focus input field\n this.inputField.focus();\n },\n onCallBtnClick: () => {\n // eslint-disable-next-line no-console\n console.log('clicked on call button');\n\n // check whether try to call on recent number\n if (\n this.inputField.value === '' &&\n this.recentCallOnNumber !== undefined\n ) {\n // eslint-disable-next-line no-console\n console.log('fill last call on number in input field value');\n this.inputField.value = this.recentCallOnNumber;\n this.inputField.focus();\n this.keypad.enableBackspaceButton();\n } else {\n // update last call on number\n this.recentCallOnNumber = this.inputField.value;\n\n // eslint-disable-next-line no-console\n console.log('placing call on ', this.inputField.value);\n }\n },\n onBackspaceBtnClick: () => {\n // eslint-disable-next-line no-console\n console.log('clicked on clear button');\n this.inputField.removeValue();\n },\n onBackspaceBtnLongPress: () => {\n // eslint-disable-next-line no-console\n console.log('long press on backspace button');\n\n // clear input value and hide backspace button\n this.inputField.value = '';\n this.inputField.focus();\n this.keypad.disableBackspaceButton();\n },\n });\n\n return this.keypad;\n }\n\n /**\n *\n * append copyright text element\n *\n */\n // eslint-disable-next-line class-methods-use-this\n get copyrightText(): HTMLParagraphElement {\n // create copyright text\n const copyrightTextElement = document.createElement('p');\n copyrightTextElement.className = 'copyright-text';\n copyrightTextElement.innerText = `Made by • Satyam Seth Ⓒ ${new Date().getFullYear()}`;\n\n return copyrightTextElement;\n }\n\n /**\n *\n * Unique id for page\n *\n * @returns {string}\n *\n */\n get id(): string {\n return `dialpad-${this.config.namespace}`;\n }\n\n /**\n *\n * querySelect for app\n *\n * @returns {HTMLElement}\n *\n */\n get element(): HTMLElement {\n return document.getElementById(this.id)!;\n }\n\n /**\n *\n * Remove dialpad skeleton from dom\n *\n */\n destroy(): void {\n this.element.remove();\n }\n\n /**\n *\n * Append dialpad skeleton into parent element\n *\n * @param parentElement {HTMLElement}\n */\n build(parentElement: HTMLElement) {\n parentElement.appendChild(this.skeleton());\n }\n}\n","import LongPressEventConfig from './types';\n\n/**\n *\n * LongPress event\n *\n */\nexport default class LongPressEvent {\n // target html element\n private config: LongPressEventConfig;\n\n // state to detect press and hold\n private isHeld: boolean = false;\n\n // setTimeout Id\n private activeHoldTimeoutId: number | null = null;\n\n // long press timeout in milliseconds\n private longPressTimeout = 500;\n\n /**\n *\n * construct LongPressEvent instance and add event listener\n *\n */\n constructor(config: LongPressEventConfig) {\n this.config = config;\n\n // start timer\n this.config.target.addEventListener(\n 'mousedown',\n this.onHoldStart.bind(this)\n );\n this.config.target.addEventListener(\n 'touchstart',\n this.onHoldStart.bind(this)\n );\n\n // stop timer\n this.config.target.addEventListener('mouseup', this.onHoldEnd.bind(this));\n this.config.target.addEventListener('mouseout', this.onHoldEnd.bind(this));\n this.config.target.addEventListener(\n 'mouseleave',\n this.onHoldEnd.bind(this)\n );\n this.config.target.addEventListener('touchend', this.onHoldEnd.bind(this));\n this.config.target.addEventListener(\n 'touchcancel',\n this.onHoldEnd.bind(this)\n );\n }\n\n /**\n *\n * start set timeout timer on long press event for callback execution\n *\n */\n private onHoldStart() {\n // eslint-disable-next-line no-console\n console.log('Start Pressing');\n this.isHeld = true;\n\n // call on press start handler\n if (this.config.onPressStart) {\n this.config.onPressStart();\n }\n\n this.activeHoldTimeoutId = window.setTimeout(() => {\n if (this.isHeld === true) {\n // eslint-disable-next-line no-console\n console.log('long press detected');\n this.config.onLongPressCallback();\n }\n }, this.longPressTimeout);\n }\n\n /**\n *\n * clear set timeout timer on long press event\n *\n */\n private onHoldEnd() {\n // eslint-disable-next-line no-console\n console.log('Stop Pressing');\n this.isHeld = false;\n\n // call on press start handler\n if (this.config.onLongPressCancel) {\n this.config.onLongPressCancel();\n }\n\n if (this.activeHoldTimeoutId !== null) {\n window.clearTimeout(this.activeHoldTimeoutId);\n this.activeHoldTimeoutId = null;\n }\n }\n\n /**\n *\n * Apply long press event without using `new` keyword\n *\n */\n static apply(config: LongPressEventConfig) {\n // eslint-disable-next-line no-new\n new LongPressEvent(config);\n }\n}\n\n// Example how to use\n// window.onload = () => {\n// // const demoButton = document.querySelector('button');\n// // Using new keyword\n// // new ClickAndHold(demoButton, () => {\n// // console.log('Long Press');\n// // alert('Long Press Detected');\n// // });\n// // // Without using new keyword\n// // ClickAndHold.apply(demoButton, () => {\n// // console.log('Long Press');\n// // alert('Long Press Detected');\n// // });\n// };\n"]} \ No newline at end of file +{"version":3,"sources":["node_modules/browser-pack/_prelude.js","bundle.js","src/ts/components/buttons/buttons.ts","src/ts/components/forms/inputs.ts","src/ts/layout/data.ts","src/ts/layout/keypad.ts","src/ts/main.ts","src/ts/pages/dialpad.ts","src/ts/utilities/longPress.ts"],"names":["r","e","n","t","o","i","f","c","require","u","a","Error","code","p","exports","call","length","module","_createClass","defineProperties","target","props","descriptor","enumerable","configurable","writable","Object","defineProperty","key","Constructor","protoProps","staticProps","prototype","__importDefault","mod","__esModule","default","value","longPress_1","DialpadButton","config","instance","TypeError","_classCallCheck","this","undefined","subtitle","onLongPress","button","_this","apply","onLongPressCallback","onPressStart","onClick","title","onLongPressCancel","_this2","addEventListener","applyLongPressEvent","addClickEventListener","parentElement","appendChild","skeleton","get","document","createElement","id","classList","add","setAttribute","ariaLabel","titleElement","subtitleElement","configureButtonEvents","innerText","_a","namespace","getElementById","InputElement","focused","focus","querySelector","currentValue","selectionStartPosition","selectionEndPosition","updatedValue","slice","updatedCaretPosition","selectionPosition","count","arguments","currentCaretPosition","beforeCaretValue","afterCaretValue","endIndex","inputEventHandler","removeValue","insertValue","caretPositionBeforeRemoveUnwantedChars","updatedValueAfterRemoveUnwantedChars","replace","validation","console","log","onValueEmpty","onValueNonEmpty","input","className","name","type","autofocus","inputMode","autocomplete","bind","makeSureFocused","selectionStart","selectionEnd","set","position","activeElement","buttons_1","data_1","Keypad","iconName","iconElement","backspaceButtonElement","disabled","keypad","forEach","onKeypadBtnClick","onZeroBtnLongPress","onZeroBtnLongPressCancel","build","callButton","backspaceButton","callBtn","getMaterialIcon","onCallBtnClick","backspaceBtn","onBackspaceBtnClick","onBackspaceBtnLongPress","dialpad_1","window","onload","body","inputs_1","keypad_1","Dialpad","dialpad","inputFieldLayout","keypadLayout","copyrightText","element","remove","inputField","disableBackspaceButton","enableBackspaceButton","replaceValue","recentCallOnNumber","copyrightTextElement","Date","getFullYear","LongPressEvent","isHeld","activeHoldTimeoutId","longPressTimeout","onHoldStart","onHoldEnd","setTimeout","clearTimeout"],"mappings":"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","file":"../bundle.js","sourcesContent":["(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c=\"function\"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error(\"Cannot find module '\"+i+\"'\");throw a.code=\"MODULE_NOT_FOUND\",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u=\"function\"==typeof require&&require,i=0;i {\r\n this.config.onLongPress!(this.config.subtitle!);\r\n },\r\n onPressStart: () => {\r\n this.config.onClick(this.config.title);\r\n },\r\n onLongPressCancel: this.config.onLongPressCancel,\r\n });\r\n }\r\n\r\n /**\r\n *\r\n * Apply click event listener on button element\r\n *\r\n * @param button\r\n *\r\n */\r\n addClickEventListener(button: HTMLButtonElement) {\r\n button.addEventListener('click', () => {\r\n this.config.onClick(this.config.title);\r\n });\r\n }\r\n\r\n /**\r\n *\r\n * If onLongPress callback is exist in config apply long press event\r\n * Else apply click event listener on button\r\n *\r\n * @param button\r\n *\r\n */\r\n configureButtonEvents(button: HTMLButtonElement) {\r\n if (this.config.onLongPress !== undefined) {\r\n // apply long press event\r\n this.applyLongPressEvent(button);\r\n } else {\r\n // add click event listener\r\n this.addClickEventListener(button);\r\n }\r\n }\r\n\r\n /**\r\n *\r\n * Dialpad button tile element\r\n *\r\n */\r\n get titleElement(): HTMLHeadingElement {\r\n const title = document.createElement('h1');\r\n title.classList.add('dialpad-btn__title');\r\n title.innerText = this.config.title;\r\n return title;\r\n }\r\n\r\n /**\r\n *\r\n * Dialpad button subtile\r\n *\r\n */\r\n get subtitleElement(): HTMLParagraphElement {\r\n const subtitle = document.createElement('p');\r\n subtitle.classList.add('dialpad-btn__subtitle');\r\n subtitle.innerText = this.config.subtitle ?? '';\r\n return subtitle;\r\n }\r\n\r\n /**\r\n *\r\n * Unique id for dialpad button\r\n *\r\n */\r\n get id() {\r\n return `dialpad-btn-${this.config.namespace}`;\r\n }\r\n\r\n /**\r\n *\r\n * Dialpad button query selector for dom manipulation\r\n *\r\n */\r\n get querySelector(): HTMLButtonElement {\r\n return document.getElementById(this.id)! as HTMLButtonElement;\r\n }\r\n\r\n /**\r\n *\r\n * Appends dialpad button to a specified parent element.\r\n *\r\n * @param parentElement\r\n *\r\n */\r\n build(parentElement: HTMLElement) {\r\n parentElement.appendChild(this.skeleton);\r\n }\r\n}\r\n","import { InputElementConfig } from './types';\r\n\r\n/**\r\n *\r\n * Input Element\r\n *\r\n */\r\nexport default class InputElement {\r\n // input element config\r\n private config: InputElementConfig;\r\n\r\n /**\r\n *\r\n * construct InputElement instance\r\n *\r\n */\r\n constructor(config: InputElementConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n *\r\n * input element skeleton\r\n *\r\n */\r\n private get skeleton(): HTMLInputElement {\r\n const input = document.createElement('input');\r\n input.id = this.id;\r\n input.className = 'input-element';\r\n input.name = 'number';\r\n input.type = 'text';\r\n input.autofocus = true;\r\n input.inputMode = 'none';\r\n input.autocomplete = 'off';\r\n\r\n // add input event listener\r\n input.addEventListener('input', this.inputEventHandler.bind(this));\r\n\r\n return input;\r\n }\r\n\r\n /**\r\n *\r\n * Input element query selector for dom manipulation\r\n *\r\n */\r\n get querySelector(): HTMLInputElement {\r\n return document.getElementById(this.id) as HTMLInputElement;\r\n }\r\n\r\n /**\r\n *\r\n * Unique id for input element\r\n *\r\n * @returns {string}\r\n *\r\n */\r\n get id(): string {\r\n return `input-${this.config.namespace}`;\r\n }\r\n\r\n /**\r\n *\r\n * Appends input element to a specified parent element.\r\n *\r\n * @param parentElement\r\n *\r\n */\r\n build(parentElement: HTMLElement) {\r\n parentElement.appendChild(this.skeleton);\r\n }\r\n\r\n /**\r\n *\r\n * Make sure input element is focused\r\n *\r\n */\r\n makeSureFocused() {\r\n if (!this.focused) {\r\n this.focus();\r\n }\r\n }\r\n\r\n /**\r\n *\r\n * Get input element selection start position\r\n *\r\n */\r\n get selectionStartPosition(): number {\r\n // make sure the input is focused\r\n this.makeSureFocused();\r\n return this.querySelector.selectionStart!;\r\n }\r\n\r\n /**\r\n *\r\n * Get input element caret end position\r\n *\r\n */\r\n get selectionEndPosition(): number {\r\n // make sure the input is focused\r\n this.makeSureFocused();\r\n return this.querySelector.selectionEnd!;\r\n }\r\n\r\n /**\r\n *\r\n * Set input element selection start and end positions\r\n *\r\n * @param position - desired caret position index value\r\n *\r\n */\r\n set selectionPosition(position: number) {\r\n // make sure the input is focused\r\n this.makeSureFocused();\r\n\r\n // set selection\r\n this.querySelector.selectionStart = position;\r\n this.querySelector.selectionEnd = position;\r\n }\r\n\r\n /**\r\n *\r\n * To check whether the input element is focused or not\r\n *\r\n */\r\n get focused(): boolean {\r\n return document.activeElement === this.querySelector;\r\n }\r\n\r\n /**\r\n *\r\n * To get input element value\r\n *\r\n */\r\n get value(): string {\r\n return this.querySelector.value;\r\n }\r\n\r\n /**\r\n *\r\n * To set input element value\r\n *\r\n * @param value - The value to set\r\n *\r\n */\r\n set value(value: string) {\r\n this.querySelector.value = value;\r\n }\r\n\r\n /**\r\n *\r\n * Focus input element\r\n *\r\n */\r\n focus() {\r\n this.querySelector.focus();\r\n }\r\n\r\n /**\r\n *\r\n * Insert a value at the caret position\r\n *\r\n * @param value - The value to be inserted\r\n *\r\n */\r\n // eslint-disable-next-line class-methods-use-this\r\n insertValue(value: string) {\r\n // capture current state\r\n const currentValue = this.value;\r\n const { selectionStartPosition, selectionEndPosition } = this;\r\n\r\n // prepare updated state\r\n let updatedValue;\r\n\r\n if (selectionStartPosition !== selectionEndPosition) {\r\n // if input selection start value is not equal to selection end position\r\n // it means input value is selected, in this case remove selected value\r\n // and insert new value at the selection start (caret) position\r\n updatedValue =\r\n currentValue.slice(0, selectionStartPosition) +\r\n value +\r\n currentValue.slice(selectionEndPosition);\r\n } else {\r\n // else input selection start value is same as selection end value\r\n // insert new value at selection start (caret) position\r\n updatedValue =\r\n currentValue.slice(0, selectionStartPosition) +\r\n value +\r\n currentValue.slice(selectionStartPosition);\r\n }\r\n const updatedCaretPosition = selectionStartPosition + value.length;\r\n\r\n // update state\r\n this.value = updatedValue;\r\n this.selectionPosition = updatedCaretPosition;\r\n }\r\n\r\n /**\r\n *\r\n * Remove characters from the value starting at the caret position\r\n *\r\n * @param count - The number of characters, default value is 1\r\n *\r\n */\r\n removeValue(count: number = 1) {\r\n // capture current state\r\n const currentValue = this.value;\r\n const currentCaretPosition = this.selectionStartPosition;\r\n\r\n // prepare updated state\r\n const beforeCaretValue = currentValue.slice(0, currentCaretPosition);\r\n\r\n // if before caret value is empty do nothing\r\n if (beforeCaretValue !== '') {\r\n const afterCaretValue = currentValue.slice(currentCaretPosition);\r\n const endIndex = beforeCaretValue.length - count;\r\n const updatedValue =\r\n beforeCaretValue.slice(0, endIndex) + afterCaretValue;\r\n const updatedCaretPosition = currentCaretPosition - count;\r\n\r\n // update state\r\n this.value = updatedValue;\r\n this.selectionPosition = updatedCaretPosition;\r\n\r\n // check empty or not\r\n this.inputEventHandler();\r\n }\r\n }\r\n\r\n /**\r\n *\r\n * @param value - The value to be replaced current last value\r\n *\r\n */\r\n replaceValue(value: string) {\r\n this.removeValue();\r\n this.insertValue(value);\r\n this.inputEventHandler();\r\n }\r\n\r\n /**\r\n *\r\n * Clear the value of input element\r\n *\r\n */\r\n clear() {\r\n this.value = '';\r\n this.focus();\r\n }\r\n\r\n /**\r\n *\r\n * Remove unwanted symbols and allow only digits, +, *, and #\r\n *\r\n */\r\n validation() {\r\n // prepare updated state\r\n const caretPositionBeforeRemoveUnwantedChars = this.selectionStartPosition;\r\n const updatedValueAfterRemoveUnwantedChars = this.value.replace(\r\n /[^0-9+*#]/g,\r\n ''\r\n );\r\n const updatedCaretPosition =\r\n caretPositionBeforeRemoveUnwantedChars +\r\n updatedValueAfterRemoveUnwantedChars.length -\r\n this.value.length;\r\n\r\n // update state\r\n this.value = updatedValueAfterRemoveUnwantedChars;\r\n this.selectionPosition = updatedCaretPosition;\r\n }\r\n\r\n /**\r\n *\r\n * `input` event handler\r\n *\r\n */\r\n private inputEventHandler() {\r\n // Remove unwanted symbols and allow only digits, +, *, and #\r\n this.validation();\r\n\r\n // check whether the value is empty or not, and act accordingly.\r\n if (this.value === '') {\r\n // eslint-disable-next-line no-console\r\n console.log('value empty');\r\n this.config.onValueEmpty();\r\n } else {\r\n // eslint-disable-next-line no-console\r\n console.log('value non empty');\r\n this.config.onValueNonEmpty();\r\n }\r\n }\r\n}\r\n","import { KeypadButtonData } from './types';\n\n/**\n *\n * Keypad buttons data\n *\n */\nconst KEYPAD_BUTTONS_DATA: Array = [\n {\n namespace: 'one',\n ariaLabel: 'One',\n title: '1',\n },\n {\n namespace: 'two',\n ariaLabel: 'Two',\n title: '2',\n subtitle: 'ABC',\n },\n {\n namespace: 'three',\n ariaLabel: 'Three',\n title: '3',\n subtitle: 'DEF',\n },\n {\n namespace: 'four',\n ariaLabel: 'Four',\n title: '4',\n subtitle: 'GHI',\n },\n {\n namespace: 'five',\n ariaLabel: 'Five',\n title: '5',\n subtitle: 'JKL',\n },\n {\n namespace: 'six',\n ariaLabel: 'Six',\n title: '6',\n subtitle: 'MNO',\n },\n {\n namespace: 'seven',\n ariaLabel: 'Seven',\n title: '7',\n subtitle: 'PQRS',\n },\n {\n namespace: 'eight',\n ariaLabel: 'Eight',\n title: '8',\n subtitle: 'TUV',\n },\n {\n namespace: 'nine',\n ariaLabel: 'Nine',\n title: '9',\n subtitle: 'WXYZ',\n },\n {\n namespace: 'star',\n ariaLabel: 'Star',\n title: '*',\n },\n {\n namespace: 'zero',\n ariaLabel: 'Zero',\n title: '0',\n subtitle: '+',\n },\n {\n namespace: 'hash',\n ariaLabel: 'Hash',\n title: '#',\n },\n];\n\nexport default KEYPAD_BUTTONS_DATA;\n","import DialpadButton from '../components/buttons/buttons';\nimport LongPressEvent from '../utilities/longPress';\nimport KEYPAD_BUTTONS_DATA from './data';\nimport { KeypadButtonData, KeypadConfig } from './types';\n\n/**\n *\n * Keypad\n *\n */\nexport default class Keypad {\n // keypad config\n private config: KeypadConfig;\n\n /**\n *\n * construct Keypad instance\n *\n */\n constructor(config: KeypadConfig) {\n this.config = config;\n }\n\n /**\n *\n * Keypad skeleton\n *\n */\n private get skeleton(): HTMLDivElement {\n const keypad = document.createElement('div');\n keypad.id = this.id;\n keypad.classList.add('keypad');\n\n // append digits buttons\n KEYPAD_BUTTONS_DATA.forEach((config: KeypadButtonData) => {\n // create button instance\n const btn = new DialpadButton({\n namespace: config.namespace,\n ariaLabel: config.ariaLabel,\n title: config.title,\n subtitle: config.subtitle,\n onClick: this.config.onKeypadBtnClick,\n onLongPress:\n config.title === '0' ? this.config.onZeroBtnLongPress : undefined,\n onLongPressCancel:\n config.title === '0'\n ? this.config.onZeroBtnLongPressCancel\n : undefined,\n });\n\n // append button\n btn.build(keypad);\n });\n\n // append dummy element\n keypad.appendChild(document.createElement('span'));\n\n // append call button\n keypad.appendChild(this.callButton);\n\n // append backspace button\n keypad.appendChild(this.backspaceButton);\n\n return keypad;\n }\n\n // eslint-disable-next-line class-methods-use-this\n getMaterialIcon(iconName: string) {\n const iconElement = document.createElement('span');\n iconElement.className = 'material-symbols-outlined';\n iconElement.innerText = iconName;\n return iconElement;\n }\n\n /**\n *\n * Keypad call button\n *\n */\n private get callButton(): HTMLElement {\n const callBtn = document.createElement('button');\n callBtn.classList.add('keypad__call-btn');\n callBtn.setAttribute('aria-label', 'call button');\n\n // append call icon\n callBtn.appendChild(this.getMaterialIcon('call'));\n\n // add click event listener\n callBtn.addEventListener('click', this.config.onCallBtnClick);\n\n return callBtn;\n }\n\n /**\n *\n * Keypad backspace button\n *\n */\n private get backspaceButton(): HTMLElement {\n const backspaceBtn = document.createElement('button');\n backspaceBtn.classList.add('keypad__backspace-btn');\n backspaceBtn.setAttribute('aria-label', 'Backspace button');\n backspaceBtn.disabled = true;\n\n // append backspace icon\n backspaceBtn.appendChild(this.getMaterialIcon('backspace'));\n\n // add click event listener\n backspaceBtn.addEventListener('click', this.config.onBackspaceBtnClick);\n\n // apply long press event\n LongPressEvent.apply({\n target: backspaceBtn,\n onLongPressCallback: this.config.onBackspaceBtnLongPress,\n });\n\n return backspaceBtn;\n }\n\n /**\n *\n * To get backspace button element for dom manipulations\n *\n */\n get backspaceButtonElement(): HTMLButtonElement {\n return this.querySelector.querySelector(\n '.keypad__backspace-btn'\n ) as HTMLButtonElement;\n }\n\n /**\n *\n * Unique id for keypad\n *\n */\n get id() {\n return `keypad-${this.config.namespace}`;\n }\n\n /**\n *\n * Keypad query selector for dom manipulation\n *\n */\n get querySelector(): HTMLDivElement {\n return document.getElementById(this.id)! as HTMLDivElement;\n }\n\n /**\n *\n * Appends keypad to a specified parent element.\n *\n * @param parentElement\n *\n */\n build(parentElement: HTMLElement) {\n parentElement.appendChild(this.skeleton);\n }\n\n /**\n *\n * Enable backspace button\n *\n */\n enableBackspaceButton() {\n this.backspaceButtonElement.disabled = false;\n }\n\n /**\n *\n * Disable backspace button\n *\n */\n disableBackspaceButton() {\n this.backspaceButtonElement.disabled = true;\n }\n}\n","import Dialpad from './pages/dialpad';\n\nwindow.onload = () => {\n // create dialpad instance\n const dialpad = new Dialpad({ namespace: 'demo' });\n\n // build dialpad\n dialpad.build(document.body);\n};\n","import InputElement from '../components/forms/inputs';\r\nimport Keypad from '../layout/keypad';\r\nimport DialpadConfig from './types';\r\n\r\n/**\r\n *\r\n * Dialpad Page\r\n *\r\n */\r\nexport default class Dialpad {\r\n // dialpad configuration\r\n private config: DialpadConfig;\r\n\r\n // input field instance\r\n private inputField!: InputElement;\r\n\r\n // keypad instance\r\n private keypad!: Keypad;\r\n\r\n // recent call number\r\n private recentCallOnNumber?: string;\r\n\r\n /**\r\n *\r\n * construct Dialpad instance\r\n *\r\n */\r\n constructor(config: DialpadConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n *\r\n * page skeleton\r\n *\r\n * @returns {HTMLDivElement}\r\n *\r\n */\r\n private skeleton(): HTMLElement {\r\n const dialpad = document.createElement('section');\r\n dialpad.id = this.id;\r\n dialpad.className = 'dialpad';\r\n\r\n // build input field\r\n this.inputFieldLayout.build(dialpad);\r\n\r\n // build keypad layout\r\n this.keypadLayout.build(dialpad);\r\n\r\n // append copyright text\r\n dialpad.appendChild(this.copyrightText);\r\n\r\n return dialpad;\r\n }\r\n\r\n /**\r\n *\r\n * To get Input Element\r\n *\r\n */\r\n private get inputFieldLayout(): InputElement {\r\n this.inputField = new InputElement({\r\n namespace: this.config.namespace,\r\n onValueEmpty: () => {\r\n // eslint-disable-next-line no-console\r\n console.log('disable backspace button');\r\n this.keypad.disableBackspaceButton();\r\n },\r\n onValueNonEmpty: () => {\r\n // eslint-disable-next-line no-console\r\n console.log('enable backspace button');\r\n this.keypad.enableBackspaceButton();\r\n },\r\n });\r\n return this.inputField;\r\n }\r\n\r\n /**\r\n *\r\n * To get Keypad Layout\r\n *\r\n */\r\n private get keypadLayout() {\r\n this.keypad = new Keypad({\r\n namespace: this.config.namespace,\r\n onKeypadBtnClick: (value: string) => {\r\n // eslint-disable-next-line no-console\r\n console.log('clicked on button', value);\r\n\r\n // insert value\r\n this.inputField.insertValue(value);\r\n this.keypad.enableBackspaceButton();\r\n },\r\n onZeroBtnLongPress: (value: string) => {\r\n // eslint-disable-next-line no-console\r\n console.log('long pressed on zero button');\r\n\r\n // insert zero button subtitle value `+`\r\n this.inputField.replaceValue(value);\r\n },\r\n onZeroBtnLongPressCancel: () => {\r\n // focus input field\r\n this.inputField.focus();\r\n },\r\n onCallBtnClick: () => {\r\n // eslint-disable-next-line no-console\r\n console.log('clicked on call button');\r\n\r\n // check whether try to call on recent number\r\n if (\r\n this.inputField.value === '' &&\r\n this.recentCallOnNumber !== undefined\r\n ) {\r\n // eslint-disable-next-line no-console\r\n console.log('fill last call on number in input field value');\r\n this.inputField.value = this.recentCallOnNumber;\r\n this.inputField.focus();\r\n this.keypad.enableBackspaceButton();\r\n }\r\n // if value is not empty (or add check for valid phone number)\r\n else if (this.inputField.value !== '') {\r\n // update last call on number\r\n this.recentCallOnNumber = this.inputField.value;\r\n\r\n // eslint-disable-next-line no-console\r\n console.log('placing call on ', this.inputField.value);\r\n }\r\n },\r\n onBackspaceBtnClick: () => {\r\n // eslint-disable-next-line no-console\r\n console.log('clicked on clear button');\r\n this.inputField.removeValue();\r\n },\r\n onBackspaceBtnLongPress: () => {\r\n // eslint-disable-next-line no-console\r\n console.log('long press on backspace button');\r\n\r\n // clear input value and hide backspace button\r\n this.inputField.value = '';\r\n this.inputField.focus();\r\n this.keypad.disableBackspaceButton();\r\n },\r\n });\r\n\r\n return this.keypad;\r\n }\r\n\r\n /**\r\n *\r\n * append copyright text element\r\n *\r\n */\r\n // eslint-disable-next-line class-methods-use-this\r\n get copyrightText(): HTMLParagraphElement {\r\n // create copyright text\r\n const copyrightTextElement = document.createElement('p');\r\n copyrightTextElement.className = 'copyright-text';\r\n copyrightTextElement.innerText = `Made by • Satyam Seth Ⓒ ${new Date().getFullYear()}`;\r\n\r\n return copyrightTextElement;\r\n }\r\n\r\n /**\r\n *\r\n * Unique id for page\r\n *\r\n * @returns {string}\r\n *\r\n */\r\n get id(): string {\r\n return `dialpad-${this.config.namespace}`;\r\n }\r\n\r\n /**\r\n *\r\n * querySelect for app\r\n *\r\n * @returns {HTMLElement}\r\n *\r\n */\r\n get element(): HTMLElement {\r\n return document.getElementById(this.id)!;\r\n }\r\n\r\n /**\r\n *\r\n * Remove dialpad skeleton from dom\r\n *\r\n */\r\n destroy(): void {\r\n this.element.remove();\r\n }\r\n\r\n /**\r\n *\r\n * Append dialpad skeleton into parent element\r\n *\r\n * @param parentElement {HTMLElement}\r\n */\r\n build(parentElement: HTMLElement) {\r\n parentElement.appendChild(this.skeleton());\r\n }\r\n}\r\n","import LongPressEventConfig from './types';\n\n/**\n *\n * LongPress event\n *\n */\nexport default class LongPressEvent {\n // target html element\n private config: LongPressEventConfig;\n\n // state to detect press and hold\n private isHeld: boolean = false;\n\n // setTimeout Id\n private activeHoldTimeoutId: number | null = null;\n\n // long press timeout in milliseconds\n private longPressTimeout = 500;\n\n /**\n *\n * construct LongPressEvent instance and add event listener\n *\n */\n constructor(config: LongPressEventConfig) {\n this.config = config;\n\n // start timer\n this.config.target.addEventListener(\n 'mousedown',\n this.onHoldStart.bind(this)\n );\n this.config.target.addEventListener(\n 'touchstart',\n this.onHoldStart.bind(this)\n );\n\n // stop timer\n this.config.target.addEventListener('mouseup', this.onHoldEnd.bind(this));\n this.config.target.addEventListener('mouseout', this.onHoldEnd.bind(this));\n this.config.target.addEventListener(\n 'mouseleave',\n this.onHoldEnd.bind(this)\n );\n this.config.target.addEventListener('touchend', this.onHoldEnd.bind(this));\n this.config.target.addEventListener(\n 'touchcancel',\n this.onHoldEnd.bind(this)\n );\n }\n\n /**\n *\n * start set timeout timer on long press event for callback execution\n *\n */\n private onHoldStart() {\n // eslint-disable-next-line no-console\n console.log('Start Pressing');\n this.isHeld = true;\n\n // call on press start handler\n if (this.config.onPressStart) {\n this.config.onPressStart();\n }\n\n this.activeHoldTimeoutId = window.setTimeout(() => {\n if (this.isHeld === true) {\n // eslint-disable-next-line no-console\n console.log('long press detected');\n this.config.onLongPressCallback();\n }\n }, this.longPressTimeout);\n }\n\n /**\n *\n * clear set timeout timer on long press event\n *\n */\n private onHoldEnd() {\n // eslint-disable-next-line no-console\n console.log('Stop Pressing');\n this.isHeld = false;\n\n // call on press start handler\n if (this.config.onLongPressCancel) {\n this.config.onLongPressCancel();\n }\n\n if (this.activeHoldTimeoutId !== null) {\n window.clearTimeout(this.activeHoldTimeoutId);\n this.activeHoldTimeoutId = null;\n }\n }\n\n /**\n *\n * Apply long press event without using `new` keyword\n *\n */\n static apply(config: LongPressEventConfig) {\n // eslint-disable-next-line no-new\n new LongPressEvent(config);\n }\n}\n\n// Example how to use\n// window.onload = () => {\n// // const demoButton = document.querySelector('button');\n// // Using new keyword\n// // new ClickAndHold(demoButton, () => {\n// // console.log('Long Press');\n// // alert('Long Press Detected');\n// // });\n// // // Without using new keyword\n// // ClickAndHold.apply(demoButton, () => {\n// // console.log('Long Press');\n// // alert('Long Press Detected');\n// // });\n// };\n"]} \ No newline at end of file diff --git a/src/ts/pages/dialpad.ts b/src/ts/pages/dialpad.ts index 704ea37..2e35835 100644 --- a/src/ts/pages/dialpad.ts +++ b/src/ts/pages/dialpad.ts @@ -116,7 +116,9 @@ export default class Dialpad { this.inputField.value = this.recentCallOnNumber; this.inputField.focus(); this.keypad.enableBackspaceButton(); - } else { + } + // if value is not empty (or add check for valid phone number) + else if (this.inputField.value !== '') { // update last call on number this.recentCallOnNumber = this.inputField.value;