PageSourceSearch

https://opac.nijl.ac.jp/media/js_c/jquery.ajaxSuggest.1.5.4.js

js nijl.ac.jp collected 2026-09-24 08:51:45 UTC 16,894 bytes, 512 lines download raw bytes

1/*
2Infomation
3==========================================================================================
4jQuery Plugin
5	Name       : jquery.ajaxSuggest
6	Version    : 1.5.4
7	Update     : 2012-02-10
8	Author     : sutara_lumpur
9	Author-URI : http://d.hatena.ne.jp/sutara_lumpur/20100718/1279420832
10	License    : MIT License (http://www.opensource.org/licenses/mit-license.php)
11	Based-on   : Uses code and techniques from following libraries...
12		* jquery.suggest 1.1
13			Author     : Peter Vulgaris
14			Author-URI : http://www.vulgarisoip.com/
15==========================================================================================
16
17Contents
18==========================================================================================
19	01. 変数・部品の定義
20	02. イベントハンドラ
21	03. Suggest用メソッド - 未分類
22	04. Suggest用メソッド - Ajax関連
23	05. Suggest用メソッド - 候補リスト関連
24	06. 処理の始まり
25==========================================================================================
26*/
27(function($) {
28	$.ajaxSuggest = function(input_obj, source, options) {
29
30		//Ajaxにおけるキャッシュを無効にする
31		$.ajaxSetup({cache: false});
32
33		//================================================================================
34		// 01. 変数・部品の定義
35		//--------------------------------------------------------------------------------
36		//**********************************************
37		//変数の初期化
38		//**********************************************
39		var show_hide        = false; //候補を、タイマー処理で表示するかどうかの予約
40		var timer_show_hide  = false; //タイマー。フォーカスが外れた後、候補を非表示にするか
41		var timer_val_change = false; //タイマー変数(一定時間ごとに入力値の変化を監視)
42		var reserve_click    = false; //マウスのキーを押し続ける操作に対応するためmousedownを検知
43		var $xhr             = false; //XMLHttpオブジェクトを格納
44		var prev_value       = '';    //Suggestの、以前の値
45		var user_value       = '';    //ユーザが入力したもともとの値
46		var is_select        = false; //キー入力ではなく、候補選択で$input_objの値が変わったか?
47		var key_select       = false; //キーで候補移動したか??
48
49		//**********************************************
50		//部品の定義
51		//**********************************************
52		$(input_obj).attr('autocomplete','off');
53		$(input_obj).addClass('suggestEnabled');
54
55		var $results = $('<ul></ul>')
56			.addClass(options.results_class)
57			.appendTo('body');
58
59		//================================================================================
60		// 02. イベントハンドラ
61		//--------------------------------------------------------------------------------
62		//**********************************************
63		//テキスト入力エリア
64		//**********************************************
65		//前処理(クロスブラウザ用)
66		if(window.opera){
67			//Opera用
68			$(input_obj).keypress(processKey);
69			$(input_obj).keydown(processKey);
70		}else{
71			//その他用
72			$(input_obj).keydown(processKey);
73		}
74
75
76		//$(input_obj).focus(function() {
77		//	show_hide = true;
78		//	checkValChange();
79		//});
80		$(input_obj).blur(function(ev) {
81			//入力値の監視を中止
82			clearTimeout(timer_val_change);
83
84			//候補消去を予約
85			show_hide = false;
86
87			//消去予約タイマーをセット
88			checkShowHide();
89		});
90		$(input_obj).mousedown(function(ev) {
91			reserve_click = true;
92
93			//消去予約タイマーを中止
94			clearTimeout(timer_show_hide);
95
96			ev.stopPropagation();
97		});
98		$(input_obj).mouseup(function(ev) {
99			$(input_obj).focus();
100			reserve_click = false;
101			ev.stopPropagation();
102		});
103
104		//**********************************************
105		//body全体
106		//**********************************************
107		$('body').mouseup(function() {
108			//消去予約タイマーを中止
109			clearTimeout(timer_show_hide);
110
111			//候補を消去する
112			show_hide = false;
113			hideResult();
114		});
115
116		//================================================================================
117		// 03. Suggest用メソッド - 未分類
118		//--------------------------------------------------------------------------------
119		//**********************************************
120		//タイマーによる入力値変化監視
121		//**********************************************
122		function checkValChange() {
123			timer_val_change = setTimeout(isChange,500);
124
125			function isChange() {
126				var now_value = $(input_obj).val();
127				if(!now_value){
128					hideResult();
129				}else if(now_value != prev_value && !is_select) {
130					if ($(input_obj).hasClass("suggestEnabled") && $('.as_results').size() > 0) {
131						suggest();
132					}
133				}
134				is_select = false;
135				prev_value = now_value;
136
137				//ユーザがもともと入力していた値を格納
138				if(!getCurrentResult()) user_value = $(input_obj).val();
139
140				//一定時間ごとの監視を再開
141				checkValChange();
142			}
143		}
144
145		//**********************************************
146		//候補の消去を本当に実行するか判断
147		//**********************************************
148		function checkShowHide() {
149			timer_show_hide = setTimeout(function() {
150				if (show_hide == false && reserve_click == false){
151					hideResult();
152				}
153			},500);
154		}
155
156		//**********************************************
157		//キー入力への対応
158		//**********************************************
159		function processKey(e) {
160			if (
161				(/27$|38$|40$|^9$/.test(e.keyCode) && $results.is(':visible')) ||
162				(/^13$|^9$/.test(e.keyCode) && getCurrentResult())
163			) {
164				if (e.preventDefault)  e.preventDefault();
165				if (e.stopPropagation) e.stopPropagation();
166
167				e.cancelBubble = true;
168				e.returnValue  = false;
169
170				switch(e.keyCode) {
171					case 38: // up
172						key_select = true;
173						prevResult();
174						break;
175
176					case 40: // down
177						key_select = true;
178						nextResult();
179						break;
180
181					case 9:  // tab
182						hideResult();
183						break;
184
185					case 13: // return
186						selectCurrentResult(true);
187						break;
188
189					case 27: //	escape
190						hideResult();
191						break;
192				}
193			} else {
194				checkValChange();
195			}
196		}
197
198		//================================================================================
199		// 04. Suggest用メソッド - Ajax関連
200		//--------------------------------------------------------------------------------
201		//**********************************************
202		//Ajaxの中断
203		//**********************************************
204		function abortAjax() {
205			if ($xhr){
206				$xhr.abort();
207				$xhr = false;
208			}
209		}
210
211		//**********************************************
212		//Ajax通信
213		//**********************************************
214		function suggest(){
215			if($(input_obj).val().search(/^[  \n\r\t]*$/) > -1) return;
216
217			//Ajax通信をキャンセル
218			abortAjax();
219
220			//ここでAjax通信を行っている
221			$xhr = $.getJSON(
222				options.source,
223				{
224					'q_word'   : $(input_obj).val(),
225					'database' : options.database,
226					'sub_info' : options.sub_info,
227					'and_or'   : options.and_or,
228					'limit'    : options.limit,
229					'order_by' : options.order_by
230				},
231				function(json_data){
232					if(!json_data || json_data.length < 1){
233						hideResult();
234					}else{
235						displayItems(json_data);
236					}
237				}
238			);
239		}
240
241		//================================================================================
242		// 05. Suggest用メソッド - 候補リスト関連
243		//--------------------------------------------------------------------------------
244		//**********************************************
245		//候補一覧の<ul>成形、表示
246		//**********************************************
247		// @params array arr_candidate   DBから検索・取得した値の配列
248		//
249		//arr_candidateそれぞれの値を<li>で囲んで表示。
250		//同時に、イベントハンドラを記述。
251		function displayItems(arr_candidate) {
252
253			//候補リストを、一旦リセット
254			$results.empty();
255
256			for (var i = 0; i < arr_candidate.length; i++) {
257				//候補リスト
258				if(options.sub_info !== false){
259					//var $li = $('<li>' + arr_candidate[i][0] + '</li>'); $$$
260					//サブ情報を格納する独自の属性"sub_info"を設定
261					//$li.attr('sub_info',arr_candidate[i][1]);
262					var $li = $('<li>')
263						.text(arr_candidate[i][0])
264						.attr('sub_info', arr_candidate[i][1]);
265				}else{
266					var $li = $('<li>' + arr_candidate[i] + '</li>');
267					$li.text($li.html());
268					//下記のように、一度にHTMLエンティティ化すると、なぜかå¤
268±æ•—する…。
269					//var $li = $('<li>').text(arr_candidate[i]);
270				}
271				$li.css("padding-left", $(input_obj).css("padding-left"));
272				$results.append($li);
273			}
274			//----------------------------------------------
275			//候補リストの位置を指定
276			//----------------------------------------------
277			var offset = $(input_obj).offset();
278
279			offset.top +=
280				$(input_obj).height() +
281				parseInt($(input_obj).css('border-top-width'), 10) +
282				parseInt($(input_obj).css('padding-top'), 10) +
283				parseInt($(input_obj).css('padding-bottom'), 10);
284			if(typeof window.addEventListener == "undefined" && typeof document.getElementsByClassName == "undefined"){
285				//IEは相対座標でoffsetを取得する。
286				//そのため、画面スクロール分を足し合わせる必要がある。
287				offset.top += parseInt($results.scrollTop(), 10);
288			}
289
290			offset.left += parseInt($(input_obj).css('padding-left'), 10);
291			if((typeof window.addEventListener == "undefined" && typeof document.getElementsByClassName == "undefined") || window.opera){
292				offset.left -= parseInt($(input_obj).css('border-left-width'), 10);
293			}
294
295			//画面に表示
296			$results
297				.show()
298				.css({'top':offset.top, 'left':offset.left - parseInt($(input_obj).css('padding-left'), 10)})
299				.width(
300					$(input_obj).width() +
301					parseInt($(input_obj).css('padding-left'), 10) +
302					parseInt($(input_obj).css('padding-right'), 10) -
303					(parseInt($(input_obj).css("border-left-width"), 10) * 2)
304				);
305
306			$results
307				.children('li')
308				.mouseover(function() {
309
310					//Firefoxでは、候補一覧の上にマウスカーソルが乗っていると
311					//うまくスクロールしない。そのための対策。イベント中断。
312					if (key_select) {
313						key_select = false;
314						return;
315					}
316
317					$results.children('li').removeClass(options.select_class);
318					$(this).addClass(options.select_class);
319					setSubInfo(this); //サブ情報
320
321				})
322				.mousedown(function(e) {
323					reserve_click = true;
324
325					//消去予約タイマーを中止
326					clearTimeout(timer_show_hide);
327					//ev.stopPropagation();
328				})
329				.mouseup(function(e) {
330					reserve_click = false;
331
332					//Firefoxでは、候補一覧の上にマウスカーソルが乗っていると
333					//うまくスクロールしない。そのための対策。イベント中断。
334					if (key_select) {
335						key_select = false;
336						return;
337					}
338					e.preventDefault();
339					e.stopPropagation();
340					selectCurrentResult(false);
341				});
342		}
343
344		//**********************************************
345		//現在選択中の候補を取得
346		//**********************************************
347		// @return object current_result 現在選択中の候補のオブジェクト(<li>要素)
348		function getCurrentResult() {
349
350			if (!$results.is(':visible')) return false;
351
352			var $current_result = $results.children('li.' + options.select_class);
353
354			if (!$current_result.length) $current_result = false;
355
356			return $current_result;
357		}
358		//**********************************************
359		//現在選択中の候補に決定する
360		//**********************************************
361		function selectCurrentResult(type) {
362
363			var $current_result = getCurrentResult();
364			if ($current_result) {
365				$(input_obj).val($current_result.text());
366				hideResult();
367
368				//added
369				prev_value = $(input_obj).val();
370			}
371			$(input_obj).focus();  //テキストボックスにフォーカスを移す
372			 //候補選択を引き金に、イベントを発火する
373			if(options.bind_to) $(input_obj).trigger(options.bind_to, type);
374		}
375		//**********************************************
376		//選択候補を次に移す
377		//**********************************************
378		function nextResult() {
379			var $current_result = getCurrentResult();
380
381			if ($current_result) {
382				$current_result
383					.removeClass(options.select_class)
384					.next()
385						.addClass(options.select_class);
386			}else{
387				$results.children('li:first-child').addClass(options.select_class);
388			}
389			//テキストボックスの値を変更
390			//候補リストからボックスへ戻るなら、元々の値を表示
391			is_select = true;
392			if($current_result && $current_result.is('li:last-child')){
393				$(input_obj).val(user_value);
394				if(options.sub_info !== false) $sub_info.hide();
395			}else{
396				var $selected = $results.children('.'+options.select_class);
397				$(input_obj).val($selected.text());
398				setSubInfo($selected); //サブ情報
399			}
400		}
401		//**********************************************
402		//選択候補を前に移す
403		//**********************************************
404		function prevResult() {
405			var $current_result = getCurrentResult();
406
407			if ($current_result) {
408				$current_result
409					.removeClass(options.select_class)
410					.prev()
411						.addClass(options.select_class);
412			}else{
413				$results.children('li:last-child').addClass(options.select_class);
414			}
415			//テキストボックスの値を変更
416			//候補リストからボックスへ戻るなら、元々の値を表示
417			is_select = true;
418			if($current_result && $current_result.is('li:first-child')){
419				$(input_obj).val(user_value);
420				if(options.sub_info !== false) $sub_info.hide();
421			}else{
422				var $selected = $results.children('.'+options.select_class);
423				$(input_obj).val($selected.text());
424				setSubInfo($selected); //サブ情報
425			}
426		}
427		//**********************************************
428		//候補エリアを消去
429		//**********************************************
430		function hideResult() {
431				$results.hide();
432				if(options.sub_info !== false) $sub_info.hide();
433
434				//Ajax通信をキャンセル
435				abortAjax();
436		}
437
438		//================================================================================
439		// 09. ComboBox用メソッド - サブ情報関連
440		//--------------------------------------------------------------------------------
441		var $sub_info = $('<div class="sub_info"></div>')
442			.hide()
443			.appendTo('body');
444
445		//**********************************************
446		//サブ情報の位置設定
447		//**********************************************
448		function setSubInfo(obj){
449			if(options.sub_info === false) return;
450			var offset = $(obj).offset();
451			$sub_info
452				.css({
453					'top'  : offset.top + 'px',
454					'left' : offset.left + $results.width() + 'px'
455				});
456			var html   = $(obj).attr('sub_info');
457			//最終的に、サブ情報が空なら表示しない
458			if(html == ''){
459				$sub_info.text(html).hide();
460			}else{
461				$sub_info.text(html).show();
462			}
463		}
464		//**********************************************
465		//サブ情報のイベントハンドラ
466		//**********************************************
467		$sub_info.mousedown(function(ev) {
468			reserve_click = true;
469
470			//消去予約タイマーを中止
471			clearTimeout(timer_show_hide);
472			ev.stopPropagation();
473		});
474		$sub_info.mouseup(function(ev) {
475			reserve_click = false;
476
477			//消去予約タイマーを中止
478			clearTimeout(timer_show_hide);
479			ev.stopPropagation();
480		});
481
482	};
483
484	//================================================================================
485	// 06. 処理の始まり
486	//--------------------------------------------------------------------------------
487	$.fn.ajaxSuggest = function(source, options) {
488		if (!source) return;
489
490		//************************************************************
491		//オプション
492		//************************************************************
493		options = $.extend({
494			//基本設定
495			source   : source,
496			database : 0,      //接続するDBの設定(配列の番号)
497			and_or   : 'AND',  //AND検索か、OR検索か?
498			limit    : 10,     //候補リストとして表示する最大件数
499			order_by : 'ASC',  //ORDER BY(SQL) で、並ベ替えるのは昇順か降順か
500			bind_to  : false,  //候補が選択されたときに発火するイベント名
501			sub_info : false,  //サブ情報を表示するか?どのフィールドを?
502			results_class : 'as_results', //候補一覧を囲む<ul>
503			select_class  : 'as_over'     //選択中の<li>
504		}, options);
505		this.each(function() {
506			if (!$(this).hasClass("suggestEnabled")) {
507				new $.ajaxSuggest(this, source, options);
508			}
509		});
510		return this;
511	};
512})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.