imask.js 121 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.IMask = {}));
  5. })(this, (function (exports) { 'use strict';
  6. /** Checks if value is string */
  7. function isString(str) {
  8. return typeof str === 'string' || str instanceof String;
  9. }
  10. /** Checks if value is object */
  11. function isObject(obj) {
  12. var _obj$constructor;
  13. return typeof obj === 'object' && obj != null && (obj == null || (_obj$constructor = obj.constructor) == null ? void 0 : _obj$constructor.name) === 'Object';
  14. }
  15. function pick(obj, keys) {
  16. if (Array.isArray(keys)) return pick(obj, (_, k) => keys.includes(k));
  17. return Object.entries(obj).reduce((acc, _ref) => {
  18. let [k, v] = _ref;
  19. if (keys(v, k)) acc[k] = v;
  20. return acc;
  21. }, {});
  22. }
  23. /** Direction */
  24. const DIRECTION = {
  25. NONE: 'NONE',
  26. LEFT: 'LEFT',
  27. FORCE_LEFT: 'FORCE_LEFT',
  28. RIGHT: 'RIGHT',
  29. FORCE_RIGHT: 'FORCE_RIGHT'
  30. };
  31. /** Direction */
  32. function forceDirection(direction) {
  33. switch (direction) {
  34. case DIRECTION.LEFT:
  35. return DIRECTION.FORCE_LEFT;
  36. case DIRECTION.RIGHT:
  37. return DIRECTION.FORCE_RIGHT;
  38. default:
  39. return direction;
  40. }
  41. }
  42. /** Escapes regular expression control chars */
  43. function escapeRegExp(str) {
  44. return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, '\\$1');
  45. }
  46. // cloned from https://github.com/epoberezkin/fast-deep-equal with small changes
  47. function objectIncludes(b, a) {
  48. if (a === b) return true;
  49. const arrA = Array.isArray(a),
  50. arrB = Array.isArray(b);
  51. let i;
  52. if (arrA && arrB) {
  53. if (a.length != b.length) return false;
  54. for (i = 0; i < a.length; i++) if (!objectIncludes(a[i], b[i])) return false;
  55. return true;
  56. }
  57. if (arrA != arrB) return false;
  58. if (a && b && typeof a === 'object' && typeof b === 'object') {
  59. const dateA = a instanceof Date,
  60. dateB = b instanceof Date;
  61. if (dateA && dateB) return a.getTime() == b.getTime();
  62. if (dateA != dateB) return false;
  63. const regexpA = a instanceof RegExp,
  64. regexpB = b instanceof RegExp;
  65. if (regexpA && regexpB) return a.toString() == b.toString();
  66. if (regexpA != regexpB) return false;
  67. const keys = Object.keys(a);
  68. // if (keys.length !== Object.keys(b).length) return false;
  69. for (i = 0; i < keys.length; i++) if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
  70. for (i = 0; i < keys.length; i++) if (!objectIncludes(b[keys[i]], a[keys[i]])) return false;
  71. return true;
  72. } else if (a && b && typeof a === 'function' && typeof b === 'function') {
  73. return a.toString() === b.toString();
  74. }
  75. return false;
  76. }
  77. /** Selection range */
  78. /** Provides details of changing input */
  79. class ActionDetails {
  80. /** Current input value */
  81. /** Current cursor position */
  82. /** Old input value */
  83. /** Old selection */
  84. constructor(opts) {
  85. Object.assign(this, opts);
  86. // double check if left part was changed (autofilling, other non-standard input triggers)
  87. while (this.value.slice(0, this.startChangePos) !== this.oldValue.slice(0, this.startChangePos)) {
  88. --this.oldSelection.start;
  89. }
  90. if (this.insertedCount) {
  91. // double check right part
  92. while (this.value.slice(this.cursorPos) !== this.oldValue.slice(this.oldSelection.end)) {
  93. if (this.value.length - this.cursorPos < this.oldValue.length - this.oldSelection.end) ++this.oldSelection.end;else ++this.cursorPos;
  94. }
  95. }
  96. }
  97. /** Start changing position */
  98. get startChangePos() {
  99. return Math.min(this.cursorPos, this.oldSelection.start);
  100. }
  101. /** Inserted symbols count */
  102. get insertedCount() {
  103. return this.cursorPos - this.startChangePos;
  104. }
  105. /** Inserted symbols */
  106. get inserted() {
  107. return this.value.substr(this.startChangePos, this.insertedCount);
  108. }
  109. /** Removed symbols count */
  110. get removedCount() {
  111. // Math.max for opposite operation
  112. return Math.max(this.oldSelection.end - this.startChangePos ||
  113. // for Delete
  114. this.oldValue.length - this.value.length, 0);
  115. }
  116. /** Removed symbols */
  117. get removed() {
  118. return this.oldValue.substr(this.startChangePos, this.removedCount);
  119. }
  120. /** Unchanged head symbols */
  121. get head() {
  122. return this.value.substring(0, this.startChangePos);
  123. }
  124. /** Unchanged tail symbols */
  125. get tail() {
  126. return this.value.substring(this.startChangePos + this.insertedCount);
  127. }
  128. /** Remove direction */
  129. get removeDirection() {
  130. if (!this.removedCount || this.insertedCount) return DIRECTION.NONE;
  131. // align right if delete at right
  132. return (this.oldSelection.end === this.cursorPos || this.oldSelection.start === this.cursorPos) &&
  133. // if not range removed (event with backspace)
  134. this.oldSelection.end === this.oldSelection.start ? DIRECTION.RIGHT : DIRECTION.LEFT;
  135. }
  136. }
  137. /** Applies mask on element */
  138. function IMask(el, opts) {
  139. // currently available only for input-like elements
  140. return new IMask.InputMask(el, opts);
  141. }
  142. // TODO can't use overloads here because of https://github.com/microsoft/TypeScript/issues/50754
  143. // export function maskedClass(mask: string): typeof MaskedPattern;
  144. // export function maskedClass(mask: DateConstructor): typeof MaskedDate;
  145. // export function maskedClass(mask: NumberConstructor): typeof MaskedNumber;
  146. // export function maskedClass(mask: Array<any> | ArrayConstructor): typeof MaskedDynamic;
  147. // export function maskedClass(mask: MaskedDate): typeof MaskedDate;
  148. // export function maskedClass(mask: MaskedNumber): typeof MaskedNumber;
  149. // export function maskedClass(mask: MaskedEnum): typeof MaskedEnum;
  150. // export function maskedClass(mask: MaskedRange): typeof MaskedRange;
  151. // export function maskedClass(mask: MaskedRegExp): typeof MaskedRegExp;
  152. // export function maskedClass(mask: MaskedFunction): typeof MaskedFunction;
  153. // export function maskedClass(mask: MaskedPattern): typeof MaskedPattern;
  154. // export function maskedClass(mask: MaskedDynamic): typeof MaskedDynamic;
  155. // export function maskedClass(mask: Masked): typeof Masked;
  156. // export function maskedClass(mask: typeof Masked): typeof Masked;
  157. // export function maskedClass(mask: typeof MaskedDate): typeof MaskedDate;
  158. // export function maskedClass(mask: typeof MaskedNumber): typeof MaskedNumber;
  159. // export function maskedClass(mask: typeof MaskedEnum): typeof MaskedEnum;
  160. // export function maskedClass(mask: typeof MaskedRange): typeof MaskedRange;
  161. // export function maskedClass(mask: typeof MaskedRegExp): typeof MaskedRegExp;
  162. // export function maskedClass(mask: typeof MaskedFunction): typeof MaskedFunction;
  163. // export function maskedClass(mask: typeof MaskedPattern): typeof MaskedPattern;
  164. // export function maskedClass(mask: typeof MaskedDynamic): typeof MaskedDynamic;
  165. // export function maskedClass<Mask extends typeof Masked> (mask: Mask): Mask;
  166. // export function maskedClass(mask: RegExp): typeof MaskedRegExp;
  167. // export function maskedClass(mask: (value: string, ...args: any[]) => boolean): typeof MaskedFunction;
  168. /** Get Masked class by mask type */
  169. function maskedClass(mask) /* TODO */{
  170. if (mask == null) throw new Error('mask property should be defined');
  171. if (mask instanceof RegExp) return IMask.MaskedRegExp;
  172. if (isString(mask)) return IMask.MaskedPattern;
  173. if (mask === Date) return IMask.MaskedDate;
  174. if (mask === Number) return IMask.MaskedNumber;
  175. if (Array.isArray(mask) || mask === Array) return IMask.MaskedDynamic;
  176. if (IMask.Masked && mask.prototype instanceof IMask.Masked) return mask;
  177. if (IMask.Masked && mask instanceof IMask.Masked) return mask.constructor;
  178. if (mask instanceof Function) return IMask.MaskedFunction;
  179. console.warn('Mask not found for mask', mask); // eslint-disable-line no-console
  180. return IMask.Masked;
  181. }
  182. function normalizeOpts(opts) {
  183. if (!opts) throw new Error('Options in not defined');
  184. if (IMask.Masked) {
  185. if (opts.prototype instanceof IMask.Masked) return {
  186. mask: opts
  187. };
  188. /*
  189. handle cases like:
  190. 1) opts = Masked
  191. 2) opts = { mask: Masked, ...instanceOpts }
  192. */
  193. const {
  194. mask = undefined,
  195. ...instanceOpts
  196. } = opts instanceof IMask.Masked ? {
  197. mask: opts
  198. } : isObject(opts) && opts.mask instanceof IMask.Masked ? opts : {};
  199. if (mask) {
  200. const _mask = mask.mask;
  201. return {
  202. ...pick(mask, (_, k) => !k.startsWith('_')),
  203. mask: mask.constructor,
  204. _mask,
  205. ...instanceOpts
  206. };
  207. }
  208. }
  209. if (!isObject(opts)) return {
  210. mask: opts
  211. };
  212. return {
  213. ...opts
  214. };
  215. }
  216. // TODO can't use overloads here because of https://github.com/microsoft/TypeScript/issues/50754
  217. // From masked
  218. // export default function createMask<Opts extends Masked, ReturnMasked=Opts> (opts: Opts): ReturnMasked;
  219. // // From masked class
  220. // export default function createMask<Opts extends MaskedOptions<typeof Masked>, ReturnMasked extends Masked=InstanceType<Opts['mask']>> (opts: Opts): ReturnMasked;
  221. // export default function createMask<Opts extends MaskedOptions<typeof MaskedDate>, ReturnMasked extends MaskedDate=MaskedDate<Opts['parent']>> (opts: Opts): ReturnMasked;
  222. // export default function createMask<Opts extends MaskedOptions<typeof MaskedNumber>, ReturnMasked extends MaskedNumber=MaskedNumber<Opts['parent']>> (opts: Opts): ReturnMasked;
  223. // export default function createMask<Opts extends MaskedOptions<typeof MaskedEnum>, ReturnMasked extends MaskedEnum=MaskedEnum<Opts['parent']>> (opts: Opts): ReturnMasked;
  224. // export default function createMask<Opts extends MaskedOptions<typeof MaskedRange>, ReturnMasked extends MaskedRange=MaskedRange<Opts['parent']>> (opts: Opts): ReturnMasked;
  225. // export default function createMask<Opts extends MaskedOptions<typeof MaskedRegExp>, ReturnMasked extends MaskedRegExp=MaskedRegExp<Opts['parent']>> (opts: Opts): ReturnMasked;
  226. // export default function createMask<Opts extends MaskedOptions<typeof MaskedFunction>, ReturnMasked extends MaskedFunction=MaskedFunction<Opts['parent']>> (opts: Opts): ReturnMasked;
  227. // export default function createMask<Opts extends MaskedOptions<typeof MaskedPattern>, ReturnMasked extends MaskedPattern=MaskedPattern<Opts['parent']>> (opts: Opts): ReturnMasked;
  228. // export default function createMask<Opts extends MaskedOptions<typeof MaskedDynamic>, ReturnMasked extends MaskedDynamic=MaskedDynamic<Opts['parent']>> (opts: Opts): ReturnMasked;
  229. // // From mask opts
  230. // export default function createMask<Opts extends MaskedOptions<Masked>, ReturnMasked=Opts extends MaskedOptions<infer M> ? M : never> (opts: Opts): ReturnMasked;
  231. // export default function createMask<Opts extends MaskedNumberOptions, ReturnMasked extends MaskedNumber=MaskedNumber<Opts['parent']>> (opts: Opts): ReturnMasked;
  232. // export default function createMask<Opts extends MaskedDateFactoryOptions, ReturnMasked extends MaskedDate=MaskedDate<Opts['parent']>> (opts: Opts): ReturnMasked;
  233. // export default function createMask<Opts extends MaskedEnumOptions, ReturnMasked extends MaskedEnum=MaskedEnum<Opts['parent']>> (opts: Opts): ReturnMasked;
  234. // export default function createMask<Opts extends MaskedRangeOptions, ReturnMasked extends MaskedRange=MaskedRange<Opts['parent']>> (opts: Opts): ReturnMasked;
  235. // export default function createMask<Opts extends MaskedPatternOptions, ReturnMasked extends MaskedPattern=MaskedPattern<Opts['parent']>> (opts: Opts): ReturnMasked;
  236. // export default function createMask<Opts extends MaskedDynamicOptions, ReturnMasked extends MaskedDynamic=MaskedDynamic<Opts['parent']>> (opts: Opts): ReturnMasked;
  237. // export default function createMask<Opts extends MaskedOptions<RegExp>, ReturnMasked extends MaskedRegExp=MaskedRegExp<Opts['parent']>> (opts: Opts): ReturnMasked;
  238. // export default function createMask<Opts extends MaskedOptions<Function>, ReturnMasked extends MaskedFunction=MaskedFunction<Opts['parent']>> (opts: Opts): ReturnMasked;
  239. /** Creates new {@link Masked} depending on mask type */
  240. function createMask(opts) {
  241. if (IMask.Masked && opts instanceof IMask.Masked) return opts;
  242. const nOpts = normalizeOpts(opts);
  243. const MaskedClass = maskedClass(nOpts.mask);
  244. if (!MaskedClass) throw new Error("Masked class is not found for provided mask " + nOpts.mask + ", appropriate module needs to be imported manually before creating mask.");
  245. if (nOpts.mask === MaskedClass) delete nOpts.mask;
  246. if (nOpts._mask) {
  247. nOpts.mask = nOpts._mask;
  248. delete nOpts._mask;
  249. }
  250. return new MaskedClass(nOpts);
  251. }
  252. IMask.createMask = createMask;
  253. /** Generic element API to use with mask */
  254. class MaskElement {
  255. /** */
  256. /** */
  257. /** */
  258. /** Safely returns selection start */
  259. get selectionStart() {
  260. let start;
  261. try {
  262. start = this._unsafeSelectionStart;
  263. } catch {}
  264. return start != null ? start : this.value.length;
  265. }
  266. /** Safely returns selection end */
  267. get selectionEnd() {
  268. let end;
  269. try {
  270. end = this._unsafeSelectionEnd;
  271. } catch {}
  272. return end != null ? end : this.value.length;
  273. }
  274. /** Safely sets element selection */
  275. select(start, end) {
  276. if (start == null || end == null || start === this.selectionStart && end === this.selectionEnd) return;
  277. try {
  278. this._unsafeSelect(start, end);
  279. } catch {}
  280. }
  281. /** */
  282. get isActive() {
  283. return false;
  284. }
  285. /** */
  286. /** */
  287. /** */
  288. }
  289. IMask.MaskElement = MaskElement;
  290. const KEY_Z = 90;
  291. const KEY_Y = 89;
  292. /** Bridge between HTMLElement and {@link Masked} */
  293. class HTMLMaskElement extends MaskElement {
  294. /** HTMLElement to use mask on */
  295. constructor(input) {
  296. super();
  297. this.input = input;
  298. this._onKeydown = this._onKeydown.bind(this);
  299. this._onInput = this._onInput.bind(this);
  300. this._onBeforeinput = this._onBeforeinput.bind(this);
  301. this._onCompositionEnd = this._onCompositionEnd.bind(this);
  302. }
  303. get rootElement() {
  304. var _this$input$getRootNo, _this$input$getRootNo2, _this$input;
  305. return (_this$input$getRootNo = (_this$input$getRootNo2 = (_this$input = this.input).getRootNode) == null ? void 0 : _this$input$getRootNo2.call(_this$input)) != null ? _this$input$getRootNo : document;
  306. }
  307. /** Is element in focus */
  308. get isActive() {
  309. return this.input === this.rootElement.activeElement;
  310. }
  311. /** Binds HTMLElement events to mask internal events */
  312. bindEvents(handlers) {
  313. this.input.addEventListener('keydown', this._onKeydown);
  314. this.input.addEventListener('input', this._onInput);
  315. this.input.addEventListener('beforeinput', this._onBeforeinput);
  316. this.input.addEventListener('compositionend', this._onCompositionEnd);
  317. this.input.addEventListener('drop', handlers.drop);
  318. this.input.addEventListener('click', handlers.click);
  319. this.input.addEventListener('focus', handlers.focus);
  320. this.input.addEventListener('blur', handlers.commit);
  321. this._handlers = handlers;
  322. }
  323. _onKeydown(e) {
  324. if (this._handlers.redo && (e.keyCode === KEY_Z && e.shiftKey && (e.metaKey || e.ctrlKey) || e.keyCode === KEY_Y && e.ctrlKey)) {
  325. e.preventDefault();
  326. return this._handlers.redo(e);
  327. }
  328. if (this._handlers.undo && e.keyCode === KEY_Z && (e.metaKey || e.ctrlKey)) {
  329. e.preventDefault();
  330. return this._handlers.undo(e);
  331. }
  332. if (!e.isComposing) this._handlers.selectionChange(e);
  333. }
  334. _onBeforeinput(e) {
  335. if (e.inputType === 'historyUndo' && this._handlers.undo) {
  336. e.preventDefault();
  337. return this._handlers.undo(e);
  338. }
  339. if (e.inputType === 'historyRedo' && this._handlers.redo) {
  340. e.preventDefault();
  341. return this._handlers.redo(e);
  342. }
  343. }
  344. _onCompositionEnd(e) {
  345. this._handlers.input(e);
  346. }
  347. _onInput(e) {
  348. if (!e.isComposing) this._handlers.input(e);
  349. }
  350. /** Unbinds HTMLElement events to mask internal events */
  351. unbindEvents() {
  352. this.input.removeEventListener('keydown', this._onKeydown);
  353. this.input.removeEventListener('input', this._onInput);
  354. this.input.removeEventListener('beforeinput', this._onBeforeinput);
  355. this.input.removeEventListener('compositionend', this._onCompositionEnd);
  356. this.input.removeEventListener('drop', this._handlers.drop);
  357. this.input.removeEventListener('click', this._handlers.click);
  358. this.input.removeEventListener('focus', this._handlers.focus);
  359. this.input.removeEventListener('blur', this._handlers.commit);
  360. this._handlers = {};
  361. }
  362. }
  363. IMask.HTMLMaskElement = HTMLMaskElement;
  364. /** Bridge between InputElement and {@link Masked} */
  365. class HTMLInputMaskElement extends HTMLMaskElement {
  366. /** InputElement to use mask on */
  367. constructor(input) {
  368. super(input);
  369. this.input = input;
  370. }
  371. /** Returns InputElement selection start */
  372. get _unsafeSelectionStart() {
  373. return this.input.selectionStart != null ? this.input.selectionStart : this.value.length;
  374. }
  375. /** Returns InputElement selection end */
  376. get _unsafeSelectionEnd() {
  377. return this.input.selectionEnd;
  378. }
  379. /** Sets InputElement selection */
  380. _unsafeSelect(start, end) {
  381. this.input.setSelectionRange(start, end);
  382. }
  383. get value() {
  384. return this.input.value;
  385. }
  386. set value(value) {
  387. this.input.value = value;
  388. }
  389. }
  390. IMask.HTMLMaskElement = HTMLMaskElement;
  391. class HTMLContenteditableMaskElement extends HTMLMaskElement {
  392. /** Returns HTMLElement selection start */
  393. get _unsafeSelectionStart() {
  394. const root = this.rootElement;
  395. const selection = root.getSelection && root.getSelection();
  396. const anchorOffset = selection && selection.anchorOffset;
  397. const focusOffset = selection && selection.focusOffset;
  398. if (focusOffset == null || anchorOffset == null || anchorOffset < focusOffset) {
  399. return anchorOffset;
  400. }
  401. return focusOffset;
  402. }
  403. /** Returns HTMLElement selection end */
  404. get _unsafeSelectionEnd() {
  405. const root = this.rootElement;
  406. const selection = root.getSelection && root.getSelection();
  407. const anchorOffset = selection && selection.anchorOffset;
  408. const focusOffset = selection && selection.focusOffset;
  409. if (focusOffset == null || anchorOffset == null || anchorOffset > focusOffset) {
  410. return anchorOffset;
  411. }
  412. return focusOffset;
  413. }
  414. /** Sets HTMLElement selection */
  415. _unsafeSelect(start, end) {
  416. if (!this.rootElement.createRange) return;
  417. const range = this.rootElement.createRange();
  418. range.setStart(this.input.firstChild || this.input, start);
  419. range.setEnd(this.input.lastChild || this.input, end);
  420. const root = this.rootElement;
  421. const selection = root.getSelection && root.getSelection();
  422. if (selection) {
  423. selection.removeAllRanges();
  424. selection.addRange(range);
  425. }
  426. }
  427. /** HTMLElement value */
  428. get value() {
  429. return this.input.textContent || '';
  430. }
  431. set value(value) {
  432. this.input.textContent = value;
  433. }
  434. }
  435. IMask.HTMLContenteditableMaskElement = HTMLContenteditableMaskElement;
  436. class InputHistory {
  437. constructor() {
  438. this.states = [];
  439. this.currentIndex = 0;
  440. }
  441. get currentState() {
  442. return this.states[this.currentIndex];
  443. }
  444. get isEmpty() {
  445. return this.states.length === 0;
  446. }
  447. push(state) {
  448. // if current index points before the last element then remove the future
  449. if (this.currentIndex < this.states.length - 1) this.states.length = this.currentIndex + 1;
  450. this.states.push(state);
  451. if (this.states.length > InputHistory.MAX_LENGTH) this.states.shift();
  452. this.currentIndex = this.states.length - 1;
  453. }
  454. go(steps) {
  455. this.currentIndex = Math.min(Math.max(this.currentIndex + steps, 0), this.states.length - 1);
  456. return this.currentState;
  457. }
  458. undo() {
  459. return this.go(-1);
  460. }
  461. redo() {
  462. return this.go(+1);
  463. }
  464. clear() {
  465. this.states.length = 0;
  466. this.currentIndex = 0;
  467. }
  468. }
  469. InputHistory.MAX_LENGTH = 100;
  470. /** Listens to element events and controls changes between element and {@link Masked} */
  471. class InputMask {
  472. /**
  473. View element
  474. */
  475. /** Internal {@link Masked} model */
  476. constructor(el, opts) {
  477. this.el = el instanceof MaskElement ? el : el.isContentEditable && el.tagName !== 'INPUT' && el.tagName !== 'TEXTAREA' ? new HTMLContenteditableMaskElement(el) : new HTMLInputMaskElement(el);
  478. this.masked = createMask(opts);
  479. this._listeners = {};
  480. this._value = '';
  481. this._unmaskedValue = '';
  482. this._rawInputValue = '';
  483. this.history = new InputHistory();
  484. this._saveSelection = this._saveSelection.bind(this);
  485. this._onInput = this._onInput.bind(this);
  486. this._onChange = this._onChange.bind(this);
  487. this._onDrop = this._onDrop.bind(this);
  488. this._onFocus = this._onFocus.bind(this);
  489. this._onClick = this._onClick.bind(this);
  490. this._onUndo = this._onUndo.bind(this);
  491. this._onRedo = this._onRedo.bind(this);
  492. this.alignCursor = this.alignCursor.bind(this);
  493. this.alignCursorFriendly = this.alignCursorFriendly.bind(this);
  494. this._bindEvents();
  495. // refresh
  496. this.updateValue();
  497. this._onChange();
  498. }
  499. maskEquals(mask) {
  500. var _this$masked;
  501. return mask == null || ((_this$masked = this.masked) == null ? void 0 : _this$masked.maskEquals(mask));
  502. }
  503. /** Masked */
  504. get mask() {
  505. return this.masked.mask;
  506. }
  507. set mask(mask) {
  508. if (this.maskEquals(mask)) return;
  509. if (!(mask instanceof IMask.Masked) && this.masked.constructor === maskedClass(mask)) {
  510. // TODO "any" no idea
  511. this.masked.updateOptions({
  512. mask
  513. });
  514. return;
  515. }
  516. const masked = mask instanceof IMask.Masked ? mask : createMask({
  517. mask
  518. });
  519. masked.unmaskedValue = this.masked.unmaskedValue;
  520. this.masked = masked;
  521. }
  522. /** Raw value */
  523. get value() {
  524. return this._value;
  525. }
  526. set value(str) {
  527. if (this.value === str) return;
  528. this.masked.value = str;
  529. this.updateControl('auto');
  530. }
  531. /** Unmasked value */
  532. get unmaskedValue() {
  533. return this._unmaskedValue;
  534. }
  535. set unmaskedValue(str) {
  536. if (this.unmaskedValue === str) return;
  537. this.masked.unmaskedValue = str;
  538. this.updateControl('auto');
  539. }
  540. /** Raw input value */
  541. get rawInputValue() {
  542. return this._rawInputValue;
  543. }
  544. set rawInputValue(str) {
  545. if (this.rawInputValue === str) return;
  546. this.masked.rawInputValue = str;
  547. this.updateControl();
  548. this.alignCursor();
  549. }
  550. /** Typed unmasked value */
  551. get typedValue() {
  552. return this.masked.typedValue;
  553. }
  554. set typedValue(val) {
  555. if (this.masked.typedValueEquals(val)) return;
  556. this.masked.typedValue = val;
  557. this.updateControl('auto');
  558. }
  559. /** Display value */
  560. get displayValue() {
  561. return this.masked.displayValue;
  562. }
  563. /** Starts listening to element events */
  564. _bindEvents() {
  565. this.el.bindEvents({
  566. selectionChange: this._saveSelection,
  567. input: this._onInput,
  568. drop: this._onDrop,
  569. click: this._onClick,
  570. focus: this._onFocus,
  571. commit: this._onChange,
  572. undo: this._onUndo,
  573. redo: this._onRedo
  574. });
  575. }
  576. /** Stops listening to element events */
  577. _unbindEvents() {
  578. if (this.el) this.el.unbindEvents();
  579. }
  580. /** Fires custom event */
  581. _fireEvent(ev, e) {
  582. const listeners = this._listeners[ev];
  583. if (!listeners) return;
  584. listeners.forEach(l => l(e));
  585. }
  586. /** Current selection start */
  587. get selectionStart() {
  588. return this._cursorChanging ? this._changingCursorPos : this.el.selectionStart;
  589. }
  590. /** Current cursor position */
  591. get cursorPos() {
  592. return this._cursorChanging ? this._changingCursorPos : this.el.selectionEnd;
  593. }
  594. set cursorPos(pos) {
  595. if (!this.el || !this.el.isActive) return;
  596. this.el.select(pos, pos);
  597. this._saveSelection();
  598. }
  599. /** Stores current selection */
  600. _saveSelection( /* ev */
  601. ) {
  602. if (this.displayValue !== this.el.value) {
  603. console.warn('Element value was changed outside of mask. Syncronize mask using `mask.updateValue()` to work properly.'); // eslint-disable-line no-console
  604. }
  605. this._selection = {
  606. start: this.selectionStart,
  607. end: this.cursorPos
  608. };
  609. }
  610. /** Syncronizes model value from view */
  611. updateValue() {
  612. this.masked.value = this.el.value;
  613. this._value = this.masked.value;
  614. }
  615. /** Syncronizes view from model value, fires change events */
  616. updateControl(cursorPos) {
  617. const newUnmaskedValue = this.masked.unmaskedValue;
  618. const newValue = this.masked.value;
  619. const newRawInputValue = this.masked.rawInputValue;
  620. const newDisplayValue = this.displayValue;
  621. const isChanged = this.unmaskedValue !== newUnmaskedValue || this.value !== newValue || this._rawInputValue !== newRawInputValue;
  622. this._unmaskedValue = newUnmaskedValue;
  623. this._value = newValue;
  624. this._rawInputValue = newRawInputValue;
  625. if (this.el.value !== newDisplayValue) this.el.value = newDisplayValue;
  626. if (cursorPos === 'auto') this.alignCursor();else if (cursorPos != null) this.cursorPos = cursorPos;
  627. if (isChanged) this._fireChangeEvents();
  628. if (!this._historyChanging && (isChanged || this.history.isEmpty)) this.history.push({
  629. unmaskedValue: newUnmaskedValue,
  630. selection: {
  631. start: this.selectionStart,
  632. end: this.cursorPos
  633. }
  634. });
  635. }
  636. /** Updates options with deep equal check, recreates {@link Masked} model if mask type changes */
  637. updateOptions(opts) {
  638. const {
  639. mask,
  640. ...restOpts
  641. } = opts; // TODO types, yes, mask is optional
  642. const updateMask = !this.maskEquals(mask);
  643. const updateOpts = this.masked.optionsIsChanged(restOpts);
  644. if (updateMask) this.mask = mask;
  645. if (updateOpts) this.masked.updateOptions(restOpts); // TODO
  646. if (updateMask || updateOpts) this.updateControl();
  647. }
  648. /** Updates cursor */
  649. updateCursor(cursorPos) {
  650. if (cursorPos == null) return;
  651. this.cursorPos = cursorPos;
  652. // also queue change cursor for mobile browsers
  653. this._delayUpdateCursor(cursorPos);
  654. }
  655. /** Delays cursor update to support mobile browsers */
  656. _delayUpdateCursor(cursorPos) {
  657. this._abortUpdateCursor();
  658. this._changingCursorPos = cursorPos;
  659. this._cursorChanging = setTimeout(() => {
  660. if (!this.el) return; // if was destroyed
  661. this.cursorPos = this._changingCursorPos;
  662. this._abortUpdateCursor();
  663. }, 10);
  664. }
  665. /** Fires custom events */
  666. _fireChangeEvents() {
  667. this._fireEvent('accept', this._inputEvent);
  668. if (this.masked.isComplete) this._fireEvent('complete', this._inputEvent);
  669. }
  670. /** Aborts delayed cursor update */
  671. _abortUpdateCursor() {
  672. if (this._cursorChanging) {
  673. clearTimeout(this._cursorChanging);
  674. delete this._cursorChanging;
  675. }
  676. }
  677. /** Aligns cursor to nearest available position */
  678. alignCursor() {
  679. this.cursorPos = this.masked.nearestInputPos(this.masked.nearestInputPos(this.cursorPos, DIRECTION.LEFT));
  680. }
  681. /** Aligns cursor only if selection is empty */
  682. alignCursorFriendly() {
  683. if (this.selectionStart !== this.cursorPos) return; // skip if range is selected
  684. this.alignCursor();
  685. }
  686. /** Adds listener on custom event */
  687. on(ev, handler) {
  688. if (!this._listeners[ev]) this._listeners[ev] = [];
  689. this._listeners[ev].push(handler);
  690. return this;
  691. }
  692. /** Removes custom event listener */
  693. off(ev, handler) {
  694. if (!this._listeners[ev]) return this;
  695. if (!handler) {
  696. delete this._listeners[ev];
  697. return this;
  698. }
  699. const hIndex = this._listeners[ev].indexOf(handler);
  700. if (hIndex >= 0) this._listeners[ev].splice(hIndex, 1);
  701. return this;
  702. }
  703. /** Handles view input event */
  704. _onInput(e) {
  705. this._inputEvent = e;
  706. this._abortUpdateCursor();
  707. const details = new ActionDetails({
  708. // new state
  709. value: this.el.value,
  710. cursorPos: this.cursorPos,
  711. // old state
  712. oldValue: this.displayValue,
  713. oldSelection: this._selection
  714. });
  715. const oldRawValue = this.masked.rawInputValue;
  716. const offset = this.masked.splice(details.startChangePos, details.removed.length, details.inserted, details.removeDirection, {
  717. input: true,
  718. raw: true
  719. }).offset;
  720. // force align in remove direction only if no input chars were removed
  721. // otherwise we still need to align with NONE (to get out from fixed symbols for instance)
  722. const removeDirection = oldRawValue === this.masked.rawInputValue ? details.removeDirection : DIRECTION.NONE;
  723. let cursorPos = this.masked.nearestInputPos(details.startChangePos + offset, removeDirection);
  724. if (removeDirection !== DIRECTION.NONE) cursorPos = this.masked.nearestInputPos(cursorPos, DIRECTION.NONE);
  725. this.updateControl(cursorPos);
  726. delete this._inputEvent;
  727. }
  728. /** Handles view change event and commits model value */
  729. _onChange() {
  730. if (this.displayValue !== this.el.value) {
  731. this.updateValue();
  732. }
  733. this.masked.doCommit();
  734. this.updateControl();
  735. this._saveSelection();
  736. }
  737. /** Handles view drop event, prevents by default */
  738. _onDrop(ev) {
  739. ev.preventDefault();
  740. ev.stopPropagation();
  741. }
  742. /** Restore last selection on focus */
  743. _onFocus(ev) {
  744. this.alignCursorFriendly();
  745. }
  746. /** Restore last selection on focus */
  747. _onClick(ev) {
  748. this.alignCursorFriendly();
  749. }
  750. _onUndo() {
  751. this._applyHistoryState(this.history.undo());
  752. }
  753. _onRedo() {
  754. this._applyHistoryState(this.history.redo());
  755. }
  756. _applyHistoryState(state) {
  757. if (!state) return;
  758. this._historyChanging = true;
  759. this.unmaskedValue = state.unmaskedValue;
  760. this.el.select(state.selection.start, state.selection.end);
  761. this._saveSelection();
  762. this._historyChanging = false;
  763. }
  764. /** Unbind view events and removes element reference */
  765. destroy() {
  766. this._unbindEvents();
  767. this._listeners.length = 0;
  768. delete this.el;
  769. }
  770. }
  771. IMask.InputMask = InputMask;
  772. /** Provides details of changing model value */
  773. class ChangeDetails {
  774. /** Inserted symbols */
  775. /** Additional offset if any changes occurred before tail */
  776. /** Raw inserted is used by dynamic mask */
  777. /** Can skip chars */
  778. static normalize(prep) {
  779. return Array.isArray(prep) ? prep : [prep, new ChangeDetails()];
  780. }
  781. constructor(details) {
  782. Object.assign(this, {
  783. inserted: '',
  784. rawInserted: '',
  785. tailShift: 0,
  786. skip: false
  787. }, details);
  788. }
  789. /** Aggregate changes */
  790. aggregate(details) {
  791. this.inserted += details.inserted;
  792. this.rawInserted += details.rawInserted;
  793. this.tailShift += details.tailShift;
  794. this.skip = this.skip || details.skip;
  795. return this;
  796. }
  797. /** Total offset considering all changes */
  798. get offset() {
  799. return this.tailShift + this.inserted.length;
  800. }
  801. get consumed() {
  802. return Boolean(this.rawInserted) || this.skip;
  803. }
  804. equals(details) {
  805. return this.inserted === details.inserted && this.tailShift === details.tailShift && this.rawInserted === details.rawInserted && this.skip === details.skip;
  806. }
  807. }
  808. IMask.ChangeDetails = ChangeDetails;
  809. /** Provides details of continuous extracted tail */
  810. class ContinuousTailDetails {
  811. /** Tail value as string */
  812. /** Tail start position */
  813. /** Start position */
  814. constructor(value, from, stop) {
  815. if (value === void 0) {
  816. value = '';
  817. }
  818. if (from === void 0) {
  819. from = 0;
  820. }
  821. this.value = value;
  822. this.from = from;
  823. this.stop = stop;
  824. }
  825. toString() {
  826. return this.value;
  827. }
  828. extend(tail) {
  829. this.value += String(tail);
  830. }
  831. appendTo(masked) {
  832. return masked.append(this.toString(), {
  833. tail: true
  834. }).aggregate(masked._appendPlaceholder());
  835. }
  836. get state() {
  837. return {
  838. value: this.value,
  839. from: this.from,
  840. stop: this.stop
  841. };
  842. }
  843. set state(state) {
  844. Object.assign(this, state);
  845. }
  846. unshift(beforePos) {
  847. if (!this.value.length || beforePos != null && this.from >= beforePos) return '';
  848. const shiftChar = this.value[0];
  849. this.value = this.value.slice(1);
  850. return shiftChar;
  851. }
  852. shift() {
  853. if (!this.value.length) return '';
  854. const shiftChar = this.value[this.value.length - 1];
  855. this.value = this.value.slice(0, -1);
  856. return shiftChar;
  857. }
  858. }
  859. /** Append flags */
  860. /** Extract flags */
  861. // see https://github.com/microsoft/TypeScript/issues/6223
  862. /** Provides common masking stuff */
  863. class Masked {
  864. /** */
  865. /** */
  866. /** Transforms value before mask processing */
  867. /** Transforms each char before mask processing */
  868. /** Validates if value is acceptable */
  869. /** Does additional processing at the end of editing */
  870. /** Format typed value to string */
  871. /** Parse string to get typed value */
  872. /** Enable characters overwriting */
  873. /** */
  874. /** */
  875. /** */
  876. /** */
  877. constructor(opts) {
  878. this._value = '';
  879. this._update({
  880. ...Masked.DEFAULTS,
  881. ...opts
  882. });
  883. this._initialized = true;
  884. }
  885. /** Sets and applies new options */
  886. updateOptions(opts) {
  887. if (!this.optionsIsChanged(opts)) return;
  888. this.withValueRefresh(this._update.bind(this, opts));
  889. }
  890. /** Sets new options */
  891. _update(opts) {
  892. Object.assign(this, opts);
  893. }
  894. /** Mask state */
  895. get state() {
  896. return {
  897. _value: this.value,
  898. _rawInputValue: this.rawInputValue
  899. };
  900. }
  901. set state(state) {
  902. this._value = state._value;
  903. }
  904. /** Resets value */
  905. reset() {
  906. this._value = '';
  907. }
  908. get value() {
  909. return this._value;
  910. }
  911. set value(value) {
  912. this.resolve(value, {
  913. input: true
  914. });
  915. }
  916. /** Resolve new value */
  917. resolve(value, flags) {
  918. if (flags === void 0) {
  919. flags = {
  920. input: true
  921. };
  922. }
  923. this.reset();
  924. this.append(value, flags, '');
  925. this.doCommit();
  926. }
  927. get unmaskedValue() {
  928. return this.value;
  929. }
  930. set unmaskedValue(value) {
  931. this.resolve(value, {});
  932. }
  933. get typedValue() {
  934. return this.parse ? this.parse(this.value, this) : this.unmaskedValue;
  935. }
  936. set typedValue(value) {
  937. if (this.format) {
  938. this.value = this.format(value, this);
  939. } else {
  940. this.unmaskedValue = String(value);
  941. }
  942. }
  943. /** Value that includes raw user input */
  944. get rawInputValue() {
  945. return this.extractInput(0, this.displayValue.length, {
  946. raw: true
  947. });
  948. }
  949. set rawInputValue(value) {
  950. this.resolve(value, {
  951. raw: true
  952. });
  953. }
  954. get displayValue() {
  955. return this.value;
  956. }
  957. get isComplete() {
  958. return true;
  959. }
  960. get isFilled() {
  961. return this.isComplete;
  962. }
  963. /** Finds nearest input position in direction */
  964. nearestInputPos(cursorPos, direction) {
  965. return cursorPos;
  966. }
  967. totalInputPositions(fromPos, toPos) {
  968. if (fromPos === void 0) {
  969. fromPos = 0;
  970. }
  971. if (toPos === void 0) {
  972. toPos = this.displayValue.length;
  973. }
  974. return Math.min(this.displayValue.length, toPos - fromPos);
  975. }
  976. /** Extracts value in range considering flags */
  977. extractInput(fromPos, toPos, flags) {
  978. if (fromPos === void 0) {
  979. fromPos = 0;
  980. }
  981. if (toPos === void 0) {
  982. toPos = this.displayValue.length;
  983. }
  984. return this.displayValue.slice(fromPos, toPos);
  985. }
  986. /** Extracts tail in range */
  987. extractTail(fromPos, toPos) {
  988. if (fromPos === void 0) {
  989. fromPos = 0;
  990. }
  991. if (toPos === void 0) {
  992. toPos = this.displayValue.length;
  993. }
  994. return new ContinuousTailDetails(this.extractInput(fromPos, toPos), fromPos);
  995. }
  996. /** Appends tail */
  997. appendTail(tail) {
  998. if (isString(tail)) tail = new ContinuousTailDetails(String(tail));
  999. return tail.appendTo(this);
  1000. }
  1001. /** Appends char */
  1002. _appendCharRaw(ch, flags) {
  1003. if (!ch) return new ChangeDetails();
  1004. this._value += ch;
  1005. return new ChangeDetails({
  1006. inserted: ch,
  1007. rawInserted: ch
  1008. });
  1009. }
  1010. /** Appends char */
  1011. _appendChar(ch, flags, checkTail) {
  1012. if (flags === void 0) {
  1013. flags = {};
  1014. }
  1015. const consistentState = this.state;
  1016. let details;
  1017. [ch, details] = this.doPrepareChar(ch, flags);
  1018. if (ch) {
  1019. details = details.aggregate(this._appendCharRaw(ch, flags));
  1020. // TODO handle `skip`?
  1021. // try `autofix` lookahead
  1022. if (!details.rawInserted && this.autofix === 'pad') {
  1023. const noFixState = this.state;
  1024. this.state = consistentState;
  1025. let fixDetails = this.pad(flags);
  1026. const chDetails = this._appendCharRaw(ch, flags);
  1027. fixDetails = fixDetails.aggregate(chDetails);
  1028. // if fix was applied or
  1029. // if details are equal use skip restoring state optimization
  1030. if (chDetails.rawInserted || fixDetails.equals(details)) {
  1031. details = fixDetails;
  1032. } else {
  1033. this.state = noFixState;
  1034. }
  1035. }
  1036. }
  1037. if (details.inserted) {
  1038. let consistentTail;
  1039. let appended = this.doValidate(flags) !== false;
  1040. if (appended && checkTail != null) {
  1041. // validation ok, check tail
  1042. const beforeTailState = this.state;
  1043. if (this.overwrite === true) {
  1044. consistentTail = checkTail.state;
  1045. for (let i = 0; i < details.rawInserted.length; ++i) {
  1046. checkTail.unshift(this.displayValue.length - details.tailShift);
  1047. }
  1048. }
  1049. let tailDetails = this.appendTail(checkTail);
  1050. appended = tailDetails.rawInserted.length === checkTail.toString().length;
  1051. // not ok, try shift
  1052. if (!(appended && tailDetails.inserted) && this.overwrite === 'shift') {
  1053. this.state = beforeTailState;
  1054. consistentTail = checkTail.state;
  1055. for (let i = 0; i < details.rawInserted.length; ++i) {
  1056. checkTail.shift();
  1057. }
  1058. tailDetails = this.appendTail(checkTail);
  1059. appended = tailDetails.rawInserted.length === checkTail.toString().length;
  1060. }
  1061. // if ok, rollback state after tail
  1062. if (appended && tailDetails.inserted) this.state = beforeTailState;
  1063. }
  1064. // revert all if something went wrong
  1065. if (!appended) {
  1066. details = new ChangeDetails();
  1067. this.state = consistentState;
  1068. if (checkTail && consistentTail) checkTail.state = consistentTail;
  1069. }
  1070. }
  1071. return details;
  1072. }
  1073. /** Appends optional placeholder at the end */
  1074. _appendPlaceholder() {
  1075. return new ChangeDetails();
  1076. }
  1077. /** Appends optional eager placeholder at the end */
  1078. _appendEager() {
  1079. return new ChangeDetails();
  1080. }
  1081. /** Appends symbols considering flags */
  1082. append(str, flags, tail) {
  1083. if (!isString(str)) throw new Error('value should be string');
  1084. const checkTail = isString(tail) ? new ContinuousTailDetails(String(tail)) : tail;
  1085. if (flags != null && flags.tail) flags._beforeTailState = this.state;
  1086. let details;
  1087. [str, details] = this.doPrepare(str, flags);
  1088. for (let ci = 0; ci < str.length; ++ci) {
  1089. const d = this._appendChar(str[ci], flags, checkTail);
  1090. if (!d.rawInserted && !this.doSkipInvalid(str[ci], flags, checkTail)) break;
  1091. details.aggregate(d);
  1092. }
  1093. if ((this.eager === true || this.eager === 'append') && flags != null && flags.input && str) {
  1094. details.aggregate(this._appendEager());
  1095. }
  1096. // append tail but aggregate only tailShift
  1097. if (checkTail != null) {
  1098. details.tailShift += this.appendTail(checkTail).tailShift;
  1099. // TODO it's a good idea to clear state after appending ends
  1100. // but it causes bugs when one append calls another (when dynamic dispatch set rawInputValue)
  1101. // this._resetBeforeTailState();
  1102. }
  1103. return details;
  1104. }
  1105. remove(fromPos, toPos) {
  1106. if (fromPos === void 0) {
  1107. fromPos = 0;
  1108. }
  1109. if (toPos === void 0) {
  1110. toPos = this.displayValue.length;
  1111. }
  1112. this._value = this.displayValue.slice(0, fromPos) + this.displayValue.slice(toPos);
  1113. return new ChangeDetails();
  1114. }
  1115. /** Calls function and reapplies current value */
  1116. withValueRefresh(fn) {
  1117. if (this._refreshing || !this._initialized) return fn();
  1118. this._refreshing = true;
  1119. const rawInput = this.rawInputValue;
  1120. const value = this.value;
  1121. const ret = fn();
  1122. this.rawInputValue = rawInput;
  1123. // append lost trailing chars at the end
  1124. if (this.value && this.value !== value && value.indexOf(this.value) === 0) {
  1125. this.append(value.slice(this.displayValue.length), {}, '');
  1126. this.doCommit();
  1127. }
  1128. delete this._refreshing;
  1129. return ret;
  1130. }
  1131. runIsolated(fn) {
  1132. if (this._isolated || !this._initialized) return fn(this);
  1133. this._isolated = true;
  1134. const state = this.state;
  1135. const ret = fn(this);
  1136. this.state = state;
  1137. delete this._isolated;
  1138. return ret;
  1139. }
  1140. doSkipInvalid(ch, flags, checkTail) {
  1141. return Boolean(this.skipInvalid);
  1142. }
  1143. /** Prepares string before mask processing */
  1144. doPrepare(str, flags) {
  1145. if (flags === void 0) {
  1146. flags = {};
  1147. }
  1148. return ChangeDetails.normalize(this.prepare ? this.prepare(str, this, flags) : str);
  1149. }
  1150. /** Prepares each char before mask processing */
  1151. doPrepareChar(str, flags) {
  1152. if (flags === void 0) {
  1153. flags = {};
  1154. }
  1155. return ChangeDetails.normalize(this.prepareChar ? this.prepareChar(str, this, flags) : str);
  1156. }
  1157. /** Validates if value is acceptable */
  1158. doValidate(flags) {
  1159. return (!this.validate || this.validate(this.value, this, flags)) && (!this.parent || this.parent.doValidate(flags));
  1160. }
  1161. /** Does additional processing at the end of editing */
  1162. doCommit() {
  1163. if (this.commit) this.commit(this.value, this);
  1164. }
  1165. splice(start, deleteCount, inserted, removeDirection, flags) {
  1166. if (inserted === void 0) {
  1167. inserted = '';
  1168. }
  1169. if (removeDirection === void 0) {
  1170. removeDirection = DIRECTION.NONE;
  1171. }
  1172. if (flags === void 0) {
  1173. flags = {
  1174. input: true
  1175. };
  1176. }
  1177. const tailPos = start + deleteCount;
  1178. const tail = this.extractTail(tailPos);
  1179. const eagerRemove = this.eager === true || this.eager === 'remove';
  1180. let oldRawValue;
  1181. if (eagerRemove) {
  1182. removeDirection = forceDirection(removeDirection);
  1183. oldRawValue = this.extractInput(0, tailPos, {
  1184. raw: true
  1185. });
  1186. }
  1187. let startChangePos = start;
  1188. const details = new ChangeDetails();
  1189. // if it is just deletion without insertion
  1190. if (removeDirection !== DIRECTION.NONE) {
  1191. startChangePos = this.nearestInputPos(start, deleteCount > 1 && start !== 0 && !eagerRemove ? DIRECTION.NONE : removeDirection);
  1192. // adjust tailShift if start was aligned
  1193. details.tailShift = startChangePos - start;
  1194. }
  1195. details.aggregate(this.remove(startChangePos));
  1196. if (eagerRemove && removeDirection !== DIRECTION.NONE && oldRawValue === this.rawInputValue) {
  1197. if (removeDirection === DIRECTION.FORCE_LEFT) {
  1198. let valLength;
  1199. while (oldRawValue === this.rawInputValue && (valLength = this.displayValue.length)) {
  1200. details.aggregate(new ChangeDetails({
  1201. tailShift: -1
  1202. })).aggregate(this.remove(valLength - 1));
  1203. }
  1204. } else if (removeDirection === DIRECTION.FORCE_RIGHT) {
  1205. tail.unshift();
  1206. }
  1207. }
  1208. return details.aggregate(this.append(inserted, flags, tail));
  1209. }
  1210. maskEquals(mask) {
  1211. return this.mask === mask;
  1212. }
  1213. optionsIsChanged(opts) {
  1214. return !objectIncludes(this, opts);
  1215. }
  1216. typedValueEquals(value) {
  1217. const tval = this.typedValue;
  1218. return value === tval || Masked.EMPTY_VALUES.includes(value) && Masked.EMPTY_VALUES.includes(tval) || (this.format ? this.format(value, this) === this.format(this.typedValue, this) : false);
  1219. }
  1220. pad(flags) {
  1221. return new ChangeDetails();
  1222. }
  1223. }
  1224. Masked.DEFAULTS = {
  1225. skipInvalid: true
  1226. };
  1227. Masked.EMPTY_VALUES = [undefined, null, ''];
  1228. IMask.Masked = Masked;
  1229. class ChunksTailDetails {
  1230. /** */
  1231. constructor(chunks, from) {
  1232. if (chunks === void 0) {
  1233. chunks = [];
  1234. }
  1235. if (from === void 0) {
  1236. from = 0;
  1237. }
  1238. this.chunks = chunks;
  1239. this.from = from;
  1240. }
  1241. toString() {
  1242. return this.chunks.map(String).join('');
  1243. }
  1244. extend(tailChunk) {
  1245. if (!String(tailChunk)) return;
  1246. tailChunk = isString(tailChunk) ? new ContinuousTailDetails(String(tailChunk)) : tailChunk;
  1247. const lastChunk = this.chunks[this.chunks.length - 1];
  1248. const extendLast = lastChunk && (
  1249. // if stops are same or tail has no stop
  1250. lastChunk.stop === tailChunk.stop || tailChunk.stop == null) &&
  1251. // if tail chunk goes just after last chunk
  1252. tailChunk.from === lastChunk.from + lastChunk.toString().length;
  1253. if (tailChunk instanceof ContinuousTailDetails) {
  1254. // check the ability to extend previous chunk
  1255. if (extendLast) {
  1256. // extend previous chunk
  1257. lastChunk.extend(tailChunk.toString());
  1258. } else {
  1259. // append new chunk
  1260. this.chunks.push(tailChunk);
  1261. }
  1262. } else if (tailChunk instanceof ChunksTailDetails) {
  1263. if (tailChunk.stop == null) {
  1264. // unwrap floating chunks to parent, keeping `from` pos
  1265. let firstTailChunk;
  1266. while (tailChunk.chunks.length && tailChunk.chunks[0].stop == null) {
  1267. firstTailChunk = tailChunk.chunks.shift(); // not possible to be `undefined` because length was checked above
  1268. firstTailChunk.from += tailChunk.from;
  1269. this.extend(firstTailChunk);
  1270. }
  1271. }
  1272. // if tail chunk still has value
  1273. if (tailChunk.toString()) {
  1274. // if chunks contains stops, then popup stop to container
  1275. tailChunk.stop = tailChunk.blockIndex;
  1276. this.chunks.push(tailChunk);
  1277. }
  1278. }
  1279. }
  1280. appendTo(masked) {
  1281. if (!(masked instanceof IMask.MaskedPattern)) {
  1282. const tail = new ContinuousTailDetails(this.toString());
  1283. return tail.appendTo(masked);
  1284. }
  1285. const details = new ChangeDetails();
  1286. for (let ci = 0; ci < this.chunks.length; ++ci) {
  1287. const chunk = this.chunks[ci];
  1288. const lastBlockIter = masked._mapPosToBlock(masked.displayValue.length);
  1289. const stop = chunk.stop;
  1290. let chunkBlock;
  1291. if (stop != null && (
  1292. // if block not found or stop is behind lastBlock
  1293. !lastBlockIter || lastBlockIter.index <= stop)) {
  1294. if (chunk instanceof ChunksTailDetails ||
  1295. // for continuous block also check if stop is exist
  1296. masked._stops.indexOf(stop) >= 0) {
  1297. details.aggregate(masked._appendPlaceholder(stop));
  1298. }
  1299. chunkBlock = chunk instanceof ChunksTailDetails && masked._blocks[stop];
  1300. }
  1301. if (chunkBlock) {
  1302. const tailDetails = chunkBlock.appendTail(chunk);
  1303. details.aggregate(tailDetails);
  1304. // get not inserted chars
  1305. const remainChars = chunk.toString().slice(tailDetails.rawInserted.length);
  1306. if (remainChars) details.aggregate(masked.append(remainChars, {
  1307. tail: true
  1308. }));
  1309. } else {
  1310. details.aggregate(masked.append(chunk.toString(), {
  1311. tail: true
  1312. }));
  1313. }
  1314. }
  1315. return details;
  1316. }
  1317. get state() {
  1318. return {
  1319. chunks: this.chunks.map(c => c.state),
  1320. from: this.from,
  1321. stop: this.stop,
  1322. blockIndex: this.blockIndex
  1323. };
  1324. }
  1325. set state(state) {
  1326. const {
  1327. chunks,
  1328. ...props
  1329. } = state;
  1330. Object.assign(this, props);
  1331. this.chunks = chunks.map(cstate => {
  1332. const chunk = "chunks" in cstate ? new ChunksTailDetails() : new ContinuousTailDetails();
  1333. chunk.state = cstate;
  1334. return chunk;
  1335. });
  1336. }
  1337. unshift(beforePos) {
  1338. if (!this.chunks.length || beforePos != null && this.from >= beforePos) return '';
  1339. const chunkShiftPos = beforePos != null ? beforePos - this.from : beforePos;
  1340. let ci = 0;
  1341. while (ci < this.chunks.length) {
  1342. const chunk = this.chunks[ci];
  1343. const shiftChar = chunk.unshift(chunkShiftPos);
  1344. if (chunk.toString()) {
  1345. // chunk still contains value
  1346. // but not shifted - means no more available chars to shift
  1347. if (!shiftChar) break;
  1348. ++ci;
  1349. } else {
  1350. // clean if chunk has no value
  1351. this.chunks.splice(ci, 1);
  1352. }
  1353. if (shiftChar) return shiftChar;
  1354. }
  1355. return '';
  1356. }
  1357. shift() {
  1358. if (!this.chunks.length) return '';
  1359. let ci = this.chunks.length - 1;
  1360. while (0 <= ci) {
  1361. const chunk = this.chunks[ci];
  1362. const shiftChar = chunk.shift();
  1363. if (chunk.toString()) {
  1364. // chunk still contains value
  1365. // but not shifted - means no more available chars to shift
  1366. if (!shiftChar) break;
  1367. --ci;
  1368. } else {
  1369. // clean if chunk has no value
  1370. this.chunks.splice(ci, 1);
  1371. }
  1372. if (shiftChar) return shiftChar;
  1373. }
  1374. return '';
  1375. }
  1376. }
  1377. class PatternCursor {
  1378. constructor(masked, pos) {
  1379. this.masked = masked;
  1380. this._log = [];
  1381. const {
  1382. offset,
  1383. index
  1384. } = masked._mapPosToBlock(pos) || (pos < 0 ?
  1385. // first
  1386. {
  1387. index: 0,
  1388. offset: 0
  1389. } :
  1390. // last
  1391. {
  1392. index: this.masked._blocks.length,
  1393. offset: 0
  1394. });
  1395. this.offset = offset;
  1396. this.index = index;
  1397. this.ok = false;
  1398. }
  1399. get block() {
  1400. return this.masked._blocks[this.index];
  1401. }
  1402. get pos() {
  1403. return this.masked._blockStartPos(this.index) + this.offset;
  1404. }
  1405. get state() {
  1406. return {
  1407. index: this.index,
  1408. offset: this.offset,
  1409. ok: this.ok
  1410. };
  1411. }
  1412. set state(s) {
  1413. Object.assign(this, s);
  1414. }
  1415. pushState() {
  1416. this._log.push(this.state);
  1417. }
  1418. popState() {
  1419. const s = this._log.pop();
  1420. if (s) this.state = s;
  1421. return s;
  1422. }
  1423. bindBlock() {
  1424. if (this.block) return;
  1425. if (this.index < 0) {
  1426. this.index = 0;
  1427. this.offset = 0;
  1428. }
  1429. if (this.index >= this.masked._blocks.length) {
  1430. this.index = this.masked._blocks.length - 1;
  1431. this.offset = this.block.displayValue.length; // TODO this is stupid type error, `block` depends on index that was changed above
  1432. }
  1433. }
  1434. _pushLeft(fn) {
  1435. this.pushState();
  1436. for (this.bindBlock(); 0 <= this.index; --this.index, this.offset = ((_this$block = this.block) == null ? void 0 : _this$block.displayValue.length) || 0) {
  1437. var _this$block;
  1438. if (fn()) return this.ok = true;
  1439. }
  1440. return this.ok = false;
  1441. }
  1442. _pushRight(fn) {
  1443. this.pushState();
  1444. for (this.bindBlock(); this.index < this.masked._blocks.length; ++this.index, this.offset = 0) {
  1445. if (fn()) return this.ok = true;
  1446. }
  1447. return this.ok = false;
  1448. }
  1449. pushLeftBeforeFilled() {
  1450. return this._pushLeft(() => {
  1451. if (this.block.isFixed || !this.block.value) return;
  1452. this.offset = this.block.nearestInputPos(this.offset, DIRECTION.FORCE_LEFT);
  1453. if (this.offset !== 0) return true;
  1454. });
  1455. }
  1456. pushLeftBeforeInput() {
  1457. // cases:
  1458. // filled input: 00|
  1459. // optional empty input: 00[]|
  1460. // nested block: XX<[]>|
  1461. return this._pushLeft(() => {
  1462. if (this.block.isFixed) return;
  1463. this.offset = this.block.nearestInputPos(this.offset, DIRECTION.LEFT);
  1464. return true;
  1465. });
  1466. }
  1467. pushLeftBeforeRequired() {
  1468. return this._pushLeft(() => {
  1469. if (this.block.isFixed || this.block.isOptional && !this.block.value) return;
  1470. this.offset = this.block.nearestInputPos(this.offset, DIRECTION.LEFT);
  1471. return true;
  1472. });
  1473. }
  1474. pushRightBeforeFilled() {
  1475. return this._pushRight(() => {
  1476. if (this.block.isFixed || !this.block.value) return;
  1477. this.offset = this.block.nearestInputPos(this.offset, DIRECTION.FORCE_RIGHT);
  1478. if (this.offset !== this.block.value.length) return true;
  1479. });
  1480. }
  1481. pushRightBeforeInput() {
  1482. return this._pushRight(() => {
  1483. if (this.block.isFixed) return;
  1484. // const o = this.offset;
  1485. this.offset = this.block.nearestInputPos(this.offset, DIRECTION.NONE);
  1486. // HACK cases like (STILL DOES NOT WORK FOR NESTED)
  1487. // aa|X
  1488. // aa<X|[]>X_ - this will not work
  1489. // if (o && o === this.offset && this.block instanceof PatternInputDefinition) continue;
  1490. return true;
  1491. });
  1492. }
  1493. pushRightBeforeRequired() {
  1494. return this._pushRight(() => {
  1495. if (this.block.isFixed || this.block.isOptional && !this.block.value) return;
  1496. // TODO check |[*]XX_
  1497. this.offset = this.block.nearestInputPos(this.offset, DIRECTION.NONE);
  1498. return true;
  1499. });
  1500. }
  1501. }
  1502. class PatternFixedDefinition {
  1503. /** */
  1504. /** */
  1505. /** */
  1506. /** */
  1507. /** */
  1508. /** */
  1509. constructor(opts) {
  1510. Object.assign(this, opts);
  1511. this._value = '';
  1512. this.isFixed = true;
  1513. }
  1514. get value() {
  1515. return this._value;
  1516. }
  1517. get unmaskedValue() {
  1518. return this.isUnmasking ? this.value : '';
  1519. }
  1520. get rawInputValue() {
  1521. return this._isRawInput ? this.value : '';
  1522. }
  1523. get displayValue() {
  1524. return this.value;
  1525. }
  1526. reset() {
  1527. this._isRawInput = false;
  1528. this._value = '';
  1529. }
  1530. remove(fromPos, toPos) {
  1531. if (fromPos === void 0) {
  1532. fromPos = 0;
  1533. }
  1534. if (toPos === void 0) {
  1535. toPos = this._value.length;
  1536. }
  1537. this._value = this._value.slice(0, fromPos) + this._value.slice(toPos);
  1538. if (!this._value) this._isRawInput = false;
  1539. return new ChangeDetails();
  1540. }
  1541. nearestInputPos(cursorPos, direction) {
  1542. if (direction === void 0) {
  1543. direction = DIRECTION.NONE;
  1544. }
  1545. const minPos = 0;
  1546. const maxPos = this._value.length;
  1547. switch (direction) {
  1548. case DIRECTION.LEFT:
  1549. case DIRECTION.FORCE_LEFT:
  1550. return minPos;
  1551. case DIRECTION.NONE:
  1552. case DIRECTION.RIGHT:
  1553. case DIRECTION.FORCE_RIGHT:
  1554. default:
  1555. return maxPos;
  1556. }
  1557. }
  1558. totalInputPositions(fromPos, toPos) {
  1559. if (fromPos === void 0) {
  1560. fromPos = 0;
  1561. }
  1562. if (toPos === void 0) {
  1563. toPos = this._value.length;
  1564. }
  1565. return this._isRawInput ? toPos - fromPos : 0;
  1566. }
  1567. extractInput(fromPos, toPos, flags) {
  1568. if (fromPos === void 0) {
  1569. fromPos = 0;
  1570. }
  1571. if (toPos === void 0) {
  1572. toPos = this._value.length;
  1573. }
  1574. if (flags === void 0) {
  1575. flags = {};
  1576. }
  1577. return flags.raw && this._isRawInput && this._value.slice(fromPos, toPos) || '';
  1578. }
  1579. get isComplete() {
  1580. return true;
  1581. }
  1582. get isFilled() {
  1583. return Boolean(this._value);
  1584. }
  1585. _appendChar(ch, flags) {
  1586. if (flags === void 0) {
  1587. flags = {};
  1588. }
  1589. if (this.isFilled) return new ChangeDetails();
  1590. const appendEager = this.eager === true || this.eager === 'append';
  1591. const appended = this.char === ch;
  1592. const isResolved = appended && (this.isUnmasking || flags.input || flags.raw) && (!flags.raw || !appendEager) && !flags.tail;
  1593. const details = new ChangeDetails({
  1594. inserted: this.char,
  1595. rawInserted: isResolved ? this.char : ''
  1596. });
  1597. this._value = this.char;
  1598. this._isRawInput = isResolved && (flags.raw || flags.input);
  1599. return details;
  1600. }
  1601. _appendEager() {
  1602. return this._appendChar(this.char, {
  1603. tail: true
  1604. });
  1605. }
  1606. _appendPlaceholder() {
  1607. const details = new ChangeDetails();
  1608. if (this.isFilled) return details;
  1609. this._value = details.inserted = this.char;
  1610. return details;
  1611. }
  1612. extractTail() {
  1613. return new ContinuousTailDetails('');
  1614. }
  1615. appendTail(tail) {
  1616. if (isString(tail)) tail = new ContinuousTailDetails(String(tail));
  1617. return tail.appendTo(this);
  1618. }
  1619. append(str, flags, tail) {
  1620. const details = this._appendChar(str[0], flags);
  1621. if (tail != null) {
  1622. details.tailShift += this.appendTail(tail).tailShift;
  1623. }
  1624. return details;
  1625. }
  1626. doCommit() {}
  1627. get state() {
  1628. return {
  1629. _value: this._value,
  1630. _rawInputValue: this.rawInputValue
  1631. };
  1632. }
  1633. set state(state) {
  1634. this._value = state._value;
  1635. this._isRawInput = Boolean(state._rawInputValue);
  1636. }
  1637. pad(flags) {
  1638. return this._appendPlaceholder();
  1639. }
  1640. }
  1641. class PatternInputDefinition {
  1642. /** */
  1643. /** */
  1644. /** */
  1645. /** */
  1646. /** */
  1647. /** */
  1648. /** */
  1649. /** */
  1650. constructor(opts) {
  1651. const {
  1652. parent,
  1653. isOptional,
  1654. placeholderChar,
  1655. displayChar,
  1656. lazy,
  1657. eager,
  1658. ...maskOpts
  1659. } = opts;
  1660. this.masked = createMask(maskOpts);
  1661. Object.assign(this, {
  1662. parent,
  1663. isOptional,
  1664. placeholderChar,
  1665. displayChar,
  1666. lazy,
  1667. eager
  1668. });
  1669. }
  1670. reset() {
  1671. this.isFilled = false;
  1672. this.masked.reset();
  1673. }
  1674. remove(fromPos, toPos) {
  1675. if (fromPos === void 0) {
  1676. fromPos = 0;
  1677. }
  1678. if (toPos === void 0) {
  1679. toPos = this.value.length;
  1680. }
  1681. if (fromPos === 0 && toPos >= 1) {
  1682. this.isFilled = false;
  1683. return this.masked.remove(fromPos, toPos);
  1684. }
  1685. return new ChangeDetails();
  1686. }
  1687. get value() {
  1688. return this.masked.value || (this.isFilled && !this.isOptional ? this.placeholderChar : '');
  1689. }
  1690. get unmaskedValue() {
  1691. return this.masked.unmaskedValue;
  1692. }
  1693. get rawInputValue() {
  1694. return this.masked.rawInputValue;
  1695. }
  1696. get displayValue() {
  1697. return this.masked.value && this.displayChar || this.value;
  1698. }
  1699. get isComplete() {
  1700. return Boolean(this.masked.value) || this.isOptional;
  1701. }
  1702. _appendChar(ch, flags) {
  1703. if (flags === void 0) {
  1704. flags = {};
  1705. }
  1706. if (this.isFilled) return new ChangeDetails();
  1707. const state = this.masked.state;
  1708. // simulate input
  1709. let details = this.masked._appendChar(ch, this.currentMaskFlags(flags));
  1710. if (details.inserted && this.doValidate(flags) === false) {
  1711. details = new ChangeDetails();
  1712. this.masked.state = state;
  1713. }
  1714. if (!details.inserted && !this.isOptional && !this.lazy && !flags.input) {
  1715. details.inserted = this.placeholderChar;
  1716. }
  1717. details.skip = !details.inserted && !this.isOptional;
  1718. this.isFilled = Boolean(details.inserted);
  1719. return details;
  1720. }
  1721. append(str, flags, tail) {
  1722. // TODO probably should be done via _appendChar
  1723. return this.masked.append(str, this.currentMaskFlags(flags), tail);
  1724. }
  1725. _appendPlaceholder() {
  1726. if (this.isFilled || this.isOptional) return new ChangeDetails();
  1727. this.isFilled = true;
  1728. return new ChangeDetails({
  1729. inserted: this.placeholderChar
  1730. });
  1731. }
  1732. _appendEager() {
  1733. return new ChangeDetails();
  1734. }
  1735. extractTail(fromPos, toPos) {
  1736. return this.masked.extractTail(fromPos, toPos);
  1737. }
  1738. appendTail(tail) {
  1739. return this.masked.appendTail(tail);
  1740. }
  1741. extractInput(fromPos, toPos, flags) {
  1742. if (fromPos === void 0) {
  1743. fromPos = 0;
  1744. }
  1745. if (toPos === void 0) {
  1746. toPos = this.value.length;
  1747. }
  1748. return this.masked.extractInput(fromPos, toPos, flags);
  1749. }
  1750. nearestInputPos(cursorPos, direction) {
  1751. if (direction === void 0) {
  1752. direction = DIRECTION.NONE;
  1753. }
  1754. const minPos = 0;
  1755. const maxPos = this.value.length;
  1756. const boundPos = Math.min(Math.max(cursorPos, minPos), maxPos);
  1757. switch (direction) {
  1758. case DIRECTION.LEFT:
  1759. case DIRECTION.FORCE_LEFT:
  1760. return this.isComplete ? boundPos : minPos;
  1761. case DIRECTION.RIGHT:
  1762. case DIRECTION.FORCE_RIGHT:
  1763. return this.isComplete ? boundPos : maxPos;
  1764. case DIRECTION.NONE:
  1765. default:
  1766. return boundPos;
  1767. }
  1768. }
  1769. totalInputPositions(fromPos, toPos) {
  1770. if (fromPos === void 0) {
  1771. fromPos = 0;
  1772. }
  1773. if (toPos === void 0) {
  1774. toPos = this.value.length;
  1775. }
  1776. return this.value.slice(fromPos, toPos).length;
  1777. }
  1778. doValidate(flags) {
  1779. return this.masked.doValidate(this.currentMaskFlags(flags)) && (!this.parent || this.parent.doValidate(this.currentMaskFlags(flags)));
  1780. }
  1781. doCommit() {
  1782. this.masked.doCommit();
  1783. }
  1784. get state() {
  1785. return {
  1786. _value: this.value,
  1787. _rawInputValue: this.rawInputValue,
  1788. masked: this.masked.state,
  1789. isFilled: this.isFilled
  1790. };
  1791. }
  1792. set state(state) {
  1793. this.masked.state = state.masked;
  1794. this.isFilled = state.isFilled;
  1795. }
  1796. currentMaskFlags(flags) {
  1797. var _flags$_beforeTailSta;
  1798. return {
  1799. ...flags,
  1800. _beforeTailState: (flags == null || (_flags$_beforeTailSta = flags._beforeTailState) == null ? void 0 : _flags$_beforeTailSta.masked) || (flags == null ? void 0 : flags._beforeTailState)
  1801. };
  1802. }
  1803. pad(flags) {
  1804. return new ChangeDetails();
  1805. }
  1806. }
  1807. PatternInputDefinition.DEFAULT_DEFINITIONS = {
  1808. '0': /\d/,
  1809. 'a': /[\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/,
  1810. // http://stackoverflow.com/a/22075070
  1811. '*': /./
  1812. };
  1813. /** Masking by RegExp */
  1814. class MaskedRegExp extends Masked {
  1815. /** */
  1816. /** Enable characters overwriting */
  1817. /** */
  1818. /** */
  1819. /** */
  1820. updateOptions(opts) {
  1821. super.updateOptions(opts);
  1822. }
  1823. _update(opts) {
  1824. const mask = opts.mask;
  1825. if (mask) opts.validate = value => value.search(mask) >= 0;
  1826. super._update(opts);
  1827. }
  1828. }
  1829. IMask.MaskedRegExp = MaskedRegExp;
  1830. /** Pattern mask */
  1831. class MaskedPattern extends Masked {
  1832. /** */
  1833. /** */
  1834. /** Single char for empty input */
  1835. /** Single char for filled input */
  1836. /** Show placeholder only when needed */
  1837. /** Enable characters overwriting */
  1838. /** */
  1839. /** */
  1840. /** */
  1841. constructor(opts) {
  1842. super({
  1843. ...MaskedPattern.DEFAULTS,
  1844. ...opts,
  1845. definitions: Object.assign({}, PatternInputDefinition.DEFAULT_DEFINITIONS, opts == null ? void 0 : opts.definitions)
  1846. });
  1847. }
  1848. updateOptions(opts) {
  1849. super.updateOptions(opts);
  1850. }
  1851. _update(opts) {
  1852. opts.definitions = Object.assign({}, this.definitions, opts.definitions);
  1853. super._update(opts);
  1854. this._rebuildMask();
  1855. }
  1856. _rebuildMask() {
  1857. const defs = this.definitions;
  1858. this._blocks = [];
  1859. this.exposeBlock = undefined;
  1860. this._stops = [];
  1861. this._maskedBlocks = {};
  1862. const pattern = this.mask;
  1863. if (!pattern || !defs) return;
  1864. let unmaskingBlock = false;
  1865. let optionalBlock = false;
  1866. for (let i = 0; i < pattern.length; ++i) {
  1867. if (this.blocks) {
  1868. const p = pattern.slice(i);
  1869. const bNames = Object.keys(this.blocks).filter(bName => p.indexOf(bName) === 0);
  1870. // order by key length
  1871. bNames.sort((a, b) => b.length - a.length);
  1872. // use block name with max length
  1873. const bName = bNames[0];
  1874. if (bName) {
  1875. const {
  1876. expose,
  1877. repeat,
  1878. ...bOpts
  1879. } = normalizeOpts(this.blocks[bName]); // TODO type Opts<Arg & Extra>
  1880. const blockOpts = {
  1881. lazy: this.lazy,
  1882. eager: this.eager,
  1883. placeholderChar: this.placeholderChar,
  1884. displayChar: this.displayChar,
  1885. overwrite: this.overwrite,
  1886. autofix: this.autofix,
  1887. ...bOpts,
  1888. repeat,
  1889. parent: this
  1890. };
  1891. const maskedBlock = repeat != null ? new IMask.RepeatBlock(blockOpts /* TODO */) : createMask(blockOpts);
  1892. if (maskedBlock) {
  1893. this._blocks.push(maskedBlock);
  1894. if (expose) this.exposeBlock = maskedBlock;
  1895. // store block index
  1896. if (!this._maskedBlocks[bName]) this._maskedBlocks[bName] = [];
  1897. this._maskedBlocks[bName].push(this._blocks.length - 1);
  1898. }
  1899. i += bName.length - 1;
  1900. continue;
  1901. }
  1902. }
  1903. let char = pattern[i];
  1904. let isInput = (char in defs);
  1905. if (char === MaskedPattern.STOP_CHAR) {
  1906. this._stops.push(this._blocks.length);
  1907. continue;
  1908. }
  1909. if (char === '{' || char === '}') {
  1910. unmaskingBlock = !unmaskingBlock;
  1911. continue;
  1912. }
  1913. if (char === '[' || char === ']') {
  1914. optionalBlock = !optionalBlock;
  1915. continue;
  1916. }
  1917. if (char === MaskedPattern.ESCAPE_CHAR) {
  1918. ++i;
  1919. char = pattern[i];
  1920. if (!char) break;
  1921. isInput = false;
  1922. }
  1923. const def = isInput ? new PatternInputDefinition({
  1924. isOptional: optionalBlock,
  1925. lazy: this.lazy,
  1926. eager: this.eager,
  1927. placeholderChar: this.placeholderChar,
  1928. displayChar: this.displayChar,
  1929. ...normalizeOpts(defs[char]),
  1930. parent: this
  1931. }) : new PatternFixedDefinition({
  1932. char,
  1933. eager: this.eager,
  1934. isUnmasking: unmaskingBlock
  1935. });
  1936. this._blocks.push(def);
  1937. }
  1938. }
  1939. get state() {
  1940. return {
  1941. ...super.state,
  1942. _blocks: this._blocks.map(b => b.state)
  1943. };
  1944. }
  1945. set state(state) {
  1946. if (!state) {
  1947. this.reset();
  1948. return;
  1949. }
  1950. const {
  1951. _blocks,
  1952. ...maskedState
  1953. } = state;
  1954. this._blocks.forEach((b, bi) => b.state = _blocks[bi]);
  1955. super.state = maskedState;
  1956. }
  1957. reset() {
  1958. super.reset();
  1959. this._blocks.forEach(b => b.reset());
  1960. }
  1961. get isComplete() {
  1962. return this.exposeBlock ? this.exposeBlock.isComplete : this._blocks.every(b => b.isComplete);
  1963. }
  1964. get isFilled() {
  1965. return this._blocks.every(b => b.isFilled);
  1966. }
  1967. get isFixed() {
  1968. return this._blocks.every(b => b.isFixed);
  1969. }
  1970. get isOptional() {
  1971. return this._blocks.every(b => b.isOptional);
  1972. }
  1973. doCommit() {
  1974. this._blocks.forEach(b => b.doCommit());
  1975. super.doCommit();
  1976. }
  1977. get unmaskedValue() {
  1978. return this.exposeBlock ? this.exposeBlock.unmaskedValue : this._blocks.reduce((str, b) => str += b.unmaskedValue, '');
  1979. }
  1980. set unmaskedValue(unmaskedValue) {
  1981. if (this.exposeBlock) {
  1982. const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
  1983. this.exposeBlock.unmaskedValue = unmaskedValue;
  1984. this.appendTail(tail);
  1985. this.doCommit();
  1986. } else super.unmaskedValue = unmaskedValue;
  1987. }
  1988. get value() {
  1989. return this.exposeBlock ? this.exposeBlock.value :
  1990. // TODO return _value when not in change?
  1991. this._blocks.reduce((str, b) => str += b.value, '');
  1992. }
  1993. set value(value) {
  1994. if (this.exposeBlock) {
  1995. const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
  1996. this.exposeBlock.value = value;
  1997. this.appendTail(tail);
  1998. this.doCommit();
  1999. } else super.value = value;
  2000. }
  2001. get typedValue() {
  2002. return this.exposeBlock ? this.exposeBlock.typedValue : super.typedValue;
  2003. }
  2004. set typedValue(value) {
  2005. if (this.exposeBlock) {
  2006. const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
  2007. this.exposeBlock.typedValue = value;
  2008. this.appendTail(tail);
  2009. this.doCommit();
  2010. } else super.typedValue = value;
  2011. }
  2012. get displayValue() {
  2013. return this._blocks.reduce((str, b) => str += b.displayValue, '');
  2014. }
  2015. appendTail(tail) {
  2016. return super.appendTail(tail).aggregate(this._appendPlaceholder());
  2017. }
  2018. _appendEager() {
  2019. var _this$_mapPosToBlock;
  2020. const details = new ChangeDetails();
  2021. let startBlockIndex = (_this$_mapPosToBlock = this._mapPosToBlock(this.displayValue.length)) == null ? void 0 : _this$_mapPosToBlock.index;
  2022. if (startBlockIndex == null) return details;
  2023. // TODO test if it works for nested pattern masks
  2024. if (this._blocks[startBlockIndex].isFilled) ++startBlockIndex;
  2025. for (let bi = startBlockIndex; bi < this._blocks.length; ++bi) {
  2026. const d = this._blocks[bi]._appendEager();
  2027. if (!d.inserted) break;
  2028. details.aggregate(d);
  2029. }
  2030. return details;
  2031. }
  2032. _appendCharRaw(ch, flags) {
  2033. if (flags === void 0) {
  2034. flags = {};
  2035. }
  2036. const blockIter = this._mapPosToBlock(this.displayValue.length);
  2037. const details = new ChangeDetails();
  2038. if (!blockIter) return details;
  2039. for (let bi = blockIter.index, block; block = this._blocks[bi]; ++bi) {
  2040. var _flags$_beforeTailSta;
  2041. const blockDetails = block._appendChar(ch, {
  2042. ...flags,
  2043. _beforeTailState: (_flags$_beforeTailSta = flags._beforeTailState) == null || (_flags$_beforeTailSta = _flags$_beforeTailSta._blocks) == null ? void 0 : _flags$_beforeTailSta[bi]
  2044. });
  2045. details.aggregate(blockDetails);
  2046. if (blockDetails.consumed) break; // go next char
  2047. }
  2048. return details;
  2049. }
  2050. extractTail(fromPos, toPos) {
  2051. if (fromPos === void 0) {
  2052. fromPos = 0;
  2053. }
  2054. if (toPos === void 0) {
  2055. toPos = this.displayValue.length;
  2056. }
  2057. const chunkTail = new ChunksTailDetails();
  2058. if (fromPos === toPos) return chunkTail;
  2059. this._forEachBlocksInRange(fromPos, toPos, (b, bi, bFromPos, bToPos) => {
  2060. const blockChunk = b.extractTail(bFromPos, bToPos);
  2061. blockChunk.stop = this._findStopBefore(bi);
  2062. blockChunk.from = this._blockStartPos(bi);
  2063. if (blockChunk instanceof ChunksTailDetails) blockChunk.blockIndex = bi;
  2064. chunkTail.extend(blockChunk);
  2065. });
  2066. return chunkTail;
  2067. }
  2068. extractInput(fromPos, toPos, flags) {
  2069. if (fromPos === void 0) {
  2070. fromPos = 0;
  2071. }
  2072. if (toPos === void 0) {
  2073. toPos = this.displayValue.length;
  2074. }
  2075. if (flags === void 0) {
  2076. flags = {};
  2077. }
  2078. if (fromPos === toPos) return '';
  2079. let input = '';
  2080. this._forEachBlocksInRange(fromPos, toPos, (b, _, fromPos, toPos) => {
  2081. input += b.extractInput(fromPos, toPos, flags);
  2082. });
  2083. return input;
  2084. }
  2085. _findStopBefore(blockIndex) {
  2086. let stopBefore;
  2087. for (let si = 0; si < this._stops.length; ++si) {
  2088. const stop = this._stops[si];
  2089. if (stop <= blockIndex) stopBefore = stop;else break;
  2090. }
  2091. return stopBefore;
  2092. }
  2093. /** Appends placeholder depending on laziness */
  2094. _appendPlaceholder(toBlockIndex) {
  2095. const details = new ChangeDetails();
  2096. if (this.lazy && toBlockIndex == null) return details;
  2097. const startBlockIter = this._mapPosToBlock(this.displayValue.length);
  2098. if (!startBlockIter) return details;
  2099. const startBlockIndex = startBlockIter.index;
  2100. const endBlockIndex = toBlockIndex != null ? toBlockIndex : this._blocks.length;
  2101. this._blocks.slice(startBlockIndex, endBlockIndex).forEach(b => {
  2102. if (!b.lazy || toBlockIndex != null) {
  2103. var _blocks2;
  2104. details.aggregate(b._appendPlaceholder((_blocks2 = b._blocks) == null ? void 0 : _blocks2.length));
  2105. }
  2106. });
  2107. return details;
  2108. }
  2109. /** Finds block in pos */
  2110. _mapPosToBlock(pos) {
  2111. let accVal = '';
  2112. for (let bi = 0; bi < this._blocks.length; ++bi) {
  2113. const block = this._blocks[bi];
  2114. const blockStartPos = accVal.length;
  2115. accVal += block.displayValue;
  2116. if (pos <= accVal.length) {
  2117. return {
  2118. index: bi,
  2119. offset: pos - blockStartPos
  2120. };
  2121. }
  2122. }
  2123. }
  2124. _blockStartPos(blockIndex) {
  2125. return this._blocks.slice(0, blockIndex).reduce((pos, b) => pos += b.displayValue.length, 0);
  2126. }
  2127. _forEachBlocksInRange(fromPos, toPos, fn) {
  2128. if (toPos === void 0) {
  2129. toPos = this.displayValue.length;
  2130. }
  2131. const fromBlockIter = this._mapPosToBlock(fromPos);
  2132. if (fromBlockIter) {
  2133. const toBlockIter = this._mapPosToBlock(toPos);
  2134. // process first block
  2135. const isSameBlock = toBlockIter && fromBlockIter.index === toBlockIter.index;
  2136. const fromBlockStartPos = fromBlockIter.offset;
  2137. const fromBlockEndPos = toBlockIter && isSameBlock ? toBlockIter.offset : this._blocks[fromBlockIter.index].displayValue.length;
  2138. fn(this._blocks[fromBlockIter.index], fromBlockIter.index, fromBlockStartPos, fromBlockEndPos);
  2139. if (toBlockIter && !isSameBlock) {
  2140. // process intermediate blocks
  2141. for (let bi = fromBlockIter.index + 1; bi < toBlockIter.index; ++bi) {
  2142. fn(this._blocks[bi], bi, 0, this._blocks[bi].displayValue.length);
  2143. }
  2144. // process last block
  2145. fn(this._blocks[toBlockIter.index], toBlockIter.index, 0, toBlockIter.offset);
  2146. }
  2147. }
  2148. }
  2149. remove(fromPos, toPos) {
  2150. if (fromPos === void 0) {
  2151. fromPos = 0;
  2152. }
  2153. if (toPos === void 0) {
  2154. toPos = this.displayValue.length;
  2155. }
  2156. const removeDetails = super.remove(fromPos, toPos);
  2157. this._forEachBlocksInRange(fromPos, toPos, (b, _, bFromPos, bToPos) => {
  2158. removeDetails.aggregate(b.remove(bFromPos, bToPos));
  2159. });
  2160. return removeDetails;
  2161. }
  2162. nearestInputPos(cursorPos, direction) {
  2163. if (direction === void 0) {
  2164. direction = DIRECTION.NONE;
  2165. }
  2166. if (!this._blocks.length) return 0;
  2167. const cursor = new PatternCursor(this, cursorPos);
  2168. if (direction === DIRECTION.NONE) {
  2169. // -------------------------------------------------
  2170. // NONE should only go out from fixed to the right!
  2171. // -------------------------------------------------
  2172. if (cursor.pushRightBeforeInput()) return cursor.pos;
  2173. cursor.popState();
  2174. if (cursor.pushLeftBeforeInput()) return cursor.pos;
  2175. return this.displayValue.length;
  2176. }
  2177. // FORCE is only about a|* otherwise is 0
  2178. if (direction === DIRECTION.LEFT || direction === DIRECTION.FORCE_LEFT) {
  2179. // try to break fast when *|a
  2180. if (direction === DIRECTION.LEFT) {
  2181. cursor.pushRightBeforeFilled();
  2182. if (cursor.ok && cursor.pos === cursorPos) return cursorPos;
  2183. cursor.popState();
  2184. }
  2185. // forward flow
  2186. cursor.pushLeftBeforeInput();
  2187. cursor.pushLeftBeforeRequired();
  2188. cursor.pushLeftBeforeFilled();
  2189. // backward flow
  2190. if (direction === DIRECTION.LEFT) {
  2191. cursor.pushRightBeforeInput();
  2192. cursor.pushRightBeforeRequired();
  2193. if (cursor.ok && cursor.pos <= cursorPos) return cursor.pos;
  2194. cursor.popState();
  2195. if (cursor.ok && cursor.pos <= cursorPos) return cursor.pos;
  2196. cursor.popState();
  2197. }
  2198. if (cursor.ok) return cursor.pos;
  2199. if (direction === DIRECTION.FORCE_LEFT) return 0;
  2200. cursor.popState();
  2201. if (cursor.ok) return cursor.pos;
  2202. cursor.popState();
  2203. if (cursor.ok) return cursor.pos;
  2204. return 0;
  2205. }
  2206. if (direction === DIRECTION.RIGHT || direction === DIRECTION.FORCE_RIGHT) {
  2207. // forward flow
  2208. cursor.pushRightBeforeInput();
  2209. cursor.pushRightBeforeRequired();
  2210. if (cursor.pushRightBeforeFilled()) return cursor.pos;
  2211. if (direction === DIRECTION.FORCE_RIGHT) return this.displayValue.length;
  2212. // backward flow
  2213. cursor.popState();
  2214. if (cursor.ok) return cursor.pos;
  2215. cursor.popState();
  2216. if (cursor.ok) return cursor.pos;
  2217. return this.nearestInputPos(cursorPos, DIRECTION.LEFT);
  2218. }
  2219. return cursorPos;
  2220. }
  2221. totalInputPositions(fromPos, toPos) {
  2222. if (fromPos === void 0) {
  2223. fromPos = 0;
  2224. }
  2225. if (toPos === void 0) {
  2226. toPos = this.displayValue.length;
  2227. }
  2228. let total = 0;
  2229. this._forEachBlocksInRange(fromPos, toPos, (b, _, bFromPos, bToPos) => {
  2230. total += b.totalInputPositions(bFromPos, bToPos);
  2231. });
  2232. return total;
  2233. }
  2234. /** Get block by name */
  2235. maskedBlock(name) {
  2236. return this.maskedBlocks(name)[0];
  2237. }
  2238. /** Get all blocks by name */
  2239. maskedBlocks(name) {
  2240. const indices = this._maskedBlocks[name];
  2241. if (!indices) return [];
  2242. return indices.map(gi => this._blocks[gi]);
  2243. }
  2244. pad(flags) {
  2245. const details = new ChangeDetails();
  2246. this._forEachBlocksInRange(0, this.displayValue.length, b => details.aggregate(b.pad(flags)));
  2247. return details;
  2248. }
  2249. }
  2250. MaskedPattern.DEFAULTS = {
  2251. ...Masked.DEFAULTS,
  2252. lazy: true,
  2253. placeholderChar: '_'
  2254. };
  2255. MaskedPattern.STOP_CHAR = '`';
  2256. MaskedPattern.ESCAPE_CHAR = '\\';
  2257. MaskedPattern.InputDefinition = PatternInputDefinition;
  2258. MaskedPattern.FixedDefinition = PatternFixedDefinition;
  2259. IMask.MaskedPattern = MaskedPattern;
  2260. /** Pattern which accepts ranges */
  2261. class MaskedRange extends MaskedPattern {
  2262. /**
  2263. Optionally sets max length of pattern.
  2264. Used when pattern length is longer then `to` param length. Pads zeros at start in this case.
  2265. */
  2266. /** Min bound */
  2267. /** Max bound */
  2268. get _matchFrom() {
  2269. return this.maxLength - String(this.from).length;
  2270. }
  2271. constructor(opts) {
  2272. super(opts); // mask will be created in _update
  2273. }
  2274. updateOptions(opts) {
  2275. super.updateOptions(opts);
  2276. }
  2277. _update(opts) {
  2278. const {
  2279. to = this.to || 0,
  2280. from = this.from || 0,
  2281. maxLength = this.maxLength || 0,
  2282. autofix = this.autofix,
  2283. ...patternOpts
  2284. } = opts;
  2285. this.to = to;
  2286. this.from = from;
  2287. this.maxLength = Math.max(String(to).length, maxLength);
  2288. this.autofix = autofix;
  2289. const fromStr = String(this.from).padStart(this.maxLength, '0');
  2290. const toStr = String(this.to).padStart(this.maxLength, '0');
  2291. let sameCharsCount = 0;
  2292. while (sameCharsCount < toStr.length && toStr[sameCharsCount] === fromStr[sameCharsCount]) ++sameCharsCount;
  2293. patternOpts.mask = toStr.slice(0, sameCharsCount).replace(/0/g, '\\0') + '0'.repeat(this.maxLength - sameCharsCount);
  2294. super._update(patternOpts);
  2295. }
  2296. get isComplete() {
  2297. return super.isComplete && Boolean(this.value);
  2298. }
  2299. boundaries(str) {
  2300. let minstr = '';
  2301. let maxstr = '';
  2302. const [, placeholder, num] = str.match(/^(\D*)(\d*)(\D*)/) || [];
  2303. if (num) {
  2304. minstr = '0'.repeat(placeholder.length) + num;
  2305. maxstr = '9'.repeat(placeholder.length) + num;
  2306. }
  2307. minstr = minstr.padEnd(this.maxLength, '0');
  2308. maxstr = maxstr.padEnd(this.maxLength, '9');
  2309. return [minstr, maxstr];
  2310. }
  2311. doPrepareChar(ch, flags) {
  2312. if (flags === void 0) {
  2313. flags = {};
  2314. }
  2315. let details;
  2316. [ch, details] = super.doPrepareChar(ch.replace(/\D/g, ''), flags);
  2317. if (!ch) details.skip = !this.isComplete;
  2318. return [ch, details];
  2319. }
  2320. _appendCharRaw(ch, flags) {
  2321. if (flags === void 0) {
  2322. flags = {};
  2323. }
  2324. if (!this.autofix || this.value.length + 1 > this.maxLength) return super._appendCharRaw(ch, flags);
  2325. const fromStr = String(this.from).padStart(this.maxLength, '0');
  2326. const toStr = String(this.to).padStart(this.maxLength, '0');
  2327. const [minstr, maxstr] = this.boundaries(this.value + ch);
  2328. if (Number(maxstr) < this.from) return super._appendCharRaw(fromStr[this.value.length], flags);
  2329. if (Number(minstr) > this.to) {
  2330. if (!flags.tail && this.autofix === 'pad' && this.value.length + 1 < this.maxLength) {
  2331. return super._appendCharRaw(fromStr[this.value.length], flags).aggregate(this._appendCharRaw(ch, flags));
  2332. }
  2333. return super._appendCharRaw(toStr[this.value.length], flags);
  2334. }
  2335. return super._appendCharRaw(ch, flags);
  2336. }
  2337. doValidate(flags) {
  2338. const str = this.value;
  2339. const firstNonZero = str.search(/[^0]/);
  2340. if (firstNonZero === -1 && str.length <= this._matchFrom) return true;
  2341. const [minstr, maxstr] = this.boundaries(str);
  2342. return this.from <= Number(maxstr) && Number(minstr) <= this.to && super.doValidate(flags);
  2343. }
  2344. pad(flags) {
  2345. const details = new ChangeDetails();
  2346. if (this.value.length === this.maxLength) return details;
  2347. const value = this.value;
  2348. const padLength = this.maxLength - this.value.length;
  2349. if (padLength) {
  2350. this.reset();
  2351. for (let i = 0; i < padLength; ++i) {
  2352. details.aggregate(super._appendCharRaw('0', flags));
  2353. }
  2354. // append tail
  2355. value.split('').forEach(ch => this._appendCharRaw(ch));
  2356. }
  2357. return details;
  2358. }
  2359. }
  2360. IMask.MaskedRange = MaskedRange;
  2361. /** Date mask */
  2362. class MaskedDate extends MaskedPattern {
  2363. static extractPatternOptions(opts) {
  2364. const {
  2365. mask,
  2366. pattern,
  2367. ...patternOpts
  2368. } = opts;
  2369. return {
  2370. ...patternOpts,
  2371. mask: isString(mask) ? mask : pattern
  2372. };
  2373. }
  2374. /** Pattern mask for date according to {@link MaskedDate#format} */
  2375. /** Start date */
  2376. /** End date */
  2377. /** Format typed value to string */
  2378. /** Parse string to get typed value */
  2379. constructor(opts) {
  2380. super(MaskedDate.extractPatternOptions({
  2381. ...MaskedDate.DEFAULTS,
  2382. ...opts
  2383. }));
  2384. }
  2385. updateOptions(opts) {
  2386. super.updateOptions(opts);
  2387. }
  2388. _update(opts) {
  2389. const {
  2390. mask,
  2391. pattern,
  2392. blocks,
  2393. ...patternOpts
  2394. } = {
  2395. ...MaskedDate.DEFAULTS,
  2396. ...opts
  2397. };
  2398. const patternBlocks = Object.assign({}, MaskedDate.GET_DEFAULT_BLOCKS());
  2399. // adjust year block
  2400. if (opts.min) patternBlocks.Y.from = opts.min.getFullYear();
  2401. if (opts.max) patternBlocks.Y.to = opts.max.getFullYear();
  2402. if (opts.min && opts.max && patternBlocks.Y.from === patternBlocks.Y.to) {
  2403. patternBlocks.m.from = opts.min.getMonth() + 1;
  2404. patternBlocks.m.to = opts.max.getMonth() + 1;
  2405. if (patternBlocks.m.from === patternBlocks.m.to) {
  2406. patternBlocks.d.from = opts.min.getDate();
  2407. patternBlocks.d.to = opts.max.getDate();
  2408. }
  2409. }
  2410. Object.assign(patternBlocks, this.blocks, blocks);
  2411. super._update({
  2412. ...patternOpts,
  2413. mask: isString(mask) ? mask : pattern,
  2414. blocks: patternBlocks
  2415. });
  2416. }
  2417. doValidate(flags) {
  2418. const date = this.date;
  2419. return super.doValidate(flags) && (!this.isComplete || this.isDateExist(this.value) && date != null && (this.min == null || this.min <= date) && (this.max == null || date <= this.max));
  2420. }
  2421. /** Checks if date is exists */
  2422. isDateExist(str) {
  2423. return this.format(this.parse(str, this), this).indexOf(str) >= 0;
  2424. }
  2425. /** Parsed Date */
  2426. get date() {
  2427. return this.typedValue;
  2428. }
  2429. set date(date) {
  2430. this.typedValue = date;
  2431. }
  2432. get typedValue() {
  2433. return this.isComplete ? super.typedValue : null;
  2434. }
  2435. set typedValue(value) {
  2436. super.typedValue = value;
  2437. }
  2438. maskEquals(mask) {
  2439. return mask === Date || super.maskEquals(mask);
  2440. }
  2441. optionsIsChanged(opts) {
  2442. return super.optionsIsChanged(MaskedDate.extractPatternOptions(opts));
  2443. }
  2444. }
  2445. MaskedDate.GET_DEFAULT_BLOCKS = () => ({
  2446. d: {
  2447. mask: MaskedRange,
  2448. from: 1,
  2449. to: 31,
  2450. maxLength: 2
  2451. },
  2452. m: {
  2453. mask: MaskedRange,
  2454. from: 1,
  2455. to: 12,
  2456. maxLength: 2
  2457. },
  2458. Y: {
  2459. mask: MaskedRange,
  2460. from: 1900,
  2461. to: 9999
  2462. }
  2463. });
  2464. MaskedDate.DEFAULTS = {
  2465. ...MaskedPattern.DEFAULTS,
  2466. mask: Date,
  2467. pattern: 'd{.}`m{.}`Y',
  2468. format: (date, masked) => {
  2469. if (!date) return '';
  2470. const day = String(date.getDate()).padStart(2, '0');
  2471. const month = String(date.getMonth() + 1).padStart(2, '0');
  2472. const year = date.getFullYear();
  2473. return [day, month, year].join('.');
  2474. },
  2475. parse: (str, masked) => {
  2476. const [day, month, year] = str.split('.').map(Number);
  2477. return new Date(year, month - 1, day);
  2478. }
  2479. };
  2480. IMask.MaskedDate = MaskedDate;
  2481. /** Dynamic mask for choosing appropriate mask in run-time */
  2482. class MaskedDynamic extends Masked {
  2483. constructor(opts) {
  2484. super({
  2485. ...MaskedDynamic.DEFAULTS,
  2486. ...opts
  2487. });
  2488. this.currentMask = undefined;
  2489. }
  2490. updateOptions(opts) {
  2491. super.updateOptions(opts);
  2492. }
  2493. _update(opts) {
  2494. super._update(opts);
  2495. if ('mask' in opts) {
  2496. this.exposeMask = undefined;
  2497. // mask could be totally dynamic with only `dispatch` option
  2498. this.compiledMasks = Array.isArray(opts.mask) ? opts.mask.map(m => {
  2499. const {
  2500. expose,
  2501. ...maskOpts
  2502. } = normalizeOpts(m);
  2503. const masked = createMask({
  2504. overwrite: this._overwrite,
  2505. eager: this._eager,
  2506. skipInvalid: this._skipInvalid,
  2507. ...maskOpts
  2508. });
  2509. if (expose) this.exposeMask = masked;
  2510. return masked;
  2511. }) : [];
  2512. // this.currentMask = this.doDispatch(''); // probably not needed but lets see
  2513. }
  2514. }
  2515. _appendCharRaw(ch, flags) {
  2516. if (flags === void 0) {
  2517. flags = {};
  2518. }
  2519. const details = this._applyDispatch(ch, flags);
  2520. if (this.currentMask) {
  2521. details.aggregate(this.currentMask._appendChar(ch, this.currentMaskFlags(flags)));
  2522. }
  2523. return details;
  2524. }
  2525. _applyDispatch(appended, flags, tail) {
  2526. if (appended === void 0) {
  2527. appended = '';
  2528. }
  2529. if (flags === void 0) {
  2530. flags = {};
  2531. }
  2532. if (tail === void 0) {
  2533. tail = '';
  2534. }
  2535. const prevValueBeforeTail = flags.tail && flags._beforeTailState != null ? flags._beforeTailState._value : this.value;
  2536. const inputValue = this.rawInputValue;
  2537. const insertValue = flags.tail && flags._beforeTailState != null ? flags._beforeTailState._rawInputValue : inputValue;
  2538. const tailValue = inputValue.slice(insertValue.length);
  2539. const prevMask = this.currentMask;
  2540. const details = new ChangeDetails();
  2541. const prevMaskState = prevMask == null ? void 0 : prevMask.state;
  2542. // clone flags to prevent overwriting `_beforeTailState`
  2543. this.currentMask = this.doDispatch(appended, {
  2544. ...flags
  2545. }, tail);
  2546. // restore state after dispatch
  2547. if (this.currentMask) {
  2548. if (this.currentMask !== prevMask) {
  2549. // if mask changed reapply input
  2550. this.currentMask.reset();
  2551. if (insertValue) {
  2552. this.currentMask.append(insertValue, {
  2553. raw: true
  2554. });
  2555. details.tailShift = this.currentMask.value.length - prevValueBeforeTail.length;
  2556. }
  2557. if (tailValue) {
  2558. details.tailShift += this.currentMask.append(tailValue, {
  2559. raw: true,
  2560. tail: true
  2561. }).tailShift;
  2562. }
  2563. } else if (prevMaskState) {
  2564. // Dispatch can do something bad with state, so
  2565. // restore prev mask state
  2566. this.currentMask.state = prevMaskState;
  2567. }
  2568. }
  2569. return details;
  2570. }
  2571. _appendPlaceholder() {
  2572. const details = this._applyDispatch();
  2573. if (this.currentMask) {
  2574. details.aggregate(this.currentMask._appendPlaceholder());
  2575. }
  2576. return details;
  2577. }
  2578. _appendEager() {
  2579. const details = this._applyDispatch();
  2580. if (this.currentMask) {
  2581. details.aggregate(this.currentMask._appendEager());
  2582. }
  2583. return details;
  2584. }
  2585. appendTail(tail) {
  2586. const details = new ChangeDetails();
  2587. if (tail) details.aggregate(this._applyDispatch('', {}, tail));
  2588. return details.aggregate(this.currentMask ? this.currentMask.appendTail(tail) : super.appendTail(tail));
  2589. }
  2590. currentMaskFlags(flags) {
  2591. var _flags$_beforeTailSta, _flags$_beforeTailSta2;
  2592. return {
  2593. ...flags,
  2594. _beforeTailState: ((_flags$_beforeTailSta = flags._beforeTailState) == null ? void 0 : _flags$_beforeTailSta.currentMaskRef) === this.currentMask && ((_flags$_beforeTailSta2 = flags._beforeTailState) == null ? void 0 : _flags$_beforeTailSta2.currentMask) || flags._beforeTailState
  2595. };
  2596. }
  2597. doDispatch(appended, flags, tail) {
  2598. if (flags === void 0) {
  2599. flags = {};
  2600. }
  2601. if (tail === void 0) {
  2602. tail = '';
  2603. }
  2604. return this.dispatch(appended, this, flags, tail);
  2605. }
  2606. doValidate(flags) {
  2607. return super.doValidate(flags) && (!this.currentMask || this.currentMask.doValidate(this.currentMaskFlags(flags)));
  2608. }
  2609. doPrepare(str, flags) {
  2610. if (flags === void 0) {
  2611. flags = {};
  2612. }
  2613. let [s, details] = super.doPrepare(str, flags);
  2614. if (this.currentMask) {
  2615. let currentDetails;
  2616. [s, currentDetails] = super.doPrepare(s, this.currentMaskFlags(flags));
  2617. details = details.aggregate(currentDetails);
  2618. }
  2619. return [s, details];
  2620. }
  2621. doPrepareChar(str, flags) {
  2622. if (flags === void 0) {
  2623. flags = {};
  2624. }
  2625. let [s, details] = super.doPrepareChar(str, flags);
  2626. if (this.currentMask) {
  2627. let currentDetails;
  2628. [s, currentDetails] = super.doPrepareChar(s, this.currentMaskFlags(flags));
  2629. details = details.aggregate(currentDetails);
  2630. }
  2631. return [s, details];
  2632. }
  2633. reset() {
  2634. var _this$currentMask;
  2635. (_this$currentMask = this.currentMask) == null || _this$currentMask.reset();
  2636. this.compiledMasks.forEach(m => m.reset());
  2637. }
  2638. get value() {
  2639. return this.exposeMask ? this.exposeMask.value : this.currentMask ? this.currentMask.value : '';
  2640. }
  2641. set value(value) {
  2642. if (this.exposeMask) {
  2643. this.exposeMask.value = value;
  2644. this.currentMask = this.exposeMask;
  2645. this._applyDispatch();
  2646. } else super.value = value;
  2647. }
  2648. get unmaskedValue() {
  2649. return this.exposeMask ? this.exposeMask.unmaskedValue : this.currentMask ? this.currentMask.unmaskedValue : '';
  2650. }
  2651. set unmaskedValue(unmaskedValue) {
  2652. if (this.exposeMask) {
  2653. this.exposeMask.unmaskedValue = unmaskedValue;
  2654. this.currentMask = this.exposeMask;
  2655. this._applyDispatch();
  2656. } else super.unmaskedValue = unmaskedValue;
  2657. }
  2658. get typedValue() {
  2659. return this.exposeMask ? this.exposeMask.typedValue : this.currentMask ? this.currentMask.typedValue : '';
  2660. }
  2661. set typedValue(typedValue) {
  2662. if (this.exposeMask) {
  2663. this.exposeMask.typedValue = typedValue;
  2664. this.currentMask = this.exposeMask;
  2665. this._applyDispatch();
  2666. return;
  2667. }
  2668. let unmaskedValue = String(typedValue);
  2669. // double check it
  2670. if (this.currentMask) {
  2671. this.currentMask.typedValue = typedValue;
  2672. unmaskedValue = this.currentMask.unmaskedValue;
  2673. }
  2674. this.unmaskedValue = unmaskedValue;
  2675. }
  2676. get displayValue() {
  2677. return this.currentMask ? this.currentMask.displayValue : '';
  2678. }
  2679. get isComplete() {
  2680. var _this$currentMask2;
  2681. return Boolean((_this$currentMask2 = this.currentMask) == null ? void 0 : _this$currentMask2.isComplete);
  2682. }
  2683. get isFilled() {
  2684. var _this$currentMask3;
  2685. return Boolean((_this$currentMask3 = this.currentMask) == null ? void 0 : _this$currentMask3.isFilled);
  2686. }
  2687. remove(fromPos, toPos) {
  2688. const details = new ChangeDetails();
  2689. if (this.currentMask) {
  2690. details.aggregate(this.currentMask.remove(fromPos, toPos))
  2691. // update with dispatch
  2692. .aggregate(this._applyDispatch());
  2693. }
  2694. return details;
  2695. }
  2696. get state() {
  2697. var _this$currentMask4;
  2698. return {
  2699. ...super.state,
  2700. _rawInputValue: this.rawInputValue,
  2701. compiledMasks: this.compiledMasks.map(m => m.state),
  2702. currentMaskRef: this.currentMask,
  2703. currentMask: (_this$currentMask4 = this.currentMask) == null ? void 0 : _this$currentMask4.state
  2704. };
  2705. }
  2706. set state(state) {
  2707. const {
  2708. compiledMasks,
  2709. currentMaskRef,
  2710. currentMask,
  2711. ...maskedState
  2712. } = state;
  2713. if (compiledMasks) this.compiledMasks.forEach((m, mi) => m.state = compiledMasks[mi]);
  2714. if (currentMaskRef != null) {
  2715. this.currentMask = currentMaskRef;
  2716. this.currentMask.state = currentMask;
  2717. }
  2718. super.state = maskedState;
  2719. }
  2720. extractInput(fromPos, toPos, flags) {
  2721. return this.currentMask ? this.currentMask.extractInput(fromPos, toPos, flags) : '';
  2722. }
  2723. extractTail(fromPos, toPos) {
  2724. return this.currentMask ? this.currentMask.extractTail(fromPos, toPos) : super.extractTail(fromPos, toPos);
  2725. }
  2726. doCommit() {
  2727. if (this.currentMask) this.currentMask.doCommit();
  2728. super.doCommit();
  2729. }
  2730. nearestInputPos(cursorPos, direction) {
  2731. return this.currentMask ? this.currentMask.nearestInputPos(cursorPos, direction) : super.nearestInputPos(cursorPos, direction);
  2732. }
  2733. get overwrite() {
  2734. return this.currentMask ? this.currentMask.overwrite : this._overwrite;
  2735. }
  2736. set overwrite(overwrite) {
  2737. this._overwrite = overwrite;
  2738. }
  2739. get eager() {
  2740. return this.currentMask ? this.currentMask.eager : this._eager;
  2741. }
  2742. set eager(eager) {
  2743. this._eager = eager;
  2744. }
  2745. get skipInvalid() {
  2746. return this.currentMask ? this.currentMask.skipInvalid : this._skipInvalid;
  2747. }
  2748. set skipInvalid(skipInvalid) {
  2749. this._skipInvalid = skipInvalid;
  2750. }
  2751. get autofix() {
  2752. return this.currentMask ? this.currentMask.autofix : this._autofix;
  2753. }
  2754. set autofix(autofix) {
  2755. this._autofix = autofix;
  2756. }
  2757. maskEquals(mask) {
  2758. return Array.isArray(mask) ? this.compiledMasks.every((m, mi) => {
  2759. if (!mask[mi]) return;
  2760. const {
  2761. mask: oldMask,
  2762. ...restOpts
  2763. } = mask[mi];
  2764. return objectIncludes(m, restOpts) && m.maskEquals(oldMask);
  2765. }) : super.maskEquals(mask);
  2766. }
  2767. typedValueEquals(value) {
  2768. var _this$currentMask5;
  2769. return Boolean((_this$currentMask5 = this.currentMask) == null ? void 0 : _this$currentMask5.typedValueEquals(value));
  2770. }
  2771. }
  2772. /** Currently chosen mask */
  2773. /** Currently chosen mask */
  2774. /** Compliled {@link Masked} options */
  2775. /** Chooses {@link Masked} depending on input value */
  2776. MaskedDynamic.DEFAULTS = {
  2777. ...Masked.DEFAULTS,
  2778. dispatch: (appended, masked, flags, tail) => {
  2779. if (!masked.compiledMasks.length) return;
  2780. const inputValue = masked.rawInputValue;
  2781. // simulate input
  2782. const inputs = masked.compiledMasks.map((m, index) => {
  2783. const isCurrent = masked.currentMask === m;
  2784. const startInputPos = isCurrent ? m.displayValue.length : m.nearestInputPos(m.displayValue.length, DIRECTION.FORCE_LEFT);
  2785. if (m.rawInputValue !== inputValue) {
  2786. m.reset();
  2787. m.append(inputValue, {
  2788. raw: true
  2789. });
  2790. } else if (!isCurrent) {
  2791. m.remove(startInputPos);
  2792. }
  2793. m.append(appended, masked.currentMaskFlags(flags));
  2794. m.appendTail(tail);
  2795. return {
  2796. index,
  2797. weight: m.rawInputValue.length,
  2798. totalInputPositions: m.totalInputPositions(0, Math.max(startInputPos, m.nearestInputPos(m.displayValue.length, DIRECTION.FORCE_LEFT)))
  2799. };
  2800. });
  2801. // pop masks with longer values first
  2802. inputs.sort((i1, i2) => i2.weight - i1.weight || i2.totalInputPositions - i1.totalInputPositions);
  2803. return masked.compiledMasks[inputs[0].index];
  2804. }
  2805. };
  2806. IMask.MaskedDynamic = MaskedDynamic;
  2807. /** Pattern which validates enum values */
  2808. class MaskedEnum extends MaskedPattern {
  2809. constructor(opts) {
  2810. super({
  2811. ...MaskedEnum.DEFAULTS,
  2812. ...opts
  2813. }); // mask will be created in _update
  2814. }
  2815. updateOptions(opts) {
  2816. super.updateOptions(opts);
  2817. }
  2818. _update(opts) {
  2819. const {
  2820. enum: enum_,
  2821. ...eopts
  2822. } = opts;
  2823. if (enum_) {
  2824. const lengths = enum_.map(e => e.length);
  2825. const requiredLength = Math.min(...lengths);
  2826. const optionalLength = Math.max(...lengths) - requiredLength;
  2827. eopts.mask = '*'.repeat(requiredLength);
  2828. if (optionalLength) eopts.mask += '[' + '*'.repeat(optionalLength) + ']';
  2829. this.enum = enum_;
  2830. }
  2831. super._update(eopts);
  2832. }
  2833. _appendCharRaw(ch, flags) {
  2834. if (flags === void 0) {
  2835. flags = {};
  2836. }
  2837. const matchFrom = Math.min(this.nearestInputPos(0, DIRECTION.FORCE_RIGHT), this.value.length);
  2838. const matches = this.enum.filter(e => this.matchValue(e, this.unmaskedValue + ch, matchFrom));
  2839. if (matches.length) {
  2840. if (matches.length === 1) {
  2841. this._forEachBlocksInRange(0, this.value.length, (b, bi) => {
  2842. const mch = matches[0][bi];
  2843. if (bi >= this.value.length || mch === b.value) return;
  2844. b.reset();
  2845. b._appendChar(mch, flags);
  2846. });
  2847. }
  2848. const d = super._appendCharRaw(matches[0][this.value.length], flags);
  2849. if (matches.length === 1) {
  2850. matches[0].slice(this.unmaskedValue.length).split('').forEach(mch => d.aggregate(super._appendCharRaw(mch)));
  2851. }
  2852. return d;
  2853. }
  2854. return new ChangeDetails();
  2855. }
  2856. extractTail(fromPos, toPos) {
  2857. if (fromPos === void 0) {
  2858. fromPos = 0;
  2859. }
  2860. if (toPos === void 0) {
  2861. toPos = this.displayValue.length;
  2862. }
  2863. // just drop tail
  2864. return new ContinuousTailDetails('', fromPos);
  2865. }
  2866. remove(fromPos, toPos) {
  2867. if (fromPos === void 0) {
  2868. fromPos = 0;
  2869. }
  2870. if (toPos === void 0) {
  2871. toPos = this.displayValue.length;
  2872. }
  2873. if (fromPos === toPos) return new ChangeDetails();
  2874. const matchFrom = Math.min(super.nearestInputPos(0, DIRECTION.FORCE_RIGHT), this.value.length);
  2875. let pos;
  2876. for (pos = fromPos; pos >= 0; --pos) {
  2877. const matches = this.enum.filter(e => this.matchValue(e, this.value.slice(matchFrom, pos), matchFrom));
  2878. if (matches.length > 1) break;
  2879. }
  2880. const details = super.remove(pos, toPos);
  2881. details.tailShift += pos - fromPos;
  2882. return details;
  2883. }
  2884. }
  2885. /** Match enum value */
  2886. MaskedEnum.DEFAULTS = {
  2887. ...MaskedPattern.DEFAULTS,
  2888. matchValue: (estr, istr, matchFrom) => estr.indexOf(istr, matchFrom) === matchFrom
  2889. };
  2890. IMask.MaskedEnum = MaskedEnum;
  2891. /** Masking by custom Function */
  2892. class MaskedFunction extends Masked {
  2893. /** */
  2894. /** Enable characters overwriting */
  2895. /** */
  2896. /** */
  2897. /** */
  2898. updateOptions(opts) {
  2899. super.updateOptions(opts);
  2900. }
  2901. _update(opts) {
  2902. super._update({
  2903. ...opts,
  2904. validate: opts.mask
  2905. });
  2906. }
  2907. }
  2908. IMask.MaskedFunction = MaskedFunction;
  2909. var _MaskedNumber;
  2910. /** Number mask */
  2911. class MaskedNumber extends Masked {
  2912. /** Single char */
  2913. /** Single char */
  2914. /** Array of single chars */
  2915. /** */
  2916. /** */
  2917. /** Digits after point */
  2918. /** Flag to remove leading and trailing zeros in the end of editing */
  2919. /** Flag to pad trailing zeros after point in the end of editing */
  2920. /** Enable characters overwriting */
  2921. /** */
  2922. /** */
  2923. /** */
  2924. /** Format typed value to string */
  2925. /** Parse string to get typed value */
  2926. constructor(opts) {
  2927. super({
  2928. ...MaskedNumber.DEFAULTS,
  2929. ...opts
  2930. });
  2931. }
  2932. updateOptions(opts) {
  2933. super.updateOptions(opts);
  2934. }
  2935. _update(opts) {
  2936. super._update(opts);
  2937. this._updateRegExps();
  2938. }
  2939. _updateRegExps() {
  2940. const start = '^' + (this.allowNegative ? '[+|\\-]?' : '');
  2941. const mid = '\\d*';
  2942. const end = (this.scale ? "(" + escapeRegExp(this.radix) + "\\d{0," + this.scale + "})?" : '') + '$';
  2943. this._numberRegExp = new RegExp(start + mid + end);
  2944. this._mapToRadixRegExp = new RegExp("[" + this.mapToRadix.map(escapeRegExp).join('') + "]", 'g');
  2945. this._thousandsSeparatorRegExp = new RegExp(escapeRegExp(this.thousandsSeparator), 'g');
  2946. }
  2947. _removeThousandsSeparators(value) {
  2948. return value.replace(this._thousandsSeparatorRegExp, '');
  2949. }
  2950. _insertThousandsSeparators(value) {
  2951. // https://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
  2952. const parts = value.split(this.radix);
  2953. parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandsSeparator);
  2954. return parts.join(this.radix);
  2955. }
  2956. doPrepareChar(ch, flags) {
  2957. if (flags === void 0) {
  2958. flags = {};
  2959. }
  2960. const [prepCh, details] = super.doPrepareChar(this._removeThousandsSeparators(this.scale && this.mapToRadix.length && (
  2961. /*
  2962. radix should be mapped when
  2963. 1) input is done from keyboard = flags.input && flags.raw
  2964. 2) unmasked value is set = !flags.input && !flags.raw
  2965. and should not be mapped when
  2966. 1) value is set = flags.input && !flags.raw
  2967. 2) raw value is set = !flags.input && flags.raw
  2968. */
  2969. flags.input && flags.raw || !flags.input && !flags.raw) ? ch.replace(this._mapToRadixRegExp, this.radix) : ch), flags);
  2970. if (ch && !prepCh) details.skip = true;
  2971. if (prepCh && !this.allowPositive && !this.value && prepCh !== '-') details.aggregate(this._appendChar('-'));
  2972. return [prepCh, details];
  2973. }
  2974. _separatorsCount(to, extendOnSeparators) {
  2975. if (extendOnSeparators === void 0) {
  2976. extendOnSeparators = false;
  2977. }
  2978. let count = 0;
  2979. for (let pos = 0; pos < to; ++pos) {
  2980. if (this._value.indexOf(this.thousandsSeparator, pos) === pos) {
  2981. ++count;
  2982. if (extendOnSeparators) to += this.thousandsSeparator.length;
  2983. }
  2984. }
  2985. return count;
  2986. }
  2987. _separatorsCountFromSlice(slice) {
  2988. if (slice === void 0) {
  2989. slice = this._value;
  2990. }
  2991. return this._separatorsCount(this._removeThousandsSeparators(slice).length, true);
  2992. }
  2993. extractInput(fromPos, toPos, flags) {
  2994. if (fromPos === void 0) {
  2995. fromPos = 0;
  2996. }
  2997. if (toPos === void 0) {
  2998. toPos = this.displayValue.length;
  2999. }
  3000. [fromPos, toPos] = this._adjustRangeWithSeparators(fromPos, toPos);
  3001. return this._removeThousandsSeparators(super.extractInput(fromPos, toPos, flags));
  3002. }
  3003. _appendCharRaw(ch, flags) {
  3004. if (flags === void 0) {
  3005. flags = {};
  3006. }
  3007. const prevBeforeTailValue = flags.tail && flags._beforeTailState ? flags._beforeTailState._value : this._value;
  3008. const prevBeforeTailSeparatorsCount = this._separatorsCountFromSlice(prevBeforeTailValue);
  3009. this._value = this._removeThousandsSeparators(this.value);
  3010. const oldValue = this._value;
  3011. this._value += ch;
  3012. const num = this.number;
  3013. let accepted = !isNaN(num);
  3014. let skip = false;
  3015. if (accepted) {
  3016. let fixedNum;
  3017. if (this.min != null && this.min < 0 && this.number < this.min) fixedNum = this.min;
  3018. if (this.max != null && this.max > 0 && this.number > this.max) fixedNum = this.max;
  3019. if (fixedNum != null) {
  3020. if (this.autofix) {
  3021. this._value = this.format(fixedNum, this).replace(MaskedNumber.UNMASKED_RADIX, this.radix);
  3022. skip || (skip = oldValue === this._value && !flags.tail); // if not changed on tail it's still ok to proceed
  3023. } else {
  3024. accepted = false;
  3025. }
  3026. }
  3027. accepted && (accepted = Boolean(this._value.match(this._numberRegExp)));
  3028. }
  3029. let appendDetails;
  3030. if (!accepted) {
  3031. this._value = oldValue;
  3032. appendDetails = new ChangeDetails();
  3033. } else {
  3034. appendDetails = new ChangeDetails({
  3035. inserted: this._value.slice(oldValue.length),
  3036. rawInserted: skip ? '' : ch,
  3037. skip
  3038. });
  3039. }
  3040. this._value = this._insertThousandsSeparators(this._value);
  3041. const beforeTailValue = flags.tail && flags._beforeTailState ? flags._beforeTailState._value : this._value;
  3042. const beforeTailSeparatorsCount = this._separatorsCountFromSlice(beforeTailValue);
  3043. appendDetails.tailShift += (beforeTailSeparatorsCount - prevBeforeTailSeparatorsCount) * this.thousandsSeparator.length;
  3044. return appendDetails;
  3045. }
  3046. _findSeparatorAround(pos) {
  3047. if (this.thousandsSeparator) {
  3048. const searchFrom = pos - this.thousandsSeparator.length + 1;
  3049. const separatorPos = this.value.indexOf(this.thousandsSeparator, searchFrom);
  3050. if (separatorPos <= pos) return separatorPos;
  3051. }
  3052. return -1;
  3053. }
  3054. _adjustRangeWithSeparators(from, to) {
  3055. const separatorAroundFromPos = this._findSeparatorAround(from);
  3056. if (separatorAroundFromPos >= 0) from = separatorAroundFromPos;
  3057. const separatorAroundToPos = this._findSeparatorAround(to);
  3058. if (separatorAroundToPos >= 0) to = separatorAroundToPos + this.thousandsSeparator.length;
  3059. return [from, to];
  3060. }
  3061. remove(fromPos, toPos) {
  3062. if (fromPos === void 0) {
  3063. fromPos = 0;
  3064. }
  3065. if (toPos === void 0) {
  3066. toPos = this.displayValue.length;
  3067. }
  3068. [fromPos, toPos] = this._adjustRangeWithSeparators(fromPos, toPos);
  3069. const valueBeforePos = this.value.slice(0, fromPos);
  3070. const valueAfterPos = this.value.slice(toPos);
  3071. const prevBeforeTailSeparatorsCount = this._separatorsCount(valueBeforePos.length);
  3072. this._value = this._insertThousandsSeparators(this._removeThousandsSeparators(valueBeforePos + valueAfterPos));
  3073. const beforeTailSeparatorsCount = this._separatorsCountFromSlice(valueBeforePos);
  3074. return new ChangeDetails({
  3075. tailShift: (beforeTailSeparatorsCount - prevBeforeTailSeparatorsCount) * this.thousandsSeparator.length
  3076. });
  3077. }
  3078. nearestInputPos(cursorPos, direction) {
  3079. if (!this.thousandsSeparator) return cursorPos;
  3080. switch (direction) {
  3081. case DIRECTION.NONE:
  3082. case DIRECTION.LEFT:
  3083. case DIRECTION.FORCE_LEFT:
  3084. {
  3085. const separatorAtLeftPos = this._findSeparatorAround(cursorPos - 1);
  3086. if (separatorAtLeftPos >= 0) {
  3087. const separatorAtLeftEndPos = separatorAtLeftPos + this.thousandsSeparator.length;
  3088. if (cursorPos < separatorAtLeftEndPos || this.value.length <= separatorAtLeftEndPos || direction === DIRECTION.FORCE_LEFT) {
  3089. return separatorAtLeftPos;
  3090. }
  3091. }
  3092. break;
  3093. }
  3094. case DIRECTION.RIGHT:
  3095. case DIRECTION.FORCE_RIGHT:
  3096. {
  3097. const separatorAtRightPos = this._findSeparatorAround(cursorPos);
  3098. if (separatorAtRightPos >= 0) {
  3099. return separatorAtRightPos + this.thousandsSeparator.length;
  3100. }
  3101. }
  3102. }
  3103. return cursorPos;
  3104. }
  3105. doCommit() {
  3106. if (this.value) {
  3107. const number = this.number;
  3108. let validnum = number;
  3109. // check bounds
  3110. if (this.min != null) validnum = Math.max(validnum, this.min);
  3111. if (this.max != null) validnum = Math.min(validnum, this.max);
  3112. if (validnum !== number) this.unmaskedValue = this.format(validnum, this);
  3113. let formatted = this.value;
  3114. if (this.normalizeZeros) formatted = this._normalizeZeros(formatted);
  3115. if (this.padFractionalZeros && this.scale > 0) formatted = this._padFractionalZeros(formatted);
  3116. this._value = formatted;
  3117. }
  3118. super.doCommit();
  3119. }
  3120. _normalizeZeros(value) {
  3121. const parts = this._removeThousandsSeparators(value).split(this.radix);
  3122. // remove leading zeros
  3123. parts[0] = parts[0].replace(/^(\D*)(0*)(\d*)/, (match, sign, zeros, num) => sign + num);
  3124. // add leading zero
  3125. if (value.length && !/\d$/.test(parts[0])) parts[0] = parts[0] + '0';
  3126. if (parts.length > 1) {
  3127. parts[1] = parts[1].replace(/0*$/, ''); // remove trailing zeros
  3128. if (!parts[1].length) parts.length = 1; // remove fractional
  3129. }
  3130. return this._insertThousandsSeparators(parts.join(this.radix));
  3131. }
  3132. _padFractionalZeros(value) {
  3133. if (!value) return value;
  3134. const parts = value.split(this.radix);
  3135. if (parts.length < 2) parts.push('');
  3136. parts[1] = parts[1].padEnd(this.scale, '0');
  3137. return parts.join(this.radix);
  3138. }
  3139. doSkipInvalid(ch, flags, checkTail) {
  3140. if (flags === void 0) {
  3141. flags = {};
  3142. }
  3143. const dropFractional = this.scale === 0 && ch !== this.thousandsSeparator && (ch === this.radix || ch === MaskedNumber.UNMASKED_RADIX || this.mapToRadix.includes(ch));
  3144. return super.doSkipInvalid(ch, flags, checkTail) && !dropFractional;
  3145. }
  3146. get unmaskedValue() {
  3147. return this._removeThousandsSeparators(this._normalizeZeros(this.value)).replace(this.radix, MaskedNumber.UNMASKED_RADIX);
  3148. }
  3149. set unmaskedValue(unmaskedValue) {
  3150. super.unmaskedValue = unmaskedValue;
  3151. }
  3152. get typedValue() {
  3153. return this.parse(this.unmaskedValue, this);
  3154. }
  3155. set typedValue(n) {
  3156. this.rawInputValue = this.format(n, this).replace(MaskedNumber.UNMASKED_RADIX, this.radix);
  3157. }
  3158. /** Parsed Number */
  3159. get number() {
  3160. return this.typedValue;
  3161. }
  3162. set number(number) {
  3163. this.typedValue = number;
  3164. }
  3165. get allowNegative() {
  3166. return this.min != null && this.min < 0 || this.max != null && this.max < 0;
  3167. }
  3168. get allowPositive() {
  3169. return this.min != null && this.min > 0 || this.max != null && this.max > 0;
  3170. }
  3171. typedValueEquals(value) {
  3172. // handle 0 -> '' case (typed = 0 even if value = '')
  3173. // for details see https://github.com/uNmAnNeR/imaskjs/issues/134
  3174. return (super.typedValueEquals(value) || MaskedNumber.EMPTY_VALUES.includes(value) && MaskedNumber.EMPTY_VALUES.includes(this.typedValue)) && !(value === 0 && this.value === '');
  3175. }
  3176. }
  3177. _MaskedNumber = MaskedNumber;
  3178. MaskedNumber.UNMASKED_RADIX = '.';
  3179. MaskedNumber.EMPTY_VALUES = [...Masked.EMPTY_VALUES, 0];
  3180. MaskedNumber.DEFAULTS = {
  3181. ...Masked.DEFAULTS,
  3182. mask: Number,
  3183. radix: ',',
  3184. thousandsSeparator: '',
  3185. mapToRadix: [_MaskedNumber.UNMASKED_RADIX],
  3186. min: Number.MIN_SAFE_INTEGER,
  3187. max: Number.MAX_SAFE_INTEGER,
  3188. scale: 2,
  3189. normalizeZeros: true,
  3190. padFractionalZeros: false,
  3191. parse: Number,
  3192. format: n => n.toLocaleString('en-US', {
  3193. useGrouping: false,
  3194. maximumFractionDigits: 20
  3195. })
  3196. };
  3197. IMask.MaskedNumber = MaskedNumber;
  3198. /** Mask pipe source and destination types */
  3199. const PIPE_TYPE = {
  3200. MASKED: 'value',
  3201. UNMASKED: 'unmaskedValue',
  3202. TYPED: 'typedValue'
  3203. };
  3204. /** Creates new pipe function depending on mask type, source and destination options */
  3205. function createPipe(arg, from, to) {
  3206. if (from === void 0) {
  3207. from = PIPE_TYPE.MASKED;
  3208. }
  3209. if (to === void 0) {
  3210. to = PIPE_TYPE.MASKED;
  3211. }
  3212. const masked = createMask(arg);
  3213. return value => masked.runIsolated(m => {
  3214. m[from] = value;
  3215. return m[to];
  3216. });
  3217. }
  3218. /** Pipes value through mask depending on mask type, source and destination options */
  3219. function pipe(value, mask, from, to) {
  3220. return createPipe(mask, from, to)(value);
  3221. }
  3222. IMask.PIPE_TYPE = PIPE_TYPE;
  3223. IMask.createPipe = createPipe;
  3224. IMask.pipe = pipe;
  3225. /** Pattern mask */
  3226. class RepeatBlock extends MaskedPattern {
  3227. get repeatFrom() {
  3228. var _ref;
  3229. return (_ref = Array.isArray(this.repeat) ? this.repeat[0] : this.repeat === Infinity ? 0 : this.repeat) != null ? _ref : 0;
  3230. }
  3231. get repeatTo() {
  3232. var _ref2;
  3233. return (_ref2 = Array.isArray(this.repeat) ? this.repeat[1] : this.repeat) != null ? _ref2 : Infinity;
  3234. }
  3235. constructor(opts) {
  3236. super(opts);
  3237. }
  3238. updateOptions(opts) {
  3239. super.updateOptions(opts);
  3240. }
  3241. _update(opts) {
  3242. var _ref3, _ref4, _this$_blocks;
  3243. const {
  3244. repeat,
  3245. ...blockOpts
  3246. } = normalizeOpts(opts); // TODO type
  3247. this._blockOpts = Object.assign({}, this._blockOpts, blockOpts);
  3248. const block = createMask(this._blockOpts);
  3249. this.repeat = (_ref3 = (_ref4 = repeat != null ? repeat : block.repeat) != null ? _ref4 : this.repeat) != null ? _ref3 : Infinity; // TODO type
  3250. super._update({
  3251. mask: 'm'.repeat(Math.max(this.repeatTo === Infinity && ((_this$_blocks = this._blocks) == null ? void 0 : _this$_blocks.length) || 0, this.repeatFrom)),
  3252. blocks: {
  3253. m: block
  3254. },
  3255. eager: block.eager,
  3256. overwrite: block.overwrite,
  3257. skipInvalid: block.skipInvalid,
  3258. lazy: block.lazy,
  3259. placeholderChar: block.placeholderChar,
  3260. displayChar: block.displayChar
  3261. });
  3262. }
  3263. _allocateBlock(bi) {
  3264. if (bi < this._blocks.length) return this._blocks[bi];
  3265. if (this.repeatTo === Infinity || this._blocks.length < this.repeatTo) {
  3266. this._blocks.push(createMask(this._blockOpts));
  3267. this.mask += 'm';
  3268. return this._blocks[this._blocks.length - 1];
  3269. }
  3270. }
  3271. _appendCharRaw(ch, flags) {
  3272. if (flags === void 0) {
  3273. flags = {};
  3274. }
  3275. const details = new ChangeDetails();
  3276. for (let bi = (_this$_mapPosToBlock$ = (_this$_mapPosToBlock = this._mapPosToBlock(this.displayValue.length)) == null ? void 0 : _this$_mapPosToBlock.index) != null ? _this$_mapPosToBlock$ : Math.max(this._blocks.length - 1, 0), block, allocated;
  3277. // try to get a block or
  3278. // try to allocate a new block if not allocated already
  3279. block = (_this$_blocks$bi = this._blocks[bi]) != null ? _this$_blocks$bi : allocated = !allocated && this._allocateBlock(bi); ++bi) {
  3280. var _this$_mapPosToBlock$, _this$_mapPosToBlock, _this$_blocks$bi, _flags$_beforeTailSta;
  3281. const blockDetails = block._appendChar(ch, {
  3282. ...flags,
  3283. _beforeTailState: (_flags$_beforeTailSta = flags._beforeTailState) == null || (_flags$_beforeTailSta = _flags$_beforeTailSta._blocks) == null ? void 0 : _flags$_beforeTailSta[bi]
  3284. });
  3285. if (blockDetails.skip && allocated) {
  3286. // remove the last allocated block and break
  3287. this._blocks.pop();
  3288. this.mask = this.mask.slice(1);
  3289. break;
  3290. }
  3291. details.aggregate(blockDetails);
  3292. if (blockDetails.consumed) break; // go next char
  3293. }
  3294. return details;
  3295. }
  3296. _trimEmptyTail(fromPos, toPos) {
  3297. var _this$_mapPosToBlock2, _this$_mapPosToBlock3;
  3298. if (fromPos === void 0) {
  3299. fromPos = 0;
  3300. }
  3301. const firstBlockIndex = Math.max(((_this$_mapPosToBlock2 = this._mapPosToBlock(fromPos)) == null ? void 0 : _this$_mapPosToBlock2.index) || 0, this.repeatFrom, 0);
  3302. let lastBlockIndex;
  3303. if (toPos != null) lastBlockIndex = (_this$_mapPosToBlock3 = this._mapPosToBlock(toPos)) == null ? void 0 : _this$_mapPosToBlock3.index;
  3304. if (lastBlockIndex == null) lastBlockIndex = this._blocks.length - 1;
  3305. let removeCount = 0;
  3306. for (let blockIndex = lastBlockIndex; firstBlockIndex <= blockIndex; --blockIndex, ++removeCount) {
  3307. if (this._blocks[blockIndex].unmaskedValue) break;
  3308. }
  3309. if (removeCount) {
  3310. this._blocks.splice(lastBlockIndex - removeCount + 1, removeCount);
  3311. this.mask = this.mask.slice(removeCount);
  3312. }
  3313. }
  3314. reset() {
  3315. super.reset();
  3316. this._trimEmptyTail();
  3317. }
  3318. remove(fromPos, toPos) {
  3319. if (fromPos === void 0) {
  3320. fromPos = 0;
  3321. }
  3322. if (toPos === void 0) {
  3323. toPos = this.displayValue.length;
  3324. }
  3325. const removeDetails = super.remove(fromPos, toPos);
  3326. this._trimEmptyTail(fromPos, toPos);
  3327. return removeDetails;
  3328. }
  3329. totalInputPositions(fromPos, toPos) {
  3330. if (fromPos === void 0) {
  3331. fromPos = 0;
  3332. }
  3333. if (toPos == null && this.repeatTo === Infinity) return Infinity;
  3334. return super.totalInputPositions(fromPos, toPos);
  3335. }
  3336. get state() {
  3337. return super.state;
  3338. }
  3339. set state(state) {
  3340. this._blocks.length = state._blocks.length;
  3341. this.mask = this.mask.slice(0, this._blocks.length);
  3342. super.state = state;
  3343. }
  3344. }
  3345. IMask.RepeatBlock = RepeatBlock;
  3346. try {
  3347. globalThis.IMask = IMask;
  3348. } catch {}
  3349. exports.ChangeDetails = ChangeDetails;
  3350. exports.ChunksTailDetails = ChunksTailDetails;
  3351. exports.DIRECTION = DIRECTION;
  3352. exports.HTMLContenteditableMaskElement = HTMLContenteditableMaskElement;
  3353. exports.HTMLInputMaskElement = HTMLInputMaskElement;
  3354. exports.HTMLMaskElement = HTMLMaskElement;
  3355. exports.InputMask = InputMask;
  3356. exports.MaskElement = MaskElement;
  3357. exports.Masked = Masked;
  3358. exports.MaskedDate = MaskedDate;
  3359. exports.MaskedDynamic = MaskedDynamic;
  3360. exports.MaskedEnum = MaskedEnum;
  3361. exports.MaskedFunction = MaskedFunction;
  3362. exports.MaskedNumber = MaskedNumber;
  3363. exports.MaskedPattern = MaskedPattern;
  3364. exports.MaskedRange = MaskedRange;
  3365. exports.MaskedRegExp = MaskedRegExp;
  3366. exports.PIPE_TYPE = PIPE_TYPE;
  3367. exports.PatternFixedDefinition = PatternFixedDefinition;
  3368. exports.PatternInputDefinition = PatternInputDefinition;
  3369. exports.RepeatBlock = RepeatBlock;
  3370. exports.createMask = createMask;
  3371. exports.createPipe = createPipe;
  3372. exports.default = IMask;
  3373. exports.forceDirection = forceDirection;
  3374. exports.normalizeOpts = normalizeOpts;
  3375. exports.pipe = pipe;
  3376. Object.defineProperty(exports, '__esModule', { value: true });
  3377. }));
  3378. //# sourceMappingURL=imask.js.map