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

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

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

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

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

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

Свойства и содержимое вкладок доступны с помощью 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());
 
}
}