11 | 2007/12 |  01

  1. 無料サーバー

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

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


The Beatles

 いちいちHTMLで書くのはめんどくさいので、日記的文章は時々平文で書いている。
 さて、昨晩はX'masだった。それに因んだ行動は何もしていないし、する気もないが、別途書いたようにChristmasソングは大好きである。


 そこで改めてJohn Lennonの Happy Christmas を youtube で検索してみた。
 もちろん、それはあった。
 あったどころか素晴らしい映像と共にその歴史的と言って良い楽曲は奏でられた。


 そこで序でに、この際だからビートルズのyoutubeに投稿されている全曲を観てみた。
 たった30曲しか投稿されていないが、その中で気に入っている曲を全てダウンロードしたことは言うまでもない。
 youtubeの効能はまさに絶大である!


 それでも欲しかった曲のいくつかはゲットできなかったが、BEATLESの主だった曲の一部は投稿されていたこともまた、言うまでもない。


 BeatlesのOld Numbersを 当時の画像と共に改めて観てみると、「Allways 三丁目の夕日」と同感覚の「昭和」がよみがえることは間違いない。


 それにしてもHappy newYear の背景に流れる動画はあまりにも悲しい! そしてそれは余りにも真実である!
 An eye for an eye will make us all blind.──「目には目を」では、我々は皆盲いてしまうだろう。
 この日本の平和の意味、世界における日本の地位、日本の僭越、傲慢に思いを馳せざるを得ない。


 他国民、他民族の犠牲の上に成り立つ文明は、いずれは崩壊する!!───(正確な引用ではないが・・・)誰かの言葉を改めてかみしめた夜であった。

jQueryのイベントメソッドを解明してみたい。

 popup Tips が一応の完成をみたので、次には jQuery がイベントをどのように処理しているのかを解明してみたい。
 それは一般的に「 Javascript でイベントをどの様に処理するのか 」、必ずやその学習になるだろう。
 だから、イベント処理の全体像把握から始めて次第に細部を解明することになるだろう。


 また、イベント関連各種メソッドの中で多用されている jQuery().data() メソッドについて、イベント処理を理解するためにも解明しなければならないだろう。


 かくして一朝一夕では出来ないだろうが、年末年始休暇を前にして時間はたっぷりある。
 この年末年始休暇には、jQueryにおけるイベント処理と長らく懸案となっている find() メソッドの2つについて解明を試みてみようと思う。

Xmas Songs について 

 またその「季節」になった。
 街にはあちこちに飾り灯が灯り、X-masに因んだmusicが喧噪の中に流れている。


 私はこの宗教上の祭りが好きである。 正確に言えばこの祭りにまつわる音楽が好きである。
 無宗教・無神論者であり、キリスト教には微塵も関心を持ってないが、歴史と文明が築いたこのお祭りに係る音楽は好きである。


 特に、音楽的な意味において、Christmasはその文化圏においてのみならず、西欧文明に浸っている世界では大きな意味を持っていると思われる。


 何故ならば、「そのための」曲が無数に作られ、概してそれは神聖さを追求しているからである。
 「宗教はアヘンである」とある著名な故人は言った。ある意味ではその通りであると思う。時の支配者への反抗ツールであった時代には、その固有の存在意義を有していたのだろうが、権力と共存・共栄関係が築かれてしまうと、それは権力への抵抗を逸らす社会的ツールになりかねない、と思う。


 しかし、それにも拘わらず、宗教が持つ神聖さ、聖なるものへの憧憬には共感を覚える。
 そしてクリスマスソングの多くはその神聖さを追求している。あるいは家族という社会の基礎単位への思いやりや愛を希求している。

 だからXmas Songsには清冽さ、神聖さ、透明性等々の特性があるのだ。

--------------------------------------------------------
▼ My Favorite Xmas Songs


 Happy Cristmas、 O Holly Night、 AveMaria、
 o.little town of bethrehem、 we three kings
 it came upon the midnight clear
 

jQueryに学ぶJavascriptの基礎(5) 論理演算子の使い方──jQuery解読(23)

別に難しいことではない・・・と最初は思いこむ

論理演算子( && 、 || 、! )は Javascript 初心者でも特に理解に苦しむ演算子ではありません。その機能は「 及び、又は、そして否定 」と直ぐに理解できてしまいます。

さて、入門書 や著名な Web Site には例えば次のように書いてあります。

「 論理演算子は右側と左側の条件式を評価して、・・・。複数の条件式を評価するために良く用いられます。」( 出典:『JAVASCRIPT HANDBOOK 4th EDITION』p.32 )

「exp1 が真、かつ、exp2 が真であれば真を、さもなければ偽を返します。」

「 exp1 が真、または、exp2 が真であれば真を返します。」( 出典:とほほのJavascript入門・・・演算子

※ ここに exp とは expression の略であり、expression が「数式」を意味することは、改めて説明するまでもないでしょう。

初心者は、このような文章を読んで学習する訳ですが、誰しも「 条件式や数式 」から、= や != が含まれる式を左右のオペランドにするのだ、と理解します。そして以下のような「 数式 」が例示されるのを見て、論理積演算子と論理和演算子を理解し、十分に納得したと錯覚してしまうのです。

  • (a > b) || (c != d) 、 (a = 3) && (b => 3)
  • (xx == "ABC") || (xx == "abc")

そもそも「式とは何か?」──このことをきちんと説明してから「条件式」なり exp なりの単語を使ってくれていれば、以下に述べるように「 四則演算のような算術式だけが論理演算子の対象となるのではない 」ということを、誤解なく理解するのです。

しかし Javascript でいう「式」とは何か、これについて上述の2つの文章では触れていません。このことが初心者に謝った認識を与えてしまうのだと思います。

特に「 条件式 」という表現は全く戴けません。この言葉では「 オペランドは条件を定めた式である 」と完璧に誤解されます。比較式や等式が左右に来るのだと錯覚してしまいます。

▲ToTop

見たこともない論理演算子の使い方の出現

さて、jQuery.js の各行に目を凝らすと、これまで見たこともない論理演算子の使い方に遭遇し、俄に戸惑います。── && が「及び」であり、|| が「又は」である、あるいはオペランドは条件式──、というそれまでの認識だけでは、全く理解できない論理演算子の使い方が多数あるからです。

その例を jQuery.1.2.1.js からいくつか抽出してみます。行頭の数字はjsファイルにおける行数です。

  1. 36 selector = selector || document;
  2. 72 return this.setArray(
    74   selector.constructor == Array && selector ||
    78   (selector.jquery || selector.length && selector != window &&
           !selector.nodeType && selector[0] != undefined && selector[0].nodeType) &&
            jQuery.makeArray( selector ) ||
    81   [ selector ] )
  3. 132 return this.length && jQuery[ type || "attr" ]( this[0], key ) || undefined;
  4. 284 t.constructor == String ?
    285  jQuery(t).get() :
    286  t.length != undefined && (!t.nodeName || jQuery.nodeName(t, "form")) ?
    287  t : [t] )

以上のそれぞれについて説明するのは長大な文章が必要となるのでやめます。

大切なことは、「式」の意味と 上の例のような論理演算子の使い方の基礎となる 論理演算子の定義づけです。

なお、以降に記すことは全て David Flanagan著、村上列訳の『Javascript 第5版』を読んで学んだことです。

▲ToTop

式 とは何か?

それは「Javascriptインタプリタが評価して値を生成できるもの」──『Javascript第5版』にはそう書いてあります。そして極めて簡潔・明瞭・網羅的に例示があります。それを見て初めて、式とは何かが理解できました。

その結果、論理演算子の左右のオペランドに置くことの出来る式とは、四則演算的な算術式だけではなく、数値、文字列、論理値、オブジェクトリテラル、配列リテラル、変数、関数リテラルなど、まさに値を生成できるオブジュクトならば何でもござれ、であることが十分かつ確実に理解できました。

以上の理解を経て、jQuery.js で多用されている 「 オブジェクトを左右のオペランドとする 」 論理演算子の使い方と意味が、やっと判読できるようになったのです。

演算子の優先順位(抜粋)

論理演算子を利用する上で、演算子の優先順位をきちんと理解しておかないと、意図と異なる結果となってしまいます。自戒を込めて強調しなければならない、と思います。

そこで、優先順位を間違いやすい演算子の正しい優先順位を、今後のためにも記しておきます。

左側ほど優先順位が高い演算子となります。つまりより左側の演算子が先にインタプリタに処理されることになります。

++ -- 算術演算子 == != === !== && ||  ?: = ,

論理演算子の使い方をオーソドックスなコードに置き換えて理解する

そうすることで理解を確実なものに出来ると思います。

以下において obj はオブジェクトの、v は変数の意です。

  1. v = obj1 && obj2; ─→ if (obj1) v = obj2; else v = undefined;
  2. v = obj1 == obj2 && obj3 || obj4;
    ─→ if (obj1 == obj2) { if (obj3) v = obj3; else v = obj4; }
       else v = false;
  3. v = obj1 || obj2 || obj3; 
    ─→ if (obj1) v = obj1;
       else if (obj2) v = obj2;
       else if (obj3) v = obj3;
       else v = undefined;

jQuery()活用(2) Popup Tips を自作する──jQuery解読(22)

  • 初稿:2007/12/13
  • Update1:2007/12/23 Window下部への popup 飛び出し補正対策を実装。
  • Update2::2007/12/24 popupボックスの「採寸」が各起動要素毎に、一度だけで済むように工夫
  • Update3:2007/12/31 popupされる文字列取得も一度だけで済むように工夫
  • Update4:2010/7/25 全面的な改訂(プラグイン化)

なにはともあれ実例を!

popup Sample Image

上の画像がここでいう popup を表示させた例です。濃い緑色のボックスとその中の白い文字が popup です。黄緑色のボックス内にマウスカーソルをオーバーさせ、 popupが表示 されるようにして、その状態のスクリーンショットを画像化したものです。マウスカーソルの右下に popup ボックスが表示されていることが分かります。

また、この実例部分にも popup 要素を付けましたので、マウスオーバーとなっていると 「popup 実例説明画像」という文字列をコンテンツとする popup が表示されます。

ここで実現した popup の特徴
  1. この popup は後で述べるコードにより実現しており、popup を引き起こすタグ要素(以下、「popup 励起要素」と呼びます)の title 属性値を popup のコンテンツとするように設計しました。つまり、何らかの class 指定を行わなくても jQuery('*[title]') で popup 励起要素を指定することが可能です。
  2. popup 励起要素内で mousemove イベントが起きると、popup 要素はマウスカーソルに追随して移動するように設計しました。
  3. popup する内容には一般的な文字列だけではなく、任意の HTML タグ要素が指定出来ます。例えば番号付き箇条書きや画像を popup させることも可能です。

(ツールチップとしての)Popup

まず実例を提示します。

下の複数の TEST ボックス(これが popup 励起要素に指定されている)内にマウスカーソルをオーバーすると、所定のコンテンツ入り popup がマウスカーソルの右下に表示され、マウスカーソルがボックスから外れると表示が消えます。これがここでいう popup です。マウスカーソルを移動させると popup 要素は追随して移動します。

TEST1 popup コンテンツは文字列
TEST2 popup コンテンツは p 要素
TEST3 popup コンテンツは画像

TEST4 popup コンテンツは動画

動画は自動起動するように設定してあり、別の popup を表示させることにより動画を途中で終わらせることが出来ます。

そもそもこのブログでは、開設(2004年10月)数ヶ月後から随所に popup を利用してきました。その後、微調整や透明化 easing の追加などの修正を行ってきたこの popup は「古典的なイベントハンドル手法」を使用しています。つまり HTML タグの属性として onmouseover/onmouseout ハンドラーを記述する方式で実装しています。

しかし、Microsoft 社の抵抗や無視にも拘わらず、既に DOM Level2 で規定されたイベントハンドリング手法が王道となっている中で、改めて jquery.js を使って popup を作ろうと思い立ち作成しました。jquery.js を利用してどのようにそれを実現するのか、という点で、何らかの参考になれば幸いです。

なお、公開されている jQuery プラグインで toolTips で検索されるものは 103 本( 2010/7/25 現在 )もあり、その多くは可変性・柔軟性において、ここで実現した popup よりも遙かに優れています。それにも拘わらず、独自のプラグインを作成したのは、偏に学習のためであり、どこまで jquery.js を使いこなせるのか、いわば自分を試すためです。

▲ToTop

ここで述べた popup 表示を実現しているコードは次の通りです。

  1:(function($){ //無名関数の指定
  2://jQueryインスタンスメソッド:setPopup の登録
  3:$.fn.setPopup=function(obj){
  4:/* setPopup jQuery インスタンスメソッド
  5: * 任意の要素に記述されている title 属性値を当該要素の popup コンテンツとするためのプラグイン
  6: * 起動例(1): $(function(){$("*[title]").setPopup();});
  7: *  title 属性を有する全ての要素をpopupする対象とする。
  8: * 起動例(2): $(function(){$("*").setPopup();});
  9: *  全ての要素をpopupする対象とする。
 10: * 起動例(3): $(function(){$("p,li").setPopup();});
 11: *  p タグ要素と li タグ要素を popup する対象とする。
 12: * 2010/07/25 Release
 13: */
 14:  //既定値オブジェクトから各プロパティを o オブジェクトに複写
 15:  // obj = {bgColor:"anyColor",maxWidth:"anypx"};
 16:  var opt = obj;
 17:  if (opt && (typeof opt !=="object" || opt.constructor !== Object))
 18:    opt={};
 19:  var o = $.extend({}, $.fn.setPopup.opts, opt),
 20:      //画面サイズ計測関数定義
 21:      getInnerSize = function(obj){
 22:        return {W:$(obj).width(), H:$(obj).height()}
 23:      },
 24:      //スクロール値計測関数定義
 25:      getScroll =  function(obj){
 26:        return {X:$(obj).scrollLeft(), Y:$(obj).scrollTop()}
 27:      };
 28:  //setPopup メソッド起動元 jQuery インスタンスの記憶
 29:  o.$firePopup = this;
 30:  //DOM Ready 登録
 31:  $(function(){
 32:    o.screen = getInnerSize(window); //画面サイズ計測
 33:    o.scroll = getScroll(window); //スクロール値計測
 34:    //Window リサイズイベントハンドラーの登録
 35:    $(window).resize(function(){o.screen = getInnerSize(window)})
 36:      //Window スクロールイベントハンドラーの登録
 37:      .scroll(function(){o.scroll = getScroll(window)});
 38:    //マウス現在座標値の取得メソッド
 39:    $(document.body).mousemove(function(e){
 40:      o.mouse = {  X: e.pageX, Y: e.pageY };
 41:    });
 42:    //popup要素の作成・用意
 43:    o.$popup = $("<div id='popup' />").css({
 44:      position:"absolute", zIndex:10, padding:o.popupPadding, color:o.color,
 45:      background:o.bgColor, border:o.bdWidth + o.bdStyle + o.bdColor,
 46:      textAlign:"left", display:"none"
 47:    }).appendTo(document.body);
 48:
 49:    // popup 要素の設定
 50:    var w,m=[],j,jqIns; //局所変数を用意
 51:    // popup を引き起こす jQuery インスタンス毎にイテレート処理を実施
 52:    o.$firePopup.each(function(i){
 53:      // popup を引き起こす各対象毎に、その title 属性値を
 54:      // popup 要素のコンテンツとするために配列に登録する
 55:      o.content[i] = $(this).attr("title") || null;
 56:      // popup を引き起こす各対象毎に、contentがあれば、
 57:      // popup 要素の算出スタイル幅を測定し、その値を変数 w に格納する。
 58:      w = o.content[i] && o.$popup.html(o.content[i]).width() || null;
 59:      // w が存在する場合、既定の最大値未満ならばそのまま使用し、
 60:          // さもなければ既定の最大値とし、w がない場合には null とする。
 61:      o.popupW[i] = w && (w < o.popupMaxWidth ? w : o.popupMaxWidth) || null;
 62:      // popupすべきコンテンツに img タグがあるかどうか調査し結果を配列 m に格納する。
 63:      m = /(<img\s)[^<]*(src\s?=\s?[\"\'][^\"\']+[\"\']+?)[^<]*(\s\/?>)+?/.exec(o.popupContent[i]);
 64:      // もし変数 m があったならば(img タグだった場合)
 65:      if (m && m[1] ==="<img "){
 66:        // 当該 img タグから jQuery インスタンスを作り、
 67:        // 絶対配置の隠蔽指定をした上で body に挿入する。
 68:        jqIns = $(m[0]).css({position:"absolute",display:"none"}).appendTo(document.body);
 69:        // 挿入された img 要素の算出スタイル値を計算させ、
 70:        // margin 辺間距離から内容辺間距離の差を既に設定済みの o.popupW[i] から
 71:        // 差し引く。
 72:        w = o.popupW[i] - (jqIns.outerWidth(true) - jqIns.width());
 73:        // img タグ要素の width 属性値を書き換えて、画像がpopup
 74:        // ボックスからはみ出さないよう適正に縮小表示されるようにする。
 75:        o.popupContent[i]=o.popupContent[i].replace(m[0],m[1]+m[2]+' border=0 width=\''+ w +'\''+m[3]);
 76:      }
 77:    }).hover( // hover イベントハンドラー登録
 78:      function(){ // mouseover イベントハンドラー
 79:      // 今マウスオーバーとなっている要素の、jQuery インスタンス
 80:      // における登録番号を取得する。
 81:      j = o.$firePopup.index(this);
 82:      // j 番目を popup 要素のコンテンツとして代入してから
 83:      // コンテンツがあれば popup 要素の横幅を設定する。
 84:      if (o.content[j]) {
 85:        o.$popup.html(o.popupContent[j]).width(o.w[j] +"px").fadeIn();
 86:        // title 属性値を削除してブラウザ既定の ツールチップ表示
 87:        // を抑止する。
 88:        $(this).attr("title", "");
 89:    },function (){ // mouseout ハンドラー
 90:      if (o.content[j]) o.$popup.fadeOut(); // コンテンツがあれば隠蔽する
 91:    }).mousemove(function(){ // firePopup 要素内で、マウスカーソルが
 92:     // 動いた時のイベントハンドラー登録
 93:      o.$popup.css({
 94:        // window からはみ出さないように left 値を調整
 95:        left:Math.min(o.mouse.X + o.popupOffset.X,
 96:          o.scroll.X + o.screen.W- o.$popup.outerWidth(true))+"px",
 97:        // window からはみ出さないように height 値を調整
 98:        top:Math.min(o.mouse.Y + o.popupOffset.Y,
 99:          o.scroll.Y + o.screen.H - o.$popup.outerHeight(true))+"px"
100:      });
101:    });
102:  });
103:}})(jQuery);
104:// 既定値を登録する。
105:$.fn.setPopup.opts={
106:  content : [], // 文字列の格納配列
107:  width : [], // popup 要素幅の格納配列
108:  maxWidth : 400, // popup 要素幅の最大幅
109:  popupOffset : {X:16,Y:16}, // popup要素とマウスカーソルの相対的な位置関係を定義
110:  popupPadding : "4px", // popup 要素のパディング値
111:  bgColor: "#eff", // popup 要素背景色
112:  bdWidth: "2px",// popup 要素のボーダー幅
113:  bdStyle: "outset", // popup 要素のボーダースタイル
114:  bdColor: "lightcyan",  // popup 要素のボーダー色
115:  color: "black"  // popup の文字色
116:};

▲ToTop

上のコードの説明と留意点

以下のアンダーライン部には title 属性を設定してあるので popup が表示されます。

構成
  1. jQuery()を最大限利用しました

    どれだけ jquery.js を使いこなせるか、それを課題としたので可能な限り jQuery インスタンスを多用しました。

  2. 初期化ブロック(15~25 行)

    jQuery インスタンス setPopup のプロパティである opts オブジェクトに既定値を設定しておき、ここから変数 o に既定値を複写します。勿論、setPopup メソッドが引数付きで起動された場合には、その引数値が採用されるようにしました

    またスクリーンサイズとスクロール値を取得する 2 つの関数を定義しました。これらは popup 要素の画面からのはみ出しを防止するために必要となる関数です。

    25行では setPopup メソッドの起動元となった jQuery インスタンスへの参照を o オブジェクトの $firePopup プロパティに代入しています。プロパティ名の最初の 1 文字に $ を付けたのは、それが jQuery インスタンスへの参照であることを明示的に示すためであり、この手法は他のプラグインの学習から学びました。

  3. DOM Ready 関数(27 ~ 97 行)

    setPopup メソッドの大半は、その性質上当該頁が読み込まれるのを待たなければ作動させらません。そこで DOM Ready 関数を使いました。

    28 ~ 37 行はスクリーンサイズとスクロール量を計測するものです。28行と29行で頁が開いた時のそれらを計算させ、31 ~ 37 行で window がリサイズされた場合とスクロールされた場合のイベントハンドラーを登録し、それらの変化に対応させています。

  4. 頁内 mousemove イベント(35 ~ 37 行)

    mousemove イベントハンドラーの登録です。頁内でマウスカーソルが動いた時に、マウスカーソルの現在座標値を取得させ o.mouse オブジェクトに値を代入します。

  5. popup要素作成(39 ~ 43 行)

    popup 要素は事前にブログエントリイ内に用意するのではなく、コードによって自動生成させます。勿論作成後に表示させてはなりませんので、display 値を "none" としています。

  6. popup 励起要素に対する様々な設定(48 ~ 95 行)

    47 行に亘る長いブロックでは、jQuery インスタンスのメソッドチェーンを多用しました。popup 励起要素に対する様々な設定を 1 つの jQuery インスタンスに対して行っています。

    48 ~ 72 行迄のブロックでは popup 励起要素各々に対して、その title 属性値を取得し、それを popup 要素内に収めた場合のコンテンツ幅(カレントスタイル値)を算出し、popup 要素のコンテンツ横幅を設定しています。

    ここでは popup 要素のカレントスタイル値の取得が重要なポイントです。文字列の横幅は、一般にブラウザがそれを描かなければ設定されません。jQuery(要素).width() メソッドは、CSSスタイル display 値が none となっている要素に対しても、カレントスタイル値を算出してくれる便利なメソッドです。

  7. popup コンテンツが画像の場合の処理(58 ~ 71 行)

    ここが今回のコード作成で最も苦労した箇所です。

    既に実例で示したように、ここで作った popup はそのコンテンツとして文字列だけではなく、HTML タグ全般を許容します。つまり箇条書きや画像も popup させられます。(勿論動画も可能です。まだ厳密には対応させていませんが、動画 HTML 文に一寸手を加えればここで作った popup 要素内に動画を表示させ自動再生させることが出来ます。)しかし、画像の場合そのサイズが一般に img タグ内に記述されていて、かつここで設定した popup 要素の既定値である 400px を遙かに越える場合が多々あり得ます。そして popup の性質上 1000px を越えるような画像の元サイズで popup することはあり得ないことですから、適正な大きさに縮小表示させなければなりません。

    ここで縮小表示させるために採用した方法は、画像の src 属性値を書き換えるものです。しかし、その属性値の書き換えは容易には出来ませんでした。画像のソース URL 値にはwidth 値が指定されているものもあれば、ないものもありますし、border 属性が設定されている場合もあります。alt 属性もあったりなかったりします。

    このように多様性のある img タグ要素に対して、所定の最大幅を超えないように画像を表示させるためには、正規表現を用いて文字列置換を行うしか方法がない、と判断しそれを実行しました。その正規表現が 58 行の ”呪文 ”です。

    なお、まだ実現していませんが、動画についても同様の方法で正規表現を使ってサイズ調整することを考えています。当面は動画毎に HTML 文に若干手を加えることで対応していきます。

    更に、一般にブログでは img タグに対して何らかの CSS 値が設定されている場合があります。padding 値などが既定のスタイル値としてテンプレートに設定されている場合が多いのです。そこで、画像をブラウザに表示させてカレントスタイル width 値を取得させ、画像のコンテンツ幅と margin 値迄を含む周囲の装飾的な幅との差を算出し、これをpopup要素のコンテンツ幅から差し引くことにより、popup 要素の最大幅に画像が収まるようにしました。これを行っているのが、60 ~ 71 行です。

  8. popp 励起要素に対する hover イベントハンドラー登録(72 ~ 85 行)

    ここでは現在対象となっている popup 励起要素がどれなのかを、どのようにして Javascript インタプリタに知らせるか、それが最大の問題でした。76 行でそれを行っていますが、jQuery(要素).index メソッドの活用が味噌でした。

    popup 励起要素内でマウスが動いた時のイベントハンドラー(85 ~ 96行)では、window 内から popup 要素がはみ出さないよう、スクリーンサイズ、スクロール値並びにマウスの現在値から、popup 要素の配置位置を設定しました。

▲ToTop

留意点
  1. popupを発生させる要素は、title 属性を持ち得る要素ならば、何でも構わないようにしました。しかも title 属性という一般的な属性値を popup コンテンツとし、汎用化を追求しました。

  2. popup コンテンツは文字列だけではなく、広く HTML 文がコンテンツたり得ます。但し動画には未だ対応していません。

  3. popup ボックスの背景色、文字色、枠等々は既定値として、jQueryインスタンス setPopup オブジェクトのプロパティで設定しました。

  4. タグ内の title 属性の値を popup 内のコンテンツとしたため、title 属性に係るブラウザ既定の動きを消さなければなりません。 title 値が二重に popup されてしまうからです。そのために、title = " " を利用しました。

jQuery()を使って吹き出し(popupWindow)を作ってみたい。

 jQueryをふんだんに使って簡潔明瞭に、しかもタグ属性には一切のJavascriptを記述することなく、マウスオーバー/アウトのイベント駆動を実現しようと思っている。

こちらに完成品があります。↓

jQuery() 活用(2) Popup Tips──jQuery解読(22)


1. mouseover時に表示させるノードをbody文末にappendする。
2. mouseoverさせるタグにあるtitle属性に書いた文字をpopupさせるものとする。
 その際には、title属性がある場合の既定の動きを抑制する。
3. popupするwindowの幅を何らかの形で指定する。但し当該タグのwidthではないのでど
 うするか・・・・。
  それは、class="popup500"等にしよう。幅のパターンは決して無尽蔵ではなく、それ
 どころか数パターンあれば良いのだから・・・。300、400、500、600 の4つで十分だろう。
4. 以上で要素ノードでの作業はお仕舞い。後はCSSの出番だ。popup表示のスタイル設
 定である。
  padding、border、background、line-height、そしてwidthを設定すればよいだろう。
5. 最後に動きをまとめるコードを書く。
 (1) class名検索でpopup500等のタグをリストアップする。これはその頁が再描画または
  非表示になるまで、何度も検索を掛けたくないから、jQueryのプロパティに取得ノードを
  記憶させるべきだろう。
 (2) 抽出されたタグにmouseover ,mouseoutのToggle イベントを設定する関数を作る。
   その中に、mouseover時のpopup表示、mouseout時のそれの隠蔽のためのコードを
  書く。
 (3) この関数を当該サイトオープン時に実行させる。
--------------------------------------------------------
 数年ぶりに平文で、つまりhtmlタグを使わないで書いてみました。

FC2ブログ管理画面問題──12月10日から新管理画面に完全移行だそうだ

本当に大丈夫?

新管理画面の様々な問題点は phpbb で散々論議されていた。そして私も上記のようにこのブログ上で何度か発信した。

全ての問題が解決した、と Fc2 ブログ管理者が判断したのだろう。ついに旧管理画面は明日をもって廃止され、10日移行は新管理画面だけの利用となるようだ。

「日時:12月10日月曜日の13時より移行開始。当日の上記の日時以後、管理画面へアクセスいたしますと、移行が完了したアカウントより新管理画面へログインされます。」→引用先 ブログ管理者用お知らせ

本当に大丈夫なのだろうか?───使い勝手、速度等々に問題はないのだろうか?

これまでの経緯を踏まえると一抹の疑念と不安を抱かざるを得ない。

携帯版管理画面も新管理画面に移行!

一方、「この度、blog1サーバーをご利用のユーザー様のアカウント限定で、携帯管理画面リニューアル版のテスト公開を致します。」とのメールが 2007/12/6 に届いた。

ここには、PC 版だけではなく携帯版をも、新管理画面に移行しようとする Fc2 の強い意志を感じる。
意見・要望の申し出先 Web サイト一覧(Fc2からの情報による)

「現在はblog1サーバーのみの公開ですが、正式公開の目処が立ち次第、全サーバーに適用となります。」とのことなので、いつころ正式公開の目処が立つかは全く不明であるとしても、近い将来携帯版も新管理画面に移行することになることは間違いない。

といっても、携帯版は全く利用してないので個人的には関係ないのであるが・・・。

Microsoft Office 2003 SP3を導入すると、入力した文字が見えなくなったり、黒く反転して表示される問題について

まさに表題の現象が私のワード、エクセルでも起きていた。原因が分からずネットサーフィンして解決したが、これは Microsoft 社による ジャストシステムへの嫌がらせと思えて仕方ない。

私は、ATOK の変換性能や日本語入力・変換に関わる性能のあれこれは、MSIMEよりも数段優れていると確信しているし、一太郎Ver3の時点から、松茸に乗り換えたり、VJE 等も使ったりしつつ、最終的にATOKにたどり着いた。Windows 全盛時代となってからも、MSIME が決して ATOK には追いついていないと、実際に使ってみて確信を得ている。

日本語変換は日本語を十分に研究してきたジャストシステム社に委ねるべきだ、などと言うつもりはないが、OSもアプリもそして言語入力システムも、その全てを押さえんとするかのマイクロソフト社の姿勢そのものに納得がいかない。あれにもこれにも手を出し、市場を席巻・制覇しようとする一企業の行動そのものが、社会全体の視点で見れば極めて由々しき戦略であると思う。

そんな中で今回の「事件」である。

それは嫌がらせ以外の何物でもない。

ますます MSIME を使いたくない気持ちが高まってきたことは言うまでもない。

新管理画面は不都合が多く、動作も遅い。敢えて旧管理画面を使う!

新管理画面の使用をやめる!

一昨日のエントリイで書いたとおり、新管理画面から行ったテンプレートの更新作業は成功しない。しかもファイルアップロードにしても、過去の記事の管理にしても、新管理画面はとにかく反応が遅い!

phpbbを覗くと、Fc2は新管理画面に拘泥しているようなので、一部には旧管理画面に戻れ、との声もあるが、これは通りそうもない。社是として新管理画面への移行を推し進めているのであろう。

ユーザーから相当の反発があると思われるのに、何故にそれほどまでに新管理画面に拘るのか解せないが、とにかくストレスが溜まる管理画面はゴメン被りたい。

そんな訳で本日から旧管理画面の利用に戻ることとした。

こちらの方が動作が速くストレスが溜まらないからである。

新管理画面の利便性にある程度慣れてしまったから、旧画面は使いにくい面が多々ある。しかし、テンプレートの変更が新管理画面では出来ないのだから、新に拘泥する理由は一厘もない。

近い将来最上部に設置したショートカットも全て旧管理画面へのそれに戻すことになるだろう。

jQuery()の挙動を解読する。(12) pushStack()解読 upon ver1.3.2──jQuery解読(21)

このエントリイの改訂履歴
  • 初稿:2007/12/04
  • 改訂:2009/3/8…… ver1.3.2 対応とするために全面改訂しました。

pushStack()再考

以前こちら( 簡単なインスタンスメソッドいくつか──jQuery解読(19) )で pushStack() について次のように触れました。

この pushStack() は大変興味深いメソッドです。新しいインスタンスオブジェクトの その名も prevObject プロパティに、直前の this が指し示すオブジェクトが格納されるようにコーディングされています。このメソッドは jquery.js で7箇所利用されています。

このことの意味をもう少し掘り下げてみたいと思います。この pushStack() メソッドはどの様な場合に利用するのか、と言う点を明らかにしたいのです。そうしないとこのメソッドを本当に分かったことにはならないと思うからです。

jQuery(obj) 再解析 upon ver 1.3.2

ところで、1.3.x でこのメソッドの機能が拡張されました。従前のこのメソッドは、新しい jQuery インスタンス( newIns とする)を作成する際に、既に在る別の jQuery インスタンス( これを仮に oldIns とする)を、newIns のプロパティに格納するだけの単純な機能しかありませんでした。

ver1.3.x では pushStack() メソッドの引数を 2 つ増やして 3 つとし、find() メソッドやその他のインスタンスメソッドをそのメソッドの引き数付きで指定出来るようになりました。

この結果、単に newIns のプロパティに oldIns を格納するだけでなく、oldIns に対して様々な jQuery インスタンスメソッドを実行する際に、当該の oldIns とメソッド情報をセットにして newIns のプロパティに格納出来るようになりました。

これにより、end() メソッドで遡れる「過去」が拡張されたはずですが、その件はまだ未確認です。

以下に、こうした機能拡張を踏まえて、改めて pushStack() メソッドのコードを解読してみます。以下の色づけしたコメントがコード進行過程を解析したつもりの解説です。

119: // Take an array of elements and push it onto the stack
120: // (returning the new matched element set)
121: pushStack: function( elems, name, selector ) {
122:  // Build a new jQuery matched element set
    // elems をそのプロパティ値に保持する新しい jQuery
    // インスタンスを作成し、それを ret に代入する。
123:  var ret = jQuery( elems );
124:
125:  // Add the old object onto the stack (as a reference)
    // pushStackの起動元オブジェクトthisを ret オブジェクトの prevObject
    // プロパティに代入する。
126:  ret.prevObject = this;
127:
    // this の contextプロパティ値を ret の context プロパティに代入する。
128:  ret.context = this.context;
129:
130:  if ( name === "find" ) // 第 2 引数が文字列 find の時には
     // 起動元に selector プロパティがあればその値の後に半角スペース
     // を付け、更に 第 3 引数の selector を付けて ret の selector プロ
     // パティ値とする。 例:this.selector = "document", selector = "p"
     // の時には、→ ret.selector = "document p" となる。
     // 尚 this.selector プロパティがなければ、右辺は selector だけとなる。
     // 従って引数 selector がなければ ret.selector = "" となる。
131:   ret.selector = this.selector + (this.selector ? " " : "") + selector;
    // find ではない第 2 引数 name が存在している場合には
132:  else if ( name )
     // 例:ret.selector = "thisSelctor.method(arg)" つまり、thisSelector
     // を起動元とする引数付き method を selector プロパティ値とする。
133:   ret.selector = this.selector + "." + name + "(" + selector + ")";
134:
135:  // Return the newly-formed element set
136:  return ret; // ret オブジェクトを返す。
137: },

▲ToTop

pushStack メソッドによるインスタンスオブジェクトの変化

以上のコメントは機械的な説明に過ぎない感があるので、もう少し具体的・視覚的に分かりやすい表現はないものかと思案して、次のようにプロパティの変化を表示してみました。起動元インスタンスを oldIns、 pushStack メソッドによる elems をプロパティとして持つ新しいインスタンスを newIns とすると、pushStack() メソッドによって、newIns オブジェクトのプロパティは以下のようになります。

newIns = jQuery(sel1.cont1).pushStack(elems,name,selector) によるインスタンスの変化

ここに定義から oldIns = jQuery(sel1.cont1) です。

■ name="", selector="" の場合 newIns は次のようになります。
newIns = {
  prevObject : jQuery(sel1,cont1),
  context : cont1,
  selector : sel1,
  length : N,
  0 : elem1, // elem1 は elemsにマッチする最初のノード
  1 : elem2, // 以下ノードが順に並ぶ。
  ・・・,
  N-1 : elemN,
  jquery : "1.3.2",
  ・・・
}

■ name="find", selector="newsel" の場合 newIns は次のようになります。
newIns = {
  prevObject : jQuery(sel1,cont1),
  context : cont1,
  selector : "sel1 newsel", // findメソッドで使用する検索条件が保持される
  // 以下略
}
■ name!="find", selector="newsel" の場合 newIns は次のようになります。
newIns = {
  prevObject : jQuery(sel1,cont1),
  context : cont1,
  selector : sel1.name(newsel), // sel1の name メソッドが newsel を引数として保持される
  // 以下略
}

▲ToTop

jquery.js における pushStack メソッドの実例を見る

jquery.js における実際の pushStack() メソッドの使われ方をフォローして、学習を深めようと思います。まず、find() インスタンスメソッドを見てみます。このメソッドは呼び出し元オブジェクトの中から、selector 条件にマッチするノードをヒットするためのもので、jQuery オブジェクトのプロパティに、検索結果をセットするために、pushStack() メソッドが使用されています。

なお、 find() メソッドによる検索対象が 1 つの場合と、複数ある場合とに分けてコードが綴られています。

jQuery().find() インスタンスメソッド
288: find: function( selector ) {
    // ▼ this (= jQuery インスタンス) の length プロパティが 1 の場合
289:  if ( this.length === 1 ) {
     // 空配列に対応する jQuery インスタンスオブジェクト( A )を作り、その
     // プロパティに、起動元の jQuery() インスタンスや、find の検索条件
     // である selector の情報を保持する。そして当該 A オブジェクトを
     // 変数 ret に代入する。
290:   var ret = this.pushStack( [], "find", selector );
291:   ret.length = 0; //配列のようなプロパティの length 値を 0 とする。
     // これにより次行で求めるインスタンスの配列のようなプロパティ名は 0 
     // から始まることになる。
     // this[0]、つまり jQuery インスタンスの 0 プロパティ値を対象として、
     // jQuery.find() クラスメソッドを実行し、結果を ret オブジェクトに代入する。
292:   jQuery.find( selector, this[0], ret );
293:   return ret; // 代入された ret を this に返す。
    // ▼ this (= jQuery インスタンス) の length プロパティが 1 でない場合
294:  } else {
295:   return this.pushStack( jQuery.unique(jQuery.map(this, function(elem){
	    // this のプロパティの 1 つ 1 つを対象として走査し、その中
	    // から selector 条件に合致する要素を抽出して map する。つまり、
	    // elem を検索結果で上書きする。重複がないかどうかチェックしてから
296:    return jQuery.find( selector, elem );
     // pushStack メソッドにより生成され、find 結果である elem が登録されている
     // jQuery インスタンスの selector プロパティ値を " elem selector"とする。
297:   })), "find", selector );
298:  }
299: },
slice() インスタンスメソッド

次は、pushStack() メソッドの第 2 引数が find ではない場合です。not() メソッドにもそのようなコードがありますが、より簡単な slice() インスタンスメソッドを見てみます。

■ jQuery().slice() インスタンスメソッド(on jquery.js ver1.3.2)
499:slice: function() {
500: return this.pushStack( Array.prototype.slice.apply( this, arguments ),
501:  "slice", Array.prototype.slice.call(arguments).join(",") );
502:},

上のコードによって返値の jQuery インスタンスオブジェクトはどうなるのか考えてみます。なお、arguments は Javascript の仕様から、配列のようなオブジェクト Arguments を参照するプロパティです。そして slice メソッドの引数となるのですから、例えば [2,5] のような位置を示す数値でなければこの式には意味がありません。

以上を踏まえて slice() メソッドの返値 Insobj は次のようなプロパティを持つことになります。なお、言うまでもなく this は slice メソッドの起動元となった jQuery インスタンスオブジェクトです。

  InsObj:{
    prevObject : this, // 模式的に this と書いたが起動元 jQuery インスタンスのこと
    context : this.context, 
    selector : this.selector.slice( m, n ),
    length : n - m + 1, // augrument=[m,n] (m < n)
    m : this[m],
    m+1 : this[m+1],
    ・・・,
    n : this[n],
    jquery : "1.3.2",
    // 以下略
  },

数日前からテンプレートの更新が全く出来ない!!

初稿:2007/12/3

改訂:2007/12/4

2007/12/3

それは数日前から始まった。テンプレートの更新が html 文も CSS 文も出来ないのである。

広告タグ<%ad> <%ad2>もきちんと入っているのに、更新ボタンを押すと「既にその名前のテンプレートが存在しているため名前を変更できません」と表示されるばかり。

挙げ句の果てには HTML も CSS も空白表示となり、更新ボタンを押すと表示されるが、それは先ほど更新したはずの内容ではなく、更新前のものしか表示されない。

で、今度は名前を変えてみるとやはり真っ白。そして更新ボタンを押すと、更新前のコンテンツが表示されるが、今度もエラー表示が出る。そのエラー表示とは削ってもいないのに、「広告タグ[<%ad>][<%ad2>]は削除できません。」である。

数日前までは問題なく更新できていたのに、一体どうしたことか?───同じような現象に悩んでいる人がいるのではないか、と検索を掛けてみたが皆目引っかからないし、phpbbを見てもそれらしいコンテンツはない。

つまりお手上げなのである。

2007/12/4

昨日更新できなかった、HTMLやCSSの更新したはずの箇所が、何と今日になって更新されていることに気がついた。

それでは、と他に修正したくて昨日諦めていた箇所も弄ってみた。

するとまたしても更新できないのである。

しかも何と旧管理画面に移行して、そこでブログデザインの変更を選択して修正すると、こちらでは直せるのである。修正後に更新ボタンをクリックすればそれはアップロードされ、テンプレートに反映されるのだ。

ところが、それを行えるには1つ条件がある。その条件とは別途、新管理画面が開いていると駄目なのだ。旧管理画面オンリイで作業をしなければいけないのだ。例えば、或るエントリイの修正作業を新管理画面で行いつつ、同時並行で旧管理画面でブログデザインの変更を行っていたら、その場合には旧管理画面からのブログデザイン変更は行えず、蹴られてしまうのである。

実は昨日も同じように旧管理画面を開いてそこで修正を施してアップロードしていたのだが、結果が反映されなかったのだ。

この原因は?

以上から推察するに、原因は新管理画面におけるテンプレート変更画面の仕様上の欠陥にあると思われる。

<%ad><%ad2>を厳しくチェックするようにしたこと、あるいは名称変更に係る仕様、このいずれかが原因となって、新管理画面におけるテンプレート変更が適切に作動しないものと思われる。

新管理画面の是非にまで話が及ぶ

phpbbを見ても新管理画面に関する苦情や質問はかなり沢山あるようだ。新管理画面上でテンプレートの変更が出来ない、との投稿もいくつかあった。中には旧管理画面に戻して欲しいとの要望もあったが、これは FC2 から明確な否定回答がなされていた。

phpbbにざっと目を通した印象として、FC2が新管理画面を撤回する気がないのであれば、その改良にもっと力を入れても良いのではないか、と感じた。いくら無料ブログとはいえ、ユーザーの負担や苛つきを土台に改善を進めていく、という手法は余りにおかしいと思われる。

jQueryに学ぶJavascriptの基礎(4) インスタンスオブジェクトからの値の取得について upon ver 1.3.2──jQuery解読(20)

このエントリイの改訂履歴
  • 初稿:2007/12/3
  • インスタンスオブジェクトについての記述を大幅改訂:2009/3/5

jQuery解読作業を進めるにつれ、Javascriptの基礎が如何に分かっていないか、ほぼ毎日のように痛感させられます。その意味ではjQuery解読は無謀なチャレンジであった訳ですが、それでも誤謬を犯すマイナスを埋め合わせて遙かに余りあるプラスがあることも毎日自覚されるので、恥を忍んで引き続きjQuery解読を進めるつもりでいます。

しかし、基礎の基礎が余りに分かってない自分に嫌気が指してきてしまい、匙を投げ出すような醜態は演じたくありません。そこで、自戒を込めて敢えて誤解していたこと、理解していなかったこと、不十分な理解に留まっていたことなどについて、つらつらと記述していきたい、と思います。

for in object loop と継承プロパティ及び固有プロパティ

先に( this 活用──jQuery解読(17) )、for in loop でインスタンスオブジェクトのプロパティを総覧しました。ここでその総覧について考えてみます。

この loop ではオブジェクトが持つ全てのプロパティを列挙出来る訳ではありません(※)が、プロトタイプオブジェクトからの継承プロパティが列挙対象となることを再確認出来ました。しかしそれさえも ECMAScript による仕様ではプロトタイプチェーンは for in loop の調査対象外、とされているようですから、いずれはこの loop でプロトタイプから継承されたプロパティも取得できなくなるかも知れません。偶々 FireFox2 や IE7 では取得できますが・・・。

※ コードによって追加されたプロパティは列挙対象となるが、組み込みオブジェクトにあらかじめ定義されたプロパティ(例えば配列のメソッドなど)は通常は列挙できない。───Javascriptクィックリファランスp.101)。

さて、ここで何が問題かというと、$("a").size() あるいは $("a").length を実行すると当該サイトのリンクタグの個数が取得できますが、この場合の要素数に何故、プロトタイププロパティ=継承プロパティが含まれないのだろうか、とふと疑問に思ったのです。しかし、継承プロパティは配列として、あるいは配列のようなプロパティとして格納されている訳ではないから、当然数えられないはずだ、と直ぐに納得しました。

そして、そもそも継承プロパティは、恰もインスタンスオブジェクトのプロパティであるかのように見えているだけ(『Javascript第5版p.154』)で、決してコピーされている訳ではないことを、改めて思い起こしました。継承プロパティはインスタンスオブジェクトの固有のプロパティではないことを、期せずして再確認した次第です。

jQuery.js は何故「配列のような」形式で取得値をインスタンスオブジェクトに返すのか?

次に、 jQuery.js が処理値をインスタンスオブジェクトに「配列のような」形式で返すことの意味を考えてみました。

そしてその理由は、逆の場合を想定して直ぐに明らかになりました。つまり、配列のようにしないで通常のオブジェクトのプロパティとして返すと仮定すると、length で数を数えることが出来ませんし、 script によって、prototype オブジェクトからの継承プロパティと、返値であるプロパティを区別することも出来ないと思われます。

つまり、スクリプトによって取得したノード(値を含む)をスクリプトで自在に扱うためには、それを配列のようなプロパティで取り込むことが必要不可欠である、ということになります。

ここに 「 配列のようなプロパティ 」 とは、0:DOMNode1, 1:DOMNode2, 3:DOMNode3, ・・・・・, N:DOMNodeN のように、0から始まる整数値をプロパティ名とし、DOMノードをプロパティ値とするプロパティのことです。

愚問のお陰で、改めて配列のようなプロパティの重要性に思いを馳せました。

jQuery()関数を呼び出した直後のインスタンスオブジェクトの状態

さて、主題です。「インスタンスオブジェクトからどの様にしてその値を取り出すか」ですが、ユーザーから呼び出された直後のインスタンスオブジェクトの状態は下図のようになっています。インスタンス=this は空の配列オブジェクトとして「出発」します。

jQuery()呼び出し直後の「 this 」

左図は $("p") によって jQuery() 関数を呼び出した直後の、init() メソッド内の変数の状態を示しています。

this(つまりインスタンスオブジェクト)はオブジェクトとして定義され、変数 selector には文字 p が、その他の変数にはまだ値が付与されていません。

jQuery()呼び出し直後の「 this 」その詳細

左図は 当該 this のプロパティを見たものです。

this=インスタンスオブジェクトは、既に prototype オブジェクトから継承された沢山のプロパティをもっていることが分かります。

この後の jQuery.js 内における処理の結果、ユーザーが指示し目的とした要素ノードが配列のようなプロパティとしてインスタンスオブジェクトに返され、これが return 連鎖を通じて最終的にユーザーが入力したAPIに返されます。その最終結果を変数 t = jQuery("p") で受け取り、その t を Firebug で表示した内容は以下の画像となります。

なお、ここに表示した一連の画像は Firebug 1.3.3 で表示された情報です。

var t = window.t = jQuery('p') の結果詳細

直上の画像でよく分かるように、jQuery("p") の結果、目的のノード( テスト用に使用したローカルサイトの p タグの一覧 )が、配列のようなプロパティ { 0:p#top, 1:p#top2, ..... 9:p } として取得されています。

インスタンスオブジェクトの値を取り出す方法

以上のように、jQuery("・・・") の返値であるインスタンスオブジェクトは、配列のようなプロパティも有するオブジェクトですから、オブジェクトからプロパティを取り出す一般的方法によって、DOM Nodes を取り出すことが出来ます。

さて、jQuery,js のコード実行過程においては、 this[num] ( num は 0,1,2,・・・であり、コード進行過程の当該段階における DOM Node 取得要素数マイナス 1 まで有効 ) によって、インスタンスから DOM ノードが取り出されるシーンがいくつもあります。

つまり、jQuery("・・・")[n-1}とすれば、目的のノード群の中から n 番目のそれを取得できます。

ところで、配列のようなプロパティに格納されているプロパティ値が DOM ノードであることに注意を払う必要があります。

例えば、配列要素を文字列表示で一覧する jQuery("element'sName").join() メソッドではエラーとなります。DOMノードは直接文字列に変換できないからでしょう。また $("p").toString()では"[object Object]"しか返されません。

$("p") を例に取れば、$("p")[num] で、オブジェクトに格納されている取得対象ノードが取得出来ますが、この場合、例えば FireFox では [object HTMLParagraphElement]と、FireBugでは <p> と表示されます。

具体的にノードの「値」を表示させたい場合には、まずオーソドックスに行うならば、

$("p")[0].nodeName、$("p")[0].firstChild

等の DOM プロパティを利用することにより、タグ名や内容等を取得することになります。

しかしこれでは折角 jQuery を使ってコードを簡略化する意味がありません。そこで、jQuery() ではインスタンスオブジェクトを取り出す様々な方法が提供されています。まず単純に DOM Nodes を取り出すメソッドは get() です。

例えば $("p").get() によって jQuery("p") インスタンスを取り出すことが出来ます。但し配列として、と言う制限付きであり、かつその要素は String ではないので alert("$('p').get()") などで表示させることは出来ません。

その場合でノードの内容を見ようとすれば、例えば $("p").eq(n-1).text() により、n 番目の p タグ内の文字情報を取得することが出来ます。

jQuery()の挙動を解読する。(11) 簡単なインスタンスメソッドいくつか──jQuery解読(19)

このエントリイの改訂履歴
  • 初稿:2007/12/3
  • 改訂:2009/2/28……get()メソッド解読箇所をjquery Ver1.3.2対応に

this の何たるかが一応分かったことを踏まえて・・・

直前のエントリイでthisを分析しました。これを踏まえて早速jQuery()インスタンスメソッド内で、縦横無尽に活用されている this に注目して、挙動解読を行いたいと思います。

ここでは get()、pushStack()、 setArray()、index() を順に取り上げてみようと思います。とりあえず内容が簡単ですから(苦笑)。

なお、以下において共通して InsObj とはインスタンスオブジェクトの意味です。

また、以下のコードリストでは jQuery UI の resizable を利用していますので、サイズは縦横自由に変更できます。W3C の仕様を守らない IE 以外では、このブログに設定されているコンテナ幅を飛び出すリサイズは出来ないので、pre タグの overflow スタイルを auto に設定し、W3C仕様の場合でも全文が見えるようにしました。

get()……目的の DOM Elements を格納した jQuery インスタンスオブジェクトから、目的のノードを要素とする配列を取得する、あるいは num 番目のノードを抽出する。

get() は2つの役割を担っています。まず、jQuery(selector,context) で取得したノードオブジェクトを、配列として取り出す為に機能します。引数を与えずに get() メソッドを実行すればノードを要素とする配列が取得できます。但し、返される配列の要素はノードですから、そのまま alert しても [Object HTMLPagraphElement] のように表示されるだけです。nodeName などの DOM メソッドで展開しないと意味のある結果は表示されません。

例えば次のボタンをクリックすると、このサイト上で alert($("p").get();) が実行されます。このページ上にある p タグの一覧を取得する訳ですが、どの様な結果が表示されるのか試すことが出来ます。

他方、整数値を引数としてget(num)を実行すれば、目的のノードを取得した jQuery インスタンスオブジェクトから num プロパティに登録されているノードが返されます。

<jquery.js ver 1.3.2>
109: // Get the Nth element in the matched element set OR
110: // Get the whole matched element set as a clean array
111: get: function( num ) {
112:  return num === undefined ?
113:
114:   // Return a 'clean' array
115:   Array.prototype.slice.call( this ) :
116:
117:   // Return just the object
118:   this[ num ];
119: },

上で色づけした行が下の Ver 1.2.1 と異なっています。

ここに this は、0 から始まる連番をプロパティ名とし、jQuery("selector") で指定した条件を満足する DOM Element をプロパティ値とする array like なプロパティ群と、jQuery.prototype プロパティ群とで構成されるオブジェクトです。Array.prototype.slice.call( this ) メソッドはこのオブジェクトから array like なプロパティ値だけを 「 配列として 」 抽出します。( → jQueryに学ぶ Javascript の基礎(6) func.apply(obj , array) upon Ver1.3.2──jQuery解読(39) 参照 )

またこの変化した行の意味は以下の引用が簡潔明瞭に説明してくれます。

Array.prototype.slice.call(arguments) というのは Arguments オブジェクトを配列に変換するための決まり文句のようなものです。Array オブジェクトの slice メソッドは、配列の一部を抜き出し新たな配列として返しますが、引数を省略すると 0 番目から length - 1 番目までの要素を抜き出したもの、すなわち元の配列全体のコピーを返します。これを Arguments オブジェクトに適用することで、Arguments オブジェクト全体をコピーした配列が返ってくるというわけです。

( 出典: JavaScript でカリー化、再び: Days on the Moon

<jquery.js ver 1.2.1>
95: get: function( num ) { // 目的とする num 番目の n を引数とし
93:  return num == undefined ? //numが未定義ならば
94:
95:   // Return a 'clean' array
96:   jQuery.makeArray( this ) : //InsObj の中の対象要素ノードの全体を配列
97:                 //に変換して返値とし
98:   // Return just the object
99:   this[num]; //num が与えられていれば InsObj 配列から num 番目を
          //抽出して返値とする。
100: },

pushStack()……対象オブジェクトの変更とバックアップ

102: pushStack: function(a) { //所与の第一引数を受け取り、
103:  var ret = jQuery(a); //それを第一引数とするjQuery(a)を起動して
          //別のInsObjを作成して、それを ret 変数に代入する。
104:  ret.prevObject = this; //その時の this を
        //retのプロパティに代入し、this をプロパティとして
105:  return ret; //持つ新規 InsObj を呼出し元に返す。
106: },

この pushStack() は大変興味深いメソッドです。新しいインスタンスオブジェクトの その名も prevObject プロパティに、直前のthisオブジェクトが格納されるようにコーディングされています。このメソッドは jQuery.js で7箇所利用されています。なお、 pushStack()解読──jQuery解読(21) にて pushStack() の必要性、役割について考えてみました。よろしければご覧ください。

setArray() ……インスタンスデータの初期化と更新

108: setArray: function( a ) {
109:  this.length = 0; //InsObjに代入されている値を全て削除して空にする。
110:  Array.prototype.push.apply( this, a ); //空のInsObjに a 配列の要素を挿入
111:  return this; // a の各要素が代入された InsObj 配列を呼出し元にreturnする。
112: },

index()……取得したノード内でobjが何番目にあるか?

118: index: function( obj ) { //目的のオブジェクトを引数とする
119:  var pos = -1; //pos変数を初期化する。
120:  this.each(function(i){ //InsObj からeach()メソッドを起動
121:   if ( this == obj ) pos = i; //定義からthis=InsObjであり、
122:  });  //その各要素をobjと比較して、objと一致すればその位置を
       //示す i を pos 変数に代入する。
123:  return pos; //合致した位置が代入された pos の値を呼出し元に return する。
124: },

jQueryに学ぶJavascriptの基礎(3) 正規表現──jQuery解読(18)

jQuery解読作業を進めるにつれ、Javascriptの基礎が如何に分かっていないか、ほぼ毎日のように痛感させられます。その意味ではjQuery解読は無謀なチャレンジであった訳ですが、それでも誤謬を犯すマイナスを埋め合わせて遙かに余りあるプラスがあることも毎日自覚されるので、恥を忍んで引き続きjQuery解読を進めるつもりでいます。

しかし、基礎の基礎が余りに分かってない自分に嫌気が指してきてしまい、匙を投げ出すような醜態は演じたくありません。そこで、自戒を込めて敢えて誤解していたこと、理解していなかったこと、不十分な理解に留まっていたことなどについて、つらつらと記述していきたい、と思います。

jQuery.js は正規表現の勉強にも最適である

正規表現文字列の奇々怪々、何がなにやらさっぱり訳が分からない記号の羅列を見れば、this の難解さなど赤子の手をひねるに等しい水準だと言えるでしょう(苦笑)。その奇々怪々な文字列が、jQuery では、様々なシーンで活用されています。

jQuery.js に登場する20箇所以上の正規表現について、ここに論じても余り意味がないでしょうが、普段余り見かけない利用方法について学習を深めることは意義深いと思います。

話題にするのは、3つ。参照対象とする部分文字列と非参照対象の部分文字列、そして非貪欲な繰り返し、です。

部分文字列

それは () で括られた一塊の文字列のことですが、塊として位置づける意味は、後でその文字列を参照したい場合、及び参照はしないが一塊の文字列として認識させたい場合とに分かれるようです。

これらの参照/非参照の部分文字列を指定しているケースについて

その端的な例は次の2例です。(左の数字はjQuery.jsにおける行数です)

 31: var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;
1202: /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,

色別で部分文字列の区別を分かりやすく表示しましたが、jQuery.js ではこれらの部分指定を活用してその部分を随意に取りだして利用しているのです。

31行の場合の部分文字列の活用内容は既に言及しましたので( インスタンスの初期化:init()──jQuery解読(5)、ここでは1202行について解読しようと思います。

1202行は jQuery.parse プロパティを定義する箇所の一部です。コード本体の説明にあるように、 Match: [@value='test'], [@foo] を探すための正規表現文字列です。なおこのparseプロパティが使用されている箇所はjQuery.filer() メソッドの 1433行1箇所だけです。

さてこの正規表現文字列は、連想配列のキー文字として @value='test' や @foo の形式の文字列を探すために一般化されて定義されたものです。

  1. ^(\[)……先頭文字が [ の意。これは部分文字列1に指定されている。
  2. @?([\w-]+) ……@があるかなくて、その後に単語文字かマイナスが1以上。この1以上の単語文字が部分文字列2に指定されている。
  3. ([!*$^~=]*)……部分文字列3。!、*、$、^、~、又は = がゼロ個以上
  4. ('?"?)……部分文字列4。' がゼロ個以上で、 " がゼロ個以上続く文字列
  5. (.*?)……非参照部分文字列。何らかの文字がゼロ個以上。なおこの ? は後述する「非貪欲な繰り返し」指定のため。
  6. \4……部分文字列4を参照する。

▲ToTop

非貪欲な繰り返しについて

これはむしろ吝嗇な繰り返しとか、貧弱な繰り返しと言った方が分かりやすいのではないかと思いますが、『Javascript 第5版』に倣って「非貪欲な」繰り返しと表現しておきます。

この用法もjQuery.jsで初めて遭遇したもので、Javascript1.5以降に実装されたそうです。繰り返し文字の最後に ? を付けると非貪欲な繰り返しになるのだそうです。例:??、+?、*? 等々。

これが登場するのは上に見た 1202 行 や 778 行で、後者は clean() インスタンスメソッドの中です。

 778:  arg = arg.replace(/(<(\w+)[^>]*?)\/>/g, function(m, all, tag){

行の中程にある [^>]*? です。これは > でない文字のゼロ個以上の非貪欲な繰り返し 、ということになります。つまり、 > ではない文字(列)を見つけた場合の最初の文字だけを意味することになります。

 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が開きます。