たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。
以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
どっちが正しいとかはどうでもいいがとかの増田エントリを見ていて、トラックバックとして書き込まれているレスをいちいちタブ開いて読むのが面倒だったので、ダブルクリックもしくは「show」ボタンのクリックでその場に読み込むようなスクリプトを探してみたんだけど、見付からなかったのでサクッと書いてみた。
Firefox + Greasemonkeyの組み合わせでしかテストしてないので、他の類似環境で動くかどうかは知りません。
さりげなく更新。一度展開した項目をもう一度展開しようとすると中身が消えてしまう問題を修正したり、外部サイトのトラックバックはインラインフレームで表示するようにしたり、項目の上でしばらく待つだけで項目を読み込むようにしたりしてみた。
もう一度検索し直してみたら似たスクリプトが既に存在していた……
更新。ボタンを押したりダブルクリックしたりした時に内容が消えてしまう問題を修正。
拡張機能勉強会の時に焚き付けられた、Text Shadowのコード(textshadow.js)を教材にして拡張機能開発のノウハウを解説していくシリーズ。
XPathをノードの検索に活用する方法を紹介したけど、肝心のXPathが書けなきゃ意味がないわけで。でもXPathって、ノードセットがどうとかノードテストがどうとか軸がどうとか修飾がどうとか、いざ勉強しようとしてもこれ専用の用語がやたらたくさん登場してきてものすごく萎える。CSSのセレクタの方が、機能は限られてるけどまだ分かりやすい。CSSのセレクタとXPath式の対応表があればいいのになあ、ということを、だいぶ前から僕は思ってた。
実は何年か前、哀さんのサイト(Black Box)でそういうコンテンツがあったんだけど、移転のゴタゴタか何かで消滅したままになってる。しかも、今「CSS XPath」みたいなキーワードでGoogleで検索してみて上位にくるエントリは、情報が不十分だったり間違いが含まれてたりする。
というわけで、CSS3セレクタ(このエントリを書いた時点ではワーキングドラフト)とXPath式の対応表で、詳細な物を作ってみた。
拡張機能勉強会の時に焚き付けられた、Text Shadowのコード(textshadow.js)を教材にして拡張機能開発のノウハウを解説していくシリーズ。
W3CのDOMでは、要素ノード(およびそのリスト)を得る方法として以下の方法がある。
getElementById(aName)
getElementsByTagName(aTagName)
childNodes
本当はネームスペースを指定して検索する物もあるんだけど、ここでは割愛。
これら以外に、W3C DOMではないがこういうのもある。
getElementsByClassName(aClassName)
getElementsByAttribute(aName, aValue)
ただ、探したい要素ノードの条件が複雑な時は、これらを使って取得したノードリストをループ回して条件判断しないといけないし、そもそもこれらでは要素ノード以外は取得できない。そこで最近のJS界隈でよく使われているのが、XPathだ。
XPathとは、/html/descendant::li[@class="navigation"]
という風な「式」でXMLノードを特定する技術だ。XPathの書き方を新たに憶える必要はあるが、これを使えば、複雑な条件に合致するノードのリストを一発で取得することができる。コードが簡潔になるのはいいことだし、FirefoxでもSafari 3でもOperaでも、普通にDOMとJavaScriptでごりごりやるのに比べて20倍以上高速に動作するという話もある。
XUL Tipsのページに書いてるけど、FirefoxではDOM3 XPathで提案されているXPath関係の機能が利用できる。詳しい解説はHawk's W3 Laboratoryの「DOMとXPathの連携」(サイトが消えてるので、インターネットアーカイブからどうぞ)を見て欲しい。リンク先では「Gecko用」と書かれてるけど、現在ではOperaとSafari 3でも利用できるようになっている。
「戻る」ボタンがどれだけ履歴を保持してるか一目でわかればどんなにいいかという話を見てサクッと実装してみた。
元記事では色とかアイコンの変化とかで視覚的に表す方法を提唱しているけれども、そこまでやる元気がなかったので、単に数字で「2」とか「4」とか表示するだけにしてます。
追記。専用ページ作った。
SOI A+zillaのアドオンコンテストの詳細ページ(英語)を見たら、伊藤穣一と村井純というビッグネームに挟まれて、よく分からん謎の人がいるんですけどどうしたらいいんですか。
……というわけでなぜかアドオンコンテストの審査員の一人になってしまいました。人生何があるかわかりません。ていうかよく考えたら自分自身がコンテストに出品したのって、参加者少数につきお寒い状況だったMozilla Party 4.0 XULコンテスト(結果)とmozilla.party.jp 5.0 XULコンテストくらいで、まともに批評の目に晒されたことがないくせに、いっちょ前に審査する側になるというのは、なんだか自分で映画作るわけじゃないのに批評はする映画評論家みたいかもしれない……。まー試験問題を作る側だから調理師免許を取ろうにも取れない服部先生みたいなとこまでいけばある意味かっこいいですけど。
ちなみに、当初は当サイトのプロフィールのページに誘導してもらうことを考えていたのですが、いきなり自己紹介漫画があるようなページに飛ばすなんてありえねーと言われてしまいましたので、適当にデッチ上げた経歴のページを代わりに置いてあります。で、タケイジュンって誰?(※title要素の内容がJun Takeiになってる)
んで、このプログラムの時間が3時間組まれてるんですが、応募者数が少ないと下手したら僕とこのお二方とで3時間トークショーをやる羽目になりかねません。皆さんどうか応募おながいします(自分で応募しやがれって? いやそう言われても審査員なんで……)。
拡張機能勉強会の時に焚き付けられた、Text Shadowのコード(textshadow.js)を教材にして拡張機能開発のノウハウを解説していくシリーズ。
Firefoxの拡張機能で、DOM要素ノードを動的に生成したり、編集したり、そうして生成したノードを後でまた収集したり、といった操作を行うような物を作る時は、必然的に、ソースの中に要素名や属性名が登場してくる。
var newNode = document.createElement('box');
newNode.setAttribute('class', 'my-custom-box');
parentBox.appendChild(newNode);
var nodes = document.evaluate('/descendant::*[@class="my-custom-box"]',
document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0, maxi = nodes.snapshotLength; i < maxi; i++)
{
this.processBox(nodes.snapshotItem(i));
}
こういう操作が一カ所だけにしか登場しないんなら別にいいけど、複数箇所で、似たような操作が何度もある場合は、要素名であるとか属性値・属性名であるとかノード検索の条件であるとかを、コードの冒頭で定数(定数プロパティ)として定義しておくことをお薦めしたい。
var myService = {
CUSTOM_BOX_NODE_NAME : 'box',
CUSTOM_BOX_CLASS_NAME : 'my-custom-box',
CUSTOM_BOX_EXPRESSION : '/descendant::*[@class="my-custom-box"]',
(略)
すると、さっきのような箇所はこうなる。
var newNode = document.createElement(this.CUSTOM_BOX_NODE_NAME);
newNode.setAttribute('class', this.CUSTOM_BOX_CLASS_NAME);
parentBox.appendChild(newNode);
var nodes = document.evaluate(this.CUSTOM_BOX_EXPRESSION, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0, maxi = nodes.snapshotLength; i < maxi; i++)
{
this.processBox(nodes.snapshotItem(i));
}
textshadow.jsの冒頭箇所を見てみると、動的に生成するIDのプレフィクスとか、途中で生成する要素のクラス名であるとか、XPath式の中に埋め込む検索条件だとかを、片っ端から定数としてまとめて定義していることが分かるはずだ。
こうしておくと、いざクラス名が他の拡張機能とかぶっていたと判明した時なんかでも、ソースの頭の方をちょこっと書き換えるだけで済む。class属性の値として文字列リテラルが書かれている箇所を片っ端から探すようなことはしなくていい。
え? 一括置換を使えばすぐだろうって? まあ、確かにたいていの場合はそうなんだけど、でもそれじゃ解決できない時もある。
Firefox 3でセキュアじゃない拡張機能はまるっきり使えなくなってしまうということで、須藤さんにお願いしてCOZMIXNGのスペース上にファイル群を移動させてもらった。配布ページからのリンクは変化がないように見えるけど、実際に辿るとリダイレクトでCOZMIXNGのファイルに飛ばすようになってる。あと、現在上がってる拡張機能については全部updateURLを書き換えた。
のりさんのところで報じられている、Firefox 3の仕様変更について、チェックインされたパッチを詳しく調べてみた。
今後拡張機能の自動更新では、以下の2つの段階でセキュアかどうかのチェックが入るようだ。
この二つの条件が満たされてやっと、アドオンの自動更新が行われるという仕組みになっている。
よって、アドオン作者が取れる選択肢は以下の4つになる。
やる方として一番楽なのは1と4なんだけど、1には重大な問題がある。
というわけでもうちょっと素早く対応できる路線として2を検討してみようと思ったんだけど、仮にどうにかしてSSL証明書を手に入れたとしても、そもそもさくらのレンタルサーバじゃビジネス用プラン以外ではSSLは使えないんだってさ……
3はやりかた自体が分からない。XMLに署名するとかハッシュ値得るとか、僕の頭ではちんぷんかんぷんです。
ということでいずれにしても今の野良アドオン天国はオシマイだと言えよう。
前にも書いた気がするけど、ISBNコードが13桁になって前のやつが使えなくなったので、13桁ISBNコードを10桁ISBNコードに変換するコードを入れて書き直してみた(Amazonの個別商品ページのURIは13桁ISBNではなく10桁ISBNベースなのです)。
var title = prompt('タイトルを入力') || '';
var isbn = prompt('ISBNコードを入力') || '';
isbn = isbn.replace(/^(urn:isbn:|isbn)/i, '');
if (!isbn) return;
var urn = 'urn:isbn:'+isbn;
var urn_part = urn.match(/^urn:isbn:(\d{3}-)?(\d-?\d+-?\d+-?[x\d])$/i);
var numRaw = urn_part[2];
var num = numRaw.replace(/-/g, '');
/*
13桁ISBNのチェックディジットは10桁ISBNのチェックディジットと異なるので、
10桁ISBN基準で再計算する。
*/
var num10 = num;
if (urn_part[2]) {
var sum = (parseInt(num.charAt(0)) * 10) +
(parseInt(num.charAt(1)) * 9) +
(parseInt(num.charAt(2)) * 8) +
(parseInt(num.charAt(3)) * 7) +
(parseInt(num.charAt(4)) * 6) +
(parseInt(num.charAt(5)) * 5) +
(parseInt(num.charAt(6)) * 4) +
(parseInt(num.charAt(7)) * 3) +
(parseInt(num.charAt(8)) * 2);
var digit = (sum % 11);
if (digit) {
digit = 11 - digit;
if (digit == 10)
digit = 'X';
}
num10 = num.replace(/.$/, digit);
}
_setClipBoard(
'[<img src="http://images.amazon.com/images/P/'+num10+'.01._AA110_FMjpg_SCTZZZZZZZ_V66486851_.jpg" alt="" />'+title+']('+urn+')'+
'([Amazon.co.jp](http://www.amazon.co.jp/exec/obidos/ASIN/'+
num10+
'/outsiderrefle-22/ref=nosim))'
);
昨日から今日にかけてモリモリと書評を書いてたのはこれが原因。
おこづかいかせげるといいなあ!
ちなみにこのスクリプトでは基本のリンク先を urn:isbn:ISBNコード というURN形式のリンクにしてありますが、Firefoxでこれを読み込むにはURN Supportなどを使う必要があります。w3mの場合は近藤氏によるリダイレクタを使うといいでしょう。IEとOperaはシラネ。
拡張機能勉強会の時に焚き付けられた、Text Shadowのコード(textshadow.js)を教材にして拡張機能開発のノウハウを解説していくシリーズ。
JavaScriptでは、普通に宣言した変数や関数はグローバルな物になる。
var name = 'hoge';
function getItem(aKey) {
return array[aKey];
}
だから、Firefoxで最初から定義されてるグローバル変数や関数と同じ名前の変数や関数を定義してしまうと、エラーが起こるし、最悪の場合はFirefoxが動かなくなってしまう。
// ステータスバーだけ表示した
// 新規ウィンドウを開く関数「loadURI」を定義。
function loadURI(aURI) {
window.open(aURI, 'mytarget', 'status');
}
// でも、これをやってしまうと、事あるごとに
// 新しいウィンドウが開かれるようになってしまう。
// なぜなら、Firefox内で既に「loadURI」という関数が
// 「ページを現在のタブで読み込む関数」として
// 定義されているから。
// 「ブラウザの一覧」のページを新しいウィンドウで開いて、
// そのウィンドウをgBrowserという変数に格納する。
gBrowser = window.open('http://piro.sakura.ne.jp/browsers-list.html');
// でも、これをやってしまうと、Firefoxがまともに
// 動かなくなる。なぜなら、Firefoxのブラウズ領域の
// 要素ノードへの参照としてgBrowserが定義されているから。
これを防ぐ手っ取り早い方法としてお勧めしたいのが、自分の拡張機能で使う変数や関数を、「自分の拡張機能専用のサービスオブジェクト」のプロパティやメソッドとして保持するようにするというやり方だ。