jquery.autocomplete.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. /*
  2. * Autocomplete - jQuery plugin 1.0
  3. *
  4. * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
  5. *
  6. * Dual licensed under the MIT and GPL licenses:
  7. * http://www.opensource.org/licenses/mit-license.php
  8. * http://www.gnu.org/licenses/gpl.html
  9. *
  10. * Revision: $Id: jquery.autocomplete.js 5329 2008-04-27 13:07:34Z joern.zaefferer $
  11. *
  12. */
  13. ;(function($) {
  14. $.fn.extend({
  15. autocomplete: function(urlOrData, options) {
  16. var isUrl = typeof urlOrData == "string";
  17. options = $.extend({}, $.Autocompleter.defaults, {
  18. url: isUrl ? urlOrData : null,
  19. data: isUrl ? null : urlOrData,
  20. delay: isUrl ? $.Autocompleter.defaults.delay : 10,
  21. max: options && !options.scroll ? 10 : 150
  22. }, options);
  23. // if highlight is set to false, replace it with a do-nothing function
  24. options.highlight = options.highlight || function(value) { return value; };
  25. // if the formatMatch option is not specified, then use formatItem for backwards compatibility
  26. options.formatMatch = options.formatMatch || options.formatItem;
  27. return this.each(function() {
  28. new $.Autocompleter(this, options);
  29. });
  30. },
  31. result: function(handler) {
  32. return this.bind("result", handler);
  33. },
  34. search: function(handler) {
  35. return this.trigger("search", [handler]);
  36. },
  37. flushCache: function() {
  38. return this.trigger("flushCache");
  39. },
  40. setOptions: function(options){
  41. return this.trigger("setOptions", [options]);
  42. },
  43. unautocomplete: function() {
  44. return this.trigger("unautocomplete");
  45. }
  46. });
  47. $.Autocompleter = function(input, options) {
  48. var KEY = {
  49. UP: 38,
  50. DOWN: 40,
  51. DEL: 46,
  52. TAB: 9,
  53. RETURN: 13,
  54. ESC: 27,
  55. COMMA: 188,
  56. PAGEUP: 33,
  57. PAGEDOWN: 34,
  58. BACKSPACE: 8
  59. };
  60. // Create $ object for input element
  61. var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
  62. var inputSourceValue = ""; //用于缓存input框中的最开始的提示部分数据 modify by jianxiong.ma
  63. var timeout;
  64. var previousValue = "";
  65. var cache = $.Autocompleter.Cache(options);
  66. var hasFocus = 0;
  67. var lastKeyPressCode;
  68. var hasResultTrigger = false ;
  69. var config = {
  70. mouseDownOnSelect: false
  71. };
  72. var select = $.Autocompleter.Select(options, input, selectCurrent, config);
  73. $input.keydown(function(event) {
  74. // track last key pressed
  75. lastKeyPressCode = event.keyCode;
  76. switch(event.keyCode) {
  77. case KEY.UP:
  78. event.preventDefault();
  79. if ( select.visible() ) {
  80. select.prev();
  81. } else {
  82. onChange(0, true);
  83. }
  84. break;
  85. case KEY.DOWN:
  86. event.preventDefault();
  87. if ( select.visible() ) {
  88. select.next();
  89. } else {
  90. onChange(0, true);
  91. }
  92. break;
  93. case KEY.PAGEUP:
  94. event.preventDefault();
  95. if ( select.visible() ) {
  96. select.pageUp();
  97. } else {
  98. onChange(0, true);
  99. }
  100. break;
  101. case KEY.PAGEDOWN:
  102. event.preventDefault();
  103. if ( select.visible() ) {
  104. select.pageDown();
  105. } else {
  106. onChange(0, true);
  107. }
  108. break;
  109. // matches also semicolon
  110. case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
  111. case KEY.TAB:
  112. case KEY.RETURN:
  113. if( selectCurrent() ){
  114. // make sure to blur off the current field
  115. if( !options.multiple )
  116. $input.blur();
  117. event.preventDefault();
  118. }
  119. break;
  120. case KEY.ESC:
  121. select.hide();
  122. break;
  123. default:
  124. select.noMsg('输入内容:'+$input.val());
  125. select.show();
  126. clearTimeout(timeout);
  127. timeout = setTimeout(onChange, options.delay);
  128. break;
  129. }
  130. }).keypress(function() {
  131. // having fun with opera - remove this binding and Opera submits the form when we select an entry via return
  132. }).focus(function(){
  133. // track whether the field has focus, we shouldn't process any
  134. // results if the field no longer has focus
  135. if ($input.val().length == 0) {
  136. select.noMsg('请输入搜索条件!');
  137. select.show();
  138. }
  139. hasFocus++;
  140. }).blur(function() {
  141. hasFocus = 0;
  142. if (!config.mouseDownOnSelect) {
  143. hideResults();
  144. }
  145. }).click(function() {
  146. // show select when clicking in a focused field
  147. if ( hasFocus++ > 1 && !select.visible() ) {
  148. onChange(0, true);
  149. }
  150. }).bind("search", function() {
  151. // TODO why not just specifying both arguments?
  152. var fn = (arguments.length > 1) ? arguments[1] : null;
  153. function findValueCallback(q, data) {
  154. var result;
  155. if( data && data.length ) {
  156. for (var i=0; i < data.length; i++) {
  157. if( data[i].result.toLowerCase() == q.toLowerCase() ) {
  158. result = data[i];
  159. break;
  160. }
  161. }
  162. }
  163. if( typeof fn == "function" ) fn(result);
  164. if(!hasResultTrigger){
  165. //$input.trigger("result", result && [result.data, result.value]);
  166. }
  167. }
  168. $.each(trimWords($input.val()), function(i, value) {
  169. if(value.length>0){
  170. request(value, findValueCallback, findValueCallback);
  171. }
  172. });
  173. }).bind("flushCache", function() {
  174. cache.flush();
  175. }).bind("setOptions", function() {
  176. $.extend(options, arguments[1]);
  177. // if we've updated the data, repopulate
  178. if ( "data" in arguments[1] )
  179. cache.populate();
  180. }).bind("unautocomplete", function() {
  181. select.unbind();
  182. $input.unbind();
  183. });
  184. function selectCurrent() {
  185. var selected = select.selected();
  186. //以下注释部分为原始代码 >> jianxiong.ma 2009-10-28
  187. //if( !selected ||$input.val()=='')
  188. // return false;
  189. if( !selected || inputSourceValue == "")
  190. return false;
  191. var v = selected.result;
  192. previousValue = v;
  193. if ( options.multiple ) {
  194. var words = trimWords($input.val());
  195. if ( words.length > 1 ) {
  196. v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
  197. }
  198. v += options.multipleSeparator;
  199. }
  200. $input.val(v);
  201. hideResultsNow();
  202. //if(!p.mustMatch){
  203. $input.trigger("result", [selected.data, selected.value]);
  204. hasResultTrigger = true ;
  205. //}
  206. return true;
  207. }
  208. function onChange(crap, skipPrevCheck) {
  209. hasResultTrigger = false ;
  210. if( lastKeyPressCode == KEY.DEL ) {
  211. select.hide();
  212. return;
  213. }
  214. var currentValue = $input.val();
  215. inputSourceValue = currentValue; //缓存提示框中的最原始的值
  216. /* change by bin.gu 09-07-01
  217. if ( !skipPrevCheck && currentValue == previousValue )
  218. return;
  219. */
  220. previousValue = currentValue;
  221. currentValue = lastWord(currentValue);
  222. var qlength = currentValue.length ;
  223. for(i = 0; i < qlength; i++) {
  224. if(currentValue.charCodeAt(i) > 128)
  225. //判断如果是中文,就增加1
  226. qlength++;
  227. }
  228. if ( qlength>= options.minChars) {
  229. $input.addClass(options.loadingClass);
  230. if (!options.matchCase)
  231. currentValue = currentValue.toLowerCase();
  232. request(currentValue, receiveData, hideResultsNow);
  233. } else {
  234. stopLoading();
  235. if(currentValue.length>0){
  236. select.noMsg('请输入'+options.minChars+'个字符或'+options.minChars/2+'个汉字!');
  237. select.show();
  238. }else{
  239. select.hide();
  240. }
  241. }
  242. };
  243. function trimWords(value) {
  244. if ( !value ) {
  245. return [""];
  246. }
  247. var words = value.split( options.multipleSeparator );
  248. var result = [];
  249. $.each(words, function(i, value) {
  250. if ( $.trim(value) )
  251. result[i] = $.trim(value);
  252. });
  253. return result;
  254. }
  255. function lastWord(value) {
  256. if ( !options.multiple )
  257. return value;
  258. var words = trimWords(value);
  259. return words[words.length - 1];
  260. }
  261. // fills in the input box w/the first match (assumed to be the best match)
  262. // q: the term entered
  263. // sValue: the first matching result
  264. function autoFill(q, sValue){
  265. // autofill in the complete box w/the first match as long as the user hasn't entered in more data
  266. // if the last user key pressed was backspace, don't autofill
  267. if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
  268. // fill in the value (keep the case the user has typed)
  269. $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
  270. // select the portion of the value not typed by the user (so the next character will erase)
  271. $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
  272. }
  273. };
  274. function hideResults() {
  275. clearTimeout(timeout);
  276. timeout = setTimeout(hideResultsNow, 200);
  277. };
  278. function hideResultsNow() {
  279. select.hide();
  280. clearTimeout(timeout);
  281. stopLoading();
  282. if (options.mustMatch) {
  283. // call search and run callback
  284. $input.search(
  285. function (result){
  286. // if no value found, clear the input box
  287. if( !result )
  288. $input.val("");
  289. }
  290. );
  291. }
  292. };
  293. function receiveData(q, data) {
  294. if ( data && data.length && hasFocus ) {
  295. stopLoading();
  296. select.display(data, q);
  297. autoFill(q, data[0].value);
  298. select.show();
  299. //add by bin.gu 09-07-22 只有一条数据时,默认选中
  300. if(data.length==1){
  301. $input.val(data[0].result);
  302. //if(!p.mustMatch){
  303. $input.trigger("result", [data[0].data, data[0].value]);
  304. hasResultTrigger = true ;
  305. //}
  306. }
  307. } else {
  308. stopLoading();
  309. //add by bin.gu 09-07-09
  310. select.noMsg('您输入的信息无匹配记录!');
  311. select.show();
  312. options.noDataCallBack();
  313. //hideResultsNow();
  314. }
  315. };
  316. function request(term, success, failure) {
  317. if (!options.matchCase)
  318. term = term.toLowerCase();
  319. var data = cache.load(term);
  320. // recieve the cached data
  321. if (data && data.length) {
  322. success(term, data);
  323. // if an AJAX url has been supplied, try loading the data now
  324. } else if( (typeof options.url == "string") && (options.url.length > 0) ){
  325. var extraParams = {
  326. timestamp: +new Date()
  327. };
  328. $.each(options.extraParams, function(key, param) {
  329. extraParams[key] = typeof param == "function" ? param() : param;
  330. });
  331. $.ajax({
  332. // try to leverage ajaxQueue plugin to abort previous requests
  333. mode: "abort",
  334. // limit abortion to this input
  335. port: "autocomplete" + input.name,
  336. dataType: options.dataType,
  337. url: options.url,
  338. data: $.extend({
  339. q: lastWord(term),
  340. limit: options.max
  341. }, extraParams),
  342. success: function(data) {
  343. var parsed = options.parse && options.parse(data) || parse(data);
  344. if(options.cacheData){
  345. cache.add(term, parsed);
  346. }
  347. success(term, parsed);
  348. }
  349. });
  350. } else {
  351. // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
  352. select.emptyList();
  353. failure(term);
  354. }
  355. };
  356. function parse(data) {
  357. var parsed = [];
  358. var rows = data.split("\n");
  359. for (var i=0; i < rows.length; i++) {
  360. var row = $.trim(rows[i]);
  361. if (row) {
  362. row = row.split("|");
  363. parsed[parsed.length] = {
  364. data: row,
  365. value: row[0],
  366. result: options.formatResult && options.formatResult(row, row[0]) || row[0]
  367. };
  368. }
  369. }
  370. return parsed;
  371. };
  372. function stopLoading() {
  373. $input.removeClass(options.loadingClass);
  374. };
  375. };
  376. $.Autocompleter.defaults = {
  377. inputClass: "ac_input",
  378. resultsClass: "ac_results",
  379. loadingClass: "ac_loading",
  380. minChars: 1,
  381. delay: 500,
  382. matchCase: true,
  383. matchSubset: true,
  384. matchContains: false,
  385. cacheLength: 10,
  386. max: 100,
  387. mustMatch: false,
  388. extraParams: {},
  389. selectFirst: true,
  390. formatItem: function(row) { return row[0]; },
  391. formatMatch: null,
  392. autoFill: false,
  393. width: 0,
  394. multiple: false,
  395. cacheData:false,
  396. multipleSeparator: ", ",
  397. highlight: function(value, term) {
  398. return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
  399. },
  400. scroll: true,
  401. scrollHeight: 180
  402. };
  403. $.Autocompleter.Cache = function(options) {
  404. var data = {};
  405. var length = 0;
  406. function matchSubset(s, sub) {
  407. if (!options.matchCase)
  408. s = s.toLowerCase();
  409. var i = s.indexOf(sub);
  410. if (i == -1) return false;
  411. return i == 0 || options.matchContains;
  412. };
  413. function add(q, value) {
  414. if (length > options.cacheLength){
  415. flush();
  416. }
  417. if (!data[q]){
  418. length++;
  419. }
  420. data[q] = value;
  421. }
  422. function populate(){
  423. if( !options.data ) return false;
  424. // track the matches
  425. var stMatchSets = {},
  426. nullData = 0;
  427. // no url was specified, we need to adjust the cache length to make sure it fits the local data store
  428. if( !options.url ) options.cacheLength = 1;
  429. // track all options for minChars = 0
  430. stMatchSets[""] = [];
  431. // loop through the array and create a lookup structure
  432. for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
  433. var rawValue = options.data[i];
  434. // if rawValue is a string, make an array otherwise just reference the array
  435. rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
  436. var value = options.formatMatch(rawValue, i+1, options.data.length);
  437. if ( value === false )
  438. continue;
  439. var firstChar = value.charAt(0).toLowerCase();
  440. // if no lookup array for this character exists, look it up now
  441. if( !stMatchSets[firstChar] )
  442. stMatchSets[firstChar] = [];
  443. // if the match is a string
  444. var row = {
  445. value: value,
  446. data: rawValue,
  447. result: options.formatResult && options.formatResult(rawValue) || value
  448. };
  449. // push the current match into the set list
  450. stMatchSets[firstChar].push(row);
  451. // keep track of minChars zero items
  452. if ( nullData++ < options.max ) {
  453. stMatchSets[""].push(row);
  454. }
  455. };
  456. // add the data items to the cache
  457. $.each(stMatchSets, function(i, value) {
  458. // increase the cache size
  459. options.cacheLength++;
  460. // add to the cache
  461. add(i, value);
  462. });
  463. }
  464. // populate any existing data
  465. setTimeout(populate, 25);
  466. function flush(){
  467. data = {};
  468. length = 0;
  469. }
  470. return {
  471. flush: flush,
  472. add: add,
  473. populate: populate,
  474. load: function(q) {
  475. if (!options.cacheLength || !length)
  476. return null;
  477. /*
  478. * if dealing w/local data and matchContains than we must make sure
  479. * to loop through all the data collections looking for matches
  480. */
  481. if( !options.url && options.matchContains ){
  482. // track all matches
  483. var csub = [];
  484. // loop through all the data grids for matches
  485. for( var k in data ){
  486. // don't search through the stMatchSets[""] (minChars: 0) cache
  487. // this prevents duplicates
  488. if( k.length > 0 ){
  489. var c = data[k];
  490. $.each(c, function(i, x) {
  491. // if we've got a match, add it to the array
  492. if (matchSubset(x.value, q)) {
  493. csub.push(x);
  494. }
  495. });
  496. }
  497. }
  498. return csub;
  499. } else
  500. // if the exact item exists, use it
  501. if (data[q]){
  502. return data[q];
  503. } else
  504. if (options.matchSubset) {
  505. for (var i = q.length - 1; i >= options.minChars; i--) {
  506. var c = data[q.substr(0, i)];
  507. if (c) {
  508. var csub = [];
  509. $.each(c, function(i, x) {
  510. if (matchSubset(x.value, q)) {
  511. csub[csub.length] = x;
  512. }
  513. });
  514. return csub;
  515. }
  516. }
  517. }
  518. return null;
  519. }
  520. };
  521. };
  522. $.Autocompleter.Select = function (options, input, select, config) {
  523. var CLASSES = {
  524. ACTIVE: "ac_over"
  525. };
  526. var listItems,
  527. more = false,
  528. active = -1,
  529. data,
  530. term = "",
  531. autoCompleteZIndex = 200,
  532. needsInit = true,
  533. element,
  534. lightbox,
  535. list;
  536. // Create results
  537. function init() {
  538. if (!needsInit)
  539. return;
  540. element = $("<div/>")
  541. .hide()
  542. .addClass(options.resultsClass)
  543. .css("position", "absolute")
  544. .appendTo(document.body);
  545. list = $("<ul>").appendTo(element).mouseover( function(event) {
  546. if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
  547. active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
  548. $(target(event)).addClass(CLASSES.ACTIVE);
  549. }
  550. }).click(function(event) {
  551. $(target(event)).addClass(CLASSES.ACTIVE);
  552. select();
  553. input.focus();
  554. return false;
  555. }).mousedown(function() {
  556. config.mouseDownOnSelect = true;
  557. }).mouseup(function() {
  558. config.mouseDownOnSelect = false;
  559. });
  560. //end
  561. if( options.width > 0 )
  562. element.css("width", options.width);
  563. needsInit = false;
  564. }
  565. function target(event) {
  566. var element = event.target;
  567. while(element && element.tagName != "LI")
  568. element = element.parentNode;
  569. // more fun with IE, sometimes event.target is empty, just ignore it then
  570. if(!element)
  571. return [];
  572. return element;
  573. }
  574. function moveSelect(step) {
  575. listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
  576. movePosition(step);
  577. var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
  578. if(options.scroll) {
  579. var offset = 0;
  580. listItems.slice(0, active).each(function() {
  581. offset += this.offsetHeight;
  582. });
  583. if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
  584. list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
  585. } else if(offset < list.scrollTop()) {
  586. list.scrollTop(offset);
  587. }
  588. }
  589. };
  590. function movePosition(step) {
  591. active += step;
  592. if (active < 0) {
  593. active = listItems.size() - 1;
  594. } else{
  595. //add by bin.gu 09-07-10
  596. if(more){
  597. if(active >= (listItems.size()-1)){
  598. active = 0;
  599. }
  600. }else{
  601. if(active >= listItems.size()){
  602. active = 0;
  603. }
  604. }
  605. }
  606. }
  607. function limitNumberOfItems(available) {
  608. return options.max && options.max < available
  609. ? options.max
  610. : available;
  611. }
  612. function initLightBox() {
  613. if (typeof(lightbox) == 'undefined') {
  614. var lightboxDiv = document.createElement("div");
  615. lightboxDiv.style.cssText = "position:absolute;left:0px;display:none;top:0px;width:100%;background:#dddddd;text-align:center;filter:Alpha(Opacity=50,Style=0);opacity:0.4";
  616. lightboxDiv.style.height = ((document.documentElement.clientHeight > document.documentElement.scrollHeight)
  617. ? document.documentElement.clientHeight
  618. : document.documentElement.scrollHeight)
  619. + "px";
  620. document.body.appendChild(lightboxDiv);
  621. lightbox = jQuery(lightboxDiv);
  622. lightbox.css('zIndex',(++autoCompleteZIndex));
  623. lightbox.bgiframe();
  624. }else{
  625. lightbox.css('zIndex',(++autoCompleteZIndex));
  626. }
  627. }
  628. function fillList() {
  629. list.empty();
  630. var max = limitNumberOfItems(data.length);
  631. for (var i=0; i < max; i++) {
  632. if (!data[i])
  633. continue;
  634. var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
  635. if ( formatted === false )
  636. continue;
  637. var li = $("<li>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_event" : "ac_odd").appendTo(list)[0];
  638. $.data(li, "ac_data", data[i]);
  639. }
  640. if(data.length>max){
  641. more = true;
  642. $("<li style='font-size:12px;color:#990000'>").html("数据未全部显示,请输入更多字符或汉字!").appendTo(list);
  643. }else{
  644. more = false;
  645. }
  646. listItems = list.find("li");
  647. if ( options.selectFirst ) {
  648. listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
  649. active = 0;
  650. }
  651. list.bgiframe();
  652. }
  653. return {
  654. display: function(d, q) {
  655. init();
  656. data = d;
  657. term = q;
  658. fillList();
  659. },
  660. next: function() {
  661. moveSelect(1);
  662. },
  663. prev: function() {
  664. moveSelect(-1);
  665. },
  666. noMsg:function(msg){
  667. init();
  668. list.html('<li style="font-size:12px;color:#990000;height:25;line-height:25px">'+msg+'</li>');
  669. listItems = list.find("li");
  670. more=true;
  671. list.bgiframe();
  672. },
  673. showLightbox : function() {
  674. lightbox.show();
  675. },
  676. hideLightbox:function(){
  677. lightbox&&lightbox.hide();
  678. },
  679. pageUp: function() {
  680. if (active != 0 && active - 8 < 0) {
  681. moveSelect( -active );
  682. } else {
  683. moveSelect(-8);
  684. }
  685. },
  686. pageDown: function() {
  687. if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
  688. moveSelect( listItems.size() - 1 - active );
  689. } else {
  690. moveSelect(8);
  691. }
  692. },
  693. hide: function() {
  694. lightbox&&lightbox.hide();
  695. element && element.hide();
  696. active = -1;
  697. },
  698. visible : function() {
  699. return element && element.is(":visible");
  700. },
  701. current: function() {
  702. return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
  703. },
  704. show: function() {
  705. initLightBox();
  706. lightbox.show();
  707. var offset = $(input).offset();
  708. var top = offset.top + input.offsetHeight;
  709. var scrollTop = document.documentElement.scrollTop;
  710. if(scrollTop > 0){
  711. if(xxdz){
  712. top = xxdz+input.offsetHeight-5;
  713. }
  714. }
  715. element.css({
  716. width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
  717. top: top,
  718. left: offset.left
  719. }).show();
  720. if(options.scroll) {
  721. list.scrollTop(0);
  722. list.css({
  723. maxHeight: options.scrollHeight,
  724. overflow: 'auto'
  725. });
  726. if ($.browser.msie
  727. && typeof document.body.style.maxHeight === "undefined") {
  728. var listHeight = 0;
  729. listItems.each(function() {
  730. listHeight += this.offsetHeight;
  731. });
  732. var scrollbarsVisible = listHeight > options.scrollHeight;
  733. list.css('height', scrollbarsVisible
  734. ? options.scrollHeight
  735. : listHeight);
  736. if (!scrollbarsVisible) {
  737. // IE doesn't recalculate width when scrollbar
  738. // disappears
  739. listItems.width(list.width()
  740. - parseInt(listItems.css("padding-left"))
  741. - parseInt(listItems.css("padding-right")));
  742. }
  743. }
  744. }
  745. // 当下拉列表超出浏览器页面时,设置top add by bin.gu 09-05-21 start
  746. var browserWidth = window.innerWidth || document.documentElement.clientWidth ||
  747. document.body.clientWidth;
  748. var browserHeight = window.innerHeight || document.documentElement.clientHeight ||
  749. document.body.clientHeight;
  750. var scrollX = (document.documentElement.scrollLeft || document.body.scrollLeft);
  751. var scrollY = (document.documentElement.scrollTop || document.body.scrollTop);
  752. var elementHeight = element.height()>options.scrollHeight?options.scrollHeight:element.height();
  753. if ((element.offset().top + elementHeight -
  754. ($.browser.msie ? document.documentElement.scrollTop : 0)) >
  755. (browserHeight + scrollY) ) {
  756. element.css('top', (offset.top-elementHeight)+ 'px');
  757. }
  758. //end
  759. },
  760. selected: function() {
  761. var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
  762. return selected && selected.length && $.data(selected[0], "ac_data");
  763. },
  764. emptyList: function (){
  765. list && list.empty();
  766. },
  767. unbind: function() {
  768. element && element.remove();
  769. }
  770. };
  771. };
  772. $.Autocompleter.Selection = function(field, start, end) {
  773. if( field.createTextRange ){
  774. var selRange = field.createTextRange();
  775. selRange.collapse(true);
  776. selRange.moveStart("character", start);
  777. selRange.moveEnd("character", end);
  778. selRange.select();
  779. } else if( field.setSelectionRange ){
  780. field.setSelectionRange(start, end);
  781. } else {
  782. if( field.selectionStart ){
  783. field.selectionStart = start;
  784. field.selectionEnd = end;
  785. }
  786. }
  787. field.focus();
  788. };
  789. })(jQuery);