script.aculo.usを読み解く

第2回 controls.js(前編)Autocompleter

この記事を読むのに必要な時間:およそ 18.5 分

0314: getToken: function() {
0315:   var bounds = this.getTokenBounds();
0316:   return this.element.value.substring(bounds[0], bounds[1]).strip();
0317: },
0318:

314~318行目のgetTokenは,トークン範囲を計算し,そこからトークンを切り出して返します。

0319: getTokenBounds: function() {
0320:   if (null != this.tokenBounds) return this.tokenBounds;
0321:   var value = this.element.value;
0322:   if (value.strip().empty()) return [-1, 0];
0323:   var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue);
0324:   var offset = (diff == this.oldElementValue.length ? 1 : 0);
0325:   var prevTokenPos = -1, nextTokenPos = value.length;
0326:   var tp;
0327:   for (var index = 0, l = this.options.tokens.length; index < l; ++index) {
0328:     tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1);
0329:     if (tp > prevTokenPos) prevTokenPos = tp;
0330:     tp = value.indexOf(this.options.tokens[index], diff + offset);
0331:     if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp;
0332:   }
0333:   return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]);
0334:}
0335:});
0336:

319~336行目のgetTokenBoundsを見ていきましょう。これは,キャレットの位置をおおまかに求めて,切り出すべきトークンの範囲を返す関数です。

返り値は[a,b]の形で,aはトークンの範囲の始点,bはその終点を表す整数です。入力エリアの内容が空かスペースだけのときはただちに[-1,0]を返します。

options.tokensは,トークンの区切り文字が入っている配列です。デフォルトでは'\n'が入っています。

320行目では,次のようになっていて,無駄な処理を省くようになっています。

if (前回の結果を消さずにこの関数を呼び出した場合) return 前回の内容;

322行目では,次のようになっています。

if (入力エリアの内容が空かスペースだけの場合) return [-1,0];

323行目では,getFirstDifferencePosで,以前の内容と,現在の内容を見比べて,内容が変わりはじめた位置を求めています。

324~332行目では,トークンの区切り文字を全て試して,区切りの幅がもっとも短くなるように範囲を計算しています。

0337:  Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) {
0338:   var boundary = Math.min(newS.length, oldS.length);
0339:   for (var index = 0; index < boundary; ++index)
0340:     if (newS[index] != oldS[index])
0341:       return index;
0342:     return boundary;
0343:  };
0344:

337~344行目のgetFirstDifferencePosは,以前の内容と,現在の内容を見比べて,内容が変わりはじめた位置を返します。

以上でAutocompleter.Baseは終わりです。次に,Ajaxでサーバに候補を問い合わせるAjax.Autocompleterについて解説します。

Ajax.Autocompleter


0345: Ajax.Autocompleter = Class.create(Autocompleter.Base, {
0346:   initialize: function(element, update, url, options) {
0347:     this.baseInitialize(element, update, options);
0348:     this.options.asynchronous  = true;
0349:     this.options.onComplete    = this.onComplete.bind(this);
0350:     this.options.defaultParams = this.options.parameters || null;
0351:     this.url                   = url;
0352:   },
0353:

345~353行目は,initializeで,通常の初期化のほか,Ajax.Autocompleter特有のオプションを追加します。

348行目のoptions.asynchronousは,Ajaxを非同期で行うオプションです。

349行目のoptions.onCompleteは,Ajaxの完了時にコールバックする関数のオプションです。

350行目のoptions.defaultParamsは,追加するクエリパラメータのオプションです。

351行目のurlは,問い合わせるサーバのURLです。

0354: getUpdatedChoices: function() {
0355:   this.startIndicator();
0356:   
0357:   var entry = encodeURIComponent(this.options.paramName) + '=' + 
0358:     encodeURIComponent(this.getToken());
0359:  
0360:   this.options.parameters = this.options.callback ?
0361:     this.options.callback(this.element, entry) : entry;
0362:  
0363:   if(this.options.defaultParams) 
0364:     this.options.parameters += '&' + this.options.defaultParams;
0365:   
0366:   new Ajax.Request(this.url, this.options);
0367: },
0368:

354~368行目のgetUpdatedChoicesは,トークンを得て,Ajaxでサーバに候補を問い合わせる関数です。

355行目でインジケータを表示し,
357行目でAjaxクエリパラメータを,まずはparamName=fooと作ります。

360行目でライブラリの利用者がクエリパラメータを自由に編集できるように,options.callbackに入力エリアとクエリパラメータを渡しています。

364行目でクエリパラメータにdefaultParamsをさらに追加します。

366行目でAjaxで候補を問い合わせます。

0369: onComplete: function(request) {
0370:   this.updateChoices(request.responseText);
0371: }
0372: });
0373:

369~373行目のonCompleteは,Ajaxの完了時にサーバからの返答を処理する関数です。

Autocompleter.Local

0374: // The local array autocompleter. Used when you'd prefer to
0375: // inject an array of autocompletion options into the page, rather
0376: // than sending out Ajax queries, which can be quite slow sometimes.
0377: //
0378: // The constructor takes four parameters. The first two are, as usual,
0379: // the id of the monitored textbox, and id of the autocompletion menu.
0380: // The third is the array you want to autocomplete from, and the fourth
0381: // is the options block.
0382: //
0383: // Extra local autocompletion options:
0384: // - choices - How many autocompletion choices to offer
0385: //
0386: // - partialSearch - If false, the autocompleter will match entered
0387: //                    text only at the beginning of strings in the 
0388: //                    autocomplete array. Defaults to true, which will
0389: //                    match text at the beginning of any *word* in the
0390: //                    strings in the autocomplete array. If you want to
0391: //                    search anywhere in the string, additionally set
0392: //                    the option fullSearch to true (default: off).
0393: //
0394: // - fullSsearch - Search anywhere in autocomplete array strings.
0395: //
0396: // - partialChars - How many characters to enter before triggering
0397: //                   a partial match (unlike minChars, which defines
0398: //                   how many characters are required to do any match
0399: //                   at all). Defaults to 2.
0400: //
0401: // - ignoreCase - Whether to ignore case when autocompleting.
0402: //                 Defaults to true.
0403: //
0404: // It's possible to pass in a custom function as the 'selector' 
0405: // option, if you prefer to write your own autocompletion logic.
0406: // In that case, the other options above will not apply unless
0407: // you support them.

このコメント文を日本語に訳すと以下のとおりです。

ローカルな配列の入力補完。補完したい語の配列をページに埋め込むことで,いちいちサーバにAjaxで問い合わせずに済むようになります(Ajaxは場合によっては,かなり遅いことがあるからです⁠⁠。 コンストラクタは4つの引数をとります。最初の2つは,いつもどおり,監視するテキストボックスのidと,候補メニューを表示するメニューのidです。3番めは,補完したい語の配列,4番めは,オプションです。

ローカル入力補完に特有のオプション:

- choices -
候補をいくつまで示すか。
- partialSearch -
もしfalseなら,語の配列にある文字列の中で,入力されたテキストと前方一致するものだけが,候補になります。デフォルトではtrueで,この場合,配列の語の文字列について,文字列中の単語ごとに前方一致が探されます。もし,文字列の全体について探したければ,さらにfullSearchオプションをtrueにしてください(デフォルトではoff⁠⁠。
- fullSearch -
配列の語の文字列の全体を検索します。
- partialChars -
単語別一致検索が動くのに必要な入力の文字数(minCharsと違って,検索の方法に関わらず何文字必要かです⁠⁠。デフォルトは2。
- ignoreCase -
大文字小文字を無視して補完するかどうか。デフォルトはtrue。
カスタマイズした関数を'selector'オプションに渡すことで,自前の補完ロジックを使うこともできます。 その場合は,上記のオプションは扱われません(あなたがサポートすれば別ですが)。

著者プロフィール

源馬照明(げんまてるあき)

名古屋大学大学院多元数理科学研究科1年。学部生のときにSchemeの素晴らしさを知ったのをきっかけに,関数型言語の世界へ。JavaScriptに,ブラウザからすぐに試せる関数型言語としての魅力と将来性を感じている。

ブログ:Gemmaの日記