PluginProbe
Booking Calendar / 11.8.4
Booking Calendar v11.8.4
11.8.4 11.8.3 11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 All 204 releases
booking / vendors / imask / esm / masked / pattern.js

pattern.js in Booking Calendar 11.8.4, at vendors/imask/esm/masked/pattern.js

465 lines 14.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import ChangeDetails from '../core/change-details.js';
2 import IMask from '../core/holder.js';
3 import { DIRECTION } from '../core/utils.js';
4 import Masked from './base.js';
5 import createMask, { normalizeOpts } from './factory.js';
6 import ChunksTailDetails from './pattern/chunk-tail-details.js';
7 import PatternCursor from './pattern/cursor.js';
8 import PatternFixedDefinition from './pattern/fixed-definition.js';
9 import PatternInputDefinition from './pattern/input-definition.js';
10 import './regexp.js';
11 import '../core/continuous-tail-details.js';
12
13 /** Pattern mask */
14 class MaskedPattern extends Masked {
15 /** */
16
17 /** */
18
19 /** Single char for empty input */
20
21 /** Single char for filled input */
22
23 /** Show placeholder only when needed */
24
25 /** Enable characters overwriting */
26
27 /** */
28
29 /** */
30
31 /** */
32
33 constructor(opts) {
34 super({
35 ...MaskedPattern.DEFAULTS,
36 ...opts,
37 definitions: Object.assign({}, PatternInputDefinition.DEFAULT_DEFINITIONS, opts == null ? void 0 : opts.definitions)
38 });
39 }
40 updateOptions(opts) {
41 super.updateOptions(opts);
42 }
43 _update(opts) {
44 opts.definitions = Object.assign({}, this.definitions, opts.definitions);
45 super._update(opts);
46 this._rebuildMask();
47 }
48 _rebuildMask() {
49 const defs = this.definitions;
50 this._blocks = [];
51 this.exposeBlock = undefined;
52 this._stops = [];
53 this._maskedBlocks = {};
54 const pattern = this.mask;
55 if (!pattern || !defs) return;
56 let unmaskingBlock = false;
57 let optionalBlock = false;
58 for (let i = 0; i < pattern.length; ++i) {
59 if (this.blocks) {
60 const p = pattern.slice(i);
61 const bNames = Object.keys(this.blocks).filter(bName => p.indexOf(bName) === 0);
62 // order by key length
63 bNames.sort((a, b) => b.length - a.length);
64 // use block name with max length
65 const bName = bNames[0];
66 if (bName) {
67 const {
68 expose,
69 repeat,
70 ...bOpts
71 } = normalizeOpts(this.blocks[bName]); // TODO type Opts<Arg & Extra>
72 const blockOpts = {
73 lazy: this.lazy,
74 eager: this.eager,
75 placeholderChar: this.placeholderChar,
76 displayChar: this.displayChar,
77 overwrite: this.overwrite,
78 autofix: this.autofix,
79 ...bOpts,
80 repeat,
81 parent: this
82 };
83 const maskedBlock = repeat != null ? new IMask.RepeatBlock(blockOpts /* TODO */) : createMask(blockOpts);
84 if (maskedBlock) {
85 this._blocks.push(maskedBlock);
86 if (expose) this.exposeBlock = maskedBlock;
87
88 // store block index
89 if (!this._maskedBlocks[bName]) this._maskedBlocks[bName] = [];
90 this._maskedBlocks[bName].push(this._blocks.length - 1);
91 }
92 i += bName.length - 1;
93 continue;
94 }
95 }
96 let char = pattern[i];
97 let isInput = (char in defs);
98 if (char === MaskedPattern.STOP_CHAR) {
99 this._stops.push(this._blocks.length);
100 continue;
101 }
102 if (char === '{' || char === '}') {
103 unmaskingBlock = !unmaskingBlock;
104 continue;
105 }
106 if (char === '[' || char === ']') {
107 optionalBlock = !optionalBlock;
108 continue;
109 }
110 if (char === MaskedPattern.ESCAPE_CHAR) {
111 ++i;
112 char = pattern[i];
113 if (!char) break;
114 isInput = false;
115 }
116 const def = isInput ? new PatternInputDefinition({
117 isOptional: optionalBlock,
118 lazy: this.lazy,
119 eager: this.eager,
120 placeholderChar: this.placeholderChar,
121 displayChar: this.displayChar,
122 ...normalizeOpts(defs[char]),
123 parent: this
124 }) : new PatternFixedDefinition({
125 char,
126 eager: this.eager,
127 isUnmasking: unmaskingBlock
128 });
129 this._blocks.push(def);
130 }
131 }
132 get state() {
133 return {
134 ...super.state,
135 _blocks: this._blocks.map(b => b.state)
136 };
137 }
138 set state(state) {
139 if (!state) {
140 this.reset();
141 return;
142 }
143 const {
144 _blocks,
145 ...maskedState
146 } = state;
147 this._blocks.forEach((b, bi) => b.state = _blocks[bi]);
148 super.state = maskedState;
149 }
150 reset() {
151 super.reset();
152 this._blocks.forEach(b => b.reset());
153 }
154 get isComplete() {
155 return this.exposeBlock ? this.exposeBlock.isComplete : this._blocks.every(b => b.isComplete);
156 }
157 get isFilled() {
158 return this._blocks.every(b => b.isFilled);
159 }
160 get isFixed() {
161 return this._blocks.every(b => b.isFixed);
162 }
163 get isOptional() {
164 return this._blocks.every(b => b.isOptional);
165 }
166 doCommit() {
167 this._blocks.forEach(b => b.doCommit());
168 super.doCommit();
169 }
170 get unmaskedValue() {
171 return this.exposeBlock ? this.exposeBlock.unmaskedValue : this._blocks.reduce((str, b) => str += b.unmaskedValue, '');
172 }
173 set unmaskedValue(unmaskedValue) {
174 if (this.exposeBlock) {
175 const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
176 this.exposeBlock.unmaskedValue = unmaskedValue;
177 this.appendTail(tail);
178 this.doCommit();
179 } else super.unmaskedValue = unmaskedValue;
180 }
181 get value() {
182 return this.exposeBlock ? this.exposeBlock.value :
183 // TODO return _value when not in change?
184 this._blocks.reduce((str, b) => str += b.value, '');
185 }
186 set value(value) {
187 if (this.exposeBlock) {
188 const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
189 this.exposeBlock.value = value;
190 this.appendTail(tail);
191 this.doCommit();
192 } else super.value = value;
193 }
194 get typedValue() {
195 return this.exposeBlock ? this.exposeBlock.typedValue : super.typedValue;
196 }
197 set typedValue(value) {
198 if (this.exposeBlock) {
199 const tail = this.extractTail(this._blockStartPos(this._blocks.indexOf(this.exposeBlock)) + this.exposeBlock.displayValue.length);
200 this.exposeBlock.typedValue = value;
201 this.appendTail(tail);
202 this.doCommit();
203 } else super.typedValue = value;
204 }
205 get displayValue() {
206 return this._blocks.reduce((str, b) => str += b.displayValue, '');
207 }
208 appendTail(tail) {
209 return super.appendTail(tail).aggregate(this._appendPlaceholder());
210 }
211 _appendEager() {
212 var _this$_mapPosToBlock;
213 const details = new ChangeDetails();
214 let startBlockIndex = (_this$_mapPosToBlock = this._mapPosToBlock(this.displayValue.length)) == null ? void 0 : _this$_mapPosToBlock.index;
215 if (startBlockIndex == null) return details;
216
217 // TODO test if it works for nested pattern masks
218 if (this._blocks[startBlockIndex].isFilled) ++startBlockIndex;
219 for (let bi = startBlockIndex; bi < this._blocks.length; ++bi) {
220 const d = this._blocks[bi]._appendEager();
221 if (!d.inserted) break;
222 details.aggregate(d);
223 }
224 return details;
225 }
226 _appendCharRaw(ch, flags) {
227 if (flags === void 0) {
228 flags = {};
229 }
230 const blockIter = this._mapPosToBlock(this.displayValue.length);
231 const details = new ChangeDetails();
232 if (!blockIter) return details;
233 for (let bi = blockIter.index, block; block = this._blocks[bi]; ++bi) {
234 var _flags$_beforeTailSta;
235 const blockDetails = block._appendChar(ch, {
236 ...flags,
237 _beforeTailState: (_flags$_beforeTailSta = flags._beforeTailState) == null || (_flags$_beforeTailSta = _flags$_beforeTailSta._blocks) == null ? void 0 : _flags$_beforeTailSta[bi]
238 });
239 details.aggregate(blockDetails);
240 if (blockDetails.consumed) break; // go next char
241 }
242 return details;
243 }
244 extractTail(fromPos, toPos) {
245 if (fromPos === void 0) {
246 fromPos = 0;
247 }
248 if (toPos === void 0) {
249 toPos = this.displayValue.length;
250 }
251 const chunkTail = new ChunksTailDetails();
252 if (fromPos === toPos) return chunkTail;
253 this._forEachBlocksInRange(fromPos, toPos, (b, bi, bFromPos, bToPos) => {
254 const blockChunk = b.extractTail(bFromPos, bToPos);
255 blockChunk.stop = this._findStopBefore(bi);
256 blockChunk.from = this._blockStartPos(bi);
257 if (blockChunk instanceof ChunksTailDetails) blockChunk.blockIndex = bi;
258 chunkTail.extend(blockChunk);
259 });
260 return chunkTail;
261 }
262 extractInput(fromPos, toPos, flags) {
263 if (fromPos === void 0) {
264 fromPos = 0;
265 }
266 if (toPos === void 0) {
267 toPos = this.displayValue.length;
268 }
269 if (flags === void 0) {
270 flags = {};
271 }
272 if (fromPos === toPos) return '';
273 let input = '';
274 this._forEachBlocksInRange(fromPos, toPos, (b, _, fromPos, toPos) => {
275 input += b.extractInput(fromPos, toPos, flags);
276 });
277 return input;
278 }
279 _findStopBefore(blockIndex) {
280 let stopBefore;
281 for (let si = 0; si < this._stops.length; ++si) {
282 const stop = this._stops[si];
283 if (stop <= blockIndex) stopBefore = stop;else break;
284 }
285 return stopBefore;
286 }
287
288 /** Appends placeholder depending on laziness */
289 _appendPlaceholder(toBlockIndex) {
290 const details = new ChangeDetails();
291 if (this.lazy && toBlockIndex == null) return details;
292 const startBlockIter = this._mapPosToBlock(this.displayValue.length);
293 if (!startBlockIter) return details;
294 const startBlockIndex = startBlockIter.index;
295 const endBlockIndex = toBlockIndex != null ? toBlockIndex : this._blocks.length;
296 this._blocks.slice(startBlockIndex, endBlockIndex).forEach(b => {
297 if (!b.lazy || toBlockIndex != null) {
298 var _blocks2;
299 details.aggregate(b._appendPlaceholder((_blocks2 = b._blocks) == null ? void 0 : _blocks2.length));
300 }
301 });
302 return details;
303 }
304
305 /** Finds block in pos */
306 _mapPosToBlock(pos) {
307 let accVal = '';
308 for (let bi = 0; bi < this._blocks.length; ++bi) {
309 const block = this._blocks[bi];
310 const blockStartPos = accVal.length;
311 accVal += block.displayValue;
312 if (pos <= accVal.length) {
313 return {
314 index: bi,
315 offset: pos - blockStartPos
316 };
317 }
318 }
319 }
320 _blockStartPos(blockIndex) {
321 return this._blocks.slice(0, blockIndex).reduce((pos, b) => pos += b.displayValue.length, 0);
322 }
323 _forEachBlocksInRange(fromPos, toPos, fn) {
324 if (toPos === void 0) {
325 toPos = this.displayValue.length;
326 }
327 const fromBlockIter = this._mapPosToBlock(fromPos);
328 if (fromBlockIter) {
329 const toBlockIter = this._mapPosToBlock(toPos);
330 // process first block
331 const isSameBlock = toBlockIter && fromBlockIter.index === toBlockIter.index;
332 const fromBlockStartPos = fromBlockIter.offset;
333 const fromBlockEndPos = toBlockIter && isSameBlock ? toBlockIter.offset : this._blocks[fromBlockIter.index].displayValue.length;
334 fn(this._blocks[fromBlockIter.index], fromBlockIter.index, fromBlockStartPos, fromBlockEndPos);
335 if (toBlockIter && !isSameBlock) {
336 // process intermediate blocks
337 for (let bi = fromBlockIter.index + 1; bi < toBlockIter.index; ++bi) {
338 fn(this._blocks[bi], bi, 0, this._blocks[bi].displayValue.length);
339 }
340
341 // process last block
342 fn(this._blocks[toBlockIter.index], toBlockIter.index, 0, toBlockIter.offset);
343 }
344 }
345 }
346 remove(fromPos, toPos) {
347 if (fromPos === void 0) {
348 fromPos = 0;
349 }
350 if (toPos === void 0) {
351 toPos = this.displayValue.length;
352 }
353 const removeDetails = super.remove(fromPos, toPos);
354 this._forEachBlocksInRange(fromPos, toPos, (b, _, bFromPos, bToPos) => {
355 removeDetails.aggregate(b.remove(bFromPos, bToPos));
356 });
357 return removeDetails;
358 }
359 nearestInputPos(cursorPos, direction) {
360 if (direction === void 0) {
361 direction = DIRECTION.NONE;
362 }
363 if (!this._blocks.length) return 0;
364 const cursor = new PatternCursor(this, cursorPos);
365 if (direction === DIRECTION.NONE) {
366 // -------------------------------------------------
367 // NONE should only go out from fixed to the right!
368 // -------------------------------------------------
369 if (cursor.pushRightBeforeInput()) return cursor.pos;
370 cursor.popState();
371 if (cursor.pushLeftBeforeInput()) return cursor.pos;
372 return this.displayValue.length;
373 }
374
375 // FORCE is only about a|* otherwise is 0
376 if (direction === DIRECTION.LEFT || direction === DIRECTION.FORCE_LEFT) {
377 // try to break fast when *|a
378 if (direction === DIRECTION.LEFT) {
379 cursor.pushRightBeforeFilled();
380 if (cursor.ok && cursor.pos === cursorPos) return cursorPos;
381 cursor.popState();
382 }
383
384 // forward flow
385 cursor.pushLeftBeforeInput();
386 cursor.pushLeftBeforeRequired();
387 cursor.pushLeftBeforeFilled();
388
389 // backward flow
390 if (direction === DIRECTION.LEFT) {
391 cursor.pushRightBeforeInput();
392 cursor.pushRightBeforeRequired();
393 if (cursor.ok && cursor.pos <= cursorPos) return cursor.pos;
394 cursor.popState();
395 if (cursor.ok && cursor.pos <= cursorPos) return cursor.pos;
396 cursor.popState();
397 }
398 if (cursor.ok) return cursor.pos;
399 if (direction === DIRECTION.FORCE_LEFT) return 0;
400 cursor.popState();
401 if (cursor.ok) return cursor.pos;
402 cursor.popState();
403 if (cursor.ok) return cursor.pos;
404 return 0;
405 }
406 if (direction === DIRECTION.RIGHT || direction === DIRECTION.FORCE_RIGHT) {
407 // forward flow
408 cursor.pushRightBeforeInput();
409 cursor.pushRightBeforeRequired();
410 if (cursor.pushRightBeforeFilled()) return cursor.pos;
411 if (direction === DIRECTION.FORCE_RIGHT) return this.displayValue.length;
412
413 // backward flow
414 cursor.popState();
415 if (cursor.ok) return cursor.pos;
416 cursor.popState();
417 if (cursor.ok) return cursor.pos;
418 return this.nearestInputPos(cursorPos, DIRECTION.LEFT);
419 }
420 return cursorPos;
421 }
422 totalInputPositions(fromPos, toPos) {
423 if (fromPos === void 0) {
424 fromPos = 0;
425 }
426 if (toPos === void 0) {
427 toPos = this.displayValue.length;
428 }
429 let total = 0;
430 this._forEachBlocksInRange(fromPos, toPos, (b, _, bFromPos, bToPos) => {
431 total += b.totalInputPositions(bFromPos, bToPos);
432 });
433 return total;
434 }
435
436 /** Get block by name */
437 maskedBlock(name) {
438 return this.maskedBlocks(name)[0];
439 }
440
441 /** Get all blocks by name */
442 maskedBlocks(name) {
443 const indices = this._maskedBlocks[name];
444 if (!indices) return [];
445 return indices.map(gi => this._blocks[gi]);
446 }
447 pad(flags) {
448 const details = new ChangeDetails();
449 this._forEachBlocksInRange(0, this.displayValue.length, b => details.aggregate(b.pad(flags)));
450 return details;
451 }
452 }
453 MaskedPattern.DEFAULTS = {
454 ...Masked.DEFAULTS,
455 lazy: true,
456 placeholderChar: '_'
457 };
458 MaskedPattern.STOP_CHAR = '`';
459 MaskedPattern.ESCAPE_CHAR = '\\';
460 MaskedPattern.InputDefinition = PatternInputDefinition;
461 MaskedPattern.FixedDefinition = PatternFixedDefinition;
462 IMask.MaskedPattern = MaskedPattern;
463
464 export { MaskedPattern as default };
465