Changeset 88030 in webkit


Ignore:
Timestamp:
Jun 3, 2011 10:39:10 AM (13 years ago)
Author:
commit-queue@webkit.org
Message:

2011-06-03 Philippe Beauchamp <philippe.beauchamp@gmail.com>

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):
Location:
trunk/Source/WebKit/chromium
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit/chromium/ChangeLog

    r88021 r88030  
     12011-06-03  Philippe Beauchamp  <philippe.beauchamp@gmail.com>
     2
     3        Reviewed by Dimitri Glazkov.
     4
     5        Add the feature "Add as search engine..." in a search text field context menu for chromium
     6        https://bugs.webkit.org/show_bug.cgi?id=47980
     7
     8        * public/WebContextMenuData.h:
     9        * public/WebSearchableFormData.h:
     10        * src/ContextMenuClientImpl.cpp:
     11        (WebKit::ContextMenuClientImpl::getCustomMenuFromDefaultItems):
     12        * src/WebSearchableFormData.cpp:
     13        (WebKit::WebSearchableFormData::WebSearchableFormData):
     14
    1152011-06-03  Naoki Takano  <takano.naoki@gmail.com>
    216
  • trunk/Source/WebKit/chromium/public/WebContextMenuData.h

    r83617 r88030  
    7777    // The absolute URL of the page in context.
    7878    WebURL pageURL;
     79
     80    // The absolute keyword search URL including the %s search tag when the
     81    // "Add as search engine..." option is clicked (left empty if not used).
     82    WebURL keywordURL;
    7983
    8084    // The absolute URL of the subframe in context.
  • trunk/Source/WebKit/chromium/public/WebSearchableFormData.h

    r62133 r88030  
    3232#define WebSearchableFormData_h
    3333
     34#include "WebInputElement.h"
    3435#include "WebString.h"
    3536#include "WebURL.h"
     
    4445    // If the provided form is suitable for automated searching, isValid()
    4546    // will return false.
    46     WEBKIT_API WebSearchableFormData(const WebFormElement&);
     47    WEBKIT_API WebSearchableFormData(const WebFormElement&, const WebInputElement& selectedInputElement = WebInputElement());
    4748
    4849    bool isValid() { return m_url.isValid(); }
  • trunk/Source/WebKit/chromium/src/ContextMenuClientImpl.cpp

    r83660 r88030  
    4242#include "FrameLoader.h"
    4343#include "FrameView.h"
    44 #include "HistoryItem.h"
    45 #include "HitTestResult.h"
     44#include "HTMLFormElement.h"
     45#include "HTMLInputElement.h"
    4646#include "HTMLMediaElement.h"
    4747#include "HTMLNames.h"
    4848#include "HTMLPlugInImageElement.h"
     49
     50#include "HistoryItem.h"
     51#include "HitTestResult.h"
    4952#include "KURL.h"
    5053#include "MediaError.h"
     
    5760#include "WebContextMenuData.h"
    5861#include "WebDataSourceImpl.h"
     62#include "WebFormElement.h"
    5963#include "WebFrameImpl.h"
    6064#include "WebMenuItemInfo.h"
     
    6266#include "WebPluginContainerImpl.h"
    6367#include "WebPoint.h"
     68#include "WebSearchableFormData.h"
    6469#include "WebSpellCheckClient.h"
    6570#include "WebString.h"
     
    270275            }
    271276        }
     277        HTMLFormElement* form = selectedFrame->selection()->currentForm();
     278        if (form && form->checkValidity() && r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag)) {
     279            HTMLInputElement* selectedElement = static_cast<HTMLInputElement*>(r.innerNonSharedNode());
     280            if (selectedElement) {
     281                WebSearchableFormData ws = WebSearchableFormData(WebFormElement(form), WebInputElement(selectedElement));
     282                if (ws.url().isValid())
     283                    data.keywordURL = ws.url();
     284            }
     285        }
    272286    }
    273287
  • trunk/Source/WebKit/chromium/src/WebSearchableFormData.cpp

    r79123 r88030  
    4646#include "TextEncoding.h"
    4747#include "WebFormElement.h"
     48#include "WebInputElement.h"
    4849
    4950using namespace WebCore;
     
    142143}
    143144
    144 // If form has only one text input element, return true. If a valid input
    145 // element is not found, return false. Additionally, the form data for all
    146 // elements is added to enc_string and the encoding used is set in
    147 // encoding_name.
    148 bool HasSuitableTextElement(const HTMLFormElement* form, Vector<char>* encodedString, String* encodingName)
    149 {
     145// Look for a suitable search text field in a given HTMLFormElement
     146// Return nothing if one of those items are found:
     147//  - A text area field
     148//  - A file upload field
     149//  - A Password field
     150//  - More than one text field
     151HTMLInputElement* findSuitableSearchInputElement(const HTMLFormElement* form)
     152{
     153    HTMLInputElement* textElement = 0;
     154    // FIXME: Consider refactoring this code so that we don't call form->associatedElements() twice.
     155    for (Vector<FormAssociatedElement*>::const_iterator i(form->associatedElements().begin()); i != form->associatedElements().end(); ++i) {
     156        if (!(*i)->isFormControlElement())
     157            continue;
     158
     159        HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(*i);
     160
     161        if (formElement->disabled() || formElement->name().isNull())
     162            continue;
     163
     164        if (!IsInDefaultState(formElement) || formElement->hasTagName(HTMLNames::textareaTag))
     165            return 0;
     166
     167        if (formElement->hasTagName(HTMLNames::inputTag) && formElement->willValidate()) {
     168            const HTMLInputElement* input = static_cast<const HTMLInputElement*>(formElement);
     169
     170            // Return nothing if a file upload field or a password field are found.
     171            if (input->isFileUpload() || input->isPasswordField())
     172                return 0;
     173
     174            if (input->isTextField()) {
     175                if (textElement) {
     176                    // The auto-complete bar only knows how to fill in one value.
     177                    // This form has multiple fields; don't treat it as searchable.
     178                    return 0;
     179                }
     180                textElement = static_cast<HTMLInputElement*>(formElement);
     181            }
     182        }
     183    }
     184    return textElement;
     185}
     186
     187// Build a search string based on a given HTMLFormElement and HTMLInputElement
     188//
     189// Search string output example from www.google.com:
     190// "hl=en&source=hp&biw=1085&bih=854&q={searchTerms}&btnG=Google+Search&aq=f&aqi=&aql=&oq="
     191//
     192// Return false if the provided HTMLInputElement is not found in the form
     193bool buildSearchString(const HTMLFormElement* form, Vector<char>* encodedString, TextEncoding* encoding, const HTMLInputElement* textElement)
     194{
     195    bool isElementFound = false;   
     196
     197    // FIXME: Consider refactoring this code so that we don't call form->associatedElements() twice.
     198    for (Vector<FormAssociatedElement*>::const_iterator i(form->associatedElements().begin()); i != form->associatedElements().end(); ++i) {
     199        if (!(*i)->isFormControlElement())
     200            continue;
     201
     202        HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(*i);
     203
     204        if (formElement->disabled() || formElement->name().isNull())
     205            continue;
     206
     207        FormDataList dataList(*encoding);
     208        if (!formElement->appendFormData(dataList, false))
     209            continue;
     210
     211        const Vector<FormDataList::Item>& items = dataList.items();
     212
     213        for (Vector<FormDataList::Item>::const_iterator j(items.begin()); j != items.end(); ++j) {
     214            // Handle ISINDEX / <input name=isindex> specially, but only if it's
     215            // the first entry.
     216            if (!encodedString->isEmpty() || j->data() != "isindex") {
     217                if (!encodedString->isEmpty())
     218                    encodedString->append('&');
     219                FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
     220                encodedString->append('=');
     221            }
     222            ++j;
     223            if (formElement == textElement) {
     224                encodedString->append("{searchTerms}", 13);
     225                isElementFound = true;
     226            } else
     227                FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
     228        }
     229    }
     230    return isElementFound;
     231}
     232} // namespace
     233
     234namespace WebKit {
     235
     236WebSearchableFormData::WebSearchableFormData(const WebFormElement& form, const WebInputElement& selectedInputElement)
     237{
     238    RefPtr<HTMLFormElement> formElement = form.operator PassRefPtr<HTMLFormElement>();
     239    const Frame* frame = formElement->document()->frame();
     240    if (!frame)
     241        return;
     242
     243    HTMLInputElement* inputElement = selectedInputElement.operator PassRefPtr<HTMLInputElement>().get();
     244
     245    // Only consider forms that GET data.
     246    // Allow HTTPS only when an input element is provided.
     247    if (equalIgnoringCase(formElement->getAttribute(methodAttr), "post")
     248        || (!IsHTTPFormSubmit(formElement.get()) && !inputElement))
     249        return;
     250
     251    Vector<char> encodedString;
    150252    TextEncoding encoding;
    151     GetFormEncoding(form, &encoding);
     253
     254    GetFormEncoding(formElement.get(), &encoding);
    152255    if (!encoding.isValid()) {
    153256        // Need a valid encoding to encode the form elements.
    154257        // If the encoding isn't found webkit ends up replacing the params with
    155258        // empty strings. So, we don't try to do anything here.
    156         return 0;
    157     }
    158     *encodingName = encoding.name();
    159 
    160     HTMLInputElement* textElement = 0;
    161     // FIXME: Consider refactoring this code so that we don't call form->associatedElements() twice.
    162     for (Vector<FormAssociatedElement*>::const_iterator i(form->associatedElements().begin()); i != form->associatedElements().end(); ++i) {
    163         if (!(*i)->isFormControlElement())
    164             continue;
    165         HTMLFormControlElement* formElement = static_cast<HTMLFormControlElement*>(*i);
    166         if (formElement->disabled() || formElement->name().isNull())
    167             continue;
    168 
    169         if (!IsInDefaultState(formElement) || formElement->hasTagName(HTMLNames::textareaTag))
    170             return 0;
    171 
    172         bool isTextElement = false;
    173         if (formElement->hasTagName(HTMLNames::inputTag)) {
    174             const HTMLInputElement* input = static_cast<const HTMLInputElement*>(formElement);
    175             if (input->isFileUpload()) {
    176                 // Too big, don't try to index this.
    177                 return 0;
    178             }
    179 
    180             if (input->isPasswordField()) {
    181                 // Don't store passwords! This is most likely an https anyway.
    182                 return 0;
    183             }
    184 
    185             if (input->isTextField())
    186                 isTextElement = true;
    187       }
    188 
    189       FormDataList dataList(encoding);
    190       if (!formElement->appendFormData(dataList, false))
    191           continue;
    192 
    193       const Vector<FormDataList::Item>& items = dataList.items();
    194       if (isTextElement && !items.isEmpty()) {
    195           if (textElement) {
    196               // The auto-complete bar only knows how to fill in one value.
    197               // This form has multiple fields; don't treat it as searchable.
    198               return false;
    199           }
    200           textElement = static_cast<HTMLInputElement*>(formElement);
    201       }
    202       for (Vector<FormDataList::Item>::const_iterator j(items.begin()); j != items.end(); ++j) {
    203           // Handle ISINDEX / <input name=isindex> specially, but only if it's
    204           // the first entry.
    205           if (!encodedString->isEmpty() || j->data() != "isindex") {
    206               if (!encodedString->isEmpty())
    207                   encodedString->append('&');
    208               FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
    209               encodedString->append('=');
    210           }
    211           ++j;
    212           if (formElement == textElement)
    213               encodedString->append("{searchTerms}", 13);
    214           else
    215               FormDataBuilder::encodeStringAsFormData(*encodedString, j->data());
    216       }
    217     }
    218 
    219     return textElement;
    220 }
    221 
    222 } // namespace
    223 
    224 namespace WebKit {
    225 
    226 WebSearchableFormData::WebSearchableFormData(const WebFormElement& form)
    227 {
    228     RefPtr<HTMLFormElement> formElement = form.operator PassRefPtr<HTMLFormElement>();
    229     const Frame* frame = formElement->document()->frame();
    230     if (!frame)
    231         return;
    232 
    233     // Only consider forms that GET data and the action targets an http page.
    234     if (equalIgnoringCase(formElement->getAttribute(HTMLNames::methodAttr), "post") || !IsHTTPFormSubmit(formElement.get()))
    235         return;
     259        return;
     260    }
     261
     262    // Look for a suitable search text field in the form when a
     263    // selectedInputElement is not provided.
     264    if (!inputElement) {
     265        inputElement = findSuitableSearchInputElement(formElement.get());
     266
     267        // Return if no suitable text element has been found.
     268        if (!inputElement)
     269            return;
     270    }
    236271
    237272    HTMLFormControlElement* firstSubmitButton = GetButtonToActivate(formElement.get());
     
    242277        firstSubmitButton->setActivatedSubmit(true);
    243278    }
    244     Vector<char> encodedString;
    245     String encoding;
    246     bool hasElement = HasSuitableTextElement(formElement.get(), &encodedString, &encoding);
     279
     280    bool isValidSearchString = buildSearchString(formElement.get(), &encodedString, &encoding, inputElement);
     281
    247282    if (firstSubmitButton)
    248283        firstSubmitButton->setActivatedSubmit(false);
    249     if (!hasElement) {
    250         // Not a searchable form.
    251         return;
    252     }
     284
     285    // Return if the search string is not valid.
     286    if (!isValidSearchString)
     287        return;
    253288
    254289    String action(formElement->action());
     
    257292    url.setQuery(formData->flattenToString());
    258293    m_url = url;
    259     m_encoding = encoding;
     294    m_encoding = String(encoding.name());
    260295}
    261296
Note: See TracChangeset for help on using the changeset viewer.