フォームへ自動入力するchrome拡張機能の作成

弊社では写真販売サイトとしてフォトラボを運営しております。
ECサイトでは当然ながら注文者の情報を入力します。

写真販売のイベントは年に複数回あり、
注文する度に注文者情報を入力しなければなりません。

何度も何度も同じ内容を入力するのは非常に手間というものですね。
※フォトラボには注文者情報をブラウザに保存する機能がありますが

ということで、フォームを自動入力する拡張機能を作ってみましょう。
※storeでの公開まではしません

chrome拡張機能の概要

chrome拡張機能を作るのは難しくないのかい?
と言われるとなんともありません。
あれはただのjavascriptです。

やってることはaタグでjavascriptを実行するのと大差ありません。
<a href=”javascript:alert(‘Hello’);”>アラート</a>

それを
・ボタン一つで実行
・サーバーのAPIと連携
・chromeのブラウザ機能の利用

といったものを交えて様々できるようにしたもの。
それがchrome拡張機能です。
簡単ですね?
※PDF編集などの拡張機能はjavascript単体では不可能なので
 基本的にどこかのサーバーにデータを飛ばしています。多分。

というわけでまずフォームを自動入力するjavascriptを作りましょう。

フォームを自動入力するjavascript

let order_name = document.querySelector('[name="order_name"]');
order_name.value = 'スペースアイ=サン';

以上。
自社で運営しているサイトでname属性も固定であれば
name属性でnodeを取得してvalueを設定するだけです。

これをフォームの数だけ繰り返します。

上記を拡張機能として作成する

※動作チェックはしてないので注意

manifest.json

{
	"manifest_version": 3,
	"name": "フォーム自動入力",
	"version": "1.0",
	"description": "フォーム自動入力",
	"background": {
		"service_worker": "background.js"
	},
	"permissions": [
		"contextMenus",
		"scripting"
	],
	"action": {}
}

background.js

chrome.runtime.onInstalled.addListener(() => {
	chrome.contextMenus.create({
		type: 'normal',
		id: 'FormAutoSet',
		title: '自動入力',
	});
});
chrome.contextMenus.onClicked.addListener((info, tab) => {
	if(info.menuItemId === 'FormAutoSet'){
		chrome.scripting.executeScript({
			target: { tabId: tab.id },
			func: formAutoSet,
		});
		;
	}
});
function formAutoSet(){
	let order_name = document.querySelector('[name="order_name"]');
	order_name.value = 'スペースアイ=サン';
}

以上の2ファイルを1つのフォルダに保存します。
Q.なんで右クリックからやるの?
A.好きだから

作成したフォルダを以下のサイトの手順2を参考にchromeへ導入します。
手順 2: アプリや拡張機能をテストする

以上で右クリックからフォーム自動入力できる拡張機能が完成しました。
おめでとうございます。

………………………。
なんてところで終わってしまってはとても味気ない話になりますね。

拡張機能らしい自動入力を構築する

さて、フォームの自動入力自体は簡単にできますがそこは拡張機能。
もっと拡張した自動入力をしたいものです。

一番使いそうなのは「自動入力内容の保存と編集」でしょうか。
ではchromeのstorage機能を使って保存しましょう。

「manifest.json」の「permissions」に「storage」を追加し、JSに保存処理を書きます。
なお値を保存するには殆どの場合オプション画面を別途作成しますが、
「service_worker」内で「このページ」の「このフォームの値」は「これ」みたいなデータの保存もやろうと思えばできます。

最終的に保存するobjectの値が

{
	"order_name":"スペースアイ=サン",
	"order_kana":"スペースアイ"
}

のようになっていれば大丈夫。

サイトごとに分けたいなら

{
	"サイトURL" : {
		"order_name":"スペースアイ=サン",
		"order_kana":"スペースアイ"
	}
}

などなど。
もっと言えば「自分の扱いやすい保存の仕方」で問題なし。

storageの保存と取り出し

リファレンスにあるのでそちらを参考にしていただき、
わかりにくかった部分のメモ。

保存のリファレンスは以下のように書いてあります

chrome.storage.local.set({ key: value }).then(() => {
	console.log("Value is set");
});

が、以下のように解釈しないとエラーになりました。

let save_obj = {key: value};
await chrome.storage.local.set({ save_obj });

つまりkey:valueのオブジェクトを保存するのではなく、
key:valueのオブジェクトを{}で囲う。

ただこうなった要因は保存したいvalueがオブジェクトだったからではないかと思われます。
または元々の仕様か。

そのためか取り出すときは

let def_value = await chrome.storage.local.get('save_obj');

と、変数名を文字列で指定する書き方になっています。
しかもこの「def_value」の中身は
「def_value[‘save_obj’]」が保存したsave_objオブジェクトになっています。
どういうこったい。

以上の保存と取り出しを使って
・保存するオプション画面
 ※取り出した値を初期値としてフォームに設定すれば編集も可能
  なおstorageを編集する方法はないので上書き保存
・自動入力時にstorageの値でvalueを入力

とすれば拡張機能らしい自動入力機能の完成です。
おめでとうございます(2回目)

ここからはちょっとした応用DA

フォーム自動入力機能を作ると誰しも思うことがあります。
私は思いました。

どんなフォームでも使いたいと。

なお自動入力の拡張機能がないかざっと調べた所、存在したのは
・あるサービスの有料会員向け拡張機能
・色々な機能を搭載した拡張機能の1機能
などなど。

もっと簡便でシンプルなものはないかと悩み多き。
対して自動入力だけなら前述の方法でできるため、
あとは目的のinputタグを取得できれば良いのです。

その方法に関するメモ書き

1.name属性を力技で取得

name属性に指定されている語句は様々あります。
名前のinputタグであれば「name,Name,shimei」といったものから「名前,氏名」という日本語もあります。
name属性ってマルチバイト文字で指定しても動作するのか…。

そこで考えます。
極論、すべてのパターンをcssセレクターに書いてしまえば可能だと。
つまり「document.querySelectorAll(‘[name=”name”],[name=”Name”],[name=”shimei”]’)」と。

プログラマとしてはスマートでないため拒否反応はありますが
実際使って速度と精度共に問題ないなら見た目上は全く問題のない話です。

よって指定したいname属性を配列に保存し、forで回してcssセレクターを作れば対応できます。
要点は「あまりに力技の書き方をプログラマとして許容できるかどうか」です。

2.labelタグを始点にする

こちらは該当するものは少なめです。
そもそもlabelがなかったり、forが指定されてなかったりするので。

つまり「labelタグ」の文字列が条件に一致するなら
そのfor先のinputタグに自動入力するという方式。

やり方は
・ページ内のlabelタグを全取得
・forで回して「innerText」を「includes」で調べて
・一致すればfor先にあるinputに該当するvalueを入力

例えばですが、
wordpressのcontactform7で作られたフォームは
name属性を指定しないと「name=”text1″」などになります。

こういった一意でないname属性の自動入力に利用できます。

3.サイト構造で記憶する

先に書きましたが「このページ」の「このフォームの値」は「これ」という指定。
つまり「example.com」の「お問い合わせページの3つ目のフォーム」は「氏名」。
といった記憶方式。

name属性、label共に一致しないものに対する最終手段でしょう。
ただし一度そのフォームを自分で入力する必要があります。

注意点と終わり

以上の3つの方法を使えばあらゆるフォームに対応した自動入力機能が作成できることでしょう。
ただし自動入力の難点として、
「clickやkeydownに関連したjsが動作しない」というものがあります。

入力直後に内容をバリデーションしているフォームです。
focusを設定することで実行されるものもありますが、
マウス操作時にjsで入力した内容が消える場合もあります。

故にフォームの自動入力は万能ではありません。

あと個人的には、設定はオプションではなくサイドパネルで行う方式が好み。
そちらは需要があれば書きます。
需要があれば。

最新ブログ一覧