[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    =?utf-8?q?=5Bkdelibs=5D_kdewebkit=3A_-_Switched_back_to_using_ja?=
From:       Dawit Alemayehu <adawit () kde ! org>
Date:       2011-01-31 23:14:43
Message-ID: 20110131231443.85238A60A9 () git ! kde ! org
[Download RAW message or body]

Git commit 759c1cd0eb5da022e5cbb9bbeb5a8a1d984f3408 by Dawit Alemayehu.
Pushed by adawit into branch 'master'.

- Switched back to using javscript to parse forms for login information due to \
problems  with QWebElement when form inputs are nested inside of a table row.

CCBUG: 256029
FIXED-IN: pending for v4.6.1

M  +179  -175  kdewebkit/kwebwallet.cpp     

http://commits.kde.org/kdelibs/759c1cd0eb5da022e5cbb9bbeb5a8a1d984f3408

diff --git a/kdewebkit/kwebwallet.cpp b/kdewebkit/kwebwallet.cpp
index 9168b01..5873459 100644
--- a/kdewebkit/kwebwallet.cpp
+++ b/kdewebkit/kwebwallet.cpp
@@ -38,6 +38,35 @@
 #define QL1S(x)   QLatin1String(x)
 #define QL1C(x)   QLatin1Char(x)
 
+// Form parsing JS code adapted from Arora.
+// See https://github.com/Arora/arora/blob/master/src/data/parseForms.js
+#define FORM_PARSING_JS "(function (){ \
+    var forms = new Array; \
+    for (var i = 0; i < document.forms.length; ++i) { \
+        var form = document.forms[i]; \
+        var formObject = new Object; \
+        formObject.name = form.name; \
+        formObject.index = i; \
+        var elements = new Array; \
+        for (var j = 0; j < form.elements.length; ++j) { \
+            var e = form.elements[j]; \
+            var element = new Object; \
+            element.name = e.name; \
+            element.value = e.value; \
+            element.type = e.type; \
+            element.readonly = e.hasAttribute('readonly'); \
+            element.disabled = e.hasAttribute('disabled'); \
+            if (element.autocomplete != null)  \
+                element.autocomplete = element.autocomplete.value; \
+            elements.push(element); \
+        } \
+        formObject.elements = elements; \
+        forms.push(formObject); \
+    } \
+    return forms; \
+}())"
+
+
 /**
  * Creates key used to store and retrieve form data.
  *
@@ -47,33 +76,9 @@ static QString walletKey(KWebWallet::WebForm form)
     QString key = form.url.toString(QUrl::RemoveQuery|QUrl::RemoveFragment);
     key += QL1C('#');
     key += form.name;
-
     return key;
 }
 
-static int getWebFields(const QWebElement &formElement,
-                        const QString& selector, \
                QList<KWebWallet::WebForm::WebField> &fields)
-{
-    QWebElementCollection collection = formElement.findAll(selector);
-    const int count = collection.count();
-
-    for(int i = 0; i < count; ++i) {
-        QWebElement element = collection.at(i);
-        const QString value = \
                element.evaluateJavaScript(QL1S("this.value")).toString();
-        if (!value.isEmpty())
-            fields << qMakePair(element.attribute(QL1S("name")), value);
-    }
-
-    return fields.count();
-}
-
-static bool isValidInputElement(const QWebElement& element)
-{
-    return (!element.isNull() &&
-            !element.hasAttribute(QL1S("readonly")) &&
-            !element.hasAttribute(QL1S("disabled")));
-}
-
 static void collectAllChildFrames(QWebFrame* frame, QList<QWebFrame*>& list)
 {
     list << frame->childFrames();
@@ -83,7 +88,6 @@ static void collectAllChildFrames(QWebFrame* frame, \
QList<QWebFrame*>& list)  }
 }
 
-
 class KWebWallet::KWebWalletPrivate
 {
 public:
@@ -122,72 +126,77 @@ KWebWallet::WebFormList \
KWebWallet::KWebWalletPrivate::parseFormData(QWebFrame *  Q_ASSERT(frame);
 
     KWebWallet::WebFormList list;
-    QWebElementCollection formElements = \
                frame->findAllElements(QL1S("form[method=post]"));
-    const int formElementCount = formElements.count();
-
-    if (fillform) {
-        for ( int i = 0; i < formElementCount; ++i ) {
-            const QWebElement formElement = formElements.at(i);
-
-            KWebWallet::WebForm form;
-            form.url = frame->url();
-            form.index = QString::number(i);
-            form.name = formElement.attribute(QL1S("name"));
-            if (q->hasCachedFormData(form))
-                list << form;
-        }
-    } else {
-        int numPasswdFields = 0;
-        QString passwdSelector;
-
-        if (!ignorepasswd)
-            passwdSelector = QL1S("input[type=password]:not([autocomplete=off])");
-
-        for (int i = 0; i < formElementCount; ++i) {
-            const QWebElement formElement = formElements.at(i);
 
-            KWebWallet::WebForm form;
-            form.url = frame->url();
-            form.index = QString::number(i);
-            form.name = formElement.attribute(QL1S("name"));
-
-            // Get all <input> elements of type 'password'
-            numPasswdFields = getWebFields(formElement, passwdSelector, \
form.fields); +    // Execute the javscript to obtain the necessary fields...
+    QVariantList results = \
frame->evaluateJavaScript(QL1S(FORM_PARSING_JS)).toList(); +    Q_FOREACH (const \
QVariant &formVariant, results) { +        QVariantMap map = formVariant.toMap();
+        KWebWallet::WebForm form;
+        form.url = frame->url();
+        form.name = map[QL1S("name")].toString();
+        form.index = map[QL1S("index")].toString();
+        bool formHasPasswords = false;
+        const QVariantList elements = map[QL1S("elements")].toList();
+        QList<KWebWallet::WebForm::WebField> inputFields;
+        Q_FOREACH (const QVariant &element, elements) {
+            QVariantMap elementMap = element.toMap();
+            const QString name = elementMap[QL1S("name")].toString();
+            const QString value = (ignorepasswd ? QString() : \
elementMap[QL1S("value")].toString()); +            const QString type = \
elementMap[QL1S("type")].toString(); +            const bool isPasswdInput = \
(type.compare(QL1S("password"), Qt::CaseInsensitive) == 0); +            const bool \
isTextInput = (type.compare(QL1S("text"), Qt::CaseInsensitive) == 0); +            if \
(name.isEmpty()) +                continue;
+            if (!isPasswdInput && !isTextInput)
+                continue;
+            if (elementMap[QL1S("autocomplete")].toString() == QL1S("on"))
+                continue;
+            if (elementMap[QL1S("disabled")].toBool())
+                continue;
+            if (fillform && elementMap[QL1S("readonly")].toBool())
+                continue;
+            if (isPasswdInput && !fillform && value.isEmpty())
+                continue;
+            if (isPasswdInput)
+                formHasPasswords = true;
+            inputFields.append(qMakePair(name, value));
+        }
 
-            // Get all <input> elements of type 'text'
-            getWebFields(formElement, \
QL1S("input[type=text]:not([autocomplete=off]), input:not([type])"), form.fields); +  \
// Only add the input fields on form save requests... +        if (formHasPasswords \
&& !fillform) +            form.fields = inputFields;
 
-            // Add the form the list if it contains a password field...
-            if ((ignorepasswd || numPasswdFields == 1) && !form.fields.isEmpty())
-                list << form;
-        }
+        // Add the form to the list if we are saving it or it has cached data.
+        if ((fillform && q->hasCachedFormData(form)) || (!fillform  && \
!form.fields.isEmpty())) +            list << form;
     }
-
     return list;
 }
 
 void KWebWallet::KWebWalletPrivate::fillDataFromCache(KWebWallet::WebFormList \
&formList)  {
-    if (wallet) {
-        QMap<QString, QString> cachedValues;
-        QMutableListIterator <WebForm> formIt (formList);
+    if (!wallet) {
+        kWarning(800) << "Unable to retreive form data from wallet";
+        return;
+    }
 
-        while (formIt.hasNext()) {
-            KWebWallet::WebForm &form = formIt.next();
-            const QString key (walletKey(form));
-            if (wallet->readMap(key, cachedValues) == 0) {
-                QMapIterator<QString, QString> valuesIt (cachedValues);
-                while (valuesIt.hasNext()) {
-                    valuesIt.next();
-                    //kDebug(800) << "wallet key:" << key << valuesIt.key() << \
                valuesIt.value();
-                    form.fields << qMakePair(valuesIt.key(), valuesIt.value());
-                }
-            } else {
-                  kWarning(800) << "Unable to read form data for key:" << key;
-            }
+    QMap<QString, QString> cachedValues;
+    QMutableListIterator <WebForm> formIt (formList);
+
+    while (formIt.hasNext()) {
+        KWebWallet::WebForm &form = formIt.next();
+        const QString key (walletKey(form));
+        if (wallet->readMap(key, cachedValues) != 0) {
+            kWarning(800) << "Unable to read form data for key:" << key;
+            continue;
+        }
+
+        QMapIterator<QString, QString> valuesIt (cachedValues);
+        while (valuesIt.hasNext()) {
+            valuesIt.next();
+            //kDebug(800) << "wallet key:" << key << valuesIt.key() << \
valuesIt.value(); +            form.fields << qMakePair(valuesIt.key(), \
valuesIt.value());  }
-    } else {
-        kWarning(800) << "Unable to retreive form data from wallet";
     }
 }
 
@@ -250,14 +259,14 @@ void KWebWallet::KWebWalletPrivate::saveDataToCache(const \
QString &key)  
 void KWebWallet::KWebWalletPrivate::removeDataFromCache(const WebFormList &formList)
 {
-    if (wallet) {
-        QListIterator<WebForm> formIt (formList);
-        while (formIt.hasNext()) {
-            wallet->removeEntry(walletKey(formIt.next()));
-        }
-    } else {
+    if (!wallet) {
         kWarning(800) << "NULL KWallet instance!";
+        return;
     }
+
+    QListIterator<WebForm> formIt (formList);
+    while (formIt.hasNext())
+        wallet->removeEntry(walletKey(formIt.next()));
 }
 
 void KWebWallet::KWebWalletPrivate::_k_openWalletDone(bool ok)
@@ -354,82 +363,86 @@ KWebWallet::WebFormList \
KWebWallet::formsWithCachedData(QWebFrame* frame, bool r  
 void KWebWallet::fillFormData(QWebFrame *frame, bool recursive)
 {
-    if (frame) {
-        KUrl::List urlList;
-        WebFormList formsList = d->parseFormData(frame);
-        if (!formsList.isEmpty()) {
-          const QUrl url (frame->url());
-          if (d->pendingFillRequests.contains(url)) {
-              kWarning(800) << "Duplicate request rejected!";
-          } else {
-              KWebWalletPrivate::FormsData data;
-              data.frame = frame;
-              data.forms << formsList;
-              d->pendingFillRequests.insert(url, data);
-              urlList << url;
-          }
+    if (!frame)
+        return;
+
+    KUrl::List urlList;
+    WebFormList formsList = d->parseFormData(frame);
+    if (!formsList.isEmpty()) {
+        const QUrl url (frame->url());
+        if (d->pendingFillRequests.contains(url)) {
+            kWarning(800) << "Duplicate request rejected!";
+        } else {
+            KWebWalletPrivate::FormsData data;
+            data.frame = frame;
+            data.forms << formsList;
+            d->pendingFillRequests.insert(url, data);
+            urlList << url;
         }
+    }
 
-        if (recursive) {
-            QList<QWebFrame*> childFrameList;
-            collectAllChildFrames(frame, childFrameList);
-            QListIterator<QWebFrame*> frameIt (childFrameList);
-            while (frameIt.hasNext()) {
-                QWebFrame *childFrame = frameIt.next();
-                formsList = d->parseFormData(childFrame);
-                if (formsList.isEmpty())
-                    continue;
-                const QUrl url (childFrame->url());
-                if (d->pendingFillRequests.contains(url)) {
-                    kWarning(800) << "Duplicate request rejected!!!";
-                } else {
-                    KWebWalletPrivate::FormsData data;
-                    data.frame = childFrame;
-                    data.forms << formsList;
-                    d->pendingFillRequests.insert(url, data);
-                    urlList << url;
-                }
+    if (recursive) {
+        QList<QWebFrame*> childFrameList;
+        collectAllChildFrames(frame, childFrameList);
+        QListIterator<QWebFrame*> frameIt (childFrameList);
+        while (frameIt.hasNext()) {
+            QWebFrame *childFrame = frameIt.next();
+            formsList = d->parseFormData(childFrame);
+            if (formsList.isEmpty())
+                continue;
+            const QUrl url (childFrame->url());
+            if (d->pendingFillRequests.contains(url)) {
+                kWarning(800) << "Duplicate request rejected!!!";
+            } else {
+                KWebWalletPrivate::FormsData data;
+                data.frame = childFrame;
+                data.forms << formsList;
+                d->pendingFillRequests.insert(url, data);
+                urlList << url;
             }
         }
-
-        if (!urlList.isEmpty())
-            fillFormDataFromCache(urlList);
     }
+
+    if (!urlList.isEmpty())
+        fillFormDataFromCache(urlList);
 }
 
 void KWebWallet::saveFormData(QWebFrame *frame, bool recursive, bool \
ignorePasswordFields)  {
-    if (frame) {
-        WebFormList list = d->parseFormData(frame, false, ignorePasswordFields);
-        if (recursive) {
-            QList<QWebFrame*> childFrameList;
-            collectAllChildFrames(frame, childFrameList);
-            QListIterator<QWebFrame*> frameIt (childFrameList);
-            while (frameIt.hasNext()) {
-                list << d->parseFormData(frameIt.next(), false, \
                ignorePasswordFields);
-            }
-        }
+    if (!frame)
+        return;
 
-        if (!list.isEmpty()) {
-            const QString key = QString::number(qHash(frame->url().toString() + \
                frame->frameName()), 16);
-            const bool isAlreadyPending = d->pendingSaveRequests.contains(key);
-            d->pendingSaveRequests.insert(key, list);
+    WebFormList list = d->parseFormData(frame, false, ignorePasswordFields);
+    if (recursive) {
+        QList<QWebFrame*> childFrameList;
+        collectAllChildFrames(frame, childFrameList);
+        QListIterator<QWebFrame*> frameIt (childFrameList);
+        while (frameIt.hasNext())
+            list << d->parseFormData(frameIt.next(), false, ignorePasswordFields);
+    }
 
-            if (!isAlreadyPending) {
-                for (int i =0 ; i < list.count(); ++i) {
-                    if (hasCachedFormData(list.at(i)))
-                        list.takeAt(i);
-                }
+    if (list.isEmpty())
+        return;
 
-                if (list.isEmpty()) {
-                    d->confirmSaveRequestOverwrites.insert(frame->url());
-                    saveFormDataToCache(key);
-                } else {
-                    emit saveFormDataRequested(key, frame->url());
-                }
-            }
-        }
+    const QString key = QString::number(qHash(frame->url().toString() + \
frame->frameName()), 16); +    const bool isAlreadyPending = \
d->pendingSaveRequests.contains(key); +    d->pendingSaveRequests.insert(key, list);
+
+    if (isAlreadyPending)
+        return;
+
+    for (int i = 0 ; i < list.count(); ++i) {
+        if (hasCachedFormData(list.at(i)))
+            list.takeAt(i);
+    }
+
+    if (list.isEmpty()) {
+        d->confirmSaveRequestOverwrites.insert(frame->url());
+        saveFormDataToCache(key);
+        return;
     }
+
+    emit saveFormDataRequested(key, frame->url());
 }
 
 void KWebWallet::removeFormData(QWebFrame *frame, bool recursive)
@@ -457,34 +470,25 @@ void KWebWallet::rejectSaveFormDataRequest(const QString & key)
 void KWebWallet::fillWebForm(const KUrl &url, const KWebWallet::WebFormList &forms)
 {
     QWebFrame *frame = d->pendingFillRequests.value(url).frame;
-    if (frame) {
-        QWebElement formElement;
-        bool filledForm = false;
-        QListIterator<WebForm> formIt (forms);
-        while (formIt.hasNext()) {
-            const WebForm form = formIt.next();
+    if (!frame)
+        return;
 
-            QListIterator<WebForm::WebField> fieldIt (form.fields);
-            while (fieldIt.hasNext()) {
-                const WebForm::WebField field = fieldIt.next();
-                if (form.name.isEmpty())
-                    formElement = \
                frame->findAllElements(QL1S("form[method=post]")).at(form.index.toInt());
                
-                else
-                    formElement = \
                frame->findFirstElement(QString::fromLatin1("form[method=post][name=%1]")
                
-                                                          .arg(form.name));
-
-                if (!formElement.isNull()) {
-                    formElement = \
                formElement.findFirst(QString::fromLatin1("input[name=%1]").arg(field.first));
                
-                    if (isValidInputElement(formElement)) {
-                        formElement.setAttribute(QL1S("value"), field.second);
-                        filledForm = true;
-                        //kDebug(800) << "Filled out input name=" << field.first;
-                    }
-                }
-            }
-        }
-        emit fillFormRequestCompleted(filledForm);
+    QString script;
+    bool wasFilled = false;
+
+    Q_FOREACH (const KWebWallet::WebForm& form, forms) {
+        Q_FOREACH(const KWebWallet::WebForm::WebField& field, form.fields)
+            script += \
QString::fromLatin1("document.forms[\"%1\"].elements[\"%2\"].value=\"%3\";\n") +      \
.arg(form.name.isEmpty() ? form.index : form.name) +                        \
.arg(field.first).arg(field.second);  }
+
+    if (!script.isEmpty()) {
+        wasFilled = true;
+        frame->evaluateJavaScript(script);
+    }
+
+    emit fillFormRequestCompleted(wasFilled);
 }
 
 KWebWallet::WebFormList KWebWallet::formsToFill(const KUrl &url) const


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic