百度Map切换城市

上个月研究了百度map,一直没时间更新博客,呵呵,今天闲了....

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Sict//EN"
    "http://www.w3.org//xhtml1/DTD/xhtml1-sict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>select city</title>

</head>
<body>
<div style="width:1200px;height:500px;border:1px solid #000;margin-top:50px;" id="container"></div>
<div class="sel_container"><strong id="curCity">西安</strong> [<a id="curCityText" href="javascript:void(0)">更换城市</a>]</div>
<div class="map_popup" id="cityList">
    <div class="popup_main">
        <div class="title">城市列表</div>
        <div class="cityList">
            <h4>测试地址:</h4>
            <a href="javascript:void(0)">北京</a><a href="javascript:void(0)">上海</a><a href="javascript:void(0)">天津</a><a href="javascript:void(0)">重庆</a>
            <a href="javascript:void(0)">西安</a>
            <hr/>
            <div class=""><form id="searchForm"><input id="cityNameSearch" type="text" value="输入城市名"/><input type="submit" class="cityNameSubmit" value="确定"/> 
            <span class="errorTip" id="citySearchTip">请输入正确的城市名</span>
            </form></div>    
            <div>
            <dl>
                <dt><a href="javascript:void(0)" class="black">全国</a></dt>
                <dd><span class="cityListDescript"> (含34个省、自治区、直辖市、特别行政区、340个地级市)</span></dd>
                <dt>直辖市:</dt>
                    <dd>
                        <a href="javascript:void(0)">北京</a><a href="javascript:void(0)">上海</a><a href="javascript:void(0)">天津</a><a href="javascript:void(0)">重庆</a>
                    </dd>
                <dt><a href="javascript:void(0)" class="black">安徽</a>:</dt>
                     <dd>
                        <a href="javascript:void(0)">合肥</a><a href="javascript:void(0)">安庆</a><a href="javascript:void(0)">蚌埠</a><a href="javascript:void(0)">亳州</a><a href="javascript:void(0)">巢湖</a><a href="javascript:void(0)">池州</a><a href="javascript:void(0)">滁州</a><a href="javascript:void(0)">阜阳</a><a href="javascript:void(0)">淮北</a><a href="javascript:void(0)">淮南</a><a href="javascript:void(0)">黄山</a><a href="javascript:void(0)">六安</a><a href="javascript:void(0)">马鞍山</a><a href="javascript:void(0)">宿州</a><a href="javascript:void(0)">铜陵</a><a href="javascript:void(0)">芜湖</a><a href="javascript:void(0)">宣城</a>
                    </dd>
                <dt><a href="javascript:void(0)" code="5785" class="black">福建</a>:</dt>
                    <dd>                
                        <a href="javascript:void(0)">福州</a><a href="javascript:void(0)">龙岩</a><a href="javascript:void(0)">南平</a><a href="javascript:void(0)">宁德</a><a href="javascript:void(0)">莆田</a><a href="javascript:void(0)">泉州</a><a href="javascript:void(0)">三明</a><a href="javascript:void(0)">厦门</a><a href="javascript:void(0)">漳州</a>
                    </dd>
                <dt><a href="javascript:void(0)" code="5775" class="black"> 甘肃</a>:</dt>
                    <dd>
                        <a href="javascript:void(0)">兰州</a><a href="javascript:void(0)">白银</a><a href="javascript:void(0)">定西</a><a href="javascript:void(0)" name="甘南藏族自治州">甘南州</a><a href="javascript:void(0)">嘉峪关</a><a href="javascript:void(0)">金昌</a><a href="javascript:void(0)">酒泉</a><a href="javascript:void(0)" name="临夏回族自治州">临夏州</a><a href="javascript:void(0)">陇南</a><a href="javascript:void(0)">平凉</a>
                        <a href="javascript:void(0)">庆阳</a><a href="javascript:void(0)">天水</a><a href="javascript:void(0)">武威</a><a href="javascript:void(0)">张掖</a>
                    </dd>
                <dt><a href="javascript:void(0)" code="5776" class="black"> 广东</a>:</dt>
                    <dd>
                        <a href="javascript:void(0)">广州</a><a href="javascript:void(0)">潮州</a><a href="javascript:void(0)">东莞</a><a href="javascript:void(0)">佛山</a><a href="javascript:void(0)">河源</a><a href="javascript:void(0)">惠州</a><a href="javascript:void(0)">江门</a><a href="javascript:void(0)">揭阳</a><a href="javascript:void(0)">茂名</a><a href="javascript:void(0)">梅州</a><a href="javascript:void(0)">清远</a><a href="javascript:void(0)">汕头</a><a href="javascript:void(0)">汕尾</a><a href="javascript:void(0)">韶关</a><a href="javascript:void(0)">深圳</a><a href="javascript:void(0)">阳江</a><a href="javascript:void(0)">云浮</a><a href="javascript:void(0)">湛江</a><a href="javascript:void(0)">肇庆</a><a href="javascript:void(0)">中山</a><a href="javascript:void(0)">珠海</a>
                    </dd>
                <dt><a href="javascript:void(0)" code="5786" class="black">广西</a>:</dt>
                    <dd>
                        <a href="javascript:void(0)">南宁</a><a href="javascript:void(0)">百色</a><a href="javascript:void(0)">北海</a><a href="javascript:void(0)">崇左</a><a href="javascript:void(0)">防城港</a><a href="javascript:void(0)">桂林</a><a href="javascript:void(0)">贵港</a><a href="javascript:void(0)">河池</a><a href="javascript:void(0)">贺州</a><a href="javascript:void(0)">来宾</a><a href="javascript:void(0)">柳州</a><a href="javascript:void(0)">钦州</a><a href="javascript:void(0)">梧州</a><a href="javascript:void(0)">玉林</a>	
                    </dd>
                <dt><a href="javascript:void(0)" code="5793" class="black">贵州</a>:</dt>
                    <dd>
                        <a href="javascript:void(0)">贵阳</a><a href="javascript:void(0)">安顺</a><a href="javascript:void(0)">毕节地区</a><a href="javascript:void(0)">六盘水</a><a href="javascript:void(0)">铜仁地区</a><a href="javascript:void(0)">遵义</a><a href="javascript:void(0)" name="黔西南布依族苗族自治州">黔西南州</a><a href="javascript:void(0)" name="黔东南苗族侗族自治州">黔东南州</a><a href="javascript:void(0)" name="黔南布依族苗族自治州">黔南州</a>
                    </dd>
                <dt><a href="javascript:void(0)" code="5790" class="black">海南</a>:</dt>
                    <dd>
                        <a href="javascript:void(0)">海口</a><a href="javascript:void(0)" name="白沙黎族自治县">白沙</a><a href="javascript:void(0)" name="保亭黎族苗族自治县">保亭</a><a href="javascript:void(0)" name="昌江黎族自治县">昌江</a><a href="javascript:void(0)">儋州</a><a href="javascript:void(0)">澄迈</a><a href="javascript:void(0)">东方</a><a href="javascript:void(0)">定安</a><a href="javascript:void(0)">琼海</a><a href="javascript:void(0)" name="琼中黎族苗族自治县">琼中</a><a href="javascript:void(0)" name="乐东黎族自治县">乐东</a><a href="javascript:void(0)">临高</a><a href="javascript:void(0)" name="陵水黎族自治县">陵水</a><a href="javascript:void(0)">三亚</a><a href="javascript:void(0)">屯昌</a><a href="javascript:void(0)">万宁</a><a href="javascript:void(0)">文昌</a><a href="javascript:void(0)">五指山</a>
                    </dd>
                
                <dt><a href="javascript:void(0)" code="5794" class="black">河北</a>:</dt>
                <dd>
                    <a href="javascript:void(0)">石家庄</a><a href="javascript:void(0)">保定</a><a href="javascript:void(0)">沧州</a><a href="javascript:void(0)">承德</a><a href="javascript:void(0)">邯郸</a><a href="javascript:void(0)">衡水</a><a href="javascript:void(0)">廊坊</a><a href="javascript:void(0)">秦皇岛</a><a href="javascript:void(0)">唐山</a><a href="javascript:void(0)">邢台</a><a href="javascript:void(0)">张家口</a>
                </dd>
            
            
                <dt><a href="javascript:void(0)" code="5799" class="black">河南</a>:</dt>
                <dd>
                    <a href="javascript:void(0)">郑州</a><a href="javascript:void(0)">安阳</a><a href="javascript:void(0)">鹤壁</a><a href="javascript:void(0)">焦作</a><a href="javascript:void(0)">开封</a><a href="javascript:void(0)">洛阳</a><a href="javascript:void(0)">漯河</a><a href="javascript:void(0)">南阳</a><a href="javascript:void(0)">平顶山</a><a href="javascript:void(0)">濮阳</a><a href="javascript:void(0)">三门峡</a><a href="javascript:void(0)">商丘</a><a href="javascript:void(0)">新乡</a><a href="javascript:void(0)">信阳</a><a href="javascript:void(0)">许昌</a><a href="javascript:void(0)">周口</a>
                    <a href="javascript:void(0)">驻马店</a>
                </dd>
            
            
                <dt><a href="javascript:void(0)" code="5771" class="black">黑龙江</a>:</dt>
                <dd>
                    <a href="javascript:void(0)">哈尔滨</a><a href="javascript:void(0)">大庆</a><a href="javascript:void(0)">大兴安岭地区</a><a href="javascript:void(0)">鹤岗</a><a href="javascript:void(0)">黑河</a><a href="javascript:void(0)">鸡西</a><a href="javascript:void(0)">佳木斯</a><a href="javascript:void(0)">牡丹江</a><a href="javascript:void(0)">七台河</a><a href="javascript:void(0)">齐齐哈尔</a><a href="javascript:void(0)">双鸭山</a><a href="javascript:void(0)">绥化</a><a href="javascript:void(0)">伊春</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5784" class="black">湖北</a>:</dt>
                <dd>
                    <a href="javascript:void(0)">武汉</a><a href="javascript:void(0)">鄂州</a><a href="javascript:void(0)" name="恩施土家族苗族自治州">恩施</a><a href="javascript:void(0)">黄冈</a><a href="javascript:void(0)">黄石</a><a href="javascript:void(0)">荆门</a><a href="javascript:void(0)">荆州</a><a href="javascript:void(0)">潜江</a><a href="javascript:void(0)">神农架林区</a><a href="javascript:void(0)">十堰</a><a href="javascript:void(0)">随州</a><a href="javascript:void(0)">天门</a><a href="javascript:void(0)">仙桃</a><a href="javascript:void(0)">咸宁</a><a href="javascript:void(0)">襄樊</a><a href="javascript:void(0)">孝感</a><a href="javascript:void(0)">宜昌</a>
                </dd>
            
            
                <dt><a href="javascript:void(0)" code="5795" class="black">湖南</a>:</dt>
                <dd>
                    <a href="javascript:void(0)">长沙</a><a href="javascript:void(0)">常德</a><a href="javascript:void(0)">郴州</a><a href="javascript:void(0)">衡阳</a><a href="javascript:void(0)">怀化</a><a href="javascript:void(0)">娄底</a><a href="javascript:void(0)">邵阳</a><a href="javascript:void(0)">湘潭</a><a href="javascript:void(0)" name="湘西土家族苗族自治州">湘西州</a><a href="javascript:void(0)">益阳</a><a href="javascript:void(0)">永州</a><a href="javascript:void(0)">岳阳</a><a href="javascript:void(0)">张家界</a><a href="javascript:void(0)">株洲</a>	
            </dd>
            
            
                <dt><a href="javascript:void(0)" code="5787" class="black">江苏</a>:</dt>
                <dd>
                    <a href="javascript:void(0)">南京</a><a href="javascript:void(0)">常州</a><a href="javascript:void(0)">淮安</a><a href="javascript:void(0)">连云港</a><a href="javascript:void(0)">南通</a><a href="javascript:void(0)">苏州</a><a href="javascript:void(0)">宿迁</a><a href="javascript:void(0)">泰州</a><a href="javascript:void(0)">无锡</a><a href="javascript:void(0)">徐州</a><a href="javascript:void(0)">盐城</a><a href="javascript:void(0)">扬州</a><a href="javascript:void(0)">镇江</a>
                </dd>
            
            
                <dt><a href="javascript:void(0)" code="5800" class="black">江西</a>:</dt>
                <dd><a href="javascript:void(0)">南昌</a><a href="javascript:void(0)">抚州</a><a href="javascript:void(0)">赣州</a><a href="javascript:void(0)">吉安</a><a href="javascript:void(0)">景德镇</a><a href="javascript:void(0)">九江</a><a href="javascript:void(0)">萍乡</a><a href="javascript:void(0)">上饶</a><a href="javascript:void(0)">新余</a><a href="javascript:void(0)">宜春</a><a href="javascript:void(0)">鹰潭</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5778"  name="吉林省" class="black">吉林</a>:</dt>
                <dd>
                <a href="javascript:void(0)">长春</a><a href="javascript:void(0)">白城</a><a href="javascript:void(0)">白山</a><a href="javascript:void(0)">吉林市</a><a href="javascript:void(0)"></a><a href="javascript:void(0)">辽源</a><a href="javascript:void(0)">四平</a><a href="javascript:void(0)">松原</a><a href="javascript:void(0)">通化</a><a href="javascript:void(0)" name="延边朝鲜族自治州">延边</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5788" class="black">辽宁</a>:</dt>
                <dd>
                    <a href="javascript:void(0)">沈阳</a><a href="javascript:void(0)">鞍山</a><a href="javascript:void(0)">本溪</a><a href="javascript:void(0)">朝阳</a><a href="javascript:void(0)">大连</a><a href="javascript:void(0)">丹东</a><a href="javascript:void(0)">抚顺</a><a href="javascript:void(0)">阜新</a><a href="javascript:void(0)">葫芦岛</a><a href="javascript:void(0)">锦州</a><a href="javascript:void(0)">辽阳</a><a href="javascript:void(0)">盘锦</a><a href="javascript:void(0)">铁岭</a><a href="javascript:void(0)">营口</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5791" class="black">内蒙古</a>:</dt>
                <dd>
                <a href="javascript:void(0)">呼和浩特</a><a href="javascript:void(0)">阿拉善盟</a><a href="javascript:void(0)">包头</a><a href="javascript:void(0)">巴彦淖尔</a><a href="javascript:void(0)">赤峰</a><a href="javascript:void(0)">鄂尔多斯</a><a href="javascript:void(0)">呼伦贝尔</a><a href="javascript:void(0)">通辽</a><a href="javascript:void(0)">乌海</a><a href="javascript:void(0)">乌兰察布</a><a href="javascript:void(0)">锡林郭勒盟</a><a href="javascript:void(0)">兴安盟</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5789" class="black">宁夏</a>:</dt>
                <dd><a href="javascript:void(0)">银川</a><a href="javascript:void(0)">固原</a><a href="javascript:void(0)">石嘴山</a><a href="javascript:void(0)">吴忠</a><a href="javascript:void(0)">中卫</a></dd>

                <dt><a href="javascript:void(0)" code="5780" class="black">青海</a>:</dt>
                <dd><a href="javascript:void(0)">西宁</a><a href="javascript:void(0)" name="果洛藏族自治州">果洛州</a><a href="javascript:void(0)">海东地区</a><a href="javascript:void(0)" name="海北藏族自治州">海北州</a><a href="javascript:void(0)" name="海南藏族自治州">海南州</a><a href="javascript:void(0)" name="海西蒙古族藏族自治州">海西州</a><a href="javascript:void(0)" name="黄南藏族自治州">黄南州</a><a href="javascript:void(0)" name="玉树藏族自治州">玉树州</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5777" class="black">山东</a>:</dt>
                <dd><a href="javascript:void(0)">济南</a><a href="javascript:void(0)">滨州</a><a href="javascript:void(0)">东营</a><a href="javascript:void(0)">德州</a><a href="javascript:void(0)">菏泽</a><a href="javascript:void(0)">济宁</a><a href="javascript:void(0)">莱芜</a><a href="javascript:void(0)">聊城</a><a href="javascript:void(0)">临沂</a><a href="javascript:void(0)">青岛</a><a href="javascript:void(0)">日照</a><a href="javascript:void(0)">泰安</a><a href="javascript:void(0)">威海</a><a href="javascript:void(0)">潍坊</a><a href="javascript:void(0)">烟台</a><a href="javascript:void(0)">枣庄</a><a href="javascript:void(0)">淄博</a><a href="javascript:void(0)"></a>
                </dd>
                <dt><a href="javascript:void(0)" code="5779" class="black">山西</a>:</dt>
                <dd><a href="javascript:void(0)">太原</a><a href="javascript:void(0)">长治</a><a href="javascript:void(0)">大同</a><a href="javascript:void(0)">晋城</a><a href="javascript:void(0)">晋中</a><a href="javascript:void(0)">临汾</a><a href="javascript:void(0)">吕梁</a><a href="javascript:void(0)">朔州</a><a href="javascript:void(0)">忻州</a><a href="javascript:void(0)">阳泉</a><a href="javascript:void(0)">运城</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5796" class="black">陕西</a>:</dt>
                <dd><a href="javascript:void(0)">西安</a><a href="javascript:void(0)">安康</a><a href="javascript:void(0)">宝鸡</a><a href="javascript:void(0)">汉中</a><a href="javascript:void(0)">商洛</a><a href="javascript:void(0)">铜川</a><a href="javascript:void(0)">渭南</a><a href="javascript:void(0)">咸阳</a><a href="javascript:void(0)">延安</a><a href="javascript:void(0)">榆林</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5801" class="black">四川</a>:</dt>
                <dd>
                <a href="javascript:void(0)">成都</a><a href="javascript:void(0)" name="阿坝藏族羌族自治州">阿坝州</a><a href="javascript:void(0)">巴中</a><a href="javascript:void(0)">达州</a><a href="javascript:void(0)">德阳</a><a href="javascript:void(0)" name="甘孜藏族自治州">甘孜州</a><a href="javascript:void(0)">广安</a><a href="javascript:void(0)">广元</a><a href="javascript:void(0)">乐山</a><a href="javascript:void(0)" name="凉山彝族自治州">凉山州</a><a href="javascript:void(0)">泸州</a><a href="javascript:void(0)">南充</a><a href="javascript:void(0)">眉山</a><a href="javascript:void(0)">绵阳</a><a href="javascript:void(0)">内江</a><a href="javascript:void(0)">攀枝花</a><a href="javascript:void(0)">遂宁</a><a href="javascript:void(0)">雅安</a><a href="javascript:void(0)">宜宾</a><a href="javascript:void(0)">资阳</a><a href="javascript:void(0)">自贡</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5782" class="black">西藏</a>:</dt>
                <dd><a href="javascript:void(0)">拉萨</a><a href="javascript:void(0)">阿里地区</a><a href="javascript:void(0)">昌都地区</a><a href="javascript:void(0)">林芝地区</a><a href="javascript:void(0)">那曲地区</a><a href="javascript:void(0)">日喀则地区</a><a href="javascript:void(0)">山南地区</a>
            </dd>
                <dt><a href="javascript:void(0)" code="5781" class="black">新疆</a>:</dt>
                <dd>
                    <a href="javascript:void(0)">乌鲁木齐</a><a href="javascript:void(0)">阿拉尔</a><a href="javascript:void(0)">阿克苏地区</a><a href="javascript:void(0)">阿勒泰地区</a><a href="javascript:void(0)" name="巴音郭楞蒙古自治州">巴音郭楞</a><a href="javascript:void(0)" name="博尔塔拉蒙古自治州">博尔塔拉州</a><a href="javascript:void(0)" name="昌吉回族自治州">昌吉州</a><a href="javascript:void(0)">哈密地区</a><a href="javascript:void(0)">和田地区</a><a href="javascript:void(0)">喀什地区</a><a href="javascript:void(0)">克拉玛依</a><a href="javascript:void(0)" name="克孜勒苏柯尔克孜自治州">克孜勒苏州</a><a href="javascript:void(0)">石河子</a><a href="javascript:void(0)">塔城地区</a><a href="javascript:void(0)">图木舒克</a><a href="javascript:void(0)">吐鲁番地区</a><a href="javascript:void(0)">五家渠</a><a href="javascript:void(0)" name="伊犁哈萨克自治州">伊犁州</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5797" class="black">云南</a>:</dt>
                <dd>
                <a href="javascript:void(0)">昆明</a><a href="javascript:void(0)">保山</a><a href="javascript:void(0)" name="楚雄彝族自治州">楚雄州</a><a href="javascript:void(0)" name="大理白族自治州">大理州</a><a href="javascript:void(0)" name="德宏傣族景颇族自治州">德宏州</a><a href="javascript:void(0)" name="迪庆藏族自治州">迪庆州</a><a href="javascript:void(0)" name="红河哈尼族彝族自治州">红河州</a><a href="javascript:void(0)">丽江</a><a href="javascript:void(0)">临沧</a><a href="javascript:void(0)" name="怒江傈僳族自治州">怒江州</a><a href="javascript:void(0)">普洱</a><a href="javascript:void(0)">曲靖</a><a href="javascript:void(0)">昭通</a><a href="javascript:void(0)" name="文山壮族苗族自治州">文山</a><a href="javascript:void(0)" name="西双版纳傣族自治州">西双版纳</a><a href="javascript:void(0)">玉溪</a>
                </dd>
                <dt><a href="javascript:void(0)" code="5798" class="black">浙江</a>:</dt>
                <dd><a href="javascript:void(0)">杭州</a><a href="javascript:void(0)">湖州</a><a href="javascript:void(0)">嘉兴</a><a href="javascript:void(0)">金华</a><a href="javascript:void(0)">丽水</a><a href="javascript:void(0)">宁波</a><a href="javascript:void(0)">衢州</a><a href="javascript:void(0)">绍兴</a><a href="javascript:void(0)">台州</a><a href="javascript:void(0)">温州</a><a href="javascript:void(0)">舟山</a>
                </dd>
            </dl>
            </div>
        </div>
        <button id="popup_close"></button>
    </div>
</div>
<style>
    .cityList{height: 320px;overflow-y: auto;width:372px;color:#333;font:12px arial,sans-serif;padding-left:10px;}   
    .cityList h4{font-size:12px;font-weight:normal;margin:0;}    
    .cityList hr{height:1px;border-top:solid 1px #ccc; border-bottom:none;}
    .cityList form,.cityList dl{margin:0;}
    .cityList dd,.cityList h4,.cityList dt{padding: 2px 0; vertical-align: top;line-height: 150%;}
    .cityList dt{float:left;width:52px;}
    .cityList dd{margin-left:52px;}
    .cityList a{color:#0000CC;text-decoration:underline;outline:none;margin-right: 8px;}
    .cityList dt a{margin-right:0;}
    .cityListDescript{color:#999;}
    .cityList .black{color:#000;}
    .cityList form span{color:red;}
    .errorTip{display:none;}
    .cityNameSubmit{cursor:pointer;}
    .sel_container{position:absolute;top:0;font-size:12px;}
    .map_popup {position: absolute;z-index: 200000;width: 382px;height: 344px;top:20px; display:none;}
    .map_popup .popup_main { background:#fff;border: 1px solid #8BA4D8;height: 100%;overflow: hidden;position: absolute;width: 100%;z-index: 2;}
    .map_popup .title {background: url("http://map.baidu.com/img/popup_title.gif") repeat scroll 0 0 transparent;
    color: #6688CC;font-size: 12px;font-weight: bold;height: 24px;line-height: 25px;padding-left: 7px;}
    .map_popup button {background: url("http://map.baidu.com/img/popup_close.gif") no-repeat scroll 0 0 transparent;
    border: 0 none;cursor: pointer;height: 12px;position: absolute;right: 4px;top: 6px;width: 12px;}
    .tangram-suggestion-main{border: 1px solid #817F82;position: absolute;z-index: 200001;background: #fff;}
    .tangram-suggestion table{cursor: default;width: 100%}
    .tangram-suggestion td{font: 14px verdana;}
    .tangram-suggestion-current{background-color: #66CC66;color: #fff;}
    .tangram-suggestion-append{padding: 2px;color: #c0c0c0;font: 12px verdana;text-align: right;}
    .tangram-suggestion-prepend{padding: 2px;color: #c0c0c0;font: 12px verdana;}
</style>

<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.1&services=true"></script>
<script type="text/javascript" src="http://img.baidu.com/js/tangram-1.3.4.js"></script>
<!--<script type="text/javascript" src="http://tangram.baidu.com/tangram-all.js"></script>-->
<script type="text/javascript" src="suggestion.js"></script>
<script type="text/javascript" >
var map = new BMap.Map("container");
map.centerAndZoom(new BMap.Point(108.91907,34.239102), 12);


var mapext = mapext || {};

var suggestionData,cname;
mapext.cityList = function(options){    
     var opts = baidu.object.extend({
        wrapID: "cityList",
        changeCityID: "curCityText",
        curCityID: "curCity",
        map: map,
        moveMap:function(){         
            var city = arguments[0];
            var local = new BMap.LocalSearch(city,{
                    renderOptions: {map:null  , autoViewport: true },
                    onSearchComplete:function(result){
                       
                        if(result.getNumPois() > 0){
                            opts.map.panTo(result.getPoi(0).point);
                        }
                        closeList();                        
                    }
                });
            local.search(city);
        }},
        options);  
     var oCityName = baidu.g(opts.curCityID),oSearch = baidu.g("cityNameSearch"),oTips = baidu.g("citySearchTip"),oSearchForm = baidu.g("searchForm");                  
     
     (function init() {
         search();   
         bindEvent(opts);
     })();

     function bindEvent(opts){
        baidu.event.on(opts.wrapID,"click",function(e){
            var elem = e.target || e.srcElement;
            if(elem.tagName.toLowerCase() == "a"){    
                cityNameSearch(elem.innerHTML,function(){
                    oCityName.innerHTML = cname;
                    opts.moveMap(elem.innerHTML);
                });               
            }
        });
        baidu.event.on("popup_close","click",function(){
           closeList();
        });
        baidu.event.on(opts.changeCityID,"click",function(e){
           openList();
        });
     }
     function search(){
        suggestion(); 
        baidu.event.on(oSearchForm,"submit",function(e){
            if(oSearch.value == '' || oSearch.value == '输入城市名'){
                    showErrTip();
                    oSearch.focus();
            }else{ 
                    cityNameSearch(oSearch.value,function(){
                        if(cname){
                            hideErrTip();
                            oCityName.innerHTML = cname;
                            opts.moveMap(oSearch.value);
                       }
                       else{
                            showErrTip();
                       }
                    });
            }
            baidu.event.stop(e);
        });
        baidu.event.on(oSearch,"focus",function(){
            if(this.value == "输入城市名"){
                this.value = '';
                this.style.color = '#000'
            }
        });
        baidu.event.on(oSearch,"onkeydown",function(e){
            if(e.keyCode == 13){
                baidu.event.fire(oSearchForm,"submit");    
            }
        });
        baidu.event.on(oSearch,"blur",function(){
            hideErrTip();

        })

     }
     function  showErrTip(){
        baidu.removeClass(oTips,"errorTip");
     }
     function hideErrTip(){
        baidu.addClass(oTips,"errorTip");
     }
     function cityNameSearch(city,callback){
        baidu.sio.callByBrowser("http://map.baidu.com/?ie=utf-8&qt=cur&wd="+ encodeURIComponent(city) +"&t="+(new Date()).getTime()+"&callback=getCityName",function(){
                       callback();
                    });
     }
     function suggestion(){
        var options = {  
            getData: function(word){    
                var that = this;
                baidu.sio.callByBrowser("http://map.baidu.com/su?wd="+encodeURIComponent(oSearch.value)+"&cid=131&type=1&ie=utf-8&t="+(new Date()).getTime()+"&callback=getCityData",function(){
                       //suggestionData.unshift(word);
                       that.setData(word, suggestionData);
                    }
                )}
        }
        var suggestion = new baidu.ui.Suggestion(options)
	    suggestion.render(oSearch, options);
     }   
     /**
      * get or set city name
      * @param {type} name :
      * @returns {none} 
      * @author looping
      */ 
     function cityName(){
        if(arguments.length == 0){//get city name
            return oCityName.innerHTML;
        }else{// set city name
            oCityName.innerHTML = arguments[0];
        }
     }
     function openList(){
        baidu.setStyle(opts.wrapID,"display","block");
     }
     function closeList(){
        baidu.setStyle(opts.wrapID,"display","none");
     }
     this.open = function(){
        openList();
     }
     this.close = function(){
        closeList();
     }
}
function getCityData(data){  
    var t = data.s;
    suggestionData = t.length ? baidu.array.map(t,function(item,i){ return item.replace(/^\$*|\$*$/g,""); }) : t ;
}
function getCityName(data){
    var t = data.content;
    if(t["error"] == 0){ 
            cname = ""; 
        }else{
            cname = t.cname;
        }
}
baidu.object.map = function (source, iterator) {
    var results = {};
    for (var key in source) {
        if (source.hasOwnProperty(key)) {
            results[key] = iterator(source[key], key);
        }
    }
    return results;
};


var list = new mapext.cityList();

//list.open();

</script>

</body>
</html>

引用js

// Copyright (c) 2009, Baidu Inc. All rights reserved.
// 
// Licensed under the BSD License
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
//      http:// tangram.baidu.com/license.html
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
 * 为Suggestion提供输入框监控功能
 * @author berg
 */

/**
 * 声明baidu包
 * @author: allstar, erik, meizz, berg
 */
var T,
    baidu = T = baidu || {version: "1.3.5"}; 

//提出guid,防止在与老版本Tangram混用时
//在下一行错误的修改window[undefined]
baidu.guid = "$BAIDU{1}quot;;

//Tangram可能被放在闭包中
//一些页面级别唯一的属性,需要挂载在window[baidu.guid]上
window[baidu.guid] = window[baidu.guid] || {};
/**
 * @namespace baidu.dom 操作dom的方法。
 */
baidu.dom = baidu.dom || {};


/**
 * 从文档中获取指定的DOM元素
 * @name baidu.dom.g
 * @function
 * @grammar baidu.dom.g(id)
 * @param {string|HTMLElement} id 元素的id或DOM元素
 * @shortcut g,G
 * @meta standard
 * @see baidu.dom.q
 *             
 * @returns {HTMLElement|null} 获取的元素,查找不到时返回null,如果参数不合法,直接返回参数
 */
baidu.dom.g = function (id) {
    if ('string' == typeof id || id instanceof String) {
        return document.getElementById(id);
    } else if (id && id.nodeName && (id.nodeType == 1 || id.nodeType == 9)) {
        return id;
    }
    return null;
};

// 声明快捷方法
baidu.g = baidu.G = baidu.dom.g;



/**
 * 获取目标元素所属的document对象
 * @name baidu.dom.getDocument
 * @function
 * @grammar baidu.dom.getDocument(element)
 * @param {HTMLElement|string} element 目标元素或目标元素的id
 * @meta standard
 * @see baidu.dom.getWindow
 *             
 * @returns {HTMLDocument} 目标元素所属的document对象
 */
baidu.dom.getDocument = function (element) {
    element = baidu.dom.g(element);
    return element.nodeType == 9 ? element : element.ownerDocument || element.document;
};





/**
 * @namespace baidu.lang 对语言层面的封装,包括类型判断、模块扩展、继承基类以及对象自定义事件的支持。
*/
baidu.lang = baidu.lang || {};


/**
 * 判断目标参数是否string类型或String对象
 * @name baidu.lang.isString
 * @function
 * @grammar baidu.lang.isString(source)
 * @param {Any} source 目标参数
 * @shortcut isString
 * @meta standard
 * @see baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isArray,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
 *             
 * @returns {boolean} 类型判断结果
 */
baidu.lang.isString = function (source) {
    return '[object String]' == Object.prototype.toString.call(source);
};

// 声明快捷方法
baidu.isString = baidu.lang.isString;


/**
 * 从文档中获取指定的DOM元素
 * **内部方法**
 * 
 * @param {string|HTMLElement} id 元素的id或DOM元素
 * @meta standard
 * @return {HTMLElement} DOM元素,如果不存在,返回null,如果参数不合法,直接返回参数
 */
baidu.dom._g = function (id) {
    if (baidu.lang.isString(id)) {
        return document.getElementById(id);
    }
    return id;
};

// 声明快捷方法
baidu._g = baidu.dom._g;




/**
 * @namespace baidu.browser 判断浏览器类型和特性的属性。
 */
baidu.browser = baidu.browser || {};

if (/msie (\d+\.\d)/i.test(navigator.userAgent)) {
    //IE 8下,以documentMode为准
    //在百度模板中,可能会有$,防止冲突,将$1 写成 \x241
/**
 * 判断是否为ie浏览器
 * @property ie ie版本号
 * @grammar baidu.browser.ie
 * @meta standard
 * @shortcut ie
 * @see baidu.browser.firefox,baidu.browser.safari,baidu.browser.opera,baidu.browser.chrome,baidu.browser.maxthon 
 */
   baidu.browser.ie = baidu.ie = document.documentMode || + RegExp['\x241'];
}


/**
 * 获取目标元素的computed style值。如果元素的样式值不能被浏览器计算,则会返回空字符串(IE)
 *
 * @author berg
 * @name baidu.dom.getComputedStyle
 * @function
 * @grammar baidu.dom.getComputedStyle(element, key)
 * @param {HTMLElement|string} element 目标元素或目标元素的id
 * @param {string} key 要获取的样式名
 *
 * @see baidu.dom.getStyle
 *             
 * @returns {string} 目标元素的computed style值
 */

baidu.dom.getComputedStyle = function(element, key){
    element = baidu.dom._g(element);
    var doc = baidu.dom.getDocument(element),
        styles;
    if (doc.defaultView && doc.defaultView.getComputedStyle) {
        styles = doc.defaultView.getComputedStyle(element, null);
        if (styles) {
            return styles[key] || styles.getPropertyValue(key);
        }
    }
    return ''; 
};

/**
 * 提供给setStyle与getStyle使用
 */
baidu.dom._styleFixer = baidu.dom._styleFixer || {};

/**
 * 提供给setStyle与getStyle使用
 */
baidu.dom._styleFilter = baidu.dom._styleFilter || [];



/**
 * 为获取和设置样式的过滤器
 * @private
 * @meta standard
 */
baidu.dom._styleFilter.filter = function (key, value, method) {
    for (var i = 0, filters = baidu.dom._styleFilter, filter; filter = filters[i]; i++) {
        if (filter = filter[method]) {
            value = filter(key, value);
        }
    }

    return value;
};

/**
 * @namespace baidu.string 操作字符串的方法。
 */
baidu.string = baidu.string || {};


/**
 * 将目标字符串进行驼峰化处理
 * @name baidu.string.toCamelCase
 * @function
 * @grammar baidu.string.toCamelCase(source)
 * @param {string} source 目标字符串
 * @remark
 * 支持单词以“-_”分隔
 * @meta standard
 *             
 * @returns {string} 驼峰化处理后的字符串
 */
 
 //todo:考虑以后去掉下划线支持?
baidu.string.toCamelCase = function (source) {
    //提前判断,提高getStyle等的效率 thanks xianwei
    if (source.indexOf('-') < 0 && source.indexOf('_') < 0) {
        return source;
    }
    return source.replace(/[-_][^-_]/g, function (match) {
        return match.charAt(1).toUpperCase();
    });
};


/**
 * 获取目标元素的样式值
 * @name baidu.dom.getStyle
 * @function
 * @grammar baidu.dom.getStyle(element, key)
 * @param {HTMLElement|string} element 目标元素或目标元素的id
 * @param {string} key 要获取的样式名
 * @remark
 * 
 * 为了精简代码,本模块默认不对任何浏览器返回值进行归一化处理(如使用getStyle时,不同浏览器下可能返回rgb颜色或hex颜色),也不会修复浏览器的bug和差异性(如设置IE的float属性叫styleFloat,firefox则是cssFloat)。<br />
 * baidu.dom._styleFixer和baidu.dom._styleFilter可以为本模块提供支持。<br />
 * 其中_styleFilter能对颜色和px进行归一化处理,_styleFixer能对display,float,opacity,textOverflow的浏览器兼容性bug进行处理。	
 * @shortcut getStyle
 * @meta standard
 * @see baidu.dom.setStyle,baidu.dom.setStyles, baidu.dom.getComputedStyle
 *             
 * @returns {string} 目标元素的样式值
 */
// TODO
// 1. 无法解决px/em单位统一的问题(IE)
// 2. 无法解决样式值为非数字值的情况(medium等 IE)
baidu.dom.getStyle = function (element, key) {
    var dom = baidu.dom;

    element = dom.g(element);
    key = baidu.string.toCamelCase(key);
    //computed style, then cascaded style, then explicitly set style.
    var value = element.style[key] ||
                (element.currentStyle ? element.currentStyle[key] : "") || 
                dom.getComputedStyle(element, key);

    // 在取不到值的时候,用fixer进行修正
    if (!value) {
        var fixer = dom._styleFixer[key];
        value = fixer && fixer.get ? fixer.get(element) : baidu.dom.getStyle(element, fixer);
    }
    
    /* 检查结果过滤器 */
    if (fixer = dom._styleFilter) {
        value = fixer.filter(key, value, 'get');
    }

    return value;
};

// 声明快捷方法
baidu.getStyle = baidu.dom.getStyle;






if (/opera\/(\d+\.\d)/i.test(navigator.userAgent)) {
/**
 * 判断是否为opera浏览器
 * @property opera opera版本号
 * @grammar baidu.browser.opera
 * @meta standard
 * @see baidu.browser.ie,baidu.browser.firefox,baidu.browser.safari,baidu.browser.chrome 
 */
    baidu.browser.opera = + RegExp['\x241'];
}

/**
 * @property isWebkit 判断是否为webkit内核
 * @grammar baidu.browser.isWebkit
 * @meta standard
 * @see baidu.browser.isGecko
 */
baidu.browser.isWebkit = /webkit/i.test(navigator.userAgent);





/**
 * @property isGecko 判断是否为gecko内核
 * @grammar baidu.browser.isGecko
 * @meta standard
 * @see baidu.browser.isWebkit
 */
baidu.browser.isGecko = /gecko/i.test(navigator.userAgent) && !/like gecko/i.test(navigator.userAgent);

/**
 * @property isStrict 判断是否严格标准的渲染模式
 * @grammar baidu.browser.isStrict
 * @meta standard
 */
baidu.browser.isStrict = document.compatMode == "CSS1Compat";


/**
 * 获取目标元素相对于整个文档左上角的位置
 * @name baidu.dom.getPosition
 * @function
 * @grammar baidu.dom.getPosition(element)
 * @param {HTMLElement|string} element 目标元素或目标元素的id
 * @meta standard
 *             
 * @returns {Object} 目标元素的位置,键值为top和left的Object。
 */
baidu.dom.getPosition = function (element) {
    element = baidu.dom.g(element);
    var doc = baidu.dom.getDocument(element), 
        browser = baidu.browser,
        getStyle = baidu.dom.getStyle,
    // Gecko 1.9版本以下用getBoxObjectFor计算位置
    // 但是某些情况下是有bug的
    // 对于这些有bug的情况
    // 使用递归查找的方式
        BUGGY_GECKO_BOX_OBJECT = browser.isGecko > 0 && 
                                 doc.getBoxObjectFor &&
                                 getStyle(element, 'position') == 'absolute' &&
                                 (element.style.top === '' || element.style.left === ''),
        pos = {"left":0,"top":0},
        viewport = (browser.ie && !browser.isStrict) ? doc.body : doc.documentElement,
        parent,
        box;
    
    if(element == viewport){
        return pos;
    }


    if(element.getBoundingClientRect){ // IE and Gecko 1.9+
        
    	//当HTML或者BODY有border width时, 原生的getBoundingClientRect返回值是不符合预期的
    	//考虑到通常情况下 HTML和BODY的border只会设成0px,所以忽略该问题.
        box = element.getBoundingClientRect();

        pos.left = Math.floor(box.left) + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
        pos.top  = Math.floor(box.top)  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop);
	    
        // IE会给HTML元素添加一个border,默认是medium(2px)
        // 但是在IE 6 7 的怪异模式下,可以被html { border: 0; } 这条css规则覆盖
        // 在IE7的标准模式下,border永远是2px,这个值通过clientLeft 和 clientTop取得
        // 但是。。。在IE 6 7的怪异模式,如果用户使用css覆盖了默认的medium
        // clientTop和clientLeft不会更新
        pos.left -= doc.documentElement.clientLeft;
        pos.top  -= doc.documentElement.clientTop;
        
        var htmlDom = doc.body,
            // 在这里,不使用element.style.borderLeftWidth,只有computedStyle是可信的
            htmlBorderLeftWidth = parseInt(getStyle(htmlDom, 'borderLeftWidth')),
            htmlBorderTopWidth = parseInt(getStyle(htmlDom, 'borderTopWidth'));
        if(browser.ie && !browser.isStrict){
            pos.left -= isNaN(htmlBorderLeftWidth) ? 2 : htmlBorderLeftWidth;
            pos.top  -= isNaN(htmlBorderTopWidth) ? 2 : htmlBorderTopWidth;
        }
    /*
     * 因为firefox 3.6和4.0在特定页面下(场景待补充)都会出现1px偏移,所以暂时移除该逻辑分支
     * 如果 2.0版本时firefox仍存在问题,该逻辑分支将彻底移除. by rocy 2011-01-20
    } else if (doc.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT){ // gecko 1.9-

        // 1.9以下的Gecko,会忽略ancestors的scroll值
        // https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and
        // https://bugzilla.mozilla.org/show_bug.cgi?id=330619

        box = doc.getBoxObjectFor(element);
        var vpBox = doc.getBoxObjectFor(viewport);
        pos.left = box.screenX - vpBox.screenX;
        pos.top  = box.screenY - vpBox.screenY;
        */
    } else { // safari/opera/firefox
        parent = element;

        do {
            pos.left += parent.offsetLeft;
            pos.top  += parent.offsetTop;
      
            // safari里面,如果遍历到了一个fixed的元素,后面的offset都不准了
            if (browser.isWebkit > 0 && getStyle(parent, 'position') == 'fixed') {
                pos.left += doc.body.scrollLeft;
                pos.top  += doc.body.scrollTop;
                break;
            }
            
            parent = parent.offsetParent;
        } while (parent && parent != element);

        // 对body offsetTop的修正
        if(browser.opera > 0 || (browser.isWebkit > 0 && getStyle(element, 'position') == 'absolute')){
            pos.top  -= doc.body.offsetTop;
        }

        // 计算除了body的scroll
        parent = element.offsetParent;
        while (parent && parent != doc.body) {
            pos.left -= parent.scrollLeft;
            // see https://bugs.opera.com/show_bug.cgi?id=249965
//            if (!b.opera || parent.tagName != 'TR') {
            if (!browser.opera || parent.tagName != 'TR') {
                pos.top -= parent.scrollTop;
            }
            parent = parent.offsetParent;
        }
    }

    return pos;
};






/**
 * 从DOM树上移除目标元素
 * @name baidu.dom.remove
 * @function
 * @grammar baidu.dom.remove(element)
 * @param {HTMLElement|string} element 需要移除的元素或元素的id
 * @remark
 * <b>注意:</b>对于移除的dom元素,IE下会释放该元素的空间,继续使用该元素的引用进行操作将会引发不可预料的问题。
 * @meta standard
 */
baidu.dom.remove = function (element) {
    element = baidu.dom._g(element);
	var tmpEl = element.parentNode;
    //去掉了对ie下的特殊处理:创建一个div,appendChild,然后div.innerHTML = ""
    tmpEl && tmpEl.removeChild(element);
};


/**
 * 对目标字符串进行格式化
 * @name baidu.string.format
 * @function
 * @grammar baidu.string.format(source, opts)
 * @param {string} source 目标字符串
 * @param {Object|string...} opts 提供相应数据的对象或多个字符串
 * @remark
 * 
opts参数为“Object”时,替换目标字符串中的#{property name}部分。<br>
opts为“string...”时,替换目标字符串中的#{0}、#{1}...部分。
		
 * @shortcut format
 * @meta standard
 *             
 * @returns {string} 格式化后的字符串
 */
baidu.string.format = function (source, opts) {
    source = String(source);
    var data = Array.prototype.slice.call(arguments,1), toString = Object.prototype.toString;
    if(data.length){
	    data = data.length == 1 ? 
	    	/* ie 下 Object.prototype.toString.call(null) == '[object Object]' */
	    	(opts !== null && (/\[object Array\]|\[object Object\]/.test(toString.call(opts))) ? opts : data) 
	    	: data;
    	return source.replace(/#\{(.+?)\}/g, function (match, key){
	    	var replacer = data[key];
	    	// chrome 下 typeof /a/ == 'function'
	    	if('[object Function]' == toString.call(replacer)){
	    		replacer = replacer(key);
	    	}
	    	return ('undefined' == typeof replacer ? '' : replacer);
    	});
    }
    return source;
};

// 声明快捷方法
baidu.format = baidu.string.format;

/**
 * @namespace baidu.event 屏蔽浏览器差异性的事件封装。
 * @property target 	事件的触发元素
 * @property pageX 		鼠标事件的鼠标x坐标
 * @property pageY 		鼠标事件的鼠标y坐标
 * @property keyCode 	键盘事件的键值
 */
baidu.event = baidu.event || {};


/**
 * 事件监听器的存储表
 * @private
 * @meta standard
 */
baidu.event._listeners = baidu.event._listeners || [];



/**
 * 为目标元素添加事件监听器
 * @name baidu.event.on
 * @function
 * @grammar baidu.event.on(element, type, listener)
 * @param {HTMLElement|string|window} element 目标元素或目标元素id
 * @param {string} type 事件类型
 * @param {Function} listener 需要添加的监听器
 * @remark
 * 
1. 不支持跨浏览器的鼠标滚轮事件监听器添加<br>
2. 改方法不为监听器灌入事件对象,以防止跨iframe事件挂载的事件对象获取失败
    
 * @shortcut on
 * @meta standard
 * @see baidu.event.un
 *             
 * @returns {HTMLElement|window} 目标元素
 */
baidu.event.on = function (element, type, listener) {
    type = type.replace(/^on/i, '');
    element = baidu.dom._g(element);

    var realListener = function (ev) {
            // 1. 这里不支持EventArgument,  原因是跨frame的事件挂载
            // 2. element是为了修正this
            listener.call(element, ev);
        },
        lis = baidu.event._listeners,
        filter = baidu.event._eventFilter,
        afterFilter,
        realType = type;
    type = type.toLowerCase();
    // filter过滤
    if(filter && filter[type]){
        afterFilter = filter[type](element, type, realListener);
        realType = afterFilter.type;
        realListener = afterFilter.listener;
    }
    
    // 事件监听器挂载
    if (element.addEventListener) {
        element.addEventListener(realType, realListener, false);
    } else if (element.attachEvent) {
        element.attachEvent('on' + realType, realListener);
    }
  
    // 将监听器存储到数组中
    lis[lis.length] = [element, type, listener, realListener, realType];
    return element;
};

// 声明快捷方法
baidu.on = baidu.event.on;

/**
 * 为目标元素移除事件监听器
 * @name baidu.event.un
 * @function
 * @grammar baidu.event.un(element, type, listener)
 * @param {HTMLElement|string|window} element 目标元素或目标元素id
 * @param {string} type 事件类型
 * @param {Function} listener 需要移除的监听器
 * @shortcut un
 * @meta standard
 * @see baidu.event.on
 *             
 * @returns {HTMLElement|window} 目标元素
 */
baidu.event.un = function (element, type, listener) {
    element = baidu.dom._g(element);
    type = type.replace(/^on/i, '').toLowerCase();
    
    var lis = baidu.event._listeners, 
        len = lis.length,
        isRemoveAll = !listener,
        item,
        realType, realListener;
    
    //如果将listener的结构改成json
    //可以节省掉这个循环,优化性能
    //但是由于un的使用频率并不高,同时在listener不多的时候
    //遍历数组的性能消耗不会对代码产生影响
    //暂不考虑此优化
    while (len--) {
        item = lis[len];
        
        // listener存在时,移除element的所有以listener监听的type类型事件
        // listener不存在时,移除element的所有type类型事件
        if (item[1] === type
            && item[0] === element
            && (isRemoveAll || item[2] === listener)) {
           	realType = item[4];
           	realListener = item[3];
            if (element.removeEventListener) {
                element.removeEventListener(realType, realListener, false);
            } else if (element.detachEvent) {
                element.detachEvent('on' + realType, realListener);
            }
            lis.splice(len, 1);
        }
    }
    
    return element;
};

// 声明快捷方法
baidu.un = baidu.event.un;

/**
 * @namespace baidu.object 操作原生对象的方法。
 */
baidu.object = baidu.object || {};


/**
 * 将源对象的所有属性拷贝到目标对象中
 * @author erik
 * @name baidu.object.extend
 * @function
 * @grammar baidu.object.extend(target, source)
 * @param {Object} target 目标对象
 * @param {Object} source 源对象
 * @see baidu.array.merge
 * @remark
 * 
1.目标对象中,与源对象key相同的成员将会被覆盖。<br>
2.源对象的prototype成员不会拷贝。
		
 * @shortcut extend
 * @meta standard
 *             
 * @returns {Object} 目标对象
 */
baidu.extend =
baidu.object.extend = function (target, source) {
    for (var p in source) {
        if (source.hasOwnProperty(p)) {
            target[p] = source[p];
        }
    }
    
    return target;
};


/**
 * 阻止事件的默认行为
 * @name baidu.event.preventDefault
 * @function
 * @grammar baidu.event.preventDefault(event)
 * @param {Event} event 事件对象
 * @meta standard
 * @see baidu.event.stop,baidu.event.stopPropagation
 */
baidu.event.preventDefault = function (event) {
   if (event.preventDefault) {
       event.preventDefault();
   } else {
       event.returnValue = false;
   }
};




/**
 * 返回一个当前页面的唯一标识字符串。
 * @name baidu.lang.guid
 * @function
 * @grammar baidu.lang.guid()
 * @version 1.1.1
 * @meta standard
 *             
 * @returns {String} 当前页面的唯一标识字符串
 */

(function(){
    //不直接使用window,可以提高3倍左右性能
    var guid = window[baidu.guid];

    baidu.lang.guid = function() {
        return "TANGRAM__" + (guid._counter ++).toString(36);
    };

    guid._counter = guid._counter || 1;
})();

/**
 * 所有类的实例的容器
 * key为每个实例的guid
 * @meta standard
 */

window[baidu.guid]._instances = window[baidu.guid]._instances || {};

/**
 * 判断目标参数是否为function或Function实例
 * @name baidu.lang.isFunction
 * @function
 * @grammar baidu.lang.isFunction(source)
 * @param {Any} source 目标参数
 * @version 1.2
 * @see baidu.lang.isString,baidu.lang.isObject,baidu.lang.isNumber,baidu.lang.isArray,baidu.lang.isElement,baidu.lang.isBoolean,baidu.lang.isDate
 * @meta standard
 * @returns {boolean} 类型判断结果
 */
baidu.lang.isFunction = function (source) {
    // chrome下,'function' == typeof /a/ 为true.
    return '[object Function]' == Object.prototype.toString.call(source);
};


/**
 * 
 * @class  Tangram继承机制提供的一个基类,用户可以通过继承baidu.lang.Class来获取它的属性及方法。
 * @name 	baidu.lang.Class
 * @grammar baidu.lang.Class(guid)
 * @param 	{string}	guid	对象的唯一标识
 * @meta standard
 * @remark baidu.lang.Class和它的子类的实例均包含一个全局唯一的标识guid。guid是在构造函数中生成的,因此,继承自baidu.lang.Class的类应该直接或者间接调用它的构造函数。<br>baidu.lang.Class的构造函数中产生guid的方式可以保证guid的唯一性,及每个实例都有一个全局唯一的guid。
 * @meta standard
 * @see baidu.lang.inherits,baidu.lang.Event
 */
baidu.lang.Class = function(guid) {
    this.guid = guid || baidu.lang.guid();
    window[baidu.guid]._instances[this.guid] = this;
};
window[baidu.guid]._instances = window[baidu.guid]._instances || {};

/**
 * 释放对象所持有的资源,主要是自定义事件。
 * @name dispose
 * @grammar obj.dispose()
 * TODO: 将_listeners中绑定的事件剔除掉
 */
baidu.lang.Class.prototype.dispose = function(){
    delete window[baidu.guid]._instances[this.guid];

    for(var property in this){
        if (!baidu.lang.isFunction(this[property])) {
            delete this[property];
        }
    }
    this.disposed = true;   // 20100716
};

/**
 * 重载了默认的toString方法,使得返回信息更加准确一些。
 * @return {string} 对象的String表示形式
 */
baidu.lang.Class.prototype.toString = function(){
    return "[object " + (this._className || "Object" ) + "]";
};





/**
 * 
 * @class   自定义的事件对象。
 * @name 	baidu.lang.Event
 * @grammar baidu.lang.Event(type[, target])
 * @param 	{string} type	 事件类型名称。为了方便区分事件和一个普通的方法,事件类型名称必须以"on"(小写)开头。
 * @param 	{Object} [target]触发事件的对象
 * @meta standard
 * @remark 引入该模块,会自动为Class引入3个事件扩展方法:addEventListener、removeEventListener和dispatchEvent。
 * @meta standard
 * @see baidu.lang.Class
 */
baidu.lang.Event = function (type, target) {
    this.type = type;
    this.returnValue = true;
    this.target = target || null;
    this.currentTarget = null;
};

/**
 * 注册对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
 * @grammar obj.addEventListener(type, handler[, key])
 * @param 	{string}   type         自定义事件的名称
 * @param 	{Function} handler      自定义事件被触发时应该调用的回调函数
 * @param 	{string}   [key]		为事件监听函数指定的名称,可在移除时使用。如果不提供,方法会默认为它生成一个全局唯一的key。
 * @remark 	事件类型区分大小写。如果自定义事件名称不是以小写"on"开头,该方法会给它加上"on"再进行判断,即"click"和"onclick"会被认为是同一种事件。 
 */
baidu.lang.Class.prototype.addEventListener = function (type, handler, key) {
    if (!baidu.lang.isFunction(handler)) {
        return;
    }

    !this.__listeners && (this.__listeners = {});

    var t = this.__listeners, id;
    if (typeof key == "string" && key) {
        if (/[^\w\-]/.test(key)) {
            throw("nonstandard key:" + key);
        } else {
            handler.hashCode = key; 
            id = key;
        }
    }
    type.indexOf("on") != 0 && (type = "on" + type);

    typeof t[type] != "object" && (t[type] = {});
    id = id || baidu.lang.guid();
    handler.hashCode = id;
    t[type][id] = handler;
};
 
/**
 * 移除对象的事件监听器。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
 * @grammar obj.removeEventListener(type, handler)
 * @param {string}   type     事件类型
 * @param {Function|string} handler  要移除的事件监听函数或者监听函数的key
 * @remark 	如果第二个参数handler没有被绑定到对应的自定义事件中,什么也不做。
 */
baidu.lang.Class.prototype.removeEventListener = function (type, handler) {
    if (typeof handler != "undefined") {
        if (baidu.lang.isFunction(handler)) {
            handler = handler.hashCode;
        } else if (!baidu.lang.isString(handler)) {
            return;
        }
    }

    !this.__listeners && (this.__listeners = {});

    type.indexOf("on") != 0 && (type = "on" + type);

    var t = this.__listeners;
    if (!t[type]) {
        return;
    }
    if (typeof handler != "undefined") {
        t[type][handler] && delete t[type][handler];
    } else {
        for(var guid in t[type]){
            delete t[type][guid];
        }
    }
};

/**
 * 派发自定义事件,使得绑定到自定义事件上面的函数都会被执行。引入baidu.lang.Event后,Class的子类实例才会获得该方法。
 * @grammar obj.dispatchEvent(event, options)
 * @param {baidu.lang.Event|String} event 	Event对象,或事件名称(1.1.1起支持)
 * @param {Object} 					options 扩展参数,所含属性键值会扩展到Event对象上(1.2起支持)
 * @remark 处理会调用通过addEventListenr绑定的自定义事件回调函数之外,还会调用直接绑定到对象上面的自定义事件。例如:<br>
myobj.onMyEvent = function(){}<br>
myobj.addEventListener("onMyEvent", function(){});
 */
baidu.lang.Class.prototype.dispatchEvent = function (event, options) {
    if (baidu.lang.isString(event)) {
        event = new baidu.lang.Event(event);
    }
    !this.__listeners && (this.__listeners = {});

    // 20100603 添加本方法的第二个参数,将 options extend到event中去传递
    options = options || {};
    for (var i in options) {
        event[i] = options[i];
    }

    var i, t = this.__listeners, p = event.type;
    event.target = event.target || this;
    event.currentTarget = this;

    p.indexOf("on") != 0 && (p = "on" + p);

    baidu.lang.isFunction(this[p]) && this[p].apply(this, arguments);

    if (typeof t[p] == "object") {
        for (i in t[p]) {
            t[p][i].apply(this, arguments);
        }
    }
    return event.returnValue;
};


/** @namespace */
baidu.ui = baidu.ui || { version: '1.3.5' };

/**
 * 通过uiType找到UI类
 * 查找规则:
 * suggestion -> baidu.ui.Suggestion
 * toolbar-spacer -> baidu.ui.Toolbar.Spacer.
 *
 * @author berg
 *
 * @param {String} uiType
 * @return {object} UI类
 */
baidu.ui.getUI = function(uiType){
    var uiType = uiType.split('-'),
        result = baidu.ui,
        len = uiType.length,
        i = 0;

    for (; i < len; i++) {
        result = result[uiType[i].charAt(0).toUpperCase() + uiType[i].slice(1)];
    }
    return result;
};



/**
 * 创建一个ui控件
 * @author berg
 * @param {object|String} UI控件类或者uiType
 * @param {object} options optional 控件的初始化属性
 *
 * autoRender : 是否自动render,默认true
 * element : render到的元素
 * parent : 父控件
 *
 * @return {object} 创建好的控件实例
 */
baidu.ui.create = function(UI, options){
    if(baidu.lang.isString(UI)){
        UI = baidu.ui.getUI(UI);
    }
    return new UI(options);
};










/**
 * UI基类,所有的UI都应该从这个类中派生出去
 *
 * @author berg
 *
 * property:
 * 
 * mainId
 */
baidu.ui.Base = {

    id : "",

    /**
     * 获得当前控件的id
     * @param {string} optional key 
     * @return {string} id
     */
    getId : function(key){
        var ui = this, idPrefix;
        //通过guid区别多实例
        idPrefix = "tangram-" + ui.uiType + '--' + (ui.id ? ui.id : ui.guid);
        return key ? idPrefix + "-" + key : idPrefix;
    },

    /**
     * 获得class,支持skin
     *
     * @param {string} optional key
     *
     * @return {string} className
     */
    getClass : function(key){
        var me = this,
            className = me.classPrefix,
            skinName = me.skin;
         if (key) {
             className += '-' + key;
             skinName += '-' + key;
         }
         if (me.skin) {
             className += ' ' + skinName;
         }
         return className;
    },

    getMain : function(){
        return baidu.g(this.mainId);
    },

    getBody : function(){
        return baidu.g(this.getId());
    },

    
    /**
     * 控件类型:如dialog
     */
    uiType : "",
    
    /**
     * 获取调用的字符串的引用前缀
     */
    getCallRef : function(){
        return "window['$BAIDU]._instances['" + this.guid + "']";
    },

    /**
     * 获取调用的字符串
     */
    getCallString : function(fn){
        var i = 0,
            arg = Array.prototype.slice.call(arguments, 1),
            len = arg.length;
        for (; i < len; i++) {
            if (typeof arg[i] == 'string') {
                arg[i] = "'" + arg[i] +"'";
            }
        }
        //如果被闭包包起来了,用baidu.lang.instance会找到最外面的baidu函数,可能出错
        return this.getCallRef() 
                + '.' + fn + '('
                + arg.join(',') 
                + ');'; 
    },

    /**
     * 添加事件. 避免析构中漏掉注销事件.
     */
    on : function(element, type, listener){
        baidu.on(element, type, listener);
        ui.addEventListener("ondispose", function(){
            baidu.un(element, type, listener);
        });
    },

    /**
     * 渲染控件到指定的元素
     * @param {HTMLElement} main optional   要渲染到的元素,可选。
     *                                      如果不传此参数,则会在body下创建一个绝对定位的div做为main
     * @return  {HTMLElement} main 渲染到的元素
     */
    renderMain : function(main){
        var ui = this,
            i = 0,
            len;
        //如果被渲染过就不重复渲染
        if (ui.getMain()) {
            return ;
        }
        main = baidu.g(main);
        //如果没有main元素,创建一个在body下面的div当作main
        if(!main){
            main = document.createElement('div');
            document.body.appendChild(main);
            main.style.position = "absolute";
            //给这个元素创建一个class,方便用户控制
            main.className = ui.getClass("main");
        }
        if(!main.id){
            main.id = ui.getId("main");
        }
        ui.mainId = main.id;
        main.setAttribute('data-guid', ui.guid);

        return main;
    },

    /**
     * 销毁当前实例
     */
    dispose : function(){
        this.dispatchEvent("dispose");
        baidu.lang.Class.prototype.dispose.call(this);
    }
};




/**
 * 创建一个UI控件类
 *
 * @param {function} constructor ui控件构造器
 * @param {object} options 选项
 *
 * @return {object} ui控件
 */
baidu.ui.createUI = function(constructor, options) {
    options = options || {};
    var superClass = options.superClass || baidu.lang.Class,
        lastInherit = superClass == baidu.lang.Class ? 1 : 0,
        i,
        n,
        ui = function(opt, _isInherits){// 创建新类的真构造器函数
            var me = this;
            opt = opt || {};
            // 继承父类的构造器,将isInherits设置成true,在后面不执行render操作
            superClass.call(me, !lastInherit ? opt : (opt.guid || ""), true);

            //扩展静态配置到this上
            baidu.object.extend(me, ui.options);
            //扩展当前options中的项到this上
            baidu.object.extend(me, opt);
            //baidu.object.merge(me, opt, {overwrite:true, recursive:true});

            me.classPrefix = me.classPrefix || "tangram-" + me.uiType.toLowerCase();

            //初始化行为
            //行为就是在控件实例上附加一些属性和方法
            for(i in baidu.ui.behavior){
                //添加行为到控件上
                if(typeof me[i] != 'undefined' && me[i]){
                    baidu.object.extend(me, baidu.ui.behavior[i]);
                    if(baidu.lang.isFunction(me[i])){
                        me.addEventListener("onload", function(){
                            baidu.ui.behavior[i].call(me[i].apply(me));
                        });
                    }else{
                        baidu.ui.behavior[i].call(me);
                    }
                }
            }

            //执行控件自己的构造器
            constructor.apply(me, arguments);

            //执行插件的构造器
            for (i=0, n=ui._addons.length; i<n; i++) {
                ui._addons[i](me);
            }
            if(opt.parent && me.setParent){
                me.setParent(opt.parent);
            }
            if(!_isInherits && opt.autoRender){ 
                me.render(opt.element);
            }
        },
        C = function(){};

    C.prototype = superClass.prototype;

    //继承父类的原型链
    var proto = ui.prototype = new C();

    //继承Base中的方法到prototype中
    for (i in baidu.ui.Base) {
        proto[i] = baidu.ui.Base[i];
    }

    /**
     * 扩展控件的prototype
     * 
     * @param {Object} json 要扩展进prototype的对象
     *
     * @return {Object} 扩展后的对象
     */
    ui.extend = function(json){
        for (i in json) {
            ui.prototype[i] = json[i];
        }
        return ui;  // 这个静态方法也返回类对象本身
    };

    //插件支持
    ui._addons = [];
    ui.register = function(f){
        if (typeof f == "function")
            ui._addons.push(f);
    };
    
    //静态配置支持
    ui.options = {};
    
    return ui;
};



/**
 * 根据参数(guid)的指定,返回对应的实例对象引用
 * @name baidu.lang.instance
 * @function
 * @grammar baidu.lang.instance(guid)
 * @param {string} guid 需要获取实例的guid
 * @meta standard
 *             
 * @returns {Object|null} 如果存在的话,返回;否则返回null。
 */
baidu.lang.instance = function (guid) {
    return window[baidu.guid]._instances[guid] || null;
};

/**
 * 提供给setAttr与getAttr方法作名称转换使用
 * ie6,7下class要转换成className
 * @meta standard
 */

baidu.dom._NAME_ATTRS = (function () {
    var result = {
        'cellpadding': 'cellPadding',
        'cellspacing': 'cellSpacing',
        'colspan': 'colSpan',
        'rowspan': 'rowSpan',
        'valign': 'vAlign',
        'usemap': 'useMap',
        'frameborder': 'frameBorder'
    };
    
    if (baidu.browser.ie < 8) {
        result['for'] = 'htmlFor';
        result['class'] = 'className';
    } else {
        result['htmlFor'] = 'for';
        result['className'] = 'class';
    }
    
    return result;
})();


/**
 * 获取目标元素的属性值
 * @name baidu.dom.getAttr
 * @function
 * @grammar baidu.dom.getAttr(element, key)
 * @param {HTMLElement|string} element 目标元素或目标元素的id
 * @param {string} key 要获取的attribute键名
 * @shortcut getAttr
 * @meta standard
 * @see baidu.dom.setAttr,baidu.dom.setAttrs
 *             
 * @returns {string|null} 目标元素的attribute值,获取不到时返回null
 */
baidu.dom.getAttr = function (element, key) {
    element = baidu.dom.g(element);

    if ('style' == key){
        return element.style.cssText;
    }

    key = baidu.dom._NAME_ATTRS[key] || key;
    return element.getAttribute(key);
};

// 声明快捷方法
baidu.getAttr = baidu.dom.getAttr;

//

/**
 * 获取元素所在的控件
 * @param {HTMLElement|string} 要查找的元素,如果是字符串,则查找这个guid为此字符串的控件
 * @param {string} optional  type 匹配查找指定类型的控件【暂未支持】
 * @return {object} ui控件
 */
baidu.ui.get = function(element/*, type*/){
    var buid;

    //如果是string,则按照guid来找
    if(baidu.lang.isString(element)){
        return baidu.lang.instance(element);
    }else{
        /*
         *type = type.toLowerCase();
         */
        do{
            //如果元素是document
        	//加上了!element判断,防止游离节点的父节点为null的情况  rocy@2010-08-05
            if(!element || element.nodeType == 9){
                return null;
            }
            if(buid = baidu.dom.getAttr(element, "data-guid")){
                     return baidu.lang.instance(buid);
                /*
                 *if( !type || buid.toLowerCase().indexOf(type) === 0){
                 *    return baidu.lang.instance(buid);
                 *}
                 */
            }
        }while((element = element.parentNode) != document.body)
    }
};


/**
 * @class  Suggestion基类,建立一个Suggestion实例
 *
 * @author berg
 * @param      {Object}                 [options]          选项.
 * @config     {Function}               onshow             当显示时触发。
 * @config     {Function}               onhide             当隐藏时触发,input或者整个window失去焦点,或者confirm以后会自动隐藏。
 * @config     {Function}               onconfirm          当确认条目时触发,回车后,或者在条目上按鼠标会触发确认操作。参数是event对象,其中有data属性,包括item和index值。item为当前确认的条目,index是条目索引。。
 * @config     {Function}               onbeforepick       使用方向键选中某一行,鼠标点击前触发。
 * @config     {Function}               onpick             使用方向键选中某一行,鼠标点击时触发。参数是event对象,其中有data属性,包括item和index值。item为当前确认的条目,index是条目索引。
 * @config     {Function}               onhighlight        当高亮时触发,使用方向键移过某一行,使用鼠标滑过某一行时会触发高亮。参数是event对象,其中有data属性,包括item和index值。item为当前确认的条目,index是条目索引。
 * @config     {Function}               view               重新定位时,会调用这个方法来获取新的位置,传入的参数中会包括top、 left、width三个值。
 * @config     {Function}               getData            在需要获取数据的时候会调用此函数来获取数据,传入的参数word是用户在input中输入的数据。
 * @config     {String}                 prependHTML        写在下拉框列表前面的html
 * @config     {String}                 appendHTML         写在下拉框列表后面的html
 */

baidu.ui.Suggestion = baidu.ui.createUI(function(options) {
    var me = this;

    me.addEventListener('onload', function() {
        //监听suggestion外面的鼠标点击
        baidu.on(document, 'mousedown', me.documentMousedownHandler);

        //窗口失去焦点就hide
        baidu.on(window, 'blur', me.windowBlurHandler);
    });

    //初始化dom事件函数
    me.documentMousedownHandler = me.getDocumentMousedownHandler();
    me.windowBlurHandler = me.getWindowBlurHandler();

}).extend(
    /**
     *  @lends baidu.ui.Suggestion.prototype
     */    
{
    uiType: 'suggestion',
    onbeforepick: new Function,
    onpick: new Function,
    onconfirm: new Function,
    onhighlight: new Function,
    onshow: new Function,
    onhide: new Function,


    /*
     * 计算view的函数
     */
    //view            : new Function(),
    /**
     * @private
     */
    getData: function() {return []},
    prependHTML: '',
    appendHTML: '',

    currentData: {},

    tplDOM: "<div id='#{0}' class='#{1}'></div>",
    tplPrependAppend: "<div id='#{0}' class='#{1}'>#{2}</div>",
    tplBody: "<table cellspacing='0' cellpadding='2'><tbody>#{0}</tbody></table>",
    tplRow: '<tr><td id="#{0}" οnmοuseοver="#{2}" οnmοuseοut="#{3}" οnmοusedοwn="#{4}" οnclick="#{5}">#{1}</td></tr>',

    /**
     * 获得suggestion的外框HTML string
     * @private
     */
    getString: function() {
        var me = this;
        return baidu.format(
            me.tplDOM,
            me.getId(),
            me.getClass(),
            me.guid
        );
    },

    /**
     * 将suggestion渲染到dom树中
     */
    render: function(target) {
        var me = this,
            main,
            target = baidu.g(target);
        
        if (me.getMain() || !target) {
            return;
        }
        if (target.id) {
            me.targetId = target.id;
        }else {
            me.targetId = target.id = me.getId('input');
        }

        main = me.renderMain();

        main.style.display = 'none';
        main.innerHTML = me.getString();

        this.dispatchEvent('onload');
    },

    /**
     * 当前suggestion是否处于显示状态
     * @private
     */
    isShowing: function() {
        var me = this,
            main = me.getMain();
        return main && main.style.display != 'none';
    },

    /**
     * 把某个词放到input框中
     * @public
	 * @param     {String}    index    条目索引.
     */
    pick: function(index) {
        var me = this,
            currentData = me.currentData,
            word = currentData && typeof index == 'number' && typeof currentData[index] != 'undefined' ? currentData[index].value : index,
            eventData = {
                data: {
                    item: word == index ? {value: index, content: index} : currentData[index],
                    index: index
                }
            };
        
        if (me.dispatchEvent('onbeforepick', eventData)) {
            me.dispatchEvent('onpick', eventData);
        }
    },

    /**
     * 绘制suggestion
     * @public
     * @param {String}  word               触发sug的字符串.
     * @param {Object}  data               suggestion数据.
     * @param {Boolean} showEmpty optional 如果sug数据为空是否依然显示 默认为false.
     *
     */
    show: function(word, data, showEmpty) {
        
        var i = 0,
            len = data.length,
            me = this;

        if (len == 0 && !showEmpty) {
            me.hide();
        } else {
            me.currentData = [];
            for (; i < len; i++) {
                if (typeof data[i].value != 'undefined') {
                    me.currentData.push(data[i]);
                }else {
                    me.currentData.push({
                        value: data[i],
                        content: data[i]
                    });
                }
            }
            
            me.getBody().innerHTML = me.getBodyString();
            me.getMain().style.display = 'block';
            me.dispatchEvent('onshow');
        }
    },

    /**
     * 高亮某个条目
     * @public
	 * @param    {String}   index    条目索引.
     */
    highlight: function(index) {
        var me = this;
        
        me.clearHighlight();
        me.getItem(index).className = me.getClass('current');
        
        this.dispatchEvent('onhighlight', {
            data: this.getDataByIndex(index)
        });
    },

    /**
     * 隐藏suggestion
     * @public
     */
    hide: function() {
        
        var me = this;
        
        //如果已经是隐藏状态就不用派发后面的事件了
        if (!me.isShowing())
            return;
        
        me.getMain().style.display = 'none';
        me.dispatchEvent('onhide');
    },

    /**
     * confirm指定的条目
	 * @public
     * @param {number|string} index or item
     * @param {string} source 事件来源
     * 
     */
    confirm: function(index, source) {
        
        var me = this;

        me.pick(index);
        me.dispatchEvent('onconfirm', {
            data: me.getDataByIndex(index) || index,
            source: source
        });
        me.hide();
    },

    /**
     * 根据index拿到传给event的data数据
     * @private
     */
    getDataByIndex: function(index) {
        
        return {
            item: this.currentData[index],
            index: index
        };
    },

    /**
     * 获得target的值
     * @public
     */
    getTargetValue: function() {
        return this.getTarget().value;
    },

    /**
     * 获得当前处于高亮状态的词索引
     * @private
     */
    getHighlightIndex: function() {
        
        var me = this,
            len = me.currentData.length,
            i = 0;
        
        if (len && me.isShowing()) {
            for (; i < len; i++) {
                if (me.getItem(i).className == me.getClass('current'))
                    return i;
            }
        }
        
        return -1;
    },

    /**
     * 清除suggestion中全部tr的蓝色背景样式
     * @private
     */
    clearHighlight: function() {
        
        var me = this,
            i = 0,
            len = me.currentData.length;
        
        for (; i < len; i++) {
            me.getItem(i).className = '';
        }
    },

    /**
     * 获得input框元素
     * @public
	 * @return {HTMLElement}   input    输入框元素.
     */
    getTarget: function() {
        return baidu.g(this.targetId);
    },

    /**
     * 获得指定的条目
     * @private
     */
    getItem: function(index) {
        return baidu.g(this.getId('item' + index));
    },

    /**
     * 渲染body部分的string
     * @private
     */
    getBodyString: function() {
        
        var me = this,
            html = '',
            itemsHTML = [],
            data = me.currentData,
            len = data.length,
            i = 0;

        function getPrependAppend(name) {
            return baidu.format(
                me.tplPrependAppend,
                me.getId(name),
                me.getClass(name),
                me[name + 'HTML']
            );
        }


        html += getPrependAppend('prepend');

        for (; i < len; i++) {
            itemsHTML.push(baidu.format(
                me.tplRow,
                me.getId('item' + i),
                data[i].content,
                me.getCallString('itemOver', i),
                me.getCallString('itemOut'),
                me.getCallRef() + '.itemDown(event, ' + i + ')',
                me.getCallString('itemClick', i)
            ));
        }

        html += baidu.format(me.tplBody, itemsHTML.join(''));
        html += getPrependAppend('append');
        return html;
    },

    /**
     * 当每一个项目over、out、down、click时调用的函数
     * 高亮某个条目
     * @private
     */
    itemOver: function(index) {
        this.highlight(index);
    },

    /**
     * @private
     */
    itemOut: function() {
        this.clearHighlight();
    },

    /**
     * @private
     */
    itemDown: function(e, index) {
        this.dispatchEvent('onmousedownitem', {
            data: this.getDataByIndex(index)
        });
        if (!baidu.ie) {
            e.stopPropagation();
            e.preventDefault();
            return false;
        }
    },

    /**
     * @private
     */
    itemClick: function(index) {
        var me = this;

        me.dispatchEvent('onitemclick', {
            data: me.getDataByIndex(index)
        });
        me.confirm(index, 'mouse');
    },


    /**
     * 外部事件绑定
     * @private
     */
    getDocumentMousedownHandler: function() {
        var me = this;
        return function(e) {
            // todo : baidu.event.getTarget();
            e = e || window.event;
            var element = e.target || e.srcElement,
                ui = baidu.ui.get(element);
            //如果在target上面或者me内部
            if (element == me.getTarget() || (ui && ui.uiType == me.uiType)) {
                return;
            }
            me.hide();
        };
    },

    /**
     * @private
     */
    getWindowBlurHandler: function() {
        var me = this;
        return function() {
            me.hide();
        };
    },

    /**
     * 销毁suggesiton
     * @public
     */
    dispose: function() {
        var me = this;
        me.dispatchEvent('dispose');

        baidu.un(document, 'mousedown', me.documentMousedownHandler);
        baidu.un(window, 'blur', me.windowBlurHandler);
        baidu.dom.remove(me.mainId);

        baidu.lang.Class.prototype.dispose.call(this);
    }
});


/**
 * 阻止事件传播
 * @name baidu.event.stopPropagation
 * @function
 * @grammar baidu.event.stopPropagation(event)
 * @param {Event} event 事件对象
 * @see baidu.event.stop,baidu.event.preventDefault
 */
baidu.event.stopPropagation = function (event) {
   if (event.stopPropagation) {
       event.stopPropagation();
   } else {
       event.cancelBubble = true;
   }
};





baidu.ui.Suggestion.register(function(me) {
    var target,
        
        //每次轮询获得的value
        oldValue = '',

        //一打开页面就有的input value
        keyValue,

        //使用pick方法上框的input value
        pickValue,
        mousedownView = false,
        stopCircleTemporary = false;


    me.addEventListener('onload', function() {
        target = this.getTarget();

        keyValue = target.value;

        //生成dom事件函数
        me.targetKeydownHandler = me.getTargetKeydownHandler();

        //加入dom事件
        baidu.on(target, 'keydown', me.targetKeydownHandler);

        target.setAttribute('autocomplete', 'off');

        //轮询计时器
        me.circleTimer = setInterval(function() {
            if (stopCircleTemporary) {
                return;
            }

            if (baidu.g(target) == null) {
                me.dispose();
            }

            var nowValue = target.value;
            //todo,这里的流程可以再简化一点
            if (
                nowValue == oldValue &&
                nowValue != '' &&
                nowValue != keyValue &&
                nowValue != pickValue
              ) {
                if (me.requestTimer == 0) {
                    me.requestTimer = setTimeout(function() {
                        me.dispatchEvent('onneeddata', nowValue);
                    }, 100);
                }
            }else {
                clearTimeout(me.requestTimer);
                me.requestTimer = 0;
                if (nowValue == '' && oldValue != '') {
                    pickValue = '';
                    me.hide();
                }
                oldValue = nowValue;
                if (nowValue != pickValue) {
                    me.defaultIptValue = nowValue;
                }
                if (keyValue != target.value) {
                    keyValue = '';
                }
            }
        }, 10);

        baidu.on(target, 'beforedeactivate', me.beforedeactivateHandler);
    });

    me.addEventListener('onitemclick', function() {
        stopCircleTemporary = false;
        //更新oldValue,否则circle的时候会再次出现suggestion
        me.defaultIptValue = oldValue = me.getTargetValue();
    });

    me.addEventListener('onpick', function(event) {
        //firefox2.0和搜狗输入法的冲突
        if (mousedownView)
            target.blur();
        target.value = pickValue = event.data.item.value;
        if (mousedownView)
            target.focus();
    });

    me.addEventListener('onmousedownitem', function(e) {
        mousedownView = true;
        //chrome和搜狗输入法冲突的问题
        //在chrome下面,输入到一半的字会进框,如果这个时候点击一下suggestion,就会清空里面的东西,导致suggestion重新被刷新
        stopCircleTemporary = true;
        setTimeout(function() {
            stopCircleTemporary = false;
            mousedownView = false;
        },500);
    });
    me.addEventListener('ondispose', function() {
        baidu.un(target, 'keydown', me.targetKeydownHandler);
        baidu.un(target, 'beforedeactivate', me.beforedeactivateHandler);
        clearInterval(me.circleTimer);
    });
});

baidu.ui.Suggestion.extend({
    //鼠标上下移动时
    selectIndexByKeybord: -1,


    /*
     * IE和M$输入法打架的问题
     * 在失去焦点的时候,如果是点击在了suggestion上面,那就取消其默认动作(默认动作会把字上屏)
     */
    beforedeactivateHandler: function() {
        return function() {
            if (mousedownView) {
                window.event.cancelBubble = true;
                window.event.returnValue = false;
            }
        };
    },

    getTargetKeydownHandler: function() {
        var me = this;

        /*
         * 上下键对suggestion的处理
         */
        function keyUpDown(up) {
            var currentData = me.currentData,
                selected;
            //如果当前没有显示,就重新去获取一次数据
            if (!me.isShowing()) {
                me.dispatchEvent('onneeddata', me.getTargetValue());
                return;
            }
            selected = me.getHighlightIndex();
            me.clearHighlight();
            if (up) {
                //最上面再按上
                if (selected == 0) {
                    //把原始的内容放上去
                    me.pick(me.defaultIptValue);
//                    selected--;
                    me.selectIndexByKeybord--;
                    return;
                }
                if (selected == -1)
                    selected = currentData.length;
                selected--;
            }else {
                //最下面再按下
                if (selected == currentData.length - 1) {
                    me.pick(me.defaultIptValue);
//                    selected = -1;
                    me.selectIndexByKeybord = -1;
                    return;
                }
                selected++;
            }
            me.highlight(selected);
            me.pick(selected);
            me.selectIndexByKeybord = selected;
        }
        return function(e) {
            var up = false, index;
            e = e || window.event;
            switch (e.keyCode) {
                case 9:     //tab
                case 27:    //esc
                    me.hide();
                    break;
                case 13:    //回车,默认为表单提交
                    baidu.event.preventDefault(e);
                    me.confirm(me.selectIndexByKeybord < 0 ? me.getTarget().value : me.selectIndexByKeybord, 'keyboard');
                    break;
                case 38:    //向上,在firefox下,按上会出现光标左移的现象
                    up = true;
                case 40:    //向下
                    baidu.event.preventDefault(e);
                    keyUpDown(up);
                    break;
            }
        };
    },

    /*
     * pick选择之外的oldValue
     */
    defaultIptValue: ''

});

/*
 *
 *  智能遮罩,根据用户参数遮住元素下面的select或者flash
 *
 *  使用方法:
 *  baidu.ui.smartCover(element);
 */


//依赖包






/**
 * 查询一个元素是否包含指定的属性
 * @name baidu.dom.hasAttr
 * @function
 * @grammar baidu.dom.hasAttr(element, name)
 * @param {DOMElement|string} element DOM元素或元素的id
 * @param {string} name 要查找的属性名
 * @version 1.3
 *             
 * @returns {Boolean} 是否包含此属性        
 */

baidu.dom.hasAttr = function (element, name){
    element = baidu.g(element);
    var attr = element.attributes.getNamedItem(name);
    return !!( attr && attr.specified );
};

/**
 * 设置目标元素的style样式值
 * @name baidu.dom.setStyle
 * @function
 * @grammar baidu.dom.setStyle(element, key, value)
 * @param {HTMLElement|string} element 目标元素或目标元素的id
 * @param {string} key 要设置的样式名
 * @param {string} value 要设置的样式值
 * @remark
 * 
            为了精简代码,本模块默认不对任何浏览器返回值进行归一化处理(如使用getStyle时,不同浏览器下可能返回rgb颜色或hex颜色),也不会修复浏览器的bug和差异性(如设置IE的float属性叫styleFloat,firefox则是cssFloat)。<br />
baidu.dom._styleFixer和baidu.dom._styleFilter可以为本模块提供支持。<br />
其中_styleFilter能对颜色和px进行归一化处理,_styleFixer能对display,float,opacity,textOverflow的浏览器兼容性bug进行处理。
		
 * @shortcut setStyle
 * @meta standard
 * @see baidu.dom.getStyle,baidu.dom.setStyles
 *             
 * @returns {HTMLElement} 目标元素
 */
baidu.dom.setStyle = function (element, key, value) {
    var dom = baidu.dom, fixer;
    
    // 放弃了对firefox 0.9的opacity的支持
    element = dom.g(element);
    key = baidu.string.toCamelCase(key);

    if (fixer = dom._styleFilter) {
        value = fixer.filter(key, value, 'set');
    }

    fixer = dom._styleFixer[key];
    (fixer && fixer.set) ? fixer.set(element, value) : (element.style[fixer || key] = value);

    return element;
};

// 声明快捷方法
baidu.setStyle = baidu.dom.setStyle;


/**
 * 批量设置目标元素的style样式值
 * @name baidu.dom.setStyles
 * @function
 * @grammar baidu.dom.setStyles(element, styles)
 * @param {HTMLElement|string} element 目标元素或目标元素的id
 * @param {Object} styles 要设置的样式集合
 * @shortcut setStyles
 * @meta standard
 * @see baidu.dom.setStyle,baidu.dom.getStyle
 *             
 * @returns {HTMLElement} 目标元素
 */
baidu.dom.setStyles = function (element, styles) {
    element = baidu.dom.g(element);

    for (var key in styles) {
        baidu.dom.setStyle(element, key, styles[key]);
    }

    return element;
};

// 声明快捷方法
baidu.setStyles = baidu.dom.setStyles;
/**
 * 提供给setStyle与getStyle使用
 * @meta standard
 */
baidu.dom._styleFilter[baidu.dom._styleFilter.length] = {
    set: function (key, value) {
        if (value.constructor == Number 
            && !/zIndex|fontWeight|opacity|zoom|lineHeight/i.test(key)){
            value = value + "px";
        }

        return value;
    }
};



/**
 * @namespace baidu.array 操作数组的方法。
 */

baidu.array = baidu.array || {};


/**
 * 遍历数组中所有元素
 * @name baidu.array.each
 * @function
 * @grammar baidu.array.each(source, iterator[, thisObject])
 * @param {Array} source 需要遍历的数组
 * @param {Function} iterator 对每个数组元素进行调用的函数,该函数有两个参数,第一个为数组元素,第二个为数组索引值,function (item, index)。
 * @param {Object} [thisObject] 函数调用时的this指针,如果没有此参数,默认是当前遍历的数组
 * @remark
 * each方法不支持对Object的遍历,对Object的遍历使用baidu.object.each 。
 * @shortcut each
 * @meta standard
 *             
 * @returns {Array} 遍历的数组
 */
 
baidu.each = baidu.array.forEach = baidu.array.each = function (source, iterator, thisObject) {
    var returnValue, item, i, len = source.length;
    
    if ('function' == typeof iterator) {
        for (i = 0; i < len; i++) {
            item = source[i];
            //TODO
            //此处实现和标准不符合,标准中是这样说的:
            //If a thisObject parameter is provided to forEach, it will be used as the this for each invocation of the callback. If it is not provided, or is null, the global object associated with callback is used instead.
            returnValue = iterator.call(thisObject || source, item, i);
    
            if (returnValue === false) {
                break;
            }
        }
    }
    return source;
};


(function(){
    var smartCover = {
        show    : show,
        hide    : hide,
        update  : update,
        shownIndex : 0,
        hideElement:{},
        iframes : [],
        options : {
            hideSelect : false,
            hideFlash: true
        }
    };

    baidu.ui.smartCover = baidu.ui.smartCover || smartCover;
    var me = baidu.ui.smartCover;

    /**
     * 获取当前需要被隐藏的元素
     * @prviate
     * @param {Array} 获取目标的nodeType
     * @param {HTMLElement} 获取目标的容器
     * @return {Array} 获取的目标数组
     */
    function getElementsToHide(elementTags,container){
        var elements = [],
            i = elementTags.length-1,
            j,
            eachElement,
            con = baidu.g(container) ? baidu.g(container) : document;

        for(; i>=0; i--){
            eachElement = con.getElementsByTagName(elementTags[i]);

            for(j = eachElement.length - 1; j>= 0; j--){
                /**
                 * 每次查找值查找当时还处于显示状态的元素
                 * 实现分层的效果
                 */
                if(eachElement[j] && eachElement[j].style.visibility != "hidden")
                    elements.push([eachElement[j],null]);
            }
        }
        return elements;
    }


    /**
     * 显示smartCover
     * @public
     * @param {UI} baidu.ui对象
     * @param {Object} options samrtCover配置参数
     * @return void
     * */
    function show(ui, options){
        /*
         * shownIndex递增
         * 层级的唯一编号
         */
        me.shownIndex += 1;
        var elementTags = [],
            op = {
                container : document
            };
        baidu.object.extend(op, smartCover.options);
        baidu.object.extend(op, options || {});
        
        op['hideFlash'] && elementTags.push("object");
        op['hideSelect'] && elementTags.push("select");

        //存入对应的层级
        me.hideElement[me.shownIndex] = getElementsToHide(elementTags,op.container);
        var main = ui.getMain(),
            pos = baidu.dom.getPosition(main),
            id = ui.getId(),
            shadeIframe = smartCover.iframes[id];

        if(baidu.ie && op['hideSelect']){
            //用iframe遮select
            if(!shadeIframe){
                shadeIframe = smartCover.iframes[id] = document.createElement('IFRAME');
                //一个简单的装饰器
                ui.getMain().appendChild(shadeIframe);
                shadeIframe.style.display = 'none';
            }

            //todo: 做为配置项,https
            shadeIframe.src = "javascript:void(0)";

            baidu.dom.setStyles(shadeIframe, {
                zIndex  : -1,
                display  : "block",
                border  : "none",
                position : "absolute",
                width : main.offsetWidth,
                height : main.offsetHeight,
                top : 0,
                left : 0,
                //Make sure that the iframe is not visible.
                filter : 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'
            });
        }
        baidu.each(me.hideElement[me.shownIndex],function(element){
            if(baidu.ui.get(element[0]) != ui){
                hideElement(element);
            }
        });
    }

    /**
     * 更新smartCover
     * @public
     * @param {UI} ui,baidu.ui对象
     * @return void
     * */
    function update(ui){
        if(baidu.ie){
            var main = ui.getMain(),
                id = ui.getId();
            if(!smartCover.iframes[id]){
                return ;
            }
            baidu.dom.setStyles(smartCover.iframes[id], {
                width : main.offsetWidth,
                height : main.offsetHeight
            });
        }
    }

    /**
     * 隐藏smartCover
     * @public 
     * @param {UI} ui,baidu.ui对象
     * @return void
     */
    function hide(ui){
        if(me.shownIndex == 0)
            return;

        var shadeIframe = smartCover.iframes[ui.getId()];

        if(baidu.ie && shadeIframe){
            shadeIframe.style.display = 'none';
        }
        baidu.each(me.hideElement[me.shownIndex],function(element){
            if(baidu.ui.get(element[0]) != ui)
            restoreElement(element);
        });
        //删除层级,shownIndex减一
        delete(me.hideElement[me.shownIndex]);
        me.shownIndex -= 1;
    }

    /**
     * 隐藏被选出的需要遮盖的元素
     * @prviate
     * @param {HTMLElement} element
     * @return void
     */
    function hideElement(element){
        if(element[1] === null){
            element[1] = element[0].style.visibility;
            element[0].style.visibility = "hidden";
        }
    }
    
    /**
     * 还原被选出的需要遮盖的元素
     * @prviate
     * @param {HTMLElement} element
     * @return void
     */
    function restoreElement(element){
        if(element[1] !== null){
            element[0].style.visibility = element[1];
            element[1] = null;
        }
    }
    
})();

/**
 * 智能遮罩,在ie6下遮住select等玩意儿
 * 当suggestion显示的时候显示遮罩,隐藏的时候同时隐藏
 * @author berg
 */
baidu.ui.Suggestion.register(function(me) {
    me.addEventListener('onshow', function() {
        baidu.ui.smartCover.show(this);
    });
    me.addEventListener('onhide', function() {
        baidu.ui.smartCover.hide(this);
    });
});

/**
 * 为Suggestion提供数据内存缓存
 * 扩展这里可做本地缓存
 * @author berg
 */

baidu.ui.Suggestion.extend({
    /*
     * 设置一组数据给suggestion
     * 调用者可以选择是否立即显示这组数据: noShow
     * @public
     */
    setData: function(word, data, noShow) {
        var me = this;
		me.dataCache[word] = data;
        if (!noShow) {
            me.show(word, me.dataCache[word]);
        }
    }
});

baidu.ui.Suggestion.register(function(me) {
    //初始化dataCache
    me.dataCache = {},
    /*
     * 获取一个词对应的me数据
     * 通过事件返回结果
     */
    me.addEventListener('onneeddata', function(ev, word) {
        var dataCache = me.dataCache;
        if (typeof dataCache[word] == 'undefined') {
            //没有数据就去取数据
            me.getData(word);
        }else {
            //有数据就直接显示
            me.show(word, dataCache[word]);
        }
    });
});

/**
 * 按照border-box模型设置元素的height和width值。只支持元素的padding/border/height/width使用同一种计量单位的情况。<br/> 不支持:<br/> 1. 非数字值(medium)<br/> 2. em/px在不同的属性中混用
 * @name baidu.dom.setBorderBoxSize
 * @author berg
 * @function
 * @grammar baidu.dom.setBorderBoxSize(element, size)
 * @param {HTMLElement|string} element 元素或DOM元素的id
 * @param {object} size 包含height和width键名的对象
 *
 * @see baidu.dom.setBorderBoxWidth, baidu.dom.setBorderBoxHeight
 *
 * @return {HTMLElement}  设置好的元素
 */
baidu.dom.setBorderBoxSize= function (element, size) {
    var result = {};
    size.width && (result.width = parseFloat(size.width));
    size.height && (result.height = parseFloat(size.height));

    function getNumericalStyle(element, name){
        return parseFloat(baidu.getStyle(element, name)) || 0;
    }
    
    if(baidu.browser.isStrict){
        if(size.width){
            result.width = parseFloat(size.width)  -
                           getNumericalStyle(element, 'paddingLeft') - 
                           getNumericalStyle(element, 'paddingRight') - 
                           getNumericalStyle(element, 'borderLeftWidth') -
                           getNumericalStyle(element, 'borderRightWidth');
            result.width < 0 && (result.width = 0);
        }
        if(size.height){
            result.height = parseFloat(size.height) -
                            getNumericalStyle(element, 'paddingTop') - 
                            getNumericalStyle(element, 'paddingBottom') - 
                            getNumericalStyle(element, 'borderTopWidth') - 
                            getNumericalStyle(element, 'borderBottomWidth');
            result.height < 0 && (result.height = 0);
        }
    }
    return baidu.dom.setStyles(element, result);
};


/**
 * 按照border-box模型设置元素的width值
 * 
 * @author berg
 * @name baidu.dom.setBorderBoxWidth
 * @function
 * @grammar baidu.dom.setBorderBoxWidth(element, width)
 * 
 * @param {HTMLElement|string} 	element DOM元素或元素的id
 * @param {number|string} 		width 	要设置的width
 *
 * @return {HTMLElement}  设置好的元素
 * @see baidu.dom.setBorderBoxHeight, baidu.dom.setBorderBoxSize
 * @shortcut dom.setOuterWidth
 */
baidu.dom.setOuterWidth = 
baidu.dom.setBorderBoxWidth = function (element, width) {
    return baidu.dom.setBorderBoxSize(element, {width : width});
};



/**
 * Tangram UI
 * Copyright 2009 Baidu Inc. All rights reserved.
 */


/**
 * 定义名字空间
 */
baidu.ui.behavior = baidu.ui.behavior || {};


/**
 * 获取目标元素所属的window对象
 * @name baidu.dom.getWindow
 * @function
 * @grammar baidu.dom.getWindow(element)
 * @param {HTMLElement|string} element 目标元素或目标元素的id
 * @see baidu.dom.getDocument
 *             
 * @returns {window} 目标元素所属的window对象
 */
baidu.dom.getWindow = function (element) {
    element = baidu.dom.g(element);
    var doc = baidu.dom.getDocument(element);
    
    // 没有考虑版本低于safari2的情况
    // @see goog/dom/dom.js#goog.dom.DomHelper.prototype.getWindow
    return doc.parentWindow || doc.defaultView || null;
};














/**
 * 设置目标元素的top和left值到用户指定的位置
 * 
 * @name baidu.dom.setPosition
 * @function
 * @grammar baidu.dom.setPosition(element, position)
 * 
 * @param {HTMLElement|string}	element 	目标元素或目标元素的id
 * @param {object} 				position 	位置对象 {top: {number}, left : {number}}
 *
 * @return {HTMLElement}  进行设置的元素
 */
baidu.dom.setPosition = function (element, position) {
    return baidu.dom.setStyles(element, {
        left : position.left - (parseFloat(baidu.dom.getStyle(element, "margin-left")) || 0),
        top : position.top - (parseFloat(baidu.dom.getStyle(element, "margin-top")) || 0)
    });
};





/**
 * @namespace baidu.page 对页面层面的封装,包括页面的高宽属性、以及外部css和js的动态添加。
 * @property rules 当前对象的规则列表
*/
baidu.page = baidu.page || {};


/**
 * 获取页面视觉区域宽度
 * @name baidu.page.getViewWidth
 * @function
 * @grammar baidu.page.getViewWidth()
 * @see baidu.page.getViewHeight
 *             
 * @returns {number} 页面视觉区域宽度
 */
baidu.page.getViewWidth = function () {
    var doc = document,
        client = doc.compatMode == 'BackCompat' ? doc.body : doc.documentElement;

    return client.clientWidth;
};

/**
 * 获取页面视觉区域高度
 * @name baidu.page.getViewHeight
 * @function
 * @grammar baidu.page.getViewHeight()
 * @see baidu.page.getViewWidth
 * @meta standard
 * @returns {number} 页面视觉区域高度
 */
baidu.page.getViewHeight = function () {
    var doc = document,
        client = doc.compatMode == 'BackCompat' ? doc.body : doc.documentElement;

    return client.clientHeight;
};

/**
 * 获取纵向滚动量
 * @name baidu.page.getScrollTop
 * @function
 * @grammar baidu.page.getScrollTop()
 * @see baidu.page.getScrollLeft
 * @meta standard
 * @returns {number} 纵向滚动量
 */
baidu.page.getScrollTop = function () {
    var d = document;
    return window.pageYOffset || d.documentElement.scrollTop || d.body.scrollTop;
};

/**
 * 获取横向滚动量
 * @name baidu.page.getScrollLeft
 * @function
 * @grammar baidu.page.getScrollLeft()
 * @see baidu.page.getScrollTop
 *             
 * @returns {number} 横向滚动量
 */
/**
 * 获取横向滚动量
 * 
 * @return {number} 横向滚动量
 */
baidu.page.getScrollLeft = function () {
    var d = document;
    return window.pageXOffset || d.documentElement.scrollLeft || d.body.scrollLeft;
};





/**
 * @namespace baidu.fn 对方法的操作,解决内存泄露问题。
 */
baidu.fn = baidu.fn || {};




/** 
 * 为对象绑定方法和作用域
 * @name baidu.fn.bind
 * @function
 * @grammar baidu.fn.bind(handler[, obj, args])
 * @param {Function|String} handler 要绑定的函数,或者一个在作用域下可用的函数名
 * @param {Object} obj 执行运行时this,如果不传入则运行时this为函数本身
 * @param {args* 0..n} args 函数执行时附加到执行时函数前面的参数
 * @version 1.3
 *
 * @returns {Function} 封装后的函数
 */
baidu.fn.bind = function(func, scope) {
    var xargs = arguments.length > 2 ? [].slice.call(arguments, 2) : null;
    return function () {
        var fn = baidu.lang.isString(func) ? scope[func] : func,
            args = (xargs) ? xargs.concat([].slice.call(arguments, 0)) : arguments;
        return fn.apply(scope || fn, args);
    };
};


/**
 * @author berg, lxp
 * @behavior 为ui控件添加定位行为
 *
 * 根据用户参数将元素定位到指定位置
 * TODO: 1. 用surround做触边折返场景时, 折返的大小通常是原始高宽+另一元素的高宽
 *
 * });
 */
(function() {
    var Posable = baidu.ui.behavior.posable = function() { };

    /**
     * 将控件或者指定元素的左上角放置到指定的坐标
     * @param {Array|Object} coordinate 定位坐标,相对文档左上角的坐标,可以是{x:200,y:300}格式,也可以是[200, 300]格式.
     * @param {HTMLElement|string} element optional 目标元素或目标元素的id,如果不指定,默认为当前控件的主元素.
     * @param {Object} options optional 选项,包括:position/coordinate/offset/insideScreen.
     */
    Posable.setPosition = function(coordinate, element, options) {
        element = baidu.g(element) || this.getMain();
        options = options || {};
        var me = this,
            args = [element, coordinate, options];
        me.__execPosFn(element, '_positionByCoordinate', options.once, args);
    };

    /**
     * 将元素放置到指定的坐标点
     *
     * @param {HTMLElement|string} source 要定位的元素.
     * @param {Array|Object} coordinate 定位坐标,相对文档左上角的坐标,可以是{x:200,y:300}格式,也可以是[200, 300]格式.
     * @param {Object} options optional 选项,同setPosition.
     */
    Posable._positionByCoordinate = function(source, coordinate, options, _scrollJustify) {
        coordinate = coordinate || [0, 0];
        options = options || {};

        var me = this,
            elementStyle = {},
            cH = baidu.page.getViewHeight(),
            cW = baidu.page.getViewWidth(),
            scrollLeft = baidu.page.getScrollLeft(),
            scrollTop  = baidu.page.getScrollTop(),
            sourceWidth = source.offsetWidth,
            sourceHeight = source.offsetHeight,
            offsetParent = source.offsetParent,
            parentPos = (!offsetParent || offsetParent == document.body) ? {left: 0, top: 0} : baidu.dom.getPosition(offsetParent);

        //兼容position大小写
        options.position = options.position ? options.position.toLowerCase() : 'bottomright';

        coordinate = _formatCoordinate(coordinate || [0, 0]);
        options.offset = _formatCoordinate(options.offset || [0, 0]);

        elementStyle.left = coordinate.x + options.offset.x - parentPos.left - (options.position.indexOf('left') >= 0 ? sourceWidth : 0);
        elementStyle.top = coordinate.y + options.offset.y - parentPos.top - (options.position.indexOf('top') >= 0 ? sourceHeight : 0);

        switch (options.insideScreen) {
           case "surround" :
                elementStyle.left += elementStyle.left < scrollLeft ? sourceWidth  : 
                                        ((elementStyle.left + sourceWidth ) > (scrollLeft + cW) ? -sourceWidth : 0);
                elementStyle.top  += elementStyle.top  < scrollTop  ? sourceHeight :
                                        ((elementStyle.top  + sourceHeight) > (scrollTop  + cH) ? -sourceHeight : 0);
                break;
            case 'fix' :
                elementStyle.left = Math.max(
                        0 - parseFloat(baidu.dom.getStyle(source, 'marginLeft')) || 0,
                        Math.min(
                            elementStyle.left,
                            baidu.page.getViewWidth() - sourceWidth - parentPos.left
                            )
                        );
                elementStyle.top = Math.max(
                        0 - parseFloat(baidu.dom.getStyle(source, 'marginTop')) || 0,
                        Math.min(
                            elementStyle.top,
                            baidu.page.getViewHeight() - sourceHeight - parentPos.top
                            )
                        );
                break;
        }
        baidu.dom.setPosition(source, elementStyle);


        //如果因为调整位置令窗口产生了滚动条,重新调整一次。
        //可能出现死循环,用_scrollJustify保证重新调整仅限一次。
        if (!_scrollJustify && (cH != baidu.page.getViewHeight() || cW != baidu.page.getViewWidth())) {
            me._positionByCoordinate(source, coordinate, {}, true);
        }
        _scrollJustify || me.dispatchEvent('onpositionupdate');
    };

    /**
     * 根据参数不同,选择执行一次或者在window resize的时候再次执行某方法
     * @private
     *
     * @param {HTMLElement|string} element 根据此元素寻找window.
     * @param {string} fnName 方法名,会在this下寻找.
     * @param {Boolean} once 是否只执行一次.
     * @return {arguments} args 执行方法的参数.
     */
    Posable.__execPosFn = function(element, fnName, once, args) {
        var me = this;

        if (typeof once == 'undefined' || !once) {
            baidu.event.on(
                baidu.dom.getWindow(element),
                'resize',
                baidu.fn.bind.apply(me, [fnName, me].concat([].slice.call(args)))
            );
        }
        me[fnName].apply(me, args);
    };
    /**
     * 格式化坐标格式
     * @param {Object|array} coordinate 要调整的坐标格式.
     * @return {Object} coordinate 调整后的格式
     * 类似:{x : number, y : number}.
     */
    function _formatCoordinate(coordinate) {
        coordinate.x = coordinate[0] || coordinate.x || coordinate.left || 0;
        coordinate.y = coordinate[1] || coordinate.y || coordinate.top || 0;
        return coordinate;
    }
})();





/**
 * 为Suggestion提供位置校准功能
 * @author berg
 */
baidu.ui.Suggestion.extend({
    posable: true,
    fixWidth: true,
    getWindowResizeHandler: function() {
        var me = this;
        return function() {
            me.adjustPosition(true);
        };
    },

	/*
     * 重新放置suggestion
     * @private
     */
    adjustPosition: function(onlyAdjustShown) {
       var me = this,
            target = me.getTarget(),
            targetPosition,
            main = me.getMain(),
            pos;

        if (!me.isShowing() && onlyAdjustShown) {
            return;
        }
        targetPosition = baidu.dom.getPosition(target),
        pos = {
                top: (targetPosition.top + target.offsetHeight - 1),
                left: targetPosition.left,
                width: target.offsetWidth
            };
        //交给用户的view函数计算
        pos = typeof me.view == 'function' ? me.view(pos) : pos;

        me.setPosition([pos.left, pos.top], null, {once: true});
        baidu.dom.setOuterWidth(main, pos.width); 
    }
});
baidu.ui.Suggestion.register(function(me) {

    me.windowResizeHandler = me.getWindowResizeHandler();

    me.addEventListener('onload', function() {
        me.adjustPosition();
        //监听搜索框与suggestion弹出层的宽度是否一致。
        if (me.fixWidth) {
            me.fixWidthTimer = setInterval(function() {
                var main = me.getMain(),
                    target = me.getTarget();
                if (main.offsetWidth != 0 && target && target.offsetWidth != main.offsetWidth) {
                    me.adjustPosition();
                    main.style.display = 'block';
                }
            }, 100);
        }
        //当窗口变化的时候重新放置
        baidu.on(window, 'resize', me.windowResizeHandler);
    });

    //每次出现的时候都重新定位,保证用户在初始化之后修改了input的位置,也不会出现混乱
    me.addEventListener('onshow', function() {
        me.adjustPosition();
    });

    me.addEventListener('ondispose', function() {
        baidu.un(window, 'resize', me.windowResizeHandler);
        clearInterval(me.fixWidthTimer);
    });

});

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值