SimpleBoxes

MacBook セットアップ (2008.02 バージョン)

ニュージーランドに戻ってきて、修理に出していた MacBook も手元に戻ってきました。

日本滞在中に内蔵メモリ 2GB と HDD(ハードディスクドライブ) 160GB を購入しておいたので、早速交換。

[画像]内蔵メモリ 2GB になった MacBook

これまでの HDD 構成は

  • MacBook 60GB
  • 外付け HDD 30GB (Mac OS X 用パーティション & Windows 用パーティション)

でしたが、これが

  • MacBook 160GB
  • 外付け HDD 60GB (Mac OS X 用フォーマット)
  • 外付け HDD 30GB (Windows 用フォーマット)

のようになります。

今まで慢性的に 2GB 以下の空き容量しかない状態で作業を行っていましたが、ハードディスク容量に余裕が出て、作業がしやすくなりました。

内臓 HDD を交換したため、Mac OS X の再インストールなど、環境を構築し直しています。多くの設定は旧 HDD からコピーして移行しているので、一から構築という訳ではありません。

ちなみに修理に出すにあたって MacBook に保存していた多くデータは、念のため一度消去していました。ですから、HDD の交換がなくてもいずれにしても何かしらのセットアップ作業は必要でした。日頃からホームディレクトリの内容を暗号化する FileVault の機能を利用しているので、わざわざ消さなくてもよかったのかも知れませんけれども。

Mac OS X セットップ

大まかな手順は、以下の通りになります。

  1. Mac OS X 10.4 のインストール
  2. Mac OS X 10.4 のアップデート
  3. バックアップからアプリケーションのコピー
  4. バックアップからライブラリ (初期設定など) のコピー

Mac OS X のバージョンアップ (10.4.6 → 10.4.11) は、ソフトウェアアップデートで可能ですが、今回は手元に取ってあったパッケージを利用してバージョンアップしています。

ソフトウェアアップデートには、「パッケージをインストールして保存」というオプションがあります。これを行っておくと、手元にパッケージファイルを残しておけるので、このような HDD 交換作業のときに一々ネットにつなぐ必要なく、バージョンアップが可能です。

[画像]ソフトウェアアップデートのアップデートメニュー

アプリケーションは、基本的に旧 HDD からコピーするだけなんですが、いくつかはインストーラを利用してインストール必要がありました (例えば、Palallels)。インストールした主なソフトウェアは以下の通り。

Parallels Desktop には Windows XP Home をインストールしましたが、さらに今回 HDD に余裕ができたので、Ubuntu もインストールしてみました。

最初すんなりとインストールできませんでしたが、モノクロカプセルさんで触れられている通りにインストールしてみたらどうにかできました。

開発環境のセットップ

開発環境のセットアップとして、主に必要な作業は以下の通り。

  1. Parallels / Windows XP のインストール
  2. Xcode のインストール
  3. MacPorts のインストール
  4. ImageMagick のインストール
  5. FileMerge の設定
  6. zip のインストール
  7. subversion のインストール
  8. MySQL のインストール
  9. Perl モジュールのインストール
  10. ウェブサーバ設定など

上記作業の中で ImageMagick のインストールは鬼門で、前回 (MacBook 購入時) にもはまったのですが、今回も少しはまりました。詳細については後日。

スポンサーリンク

Windows Vista のアップグレードではまる

家族ぐるみでお付き合いさせていただいている方が、最近新しいラップトップ PC を購入しました。

そのラップトップ PC には、Windows Vista Home Basic がインストールされていましたが、「ログインするユーザーによって日本語表示か英語表示かを切り替えたい」という相談を受けました。

Windows XP では、そのような機能はありませんでしたが、Windows Vista なら表示言語の切り替えが可能なようです。

Vista 発売当初、Windows Vista では……バージョンに関わらず…… Mac OS X のように、特別なファイルをインストールすることもなく、表示言語が選択可能だと思っていました。

Mac OS X では、インタフェース表示言語の切り替えは標準の機能で、世界中のどこで購入しても不自由なく日本語が利用できます。特別なファイルをインストールしたりする必要はありません。ニュージーランドで購入した MacBook でも日本語インタフェースで利用できますし、逆に日本で購入した Mac に対して、英語やフランス語など「日本語以外」を表示言語として利用することも可能です。

しかしながら、どういう理由でかは分かりませんが、表示言語を切り替えるためには Ultimate もしくは Enterprise というバージョンが必要なようです。

そこで Windows Vista Ultimate のアップグレード版を購入し、インストール作業をすることになりました。Windows Vista Ultimate アップグレード版は日本の方が安かったので、日本滞在中に購入していました。

[写真]購入した Windows Vista の豪華なパッケージ。

まず、最初に躓いたのが、いわゆる「アップグレード」ができないことでした。

アップグレード対象製品とアップグレード手順を確認すると、Windows Vista Home Basic から Ultimate のアップグレードでは「アップグレードインストール」が可能らしいのですが、Home Basic 英語版から Ultimate 日本語版は考慮されていないようです。

改めて、よぉくパッケージを見ると、小さな文字で「日本語製品のみ対象となります」と書いてありました。……もしかしたら、アップグレード対象外、なんでしょうか。

ライセンス条件などに関しては、何度も Microsoft のウェブページで確認したつもりでしたが、パッケージの言語間の差異やそれにかかるライセンス条件について触れているページは見つけることはできませんでした。プリインストールされた Windows Vista Home Basic から購入した Windows Vista Ultimate 日本語版へのアップグレードはライセンス的に問題ないと私は思っていますが、直接 Microsoft に確認していません。

「アップグレード」ができないので、新規インストールをしました。

インストールは無事できたのですが、なにやら表示がぼやけています。

「おかしいな」と思ってディスプレイの設定を確認すると、正しい解像度が設定されておらず、選択肢にありません。どうもドライバがインストールされていないようです。

ちなみに、プリインストールされていた Windows Vista Home Basic は「windows.old」というフォルダに移動されて保存されます。上書きはされませんので、元に戻すのはそれほど難しくないような気がします。

プリインストールされた Windows Vista Home Basic では、きちんとドライバもインストールされていましたが、Windows Vista Ultimate を「新規インストール」したためにドライバが標準の汎用的なドライバになってしまっているようでした。

試行錯誤の末、プリインストールされていたリカバリープログラムを退避されていた「windows.old」領域から発見して、それを無理矢理立ち上げて、必要だと思われるハードウェアドライバをひとつずつインストールし直すことで復旧させます。……た、大変だった……。

……

どうにかこうにか形を整えることができたので、当初の一番大きな目的であった「英語インタフェースと日本語インタフェースをログインユーザーによって切り替える」という設定をします。

ヘルプを見ると……

メニューとダイアログで使われる言語には既定でインストールされているものもありますが、追加言語ファイルをインストールする必要があるものもあります。

Windows Vista ヘルプ : メニューとダイアログで使われる言語をインストールする

コントロールパネルの「地域と言語のオプション」→「表示言語」を見ると、既定ではインストールされていないようなので、「追加言語ファイルをインストールする必要」がありそうです。

これらのファイルは、コンピュータ、ネットワーク上のコンピュータ、または Windows DVD にあるか、または Web からダウンロードできます。

Windows Vista ヘルプ : メニューとダイアログで使われる言語をインストールする

この「Windows DVD」というのがよく分かりません。「Windows Vista Ultimate のインストール DVD」のことなんでしょうか……。しかしながら、インストールディスクのどこにファイルがあるのか分かりません。……ざっくり調べてみましたが、どうやら該当するようなファイル無さげです。

さらにオンラインヘルプを見ると、Windows Update から「追加言語ファイル」を入手できる様子です。

Windows Update を立ち上げると、まず定例アップデートが適用されました。それらのアップデートを行わないと「利用可能な更新プログラム」を表示するメニューが現れません。

もしかしたら、アップデートを一度中断したら表示できたのかもしれませんが、ちょっと怖くてできませんでした。

定例アップデートもどうにか無事に適用され、何度かの再起動を経てようやく目的の「追加言語ファイル」を入手……

……

……

……ファイルサイズが 250MB 以上ある…………

だ、ダイアルアップなんですけど。どんぐらい時間かかるんでしょうか……。

結局、先方のお家では、全ての作業を行うことができませんでした。ADSL が利用できる自宅に引き取って、その後の作業を行うことに。

う〜ん、英語ぐらいは標準で用意してくれても良さそうな気がしたんですが、何か事情でもあるんでしょうか。

スポンサーリンク

さようなら、EGWORD & EGBRIDGE

Mac OS X 向けに日本語入力ソフト egbridge や日本語ワープロソフト egword を開発・販売していたエルゴソフトから「パッケージソフト事業終了のお知らせ」がありました。

私はエルゴソフトからの ERGO PRESS という登録ユーザー向けメールマガジンで知りました。

初めてそのお知らせを見たときは「何かの冗談?」かと思ってしまったほど。にわかに信じることができませんでした。

エルゴソフトは Apple より前に Macintosh の日本語環境を構築したとも言っても過言ではなく、Mac での日本語環境を語る上では避けては通れない老舗メーカーのひとつです。

クラシックな MacOS 頃から Mac OS のバージョンアップへの対応もかなり早く、「エルゴソフトなら安心」というような印象を持っていました。

私自身は EGWORD / EGBRIDGE のユーザーで、ずっとコンビニ決済でバージョンアップしていたのですが、ニュージーランドに移住してからはバージョンアップ手続きをしていませんでした。日本在住であれば、まず間違いなく利用し続けていたと思います。

Classic な MacOS では、PDF の出力機能が標準機能ではありませんでした。EGWORD では PDF の書き出し機能があって、PDF 生成ソフトウェアとしてよく利用していました。ところが、Mac OS X で、PDF 出力機能が標準となり、主な目的であった「あるソフトウェアのマニュアル」の形式を PDF から HTML 形式に変更したというのもあって、EGWORD の出番はだんだんと少なくはなっていました。

恥ずかしながら、今回の件を通して初めて、開発者である廣瀬さんのウェブログを知りました。当然ながら今回の件についても触れられています。

素晴らしいソフトウェアを本当にありがとうございました。

これまで EGWORD / EGBRIDGE に携わってきた方々の新しい場でのご活躍をお祈りいたします。

スポンサーリンク

Serene Bach 3.0 公開に寄せて

Serene Bach 3.0 β版をようやく公開しました。昨年 7 月に開発始めているので、ここまで 17 ヶ月かかっています。

Serene Bach 2.* は、およそ半年だったので、およそ三倍。途中開発していない期間もありますから、単純比較できませんが。

それはさておき。

Serene Bach 3.0 (主に管理画面)の作り込みで少し苦労した部分をまとめてみました。

CodePressの導入

Serene Bach 3.0 では標準のエディタとして、CodePress を導入しました。

CodePress は HTML のタグなどのハイライトをサポートする JavaScript ライブラリです。

Movable Type 4.0 のテンプレート編集にも採用されているので、目にした方もいらっしゃるのではないでしょうか。

そのままだと Safari 上では動かないので、いくつか独自の修正を入れています。詳細については、すでに述べているので、ここでは割愛します。

また、Serene Bach 3.0 ではエディタ部分が独立したモジュールになっているので、後からの差し替えが以前のバージョンよりも遥かに容易になっていると思います。

リキッドデザインの適用

Serene Bach 3.0 では、管理画面をリキッドデザインに変更しました。管理画面の幅は、ブラウザのウィンドウサイズに追従して変動します。

最小幅と最大幅を設定して、ウィンドウ幅を極端に変更した場合のレイアウト崩れが起きないようにしています(ただし、一部の対応ブラウザのみ)。

sb/Serene Bach 2.* では、700px の固定幅を使っていましたが、手狭に感じる場面があったので、思い切って変更しました。

リキッドデザインに変更すること自体は、それほど難しくありませんでした。やや苦労したのは、管理画面で多用されているテーブルのスタイル指定です。

Serene Bach の管理画面では、一覧性を重視するような場面においてテーブルを利用しています。

そのため、sb/Srene Bach のデザイン上のポリシーとして、「テーブル内の各項の高さは、できるだけ統一させる」というのがあります。

従来の管理画面ですと、テーブル幅を固定していたので、各項に収められる文字数に対して、大体あたりを付けられます。長い文字列を表示させるような場合は、規定の長さにクリップして出力していました。

ところが、リキッドデザインになると、どの程度の長さを許容できるかは分かりません。ですので、長い文字列もすべて出力しています。

もちろん、そのままだと文字列に応じて、各項の高さがばらばらになってしまい、一覧性が著しく欠けてしまう可能性があります。そこで以下のような CSS を適用します。

table td.elem {
  text-align: left;
/* except MacIE \*/
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
/* end for MacIE */
}

このスタイル指定により、class 属性に "elem" が指定された td 要素は、折り返し表示されなくなります。

Internet Explorer for Mac 向けのハックを使って、Internet Explorer for Mac には適用されないようにしています。したがって Internet Explorer for Mac では、折り返して表示されます。これは Internet Explorer for Mac では overflow: hidden; がうまく効いてくれないための対応です。

text-overflow: ellipsis; は、Safari / Internet Explorer for Windows / CSS3 で利用できるプロパティで、クリップされる場合に「...」という省略記号を表示してくれるようになります。

基本的なスタイルはこれでいいのですが、そのままだと各項の幅が、ブラウザによって、うまく指定できないという問題が生じました。

そこで colgroup 要素と col 要素を追加し、テーブルの各列の幅を指定します。こうすることでレンダリングエンジン間の差異が少なくなる印象です。

例えば、以下のようなテーブルがあったとして、

<table>
<tr><th>ID</th><th>タイトル</th><th>日付</th></tr>
<tr><td>ID1</td><td>これはサンプルです</td><td>2007.12.04</td></tr>
</table>

これを以下のように記述します。

<table>
<colgroup><col class="id" /><col class="title" /><col class="date" /></colgroup>
<tr><th>ID</th><th>タイトル</th><th>日付</th></tr>
<tr><td>ID1</td><td>これはサンプルです</td><td>2007.12.04</td></tr>
</table>

その上で、col 要素に対して幅を指定するスタイルを設定します。

table col.id {
  width: 4em;
}
table col.date {
  width: 9em;
}

MySQL/SQLite の AUTO_INCREMENT オプション

MySQL/SQLite では、フィールドの属性として「AUTO_INCREMENT」を指定することができます。

これは id など、データ毎に独立して重複しない値を設定したいときに有効なオプションです。当然ながら Serene Bach 3.0 でも利用しています。

ところが、これを指定すると、最初の id が 1 になってしまいます。0 から始まらない。

Serene Bach では、いくつか id = 0 のオブジェクトを特定して利用している場面があるので、このままでは大幅なコード変更が必要になってしまいます。

とりあえず、SQLite では直接 id を指定したデータを insert する分には問題ない様子。

MySQL では、以下のオプションがありました。これを接続時に設定することで最初の番号として 0 を利用できるようになります。

SQL_MODE='NO_AUTO_VALUE_ON_ZERO'

スポンサーリンク

[javascript]文字の実体参照化

Javascript で文字の実体参照化を行う関数が phpspot開発日誌 にて、紹介されています

引用元なんでしょうか、Tudástár - Prog.Hu というサイトにリンクが張られていましたが、当方の環境からではオリジナルのコードを見つけられませんでした。

function htmlspecialchars(ch) {
  ch = ch.replace(/&/g,"&amp;") ;
  ch = ch.replace(/"/g,"&quot;") ;
  ch = ch.replace(/'/g,"&#039;") ;
  ch = ch.replace(/</g,"&lt;") ;
  ch = ch.replace(/>/g,"&gt;") ;
  return ch ;
}

ここでは replace を使って正規表現による文字置換によって実装されています。

Javascript で HTMLエスケープを行うPHP関数、htmlspecialchars を実装」でも触れられている通り、文字クラスの prototype による実装も可能で、その場合には、以下のようなコードになるでしょう。

String.prototype.htmlspecialchars = function() {
  ch = this + "";
  ch = ch.replace(/&/g,"&amp;") ;
  ch = ch.replace(/"/g,"&quot;") ;
  ch = ch.replace(/'/g,"&#039;") ;
  ch = ch.replace(/</g,"&lt;") ;
  ch = ch.replace(/>/g,"&gt;") ;
  return ch ;
}

ただ、この場合、htmlspecialchars なんて名前だと長くて分かりにくい気もするので、prototype.js のように escapeHTML のような名前にしておくのが無難かもしれません。

個人的には「実体参照化」という意味を込めて「entitize」という英単語をでっち上げちゃいますが。

さて、ここで紹介したスクリプトは replace を使っていますが、使わなくても実装できます。

String.prototype.entitize = function()
{
  var str = "" + this;
  str = str.split("&").join("&amp;");
  str = str.split("<").join("&lt;");
  str = str.split(">").join("&gt;");
  str = str.split('"').join("&quot;");
  str = str.split("{").join("&#123;");
  str = str.split("}").join("&#125;");
  str = str.split("'").join("&#039;");
  return str;
}

splitjoin を使います。

perl だと正規表現を使った置換よりも組み込み関数 splitjoin を駆使した後者の方が実行速度が速そうです。

javascript だとどうなんだろう?と思って、簡単なスクリプトを組んで実験してみてみました

Firefox 2.0.0.8 と Safari 2.0.4 と Opera 9.23 (いずれも Mac OS X 版)を使ってテストしたところ、

  • Firefox : split の方が速い (2 〜 3 倍)
  • Safari / Opera : replace の方が速い (1.5 〜 3.5倍)

という結果になりました。ブラウザによって変わってくるので、どっちがいいかはこれだけでは判断できない感じでしょうか。

ちなみに実体参照化の逆変換を行うスクリプトは以下のようになります(split による実装ですが、replace による実装もほぼ同様です)。

String.prototype.detitize = function()
{
  var str = "" + this;
  str = str.split("&#039;").join("'");
  str = str.split('&#123;').join("{");
  str = str.split('&#125;').join("}");
  str = str.split("&quot;").join('"');
  str = str.split("&gt;").join(">");
  str = str.split("&lt;").join("<");
  str = str.split("&amp;").join("&");
  return str;
}

実体参照化の場合は、& の変換を一番先に行う必要があり、逆実体参照化の場合は、&amp; の変換を一番最後に行う必要があります。

ちなみに entitize , detitize は共に造語です。英語圏で通用するかは全く分かりません。

続きを読む

スポンサーリンク

mixi デザインリニューアルに関してのご意見

こんな回答で良いの

そもそも質問者が mixi のリニューアルに否定的な目で見ているのでアレ(どれ?)なんですが……。

これはあくまでも、このウェブサイトの立ち位置や、これまでの流れ・仕組みなどは考慮せず、このページを見ただけの感想でしかありません。念のため。

特に二番手の回答者、寺田あつし氏の回答にかなりびっくりしました。

いまだにphpではなくperlで動いているあたり

なんて発言も正直「どうかしてる」としか言いようがないんですけど、

情に流され、経営者としての判断を誤った社長

とか今回のリニューアルと関係あるの?

三番手の回答者、谷口浩一氏の意見だと、

今回のリニューアルで一番の問題は、横幅が200ピクセル少々増えて、横スクロールが発生してしまう利用環境がすごく増えたこと

それが「一番」問題なんだろうか?

私には、以前にはユーザー側で 2 or 3 カラムが選択可能であった仕様が変更されてしまった、というのが一番大きいと思うんだけど。

スポンサーリンク

ユーザースタイルシート for mixi

リニューアル後のmixiを2カラム/750px幅化するユーザースタイルシートを書いてみたで公開されているユーザースタイルシートをベースに自分向けにカスタマイズしてみました。

User CSS for mixi

変更点は以下の通り。

  • コンテンツがセンタリングされるように
  • ナビゲーションバーの長さが大体 750px になるように
  • 最新情報のタイトル・コンテンツのデザインを旧デザインっぽく?
  • プルダウンメニューが利用できるように
  • ロゴを何となく復活させてみた

グローバルナビゲーションの画像はリサイズしているので、Windows だと汚くなります。

[2008.03.26 追記] 2008.03 にこっそりと mixi のデザインが変更になったことを受けて、スタイル内容も変更しました。

@namespace url(http://www.w3.org/1999/xhtml);

@-moz-document domain("mixi.jp") {

/* original code by http://www.akiyan.com/blog/archives/2007/10/mixi2765px.html */

body {
  width:750px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* ロゴ */
h1 {
  width:750px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* 広告バナー非表示 */
.adBanner {
  display:none !important;
}

/* 右カラム非表示 */
#bodySub { display:none }

/* ヘッダの背景を透過色に */
#headerArea {
  width:750px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* ヘッダエリアの幅調整 */
#headerArea {
  width:750px !important;
  margin-left: auto !important;
  margin-right:: auto !important;
}

/* ヘッダの高さを自動に */
#headerArea { height:auto !important }

/* 本文エリアの幅調整 */
#bodyArea {
  width:750px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* グローバルナビゲーションの幅調整 */
#globalNavigation {
  width:750px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* グローバルナビゲーションのmikly・動画・フォトボタン非表示 */
#globalNavigation ul.contentsNavigation li {
  width: 57px !important;
  height: 28px !important;
}
#globalNavigation ul.contentsNavigation li.home {
  width: 66px !important;
}

/* ローカルナビゲーションの幅調整 */
#localNavigation {
  width: 750px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}
#localNavigation ul li {
  height: 20px !important;
}
#localNavigation ul.localNaviHome li {
  width: 73px !important;
}
#localNavigation ul.localNaviFriend li {
  width: 79px !important;
}
#localNavigation ul.localNaviCommunity li {
  width: 89px !important;
}
#localNavigation ul.localNaviNews li {
  width: 65px !important;
}

/* ローカルナビゲーションのプルダウンボタン非表示 */
#diaryPullDownButton,
#videoPullDownButton,
#photoPullDownButton,
#reviewPullDownButton,
#eventPullDownButton,
#topicPullDownButton {
  display: none !important;;
}

/* フッター幅調整 */
#footerArea {
  width:750px !important;
  margin-left: auto !important;
  margin-right: auto !important;
}

/* フッターナビゲーションマージン調整 */
#footerArea ul.footerNavigation01 li {
  margin:0 2px !important
}

/* 検索フォーム非表示 */
div.searchForm01{
  display:none
}

/* 「最新情報」ヘッダの非表示 */
#mymixiUpdate div.heading01 { display:none }

/* 最新情報タイトル */
#bodyContents div.heading02 {
/*
  background: transparent url(http://img.mixi.jp/img/basic/heading/body_contents001.gif) no-repeat scroll 0% !important;
  height: 28px !important;
*/
}

/* 最新情報コンテンツ */
#bodyContents div.contents {
  background-color: #f8f8f8 !important;
  border: 1px solid #DFB479 !important;
}
#bodyContents div#myUpdate div.contents,
#bodyContents div#intro div.contents {
  background-color: transparent !important;
  border: 0px none #DFB479 !important;
}
#bodyContents div.contents dl {
  margin: -1px !important;
}

/* 自身の最新情報・友人紹介文 */
#myUpdate div.heading01,
#intro div.heading01 {
/*
  background:  transparent url(http://img.mixi.jp/img/basic/heading/body_contents002.gif) no-repeat scroll 0% !important;
  height: 28px !important;
  width: 442px !important;
*/
}

}

スポンサーリンク

BEGIN ブロックではまる (perl)

表題の通り、BEGIN ブロックの扱いではまったので、忘れないようにメモ。

package test;
use vars qw( $CHECK );
$CHECK = undef; # 初期化
BEGIN {
  eval { require test::optional; };
  $CHECK = 1 if (!$@); # optional モジュールを呼び出せたので、フラグを立てる
};

上記のようなコードを記述していたのですが、意図した通り動いてくれていませんでした。

BEGIN ブロック内では、$CHECKは「1」になっているのですが、後から(例えば、test モジュールを要求したモジュールから)参照すると、$CHECKが未定義に見えます。

BEGIN ブロックが存在した場合、そのコードは真っ先に実行されます。その後、BEGIN ブロック外のコードが、必要ならば、実行されます。

そのため、BEGIN ブロックで「1」になった $CHECK は、その後、 「$CHECK = undef; # 初期化」と記述された行が実行されることにより、未定義になります。「初期化」と書かれながら、初期化になっていませんでした。

正しくは、以下の通り。

package test;
use vars qw( $CHECK );
BEGIN {
  $CHECK = undef; # 初期化
  eval { require test::optional; };
  $CHECK = 1 if (!$@); # optional モジュールを呼び出せたので、フラグを立てる
};

基本っぽいことですが、すっかりはまってしまっていました。

スポンサーリンク

WebKit で CodePress を利用するために

CodePress (http://codepress.org/) は、ウェブブラウザ上で HTML や JavaScript などのソースを編集するために、文法カラーリングなどをサポートする便利なスクリプトです。

CodePress in Safari

Movable Type 4 では、テンプレートエディタとして利用されていて、Serene Bach 3 でも大いに利用しています。

CodePress の最新リリースバージョンは v 0.9.5 ですが、サポートされているブラウザは Firefox (Mozilla系ブラウザ)、Internet Explorer for Windows、Opera となっています。Safari は残念ながら、現時点では対象外です。

ざっと調べてみましたが、基本的な機能(文法カラーリング)ならば、Safari でも動作させることができます→CodePress 動作サンプル

Onload イベント

Firefox と Opera では、DOMContentLoaded イベントをトリガーにして CodePress を起動させています。

このイベントは Safari ではサポートされていません。従って、DOMContentLoaded の代わりに load イベントを利用します。

contentWindow の挙動の差異

CodePress では、textarea 要素にかぶせるようにして iframe 要素を配置して、その中で独自のエディタを動作させます。

iframe 要素で動作させたエディタの内部情報を取得するのに contentWindow プロパティを利用しています。

contentWindow は Safari 2.0 でも動作するのですが、その挙動が若干 Firefox などとは異なるため、iframe 内部の情報を正しく取得することができません。

codepress.js では、以下のようにして iframe で定義された CodePress オブジェクトを取得しています。

self.editor = self.contentWindow.CodePress;

[note] ここで、self は CodePress で作成した iframe 要素の DOM オブジェクトです。

self.editor には、iframe 内部で生成された CodePress オブジェクトが入って、内部の setCode やら syntaxHightlight やらのメソッドをコールできるようになります。

self.editor.setCode(self.textarea.value);
self.editor.syntaxHighlight('init');

ところが、Safari では、self.editor.setCode が関数ではないと怒られます。ontentWindow 自体はきちんと認識されているにもかかわらず、それを変数に代入すると参照できなくなってしまうような印象です。

ですので、Safari では、self.editor を利用するのではなく、常時 contentWindow を介して内部関数をコールしてあげる必要がある様子です。

self.contentWindow.CodePress.setCode(self.textarea.value);
self.contentWindow.CodePress.syntaxHighlight('init');

getSelection と getRangeAt

Safari では、Firefox 同様、window.getSelection が利用できます。

Firefox では、以下のようなコードで、選択された範囲の DOM Range オブジェクト range を取得できます。

var range = window.getSelection().getRangeAt(0);

しかしながら、Safari では、getSelection で取得できる DOM Selection オブジェクトが getRangeAt というメソッドを持っていないようです

[note] Safari 2.0.4 でのみ確認。Safari 3.0 では確認していません。

そこで、Safari では以下のようなコードで選択された範囲の DOM Range オブジェクト range を取得します。

var selection = window.getSelection();
var range = window.document.createRange();
range.setStart(selection.baseNode, selection.baseOffset);
range.setEnd(selection.extentNode, selection.extentOffset);

designMode で編集された内容

Safari では、Firefox 同様、iframe の属性として、designMode = 'on' をセットすることで、iframe の内容を編集可能にします。

CodePress では、マークアップはシンタックスカラーリングのためだけに利用されます。

そのため、syntaxHightlight メソッドで、シンタックスカラーリングを行う際に、一度編集された内容を復元して、マークアップし直すという操作が行われます。

designMode を変更して、編集モードになった時に、Safari では、改行挿入時に行われる操作が Firefox とは異なるため、そのままでは適用できません。

具体的には以下のような操作になるようです。

  • 一回目の改行では、ブロック分け操作になる。そのため空の div 要素が挿入される。
  • そのまま二回目の改行では、br 要素が挿入されるが、class 属性として、khtml-block-placeholder (Safari 3.0 では webkit-block-placeholder) が指定されている。

そのため、改行コードのバッファリング操作が Firefox とは異なります。

iframe に対するスタイル指定

CodePress では、iframe の読み込みを行う前に iframe のスタイルに関して position プロパティを absolute に指定しています。

挿入される iframe によって、textarea がずれてしまう現象を防ぐために行っているようです。

Safari 2 だと、position プロパティを absolute から static に変更すると、何故か iframe を再度読み込んでしまう現象が発生します。

これを防ぐためには position プロパティを最初から static にしておくという対処が考えられます。

ちなみにこのバグ(?)は Safari 3 では修正されているようで、Safari 3 では、この修正をする必要はありません。

更なる問題

ここまでの対応で、とりあえず CodePress の基本的な動作は実現可能になります。

しかしながら、CodePress 起動後の CodePress へのアクセスなどまだ解決すべき問題が残っています。

また、安定性も今ひとつで、特に undo 操作を行うと簡単にブラウザが落ちます。普通に利用する分には問題なさそうですが。

スポンサーリンク

[perl]ハッシュ(連想配列)のマージ

perlのハッシュ(連想配列)のマージについてちょっと調べました。自分用のメモとして記録しておきます。

一番直観的な方法は以下のようなコードでしょう。

%hash = (%hash, %addition);

ハッシュ %hash に対して、%addition の内容を追加します。

my %hash = (
  'key1' => 'value1',
  'key2' => 'value2',
);
my %addition = (
  'key3' => 'value3',
  'key4' => 'value4',
  'key1' => 'override1',
);
%hash = (%hash, %addition);

上述のようなコードを実行すると、%hash の内容は以下のようになります。

  'key1' => 'override1',
  'key2' => 'value2',
  'key3' => 'value3',
  'key4' => 'value4',

key1 の内容が上書きされているのがポイント。

whileforeach でループを回してハッシュをマージする方法も利用できます。

whileeach を組み合わせると、以下のようなコードになります。

while (my($key,$val) = each (%addition))
{
  $hash{$key} = $val;
}

foreachkeys を組み合わせて、以下のような方法でもマージできます。

foreach my $key (keys %addition)
{
  $hash{$key} = $addition{$key};
}

同様の操作は map を使っても可能です。

map { $hash{$_} = $addition{$_} } keys %addition;

最後にスライスを使う方法もあります。スライスを使い慣れた人には、ぱっと書けると思うのですが、私にはすぐには書けませんでした。

@hash { keys %addition } = values %addition;

%hash ではなく、@hash と記述します。

ハッシュのリファレンスを利用した場合も同様に記述できます。

# normal merge
$hash = {%{$hash}, %addition};
# use while
while (my($key,$val) = each (%addition))
{
  $hash->{$key} = $val;
}
# use foreach
foreach my $key (keys %addition)
{
  $hash->{$key} = $addition{$key};
}
# use map
map { $hash->{$_} = $addition{$_} } keys %addition;
# use slice
@{$hash} { keys %addition } = values %addition;

速度がどの程度違うのか、調べてみました。

利用したコードは「続き」に記載しています。

foreach:  4 wallclock secs ( 4.17 usr +  0.00 sys =  4.17 CPU) @ 119904.08/s (n=500000)
    map:  5 wallclock secs ( 3.96 usr +  0.00 sys =  3.96 CPU) @ 126262.63/s (n=500000)
  merge:  7 wallclock secs ( 6.66 usr +  0.01 sys =  6.67 CPU) @ 74962.52/s (n=500000)
  slice:  5 wallclock secs ( 4.32 usr +  0.01 sys =  4.33 CPU) @ 115473.44/s (n=500000)
  while:  5 wallclock secs ( 4.35 usr +  0.01 sys =  4.36 CPU) @ 114678.90/s (n=500000)

使うなら、map でしょうか。

スライスを利用した方法も、マージするハッシュの内容によって速くなる場合がありましたが、具体的な条件が分かりませんでした。

従って、手元の簡単な調査では map によるマージが比較的安定した結果を出すという印象です。

続きを読む

スポンサーリンク

9/13