/** * Add an onchange event handler to the specified textfield object * to validate the user's input and autocomplete it if necessary. * The type argument is the Metaweb type, such as "/music/artist" * for which autocompletion should be done. * * The optional message argument specifies a document element into * which error messages (such as "invalid input" or "incomplete input" * should be displayed) The optional constraints argument is an object * that contains additional MQL properties that should be added to the * query. This can be use to further constrain the autocompletion * beyond simple type-based autocompletion. * * If the callback handler determines that the user's input is invalid or * incomplete, it sets the cssClass property to "invalid" or "incomplete" * (overwriting any other class values specified by that property). * You can define these CSS classes to set background colors or otherwise * highlight fields that require the user's attention. * * Validity and autocompletion is done using the ~= pattern matching * operator to ask for results of the specified type that begin with * the specified string. The query requests that results are sorted by * name and that only the first two are returned. If no results are * returned, this means that the user's input is invalid. If exactly * one result is returned, then the user's input is unique and * autocompletion is performed. If two results are returned, then the * user's input is not unique, but may still be valid, if the input * matches the first result (because the results are sorted), and that * result is a prefix of the second. If two results are returned and * the first result is not the same as the user's input, then the * input is incomplete. * * This function sets the onchange and class attributes of the text * field element and should not be used with HTML elements that set * these attributes themselves. Also, this function alters the * visibility and content of the optional message element. */ Metaweb.addValidationAndCompletion = function(textfield, type, message, constraints) { // Ensure that the message element, if any, is hidden if (message) message.style.visibility = "hidden"; // And add an event handler to the text field. textfield.onchange = function() { // Get the user's input and convert to lowercase. // Metaweb does case-insensitive pattern matching. var input = this.value.toLowerCase(); // This is the MQL query we use for autocompletion var query = [{ type: type, // Find objects of this type name: null, // We want to know object name "name~=": "^" + input + "*", // ^ and * make this a prefix match sort: "name", // Shortest completions first limit: 2 // We only care about the first 2 }]; // Add any additional constraints to the query if (constraints) for (c in constraints) query[0][c] = constraints[c]; // Now submit the query and pass the results to the nested function Metaweb.read(query, function(results) { // If there are no results, input is invalid if (results.length == 0) { // Set invalid class and display invalid message textfield.className = "invalid"; if (message) { message.innerHTML = "invalid input"; message.style.visibility = "visible"; } } // If there is one result or if the first result // matches exactly, input is valid. else if (results.length == 1 || results[0].name.toLowerCase() == input) { // Autocomplete the value. // Use capitalization Metaweb returns to us textfield.value = results[0].name; // Clear class and message textfield.className = ""; if (message) { message.innerHTML = ""; message.style.visibility = "hidden"; } } // If there is more than one result and no match // then the user's input is incomplete else { // Set incomplete class and message textfield.className = "incomplete"; if (message) { message.innerHTML="incomplete input"; message.style.visibility = "visible"; } } }); } }k