Home > Latest topics

Latest topics 近況報告

たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。

萌えるふぉくす子さんだば子本制作プロジェクトの動向はもえじら組ブログで。

宣伝1。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能! シス管系女子って何!? - 「シス管系女子」特設サイト

宣伝2。Firefox Hacks Rebooted発売中。本書の1/3を使って、再起動不要なアドオンの作り方のテクニックや非同期処理の効率のいい書き方などを解説しています。既刊のFirefox 3 Hacks拡張機能開発チュートリアルと併せてどうぞ。

Firefox Hacks Rebooted ―Mozillaテクノロジ徹底活用テクニック
浅井 智也 池田 譲治 小山田 昌史 五味渕 大賀 下田 洋志 寺田 真 松澤 太郎
オライリージャパン

Page 1/239: 1 2 3 4 5 6 7 8 9 »

絵文字✨とTwitter Bot🤖と私👤とEmoji Editor📝 - Dec 15, 2016

このエントリは絵文字Advent Calendar 2016とのクロスポストです。(→Qiitaの方の投稿

この記事では、自分が絵文字込みのテキストを楽に編集するために作ったEmoji Editorという簡単なツールを紹介します。

PCでパレットから絵文字を入力したいんです……😭

唐突ですが皆さん、どうやって絵文字を入力されてますか?

Android版のGoogle日本語のように絵文字のパレットが付いていたり、macOSの日本語入力のように標準辞書に入っていて普通に「すし」と入れて変換すれば「🍣」になったりする環境もあるようなのですが、自分が主に使っているWindows 7+ATOK2016の環境とUbuntu 16.04LTS+ATOK X3の環境では良い方法がなさげです。自分は絵文字はパレットから選択したい派、というか顔文字に対応する読みをいちいち覚えてられない派なので、やるなら一覧の中からぽちぽちクリックして選びたいです。しかしATOKに付属の文字パレットというユーティリティの分類には「顔」みたいなグループ分けが無いため、Unicode絵文字を使おうと思うとUnicodeの表のあっちこっちを行き来しながら探さないといけません。(最新のATOK2017ではこの辺どうなんでしょう?)

また、これはカラー絵文字のフォントが無いという古い環境だからのようですが、文字パレット上だけでなくテキストエディタ上でも絵文字は白黒表示です。自分が絵文字を使いたいのは主にTwitterでの投稿なので、見るならTwitter上でどう見えるかが分からないと安心して使えません。

元々絵文字を使う習慣が無かった自分が絵文字に触れる機会が増えたのは、「シス管系女子」の広報用Twitterアカウント(みんとちゃんbot)がきっかけです。いつもの自分のノリでやると堅すぎると思ったので、みんとちゃんbotの発言についてはあえて絵文字を入れて柔らかい印象を持ってもらえるようにしたい、という下心ドリブンです。

当初はAndroidのGoogle日本語入力から絵文字を入れていましたが、運用のためのbotスクリプトを作成して、発言データにするためのテキストを大量に用意する段階になってPC上で作業に入ろうとしたときに、前述のような状況に気が付きました。

そこでとりあえずTwitter絵文字が使えるパレットを探してみた所、テスト用にちょっと投稿するだけならTwitterの絵文字をデスクトップPCから使おう! Ver2というサービスで絵文字の入力自体はできる事が分かりました。が、このページは既に作成済みのデータの編集には使えません。やはりここは、Twitter絵文字を含んだプレーンテキストをWYSIWYGで編集できるツールが欲しくなるところです。

探し方が悪かったのかもしれませんが、自分はその時「まさにこれだ!」と思える物を見つけられなかったため、無いなら作るか……という事で作りました。その名もEmoji Editor(名前が安直すぎる)。HTMLファイル1つだけで完結する、フレームワークも何も使ってないSPAとも呼べないような代物です。 (Emoji Editorの画面)

このエントリの公開を機に、GitHubにリポジトリを作りましたので、forkしたりプルリクしたりして頂ければ幸いです。

続きを表示する ...

system-admin-girl.comのこと - Dec 04, 2015

シス管系女子の特設サイトができました、というか例によって自分で作りました。 3日ほど夜なべして。

どうしてこうなった

電子書籍はいわゆる印税契約だけど紙の方は原稿料買い切り(書籍じゃなくムックだから)なので、プロモーションに工数かけてもあまり得にならないんですよね。なのに何故やったのかというと……要するに、欲しかったんですよ!!! 僕が!!!!!

いやね、連載5年目に入ろうとしてるのにWeb上では相変わらず知名度が低くて、知ってる人は知ってる的な立ち位置がいいかげん辛くなってきたというか、この間なんて「たまたま日経Linuxを見たらこんなの(#!シス管系女子Season3 Petitまとめ読み)あったんだけど、これってもしかしてシェルスクリプトマガジンのシェル女子の便乗企画……?」みたいに思われてしまった、というのは被害妄想もいいとこなんですが、「それもこれもみんな、ここ見れば大体分かるっていう位置付けの公式サイトが無いせいなんや!」と大人げなく嫉妬に狂いまして、手元にあった素材と原稿データをイラレの上で切り貼りしていわゆる1枚ペラのページのこんな妄想画像 を作って「こういうのがほしいんだよこういうのがああああああ!! 日経Linuxのサイトの中に特設ページ作ってもらえませんかね!?」と日経BPサイドに提案してみたものの、会社の方針とかであんまり他のページと違う物は載せられないのでPDF置いとくだけならまぁなんとか……と言われてしまって「そういうことじゃないんだよおおおおお!!!」と血の涙流しながらHTMLとCSSをゴリゴリ書いてさくらのレンタルサーバの一番安いプラン借りてお名前.comでドメイン取って(独自ドメイン取るのこれが初めてですよ! なんと!)突貫工事で作った、というのが真相ですハイ。 説明文が「Piro氏」とか微妙に客観なのは、元が日経BPへの提案用だったからで。

3日でできたのは十数年越しのイメトレのおかげや……

思い返せばかれこれ14~5年は前ですかね? CSSコミューンで偉そうなこと言ってて「Web業界に進みたいな」とか一瞬思ってたあの頃。 CSS2の仕様通りに書いた物をInternet Explorerが微妙にまともにレンダリングしてくれなくて、それでもNetscape Communicator 4での悲惨な対応具合に比べればまだマシというネスケ派の自分にとっては「ギギギ……!」と歯ぎしりせずにはおれない状況で、NC4でもIEでもきちんと表示できてW3C的にも(というかAnother HTML-lint的に?)Validで且つそこそこ凝った見た目を実現して「W3Cの理想は非現実的な絵空事なんかとちゃうんやで!!!」と世界の片隅でアピールしたい!という思いからこんなスタイルシートあんなスタイルシートそんなスタイルシートといったいろんな実験作を書いて粋がってた日々。 当時最もCSS2の実装が進んでたGeckoエンジンでさえできることは全然限られていて、「あぁ……この仕様にある:nth-child(2n-1)ってのが使えれば装飾の左右振り分けも簡単なのに……!」と思いながらclass="even"とかclass="odd"とか書いて騙し騙しやってましたとも。 ドロップシャドウひとつ作るのにも画像を作ってスライスして……よくあんなめんどくさいことやってたもんだ。 しかも人力で。 (素人でお金も無いのでDream WeaverだのFireworksだのは手が出なかった)

素人の僕でこんなんだった訳だけど、当時から業務として手がけておられた方々は僕なんかよりはるかに切実な思いでこういう事と向き合っていたのであろう。 CSS昔話 Advent Calendar 2015 - Adventarにはそういう時期の苦労話がたくさん集まってきそうな気配を感じている。

それが、今じゃどうですか。 文字の影text-shadowボックスの影box-shadow角丸border-radiusも背景色の半透明もグラデーションも奇数番目と偶数番目での振り分け:nth-child(2n-1)も、テキストでちょちょいっと書けば即反映ですよ。 当時は想像もしてなかった、CSSメディアクエリーなんて物もできてるし。 あの頃「こういう風に作れればいいのになあああ!!!」とイメージトレーニングしていた理想のCSS世界がまさに目の前にあるという感慨深さよ。 document.querySelectorAll()で要素をガッと集めてきて制御したり、今画面内にある画像をdocument.elementFromPoint()でダイレクトに取得して位置合わせしたり、Firefoxのアドオン開発でも苦労してた部分があっさりクロスブラウザで動いてくれちゃってて。 FirefoxとChromeのWindows版とAndroid版でだけ検証してリリースしちゃいましたが、後でIE11で見たら全く支障なく完璧に表示されてたし。 あまりのあっけなさに目がテンになり、その後感涙でむせび泣きかねない勢いでした。

SNSでシェアしやすく

……とまあ、昔取った杵柄で一枚ペラ&試し読み簡易マンガビューワーを作るところまではよかったんですが、宣伝のためのサイトなのにSNS連携のシェア用ボタンを入れてなかったり、FacebookやTwitterでシェアされたときにいい感じに画像を出す工夫をしてなかったり、「それやらないの今時あり得ないでしょ……」な手落ちだらけで、「エッなにそれいつの間にそんな事になってたの」と完全に浦島太郎でした。 かろうじてGoogleアナリティクスは存在を知っていたので、それだけは入れてましたが。

皆さんの助けが無ければ、作ったはいいものの結局やっぱり誰にも見られない廃墟サイト化一直線……という末路を辿っていたところでした。 大変お世話になりました。

良い物作ってるつもりでもプロモーションできてなきゃ存在しないのと同じ

思い出話8割に実用情報2割くらいでこんなエントリを書き記して何やってんのって自分でも思いますが、今僕が主たる仕事の場にしてるフリーソフトウェアの世界でも、プロモーションはやっぱ大事だなって思うんですよね。 先行実装があってそれなりに頑張って丁寧に作ってたのに、その存在を知らなかった人が後から作った荒い出来の物が「これ新しい!!! こんなの欲しかった!!!!」って人気をかっさらってって、先達の頑張りが全く誰からも評価されないまま消えていってしまう……俺達は、あと何回そんな悲劇を目にすればいい? 俺はあと何回、顧みられることの無い先駆者を目にすればいいんだ?

というわけで、今後仕事絡みで何か作って公開する時にまた参照したいので自分用のメモとして今回参照した情報をまとめたというのがこのエントリの趣旨なのでした。

まぁ、このsystem-admin-girl.comが実際どれだけ成果が出るかというのは分からない、ともすれば結局やっぱり廃墟になっちゃったねというオチもあり得そうではありますが、「だからこういう風にして欲しかったんだよぉぉおおおお!!」と地団駄踏んで不満溜め込んでるよりは、「思ってたやりたかったとおりの事やったけど駄目でしたわハハハ……」となる方がまだ精神衛生上良さそうなので、これで安心して眠れます。 おやすみなさい。

ページ内の見出し一覧をMarkdownのリスト形式で出力するbookmarklet - Jul 05, 2012

前に似たような事をやった気がするけど。

javascript:

var tab  = '   ',
    min = prompt('Input minimum level of the headings (default=1)');

function tabs(n) {
  var ret = [];
  for (var i = 0; i < n; i++) ret.push(tab);
  return ret.join('');
};

function collectHeadings(minLevel) {
  var rawHeadings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
  var headings = [];
  var heading, node;
  for (var i = 0, maxi = rawHeadings.length; i < maxi; i++)
  {
    node = rawHeadings[i];
    heading = {
      node: node,
      id: node.id,
      label: node.textContent,
      level: parseInt(node.localName.charAt(1))
    };
    if (heading.level >= min)
      headings.push(heading);
  }
  return headings;
}

function generateList(headings) {
  var list = [],
      h,
      id,
      item,
      nest = 0;
  for (var i = 0; i < headings.length; i++)
  {
    h = headings[i];
    id = h.id || h.node.parentNode.id || h.node.parentNode.parentNode.id;
    item = (id) ? '['+h.label+'](#'+id+')' : h.label ;
    if (i > 0) {
      if (h.level > headings[i-1].level) {
        nest += 1;
      } else if (h.level < headings[i-1].level) {
        nest -= 1;
      }
    }
    if (nest == 0) {
      list.push(' * '+item+'\n');
    } else {
      list.push(tabs(nest)+'* ' + item + '\n');
    }
  }
  return list.join('');
}

var headings = collectHeadings(Math.max(1, min));
var list = generateList(headings);
if (list) window.open('data:text/plain,'+encodeURIComponent(list));

見出しレベルの関係がちゃんとしてないとうまく動かない。あとsection/headingのネストには対応してない。

JSDeferred - Why this code doesn't work? - Jun 12, 2012

I got a mail.

I've started to use jsdeferred 2 days ago and I'm really really happy with it because I consider it's really easy to use, light and it looks very powerfull. Anyway, I have one little doubt I hope you can help me about.

Here's the thing, I would like to deferredize some functions to use in some chains, but I haven't figured out what's the best way to get it, I put you a little example

If I try something basic like this:

function my_deferred(data) {
var deferred = new Deferred();
deferred.call(data);
return deferred;
}

function main() {
Deferred.define();

my_deferred("foo").
  next(function(data) {
    console.log(data);
  });
}

The chain is not executed (I don't know why). But if I change to something like this, using setTimeout, it works:

function my_deferred(data) {
var deferred = new Deferred();
setTimeout(function() {
  deferred.call(data);
},1);
return deferred;
}

function main() {
Deferred.define();

my_deferred("foo").
  next(function(data) {
    console.log(data);
  });
}

The question is, wouldn't it be possible to get the right behaviour of the chain without using setTimeout? I would like to deferredize some functions without the penalty of using setTimeout.

You should use Deferred.next() ( it is available as a global function next() if you use Deferred.define() ) instead of setTimeout(), like:

function  my_deferred(data) {
  var deferred = new Deferred();
  Deferred.next(function() {
    deferred.call(data);
  });
  return deferred;
}

Deferred.next() works just like setTimeout(), but in most cases it works faster than setTimeout().

deferred.call() just calls the next job which is registered as a callback function given to its .next() method. So, you have to call deferred.call() after you register the next job.

However, In your case, any "next job" has not been registered yet when you call deferred.call(). As the result, the "next job" registered after deferred.call() was called won't be called by anyone.

function my_deferred(data) {
  // (3) Now, we are in this function.
  var deferred=new Deferred();
  deferred.call(data); // (4) deferred.call() is called, then
                       //     the next job ( registered via
                       //     deferred.next() ) is also called.
                       //     However, it has not been registered yet.
                       //     As the result, nothing happens.
  return deferred; // (5) We return the deferred object and
                   //     exit from this function.
}

function main() {
  // (1) Starting position of this event loop.
  Deferred.define();

  // (2) The function is called.
  my_deferred("foo").
    next(function(data) {
      // We never come here!!
      console.log(data);
    }); // (6) You register the next job to the returned deferred
        //     object, via its next() method. However, because
        //     deferred.call() was already called, the job will
        //     never be called by anyone.
  // (7) End of this event loop.
}

Instead,

function my_deferred(data) {
  // (3) Now, we are in this function.
  var deferred=new Deferred();
  Deferred.next() {
    // (8) Now, the next event loop is started.
    deferred.call(data); // (9) deferred.call() is called, then
                         //     the registered next job is also called.
  }); // (4) We just reserve the task for the next event loop.
  return deferred; // (5) We return the deferred object and
                   //     exit from this function.
}

function main() {
  // (1) Starting position of this event loop.
  Deferred.define();

  // (2) The function is called.
  my_deferred("foo").
    next(function(data) {
      // (10) We are here!
      console.log(data);
    }); // (6) You register the next job to the returned object.
  // (7) End of this event loop.
}

As above, you must register the next job to the deferred object before its call() is called.


ちょよんごさんによると、このメールの送り主の人(ここでは省いたけど、WebGL用のスクリプトを書いてるそうです)は、JSDeferredを使ってるとおぼしき開発者に手当たり次第質問を投げてるらしい。そんなこととはつゆ知らず「僕作者じゃないんだけどなあ」と呑気にちょよんごさんに転送してしまって、余計なストレスをかけてしまったようなので罪滅ぼしと思って真面目に返信してみた。伝わってるかどうかは分かんないけど。

これはJSDeferredの結構典型的なハマリ所だと思う。XMLHttpRequestとかNode.jsの非同期なメソッドみたいに、コールバック関数が必ず次以降のイベントループで呼ばれる物に対してであれば、このメールの送り主の人が書いてるような

var Deferred = require('jsdeferred').Deferred;
var fs = require('fs');

function statDeferred(filePath) {
  var deferred = new Deferred();
  fs.stat(filePath, function(error, stats) {
    if (error)
      deferred.fail(error);
    else
      deferred.call(stats);
  });
  return deferred;
}

statDeferred('/tmp/foobar')
  .next(function(stats) {
    if (stats.isDirectory()) {
      ...
    }
  });

こういう流れの書き方で何も問題ない。

問題は、やらせたい処理が同期的であった場合で、

function statDeferred(filePath) {
  var deferred = new Deferred();
  try {
    var stats = fs.statSync(filePath);
    deferred.call(stats);
  } catch(error) {
    deferred.fail(error);
  }
  return deferred;
}

これでは動かないのですよね。 何故かというと、 deferred.call() は「その deferrednext() に渡された関数、という形で あらかじめ 登録されていた『次のジョブ』を実行する」物だから。 この例だと statDeferred()deferredreturn する前に deferred.call() を呼んでしまっているから、その後で次のジョブを登録しても、登録した「次のジョブ」を呼ぶ人が誰もいないわけです。

function statDeferred(filePath) {
  // (2) 関数の中に入った。
  var deferred = new Deferred();
  try {
    var stats = fs.statSync(filePath); // (3) 処理を実行した。
    deferred.call(stats); // (4) 登録済みの「次のジョブ」を実行しよう……
                          //     とするんだけど、まだ何も登録されてないので、
                          //     当然何も起こらない。
  } catch(error) {
    deferred.fail(error);
  }
  return deferred; // (5) 関数を抜けた。
}

// (1) 今のイベントループでのスタート地点。
statDeferred('/tmp/foobar')
  .next(function(stats) {
    // 「次のジョブ」の登録後に deferred.call() が呼ばれないので、ここには到達しない。
    if (stats.isDirectory()) {
      ...
    }
  }); // (6) 戻り値の next() を呼んで、「次のジョブ」を登録した(今更)。
// (7) 今のイベントループの終わり。

だから、 setTimeout() なり Deferred.next() なりを使って、 deferred.call() を呼ぶ処理を「次のジョブを登録する処理」よりも後(=次のイベントループ)に実行する必要がある。そうすれば、

function statDeferred(filePath) {
  // (2) 関数の中に入った。
  var deferred = new Deferred();
  Deferred.next(function() {
    // (7) 次のイベントループで、予約されたこの処理が始まる。
    try {
      var stats = fs.statSync(filePath);
      deferred.call(stats); // (8) 登録済みの「次のジョブ」を連鎖的に呼ぶ。
    } catch(error) {
      deferred.fail(error);
    }
  }); // (3) 次のイベントループで実行するように予約。
  return deferred; // (4) 関数を抜けた。
}

// (1) 今のイベントループでのスタート地点。
statDeferred('/tmp/foobar')
  .next(function(stats) {
    // (9) 「次のジョブ」として、この処理が始まる。
    if (stats.isDirectory()) {
      ...
    }
  }); // (5) 戻り値の next() を呼んで、次のジョブを登録した。
// (6) 今のイベントループの終わり。

……という順番で処理が進むから、期待通りに動くようになる。

どの処理が一体何をしているのか、どの関数が何を返しているのか、自分が呼んでいるメソッドは誰のメソッドなのか、といった事をちゃんと理解しておくと、この話がすっと頭に入ってくると思うんだけど、ただの構文として覚えてしまっていると、メールの送り主の人みたいに「何で動かないの……」って詰まってしまうんだと思う。

という風に偉そうな事を言ってるけど、僕自身も最初は多分ただの構文として覚えてた方で、ただ、「同期処理の時は setTimeout() なり Deferred.next() なりを使って deferred.call() を呼ぶ」という所までを「構文」として暗記していたから、結果的にはちゃんと動いてくれてたという状態だったんだと思う。その後若手IT勉強会の中でコードリーディングをやってだんだん仕組みが分かってきて、「ああなるほど、こういうことだったんだ」と理解できるようになった。

Firefox Hacks Rebootedでもいっぱい書いたけど、JSDeferredの本質は、「あらゆる処理について、その次にやらせたい仕事を next() のコールバック関数という形で後から登録できるようにする」ものだ、と僕は認識してる。「後から登録する」という都合上、この性質は非同期処理(関数を抜けた時点でまだ処理が始まっていないという種類の処理)と非常に相性がいい。けれども、非同期処理じゃないと使えないわけではない。ただ、「後から登録する」というのは、普通に順番通りに進む同期的な処理の中では行えないイレギュラーな事だから、 setTimeout()Deferred.next() を使わざるを得なくて、それで初見の人に分かりにくくなってしまう。そこがもどかしい所だ。

FirefoxのmozRequestAnimationFrame()の仕様が変わってた - Dec 02, 2011

2011年11月30日付けのNightly 11.0a1でツリー型タブが動かないっていう報告を受けたので調べてみたら、なんかJavaScriptベースでアニメーション効果を実装する時に使えるFirefox 4から(だったっけ?)の新しい機能に基づいたアニメーション管理のための仕組みが期待した通りに動かなくなってて、あれこれ試してるうちにどうもmozRequestAnimationFrame()の使い方のうちDOMイベントベースでやる方のが動かなくなっててコールバック関数を使う方法でならうごくっぽいという事が分かったので、ツリー型タブ0.12.2011120101からはそのように変更した。

えむけいさんが教えて下さった所によると、これはBug 704171 – Remove the no-argument form of requestAnimationFrameでの変更による物で、要するに「DOMイベントベースの方法は正式な仕様になりそうにないし誰も使ってないし、もう廃止してよくね?」ってことで、Geckoでしか使えなかったDOMイベントベースの方法は廃止されて、WebKit等でも利用できるのと同じ形式のAPIに統一されたんだそうだ。まさにその当日にMDNのドキュメントを調べてて、その廃止された方の使い方が解説されていて、MDNにも書いてある使い方なのにおっかしーなーと首をひねってたんだけど、単にドキュメントの更新が間に合っていなかっただけだった。

現実的には妥当な決定だと思うけど、なんか釈然としない。例外のメッセージで「仕様が変わった、古い使い方はもう使えない」とかそういう情報を出してくれれば、もうちょっとすんなり原因に気がつけただろうに……

Firefox Hacks Rebooted、オライリーから出ました - Oct 27, 2011

既にご存じの方もいらっしゃるかとは思いますが、オライリーから「Firefox Hacks Rebooted」という本が出ました3年前に出た「Firefox 3 Hacks」の続き……でもないのですが、似たようなコンセプトで「今」の話をまとめた本です。

本1冊を通して1つのストーリーに基づいて何かを体系立てて解説する、という本ではなくて、各著者が自分の得意分野で好きなように書きたい事を書きまくった本、というのが実情を正しく言い表している気がします(元々、オライリーの「○○ Hacks」というタイトルは「なんでもあり」のブランドなんだそうで……その言葉に甘えてしまいました)。

以下、各章の対象読者層と思われる層、内容の簡単な紹介と、定量的に傾向を把握するための手がかりとしてページ数と全体に対する割合を表にしてみました。これを見ると一発で分かりますが、僕(4章と6章の一部を担当)の暴走が著しいですね。やばい。

主な対象読者層 内容 ページ数 全体の中でのパーセンテージ
1章 エンドユーザ Firefoxの新機能紹介など基本的な事。Firefox 3.6とFirefox 4以降との間で何が変わったのかのまとめ。 54 11%
2章 開発者寄りのユーザ VimperatorとKeySnailの解説。と、Twitter用アドオンの解説。ブラウザとしてのFirefoxをガンガン使いこなしていく人向け。 42 9%
3章 アドオン開発者 Add-on SDKを使ったアドオン開発のチュートリアル。アドオンの開発をこれから始めたいという人向け。 68 14%
4章 アドオン開発経験者 Bootstrapped Extensions、ChromeWorker、e10sなど、Add-on SDKよりも下のレイヤの技術の解説。今既にアドオンを開発してるという人や、Add-on SDKではできない・標準ライブラリでカバーされてない範囲の事に手を出そうと思ってる人向け。 156 33%
5章 Webデベロッパー Firefoxで利用できるHTML5関連技術やECMAScriptの紹介。Webデベロッパー(主にフロントエンド)向け。 98 21%
6章 アドオン開発経験者、Webデベロッパー ハードウェア寄りの話と、その他のこぼれ話。アドオンやWebアプリの開発で、ネイティブアプリ並の事をやりたい人向けの話が多め。かも。 56 12%

自分の担当箇所だけ細かく見てみると、ページ数と全体に対する割合はこんな感じです。

  • Bootstrapped Extensions(再起動のいらないアドオン)の話:54ページ、11%
  • 非同期処理の紹介:72ページ、15%
    • そのうち、JSDeferredの紹介:43ページ、9%
  • js-ctypes(6章):27ページ、6%

調子に乗って脳汁ドバドバ出して書きまくる→ページ数が増える→値段上がる→損益分岐点も上がる という危険なコンボが発動してしまったためかお値段高めとなっておりますが、自分の担当箇所も他の方の担当箇所もひっくるめて、腰を据えて読むに値する情報ばかりなんじゃないかなーと思っております。Webで難なく読める文章の長さと、(紙でも電子でも)書籍の形になってた方が読みやすい文章の長さって、やっぱり違うと思いますしね。

本書のサポートサイトも公開されており、正誤表や本文中の各コードリストのダウンロード、本文の一部を切り出したサンプルPDFの無償公開などがあります。正誤表等はこれから更新されていくと思いますので、本書をお読みになられる際はこちらのサイトも併せてご参照いただければ幸いです。

以下は、思い出話です。

本書の企画がスタートしたのは、Firefox 4の正式版が出る前の2010年5月頃だったと思います(今メールボックスの一番古いメールの日付を見て確認した)。当時はまだ内部バージョンがFirefox 3.7とか言われていた頃で、Aero Glassが標準で入るのか?とか、そんな事を言ってた時期でした(という事も今Wikipediaを見て確認した)。

それからしばらく、どんな内容にするのがいいか? どんな人に執筆を依頼しようか?(今著者の一覧に名前が載ってる方の中には、最初の時点で名前が挙がってた著者の側から「是非この人にも書いてもらいたい!」と引っ張り込んだ人もいるのです) という事を話し合っていて、執筆者が確定したのが8月。そこからぼちぼち書き始めて、なんやかやで1年経ってしまいました(普通はここまで難産にはならないみたいです)。その間にFirefoxのバージョン番号もどんどん上がっていって、もうすぐFirefox 8ですよ奥さん! 時間が過ぎるのは本当に早いものですね。

最初の頃は、自分は「Firefox 3 Hacksで書いた内容をFriefox 4時点での情報に基づいてリライトするか?」程度の事を考えていました。でも、それじゃあ書いてる自分がつまらないし、それこそすぐに陳腐化してしまいます。それでうんうん唸りながら調べていくうちに、Firefox 4以降の話で新しい基盤の技術になりそうなトピックがいくつかあるという事が分かってきたので、それじゃあってんで、そこをターゲットにして書いていく事にしました。実は、自分の担当箇所は半年くらい前にほぼ完成してたんですよね。そこから本書の発売までの間は、(他の事に時間を使ってたからというのもありますが、)細かい記述のアップデート程度しかやってません。高速リリースになってからガンガン方針が変わったり実装が変わったりしてて、本書に書いた「テクニック」の中にも、既に「もうこんな回りくどい事しなくてもいいんだけどなぁ」な感じになってしまった話題がいくつかあるにはあるのですが(校正の詰めの詰めに入った段階でまたどどっと変更が入ってきて、どーしても間に合わなかったんです……)、全体としてはちゃんと今でも、そしてこれからも通用する話になってると思います。あの時の自分の目の付け所は、そんなには間違ってなかった、はず。

紆余曲折があった末にようやく世に出る事ができた本書ですが、アドオン開発者の方の手助けとなり、また、アドオン開発に手を出してみようと考えている方の手引きとなれば、幸いです。

他の著者の方々による本書の紹介のエントリ:

nsIFocusManagerを使ってウィンドウを最前面に持ってくる方法 - Jun 24, 2011

Firefox上でいくつかのサブウィンドウを開いていて、それらのウィンドウすべてがワンセットで他のウィンドウより前に出てきていて欲しい場面、というのがある。

例えば、GIMPはツールボックス等が複数のウィンドウにばらけている。これがもし、画像を編集するウィンドウにフォーカスしたらツールボックスのウィンドウがその背後に隠れてしまうという風になっていると、まるで作業にならないだろう(古いバージョンのGIMPをWindowsで使った時にはそんな風になってて頭を抱えた記憶がある)。

また、そういうワンセットで表示されていて欲しいウィンドウ達が、同時に起動している他のアプリケーションのウィンドウの前と後ろにそれぞればらけてしまうというのも、使う時に地味にうざい。

Firefoxの上で、拡張機能が開くウィンドウでGIMPのウィンドウ群のような振る舞いをさせるにはどうすればよいのか。このエントリでは2つの方法を紹介する。

まず1つ目。nsIXULWindowインターフェースのzLevelプロパティを使うと、Firefoxのプロセスが開くウィンドウの重ね合わせの順序をある程度制御する事ができる。一番単純なやり方は、ウィンドウを一時的に最前面表示に切り替えて、その後すぐに元に戻す、という方法だろう。

var XULWindow = window
                .top
                .QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIWebNavigation)
                .QueryInterface(Ci.nsIDocShellTreeItem)
                .treeOwner
                .QueryInterface(Ci.nsIInterfaceRequestor)
                .getInterface(Ci.nsIXULWindow);

var originalZIndex = XULWindow.zLevel;
XULWindow.zLevel = Ci.nsIXULWindow.highestZ;
window.setTimeout(function() {
    XULWindow.zLevel = originalZIndex;
}, 0);

ただ、仕様上の制限のため、この方法はWindowsでしか使えない。少なくともUbuntu 10.04のGnomeでは機能しなかった。

代わりに考えられるもう1つのやり方が、フォーカスを使うやり方だ。単純に考えても、window.focus()でウィンドウにフォーカスを与えると、強制的にそのウィンドウを最前面に持ってくる事ができる。

しかしこの方法にも問題がある。普通にwindow.focus()すると、例えばそのウィンドウの中の特定のテキストボックスにフォーカスしていたとしても、そのフォーカスが失われてしまう事になる。

この問題を回避するには、Gecko 1.9.2/Firefox 3.6から導入されたフォーカスマネージャを使わないといけない。具体的には以下のようにする。

var FocusManager = Cc['@mozilla.org/focus-manager;1']
                   .getService(Ci.nsIFocusManager);

// 現在フォーカスされている要素を取得する。
// 第1引数:検索する最上位のDOMWindow
// 第2引数:再帰的な検索を行うかどうかのフラグ(trueを渡す)
// 第3引数:その要素が含まれているフレームのDOMWindowを
//          受け取るためのスロットとなるオブジェクト
var focusedWindow = {};
var focusedElement = FocusManager.getFocusedElementForWindow(window, true, focusedWindow);

// 現在のフォーカスが何によって与えられたかの情報を取得する。
var reason = FocusManager.getLastFocusMethod(focusedWindow.value);

// フレームにフォーカスする。
focusedWindow.value.focus();

// フォーカスされていた要素がある時は、その要素にもフォーカスする。
if (focusedElement) {
    // フォーカスを与える時に、スクロール状態等に変更を加えないように指定する
    let flags = Ci.nsIFocusManager.FLAG_RAISE |
                Ci.nsIFocusManager.FLAG_NOSCROLL |
                Ci.nsIFocusManager.FLAG_NOSWITCHFRAME |
                reason;
    FocusManager.setFocus(focusedElement, flags);
}

こうすれば、Linuxでも要素のフォーカス状態を失わせずにウィンドウを最前面に持って来れる。ウィンドウのフォーカスを動的に切り替えるため、その都度各ウィンドウが画面上でぺかぺか点滅してしまう(一瞬だけフォーカスされて、その直後にフォーカスが失われるため)、というデメリットはあるが。

js-ctypesで期待した通りにガーベジコレクトされてくれないから自分でmalloc/freeする - Mar 27, 2011

最初に要点だけまとめておくと、

  • js-ctypesを使う時は、JavaScriptのコード側では基本的にメモリの管理のことは考えなくてもいい(ガーベジコレクト任せにしていい)事になってる。
  • しかし実際使ってみると、JavaScriptからjs-ctypes経由で自分でmalloc/freeしないとどうにもならないという場面があるみたい。
  • なのでJavaScriptからjs-ctypes経由でmalloc/freeする方法とその実例を紹介する。

という話です。

続きを表示する ...

64bit整数を使わないという、js-ctypesの最適化ノウハウ - Mar 27, 2011

先に結論だけ書くと、

  • js-ctypesでCのライブラリから帰ってきた64ビット整数を32ビット整数2つで代用できる場面では、32ビット整数にしておいた方が何倍も速くなることがある
  • ctypes.uint32_tとctypes.unsigned_longが同じ意味になる場合(Win32/Win64など)はctypes.uint32_tを使った方がいい

という話です。以下、実際にどういうケースでこれが役立つかの説明です。

続きを表示する ...

js-ctypes - Mar 20, 2011

js-ctypesはFirefox 3.6から利用できるMozillaの独自の機能で、平たく言うとC言語の実装の中で定義された関数をJavaScriptから呼べるようにするという物。Pythonにctypesという機能があって、それのJavaScript版がjs-ctypes。

Firefox 3.6(Gecko 1.9.2)ではできる事の制限が厳しかったので使えるケースがあんまり無かったようなんだけど、Firefox 4(Gecko 2.0)では構造体がサポートされたので一気に使える場面が増えた。らしい。

システムモニターをFirefox 4に対応させなきゃねと思ってたんだけど、Compartmentがどうとか色々変更があったのを全部調べてたら絶対自分の手に負えん!!と思ったので、いっそのことjs-ctypesで実装すりゃいいんじゃね? と思って、試行錯誤しながらやってみてる。試行錯誤の様子はリポジトリを見るとバレバレです。

js-ctypesのいい所:

  • コンパイルしなくていい。SDKやらビルド環境やらを整えるのに苦労しなくてもいい。
  • 単にバイナリを用意できてないだけで、その環境でバイナリをビルドしさえすれば大丈夫なのに……って場合には、多分そのまま動く。(動かない場合もある)
  • CとJavaScriptの境界で動作するコードで考えなきゃいけなかった諸々の事(JavaScriptのコンテキストがどうだとか、nsIVariantを経由したりJSObjにしたりとか、いろんな事)を考えなくてもいい。

困った所:

  • 結局はCなので、C言語が分かってないとどうしようもない。(僕はjs-ctypesでちょっとC言語への理解が深まりました……)
  • Cでの開発だったらヘッダファイルをインクルードすればそれでいいという場面でも、js-ctypes用に構造体の定義をJavaScriptで全部書き直さないといけない。
  • 取得した値が数値になってると思って「+」演算子で計算しようとするとハマる。数値を返すような関数でも返ってくる値はjs-ctypesによってラップされたオブジェクトなので、「+」演算子で繋げると文字列連結になってしまう(「-」などの、数値型に暗黙のうちに変換する演算子であれば問題は起こらない)。
    • 必ずparseInt()する、みたいな癖を付けとくとハマらなくていいと思う。
  • JavaScriptの書き方が悪くてJITされてないせいもあるのかもしれないけど、ループが遅くいからか、Cで書くよりずいぶんパフォーマンスが落ちる場面がある。メモリ消費量の計算だけでCPUを20%近く使っちゃうことになったりとか……

JavaScriptでFirefoxをクラッシュさせたかったらjs-ctypesでメモリ破壊とかやると手っ取り早いですよ! と、数え切れないほどFirefoxをクラッシュさせて思いました。

Page 1/239: 1 2 3 4 5 6 7 8 9 »

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のつぶやき

オススメ

Mozilla Firefox ブラウザ無料ダウンロード