/*
 *
 * Copyright (c) 2009 Jimbo
 * Dual licensed under the MIT and GPL licenses.
 * 
 * Date: 2010-10-22 (Fri, 22 Oct. 2010)
 * Revision: 0.1
 * Email:jimboyeah@gmail.com
 * 
 * Last Modify: 2010-10-22 14:08:08
 * Content: TODO: mouse scrolling action effect
 * 
 * Pretty 1.0 
 * Date:2010-2-15, 农历年初二，祝贺信息发出前。
 * Bug: 
 *    两个Pretty不能并例。 解决方法：使用表格，用两个同行td分隔来处理。
 *    不会反向弹出列表
 *    不可以键盘操作
 *    不可以自动限定列表高度
 *    在IE6下会被SELECT穿透
 *    不可以級连
 *    不可以分组
 *
 * Pretty 1.0 RC 
 * Date:2010-11-23 which day I can't hears any thing of my alarm seted in my iPod.
 * Bug fix: all found in Pretty 1.0
 *
 */

/*
 *Internet Explorer 6:  userAgent = Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)
 *Mozilla Firefox 3:    userAgent = Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.10) Gecko/2009042316 Firefox/3.0.10
 *Safari 3:             userAgent = Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/525.28.3 (KHTML, like Gecko) Version/3.2.3 Safari/525.29
 *Opera 10:             userAgent = Opera/10.00 (Windows NT 5.1; U; zh-cn) Presto/2.2.2
 *Netscape Navigator 9: userAgent = Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080219 Firefox/2.0.0.12 Navigator/9.0.0.6
 *Chrome:               userAgent = Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.55 Safari/533.4
 *Maxthon:              userAgent = Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US) AppleWebKit/533.9 (KHTML, like Gecko) Maxthon/3.0 Safari/533.9
*/
var UA = window.navigator.userAgent;
var isIE = UA.indexOf("MSIE")!=-1;
var isMF = UA.indexOf("Firefox")!=-1&&UA.indexOf("Navigator")==-1;
var isBadMaxThon = UA.indexOf("Maxthon")!=-1;
var isBadChrome = UA.indexOf("Chrome")!=-1;
var isSF = UA.indexOf("Safari")!=-1 && isBadMaxThon==false && isBadChrome==false;
var isNN = UA.indexOf("Navigator")!=-1;
var isOP = UA.indexOf("Opera")!=-1;
//jQuery.ready比window.onload更快！
function bindReady(ready){

  var sentinal_ready = false;
  var isAttached = "";

	// Mozilla,Chrome,Maxthon,Opera (see further below for it) and webkit nightlies currently support this event
	if ( document.addEventListener && !isOP){
		// Use the handy event callback
		document.addEventListener( "DOMContentLoaded", ready, false );
    isAttached = "addEventListener";
    return;
  }
	// If IE is used and is not in a frame
	// Continually check to see if the document is ready
	if (isIE && window == top){
    isAttached = "IE";
    (function(){
      if (sentinal_ready) return;
      try {
        // If IE is used, use the trick by Diego Perini
        // http://javascript.nwbox.com/IEContentLoaded/
        document.documentElement.doScroll("left");
      } catch( error ) {
        setTimeout( arguments.callee, 0 );
        return;
      }
      // and execute any waiting functions
      ready();
      sentinal_ready = true;
    })();
    return;
  }

	if ( isOP ){
    isAttached = "opera";
		document.addEventListener( "DOMContentLoaded", function () {
			if (sentinal_ready) return;
			for (var i = 0; i < document.styleSheets.length; i++)
				if (document.styleSheets[i].disabled) {
					setTimeout( arguments.callee, 0 );
					return;
				}
			// and execute any waiting functions
			ready();
      sentinal_ready = true;
		}, false);
    return;
  }

	if ( isSF ) {
    isAttached = "safari";
		var numStyles;
		(function(){
			if (sentinal_ready) return;
			if ( document.readyState != "loaded" && document.readyState != "complete" ) {
				setTimeout( arguments.callee, 0 );
				return;
			}
			if ( numStyles === undefined ){
				//numStyles = jQuery("style, link[rel=stylesheet]").length;
        numStyles = document.getElementsByTagName("style").length;
        var lks = document.getElementsByTagName("link");
        for(var i=0; i<lks.length; i++) if(lks[i].rel=="stylesheet") numStyles++;
      }
			if ( document.styleSheets.length != numStyles ) {
				setTimeout( arguments.callee, 0 );
				return;
			}
			// and execute any waiting functions
			ready();
      sentinal_ready = true;
		})();
    return;
  }
	// A fallback to window.onload, that will always work
	bind(window,"onload",ready,false);
}

bindReady(function (){
  //文档加载后可执行区......
  if(window.Pretty) throw "window.Pretty has defined, so Pretty will overwrite it.";
  window.Pretty = new Class_Pretty();
  Pretty.init();
  }
);

//event assistant
function proxy(tag,fun){
  return function(e){
    if(typeof(fun)=="function")
      return fun.call(tag,e);
    return null
  }
}

//the bind method will attach context object by default, so event can not be remove, or use the remove prameter 
function bind(tag,event,handler,capture,removable){
  if(typeof(handler)!="function")throw new Error("handler must a function");
  if(typeof(tag)!="object") throw new Error("tag must an DOM element");
  capture = capture?true:false;
  removable = removable?true:false;
  if(event=="onmousewheel"&&!isIE) event = "DOMMouseScroll";
  if(event=="DOMMouseScroll"&&isIE) event = "onmousewheel";
  if(!removable) handler = proxy(tag,handler);
  if (tag.addEventListener){
    tag.addEventListener(event.replace(/^on/,""),handler,capture);
    if(event=="DOMMouseScroll") //Opera/Chrome/Safari
      tag.onmousewheel=handler;
      //tag.addEventListener("onmousewheel", handler, capture);
  }else if(tag.attachEvent){
    tag.attachEvent(event,handler);
  }else{
    tag[event] = handler;
  }
}

function loose(tag,event,handler,capture){
  if(typeof(handler)!="function")throw new Error("handler must a function");
  if(typeof(tag)!="object") throw new Error("tag must an DOM element");
  capture = capture?true:false;
  if(event=="onmousewheel"&&!isIE) event = "DOMMouseScroll";
  if(event=="DOMMouseScroll"&&isIE) event = "onmousewheel";
  if (tag.addEventListener){
    tag.removeEventListener(event.replace(/^on/,""),handler,capture);
  }else if(tag.detachEvent){
    tag.detachEvent(event,handler);
  }else{
    tag[event] = null; //arbitary set null
  }
}

//*****************************************************************************
//toggleClass JavaScript Kit by Jimbo 2010/8/1
function toggleClass(el,s){
  var rx = new RegExp(s+" | "+s+"|^"+s+"$");
  if(rx.test(el.className)){
    el.className = el.className.replace(s,"").replace("  ","");
  }else{
    el.className = el.className + " " + s;
  }
}
function betweenClass(el,a,b){
  var rxa = new RegExp(a+" | "+a+"|^"+a+"$");
  var rxb = new RegExp(b+" | "+b+"|^"+b+"$");
  dbg("betweenClass:"+el.className);
  if(rxa.test(el.className)){
    el.className = el.className.replace(a,b).replace("  ","");
  }else if(rxb.test(el.className)){
    el.className = el.className.replace(b,a).replace("  ","");
  }else{
    el.className = el.className + " " + a;
  }
}
function hasClass(el,c){
  var rxa = new RegExp(a+" | "+a+"|^"+a+"$");
  return rxa.test(el.className);
}
function getWith(els,classname){
  var r = new RegExp(classname+" | "+classname+"|^"+classname+"$","i");
  for(var i=0;i<els.length;i++){
    if(r.test(els[i].className)) return els[i];
  }
}
function removeClass(tag,classname){
  var cs = classname.split(" ");
  var nc = tag.className;
  for(var i=0; i<cs.length; i++){
    if(cs[i]==" ") cs[i]="";
    nc = nc.replace(cs[i],"");
  }
  tag.className = nc;
}
function addClass(tag,classname){
  var nc = tag.className+" "+classname;
  nc = nc.replace("  "," ");
  var cs = nc.split(" ");
  var pc = {};
  for(var i=0; i<cs.length; i++){
    if(cs[i]!=""){
      pc[cs[i]]=(cs[i]);
    }
  }
  nc = "";
  for(var c in pc) nc += " "+c;
  tag.className = nc.substr(1);
}

//*****************************************************************************
//debug auxility
function dbg(s,b){
  return false;
  if(!document.getElementById('debuger')){
    d  = document.createElement("div");
    d.id = 'debuger';
    d.style.position="absolute";
    document.body.appendChild(d);
  }
  document.getElementById('debuger').innerHTML += s + (b?"":"<br>");
}

function describe(t,v){
  var s = "";
  for(var p in t) s += "<br />["+p+"]"+(v?"="+t[p]:"");
  dbg(s);
}



///////////////////////////////////////////////////////////////////////////////////
var Class_Pretty = function(){
  this.init = _init;
  this.make = _make;
  //define a global array to story select tags and update in _proxy
  //this array is needs when a list needs to hide
  var selects = [];
  var ss = [];

  var $ = function(s){return typeof(s)=="object"?s:document.getElementById(s);};
  var iev = IEV();
  
  function IEV(){
    var i = window.navigator.userAgent.indexOf("MSIE");
    if (i!=-1){
      return(parseInt(window.navigator.userAgent.substring(i+4)));
    }else{
      return 0;
    }
  }
  function _make(tag){
    if(tag.tagName.toLowerCase()=="select"){
      //var found = false;
      //for(var i=0; i<ss.length; i++){
      //  if(ss[i]==tag){
      //    found=true;
      //    dbg("_make:"+tag.className+"|"+ss[i].className);
      //  }
      //}
      //if(found){
        //tag.update();
      //}else{
        _pretty_list(tag,ss.length)
      //  ss.push(tag);
      //}
    }else{
      throw "TODO:Pretty this tag:"+tag.tagName;
    }
  }
  function _pretty_list(s,i){
    //make it updatable
    s.update = _proxy(s,i);
    s.update();
    //new Selcer(ss[i],i,ss[i].className.replace("presel",""));
  }
  function _proxy(tag,index){
    return function(){
      var found = false;
      for(var i=0; i<selects.length; i++){
        if(selects[i]==tag) {
          found = true;
          break;
        }
      }
      if(!found) selects.push(tag);
      new Selcer(tag,index,tag.className.replace("presel",""));
    };
  }

  function _init(){
    //input initializer
    var is = document.getElementsByTagName("input");
    dbg("count input:" + is.length);
    for (var i=0; i<is.length; i++){
      if(is[i].className.indexOf("prebox")!=-1){
        new Prebox(is[i],i,is[i].className.replace("prebox",""));
      }
    }
  
    //select initializer
    ss = document.getElementsByTagName("select");
    dbg("count select:" + ss.length);
    bind(document,"onclick",function(){
      //TODO:clear list if nessaray
      //alert("document.onclick:"+selects.length);
      //todo:clear that doesn't exists
      var exists = [];
      for(var i=0; i<selects.length; i++){
        if(selects[i]){
          //alert("index:"+i+","+selects[i]);
          try{
            selects[i].hide();
            exists.push(selects[i]);
          }catch(ex){
            dbg("document.onclick try to remove node that was lost");
          }
        }
      }
      selects = exists;
    });
    for (var i=0; i<ss.length; i++){
      if(ss[i].className.indexOf("presel")!=-1){
        _pretty_list(ss[i],i);
      }
    }
  }

  ///////////////////////////////////////////////////////////////////////////////////
  var RC = new Array;
  var CheckFlip = function (ip,ico){
    ip.checked=!ip.checked;
    if(ip.onclick) ip.onclick();
    if(ip.type.toLowerCase()=="radio"){
      for(var i=0; i<RC[ip.name].length; i++)
        RC[ip.name][i].className = RC[ip.name][i].className.replace(" checked","");
    }
    ico.className = (ip.checked?ico.className+" checked":ico.className.replace(" checked",""));
  }

  function Prebox(ip,ix,ic){
    var cnt,txt,rel;
    if(ip.parentNode.tagName.toLowerCase()=="label"){
      cnt = ip.parentNode.parentNode;
      txt = ip.parentNode.innerText || ip.parentNode.textContent || "";
      rel = ip.parentNode;
    }else{
      cnt = ip.parentNode;
      txt = "";
      rel = ip;
    }
    rel.style.display = 'none';

    var out = document.createElement("span");
        out.className = "prebox_"+ip.type+" "+ic;
    var ico = document.createElement("span");
        ico.className = "ricon"+(ip.checked?" checked":"");
    var lb = document.createElement("span");
        lb.className = "label";
        lb.innerHTML = txt;
    if(ip.type.toLowerCase()=="radio"){
      if(!RC[ip.name]) RC[ip.name] = new Array();
      RC[ip.name].push(ico);
    }
    out.appendChild(ico);
    out.appendChild(lb);
    out.onclick = function(){CheckFlip(ip,ico);};
    cnt.insertBefore(out,rel);
  }

  ///////////////////////////////////////////////////////////////////////////////////
  //var cleaner = function (e,tle,inn){//任务1、焦点回归。2、摆动响应 3、焦点消去
  //  e = e||event;
  //  d = document.activeElement;
  //  dbg('d.tagName='+d.tagName);
  //  //dbg('e.relatedElement='+e.relatedElement);
  //  
  //  if(d.className=="pretle"){  //标题或滚动条焦点 摆动响应
  //    dbg('摆动响应 ' +inn.className);
  //    if(inn.className.indexOf("prebor_en")!=-1) toggle_dis(inn,"prebor");
  //  }else if(d.className=="seltm"){ //子项焦点　焦点回归
  //    dbg('焦点回归');
  //    tle.focus();
  //  }else{ //焦点消去, 隐藏列表
  //    dbg('焦点消去 '+inn.className);
  //    //延时修正MF的误动作(前期隐藏导致seltm无click事件)
  //    setTimeout(function(){if(inn.className.indexOf("prebor_en")!=-1) toggle_dis(inn,"prebor");},300);
  //  }
  //  return true;
  //};

  var toggle = function (s){
    var tag = $(s);
    if (tag.style.display=="block")
    { 
      tag.style.display="none";
    }else{
      tag.style.display="block";
    }
  };

  //function toggle_dis(s,a,b){
  //  var tag = $(s);
  //  dbg("toggle_dis:"+tag.className);
  //  if (tag.className.indexOf(b+"_en")==-1)
  //  {
  //   tag.parentNode.style.position = "relative";
  //   tag.className=b+"_en";
  //  }else{
  //    tag.parentNode.style.position = "static";
  //    tag.className=b;
  //  }
  //  return true;
  //}

  function _betweenClass(el,a,b){
    var rxa = new RegExp(a+" | "+a+"|^"+a+"$");
    var rxb = new RegExp(b+" | "+b+"|^"+b+"$");
    dbg("_betweenClass:"+el.className);
    if(rxa.test(el.className)){
      el.parentNode.style.position = "static";
      el.className = el.className.replace(a,b).replace("  ","");
    }else if(rxb.test(el.className)){
      el.parentNode.style.position = "relative";
      el.className = el.className.replace(b,a).replace("  ","");
    }else{
      el.className = el.className + " " + a;
    }
  }

  function Selcer(s,index,addclass){
    var _sel = s;
    var _this = this;
    var max_height = 800;
    var min_height = 64;

    //before initialize, destory the old one if exists, and let our s.update method work up
    if(s.board){
      s.parentNode.removeChild(s.board);
      s.board = null;
      s.list = null;
    }

    _init(s);
    function _init(sel){
      //注意，构造Selcer对象时，其内部的this 和_init内部的this指向的对象是不同的！
      //通过测试，_init内部的this指向window。由此可见new Selcer()只构造了Selcer，
      //并不构造其内部的_init。_init只是Selcer对象的私有方法，并且运行在window上下文中。
      if(sel.tagName.toLowerCase()!="select") throw "Pretty init error!";
      var opts = sel.getElementsByTagName("option");
      var tle = document.createElement("a");
          tle.href = 'javascript:void(0);';
          tle.className = 'prele';
      var inn = document.createElement("div");
          inn.className = 'prebor';
      var out = document.createElement("div");
          out.className = 'pretty '+addclass;
          //out.style.display = isIE? "inline-block":"inline-block";
          out.appendChild(tle);
          out.appendChild(inn);

      bind(out,"onclick",function(e){
        e = e||event;
        if(e.stopPropagation) e.stopPropagation();
        e.cancelBubble = true;
      });
      bind(inn,"onclick",function(e){
        e = e||event;
        var tag = e.target || e.srcElement;
        //just process list item click event
        var body = document.body;
        while(tag.parentNode != body){
          if(tag.className.indexOf("seltm")!=-1){
            break;
          }
          tag = tag.parentNode;
        }
        if(tag.className.indexOf("seltm")!=-1){
          dbg("inner list received onclick under seltm.");
          return Changed(tag,as[sel.selectedIndex]);
        }else{
          dbg("inner list received onclick from unknown.");
          return false;
        }
      });

      //story handle for a update process
      s.board = out;
      s.list = inn;
      s.hide = hide;
      s.show = show;
      s.pick = pick;
      s.next = next;
      s.previous = previous;
      /*fix scroll in IE
      inn.onscroll = function(e){
        dbg("inn.onscroll");
        this.setAttribute("scrolling",true);
        return true;
      };
      */
      //对于何时消隐列表的问题上，我一直不太愿意使用document.onclick, 我认为这是跨界的耦合，不是良好程序写作习惯。
      //其实这就违背了良好用户体验的宗旨，这里的用户包含开发人员，因为Pretty从一开始就是定位在降低开发人员的按劳动强度为目标的。
      //如果用pretty的子节点的焦点事件来控制，这会引起大量的问题甚至不可以达到预期效果。
      //这当然可以为每个子元素加载一个算定义的onblur和onfocus事件来实现，但成本亦是偏高的。
      //事实上，使用用document.onclick事件来检测隐藏列表的时机是最优化的，体验亦最好。
      //注意，使用document.onclick并不是完美的，如果一个元素禁止了事件的传播(event.cancelBubble=true, event.stopPropagation())，那么document将不会收到任何相关的消息。

      //tle.ondeactivate = deact;//MF不支持
      //onblur事件中目标为null,一个好的尝试是使用document.activeElement对象。
      //tle.onblur = function(e){
        //e = e||event;
        //describe(event);
        //对付IE's onscroll, inn.onscroll会有相应的配合,onblur先于onscroll,要应用延时检测．
        //但这样引入了focus的争夺中,要判断inn的状态是否是开启的．
        //dbg("tle.onblur");
        //setTimeout(function(e){
        //  if(inn.getAttribute("scrolling")){
        //    inn.setAttribute("scrolling",false);
        //  }else{
        //  cleaner(e,tle,inn);
        //  }
        //  if(inn.className.indexOf("_en")!=-1) tle.focus();
        //},50);
      //};
      //use focus to process key event
      tle.onfocus = function(e){
        e = e || event;
        bind(tle,"onkeypress",key,true,true);
      }

      //for downsideup
      var CLEAN_HEIGHT = 48;
      tle.onclick = flip;
      //function(event){
      //  dbg("tle.onclick");
      //  find a proper height and direction to popup
      //  flip();
      //};

      function Changed(a,oa,silence){
        //dbg("Changed:"+s.onclick);
        if(oa) oa.className = oa.className.replace("seltm-active","").replace("  "," ");
        a.className += " seltm-active";
        var g = a.parentNode
        if(g.className.indexOf("selgroup")!=-1&&g.className.indexOf("selgroup-active")==-1){
          g.className += " selgroup-active";
        }
        tle.innerHTML = a.innerHTML;
        hide();
        dbg(a.getAttribute('value')+" <> "+a.innerHTML);
        sel.selectedIndex = a.getAttribute('index');
        if(!silence&&s.onclick) return sel.onclick();
        return true;
      };

      function key(e){
        e = e || event;
        var code = e.keyCode || e.charCode;
        //describe(e,true);
        switch(code){
          case 9: //tab
          case 27: //esc
          case 32: //space
            loose(tle,"onkeypress",key,true);
            _betweenClass(inn,'prebor_en',"prebor");
            break;
          case 37: //left
          case 38: //up
            if(inn.className.indexOf("_en")!=-1){
              previous();
              show();
            }else{
              show();
            }
            break;
          case 39: //right
          case 40: //down
            if(inn.className.indexOf("_en")!=-1){
              next();
              show();
            }else{
              show();
            }
            break;
          default:
            dbg("key code:"+code+", index:"+sel.selectedIndex);
        }
        if(e.preventDefault) e.preventDefault();
        e.returnValue = false;
      }

      function pick(index){
        index = index%as.length;
        if(as[index]) Changed(as[index],as[sel.selectedIndex]);
      }
      function previous(){
        index = sel.selectedIndex==0? as.length-1:sel.selectedIndex-1;
        Changed(as[index],as[sel.selectedIndex]);
      }
      function next(){
        index = (+sel.selectedIndex+1)%as.length;
        Changed(as[index],as[sel.selectedIndex]);
      }

      function hide(){
        if(inn.className.indexOf("_en")!=-1) flip();
      };
      function show(){
        if(inn.className.indexOf("_en")==-1) flip();
      };
      function flip(){
        if(inn.className.indexOf("_en")==-1){
          var r = tle.getBoundingClientRect();
          var th = r.bottom-r.top;

          var old_display = inn.style.display;
          inn.style.height = "auto";
          inn.style.display = "block";
          var rb = inn.getBoundingClientRect();
          inn.style.display = old_display;
          var bh = rb.bottom-rb.top;

          var ch = document.documentElement.clientHeight;
          //var sh = document.documentElement.scrollHeight
          //var tt = r.top+document.documentElement.scrollTop;

          bh = (bh>max_height) ?max_height:bh;//max-height:240px;_height:240px;_overflow-y:auto;
          var room = ch-r.bottom>r.top? ch-r.bottom:r.top;
          room = room<min_height? min_height:room;
          bh = bh>room? room:bh;
          inn.style.height = bh+"px";

          //if(sh-tt-th-CLEAN_HEIGHT<bh&&tt>=bh){
          if(bh+r.bottom>ch&&r.bottom>ch/2){
            inn.style.bottom = (th+1)+"px";
            inn.style.top = "auto";
          }else{
            inn.style.top = (th+1)+"px";
            inn.style.bottom = "auto";
          }
        }
        _betweenClass(inn,'prebor_en','prebor');
        //tle.focus();
        inn.style.width = (out.offsetWidth-2)+"px";
      }


      //make anchor list according to options
      //today I will make it implemetated to the option group
      //dbg("option group:"+sel.groups);
      var as = new Array();
      var gps = new Array();
      for (var i=0; i<opts.length; i++){
        var opt = opts[i];
        var pn = opt.parentNode;
        var item = document.createElement("a");
        as[i] = item;
        item.setAttribute('value',opt.value);
        item.setAttribute('index',opt.index);

        if(opt.value == "" && i==0){
          tle.innerHTML = opts[0].innerHTML;
          item.innerHTML = opts[0].innerHTML;
          continue;
        }
        //put option in it's group if it is
        if(pn != sel){
          //dbg("treat it's parentnode as optgroup:"+pn.label);
          var found = false;
          for(var j=0; j<gps.length; j++){
            if(gps[j].optgroup == pn){
              //dbg("  FOUND:"+pn.label+", "+gps[j].optgroup.label);
              found = true;
              break;
            }else{
              //dbg("  NOT FOUND:"+pn.label+", "+gps[j].optgroup.label);
            }
          }
          if(!found){
            var gd = document.createElement("div");
            var gt = document.createElement("a");
            gt.className = "seltm grouptm";
            gt.href = 'javascript:void(0);';
            gt.innerHTML = pn.label;

            //I will make closure to manager gd
            gt.onclick = (function(gd){
              return function(e){
                e = e || event;
                var tag = e.target || e.srcElement;
                if(gd.className.indexOf(" selgroup-active")!=-1){
                  gd.className = gd.className.replace(" selgroup-active","");
                }else{
                  gd.className += " selgroup-active";
                }
                dbg("this is this:"+(tag==this)+", "+gd.className);
                if(tag==this){
                  if(e.stopPropagation) e.stopPropagation();
                  e.cancelBubble = true;
                };
              };
            })(gd);

            gd.className = "selgroup selgroup-active";
            gd.setAttribute("group",gps.length);
            gps[gps.length] = {optgroup:pn,wrap:gd,opts:new Array()};
            inn.appendChild(gt);
            inn.appendChild(gd);
            //dbg("add new group:"+pn.label);
          }
          gps[gps.length-1].opts.push(opt);
          gps[gps.length-1].wrap.appendChild(item);
        }else{
          inn.appendChild(item);
        }
        //item.onclick = function(event){
        //  dbg("list item.onclick");
        //  return Changed(tle,this,as[sel.selectedIndex],sel,inn);
        //};
        var href = opt.getAttribute("href");
        var src = opt.getAttribute("src");
        var target = opt.getAttribute("target");
        if(href){
          item.href = href;
          item.target = target;
          //item.onclick = function(){return false;};
        }else{
          item.href = 'javascript:void(0);';
          //item.onclick = function(event){return Changed(tle,this,as[sel.selectedIndex],sel,inn);};
        }
        item.className = 'seltm';
        item.innerHTML = opt.innerHTML;
        if(src){
          item.innerHTML = "<img class='nobor mid' src='"+src+"' alt='' />"+item.innerHTML;
        }
        if(opt.selected){
          //tle.innerHTML = opt.innerHTML;
          Changed(item,null,true);
        }
      }

      sel.parentNode.insertBefore(out,sel); //添加结构到DOM生效
      //注意IE中inline、relative的子节点的left=0px指的是中间位置。
      //inn.style.left = (ox)+"px";

      inn.style.left = "0px";
      //为避免初始状态下元素的父节点不可见时其尺度不可用，将宽度设置转移到click事件中。
      //inn.style.width = (out.offsetWidth-2)+"px"; //在xhtml1-transitional.dtd环境下补偿边框以居中
      sel.style.display = "none";
      //out.setAttribute('style',addstyle); //IE不可以getAttribute或setAttribute到HTML标记
    }

  }
}

//注意prototype继承成员不能访问闭包。如_this。
//Selcer.prototype.Changed = function (a,s){      };

