
Contents
コードと使い方
以下の Github リポジトリにコードを置きました。 インストール方法としては、以下のように Google Chrome の拡張機能の画面に進み、「パッケージ化されていない拡張機能を読み込む」ボタンを押して、Github リポジトリからダウンロードした「leetcode-show-numlike」ディレクトリを選択するだけです。
解説
Chrome 拡張の作り方
今まで Chrome 拡張を作ったことがなく、今回始めて作ったのですが、思った以上に簡単でした。 最小限の構成としては、同じディレクトリに manifest.json とメインの Javascript ファイルを設置するだけです。manifest.json と app.js の中身を以下のように書いて、「パッケージ化されていない拡張機能を読み込む」から拡張機能をインストールすれば、LeetCode の問題のリストページにアクセスした際にダイアログボックスが表示されます。$ tree zuqqhi2-ext-test/ zuqqhi2-ext-test/ ├── app.js └── manifest.json 0 directories, 2 files
{ "name": "Zuqqhi2ExtTest", "version": "0.1.0", "manifest_version": 2, "description": "Test.", "content_scripts": [{ "matches": ["https://leetcode.com/problemset/all/*"], "js": ["app.js"], "css": [] }], "permissions": [] }
alert('Test');

今回作ったもの
以下のことをやっているだけのすごく単純な作りです。- 処理に使う要素が読み込まれるのを待ちます。
- 問題のリストページの場合は、表に列を追加して、LocalStorage から読み込んだ問題ごとの Like/Dislike 数を追加した列に表示します。
- 個別の問題ページの場合は、LocalStorage に Like/Dislike 数を保存します。
ページが表示されてからも処理に使う要素が表示されるまで待つようにしています。待たない場合は要素がなくてエラーになってしまうので。 以下のコードの部分で問題のリストページでは MutationObserver で要素が表示されるのを待っているのですが、個別の問題のページでは MutationObserver がうまく動かなかったので setInterval で適当に 500 ミリ秒ごとに要素が表示されるか見て、要素が表示されていれば LocalStorage に Like/Dislike 数を保存して終了する形になっています。 例えば個別の問題のページでは、Like/Dislike ボタンの要素を取得するのに(仕方なく)「btn__r7r7」クラスを指定しているので、個別の問題のページがちょっとでも修正されるとクラスが見つからなくて動かなくなると思います。// Common functions function loadProblemInfo() { // Clean or initialize localStorage var problem_info = {} if (localStorage.getItem('zuqqhi2-leetcode-show-numlike')) { try { problem_info = JSON.parse(localStorage.getItem('zuqqhi2-leetcode-show-numlike')) } catch (e) { localStorage.removeItem('zuqqhi2-leetcode-show-numlike') localStorage.setItem('zuqqhi2-leetcode-show-numlike', '{}') } } else { localStorage.setItem('zuqqhi2-leetcode-show-numlike', '{}') } return problem_info }
// Problem list page (Show number of like and dislike) var observer = undefined if (document.location.href.startsWith('https://leetcode.com/problemset/all/')) { observer = new MutationObserver(() => { const elems = document.querySelectorAll(".question-list-base > .question-list-table > .table > .reactable-data > tr") if (elems.length > 0) { ... observer.disconnect() } }) const targetNode = document.getElementsByClassName('question-list-base')[0] observer.observe( targetNode, {childList: true, subtree: true} ) // Each problem page (Save number of like and dislike) // Note: MutationOberser doesn't work on this page. So, just using setInterval function. } else { observer = () => { const elems = document.querySelectorAll(".btn__r7r7") if (elems.length === 4) { ... } } const observation = () => { console.log('zuqqhi2-leetcode-show-numlike: under observation...') const targetNode = document.getElementsByClassName('btn__r7r7')[0] if (targetNode !== undefined) { console.log('zuqqhi2-leetcode-show-numlike: observation is finished') observer() return true } else { return false } } const interval_id = setInterval(() => { if (observation()) { clearInterval(interval_id); } }, 500) }