Abstract.Insertionクラス

前提条件:DOMについての理解

Insertion関連のクラスを理解するためには、DOMについての理解が不可欠になります。実は筆者もあまり詳しいとは言えません^^; このため、不適切な記述があるかもしれませんが、ご容赦ください。気がついたらその都度修正します・・・。

【抜粋】一部省略
Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();
(省略)
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

prototype.jsの最初のほうで作成したAbstractオブジェクトを名前空間にしています*1。名前のとおり、抽象クラス扱いです。後述のInsertion.Before、Insertion.Top、Insertion.Bottom、Insertion.Afterクラスにより継承されます。継承は以下のようになっています。

【参考】Abstract.Insertionクラスの継承
Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
(省略)
});

抽象クラス実装方法としては前述Ajax.Baseクラスに似ています。「Ajax.Baseクラス - Backstage of theater.js」を参照してください。ちょっと違うのは、コンストラクタとなるAbstract.Insertionの関数に処理があるということです。次で解読します。

Abstract.Insertionコンストラク

【抜粋】
Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertionクラスのコンストラクタとなる関数*2。これは上で挙げた「Abstract.Insertionクラスの継承」の例の場合、「new Abstract.Insertion('beforeBegin')」で実行されます。initilizeメソッドはこの時点では実行されないので注意してください。initilizeメソッドが実行されるのは、各サブクラスのインスタンスが生成されるときです。

Abstract.Insertionのadjacencyプロパティには、後述の4クラスによる継承時に以下の文字列が設定されます。

クラス adjacencyプロパティ設定文字列
Insertion.Before beforeBegin
Insertion.Top afterBegin
Insertion.Bottom beforeEnd
Insertion.After afterEnd

次に述べるinitilizeメソッドで使用します。

initilizeメソッド

【抜粋】
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        if (this.element.tagName.toLowerCase() == 'tbody') {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

後述のInsertion.Before、Insertion.Top、Insertion.Bottom、Insertion.Afterクラス共通のinitilizeメソッドです。第一引数は基準要素、第二引数は挿入するHTMLソースです。

IEOperaの場合は、要素のinsertAdjacentHTMLメソッドを使用しています。insertAdjacentHTMLについては以下を参照してください。

【参考サイト】:Microsoft API and Reference Catalog

前述のadjacencyプロパティを使用しています。

ただ、「HTMLに誤りがあると、このメソッドは失敗する。」とあるので、tableタグで囲まれていないtrやtdタグの挿入はできないようです。この場合は次のcontentFromAnonymousTableメソッドでNodeを作ってから、各サブクラスが実装するinsertContentメソッドにより挿入しています。

Netscape等のMozilla系ブラウザにはinsertAdjacentHTMLメソッドがないため、別の方法で挿入します。

要素のownerDocumentプロパティはdocumentオブジェクトと(結果的に)ほぼ同義です。

【参考サイト】:http://allabout.co.jp/internet/javascript/closeup/CU20041015A/index.htm

createRangeメソッドによりRangeオブジェクトを作成しています。

【参考サイト】:
http://members.jcom.home.ne.jp/jintrick/Personal/DOM_Range.html
JavaScript Tips collection - Mozilla's Blues
This Document has Moved
This Document has Moved

サブクラスが実装するinitializeRangeメソッドを呼び出し、Rangeオブジェクトの位置を設定します。その後、RangeオブジェクトのcreateContextualFragmentメソッドでHTML文字列をDocumentFragment化し、サブクラスが実装するinsertContentメソッドで指定位置に挿入します。

【参考サイト】:http://members.jcom.home.ne.jp/jintrick/Personal/documentFragment.html

すみません、参考サイトばっかりで・・・。

createContextualFragmentメソッドについてですが、詳しいことがすぐには分からないです。どうやらMozilla系独自のメソッドみたいで、参考サイト「This Document has Moved」には記述がありません。推察するに、setStartBeforeメソッド等で位置を指定後、ソースを引数にして使用すると、その位置に適合したDocumentFragmentを返却してくれる、という動作のように思えます。サブクラス実装のinitializeRangeメソッドはそのための準備ということでしょう。

挿入後の0.01秒後、引数content中のスクリプトタグの内容をeval関数で実行しています。

contentFromAnonymousTableメソッド

【抜粋】
  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }

前述initializeメソッドで、IEでテーブルに行*3を追加するために、HTML文字列からNodeを生成するためのメソッドです。こうやるんですね・・・。各サブクラスのinsertContentメソッドで使用するために、Arrayオブジェクトに変換しています。詳しくは後述の各クラスを参照してください。

例も各サブクラスで提示します。

*1:これ以前は抽象クラスにAbstractを使っていないのですが。抽象クラス実装はなぜか統一性がないですね・・・

*2:prototype.jsではClass.createメソッドを使うことが多いため、コンストラクタを直に記述するのは珍しいです

*3:以前、後続Verでセル追加が可能のように書いていましたが、間違いです・・・