Mouse dictionary helper

Mouse Dictionary で引いた結果をAnkiwebのdeckに登録する君

当前为 2021-07-09 提交的版本,查看 最新版本

// ==UserScript==
// @name         Mouse dictionary helper
// @namespace    http://tampermonkey.net/
// @version      0.4
// @description  Mouse Dictionary で引いた結果をAnkiwebのdeckに登録する君
// @author       @ozero
// @match        *://*/*
// @grant       GM.setValue
// @grant       GM.getValue
// ==/UserScript==

'use strict';

/*
# Mouse Dictionary で引いた結果をAnkiwebのdeckに登録する君

英単語の意味だけ調べて済ませてたか、手作業で辞書から単語帳にコピペしてた人へ。辞書で引いた内容を即Anklwebの単語帳に登録できます。

1. Mouse dictinaryで単語の意味を表示する
2. Mouse dictinaryウィンドウをクリック
3. Ankiwebの単語登録画面が開いて、入力欄にさっき調べてた単語&意味が自動入力される
4. あとは自動入力の内容を確かめて、Saveクリックして閉じる

なお↑の 2. で Ctrl + クリック したら、自動入力に加えて「自動保存&Ankiwebのタブ自動クローズ」までやります。

## セットアップ

まずブラウザにTamperMonkey拡張を入れ、このスクリプトもインストールします。次に以下の手順で連携させます。

1. 拡張 Mouse Dictionary のオプションを開く
2. 設定を開く
3. 上級設定を開く
4. 項目「HTMLテンプレート」をみる
5. テンプレート「Mouse Dictionaryウィンドウ全体」のdivタグに、クラス名 `mouse_dictonary_helper` を足す

足した結果はこうなる

```
<div class="notranslate mouse_dictonary_helper"
     style="all:initial;
            {{systemStyles}}
            width: {{width}}px;
            height: {{height}}px;
            position: fixed;
            overflow-x: hidden;
            overflow-y: {{scroll}};
            top: 5px;
            background-color: {{backgroundColor}};
            z-index: 2147483646;
            padding: 2px 4px 2px 4px;
            border: 1px solid #A0A0A0;"
>
</div>
```

んで、設定を保存してセットアップ終わり。


## 実際の動作(手動追加)

1. Ankiweb にログインする
2. ページを開いて、Mouse Dictionary 拡張を実行
3. 単語をダブルクリックで選択固定
4. Mouse Dictionary ウィンドウをクリック
5. Ankiweb のデッキ追加ページが開いて、Mouse Dictinary で表示されていた内容がAutofillされる


## 実際の動作(自動追加&Ankiwebウィンドウ自動クローズ)

1. Ankiweb にログインする
2. ページを開いて、Mouse Dictionary 拡張を実行
3. 単語をダブルクリックで選択固定
4. Mouse Dictionary ウィンドウを Ctrl + クリック
5. Ankiweb のデッキ追加ページが開いて、Mouse Dictinary で表示されていた内容がAutofillされる
6. 自動でAnkiweb のデッキ追加ページのSaveボタンがクリックされる
7. 自動でAnkiweb のデッキ追加ページがクローズされる


## なんでコンテンツがドメインまたいでるの

`GM.setValue`, `GM.getValue` で userscript実行環境側のストレージを経由して受け渡しをしています。

- https://wiki.greasespot.net/GM.setValue
- https://wiki.greasespot.net/GM.getValue


*/

//Mouse dictionaryウィンドウクリック時の処理及び関連付け
( () => {
  let mouse_dictonary_helper = {};

  //Mouse dictionaryウィンドウの内容をGM.setValueでGMストレージに保存
  mouse_dictonary_helper.gsetval = (event) => {
    let mdh_element = document.getElementsByClassName('mouse_dictonary_helper')
    if(!mdh_element[0]){
      return false;
    }
    let content = mdh_element[0].innerText;
    GM.setValue( "mdhtmp", content );
    //console.log("set mdh", content);

    //Ctrlキー押下有無(→AnkiwebでAutofill後自動save&close)も持っとく
    if(event.ctrlKey ){
      GM.setValue( "mdhAutosave", "yes" );//set autosave flag
    }else{
      GM.setValue( "mdhAutosave", "no" );
    }

    //ついでにAnkiwebのデッキ追加ウィンドウを開く
    window.open('https://ankiuser.net/edit/', '_blank');

    return;
  };

  //Mouse dictionaryウィンドウの有無をpolling(200ms毎)してクリックイベントを追加
  const mdh_window_poll = () => {
    let mdh_element = document.getElementsByClassName('mouse_dictonary_helper')
    if(mdh_element[0]){
      mdh_element[0].addEventListener('click', mouse_dictonary_helper.gsetval, false);
      console.log("mdh addEventListener");
      return true;
    }else{
      setTimeout(()=>{
        mdh_window_poll();
      }, 200);
      //console.log("mdh polling");
      return false;
    }
  }
  mdh_window_poll();//Pollingの起動

} )();


//Ankiwebのデッキ追加URLを開いた際の入力欄autofill
(async function(){

  if(window.location.href !== "https://ankiuser.net/edit/"){
    return;
  }

  const mdhtmp = await GM.getValue( "mdhtmp", "" );
  if(mdhtmp === ""){
    return;
  }
  //console.log("get mdh", mdhtmp);

  //Util
  const sleep = (msec) => {
    return new Promise(resolve => setTimeout(resolve, msec))
  };

  //wait for form-dom loaded
  let loaded = false;
  while(!loaded){
    let el_front = document.getElementById("f0");
    if(!el_front){
      await sleep(100);
      continue;
    }
    let el_back = document.getElementById("f1");
    if(!el_back){
      await sleep(100);
      continue;
    }
    loaded = true;
  }

  //Autofill
  const mdhtmp_2 = mdhtmp.split("\n\n");
  const mdhtmp_3 = mdhtmp_2.shift().split("\n");
  const head = mdhtmp_3.shift().toLowerCase();//登録する単語は小文字に揃える
  const body = mdhtmp_3.join("\n");
  let el_front = document.getElementById("f0");
  let el_back = document.getElementById("f1");
  el_front.innerText = head;
  el_back.innerText = body;

  //Clear
  GM.setValue( "mdhtmp", "" );

  //もし既知の単語ならAlert出してここで止める
  const mdhKnownwordJson = await GM.getValue( "mdhKnownword", "{}" );
  let mdhKnownword = JSON.parse(mdhKnownwordJson);
  if(mdhKnownword[head]){
    document.title = "⚠二重登録";
    alert("二重登録: 単語 '" + head + "' は、過去にデッキに登録されています");
    return;
  }else{
    //既知の単語に追加する
    mdhKnownword[head] = true;
    GM.setValue( "mdhKnownword", JSON.stringify(mdhKnownword) );
  }

  //Autosave & close
  const mdhAutosave = await GM.getValue( "mdhAutosave", "no" );
  if(mdhAutosave !== "yes"){
    return;
  }
  GM.setValue( "mdhAutosave", "" );//clear autosave flag

  //Tell Autosave&close to user
  document.getElementById("msg").innerText="Auto Save & Auto Close ENABLED.";
  document.getElementById("msg").style.display = "block";

  await sleep(500);
  let el_btn = document.querySelector("body > main > p > button");
  el_btn.click();

  await sleep(1000);
  window.close();

})();


//Ankiwebの登録済み単語一覧を読み取ってGM.setValueでローカルに格納しておくやつ
(async function(){

  if(window.location.href !== "https://ankiweb.net/search/"){
    return;
  }

  let el_words = document.querySelectorAll("body > main > table > tbody > tr > td");
  if(el_words.length < 1){
    return;
  }

  //登録済み単語一覧をストレージに格納する
  let words = {};
  for(let el_w1 of el_words){
    let el_w2 = ("" + el_w1.innerText).split(" / ");
    if(el_w2.length < 2){
      continue;
    }
    let word = el_w2[0].toLowerCase();
    words[word] = true;
  }
  GM.setValue( "mdhKnownword", JSON.stringify(words) );

  return;
})();

//console.log("mdh loaded");

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址