PageSourceSearch

https://staatstheater-hannover.de/module/jscript/lib/jquery_plugins/autocomplete2/mod.autocomplete.js

js staatstheater-hannover.de collected 2026-09-24 09:42:10 UTC 20,205 bytes, 544 lines download raw bytes

1/* This file is part of cbautocomplete2.
2 * Copyright © 2010-2013 stiftung kulturserver.de ggmbh <[email protected]>
3 *
4 * cbui is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * cbui is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with cbui.  If not, see <http://www.gnu.org/licenses/>.
16 */
17
18/**
19 * jQuery .autoComplete()
20 *
21 * Transforms an <input/> into an autoComplete box
22 * TODOs
23 * 1) scroll when using arrow keys and marked element is not visible
24 * 2) fix ie6 style issues
25 *
26 * @Author Andre Mohren
27 */
28jQuery.fn.autoComplete = function(params) {
29
30   /**
31    * Predefined parameters with their default value
32    */
33   var options = {
34      /**
35       * How long has the entered string to be before we start to search?
36       */
37      'minimumKeys':   '2',
38      /**
39       * How long to wait after pressing a key for start searching?
40       */
41      'waitTime':      '1000',
42      /**
43       * Is the <inpout/> value already validated at loading time?
44       */
45      'validated':     false,
46       /**
47        *Is the initial <inpout/> value already validated at loading time?
48        */
49       initValidated : false,
50      /**
51       * Which url will be called to get out completion data?
52       */
53      'requestUrl':    '/module/jscript/lib/jquery_plugins/autocomplete2/exampleAjax.php',
54      /**
55       * Should we close the box and reset the <input/> when its losing focus?
56       */
57      'closeWhenBlur': true,
58      /**
59       * Name of the search-param which will be send as _GET to PHP.
60       */
61      'requestParam':  'actualInput',
62      /**
63       * Are not validated values allowed?
64       */
65      'allowFreetext':  false,
66      /**
67       * Where do we put the selected id?
68       */
69      'putIdInto': '',
70      /**
71       * Custom callback for click?
72       */
73      'customCallback': false,
74      /**
75       * Custom callback final for click?
76       */
77      'customCallbackFinal': false,
78      /**
79       * Header
80       */
81      'header': false,
82      /**
83       * Footer
84       */
85      'footer': false,
86      /**
87       * Free text entry in footer
88       */
89      'footerFreetext' : false,
90      /**
91       * Description line in case of free text entry in footer
92       */
93      'footerMissingText' : '',
94      /**
95       * Info line in case of free text entry in footer
96       */
97      'footerInfoText' : '',
98      /**
99       * Text to display when there's no results
100       */
101      'noResultsText' : '',
102      /**
103       * Text for the button that is going to be placed in the footer
104       */
105      'button' : false,
106      /**
107       * Provide a callback for buttonb click
108       */
109      'onButtonClick' : false,
110      /**
111       * Trap "enter" keypress to avoid submitting forms?
112       */
113      'trapEnter': false,
114      /**
115       * Provide a callback for showbox
116       */
117      'onShow' : false,
118      /**
119       * is some other value for filtering required, store to extraParams dynamical
120       */
121      'dynamicFilterValue': {
122         'urlAddon': '',
123         'valueFrom': ''
124      }
125   };
126
127   /*
128    * All other parameters are passed on as extra request parameters
129    */
130   var extra = {};
131   for(var param in params) {
132      if (options[param] != undefined) {
133         options[param] = params[param];
134      } else {
135         extra[param] = params[param];
136      }
137   }
138   options.extraParams = extra;
139
140   jQuery(this).each(function() {
141      //ToDo: save old blur function for later useage
142      jQuery(this).unbind('blur');
143      //ToDo: bind only <input/>
144      //ToDo: compare parameters with old box
145      //ToDo: icon not over border
146      //ToDo: scroll when using key-selecting
147
148      /**
149       * Our <input/>
150       */
151      var element = this;
152      /**
153       * Used for saving the timeout
154       */
155      var timeout = '';
156      /**
157       * HTML Code for the box
158       */
159      var box = jQuery('<div class="__AC_position"><div class="__AC_close"></div><div class="__AC_layer"></div></div>');
160      var validatingBox = jQuery('<div class="__AC_position"><div class="__AC_layer __AC_validating"></div></div>');
161
162      /**
163       * The default value of the box
164       */
165      var def = jQuery(element).val();
166      /**
167       * Used for temporary saving what we have typed into the box
168       */
169      var typed = '';
170      /**
171       * Is the box open at the moment?
172       */
173      var boxShown = false;
174      /**
175       * Do we mouseover an entry at the moment?
176       */
177      var hoverEntry = false;
178      /**
179       * The default state of the box
180       */
181      var isValidated = options['validated'];
182	  /**
183       * The proofed default state of the box
184       */
185	  var initValidated = options['initValidated'];
186      /**
187       * Has the box focus?
188       */
189      var hasFocus = false;
190      /**
191       * Is our last saved value freetext?
192       */
193      var isFreetext = false;
194      /**
195       * The original value
196       */
197      var originalVal = jQuery(element).val();
198
199      /**
200       * Display the validated state
201       */
202      var validated = function() {
203         jQuery(element).removeClass('__AC_invalidated __AC_validating __AC_editing __AC_freetext')
204            .addClass('__AC_validated');
205         validatingBox.remove();
206      };
207
208      /**
209       * Display the invalidated state
210       */
211      var invalidated = function() {
212         jQuery(element).removeClass('__AC_validated __AC_validating __AC_editing __AC_freetext')
213            .addClass('__AC_invalidated');
214         validatingBox.remove();
215      };
216
217      /**
218       * Display the working state
219       */
220      var validating = function() {
221         jQuery(element).removeClass('__AC_validated __AC_invalidated __AC_editing __AC_freetext')
222            .addClass('__AC_validating');
223         validatingBox.remove();
224      };
225
226      /**
227       * Display the editing state
228       */
229      var editing = function() {
230         jQuery(element).removeClass('__AC_validated __AC_invalidated __AC_validating __AC_freetext')
231            .addClass('__AC_editing');
232
233         jQuery(element).one('keypress', function(e) {
234            if (!boxShown && e.which != 13 && e.which != 27) {
235               showValidatingBox();
236            }
237         });
238      };
239
240      /**
241       * Display the freetext state
242       */
243      var freetext = function() {
244         jQuery(element).removeClass('__AC_validated __AC_invalidated __AC_validating __AC_editing')
245            .addClass('__AC_freetext');
246         validatingBox.remove();
247      };
248
249      var selectEntry = function() {
250	      var val = jQuery(this).attr('data-ac-value');
251         jQuery(element).val(val);
252         validated();
253         hideBox();
254         hoverEntry = false;
255         typed = def = val;
256         isFreetext = false;
257         if (options['putIdInto'] != "") {
258            jQuery(options['putIdInto']).val(jQuery(this).attr('id')).change();
259         }
260         if (options['customCallbackFinal']) {
261            options['customCallbackFinal']({
262               'Element': jQuery(element),
263               'Id' : jQuery(this).attr('id'),
264               'Title' : val
265            });
266         }
267      };
268
269      /**
270       * Show box
271       */
272      var showBox = function() {
273         if (hasFocus || !options['closeWhenBlur']) {
274            validating();
275            boxShown = true;
276            options.extraParams[options.requestParam] = typed;
277
278            // get extraParams dynamical
279            if (options['dynamicFilterValue']['urlAddon'] != '' && options['dynamicFilterValue']['valueFrom'] != '') {
280               options.extraParams[options['dynamicFilterValue']['urlAddon']] = jQuery('#' + options['dynamicFilterValue']['valueFrom']).val();
281            }
282
283            jQuery.getJSON(
284               options['requestUrl'],
285               options.extraParams,
286               function(JSONdata) {
287                  if (hasFocus || !options['closeWhenBlur']) {
288
289                     /* handle deprecated format: {data : [{ results : [...] }] */
290                     if (JSONdata.data != undefined && JSONdata.results == undefined && JSONdata.data[0]) JSONdata = JSONdata.data[0];
291
292                     box.find('.__AC_layer').html('<div class="__AC_data"></div>');
293                     box.find('.__AC_close').click(function() {
294                        hoverEntry = false;
295                        jQuery(element).val('').blur();
296                     }).hover(function() {
297                           hoverEntry = true;
298                        }, function() {
299                           hoverEntry = false;
300                        }
301                     );
302                     if (JSONdata['header'] != undefined) {
303                        box.find('.__AC_layer').prepend(JSONdata['header']);
304                     } else if (options['header']) {
305                        box.find('.__AC_layer').prepend(jQuery(options['header']).clone(true));
306                     }
307                     if (JSONdata['results'] != undefined) {
308                        var position = box.find('.__AC_data');
309                        if (JSONdata['results'].length > 0) {
310                           for (var record in JSONdata['results']) {
311                              var callback = selectEntry;
312                              if (typeof(JSONdata['results'][record]['customCallback']) !== 'undefined') {
313                                 callback = JSONdata['results'][record]['customCallback'];
314                              } else if (options['customCallback']) {
315                                 callback = options['customCallback'];
316                              }
317
318                              jQuery('<div class="__AC_record" ' +
319	                                    'title="' +JSONdata['results'][record]['value'] + ' | ' +JSONdata['results'][record]['id']+ '" ' +
320	                                    'id="' +JSONdata['results'][record]['id'] + '" ' +
321	                                    'data-ac-value="' +JSONdata['results'][record]['value'] + '">' +
322                                       JSONdata['results'][record]['info'] + '</div>')
323                                    .appendTo(position).click(callback).hover(function() {
324                                 jQuery(this).addClass('__AC_ie8HoverFix');
325                                 hoverEntry = true;
326                                 jQuery('.__AC_keyhover').removeClass('__AC_keyhover');
327                                 isFreetext = false;
328                              }, function() {
329                                 jQuery(this).removeClass('__AC_ie8HoverFix');
330                                 hoverEntry = false;
331                              });
332                           }
333                        } else {
334                           box.find('.__AC_layer').append('<div>' + options['noResultsText'] + '</div>');
335                        }
336                     } else {
337                           box.find('.__AC_layer').append('<div>' + options['noResultsText'] + '</div>');
338                        }
339
340                     var footerFreetext = options['footerFreetext'] || JSONdata['footerFreetext'];
341                     var footerMissingText = options['footerMissingText'] || JSONdata['footerMissingText'];
342                     var footerInfoText = options['footerInfoText'] || JSONdata['footerInfoText'];
343                     if (JSONdata['footer'] != undefined) {
344                        box.find('.__AC_layer').append(JSONdata['footer']);
345                     } else if (options['footer']) {
346                        box.find('.__AC_layer').append(jQuery(options['footer']).clone(true));
347                     } else if (footerFreetext) {
348                        box.find('.__AC_layer').append(jQuery('<div class="__AC_button">' + footerMissingText + '</div>').click(function(){
349                           jQuery(element).val("");
350                           jQuery('<div><input class="autocomplete-new-city"/><button class="input-button-go __AC_button">go</button></div>').find("button").click(function(){
351                              var name = jQuery(this).parent().find("input").val();
352                              hideBox();
353                              hoverEntry = false;
354                              if (name != "") {
355                                 freetext();
356                                 isFreetext = true;
357                              } else {
358                                 invalidated();
359                                 isFreetext = false;
360                              }
361                              jQuery(element).val(name);
362                              def = typed = name;
363                              jQuery(element).blur();
364                           }).css({
365                              "display": "block",
366                              "margin-left": parseInt(jQuery(".__AC_data").innerWidth()) - 70 + "px"
367                           }).parent().find("input").keyup(function(e){
368                              if (e.which == 13) {
369                                 jQuery(this).parent().find("button").click();
370                              }
371                           }).css({
372                              "width": parseInt(jQuery(".__AC_data").innerWidth()) - 90 + "px"
373                           }).attr('placeholder', footerInfoText).focus(function() {
374                              jQuery(this).unbind("focus").css({
375                                 "color": "#000000"
376                              }).val("");
377                           }).parent().hover(function() {
378                              hoverEntry = true;
379                           }, function() {
380                              hoverEntry = false;
381                           }).insertAfter(this);
382                           jQuery(this).remove();
383                           jQuery(".__AC_data").remove();
384                        }).hover(function() {
385                           hoverEntry = true;
386                        }, function() {
387                           hoverEntry = false;
388                        }).css({
389                           "color": "#BB3A11",
390                           "background-color": "#F9F5E1",
391                           "margin-right": "10px",
392                           "margin-top": "10px",
393                           "padding": "2px",
394                           "cursor": "pointer"
395                        }));
396                     } else if (options['button'] != undefined && typeof options['onButtonClick'] === 'function') {
397                        box.find('.__AC_layer').append('<div class="__AC_button">' + options['button'] + '</div>');
398                        box.find('.__AC_button').click(function(e) {
399                              options['onButtonClick'](e);
400                              hideBox();
401                         });
402                     }
403                     box.css('width', jQuery(element).outerWidth() + 'px')
404                     jQuery(element).parent().append(box);
405                     editing();
406                     if (options['onShow'] && typeof options['onShow'] === 'function') {
407                        options['onShow']();
408                     }
409                  }
410               }
411            );
412         }
413      };
414
415      /**
416       * Hide the box
417       */
418      var hideBox = function() {
419         box.remove();
420         boxShown = false;
421      };
422
423      var showValidatingBox = function() {
424            validatingBox.appendTo(jQuery(element).parent())
425                  .css('width', jQuery(element).outerWidth() + 'px');
426      }
427
428      /**
429       * Function which will be triggered when we focus the box.
430       */
431      jQuery(element).focus(function() {
432         hasFocus = true;
433         if (!isValidated && originalVal == jQuery(element).val()) {
434            jQuery(element).val('');
435         }
436         editing();
437      });
438
439      /**
440       * Leaving the box
441       */
442      jQuery(element).blur(function() {
443         hasFocus = false;
444         if (jQuery(element).val() == '') {
445            hideBox();
446            jQuery(element).val(originalVal);
447            if (isValidated) {
448               validated();
449            } else {
450               invalidated();
451            }
452         } else  if (options['allowFreetext']) {
453            hideBox();
454            freetext();
455         } else if (!hoverEntry && options['closeWhenBlur']) {
456            hideBox();
457            if (def != jQuery(element).val()) {
458               jQuery(element).val(def);
459            }
460            if (isFreetext) {
461               freetext();
462            } else if (isValidated || def == typed) {
463               validated();
464            } else {
465               jQuery(element).val(def);
466               invalidated();
467            }
468         } else if (def == typed) {
469            if (isFreetext) {
470               freetext();
471            } else {
472               validated();
473            }
474         }
475      });
476
477
478      /**
479       * Key enter, has to be done on keypress so that it happens before any submit events
480       */
481      jQuery(element).keypress(function(keyCapture) {
482         if (keyCapture.which == '13') {
483            // simulate click to trigger correct callback (possibly from JSONdata)
484            jQuery('.__AC_keyhover').click();
485            return !options.trapEnter;
486         }
487         return true;
488      });
489
490      /**
491       * Pressing and button which the box has focus
492       */
493      jQuery(element).keyup(function(keyCapture) {
494         clearTimeout(timeout);
495         typed = jQuery(element).val();
496          /**
497           * Key escape
498           */
499         if (keyCapture.which == 27) {
500            hideBox();
501            jQuery(element).blur();
502          /**
503           * Key up-arrow
504           */
505         } else if (keyCapture.which == '38') {
506            if (jQuery('.__AC_keyhover').length == 0 || jQuery('.__AC_keyhover').prev().length == 0) { // || first
507               jQuery('.__AC_keyhover').removeClass('__AC_keyhover');
508               jQuery('.__AC_data div:last-child').addClass('__AC_keyhover');
509            } else {
510               jQuery('.__AC_keyhover').removeClass('__AC_keyhover').prev().addClass('__AC_keyhover');
511            }
512          /**
513           * Key down-arrow
514           */
515         } else if (keyCapture.which == '40') {
516            if (jQuery('.__AC_keyhover').length == 0 || jQuery('.__AC_keyhover').next().length == 0) { // || last
517               jQuery('.__AC_keyhover').removeClass('__AC_keyhover');
518               jQuery('.__AC_data div:first-child').addClass('__AC_keyhover');
519            } else {
520               jQuery('.__AC_keyhover').removeClass('__AC_keyhover').next().addClass('__AC_keyhover');
521            }
522         } else if (typed.length < options['minimumKeys']) {
523            hideBox();
524            //showValidatingBox();
525         } else if (def != typed && typed.length >= options['minimumKeys']) {
526            hideBox();
527            showValidatingBox();
528            timeout = window.setTimeout(function() {
529               showBox();
530            }, options['waitTime']);
531         }
532      });
533
534      /**
535       * Do correct styling of the box at init
536       */
537      if (isValidated || initValidated) {
538         validated();
539      } else {
540         invalidated();
541      }
542
543   });
544};

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.