+
+/** When the form is submitted hide everything, cancel updates... */
+function os_eventOnsubmit( e ) {
+ var targ = os_getTarget( e );
+
+ os_is_stopped = true;
+ // kill timed requests
+ if( os_timer != null && os_timer.id != null ) {
+ clearTimeout( os_timer.id );
+ os_timer = null;
+ }
+ // Hide all suggestions
+ for( i = 0; i < os_autoload_inputs.length; i++ ) {
+ var r = os_map[os_autoload_inputs[i]];
+ if( r != null ) {
+ var b = document.getElementById( r.searchform );
+ if( b != null && b == targ ) {
+ // set query value so the handler won't try to fetch additional results
+ r.query = document.getElementById( r.searchbox ).value;
+ }
+ os_hideResults( r );
+ }
+ }
+ return true;
+}
+
+
+
+/** Hide results from the user, either making the div visibility=hidden or
+ * detaching the datalist from the input. */
+function os_hideResults( r ) {
+ if ( os_use_datalist ) {
+ document.getElementById( r.searchbox ).setAttribute( 'list', '' );
+ } else {
+ var c = document.getElementById( r.container );
+ if ( c != null ) {
+ c.style.visibility = 'hidden';
+ }
+ }
+ r.visible = false;
+ r.selected = -1;
+}
+
+function os_decodeValue( value ) {
+ if ( decodeURIComponent ) {
+ return decodeURIComponent( value );
+ }
+ if( unescape ) {
+ return unescape( value );
+ }
+ return null;
+}
+
+function os_encodeQuery( value ) {
+ if ( encodeURIComponent ) {
+ return encodeURIComponent( value );
+ }
+ if( escape ) {
+ return escape( value );
+ }
+ return null;
+}
+
+/** Handles data from XMLHttpRequest, and updates the suggest results */
+function os_updateResults( r, query, text, cacheKey ) {
+ os_cache[cacheKey] = text;
+ r.query = query;
+ r.original = query;
+ if( text == '' ) {
+ r.results = null;
+ r.resultCount = 0;
+ os_hideResults( r );
+ } else {
+ try {
+ var p = eval( '(' + text + ')' ); // simple json parse, could do a safer one
+ if( p.length < 2 || p[1].length == 0 ) {
+ r.results = null;
+ r.resultCount = 0;
+ os_hideResults( r );
+ return;
+ }
+ if ( os_use_datalist ) {
+ os_setupDatalist( r, p[1] );
+ } else {
+ os_setupDiv( r, p[1] );
+ }
+ } catch( e ) {
+ // bad response from server or such
+ os_hideResults( r );
+ os_cache[cacheKey] = null;
+ }
+ }
+}
+
+/**
+ * Create and populate a <datalist>.
+ *
+ * @param r os_Result object
+ * @param results Array of the new results to replace existing ones
+ */
+function os_setupDatalist( r, results ) {
+ var s = document.getElementById( r.searchbox );
+ var c = document.getElementById( r.container );
+ if ( c == null ) {
+ c = document.createElement( 'datalist' );
+ c.setAttribute( 'id', r.container );
+ document.body.appendChild( c );
+ } else {
+ c.innerHTML = '';
+ }
+ s.setAttribute( 'list', r.container );
+
+ r.results = new Array();
+ r.resultCount = results.length;
+ r.visible = true;
+ for ( i = 0; i < results.length; i++ ) {
+ var title = os_decodeValue( results[i] );
+ var opt = document.createElement( 'option' );
+ opt.value = title;
+ r.results[i] = title;
+ c.appendChild( opt );
+ }
+}
+
+/** Fetch namespaces from checkboxes or hidden fields in the search form,
+ if none defined use wgSearchNamespaces global */
+function os_getNamespaces( r ) {
+ var namespaces = '';
+ var elements = document.forms[r.searchform].elements;
+ for( i = 0; i < elements.length; i++ ) {
+ var name = elements[i].name;
+ if( typeof name != 'undefined' && name.length > 2 && name[0] == 'n' &&
+ name[1] == 's' && (
+ ( elements[i].type == 'checkbox' && elements[i].checked ) ||
+ ( elements[i].type == 'hidden' && elements[i].value == '1' )
+ )
+ ) {
+ if( namespaces != '' ) {
+ namespaces += '|';
+ }
+ namespaces += name.substring( 2 );
+ }
+ }
+ if( namespaces == '' ) {
+ namespaces = wgSearchNamespaces.join('|');
+ }
+ return namespaces;
+}
+
+/** Update results if user hasn't already typed something else */
+function os_updateIfRelevant( r, query, text, cacheKey ) {
+ var t = document.getElementById( r.searchbox );
+ if( t != null && t.value == query ) { // check if response is still relevant
+ os_updateResults( r, query, text, cacheKey );
+ }
+ r.query = query;
+}
+
+/** Fetch results after some timeout */
+function os_delayedFetch() {
+ if( os_timer == null ) {
+ return;
+ }
+ var r = os_timer.r;
+ var query = os_timer.query;
+ os_timer = null;
+ var path = wgMWSuggestTemplate.replace( "{namespaces}", os_getNamespaces( r ) )
+ .replace( "{dbname}", wgDBname )
+ .replace( "{searchTerms}", os_encodeQuery( query ) );
+
+ // try to get from cache, if not fetch using ajax
+ var cached = os_cache[path];
+ if( cached != null && cached != undefined ) {
+ os_updateIfRelevant( r, query, cached, path );
+ } else {
+ var xmlhttp = sajax_init_object();
+ if( xmlhttp ) {
+ try {
+ xmlhttp.open( 'GET', path, true );
+ xmlhttp.onreadystatechange = function() {
+ if ( xmlhttp.readyState == 4 && typeof os_updateIfRelevant == 'function' ) {
+ os_updateIfRelevant( r, query, xmlhttp.responseText, path );
+ }
+ };
+ xmlhttp.send( null );
+ } catch ( e ) {
+ if ( window.location.hostname == 'localhost' ) {
+ alert( "Your browser blocks XMLHttpRequest to 'localhost', try using a real hostname for development/testing." );
+ }
+ throw e;
+ }
+ }
+ }
+}
+
+/** Init timed update via os_delayedUpdate() */
+function os_fetchResults( r, query, timeout ) {
+ if( query == '' ) {
+ r.query = '';
+ os_hideResults( r );
+ return;
+ } else if( query == r.query ) {
+ return; // no change
+ }
+
+ os_is_stopped = false; // make sure we're running
+
+ // cancel any pending fetches
+ if( os_timer != null && os_timer.id != null ) {
+ clearTimeout( os_timer.id );
+ }
+ // schedule delayed fetching of results
+ if( timeout != 0 ) {
+ os_timer = new os_Timer( setTimeout( "os_delayedFetch()", timeout ), r, query );
+ } else {
+ os_timer = new os_Timer( null, r, query );
+ os_delayedFetch(); // do it now!
+ }
+}
+
+/** Find event target */
+function os_getTarget( e ) {
+ if ( !e ) {
+ e = window.event;
+ }
+ if ( e.target ) {
+ return e.target;
+ } else if ( e.srcElement ) {
+ return e.srcElement;
+ } else {
+ return null;
+ }
+}
+
+/** Check if x is a valid integer */
+function os_isNumber( x ) {
+ if( x == '' || isNaN( x ) ) {
+ return false;
+ }
+ for( var i = 0; i < x.length; i++ ) {
+ var c = x.charAt( i );
+ if( !( c >= '0' && c <= '9' ) ) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/** Call this to enable suggestions on input (id=inputId), on a form (name=formName) */
+function os_enableSuggestionsOn( inputId, formName ) {
+ os_initHandlers( inputId, formName, document.getElementById( inputId ) );
+}
+
+/** Call this to disable suggestios on input box (id=inputId) */
+function os_disableSuggestionsOn( inputId ) {
+ r = os_map[inputId];
+ if( r != null ) {
+ // cancel/hide results
+ os_timer = null;
+ os_hideResults( r );
+ // turn autocomplete on !
+ document.getElementById( inputId ).setAttribute( 'autocomplete', 'on' );
+ // remove descriptor
+ os_map[inputId] = null;
+ }
+
+ // Remove the element from the os_autoload_* arrays
+ var index = os_autoload_inputs.indexOf( inputId );
+ if ( index >= 0 ) {
+ os_autoload_inputs[index] = os_autoload_forms[index] = '';
+ }
+}
+
+/************************************************
+ * Div-only functions (irrelevant for datalist)
+ ************************************************/
+