vmes-flowable
Version:
ceshibao
151 lines (122 loc) • 3.2 kB
JavaScript
;
/**
* Calculate the selection update for the given
* current and new input values.
*
* @param {Object} currentSelection as {start, end}
* @param {String} currentValue
* @param {String} newValue
*
* @return {Object} newSelection as {start, end}
*/
function calculateUpdate(currentSelection, currentValue, newValue) {
var currentCursor = currentSelection.start,
newCursor = currentCursor,
diff = newValue.length - currentValue.length,
idx;
var lengthDelta = newValue.length - currentValue.length;
var currentTail = currentValue.substring(currentCursor);
// check if we can remove common ending from the equation
// to be able to properly detect a selection change for
// the following scenarios:
//
// * (AAATTT|TF) => (AAAT|TF)
// * (AAAT|TF) => (AAATTT|TF)
//
if (newValue.lastIndexOf(currentTail) === newValue.length - currentTail.length) {
currentValue = currentValue.substring(0, currentValue.length - currentTail.length);
newValue = newValue.substring(0, newValue.length - currentTail.length);
}
// diff
var diff = createDiff(currentValue, newValue);
if (diff) {
if (diff.type === 'remove') {
newCursor = diff.newStart;
} else {
newCursor = diff.newEnd;
}
}
return range(newCursor);
}
module.exports = calculateUpdate;
function createDiff(currentValue, newValue) {
var insert;
var l_str, l_char, l_idx = 0,
s_str, s_char, s_idx = 0;
if (newValue.length > currentValue.length) {
l_str = newValue;
s_str = currentValue;
} else {
l_str = currentValue;
s_str = newValue;
}
// assume there will be only one insert / remove and
// detect that _first_ edit operation only
while (l_idx < l_str.length) {
l_char = l_str.charAt(l_idx);
s_char = s_str.charAt(s_idx);
// chars no not equal
if (l_char !== s_char) {
if (!insert) {
insert = {
l_start: l_idx,
s_start: s_idx
};
}
l_idx++;
}
// chars equal (again?)
else {
if (insert && !insert.complete) {
insert.l_end = l_idx;
insert.s_end = s_idx;
insert.complete = true;
}
s_idx++;
l_idx++;
}
}
if (insert && !insert.complete) {
insert.complete = true;
insert.s_end = s_str.length;
insert.l_end = l_str.length;
}
// no diff
if (!insert) {
return;
}
if (newValue.length > currentValue.length) {
return {
newStart: insert.l_start,
newEnd: insert.l_end,
type: 'add'
};
} else {
return {
newStart: insert.s_start,
newEnd: insert.s_end,
type: newValue.length < currentValue.length ? 'remove' : 'replace'
};
}
}
/**
* Utility method for creating a new selection range {start, end} object.
*
* @param {Number} start
* @param {Number} [end]
*
* @return {Object} selection range as {start, end}
*/
function range(start, end) {
return {
start: start,
end: end === undefined ? start : end
};
}
module.exports.range = range;
function splitStr(str, position) {
return {
before: str.substring(0, position),
after: str.substring(position)
};
}