TL; DR: użyć kodu fragment poniżej.
Wygląda na to, że to, co robi Dokumenty Google po wybraniu Wstaw> Tabela, polega na rozbiciu bieżącego akapitu na dwa akapity, a następnie wstawieniu nowej tabeli pomiędzy.
Trudną częścią jest podzielenie akapitu na dwie części. Próbowałem to osiągnąć na kilka sposobów. Nie mogłem znaleźć żadnego wywołania API z dokumentacji Google Apps Script, która to robi (interfejs API arkusza kalkulacyjnego ma metodę moveTo()
na obiekcie Range
, ale to nam nie pomoże). Miałem nadzieję, że uda mi się skopiować elementy z określonej pozycji w akapicie do kolejnego akapitu i usunąć oryginały. Jednak od czasu Document Service does not allow explicit insertion of several element types, ale można nimi manipulować tylko w miejscu, takim jak elementy Equation
, kopiowanie tych jeden po drugim jest niemożliwe.
Na szczęście, Paragraph
ma metodę copy()
, która wykonuje głęboką kopię. Więc przyjmuję to, aby skopiować cały akapit, usunąć wszystko od pozycji kursora do przodu w oryginalnym akapicie i usunąć wszystko do miejsca, w którym kursor znajdował się w kopii akapitu. W ten sposób masz podział akapitu w środku i możesz wstawić tabelę w wymaganej pozycji. Działa to tak samo dla modelu ListItem
.
Oto kod funkcji splitParagraphAt()
, która zwraca nowo utworzony akapit (lub element listy, który jest następnym rodzeństwem oryginalnego). Wrzuciłem dodatkowe kontrole do kodu, aby upewnić się, że to, co robisz, jest tym, co myślisz, że robi. Następnie dodałem krótki fragment kodu, w jaki sposób można go użyć do wstawienia tabeli w bieżącej pozycji kursora. Można użyć splitParagraphAt()
podobnie jak wstawić dowolny element w pozycji kursora. Nie testowałem tego dokładnie, więc wszelkie dane wejściowe są mile widziane.
/**
* Splits the contents of the paragraph (or list item) at the given position,
* producing two adjacent paragraphs (or list items). This function may be used
* to insert any kind of element at an arbitrary document position, but placing
* it immediately before the second paragraph (or list item).
*
* @param {Position} pos The position where the paragraph (or list item) should
* be split. `pos.getElement()` should be either a Text, Paragraph or
* ListItem object.
*
* @returns {ContainerElement} The second (newly created) Paragraph or ListItem
* object.
*
*/
function splitParagraphAt(pos) {
var el = pos.getElement(), offset = pos.getOffset();
var inParagraph = (el.getType() == DocumentApp.ElementType.PARAGRAPH || el.getType() == DocumentApp.ElementType.LIST_ITEM);
if (!inParagraph && (el.getType() != DocumentApp.ElementType.TEXT)) {
throw new Error("Position must be inside text or paragraph.");
}
var par;
if (inParagraph) {
// in this case, `offset` is the number of child elements before this
// Position within the same container element
par = el;
if (offset == par.getNumChildren()) {
// we're at the end of the paragraph
return par.getParent().insertParagraph(
par.getParent().getChildIndex(par) + 1, "");
}
el = par.getChild(offset);
}
else {
par = el.getParent();
if (par == null || (par.getType() != DocumentApp.ElementType.PARAGRAPH && par.getType() != DocumentApp.ElementType.LIST_ITEM)) {
throw new Error("Parent of text is not a paragraph or a list item.");
}
}
var parContainer = par.getParent();
if (!("insertParagraph" in parContainer)) {
throw new Error("Cannot insert another paragraph in this container.");
}
// This assumes the given position is in the current document.
// alternatively, one may traverse through parents of par until document
// root is reached.
var doc = DocumentApp.getActiveDocument();
var elIndex = par.getChildIndex(el);
var newPar = par.copy();
var newEl = newPar.getChild(elIndex);
// remove everything up to position from the new element
if (!inParagraph && (offset != 0)) {
newEl.deleteText(0, offset-1);
}
newEl = newEl.getPreviousSibling();
while (newEl != null) {
// get the previous sibling before we remove the element.
var prevEl = newEl.getPreviousSibling();
newEl.removeFromParent();
newEl = prevEl;
}
// since we might remove el itself, we get the next sibling here already
var nextEl = el.getNextSibling();
// remove everything from position onwards in the original element
if (!inParagraph && (offset != 0)) {
el.deleteText(offset, el.getText().length-1);
}
else {
// we're at the beginning of the text (or just before a paragraph
// subelement) and need to remove the entire text/subelement.
el.removeFromParent();
}
el = nextEl;
while (el != null) {
// get the next sibling before we remove the element.
nextEl = el.getNextSibling();
el.removeFromParent();
el = nextEl;
}
// actually insert the newly created paragraph into the document tree.
switch (par.getType()) {
case DocumentApp.ElementType.PARAGRAPH:
parContainer.insertParagraph(parContainer.getChildIndex(par)+1, newPar);
break;
case DocumentApp.ElementType.LIST_ITEM:
parContainer.insertListItem(parContainer.getChildIndex(par)+1, newPar);
break;
}
return newPar;
}
Oto fragment kodu do wstawiania tabeli w pozycji kursora i ustawienie pozycji kursora w pierwszej komórce tabeli:
var doc = DocumentApp.getActiveDocument();
var cursor = doc.getCursor();
var el = (cursor.getOffset() == 0? cursor.getElement() : splitParagraphAt(cursor));
var parentEl = el.getParent();
var table = parentEl.insertTable(parentEl.getChildIndex(el), [['ಠ‿ಠ']]);
doc.setCursor(doc.newPosition(table.getCell(0, 0), 0));
Należy pamiętać, że nie należy jeszcze pewne dodatkowe kontrole na zobacz, czy jest zaznaczenie, czy nie, itp. W szczególności zakłada się, że to cursor
nie będzie null
.