03 | 2009/04 |  05

  1. 無料サーバー

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

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


スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

自作 jQuery プラグイン :アニメーションポップアップ で遊ぶ

animatedPopup で他サイトの写真や動画を表示する。

完成した自作 jQuery プラグイン「 animatedPopup 」を実際に使ってその可能性を見極めてみようと思う。それはまたこのプラグインの PR にもなるだろう。

なお jQuery 本家サイトのプラグインサイトに登録してみたいが、英語解説を書く自信がないので行えないだろう。(苦笑)

さて、このエントリイでは、他サイトの写真や動画を幾つかポップアップしてみる。

但し、トップページを経由しないでダイレクトにアクセスすることを認めない素材サイトが結構多いため、ダイレクトアクセス が可能な Web サイトに限定して探さざるを得なかった。

全てボタンをクリックすれば、画面中心部に写真や動画がポップアップされるように設定した。但し jquery プラグイン animatedPopup はIEでは動かないことを断わざる得ない。

  • (出典は pixta )easing は easeOutElastic を使用し背景色等はグレー系を指定
  • (出典は pixta )easing は easeInOutExpo を使用し背景色等は既定値のママ
  • (出典は フォトライブラリー )easing は easeInOutSine を使用し、背景色等は紫系を使用
  • (出典は LinkStyle )easing はeaseInOutBack、背景色は赤系を使用
  • (出典は youtube )easing は温和しめの swing、背景色は緑系を使用

上の5つの animatedPopup プラグイン活用事例において、次の点に着目してもらえれば幸いである。

  • 背景色とボーダー色・種類、並びに easing は5つそれぞれに変えた。
  • easing 所要時間は「夏の丘」: 1 秒、「地球と月」:1.2秒、「ライトシャワー」:1.4秒、「暮色」:1.5秒、動画:1.8 秒と変化させた。

なお、このアニメ-テッドポップアップのコードについては、以前のエントリイ で詳細に解説を加えたので、時間と興味があればそちらを見て戴きたい。

さて、上の5つの実行結果についてだ。

まず写真4枚は「一応」設定通りに動いてくれた。しかし動画は埋め込みタグ情報からは横幅を自動的には取得できなかった。( object タグや embed タグには width 値が明記されているが、これをjquery.js に用意されている outerWidth やouterHeigh メソッドでは取得できないようだ。)

そこで、やむなく第5引数である options に横幅指定を入れて強制的に横幅を設定した。

動画においてこのような問題はあるものの、一部の問題を除いて設計通りの動きをしてくれることが確かめられたので、(..)(^^)(^。^)(*^o^)(^O^)ウレシーーーー!!!

その一部の問題については項を改めて以下に記したい。

▲ToTop

一部の、しかし既に解決した2つの問題点について

一部の問題点とは、第一に、背景色やボーダーの仕様(色・太さ・種類)を各ポップアップで変化するようにコードを書いているのに、そうならず、5つ全ての背景色が同じになってしまったり、ボーダーが表示されなかったりしたことである。

この点については、animatedPopup プラグインそのもののバグだったため、そのバグ退治に相当の時間を費やして改善を図った結果、やっと意図したとおりに表示されるようになった。

このバグは現在では退治済みなので、既にこの「一部の問題」は発生しなくなった。

第二の問題点は情報の先読み欠如である。画像や動画の先読み指定を行っていなかったため、初めてこのページを開いてボタンクリックしたときには、画像がうまく表示されなかったのだ。

久しく画像を扱っていなかったので(苦笑)、当然指定すべき先読み指定を忘れていたのだ。

勿論この点も解決済みである。

▲ToTop

次に他サイトそのものをポップアップしてみる

上では、或るサイト内に存在している画像や動画の1つをポップアップしたが、次にサイトそのものをポップアップしてみる。これにはインナーフレームを使うことが相応しい。

ここでは easing はjquery.js の既定値(swing)を使用し、背景色等はグレー系、easing 所要時間は 1.8 秒とした。

実はサイトの縮小表示を行いたいのだが、それを実現する方法がIE以外では分からないため、当面は不可能だ。

スポンサーサイト

IE8 がWeb標準準拠だったとは!

全く知らなかった。予想はしていたもののこんなに早く実現するとは!

自作した jQuery プラグイン 「 animatedPopup 」 がIE8でうまく動かないその原因を色々探っている内に、何とIE8はWeb標準をサポートしたことを知った。それは予想はしていたがこれほど早くそうなるとは予期していなかったので,まさしく青天の霹靂と言う事態だ。

そもそも IE7 の描画モードを標準としてIE8もそれに準拠させる予定だったらしいから( Microsoft、IE 8で最新Web標準モードをデフォルトに - ITmedia News )、Microsoft 社が大きな方針転換を行ったわけだ。

こちらのサイト ( Internet Explorer 8正式版レビュー - @IT ) に詳しい情報があるのでそれを色々読んで、状況はそれなりに理解したが、固有仕様で凝り固まっている IE6 をまだ使っている人、あるいは使わざるを得ない人が相当数存在するし、IE7 も然りである。そんな中でこのブログサイトはDOCTYPEを宣言しているので、自動的に IE8 標準モード=Web標準準拠モードで表示されているわけだ。

頑迷に固有仕様を死守してきた Microsoft 社が Web 標準の潮流を流石に無視し続けることが出来ず、IE8 においてやっと(10年ぶりくらいになるだろうか)、標準の軍門に下ったことは実に喜ばしいことであり、「奢れる者久しからず」の教訓がここでも実証されたとも言えるだろう。

Microsoft がついに Web 標準の軍門に下った歴史的事件であればこそ、その事実を踏まえて IE8 は標準モードつまりWeb 標準準拠モードで利用したいものだ。

遅ればせながらやっと実現した!───複数ファイル一括アップロード

やっと複数ファイル一括アップロードが実現した。

Fc2ブログ開設以来ずっと要望が多かった機能であり、Fc2社の尽力を多としたい。

FC2総合インフォメーション 【ブログ】複数ファイルのアップロードに対応!>

jQuery プラグイン としてアニメーションポップアップ : animatedPopup を自作した。

このエントリイの改訂履歴など
  • 初稿:2009/04/19
  • 完結:2009/04/23
  • 第 1 回改訂:2009/04/25 right、bottom 指定をやめ全て left 又は top に統一した。
  • 第 2 回改訂:2009/04/26 画像も表示できるように引数処理を修正した。またポップアップ表示ボックスの色味を自在に操れるように引数を1つ追加した。これらによりこのプラグインの使いやすさが向上した。
  • 第 3 回改訂:背景やボーダーの色が思うように変化しないバグを修正
  • 第 4 回改訂:全面的改訂を断行。その内容は別のエントリイ → 自作プラグイン-アニメーションポップアップを全面改訂 にまとめました。これに伴いここで説明するプラグイン名を animatedPopupOld に変更しました。

残念ながら IE ではここで説明するプラグインは動きません。

その理由は IE8 のエラーメッセージに拠れば「 jquery.js のアニメーション関連コードに問題有り 」と表示されます。他方、Firefox、Opera 及び Windows 版 safari では問題なくこのページのアニメーションが表示されます。IE 8 で動かない理由は解明できていません。IE でも動くように改訂したいのですが、原因が解明できないため対応策が見つかりません。

ここで言う Animated Popup とは

ポップアップ表示をアニメーションメソッドを使って行うことを意味しています。例えば極小の点から一定の幅と高さを有する表示ボックスをズームポップアップし、それを消すときにはズームアウトするような、そんなポッップアップです。

Windows Vista でウィンドウ開閉時に行われるような、あのようなズームイン/アウトをポップアップ表示/隠蔽にも取り入れてみたいと思い立ち 4月11日頃に作成を開始しました。

何はさておき、その実例を示すことが先決でしょう。

下のボタンをクリックするとあるいはその近傍に、あるいは画面中央に、あるいは画面右下に、あるいは指定してある位置 {left:100px,top:200px} に、ポップアップがズームイン/アウトされます。表示する際のポップアップサイズは順に300、350、400、500px に、またアニメーションに要する時間はそれぞれ 1200、600、1600、2000 ミリ秒に設定してあります。

 クリックした位置の傍にポップアップ表示します。

クリックすると画面の中央にポップアップ表示します。

クリックすると画面の右下にポップアップ表示します。

クリックすると指定してある位置にポップアップ表示します。

クリックすると画面の中央に或るサイトの或る写真をポップアップ表示します。写真出典元は フォトライブラリ です。

▲ToTop

Animation と Easing

Easing は Animation 動作速度を変化させる「加速度メソッド」のことで、元々 Flash ツールである Acrion Script の Tween クラスの加速度メソッドとして誕生したようです。(半可通の知識しか持ち合わせていないので「ようです」としておきます。)

この Easing 関数が jQuery プラグインとして提供されているので、早速それを導入し、このページでは敢えて動きの激しい easeOutElastic を使用しました。本来、文字を表示するには変化の激しい elastic は相応しくないでしょうが、Easing を初めて使用した記念として「激しい」ものを選択してみたのです。

因みに、George Smith 氏により提供されているプラグイン「Easing Plugin」は 10 種類あり、各々に3つの効果(easeIn、easeOut、easeInOut)を持たせて Easing 関数が定義されているため、都合 30 種類の easing 関数があります。→ Plugins | jQuery Plugins

その Easing の各々の動きの違いを示したサイトとして興味深いのは、flash ムービーですが easing_demo が実に分かりやすく有益です。これによりそれぞれの Easing がどんな挙動をするのか一目瞭然に理解できます。easing 関数内の代数式がグラフ化されていることも非常に有益です。

そこで、このデモサイトをまねて、このページ上で実現しているアニメーションポップアップに対して 32 種類(jquery.js にビルトインされている linear と swing の 2 種類を追加したため 32)の Easing 効果を適用するリストボックスを設置してみました。easing_demo に比べて文字表示の場合には各 easing の差異がわかりにくいのですが、まあそれはご愛敬ということで...。

下のリストボックスの説明
  • アニーメーションポップアップの表示位置は 「 画面中央 」 としました。
  • Easing に要する時間はそれぞれの関数の差異が分かり易いように長めに設定しました(2秒)。
  • jquery.js に組み込まれている linear と swing の 2 つの Easing 関数もリストアップしたので都合 32 種類の easing 関数が登録されています。
  • 別の easing 関数を選択する前に表示されているポップアップを隠蔽する必要はありません。自動的に前の表示を消して、新たな表示を行います。
補足:上の リストボックスに係るスクリプトの説明

このページのソースコードを表示すれば分かることですが、jquery.js を使って初めて form を扱ったので、記録を残すために敢えてここに記します。

■アイテムが選択された際の処理を行うスクリプトコード
$("#sel707").change(function(){
 var index = this.selectedIndex,
   selEasing = this.options[index].value,
   txt="これは easing 関数: "+selEasing+" を使って<br />表示/隠蔽するアニメーションポップアップです。";
 $(this).animatedPopupOld(txt,["c","c"],2000,selEasing,{width:"400px"});
});
html説明
selectタグに id="sel707" と size=10を、最初の option タグに非選択属性 disabled="disabled" を、二番目の option タグに初期値 selected="selected" を設定しました。
Javascript 説明
  • 要点は selectタグの jQuery インスタンスに change イベントを登録することです。
  • まずリストボックスから選択されたアイテムのインデックス番号を変数に代入し、その値を使って options 配列から選択されたアイテムの value 値を取りだし、最後にポップアップ文を構成します。
  • 以上の僅か 3 つの変数を定義するだけで準備は完了。後は適切な引数付きで animatedPopup メソッドを登録するだけです。

以上の簡単なコードによって、リストボックス内の項目が選択されたその瞬間に発生する change イベントにより、イベントハンドラーが起動されて必要な処理を行います。

▲ToTop

作成した Animaeted Popup の仕様

  • 作成した Animaeted Popup は jquery.js のプラグインとして組み込める形式としました。
  • Animaeted Popup の呼び出しは次の書式で行います。jQuery(expr) はjQueryインスタンスならば何でも構いません。
    jQuery(expr).animatedPopupOld(contents, layout, duration, easing, options, options2);
  • <引数の説明>
     * contents: Strings in Animated Popup
     * layout: displaying position of Animated Popup
     *         text,ex. ["c","t"] (It means :left="center",top="top")
     *         or object,ex.{left:"100px",top:"200px"}
     *         or {left:"center",top:"100px"}
     * duration: durating time of animation(msec), ex.500 or "slow" etc.
     * easing: easing name (text), ex."easeInOutQuad","easeOutBounce",..32通りの指定が可能
     * 但し 32 種類を利用するには Easing Plugin をインクルードする必要があります。
     * このサイトで利用している jquery.js には Easing Plugin を組み込み済みです。
     * options: Add CSS Object to Popup DIV, ex.{width:"400px",・・・}
     * options2: Add CSS Object to Popup DIV's CLOSE Bar, ex.{background:"midnightblue",・・・}
     * 全ての引数にはデフォルト値が設置済みなので、複数の任意の引数が省略され
     * ても誤動作しません。
     * 何も引数がない場合、その旨を表示する animatedPopupOld を画面中央に表示します。

▲ToTop

作成した Animaeted Popup の Javascript コード

コードは長めになりました。説明を含めて 190 行あります。

ここでその全てを掲載しブロックごとに解説を加えることとします。

animatedPopupOld プラグインの全コード
  1:(function($){
  2:$.fn.extend({
  3:animatedPopupOld: function(contents,layout,duration,easing,options,options2){
  4:/*
  5: * <Example of Implementation>
  6: * jQuery("p").animatedPopupOld("And I love you so. Yesterday. Yellow Submarine.",
  7: *   ["c","b"],800,"swing",{width:"300px"})
  8: *
  9: * <arguments explanation >
 10: * contents: Strings in Animated Popup
 11: * layout: displaying position of Animated Popup
 12: *      text,ex. ["c","t"] (It means :left="center",top="top")
 13: *      or object,ex.{left:"100px",top:"200px"}
 14: *      or {"left":"center","top":"100px"}
 15: * duration: durating time of animation(msec), ex.500 or "slow" etc.
 16: * easing: easing name (text), ex."easeInOutQuad","easeOutBounce",...
 17: * options: Add CSS Object to Popup DIV, ex.{"width":"400px",・・・}
 18: * options2: Add CSS Object to Popup DIV's Title DIV, ex.{background:"midnightblue",・・・}
 19: *
 20: * <history>
 21: * released 2009/4/22 ver0.1
 22: * update 2009/4/25 ver0.2, 2009/4/26 ver0.3
 23: */
 24: var jQInst=$(this), winWH = {width:$(window).width(),height:$(window).height()},
 25:  errFlag,lcr,tcb,xName,yName,m=[],addValue={x:0,y:0},isImg,
 26:  mousePos={left:0,top:0},xCenter=$(window).width()/2,yCenter=$(window).height()/2;
 27:  // CSS 既定値は width 値が contents により変わるので、関数化しインスタンス毎に設定する。
 28: var defaultCSS =function(){
 29:  isImg = contents.match(/.*((<img.+src.+)|(<object.+)|(<embed.+)).*/i);
 30:  return {
 31:   "color":"white","font-weight":"bold","margin":0, "padding":"19px 5px 5px 5px",
 32:   /* 画像の場合ここで width を決めては駄目*/
 33:   "width": (isImg && isImg[1]) ? null : "300px",
 34:   "background-color":"royalblue", "border":"5px plum ridge", "text-align":"center",
 35:   "display":"block","visibility":"visible"
 36:  }
 37: }
 38: /* ポップアップに使用するCSS値を設定する*/
 39: var popupCSS = $.extend(true,defaultCSS(),options || {});
 40: /* closeBar CSS値も容易に変更できるように設定する */
 41: var closeBarCSS = function(){return $.extend(true,{
 42:  "position":"absolute","zIndex":"1001","text-align":"center",
 43:  "opacity":0.75,"top":0,"left":0,"width":"100%","cursor":"pointer",
 44:  "font-size":"small","lineHeight":"1.2em","background-color":"midnightblue"
 45: },options2 || {})};
 46:
 47: // bind onmousemove event on document
 48: mousePos.oX = 4; mousePos.oY = 16; //マウスカーソルからの離隔距離
 49: $(window).mousemove(function(e){
 50:  mousePos.left = (jQuery.browser.msie ? window.event.clientX - document.body.clientLeft : e.clientX) + mousePos.oX;
 51:  mousePos.top = (jQuery.browser.msie ? window.event.clientY - document.body.clientTop : e.clientY) + mousePos.oY;
 52: });
 53:
 54: // error 処理関数(後に拡張できるように関数にしておく)
 55: var errFunc = function(){ errFlag=true; return function(){return}}
 56:
 57: // animatedPopupOld の配置位置算出関数
 58: var getPos = function(layout){
 59:  if (layout && layout.constructor!= Object && layout.constructor!= Array ){
 60:   alert("配置は2つのテキスト:例 \"Center\",\"Top\" 、または\nオブジェクト形式:例 {left:\"10px\",top:\"100px\"} で指定してください。");
 61:   errFunc()();
 62:  }
 63:  var setPos = layout;
 64:  if (setPos.constructor==Array) {
 65:   var chk1 = /^((l.*)|(c.*)|(r.*))/.exec(setPos[0].toLowerCase());
 66:   var chk2 = /^((t.*)|(c.*)|(b.*))/.exec(setPos[1].toLowerCase());
 67:   if (chk1 && chk2){
 68:    lcr = chk1[2] && "left" || chk1[3] && "center" || chk1[4] && "right";
 69:    tcb = chk2[2] && "top" || chk2[3] && "center" || chk2[4] && "bottom";
 70:    xName = (lcr!=="right") ? "left" : "right";
 71:    yName = (tcb!=="bottom") ? "top" : "bottom";
 72:   } else {
 73:    if (!chk1 && !chk2) {
 74:     alert("左右上下 \""+ setPos[0] +" , "+ setPos[1] +"\" 共に指定が間違っています。\nやり直してください。");
 75:    } else if (!chk1 && chk2){
 76:     alert("左右の指定 \""+ setPos[0] +"\" が間違っています。\nやり直してください。");
 77:    } else if (chk1 && !chk2 ){
 78:     alert("上下の指定 \""+ setPos[1] +"\" が間違っています。\nやり直してください。");
 79:    }
 80:     errFunc()();
 81:   }
 82:  } else if (typeof setPos!=="string" && setPos.constructor==Object) {
 83:   for (name in setPos){
 84:    name=name.toLowerCase();
 85:    if (name=="left" || name=="right") {xName = name;lcr=name}
 86:    if (name=="top" || name=="bottom") {yName = name;tcb=name}
 87:   }
 88:   if (xName==null || yName==null){
 89:    alert("left、right、top、bottom 以外の\n指定は無効です。やり直してください。");
 90:    errFunc()();
 91:   }
 92:   // 位置指定値が "left" のように文字で為されたときの対応
 93:   if (!setPos[xName].match(/\d+/))
 94:    m[0] = setPos[xName].toLowerCase().match(/^(left|center|right)$/);
 95:   if (!setPos[yName].match(/\d+/))
 96:    m[1] = setPos[yName].toLowerCase().match(/^(top|center|bottom)$/);
 97:   if (!setPos[xName].match(/\d+/) && m[0]===null || !setPos[yName].match(/\d+/) && m[1]==null){
 98:    alert("配置指定値が間違っています。\nやり直してください。");
 99:    errFunc()();
100:   }
101:   addValue={
102:    x :( m[0] ? ((m[0]==="center") ? xCenter :0) : parseInt(setPos[xName])),
103:    y :( m[1] ? ((m[1]==="center") ? yCenter :0) : parseInt(setPos[yName]))
104:   };
105:  } else if(layout){
106:   alert("配置指定が無効です。やり直してください。"); errFunc()();
107:  }
108:  var obj={};
109:  obj[xName]= ((lcr==="center") ? xCenter : 0) + addValue.x;
110:  obj[yName]= ((tcb==="center") ? yCenter : 0) + addValue.y;
111:  return obj;
112: };
113:
114:$(function(){
115: // popup 表示用の div 要素タグの作成
116: if (!$("#dispElem").size()) {
117:  $("<div id='dispElem'></div>").css({
118:   position:"absolute",display:"none",zIndex:"1000"
119:  }).appendTo(document.body);
120: }
121: var disp=$("#dispElem");
122:
123: // Popup 隠蔽用×タグの作成
124: if (!$("#xMark").size()){
125:  $("<div id='xMark'>CLOSE</div>").append("<div style='width:13px;float:right;margin-top:-1em;'>×</div>").appendTo(disp);
126: }
127: var xMark = $("#xMark").css(closeBarCSS());
128:
129: // STEP1:*************** 表示前に popup エレメントの高さを測定する
130: var getElemWH= function(){ // 表示 popup サイズ算定
131:  // popup 表示前に横幅と文字数に応じた高さを計測する(非表示描画で測定)
132:  contents = contents || "ポップアップする内容が指定されていません。<br />やり直してください。";
133:  disp.html(contents).css($.extend(true,popupCSS,{"visibility":"hidden","height":null}));
134:  if(isImg && isImg[1]) disp.css("width",null);
135:  return {
136:   iW: popupCSS.width=(options && parseInt(options.width) || defaultCSS().width && parseInt(defaultCSS().width) || disp.width()),
137:   iH: popupCSS.height=disp.height(),
138:   oW: disp.outerWidth(),oH: disp.outerHeight()
139:  }
140: }
141:
142:  // 幅/高さが極小の要素 css 値を設定する。これにより拡張/縮小を演出する。
143:  // またここで初めてスクロールされていた場合の変動値を配置px値に追加する。
144: var shrinkCSS=function(){
145:  var scrLeft=$(window).scrollLeft(),scrTop=$(window).scrollTop(),
146:   obj={"width":"1px", "height":"1px", "border":"0px", "padding":"0px","margin":"0px"};
147:  if (!layout){
148:   obj.left=mousePos.left+scrLeft+"px";
149:   obj.top=mousePos.top+scrTop+"px";
150:  } else {
151:   var pos = getPos(layout);
152:   if (errFlag) return;
153:   obj.left=((xName=="left")-(xName=="right"))*pos[xName]+
154:    (xName=="right")*winWH.width + scrLeft+"px";
155:   obj.top=((yName=="top")-(yName=="bottom"))*pos[yName]+
156:    (yName=="bottom")*winWH.height + scrTop+"px";
157:  }
158:  return obj;
159: }
160:
161: var hideElem = function(e){ // popup 要素をアニメーション隠蔽する
162:  disp.empty().animate(shrinkCSS(),{queue:false,duration:duration,easing:easing});
163: }
164: var animaElem = function(e){
165:  $(":animated").queue('fx',[]).stop(); // 登録済みのアニメを全て削除停止する
166:  var doneShrink = shrinkCSS(); // この関数内で1回だけ起動する
167:  if (errFlag) return;
168:  // STEP2:***************
169:  var elemWH = getElemWH(); //エレメントサイズ計測実行
170:  if (!layout){ // 画面からはみ出さないように CSS 値を調整
171:   if (winWH.width < mousePos.left+elemWH.oW)
172:    popupCSS.left = winWH.width + $(window).scrollLeft() - elemWH.oW +"px";
173:   if (winWH.height < mousePos.top+elemWH.oH)
174:    popupCSS.top =  winWH.height + $(window).scrollTop() - elemWH.oH +"px";
175:  } else { // popup をセンター配置する場合の CSS 設定
176:   popupCSS.left = parseInt(doneShrink.left) -
177:    ((lcr==="center" || m[0] && m[0]==="center") ? Math.round(elemWH.oW/2) : (xName==="right") ? Math.round(elemWH.oW) :0) +"px";
178:   popupCSS.top = parseInt(doneShrink.top) -
179:    ((tcb==="center" || m[1] && m[1]==="center") ? Math.round(elemWH.oH/2) : (tcb==="bottom") ? Math.round(elemWH.oH) :0) +"px";
180:  }
181:
182:  // STEP3:*************** 極小要素を指定されたアニメーション起動位置に配置
183:  // dispElem の幅と高さを1pxにして所定位置に配置する(但し非表示描画)
184:  disp.empty().css(doneShrink);
185:  // STEP4:*************** 表示アニメーション
186:  disp.html(contents).append(xMark.css(closeBarCSS()))
187:   .css({visibility: "visible",display:"block"})
188:   .animate(popupCSS,{queue:false,duration:duration||"slow",easing:easing||"swing"});
189:  // STEP5:*************** × クリック時に隠蔽アニメーションを起動する。
190:  // ここで隠蔽関数を起動するようにしておかないと、複数回ボタンがクリックされた
191:  // 場合に隠蔽操作ができなくなる。理由は未解明。
192:  xMark.click(hideElem);
193: }
194: jQInst.click( errFlag ? function(){errFlag=false; $(this).unbind("click");} : animaElem );
195:}); // End of "DOMReady function"
196:} // End of "animatedAlert function"
197:}); // End of "Extend function"
198:})(jQuery);

▲ToTop

animatedPopupOld プラグインの解説

その意味や役割から幾つかのブロックに分けて解説します。

第Ⅰブロック(#1-22)

まず最初のブロックは、このメソッドの引数を定義しそれらを解説している部分です。

無名関数による起動と DOMReady 関数の利用(#1、#100)

このプラグインでは、一般的方法に倣って全体を無名関数で括り、即実行するようにしました。またポップアップ表示やポップアップ消去のための絶対配置 div 要素を追加し、かつそれらに様々なメソッドを適用する必要があることから、必要最小限の範囲を DOMReady function で括りました。

$.fn.extend クラスメソッドの利用(#2)

これにより、jQuery インスタンスのメソッドとして animatedPopupOld 関数を登録します。

animatedPopupOld 関数の引数(#3-18)

引数は6つあります。第一引数はポップアップボックス内に表示する文字列で、第2引数 layout は様々な方法でポップアップ位置を指定できるよう工夫し、第2引数を指定しない場合には、起動元 jQuery インスタンスが指し示す要素の近傍にポップアップするように設計しました。

第5及び第6引数も工夫しました。extend メソッドの2つめの使い方、つまり「 オブジェクト拡張 」を利用して、popup 要素のデフォルトCSS を設定しておくと共に、options で自在にそれを変更できるようにしました。幅や色、ボーダーの色と幅等々気分自由に変更することが出来るようにすることが目的であり、それを達成しました。

なお、この方法は jquery.js の Ajax ブロックで採用されていますのでそれを参考に考案しました。

▲ToTop

第Ⅱブロック(#24-45)

このブロックは、ローカル変数を定義している部分です。

■変数定義部分(再掲)
 24: var jQInst=$(this), winWH = {width:$(window).width(),height:$(window).height()},
 25:  errFlag,lcr,tcb,xName,yName,m=[],addValue={x:0,y:0},isImg,
 26:  mousePos={left:0,top:0},xCenter=$(window).width()/2,yCenter=$(window).height()/2;
 27:  // CSS 既定値は width 値が contents により変わるので、関数化した。
 28: var defaultCSS =function(){
 29:  isImg = contents.match(/.*((<img.+src.+)|(<object.+)|(<embed.+)|(<iframe.+)).*/i);
 30:  return {
 31:   "color":"white","font-weight":"bold","margin":0, "padding":"19px 5px 5px 5px",
 32:   /* 画像の場合ここで width を決めては駄目*/
 33:   "width": (isImg && isImg[1]) ? null : "300px",
 34:   "background-color":"royalblue", "border":"5px plum ridge", "text-align":"center",
 35:   "display":"block","visibility":"visible"
 36:  }
 37: }
 38: /* ポップアップに使用するCSS値を設定する*/
 39: var popupCSS = $.extend(true,defaultCSS(),options || {});
 40: /* closeBar CSS値も容易に変更できるように設定する */
 41: var closeBarCSS = function(){return $.extend(true,{
 42:  "position":"absolute","zIndex":"1001","text-align":"center",
 43:  "opacity":0.75,"top":0,"left":0,"width":"100%","cursor":"pointer",
 44:  "font-size":"small","lineHeight":"1.2em","background-color":"midnightblue"
 45: },options2 || {})};
jQuery インスタンスの取得(#24)

まず最初にこのプラグインの呼び出し元となる jQuery インスタンスを取得します。

DOMReady 関数内で jQuery インスタンスを呼び出そうとしたのですが、関数内では this は window オブジェクトを参照してしまうため、前もってここで取得しておくことにしました。

表示中の window の幅と高さの取得(#24)

これは jquery.js で定義されているクロスブラウザな便利なメソッドをそのまま活用しました。

これらの値を取得する意味は、画面の中央や左や右にピタリと寄せて配置する場合に利用するためです。

ポップアップ窓のデフォルト CSS 設定(#28-37)

ボーダーやパディング、そして色と背景色──これらの初期値を定めておかないとその都度思案し確定し指定しなければなりません。これはいかにも面倒なので既定値を設定しました。options で特に指定しなければ既定値が適用された popup 窓が表示されるわけです。

実は画像や動画にも対応させるために、最終段階でこのブロックを大きく改変しました。

#29 では正規表現を利用して img タグ、object タグ、embed タグ、あるいは iframe タグ文字列が第一引数 contents に含まれるかどうかをチェックします。そしてそれらのいずれかが含まれる場合には、デフォルト値としての画像サイズを設定しないこととしました。(#33)

これは引用先のCSS設定を反映する場合があったので、敢えて width 値を定めずにおいて、引用先サイトの padding 設定値なども反映した outerWidth 値を取得するためです。

実際に表示するポップアップ窓の CSS 値の指定(#38-39)

これには extend メソッドの2つめの機能である"ボブジェクト拡張"を利用しました。

optionsで任意の CSS 値を与えれば、デフォルトCSSを上書きしてユーザーの要望通りの表現を実現することが出来ます。また ||{} により options が指定されなかった場合にデフォルト値を利用するように工夫しました。

ポップアップ窓上辺の CLOSE バー CSS 値の指定(#40-45)

これも extend メソッドの"ボブジェクト拡張"を利用しました。

options2で任意の CSS 値を与えれば、デフォルト値を上書きしてユーザーの要望通りの表現を実現することが出来ます。また ||{} により options2 が指定されなかった場合にデフォルト値を利用するように工夫しました。

その他の変数(#25-27)

重要な役割を果たすローカル変数をここで定義しました。

addValue は配置位置がピクセル指定された場合のそのピクセル値を格納します。

mousePos はイベント発生要素の近傍にポップアップを配置する場合に必要となるマウスカーソルの現在値を所得するための変数です。

xCenter、yCenter は画面中央に配置するために必要な値で、それぞれ横方向の画面中央位置、縦方向の画面中央位置を取得します。

▲ToTop

第Ⅲブロック:マウス move イベントの登録とエラー対応(#4752)

第2引数 layout を指定しない場合に、マウスカーソル近傍にポップアップさせるためには、マウスの動きを常に Javascriptが 「監視」 しその位置を取得していなければなりません。そのためのイベント登録を行う部分です。これにより document の任意の箇所においてマウスカーソルの動きを常駐監視し、その位置を取得することになります。

 47: // bind onmousemove event on document
 48: mousePos.oX = 4; mousePos.oY = 16; //マウスカーソルからの離隔距離
 49: $(window).mousemove(function(e){
 50:  mousePos.left = (jQuery.browser.msie ? window.event.clientX - document.body.clientLeft : e.clientX) + mousePos.oX;
 51:  mousePos.top = (jQuery.browser.msie ? window.event.clientY - document.body.clientTop : e.clientY) + mousePos.oY;
 52: });
 53:
 54: // error 処理関数
 55: var errFunc = function(){ errFlag=true; return function(){return}}

ここでも IE が、IE だけが特殊な方法を採用しており、そのために面妖な設定をしなければならないのはユーザーにとって不幸なことです。早く IE のユーザー比率が低下することを願ってやみません。IE8 の登場によりその願いはまた叶うことなく先送りされてしまいましたが、中長期的には IE 固有の仕様は消え去る運命にあることは間違いないでしょう。

実際、後のエントリイで触れましたが、IE8 では少なくともスタイル設定に関しては Web 標準準拠に切り替わりました。これは 1 社だけで頑迷に固執し続けてきた奢りが、10年来のブラウザ戦争の中でやっと崩れ去ったことを意味しており、記念すべき歴史的事件と言って差し支えないでしょう。

#54 のエラー対応は「関数を返値とする」特殊な関数を利用します。これにより返値は return 値を有する関数となるので、errFunc()() のようにして、返値である関数を呼び出し先で実行することによりトップレベルにおいて return 値を返すことが可能となります。

ここに最初の括弧は errFunc 関数を実行するため、2つめの括弧は errFunc 関数の返値としての関数を実行するためです。#61 など随所で活用しています。

▲ToTop

第Ⅳブロック:ポップアップ配置位置の設定メソッド(#57-112)

このブロックはたった1つのメソッド登録ですが長大になりました。しかし、様々な指定方法に対応するために必要不可欠な部分であり、長くなってしまったのはエラー処理をふんだんに盛り込んだためでもあります。

#59-62 は最初のエラー処理です。

不適切な layout 指定があった場合の警告表示とコード進行停止を指定しています。

#64-82 は layout が配列だった場合の処理です。

#65-72 で、left、le あるいは l だけでも受容するように指定文字を簡略化できるように工夫し、所定の文字が与えられた場合には、それらを left、center、right、top、bottom の文字列に変換しています。

lcr には left、center、または right の文字が入力され、tcb には top、center、または bottom が代入されます。

また、xName には left か right が、yName には top か bottom が代入されます。

#73-81 は配列指定が適切ではなかった場合のエラー処理です。

#82-107 は layout がオブジェクト指定された場合の処理です。

#83-87では layout オブジェクトを走査して、配置指定に係る定義値を取得し、変数に代入します。捜査の結果必要な文字がなければ #88-91 でエラー処理します。

#92-100 は 配置指定が px 値ではなく "center" などの文字列で行われた場合の処理です。

#93-97 で配列 m に横方向と縦方向の配置指定文字列を代入し、layout が適切な指定でなければ、#97-100 でエラー処理します。

#101-107 では縦横方向の配置指定値を取得します。

二項演算子を活用して、センター配置か否か、及び px 指定値がある場合の2つのケースから値を取得します。

エラー発生時には空オブジェクトを返すようにしました。

#108-110 ではここ迄の処理で確定した配置用変数を活用して CSS 値を設定します。

センター配置の場合のみ画面中央位置を取得し、その他は指定されていればピクセル値を代入します。

▲ToTop

第Ⅴブロック:ポップアップ用 div 要素の作成(#111-134)

ブラウザにとってポップアップ用要素が用意できなければ何も始められないため、これ以降は DOMReady 関数で括ります。

popup 表示用の div 要素タグの作成(#115-120)

2回目以降の animatedPopupOld 起動時に dispElem が重複設置されないように 116 行でこのノードの存在確認を行います。もし存在すれば、改めて変数 disp に当該ノードを参照する jQuery インスタンスを登録します。

存在しない場合には、タグ要素を CSS 設定値を含めて作成し、その後に jQuery インスタンスを作成し変数に代入します。

この CSS 設定では絶対配置、非表示、レイヤー順を指定し、ポップアップを自在に配置できるように、また body 部に追加した時点ではそれが表示されないよう準備します。

popup 隠蔽用×印タグの作成(#123-127)

ポップアップ用 div 要素の右上にこのポップアップを隠蔽するためのバツ印を用意しました。ここでも二重登録しないようにこの要素の存在確認を行います。

更に×印だけではマウスカーソルをその位置にフィットする手間が面倒なので、隠蔽クリックを受け入れる箇所を点から線に拡張して、タイトルバー形式にしました。

▲ToTop

第Ⅵブロック:アニメーション用の諸関数定義(#129-193)

ここ迄でアニメーションポップアップのための準備が終わりました。愈々、動きのあるポップアップ表示や隠蔽操作のための関数を定義します。

ポップアップする要素の高さのサイズを測定する getElemWH 関数

まず第一引数 contents が未指定の場合の対応を 132 行で行いました。未指定の場合には所定の文章( || の右側の文章 )を用意しておき、これを animetedPopup 関数を使ってポップアップします。

文字列をポップアップする場合特に、その要素サイズを「表示前に」如何にブラウザに知らせるかが課題となります。文字列の文字数が固定されていても、文字の横幅は一定ではないので内容によってはサイズは変わりますし、一般にポップアップ表示を行う文字列は長さは不定・可変です。そのためブラウザは、幅が指定されていなければ表示領域一杯の幅が指定されたものと見なし、或いは要素の幅が指定されている場合にはその幅で要素を表示しますが、ブラウザはこれらのいずれの場合においても、要素表示前にはその要素の高さを認識しません。

別のエントリイで不定型ボックスサイズを表示する前にブラウザに認識させる方法について詳細に触れましたが、このプラグインで採用した方法は、自前で考案した透明化してサイズを測定する方法ではなく、jquery.js で利用されている visibility 属性を利用する方法を採用しました。

jquery.js で採用している表示前サイズ計測方法は、1. position : absolute、2. display : block、3. visibility : hidden とすることにより、「絶対配置のブロック表示状態にしてそれを表示させない」状態を作るものです。(jquery.js: css 関数内の #773 で呼び出される #735-748 の swap 関数)

なお、このプラグインで実際に必要となるのは outerHeight と innerHeight なのですが、この際無意味ですが4つのサイズを測定しておくようにしました(苦笑)。

またinnerHeight については、代入式を iH のプロパティ値とすることにより、同時に 2 つのプロパティに値を取得させました。

ポップアップボックスの拡張/縮小を演出する shrinkCSS 関数

アニメーションを演出するために幅と高さが極小のスタイル値を設定します。これによりアニメーションの始点と終点の位置と要素の表示状態を取得します。

またアニメーションの始点/終点を取得するためには、縦横のスクロール状態を Javascript インタープリタに認識させなければなりませんから、この関数内でスクロール値を取得します(#145)。

後述するように、クリック時のイベントハンドラー内から、shrinkCSS 関数を呼び出して、そのときのスクロール値を取得します。

次にこの関数内から #151 で getPos 関数を呼び出していますが、これにより画面内の左右上下中心のどの位置に配置するか、あるいはマウスカーソルの近傍に配置するかを確定します。

エラーフラグが立っている場合にはコード進行を止めます。(#147)

#153-156で right や bottom 指定された場合に left や top に変換しています。

right / bottom 指定された値をleft / top に変換する計算式は、最後の最後まで苦労を重ねました。getPos 関数からの戻り値は、right / bottom 指定のママですが、#153-156 においてこれらを left / top に変換します。この結果 shrinkCSS 関数からの戻り値は left / top のみとなります。

popup 要素をアニメーション隠蔽する hideElem 関数

これはいわば逆アニメーションで、animaElem 関数で表示したポップアップを縮小しながら隠蔽します。最初にコンテンツを削除してから shrinkCSS 関数をよびだし、かつこのアニメーションを待ち行列に登録しないよう queue 値を false にします。

なお、shrinkCSS 関数でエラーが発生する可能性がありますが、hideElem 関数は、必ずanimaElem 関数が走行した後にしか起動されず、animaElem 関数内において shrinkCSS 関数にエラーが発生した場合の処理は記述されています。エラー発生時には hideElem 関数呼び出しまで到達しませんので、当該関数ではエラー処理を必要としません。

アニメーションポップアップ表示を行う animaElem 関数

ここでは次のような様々な処理を行っています。1.登録アニメーションの削除と停止(#165)、2. この関数内で一回だけ shrinkCSS 関数を呼び出し、結果を変数に記録(#166)、この返値が空の場合の処理(#167)3.画面からポップアップをはみ出させない処理(#170-174)、4.画面センターに配置する場合、あるいは right / bottom が指定された場合の、ポップアップサイズと表示位置の調整(#176-180)、4.アニメーションの始点設定(#184)、5.アニメーション表示(#186-188)(ここでも隠蔽処理同様に待ち行列には登録しません。)、そして 6.ポップアップ窓の隠蔽ハンドラー呼び出しです(#190-192)。

ここでの要点は以下の点です。

  • ポップアップ要素を画面外にはみ出させない処理のために必要となる要因は、画面サイズ、スクロール値及びポップアップ要素のサイズです。
  • アニメーション待ち行列の扱いは、全てのアニメーションを非登録としました。当然ですが登録してしまうと、二度目以降の animatedPopupOld() 起動時において、最初以降から直前までの以前に利用したアニメーションが順次起動してしまうためです。
  • 179行で、duration や easing が指定されなかった場合のデフォルト値を設定しました。
  • ポップアップの隠蔽はクリックイベントを登録して行いますが、表示関数の中から行うようにしました。連続してクリックしてポップアップさせた場合に、クリックしてもそれを消せない場合が発生したためです(原因は不明)。

▲ToTop

第Ⅶブロック:クリックイベントの登録(#190)

最後の処理です。要素タグへのクリックイベント登録では、エラー発生時に登録済みクリックイベントを削除するようにしました。ここで最初にして最後ですが errflag 値を利用します。

イベントハンドラー内で使用した $(this) は click が jQInst のメソッドですから、jQInst を参照します。

jQuery の挙動を解読する(35):Traversing メソッドについて(1) ──jQuery解読(52)

何回かに分けて Traversing に分類されているインスタンスメソッドの解読を行います。

全体の項目とこのエントリイの項目
  • eq()、slice()、is()、filter()、closest()、not()、add()
  • children()、contents()、find()、next()、nextAll()
  • offsetParent()、parent()、parents()、prev()、prevAll()、siblings()、andSelf()、end()

このエントリイでは、本家サイトにおいて Traversing に分類されているインスタンスメソッドの内、次のメソッドを解読対象とします。

eq()、slice()、is()、filter()、closest()、not()、add()

eq()、slice() メソッド解読

eq() メソッドはインスタンスに登録されている要素ノードから、i+1 番目の 1 つのノードを取り出します。

そのために使用される slice() メソッドはインスタンス内に登録されている要素ノードから、連続した一部を取り出すためのメソッドです。このメソッドを適用すると、元のインスタンスの一部のプロパティを保持する新たなインスタンスが得られます。このとき、pushStack() メソッドにより、新たなインスタンスの selector プロパティには抽出経過を記録する文字列が代入されます。

■ eq() メソッド……インスタンスの配列 like なプロパティから i 番目の要素を取り出す
495: eq: function( i ) {
496:  return this.slice( i, +i + 1 );
497: }, 

■ slice() メソッド …… インスタンスの配列 like なプロパティからその連続した部分を取り出す
499: slice: function() {
500:  return this.pushStack( Array.prototype.slice.apply( this, arguments ),
501:   "slice", Array.prototype.slice.call(arguments).join(",") );
502: },
このエントリイ上で eq()、slice() を試してみる

左のボタンをクリックすると、最初の pre タグの背景色が teal になり、もう一度このボタンをクリックすると元に戻ります。

左のボタンをクリックすると 6 番目から 9 番目迄の 4 つの p タグ背景色が teal に変わり、もう一度クリックすると元に戻ります。

尚、ボタンをクリックした際には、mousedown 時にそのボタンの背景色が変わり、mouseup すると元に戻るように設定しました。

is()、filter() メソッド解読

is() メソッドは或るノードがインスタンス内に登録されているかどうかを調べます。filter() メソッドはその名の通りインスタンス内に登録されているノードを対象として、一定の条件でフィルタリングを行います。

■ jQuery(a).is(s) …… a にマッチする要素ノード内に s にマッチする要素があるかどうか調査する。
401: is: function( selector ) {
    // 引数 selector が存在し、かつ jQuery インスタンスの中に selector に
    // マッチするノードが 1 つ以上あれば true を、なければ false を返す。
402:  return !!selector && jQuery.multiFilter( selector, this ).length > 0;
403: },

■ jQuery(s,c).filter(selector) メソッド
349: filter: function( selector ) {
    // selector が関数の場合とそうでない場合とに分けて pushStack() メソッ
    // ドの結果を受け取る。
350:  return this.pushStack(
351:   jQuery.isFunction( selector ) && // selector が関数ならば
     // インスタンスの各プロパティに登録されている要素ノードに対して
352:   jQuery.grep(this, function(elem, i){
353:    return selector.call( elem, i ); // 順番に関数を適用し結果を返す。
354:   }) || // あるいは
355:   // 関数でない場合には、multiFilter メソッドを使用して、インスタンス
     // に登録されている要素ノードから selector にマッチする要素を取り出す。
356:   jQuery.multiFilter( selector, jQuery.grep(this, function(elem){
357:    return elem.nodeType === 1;
358:   }) ), "filter", selector );
359: },
このエントリイ上で is()、filter() を試してみる

左のボタンをクリックすると、この p タグの contents に「左のボタン」という文字列があるかどうか調べ、結果を animate 表示 します。当然それは存在しているのでtrueであることを示す文字列がアニメーションポップアップで表示されます。

尚、このボタンは単純なクリックボタンで toggle にはなっていません。表示された popup を消去するにはその popup 内にある×をクリックします。またボタンが複数回クリックされた場合には、popup を即ぐに消し去ってから新たなポップアニメーションが起動します。

また、このボタンだけは IE8 では作動しません。おそらくは IE8 の Animation に関するバグのためだと思われますが、正確な原因は不明です。

左のボタンをクリックすると「 左のボタン 」という文字列を含む全ての p タグ背景色が teal に変わり、もう一度クリックすると元に戻ります。

尚、ボタンをクリックした際には、mousedown 時にそのボタンの背景色が変わり、mouseup すると元に戻るように設定しました。

closest() メソッド解読

これは 1.3.x から追加された新しいメソッドです。jQuery(s,c)にマッチする要素( A )を対象として、closest(selector) を適用すると、A 及びその親ノードの中から、selector フィルタにマッチするノードをを取得します。

要点はインスタンスが参照しているノードからだけではなく、その親ノードからも条件に合致するノードを探す点にあります。イベントオブジェクトがバブリングして親要素にも達するように、このメソッドは親要素をも対象としている点が注目されます。「 closest(近親者)」と名付けられた所以です。

■ jQuery(s,c).closest(selector) メソッド
361: closest: function( selector ) {
    // jQuery.expr.match.POS は /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/
    // である( #1663 から )。そしてこの正規表現は次のような文字列となる。
    //「 コロンの後に nth から odd までのいずれかの文字列があり、その後に(数字)が 
    // 1 回以下続き、その後に - ではない 1 文字があるか行末まで何もない 」
    // ── selector がこのような文字列の場合には、 jQuery(selector) の
    // 結果を変数 pos に代入し、そうでない場合には null 値を代入する。
362:  var pos = jQuery.expr.match.POS.test( selector ) ? jQuery(selector) : null,
363:   closer = 0;
364:
365:  return this.map(function(){ // インスタンスに map メソッド処理を行って返す。
     // この結果、インスタンスの各要素及びその親ノードの中から、selector 条件に
     // 合致するノードが抽出され、それらをプロパティとする jQuery インスタンス
     // が返される。
366:   var cur = this; // この this は map メソッド内にあるので、
             // インスタンスに登録されている個々の要素ノードを指す。
367:   while ( cur && cur.ownerDocument ) { // cur 及びその document ノードが
      // ある限り、変数 pos があれば cur が pos の何番目かにあるかどうか
      // チェックし、pos がなければ cur にマッチする要素の中に selector
      //  にマッチするものがあるかどうかをチェックし、いずれかが true であれば、
368:    if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selector) ) {
       // cur 要素に closest と言う名前と closer 値を関連づける。
369:     jQuery.data(cur, "closest", closer);
370:     return cur; // curを返す。
371:    }
372:    cur = cur.parentNode; // cur をその親ノードとし、closer 値を増加する。
373:    closer++;
374:   }
375:  });
376: },

左のボタンをクリックすると「 メソッド 」という文字列を含む全ての p タグ背景色が teal に変わり、もう一度クリックすると元に戻ります。

尚、ボタンをクリックした際には、mousedown 時にそのボタンの背景色が変わり、mouseup すると元に戻るように設定しました。

not()、add() メソッド解読

not メソッドは名前からその機能が推測しにくいメソッドです。is() メソッドは「あるかないか」の真偽値を返しますが、notメソッドの返値は jQuery オブジェクトです。

このメソッドは jQuery インスタンスから、selector で指定された条件を満たさないノードを抽出します。

他方、add() メソッドはその名の通り、jQuery インスタンスに selector 条件に合致するノードを「追加」します。

■ jQuery(s,c).not(selector) メソッド
378: not: function( selector ) {
379:  if ( typeof selector === "string" ) // selector が文字列の時
380:   // test special case where just one selector is passed in
     // isSimple は #33 から /^.[^:#\[\.,]*$/。つまり最初に何か 1 文字があり、
     // 次に : でも、# でも、 [ でも、.でも、 ,でもない文字がゼロ個以上続く
     // 文字列を意味する。つまり、何らかのフィルターでもなく、クラス名でもなく、
     // id でもなく、複数のセレクタでもない単純な文字列を意味する。
381:   if ( isSimple.test( selector ) ) // selector が上のような条件の文字列ならば
      // インスタンスから selector 条件を満足するノードを削除し、その結果を
      // jQuery インスタンスを返す。
382:    return this.pushStack( jQuery.multiFilter( selector, this, true ), "not", selector );
383:   else // 単純ではない文字列だったら、インスタンスから selector 条件に
      // 合致するノードを抽出して selector に代入する。
384:    selector = jQuery.multiFilter( selector, this );
385:  // selector に length 値があって、最後の selector 値が定義されていて、
    // selector がノードではなければ true を返す。
386:  var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
387:  return this.filter(function() { // インスタンスに登録されている各ノード
     // に対してfilter メソッドにより引数の関数を適用する。filter メソッド
     // 内では grep メソッドが条件に合致するノードだけを抽出する。
     // これにより各ノードが selector に合致しない場合には true が返され、
     // 合致した場合には false が返される。この結果 selctor 条件に合致しない
     // ノードだけが残され、これをプロパティとする jQuery インスタンスが返される。
388:   return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
389:  });
390: },

■ jQuery(s,c).add(selector) メソッド
392: add: function( selector ) {
393:  return this.pushStack( jQuery.unique( jQuery.merge(
394:   this.get(), // merge メソッドの第 1 引数は配列でなければならない。
395:   typeof selector === "string" ?
      // merge メソッドは第 2 引数が配列 like なプロパティ値を持つオブ
      // ジェクトであっても、配列そのものでも同様に扱える。
396:    jQuery( selector ) :
397:    jQuery.makeArray( selector )
398:  )));
399: },

jQuery の挙動を解読する(34):要素属性に係るメソッドの解読 ── jQuery解読(51)

このエントリイでは、本家サイトにおいて Attributes に分類されているインスタンスメソッドを対象にしてそのコード解読を行います。なお、Attri() メソッドはこちらのエントリイ( jQuery() の挙動を解読する(30) jQuery を使ってタグ属性や css 値を設定/取得する upon ver1.3.2──jQuery解読(45) )において、また text() と html() メソッドは、こちらのエントリイ( jQuery の挙動を解読する(33):DOM Manipulate メソッド解読──jQuery解読(50) )で、それぞれ解読済みなので、ここで対象とするメソッドは次の通りです。

addClass()、hasClass()、removeClass()、toggleClass()、val()

addClass()、hasClass()、removeClass()、toggleClass() が行う処理

これらのインスタンスメソッドは、順に、class 属性の「追加」、「有無調査」、「削除」及び「追加/削除の交互作用」を行うためのもので、hasClass() メソッド以外は 1 つのインスタンスメソッドの中に盛り込まれているので、解読するコードブロック数は 2 つになります。

まずは hasClass() から。

これは class 属性が存在するかしないかを調査するためのメソッドで返値は真偽値です。

■ hasClass( selector ) メソッド
405: hasClass: function( selector ) {
    // 引数 selector が存在し、かつ「 .selector 」が存在すれば true を、
    // 存在しなければ false を返す。
406:  return !!selector && this.is( "." + selector );
407: },
■ 関連メソッド(1) jQuery(a).is(s) …… a 内に s が在るかどうか調査する。
401: is: function( selector ) {
    // 引数 selector が存在し、かつ jQuery インスタンスの中に selector に
    // マッチするノードが 1 つ以上あれば true を、なければ false を返す。
402:  return !!selector && jQuery.multiFilter( selector, this ).length > 0;
403: },
■ 関連メソッド(2) jQuery.multiFilter()……elems 内から expr 該当/非該当要素を抽出する。
2383: jQuery.multiFilter = function( expr, elems, not ) {
2384:  if ( not ) { // not が true ならば
2385:  expr = ":not(" + expr + ")"; // expr 文字列を加工する。
2386: }
2387:  // 対象ノード elems から expr にマッチする要素を抽出する。
    // 返値は Sizzle.matches メソッドの定義から配列となる。
2388:  return Sizzle.matches(expr, elems);
2389: };

▲ToTop

次に、addClass()、removeClass()、toggleClass() について。

これらのメソッドは下に見るように jQuery.each( { name:function(){} },fn ) 形式のコードで定義されており、この構造のメソッドについては,別のエントリイ( anything from here jQuery の挙動を解読する(31):jQuery.each({ nameN:fnN(){}},function(){}) によるメソッド登録──jQuery解読(48) )でその解読を済ませています。

ここでは 3 つのクラス属性に関するメソッドが共通して利用している className クラスメソッドについて解読します。

■ addClass()、removeClass()、toggleClass()
1218:jQuery.each({
1219: removeAttr: function( name ) {
1220:  jQuery.attr( this, name, "" );
1221:  if (this.nodeType == 1)
1222:   this.removeAttribute( name );
1223: },
1224:
1225: addClass: function( classNames ) {
1226:  jQuery.className.add( this, classNames );
1227: },
1228:
1229: removeClass: function( classNames ) {
1230:  jQuery.className.remove( this, classNames );
1231: },
1232:
1233: toggleClass: function( classNames, state ) {
1234:  if( typeof state !== "boolean" )
1235:   state = !jQuery.className.has( this, classNames );
1236:  jQuery.className[ state ? "add" : "remove" ]( this, classNames );
1237: },
1238:
1239: remove: function( selector ) {
1240:  if ( !selector || jQuery.filter( selector, [ this ] ).length ) {
1241:   // Prevent memory leaks
1242:   jQuery( "*", this ).add([this]).each(function(){
1243:    jQuery.event.remove(this);
1244:    jQuery.removeData(this);
1245:   });
1246:   if (this.parentNode)
1247:    this.parentNode.removeChild( this );
1248:  }
1249: },
1250:
1251: empty: function() {
1252:  // Remove element nodes and prevent memory leaks
1253:  jQuery(this).children().remove();
1254:
1255:  // Remove any remaining nodes
1256:  while ( this.firstChild )
1257:   this.removeChild( this.firstChild );
1258: }
1259:}, function(name, fn){
1260: jQuery.fn[ name ] = function(){
1261:  return this.each( fn, arguments );
1262: };
1263:});
■ jQuery.className()
709: className: {
710:  // internal only, use addClass("class")
    // このメソッドは jquery.js 内部でのみ使用するメソッドであり、
    // addClass("class") と記述して使用する。
711:  add: function( elem, classNames ) {
     // classNames をスペースで区切って Name 毎に配列の要素にして、
     // Name 毎に巡回処理する。
712:   jQuery.each((classNames || "").split(/\s+/), function(i, className){
      // elem が要素ノードでそれが className と一致するクラス名を持っていなければ
713:    if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
       // elem のクラス名があれば半角スペースを付け、なければ
       // 何も付けずに、className を elem のクラス名として追加登録する。
714:     elem.className += (elem.className ? " " : "") + className;
715:   });
716:  },
717:
718:  // internal only, use removeClass("class")
719:  remove: function( elem, classNames ) {
720:   if (elem.nodeType == 1) // elem が要素ノードならば
721:    elem.className = classNames !== undefined ? // elem にクラス名があれば
       // 要素 elem のクラス名を要素とする配列を作り、配列要素に対して
       // grep 処理を行う。
722:     jQuery.grep(elem.className.split(/\s+/), function(className){
        // classNames 内に className があるかないか調査し、
        // なければ true を、あれば false を返して、grep メソッド処理を行う。
        // ここに grep メソッドの第 3 引数が指定されていないので、渡された
        // 真偽値が true の場合はその要素を残し、false の場合には削除する。
        // この結果、grep から返される配列の要素から classNames 文字列に含
        // まれるクラス名は消えることになる。
723:      return !jQuery.className.has( classNames, className );
724:     }).join(" ") : // 返された配列の要素を半角スペースで結合して文字列にする。
       // こうして elem.className には classNames 内に含まれているクラス名が
       // 削除されたクラス名が代入される。
725:     ""; // クラス名がなければ空文字を返す。
726:  },
727:
728:  // internal only, use hasClass("class")
    // elem ノードが className というクラス名を持つかどうかを調べるメソッド
729:  has: function( elem, className ) {
     // 要素ノード elem が存在すれば、elem のクラス名か elem を要素とする
     // 配列の要素に、className があるかどうかを調査し、あれば true を、
     // 要素でなければ false を返す。
730:   return elem && jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
731:  }
732: },

jQuery(s,c).val(v) が行う処理

val(v) インスタンスメソッドは、v がない場合には jQuery(s,c) で抽出されるエレメント内の value 属性値を取得し、v がある場合には当該エレメントの value 属性値を設定します。様々な form 部品( input、button、select 等 )の value 属性を操作するためのメソッドなので、form 部品を余り使用しない私にとっては縁遠いものです。

なお、このメソッドが対象とする要素エレメントは、value 属性値を取得する場合には jQuery インスタンスに登録された最初のノードだけですが、設定する場合にはそのような限定はありません。

■ val(value) メソッド
409: val: function( value ) {
    // ケースA: value が未定義の場合、つまり 対象とするform 部品要素から
    // value を取得する場合の処理
410:  if ( value === undefined ) {
411:   var elem = this[0]; //インスタンスの最初のノードを elem に代入する。
412: 
413:   if ( elem ) { // elem があれば
414:    if( jQuery.nodeName( elem, 'option' ) ) elem が option タグならば
       // 属性値 value が明記されていればその値を返し、なければ text 値
       // を返す。なお、空オブジェクトとの or 条件としたのは value が未
       // 定義の時に undefined を返さないための対策か?
415:     return (elem.attributes.value || {}).specified ? elem.value : elem.text;
416:    
417:    // We need to handle select boxes special
418:    if ( jQuery.nodeName( elem, "select" ) ) { // elem が select タグならば
419:     var index = elem.selectedIndex,
420:      values = [],
421:      options = elem.options,
422:      one = elem.type == "select-one"; // type 値が "select-one"かどうか
423: 
424:     // Nothing was selected
425:     if ( index < 0 )
426:      return null; // 何も選択されていないならば null 値を返す。
427: 
428:     // Loop through all the selected options
       // one が true ならば i を indexとし、 max を index +1 とする、
       // false ならば i=0、max は options の要素数とする。
       // i < max を loop 条件とし、増分値は i++ とする。
429:     for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
430:      var option = options[ i ]; // i 番目の options ノードを変数 option に代入
431: 
432:      if ( option.selected ) { // option に selected 属性があれば
433:       // Get the specifc value for the option
         // val() メソッドを再帰呼び出しして結果を value に返す。
434:       value = jQuery(option).val();
435: 
436:       // We don't need an array for one selects
437:       if ( one ) // type 属性が select-one となっていた場合
438:        return value;
439: 
440:       // Multi-Selects return an array
441:       values.push( value );
442:      } // End of if (#432)
443:     } // End of for loop (#429)
444: 
445:     return values;
446:    }
447: 
448:    // Everything else, we just grab the value
      // キャリッジリターンを削除する。
449:    return (elem.value || "").replace(/\r/g, "");
450: 
451:   }
452: 
453:   return undefined; // 未定義値を返す。
454:  }
455: 
    //ケースB: value が数値の時。このときには value を設定することになる。
456:  if ( typeof value === "number" )
457:   value += ''; // 文字列に変換する
458: 
459:  return this.each(function(){ // インスタンス値を更新する。
460:   if ( this.nodeType != 1 ) // インスタンスが要素ノードではないとき
461:    return; // 何もしないで val() メソッドの適用を終える。
462:   // 従って以下のコードはインスタンスが要素ノードの時だけ進行される。
     // value が配列で、type 属性にラジオボタン又はチェックボックスがある場合
463:   if ( jQuery.isArray(value) && /radio|checkbox/.test( this.type ) )
      // this.value 値または this.name 値が value 配列内の要素と
      // 一致すれば checked 値を true とする。つまり当該ノードを「選択」
      // 状態とする。
464:    this.checked = (jQuery.inArray(this.value, value) >= 0 ||
465:     jQuery.inArray(this.name, value) >= 0);
466: 
     // インスタンスに登録されているノードが select タグの場合
467:   else if ( jQuery.nodeName( this, "select" ) ) {
      // value を配列 values に代入する。
468:    var values = jQuery.makeArray(value);
469: 
      // インスタンス内の各 option ノードを走査して
470:    jQuery( "option", this ).each(function(){
       // this.value または this.text 値が values 配列内にあれば
       // その要素の selected 値を true とする。
471:     this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
472:      jQuery.inArray( this.text, values ) >= 0);
473:    });
474: 
475:    if ( !values.length ) // 配列要素が空ならば
476:     this.selectedIndex = -1; // 無選択状態とする。
477: 
478:   } else // 属性がラジオボタンでも、チェックボックスでも、select でもなければ
479:    this.value = value; // インスタンスの value 属性値を value とする。
480:  });
481: },

▲ToTop

jQuery を使ってDOM Manipulate──例題で動きを見る

jQuery で DOM Manipulate

このエントリイでは、各種 DOM Manipulate のための jQuery インスタンスメソッドの例を試します。

それぞれのメソッドの働き方や差異は、jQuery本家サイトの Document でも見ることが出来ますが、相互に比較しながら一覧出来た方がより分かりやすいので、そのような例題を作ってみました。

なおここであつかったメソッドの解読は関連エントリイリスト内に表示した「・・・解読(50)」で行っています。

適用例の説明
  • 下のボタンは各種 DOM Manipulate メソッドを実行するためのもの。15 のいずれかをクリックすると、ボタンの下にある薄緑色のボックス内で各種メソッドの効果を表示します。
  • メソッドの適用効果を消去するにはもう一度同じボタンをクリックします。
  • メソッドの適用対象は、薄緑色のボックス内に配置した 3 つの p タグです。これをボタン上では $(this) と表示しました。3 つの pタグはピンクの枠で示していますが、それらを対象として各種 DOM Manipulate メソッドを適用します。
  • 他方、働き方を逆転させるメソッドの場合には、メソッド起動要素がサイト内に存在していなければ成りませんので、そのための要素として DIV タグ( class="targetDiv704" )を用意しました。

メソッドの引数として次の html 文字列を準備しました。

  • "<div style='background-color:maroon;border:4px dotted gray;margin:2px;padding:2px;'></div>"
  • "<p style='background-color:maroon;border:4px dotted gray;margin:2px;padding:2px;'>これはボタンをクリックしたことにより追加されたノードです。</p>"
  
   
   
   

(第1 pタグ)これは各種 DOM Manipulate メソッドの働き方を視覚的に見やすくしたサンプルです。

(第2 pタグ)このブロックを包含する div タグがあり、その中に複数の 3 つの p タグと 2 つの div タグを配置し、3 つめのパラグラフには画像を配置しました。

(第1 divタグ)3 つの p タグを操作対象として各種のメソッドを適用します。

(第3 pタグ) これは画像を含むパラグラフです。

(第2 divタグ)
逆転メソッドで使用する div タグ

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

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。