Modified: trunk/Source/WebKit/chromium/ChangeLog (88029 => 88030)
--- trunk/Source/WebKit/chromium/ChangeLog 2011-06-03 17:03:21 UTC (rev 88029)
+++ trunk/Source/WebKit/chromium/ChangeLog 2011-06-03 17:39:10 UTC (rev 88030)
@@ -1,3 +1,17 @@
+2011-06-03 Philippe Beauchamp <[email protected]>
+
+ Reviewed by Dimitri Glazkov.
+
+ Add the feature "Add as search engine..." in a search text field context menu for chromium
+ https://bugs.webkit.org/show_bug.cgi?id=47980
+
+ * public/WebContextMenuData.h:
+ * public/WebSearchableFormData.h:
+ * src/ContextMenuClientImpl.cpp:
+ (WebKit::ContextMenuClientImpl::getCustomMenuFromDefaultItems):
+ * src/WebSearchableFormData.cpp:
+ (WebKit::WebSearchableFormData::WebSearchableFormData):
+
2011-06-03 Naoki Takano <[email protected]>
Reviewed by Eric Seidel.
Modified: trunk/Source/WebKit/chromium/public/WebContextMenuData.h (88029 => 88030)
--- trunk/Source/WebKit/chromium/public/WebContextMenuData.h 2011-06-03 17:03:21 UTC (rev 88029)
+++ trunk/Source/WebKit/chromium/public/WebContextMenuData.h 2011-06-03 17:39:10 UTC (rev 88030)
@@ -77,6 +77,10 @@
// The absolute URL of the page in context.
WebURL pageURL;
+ // The absolute keyword search URL including the %s search tag when the
+ // "Add as search engine..." option is clicked (left empty if not used).
+ WebURL keywordURL;
+
// The absolute URL of the subframe in context.
WebURL frameURL;
Modified: trunk/Source/WebKit/chromium/public/WebSearchableFormData.h (88029 => 88030)
--- trunk/Source/WebKit/chromium/public/WebSearchableFormData.h 2011-06-03 17:03:21 UTC (rev 88029)
+++ trunk/Source/WebKit/chromium/public/WebSearchableFormData.h 2011-06-03 17:39:10 UTC (rev 88030)
@@ -31,6 +31,7 @@
#ifndef WebSearchableFormData_h
#define WebSearchableFormData_h
+#include "WebInputElement.h"
#include "WebString.h"
#include "WebURL.h"
@@ -43,7 +44,7 @@
public:
// If the provided form is suitable for automated searching, isValid()
// will return false.
- WEBKIT_API WebSearchableFormData(const WebFormElement&);
+ WEBKIT_API WebSearchableFormData(const WebFormElement&, const WebInputElement& selectedInputElement = WebInputElement());
bool isValid() { return m_url.isValid(); }
Modified: trunk/Source/WebKit/chromium/src/ContextMenuClientImpl.cpp (88029 => 88030)
--- trunk/Source/WebKit/chromium/src/ContextMenuClientImpl.cpp 2011-06-03 17:03:21 UTC (rev 88029)
+++ trunk/Source/WebKit/chromium/src/ContextMenuClientImpl.cpp 2011-06-03 17:39:10 UTC (rev 88030)
@@ -41,11 +41,14 @@
#include "EventHandler.h"
#include "FrameLoader.h"
#include "FrameView.h"
-#include "HistoryItem.h"
-#include "HitTestResult.h"
+#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
#include "HTMLMediaElement.h"
#include "HTMLNames.h"
#include "HTMLPlugInImageElement.h"
+
+#include "HistoryItem.h"
+#include "HitTestResult.h"
#include "KURL.h"
#include "MediaError.h"
#include "Page.h"
@@ -56,11 +59,13 @@
#include "WebContextMenuData.h"
#include "WebDataSourceImpl.h"
+#include "WebFormElement.h"
#include "WebFrameImpl.h"
#include "WebMenuItemInfo.h"
#include "WebPlugin.h"
#include "WebPluginContainerImpl.h"
#include "WebPoint.h"
+#include "WebSearchableFormData.h"
#include "WebSpellCheckClient.h"
#include "WebString.h"
#include "WebURL.h"
@@ -269,6 +274,15 @@
}
}
}
+ HTMLFormElement* form = selectedFrame->selection()->currentForm();
+ if (form && form->checkValidity() && r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag)) {
+ HTMLInputElement* selectedElement = static_cast<HTMLInputElement*>(r.innerNonSharedNode());
+ if (selectedElement) {
+ WebSearchableFormData ws = WebSearchableFormData(WebFormElement(form), WebInputElement(selectedElement));
+ if (ws.url().isValid())
+ data.keywordURL = ws.url();
+ }
+ }
}
#if OS(DARWIN)
Modified: trunk/Source/WebKit/chromium/src/WebSearchableFormData.cpp (88029 => 88030)
--- trunk/Source/WebKit/chromium/src/WebSearchableFormData.cpp 2011-06-03 17:03:21 UTC (rev 88029)
+++ trunk/Source/WebKit/chromium/src/WebSearchableFormData.cpp 2011-06-03 17:39:10 UTC (rev 88030)
@@ -45,6 +45,7 @@
#include "HTMLSelectElement.h"
#include "TextEncoding.h"
#include "WebFormElement.h"
+#include "WebInputElement.h"
using namespace WebCore;
using namespace HTMLNames;
@@ -141,99 +142,133 @@
return true;
}
-// If form has only one text input element, return true. If a valid input
-// element is not found, return false. Additionally, the form data for all
-// elements is added to enc_string and the encoding used is set in
-// encoding_name.
-bool HasSuitableTextElement(const HTMLFormElement* form, Vector<char>* encodedString, String* encodingName)
+// Look for a suitable search text field in a given HTMLFormElement
+// Return nothing if one of those items are found:
+// - A text area field
+// - A file upload field
+// - A Password field
+// - More than one text field
+HTMLInputElement* findSuitableSearchInputElement(const HTMLFormElement* form)
{
- TextEncoding encoding;
- GetFormEncoding(form, &encoding);
- if (!encoding.isValid()) {
- // Need a valid encoding to encode the form elements.
- // If the encoding isn't found webkit ends up replacing the params with
- // empty strings. So, we don't try to do anything here.
- return 0;
- }
- *encodingName = encoding.name();
-
HTMLInputElement* textElement = 0;
// FIXME: Consider refactoring this code so that we don't call form->associatedElements() twice.
for (Vector<FormAssociatedElement*>::const_iterator i(form->associatedElements().begin()); i != form->associatedElements().end(); ++i) {
if (!(*i)->isFormControlElement())
continue;
+
HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(*i);
+
if (formElement->disabled() || formElement->name().isNull())
continue;
if (!IsInDefaultState(formElement) || formElement->hasTagName(HTMLNames::textareaTag))
return 0;
- bool isTextElement = false;
- if (formElement->hasTagName(HTMLNames::inputTag)) {
+ if (formElement->hasTagName(HTMLNames::inputTag) && formElement->willValidate()) {
const HTMLInputElement* input = static_cast<const HTMLInputElement*>(formElement);
- if (input->isFileUpload()) {
- // Too big, don't try to index this.
+
+ // Return nothing if a file upload field or a password field are found.
+ if (input->isFileUpload() || input->isPasswordField())
return 0;
- }
- if (input->isPasswordField()) {
- // Don't store passwords! This is most likely an https anyway.
- return 0;
+ if (input->isTextField()) {
+ if (textElement) {
+ // The auto-complete bar only knows how to fill in one value.
+ // This form has multiple fields; don't treat it as searchable.
+ return 0;
+ }
+ textElement = static_cast<HTMLInputElement*>(formElement);
}
+ }
+ }
+ return textElement;
+}
- if (input->isTextField())
- isTextElement = true;
- }
+// Build a search string based on a given HTMLFormElement and HTMLInputElement
+//
+// Search string output example from www.google.com:
+// "hl=en&source=hp&biw=1085&bih=854&q={searchTerms}&btnG=Google+Search&aq=f&aqi=&aql=&oq="
+//
+// Return false if the provided HTMLInputElement is not found in the form
+bool buildSearchString(const HTMLFormElement* form, Vector<char>* encodedString, TextEncoding* encoding, const HTMLInputElement* textElement)
+{
+ bool isElementFound = false;
- FormDataList dataList(encoding);
- if (!formElement->appendFormData(dataList, false))
- continue;
+ // FIXME: Consider refactoring this code so that we don't call form->associatedElements() twice.
+ for (Vector<FormAssociatedElement*>::const_iterator i(form->associatedElements().begin()); i != form->associatedElements().end(); ++i) {
+ if (!(*i)->isFormControlElement())
+ continue;
- const Vector<FormDataList::Item>& items = dataList.items();
- if (isTextElement && !items.isEmpty()) {
- if (textElement) {
- // The auto-complete bar only knows how to fill in one value.
- // This form has multiple fields; don't treat it as searchable.
- return false;
- }
- textElement = static_cast<HTMLInputElement*>(formElement);
- }
- for (Vector<FormDataList::Item>::const_iterator j(items.begin()); j != items.end(); ++j) {
- // Handle ISINDEX / <input name=isindex> specially, but only if it's
- // the first entry.
- if (!encodedString->isEmpty() || j->data() != "isindex") {
- if (!encodedString->isEmpty())
- encodedString->append('&');
- FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
- encodedString->append('=');
- }
- ++j;
- if (formElement == textElement)
- encodedString->append("{searchTerms}", 13);
- else
- FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
- }
+ HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(*i);
+
+ if (formElement->disabled() || formElement->name().isNull())
+ continue;
+
+ FormDataList dataList(*encoding);
+ if (!formElement->appendFormData(dataList, false))
+ continue;
+
+ const Vector<FormDataList::Item>& items = dataList.items();
+
+ for (Vector<FormDataList::Item>::const_iterator j(items.begin()); j != items.end(); ++j) {
+ // Handle ISINDEX / <input name=isindex> specially, but only if it's
+ // the first entry.
+ if (!encodedString->isEmpty() || j->data() != "isindex") {
+ if (!encodedString->isEmpty())
+ encodedString->append('&');
+ FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
+ encodedString->append('=');
+ }
+ ++j;
+ if (formElement == textElement) {
+ encodedString->append("{searchTerms}", 13);
+ isElementFound = true;
+ } else
+ FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
+ }
}
-
- return textElement;
+ return isElementFound;
}
-
} // namespace
namespace WebKit {
-WebSearchableFormData::WebSearchableFormData(const WebFormElement& form)
+WebSearchableFormData::WebSearchableFormData(const WebFormElement& form, const WebInputElement& selectedInputElement)
{
RefPtr<HTMLFormElement> formElement = form.operator PassRefPtr<HTMLFormElement>();
const Frame* frame = formElement->document()->frame();
if (!frame)
return;
- // Only consider forms that GET data and the action targets an http page.
- if (equalIgnoringCase(formElement->getAttribute(HTMLNames::methodAttr), "post") || !IsHTTPFormSubmit(formElement.get()))
+ HTMLInputElement* inputElement = selectedInputElement.operator PassRefPtr<HTMLInputElement>().get();
+
+ // Only consider forms that GET data.
+ // Allow HTTPS only when an input element is provided.
+ if (equalIgnoringCase(formElement->getAttribute(methodAttr), "post")
+ || (!IsHTTPFormSubmit(formElement.get()) && !inputElement))
return;
+ Vector<char> encodedString;
+ TextEncoding encoding;
+
+ GetFormEncoding(formElement.get(), &encoding);
+ if (!encoding.isValid()) {
+ // Need a valid encoding to encode the form elements.
+ // If the encoding isn't found webkit ends up replacing the params with
+ // empty strings. So, we don't try to do anything here.
+ return;
+ }
+
+ // Look for a suitable search text field in the form when a
+ // selectedInputElement is not provided.
+ if (!inputElement) {
+ inputElement = findSuitableSearchInputElement(formElement.get());
+
+ // Return if no suitable text element has been found.
+ if (!inputElement)
+ return;
+ }
+
HTMLFormControlElement* firstSubmitButton = GetButtonToActivate(formElement.get());
if (firstSubmitButton) {
// The form does not have an active submit button, make the first button
@@ -241,22 +276,22 @@
// name of the submit button.
firstSubmitButton->setActivatedSubmit(true);
}
- Vector<char> encodedString;
- String encoding;
- bool hasElement = HasSuitableTextElement(formElement.get(), &encodedString, &encoding);
+
+ bool isValidSearchString = buildSearchString(formElement.get(), &encodedString, &encoding, inputElement);
+
if (firstSubmitButton)
firstSubmitButton->setActivatedSubmit(false);
- if (!hasElement) {
- // Not a searchable form.
+
+ // Return if the search string is not valid.
+ if (!isValidSearchString)
return;
- }
String action(formElement->action());
KURL url(frame->loader()->completeURL(action.isNull() ? "" : action));
RefPtr<FormData> formData = FormData::create(encodedString);
url.setQuery(formData->flattenToString());
m_url = url;
- m_encoding = encoding;
+ m_encoding = String(encoding.name());
}
} // namespace WebKit