化石を発見
どことは言わないが,とある有名企業で残骸を発見した.
ご丁寧に「Internet Explorerでしか開けません」と書いてある.
MacやLinuxでは見られないというのはなんとも悲しい.
中身を見たらVBScriptで書いてあるではないか!
残念,2年前(2017/07)にInternet Explorer 11からデフォで外されると発表されたので,もはやIEですらエミュレーションモードでしか開けないページとなっているのである.
良いサービスではあるので,なんとか自分用に使えるようにしてみた.
利用規約に引っかかるとは思いませんが,なにかあると嫌なので実際にどのWebサイトかへの言及は避けます.
HTML5/JavaScriptで書き直す
といってもサーバに手を加えることはできない.
ローカルでhtml/jsのそれぞれを用意して,GETしてきてはbodyだけをすげかえて描画する,ということをしてなんとか表示できるようにした.
(準備)CORSをすり抜ける
ローカルにあるhtmlファイルのoriginはnullなので,XMLHttpRequestのような関数で該当のWebページを取ってこようとするとCORSに引っかかる.
/path/to/chrome --disable-web-security --user-data-dir
のように,2つのオプションをつけてChromeを起動すれば,CORSを無効にすることができる.
JavaScriptでフェッチして描画
該当のWebページは以下のような構成になっている.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=x-sjis" />
<script language="vbscript">
Sub hoge
location.href = "fuga.html"
</script>
</head>
<body>
<button onclick="Call hoge">
</body>
</html>
ボタンアクションなどに合わせてVBScriptでページの遷移をしているから,IE以外では使えないということらしい.
最近は減ったはずだが,Shift_JIS(x-sjis)を使っているのでこの際UTF-8になおしてやろう.
文字エンコーディングを変更するためには,一度Blobで取得して,それをテキストとして解釈すればよい.
あとはDOMにパースして必要な部分を描画する.
こっちで用意したhtml/jsから読み込むにはこんな感じのコードを用意する.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
window.onload = () => {
getBlob("piyo.html").then(
(blob) => translateFrom(blob, "x-sjis").then(
(doc) => displayBody(doc)
)
)
}
var getBlob = (url) => {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.onload = () => {
resolve(xhr.response);
}
xhr.responseType = "blob";
xhr.open("GET", url);
xhr.send();
});
}
var translateFrom = (blob, encoding) => {
return new Promise((resolve, reject) => {
var rdr = new FileReader();
rdr.onload = (event) => {
// text/html -> DOM
var psr = new DOMParser();
var doc = psr.parseFromString(event.target.result, "text/html")
resolve(doc);
}
// x-sjis(encoding) -> utf-8
rdr.readAsText(blob, encoding);
});
}
var displayBody = (doc) => {
// deeply copy the body
var body = document.importNode(doc.body, true);
// replace original body with fetched one
var html = document.body.parentNode;
html.removeChild(document.body);
html.appendChild(body);
}
</script>
</head>
<body>
<p>loading...</p>
</body>
</html>
ひとまずこれで,body以下を取り込むことができる.
ボタンの中身を入れ替える
ボタンはいまだにCall hoge
になっていて,これはVBScriptを呼び出している.
そこでこのボタンを見つけて,onclick時のイベントを書き換えてあげよう.
下は変更する部分のみを記述する.
window.onload = () => {
getBlob("piyo.html").then(
(blob) => translateFrom(blob, "x-sjis").then(
(doc) => useJSFunction(doc).then(
(doc) => displayBody(doc)
)
)
)
}
var useJSFunction = (doc) => {
var buttons = doc.getElementsByTagName("button");
for (var i = 0; i < buttons.length; i++) {
var b = buttons[i];
var oldFunc = b.getAttribute("onclick");
var newFunc = oldFunc.replace("Call ", "javascript: ");
b.setAttribute("onclick", newFunc);
}
}
var hoge = () => {
getBlob("fuga.html").then(
(blob) => translateFrom(blob, "x-sjis").then(
(doc) => displayBody(doc)
)
)
}
ほとんどのブラウザで,onclickなどの処理はJavaScriptで解釈されるのがデフォルトのはずだが,一応JavaScriptのコードですよーということを明記しておく.
実際にボタンが押されるとJavaScriptのhoge関数が呼ばれて,fuga.htmlのbodyを表示するようになる.
もちろんfuga.htmlでVBScriptが使われていて変更する必要があるなら,変更した上でbodyに描画する.
取ってきたhtmlのタグに含まれていないデザインは吹き飛ぶので,適宜<head>
内にcssへの参照を入れておいたり,styleをJavaScriptからいじるなどしても良い.
formタグへの対応
上の例ではボタンクリック時のページ遷移を,フェッチしてbodyに描画するというものに置き換えていた.
これは,あくまで自分のローカル内に用意したhtmlファイルから外に出ないためだ.
なので<a>
タグなども同様に,hrefをjavascript: void(0)
などにしてリンクを無効にして,onclickで対象のページを取ってくる作業が必要だ.
しかし<form>
タグなどでactionへの送信後にページにジャンプするものは,これでは対処できない.
タグの仕様で,ジャンプすることが原則になっているためだ.
ならば,<form>
でやっていることをJavaScriptから実行してしまえばいい.
var submitForm = (url, data) => {
// data: e.g. [hoge: "hogehoge", fuga: "fugafuga"]
var urlEncodedDataPairs = [];
for(var name in data) {
urlEncodedDataPairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name]));
}
var urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+');
var xhr = new XMLHttpRequest();
xhr.onload = (event) => {
alert("done");
}
xhr.open("POST", url);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(urlEncodedData);
}
まとめ
おわかりいただけたとおり,エラーハンドリングはほとんどしていません.
Promiseでreject使ってるくせに何やってんだよ!
というお叱りもいただくかもしれません.
また私がJavaScriptの初心者なので,変な書き方やブラウザ互換性のないコードになっているかもしれません.
そのあたりのブラッシュアップのためにも,コメントはどんどん待っております.