必要に応じて複数回クローンを作成するようなモデルエレメントに対してgetChildsを実行した場合、getChildsの機能によってiTやvalueなどが変化するため、一度getChildsで処理したエレメントやその複製をgetChildsに渡すと、意図した参照用プロパティが得られないという問題がありました。
上記の問題は、本日公開するgetCloneという独自関数で解決できます。
以下ソース
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>getChilds</title> | |
<style type=text/css> | |
.max{width:100%;height:100%} | |
.w-max{width:100%} | |
</style> | |
</head> | |
<body> | |
<table class=max> | |
<tr height=1> | |
<td> | |
<button>追加</button> | |
<button>オールクリア</button> | |
</td> | |
</tr> | |
<tr> | |
<td> | |
<div class=max style="overflow:auto;border:solid 1px #000;padding:10px;" title=メイン> | |
<table title=モデル border=1 class=w-max> | |
<td><textarea class=w-max></textarea></td> | |
<td width=1> | |
<button>削除</button> | |
</td> | |
</table> | |
</div> | |
</td> | |
</tr> | |
</table> | |
</body> | |
<script> | |
resizeTo(350,300) | |
CN='childNodes', iT='innerText', LEN='length', FI='firstChild', PR='previousSibling', PA='parentNode', NE='nextSibling', iB='insertBefore' | |
for0L=function(arr,fun){for(var i=0,L=arr[LEN],res;i<L;i++){if(res=fun(i,arr[i])){return res}}} | |
forIn=function(obj,fun){var name,res; for(name in obj){if(res=fun(name, obj[name])){return res}}} | |
isEqual=function(elemA, elemB){ | |
// elemAとelemBが同一エレメントを参照しているならtrueを返す。それ以外はfalseを返す。 | |
var d=document.createElement('div'), fun=this.isEqual=function(elemA, elemB){ | |
elemA[iB](d.removeNode(true), elemA[FI]) | |
var str=d[iT]=1111111, sw=false | |
while(!sw){ | |
if(elemB[FI][iT]!=str){ break } | |
str=d[iT]=1234567 | |
if(elemB[FI][iT]!=str){ break } | |
sw = true | |
} | |
d.removeNode(true) | |
return sw | |
} | |
return fun(elemA, elemB) | |
} | |
getChilds=function(){ | |
var tagName2接頭辞={button:'btn', input:'inp', select:'sel', a:'lnk', iframe:'ifr', table:'tbl', textarea:'ta'} | |
var inp接頭辞={checkbox:'chk', radio:'rad', text:'inp', number:'num'} | |
var arr階層=[], arr階層_i=0 | |
var get名前=function(){ | |
var F=function(prop, v){return {prop:prop, v:v}} | |
var E, objNames={value:1, title:1, innerText:1}, forIn用=function(name){ return E[name] ? F(name, E[name]) : 0 } | |
return function(elem){ | |
E = elem | |
var obj=forIn(objNames, forIn用), it=E[iT], src=E.src | |
if(obj){return obj} | |
if(src){return F('src', src.replace(/[\\\/]([^\\\/]+)$/)[1])} | |
} | |
}() | |
var return用obj, objクリア対象外={btn:1} | |
var for0L用=function(i, elem){ | |
var name=(elem.tagName || '').toLowerCase() | |
if(!name){return} | |
arr階層[arr階層_i] = true | |
arr階層[++arr階層_i] = false | |
fun再帰(elem[CN]) | |
arr階層_i-- | |
// 例えば「<button>開始</button>」なら「btn開始」のような名前で参照できるようにする。 | |
var 接頭辞 = ((name=='input' ? inp接頭辞[elem.type] : '') || tagName2接頭辞[name] || name) | |
var 名前 = get名前(elem) | |
// 名前があってもそれがiT由来で、かつ子要素を持つエレメントの場合は参照の対象外。 | |
if(!名前 || 名前.prop!=iT || !arr階層[arr階層+1]){return用obj[接頭辞 + (名前 ? 名前.v : '')] = elem} | |
// 名前.vが「*」から始まる場合は「*」のみ削除する。それ以外の場合は名前.v=''とする。 | |
if(名前 && !objクリア対象外[接頭辞] && (名前.prop!=iT || !arr階層[arr階層_i+1])){ elem[名前.prop] = 名前.v.charAt(0)=='*' ? 名前.v.replace(/^\*/,'') : '' } | |
arr階層.pop() | |
} | |
var fun再帰=function(cn){ for0L(cn,for0L用) } | |
var getChilds=function(elem){return用obj={elem:elem}; fun再帰(elem[CN]); return return用obj} | |
getChilds.getClone = function(objModel){ | |
// elemとobjChildsの関係性を丸ごと複製したものを作成して返す。 | |
var elemClone=objModel.elem.cloneNode(true), objRet={elem:elemClone} | |
forIn(objModel, function(name, elem){ | |
if(name=='elem'){return} | |
var arr=[], elemC=elemClone | |
while(elem[PR] || (elem[PA] && elem[PA].tagName) ){ | |
if(elem[PR]){ | |
arr.unshift(NE); elem=elem[PR] | |
}else{ | |
arr.unshift(FI); elem=elem[PA] | |
} | |
if(isEqual(elem, objModel.elem)){break} | |
} | |
for0L(arr, function(i, str){ elemC=elemC[str] }) | |
objRet[name] = elemC | |
}) | |
return objRet | |
} | |
return getChilds | |
}() | |
var obj=getChilds(document.body[FI]), objモデル=getChilds(obj.tblモデル.removeNode(true)) | |
var 初期化=function(obj){ | |
obj.btn削除.onclick = function(){ obj.elem.removeNode(true) } | |
obj.ta.value = (new Date()).toLocaleString() | |
} | |
with(obj){ | |
btn追加.onclick=function(){ | |
var newObj=getChilds.getClone(objモデル) | |
divメイン[iB](newObj.elem) | |
初期化(newObj) | |
} | |
btnオールクリア.onclick=function(){ divメイン[iT] = '' } | |
} | |
</script> | |
</html> |
動作画面

これでクローン作製用モデルエレメントも名付けに悩まなくてOK!
0 件のコメント:
コメントを投稿