Работа с вкладками

Apps Script для Google Docs позволяет получать доступ к контенту с любой вкладки документа.

Что такое вкладки?

В Документах Google есть организационный уровень, называемый вкладками . Документы позволяют пользователям создавать одну или несколько вкладок в одном документе, подобно тому, как сегодня существуют вкладки в Таблицах. Каждая вкладка имеет свой заголовок и идентификатор (добавленный в URL-адрес). Вкладка также может иметь дочерние вкладки — вкладки, вложенные под другую вкладку.

Доступ к вкладкам

Свойства и содержимое вкладок доступны с помощью Document.getTabs() , который возвращает список Tab s. В последующих разделах дается краткий обзор класса Tab ; документация по классу Tab также предоставляет более подробную информацию.

Свойства вкладки

Свойства вкладки можно получить с помощью таких методов, как Tab.getId() и Tab.getTitle() .

Содержимое вкладки

Содержимое документа на каждой вкладке можно получить с помощью Tab.asDocumentTab() . В разделе «Изменения в структуре класса документа» описывается, как это можно использовать.

Иерархия вкладок

Дочерние вкладки отображаются в скрипте Google Apps через Tab.getChildTabs() . Доступ к содержимому всех вкладок требует обхода «дерева» дочерних вкладок. Например, рассмотрим документ, содержащий следующую иерархию вкладок:

Пользовательский интерфейс списка таблиц, содержащий три вкладки верхнего уровня, некоторые из которых имеют дочерние вкладки.

Чтобы получить доступ к вкладке 3.1.2 , вы можете сделать следующее:

// Print the ID of Tab 3.1.2.
const doc = DocumentApp.getActiveDocument();
const tab = doc.getTabs()[2].getChildTabs()[0].getChildTabs()[1];
console.log(tab.getId());

См. примеры блоков кода в последующих разделах, в которых представлен пример кода для перебора всех вкладок в документе.

Другие способы получения вкладок

Есть два других способа получения вкладок:

  • Document.getTab(tabId) : возвращает вкладку с указанным идентификатором.
  • Document.getActiveTab() : возвращает активную вкладку пользователя. Работает только в сценариях, привязанных к документу. В последующих разделах это описано более подробно.

Изменения в структуре класса документа

Раньше в документах не было концепции вкладок, поэтому класс документа предоставлял методы для прямого доступа и изменения текстового содержимого документа. В эту категорию попадают следующие методы:

Благодаря дополнительной структурной иерархии вкладок эти методы больше не представляют семантически текстовое содержимое всех вкладок в документе. Текстовый контент теперь будет представлен на другом слое; все вышеупомянутые текстовые методы доступны через DocumentTab .

Эти существующие методы класса Document будут получать доступ к содержимому или изменять его либо на активной вкладке (в сценариях, привязанных к конкретному документу), либо на первой вкладке (если активная вкладка недоступна).

Доступ к текстовому содержимому на определенной вкладке

Вместо использования текстовых методов Document , рекомендуется вместо этого использовать методы, доступные из класса DocumentTab (который доступен через метод Tab.asDocumentTab() ). Например:

// Print the text from the body of the active tab.
const doc = DocumentApp.getActiveDocument();
const documentTab = doc.getActiveTab().asDocumentTab();
const body = documentTab.getBody();
console.log(body.getText());

Изменения в выборе пользователей

Методы выделения текста

Класс Document предоставляет методы получения и установки для управления тем, где в тексте выбирает пользователь в активном документе. Эти методы работают в контексте активной вкладки пользователя, запускающего скрипт.

  • Document.getCursor() : Возвращает позицию курсора пользователя на активной вкладке .
  • Document.getSelection() : Возвращает диапазон выбора пользователя на активной вкладке .
  • Document.setCursor(position) : устанавливает позицию курсора пользователя в активном документе. Если позиция находится на неактивной вкладке, то активная вкладка пользователя также переключается на вкладку, связанную с этой позицией.
  • Document.setSelection(range) : устанавливает диапазон выбора пользователя в активном документе. Если диапазон находится на неактивной вкладке, то активная вкладка пользователя также переключается на вкладку, связанную с этим диапазоном.

Методы выбора вкладок и варианты использования

С появлением вкладок может оказаться полезным получить и установить активную вкладку пользователя, запускающего скрипт. Это можно сделать с помощью следующих методов:

  • Document.getActiveTab() : возвращает активную Tab пользователя в активном документе.
  • Document.setActiveTab(tabId) : устанавливает выбранную пользователем Tab в текущем документе на вкладку с указанным идентификатором.

Целостный «выбор» пользователя состоит из комбинации активной вкладки и текущей позиции курсора или диапазона выбора. Два шаблона работы с активным выбором — либо явно изменить активную вкладку пользователя на конкретную вкладку, либо использовать активную вкладку пользователя.

Явное изменение активной вкладки пользователя можно выполнить с помощью Document.setActiveTab(tabId) . Альтернативно, вызов Document.setCursor(position) или Document.setSelection(range) с Position или Range из неактивной вкладки сделает эту вкладку новой активной.

Если предполагаемое поведение сценария заключается в использовании активной вкладки пользователя без ее изменения, то Document.setActiveTab(tabId) не требуется. Методы Document.getCursor() и Document.getSelection() уже будут работать с активной вкладкой в ​​зависимости от вкладки, с которой пользователь запускает скрипт.

Обратите внимание, что документ не поддерживает выбор нескольких вкладок, а также несколько позиций или диапазонов на разных вкладках. Таким образом, использование Document.setActiveTab(tabId) очистит предыдущую позицию курсора или диапазон выбора.

Методы положения и диапазона для конкретной вкладки

Конкретная вкладка — это то, что придает смысл концепциям выбора текста Position и Range . Другими словами, позиция курсора или диапазон выбора имеют смысл только в том случае, если сценарий знает конкретную вкладку, внутри которой находится позиция или диапазон.

Это достигается с помощью методов DocumentTab.newPosition(element, offset) и DocumentTab.newRange() , которые создают позицию или диапазон, нацеленные на конкретную DocumentTab , из которой вызывается метод. Напротив, Document.newPosition(element, offset) и Document.newRange() создадут позицию или диапазон, нацеленные на активную вкладку (или первую вкладку, если скрипт не привязан).

См. примеры блоков кода в последующих разделах, в которых представлен пример кода для работы с выборками.

Общие шаблоны использования вкладок

Следующие примеры кода описывают различные способы взаимодействия с вкладками.

Чтение содержимого вкладок со всех вкладок в документе.

Существующий код, который делал это до появления функции вкладок, можно перенести для поддержки вкладок, пройдя по дереву вкладок и вызвав методы получения из Tab и DocumentTab вместо Document . В следующем примере частичного кода показано, как распечатать все текстовое содержимое каждой вкладки документа. Этот код обхода вкладок можно адаптировать для многих других случаев использования, в которых не важна фактическая структура вкладок.

/** Logs all text contents from all tabs in the active document. */
function logAllText() {
  // Generate a list of all the tabs in the document, including any
  // nested child tabs. DocumentApp.openById('abc123456') can also
  // be used instead of DocumentApp.getActiveDocument().
  const doc = DocumentApp.getActiveDocument();
  const allTabs = getAllTabs(doc);

  // Log the content from each tab in the document.
  for (const tab of allTabs) {
    // Get the DocumentTab from the generic Tab object.
    const documentTab = tab.asDocumentTab();
    // Get the body from the given DocumentTab.
    const body = documentTab.getBody();
    // Get the body text and log it to the console.
    console.log(body.getText());
  }
}

/**
 * Returns a flat list of all tabs in the document, in the order
 * they would appear in the UI (i.e. top-down ordering). Includes
 * all child tabs.
 */
function getAllTabs(doc) {
  const allTabs = [];
  // Iterate over all tabs and recursively add any child tabs to
  // generate a flat list of Tabs.
  for (const tab of doc.getTabs()) {
    addCurrentAndChildTabs(tab, allTabs);
  }
  return allTabs;
}

/**
 * Adds the provided tab to the list of all tabs, and recurses
 * through and adds all child tabs.
 */
function addCurrentAndChildTabs(tab, allTabs) {
  allTabs.push(tab);
  for (const childTab of tab.getChildTabs()) {
    addCurrentAndChildTabs(childTab, allTabs);
  }
}

Чтение содержимого вкладки с первой вкладки документа.

Это похоже на чтение всех вкладок.

/** 
 * Logs all text contents from the first tab in the active 
 * document. 
 */
function logAllText() {
  // Generate a list of all the tabs in the document, including any
  // nested child tabs.
  const doc = DocumentApp.getActiveDocument();
  const allTabs = getAllTabs(doc);

  // Log the content from the first tab in the document.
  const firstTab = allTabs[0];
  // Get the DocumentTab from the generic Tab object.
  const documentTab = firstTab.asDocumentTab();
  // Get the body from the DocumentTab.
  const body = documentTab.getBody();
  // Get the body text and log it to the console.
  console.log(body.getText());
}

Обновить содержимое вкладки на первой вкладке

В следующем примере частичного кода показано, как настроить таргетинг на определенную вкладку при выполнении обновлений.

/** Inserts text into the first tab of the active document. */
function insertTextInFirstTab() {
  // Get the first tab's body.
  const doc = DocumentApp.getActiveDocument();
  const firstTab = doc.getTabs()[0];
  const firstDocumentTab = firstTab.asDocumentTab();
  const firstTabBody = firstDocumentTab.getBody();

  // Append a paragraph and a page break to the first tab's body
  // section.
  firstTabBody.appendParagraph("A paragraph.");
  firstTabBody.appendPageBreak();
}

Обновить содержимое вкладок на активной или выбранной вкладке

В следующем примере частичного кода показано, как выбрать активную вкладку при выполнении обновлений.

/**
 * Inserts text into the active/selected tab of the active
 * document.
 */
function insertTextInActiveTab() {
  // Get the active/selected tab's body.
  const doc = DocumentApp.getActiveDocument();
  const activeTab = doc.getActiveTab();
  const activeDocumentTab = activeTab.asDocumentTab();
  const activeTabBody = activeDocumentTab.getBody();

  // Append a paragraph and a page break to the active tab's body
  // section.
  activeTabBody.appendParagraph("A paragraph.");
  activeTabBody.appendPageBreak();
}

Установите положение курсора или диапазон выбора на активной вкладке

В следующем примере частичного кода показано, как обновить положение курсора или диапазон выбора на активной вкладке пользователя. Это актуально только для связанных сценариев.

/**
 * Changes the user's selection to select all tables within the tab
 * with the provided ID.
 */
function selectAllTables(tabId) {
  const doc = DocumentApp.getActiveDocument();
  const tab = doc.getTab(tabId);
  const documentTab = tab.asDocumentTab();

  // Build a range that encompasses all tables within the specified
  // tab.
  const rangeBuilder = documentTab.newRange();
  const tables = documentTab.getBody().getTables();
  for (let i = 0; i < tables.length; i++) {
    rangeBuilder.addElement(tables[i]);
  }
  // Set the document's selection to the tables within the specified
  // tab. Note that this actually switches the user's active tab as
  // well.
  doc.setSelection(rangeBuilder.build());
}

Установить активную или выбранную вкладку

В следующем примере частичного кода показано, как изменить активную вкладку пользователя. Это актуально только для связанных сценариев.

/**
 * Changes the user's selected tab to the tab immediately following
 * the currently selected one. Handles child tabs.
 *
 * 

Only changes the selection if there is a tab following the * currently selected one. */ function selectNextTab() { const doc = DocumentApp.getActiveDocument(); const allTabs = getAllTabs(doc); const activeTab = doc.getActiveTab(); // Find the index of the currently active tab. let activeTabIndex = -1; for (let i = 0; i < allTabs.length; i++) { if (allTabs[i].getId() === activeTab.getId()) { activeTabIndex = i; } } // Update the user's selected tab if there is a valid next tab. const nextTabIndex = activeTabIndex + 1; if (nextTabIndex < allTabs.length) { doc.setActiveTab(allTabs[nextTabIndex].getId()); } }