Optimize and clean-up form history

Switch from g_file_test() to g_access()

Initialize suggestions once the DOM is ready and only once

No need to handle WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED

[JS] Hide suggestions if search pattern was cleared

[JS] Human usable up/ down navigation in the suggestion window

Reusing a single suggestion window introduced a regression.
Suggestions were filling into the wrong editbox if there was more
than 1 on the page.

Some comments fixed and style clean-ups

Removed dead code
This commit is contained in:
Alexander Butenko 2009-12-19 10:45:39 +01:00 committed by Christian Dywan
parent 045cc81b45
commit 9af30a1eda
3 changed files with 52 additions and 70 deletions

View file

@ -1,9 +1,6 @@
div.suggestions { div.suggestions {
-moz-box-sizing: border-box; -webkit-appearance: listbox;
box-sizing: border-box;
border: 1px solid #cccccc;
text-align: left; text-align: left;
background-color: #ffffff;
position: absolute; position: absolute;
z-index: 999; z-index: 999;
} }

View file

@ -38,7 +38,6 @@ function AutoSuggestControl(oTextbox /*:HTMLInputElement*/,
* @param bTypeAhead If the control should provide a type ahead suggestion. * @param bTypeAhead If the control should provide a type ahead suggestion.
*/ */
AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/) { AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/) {
//make sure theres at least one suggestion
if (aSuggestions.length > 0) { if (aSuggestions.length > 0) {
this.showSuggestions(aSuggestions); this.showSuggestions(aSuggestions);
} else { } else {
@ -51,35 +50,16 @@ AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/) {
* @scope private * @scope private
*/ */
AutoSuggestControl.prototype.createDropDown = function () { AutoSuggestControl.prototype.createDropDown = function () {
var oThis = this;
var sDiv = document.getElementById("suggestions_box"); var sDiv = document.getElementById("suggestions_box");
if (sDiv) {
if (sDiv)
this.layer = sDiv; this.layer = sDiv;
else return;
{
this.layer = document.createElement("div");
this.layer.className = "suggestions";
this.layer.id = "suggestions_box";
this.layer.style.visibility = "hidden";
this.layer.style.width = this.textbox.offsetWidth;
} }
this.layer.onmousedown = this.layer = document.createElement("div");
this.layer.onmouseup = this.layer.className = "suggestions";
this.layer.onmouseover = function (oEvent) { this.layer.id = "suggestions_box";
oEvent = oEvent || window.event; this.layer.style.visibility = "hidden";
oTarget = oEvent.target || oEvent.srcElement; this.layer.style.width = this.textbox.offsetWidth;
if (oEvent.type == "mousedown") {
oThis.textbox.value = oTarget.firstChild.nodeValue;
oThis.hideSuggestions();
} else if (oEvent.type == "mouseover") {
oThis.highlightSuggestion(oTarget);
} else {
oThis.textbox.focus();
}
};
document.body.appendChild(this.layer); document.body.appendChild(this.layer);
}; };
@ -91,12 +71,10 @@ AutoSuggestControl.prototype.createDropDown = function () {
AutoSuggestControl.prototype.getLeft = function () /*:int*/ { AutoSuggestControl.prototype.getLeft = function () /*:int*/ {
var oNode = this.textbox; var oNode = this.textbox;
var iLeft = 0; var iLeft = 0;
while (oNode.tagName != "BODY") {
while(oNode.tagName != "BODY") {
iLeft += oNode.offsetLeft; iLeft += oNode.offsetLeft;
oNode = oNode.offsetParent; oNode = oNode.offsetParent;
} }
return iLeft; return iLeft;
}; };
@ -141,17 +119,15 @@ AutoSuggestControl.prototype.handleKeyDown = function (oEvent /*:Event*/) {
*/ */
AutoSuggestControl.prototype.handleKeyUp = function (oEvent /*:Event*/) { AutoSuggestControl.prototype.handleKeyUp = function (oEvent /*:Event*/) {
var iKeyCode = oEvent.keyCode; var iKeyCode = oEvent.keyCode;
//for backspace (8) and delete (46), shows suggestions without typeahead
if (iKeyCode == 8 || iKeyCode == 46) { if (iKeyCode == 8 || iKeyCode == 46) {
this.provider.requestSuggestions(this); this.provider.requestSuggestions(this);
//make sure not to interfere with non-character keys //make sure not to interfere with non-character keys
} else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode < 46) || (iKeyCode >= 112 && iKeyCode <= 123) ) { } else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode < 46) || (iKeyCode >= 112 && iKeyCode <= 123) ) {
//ignore //ignore
} else if (oEvent.ctrlKey) { } else if (oEvent.ctrlKey) {
iKeyCode = 0;
this.hideSuggestions(); this.hideSuggestions();
} else { } else {
//request suggestions from the suggestion provider with typeahead //request suggestions from the suggestion provider
this.provider.requestSuggestions(this); this.provider.requestSuggestions(this);
} }
}; };
@ -227,11 +203,15 @@ AutoSuggestControl.prototype.init = function () {
AutoSuggestControl.prototype.nextSuggestion = function () { AutoSuggestControl.prototype.nextSuggestion = function () {
var cSuggestionNodes = this.layer.childNodes; var cSuggestionNodes = this.layer.childNodes;
if (cSuggestionNodes.length > 0 && this.cur < cSuggestionNodes.length-1) { if (!cSuggestionNodes.length)
var oNode = cSuggestionNodes[++this.cur]; return;
this.highlightSuggestion(oNode);
this.textbox.value = oNode.firstChild.nodeValue; if (this.cur == cSuggestionNodes.length-1)
} this.cur = -1;
var oNode = cSuggestionNodes[++this.cur];
this.highlightSuggestion(oNode);
this.textbox.value = oNode.firstChild.nodeValue;
}; };
/** /**
@ -242,24 +222,15 @@ AutoSuggestControl.prototype.nextSuggestion = function () {
AutoSuggestControl.prototype.previousSuggestion = function () { AutoSuggestControl.prototype.previousSuggestion = function () {
var cSuggestionNodes = this.layer.childNodes; var cSuggestionNodes = this.layer.childNodes;
if (cSuggestionNodes.length > 0 && this.cur > 0) { if (!cSuggestionNodes.length)
var oNode = cSuggestionNodes[--this.cur]; return;
this.highlightSuggestion(oNode);
this.textbox.value = oNode.firstChild.nodeValue;
}
};
/** if (this.cur == -1 || this.cur == 0)
* Selects a range of text in the textbox. this.cur = cSuggestionNodes.length;
* @scope public
* @param iStart The start index (base 0) of the selection. var oNode = cSuggestionNodes[--this.cur];
* @param iLength The number of characters to select. this.highlightSuggestion(oNode);
*/ this.textbox.value = oNode.firstChild.nodeValue;
AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*:int*/) {
if (this.textbox.setSelectionRange) {
this.textbox.setSelectionRange(iStart, iLength);
}
this.textbox.focus();
}; };
/** /**
@ -269,6 +240,7 @@ AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*
* @param aSuggestions An array of suggestions for the control. * @param aSuggestions An array of suggestions for the control.
*/ */
AutoSuggestControl.prototype.showSuggestions = function (aSuggestions /*:Array*/) { AutoSuggestControl.prototype.showSuggestions = function (aSuggestions /*:Array*/) {
var oThis = this;
var oDiv = null; var oDiv = null;
this.layer.innerHTML = ""; //clear contents of the layer this.layer.innerHTML = ""; //clear contents of the layer
@ -282,6 +254,21 @@ AutoSuggestControl.prototype.showSuggestions = function (aSuggestions /*:Array*/
this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px"; this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
this.layer.style.visibility = "visible"; this.layer.style.visibility = "visible";
this.layer.style.position = "absolute"; this.layer.style.position = "absolute";
this.layer.onmousedown =
this.layer.onmouseup =
this.layer.onmouseover = function (oEvent) {
var oEvent = oEvent || window.event;
var oTarget = oEvent.target || oEvent.srcElement;
if (oEvent.type == "mousedown") {
oThis.textbox.value = oTarget.firstChild.nodeValue;
oThis.hideSuggestions();
} else if (oEvent.type == "mouseover") {
oThis.highlightSuggestion(oTarget);
} else {
oThis.textbox.focus();
}
};
}; };
/** /**
@ -295,14 +282,13 @@ FormSuggestions.prototype.requestSuggestions = function (oAutoSuggestControl /*:
if (!this.suggestions) if (!this.suggestions)
return; return;
if (!sTextboxValue.length)
return;
//search for matching suggestions //search for matching suggestions
for (var i=0; i < this.suggestions.length; i++) { if (sTextboxValue.length)
if (this.suggestions[i].toLowerCase().indexOf(sTextboxValue) == 0) { for (var i=0; i < this.suggestions.length; i++) {
aSuggestions.push(this.suggestions[i]); if (this.suggestions[i].toLowerCase().indexOf(sTextboxValue) == 0) {
} aSuggestions.push(this.suggestions[i]);
}
} }
//provide suggestions to the control //provide suggestions to the control
oAutoSuggestControl.autosuggest(aSuggestions); oAutoSuggestControl.autosuggest(aSuggestions);

View file

@ -38,13 +38,13 @@ formhistory_prepare_js ()
gchar* data_path = g_build_filename (MDATADIR, PACKAGE_NAME, "res", NULL); gchar* data_path = g_build_filename (MDATADIR, PACKAGE_NAME, "res", NULL);
file = g_build_filename (data_path,"/autosuggestcontrol.js",NULL); file = g_build_filename (data_path,"/autosuggestcontrol.js",NULL);
if (!g_file_test (file, G_FILE_TEST_EXISTS)) if (g_access (file, F_OK) != 0)
return FALSE; return FALSE;
g_file_get_contents (file, &autosuggest, NULL, NULL); g_file_get_contents (file, &autosuggest, NULL, NULL);
g_strchomp (autosuggest); g_strchomp (autosuggest);
file = g_build_filename (data_path,"/autosuggestcontrol.css",NULL); file = g_build_filename (data_path,"/autosuggestcontrol.css",NULL);
if (!g_file_test (file, G_FILE_TEST_EXISTS)) if (g_access (file, F_OK) != 0)
return FALSE; return FALSE;
g_file_get_contents (file, &style, NULL, NULL); g_file_get_contents (file, &style, NULL, NULL);
g_strchomp (style); g_strchomp (style);
@ -58,7 +58,6 @@ formhistory_prepare_js ()
jsforms = g_strdup_printf ( jsforms = g_strdup_printf (
"%s" "%s"
"window.addEventListener ('load', function () { initSuggestions (); }, true);"
"window.addEventListener ('DOMContentLoaded'," "window.addEventListener ('DOMContentLoaded',"
"function () {" "function () {"
" var styles = document.getElementsByTagName('style');" " var styles = document.getElementsByTagName('style');"
@ -66,6 +65,7 @@ formhistory_prepare_js ()
" if (styles[i].getAttribute('title') == 'formhistory')" " if (styles[i].getAttribute('title') == 'formhistory')"
" return;" " return;"
" }" " }"
" initSuggestions ();"
" var mystyle = document.createElement('style');" " var mystyle = document.createElement('style');"
" mystyle.setAttribute('type', 'text/css');" " mystyle.setAttribute('type', 'text/css');"
" mystyle.setAttribute('title', 'formhistory');" " mystyle.setAttribute('title', 'formhistory');"
@ -215,8 +215,7 @@ formhistory_navigation_decision_cb (WebKitWebView* web_view,
"}" "}"
"dumpForm (document.getElementsByTagName('input'))"; "dumpForm (document.getElementsByTagName('input'))";
if (webkit_web_navigation_action_get_reason (action) == WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED if (webkit_web_navigation_action_get_reason (action) == WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED)
|| webkit_web_navigation_action_get_reason (action) == WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED)
{ {
gchar* value = sokoke_js_script_eval (js_context, script, NULL); gchar* value = sokoke_js_script_eval (js_context, script, NULL);
if (value) if (value)