BookLiveで今まで使ってきた金額を出すスクリプト書いた
いやー久しぶりにJavaScript書いたわー。
(function(d){var s=d.createElement("script");s.src="//dl.dropboxusercontent.com/u/414379/www/BookLivePaid/script.js";d.body.appendChild(s)})(document)
一時期Amazon.co.jpで使った額を調べるスクリプトが流行ったことがありましたが、アレのBookLive版だと思えば大体あってます。
使い方
- 上のコードをコピーします。
- http://booklive.jp/my/top に移動してBookLiveにログインします。
- すでにログイン済みならトップページで実行しても問題ないはず。
- 開発者コンソール出す。
- 貼り付けてEnter。
- コンソールに結果が出力されます。
動作確認はIE11でしかしていません。
たぶん他でも動くと思いますが、Firefoxさん辺りは実行前に警告文出すかも。
IE/Firefox/Chromeのそれぞれ最新版で正常に動作することを確認しました。
ソース
実際に実行されるスクリプトの中身です。
呼び出すソースはDropboxにアップロードしたものですが、コードは同一です。
main(); function main() { var now = new Date(); var startYear = now.getFullYear(); var startMonth = now.getMonth() + 1; var paid = 0; var least = prompt("何年まで遡りますか?", startYear); if (!/^[0-9]{4}$/.test(least)) { console.warn("半角4文字の西暦で入力してください。"); return; } for (var y = startYear + 1; --y >= least; ) { for (var m = (y === startYear ? startMonth : 12) + 1; --m > 0; ) { paid += monthSum(y, m); console.info("ここまでの累計: " + paid + "円"); } } console.info("合計: " + paid + "円"); } function monthSum(year, month) { var sum = 0; console.info(year + "年" + month + "月のリクエスト中..."); var doc = request("/my/product?year=" + year + "&month=" + month); var nodes = doc.querySelectorAll('[id^="myproduct_display"]'); if (nodes.length !== 0) { sum = [].slice.call(nodes) .map(function(e){ return e.textContent.trim(); }) .filter(function(text){ return text.indexOf("円") === text.length - 1; }) .map(function(price){ return parseInt(price.split(",").join("")); }) .reduce(function(a, b){ return a + b; }); } console.info(sum + "円"); return sum; } function request(url) { var xhr = new XMLHttpRequest(); xhr.open("GET", url, false); xhr.send(null); var range = document.createRange(); return range.createContextualFragment(xhr.responseText); }
ちなみに
私の消費金額は2013年1月から7月12日現在で654,126円らしいです。
今更Brainf*ckインタプリタ
何番煎じだよって感じのネタ。
まぁ、JavaScriptの練習ですね。
https://dl.dropboxusercontent.com/u/414379/www/brainf_ck/brainf_ckInterpreter.html
素地自体はあっさり作れたんですが、細かいところをアレも気になるコレも気になるってな感じでちょこちょこ弄っていたら、なんだかんだで3日くらい開発にかかってしまいました。
デザインには全く気を払っていないのでCSSは未使用です。
ところでイベントリスナの登録用メソッドについては、エラーハンドリングとか全然してませんしIE8以下全滅ですけど、それなりに流用できるのではないかな?と思います。
こんなの↓
HTMLElement.prototype.addEvent = function(){ var args = Array.apply(null, arguments); switch (args.length) { case 1: addEventObj.call(this, args[0]); break; case 2: if (typeof args[0] === "string") { this.addEventListener(args[0], args[1].bind(this), false); } else { addEventArr.call(this, args[0], args[1]); } break; } function addEventObj(eventSet){ var DELIMITER = ","; var name = ""; var event = {}; var namesArray = []; for (name in eventSet) { event = eventSet[name]; if (name.indexOf(DELIMITER) !== -1) { namesArray = name.split(DELIMITER).map(function(e){ return e.trim() }); addEventArr.call(this, namesArray, event); } else { this.addEventListener(name, event.bind(this), false); } } } function addEventArr(eventNameList, event) { eventNameList.forEach(function(e){ this.addEventListener(e, event.bind(this), false); }, this); } };
※ここではインデント浅くするためにprototype
に直接生やしてますが、元コードではObject.defineProperty
使ってます。
これによって、例えば
var sample = document.getElementById("sample"); // 普通の単なるエイリアスっぽい書き方 sample.addEvent("click", function(){ alert("hello!"); }); // 一気に複数リスナ指定 sample.addEvent(["click", "focus"], function(){ alert("hello!"); }); // 一気に複数イベント指定 sample.addEvent({ "click": function(){ alert("hello!"); }, "focus": function(){ alert("yeah!"); } }); // もちっと複雑に sample.addEvent({ "click": function(){ alert("hello!"); }, "focus, blur": function(){ alert("yeah!"); } });
みたいなコードでイベントリスナの追加ができるようになります。
あれ、それjQueryでできるんじゃね?と思ったアナタはスルドイ!!
でも最後の複雑な複数イベント登録はプラグイン無しの素のjQueryではできないと思っているんですが、どうでしょうか。実はできるのかな…。うーん。
まぁjQueryを使わないところに価値があるということで。
この記事書き始めてから思ったけど、call
とかbind
とか使わなくても、先頭の方でvar _this = this;
とか書いておいてそれ参照すりゃ済む話ですね…。
IEスキーとして一言物申したい
Web開発に必携の「Google Chrome デベロッパーツール」の便利ワザ10個まとめ*二十歳街道まっしぐら
を読んで、
うん!WebkitのDevTools便利だよね!でもそれほとんどIE11のF12 開発者ツール(以下、開発者ツール)でもできるよ!!
って言いたかった。
わざわざ対抗する意味あるのかとかそういうのは置いといて。
元記事に倣って、順に書いていきたいと思います。
2.虫眼鏡で要素の選択
要素を選択中
要素サイズがリアルタイムで見られないのはちょい残念。
でも隣や上下の要素とのズレが見やすいのは評価してあげてもいいと思うんだ。
5.スマートフォンページの動作確認
これは簡単に使える。
ただし、モバイルのUAはデフォルトでWindows Phoneしかないので、その他を使いたい場合は適宜自分で追加する必要がある。
これが少し、いやかなり面倒。
カスタムUAは一度追加すれば記憶してくれるので、2度目以降は比較的楽に設定できる。
ちなみにiPadのUAは初めからある。
タッチイベントのエミュレーションは試してないから知らないけど、たぶんできないんじゃないかな…。
6.読み込まれている外部ファイルを一覧表示
これはできない。
文句なしにWebkit系のDevToolsが圧倒的に便利です。
一応ネットワークタブで監視をスタートしてF5すれば、読み込まれるファイルとその中身は確認できるけど、それは他でもできるし。
ただし、JSファイルに限れば一覧できる。
なぜかChakraエンジン内でのみ実行されるコードも列挙される
7.圧縮されたソースコードを整形
before
after
右上の{三}
みたいなところクリックすれば見やすくなる。
その右隣のabcって書かれたやつは、画面端でコードを折り返すかどうか。
見やすい方をお好みで。
8.JavaScriptをデバッグする
これは余裕でできます。
というかこんな基本的な機能もないやつが開発者向けのツール名乗っちゃいかんでしょ。
ブレークポイント打ったり、一時停止・再開、ステップイン、ステップオーバー、ステップアウトなど、当たり前のことは当たり前にできる。
ウォッチ式一覧と、コールスタック、ブレークポイント
コールスタックとブレークポイントはタブ切り替え方式で、選択した方がその下に表示される。
もちろん自分でウォッチ式を追加することもできる。
以上、まとめ
うーん、こうやって見ると開発者ツールって割と柔軟性がないな…。
まぁ俺はこっちのが慣れてるから好きだけどね!
あ、あと開発者ツールは完全日本語化されてるから機能の理解はしやすいと思う。
開発者ならある程度は英語読めるだろうから関係ないかもしんないけど。
エントリ執筆当初は文体の9割をパクって書いてたけど、流石にどうなの?と思ってかなり雑に書き直した。
小見出しが丸パクリなのはその名残。
DOM弄り
仕事中息抜きに書いてた。
文書の元々のソースコードと実際の表示が違うというのをやってみたかった。
ちなみに文書を読み込んだ時点で文書型は決まってしまうので、あとからDOCTYPE書き換えても意味ないです。
https://dl.dropboxusercontent.com/u/414379/www/DOMreplace/index.html
文字コードはUTF-8(BOMなし)で作ったけど、英数だけだとバイナリレベルで見たときにASCIIと変わらない。
そうなると、DOM操作で日本語を挿入したときにWebブラウザが盛大に文字化け*1するので、それを防ぐために無理やり日本語をすべり込ませてみた。
DOCTYPEやDocumentそのものを作り出すメソッドがdocument.implementation
にあるけど、まぁ普通にJavaScriptコードを書く分には一生お世話にならないメソッドたちでしょう。
JavaやPerlなどの高位なプログラムからXMLを出力するときに使う為にあるものかなと。
CSSは特に何か意識したわけでもなく、なんとなく書いた。
var pi = document.createProcessingInstruction('xml', 'version="1.0" encoding="UTF-8"'); document.appendChild(pi); //==> <?xml version="1.0" encoding="UTF-8"?>
ってやってるけど、XML宣言はPIではないので、これは実は間違い。
比較的新しいバージョンのMozilla系エンジンでは動くけど、その他では例外を吐く。
その為try-catch
で捕まえてエラーコードだけ出力するようにしておいてある。
XML宣言は、文字コードがUTF-8の場合は省略してもいいことになっており、それ故にXHTMLでValidだと思います。
それから、createElement
で要素生成してるけど、今回のケースではXHTMLで作っていることを明示的に示す必要があると思うので、本当ならcreateElementNS
を使うべきだと思った。
めんどくさいのでしてない。
また、極力Web標準仕様に則って書いているため、古いIE(IE7以前?)では
elem.setAttribute("class", "stretchable");
で処理がうまく通らないと思う。
理由は、古いIEではsetAttribute
メソッドが、プロパティへの代入のシンタックスシュガーであるため。
つまりelem.setAttribute("class", "stretchable")
はIE内部でelem.class = "stretchable"
として解釈されてしまっていた。というような記述をどこかで読んだ。
ちなみにsetAttribute
について、一部で第二引数にオブジェクトを入れてるコードを紹介しているサイトが散見されるけど、仕様上は第一引数も第二引数もプリミティブな文字列でないとダメだったはず。
どうしてもっていう場合は「古いIE向けのハックとして」程度に収めておくべきかと。
スーパーpre記法で書いたコード部分に行番号を出すようにした
こんなコードをフッタに入れた。
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script> <script> jQuery(function($){ $("pre.code").each(function(){ var df = document.createDocumentFragment(); var ol = $('<ol>').appendTo(df); $.each($(this).html().split("\n").filter(function(e, i, arr){ return i !== arr.length - 1; }), function(i){ $('<li>').html(this).appendTo(ol); }); $(this).empty().append(df); }); }); </script>
※jQueryで書いてるけど、ES5のメソッド使ってるので結局IE8以前では動きません。
今回はやっつけ実装なので、時間があったらまた見直してみる。
追記 (2014/01/18 13:55)
IE8以下でも動作するようにした。
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script> <script> jQuery(function($){ $("pre.code").each(function(){ var df = document.createDocumentFragment(); var ol = $('<ol>').appendTo(df); $.each($(this).html().split("\n").slice(0, -1), function(i){ $('<li>').html(this).appendTo(ol); }); $(this).empty().append(df); }); }); </script>
たぶん動作速度も上がったと思う。体感はできないけど。
どこが変わったかっつーとArray.prototype.filter
をやめてArray.prototype.slice
にしただけ。
要は配列の最後の要素が邪魔だっただけなので、無理にfilter使う必要が全くなかった。
追記 2020/07/02
純粋な JavaScript のみで再実装しました。jQueryからの脱却。
処理内容自体は同じです。
<script> document.addEventListener('DOMContentLoaded', () => { document.getElementById('main-inner').querySelectorAll('pre.code').forEach(el => { const ol = document.createElement('ol'); ol.append(...el.innerHTML.split('\n').slice(0, -1) .map(s => Object.assign(document.createElement('li'), { innerHTML: s }))); el.innerHTML = ''; el.append(ol); }); }); </script>