在光标位置

时间:2015-11-26 19:15:16

标签: google-apps-script google-docs

我正在处理Google文档添加,将文本转换为表格。它允许用户1)选择一些文本或2)将光标放在他们想要的文本中,当单击侧边栏中的自定义按钮时,脚本将:

  1. 在光标位置插入单行单个单元格表或所选文本的startIndex
  2. 在该单元格内放置用户选择的文本或放置光标的元素的完整文本,
  3. 删除原始选定的文本/元素,以便只保留表格
  4. (基本上,这只是“绘制”围绕所选文本或元素的表格)

    documentation的概述显示可以通过var element = cursor.insertText('ಠ‿ಠ');插入文本,但是没有类似的插入其他元素的方法。因此,我一直试图使用insertTable(childIndex, cells)取得不同程度的成功。关注用户只是将光标放在元素中的情况,我可以插入一个带有正确文本的表并删除原始文本,但我找不到将表插入正确位置的方法。我试过以下,但无济于事:

    1. var newTable = body.insertTable(cursor.getOffset(), [['Test Text']]); - 这会创建表格,但会将其插入错误的位置,似乎基于文本放置在文本中的位置,通常位于文档的开头。

    2. var el = cursor.getElement().asBody(); var newTable = el.insertTable(0, [['Test Text']]); - 这没有任何作为

    3. var el = cursor.getElement().getParent().asBody(); var newTable = el.insertTable(0, [['Test Text']]); - 这没有任何作为

    4. var el = cursor.getElement(); var parent = el.getParent().getChildIndex(el); var newTable = body.insertTable(parent, [['Test Text']]); - 这会将表格插入文档的最开头。

    5. 搜索Stack Overflow会产生this very similar question,建议在光标位置插入一些占位符文本,然后在文档中搜索插入的字符串并放置一个表格。这种方法有两个主要问题:

      1. 我需要直接修改插入点周围的文本,插入额外的文本似乎可能会使这更难,并且
      2. 更重要的是,我仍然不知道如何获得表格插入点的正确位置。
      3. 如果有人可以扩展占位符文本方法,或者可以提供新的解决方案,那将非常有帮助。谢谢!

2 个答案:

答案 0 :(得分:4)

我使用以下GAS代码在Google文档中的当前光标位置插入表格。如果光标在换行符上,效果会更好。

  var doc = DocumentApp.getActiveDocument();
  var body = doc.getBody();
  var cursor = doc.getCursor();

  var element = cursor.getElement();
  var parent = element.getParent();
  //here table is an array of cells like
  // [[r1c1, r1c2], [r2c1, r2c2]]
  body.insertTable(parent.getChildIndex(element) + 1, table);

编辑:为了更好地了解Google文档中光标位置的工作原理,我建议您运行以下光标检查器github项目

https://github.com/google/google-apps-script-samples/tree/master/cursor_inspector

答案 1 :(得分:1)

TL; DR:使用下面的代码段。

当您选择插入>时,Google文档似乎会执行此操作。表,是将当前段落分成两段,然后在其间插入一个新表。

困难的部分是将段落分成两部分。我试图通过几种方式实现这一目标。我无法从Google Apps脚本文档中找到执行此操作的任何API调用(电子表格API在moveTo()对象上有Range方法,但这不能帮助我们) 。我希望我可以将段落中给定位置的元素复制到另一段并删除原件。但是,由于Document Service does not allow explicit insertion of several element types但只能在原地操作它们,例如Equation元素,因此逐个复制这些元素是不可能的。

幸运的是,Paragraphcopy()方法执行深层复制。所以我对此的看法是复制整个段落,从原始段落中的光标位置向前移除所有内容,并删除光标在段落副本中的所有位置。这样,您可以在中间拆分段落,并可以在所需位置插入表格。对于ListItem,它的工作方式相同。

这是函数splitParagraphAt()的代码,它返回新创建的段落(或列表项;它是原始段落的下一个兄弟)。我在代码中添加了一些额外的检查,以确保它所做的是你认为它正在做的事情。接下来,我添加了一个简短的代码摘录,介绍如何使用它在当前光标位置插入一个表。可以使用splitParagraphAt()类似于在光标位置插入任何元素。我没有对此进行彻底测试,因此欢迎任何输入。

/**
 * 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;
}

这里是用于在光标位置插入表格并在表格的第一个单元格中设置光标位置的代码摘录:

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));

请注意,仍然需要进行一些额外的检查以确定是否有选择等。具体而言,假设cursor不会是null