---
# System prepended metadata

title: 2023-12-11開發日誌
tags: [單字檢測, '開發日程:2023', '開發日程:2023-12']

---

# 2023-12-11開發日誌
## 歌: 4:00 A.M
## 單字檢測:

### 動機
本來已經做一個段落了，高一上受到補習班老師的委託增加1-6及版本的單字
又覺得本來的不夠好用 所以大改一番

---

### 新增之功能
補習班老師給了1-6級單字託我把1-6級的單字檢測分頁做出來
所以新增資料、音標欄和網站新單字表選項和表現方式是首要之務

#### 1-6級資料整合
* 就樸實無華的進行排序
* 排序過程中發現有以下這種的格式會無法排序
![image](https://hackmd.io/_uploads/B192iD48a.png)
* 但實際搜尋下來發現也沒幾個(頂多五個左右)所以就手動處理了(複製中文=>連接=>刪除下欄)
* 改變伺服器(GAS):
    * 基本上兩個單字本所要的其他參數(選擇個數 ，起始結尾字母)都大致相同 所以我決定就只是加上一個新的 parameter:sheet 這樣就不用做其他的判斷
* 音標顯示
    * 小錯誤搞了我好久
    * 本來想做成按鈕卻發現這樣挺占版面的




### 成果

* 網站:
https://watermelon-1234.github.io/memorize_voc/

* GAS端:
    * 檔案
        * **單字涉及著作權 不公開**
    * CodeGs
由於增加了一本單字本，所以我決定增加單字抽取有關的引數
`var sheet = e.parameter.sheet;` 
好處當然是可以直接用名子去抓sheet 不用switch-case等等的處理
主要變化
```javascript=
//只放心增或者改變的code
function doGet(e)//多收request的parameter
{
  var sheet = e.parameter.sheet;
    if(...)
        var resultArray = pickAndOutputWords(startLetter,endLetter,numToPick,sheet); 
    //或者
    else if
        var resultArray = pickall(startLetter,endLetter,sheet); // 执行功能
}
function pickAndOutputWords(startLetter='A', endLetter='B', numToPick='5',sheetName="3-5:chosen") {
    &&
function pickall(startLetter='A', endLetter='B', sheetName="3-5:chosen") {
//增加靈活性
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
}
```

2. index.html
* 因為自己使用下來 很明顯的再行動端(手機平板)如果滑到其他Page不理它過一陣子就會被refresh成原本的樣子了<br>阿本來單字不見就很OOXX所以我在找有沒有什麼辦法在header裡面卡refresh但感覺是沒料<br>因為這是牽涉到記憶體配置等 唯一的想法就是做成APP然後用<strong>背景APP刷新</strong>的設定等等
```htmlembedded=
      <span style="font-size: 25%; color: white;">注意!如果手機切換到其他分頁或者app可能會因為手機端的記憶體空間配置而自動刷新而讓單字消失!</span>
```

* 這value設定好就不用煩惱sheet對照的問題了:>
```=htmlembeded
        <label for="sheetName">單字範圍</label>
        <select id="sheetName" >
          <option value="3-5:chosen">3-5級挑選版</option>
          <option value="1-6:chosen">1-6級挑選版</option>
        </select><br>
```
3. script.js
* 處理單字的開頭結尾的下式選單:
 ![image](https://hackmd.io/_uploads/HyD_ePfva.png)

原本:先選開始而且後面的只要超出範圍就會先變成空白要重選很麻煩
```javascript=
function populateEndLetters() {//作為下拉式選單的內容
    var startLetter = document.getElementById("startLetter").value;
    var endLetterSelect = document.getElementById("endLetter");

    var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    var startIndex = alphabet.indexOf(startLetter);
    var endIndex = alphabet.indexOf(endLetterSelect.value);
    endLetterSelect.innerHTML = "<option value='' disabled selected></option>";  
    for (var i = startIndex; i < alphabet.length; i++) {
        var letter = alphabet.charAt(i);
        var option = document.createElement("option");
        option.value = letter;
        option.innerText = letter;
        endLetterSelect.appendChild(option);
    }
    if(endIndex < startIndex) {
        endLetterSelect.selectedIndex = 1;
    }
    else
    {
        endLetterSelect.selectedIndex = endIndex - startIndex +1;
    }
}
```

* 防止網頁掛掉而甚麼都不反映 使用者會很矇
```javascript=
pickAndOutputWords(startLetter, endLetter, numToPick,sheet)
.then(words => {
    displayWords(words);
})
.catch(error => {
    console.error('Error:', error);
    outputDiv.innerHTML = " ERROR: " + error+ "<br>請聯繫作者";
});
```
* 顯示文字部分
```javascript=
function displayWords(words) {
```
標號數字:
```javascript=
content += "<tr><td class=\"ranking\"><p>"+(i+1)+".</p></td>";
```

英文單字 點下去要能夠跳音標
```javascript=
content += "<td><p class=\"pronouncing-switch\" data-value=\""+words[i][2].replace(/'/g, '&apos;')+"\">" + words[i][0] + "</p></td>";
```
複製英文單字，必須放這邊是因為
```javascript=
content += "<input type=\"button\" id=\"copyBtn\" value=\"複製單字到剪貼簿\">";
    content += "<input type=\"button\" onclick=\"toggleRowVisibility(this)\" value=\"只出現不會的字\"></input>";
    outputDiv.innerHTML = content;
    switch_col_one();
    document.getElementById('copyBtn').addEventListener('click', function() {
        // 在這裡使用 this
        create_alphabat_content();
        this.value = "已複製完成!";
    });
}
```
* 切單字-音標
```javascript=
function col_one_unite(){
  // 取得所有具有 pronouncing-switch 類別的元素
  const pronouncingElements = document.querySelectorAll('.pronouncing-switch');
  // 取得 body 元素的字體
  const bodyFont = window.getComputedStyle(document.body).getPropertyValue("font-family");

  // 為每個元素添加點擊事件監聽器
  pronouncingElements.forEach(element => {
      const currentContent = element.textContent;
      const valueAttribute = element.getAttribute('data-value');

      // 根據 value 屬性的第一個字元執行不同的操作
      if (currentContent.startsWith('〔')) {
          // 如果第一個字元是 '〔'，則修改字體並讓內容和 value 互換
          element.textContent = valueAttribute;
          element.setAttribute("data-value", currentContent); // 更新內容
          element.style.fontFamily = 'PHONETIC'; // 修改字體
      } 
  });
}


```
> chatgpt註解寫得真好

* 複製文字部分
前面已經在displayWord那邊放eventlistener了
所以就直接寫function了
對了 `col_one_unite();`是把所有的`class=".pronouncing-switch"`都從音標改成英文
```javascript=
function create_alphabat_content()
  {
  col_one_unite();
    // 獲取指定的div元素
  const targetDiv = document.getElementById('outputDiv'); // 請將'yourDivId'替換為實際的div元素ID
  
  // 獲取該div中的所有表格
  const tables = targetDiv.getElementsByTagName('table');

  // 如果有多個表格，選擇你想要處理的表格（例如，這裡選擇第一個表格）
  const targetTable = tables[0];

  // 獲取該表格中所有行
  const rows = targetTable.getElementsByTagName('tr');

  // 創建一個空字符串，用於保存結果
  let resultString = '';

  // 迭代處理每一行，將第一列的textContent添加到結果字符串中
  for (let i = 0; i < rows.length; i++) {
      const cells = rows[i].getElementsByTagName('td'); // 如果是th而不是td，請適當更改
      if (cells.length > 0) {
          resultString += cells[1].textContent.trim() + '\n'; // 添加到結果字符串中，可以根據需要添加分隔符號
      }
  }
  //this.innerHTML = "已複製完成!";
  //console.log(this)
  // 現在resultString包含所有第一列的textContent
  copyToClipboard(resultString);

}

function copyToClipboard(content) {
    // 建立一個 textarea 元素
  const textarea = document.createElement('textarea');
  
  // 將內容設置為要複製的內容
  textarea.value = content;

  // 將 textarea 加入 DOM 中
  document.body.appendChild(textarea);

  // 選擇 textarea 中的內容
  textarea.select();

  try {
    // 嘗試複製內容到剪貼簿
    const success = document.execCommand('copy');

    if (!success) {
      console.error('無法複製到剪貼簿');
    }
  } catch (err) {
    console.error('複製到剪貼簿時發生錯誤', err);
  } finally {
    // 移除 textarea
    document.body.removeChild(textarea);
  }
}
```

### 尾聲
大體上真的就這樣差不多，但應該還是可以挖大坑來填(登入系統)
這可能就不是github可以吃的 或者我要架在render之類了 如果放github語法應該會相當侷限就是

就真的每次想做任何project都是不確定是否有相關技能之下
所以邊做邊學的好處就是順便有能力增進 還有暴增解決問題方法

~~阿壞處很明顯就是速度很慢~~

### 同場加映
沒頭沒尾的講一下base64
主要就是加密法
好像國小就會了
#### 算法
![image](https://hackmd.io/_uploads/HJfuswzv6.png)
不難懂就直接放圖片了

#### 用法
當然可以網路上找線上轉換:
https://www.base64decode.org/

最大的問題就是我要丟的東西如果量超大
當然貼不上去(檔案大的話就算丟txt也跑不太動(畢竟如果是把圖片轉txt大小肯定根本來的圖片不同))

所以我們可以從<strong>CMD</strong>開搞
就是要用其中的<strong>certutil</strong>
我也不知道他的完整功能其實 有興趣就`certutil /?`

![image](https://hackmd.io/_uploads/S1ghTDfP6.png)
~~卡波真可愛~~
 主要的用法就是
`certutil -encode A.txt b.txt`
會把A檔案加密成 b.txt
(b不能已存在)

當然可以改成其他檔案類型

大概長這這樣:
```
C:\Users\vagrant>type out.txt
hello

C:\Users\vagrant>certutil -encode out.txt hello2.txt
Input Length = 6
Output Length = 66
CertUtil: -encode command completed successfully.

C:\Users\vagrant>type hello2.txt
-----BEGIN CERTIFICATE-----
aGVsbG8K
-----END CERTIFICATE-----
```
和這樣:
`certutil -decode c:\foo.asc c:\foo.exe`
