Google ドキュメント用の Google Apps Script を使用すると、ドキュメントの任意のタブからコンテンツにアクセスできます。
タブとは
ドキュメントには、タブと呼ばれる組織レイヤがあります。ドキュメントでは、現在のスプレッドシートのタブと同様に、1 つのドキュメント内に複数のタブを作成できます。各タブには独自のタイトルと ID があります(URL に追加されます)。タブには子タブを含めることもできます。子タブは別のタブの下にネストされたタブです。
タブにアクセスする
タブのプロパティとコンテンツには Document.getTabs でアクセスできます。これは Tab のリストを返します。以降のセクションでは、Tab クラスの概要を説明します。Tab クラスのドキュメントにも、より詳細な情報が記載されています。
タブのプロパティ
タブのプロパティは、Tab.getId や Tab.getTitle などのメソッドを使用して取得できます。
タブの内容
各タブ内のドキュメント コンテンツは、Tab.asDocumentTab を使用して取得できます。ドキュメント クラスの構造の変更セクションで、この使用方法について説明します。
タブの階層
子タブは、Apps Script で 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());
ドキュメント内のすべてのタブを反復処理するサンプルコードについては、後のセクションのサンプルコード ブロックをご覧ください。
タブを復元するその他の方法
タブを取得する方法は他にも 2 つあります。
Document.getTab: 指定された ID のタブを返します。Document.getActiveTab: ユーザーのアクティブなタブを返します。ドキュメントにバインドされているスクリプトでのみ機能します。以降のセクションで、これについて詳しく説明します。
ドキュメント クラスの構造の変更
以前は、ドキュメントにタブの概念がなかったため、Document クラスはドキュメントのテキスト コンテンツに直接アクセスして変更するメソッドを公開していました。このカテゴリに分類されるメソッドは次のとおりです。
Document.addBookmarkDocument.addFooterDocument.addHeaderDocument.addNamedRangeDocument.getBodyDocument.getBookmarkDocument.getBookmarksDocument.getFooterDocument.getFootnotesDocument.getHeaderDocument.getNamedRangeByIdDocument.getNamedRangesDocument.getNamedRangesDocument.newPositionDocument.newRange
タブの構造階層が追加されたため、これらのメソッドはドキュメント内のすべてのタブのテキスト コンテンツを意味的に表さなくなりました。テキスト コンテンツは別のレイヤで表されるようになり、前述のテキスト メソッドはすべて 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 が非アクティブなタブにある場合、ユーザーのアクティブなタブもその Position に関連付けられたタブに切り替えられます。Document.setSelection: アクティブなドキュメントでユーザーの選択範囲を設定します。Range が非アクティブなタブにある場合、ユーザーのアクティブなタブもその Range に関連付けられたタブに切り替えられます。
タブの選択方法とユースケース
タブの導入により、スクリプトを実行しているユーザーのアクティブなタブを取得して設定します。次のメソッドを使用します。
Document.getActiveTab: アクティブなドキュメントでユーザーのアクティブなTabを返します。Document.setActiveTab: 現在のドキュメントでユーザーが選択したTabを、指定された ID のタブに設定します。
ユーザーの全体的な「選択」は、アクティブなタブと、現在のカーソル位置または選択範囲のいずれかの組み合わせで構成されます。アクティブな選択を操作するパターンは、ユーザーのアクティブなタブを特定のタブに明示的に変更するか、ユーザーのアクティブなタブを使用するかの 2 つです。
Document.setActiveTab を使用して、ユーザーのアクティブなタブを明示的に変更します。また、非アクティブなタブから Position または Range を使用して Document.setCursor または Document.setSelection を呼び出すと、そのタブが新たにアクティブになります。
スクリプトの目的が、ユーザーのアクティブなタブを変更せずに使用することである場合、Document.setActiveTab は必要ありません。Document.getCursor メソッドと Document.getSelection メソッドは、ユーザーがスクリプトを実行しているタブに基づいて、アクティブなタブに対して動作します。
ドキュメントでは、複数のタブの選択、複数の位置、異なるタブにまたがる範囲はサポートされていません。そのため、Document.setActiveTab を使用すると、前のカーソル位置または選択範囲がクリアされます。
特定のタブの位置と範囲のメソッド
特定のタブは、Position と Range のテキスト選択のコンセプトに意味を与えます。カーソル位置または選択範囲は、スクリプトがその位置または範囲が属する特定のタブを認識している場合にのみ意味を持ちます。
これは、メソッドの呼び出し元の特定の DocumentTab をターゲットとする Position または Range を構築する DocumentTab.newPosition メソッドと DocumentTab.newRange メソッドを使用して実現されます。一方、Document.newPosition と Document.newRange は、アクティブなタブ(スクリプトがバインドされていない場合は最初のタブ)内の Position または Range を構築します。
選択の操作に関するサンプルコードについては、後述のセクションのサンプルコード ブロックをご覧ください。
タブの一般的な使用パターン
次のコードサンプルは、タブを操作するさまざまな方法を示しています。
ドキュメント内のすべてのタブからタブの内容を読み取る
タブ機能の前にこれを行っていた既存のコードは、タブツリーをトラバースし、Document ではなく Tab と DocumentTab からゲッター メソッドを呼び出すことで、タブをサポートするように移行できます。次のコードサンプルの一部は、ドキュメント内のすべてのタブのテキスト コンテンツを印刷する方法を示しています。このタブ トラバーサル コードは、タブの実際の構造を気にしない他の多くのユースケースに適用できます。
/** 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()); } }