Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Hanzel <mhanzel@gitlab.com>2019-06-13 09:17:41 +0300
committerMartin Hanzel <mhanzel@gitlab.com>2019-06-13 09:17:41 +0300
commitfe07976daa98a377a0d7892c1fbd5e40794a8426 (patch)
treed3951936f73a197eba93363e7101b136ba18883c
parent7d6b3cc3db40b569b968424b4c9fbd9480dfbec3 (diff)
Add setRangeText custom implemenetation
-rw-r--r--app/assets/javascripts/gl_form.js160
-rw-r--r--app/assets/javascripts/helpers/indent_helper.js69
2 files changed, 143 insertions, 86 deletions
diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js
index b470c075da6..d941db6d0c0 100644
--- a/app/assets/javascripts/gl_form.js
+++ b/app/assets/javascripts/gl_form.js
@@ -3,9 +3,9 @@ import autosize from 'autosize';
import GfmAutoComplete, { defaultAutocompleteConfig } from 'ee_else_ce/gfm_auto_complete';
import dropzoneInput from './dropzone_input';
import { addMarkdownListeners, removeMarkdownListeners } from './lib/utils/text_markdown';
-import IndentHelper from './helpers/indent_helper';
-import { getPlatformLeaderKeyHTML, keystroke } from './lib/utils/common_utils';
-import UndoStack from './lib/utils/undo_stack';
+// import IndentHelper from './helpers/indent_helper';
+import { getPlatformLeaderKeyHTML } from './lib/utils/common_utils';
+// import UndoStack from './lib/utils/undo_stack';
export default class GLForm {
constructor(form, enableGFM = {}) {
@@ -23,8 +23,8 @@ export default class GLForm {
}
});
- this.undoStack = new UndoStack();
- this.indentHelper = new IndentHelper(this.textarea[0]);
+ // this.undoStack = new UndoStack();
+ // this.indentHelper = new IndentHelper(this.textarea[0]);
// This shows the indent help text in the Wiki editor, since it's still a
// HAML component
@@ -100,83 +100,83 @@ export default class GLForm {
clearEventListeners() {
this.textarea.off('focus');
this.textarea.off('blur');
- this.textarea.off('keydown');
+ // this.textarea.off('keydown');
removeMarkdownListeners(this.form);
}
- setState(state) {
- const selection = [this.textarea[0].selectionStart, this.textarea[0].selectionEnd];
- this.textarea.val(state);
- this.textarea[0].setSelectionRange(selection[0], selection[1]);
- }
-
- handleUndo(event) {
- /*
- Custom undo/redo stack.
- We need this because the toolbar buttons and indentation helpers mess with
- the browser's native undo/redo capability.
- */
-
- const content = this.textarea.val();
- const { selectionStart, selectionEnd } = this.textarea[0];
- const stack = this.undoStack;
-
- if (stack.isEmpty()) {
- // ==== Save initial state in undo history ====
- stack.save(content);
- }
-
- if (keystroke(event, 'Leader+Z')) {
- // ==== Undo ====
- event.preventDefault();
- stack.save(content);
- if (stack.canUndo()) {
- this.setState(stack.undo());
- }
- } else if (keystroke(event, 'Leader+Shift+Z') || keystroke(event, 'Leader+Y')) {
- // ==== Redo ====
- event.preventDefault();
- if (stack.canRedo()) {
- this.setState(stack.redo());
- }
- } else if (keystroke(event, 'Space') || keystroke(event, 'Enter')) {
- // ==== Save after finishing a word ====
- stack.save(content);
- } else if (selectionStart !== selectionEnd) {
- // ==== Save if killing a large selection ====
- stack.save(content);
- } else if (content === '') {
- // ==== Save if deleting everything ====
- stack.save('');
- } else {
- // ==== Save after 1 second of inactivity ====
- stack.scheduleSave(content);
- }
- }
-
- handleIndent(event) {
- if (keystroke(event, 'Leader+[')) {
- // ==== Unindent selected lines ====
- event.preventDefault();
- this.indentHelper.unindent();
- } else if (keystroke(event, 'Leader+]')) {
- // ==== Indent selected lines ====
- event.preventDefault();
- this.indentHelper.indent();
- } else if (keystroke(event, 'Enter')) {
- // ==== Auto-indent new lines ====
- event.preventDefault();
- this.indentHelper.newline();
- } else if (keystroke(event, 'Backspace')) {
- // ==== Auto-delete indents at the beginning of the line ====
- this.indentHelper.backspace(event);
- }
- }
-
- handleKeyShortcuts(event) {
- this.handleIndent(event);
- this.handleUndo(event);
- }
+ // setState(state) {
+ // const selection = [this.textarea[0].selectionStart, this.textarea[0].selectionEnd];
+ // this.textarea.val(state);
+ // this.textarea[0].setSelectionRange(selection[0], selection[1]);
+ // }
+
+ // handleUndo(event) {
+ // /*
+ // Custom undo/redo stack.
+ // We need this because the toolbar buttons and indentation helpers mess with
+ // the browser's native undo/redo capability.
+ // */
+ //
+ // const content = this.textarea.val();
+ // const { selectionStart, selectionEnd } = this.textarea[0];
+ // const stack = this.undoStack;
+ //
+ // if (stack.isEmpty()) {
+ // // ==== Save initial state in undo history ====
+ // stack.save(content);
+ // }
+ //
+ // if (keystroke(event, 'Leader+Z')) {
+ // // ==== Undo ====
+ // event.preventDefault();
+ // stack.save(content);
+ // if (stack.canUndo()) {
+ // this.setState(stack.undo());
+ // }
+ // } else if (keystroke(event, 'Leader+Shift+Z') || keystroke(event, 'Leader+Y')) {
+ // // ==== Redo ====
+ // event.preventDefault();
+ // if (stack.canRedo()) {
+ // this.setState(stack.redo());
+ // }
+ // } else if (keystroke(event, 'Space') || keystroke(event, 'Enter')) {
+ // // ==== Save after finishing a word ====
+ // stack.save(content);
+ // } else if (selectionStart !== selectionEnd) {
+ // // ==== Save if killing a large selection ====
+ // stack.save(content);
+ // } else if (content === '') {
+ // // ==== Save if deleting everything ====
+ // stack.save('');
+ // } else {
+ // // ==== Save after 1 second of inactivity ====
+ // stack.scheduleSave(content);
+ // }
+ // }
+ //
+ // handleIndent(event) {
+ // if (keystroke(event, 'Leader+[')) {
+ // // ==== Unindent selected lines ====
+ // event.preventDefault();
+ // this.indentHelper.unindent();
+ // } else if (keystroke(event, 'Leader+]')) {
+ // // ==== Indent selected lines ====
+ // event.preventDefault();
+ // this.indentHelper.indent();
+ // } else if (keystroke(event, 'Enter')) {
+ // // ==== Auto-indent new lines ====
+ // event.preventDefault();
+ // this.indentHelper.newline();
+ // } else if (keystroke(event, 'Backspace')) {
+ // // ==== Auto-delete indents at the beginning of the line ====
+ // this.indentHelper.backspace(event);
+ // }
+ // }
+ //
+ // handleKeyShortcuts(event) {
+ // this.handleIndent(event);
+ // this.handleUndo(event);
+ // }
addEventListeners() {
this.textarea.on('focus', function focusTextArea() {
@@ -189,6 +189,6 @@ export default class GLForm {
.closest('.md-area')
.removeClass('is-focused');
});
- this.textarea.on('keydown', e => this.handleKeyShortcuts(e.originalEvent));
+ // this.textarea.on('keydown', e => this.handleKeyShortcuts(e.originalEvent));
}
}
diff --git a/app/assets/javascripts/helpers/indent_helper.js b/app/assets/javascripts/helpers/indent_helper.js
index 3641551471f..203ec493a26 100644
--- a/app/assets/javascripts/helpers/indent_helper.js
+++ b/app/assets/javascripts/helpers/indent_helper.js
@@ -32,6 +32,63 @@ export default class IndentHelper {
}
/**
+ * Re-implementation of textarea's setRangeText method, because IE/Edge don't support it.
+ *
+ * @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#dom-textarea%2Finput-setrangetext
+ */
+ setRangeText(replacement, start, end, selectMode) {
+ // Disable eslint to remain as faithful as possible to the above linked spec
+ /* eslint-disable no-param-reassign, no-case-declarations */
+ const text = this.element.value;
+
+ if (start > end) {
+ throw new RangeError('setRangeText: start index must be less than or equal to end index');
+ }
+
+ // Clamp to [0, len]
+ start = Math.max(0, Math.min(start, text.length));
+ end = Math.max(0, Math.min(end, text.length));
+
+ let selection = { start: this.element.selectionStart, end: this.element.selectionEnd };
+
+ this.element.value = text.slice(0, start) + replacement + text.slice(end);
+
+ const newLength = replacement.length;
+ const newEnd = start + newLength;
+
+ switch (selectMode) {
+ case 'select':
+ selection = { start, newEnd };
+ break;
+ case 'start':
+ selection = { start, end: start };
+ break;
+ case 'end':
+ selection = { start: newEnd, end: newEnd };
+ break;
+ case 'preserve':
+ default:
+ const oldLength = end - start;
+ const delta = newLength - oldLength;
+ if (selection.start > end) {
+ selection.start += delta;
+ } else if (selection.start > start) {
+ selection.start = start;
+ }
+ if (selection.end > end) {
+ selection.end += delta;
+ } else if (selection.end > start) {
+ selection.end = newEnd;
+ }
+ }
+
+ this.element.setSelectionRange(selection.start, selection.end);
+
+ /* eslint-enable no-param-reassign, no-case-declarations */
+ }
+
+
+ /**
* Returns an array of lines in the textarea, with information about their
* start/end offsets and whether they are included in the current selection.
*/
@@ -65,11 +122,11 @@ export default class IndentHelper {
// Special case: if cursor is at the beginning of the line, move it one
// indent right.
const line = selectedLines[0];
- this.element.setRangeText(this.seq, line.start, line.start, 'end');
+ this.setRangeText(this.seq, line.start, line.start, 'end');
} else {
selectedLines.reverse();
selectedLines.forEach(line => {
- this.element.setRangeText(INDENT_SEQUENCE, line.start, line.start, 'preserve');
+ this.setRangeText(INDENT_SEQUENCE, line.start, line.start, 'preserve');
});
}
}
@@ -83,7 +140,7 @@ export default class IndentHelper {
lines
.filter(line => line.text.startsWith(this.seq))
.forEach(line => {
- this.element.setRangeText('', line.start, line.start + this.seq.length, 'preserve');
+ this.setRangeText('', line.start, line.start + this.seq.length, 'preserve');
});
}
@@ -95,13 +152,13 @@ export default class IndentHelper {
if (this.isRangeSelection()) {
// Manually kill the selection before calculating the indent
- this.element.setRangeText('', start, end, 'start');
+ this.setRangeText('', start, end, 'start');
}
// Auto-indent the next line
const currentLine = this.splitLines().find(line => line.end >= start);
const spaces = countLeftSpaces(currentLine.text);
- this.element.setRangeText(`\n${' '.repeat(spaces)}`, start, start, 'end');
+ this.setRangeText(`\n${' '.repeat(spaces)}`, start, start, 'end');
}
/**
@@ -123,7 +180,7 @@ export default class IndentHelper {
if (spacesToDelete === 0) {
spacesToDelete = this.seq.length;
}
- this.element.setRangeText('', start - spacesToDelete, start, 'start');
+ this.setRangeText('', start - spacesToDelete, start, 'start');
}
}
}