コメントでは厳し目なこと書きましたが、一応確認で書いた中途半端なコードは書いておきます。
メニューに「マクロ」が追加されるので、実行するとサイドバーが表示されます。
事前準備:
- Google ドライブに挿入するテンプレートを保存するフォルダを作成する。
- 上記フォルダにテンプレートとなるドキュメントを保存する。
制限事項:
- Paragraph の中にカーソルがある場合は、正常に動作しません。
- テキスト、テーブル、インラインイメージしか考慮してません。
JavaScript
1const ui = DocumentApp.getUi();
2
3function onOpen() {
4 ui.createMenu("マクロ").addItem("showSidebar", "showSidebar").addToUi();
5}
6
7function showSidebar() {
8 const files = (() => {
9 const templateFolder = DriveApp.getFolderById(
10 "(テンプレートとなるドキュメントファイルを保存するフォルダID)"
11 );
12
13 const iterator = templateFolder.getFilesByType(
14 "application/vnd.google-apps.document"
15 );
16 const result = [];
17 while (iterator.hasNext()) {
18 const file = iterator.next();
19 result.push({ id: file.getId(), name: file.getName() });
20 }
21 return result;
22 })();
23
24 const template = HtmlService.createTemplateFromFile("Sidebar");
25 template.files = JSON.stringify(files);
26 const htmlOutput = template.evaluate();
27 ui.showSidebar(htmlOutput);
28}
29
30function insertDocument(fileId) {
31 try {
32 const insertBody = DocumentApp.openById(fileId).getBody();
33
34 const doc = DocumentApp.getActiveDocument();
35 const position = doc.getCursor();
36 const element = position.getElement();
37 const parent = element.getParent();
38 let index = parent.getChildIndex(element);
39
40 const parentType = parent.getType();
41 const offset = position.getOffset();
42 const surroundingText = position.getSurroundingText().getText();
43 const surroundingTextOffset = position.getSurroundingTextOffset();
44
45
46 if (parent.getType() === DocumentApp.ElementType.PARAGRAPH) {
47 const parentParagraph = parent.asParagraph();
48 for (let i = 0; i < insertBody.getNumChildren(); i++) {
49 const child = insertBody.getChild(i);
50 if (child.getType() === DocumentApp.ElementType.PARAGRAPH) {
51 const paragraph = child.asParagraph().copy();
52 if (paragraph.getNumChildren() !== 0)
53 parentParagraph.insertParagraph(index++, paragraph);
54 } else if (child.getType() === DocumentApp.ElementType.INLINE_IMAGE) {
55 parentParagraph.insertInlineImage(
56 index++,
57 child.asInlineImage().copy()
58 );
59 } else if (child.getType() === DocumentApp.ElementType.TABLE) {
60 parentParagraph.insertTable(index++, child.asTable().copy());
61 }
62 }
63 } else {
64 for (let i = 0; i < insertBody.getNumChildren(); i++) {
65 const child = insertBody.getChild(i).copy();
66 if (child.getType() === DocumentApp.ElementType.PARAGRAPH) {
67 const paragraph = child.asParagraph();
68 if (paragraph.getNumChildren() !== 0)
69 parent.insertParagraph(index++, paragraph);
70 } else if (child.getType() === DocumentApp.ElementType.INLINE_IMAGE) {
71 parent.insertInlineImage(index++, child.asInlineImage().copy());
72 } else if (child.getType() === DocumentApp.ElementType.TABLE) {
73 parent.insertTable(index++, child.asTable().copy());
74 }
75 }
76 }
77
78 step = "complete";
79 } catch (ex) {
80 ui.alert("error = " + JSON.stringify(ex, null, 2));
81 }
82}
HTML
1<!DOCTYPE html>
2<html>
3 <head>
4 <base target="_top">
5 <title>Sidebar</title>
6 <style>
7 body { text-align:center; }
8 button[type=button] {
9 width: 250px;
10 height: 50px;
11 margin-bottom: 10px;
12 }
13 </style>
14 <script>
15 window.addEventListener("DOMContentLoaded", () => {
16 const body = document.querySelector("body");
17 const files = JSON.parse("<?=files?>");
18 files.forEach(file => {
19 const button = document.createElement("button");
20 button.setAttribute("type", "button");
21 button.textContent = file.name;
22 button.value = file.id;
23 button.addEventListener("click", () =>{
24 google.script.run
25 .withSuccessHandler(() => {})
26 .withFailureHandler(error => console.log(error))
27 .insertDocument(file.id);
28 } );
29 body.appendChild(button);
30 });
31 });
32 </script>
33 </head>
34 <body>
35 <h3>テンプレート挿入</h3>
36 </body>
37</html>