document.getElementsByTagName("div")[0].spanNum()で、渡されたdivエレメントの中のspanの個数を返すようにしたいです。Object.extend(HTMLDivElement.prototype, { ←エラー
spanNum:function(){
return this.getElementsByTagName("span").length;
}
});上のでは、「HTMLDivElementなんてないよ」と言われます。var DOMExtensions = {
spanNum : function () {
return this.getElementsByTagName ('span').length;
}
};
var node = document.getElementsByTagName ('div')[0];
DOMExtensions.spanNum.call (node);function EnumerableHTMLDivElement (element) {
this.element = element;
}
EnumerableHTMLDivElement.prototype.spanNum = function () {
return this.element.getElementsByTagName ('span').length;
};
var node = document.getElementsByTagName ('div')[0];
var obj = new EnumerableHTMLDivElement (node);
obj.spanNum ();HTMLDivElement.prototype.__defineGetter__ = function ('spanNum', function () {
return this.getElementsByTagName ('span').length;
} );
var node = document.getElementsByTagName ('div')[0];
node.spanNum; // length のような生きたプロパティvar node = document.getElementsByTagName("div")[0]."div要素内のspan要素の中から指定されたspan要素だけを含んだdiv要素を返す関数"."div要素の内部のspan要素を指定された規則に従い並べ替える関数"."div要素の内部のspan要素を逆順に並べ替える関数";というように、div要素を持ちまわして処理を記述できたらステキだな〜、と思ったわけです。<DIV id="test"> <DIV name="0"><SPAN>ken</SPAN><SPAN>19</SPAN></DIV> <DIV name="1"><SPAN>john</SPAN><SPAN>18</SPAN></DIV> <DIV name="2"><SPAN>mary</SPAN><SPAN>14</SPAN></DIV> <DIV name="3"><SPAN>yasu</SPAN><SPAN>17</SPAN></DIV> </DIV>以下の新規クラスを作成し、
function EnumerableHTMLDivElement(element){
this.element=element;
}
EnumerableHTMLDivElement.prototype=Object.extend({
rlength:function(){ //Row length
return this.element.getElementsByTagName("div").length;
},
clength:function(){ //Column length
return this.element.getElementsByTagName("div")[0].getElementsByTagName("span").length;
},
swap:function(numa,numb){
var tmp=this.element.getElementsByTagName("div")[numa].name;
this.element.getElementsByTagName("div")[numa].name=this.element.getElementsByTagName("div")[numb].name;
this.element.getElementsByTagName("div")[numb].name=tmp;
return this;
},
reverse:function(){
for(var i=0;i<this.rlength()/2;i++){
this.swap(i,this.rlength()-1-i);
}
return this;
}
});以下のようにして動作が確認できました。var obj=new BookDiv($("test"));
obj.swap(0,1).reverse();
/* 以下のようになる
<DIV id="test">
<DIV name="3"><SPAN>ken</SPAN><SPAN>19</SPAN></DIV>
<DIV name="2"><SPAN>john</SPAN><SPAN>18</SPAN></DIV>
<DIV name="0"><SPAN>mary</SPAN><SPAN>14</SPAN></DIV>
<DIV name="1"><SPAN>yasu</SPAN><SPAN>17</SPAN></DIV>
</DIV>
*/とりあえずname属性だけですが、後はゴリゴリ実装していこうと思います。Object.extend(String.prototype, {
pickout:function(start,end){
return this.substring(0,start)+this.substring(end,this.length);
}
});<ul id="test">
<li class="person">
<span class="name">Ken</span>
<span class="age">19</span>
</li>
<li class="person">
<span class="name">John</span>
<span class="age">18</span>
</li>
<li class="person">
<span class="name">Mary</span>
<span class="age">14</span>
</li>
<li class="person">
<span class="name">Yasu</span>
<span class="age">17</span>
</li>
</ul><script type="application/javascript">
function getElementsByXPath (expression) {
return document.evaluate (expression, this, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
}
function personLength () {
return getElementsByXPath.call (this, 'child::*[ @class="person" ]').snapshotLength;
}
function swapPersons (person1, person2) {
if (person1 && person2) {
var tmp = document.createElement ('span');
person1.parentNode.replaceChild (tmp, person1);
person2.parentNode.replaceChild (person1, person2);
tmp.parentNode.replaceChild (person2, tmp);
}
}
function swapPersonsByPosition (pos1, pos2) {
var result = getElementsByXPath.call (this, 'child::*[ @class="person" ]'
+ '[ position() = ' + pos1 + ' or position() = ' + pos2 + ']');
swapPersons.call (this, result.snapshotItem (0), result.snapshotItem (1));
}
function swapPersonsByName (name1, name2) {
var result = getElementsByXPath.call (this, 'child::*[ @class="person" ]'
+ '[ child::*[ @class="name" ] = "' + name1 + '" '
+ 'or child::*[ @class="name" ] = "' + name2 + '"]');
swapPersons.call (this, result.snapshotItem (0), result.snapshotItem (1));
}
function reverse () {
var i = 0;
var I = personLength.call (this);
for (; i < (I / 2); i++) swapPersonsByPosition.call (this, i + 1, I - i);
}
//______________________________________________________________________
function PersonList (element) {
this.element = element;
}
PersonList.prototype.reverse = function () {
reverse.apply (this.element, arguments);
return this;
};
PersonList.prototype.swapPersonsByPosition = function () {
swapPersonsByPosition.apply (this.element, arguments);
return this;
};
PersonList.prototype.swapPersonsByName = function () {
swapPersonsByName.apply (this.element, arguments);
return this;
};
//______________________________________________________________________
var pList = new PersonList (document.getElementById ('test'));
pList.swapPersonsByPosition (1, 2)
.swapPersonsByName ('John', 'Mary')
.reverse (); // Yasu, John, Ken, Mary
</script>// HTMLElement
function hasClassName (className) {
var expression = new RegExp (' ' + className + ' ', 'i');
return expression.test (' ' + this.className + ' ');
}
// NodeList
function getElementsByFilter (filter) {
var result = [ ];
var i = 0;
var I = this.length;
for (; i < I; i++) {
if (this[i].nodeType == 1 /*Node.ELEMENT_NODE*/ && filter (this[i], i)) {
result.push (this[i]);
}
}
return result;
}
// Element
function getChildElements (filter) {
return getElementsByFilter.call (this.childNodes, filter || function () { return true; } );
}
// Element
function getDescendantElements (filter) {
return getElementsByFilter.call (this.getElementsByTagName ('*'), filter || function () { return true; } );
}
//______________________________________________________________________
function swapPersons (person1, person2) {
if (person1 && person2) {
var tmp = document.createElement ('span');
person1.parentNode.replaceChild (tmp, person1);
person2.parentNode.replaceChild (person1, person2);
tmp.parentNode.replaceChild (person2, tmp);
}
}
// Element
function personLength () {
return getChildElements.call (this).length;
}
// Element
function swapPersonsByPosition (pos1, pos2) {
var nodes = getChildElements.call (this, function (node, i) { return true; } );
swapPersons.call (this, nodes[pos1], nodes[pos2]);
}
// Element
function swapPersonsByName (name1, name2) {
var nodes = getDescendantElements.call (this, function (node) {
return hasClassName.call (node, 'name') &&
(node.firstChild.data == name1 || node.firstChild.data == name2);
} );
if (nodes[0]) nodes[0] = nodes[0].parentNode;
if (nodes[1]) nodes[1] = nodes[1].parentNode;
swapPersons.call (this, nodes[0], nodes[1]);
}
// Element
function reverse () {
var i = 0;
var I = personLength.call (this);
for (; i < (I / 2); i++) swapPersonsByPosition.call (this, i, I - 1 - i);
}
//______________________________________________________________________
function PersonList (element) {
this.element = element;
}
PersonList.prototype.reverse = function () {
reverse.apply (this.element, arguments);
return this;
};
PersonList.prototype.swapPersonsByPosition = function () {
swapPersonsByPosition.apply (this.element, arguments);
return this;
};
PersonList.prototype.swapPersonsByName = function () {
swapPersonsByName.apply (this.element, arguments);
return this;
};
//______________________________________________________________________
var pList = new PersonList (document.getElementById ('test'));
pList.swapPersonsByPosition (0, 1)
.swapPersonsByName ('John', 'Mary')
.reverse ();
// Yasu, John, Ken, Mary// NodeList
function getElementsByFilter (filter) {
var result = [ ];
var i = 0;
var I = this.length;
for (; i < I; i++) {
if (this[i].nodeType == 1 /*Node.ELEMENT_NODE*/ && filter (this[i], i)) {
result.push (this[i]);
}
}
return result;
}これの出力が、thisが階層になっていた場合どうなるのか私は知らないのですが、EnumerableHTMLDivElement.prototype=Object.extend({
rlength:function(){ //Row length
return this.element.getElementsByTagName("div").length;
},
clength:function(){ //Column length
return this.element.getElementsByTagName("div")[0].getElementsByTagName("span").length;
}
});分けてやるPersonList.prototype.swapPersonsByPosition = function () {
swapPersonsByPosition.apply (this.element, arguments);
return this;
};
PersonList.prototype.swapPersonsByName = function () {
swapPersonsByName.apply (this.element, arguments);
return this;
};理由をお教え願えないでしょうか?function reverse () {
var i = 0;
var I = personLength.call (this);
for (; i < (I / 2); i++) swapPersonsByPosition.call (this, i, I - 1 - i);
}Iを先に求めておくのは、実行速度のためということで納得できるのですが、function reverse () {
var I = personLength.call (this);
for (var i = 0; i < (I / 2); i++) swapPersonsByPosition.call (this, i, I - 1 - i);
}としてしまうのですが。function getElementsByFilter (filter) {
if (this instanceOf NodeList) {
....
} else {
throw TypeError;
}
}PersonList.prototype = {
swap : function () { ...; },
length : function () { ...; }
};// public class PersonList extends List
PersonList.prototype = new List;
PersonList.prototype.constructor = PersonList;
PersonList.prototype.swap = function () { ...; };
PersonList.prototype.length = function () { ...; };function reverse () {
var i = 0;
var I = personLength.call (this);
while (i < I) swapPersonsByPosition.call (this, i, I - 1 - i++);
}