mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-05-27 14:33:59 +00:00
fixed behaviour of shift click and shift keys (#3274)
removed some glitches, removed duplicate code
This commit is contained in:
parent
77f37db3c9
commit
07094a4ec5
4 changed files with 160 additions and 211 deletions
|
|
@ -824,6 +824,58 @@
|
|||
*/
|
||||
insertNewline: function() {
|
||||
this.insertChars('\n');
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the selectionStart and selectionEnd according to the ne postion of cursor
|
||||
* mimic the key - mouse navigation when shift is pressed.
|
||||
*/
|
||||
setSelectionStartEndWithShift: function(start, end, newSelection) {
|
||||
if (newSelection <= start) {
|
||||
if (end === start) {
|
||||
this._selectionDirection = 'left';
|
||||
}
|
||||
else if (this._selectionDirection === 'right') {
|
||||
this._selectionDirection = 'left';
|
||||
this.selectionEnd = start;
|
||||
}
|
||||
this.selectionStart = newSelection;
|
||||
}
|
||||
else if (newSelection > start && newSelection < end) {
|
||||
if (this._selectionDirection === 'right') {
|
||||
this.selectionEnd = newSelection;
|
||||
}
|
||||
else {
|
||||
this.selectionStart = newSelection;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// newSelection is > selection start and end
|
||||
if (end === start) {
|
||||
this._selectionDirection = 'right';
|
||||
}
|
||||
else if (this._selectionDirection === 'left') {
|
||||
this._selectionDirection = 'right';
|
||||
this.selectionStart = end;
|
||||
}
|
||||
this.selectionEnd = newSelection;
|
||||
}
|
||||
},
|
||||
|
||||
setSelectionInBoundaries: function() {
|
||||
var length = this.text.length;
|
||||
if (this.selectionStart > length) {
|
||||
this.selectionStart = length;
|
||||
}
|
||||
else if (this.selectionStart < 0) {
|
||||
this.selectionStart = 0;
|
||||
}
|
||||
if (this.selectionEnd > length) {
|
||||
this.selectionEnd = length;
|
||||
}
|
||||
else if (this.selectionEnd < 0) {
|
||||
this.selectionEnd = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -148,35 +148,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
var newSelection = this.getSelectionStartFromPointer(e),
|
||||
start = this.selectionStart, end = this.selectionEnd;
|
||||
if (e.shiftKey) {
|
||||
if (newSelection < start) {
|
||||
if (end === start) {
|
||||
this._selectionDirection = 'left';
|
||||
}
|
||||
else if (this._selectionDirection === 'right') {
|
||||
this._selectionDirection = 'left';
|
||||
this.selectionEnd = start;
|
||||
}
|
||||
this.selectionStart = newSelection;
|
||||
}
|
||||
else if (newSelection > start && newSelection < end) {
|
||||
if (this._selectionDirection === 'right') {
|
||||
this.selectionEnd = newSelection;
|
||||
}
|
||||
else {
|
||||
this.selectionStart = newSelection;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// newSelection is > selection start and end
|
||||
if (end === start) {
|
||||
this._selectionDirection = 'right';
|
||||
}
|
||||
else if (this._selectionDirection === 'left') {
|
||||
this._selectionDirection = 'right';
|
||||
this.selectionStart = end;
|
||||
}
|
||||
this.selectionEnd = newSelection;
|
||||
}
|
||||
this.setSelectionStartEndWithShift(start, end, newSelection);
|
||||
}
|
||||
else {
|
||||
this.selectionStart = newSelection;
|
||||
|
|
|
|||
|
|
@ -255,6 +255,25 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
return (e && e.clipboardData) || fabric.window.clipboardData;
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds the width in pixels before the cursor on the same line
|
||||
* @private
|
||||
* @param {Number} lineIndex
|
||||
* @param {Number} charIndex
|
||||
* @return {Number} widthBeforeCursor width before cursor
|
||||
*/
|
||||
_getWidthBeforeCursor: function(lineIndex, charIndex) {
|
||||
var textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex),
|
||||
widthOfLine = this._getLineWidth(this.ctx, lineIndex),
|
||||
widthBeforeCursor = this._getLineLeftOffset(widthOfLine), _char;
|
||||
|
||||
for (var i = 0, len = textBeforeCursor.length; i < len; i++) {
|
||||
_char = textBeforeCursor[i];
|
||||
widthBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);
|
||||
}
|
||||
return widthBeforeCursor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets start offset of a selection
|
||||
* @param {Event} e Event object
|
||||
|
|
@ -262,64 +281,89 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
* @return {Number}
|
||||
*/
|
||||
getDownCursorOffset: function(e, isRight) {
|
||||
var selectionProp = isRight ? this.selectionEnd : this.selectionStart,
|
||||
var selectionProp = this._getSelectionForOffset(e, isRight),
|
||||
cursorLocation = this.get2DCursorLocation(selectionProp),
|
||||
_char, lineLeftOffset, lineIndex = cursorLocation.lineIndex,
|
||||
textOnSameLineBeforeCursor = this._textLines[lineIndex].slice(0, cursorLocation.charIndex),
|
||||
textOnSameLineAfterCursor = this._textLines[lineIndex].slice(cursorLocation.charIndex),
|
||||
textOnNextLine = this._textLines[lineIndex + 1] || '';
|
||||
|
||||
lineIndex = cursorLocation.lineIndex;
|
||||
// if on last line, down cursor goes to end of line
|
||||
if (lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) {
|
||||
|
||||
// move to the end of a text
|
||||
return this.text.length - selectionProp;
|
||||
}
|
||||
var charIndex = cursorLocation.charIndex,
|
||||
widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),
|
||||
indexOnOtherLine = this._getIndexOnLine(lineIndex + 1, widthBeforeCursor),
|
||||
textAfterCursor = this._textLines[lineIndex].slice(charIndex);
|
||||
|
||||
var widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, lineIndex);
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor);
|
||||
|
||||
var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset;
|
||||
|
||||
for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) {
|
||||
_char = textOnSameLineBeforeCursor[i];
|
||||
widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);
|
||||
}
|
||||
|
||||
var indexOnNextLine = this._getIndexOnNextLine(
|
||||
cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor);
|
||||
|
||||
return textOnSameLineAfterCursor.length + 1 + indexOnNextLine;
|
||||
return textAfterCursor.length + indexOnOtherLine + 2;
|
||||
},
|
||||
|
||||
/**
|
||||
* private
|
||||
* Helps finding if the offset should be counted from Start or End
|
||||
* @param {Event} e Event object
|
||||
* @param {Boolean} isRight
|
||||
* @return {Number}
|
||||
*/
|
||||
_getSelectionForOffset: function(e, isRight) {
|
||||
if (e.shiftKey && this.selectionStart !== this.selectionEnd && isRight) {
|
||||
return this.selectionEnd;
|
||||
}
|
||||
else {
|
||||
return this.selectionStart;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} e Event object
|
||||
* @param {Boolean} isRight
|
||||
* @return {Number}
|
||||
*/
|
||||
getUpCursorOffset: function(e, isRight) {
|
||||
var selectionProp = this._getSelectionForOffset(e, isRight),
|
||||
cursorLocation = this.get2DCursorLocation(selectionProp),
|
||||
lineIndex = cursorLocation.lineIndex;
|
||||
if (lineIndex === 0 || e.metaKey || e.keyCode === 33) {
|
||||
// if on first line, up cursor goes to start of line
|
||||
return -selectionProp;
|
||||
}
|
||||
var charIndex = cursorLocation.charIndex,
|
||||
widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),
|
||||
indexOnOtherLine = this._getIndexOnLine(lineIndex - 1, widthBeforeCursor),
|
||||
textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex);
|
||||
// return a negative offset
|
||||
return -this._textLines[lineIndex - 1].length + indexOnOtherLine - textBeforeCursor.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* find for a given width it founds the matching character.
|
||||
* @private
|
||||
*/
|
||||
_getIndexOnNextLine: function(cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor) {
|
||||
var lineIndex = cursorLocation.lineIndex + 1,
|
||||
widthOfNextLine = this._getLineWidth(this.ctx, lineIndex),
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfNextLine),
|
||||
widthOfCharsOnNextLine = lineLeftOffset,
|
||||
indexOnNextLine = 0,
|
||||
_getIndexOnLine: function(lineIndex, width) {
|
||||
|
||||
var widthOfLine = this._getLineWidth(this.ctx, lineIndex),
|
||||
textOnLine = this._textLines[lineIndex],
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfLine),
|
||||
widthOfCharsOnLine = lineLeftOffset,
|
||||
indexOnLine = 0,
|
||||
foundMatch;
|
||||
|
||||
for (var j = 0, jlen = textOnNextLine.length; j < jlen; j++) {
|
||||
for (var j = 0, jlen = textOnLine.length; j < jlen; j++) {
|
||||
|
||||
var _char = textOnNextLine[j],
|
||||
var _char = textOnLine[j],
|
||||
widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j);
|
||||
|
||||
widthOfCharsOnNextLine += widthOfChar;
|
||||
widthOfCharsOnLine += widthOfChar;
|
||||
|
||||
if (widthOfCharsOnNextLine > widthOfCharsOnSameLineBeforeCursor) {
|
||||
if (widthOfCharsOnLine > width) {
|
||||
|
||||
foundMatch = true;
|
||||
|
||||
var leftEdge = widthOfCharsOnNextLine - widthOfChar,
|
||||
rightEdge = widthOfCharsOnNextLine,
|
||||
offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor),
|
||||
offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor);
|
||||
var leftEdge = widthOfCharsOnLine - widthOfChar,
|
||||
rightEdge = widthOfCharsOnLine,
|
||||
offsetFromLeftEdge = Math.abs(leftEdge - width),
|
||||
offsetFromRightEdge = Math.abs(rightEdge - width);
|
||||
|
||||
indexOnNextLine = offsetFromRightEdge < offsetFromLeftEdge ? j + 1 : j;
|
||||
indexOnLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -327,12 +371,13 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
|
||||
// reached end
|
||||
if (!foundMatch) {
|
||||
indexOnNextLine = textOnNextLine.length;
|
||||
indexOnLine = textOnLine.length - 1;
|
||||
}
|
||||
|
||||
return indexOnNextLine;
|
||||
return indexOnLine;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Moves cursor down
|
||||
* @param {Event} e Event object
|
||||
|
|
@ -344,124 +389,6 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
this._moveCursorUpOrDown('Down', e);
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves cursor down without keeping selection
|
||||
* @param {Number} offset
|
||||
*/
|
||||
moveCursorDownWithoutShift: function(offset) {
|
||||
this._selectionDirection = 'right';
|
||||
this.selectionEnd = this.selectionEnd + offset;
|
||||
this.selectionStart = this.selectionEnd;
|
||||
return offset !== 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* private
|
||||
*/
|
||||
swapSelectionPoints: function() {
|
||||
var swapSel = this.selectionEnd;
|
||||
this.selectionEnd = this.selectionStart;
|
||||
this.selectionStart = swapSel;
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves cursor down while keeping selection
|
||||
* @param {Number} offset
|
||||
*/
|
||||
moveCursorDownWithShift: function(offset) {
|
||||
if (this.selectionEnd === this.selectionStart) {
|
||||
this._selectionDirection = 'right';
|
||||
}
|
||||
if (this._selectionDirection === 'right') {
|
||||
this.selectionEnd += offset;
|
||||
}
|
||||
else {
|
||||
this.selectionStart += offset;
|
||||
}
|
||||
if (this.selectionEnd < this.selectionStart && this._selectionDirection === 'left') {
|
||||
this.swapSelectionPoints();
|
||||
this._selectionDirection = 'right';
|
||||
}
|
||||
if (this.selectionEnd > this.text.length) {
|
||||
this.selectionEnd = this.text.length;
|
||||
}
|
||||
return offset !== 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Event} e Event object
|
||||
* @param {Boolean} isRight
|
||||
* @return {Number}
|
||||
*/
|
||||
getUpCursorOffset: function(e, isRight) {
|
||||
var selectionProp = isRight ? this.selectionEnd : this.selectionStart,
|
||||
cursorLocation = this.get2DCursorLocation(selectionProp),
|
||||
lineIndex = cursorLocation.lineIndex;
|
||||
// if on first line, up cursor goes to start of line
|
||||
if (lineIndex === 0 || e.metaKey || e.keyCode === 33) {
|
||||
return selectionProp;
|
||||
}
|
||||
|
||||
var textOnSameLineBeforeCursor = this._textLines[lineIndex].slice(0, cursorLocation.charIndex),
|
||||
textOnPreviousLine = this._textLines[lineIndex - 1] || '',
|
||||
_char,
|
||||
widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, cursorLocation.lineIndex),
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor),
|
||||
widthOfCharsOnSameLineBeforeCursor = lineLeftOffset;
|
||||
|
||||
for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) {
|
||||
_char = textOnSameLineBeforeCursor[i];
|
||||
widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i);
|
||||
}
|
||||
|
||||
var indexOnPrevLine = this._getIndexOnPrevLine(
|
||||
cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor);
|
||||
|
||||
return textOnPreviousLine.length - indexOnPrevLine + textOnSameLineBeforeCursor.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getIndexOnPrevLine: function(cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor) {
|
||||
|
||||
var lineIndex = cursorLocation.lineIndex - 1,
|
||||
widthOfPreviousLine = this._getLineWidth(this.ctx, lineIndex),
|
||||
lineLeftOffset = this._getLineLeftOffset(widthOfPreviousLine),
|
||||
widthOfCharsOnPreviousLine = lineLeftOffset,
|
||||
indexOnPrevLine = 0,
|
||||
foundMatch;
|
||||
|
||||
for (var j = 0, jlen = textOnPreviousLine.length; j < jlen; j++) {
|
||||
|
||||
var _char = textOnPreviousLine[j],
|
||||
widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j);
|
||||
|
||||
widthOfCharsOnPreviousLine += widthOfChar;
|
||||
|
||||
if (widthOfCharsOnPreviousLine > widthOfCharsOnSameLineBeforeCursor) {
|
||||
|
||||
foundMatch = true;
|
||||
|
||||
var leftEdge = widthOfCharsOnPreviousLine - widthOfChar,
|
||||
rightEdge = widthOfCharsOnPreviousLine,
|
||||
offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor),
|
||||
offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor);
|
||||
|
||||
indexOnPrevLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// reached end
|
||||
if (!foundMatch) {
|
||||
indexOnPrevLine = textOnPreviousLine.length - 1;
|
||||
}
|
||||
|
||||
return indexOnPrevLine;
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves cursor up
|
||||
* @param {Event} e Event object
|
||||
|
|
@ -479,16 +406,18 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
* @param {Event} e Event object
|
||||
*/
|
||||
_moveCursorUpOrDown: function(direction, e) {
|
||||
// getUpCursorOffset
|
||||
// getDownCursorOffset
|
||||
var action = 'get' + direction + 'CursorOffset',
|
||||
moveAction = 'moveCursor' + direction,
|
||||
offset = this[action](e, this._selectionDirection === 'right');
|
||||
if (e.shiftKey) {
|
||||
moveAction += 'WithShift';
|
||||
this.moveCursorWithShift(offset);
|
||||
}
|
||||
else {
|
||||
moveAction += 'WithoutShift';
|
||||
this.moveCursorWithoutShift(offset);
|
||||
}
|
||||
if (this[moveAction](offset)) {
|
||||
if (offset !== 0) {
|
||||
this.setSelectionInBoundaries();
|
||||
this.abortCursorAnimation();
|
||||
this._currentCursorOpacity = 1;
|
||||
this.initDelayedCursor();
|
||||
|
|
@ -498,23 +427,14 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
},
|
||||
|
||||
/**
|
||||
* Moves cursor up with shift
|
||||
* Moves cursor with shift
|
||||
* @param {Number} offset
|
||||
*/
|
||||
moveCursorUpWithShift: function(offset) {
|
||||
if (this.selectionEnd === this.selectionStart) {
|
||||
this._selectionDirection = 'left';
|
||||
}
|
||||
if (this._selectionDirection === 'right') {
|
||||
this.selectionEnd -= offset;
|
||||
}
|
||||
else {
|
||||
this.selectionStart -= offset;
|
||||
}
|
||||
if (this.selectionEnd < this.selectionStart && this._selectionDirection === 'right') {
|
||||
this.swapSelectionPoints();
|
||||
this._selectionDirection = 'left';
|
||||
}
|
||||
moveCursorWithShift: function(offset) {
|
||||
var newSelection = this._selectionDirection === 'left'
|
||||
? this.selectionStart + offset
|
||||
: this.selectionEnd + offset;
|
||||
this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection);
|
||||
return offset !== 0;
|
||||
},
|
||||
|
||||
|
|
@ -522,10 +442,15 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot
|
|||
* Moves cursor up without shift
|
||||
* @param {Number} offset
|
||||
*/
|
||||
moveCursorUpWithoutShift: function(offset) {
|
||||
this._selectionDirection = 'left';
|
||||
this.selectionStart -= offset;
|
||||
this.selectionEnd = this.selectionStart;
|
||||
moveCursorWithoutShift: function(offset) {
|
||||
if (offset < 0) {
|
||||
this.selectionStart += offset;
|
||||
this.selectionEnd = this.selectionStart;
|
||||
}
|
||||
else {
|
||||
this.selectionEnd += offset;
|
||||
this.selectionStart = this.selectionEnd;
|
||||
}
|
||||
return offset !== 0;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@
|
|||
|
||||
iText.selectionStart = 28;
|
||||
iText.selectionEnd = 31;
|
||||
iText.moveCursorUp({ shiftKey: false});
|
||||
iText.moveCursorUp({ shiftKey: false });
|
||||
equal(selection, 1, 'should fire');
|
||||
equal(iText.selectionStart, 9, 'should move to upper line');
|
||||
equal(iText.selectionEnd, 9, 'should move to upper line');
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
|
||||
iText.selectionStart = 1;
|
||||
iText.selectionEnd = 4;
|
||||
iText.moveCursorDown({ shiftKey: false});
|
||||
iText.moveCursorDown({ shiftKey: false });
|
||||
equal(selection, 1, 'should fire');
|
||||
equal(iText.selectionStart, 24, 'should move to down line');
|
||||
equal(iText.selectionEnd, 24, 'should move to down line');
|
||||
|
|
@ -119,7 +119,7 @@
|
|||
|
||||
iText.selectionStart = 28;
|
||||
iText.selectionEnd = 31;
|
||||
iText.moveCursorLeft({ shiftKey: false});
|
||||
iText.moveCursorLeft({ shiftKey: false });
|
||||
equal(selection, 1, 'should fire');
|
||||
equal(iText.selectionStart, 28, 'should move to selection Start');
|
||||
equal(iText.selectionEnd, 28, 'should move to selection Start');
|
||||
|
|
|
|||
Loading…
Reference in a new issue