分页: 31 / 31

Re: 將製作ejcees(中國象棋打譜程式)

发表于 : 2026年 5月 1日 13:44
ejsoon
gemini pro

You’ve reached your Pro model limit
Responses will use other models until it resets on May 1, 4:52 PM.

代码: 全选

Here are the modifications to address your requirements. The URL logic has been updated to strictly require `#`, and FEN encoding/decoding has been modified to handle `r` and `f` in place of the standard `-` placeholders (or appended to `i`).

### 1. Update `encodeUrlParam()`
Update the `encodeUrlParam` method to inject the `r` and `f` flags into the FEN string.

```javascript
  encodeUrlParam(node, isRoot) {
    let res = '';
    if (isRoot) {
      let rFlag = this.isRotateEnabled ? 'r' : '';
      let fFlag = this.isFlipEnabled ? 'f' : '';

      if (node.fen === this.INITIAL_FEN) {
        res += 'i' + rFlag + fFlag;
      } else {
        // Replace the '-' castling/en passant placeholders with 'r' and 'f'
        let fenArr = node.fen.split(' ');
        if (this.isRotateEnabled && fenArr.length >= 3) fenArr[2] = 'r';
        if (this.isFlipEnabled && fenArr.length >= 4) fenArr[3] = 'f';
        
        // Replace spaces with commas
        res += fenArr.join(',');
      }
    }

    if (node.c) {
      res += ';' + encodeURIComponent(node.c);
    }

    if (node.v && node.v.length > 0) {
      if (node.v.length === 1) {
        let child = node.v[0];
        let moveStr = child.move;
        res += '+' + moveStr + this.encodeUrlParam(child, false);
      } else {
        res += '@';
        let branchStrs = [];
        for (let i = 0; i < node.v.length; i++) {
          let child = node.v[i];
          let moveStr = child.move;
          branchStrs.push(moveStr + this.encodeUrlParam(child, false));
        }
        res += branchStrs.join('&') + '$';
      }
    }
    return res;
  }
```

### 2. Update `parseUrlHash()`
Update the `parseUrlHash` method to extract the `r` and `f` flags, revert them back to `-`, and save their state to the root node.

```javascript
  parseUrlHash(hashStr) {
    let pos = 0;

    const peek = () => {
      return pos < hashStr.length ? hashStr[pos] : null;
    };

    const consume = () => {
      return pos < hashStr.length ? hashStr[pos++] : null;
    };

    // 1. Read FEN and extract rotate/flip flags
    let fenStr = '';
    let parsedR = false;
    let parsedF = false;

    if (peek() === 'i') {
      consume();
      fenStr = this.INITIAL_FEN;
      // Handle variations like 'ir', 'if', 'irf', 'ifr'
      while (peek() === 'r' || peek() === 'f') {
        if (peek() === 'r') { parsedR = true; consume(); }
        else if (peek() === 'f') { parsedF = true; consume(); }
      }
    } else {
      let fenChars = [];
      while (peek() !== null && peek() !== ';' && peek() !== '+' && peek() !== '@') {
        fenChars.push(consume());
      }
      let fenRaw = fenChars.join('');
      let fenArr = fenRaw.split(',');
      
      // Revert 'r' and 'f' back to standard '-' FEN placeholders
      if (fenArr.length >= 3 && fenArr[2] === 'r') {
        parsedR = true;
        fenArr[2] = '-';
      }
      if (fenArr.length >= 4 && fenArr[3] === 'f') {
        parsedF = true;
        fenArr[3] = '-';
      }
      fenStr = fenArr.join(' ');
    }

    let rootNode = {
      fen: fenStr,
      move: null,
      r: parsedR ? 1 : 0,
      f: parsedF ? 1 : 0,
      c: '',
      v: []
    };

    const createChildFromMove = (parentFen, moveStr) => {
// ... keep the rest of parseUrlHash unchanged
```

### 3. Update `importExportedText()`
Replace the two separate URL checking blocks at the beginning of `importExportedText` with this combined logic. `#` is now the strict requirement.

```javascript
  importExportedText(text, importedFen = null) {
    text = text.trim();
    if (!text || text.startsWith('go ')) {
      this.renderRecordUI();
      this.renderNoteUI();
      this.updateToolHighlights();
      return;
    }

    // NEW URL PARSING LOGIC: Containing '#' is a strict requirement
    if (text.includes('#')) {
      let parts = text.split('#');
      let beforeHash = parts[0].trim();
      let hashPart = parts.length > 1 ? parts[1].trim() : '';

      if (hashPart === '') {
        this.baseUrl = beforeHash;
        this.renderRecordUI();
        this.renderNoteUI();
        this.updateToolHighlights();
        return;
      } else {
        let currentDomain = window.location.origin + window.location.pathname;
        if (beforeHash !== '' && beforeHash !== currentDomain) {
          this.baseUrl = beforeHash;
        }
        
        try {
          let parsedTree = this.parseUrlHash(hashPart);
          if (parsedTree && parsedTree.fen) {
            this.historyFEN = parsedTree;
            this.initBranch();
            this.currentStepIndex = 0;
            
            // Assign rotate and flip states based on parsed data
            this.isRotateEnabled = this.historyFEN.r === 1;
            this.isFlipEnabled = this.historyFEN.f === 1;
            this.reapplyVisualPositions();
            
            this.renderRecordUI();
            this.renderNoteUI();
            this.jumpToStep(0);
            this.saveStateToUndo();
            this.updateToolHighlights();
            return;
          }
        } catch (e) {
          console.log('Failed to parse as URL parameter, falling back to text notation.', e);
        }
      }
    }

    // Normalize Chinese notations
    text = text
      .replace(/车/g, '車')
// ... keep the rest of importExportedText unchanged (remove the old `if (text.includes('#') || text.startsWith('i;') ...)` block since it is now consolidated above)
```

Re: 將製作ejcees(中國象棋打譜程式)

发表于 : 2026年 5月 1日 13:51
ejsoon
ejceesobj202605011350

這回PGN和URL格式都有rotate和flip了,但是東萍漏掉了…

Re: 將製作ejcees(中國象棋打譜程式)

发表于 : 2026年 5月 1日 13:56
ejsoon

代码: 全选

明白了!你指的不是給訪客看的「網站導航欄」,而是管理者登入後看到的頂部黑色條狀 **「工具列」(Admin Bar / Toolbar)**。

預設情況下,WordPress 的工具列只有「新建 > 媒體」,但沒有直接「進入媒體庫列表」的捷徑。要實現這個功能,最簡單且不影響網站速度的方法是在你的佈景主題 `functions.php` 檔案中加入一小段代碼。

### 解決方案:使用代碼新增工具列連結

你可以透過自定義函數來擴充工具列。請將以下代碼貼到你主題的 `functions.php` 檔案末尾:

```php
// 在管理員工具列中新增「媒體庫」連結
function custom_admin_bar_media_link($wp_admin_bar) {
    $args = array(
        'id'    => 'quick-media',      // 節點 ID
        'title' => '媒體庫',           // 顯示的文字
        'href'  => admin_url('upload.php'), // 連結位址
        'meta'  => array(
            'class' => 'custom-media-link',
        )
    );
    $wp_admin_bar->add_node($args);
}
add_action('admin_bar_menu', 'custom_admin_bar_media_link', 999);
```

---

### 操作步驟

1.  **進入編輯器**:在 WordPress 後台,前往 **外觀 (Appearance) > 佈景主題編輯器 (Theme File Editor)**。
2.  **選擇檔案**:在右側清單中找到 `functions.php` (佈景主題函式庫)。
3.  **貼上代碼**:將上述代碼複製並貼在檔案的最下方。
4.  **儲存**:點擊「更新檔案」。
5.  **查看效果**:重新整理頁面,你會發現頂部黑條多了一個 **「媒體庫」** 的按鈕。

---

### 為什麼代碼最後是 `999`?
這是一個「優先級」參數。數字越大,你的「媒體庫」按鈕就會越靠**右側**顯示(在所有預設按鈕之後)。如果你希望它靠左一點,可以把 `999` 改成較小的數字(如 `50`)。

### 另一種「懶人」方法:使用外掛
如果你不習慣改代碼,可以使用 **"Branda"** 或 **"Admin Toolbar Editor"** 這類外掛。它們提供視覺化介面,讓你可以自由拖拽、新增或隱藏頂部工具列的任何連結。

> **小撇步**:如果你經常需要上傳檔案,原本工具列上的 **「+ 新增」>「媒體」** 其實已經在那了,但它直接跳到「上傳」介面,而非「列表」介面。上面的代碼能完美幫你補足「看列表」的需求。

這樣設定後,管理起來是不是順手多了?

我要加到第一個下拉菜單中,也就是dashboard、plugins、theme、widgets、menus的下方,同時我想修改這個菜單,裡面的一些默認項目我一般很少用。

代码: 全选

這是一個非常專業的需求。要修改 WordPress 工具列(Admin Bar)左側「網站名稱」下的那個下拉選單(也就是包含 Dashboard、Themes、Widgets 等項目的選單),我們需要用到 `wp_before_admin_bar_render` 這個 Hook。

透過這個方法,我們可以同時做到:
1. **刪除**你很少用的項目(例如:自訂、評論等)。
2. **新增**你想要的項目(例如:媒體庫)。

### 解決方案:自訂工具列下拉菜單

請將以下代碼放入你佈景主題的 `functions.php` 中:

```php
function customize_my_admin_bar_menu() {
    global $wp_admin_bar;

    /* --- 1. 移除不常用的預設項目 --- */
    // 移除「自訂」 (Customize)
    $wp_admin_bar->remove_node('customize');
    // 移除「評論」 (Comments)
    $wp_admin_bar->remove_node('comments');
    // 移除「更新」 (Updates)
    $wp_admin_bar->remove_node('updates');

    // 如果你想移除下拉選單中的特定子項目,可以參考以下 ID:
    // $wp_admin_bar->remove_node('themes');  // 移除「佈景主題」
    // $wp_admin_bar->remove_node('widgets'); // 移除「小工具」
    // $wp_admin_bar->remove_node('menus');   // 移除「選單」

    /* --- 2. 在第一個下拉選單中加入新項目 --- */
    // 'parent' => 'site-name' 會將它放到網站名稱下方的下拉清單中
    $wp_admin_bar->add_node(array(
        'id'     => 'quick-media-list',
        'parent' => 'site-name',      // 關鍵:這會讓它出現在第一個下拉選單
        'title'  => '媒體庫',          // 顯示文字
        'href'   => admin_url('upload.php'),
        'meta'   => array('class' => 'my-custom-admin-item')
    ));

    // 你可以繼續加另一個項目
    $wp_admin_bar->add_node(array(
        'id'     => 'quick-all-pages',
        'parent' => 'site-name',
        'title'  => '所有頁面',
        'href'   => admin_url('edit.php?post_type=page'),
        'meta'   => array('class' => 'my-custom-admin-item')
    ));
}
add_action('wp_before_admin_bar_render', 'customize_my_admin_bar_menu', 999);
```

---

### 代碼解說與調整指南:

1.  **如何移除其他項目?**
    WordPress 工具列的每個按鈕都有一個 ID。常見的 ID 包括:
    * `dashboard`: 控制台
    * `themes`: 佈景主題
    * `widgets`: 小工具
    * `menus`: 選單
    * `new-content`: 「+ 新增」按鈕
    * 如果你想刪除哪一個,就用 `$wp_admin_bar->remove_node('ID名稱');`。

2.  **如何決定新項目的位置?**
    在 `add_node` 的參數中,`'parent' => 'site-name'` 是最重要的。這告訴 WordPress 這個新連結是隸屬於左上角「網站名稱」這個父級選單下的子項目。

3.  **如何調整先後順序?**
    預設情況下,新加入的項目會排在該選單的**最下方**。如果你希望精確控制排序,WordPress 原生的 `add_node` API 對子項目的排序支援較有限。如果對順序有極致要求,通常建議先移除所有項目,再按照你想要的順序全部重新加回去。

### 溫馨提示
* **子佈景主題 (Child Theme)**:如果你是在編輯現成的主題,強烈建議在「子佈景主題」的 `functions.php` 裡修改,否則主題更新後你的設定會消失。
* **多站點模式**:如果你使用的是 WordPress 多站點(Multisite),ID 可能會稍微不同(通常是 `site-name` 變成了 `appearance` 下的子項),但一般單一網站使用上述代碼即可。

這樣修改後,你的頂部導航欄就會變得非常乾淨,且只留下你真正需要的快捷鍵了!

Re: 將製作ejcees(中國象棋打譜程式)

发表于 : 2026年 5月 1日 20:43
ejsoon
改進:
一,meta設置按鈕將一直顯示在rcdtext的右上角。

二,Rotate和Flip將不會在meta窗口中顯示。meta窗口的「垃圾桶」應改為一個svg圖標,可使用代碼中已有的圖標。

三,在導出函式中,將取消前面的提前賦值,全部改成臨時賦值。

四,在meta窗口中的default按鈕右邊增加一個Zh/En的切換按鈕,當切換成En時,PD format將導出英文格式。

五,當rotate和flip為true時,導出dp format時將把「rotate\n」、「flip\n」輸出至前面。導入時將它們賦值後刪掉,不要把它們當成評論。

只需給出所要修改的地方,所有的代碼和注釋都要使用英文。

代码: 全选

改進:
一,meta設置按鈕將一直顯示在rcdtext的右上角。

二,Rotate和Flip將不會在meta窗口中顯示。meta窗口的「垃圾桶」應改為一個svg圖標,可使用代碼中已有的圖標。

三,在導出函式中,將取消前面的提前賦值,全部改成臨時賦值。

四,在meta窗口中的default按鈕右邊增加一個Zh/En的切換按鈕,當切換成En時,PD format將導出英文格式。

五,當rotate和flip為true時,導出dp format時將把「rotate\n」、「flip\n」輸出至前面。導入時將它們賦值後刪掉,不要把它們當成評論。

只需給出所要修改的地方,所有的代碼和注釋都要使用英文。