446 lines
12 KiB
JavaScript
446 lines
12 KiB
JavaScript
import { _ as _createClass, a as _classCallCheck, f as _slicedToArray } from '../_rollupPluginBabelHelpers-b054ecd2.js';
|
|
import ChangeDetails from '../core/change-details.js';
|
|
import ContinuousTailDetails from '../core/continuous-tail-details.js';
|
|
import { isString, normalizePrepare, forceDirection, DIRECTION } from '../core/utils.js';
|
|
import IMask from '../core/holder.js';
|
|
|
|
/** Supported mask type */
|
|
|
|
/** Provides common masking stuff */
|
|
var Masked = /*#__PURE__*/function () {
|
|
// $Shape<MaskedOptions>; TODO after fix https://github.com/facebook/flow/issues/4773
|
|
|
|
/** @type {Mask} */
|
|
|
|
/** */
|
|
// $FlowFixMe no ideas
|
|
|
|
/** Transforms value before mask processing */
|
|
|
|
/** Validates if value is acceptable */
|
|
|
|
/** Does additional processing in the end of editing */
|
|
|
|
/** Format typed value to string */
|
|
|
|
/** Parse strgin to get typed value */
|
|
|
|
/** Enable characters overwriting */
|
|
|
|
/** */
|
|
|
|
/** */
|
|
function Masked(opts) {
|
|
_classCallCheck(this, Masked);
|
|
|
|
this._value = '';
|
|
|
|
this._update(Object.assign({}, Masked.DEFAULTS, opts));
|
|
|
|
this.isInitialized = true;
|
|
}
|
|
/** Sets and applies new options */
|
|
|
|
|
|
_createClass(Masked, [{
|
|
key: "updateOptions",
|
|
value: function updateOptions(opts) {
|
|
if (!Object.keys(opts).length) return; // $FlowFixMe
|
|
|
|
this.withValueRefresh(this._update.bind(this, opts));
|
|
}
|
|
/**
|
|
Sets new options
|
|
@protected
|
|
*/
|
|
|
|
}, {
|
|
key: "_update",
|
|
value: function _update(opts) {
|
|
Object.assign(this, opts);
|
|
}
|
|
/** Mask state */
|
|
|
|
}, {
|
|
key: "state",
|
|
get: function get() {
|
|
return {
|
|
_value: this.value
|
|
};
|
|
},
|
|
set: function set(state) {
|
|
this._value = state._value;
|
|
}
|
|
/** Resets value */
|
|
|
|
}, {
|
|
key: "reset",
|
|
value: function reset() {
|
|
this._value = '';
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "value",
|
|
get: function get() {
|
|
return this._value;
|
|
},
|
|
set: function set(value) {
|
|
this.resolve(value);
|
|
}
|
|
/** Resolve new value */
|
|
|
|
}, {
|
|
key: "resolve",
|
|
value: function resolve(value) {
|
|
this.reset();
|
|
this.append(value, {
|
|
input: true
|
|
}, '');
|
|
this.doCommit();
|
|
return this.value;
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "unmaskedValue",
|
|
get: function get() {
|
|
return this.value;
|
|
},
|
|
set: function set(value) {
|
|
this.reset();
|
|
this.append(value, {}, '');
|
|
this.doCommit();
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "typedValue",
|
|
get: function get() {
|
|
return this.doParse(this.value);
|
|
},
|
|
set: function set(value) {
|
|
this.value = this.doFormat(value);
|
|
}
|
|
/** Value that includes raw user input */
|
|
|
|
}, {
|
|
key: "rawInputValue",
|
|
get: function get() {
|
|
return this.extractInput(0, this.value.length, {
|
|
raw: true
|
|
});
|
|
},
|
|
set: function set(value) {
|
|
this.reset();
|
|
this.append(value, {
|
|
raw: true
|
|
}, '');
|
|
this.doCommit();
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "isComplete",
|
|
get: function get() {
|
|
return true;
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "isFilled",
|
|
get: function get() {
|
|
return this.isComplete;
|
|
}
|
|
/** Finds nearest input position in direction */
|
|
|
|
}, {
|
|
key: "nearestInputPos",
|
|
value: function nearestInputPos(cursorPos, direction) {
|
|
return cursorPos;
|
|
}
|
|
/** Extracts value in range considering flags */
|
|
|
|
}, {
|
|
key: "extractInput",
|
|
value: function extractInput() {
|
|
var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
return this.value.slice(fromPos, toPos);
|
|
}
|
|
/** Extracts tail in range */
|
|
|
|
}, {
|
|
key: "extractTail",
|
|
value: function extractTail() {
|
|
var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
return new ContinuousTailDetails(this.extractInput(fromPos, toPos), fromPos);
|
|
}
|
|
/** Appends tail */
|
|
// $FlowFixMe no ideas
|
|
|
|
}, {
|
|
key: "appendTail",
|
|
value: function appendTail(tail) {
|
|
if (isString(tail)) tail = new ContinuousTailDetails(String(tail));
|
|
return tail.appendTo(this);
|
|
}
|
|
/** Appends char */
|
|
|
|
}, {
|
|
key: "_appendCharRaw",
|
|
value: function _appendCharRaw(ch) {
|
|
if (!ch) return new ChangeDetails();
|
|
this._value += ch;
|
|
return new ChangeDetails({
|
|
inserted: ch,
|
|
rawInserted: ch
|
|
});
|
|
}
|
|
/** Appends char */
|
|
|
|
}, {
|
|
key: "_appendChar",
|
|
value: function _appendChar(ch) {
|
|
var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
var checkTail = arguments.length > 2 ? arguments[2] : undefined;
|
|
var consistentState = this.state;
|
|
var details;
|
|
|
|
var _normalizePrepare = normalizePrepare(this.doPrepare(ch, flags));
|
|
|
|
var _normalizePrepare2 = _slicedToArray(_normalizePrepare, 2);
|
|
|
|
ch = _normalizePrepare2[0];
|
|
details = _normalizePrepare2[1];
|
|
details = details.aggregate(this._appendCharRaw(ch, flags));
|
|
|
|
if (details.inserted) {
|
|
var consistentTail;
|
|
var appended = this.doValidate(flags) !== false;
|
|
|
|
if (appended && checkTail != null) {
|
|
// validation ok, check tail
|
|
var beforeTailState = this.state;
|
|
|
|
if (this.overwrite === true) {
|
|
consistentTail = checkTail.state;
|
|
checkTail.unshift(this.value.length);
|
|
}
|
|
|
|
var tailDetails = this.appendTail(checkTail);
|
|
appended = tailDetails.rawInserted === checkTail.toString(); // not ok, try shift
|
|
|
|
if (!(appended && tailDetails.inserted) && this.overwrite === 'shift') {
|
|
this.state = beforeTailState;
|
|
consistentTail = checkTail.state;
|
|
checkTail.shift();
|
|
tailDetails = this.appendTail(checkTail);
|
|
appended = tailDetails.rawInserted === checkTail.toString();
|
|
} // if ok, rollback state after tail
|
|
|
|
|
|
if (appended && tailDetails.inserted) this.state = beforeTailState;
|
|
} // revert all if something went wrong
|
|
|
|
|
|
if (!appended) {
|
|
details = new ChangeDetails();
|
|
this.state = consistentState;
|
|
if (checkTail && consistentTail) checkTail.state = consistentTail;
|
|
}
|
|
}
|
|
|
|
return details;
|
|
}
|
|
/** Appends optional placeholder at end */
|
|
|
|
}, {
|
|
key: "_appendPlaceholder",
|
|
value: function _appendPlaceholder() {
|
|
return new ChangeDetails();
|
|
}
|
|
/** Appends optional eager placeholder at end */
|
|
|
|
}, {
|
|
key: "_appendEager",
|
|
value: function _appendEager() {
|
|
return new ChangeDetails();
|
|
}
|
|
/** Appends symbols considering flags */
|
|
// $FlowFixMe no ideas
|
|
|
|
}, {
|
|
key: "append",
|
|
value: function append(str, flags, tail) {
|
|
if (!isString(str)) throw new Error('value should be string');
|
|
var details = new ChangeDetails();
|
|
var checkTail = isString(tail) ? new ContinuousTailDetails(String(tail)) : tail;
|
|
if (flags && flags.tail) flags._beforeTailState = this.state;
|
|
|
|
for (var ci = 0; ci < str.length; ++ci) {
|
|
details.aggregate(this._appendChar(str[ci], flags, checkTail));
|
|
} // append tail but aggregate only tailShift
|
|
|
|
|
|
if (checkTail != null) {
|
|
details.tailShift += this.appendTail(checkTail).tailShift; // TODO it's a good idea to clear state after appending ends
|
|
// but it causes bugs when one append calls another (when dynamic dispatch set rawInputValue)
|
|
// this._resetBeforeTailState();
|
|
}
|
|
|
|
if (this.eager && flags !== null && flags !== void 0 && flags.input && str) {
|
|
details.aggregate(this._appendEager());
|
|
}
|
|
|
|
return details;
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "remove",
|
|
value: function remove() {
|
|
var fromPos = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
var toPos = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.value.length;
|
|
this._value = this.value.slice(0, fromPos) + this.value.slice(toPos);
|
|
return new ChangeDetails();
|
|
}
|
|
/** Calls function and reapplies current value */
|
|
|
|
}, {
|
|
key: "withValueRefresh",
|
|
value: function withValueRefresh(fn) {
|
|
if (this._refreshing || !this.isInitialized) return fn();
|
|
this._refreshing = true;
|
|
var rawInput = this.rawInputValue;
|
|
var value = this.value;
|
|
var ret = fn();
|
|
this.rawInputValue = rawInput; // append lost trailing chars at end
|
|
|
|
if (this.value && this.value !== value && value.indexOf(this.value) === 0) {
|
|
this.append(value.slice(this.value.length), {}, '');
|
|
}
|
|
|
|
delete this._refreshing;
|
|
return ret;
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "runIsolated",
|
|
value: function runIsolated(fn) {
|
|
if (this._isolated || !this.isInitialized) return fn(this);
|
|
this._isolated = true;
|
|
var state = this.state;
|
|
var ret = fn(this);
|
|
this.state = state;
|
|
delete this._isolated;
|
|
return ret;
|
|
}
|
|
/**
|
|
Prepares string before mask processing
|
|
@protected
|
|
*/
|
|
|
|
}, {
|
|
key: "doPrepare",
|
|
value: function doPrepare(str) {
|
|
var flags = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
return this.prepare ? this.prepare(str, this, flags) : str;
|
|
}
|
|
/**
|
|
Validates if value is acceptable
|
|
@protected
|
|
*/
|
|
|
|
}, {
|
|
key: "doValidate",
|
|
value: function doValidate(flags) {
|
|
return (!this.validate || this.validate(this.value, this, flags)) && (!this.parent || this.parent.doValidate(flags));
|
|
}
|
|
/**
|
|
Does additional processing in the end of editing
|
|
@protected
|
|
*/
|
|
|
|
}, {
|
|
key: "doCommit",
|
|
value: function doCommit() {
|
|
if (this.commit) this.commit(this.value, this);
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "doFormat",
|
|
value: function doFormat(value) {
|
|
return this.format ? this.format(value, this) : value;
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "doParse",
|
|
value: function doParse(str) {
|
|
return this.parse ? this.parse(str, this) : str;
|
|
}
|
|
/** */
|
|
|
|
}, {
|
|
key: "splice",
|
|
value: function splice(start, deleteCount, inserted, removeDirection) {
|
|
var tailPos = start + deleteCount;
|
|
var tail = this.extractTail(tailPos);
|
|
var oldRawValue;
|
|
|
|
if (this.eager) {
|
|
removeDirection = forceDirection(removeDirection);
|
|
oldRawValue = this.extractInput(0, tailPos, {
|
|
raw: true
|
|
});
|
|
}
|
|
|
|
var startChangePos = this.nearestInputPos(start, deleteCount > 1 && start !== 0 && !this.eager ? DIRECTION.NONE : removeDirection);
|
|
var details = new ChangeDetails({
|
|
tailShift: startChangePos - start // adjust tailShift if start was aligned
|
|
|
|
}).aggregate(this.remove(startChangePos));
|
|
|
|
if (this.eager && removeDirection !== DIRECTION.NONE && oldRawValue === this.rawInputValue) {
|
|
if (removeDirection === DIRECTION.FORCE_LEFT) {
|
|
var valLength;
|
|
|
|
while (oldRawValue === this.rawInputValue && (valLength = this.value.length)) {
|
|
details.aggregate(new ChangeDetails({
|
|
tailShift: -1
|
|
})).aggregate(this.remove(valLength - 1));
|
|
}
|
|
} else if (removeDirection === DIRECTION.FORCE_RIGHT) {
|
|
tail.unshift();
|
|
}
|
|
}
|
|
|
|
return details.aggregate(this.append(inserted, {
|
|
input: true
|
|
}, tail));
|
|
}
|
|
}, {
|
|
key: "maskEquals",
|
|
value: function maskEquals(mask) {
|
|
return this.mask === mask;
|
|
}
|
|
}]);
|
|
|
|
return Masked;
|
|
}();
|
|
Masked.DEFAULTS = {
|
|
format: function format(v) {
|
|
return v;
|
|
},
|
|
parse: function parse(v) {
|
|
return v;
|
|
}
|
|
};
|
|
IMask.Masked = Masked;
|
|
|
|
export { Masked as default };
|