Add count of selected characters on text/code menu
This commit is contained in:
parent
d9746e3a84
commit
aff04b9cd0
|
@ -89,6 +89,20 @@ div.jsoneditor-menu > div.jsoneditor-modes > button.jsoneditor-separator {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.jsoneditor-menu > div.jsoneditor-curserinfo {
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.jsoneditor-menu > div.jsoneditor-curserinfo > .jsoneditor-curserinfo-label {
|
||||||
|
margin: 0 2px 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.jsoneditor-menu > div.jsoneditor-curserinfo > span {
|
||||||
|
color: white;
|
||||||
|
opacity: 0.8;
|
||||||
|
font-size: 10pt;
|
||||||
|
}
|
||||||
|
|
||||||
div.jsoneditor-menu a {
|
div.jsoneditor-menu a {
|
||||||
font-family: arial, sans-serif;
|
font-family: arial, sans-serif;
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
|
|
|
@ -77,6 +77,7 @@ textmode.create = function (container, options) {
|
||||||
this.aceEditor = undefined; // ace code editor
|
this.aceEditor = undefined; // ace code editor
|
||||||
this.textarea = undefined; // plain text editor (fallback when Ace is not available)
|
this.textarea = undefined; // plain text editor (fallback when Ace is not available)
|
||||||
this.validateSchema = null;
|
this.validateSchema = null;
|
||||||
|
this.curserInfoElements = {};
|
||||||
|
|
||||||
// create a debounced validate function
|
// create a debounced validate function
|
||||||
this._debouncedValidate = util.debounce(this.validate.bind(this), this.DEBOUNCE_INTERVAL);
|
this._debouncedValidate = util.debounce(this.validate.bind(this), this.DEBOUNCE_INTERVAL);
|
||||||
|
@ -140,6 +141,51 @@ textmode.create = function (container, options) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create curser and count info
|
||||||
|
var curserAndCountInfo = document.createElement('div');
|
||||||
|
curserAndCountInfo.className = 'jsoneditor-curserinfo';
|
||||||
|
|
||||||
|
var countLabel = document.createElement('span');
|
||||||
|
countLabel.className = 'jsoneditor-curserinfo-label';
|
||||||
|
countLabel.innerText = 'characters selected';
|
||||||
|
countLabel.style.display = 'none';
|
||||||
|
|
||||||
|
var countVal = document.createElement('span');
|
||||||
|
countVal.className = 'jsoneditor-curserinfo-count';
|
||||||
|
countVal.innerText = 0;
|
||||||
|
countVal.style.display = 'none';
|
||||||
|
|
||||||
|
this.curserInfoElements.countLabel = countLabel;
|
||||||
|
this.curserInfoElements.countVal = countVal;
|
||||||
|
|
||||||
|
curserAndCountInfo.appendChild(countVal);
|
||||||
|
curserAndCountInfo.appendChild(countLabel);
|
||||||
|
|
||||||
|
|
||||||
|
// var lnLabel = document.createElement('span');
|
||||||
|
// lnLabel.className = 'jsoneditor-curserinfo-label';
|
||||||
|
// lnLabel.innerText = 'Ln:';
|
||||||
|
|
||||||
|
// this.curserInfoElements.lnVal = document.createElement('span');
|
||||||
|
// this.curserInfoElements.lnVal.className = 'jsoneditor-curserinfo-count';
|
||||||
|
// this.curserInfoElements.lnVal.innerText = 0;
|
||||||
|
|
||||||
|
// curserAndCountInfo.appendChild(lnLabel);
|
||||||
|
// curserAndCountInfo.appendChild(this.curserInfoElements.lnVal);
|
||||||
|
|
||||||
|
// var colLabel = document.createElement('span');
|
||||||
|
// colLabel.className = 'jsoneditor-curserinfo-label';
|
||||||
|
// colLabel.innerText = 'Col:';
|
||||||
|
|
||||||
|
// this.curserInfoElements.colVal = document.createElement('span');
|
||||||
|
// this.curserInfoElements.colVal.className = 'jsoneditor-curserinfo-count';
|
||||||
|
// this.curserInfoElements.colVal.innerText = 0;
|
||||||
|
|
||||||
|
// curserAndCountInfo.appendChild(colLabel);
|
||||||
|
// curserAndCountInfo.appendChild(this.curserInfoElements.colVal);
|
||||||
|
|
||||||
|
this.menu.appendChild(curserAndCountInfo);
|
||||||
|
|
||||||
var emptyNode = {};
|
var emptyNode = {};
|
||||||
var isReadOnly = (this.options.onEditable
|
var isReadOnly = (this.options.onEditable
|
||||||
&& typeof(this.options.onEditable === 'function')
|
&& typeof(this.options.onEditable === 'function')
|
||||||
|
@ -200,6 +246,7 @@ textmode.create = function (container, options) {
|
||||||
|
|
||||||
// register onchange event
|
// register onchange event
|
||||||
aceEditor.on('change', this._onChange.bind(this));
|
aceEditor.on('change', this._onChange.bind(this));
|
||||||
|
aceEditor.on('changeSelection', this._onSelect.bind(this));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// load a plain text textarea
|
// load a plain text textarea
|
||||||
|
@ -218,6 +265,10 @@ textmode.create = function (container, options) {
|
||||||
// oninput is undefined. For IE8-
|
// oninput is undefined. For IE8-
|
||||||
this.textarea.onchange = this._onChange.bind(this);
|
this.textarea.onchange = this._onChange.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea.onselect = this._onSelect.bind(this);
|
||||||
|
textarea.onmousedown = this._onMouseDown.bind(this);
|
||||||
|
textarea.onblur = this._onBlur.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setSchema(this.options.schema, this.options.schemaRefs);
|
this.setSchema(this.options.schema, this.options.schemaRefs);
|
||||||
|
@ -244,6 +295,25 @@ textmode._onChange = function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle text selection
|
||||||
|
* Calculates the cursor position and selection range and updates menu
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
textmode._onSelect = function () {
|
||||||
|
var selectionRange = {};
|
||||||
|
|
||||||
|
if (this.textarea) {
|
||||||
|
selectionRange = util.getInputSelection(this.textarea);
|
||||||
|
} else if (this.aceEditor) {
|
||||||
|
this._setSelectionCountDisplay(this.aceEditor.getSelectedText().length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectionRange.start !== selectionRange.end) {
|
||||||
|
this._setSelectionCountDisplay(Math.abs(selectionRange.end - selectionRange.start));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event handler for keydown. Handles shortcut keys
|
* Event handler for keydown. Handles shortcut keys
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
|
@ -269,6 +339,37 @@ textmode._onKeyDown = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._setSelectionCountDisplay();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for mousedown.
|
||||||
|
* @param {Event} event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
textmode._onMouseDown = function (event) {
|
||||||
|
this._setSelectionCountDisplay();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event handler for blur.
|
||||||
|
* @param {Event} event
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
textmode._onBlur = function (event) {
|
||||||
|
this._setSelectionCountDisplay();
|
||||||
|
};
|
||||||
|
|
||||||
|
textmode._setSelectionCountDisplay = function (value) {
|
||||||
|
if(value && this.curserInfoElements.countVal) {
|
||||||
|
this.curserInfoElements.countVal.innerText = value;
|
||||||
|
this.curserInfoElements.countVal.style.display = 'inline';
|
||||||
|
this.curserInfoElements.countLabel.style.display = 'inline';
|
||||||
|
} else {
|
||||||
|
this.curserInfoElements.countVal.style.display = 'none';
|
||||||
|
this.curserInfoElements.countLabel.style.display = 'none';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -405,7 +506,6 @@ textmode.setText = function(jsonText) {
|
||||||
|
|
||||||
this.options.onChange = originalOnChange;
|
this.options.onChange = originalOnChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate JSON schema
|
// validate JSON schema
|
||||||
this.validate();
|
this.validate();
|
||||||
};
|
};
|
||||||
|
@ -445,7 +545,7 @@ textmode.validate = function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.length > 0) {
|
if (errors.length > 0) {
|
||||||
// limit the number of displayed errors
|
// limit the number of displayed errors
|
||||||
var limit = errors.length > MAX_ERRORS;
|
var limit = errors.length > MAX_ERRORS;
|
||||||
if (limit) {
|
if (limit) {
|
||||||
|
|
|
@ -790,6 +790,60 @@ exports.textDiff = function textDiff(oldText, newText) {
|
||||||
return {start: start, end: newEnd};
|
return {start: start, end: newEnd};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an object with the selection range or cursor position (if both have the same value)
|
||||||
|
* Support also old browsers (IE8-)
|
||||||
|
* Source: http://ourcodeworld.com/articles/read/282/how-to-get-the-current-cursor-position-and-selection-within-a-text-input-or-textarea-in-javascript *
|
||||||
|
* @param {DOMElement} el A dom element of a textarea or input text.
|
||||||
|
* @return {Object} reference Object with 2 properties (start and end) with the identifier of the location of the cursor and selected text.
|
||||||
|
**/
|
||||||
|
exports.getInputSelection = function(el) {
|
||||||
|
var start = 0, end = 0, normalizedValue, range, textInputRange, len, endRange;
|
||||||
|
|
||||||
|
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
|
||||||
|
start = el.selectionStart;
|
||||||
|
end = el.selectionEnd;
|
||||||
|
} else {
|
||||||
|
range = document.selection.createRange();
|
||||||
|
|
||||||
|
if (range && range.parentElement() == el) {
|
||||||
|
len = el.value.length;
|
||||||
|
normalizedValue = el.value.replace(/\r\n/g, "\n");
|
||||||
|
|
||||||
|
// Create a working TextRange that lives only in the input
|
||||||
|
textInputRange = el.createTextRange();
|
||||||
|
textInputRange.moveToBookmark(range.getBookmark());
|
||||||
|
|
||||||
|
// Check if the start and end of the selection are at the very end
|
||||||
|
// of the input, since moveStart/moveEnd doesn't return what we want
|
||||||
|
// in those cases
|
||||||
|
endRange = el.createTextRange();
|
||||||
|
endRange.collapse(false);
|
||||||
|
|
||||||
|
if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
|
||||||
|
start = end = len;
|
||||||
|
} else {
|
||||||
|
start = -textInputRange.moveStart("character", -len);
|
||||||
|
start += normalizedValue.slice(0, start).split("\n").length - 1;
|
||||||
|
|
||||||
|
if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
|
||||||
|
end = len;
|
||||||
|
} else {
|
||||||
|
end = -textInputRange.moveEnd("character", -len);
|
||||||
|
end += normalizedValue.slice(0, end).split("\n").length - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
start: start,
|
||||||
|
end: end
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (typeof Element !== 'undefined') {
|
if (typeof Element !== 'undefined') {
|
||||||
// Polyfill for array remove
|
// Polyfill for array remove
|
||||||
(function (arr) {
|
(function (arr) {
|
||||||
|
|
Loading…
Reference in New Issue