Google Docs 內有 Markdown 功能可以使用,必須手動去開啟,路徑為 工具 => 偏好設定 => 啟用 Markdowm
開啟後右鍵選單上就會有 Markdown 功能
另外編輯時也支援 Markdown 語法輸入,詳見官方文章介紹 - 在 Google 文件、簡報和繪圖中使用 Markdown
~楓花雪岳~
星期二, 2月 24, 2026
星期五, 2月 20, 2026
[GAS] 這個應用程式是由 Google Apps Script 的使用者建立
把 [網頁應用程式] 部屬出去執行後,在網頁上方匯出出現 [這個應用程式是由 Google Apps Script 的使用者建立] 安全性警告,這個沒有辦法直接移除,常見繞道隱藏方式為把網頁內嵌在 Google Site 內
直接拿 [JS] 基礎練習 UI 畫面來呈現
XFrameOptionsMode
直接拿 [JS] 基礎練習 UI 畫面來呈現
XFrameOptionsMode
- ALLOWALL:No X-Frame-Options header will be set. This will let any site iframe the page, so the developer should implement their own protection against clickjacking.
- DEFAULT:Sets the default value for the X-Frame-Options header, which preserves normal security assumptions. If a script does not set an X-Frame-Options mode, Apps Script uses this mode as the default.
function doGet() {
return HtmlService.createTemplateFromFile('index')
.evaluate()
.setTitle('圖書館館藏管理系統')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
一開始嚐試把 GAS 網頁應用程式內嵌在 Google Site 時,並沒有指定 ALLOWALL,但一樣可以正常顯示,大概是 DEFAULT 會把 Google 相關服務設定為白名單或信任服務之類,所以不需要特別指定,萬一是要把 GAS 網頁應用程式內嵌在其他平台,就一定要明確設定 ALLOWALLGAS 警語隱藏是 Goolge Site 標誌,下面則是內崁的 GAS 網頁應用程式,已經不會出現官方制式警語
- 參考資料
- Enum XFrameOptionsMode
- Class HtmlOutput
- FB 討論 - 把網頁內崁在 Wix Site 經驗談
星期三, 2月 18, 2026
[JS] 基礎練習
該筆記會在 GAS 上練習 js
gs code
index.html
js.html
- 資料來源:陣列、物件概念
- 基礎函示:push、filter 使用
- DOM API:使用 API 來顯示資料,而非使用 innerHTML
- addEventListener 註冊事件:DOMContentLoaded 和 Click 事件
/**
* 處理 HTTP GET 請求
* @return {HtmlOutput}
*/
function doGet() {
return HtmlService.createTemplateFromFile('index')
.evaluate()
.setTitle('圖書館館藏管理系統');
}
/**
* 嵌入 HTML 檔案內容
* @param {string} filename 檔案名稱
* @return {string} 檔案內容
*/
function include(filename) {
return HtmlService.createHtmlOutputFromFile(filename).getContent();
}
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h2>新增書籍館藏</h2>
<div class="input-group">
<select class="bookCategory">
<option value="程式語言">程式語言</option>
<option value="文學小說">文學小說</option>
<option value="商業理財">商業理財</option>
</select>
<input type="text" placeholder="書籍名稱" class="bookTitle">
<input type="text" placeholder="作者" class="bookAuthor">
<input type="button" class="addBtn" value="加入館藏">
</div>
<h2>館藏查詢與篩選</h2>
<div class="filterGroup">
<input type="button" value="全部">
<input type="button" value="程式語言">
<input type="button" value="文學小說">
<input type="button" value="商業理財">
</div>
<ul class="bookList"></ul>
<?!= include('javascript'); ?>
</body>
</html>
<script>
/**
* 書籍測試資料
*/
let libraryData = [
{ title: "深入淺出 JavaScript", author: "Eric Freeman", category: "程式語言" },
{ title: "哈利波特", author: "J.K. Rowling", category: "文學小說" },
{ title: "原子習慣", author: "James Clear", category: "商業理財" },
{ title: "Clean Code", author: "Robert C. Martin", category: "程式語言" }
];
// 選取 DOM 元素
const bookList = document.querySelector('.bookList');
const bookTitle = document.querySelector('.bookTitle');
const bookAuthor = document.querySelector('.bookAuthor');
const bookCategory = document.querySelector('.bookCategory');
const addBtn = document.querySelector('.addBtn');
const filterGroup = document.querySelector('.filterGroup');
/**
* 使用純 DOM API 產生書籍列表
* @param {Array} data 欲顯示的書籍陣列
*/
function renderLibrary(data) {
// 清空目前列表
while (bookList.firstChild) {
bookList.removeChild(bookList.firstChild);
}
// 建立新節點
data.forEach(function(book) {
const li = document.createElement('li');
// 建立書籍資訊容器
const infoSpan = document.createElement('span');
infoSpan.textContent = `[${book.category}] 《${book.title}》 - 作者:${book.author}`;
li.appendChild(infoSpan);
bookList.appendChild(li);
});
}
/**
* 新增書籍
*/
addBtn.addEventListener('click', function() {
const title = bookTitle.value.trim();
const author = bookAuthor.value.trim();
const category = bookCategory.value;
if (title === "" || author === "") {
alert("請完整填寫書名與作者!");
return;
}
const newBook = {
title: title,
author: author,
category: category
};
libraryData.push(newBook);
// 重新渲染並清空輸入框
renderLibrary(libraryData);
bookTitle.value = "";
bookAuthor.value = "";
});
/**
* 篩選資料功能
*/
filterGroup.addEventListener('click', function(e) {
if (e.target.type !== "button") return;
const filterType = e.target.value;
let result;
if (filterType === "全部") {
result = libraryData;
} else {
result = libraryData.filter(function(book) {
return book.category === filterType;
});
}
renderLibrary(result);
});
/**
* 初始化頁面
*/
document.addEventListener('DOMContentLoaded', function() {
renderLibrary(libraryData);
});
</script>
星期一, 2月 09, 2026
[GAS] Library - 最新程式碼快照 (開發人員模式)
在 [GAS] 資料庫 (Library) 筆記時有提到版本內有 [最新程式碼快照 (開發人員模式)] 可以使用,但實際應用時發現,原來要存取 [最新程式碼快照 (開發人員模式)] 必須具備 [編輯者] 權限,當初分享 library 給別人使用,因為只授予 [檢視者],就無法存取
星期四, 2月 05, 2026
[GAS] Slide 合併資料
Slide 常見應用場景,在一個範本 Slide 上設定多個 {{文字說明}} 符號,並從 Google Sheet 內抓取資料後,根據實務需求取代 {{文字說明}},該筆記以課程結業證書為例筆記
Slide 範本
gs Code
把 [課程結業證書範本 Slide] 複製至新位置,該筆記是以根目錄內的日期資料夾 (EX:2026-02-05) 去,並把學員資料透過 replaceAllText() 更新至 Slide {{文字說明}}
{{文字說明}} 基本上在 Slide 內是唯一的識別文字就行,前後有沒有符號包起來不是重點,但既然官方教學都使用 {{}} 包起來,就延續該風格囉,Slide 內有三個文字說明,分別為 {{學員姓名}}、{{課程名稱}}、{{日期}}
replaceAllText(findText, replaceText) 函式
執行結果
該筆記只有使用 replaceAllText() 取代文字,還有兩個主題分別為
Slide 範本
gs Code
把 [課程結業證書範本 Slide] 複製至新位置,該筆記是以根目錄內的日期資料夾 (EX:2026-02-05) 去,並把學員資料透過 replaceAllText() 更新至 Slide {{文字說明}}
{{文字說明}} 基本上在 Slide 內是唯一的識別文字就行,前後有沒有符號包起來不是重點,但既然官方教學都使用 {{}} 包起來,就延續該風格囉,Slide 內有三個文字說明,分別為 {{學員姓名}}、{{課程名稱}}、{{日期}}
replaceAllText(findText, replaceText) 函式
- findText:以該筆記為例,是指 {{文字說明}}
- replaceText:取代 {{文字說明}} 的內容
function SlideMergeData() {
const presentation = SlidesApp.getActivePresentation();
const timeZone = Session.getScriptTimeZone();
const dateString = Utilities.formatDate(new Date(), timeZone, "yyyy-MM-dd");
// 設定根 FolderID
const rootFolderId = GetFolderID();
const rootFolder = DriveApp.getFolderById(rootFolderId);
// 檢查並刪除同名的日期資料夾
const existingFolders = rootFolder.getFoldersByName(dateString);
while (existingFolders.hasNext()) {
const oldFolder = existingFolders.next();
oldFolder.setTrashed(true); // 將舊資料夾移至垃圾桶
}
// 建立日期資料夾
const dateFolder = rootFolder.createFolder(dateString);
// 複製範本 Slide 來使用
const templateFile = DriveApp.getFileById(presentation.getId());
const studentName = "王小強";
const copyFile = templateFile.makeCopy(studentName, dateFolder);
// 開啟新 Slide 並進行文字替換
const newPresentation = SlidesApp.openById(copyFile.getId());
newPresentation.replaceAllText('{{學員姓名}}', studentName);
newPresentation.replaceAllText('{{課程名稱}}', "Google Apps Script");
newPresentation.replaceAllText('{{日期}}', dateString);
newPresentation.saveAndClose();
}
執行結果
該筆記只有使用 replaceAllText() 取代文字,還有兩個主題分別為
- replaceAllShapesWithImage 取代圖片
- BatchUpdate:有效能考量使用,需要開啟 Google Drive API 服務
目前沒有使用到,單純紀錄
訂閱:
意見 (Atom)







