| 1 |
import { DIRECTION } from '../../core/utils.js'; |
| 2 |
|
| 3 |
class PatternCursor { |
| 4 |
constructor(masked, pos) { |
| 5 |
this.masked = masked; |
| 6 |
this._log = []; |
| 7 |
const { |
| 8 |
offset, |
| 9 |
index |
| 10 |
} = masked._mapPosToBlock(pos) || (pos < 0 ? |
| 11 |
// first |
| 12 |
{ |
| 13 |
index: 0, |
| 14 |
offset: 0 |
| 15 |
} : |
| 16 |
// last |
| 17 |
{ |
| 18 |
index: this.masked._blocks.length, |
| 19 |
offset: 0 |
| 20 |
}); |
| 21 |
this.offset = offset; |
| 22 |
this.index = index; |
| 23 |
this.ok = false; |
| 24 |
} |
| 25 |
get block() { |
| 26 |
return this.masked._blocks[this.index]; |
| 27 |
} |
| 28 |
get pos() { |
| 29 |
return this.masked._blockStartPos(this.index) + this.offset; |
| 30 |
} |
| 31 |
get state() { |
| 32 |
return { |
| 33 |
index: this.index, |
| 34 |
offset: this.offset, |
| 35 |
ok: this.ok |
| 36 |
}; |
| 37 |
} |
| 38 |
set state(s) { |
| 39 |
Object.assign(this, s); |
| 40 |
} |
| 41 |
pushState() { |
| 42 |
this._log.push(this.state); |
| 43 |
} |
| 44 |
popState() { |
| 45 |
const s = this._log.pop(); |
| 46 |
if (s) this.state = s; |
| 47 |
return s; |
| 48 |
} |
| 49 |
bindBlock() { |
| 50 |
if (this.block) return; |
| 51 |
if (this.index < 0) { |
| 52 |
this.index = 0; |
| 53 |
this.offset = 0; |
| 54 |
} |
| 55 |
if (this.index >= this.masked._blocks.length) { |
| 56 |
this.index = this.masked._blocks.length - 1; |
| 57 |
this.offset = this.block.displayValue.length; // TODO this is stupid type error, `block` depends on index that was changed above |
| 58 |
} |
| 59 |
} |
| 60 |
_pushLeft(fn) { |
| 61 |
this.pushState(); |
| 62 |
for (this.bindBlock(); 0 <= this.index; --this.index, this.offset = ((_this$block = this.block) == null ? void 0 : _this$block.displayValue.length) || 0) { |
| 63 |
var _this$block; |
| 64 |
if (fn()) return this.ok = true; |
| 65 |
} |
| 66 |
return this.ok = false; |
| 67 |
} |
| 68 |
_pushRight(fn) { |
| 69 |
this.pushState(); |
| 70 |
for (this.bindBlock(); this.index < this.masked._blocks.length; ++this.index, this.offset = 0) { |
| 71 |
if (fn()) return this.ok = true; |
| 72 |
} |
| 73 |
return this.ok = false; |
| 74 |
} |
| 75 |
pushLeftBeforeFilled() { |
| 76 |
return this._pushLeft(() => { |
| 77 |
if (this.block.isFixed || !this.block.value) return; |
| 78 |
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.FORCE_LEFT); |
| 79 |
if (this.offset !== 0) return true; |
| 80 |
}); |
| 81 |
} |
| 82 |
pushLeftBeforeInput() { |
| 83 |
// cases: |
| 84 |
// filled input: 00| |
| 85 |
// optional empty input: 00[]| |
| 86 |
// nested block: XX<[]>| |
| 87 |
return this._pushLeft(() => { |
| 88 |
if (this.block.isFixed) return; |
| 89 |
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.LEFT); |
| 90 |
return true; |
| 91 |
}); |
| 92 |
} |
| 93 |
pushLeftBeforeRequired() { |
| 94 |
return this._pushLeft(() => { |
| 95 |
if (this.block.isFixed || this.block.isOptional && !this.block.value) return; |
| 96 |
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.LEFT); |
| 97 |
return true; |
| 98 |
}); |
| 99 |
} |
| 100 |
pushRightBeforeFilled() { |
| 101 |
return this._pushRight(() => { |
| 102 |
if (this.block.isFixed || !this.block.value) return; |
| 103 |
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.FORCE_RIGHT); |
| 104 |
if (this.offset !== this.block.value.length) return true; |
| 105 |
}); |
| 106 |
} |
| 107 |
pushRightBeforeInput() { |
| 108 |
return this._pushRight(() => { |
| 109 |
if (this.block.isFixed) return; |
| 110 |
|
| 111 |
// const o = this.offset; |
| 112 |
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.NONE); |
| 113 |
// HACK cases like (STILL DOES NOT WORK FOR NESTED) |
| 114 |
// aa|X |
| 115 |
// aa<X|[]>X_ - this will not work |
| 116 |
// if (o && o === this.offset && this.block instanceof PatternInputDefinition) continue; |
| 117 |
return true; |
| 118 |
}); |
| 119 |
} |
| 120 |
pushRightBeforeRequired() { |
| 121 |
return this._pushRight(() => { |
| 122 |
if (this.block.isFixed || this.block.isOptional && !this.block.value) return; |
| 123 |
|
| 124 |
// TODO check |[*]XX_ |
| 125 |
this.offset = this.block.nearestInputPos(this.offset, DIRECTION.NONE); |
| 126 |
return true; |
| 127 |
}); |
| 128 |
} |
| 129 |
} |
| 130 |
|
| 131 |
export { PatternCursor as default }; |
| 132 |
|