Apps Script : Gérer les onglets dans Docs
Si vous utilisez Google Docs régulièrement, vous n’avez pas pu passer à côté de cette mise à jour : désormais, vous avez accès à des onglets dans votre document ! L’ensemble des onglets se trouve désormais à […]
Ce que vous allez découvrir
- Un changement de structure et de comportement
- Accéder aux onglets et les manipuler
- Position du curseur et sélection actuelle
- Aller plus loin
Apps Script : Gérer les onglets dans Docs
Si vous utilisez Google Docs régulièrement, vous n’avez pas pu passer à côté de cette mise à jour : désormais, vous avez accès à des onglets dans votre document ! L’ensemble des onglets se trouve désormais à gauche de votre document, et chaque onglet se comporte en quelque sorte comme son propre document, l’ensemble des onglets formant le document dans son ensemble. Un changement approprié lorsque les documents numériques n’ont plus tant vocation à être imprimés, et qu’une telle organisation rend ainsi la lecture plus digeste et le texte plus facile à parcourir.
Un exemple de document Google Docs avec de nombreux onglets sur le côté
Mais pour chaque nouvelle fonctionnalité des outils Google Workspace vient la question fatidique : que peut-on faire avec Apps Script ? Une question plus que pertinente dans notre cas, car un tel changement bouleverse complètement la structure des documents pour Apps Script ! Faisons un petit tour de tout cela, et voyons les fonctions offertes aux développeurs pour manipuler ces onglets.
Un changement de structure et de comportement
Si vous avez fait des scripts manipulant Google Docs, l’annonce de l’arrivée des onglets n’a pas dû trop vous surprendre. En effet, plusieurs mails ont prévenu que cette nouvelle fonctionnalité pourrait modifier significativement le comportement de scripts déjà existants. Pourquoi cela ? Tout simplement parce que les documents ne sont plus organisés de la même façon, et donc que le code pour accéder aux différents éléments réplique ce changement !
Ainsi, la classe Document, centrale pour manipuler le document, possède un certain nombre de méthodes qui permettaient d’accéder ou de modifier directement des éléments texte. La liste de ces méthodes est fournie ici :
- Document.addBookmark(position)
- Document.addFooter()
- Document.addHeader()
- Document.addNamedRange(name, range)
- Document.getBody()
- Document.getBookmark(id)
- Document.getBookmarks()
- Document.getFooter()
- Document.getFootnotes()
- Document.getHeader()
- Document.getNamedRangeById(id)
- Document.getNamedRanges()
- Document.getNamedRanges(name)
- Document.newPosition(element, offset)
- Document.newRange()
Toutes ces méthodes sont toujours fonctionnelles, mais avec l’arrivée des onglets, elles n’opèrent plus de la même manière. Deux possibilités :
- Si votre script est lié au document, alors ces méthodes s’appliqueront à l’onglet actif du document.
- Si votre script n’est pas lié à un document, alors ces méthodes s’appliqueront au premier onglet du document.
Si vos documents n’ont pas changé, vos scripts sont donc toujours fonctionnels, puisque tout document comporte toujours un onglet par défaut. Toutefois, si vos utilisateurs changent vos anciens documents en rajoutant des onglets, prenez bien garde à ce que vos scripts fassent bien ce qui est attendu d’eux ! Cela devrait être le cas en général, mais il peut valoir le coup de repasser dessus pour vérifier.
Accéder aux onglets et les manipuler
Intéressons-nous désormais aux onglets en eux-mêmes. Y accéder est extrêmement simple, et est similaire à l’accès aux Sheets de SpreadsheetApp :
- Vous pouvez obtenir la liste des onglets de plus haut niveau avec Document.getTabs()
- Vous pouvez obtenir un onglet spécifique avec Document.getTab(tabId)
- Vous pouvez obtenir l’onglet actif de l’utilisateur avec Document.getActiveTab() (uniquement avec un script lié)
L’identifiant d’un onglet se trouve dans l’adresse, derrière tab=. Par exemple, le premier onglet a toujours l’identifiant t.0. Vous pouvez aussi récupérer l’identifiant d’un onglet avec la méthode Tab.getId().
Toutefois, une question se pose : qu’est-ce que j’entends par « les onglets de plus haut niveau » ?
Vous avez pu le remarquer, les onglets ne sont pas organisés comme des feuilles dans Sheets : il est possible de rajouter des sous-onglets à tout onglet, et ce indéfiniment. Un onglet peut donc avoir un sous-onglet qui peut lui-même avoir un sous-onglet qui… bref. La structure des onglets est ici ce qu’on appelle en informatique un arbre, chaque onglet étant potentiellement un nœud (ou parent) menant à plusieurs autres branches (ses enfants).
Comment faire aller pour accéder à l’ensemble des onglets ? Il y a plusieurs solutions, en fonction du résultat attendu, mais toutes les deux font appel à la récursion. La solution la plus simple, qui consiste à simplement parcourir chaque onglet et récupérer ses enfants (et ce de manière récursive) et ajouter l’ensemble à la liste des onglets trouvés est donnée en exemple par Google :
/**
* 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);
}
}
Toutefois, faire ainsi vous fait perdre l’arbre. Si vous devez réaliser une opération uniquement sur les onglets les plus bas, ou uniquement ceux du premier niveau, par exemple, une telle liste ne vous permet pas de retrouver rapidement cette information. Une autre façon de faire permettant de garder la notion d’arbre tout en ayant l’ensemble des onglets peut être celle-ci :
/**
* Retourne un arbre de tous les onglets du document donné (ou de l’onglet donné). Chaque nœud est représenté en tant qu’objet avec deux propriétés : currentTab, contenant une instance de Tab représentant notre onglet, et childTabs, un tableau de nœuds similaires (vides s’il n’y a pas d’onglets enfants).
*/
function getTabsTree(docOrTab){
const tabs = Object.hasOwn(docOrTab, « getTabs ») ? docOrTab.getTabs() : docOrTab.getChildTabs();
return tabs.map(tab => ({
currentTab: tab,
childTabs: getTabsTree(tab)
}))
}
À noter qu’un onglet Tab n’est pas la même chose que DocumentTab ! L’onglet Tab est en quelque sorte la « coquille » autour de l’onglet. Pour obtenir son contenu, il faudra utiliser la méthode spécifique Tab.asDocumentTab(), de la même manière que Element doit être récupéré avec (par exemple) asParagraph() pour obtenir un paragraphe. Pénible, mais on s’y fait.
Position du curseur et sélection actuelle
L’ajout des onglets a aussi légèrement complexifié la notion de curseur et de la sélection, mais d’une manière qui reste intuitive. Le résumé est le suivant :
- Document.getCursor(): Renvoie la position du curseur (la barre clignotante) dans l’onglet actif.
- Document.getSelection(): Renvoie la plage de sélection dans l’onglet actif.
- Document.setCursor(position): Fixe la position du curseur à une position donnée. Cette position est toujours relative à un onglet, et si cet onglet n’est pas l’onglet actif, alors il le devient.
- Document.setSelection(range): Fixe la sélection à celle donnée. De la même manière, si la sélection en question est dans un onglet inactif, alors celui-ci devient l’onglet actif.
Par exemple, si vous souhaitez un script qui ajoute un paragraphe de texte dans le deuxième onglet du document actif et place le curseur à la fin de ce paragraphe, vous devrez utiliser la méthode DocumentTab.newPosition(element, offset) pour obtenir la position en question, et la fixer mettra l’utilisateur sur cet onglet. Voici le code équivalent :
/**
* Ajoute un paragraphe au deuxième onglet (s’il existe, sinon le code plantera) du document, puis place le curseur de l’utilisateur à la fin de ce paragraphe.
*/
function addParagraphToSecondTab(){
const doc = DocumentApp.getActiveDocument();
const secondDocumentTab = doc.getTabs()[1].asDocumentTab();
const newParagraph = secondDocumentTab.getBody().appendParagraph(« Ceci est un nouveau paragraphe de texte. »);
const newPosition = secondDocumentTab.newPosition(newParagraph.getChild(0), newParagraph.getText().length);
doc.setCursor(newPosition);
}
Aller plus loin
Comme vous pouvez le constater, si les onglets ont rajouté une légère complexité pour nos scripts, ce n’est rien d’insurmontable, et cela reste assez proche des manipulations que l’on fait déjà avec Google Sheets. Il y a quelques petites subtilités avec la notion d’arbre et la différence entre Tab et DocumentTab, mais on s’y fait vite.
Si tout cela vous dépasse toujours, en revanche, et que vous ne savez pas du tout comment faire pour arriver à faire fonctionner votre code, pas d’inquiétude ! Vous pouvez poser vos questions sur notre forum, ou, si vous le souhaitez, faire directement appel à nos services, soit avec une formation Apps Script dédiée, soit en prenant rendez-vous avec nous pour que nous puissions discuter de votre projet. Nous serons toujours ravis de vous aider !
- Articles connexes
- Plus de l'auteur