I am inserting text into a document and each text insertion is added to a named range so that I can look them all up with getNamedRanges(NAME)
and getNamedRangesById(ID)
.
Now I need to check if the current cursor position is on a named range and I have yet to figure out how.
This post is similar: How to determine the named range from position in Google Docs through Google Apps Script
But when the cursor is on a namedrange cursor.getElement()
returns Text
object, not the named range.
How can I determine if the cursor is currently positioned on a named range?
In this workaround, I checked whether the cursor position is included in the namedRange by comparing the indexes of paragraph of both the namedRange and the cursor position.
The flow of the script is as follows.
cursor
becomes null
.myFunction()
returns true
.
myFunction()
returns false
.Before you use this script, please set the namedRange ID.
function myFunction() {
var nameRangeId = "###"; // Please set namedRange ID here.
var getIndex = function(doc, e) {
while (e.getParent().getType() != DocumentApp.ElementType.BODY_SECTION) e = e.getParent();
return doc.getBody().getChildIndex(e);
};
var doc = DocumentApp.getActiveDocument();
// For namedRange
var namedRange = doc.getNamedRangeById(nameRangeId);
if (namedRange) {
var indexOfNamedRange = namedRange.getRange().getRangeElements().map(function(e) {return getIndex(doc, e.getElement())});
} else {
throw new Error("No namedRange.");
}
var name = namedRange.getName();
// For cursor
var cursor = doc.getCursor();
if (cursor) {
var indexOfCursor = getIndex(doc, cursor.getElement());
if (~indexOfNamedRange.indexOf(indexOfCursor)) {
Logger.log("Inside of %s", name);
return true;
}
Logger.log("Outside of %s", name);
return false;
}
// For select
var select = doc.getSelection();
if (select) {
var indexOfSelect = select.getRangeElements().map(function(e) {return getIndex(doc, e.getElement())});
if (indexOfSelect.some(function(e) {return ~indexOfNamedRange.indexOf(e)})) {
Logger.log("Inside of %s", name);
return true;
}
Logger.log("Outside of %s", name);
return false;
}
throw new Error("No cursor and select.");
}
// For select
.true
is returned. About this, please modify for your situation.I had understood that from this situation, OP has set the named range to the paragraph. When I proposed a sample script for this, I thought that I correctly understood OP's goal. But, from gaspar's following comment,
this only shows whether the cursor is in the same element as the named range, but in case of named range partial text it gives a false positive finding if the cursor is in the same element but not in the same text part
If OP sets the part of the paragraph as the named range, and OP wants to check whether the cursor is included in the named range, the sample script is as follows.
function myFunction() {
var nameRangeId = "###"; // Please set namedRange ID here.
var getIndex = function (doc, e) {
while (e.getParent().getType() != DocumentApp.ElementType.BODY_SECTION) e = e.getParent();
return doc.getBody().getChildIndex(e);
};
var doc = DocumentApp.getActiveDocument();
// For namedRange
var namedRange = doc.getNamedRangeById(nameRangeId);
if (namedRange) {
var indexOfNamedRange = namedRange.getRange().getRangeElements().map(e => ({ idx: getIndex(doc, e.getElement()), start: e.getStartOffset(), end: e.getEndOffsetInclusive() }));
} else {
throw new Error("No namedRange.");
}
var name = namedRange.getName();
// For cursor
var cursor = doc.getCursor();
if (cursor) {
var indexOfCursor = getIndex(doc, cursor.getElement());
var offset = cursor.getOffset();
if (indexOfNamedRange.some(({ idx, start, end }) => idx == indexOfCursor && ((start == -1 && end == -1) || (offset > start && offset < end)))) {
Logger.log("Inside of %s", name);
return true;
}
Logger.log("Outside of %s", name);
return false;
}
// For select
var select = doc.getSelection();
if (select) {
var indexOfSelect = select.getRangeElements().map(e => ({ idx: getIndex(doc, e.getElement()), start: e.getStartOffset(), end: e.getEndOffsetInclusive() }));
if (indexOfSelect.some(e => indexOfNamedRange.some(({ idx, start, end }) => idx == e.idx && ((start == -1 && end == -1) || ((e.start > start && e.start < end) || (e.end > start && e.end < end)))))) {
Logger.log("Inside of %s", name);
return true;
}
Logger.log("Outside of %s", name);
return false;
}
throw new Error("No cursor and select.");
}