Joplinはお転婆の跳ねっ返りでじゃじゃ馬なんだな

05/06

Develop My Plugin 2

目次

プラグイン開発で問題が

前回の続き。
前回はタグ変換の仕組みを実装したので、残りの実装を行っていこうとしたのだが、Joplin API Referencesを見ていたらネットワーク関連のAPIが見当たらない。
え?もしかして自らネットワークを介してデータ送受信ができないってこと?
マジで?

てことは、自前で作らないといけないのか。
ま、javascriptは書き慣れてるからいいか。

前回のをアップデート

リポジトリは前回紹介したのものなので、詳しい人はぶっちゃけそこを見ていただくだけで良いと思う。

自分のプラグインを使ってみてショートカットキーを結構使うことが分かったので、コンテキストメニューから呼び出すとか面倒くさいのでやめることにする。

選択した文字列をGoogle検索に投げて、候補を表示させて、候補から選んだリンクを使ってMarkdown記法で返すってやつを作ってみる。

ダイアログを作る

検索結果を表示させる場所が欲しいのでAPIからdialogsを使って、モーダルなダイアログを作ってみる。
んで、検索結果をそこにはっつけてやろうと思ってささっと作ったら、早速壁にぶち当たる。

iframeの壁

基本的なGoogleの検索アドレスは

https://www.google.com/search?q=クエリ

こんな感じなのでこの表示結果をiframeタグ使って表示させようとしたら、Googleのレスポンスヘッダに「X-Frame-Options: SAMEORIGIN」が入っているようでiframe使うときは同一ドメインでないと使えないらしい。 1
なので自前でサイトの結果を取得して、自前で画面を作って、、、、、ってことをする他ないようだ。
ま、いつもやっているWebScrapingをここでもやらなくてはいけないようだ。
やると決まったらあとは手を動かしてみる。

Dialogs

ダイアログで使う基本的なHTMLはcommon.tsに定義しておく。

common.ts

function showGSDialog(selected: string){
	let query=`<input id='query' type='hidden' name='query' value='${selected}'>`;

	return `
	<h2 id='linktitle'></h2>
	<div id='result'></div>
	<form id='formdata' name='formdata'>
	<input id='resultURL' name='resultURL' type='hidden' value=''>
	<input id='resultTitle' name='resultTitle' type='hidden' value=''>
	${query}
	</form>
	`;
}
h2: 選択したリンク文字列を表示
div#result: 検索結果をliタグで一覧表示
input#resultURL: 選択したリンクのURLを保持しておくところ
input#resultTitle: 選択リンクのリンク文字列を保持しておくところ
input#query: Joplinの本体ノートから渡される選択文字列(検索文字列)

これでは検索が実行されないので、機能をさせるためにdialog.jsをダイアログに追加しておく。

index.ts

		const dialogs = joplin.views.dialogs;
		const dialog = await dialogs.create('search_dialog');
		await joplin.views.dialogs.addScript(dialog, 'dialog.js');
		await joplin.views.dialogs.addScript(dialog, 'dialog.css');
		await dialogs.setButtons(dialog, [
			{
				id: 'cancel',
				title: 'Close'
			}
		]);

dialog.js

function searchInGoogle() {
    let query=document.getElementById('query').value;
    let searchengine='https://www.google.com/search?q=';
    let result=document.getElementById('result');

    console.log('query:'+query+'');
    fetch(searchengine + query).then(response => response.text()).then((data)=>{
        let xml=new DOMParser();
        let _div=xml.parseFromString(data, 'text/html');
        let div=_div.getElementsByClassName("yuRUbf");

        result.innerHTML+='<ul>';
        Array.prototype.forEach.call(div, function(element, index){
            let title=element.getElementsByClassName("LC20lb")[0].innerHTML;
            let link=element.getElementsByTagName("a")[0].getAttribute("href");
            result.innerHTML+=`<li><a id='link_${index}' href='javascript:return false;' onclick='clickValue("${link}",${index})'>${title}</a></li>`;
        });
        result.innerHTML+='</ul>';
    });
}
function clickValue(url, index){
    let resultURL=document.getElementById('resultURL');
    let resultTitle=document.getElementById('resultTitle');
    let linktitle=document.getElementById('linktitle');
    let linkid=document.getElementById("link_"+index).innerText;

    resultURL.value=url;
    linktitle.innerText=linkid;
    resultTitle.value=linkid;
    return true;
}

searchInGoogle();

久々素のjsなんて書いた。

dialog側での処理

dialog内でゴニョゴニョしたものは、最終的に閉じられるとopenメソッドの戻り値として<form>内の情報をformDataってかたちで返ってくる。
それをごにょごにょするだけで実現できる。
簡単だな。

実例

この記事はもちろんJoplinで書いていて、サイトの貼り付けにはかなり重宝している。
ここでプラグインを使ってこんなことができるってことを紹介する。

正式名称を覚えていないような商品名や会社名があったとする。
例えば、カップラーメンの赤いきつねは知っているのにそばのやつの名前をど忘れしてしまったとかあったとする。(ないよ)
そういうときは、

そば 赤いきつね

って感じで書いてそれを選択して「Ctrl|Cmd + Shift + G」で検索ダイアログが表示されるので、そこに表示される結果から「緑のたぬき」がわかり、更にそこをクリックしてダイアログを閉じれば、
マルちゃん 赤いきつね緑のたぬき | 東洋水産株式会社
というリンクになって返ってくる。
ブラウザに切り替えて文字を入れる手間が減り結構便利だと思うのだが。

どうだろう。

最後に

次は、Google翻訳もやってみよう。


コメント: