02 | 2008/03 |  04

  1. 無料サーバー

User forum-FC2BLOG-Info-Edit Template-Post-Edit-Upload-LogOut

CSSやJavascript自習の苦闘史を綴っていきたい。恐縮ですがJavascriptを有効にしてご覧ください。
2005年12月から社会問題も掲載!


フレッツの場合において、OS起動時にPPPoE接続でインターネットに自動接続するための要点

1. 広帯域接続の作成

これについては例えば次のようなプロバイダサイトの絵入りマニュアルが分かりやすい。

しかしながら、これらのプロバイダサイトのマニュアルでは、アプリケーションソフト起動時にインターネットに自動接続する方法について触れているものの ( 正確に言えば nifty サイトのマニュアルではその点は全く触れられていない。何とブラウザやメールソフトなどのアプリケーションを利用する時に、手動でネットに接続することを前提としたマニュアルとなっている。)、OS 起動時にインターネットに自動接続する方法については、全く触れていない。

インターネット常時接続時代においては、パソコン起動=インターネット接続が当たり前であり、本来、そのような使い方を想定したマニュアルにすべきだ。

▲ToTop

2. OS起動時にインターネットに自動接続するようにする設定

ブラウザもメーラーもいずれも起動していなくても OS が起動したら自動的にインターネットに接続するようにしてこそ、常時接続の意味があるというもの。例えばOS起動直後にまず Internet radio からの音楽を楽しみたい、という使い方もあるので、インターネット接続を OS 起動時に自動的に行うことが好ましいのだ。

まず、フレッツ接続ツールを使う場合の方法については、 NTT西日本 | フレッツ | よくあるご質問 に、画像はないが言葉だけによる説明がある。

一方、PPPoE接続の場合における同様のマニュアルはプロバイダサイトでは適当なものが見あたらない。

あったとしてもインターネットエクスプローラや OutlookEdxpress 起動時に自動接続するマニュアルであって、OS 起動時の自動接続に関するものではない。

作成した接続のプロパティ - オプションにおいて、「名前、パスワード、証明書などの入力を求める」のチェックを外すことが重要なポイントなろう。

上の設定だけでも自動接続にはならないが、上の設定を終えた後に Windows を起動すれば起動時に接続ダイアログが表示されるので、その中の「自動接続する」のチェックボックスをその段階で on にすれば、それ以降の Windows 起動時にはインターネットに自動接続される。

こうして、フレッツ光サービスによるインターネット接続を利用している場合において、Windows起動時に自動的にインターネットに接続出来るようになる。

▲ToTop

PPPoE接続に影響する Windows Service

次の4つのサービスがPPPoE接続に関わる決定的な影響をしっかり踏まえておく必要がある。

  1. Telephony……説明には「テレフォニー デバイスと IP ベース音声接続を制御するテレフォニー API (TAPI) を供給します。ローカル コンピュータと同様、このサービスを実行しているサーバーを LAN をとおして制御できます。」とある。要はダイアルアップ接続( PPPoE接続はこれに該当する )を使用するには、このサービスが開始されていなければならない。
  2. Remote Access Connection Manager……説明に「ネットワーク接続を作成します。」とあるように、これが「開始」状態になっていないと、新しい接続を作成することが出来ない。なおこのサービスはTelephonyサービスに依存しているので、Telephonyサービスが開始されていなければならない。
  3. Remote Access Auto Connection Manager……説明には「プログラムがリモート DNS、NetBIOS 名または NetBIOS アドレスを参照するときに必ず、リモート ネットワークへの接続を作成します。」とある。不要なサービスを停止する -[Di]によれば、「IE以外のソフトから自動的にダイアルアップ接続をするものなので、ダイアルアップの人は手動」に設定する必要があるようだ。Remote Access Connection ManagerとTelephonyに依存している。
    しかし、browser起動時にネットに接続するのではなくOS起動後に自動的にネットに接続する用に設定した場合にはこのサービスは不要となるはずだ。
  4. Remote Procedure Call(RPC)……説明には「エンド ポイント マッパーや各種の RPC サービスを提供します。」とある。エンド ポイント マッパーなんて何の事やらさっぱり分からないが、ASCII24 - アスキー デジタル用語辞典 - RPCによれば、RPCとは「ネットワーク上の異なるマシンで処理を実行する手続き。あるいはそのプロトコル。分散コンピューティング環境の基盤となる技術」とある。
    そしていくつかのサイトを覗いてみた限り、このサービスは有効にしておいた方が賢明なようである。

またしてもログイン出来ない状態が出現! Fc2さんこれでは困ります!

3月30日午後12時前のこと

新記事を投稿しようとしたところ、「込みいっています。しばらくしてから改めて・・・」とのメッセージが表示され、新規投稿も過去記事の編集も出来ない状態となりました。

数日前の深夜(22~24時の時間帯)にも同様の現象が発生したのですが、まさか日曜日の真っ昼間にログイン出来ないほどにサーバーが混雑しているとは吃驚です。

余程アクセスの多いサイトがあるためなのか、別の原因があるのか分かりませんが、まるで繋がらないテレホンテクニカルサポートのような現象が、連続して出現していることに、驚くと共に、幻滅しています。

このようなことが頻発するのであれば、別のブログサービスに乗り換えることも視野に入れた対策を検討せざるを得なくなります。

最も自由度が高く、つまりユーザビリティの高いブログサービスとして、気に入っているのですが、今回のようにログインしたい時に出来ない状態が繰り返されると、サービスの基本的な要件として失格です。

何とかして欲しいものです!

ウィルスチェックソフトがおかしくなってしまった!

Internet Security 2007 が突如としておかしくなってしまった

数日前からエラーが出ていたが、昨晩遅くになってついに LiveUpdate が事実上出来なくなってしまった。

流石にウィルスチェックソフトなしでネットを徘徊する訳にも行かないので、 Internet Security 2007 が推奨する作業を進めてみた。そして何の気なしに行った作業によって何とInstallされているInternet Security 2007 が全て削除されてしまったのである。

作業を開始してから、あれおかしい、もしや削除行為が進行しているのではないか、と懸念し、驚愕し、焦燥した時には既に遅かった。完璧にそれは削除されてしまったのである。

1年以上前にそれを購入した時にダウンロードしたファイルのバックアップは取ってなかったので、改めてダウンロードしようとしたが60日を経過するとダウンロード出来ない旨の、御宣託がSymantecサイトに書いてある。

ということは折角パターンファイルの更新を有料で期間延長したばかりだというのに、2008を買うしかないのか?!?!?!───そんな馬鹿な!

▲ToTop

Symantec社の対応には納得がいかない

期限切れになる15日程前にメールで自動更新するかどうか問い合わせるメールが来た。正確に言えば来ていた。気がつかなかったのだ。

そして10日程すると何と 5000 円以上の課金をされて自動更新されてしまったのである。

最新バージョンを購入しようか、と思っていた矢先に一遍のメール通知だけで強引に自動更新してしまうなんて、あまりにも殿様商売ではないか!

そもそも以前から、Symantec社の対応には怒りを感じていた。一言で言えば不親切極まりないのである。2008について日経パソコンでは如何にメモリを食わないか、起動が速いかを得々と宣伝しているが、裏返せば2007まではメモリを大量に消費し、起動も遅かったと自白しているようなものだ。

ホームページも極めて分かりにくいし、エラーがあった時の詳細情報は、正直なところ、その内容を理解出来るユーザーがどれ程いると思っているのか、根本的に抗議したいほど難解である。

・・・とSymantec 社への怒りを綴っていると際限がないので、ここで主題に戻ろう。

▲ToTop

自動更新したばかりなのに2008を買うなんてあり得ない!

意地でも買いたくない。本来ならばセキュリティソフトの乗り換えを検討していたのだから。

しかし、ではどうすればよいのか?

Internet Security 2007 は削除してしまったし、ダウンロードしたファイルはコピーを取っておかなかった。つまりこのままでは Internet Security 2007 を再インストールすることは不可能であり、追加購入するしかないのか?!

否否!!断じて否!

こんな時のためにもまた、イメージバックアップが生きてくるのだった。

半年前にバックアップしておいたC:ドライブを復元し、その後必要なUpdateを繰り返せば、Internet Security 2007 が生き返るのではないか?!

そしてそれは成功した!イメージバックアップ様々なのだ

数時間を要したが、Microsoft Update と Internet Security 2007 のパターンファイル Update を無事終えることが出来、今こうしてネットに接続したパソコンに向かって文章を綴り、メールチェックを行い、サイトサーフィンも普段通り行っている。

イメージバックアップをしてあったお陰で、故障する前の時点の正常に作動していたInternet Security 2007 を復元し利用することが出来たのである。

感謝 イメージバックアップ!

blog1serverが混雑でアクセスできないのは迷惑なことである!

 ここ数日午後10時から11時の間、殆どアクセスできない状況が続いている。blog1へのAccessが集中しているらしいのだ。
 これはおそらくblog1サーバー内に人気の高いブログがあって、そこへのAccessが集中するために発生する現象だと思われるが、迷惑千万な話である。

 そうしたAccessが集中するブログが有る場合には、何らかの対応をFc2で取ってくれないと、他のユーザーが迷惑してしまう訳で、善処を強く希望したい。

Ajax通信による最新/以前/以後の合計30個のエントリイタイトル情報の取得について

このエントリイの改訂履歴
  • 初稿:2008/3/23
  • 大幅な追記(連続するAjax通信の結果をどのようにして過不足なく取得するのかについて):2008/7/13
3/23 の記事

jQuery を活用した Ajax 通信にここ半年ほどのめり込んできました。

しかしアクセスログを見てみると、Ajaxに関するエントリイは余りアクセスが有りません。つまり関心を呼んでいないのです。

jQuery + Ajax の組み合わせは決して一般的ではないし、Javascripter にとってさえもメジャーな話題ではないのかもしれません。つまり、jQuery の Ajax ユーティリティを利用する行為自体が極めてマニアックなのかも知れません。だからアクセスも少ないのでしょう。

決して見られるために書いている訳ではないので、アクセス数に一喜一憂している訳ではありません。それはある意味では二の次であって、書きたいことを書き綴ることに意味があります。一般的な話題ではなく寧ろ deep な話題と言えますから、その意味では閲覧される確率は決して高い筈はないと思います。

それでも尚、読まれているかどうかは気になります。

反応は皆無に近く(あるのは迷惑千万なエロイ書き込みばかりです。(;_;)ウルウル)

最近は、無言の黒い壁に向かって全く自己満足で書き続けている気がしています。

それもこの国の Blog の1つの有り様ですから、致し方ないことなのですが...

▲ToTop

jQuery や Ajax を話題とするサイトや SNS を見つけたい

どうせ書くならば、共通の話題に関心のある方々に読んで貰いたい、あるいは情報交換をしたい、と願っています。

こう書いたからと言ってアクセスが増えたり、また情報交換が可能となるなんて思っていませんが、それでも尚書き綴りたい今日この頃なのです。


以後は 7/13 の記事

連続するAjax通信結果を過不足なく取得する具体的な方法

以下の関連エントリイに共通する「 連続する Ajax 通信からの結果取得方法 」について、ここでまとめておきます。

つづく

Google Page 利用雑感

突然の未知との遭遇

ファイル置き場で色々検索を掛けている中で、GooglePage を利用しているサイトを偶々、本当に偶然に見つけました。「ナンジャこりゃ?」とグーグって見ると、WYSWYG な Homepage 作成を提供している無料サービスであることが判明し、早速ファイル置き場としてこれを活用するために登録し、そして活用したのでした。

ファイル置き場としての性能を考慮する時、それが Google Code と決定的に異なるメリットは upload したファイルの上書きが可能であることです。

これは Google Code を使えば分かることですが、上書きが出来ない、少なくとも直ぐに反映されないことは大変使いにくいものです。結局、同名の version 番号を付けたファイルを沢山 upload する羽目になってしまうからです。

その点 Google Page は曲がりなりにもホームページ形式のウェブサイトですから、uploadしたファイルの上書きは当然可能であり、むしろ当たり前のことです。

その使い勝手

WYSWYG な Homepage 作成サイトですから、当然簡単に Homepage が作れてしまいます。それをブログとして活用することも、英語を native とする人間ならば簡単かも知れません。作成されるソースファイルを見ると「なんじゃこりゃ?」と驚くほどのコードの羅列なので、HTMLファイルを編集するという感じの使い方は出来ないとは思いますが、ファイル置き場として使うのですから、決して複雑なレイアウトを行う訳でもないし、むしろ単にファイルが置けて、別サイトから自由にリンクを貼れれば良い訳ですから、複雑なレイアウトは不必要です。

その意味では、GooglePage はファイル置き場として最適と言えるでしょう。そのファイルが写真や動画の場合には決してベストの選択肢ではないでしょうが、HTML、Javascript、CSS などのコードファイルである限り、その利用の便さえ問題がなければ(事実今のところ問題は皆無です)、最高の無料 Homepage サービスと言えるでしょう。

▲ToTop

iDrive が悪いのではないかも──Internet Security が停止してしまった!

関連エントリイ一覧 in this Blog

このEntryを書いてから数日後に起こった Internet Security 2007 のエラーから推測すると、以下に書いたことは憶測であり、そもそもの原因は iDrive にはないかも知れません。

よって以下の文章は全面的に取り消すこととします。

1つのファイル置き場である iDrive の利用をやめる!

無料オンラインストレージサービス iDrive を利用するには、固有のアプリケーションをローカル PC にインストールしなければなりません。

さて、必要なインストールを行って何日か経過したある日のことです。

メールが全く受信出来なくなってしまい、その原因を究明している中で、ウィルスソフトが起動してないこと、そのためにメール受信も出来なくなっていることに気がつきました。そのことが判明するまでに数時間が経過しましたから、その間にウィルスに感染したのではないか、とビビリながら、同時に早急に復旧しなければならない深刻な事態となっていることに驚きを覚えました。

いつからこんな状況になってしまったのか、そういえば昨晩もメールが受信できなかったような...、と記憶の糸を辿ったのですが、それ以前はどうであったか思い出せません。

しかし兎にも角にも Anti Virus が動いていないのですから、一刻も早くこれを有効にしないといけません。Web 頁を開くだけでも感染するサイトもある訳ですから、当然焦りました。早速 Norton Protection Center を起動して警告が出ている箇所をクリックし、必要な修復を施しました。 Live Update を繰り返すだけでしたが、その後再起動したところエラーは消え、メールも受信出来るようになりました。

▲ToTop

iDrive を操作するとまたしても Norton Protection Center にエラーが...

iDrive 関連アプリケーションをインストールすると、デフォルトでスタートアップフォルダに登録されるようで、パソコンを起動すると関連アプリが起動しログインを求めます。それをキャンセルすると Norton Protection Center にエラーが出てしまうのです。

つまり iDrive が Norton Protection Center と干渉し合っているようなのです。

そこで大して使っていない iDrive をアンインストールし、その後 LiveUpdate を繰り返してやっと AntiVirus を走らせると共にメール受信を可能としました。

iDrive は使用しない方が無難でしょう!

Microsoft's Windows Live SkyDrive を使ってみる

関連エントリイ一覧 in this Blog

それはブックマークレット作成に関わって始まった

よく知られているようにブックマークレットには文字数制限があります。IE では 508 文字、Firefox では2000 文字などです。それはある意味では当然の措置です。アンカータグ内に際限もなく長い Javascript コードを書くことを認めてしまえば、リンク機能を使った「悪さ」を許容することになるのかもしれません。それにしてもIEの508文字は余りに短すぎますが...。

さて、ブックマークレットを使えば任意のサイトにおいて、 Javascript や CSS ファイルをインクルード出来ますが、そのためにはそれらのファイルを置く場所が必要です。いわゆるオンラインストレージが必要になります。

ファイル置き場、又はオンラインストレージサービス(OLSS)概観

オンラインストレージに関しては、「オンラインストレージを使ってみよう(2001/4/23)」 に詳述されています。

impressのこの頁が書かれた年月日に注目すれば分かることですが、ファイル置き場は2000年頃には一世を風靡していました。競うように次々とサービスが提供されていたらしいのです。しかし理由は分かりませんが、現在は当時に比べれば下火となっているようです。

しかし、上記ページが書かれた後にも、Google が G Mail Drive を始め、最近ではネット業界の流れに乗り遅れまいと、破格の買収価格を提示して Yahoo 買収に奔走している、あの Microsoft 社が Windows Live SkyDrive という長い名前のオンラインストレージサービスをこの2月22日から38カ国で開始しました。

更に、Google は容量無制限の OLSS を開発中との報道もあります。

こんなことから、改めて OLSS に注目が集まりつつある、と言えるでしょう。

OLSS は殆どログイン制を採用しているが...

さて、日本の OLSS では、ジャストシステム社のインターネットディスクが老舗とも言える位置を占め、SONY の WebPocket がそれを追いかけているように思われます。ここで注目すべきことはこれらのOLSSが共にログインして使用する、原始的な利用形態を採用していることです。専用ソフトを利用してファイルを操作することも共通しています。

そして別のエントリイで書いたとおり、これらの2社の OLSS は外部からのリンクを認めていません。不特定多数のアクセスを排除しているのです。つまりこれらのOLSSは、特定の個人や組織によって利用するあくまでも閉じられたファイル置き場に過ぎません。

一方、G Mail Drive では特にログインを意識せずに利用出来るものの、これは既に Gmail アカウントによるログインが済んでいる状態で利用するからログインを意識しなくて済むのであって、基本的にはログインが必要な閉じたファイル置き場であることに替わりはありません。オンラインで使える自分の、自分だけのハードディスク装置と言えます。

これらに対して Windows Live SkyDrive の場合、HTMLマークアップによるブログ等への埋め込み機能があります。これを利用すれば、skyDrive の公開フォルダに置いたファイルへのリンクを任意のブログ内に貼ることが可能となります。つまりファイル置き場として利用できるはずです。

まず単純なファイル埋め込みを試してみます。下の setjQnFbug-WL.js をクリックするとその下の図のようなサイトが開かれ、当該ファイルをダウンロードする画面となります。つまり SkyDrive は誰でもアクセスできるファイル置き場として利用できる訳です。

SkyDriveTest結果図

不特定多数の人によるファイルダウンロードが可能ならば次に、ブックマークレットによるファイル操作も可能なのではないか、と考え、ここではこの一ヶ月間追求してきた、Ajax通信によってFc2ブログのエントリイタイトルを取得するブックマークレットが、 SkyDrive 上のファイルを呼び出した場合に動作するかどうか試してみました。

fc2BlogのエントリイタイトルをAjax通信で取得表示するブックマークレット

そしてそれは駄目でした!

JSファイルのインクルードまでは出来るのですが、肝心のインクルードしたファイルを読み込むことが出来ないようなのです。また何故か CSS ファイルはインクルード出来ませんでした。

SkyDriveもまた ブックマークレットのためのファイル置き場には使えませんでした

ということがこのエントリイの結論です。

Google Code を利用した感想

Google Code は簡単に利用できるファイル置き場としてGood!

Google Code は1プロジェクト当たり 100MB のディスクスペースが提供され、1ユーザー当たりのプロジェクト件数制限は見あたりませんので、実質無制限なファイル置き場として活用できます。

与えられる URI はプロジェクト名から始まるので分かりやすく、upload、download 操作も簡単にできます。

英語の説明書きしかありませんが、特に難しいことが書いてある訳でもないので、何度か使えば操作も難しくありません。

多くのディスクスペースが id やパスワード入力を求め、ファイル置き場としての利用に大きな制限を掛けている中で、Google Code の存在は貴重なものです。

ファイル上書き操作に難点が...

以前次のように書きました。

Google Code では登録済みファイルの上書き更新が出来ません。間違って登録してもそれを取り消せないのです。説明を読むと削除に同一名による新規ファイル登録が可能なように書いてあるのですが、何度試しても駄目でした。

この上書き禁止ルールは、際限なく登録されるファイル置き場として悪用されないための、1つの防護策なのかも知れません。

上に書いたことは正確ではありませんでした。

上書きは基本的に可能で、そのことは説明通りでした。注意すべきことは上書き変更が即座に反映されないことです。

上書きしてもその変更結果を直ぐに確認できないのです。しかし一定の時間(それが何時間なのか、何日なのかは不明)が経過すると、確かに変更が反映されます。

つまり、頻繁にファイル更新を行う行為は認めないが、ファイルの上書きは認める。頻繁な更新を抑制するために、更新にタイムラグを設け、出来るだけ更新を行わないようにさせる───という設計思想だと考えられます。

以上の特性を踏まえて利用すれば、大変貴重で有益な無料サービスだと思われます。

また、Systems engineer の間では Google Code Search が注目されているようで、Google Code でネット検索しても search のことばかりが表示されます。

▲ToTop

Javascript コードおよびCSSファイル説明

ファイル構成

ファイル置き場と Ajax 通信を活用して、任意のFc2ブログから情報を得る

  • 2008/3/12 : 初稿
  • 2008/7/9 : コードの抜本改訂とファイル置き場利用版up
  • 2008/7/12 : Ajax 通信関連部分を更に抜本改正
  • 2008/7/20 : Ajax 通信関連部分で確実性を更に向上(ここで Ajax 関連コードは完成し、これ以降はあれこれのユーザビリティの向上対策を施した。)
  • 2008/7/21 : id 及び class 名称を他の Fc2 ブログで使われていないと推定される固有のものに変更
  • 2008/8/12 : 各 Ajax 通信所要時間を記録し閲覧できるように変更。このプロジェクトの削除(関連cssファイルやjsファイルの登録削除)と隠蔽(単にpopup小窓を隠すだけ)を分け、各ボタンを配置。
  • 2008/8/14 : responseText の 文字化け対策として、或る <meta/> タグを追加するように変更

他ブログ上での Ajax 通信をついに実現( 2008/7/9 記 )

上の関連エントリイでつらつらと述べてきた課題──すなわち他の任意のFc2ブログサイト上において、ブックマークレットによって必要なスクリプトをインクルードし、当該スクリプトによる Ajax 通信によって当該ブログの情報を取得し、それを当該ブログ上に表示する──が、やっと解決しました。( 8/12 完結 )

上記 「 Related Entries in this Blog 」 の No1エントリイで計画したことが、No.2 エントリイで述べた、過去/未来/最新エントリイタイトル取得/表示を行う Ajax 通信の成功と、No.3 とNo.4 エントリイで述べたファイル置き場問題の解決によって実現したのです。

何はさておき、結果を画像で紹介することが最も分かりやすいでしょう。( 2008/8/14 追記 )

サンプル 1【 Fc2総合インフォメーションブログ 】

下の画像は、Fc2総合インフォメーションブログ上でこのプロジェクトを実行した際の表示結果抜粋です。

Fc2 総合インフォメーションブログ上で Ajax 通信によって最新/以前/以後エントリイのタイトル情報などを取得した結果を示すサンプル画像 1
サンプル 2【 関西ZIGZAG 】

下の画像は、人気ブログ「 関西 ZIGAZAG 」ブログ上でこのプロジェクトを実行した際の表示結果の抜粋です。

関西 ZIGAZAG ブログ上で Ajax 通信によって最新/以前/以後エントリイのタイトル情報などを取得した結果を示すサンプル画像 2
サンプル 3【 FCafe 】

下の画像は、自ブログ開設時からお世話になってきたサイト上でこのプロジェクトを実行した際の表示結果の抜粋を示すものです。

FCafe ブログ上で Ajax 通信によって最新/以前/以後エントリイのタイトル情報などを取得した結果を示すサンプル画像 3

今回のプロジェクト「Fc2ブログ エントリイ情報取得」の概要

今回作成したコード群は、任意の Fc2 ブログ上で jQuery を活用してエントリイタイトル等を取得するツールです。また併せて jQuery.js と ( Firefox 以外の browser の場合には )firebugLite もインクルードするようにしたので、IE や Opera などにおいても jQuery と firebugLite を使用し、スクリプトテストや DOM 操作を行うことも可能としました。

つまり、或る Fc2 ブログサイトの、或る個別エントリイ頁を開いた状態でブックマークを起動すれば、以前、最新及び以後の各 10 個のエントリイに係る諸情報(具体的にはタイトル、Entry番号、投稿日など)が閲覧できると共に、そのページ上で jQuery.js と firebugLite.js を使って Javascript コードの実行が出来るわけです。

プロジェクトのファイル構成( 2008/7/9 記 )

コード群はブックマークレットを含めて以下の6つから構成されます。

  1. ブックマークレット……次の setjQnFbug_getFc2EnTts.js を登録するため
  2. スクリプト登録用JSファイル( setjQnFbug_getFc2EnTts.js )……今回のプロジェクト実行に必要な以下の 4 つの全てのファイルを、今閲覧中の任意の Fc2 サイトのHTML文のヘッダー部に登録するための、短い Javascript コードファイル
  3. 上の 2. のファイルで登録するファイルは以下の 4 つです。
    1. jQuery.js、
    2. firebug.js、
    3. getFc2EntryTitles-gp.js( Ajax 通信用オリジナルJSファイル)
    4. getFc2EntryTitles-gp.css(通信結果表示用オリジナルスタイルシート……Ajax通信結果を固有に用意した絶対配置要素内で表示させるために、各ブログに依存しない固有のスタイルシートを用意)

ここに、このプロジェクトでは Ajax 通信処理をはじめとして、随所に jQuery.js を多用したコードを記述し実行しているため、jQuery.js が組み込まれていないブログの場合も想定し(大多数は組み込まれていないと思われる)、なければそれをインクルードするようにしました。

また firebugLite も組み込むようにしたので、IE や Opera 上でも Javascript のテストが容易に出来るようにしました。

以上により、Fc2のブログであれば何であれ、個別エントリイ表示モードの場合において、jQuery を活用して Ajax 通信を行い、エントリイタイトル情報を取得すると共に、firebugLite を使った Javascript の走行テストが出来るようにしました。

▲ToTop

ファイル置き場は Google Page を活用( 2008/7/9 記 )

ファイル置き場に出来るかも知れない、と考えた Just Sysytem 社のインターネットディスクは、同社への問い合わせの結果、使えないことが判明しました。また SONY の WebPocket にも問い合わせましたが、こちらも駄目でした。

有料なのに、それでもなお、ファイル置き場を認めない理由は全く理解できません。

確かに「 アクセスが集中する、ウィルスファイルを置かれる可能性も否定できないから踏み台とされる、つまりサービスの利用よりも悪用に手を貸すことになる 」等の否定的な側面が懸念されます。そしてこの懸念から解放されるためには、ファイル置き場を認めないことが安易な方法なのでしょう。

───と、いくら批判し、嘆いていても仕方ないので、調べた中で、無料で容易にファイル置き場として利用できる Google Page ウェブサイトを活用することにしました。Google page 上にマイページを立ち上げ、そこに上記 6 つのファイルの内ブックマークレットを除く 5 つのファイルを GooglePage サイトに upload し、自作ブックマークレットを作動させてその稼働を半年以上に渡って確認しています。

※ この少し下に成功したブックマークレットを置きました。

このプロジェクトの利用方法( 2008/3/12 記 )

ブックマークレット

以下のブックマークレットを(ブックマーク又はお気に入りに登録し)クリックすれば、関連する JS ファイルや CSS ファイルが head タグ内に追加され、固有の絶対配置要素が画面上部に表示されます。FireFox 、 Opera 及び IE7 で動作確認済みです。

後は Before・・・、Recent・・・、After・・・ などのボタンをクリックすれば、所定の情報が絶対配置要素内に表示されます。

Ajax 通信をやり直すボタン( ReLoad Data ボタン )や、Ajax 通信に要した時間を知ることが出来るような Log 閲覧ボタンも設置しました。また、結果を表示する小窓が邪魔になったら、隠蔽することも出来るし、ブックマークレットによってインクルードした関連スクリプト・cssファイルを削除するボタンも設置しました(但し jQuery.js と firebug.js は残すようにしました)。

こうして、Ajax通信結果を示す小窓が邪魔になったら隠蔽し、ブックマークレットを再起動すれば、隠蔽直前の状態で小窓が復帰するようにすると共に(Ajax 通信結果は閲覧中の頁がリロードされない限りメモリ上に残る仕様としたのです)、インクルードファイルが邪魔になったら簡単に剥離・削除出来る仕様にしました。

次のブックマークレットをお気に入りに登録すれば、今回のプロジェクトを任意の Fc2 ブログサイトで共通して使うことが出来ます。また、単に以下のブックマークレットをクリックするだけでも、今ご覧戴いているこのエントリイを対象としてブックマークレットを利用できます。

このプロジェクトの起点となるブックマークレット

※ 2008/8/11迄上記ブックマークレットのコードに一部ミスがあり機能しませんでした。利用しようとしてくださった方々には大変ご迷惑をお掛けいたしました。

Ajax 通信結果の表示

ブックマークレットをクリックすると、次のような小窓がブラウザの上部に表示されます。

Ajax 通信結果を表示する絶対配置要素の図

上の図は既に Ajax 通信が終わった状態の画像ですが、7つのボタンは左から順に「(1)今見ているエントリイの前の10個のエントリイタイトル表示、(2)最新の10エントリイ表示、(3)今見ているエントリイの後に投稿された10エントリイのタイトル表示、(4)Ajax通信再実施、(5)所要時間表示閲覧、(6)小窓の隠蔽、(7)関連スクリプトやcssファイルの削除」を行うためのものです。

例えば 「 Recent Entries 」 ボタンをクリックすると下図のようにタイトル名とエントリイナンバーが表示されます。Ajax 通信をやり直すことができるように設けた 「 Relaod Data 」 ボタンは、何らかの事情で取得結果がおかしかった場合などに Ajax 通信をやり直すことが出来るように配置したものです。このボタンをクリックすれば Ajax 通信に要した時間を比較して知ることも出来ます。

Ajax 通信結果である過去エントリイ10タイトルを見ている図
表示エントリイ上で jQuery と Firebug Liteを活用!

単に、エントリイタイトルを閲覧するだけでなく、このプロジェクトでは jQuery.js と FirebugLite もインクルードしますので、IE や Opera において、ちょっとした Javascript 利用が(デバッグ環境とまではいかないが、テストや学習に活用出来る)、エントリイ頁上でリアルタイムに行えるようになります。F12 キー又は CTRL+Shift+Lキーを押せば firebug Lite を起動することが出来ます。

▲ToTop

Javascript コードおよびCSSファイル説明( 2008/3/12 初稿:その後漸次改訂。確定は2008/8/14 )

1. スクリプトをインクルードするためのブックマークレット

ブックマークレットは各種のスクリプトや CSS ファイルをインクルードするための、いわば初期化スクリプトです。たった1つのスクリプトの存在をチェックし、存在していなければインクルードします。

そもそも全てのコードをブックマークレットに記述できればそれが最も合理的なのですが、ブックマークレットにはブラウザ毎に文字数制限があり、ここで行ったことはとてもその制限値内には収まらないので、複雑な手続きを経なければなりませんでした。

<a href="javascript:
(function(){
  // 文字数を減らすために変数を纏めて指定
  var%20x=0,i=0,
  h=document.getElementsByTagName('head')[0],
  t=document.getElementsByTagName('script'),
  s=document.createElement('script');
  // headタグ内を検索して
  if(t) for(;i<t.length;i++) 
    // setjQnFbug 文字の有無を走査し、有れば x に 1 を代入
    if(/setjQnFbug/.test(t[i].src)) x+=1;
    // setjQnFbug 文字が見つからなければ所定のjsファイルをインクルードする
    if(x==0){
      s.src='http://hkom007.googlepages.com/setjQnFbug_getFc2EnTts.js';
      s.type='text/javascript';
      // headタグ内にスクリプトタグを追加
      h.appendChild(s);
    // 既に所定のjsファイルがインクルード済みならば所定の関数(chkScript)を起動する。
    // この関数は3つのjsファイルと1つのCSSファイルのインクルードを行うためのもの
    }else%20chkScript();
})()">set jQuery & FirebugLite & getFc2EntryTitles.js</a>

▲ToTop

2. Javascript 及び css ファイルの一括インクルードを行う

setjQnFbug_getFc2EnTts.js は 4 つのファイルを一括してインクルードするコードだけを記述した 小さな JS ファイルです。といってもブックマークレットにするには文字数が多すぎてIEで読み込めないため、ブックマークレットとは別に設置した訳です。このファイル作成の当初段階では、インクルードするだけではなく、その後の処理も1つのファイルに纏めようとしましたが、それは無理でした。

何故ならば、インクルードのためのコードに続けて、インクルードされたファイルを使用して様々な処理を行うコードを書いて実行すると、インクルードが中断されてしまうからです。

ブラウザがファイルをインクルードする処理を行っている間に、JS インタープリタが次の処理を行おうとすると、インクルードそのものが中断されてしまうのです。

そのためインクルード専用のファイルと、インクルードされたファイルを利用して諸処理を実行するコードを記述したファイルとを別々に分けました。

// このスクリプトがインクルード済みの場合に関数が起動できるよう
// 名前付き関数とし、最後の行でこの関数を起動する。
var chkScript = function(){
  var v=0,w=0,x=0,y=0,z=0,i=0,
    h=document.getElementsByTagName('head')[0],
  m=document.getElementsByTagName('meta'),
    t=document.getElementsByTagName('script'),
    l=document.getElementsByTagName('link'),
    s=document.createElement('script');
  // 文字化け対策 
  // http-equiv="content-type" かつ content="application\/x-javascript charset=euc-jp"であるmetameguがあるかどうか走査
  // 存在すれば v 値を加算する。 
 if(m) for(;i<m.length; i++){
  if(/content-type/.test(m[i].getAttribute("http-equiv"))
   && /application\/x-javascript charset=euc-jp/.test(m[i].content)) v+=1;
 }
  // v 値がゼロならば meta タグを追加する。 
 if (!v){ 
  var k=document.createElement('meta');
  k.setAttribute("http-equiv","content-type");
  k.content = "application/x-javascript charset=euc-jp";
  h.appendChild(k);
 }
  // 所定のスタイルシートがインクルード済みかどうか link タグ走査し、あれば記録。
 if(l) for(i=0 ;i<l.length; i++) {if(/getFc2EntryTitles/.test(l[i].href)) w+=1}
  // CSSファイルのインクルード
 if(!w) {
  var k = document.createElement('link');
  k.rel = "stylesheet";
  k.type = "text/css";
  k.media = "screen, print";
  k.href='http://hkom007.googlepages.com/getFc2EntryTitles-gp.css';
  h.appendChild(k);
 }
  // jquery、firebug 及び getFc2EntryTitles の文字を含むスクリプトタグを走査し、
  // 存在していればそのことを記録する。
 if(t) for(i=0;i<t.length;i++){
  if(/jquery[^u][^i]+/.test(t[i].src)) x+=1;
  if(/firebug/.test(t[i].src)) y+=1;
  if(/getFc2EntryTitles/.test(t[i].src)) {
      // ブックマークレットが複数回起動された場合の処理
      // インクルード済みで結果表示小窓が非表示ならば表示する
      var tmp = document.getElementById("ajaxPopup");
      if (tmp && tmp.style.display == "none") tmp.style.display="block";
    } // 結果表示小窓が表示済みならば、何もしないでif文を終える。
 }
  // 以降で反復利用する文字列を定義
 s.type='text/javascript';
  // jQuery.js のインクルード
  // jQuery.js は単に firebug Lite から利用するだけではなく、Ajax通信や
  // その取得結果を表示するコードで多用します。
  // なお、min 版を利用することにしました。
 if (!x){
  s.src='http://hkom007.googlepages.com/jquery126min-gp.js';
  h.appendChild(s);
 }
  // firebugLite のインクルード
 if(!/firefox/.test(navigator.userAgent.toLowerCase()) && y==0){
  var c=document.createElement('script');
  c.src='http://hkom007.googlepages.com/firebug-gp.js';
  c.type=s.type;
  h.appendChild(c)
 }
  // Ajax 通信を行う本体コードの getFc2EntryTitles.js のインクルード
 if (!z){
  var r=document.createElement('script');
  r.type=s.type;
  r.src='http://hkom007.googlepages.com/getFc2EntryTitles-gp.js';
  h.appendChild(r);
 }
  // 無名関数としなかったのは再呼び出しがあり得るからです。
};chkScript(); //関数実行

▲ToTop

3. 結果を表示する小窓用 CSS ファイル

取得結果を絶対配置要素内に表示させるために、CSS ファイルを作成しました。これによりどんな Fc2 ブログであっても Ajax 通信結果を同様に表示するようにしました。

なお、任意のFc2ブログで活用できるようにするには、id や class の名称に工夫が必要であることを、いくつかのサイトで試してみて納得しました。このプロジェクトで利用する名称が、閲覧しているブログサイト内で利用されてる名称と重複してしまってはいけない、ということです。

このことは振り返れば余りに当たり前のことですが、実行して初めて分かった次第です(^_^;)。

経緯はこうでした。( 2008/7/21 追記 )

FC2総合インフォメーション 【ブログ】画像ファイル挿入の仕様変更のお知らせ でこのプロジェクトを試してみたのですが、その際に当該サイトで使用されている id 名称( #menuBlock )が、このプロジェクトで利用していた id 名称と重複していたため、当該サイトでは予想外の挙動が起きてしまいました。

そこで初めて、任意の Fc2 サイトと id や class 名称が干渉しないよう、このプロジェクトでは他には絶対に存在しないであろう、固有の名称を使用しなければならない、と気がついた訳です。

こうして id 及び class 名称は以下にあるように長たらしいものとなりました。全ての id 及び class 名称に、「 getEntryTitles_ 」なる接頭語を付けたのです。これで「おそらく」世界で唯一の名称になったのではないか、と一人合点しています。

更に CSS ファイルでは重要なことがあります。( 2008/8/17 追記 )

それは自分のブログで様々な CSS コードを書いている限り全く問題とはならなかったことであり、他のサイト上で自分が書いた CSS ファイルを適用する際には、必ず注意しなければならない問題です。

その問題とは CSS ファイルの優先順位です。

ブラウザにはそれぞれ固有のスタイル値があり、また当然のことですがそれぞれのブログには、作者固有の、またはテンプレート固有のスタイル値があります。そして私が考え、CSSファイルで表現したスタイル値があります。これらの優先順位についてこれまで全く考慮する必要がなかったのですが、他の方のブログ上で MyCSS ファイルを適用することになった時点で、即座にこの CSS ファイルの優先順位が切実な課題となってきたのです。

そこで数年ぶりに改めて CSS の学習を思い起こし、また一部再学習して !important 属性を使うことに到達しました。

@charset "euc-jp";
	#getEntryTitles_pasteData ul { /* important によって任意の Fc2ブログにおいて同一の */
		margin:0 0 0.5em 1.5em !important; /* 結果を得るようにした。*/
		padding:0 !important; /* ここに到達するまでに結構悩んでしまった。*/
		clear:both !important;
	}
	#getEntryTitles_pasteData ul li{
		margin:0 !important;
		padding:0 !important;
	}
	#getEntryTitles_ajaxPopup{
		position:absolute; z-index:100000; top:150px;left:50%;
		width:0; height:0; margin:0px;
		font-size:small;
		text-align:left;
		color:black;
		display:none;
	}
	#getEntryTitles_menuBlock {
		padding:10px;
		width:0px; height:0px;	/*not auto*/
		background-color:#def;
		border:2px #777 solid;
		display:none;
	}
	#getEntryTitles_loading {
		clear:both;
		padding:5px 10px;
	}
	#getEntryTitles_pasteData {
		clear:both;
		margin-top:-28px;
		display:none;
	}
	#getEntryTitles_pasteData a:link{color:blue; text-decoration: none;}
	#getEntryTitles_pasteData a:visited { color: purple; text-decoration: none;}
	#getEntryTitles_pasteData a:hover {
		color:darkgreen;
		background:#dd0; 
		text-decoration: none; 
	}
	#getEntryTitles_pasteData a:active { color: lightblue; text-decoration: none;}

	#getEntryTitles_finish, #getEntryTitles_resultbefore, #getEntryTitles_resultrecent,#getEntryTitles_resultafter {
		padding:0 10px 10px 10px;
		background:#def;
		border-left:2px #777 solid;
		border-right:2px #777 solid;
		border-bottom:2px #777 solid;
		display:none;
	}
	.getEntryTitles_btn {
		width:120px;
		float:left;
		margin:0 2px;
		padding:2px;
		border:1px black solid;
		font-weight:bold;
		color:white;
		background-color:#89A;
		text-align:center;
	}
	#getEntryTitles_viewLog {
		float:left;
		width:50px;
		margin:0 2px;
		padding:2px;
		border:1px black solid;
		font-weight:bold;
		color:white;
		background-color:#89A;
		text-align:center;
	}
	#getEntryTitles_hideThis, #getEntryTitles_removeThis {
		float:right;
		width:20px;
		margin:0px 2px;
		padding:2px;
		border:1px black solid;
		font-weight:bold;
		color:white;
		background-color:#89A;
		text-align:center;
	}
	#cmtbtn1{
		text-align:center;
		margin-top:-2em;
		display:block; width:16em; float:right;
	}
	#cmtbtn2{
		text-align:center;
		border:1px solid darkgray;
		padding:2px;
		margin-top:-2em;
		width:12em; float:right;
	}

▲ToTop

4. メインの JS コード( Ajax通信実施、結果表示等全ての処理を実行する )

Ajax 通信処理、取得結果表示処理などを行うメインコードを書いたファイルです。

必要なファイル全てのインクルードを行ってから、getFc2EntryTItles-gp.js によって Ajax 通信処理を行い、その取得結果を表示中のブログ内に表示します。

結果を表示する小窓にはスクロールイベントを登録し、スクロール時にも常に画面上部に表示され続けるようにしました。

  1 :/* getFc2EntryTItles-gp.js
  2 : * 2008/7/21 Release
  3 : * 2008/8/12, 2008/8/17 update
  4 : */
  5 :// fc2ブログでかつ個別 Entry 表示モードの場合にのみコードを進行する。
  6 :if (location.href.indexOf("fc2")!=-1 && location.href.indexOf("blog-entry-")!=-1){
  7 :(function($){
  8 : var now=function(){return +new Date;}; // 時刻取得関数
  9 : $.extend({ // 時刻・timer起動回数記録用 jQuery 拡張オブジェクト
 10 :  tr:{
 11 :   start:now(),
 12 :   registerEvent:"",
 13 :   ajax:{ recent:[],before:[],after:[]},
 14 :   end:"",
 15 :   waitRecentAjaxCnt:0,setEndingCnt:0
 16 :  }
 17 : });
 18 : // ローカル変数定義
 19 : var aP,mB,ld,pD,fn,lg,r_c,r_b,r_a, constStr="getEntryTitles_";
 20 : var html = { before:[], after:[], recent:[] },getStr ={ before:"", after:"", recent:"" },
 21 :  blogTitle =null, regExpr = "",border={ before:0, after:0},realElm={before:0,after:0},thisEntryNo, lastNo, itval,complement,cmt=0;
 22 :
 23 : // 取得結果表示用のタグを作り表示する。
 24 : if ( $("#"+constStr+"ajaxPopup").size()==0) {
 25 :  $(document.body).append(
 26 :   '<div id="getEntryTitles_ajaxPopup">'+
 27 :    '<div id="getEntryTitles_menuBlock">'+
 28 :     '<button id="getEntryTitles_before" class="getEntryTitles_btn" title="このエントリイより前のエントリイのタイトル情報を見る">Before Entries</button>'+
 29 :     '<button id="getEntryTitles_recent" class="getEntryTitles_btn" title="最新エントリイのタイトル情報を見る">Recent Entries</button>'+
 30 :     '<button id="getEntryTitles_after" class="getEntryTitles_btn" title="このエントリイより後のエントリイのタイトル情報を見る">After Entries</button>'+
 31 :     '<button id="getEntryTitles_reload" class="getEntryTitles_btn" title="Ajax通信をやり直す">ReLoad Data</button>'+
 32 :     '<button id="getEntryTitles_viewLog" title="Ajax 通信の所要時間を見る">Log</button>'+
 33 :     '<button id="getEntryTitles_removeThis" title="このプロジェクトの関連スクリプトやcssを一気に削除する。">'+decodeURI(encodeURI("×"))+'</button>'+
 34 :     '<button id="getEntryTitles_hideThis" title="この小窓を隠蔽する。再表示はブックマークレットを再度クリックすれば良い。">-</button>'+
        // 通信中であることを表示するタグ
 35 :     '<div id="getEntryTitles_loading"><img src="http://hkom007.googlepages.com/loading_16.gif" width="16" height="16" border="0" alt="" /> Now Loading...</div>'+
 36 :    '</div>'+
 37 :    '<div id="getEntryTitles_pasteData">'+
        // 連続する Ajax 通信の全てが終わったことを表示するタグ
 38 :     '<div id="getEntryTitles_finish"><div><strong>Finish Ajax Communication !</strong></div><div id="getEntryTitles_log"></div></div>'+
        // 以前エントリイタイトル名等を表示するタグ
 39 :     '<div id="getEntryTitles_resultbefore"></div>'+
        // 最新エントリイタイトル名等を表示するタグ
 40 :     '<div id="getEntryTitles_resultrecent"></div>'+
        // 以後エントリイタイトル名等を表示するタグ
 41 :     '<div id="getEntryTitles_resultafter"></div>'+
 42 :    '</div>'+
 43 :   '</div>'
 44 :  );
 45 : } else {
 46 :  $("#"+constStr+"ajaxPopup").show();
 47 :  return;
 48 : };
 49 :
 50 : // 表示/非表示を操作するために必要な要素をショートカット変数に代入する。
 51 : aP=$("#"+constStr+"ajaxPopup");
 52 :  mB=$("#"+constStr+"menuBlock");
 53 :    ld = $("#"+constStr+"loading");
 54 :  pD=$("#"+constStr+"pasteData");
 55 :    fn = $("#"+constStr+"finish");
 56 :       lg =$("#"+constStr+"log");
 57 :    r_c = $("#"+constStr+"resultrecent");
 58 :    r_b = $("#"+constStr+"resultbefore"); r_a = $("#"+constStr+"resultafter");
 59 :
 60 : // 結果表示ポップアップに対するアニメーション関数。真ん中から吹き出すような効果を狙った。
 61 : var doExplodeShrink = function(elem,w,h,padbdr,left,state){
 62 :  elem.show().animate({
 63 :   width: w=="auto" ? "auto" : w+"px", height:h=="auto"?  "auto" : h+"px",
 64 : //  display:state, // IEでは機能しないためやむなく削除
 65 :   marginLeft:left ? (-parseInt(w/2)-padbdr+"px") : 0
 66 :  },400,"swing");
 67 : };
 68 :
 69 : // イベントハンドラー登録
 70 : $.tr.registerEvent=now();
    // 固定配置的に配置するためのスクロールイベントハンドラー
 71 : $(window).scroll(function(){
 72 :  $("#"+constStr+"ajaxPopup").css({
 73 :   top:10 +( window.pageYOffset || Math.max(document.body.scrollTop, document.documentElement.scrollTop) )+"px",
 74 :   marginLeft:-320+ ( window.pageXOffset || Math.max(document.body.scrollLeft, document.documentElement.scrollLeft) )+"px"
 75 :  });
 76 : });
 77 :
    // 最新/過去/未来エントリ情報を表示させるクリックイベントハンドラー
 78 : $.each([$("#"+constStr+"recent"),$("#"+constStr+"before"),$("#"+constStr+"after")],function(j){
 79 :  $(this).click(function(){
 80 :   $([fn,r_c,r_b,r_a]).each(function(i){
 81 :    i==j+1 ? $(this).show() : $(this).hide();
 82 :   });
 83 :   this.blur();
 84 :  });
 85 : });
 86 :
    // Ajax通信をやり直すボタン
 87 : $("#"+constStr+"reload").click(function(){
 88 :  $.tr.start=now();
 89 :  this.blur();
 90 :  pD.hide().children().hide();
 91 :  mB.hide();
 92 :  doExplodeShrink(aP,0,0,0,true,"none");
 93 :  ld.show();
 94 :  makeLists(10);
 95 : });
 96 :
    // Ajax通信に要した時間を見る為のボタン
 97 : $("#"+constStr+"viewLog").click(function(){
 98 :  $([r_c,r_b,r_a]).each(function(){$(this).hide();});
 99 :  fn.show();
100 :  this.blur();
101 : });
102 :
    // 小窓を一時的に隠蔽するボタン
103 : $("#"+constStr+"hideThis").click(function(){
104 :  this.blur();
105 :  aP.hide();
106 : });
107 :
    // プロジェクトに係るjsファイルやcssファイルを削除するボタン
108 : $("#"+constStr+"removeThis").click(function(){
109 :  this.blur();
110 :  aP.remove();
111 :  $("script[src*='getFc2EntryTitles']").remove();
112 :  $("script[src*='setjQnFbug']").remove();
113 :  $("link[src*='getFc2EntryTitles']").remove();
114 : });
115 :
116 : mB.children().hover( // ボタンにマウスオーバー/アウトした際のイベントハンドラー
117 :  function(){
118 :   $(this).css({color:"black",backgroundColor:"#dd0"});
119 :  },
120 :  function(){
121 :   $(this).css({color:"white",backgroundColor:"#89A"});
122 :  }
123 : );
124 :
125 :// 最近のタイトルを取得する関数を定義
   // limit 個数のエントリイタイトル情報を Ajax 通信によって取得する。
126 :var makeRecentEntryList = function (limit){
127 : var No, subject, date, iter=0, ret=[],
128 :  target ={  //xml ファイル内での順番
129 :     link:[],     //0
130 :   title:[],     //1
131 : // description:[],  //2 これは利用しない
132 : // content:[],    //3 同上
133 :    subject:[],    //4
134 :   date:[]      //5
135 :  };
136 :
137 : // エントリイタイトルを取得する
138 : $.ajax({
     // 閲覧中のFc2ブログの xml ファイルのアドレスを設定する。
139 :  url: /(http:.+fc2\.com\/.*)blog-/.exec(location.href)[1] + "?xml" || null,
140 :  type: "GET",
141 :  dataType: "xml",
     // xmlファイルが成功裏にダウンロード出来た場合の処理関数
142 :  success: function(xml){
143 :   var tmpStr = '<div>'+decodeURI(encodeURI("最新のエントリイ情報がありません。"))+'</div>';
144 :   if (xml==null) {getStr.recent = tmpStr; return;}
145 :   // Blogタイトルを取得する
146 :   blogTitle = $(xml).find("title").eq(0).text();
147 :   // 最新エントリイ情報を巡回取得
148 :   $.tr.ajax.recent["start"]=now();
149 :   $.each(target,function(key){
150 :    $.each($(xml).find("item"), function(i,n){
        // 取得結果を ret 配列の i 番目に代入
151 :     ret[i]= [$(n).children().eq(0), $(n).children().eq(1), $(n).children().eq(4),$(n).children().eq(5)];
        // ret配列内のテキスト文字列を抽出して target 配列に代入する。
152 :     target[key].push( ret[i][iter].text() );
153 :    });
       // 次のエントリイ情報を取得するために(46行で初期値ゼロを定義済み)
154 :    iter++;
155 :   });
156 :   try {
       // エントリイ番号、エントリイタイトル、投稿年月日を取得する。
157 :    for (var i=0 ; (i < limit) && target.link[i] ; i++) {
158 :     No = /entry-([0-9]+)/.exec(target.link[i])[1];
159 :     i==0 && (lastNo = Number(No)); // 最新エントリイ番号を取得
160 :     subject =" , " +target.subject[i];
161 :     date =" , " +target.date[i].substring(0,10); // 年月日のみを抽出
        // limit 個の取得結果を表示用に整序して配列 html.recent に代入する。
162 :     html.recent.push( "<li><a href='" + target.link[i] + "' target='_blank'>" + target.title[i] + "</a> (No." + No + subject + date + ")</li>" );
163 :    }
164 :    $.tr.ajax.recent["end"]=now(); // 時刻記録
       // 格納済み配列を HTML 文字列に併合して最終表示用に整序する。
165 :    getStr.recent = "<div><strong>Recent " + Math.min(limit,i) + " Entries</strong></div><ul style='margin-left:1.5em;list-style-type:disc'>" + html.recent.join('') + "</ul>";
       // 最終表示用に整序した HTML 文字列を表示用タグに挿入する。
166 :    r_c.html(getStr.recent);
167 :   } catch (err) { // 何らかのエラーが発生した場合にはその旨を表示する。
168 :    r_c.html(tmpStr);
169 :   }
170 :  } // End of success()メソッ
171 : }); // End of ajax()メソッド
172 :}; //End of makeRecentEntryTitle func
173 :
174 :// 前後のタイトルを取得するための準備を行う
175 :var makeEntryList = function(b_a,limit){
176 : var thisHTTP, getEntryNos=[], thisURL=[]; // ローカル変数定義
    // エントリイアドレス文字列を分解するための正規表現文字列定義
177 : regExpr = /(http:.+entry-)([0-9]+)/;
    // 今開いているエントリイのエントリイ番号を取得する。
178 : thisEntryNo = Number(regExpr.exec(location.href)[2]);
    // 今開いているエントリイアドレスのエントリイ番号前までの文字列を取得する。
179 : thisHTTP = regExpr.exec(location.href)[1];
    // 以前エントリイについてアドレス名にエラーが出ないように
    // この段階では最新エントリイタイトル名取得関数内で設定した。
    // 最新エントリイ番号値は上で取得済みなので、これを活用して
    // 以後番号も存在しない番号を取得しないようにする。
180 : border[b_a] = Math.min(limit+1, b_a == "before" ? thisEntryNo : Number(lastNo)-thisEntryNo+1);
181 : if (border[b_a]==1) thisURL.length=0; // 求める以前エントリイがない場合の処理
182 : else {
     // 求める以前または以後のエントリイが存在すれば
183 :  for (var i=1; i < border[b_a]; i++)
      // そのアドレス文字列を作成し配列に格納する。
184 :   thisURL.push(thisHTTP + (thisEntryNo - (b_a == "before" ? i : -i)) +".html" );
185 : }
186 : realElm[b_a] = 0; // 初期化
187 : // 準備完了! Ajax 通信開始
188 : getTitlesByAjax.call(this, b_a,thisURL);
189 :};
190 :
191 :// Ajax 通信によりエントリイタイトル等を取得する関数の定義
   // b_a は以前のエントリイか、以後のエントリイかを示す文字列
192 :var getTitlesByAjax = function (b_a,thisURL){
193 : if ( thisURL.length != 0 ) {
     // エントリイアドレス毎に巡回処理を行う。
194 :  $.each(thisURL,function(i,aryitem){
195 :   $.tr.ajax[b_a][i]=[];
196 :   $.tr.ajax[b_a][i]["start"]=now();
197 :   $.get(aryitem,function(data){ //data は thisURL[i] の html テキスト文
       // エントリイタイトル部分を抽出するための正規表現文字列を定義する。
198 :    regExpr = /<title>(.*)<\/title>/;
       // ブログタイトル文字列があればそれをエントリイタイトル文字列から削除する。
199 :    var titleStr = blogTitle && regExpr.exec(data)[1].replace(blogTitle,"") || "" ;
200 :    if ( /\S+/.test(titleStr)){ //空白だけのタイトル名は補足しない。
201 :     ++realElm[b_a]; // 取得したタイトル数をカウントする。
        // 1つのエントリイのタイトル名、エントリイ番号を取得

202 :     html[b_a][i]="<li><a href='" + aryitem + "' target='_blank'>" + decodeURI(encodeURI(titleStr)) +" (Entry No." + /entry-([0-9]+)/.exec(aryitem)[1] + ")</a></li>";
203 :    }
204 :    $.tr.ajax[b_a][i]["end"]=now(); // 時間記録
       // 最後の通信処理が終わったらsetEnding()関数をタイマー起動する。
205 :    if (b_a == "after" && aryitem == thisURL[thisURL.length-1]) 
206 :     itval=setInterval(setEnding,20);
207 :   });
208 :  });
209 : } else {if (b_a == "after") itval=setInterval(setEnding,20)}
210 :};
211 :
   // 終了処理関数定義
212 :var setEnding = function (){
213 : $.tr.setEndingCnt++; // 回数記録
214 : if (jQuery.active==0){ // Ajax通信結果が取得出来たならば
215 :   if (itval) {clearInterval(itval);itval=null;} //タイマー変数停止無効化
     // 以前・以後別に処理
216 :   $.each(["before","after"],function(i,b_a){
      // 取得結果がない場合
217 :  if (realElm[b_a]==0)
218 :   getStr[b_a]="<div>"+ (b_a=='before' ? 'Before ' : 'After ') + "Entry "+ decodeURI(encodeURI('はありません。')) + "</div>";
219 :  else {
      // 欠番があった場合の説明文を complement 変数に代入
220 :   complement = (border[b_a]-1 -realElm[b_a]!=0) ? 
221 :    " ( " +decodeURI(encodeURI("欠番があります。")) +" )" : "";
      // 取得結果を HTML 文字列にして変数に代入
222 :   getStr[b_a] = "<div><strong>"+ (b_a=='before' ? 'Before ' : 'After ') + realElm[b_a] + " Entries" + complement +"</strong></div><ul>" + html[b_a].join('') + "</ul>";
223 :  }
     // HTML 文字列化された取得結果文字列を所定のタグに挿入する。
224 :  $("#"+constStr+"result"+b_a).html(getStr[b_a]);
225 :  if (b_a=="after") {
      // Now loading...文字を隠蔽
226 :   ld.hide();
      // 結果表示ボタンの無効化と半透明化を解除
227 :   $(".getEntryTitles_btn").attr("disabled","").animate({opacity:1.0});
      // 以前タイトルの所要時間を設定(ゼロの時にも対応)
228 :   var beforeTime=$.tr.ajax.before.length ? "<li>以前タイトル取得 Ajax 通信所要時間: "+ ($.tr.ajax.before[realElm.before-1].end-$.tr.ajax.before[0].start)/1000 +" 秒</li>" : "";
      // 以後タイトルの所要時間を設定(ゼロの時にも対応)
229 :   var afterTime=$.tr.ajax.after.length ? "<li>以後タイトル取得 Ajax 通信所要時間: "+ ($.tr.ajax.after[realElm.after-1].end-$.tr.ajax.after[0].start)/1000 +" 秒</li>" : "";
      // 所要時間を表示するためのHTML文の作成
230 :   var AjaxLog ="<ul style='margin-bottom:5px'>"+
231 :    "<li>クリック後 Ajax 通信開始迄の所要時間: "+($.tr.ajax.recent.start-$.tr.start)/1000 +" 秒</li>"+
232 :    "<li>最新タイトル取得 Ajax 通信所要時間: "+ ($.tr.ajax.recent.end-$.tr.ajax.recent.start)/1000 +" 秒</li>"+ beforeTime + afterTime +
233 :    "<li>このプロジェクト全体の所要時間: "+ (($.tr.end=now())-$.tr.start)/1000 +" 秒</li></ul>";
      // ログ閲覧回数の記録
234 :   cmt++;
      // 一度目の所要時間表示文字列
235 :   var cmtbtn1="<button id='cmtbtn1' onclick='this.blur();window.open(\"http://hkom.blog1.fc2.com/blog-entry-631.html\",target=\"_blank\")'>この Ajax 通信や所要時間について</button>";
      // 二度目以降の所要時間表示文字列
236 :   var cmtbtn2="<div id='cmtbtn2'>" +(cmt-1)+" 回目の Reload 結果</div>";
237 :   lg.append(AjaxLog+(cmt==1 ? cmtbtn1:cmtbtn2)); // 経過時間ログの挿入
      // 結果表示エレメントの表示
238 :   pD.css({width:"640px",height:"auto"}).show();
      // 通信終了を知らせる文字列の表示(アニメーション)
239 :   fn.show().children().eq(0).fadeIn("slow",function(){$(this).css({color:"darkgreen",background:"pink"})}).fadeOut("slow").fadeIn("slow",function(){lg.show()});
240 :  }
241 :   });
242 : }
243 :};
244 :
   // 一連のAjax通信関数を起動する関数
245 :var makeLists = function(num){
    // popup小窓のアニメーション表示のため
246 : doExplodeShrink(aP,640,600,0,true,"block");// ここでサイズ指定。最外側の div 要素を表示
247 : doExplodeShrink(mB,616,50,12,false,"block"); //OK42=Firefox.Opera,but50=forIE,
    // 結果表示用のボタンの無効化と半透明化並びにその他のボタンの有効化等
248 : $(".getEntryTitles_btn").each(function(i){
249 :  i<3 ? $(this).attr("disabled","disabled").animate({opacity:0.4})
250 :   : $(this).attr("disabled","").animate({opacity:1.0});
251 : });
252 : $.each(["recent","before","after"],function(i,n){ // 結果を格納する変数の初期化
253 :  getStr[n]=""; html[n].length=0;
254 : });
255 : makeRecentEntryList(num); // 最新エントリイ情報取得開始
    // Ajax通信開始待機関数の定義
256 : var nextAjaxTimer = function(){
257 :  $.tr.waitRecentAjaxCnt++; // 回数を記録
258 :  if (jQuery.active==0) { // Recent Entry Titles 情報の取得が終わったら
259 :   if (timer) {clearInterval(timer);timer=null;}
      // 「以前」情報取得のためのAjax通信関数起動
260 :   makeEntryList("before",num); // ここは連続して履行しても
      // 「以後」情報取得のためのAjax通信関数起動
261 :   makeEntryList("after",num);  // 問題なく取得結果を html 化できる。
262 :  }
263 : };
    // タイマー起動
264 : var timer = setInterval(nextAjaxTimer,100);
265 :};
266 : makeLists(10); // 一連の関数を起動
267 :})(jQuery); // 引数 jQuery で無名関数を起動
268 :} else alert("閲覧中のサイトは FC2 ブログではないか、Fc2 ブログであっても個別エントリイ表示モードではありません。\nこのプロジェクトは、Fc2ブログの個別エントリイ表示モードの場合のみ使用できます。");
269 :

ファイル置き場問題(2) 結局有料サイトしかないのか?! 否!Google Codeが!

概ね5時間掛けて色々調べた結果...!!

リンクが貼れるファイルを無料ホスティングサービスでゲットすることは、かなり困難であることが判明しました。

そこで最後のチャレンジで Google Code に登録してみました。すると何と!upload 出来て、かつリンクを貼ってダウンロード出来るではありませんか!

早速、その例を下に掲載してみます。

firebug.js

firebugx.js

既存のファイルなので Google Code Website の主旨に反するでしょうが、テストということで許して貰うとして(苦笑)、上のリンクをクリックすると直ぐにダウンロードを開始するダイアログが表示されます。まさにこれこそ願っていた環境なので、ついに目的を達することが出来ました。

これにより、各種のブックマークレットによって各種のサイト上でスクリプトをインクルードし、Ajax 通信などによる情報取得/表示を実現する道が開けました。

例えば、先のエントリイで掲載したブックマークレット( jQuery と firebugLite を一括してインクルードするもの)において、その中の firebug.js ファイルのリンク先を webos-goodies から、Google Code に変えたものを以下に掲載しました。

これで (1) jQuery1.2.3.jsと (2) firebug.js のインクルードが実現すれば、万々歳です。

そしてそれは実現できました!!

下のリンクをお気に入りに登録すれば、 jQuery と firebugLite を一括してインクルードするブックマークレットとして使えます。
No1簡易版 jQuerify + FirebugLite

▲ToTop

それでも有料サイトを使うべきかも知れない

Google Code サイトは他者に貢献できるようなファイルを置く場所だと思われますので、私のような使い方、あるいは私のようなレベルの素人が使うのは、いかにも僭越な気がします。

よってGoogle Code には遠慮して、有料サイトを使うべきかも知れません。

しかし、暫くの間は自作の ブックマークレットを含む Javascript コード等を Google Code に upload し、このブログ上からダウンロードやインクルード出来るようにしてみようか、と思っています。

JustSystem や Sony が提供するホスティングサービスを利用することは、いつでも可能なことですし、Google Codeでは写真や動画あるいは通常の文書ファイルは保存できません。毎月 300 円程度で確実にファイル置き場として利用できるのであれば、決して高くはありませんから、追って有料サービス利用に踏み切ろうかと、思案中です。

ps:昨日確認したところ、二社とも無料期間を設けて自社サービスへの誘導を行っていました。

ファイル置き場問題に明るい展望が開けた!、かと思いきや・・・駄目だった。

駄目元でも良いから...とグーグったら!

検索用語はずばり「無料 ファイル置き場」。するといくつかの候補がリストアップされるではありませんか!

iDrive───これは英語圏のもので無料ではあるものの、利用規約などとても読む気にはならないので、最後の手段かな、と概観してみました。使えそうではありました。( Free Online Backup - IDrive - Encrypted, Secure and Automated! )一度は無料サービス提供をやめたはず(2001年)ですが、その後また再開したものと思われます。何と 2GB の容量が無料で使えるようです。

但し、バックアップ用途としてのディスク容量の提供に限定されているのかも知れませんが、詳細は調べ切れていません。

なお、有料の eXys iDrive(WebDAV対応 大容量 オンラインストレージ - eXys iDrive - 簡単・安全にファイルを保存・共有できます) とは全く別物です。

次に、Google の無料サービスでも使えそうなものがあるようです。プロジェクト ホスティング「独自のオープンソース プロジェクト用に コードとドキュメントのホスティング サービスを無料で提供。」とありますが、jQuery.js ファイルも Google サイトに置いてあったことを思い出しました。( 開発者ホーム - Google Code

しかしこちらは色々とハードルが高そうな気がします。

更に、オンラインストレージに関して、概括的・具体的・網羅的な情報を提供してくれるこんなサイト( オンラインストレージを使ってみよう )もありました。

そしてたどり着いたのは infoseek です。今や楽天傘下に組み込まれているとは知りませんでしたが、こちらの無料ホームページサービスはファイル置き場を認めているらしいのです。

日本語でファイル置き場と言う用語に引っかかるサイトの多くは infoseek の登録 Homepage であることからも象徴されるように、infoseek の Homepage サービスをファイル置き場として活用している方が沢山いるらしいことも判明しました。

▲ToTop

というわけで早速 infoseek に Homepage 開設しようとして...But!

ユーザー登録を終えると「iswebライト新規登録時のご確認」画面が表示されますが、そこには「他サイトからのCGI及びデータの参照を禁止します。 」と書かれているではありませんか!

つまりファイル置き場には出来ない、と言う結論になります。

しかし一方ではいくつかのブログサイトで、ファイル置き場として使っていることを公言しているエントリイもあったりしますので、もしかしたら最近になって「置き場禁止」へと方針を転換したのかも知れません。うむ...。出鼻を挫かれてしまいました!

▲ToTop

そこで更にネット検索を重ねたところ...!!

あった。ありました!

メールアドレスとパスワードを登録するだけで容量制限なしで使えるという、超簡単ストレージが!
「 何の予告もなくファイルを全削除されました(08.1/1)。そして消えていたファイルが全て元通りになってました。何だったんだ?!(08.1/4) 」との記述が象徴しているように( 8倍速対応 | 無料無制限のオンラインストレージ-MediaFire )、何時消えてなくなるかも知れませんが、そのことを覚悟した上で( まさしく駄目元で )利用してみようかと思います。

容量制限なし、登録は超簡単な無料オンラインストレージ

早速アップロードしてみましたが、アップロードが終わるとメルアドとパスワードを入力する画面が表示され、Image Page URL とリンク HTML 文とが直ぐにゲットできてしまいます。

使用例1:例えば写真を登録してみました

Unlimited Free Image and File Hosting at MediaFire
(例)Media Fireに保存した写真

使用例2:jsファイル

firebug.js

しかし...

写真などをダウンロードするのは良いでしょうが、インクルード用 js ファイル置き場としては適さないことが分かりました。

ダウンロードしようとすると MediaFire サイトが開くのです。そしてウィルスチェックが自動的に行われ、その後画面をクリックして初めてダウンロードするようになるのです。これではjsファイルのファイル置き場としては実用的ではありません。

そこでブックマークレットの一部にMediaFireからインクルードするjsファイルを組み込もうと思いましたが、ファイル名が http://www.mediafire.com/?ymw9kjb0jig のように独自ネームに変えられてしまうため、これも駄目だと分かりました。

ということで、明るい展望は開けませんでした。

苦闘5時間の末に!

それでも食い下がった結果、苦闘5時間の末についに「発見し、利用を開始」しました───外部からリンクを貼りそれを参照可能な無料サービスを。このことについては次の Entry( ファイル置き場問題(2) 結局有料サイトしかないのか?! 否!Google Codeが! )で詳述します。

jQuery と FirebugLite を一括登録するブックマークレット

以前次のように書きました。

jQueryブックマークレット(=jQuerify)を利用する前提として、Firebug(firefoxの場合)又はFirebug Lite(IE、Operaの場合)を組み込む必要があります。前者の場合にはFirefoxのアドオンとしてBrowser自身に組み込めばお仕舞いで、簡単に jQuerify を利用することが出来ます。

一方、後者の Firebug Lite の場合には、jQuerify を適用するサイトに、Firebug Liteをインクルードしなければなりませんが、それを一々追加するのでは余りに面倒です。

そこで、Firebug Lite と jQuerify を同時にインクルードするブックマークレットを作成し、容易にインクルード出来るようにすれば便利なはずです。

ここに、jQuerifyブックマークレットにおいて使用する jQuery は、Google のファイル置き場に置いてあるので、そこへのリンクを貼ればよいのですが、IE 、Opera 及び safari 用の Firebug Lite の方は当該サイトに zip 圧縮ファイルがあるだけですから、自ブログサーバーまたは自サーバー等に展開したファイルを置く必要が出てきます。

この時に問題となるのは、Fc2ブログサーバーに置いたファイルに対して、別のドメインや他の fc2 ブログ頁からリンクを貼ることが認められてない、ということです。当然の措置ですが Fc2 はFc2ブログのファイル置き場を、外部サイトから利用する所謂「ファイル置き場」として利用することを、認めていません。

jQuerify.jsブックマークレットを利用したい in this Blog

先のエントリを記述した時点では、「ファイル置き場」を探して彷徨ったものの、適切なサイトを見いだせませんでした。そのため今回解決した 「jQuerify と firebugLite を一括してブックマークレットにする」ことを諦めていたのです。

▲ToTop

サーバーに FirebugLite を置き、その利用を認めているサイトがあった!───がしかし...

その後、あれこれと探す中で希少なサイトが見つかりました。展開した Firebug Lite ファイルを置き、その利用を認めているサイトがあったのです( WebOS Goodies )。そこで早速それを利用させていただくこととし、今回念願のブックマークレットを作成しました。

感謝! webos-goodies!

このエントリイでは、jQuerify と firebugLite を一括インクルードするブックマークレットを紹介させて貰いますが、IEには文字数制限がありますし、fireFox などの Mozilla 系ブラウザの場合には firebugLite をインクルードする必要はないので、それらを考慮して複数のブックマークレットを作成しました。

その後 webos-goodies の firebug は使用できなくなってしまいました。断りもなく勝手にリンクを貼ったことが失礼に当たってしまったのかも知れません。陳謝!

そこで別のファイル置き場を探してそこにfirebugを置くことにしました。

No1.簡易版ブックマークレット
( Firefox or Opera or IE 用. scriptタグの有無などを確認しない簡易版 )

まず、jQuerify と firebugLite を一括してインクルードするブックマークレット No1 を作成しました。文字数は 391 文字で IE6 における文字数制限 508 文字以内に納めるべく、ブラウザチェックやscriptタグチェックを一切行わない原始的なバージョンです。いくつかのサイト上で IE7、Firefox 及び Opera で動作を確認しました。

なお既に firebug が組み込まれている Firefox などでこのブックマークを実行すると、firebug 本体とは別に firebugLite が登録されてしまいます。こうした事態を発生させないために No2 を作成しました。

下のリンクをお気に入りに登録すれば使えます。
No1.簡易版 jQuerify + FirebugLite
No2.拡張版ブックマークレット( Firefox or Opera 用 )

上記のブックマークレットでも実用的に支障はないのですが、ブックマークを二度以上 click してしまうことも良くありますので、本来重複登録しないようにすべきです。また firebug 本体を組み込んだ Mozilla 系ブラウザにおいては、firebugLite を組み込む意味は皆無です。

そこでインクルード済みかどうかをチェックすると共に、Mozilla 系ブラウザの場合には firebugLite を組み込まないようにしました。つまり Firefox などの Mozilla 系ブラウザでは firebug は組み込み済みのものと仮定し、このブックマークレットを使う場合には、jQuery だけをインクルードするようにしました。

文字数は 543 で、いくつかのサイト上で Firefox 及び Opera で動作を確認しました。

なお、このブックマークレットは IE の文字数制限値 508 を越えていますので IE6 及び 7 では動作しません。このため、別途 No3 を作成しました。

次のリンクをお気に入りに登録すれば使えます。
No2:for Firefox or Opera, jQuerify + FirebugLite
No3.拡張版ブックマークレット( IE or Opera 用 )

script 存在を確認する機能を持たせた上で、IE でも動くような文字数制限ぎりぎりのコードを作成しました。文字数は 492 文字です。そのため性能を削らざるを得ず、具体的にはブラウザチェックを排除せざるを得ませんでした。

このため Mozilla 系でも動いてしまい、firebug 本体が組み込まれていても firebugLite をインクルードしてしまう欠点があるので、敢えて IE or Opera 用としました。

動作確認は IE と Opera 及び Firefox(Firefoxの場合には firebugLite が登録されてしまいますが)で行いました。

次のリンクをお気に入りに登録すれば使えます。
No3:for IE or Opera, jQuerify + FirebugLite
※ Opera の場合には IE 程の文字数制限はないようなので、 No2 、No3 のどちらでも使えます。

各ブックマークレットのコード

No1( script タグの存在有無を確認しない版 )

上のブックマークレットのコードは以下の通りです。分かりやすく改行等を入れました。

<div>下のリンクをお気に入りに登録すれば使えます。<a href="javascript:
(function(){
  // 文字数を減らすため最初に全ての変数を一括定義
  var%20h = document.getElementsByTagName('head')[0],
  s = document.createElement('script'),
  c = document.createElement('script');
  // jquery インクルード
  s.src = 'http://jqueryjs.googlecode.com/files/jquery-1.2.3.pack.js';
  s.type = 'text/javascript';
  h.appendChild(s);
  // ブラウザチェック(IE、Opera 及び Safari)
  if(/(msie|opera|webkit)/.test(navigator.userAgent.toLowerCase())){
    c.type = s.type;  // 文字数を減らすため複写出来るものはそれを活用
    // firebug Lite アドレス
    c.src = 'http://hkom007.googlepages.com/firebug-gp.js';
    h.appendChild(c);
  }
})()">No1.簡易版 jQuerify + FirebugLite</a></div>
No2( script タグの存在確認版で Firefox or Opera 用)

上のブックマークレットのコードは以下の通りです。分かりやすく改行等を入れ、また読みやすいようにスペースも入れました。

<div>下のリンクをお気に入りに登録すれば使えます。<a href="javascript:
(function(){
  // 文字数を減らすため最初に全ての変数を一括定義
  var x = 0,y = 0,h = document.getElementsByTagName('head')[0],
  t = document.getElementsByTagName('script'),
  s = document.createElement('script'),
  c = document.createElement('script'),i=0;
  s.type='text/javascript';  // これも文字数を減らすために二度表示しないように
  // script タグがあれば
  if(t){
    for(;i<t.length;i++){
      if( /jquery-/.test(t[i].src) ) x += 1;
      if( /firebug/.test(t[i].src) ) y += 1;
    }
  }
  // scriptタグがないか、又は
  // jquery 文字列がない場合の src = jquery.js の script タグ追加
  if (x==0) {
    s.src = 'http://jqueryjs.googlecode.com/files/jquery-1.2.3.pack.js';
    h.appendChild(s);
  }
  // Mozilla系ではなく、かつ scriptタグがないか、
  // 又は firebug 文字列がない場合の src = firebug.js の script タグ追加
  if ( !/mozilla/.test(navigator.userAgent.toLowerCase()) && y==0 ) {
    c.type = s.type;  // 文字数節約のためこうした
    c.src = 'http://hkom007.googlepages.com/firebug-gp.js';
    h.appendChild(c);
  }
})()">No2:for Firefox or Opera用, jQuerify + FirebugLite</a></div>
No3( script タグの存在確認版で IE or Opera 用)

No3 は No2 と以下の部分が異なるだけです。

No2:  if ( !/mozilla/.test(navigator.userAgent.toLowerCase()) && y==0 ) {
          ↓
No3:  if ( y==0 ) {

jQuery Ajax Utilities を活用して、任意のFc2ブログから情報を得たい。

自分のブログサイト以外で Ajax 通信したいが・・・

上のリンクにあるように、myBlog の任意の頁を開いた状態で、Fc2ブログサーバーのmy HTML または xml ファイルにアクセスして、過去/最新/未来のエントリイタイトル等を取得する術を自作しました。

作成してみて、改めて jQuery の素晴らしさ(使いやすさ、こうしたメソッドがあるかも知れないと思うと大体存在している気配りの深さと広さ、何よりも簡潔な記述を可能とする洗練)に感服しました。引き続き解読作業を進めていくことに、ますます意を強くした次第です。

さて、Ajax は同一ドメイン内における情報のやりとりを、頁をロードし直すことなく可能とするテクニックですが、それは Google がそうしているように、別に自分のサイトでなくても良い、ということに、今更ながらに気がつきました。

Google Map が Ajax 普及に火を付けたことは余りに有名ですが、Google Map の開発者でもなく、著作権などの権利を有することもない、Google 社と無関係な人が誰でも Google Map 上で Ajax 通信を使っているわけですから、Ajax 通信をそのサイト上で仕掛けることが出来さえすれば、そのサイトの管理者ではない第三者が、どんなサイトでも Ajax テクニックを利用することが出来るはずです。

そこで、それが可能となる条件を考えてみました。

  1. 当該サイトが Javascript を有効に出来ること(ユーザーがscriptタグを設置できないブログも多々ある)
  2. 当該サーバーのドメイン内しか処理対象とならないから、ドメイン越えでスクリプトを読み込ませるために、読み込ませるスクリプトファイルを置くサーバーが確保できること
  3. 出来れば jQuery が使える環境下にあること
  4. 出来れば、当該サーバーが提供している xml ファイルの URI が明らかになっていること(これは RSS 配信をしていれば簡単に入手できる)

等のはずです。

▲ToTop

しかし、Fc2 ブログサーバーは規約でファイル置き場には出来ない

早速試してみたいのですが、当面それは不可能です。何故ならば規約上 Fc2 ブログサーバーは所謂「ファイル置き場」には出来ないからです。従ってここで述べようとしていることは、Fc2 ブログ以外のファイル置き場として認められているサーバーに、所与のスクリプトファイルが置けなければ実現しません。

つまり技術的には別ドメインに Ajax 通信を行うように仕組むことは十分可能ですが、ファイル置き場がない限りそれはルール上出来ない、ということになります。残念!

以前もファイル置き場を探しましたが、「無料で」それが可能となるサイトは見つけられなかったので、以下に述べることは自分のファイルサーバーでも持たない限り夢と終わる話となります。

ファイル置き場が見つかった暁に実行する「夢」

その上で手順だけ夢見てみます。

  1. Ajax 通信を行うコードを作成し、これを jQuery.js と一緒にインクルードするコードを作る。
  2. これをブックマークレットにする。
  3. 当該ブックマークレットを任意のサイト上で実行する。

ここに問題となるのはブックマークレットに文字数制限があることですが、外部から読み込むファイル(下の例ではfoo.js)内に諸々の処理を記述するのであって、ブックマークレットでは外部から読み込むファイルを設定するだけですので、文字数制限は障害にはなりません。

そのブックマークレットは以下のようになるはずです。

※ 仮想のファイルを使った例示ですので決して動作しません。また既に必要なscriptタグが存在している場合の分岐処理は未作成です。

<a href='javascript:(function(){
var head=document.getElementsByTagName("head")[0],
script = document.createElement("script");
script.setAttribute("src","http://jqueryjs.googlecode.com/files/jquery-1.2.3.pack.js");
script.setAttribute("type","text/javascript");
head.appendChild(script);
script = document.createElement("script");
script.setAttribute("src","http://fileServerAddress/foo.js");
script.setAttribute("type","text/javascript");
head.appendChild(script);
})()'>Do! Ajax 通信</a>

ファイル置き場からインクルードするjsファイルに、jquery.js をインクルードするコードも盛り込んでしまえばよいのですから、もっと短くするべきでしょう。折角だからインクルード済みかどうかもチェックするのがベターでしょう。

上のコードを改善したブックマークは以下のようになるでしょう。

<a href='javascript:
(function(){
  var%20h=document.getElementsByTagName("head")[0],
  t = document.getElementsByTagName('script'),
  s = document.createElement("script"),
  i = 0, x = 0;
  if (t) 
    for(; i<t.length; i++)
      if( t[i].src.indexOf('foo.js') != -1 ) x += 1;
  if (x == 0) {
    s.type = "text/javascript";
    s.src = "http://fileServerAddress/foo.js";
    h.appendChild(s);
  }
})()'>Do! Ajax 通信</a>

上の foo.js ファイル内において、Ajax 通信を行いその結果を表示するようなメソッドを記述しておき、当該ファイルがインクルードされると同時に、そのメソッドを実行させるようにすれば、例えば最新10エントリイリスト、過去の10エントリイリスト等々を表示させることが可能となります。foo.js内で1つの絶対配置ボックスを用意し、その中にいくつかのボタンを設けて、様々な Ajax 通信結果を表示させることも可能となるでしょう。

また、xmlファイルではなく HTML ファイルにアクセスすれば、過去1ヶ月間、1年間などのエントリイタイトルリストをゲットすることも可能でしょう。

jQuery Ajax を活用したエントリイタイトルの各種取得法──集大成!

改訂履歴
  • 初稿:2008/3/2
  • 抜本改訂:2008/7/5
    • タイマーを組み込み或る Ajax 通信完了後に、次の異なる種類の Ajax 通信を行うようにした。但しこの時組み込んだタイマーは、Ajax 通信状態に依存するものではなく、経験的に必要と思われる所要時間を手動で設定していた。
  • 再度の抜本改定:2008/8/8
    • Ajax 通信終了フラグを jQuery.active プロパティに統一した。
    • Ajax 通信の所要時間を記録するコードを組み込み、その結果をエントリイタイトルリスト下部に表示するようにした。

これまで行ってきたこと

それはjQuery.jsの GET メソッドを使って ResponseText と ResponseXML を取得し、このブログサイトの過去/未来/最新のエントリイタイトル名称等を取得することでした。

それらは以下のエントリイで説明したように「一応」実現しました。

そして、これらの情報取得が可能になったことによって、そもそもやりたかったことを実現する手段が獲得出来ました。すなわち、ナビゲーションバーの直前のエントリイや直後のエントリイ文字列にマウスオーバーすると、直前/最新/直後の任意の数のエントリイタイトル等の情報をポップアップ表示させることです。

そのためにこそ、任意のエントリイの直前エントリイタイトル取得を試みてきた訳ですし、両方に挟まれた「ホームへ」文字列にマウスオーバーした時にも同様にポップアップさせるべきだと考え、それは最新10エントリイタイトルにしようと思い、それを実現するための前段の措置として最新エントリイ情報の取得について模索したのでした。

さて、何はともあれ実現したこれらのポップアップ表示をまずは画像で紹介させていただきます。

直前10/最新10/直後10エントリイタイトルの Ajax 通信による取得

これらの3つの情報を簡単に取得することは Ajax 通信を使ってこそ可能になります。直前/直後のエントリイ情報は、閲覧しているエントリイ毎に異なる訳ですから、ここにこそ Ajax 利用のメリットがあります。

まず実現した3つのポップアップ画像を示します。

直前10エントリイタイトル情報


最新10エントリイタイトル情報


直後10エントリイタイトル情報

▲ToTop

コード作成上留意したこと

この下の節で詳細な説明を付けた Javascript コードを掲載しましたので、以下の説明はそちらを見ていただければより分かりやすくなるかと思います。

1. コードの概要、要点など

結果を popup させるための HTML テンプレートと popup 要素のための CSS テンプレートに必要な加工行った上で Javascript コードを作成しました。そのコードそのものの説明は後述するとして、まずその概要やポイントを纏めておきます。

  1. 通信結果をポップアップ表示するための入れ物=絶対配置要素(popup要素)を HTML 文に挿入する( 22-25 行)

    取得したエントリイタイトルリストを表示させる方法としてポップアップを選びました。閲覧上固定的に表示する必要はありませんし、邪魔にならずに目的とする情報を随時閲覧できる方法としてポップアップが最適です。

  2. Ajax 通信中にそのことを示す表示について

    Ajax通信に関する記述を読むと必ず次のことが強調されています。─── Ajax 通信は背景で処理されるので、そのことを知らせないと閲覧者はパソコンが固まったのではないか、と誤解する。閲覧者を戸惑わせないためにも、Ajax通信中は今通信中であることなどを示すべきである。

    しかし、その表示は恒常的に出ている必要はなく(常に見えていてはむしろ邪魔)、popupさせようとしたその時にまだ通信中であればその時に限って表示すればよい訳です。

    さてここで述べているコードは頁が開かれると同時に起動して背景で動いています。そして頁オープン後数秒で結果を取得し、マウスオーバーを待つ状態になります。

    ですから、敢えてAjax通信中であることを表示する必要はないと判断し何も策を講じませんでした。

    正確に言えば表示するような文言を用意したのです( 20 行 )が、取得までの時間が短すぎて表示する暇がないようです。(苦笑)

  3. 最新のエントリイタイトルを xml ファイルから獲得する関数定義( 84-116 行)

    IEの場合 xml 文書の名前空間処理(DOM の getElementsByTagNameNS メソッド)に対応していません。最初は xml 文書の名前空間や DOM の getElementsByTagNameNS メソッドのこと自体を知らなかったので、どうして IE では結果を取得できないのか皆目見当が付きませんでした。

    仕方なく、使いにくいデバックツールしかないので面倒だったのですが、IE上で自作コードをデバッグしてみて、やっと IE が名前空間を使用したタグを認識できないと言うことを知ったのでした。

    そこでコードに改良を加えるために xml 文書を詳しく眺めてみると item 要素にエントリイ情報が内包されていることが確認できましたので、item 要素を配列内に全て取得してから、その中から必要な要素だけを抽出する方法を採用して、IE でもその他のブラウザと同様の結果が取得できるようにしました。(98-101行。この target オブジェクトは item タグ内から目的とする要素だけを抽出したその結果を受け取るためのもの。)

    XML文書の名前空間に関する参考サイト:XML 名前空間の簡単な説明

  4. 直前/直後のエントリイタイトルを HTML ファイルから獲得する関数定義(119-153行)

    まず、今見ている頁の直前/直後のエントリイアドレスを取得する方法を考えました。直ぐに今見ている頁の URI アドレスを取得して、それを活用すればよいと判断し、URIアドレスからエントリイ番号とそれ以外とを分離するために、正規表現の exec メソッドを活用しました。(121-123行)

    次に HTML 文書からタイトルをゲットするタグはどれがよいのか選択しました。当然それは title タグです。しかし title タグ内にはブログタイトルも含まれているので、substring メソッドを使ってこれを除去しました。(142行)

    なお、この関数で最後まで頭を悩ました問題は境界問題(前後のエントリイ数が10に満たない場合)でした。これについては後述します。

  5. Ajax 通信の要点( 89-115 行及び 141-150 行 )

    このプロジェクトでは Ajax 通信を都合 21 回行っています。

    まず最初に、最新エントリイ情報を取得するために xml ファイルを取得しています。( 89-115 行 )

    次に、前/後のそれぞれ 10 個のエントリイ情報を取得するために、10 回ずつ合計 20 回の Ajax 通信を履行しています。( 141-150 行 )

    これらの 21 回の通信で特に難しかったのは、10 個ずつ合計 20 個のエントリイタイトル情報を取得する通信において、その起動を適切なタイミングで行うためのコードの作成でした。

    最新エントリイ情報を取得する Ajax 通信は、たった 1 回だけで最新 10 個のエントリイ情報を取得できてしまいますので、1 回の Ajax 通信結果から 10 個の情報を拾い出すだけで事足ります。

    しかし、20 回の非同期で連続進行している最中に結果を取得するのは非常に難しかったのです。

    その困難性の打開策については次項で述べます。

  6. Ajax 通信メソッド関数の実行( 179-189 行 )

    Ajax 通信メソッドを実行する上でのポイントはそのタイミングです。

    HTML 文内の要素にアクセスするコード( popup 要素に通信結果を格納する等 )は、その対象が存在しなければ機能しません。つまり Ajax 通信結果を格納する popup 要素が存在していなければ通信結果は表示出来ません。しかし、だからといって、通信開始を DOM 読み込み完了後にしたのでは、背景で静かに駆動してくれる Ajax 通信を折角利用するメリットが半減してしまいます。そこで HTML 内のタグにアクセスするコードやイベントハンドラー部分だけに、DOM Ready メソッドを適用することにして、DOM 読み込み完了前に Ajax 通信を開始することとしました。

    次に、連続する Ajax 通信から結果を正確に取得するコードにおいて最大のポイントとなったことが 2 つあります。

    第一のポイントは timer を使うことです。( この方式に到達するまでに数ヶ月の時を要してしまいました。 )

    これにより先行通信と後続通信との間に必要最小限のタイムラグを置くことが出来、先行通信結果の一部を後続通信で利用することを可能としました。。

    第二に、複数の Ajax 通信を行う場合で先行する通信結果の一部の値を後続の通信で使用する場合には、先行通信が終わったことを確実に Javascript に知らせなければなりません。そして確実に先行通信が終わってから後続通信を開始しなければなりません。

    そのためには、先行通信が終わったことを知らせるフラグが必要となり、そのフラグとして jQuery.active プロパティを活用したのです。

    こうして jQuery.active フラグの値に応じて、setInterval timer を停止し、あるいは継続させるようにしました。

  7. popup要素そのものの位置と表示の制御( 35-56 行 )

    ナビゲーションバーに mouseover した時に出現させるポップアップの位置は、当該ナビゲーションバーの近傍が相応しいと誰しも考えるでしょう。

    今回はナビゲーションバーの直下に表示するようにさせたかったので、最初は my コードで長年使用してきた位置表示用のコードを利用してみました。

    しかし折角 jQuery を活用するのですから、改めてそのコードを十分に利用した方が得策であると判断し、CSS に係る jQuery.js コードをざっと見渡し、本家頁のドキュメントを概観して、十分にその機能が果たせることが分かったので、フルに活用してみました。

    利用したメソッドは以下の通りです。

    $(~).width()、$(~).css()、$(~).position().left、$(~).position().top

  8. popup要素を表示/非表示するためのマウスイベント

    よく使われる popup は或る要素(= popup 発生元となる)上で mouseover イベントが発生した場合に、その近傍に小窓を popup させると共に、当該発生元要素で mouseout イベントが発生した場合に当該 popup を非表示にするものです。

    しかし、今回はそれだけでは駄目です。ナビゲーション要素( A 要素)に mouseover した時に popup 要素( B 要素)を表示させる点は同様ですが、その後 popup の中に mouseover した時、つまりA 要素から mouseout して B 要素に mouseover した時に、当該 popup を消してしまっては意味がありません。

    B 要素(popup)は、A 又は B 要素から mouseover した時に消えるようにしなければなりません。併せて B 要素から mouseout した時には、その行き先が A 要素でない場合にだけ B 要素を消さなければなりません。

    つまり2つの要素間を mouseover/out/move する複雑なイベントを処理する必要があります。そこで今回は relatedTarget(IE以外)プロパティ又は toElement(IE専用)プロパティを活用することにしました。

    2つの要素間を mouseover/out するイベントを処理する場合によく使われる方法は setTimeout メソッドの利用です。

    A要素(それには mouseout イベントがバインドされており、そのイベントハンドラー関数は B 要素を隠蔽するもの)から mouseout した時に、B 要素を隠蔽する関数の駆動に timer をセットしておき、 B 要素に mouseover した場合には、このタイマーを停止させて B 要素が隠蔽されることを防ぐものです。この方法では同時に B 要素からの mouseout イベントハンドラー関数にも、同じタイマーをセットすることになります。

    この方法はちらつきを防止する上でも有効であり、実はこのサイトのメニュー表示に、タイマー付きの mouseout イベントハンドラー関数を使用しています。

    しかしながら、この方法には1つ欠点があります。それは popup が消えるのに所定の時間を要すると言う点です。必要がない時に直ぐに popup が消えてくれないのです。この欠点をなくすために今回は relatedTarget(又はtoElement)プロパティを利用することにしました。

    ところで、これらの mouse カーソルの「行き先」情報を有するプロパティは、mouseover/out イベントだけでしか使えないプロパティです。さて ver 1.2.2 以降の jQuery.js の hover メソッドにおいては IE の場合 mouseenter/leave メソッドを起動するように改変されました。つまり IE で toElementプロパティを使おうと思えば、 jQuery の hover メソッドは利用出来ないのです。

    こうして popup を引き起こすナビゲーションバー上での mouseover/out イベント処理に関しては、敢えて DOM 0 レベルの「メソッドによるイベントハンドラー」を使うことにしました。( 58-72 行 )

  9. relatedTarget と toElement メソッド利用上の注意点

    ナビゲーションバーに mouseover した時に popup 表示が引き起こされますが、この popup 内に mousemove する時に relatedTarget 又はtoelement プロパティを活用します。

    そして簡潔に済ますために3つの異なる popup 要素には class 名「 popup 」が振ってあります。(22-25行参照)これは、

    1: var itsClassName = e ? e.relatedTarget.class : window.event.toElement.class;

    2: if (itsClassName!="popup") $(".popup").css("visibility","hidden");

    と書いて3つの popup 要素に mouseover した場合にはそれを消さないようにしたかったのです。

    そして FireFox ではそれに成功したのですが、IE では全く駄目でした。1行目が有効に働かないのです。仕方なく.id の場合には巧くいくので、やむなくこちら(29-38行)にあるように idName を頼りにして relatedTarget 等を利用することにしました。

  10. 個別エントリイ表示以外のモードの時の扱い

    月別、カテゴリイ別等の表示の場合には今回の Ajax 通信は一切関係がないので、コードの冒頭に表示モードチェックを行うようにして、無駄を排除しました。

  11. コード進行経過時間の取得と表示

    これが必要となったのは、背景で静かに進行する Ajax 通信の進行過程を何とか把握し明示させたいと思ったためです。

    そのための固有の変数を jQuery グローバル変数のプロパティとして設定し( 11-19 行 )、コードの随所に現在時刻を取得する関数を埋め込んで、通信開始/終了、コード進行開始/終了等の経過時間を計測するようにしました。

    当然その取得値をpopup枠内に表示するようにしたことは言うまでもありません。( 168-175 行 )

    なお、popup内に表示される所要時間について一言触れておくべきでしょう。

    この所要時間は各値を合計しても全体の所要時間と一致しません。以前エントリイと以後エントリイの情報を取得するための Ajax 通信は、20 回の連続する通信であり、これらの全ては殆ど同時に開始されるからです。

▲ToTop

2. 境界領域( 直前/直後のエントリイ数が設定した表示数に満たない場合 )への対応

最新エントリイを開いている時には直後エントリイは存在しませんし、(10個のエントリイを対象とした場合。以下同様)最新10以下のエントリイを開いている時には直後エントリイ数は10に満ちません。またエントリイ番号 10 以内のエントリイを見ている時には直前エントリイは 10 に満ちません。この、いわば境界領域における挙動の制御にかなり時間を要しました。

ここで行った Ajax 通信で取得する情報は、各エントリイの HTML 文と RSS 配信にも利用されている最新情報に係る xml 文です。これらからエントリイの各種情報(タイトル、リンク、カテゴリイ及び投稿日時)を取得することが目的ですが、各エントリイの情報を獲得するのに不可欠な第一義的情報は、その URI アドレスであり、各エントリ毎に異なるのはそのエントリイ番号です。

具体的には、Fc2 ブログ URI 個別エントリイ表示の場合 http://username.blogN.fc2.com/blog-entry-NNN.html となりますが、このNNNを取得することが最初に行うべきことです。

こうしてエントリイ番号を頼りに複数のエントリイ情報にアクセスするのですが、最新エントリイより大きな数の NNN をもった URI アドレスにアクセスした場合、Ajax 通信はエラーを返しません。Fc2 Web サーバーは空のエントリイ部分を持つ頁をブラウザに提供するからです。

http://username.blogN.fc2.com/ までは実在するアドレス( protocol: "http:"と hostname: "username.blogN.fc2.com" の組み合わせ)なので 404 Not Found にはならず、かつその後に続く「blog-entry-NNN.html」も「論理的には」有効な文字列なのでエラーとならないのでしょう。

一方、NNN が負の値の場合には Fc2 Web サーバーはエラー頁 http://error.fc2.com/blog/ を返します。http://・・・entryの後に「--」とマイナスが2つ以上続くと論理的に不正なアドレスとみなすのでしょう。

ここに Ajax 通信は同一ホスト内でしか有効ではありませんから、今見ているブログ頁と異なるホストアドレスがサーバーから送られた時点で Ajax 通信用 Javascript コードが通信エラーを投げます。

従って、負のエントリイナンバーにアクセスしないようにするか、あるいはエラーが返された時の対応をコードに記述しなければなりません。

解決策としては、より一般化できるエラー処理を使うべきかとも思いましたが、とりあえずより簡単な方法であって同時に無駄なアクセスやエラー処理をしなくて済む方法、つまり負の値を持ったアドレスをサーバーに投げないようにしました。( 124 行)

▲ToTop

3つのエントリイタイトル取得 Ajax コードとその説明

コードはかなり巨大なもの(簡単な解説を含めて 191 行)となりました。そのため独自のファイルに纏めこれをインクルードして利用するようにしました。

いずれ完璧になればタブや不要なスペース、コメントを全て削除して圧縮版を作成するつもりですが、しばらくは非圧縮版を試験走行させるつもりです。( 2008/8/9 圧縮版を upload して使用しています。)

いずれにせよ、直前直後の10エントリイのタイトルなどが簡単に閲覧できることは、サイト情報の総覧性を高めることになりますので、私は非常に重要な情報提供であると考えています。

ということで、臥薪嘗胆したコードの全貌を以下に明らかにします。

関連する HTML 文

HTML 文においては、公式テンプレートの場合にコメントエリア( <!--comment_area--> ~ <!--/comment_area--> )内にあるナビゲーションバーを加工する必要があります。popup を当該要素の直下に表示させるためには、ナビゲーションバーをブロック要素に変更しなければなりません。そしてこのブロックを float-left スタイルを使って横一列に並べなければなりません。また DOM 操作のための id も振らねばなりません。

なお、画像をリンクタグ内に含めると IE においてマウスが離れた時に文字列を含むリンク全体が点滅するので、矢印画像はリンク外に外しました。

<div class="navi_container">
  <!--nextentry--><div id ="beforeEntryTitle" class="f_l lh_11 pl_15"
  style="background:url('http://blog1.fc2.com/image/e/64.gif') transparent no-repeat left center">
  <a href="<%nextentry_url>" onclick="this.blur();" title="<%nextentry_title>" accesskey="4">直前のEntry(4)</a></div>
  <div class="f_l lh_11"> | </div><!--/nextentry-->
  <div id ="recentEntryTitle" class="f_l lh_11"><a href="<%url>" accesskey="5">ホーム(5)</a>
  </div><!--preventry--><div class="f_l lh_11"> | </div>
  <div id ="afterEntryTitle" class="f_l lh_11 pr_15" style="background:url('http://blog1.fc2.com/image/e/63.gif') no-repeat right center transparent">
  <a href="<%preventry_url>" title="<%preventry_title>" onclick="this.blur();" accesskey="6"> 直後のEntry(6)</a></div><!--/preventry-->
  <div class="c_b"></div></div>
関連する CSS 文

(1)float-left 指定、(2) float 指定の解除、(3) popup 絶対配置要素指定───この3つをクラス名で設定しました。

その他汎用しているクラス名も活用しました。

  .f_l {float:left;}
  .c_b {clear:block;}
  .popup {
     position: absolute; z-index:1000;
     color: #eee; background-color: #2f4f4f;
     margin: 0;
     padding : 4px ;
     line-height : 1.2; text-align: left;
     border: 2px ridge #aeb;
     display: block;
     visibility: hidden;
  }
  .ta_c {text-align:center;}
  .em {font-weight:bold;}
  .lh_11 {line-height:1.1}
  .pl_15 {padding-left:1.5em}
  .pr_15 {padding-right:1.5em}
Javascript コード
  1 :/*
  2 : * fileName : get3modeEntryTitles.js
  3 : * released : 2008/03/01
  4 : * verup : 2008/07/04, 2008/08/09
  5 : */
  6 :// 個別表示モードではない場合には何もしないでコード進行を終える。
  7 :if (location.href.indexOf("entry")==-1) (function (){return;})();
  8 :else{
  9 :(function($){
 10 : var now=function(){return +new Date;}; // 現在時刻取得
 11 : $.extend({ // 所要時間計測・待機起動回数記録用 jQuery 拡張オブジェクト
 12 :  tr:{
 13 :   start:now(), // 時刻値を取得
 14 :   registerEvent:"",
 15 :   ajax:{ recent:[],before:[],after:[] },
 16 :   end:"",
 17 :   setEndingCnt:0,waitRecentAjaxCnt:0
 18 :  }
 19 : });
    // load 中であることを示す文言の登録
 20 : var loading="<div id='loading' class='ta_c'><img src='http://blog-imgs-31.fc2.com/h/k/o/hkom/loading_16.gif' width='16' height='16' border='0' alt='' /> Now Loading...</div>";
 21 : $(function(){
     // container内に以前/最新/以後の各々のエントリイタイトルを表示するタグを用意
 22 :  $("#container").append(
 23 :   "<div id='popup_before' class='popup'>"+loading+"</div>",
 24 :   "<div id='popup_recent' class='popup'>"+loading+"</div>",
 25 :   "<div id='popup_after' class='popup'>"+loading+"</div>"
 26 :  );
 27 :
 28 :  // イベント発生要素(ナビゲーションブロック)からの mouseout メソッド
 29 :  var hidePopup = function(e) {
 30 :   var itsIdName = e ? e.relatedTarget.id : window.event.toElement.id;
 31 :   if (itsIdName.indexOf("popup") < 0) $(".popup").css("visibility","hidden");
 32 :  }
 33 :
 34 :  // イベント発生要素に沿ってpopupを表示する
 35 :  var popupAlong = function (idName,width,align) {
 36 :   var targetElem = this;
 37 :   var jQidName = "#" + idName;
 38 :   var popupInst = jQuery(jQidName);
 39 :
 40 :   // left,center及びright配置を行うために CSS 値を取得する。
 41 :   var shift = $("#container").width() -(width || 400)
 42 :    - parseInt(popupInst.css("border-left-width"))
 43 :    - parseInt(popupInst.css("border-right-width"))
 44 :    - parseInt(popupInst.css("padding-left"))
 45 :    - parseInt(popupInst.css("padding-right"));
 46 :   // そして popup の横位置指定
 47 :    popupInst[0].style.left = $("#container").position().left +"px";
 48 :    popupInst[0].style.marginLeft = 
 49 :     (align == "left" ? parseInt(popupInst.css("border-left-width")) :
 50 :     align == "right" ? shift : shift/2 )+ "px";
 51 :   // Elementの高さだけ下に
 52 :   popupInst[0].style.top = $(this).position().top  + targetElem.offsetHeight +"px";
 53 :   // popupElementの幅を設定(デフォルトは600とする)
 54 :   popupInst[0].style.width = (width || 600) +"px";
 55 :   popupInst[0].style.visibility = "visible";
 56 :  }
 57 :
 58 :  // 前・最新・後リストの表示/隠蔽イベントハンドラー
 59 :  $.each( ["before","recent","after"] ,function(i,item){
 60 :   if ( !!document.getElementById( item +"EntryTitle" ) ){
 61 :    document.getElementById( item + "EntryTitle" ).onmouseover = function(){
 62 :     popupAlong.call(this,'popup_'+item ,600,['left','center','right'][i]);
 63 :    };
 64 :    document.getElementById(item + "EntryTitle").onmouseout = hidePopup;
 65 :   }
 66 :  });
 67 :
 68 :  // 表示された popup の hover イベントハンドラー
 69 :  $(".popup").hover(
 70 :   function(e){if ( $(this).css("visibility","visible") ) return;},
 71 :   function(e){ $(this).css("visibility","hidden"); }
 72 :  );
 73 : }); //End of $(function(){})
 74 :
 75 : // variable
 76 : var html = {recent:[],before:[],after:[]}, getStr={recent:0,before:0,after:0},lastNo, regExpr,thisEntryNo, complement,itval, border={before:0, after:0},realElm = {before:0,after:0};
 77 :
 78 : // 最近のタイトルを取得する関数を定義
 79 : var makeRecentEntryList = function (limit){ // limitは取得タイトル数
     // この関数内で使用する変数を定義する
 80 :  var No, subject, date, iter=0, ret=[];
 81 :  var target ={  //xml ファイル内での順番
 82 :       link:[],     //0
 83 :       title:[],     //1
 84 :   // description:[],  //2……今回は使用しない
 85 :     // content:[],    //3……今回は使用しない
 86 :       subject:[],    //4
 87 :       date:[]      //5
 88 :   };
     // Ajax 通信を行う。
 89 :  $.ajax({
      // 開いている頁のURIアドレスからhttp://○○FC2.com/?xmlを生成する
 90 :   url: /http:.+fc2\.com\//.exec(location.href)[0] + "?xml" || null,
 91 :   type: "GET",
 92 :   dataType: "xml", // データタイプ xml を指示
 93 :   success: function(xml){ //取得した xml 文書情報を引数 xml に代入
       // XML文書が取得できなかった場合「ありません。」を変数に代入
 94 :    var tmpStr = '<div>'+decodeURI("%E6%9C%80%E6%96%B0%E3%81%AE%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AA%E3%82%A4%E6%83%85%E5%A0%B1%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93")+'</div>';
 95 :    if (xml==undefined || xml==null) {getStr.recent = tmpStr; return;}
       // この時点の時刻値を取得
 96 :    $.tr.ajax.recent["start"]=now();
        // 各々の target オブジェクト(link、title等)に対して巡回処理。
        // 引数 key で target オブジェクトの各プロパティを受け取る。
       // xml文書内から item タグを抽出し、その各々に対して巡回処理。
       // ここに xml文書内にある item タグはブログの環境設定で登録した
       // エントリイ数だけ存在し、当該の各エントリイに対応している。
 97 :    $.each(target,function(key){
        // 各 item タグの各子要素から必要なタグを抽出し ret 配列に格納する。
        // 必要なタグは 0:link、1:title、4:subject、5:date であり、
        // ret[i] は i 番目の item タグの情報(つまりエントリイ情報)が格納される
        // 配列になる。ret = [ [link0,title0,subject0,data0], [],...,[] ] である。
 98 :     $.each($(xml).find("item"), function(i,n){
 99 :      ret[i]= [$(n).children().eq(0), $(n).children().eq(1), $(n).children().eq(4),$(n).children().eq(5)];
         // 取得した各エントリイの link などの4つの情報を、target オブジェクト
         // 内の各々のプロパティ配列に挿入する。
100 :      target[key].push( ret[i][iter].text() );
101 :     });
        // 変数 iter の値は target オブジェクトのプロパティ毎に順に増加する。
        // iter 値に対応する項目は順に 0:link、1:title、2:subject、3:date となる。
102 :     iter++;
103 :    });
       // xml文書から取得した諸情報をブログ内で表示するために整序する。
104 :    for (var i=0; i < limit; i++) {
        // アドレス情報(target.link[i])からエントリイナンバーを抽出する。
        // 抽出する個数は limit 値により制限される。
105 :     No = /entry-([0-9]+)/.exec(target.link[i])[1];
        // 最終のエントリイ番号を取得する。
106 :     i==0 && (lastNo = Number(No));
        // カテゴリー名は subject タグに登録されている。
107 :     subject =" , " +target.subject[i];
        // 日付情報から時刻を除去し年月日だけを抽出する。
108 :     date =" , " +target.date[i].substring(0,10);
        // 上で整序したタイトル名などを格納した配列から各要素を取り出して一連の文字
        // 列にする。
109 :     html.recent.push( "<li><a href='" + target.link[i] + "' target='_blank'>" + target.title[i] + "</a> (No." + No + subject + date + ")</li>");
110 :    }
       // 時刻を記録
111 :    $.tr.ajax.recent["end"]=now();
       // 表示された時に分かりやすいように、キャプションを付け、
       // まとめた情報を popup される絶対配置要素内に挿入する
112 :    getStr.recent = "<div class='ta_c'><em>Recent " + limit + " Entries</em></div><ul class='ml_1_5'>" + html.recent.join('') + "</ul>";
       // 表示に当たって DOM ready Listに待機させる。
113 :    $(function(){$("#popup_recent").html(getStr.recent);});
114 :   } //End of success()
115 :  }); //End of ajax()
116 : }; //End of makeRecentEntryTitle func
117 :
118 : // 前後のタイトルを取得するための準備を行う
    // 引数は順に前か後かを表す文字列と求めるタイトル数
119 : var makeEntryList = function(beforeafter,limit){
     // ローカル変数定義
120 :  var thisHTTP, getEntryNos=[], thisURL=[];
121 :  regExpr = /(http:.+entry-)([0-9]+)/;
     // 今、開いているエントリイのエントリイ番号を取得
122 :  thisEntryNo = Number(regExpr.exec(location.href)[2]);
     // 今、開いているエントリイのエントリイアドレスの番号より前の文字列を取得
123 :  thisHTTP = regExpr.exec(location.href)[1];
124 :  border[beforeafter] = Math.min(limit+1, beforeafter == "before" ? thisEntryNo :Number(lastNo)-thisEntryNo+1 );
     // マイナスの番号にならぬように調整すると共に、先行する Ajax通信
     // で取得した lastNo 値を使って最終エントリイ番号を設定する。
     // 開いているエントリイが 1 番か最終エントリイの場合
125 :  if (border[beforeafter]==1) thisURL.length=0;
     // 連続する limit 個のエントリイ URI を設定し、配列に格納する。
126 :  else {
127 :   for (var i=1; i < border[beforeafter]; i++)
128 :    thisURL.push(thisHTTP + (thisEntryNo - (beforeafter == "before" ? i : -i)) +".html" );
129 :  }
130 :  // 準備完了! Ajax 通信開始
131 :  getTitlesByAjax.call(this, beforeafter,thisURL);
132 : }
133 :
134 : // Ajax 通信により前後のエントリイタイトル等を取得する関数の定義
    // 今開いているエントリイの前後のエントリイタイトル等を Ajax 通信で取得するために
    // 必要な関数を定義する。この関数は makeEntryList()から呼び出して使用する。
    // 引数 tense は前か後を指定するための before/after 値を受け取り、thisURL は
    // タイトル名等を取得するための、全てのエントリイの URI アドレスを格納した配列である。
135 : function getTitlesByAjax(tense,thisURL){
     // エントリイ番号値が存在すれば
136 :   if ( thisURL.length != 0 ) {
137 :  regExpr = /<title>(.*)<\/title>/;
138 :  $.each(thisURL,function(i,aryitem){
      // この時点の時刻値取得
139 :   $.tr.ajax[tense][i]=[];
140 :   $.tr.ajax[tense][i]["start"]=now();
141 :   $.get(aryitem,function(data){ // data は thisURL[i] の html テキスト文
       // title 文字列からブログタイトルを削除する。
142 :    var titleStr = regExpr.exec(data)[1].substring(19);
143 :    if ( /\S+/.test(titleStr)){ // 空白だけのタイトル名は補足しない。
144 :     ++realElm[tense]; // タイトルを取得する数をカウントする。
        // 取得結果を表示用に整序して配列に格納
145 :     html[tense][i] = "<li><a href='" + aryitem + "' target='_blank'>" + titleStr +" (EntryNo." + /entry-([0-9]+)/.exec(aryitem)[1] + ")</a></li>";
146 :    }
147 :    $.tr.ajax[tense][i]["end"]=now(); // 終了時刻を記録
       // 時制が「以後」で最後のエントリイアドレスになったら、取得結果をまとめる関数を起動
148 :    if (tense == "after" && aryitem == thisURL[thisURL.length-1]) 
149 :     itval = setInterval(setEnding,20); // インターバル関数を起動
150 :   });
151 :  });
     // エントリイ番号値が存在しない場合
152 :   } else {if (tense=="after") itval = setInterval(setEnding,20);}
153 : };
154 :
    // 最終処理用の関数を定義
155 : var setEnding = function (){
156 :  var AjaxLog=""; $.tr.setEndingCnt++; // 繰り返し数を記録
157 :  if (jQuery.active==0){ // 全ての Ajax 通信結果が取得出来ていれば
      // itval 変数があればタイマーをクリアし、その値を null 値とする。
158 :   if (itval) {clearInterval(itval);itval=null;}
      // 以前/以後の順に
159 :   $.each(["before","after"],function(i,tense){
160 :    if (realElm[tense]==0) // 1 つも値がなければ
        // 変数値にその旨を示す情報を設定する。
161 :     getStr[tense]="<div class='ta_c'>"+ (tense=='before' ? 'Before ' : 'After ') + "Entry "+ decodeURI('%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82') + "</div>";
       // 1 つ以上の値があれば
162 :    else 
        // 欠番がある場合にそのことを示す文字列を設定
163 :     complement = (border[tense]-1 -realElm[tense]!=0) ? 
164 :      " ( " +decodeURI("%E6%AC%A0%E7%95%AA%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82") +" )" : "";
        // 以前/以後の別に取得結果とその説明を HTML 文にまとめる。
165 :     getStr[tense] = "<div class='ta_c'><strong>"+ (tense=='before' ? 'Before ' : 'After ') + realElm[tense] + " Entries" + complement +"</strong></div><ul style='margin-left:1.5em;list-style-type:disc'>" + html[tense].join('') + "</ul>";
       // 以前タイトル値取得所要時間計測結果処理
166 :    var beforeTime=$.tr.ajax.before.length ? "<li>以前タイトル取得 Ajax 通信所要時間: "+ ($.tr.ajax.before[realElm.before-1].end-$.tr.ajax.before[0].start)/1000 +" 秒</li>" : "";
       // 以後タイトル値取得所要時間計測結果処理
167 :    var afterTime=$.tr.ajax.after.length ? "<li>以後タイトル取得 Ajax 通信所要時間: "+ ($.tr.ajax.after[realElm.after-1].end-$.tr.ajax.after[0].start)/1000 +" 秒</li>" : "";
       // 所要時間を示すための文字列を構成する。
168 :    AjaxLog ="<ul style='margin:0.5em;border-top:white dotted 1px;padding:0.5em 0.5em 0  1em;list-style-type:circle'>"+
169 :     "<li>クリック後 Ajax 通信開始迄の所要時間: "+($.tr.ajax.recent.start-$.tr.start)/1000 +" 秒</li>"+
170 :     "<li>最新タイトル取得 Ajax 通信所要時間: "+ ($.tr.ajax.recent.end-$.tr.ajax.recent.start)/1000 +" 秒</li>"+ beforeTime + afterTime +
171 :     "<li>このプロジェクト全体の所要時間: "+ (($.tr.end=now())-$.tr.start)/1000 +" 秒</li></ul>"+
        // この頁へのリンクをボタンで設置
172 :     <div style='text-align:right;margin:-2em 1em 0.5em 0 '><button onclick='this.blur();window.open(\"http://hkom.blog1.fc2.com/blog-entry-626.html\",target=\"_blank\")'>この Ajax 通信や所要時間について</button></div>";
       // 取得結果を表示させるために DOM Ready 登録する。
173 :    $(function(){$("#popup_"+tense).html(getStr[tense]+AjaxLog)});
174 :   });
      // 最新エントリイ情報の所要時間記録を取得結果表示 HTML 文に追記する。
175 :   $(function(){$("#popup_recent").append(AjaxLog)});
176 :  }
177 : }
178 :
179 : // 前後及び最新のタイトルリスト作成
180 : makeRecentEntryList(10); // 最近リスト取得実行
    // 反復待機関数
181 : var nextAjaxTimer = function(){
182 :  $.tr.waitRecentAjaxCnt++; // 反復回数を記録
     // Recent Entries'Ajax 通信結果が取得出来ていれば
183 :  if (jQuery.active==0) {
      // インターバル変数を無効にする。
184 :   if (ival) {clearInterval(ival);ival=null;}
185 :   // ここは連続して履行しても問題なく取得結果を html 化できる。
186 :   makeEntryList("before",10); // 以前エントリイ
187 :   makeEntryList("after",10);  // 以後エントリイ
188 :  }
189 : }
    // 待機関数を間欠的に起動する。
190 : var ival = setInterval(nextAjaxTimer,100);
   // 無名関数を引数付きで起動する
191 :})(jQuery);
192 :}

 90%近いシェアを握っているインターネットエクスプローラの描画エンジンを利用したタブbrowser。沢山のタブbrowserがあるが、多機能、カスタマイズフリー、スクリプト利用等で一日の長がある。Gekkoエンジンへの対応も行われ、IEからの自立独立の方向に向かっている。2005年7月にはIE7が登場する見通しの中で、今後の発展が望まれる。

 多様なCSS作成支援機能を備えた、タグ入力式 HTML&CSS作成支援エディタ。スキンデザインもすっきりしている。テキストエディター上で作成するよりも確実で安全にタグ打ちが出来る。
文字コードを選べないのが欠点。

 StyleNote同様のタグ入力式 HTML&CSS 作成支援エディタ。長年使用してきたが現在StyleNoteに乗り換えつつある。

 クリップボード履歴情報を活用する為のソフト。画像まで履歴を取ってくれるのが嬉しい。このソフトを使わない日は絶対ない程に重宝し、愛用している。

 起動中のウィンドウの「コピーできない」説明文などの文字列を取得し、コピー可能な文字データにするツール。何かと便利。

 ストリーミングデータを保存することが出来るソフト。動画利用には不可欠なソフトだ。

 無料ながらレイヤー機能を有し、スクリプトによる拡張も可能な、sleipnir作者が提供している優れもの画像編集ソフト。

 画面キャプチャソフトと言えばこれに勝るものなし、ではないだろうか? 様々な取得方法を有しており、ブログ作成にもHomepage作成に不可欠だ。Jtrimと並んでWoodyBellsの作品。

 複数ファイルの同時編集は出来ないが、透過pngも作れる画像編集ソフト。
(以下当該サイトから抜粋)初心者にも簡単に操作が出来るフォトレタッチソフトです。多くの加工機能で画像に様々な効果を与えることができます。非常に軽快に動作するため、ストレスなく操作できます。

 Animation Gifファイルを作れる無料ソフト。

 キャプチャソフト。画面内にサイト全体が表示しきれない場合でも、これを使えば全体をキャプチャすることが出来る。

 画像処理。画像のフォーマット変換のみならず、色数やサイズ、圧縮率の変更まで一括処理できてしまう『BatchGOO!』は、大量の画像をまとめて処理したいときに大変便利なソフト。BMP, TIFF, JPEG, PCX, PNG の相互変換をはじめ、色数・サイズ・解像度の統一、JPEG圧縮率の調節など、ホームページ用の画像や携帯電話用の壁紙を揃えるのに抜群の相性を見せる。(Vectorの当該ソフト紹介頁より抜粋引用)

 名前から直ぐに想像が付くように画像のサイズを測るためのソフトだ。Homepage作成には欠かせない。2カラム、3カラムのレイアウトを行う場合に大変重宝する。

 ランチャーソフトは沢山あるが、中でもこれが一押しだ。2年以上使ってきたがその操作性には毎日満足している。これを使い始めてからデスクトップには一切のアイコンを表示することをやめてしまった。

 AdobeReader7によって、起動時間が長すぎるという長年のユーザーの不満はある程度解消した。そのためこの高速化ソフトは存在価値が低下してしまったかもしれない。AdobeReader6迄はこのソフトによる起動高速化で恩恵を受けてきた。

 IE専用が難点だが、様々なサイト内でIDやパスワードを入力するのに重宝するソフト。コンテキストメニューから簡単に起動できるのがGood! sleipnir等のIEの描画エンジンを利用しているブラウザでも使える。

 利用しているパソコンの諸元値を取得するには、このソフトがベストだ。インストール済みソフトの一覧が取得できるのも嬉しい。

 WMPは機能が豊富なだけ重い。RealPlayerも同様だ。そこでMedia Player Classicを使いたい。動作が軽快なだけではなく、対応しているファイル形式もすこぶる多く、これひとつで、wmvもrmも表示できてしまうのだから凄い! 数多あるMedia Playerの王様と言えるだろう。

 自宅でPCを起動しているときには必ず起動しているメディアプレーヤー。何かと過剰なWinampよりも、起動も速くスキンはシンプルだ。

 DivX, Xvid, Mov, Vob, Mpeg, Mpeg4, avi, wmv, dv, などの動画をDVD-Video形式に変換できるフリーソフト。クリックするとDVD関連ソフト紹介サイト=「DVDなToolたち」なるHomepageが開きます。