diff --git a/mobile/android/base/FormAssistPopup.java b/mobile/android/base/FormAssistPopup.java index e4ce2f22011..f8950dfce27 100644 --- a/mobile/android/base/FormAssistPopup.java +++ b/mobile/android/base/FormAssistPopup.java @@ -44,7 +44,10 @@ import android.content.Context; import android.util.Log; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.util.Pair; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.view.inputmethod.InputMethodManager; @@ -91,8 +94,10 @@ public class FormAssistPopup extends ListView implements GeckoEventListener { setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parentView, View view, int position, long id) { if (mTypeShowing.equals(PopupType.AUTOCOMPLETE)) { + // Use the value stored with the autocomplete view, not the label text, + // since they can be different. TextView textView = (TextView) view; - String value = textView.getText().toString(); + String value = (String) textView.getTag(); GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FormAssist:AutoComplete", value)); hide(); } @@ -149,13 +154,8 @@ public class FormAssistPopup extends ListView implements GeckoEventListener { } private void showAutoCompleteSuggestions(JSONArray suggestions, JSONArray rect, double zoom) { - ArrayAdapter adapter = new ArrayAdapter(mContext, R.layout.autocomplete_list_item); - try { - for (int i = 0; i < suggestions.length(); i++) - adapter.add(suggestions.get(i).toString()); - } catch (JSONException e) { - Log.e(LOGTAG, "JSONException: " + e); - } + AutoCompleteListAdapter adapter = new AutoCompleteListAdapter(mContext, R.layout.autocomplete_list_item); + adapter.populateSuggestionsList(suggestions); setAdapter(adapter); if (positionAndShowPopup(rect, zoom)) @@ -266,4 +266,48 @@ public class FormAssistPopup extends ListView implements GeckoEventListener { GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FormAssist:Hidden", null)); } } + + private class AutoCompleteListAdapter extends ArrayAdapter> { + private LayoutInflater mInflater; + private int mTextViewResourceId; + + public AutoCompleteListAdapter(Context context, int textViewResourceId) { + super(context, textViewResourceId); + + mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mTextViewResourceId = textViewResourceId; + } + + // This method takes an array of autocomplete suggestions with label/value properties + // and adds label/value Pair objects to the array that backs the adapter. + public void populateSuggestionsList(JSONArray suggestions) { + try { + for (int i = 0; i < suggestions.length(); i++) { + JSONObject suggestion = (JSONObject) suggestions.get(i); + String label = suggestion.getString("label"); + String value = suggestion.getString("value"); + add(new Pair(label, value)); + } + } catch (JSONException e) { + Log.e(LOGTAG, "JSONException: " + e); + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) + convertView = mInflater.inflate(mTextViewResourceId, null); + + Pair item = getItem(position); + TextView itemView = (TextView) convertView; + + // Set the text with the suggestion label + itemView.setText(item.first); + + // Set a tag with the suggestion value + itemView.setTag(item.second); + + return convertView; + } + } } diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 4f3e8cf43e0..1a731b910d5 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -2952,7 +2952,41 @@ var FormAssistant = { if (value == aSearchString) continue; - suggestions.push(value); + // Supply a label and value, since they can differ for datalist suggestions + suggestions.push({ label: value, value: value }); + } + + return suggestions; + }, + + /** + * (Copied from mobile/xul/chrome/content/forms.js) + * This function is similar to getListSuggestions from + * components/satchel/src/nsInputListAutoComplete.js but sadly this one is + * used by the autocomplete.xml binding which is not in used in fennec + */ + _getListSuggestions: function _getListSuggestions(aElement) { + if (!(aElement instanceof HTMLInputElement) || !aElement.list) + return []; + + let suggestions = []; + let filter = !aElement.hasAttribute("mozNoFilter"); + let lowerFieldValue = aElement.value.toLowerCase(); + + let options = aElement.list.options; + let length = options.length; + for (let i = 0; i < length; i++) { + let item = options.item(i); + + let label = item.value; + if (item.label) + label = item.label; + else if (item.text) + label = item.text; + + if (filter && label.toLowerCase().indexOf(lowerFieldValue) == -1) + continue; + suggestions.push({ label: label, value: item.value }); } return suggestions; @@ -2977,7 +3011,12 @@ var FormAssistant = { if (!this._isAutoComplete(aElement)) return false; - let suggestions = this._getAutoCompleteSuggestions(aElement.value, aElement); + let autoCompleteSuggestions = this._getAutoCompleteSuggestions(aElement.value, aElement); + let listSuggestions = this._getListSuggestions(aElement); + + // On desktop, we show datalist suggestions below autocomplete suggestions, + // without duplicates removed. + let suggestions = autoCompleteSuggestions.concat(listSuggestions); // Return false if there are no suggestions to show if (!suggestions.length)