Element.ClassNamesクラス

【抜粋】一部省略
Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },
(省略)
}

Object.extend(Element.ClassNames.prototype, Enumerable);

Elementオブジェクトを名前空間にして、Enumerableクラスを継承しています。

要素のCSSクラスを扱うクラスです。オブジェクトのクラスの名前(ここでいう「Element.ClassNames」や、配列の「Array」等)を扱うわけではありません。*1

要素のCSSクラスは、classNameプロパティに文字列で設定されています。複数設定されている場合は、タグでの指定時と同様に空白区切りで連結されています。これを変更すると、その時点で実際に適用されるCSSクラスも変更されます。Element.ClassNamesはこれを扱いやすくするために作られたクラスといえます。

http://q.hatena.ne.jp/1169784184

initializeメソッド

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

インスタンス生成時に、引数の要素(ID指定可)をelementプロパティに格納します。

_eachメソッド

【抜粋】
  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

Enumerableクラスを継承するために必要なメソッド。プログラマが呼び出すことを想定していません。要素のclassNameプロパティ、つまりCSSクラス名を空白分割して配列にしています。selectメソッドで空文字を除外しています。空文字になるケースがちょっと分からないのですが・・・。

その上で、配列に格納されている各CSSクラス名を、引数の関数iteratorで処理しています*2。よって、Enumerableクラスから継承するメソッドでは、各CSSクラス名を処理対象とすることができます。

setメソッド

【抜粋】
  set: function(className) {
    this.element.className = className;
  },

引数のCSSクラス名を、要素のclassNameに設定するメソッド。

例は最後にまとめます。

addメソッド

【抜粋】
  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set(this.toArray().concat(classNameToAdd).join(' '));
  },

引数のCSSクラス名を、要素のCSSクラス名に追加するメソッド。ただし、すでに追加されている場合は処理しません。includeおよびtoArrayメソッド*3が対象とするのは要素(this)ではなくて、前述_eachメソッドが返却する、要素のCSSクラス名を格納した配列であることに注意してください。*4

例は最後にまとめます。

removeメソッド

【抜粋】
  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set(this.select(function(className) {
      return className != classNameToRemove;
    }).join(' '));
  },

引数のCSSクラス名を、要素のCSSクラス名から削除するメソッド。ただし、設定されていない場合は処理しません。selectメソッド*5が対象とするのが、前述_eachメソッドが返却するCSSクラス名の配列であるのは、addメソッドと同じです。

toStringメソッド

【抜粋】
  toString: function() {
    return this.toArray().join(' ');
  }

要素のCSSクラス名を半角空白区切りの文字列にして返却するメソッド。this.element.classNameプロパティとほとんど変わりませんが、区切りの空白文字が必ず半角空白1字になる点が違います。classNameプロパティは、タグ等の設定をそのまま保持しているので、区切りに複数の空白文字が存在することがあります。

【例】
<html>
<head>
<title></title>
<style>
<!--
.classA{
  border:solid blue 2px;
}
.classB{
  background-color:yellow;
}
.classC{
  color:red;
  font-weight:bold;
}
-->
</style>
<script language="javascript" src="prototype.js" charset="utf-8"></script>
<script>
<!--
var testCN;
function init(){
  testCN = new Element.ClassNames('test');
  showCN();
}
function showCN(){
  $('testCN').value = testCN.toString();
}
//-->
</script>
</head>
<body onload="init();">
<div id="test" class="classA classB">TEST TEST TEST</div>
<input type="text" id="testCN" style="width:200px;"/>
<button onclick="testCN.set($('testCN').value);showCN();">SET</button>
<br/>
<button onclick="testCN.add('classA');showCN();">ADD classA</button>
<button onclick="testCN.remove('classA');showCN();">REMOVE classA</button>
<button onclick="testCN.add('classB');showCN();">ADD classB</button>
<button onclick="testCN.remove('classB');showCN();">REMOVE classB</button>
<button onclick="testCN.add('classC');showCN();">ADD classC</button>
<button onclick="testCN.remove('classC');showCN();">REMOVE classC</button>
</body>
</html>

*1:instanceof演算子で特定クラスのインスタンスであるかどうかを調べることはできます。また、オブジェクトのconstructorプロパティを使う手もあります。toString()するとクラス名が取れる場合もありますが、prototype.jsのクラス作成方法だと全部Class.createの無名関数になってしまいます。。。

*2:コード内の_eachはArrayクラスのメソッド。

*3:Enumerableクラスから継承したメソッド

*4:toArrayメソッドを経由するのも変な感じですが、CSSクラス名の配列そのものを取得するためにはこれが一番簡単みたいです。。。

*5:Enumerableクラスから継承したfindAllメソッドの別名。