File indexing completed on 2024-04-28 16:01:19

0001 /*
0002     SPDX-FileCopyrightText: 2009 Dawit Alemayehu <adawit@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "kwebkitpart_ext.h"
0008 
0009 #include "kwebkitpart_debug.h"
0010 #include "kwebkitpart.h"
0011 #include "webview.h"
0012 #include "webpage.h"
0013 #include "settings/webkitsettings.h"
0014 
0015 #include <KUriFilter>
0016 #include <KConfigGroup>
0017 #include <KToolInvocation>
0018 #include <KSharedConfig>
0019 #include <KIO/OpenUrlJob>
0020 #include <KIO/JobUiDelegate>
0021 #include <KLocalizedString>
0022 
0023 #include <Sonnet/Dialog>
0024 #include <Sonnet/BackgroundChecker>
0025 
0026 #include <QAction>
0027 #include <QBuffer>
0028 #include <QClipboard>
0029 #include <QDir>
0030 #include <QApplication>
0031 #include <QInputDialog>
0032 #include <QPrintDialog>
0033 #include <QPrintPreviewDialog>
0034 #include <QTemporaryFile>
0035 #include <QMimeData>
0036 #include <QWebHistory>
0037 #include <QWebElementCollection>
0038 
0039 #define QL1S(x)     QLatin1String(x)
0040 #define QL1C(x)     QLatin1Char(x)
0041 
0042 
0043 WebKitBrowserExtension::WebKitBrowserExtension(KWebKitPart *parent, const QByteArray& cachedHistoryData)
0044                        :KParts::BrowserExtension(parent),
0045                         m_part(parent)
0046 {
0047     enableAction("cut", false);
0048     enableAction("copy", false);
0049     enableAction("paste", false);
0050     enableAction("print", true);
0051 
0052     if (cachedHistoryData.isEmpty()) {
0053         return;
0054     }
0055 
0056     QBuffer buffer;
0057     buffer.setData(cachedHistoryData);
0058     if (!buffer.open(QIODevice::ReadOnly)) {
0059         return;
0060     }
0061 
0062     // NOTE: When restoring history, webkit automatically navigates to
0063     // the previous "currentItem". Since we do not want that to happen,
0064     // we set a property on the WebPage object that is used to allow or
0065     // disallow history navigation in WebPage::acceptNavigationRequest.
0066     view()->page()->setProperty("HistoryNavigationLocked", true);
0067     QDataStream s (&buffer);
0068     s >> *(view()->history());
0069 }
0070 
0071 WebKitBrowserExtension::~WebKitBrowserExtension()
0072 {
0073 }
0074 
0075 WebView* WebKitBrowserExtension::view()
0076 {
0077     if (!m_view && m_part) {
0078         m_view = qobject_cast<WebView*>(m_part->view());
0079     }
0080 
0081     return m_view;
0082 }
0083 
0084 int WebKitBrowserExtension::xOffset()
0085 {
0086     if (view())
0087         return view()->page()->mainFrame()->scrollPosition().x();
0088 
0089     return KParts::BrowserExtension::xOffset();
0090 }
0091 
0092 int WebKitBrowserExtension::yOffset()
0093 {
0094     if (view())
0095         return view()->page()->mainFrame()->scrollPosition().y();
0096 
0097     return KParts::BrowserExtension::yOffset();
0098 }
0099 
0100 void WebKitBrowserExtension::saveState(QDataStream &stream)
0101 {
0102     // TODO: Save information such as form data from the current page.
0103     QWebHistory* history = (view() ? view()->history() : nullptr);
0104     const int historyIndex = (history ? history->currentItemIndex() : -1);
0105     const QUrl historyUrl = (history ? QUrl(history->currentItem().url()) : m_part->url());
0106 
0107     stream << historyUrl
0108            << static_cast<qint32>(xOffset())
0109            << static_cast<qint32>(yOffset())
0110            << historyIndex
0111            << m_historyData;
0112 }
0113 
0114 void WebKitBrowserExtension::restoreState(QDataStream &stream)
0115 {
0116     QUrl u;
0117     QByteArray historyData;
0118     qint32 xOfs = -1, yOfs = -1, historyItemIndex = -1;
0119     stream >> u >> xOfs >> yOfs >> historyItemIndex >> historyData;
0120 
0121     QWebHistory* history = (view() ? view()->page()->history() : nullptr);
0122     if (history) {
0123         bool success = false;
0124         if (history->count() == 0) {   // Handle restoration: crash recovery, tab close undo, session restore
0125             if (!historyData.isEmpty()) {
0126                 historyData = qUncompress(historyData); // uncompress the history data...
0127                 QBuffer buffer (&historyData);
0128                 if (buffer.open(QIODevice::ReadOnly)) {
0129                     QDataStream stream (&buffer);
0130                     view()->page()->setProperty("HistoryNavigationLocked", true);
0131                     stream >> *history;
0132                     QWebHistoryItem currentItem (history->currentItem());
0133                     if (currentItem.isValid()) {
0134                         if (currentItem.userData().isNull() && (xOfs != -1 || yOfs != -1)) {
0135                             const QPoint scrollPos (xOfs, yOfs);
0136                             currentItem.setUserData(scrollPos);
0137                         }
0138                         // NOTE 1: The following Konqueror specific workaround is necessary
0139                         // because Konqueror only preserves information for the last visited
0140                         // page. However, we save the entire history content in saveState and
0141                         // and hence need to elimiate all but the current item here.
0142                         // NOTE 2: This condition only applies when Konqueror is restored from
0143                         // abnormal termination ; a crash and/or a session restoration.
0144                         if (QCoreApplication::applicationName() == QLatin1String("konqueror")) {
0145                             history->clear();
0146                         }
0147                         //qCDebug(KWEBKITPART_LOG) << "Restoring URL:" << currentItem.url();
0148                         m_part->setProperty("NoEmitOpenUrlNotification", true);
0149                         history->goToItem(currentItem);
0150                     }
0151                 }
0152             }
0153             success = (history->count() > 0);
0154         } else {        // Handle navigation: back and forward button navigation.
0155             //qCDebug(KWEBKITPART_LOG) << "history count:" << history->count() << "request index:" << historyItemIndex;
0156             if (history->count() > historyItemIndex && historyItemIndex > -1) {
0157                 QWebHistoryItem item (history->itemAt(historyItemIndex));
0158                 //qCDebug(KWEBKITPART_LOG) << "URL:" << u << "Item URL:" << item.url();
0159                 if (u == item.url()) {
0160                     if (item.userData().isNull() && (xOfs != -1 || yOfs != -1)) {
0161                         const QPoint scrollPos (xOfs, yOfs);
0162                         item.setUserData(scrollPos);
0163                     }
0164                     m_part->setProperty("NoEmitOpenUrlNotification", true);
0165                     history->goToItem(item);
0166                     success = true;
0167                 }
0168             }
0169         }
0170 
0171         if (success) {
0172             return;
0173         }
0174     }
0175 
0176     // As a last resort, in case the history restoration logic above fails,
0177     // attempt to open the requested URL directly.
0178     qCDebug(KWEBKITPART_LOG) << "Normal history navgation logic failed! Falling back to opening url directly.";
0179     m_part->openUrl(u);
0180 }
0181 
0182 
0183 void WebKitBrowserExtension::cut()
0184 {
0185     if (view())
0186         view()->triggerPageAction(QWebPage::Cut);
0187 }
0188 
0189 void WebKitBrowserExtension::copy()
0190 {
0191     if (view())
0192         view()->triggerPageAction(QWebPage::Copy);
0193 }
0194 
0195 void WebKitBrowserExtension::paste()
0196 {
0197     if (view())
0198         view()->triggerPageAction(QWebPage::Paste);
0199 }
0200 
0201 void WebKitBrowserExtension::slotSaveDocument()
0202 {
0203     if (view())
0204         emit saveUrl(view()->url());
0205 }
0206 
0207 void WebKitBrowserExtension::slotSaveFrame()
0208 {
0209     if (view())
0210         emit saveUrl(view()->page()->currentFrame()->url());
0211 }
0212 
0213 void WebKitBrowserExtension::print()
0214 {
0215     if (view())
0216         slotPrintRequested(view()->page()->currentFrame());
0217 }
0218 
0219 void WebKitBrowserExtension::updateEditActions()
0220 {
0221     if (!view())
0222         return;
0223 
0224     enableAction("cut", view()->pageAction(QWebPage::Cut)->isEnabled());
0225     enableAction("copy", view()->pageAction(QWebPage::Copy)->isEnabled());
0226     enableAction("paste", view()->pageAction(QWebPage::Paste)->isEnabled());
0227 }
0228 
0229 void WebKitBrowserExtension::updateActions()
0230 {
0231     const QString protocol (m_part->url().scheme());
0232     const bool isValidDocument = (protocol != QL1S("about") && protocol != QL1S("error"));
0233     enableAction("print", isValidDocument);
0234 }
0235 
0236 void WebKitBrowserExtension::searchProvider()
0237 {
0238     if (!view())
0239         return;
0240 
0241     QAction *action = qobject_cast<QAction*>(sender());
0242     if (!action)
0243         return;
0244 
0245     QUrl url = action->data().toUrl();
0246 
0247     if (url.host().isEmpty()) {
0248         KUriFilterData data;
0249         data.setData(action->data().toString());
0250         if (KUriFilter::self()->filterSearchUri(data, KUriFilter::WebShortcutFilter))
0251             url = data.uri();
0252     }
0253 
0254     if (!url.isValid())
0255       return;
0256 
0257     KParts::BrowserArguments bargs;
0258     bargs.frameName = QL1S("_blank");
0259     emit openUrlRequest(url, KParts::OpenUrlArguments(), bargs);
0260 }
0261 
0262 void WebKitBrowserExtension::reparseConfiguration()
0263 {
0264     // Force the configuration stuff to reparse...
0265     WebKitSettings::self()->init();
0266 }
0267 
0268 void WebKitBrowserExtension::disableScrolling()
0269 {
0270     QWebView* currentView = view();
0271     QWebPage* page = currentView ? currentView->page() : nullptr;
0272     QWebFrame* frame = page ? page->mainFrame() : nullptr;
0273 
0274     if (!frame)
0275         return;
0276 
0277     frame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff);
0278     frame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff);
0279 }
0280 
0281 void WebKitBrowserExtension::zoomIn()
0282 {
0283     if (view())
0284         view()->setZoomFactor(view()->zoomFactor() + 0.1);
0285 }
0286 
0287 void WebKitBrowserExtension::zoomOut()
0288 {
0289     if (view())
0290         view()->setZoomFactor(view()->zoomFactor() - 0.1);
0291 }
0292 
0293 void WebKitBrowserExtension::zoomNormal()
0294 {
0295     if (view()) {
0296         if (WebKitSettings::self()->zoomToDPI())
0297             view()->setZoomFactor(view()->logicalDpiY() / 96.0f);
0298         else
0299             view()->setZoomFactor(1);
0300     }
0301 }
0302 
0303 void WebKitBrowserExtension::toogleZoomTextOnly()
0304 {
0305     if (!view())
0306         return;
0307 
0308     KConfigGroup cgHtml(KSharedConfig::openConfig(), "HTML Settings");
0309     bool zoomTextOnly = cgHtml.readEntry( "ZoomTextOnly", false );
0310     cgHtml.writeEntry("ZoomTextOnly", !zoomTextOnly);
0311     cgHtml.sync();
0312 
0313     view()->settings()->setAttribute(QWebSettings::ZoomTextOnly, !zoomTextOnly);
0314 }
0315 
0316 void WebKitBrowserExtension::toogleZoomToDPI()
0317 {
0318     if (!view())
0319         return;
0320 
0321     bool zoomToDPI = !WebKitSettings::self()->zoomToDPI();
0322     WebKitSettings::self()->setZoomToDPI(zoomToDPI);
0323     
0324     if (zoomToDPI)
0325         view()->setZoomFactor(view()->zoomFactor() * view()->logicalDpiY() / 96.0f);
0326     else 
0327         view()->setZoomFactor(view()->zoomFactor() * 96.0f / view()->logicalDpiY());
0328     
0329     // Recompute default font-sizes since they are only DPI dependent when zoomToDPI is false.
0330     WebKitSettings::self()->computeFontSizes(view()->logicalDpiY());
0331 }
0332 
0333 void WebKitBrowserExtension::slotSelectAll()
0334 {
0335     if (view())
0336         view()->triggerPageAction(QWebPage::SelectAll);
0337 }
0338 
0339 void WebKitBrowserExtension::slotFrameInWindow()
0340 {
0341     if (!view())
0342         return;
0343 
0344     KParts::BrowserArguments bargs;
0345     bargs.setForcesNewWindow(true);
0346 
0347     KParts::OpenUrlArguments uargs;
0348     uargs.setActionRequestedByUser(true);
0349 
0350     QUrl url (view()->page()->currentFrame()->baseUrl());
0351     url = url.resolved(view()->page()->currentFrame()->url());
0352 
0353     emit createNewWindow(url, uargs, bargs);
0354 }
0355 
0356 void WebKitBrowserExtension::slotFrameInTab()
0357 {
0358     if (!view())
0359         return;
0360 
0361     KParts::OpenUrlArguments uargs;
0362     uargs.setActionRequestedByUser(true);
0363 
0364     KParts::BrowserArguments bargs;
0365     bargs.setNewTab(true);
0366 
0367     QUrl url (view()->page()->currentFrame()->baseUrl());
0368     url = url.resolved(view()->page()->currentFrame()->url());
0369 
0370     emit createNewWindow(url, uargs, bargs);
0371 }
0372 
0373 void WebKitBrowserExtension::slotFrameInTop()
0374 {
0375     if (!view())
0376         return;
0377 
0378     KParts::OpenUrlArguments uargs;
0379     uargs.setActionRequestedByUser(true);
0380 
0381     KParts::BrowserArguments bargs;
0382     bargs.frameName = QL1S("_top");
0383 
0384     QUrl url (view()->page()->currentFrame()->baseUrl());
0385     url = url.resolved(view()->page()->currentFrame()->url());
0386 
0387     emit openUrlRequest(url, uargs, bargs);
0388 }
0389 
0390 void WebKitBrowserExtension::slotReloadFrame()
0391 {
0392     if (view())
0393         view()->page()->currentFrame()->load(view()->page()->currentFrame()->url());
0394 }
0395 
0396 static QString iframeUrl(QWebFrame* frame)
0397 {
0398    return ((frame && frame->baseUrl().isValid()) ? frame->baseUrl() : frame->url()).toString();
0399 }
0400 
0401 void WebKitBrowserExtension::slotBlockIFrame()
0402 {
0403     if (!view())
0404         return;
0405 
0406     bool ok = false;
0407     const QString urlStr = iframeUrl(view()->contextMenuResult().frame());
0408     const QString url = QInputDialog::getText(view(),
0409                                               i18n("Add URL to Filter"),
0410                                               i18n("Enter the URL:"),
0411                                               QLineEdit::Normal,
0412                                               urlStr, &ok);
0413     if (ok && !url.isEmpty()) {
0414         WebKitSettings::self()->addAdFilter(url);
0415         reparseConfiguration();
0416     }
0417 }
0418 
0419 void WebKitBrowserExtension::slotSaveImageAs()
0420 {
0421     if (view())
0422         view()->triggerPageAction(QWebPage::DownloadImageToDisk);
0423 }
0424 
0425 void WebKitBrowserExtension::slotSendImage()
0426 {
0427     if (!view())
0428         return;
0429 
0430     QStringList urls;
0431     urls.append(view()->contextMenuResult().imageUrl().path());
0432     const QString subject = view()->contextMenuResult().imageUrl().path();
0433     KToolInvocation::invokeMailer(QString(), QString(), QString(), subject,
0434                                   QString(), //body
0435                                   QString(),
0436                                   urls); // attachments
0437 }
0438 
0439 void WebKitBrowserExtension::slotCopyImageURL()
0440 {
0441     if (!view())
0442         return;
0443 
0444     QUrl safeURL(view()->contextMenuResult().imageUrl());
0445     safeURL.setPassword(QString());
0446     // Set it in both the mouse selection and in the clipboard
0447     QMimeData* mimeData = new QMimeData;
0448 //TODO: Porting: test
0449     QList<QUrl> safeURLList;
0450     safeURLList.append(safeURL);
0451     mimeData->setUrls(safeURLList);
0452     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
0453 
0454     mimeData = new QMimeData;
0455     mimeData->setUrls(safeURLList);
0456     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection);
0457 }
0458 
0459 
0460 void WebKitBrowserExtension::slotCopyImage()
0461 {
0462     if (!view())
0463         return;
0464 
0465     QUrl safeURL(view()->contextMenuResult().imageUrl());
0466     safeURL.setPassword(QString());
0467 
0468     // Set it in both the mouse selection and in the clipboard
0469     QMimeData* mimeData = new QMimeData;
0470     mimeData->setImageData(view()->contextMenuResult().pixmap());
0471 //TODO: Porting: test
0472     QList<QUrl> safeURLList;
0473     safeURLList.append(safeURL);
0474     mimeData->setUrls(safeURLList);
0475     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
0476 
0477     mimeData = new QMimeData;
0478     mimeData->setImageData(view()->contextMenuResult().pixmap());
0479     mimeData->setUrls(safeURLList);
0480     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection);
0481 }
0482 
0483 void WebKitBrowserExtension::slotViewImage()
0484 {
0485     if (view())
0486         emit createNewWindow(view()->contextMenuResult().imageUrl());
0487 }
0488 
0489 void WebKitBrowserExtension::slotBlockImage()
0490 {
0491     if (!view())
0492         return;
0493 
0494     bool ok = false;
0495     const QString url = QInputDialog::getText(view(),
0496                                               i18n("Add URL to Filter"),
0497                                               i18n("Enter the URL:"),
0498                                               QLineEdit::Normal,
0499                                               view()->contextMenuResult().imageUrl().toString(),
0500                                               &ok);
0501     if (ok && !url.isEmpty()) {
0502         WebKitSettings::self()->addAdFilter(url);
0503         reparseConfiguration();
0504     }
0505 }
0506 
0507 void WebKitBrowserExtension::slotBlockHost()
0508 {
0509     if (!view())
0510         return;
0511 
0512     QUrl url (view()->contextMenuResult().imageUrl());
0513     url.setPath(QL1S("/*"));
0514     WebKitSettings::self()->addAdFilter(url.toString(QUrl::RemoveUserInfo | QUrl::RemovePort));
0515     reparseConfiguration();
0516 }
0517 
0518 void WebKitBrowserExtension::slotCopyLinkURL()
0519 {
0520     if (view())
0521         view()->triggerPageAction(QWebPage::CopyLinkToClipboard);
0522 }
0523 
0524 void WebKitBrowserExtension::slotCopyLinkText()
0525 {
0526     if (view()) {
0527         QMimeData* data = new QMimeData;
0528         data->setText(view()->contextMenuResult().linkText());
0529         QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard);
0530     }
0531 }
0532 
0533 void WebKitBrowserExtension::slotCopyEmailAddress()
0534 {
0535     if (view()) {
0536         QMimeData* data = new QMimeData;
0537         const QUrl url (view()->contextMenuResult().linkUrl());
0538         data->setText(url.path());
0539         QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard);
0540     }
0541 }
0542 
0543 void WebKitBrowserExtension::slotSaveLinkAs()
0544 {
0545     if (view())
0546         view()->triggerPageAction(QWebPage::DownloadLinkToDisk);
0547 }
0548 
0549 void WebKitBrowserExtension::slotViewDocumentSource()
0550 {
0551     if (!view())
0552         return;
0553 
0554     const QUrl pageUrl (view()->url());
0555     if (pageUrl.isLocalFile()) {
0556         auto* job = new KIO::OpenUrlJob(pageUrl, QL1S("text/plain"));
0557         job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, view()));
0558         job->start();
0559     } else {
0560         QTemporaryFile tempFile(QDir::tempPath() +
0561                                 QLatin1Char('/') +
0562                                 QCoreApplication::applicationName() +
0563                                 QLatin1String("XXXXXX.html"));
0564         tempFile.setAutoRemove(false);
0565         if (tempFile.open()) {
0566             tempFile.write(view()->page()->mainFrame()->toHtml().toUtf8());
0567             tempFile.close();
0568             auto* job = new KIO::OpenUrlJob(QUrl::fromLocalFile(tempFile.fileName()), QL1S("text/plain"));
0569             job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, view()));
0570             job->setDeleteTemporaryFile(true);
0571             job->start();
0572         }
0573     }
0574 }
0575 
0576 void WebKitBrowserExtension::slotViewFrameSource()
0577 {
0578     if (!view())
0579         return;
0580 
0581     const QUrl frameUrl(view()->page()->currentFrame()->url());
0582     if (frameUrl.isLocalFile()) {
0583         auto* job = new KIO::OpenUrlJob(frameUrl, QL1S("text/plain"));
0584         job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, view()));
0585         job->start();
0586     } else {
0587         QTemporaryFile tempFile(QDir::tempPath() +
0588                                 QLatin1Char('/') +
0589                                 QCoreApplication::applicationName() +
0590                                 QLatin1String("XXXXXX.html"));
0591         tempFile.setAutoRemove(false);
0592         if (tempFile.open()) {
0593             tempFile.write(view()->page()->currentFrame()->toHtml().toUtf8());
0594             tempFile.close();
0595             auto* job = new KIO::OpenUrlJob(QUrl::fromLocalFile(tempFile.fileName()), QL1S("text/plain"));
0596             job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, view()));
0597             job->setDeleteTemporaryFile(true);
0598             job->start();
0599         }
0600     }
0601 }
0602 
0603 static bool isMultimediaElement(const QWebElement& element)
0604 {
0605     if (element.tagName().compare(QL1S("video"), Qt::CaseInsensitive) == 0)
0606         return true;
0607 
0608     if (element.tagName().compare(QL1S("audio"), Qt::CaseInsensitive) == 0)
0609         return true;
0610 
0611     return false;
0612 }
0613 
0614 void WebKitBrowserExtension::slotLoopMedia()
0615 {
0616     if (!view())
0617         return;
0618 
0619     QWebElement element (view()->contextMenuResult().element());
0620     if (!isMultimediaElement(element))
0621         return;
0622 
0623     element.evaluateJavaScript(QL1S("this.loop = !this.loop;"));
0624 }
0625 
0626 void WebKitBrowserExtension::slotMuteMedia()
0627 {
0628     if (!view())
0629         return;
0630 
0631     QWebElement element (view()->contextMenuResult().element());
0632     if (!isMultimediaElement(element))
0633         return;
0634 
0635     element.evaluateJavaScript(QL1S("this.muted = !this.muted;"));
0636 }
0637 
0638 void WebKitBrowserExtension::slotPlayMedia()
0639 {
0640     if (!view())
0641         return;
0642 
0643     QWebElement element (view()->contextMenuResult().element());
0644     if (!isMultimediaElement(element))
0645         return;
0646 
0647     element.evaluateJavaScript(QL1S("this.paused ? this.play() : this.pause();"));
0648 }
0649 
0650 void WebKitBrowserExtension::slotShowMediaControls()
0651 {
0652     if (!view())
0653         return;
0654 
0655     QWebElement element (view()->contextMenuResult().element());
0656     if (!isMultimediaElement(element))
0657         return;
0658 
0659     element.evaluateJavaScript(QL1S("this.controls = !this.controls;"));
0660 }
0661 
0662 static QUrl mediaUrlFrom(QWebElement& element)
0663 {
0664     QWebFrame* frame = element.webFrame();
0665     QString src = frame ? element.attribute(QL1S("src")) : QString();
0666     if (src.isEmpty())
0667         src = frame ? element.evaluateJavaScript(QL1S("this.src")).toString() : QString();
0668 
0669     if (src.isEmpty())
0670         return QUrl();
0671 
0672     return QUrl(frame->baseUrl().resolved(QUrl::fromEncoded(QUrl::toPercentEncoding(src), QUrl::StrictMode)));
0673 }
0674 
0675 void WebKitBrowserExtension::slotSaveMedia()
0676 {
0677     if (!view())
0678         return;
0679 
0680     QWebElement element (view()->contextMenuResult().element());
0681     if (!isMultimediaElement(element))
0682         return;
0683 
0684     emit saveUrl(mediaUrlFrom(element));
0685 }
0686 
0687 void WebKitBrowserExtension::slotCopyMedia()
0688 {
0689     if (!view())
0690         return;
0691 
0692     QWebElement element (view()->contextMenuResult().element());
0693     if (!isMultimediaElement(element))
0694         return;
0695 
0696     QUrl safeURL(mediaUrlFrom(element));
0697     if (!safeURL.isValid())
0698         return;
0699 
0700     safeURL.setPassword(QString());
0701     // Set it in both the mouse selection and in the clipboard
0702     QMimeData* mimeData = new QMimeData;
0703 //TODO: Porting: test
0704     QList<QUrl> safeURLList;
0705     safeURLList.append(safeURL);
0706     mimeData->setUrls(safeURLList);
0707     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Clipboard);
0708 
0709     mimeData = new QMimeData;
0710     mimeData->setUrls(safeURLList);
0711     QApplication::clipboard()->setMimeData(mimeData, QClipboard::Selection);
0712 }
0713 
0714 void WebKitBrowserExtension::slotTextDirectionChanged()
0715 {
0716     QAction* action = qobject_cast<QAction*>(sender());
0717     if (action) {
0718         bool ok = false;
0719         const int value = action->data().toInt(&ok);
0720         if (ok) {
0721             view()->triggerPageAction(static_cast<QWebPage::WebAction>(value));
0722         }
0723     }
0724 }
0725 
0726 static QVariant execJScript(WebView* view, const QString& script)
0727 {
0728     QWebElement element (view->contextMenuResult().element());
0729     if (element.isNull())
0730         return QVariant();
0731     return element.evaluateJavaScript(script);
0732 }
0733 
0734 void WebKitBrowserExtension::slotCheckSpelling()
0735 {
0736     const QString text (execJScript(view(), QL1S("this.value")).toString());
0737 
0738     if ( text.isEmpty() ) {
0739         return;
0740     }
0741 
0742     m_spellTextSelectionStart = 0;
0743     m_spellTextSelectionEnd = 0;
0744 
0745     Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker;
0746     Sonnet::Dialog* spellDialog = new Sonnet::Dialog(backgroundSpellCheck, view());
0747     backgroundSpellCheck->setParent(spellDialog);
0748     spellDialog->setAttribute(Qt::WA_DeleteOnClose, true);
0749     spellDialog->showSpellCheckCompletionMessage(true);
0750     connect(spellDialog, SIGNAL(replace(QString,int,QString)), this, SLOT(spellCheckerCorrected(QString,int,QString)));
0751     connect(spellDialog, SIGNAL(misspelling(QString,int)), this, SLOT(spellCheckerMisspelling(QString,int)));
0752     spellDialog->setBuffer(text);
0753     spellDialog->show();
0754 }
0755 
0756 void WebKitBrowserExtension::slotSpellCheckSelection()
0757 {
0758     QString text (execJScript(view(), QL1S("this.value")).toString());
0759 
0760     if ( text.isEmpty() ) {
0761         return;
0762     }
0763 
0764     m_spellTextSelectionStart = qMax(0, execJScript(view(), QL1S("this.selectionStart")).toInt());
0765     m_spellTextSelectionEnd = qMax(0, execJScript(view(), QL1S("this.selectionEnd")).toInt());
0766     // qCDebug(KWEBKITPART_LOG) << "selection start:" << m_spellTextSelectionStart << "end:" << m_spellTextSelectionEnd;
0767 
0768     Sonnet::BackgroundChecker *backgroundSpellCheck = new Sonnet::BackgroundChecker;
0769     Sonnet::Dialog* spellDialog = new Sonnet::Dialog(backgroundSpellCheck, view());
0770     backgroundSpellCheck->setParent(spellDialog);
0771     spellDialog->setAttribute(Qt::WA_DeleteOnClose, true);
0772     spellDialog->showSpellCheckCompletionMessage(true);
0773     connect(spellDialog, SIGNAL(replace(QString,int,QString)), this, SLOT(spellCheckerCorrected(QString,int,QString)));
0774     connect(spellDialog, SIGNAL(misspelling(QString,int)), this, SLOT(spellCheckerMisspelling(QString,int)));
0775     connect(spellDialog, SIGNAL(done(QString)), this, SLOT(slotSpellCheckDone(QString)));
0776     spellDialog->setBuffer(text.mid(m_spellTextSelectionStart, (m_spellTextSelectionEnd - m_spellTextSelectionStart)));
0777     spellDialog->show();
0778 }
0779 
0780 void WebKitBrowserExtension::spellCheckerCorrected(const QString& original, int pos, const QString& replacement)
0781 {
0782     // Adjust the selection end...
0783     if (m_spellTextSelectionEnd > 0) {
0784         m_spellTextSelectionEnd += qMax (0, (replacement.length() - original.length()));
0785     }
0786 
0787     const int index = pos + m_spellTextSelectionStart;
0788     QString script(QL1S("this.value=this.value.substring(0,"));
0789     script += QString::number(index);
0790     script += QL1S(") + \"");
0791     script +=  replacement;
0792     script += QL1S("\" + this.value.substring(");
0793     script += QString::number(index + original.length());
0794     script += QL1S(")");
0795 
0796     //qCDebug(KWEBKITPART_LOG) << "**** script:" << script;
0797     execJScript(view(), script);
0798 }
0799 
0800 void WebKitBrowserExtension::spellCheckerMisspelling(const QString& text, int pos)
0801 {
0802     // qCDebug(KWEBKITPART_LOG) << text << pos;
0803     QString selectionScript (QL1S("this.setSelectionRange("));
0804     selectionScript += QString::number(pos + m_spellTextSelectionStart);
0805     selectionScript += QL1C(',');
0806     selectionScript += QString::number(pos + text.length() + m_spellTextSelectionStart);
0807     selectionScript += QL1C(')');
0808     execJScript(view(), selectionScript);
0809 }
0810 
0811 void WebKitBrowserExtension::slotSpellCheckDone(const QString&)
0812 {
0813     // Restore the text selection if one was present before we started the
0814     // spell check.
0815     if (m_spellTextSelectionStart > 0 || m_spellTextSelectionEnd > 0) {
0816         QString script (QL1S("; this.setSelectionRange("));
0817         script += QString::number(m_spellTextSelectionStart);
0818         script += QL1C(',');
0819         script += QString::number(m_spellTextSelectionEnd);
0820         script += QL1C(')');
0821         execJScript(view(), script);
0822     }
0823 }
0824 
0825 
0826 void WebKitBrowserExtension::saveHistory()
0827 {
0828     QWebHistory* history = (view() ? view()->history() : nullptr);
0829 
0830     if (history && history->count() > 0) {
0831         //qCDebug(KWEBKITPART_LOG) << "Current history: index=" << history->currentItemIndex() << "url=" << history->currentItem().url();
0832         QByteArray histData;
0833         QBuffer buff (&histData);
0834         m_historyData.clear();
0835         if (buff.open(QIODevice::WriteOnly)) {
0836             QDataStream stream (&buff);
0837             stream << *history;
0838             m_historyData = qCompress(histData, 9);
0839         }
0840         QWidget* mainWidget = m_part ? m_part->widget() : nullptr;
0841         QWidget* frameWidget = mainWidget ? mainWidget->parentWidget() : nullptr;
0842         if (frameWidget) {
0843             emit saveHistory(frameWidget, m_historyData);
0844             // qCDebug(KWEBKITPART_LOG) << "# of items:" << history->count() << "current item:" << history->currentItemIndex() << "url:" << history->currentItem().url();
0845         }
0846     } else {
0847         Q_ASSERT(false); // should never happen!!!
0848     }
0849 }
0850 
0851 void WebKitBrowserExtension::slotPrintRequested(QWebFrame* frame)
0852 {
0853     if (!frame)
0854         return;
0855 
0856     // Make it non-modal, in case a redirection deletes the part
0857     QPointer<QPrintDialog> dlg (new QPrintDialog(view()));
0858     if (dlg->exec() == QPrintDialog::Accepted) {
0859         frame->print(dlg->printer());
0860     }
0861     delete dlg;
0862 }
0863 
0864 void WebKitBrowserExtension::slotPrintPreview()
0865 {
0866     // Make it non-modal, in case a redirection deletes the part
0867     QPointer<QPrintPreviewDialog> dlg (new QPrintPreviewDialog(view()));
0868     connect(dlg.data(), SIGNAL(paintRequested(QPrinter*)),
0869             view()->page()->currentFrame(), SLOT(print(QPrinter*)));
0870     dlg->exec();
0871     delete dlg;
0872 }
0873 
0874 void WebKitBrowserExtension::slotOpenSelection()
0875 {
0876     QAction *action = qobject_cast<QAction*>(sender());
0877     if (action) {
0878         KParts::BrowserArguments browserArgs;
0879         browserArgs.frameName = "_blank";
0880         emit openUrlRequest(QUrl(action->data().toUrl()), KParts::OpenUrlArguments(), browserArgs);
0881     }
0882 }
0883 
0884 void WebKitBrowserExtension::slotLinkInTop()
0885 {
0886     if (!view())
0887         return;
0888 
0889     KParts::OpenUrlArguments uargs;
0890     uargs.setActionRequestedByUser(true);
0891 
0892     KParts::BrowserArguments bargs;
0893     bargs.frameName = QL1S("_top");
0894 
0895     const QUrl url (view()->contextMenuResult().linkUrl());
0896 
0897     emit openUrlRequest(url, uargs, bargs);
0898 }
0899 
0900 ////
0901 
0902 KWebKitTextExtension::KWebKitTextExtension(KWebKitPart* part)
0903     : KParts::TextExtension(part)
0904 {
0905     connect(part->view(), SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()));
0906 }
0907 
0908 KWebKitPart* KWebKitTextExtension::part() const
0909 {
0910     return static_cast<KWebKitPart*>(parent());
0911 }
0912 
0913 bool KWebKitTextExtension::hasSelection() const
0914 {
0915     return part()->view()->hasSelection();
0916 }
0917 
0918 QString KWebKitTextExtension::selectedText(Format format) const
0919 {
0920     switch(format) {
0921     case PlainText:
0922         return part()->view()->selectedText();
0923     case HTML:
0924         return part()->view()->selectedHtml();
0925     }
0926     return QString();
0927 }
0928 
0929 QString KWebKitTextExtension::completeText(Format format) const
0930 {
0931     switch(format) {
0932     case PlainText:
0933         return part()->view()->page()->currentFrame()->toPlainText();
0934     case HTML:
0935         return part()->view()->page()->currentFrame()->toHtml();
0936     }
0937     return QString();
0938 }
0939 
0940 ////
0941 
0942 KWebKitHtmlExtension::KWebKitHtmlExtension(KWebKitPart* part)
0943     : KParts::HtmlExtension(part)
0944 {
0945 }
0946 
0947 
0948 QUrl KWebKitHtmlExtension::baseUrl() const
0949 {
0950     return part()->view()->page()->mainFrame()->baseUrl();
0951 }
0952 
0953 bool KWebKitHtmlExtension::hasSelection() const
0954 {
0955     return part()->view()->hasSelection();
0956 }
0957 
0958 KParts::SelectorInterface::QueryMethods KWebKitHtmlExtension::supportedQueryMethods() const
0959 {
0960     return (KParts::SelectorInterface::EntireContent
0961             | KParts::SelectorInterface::SelectedContent);
0962 }
0963 
0964 static KParts::SelectorInterface::Element convertWebElement(const QWebElement& webElem)
0965 {
0966     KParts::SelectorInterface::Element element;
0967     element.setTagName(webElem.tagName());
0968     Q_FOREACH(const QString &attr, webElem.attributeNames()) {
0969         element.setAttribute(attr, webElem.attribute(attr));
0970     }
0971     return element;
0972 }
0973 
0974 
0975 static QString queryOne(const QString& query)
0976 {
0977    QString jsQuery = QL1S("(function(query) { var element; var selectedElement = window.getSelection().getRangeAt(0).cloneContents().querySelector(\"");
0978    jsQuery += query;
0979    jsQuery += QL1S("\"); if (selectedElement && selectedElement.length > 0) { element = new Object; "
0980                    "element.tagName = String(selectedElements[0].tagName); element.href = String(selectedElements[0].href); } "
0981                    "return element; }())");
0982    return jsQuery;
0983 }
0984 
0985 static QString queryAll(const QString& query)
0986 {
0987    QString jsQuery = QL1S("(function(query) { var elements = []; var selectedElements = window.getSelection().getRangeAt(0).cloneContents().querySelectorAll(\"");
0988    jsQuery += query;
0989    jsQuery += QL1S("\"); var numSelectedElements = (selectedElements ? selectedElements.length : 0);"
0990                    "for (var i = 0; i < numSelectedElements; ++i) { var element = new Object; "
0991                    "element.tagName = String(selectedElements[i].tagName); element.href = String(selectedElements[i].href);"
0992                    "elements.push(element); } return elements; } ())");
0993    return jsQuery;
0994 }
0995 
0996 static KParts::SelectorInterface::Element convertSelectionElement(const QVariant& variant)
0997 {
0998     KParts::SelectorInterface::Element element;
0999     if (!variant.isNull() && variant.type() == QVariant::Map) {
1000         const QVariantMap elementMap (variant.toMap());
1001         element.setTagName(elementMap.value(QL1S("tagName")).toString());
1002         element.setAttribute(QL1S("href"), elementMap.value(QL1S("href")).toString());
1003     }
1004     return element;
1005 }
1006 
1007 static QList<KParts::SelectorInterface::Element> convertSelectionElements(const QVariant& variant)
1008 {
1009     QList<KParts::SelectorInterface::Element> elements;
1010     const QVariantList resultList (variant.toList());
1011     Q_FOREACH(const QVariant& result, resultList) {
1012         const QVariantMap elementMap = result.toMap();
1013         KParts::SelectorInterface::Element element;
1014         element.setTagName(elementMap.value(QL1S("tagName")).toString());
1015         element.setAttribute(QL1S("href"), elementMap.value(QL1S("href")).toString());
1016         elements.append(element);
1017     }
1018     return elements;
1019 }
1020 
1021 KParts::SelectorInterface::Element KWebKitHtmlExtension::querySelector(const QString& query, KParts::SelectorInterface::QueryMethod method) const
1022 {
1023     KParts::SelectorInterface::Element element;
1024 
1025     // If the specified method is None, return an empty list...
1026     if (method == KParts::SelectorInterface::None)
1027         return element;
1028 
1029     // If the specified method is not supported, return an empty list...
1030     if (!(supportedQueryMethods() & method))
1031         return element;
1032 
1033     switch (method) {
1034     case KParts::SelectorInterface::EntireContent: {
1035         const QWebFrame* webFrame = part()->view()->page()->mainFrame();
1036         element = convertWebElement(webFrame->findFirstElement(query));
1037         break;
1038     }
1039     case KParts::SelectorInterface::SelectedContent: {
1040         QWebFrame* webFrame = part()->view()->page()->mainFrame();
1041         element = convertSelectionElement(webFrame->evaluateJavaScript(queryOne(query)));
1042         break;
1043     }
1044     default:
1045         break;
1046     }
1047 
1048     return element;
1049 }
1050 
1051 QList<KParts::SelectorInterface::Element> KWebKitHtmlExtension::querySelectorAll(const QString& query, KParts::SelectorInterface::QueryMethod method) const
1052 {
1053     QList<KParts::SelectorInterface::Element> elements;
1054 
1055     // If the specified method is None, return an empty list...
1056     if (method == KParts::SelectorInterface::None)
1057         return elements;
1058 
1059     // If the specified method is not supported, return an empty list...
1060     if (!(supportedQueryMethods() & method))
1061         return elements;
1062 
1063     switch (method) {
1064     case KParts::SelectorInterface::EntireContent: {
1065         const QWebFrame* webFrame = part()->view()->page()->mainFrame();
1066         const QWebElementCollection collection = webFrame->findAllElements(query);
1067         elements.reserve(collection.count());
1068         Q_FOREACH(const QWebElement& element, collection)
1069             elements.append(convertWebElement(element));
1070         break;
1071     }
1072     case KParts::SelectorInterface::SelectedContent: {
1073         QWebFrame* webFrame = part()->view()->page()->mainFrame();
1074         elements = convertSelectionElements(webFrame->evaluateJavaScript(queryAll(query)));
1075         break;
1076     }
1077     default:
1078         break;
1079     }
1080     return elements;
1081 }
1082 
1083 QVariant KWebKitHtmlExtension::htmlSettingsProperty(KParts::HtmlSettingsInterface::HtmlSettingsType type) const
1084 {
1085     QWebView* view = part() ? part()->view() : nullptr;
1086     QWebPage* page = view ? view->page() : nullptr;
1087     QWebSettings* settings = page ? page->settings() : nullptr;
1088 
1089     if (settings) {
1090         switch (type) {
1091         case KParts::HtmlSettingsInterface::AutoLoadImages:
1092             return settings->testAttribute(QWebSettings::AutoLoadImages);
1093         case KParts::HtmlSettingsInterface::JavaEnabled:
1094             return settings->testAttribute(QWebSettings::JavaEnabled);
1095         case KParts::HtmlSettingsInterface::JavascriptEnabled:
1096             return settings->testAttribute(QWebSettings::JavascriptEnabled);
1097         case KParts::HtmlSettingsInterface::PluginsEnabled:
1098             return settings->testAttribute(QWebSettings::PluginsEnabled);
1099         case KParts::HtmlSettingsInterface::DnsPrefetchEnabled:
1100             return settings->testAttribute(QWebSettings::DnsPrefetchEnabled);
1101         case KParts::HtmlSettingsInterface::MetaRefreshEnabled:
1102             return view->pageAction(QWebPage::StopScheduledPageRefresh)->isEnabled();
1103         case KParts::HtmlSettingsInterface::LocalStorageEnabled:
1104             return settings->testAttribute(QWebSettings::LocalStorageEnabled);
1105         case KParts::HtmlSettingsInterface::OfflineStorageDatabaseEnabled:
1106             return settings->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled);
1107         case KParts::HtmlSettingsInterface::OfflineWebApplicationCacheEnabled:
1108             return settings->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled);
1109         case KParts::HtmlSettingsInterface::PrivateBrowsingEnabled:
1110             return settings->testAttribute(QWebSettings::PrivateBrowsingEnabled);
1111         case KParts::HtmlSettingsInterface::UserDefinedStyleSheetURL:
1112             return settings->userStyleSheetUrl();
1113         default:
1114             break;
1115         }
1116     }
1117 
1118     return QVariant();
1119 }
1120 
1121 bool KWebKitHtmlExtension::setHtmlSettingsProperty(KParts::HtmlSettingsInterface::HtmlSettingsType type, const QVariant& value)
1122 {
1123     QWebView* view = part() ? part()->view() : nullptr;
1124     QWebPage* page = view ? view->page() : nullptr;
1125     QWebSettings* settings = page ? page->settings() : nullptr;
1126 
1127     if (settings) {
1128         switch (type) {
1129         case KParts::HtmlSettingsInterface::AutoLoadImages:
1130             settings->setAttribute(QWebSettings::AutoLoadImages, value.toBool());
1131             return true;
1132         case KParts::HtmlSettingsInterface::JavaEnabled:
1133             settings->setAttribute(QWebSettings::JavaEnabled, value.toBool());
1134             return true;
1135         case KParts::HtmlSettingsInterface::JavascriptEnabled:
1136             settings->setAttribute(QWebSettings::JavascriptEnabled, value.toBool());
1137             return true;
1138         case KParts::HtmlSettingsInterface::PluginsEnabled:
1139             settings->setAttribute(QWebSettings::PluginsEnabled, value.toBool());
1140             return true;
1141         case KParts::HtmlSettingsInterface::DnsPrefetchEnabled:
1142             settings->setAttribute(QWebSettings::DnsPrefetchEnabled, value.toBool());
1143             return true;
1144         case KParts::HtmlSettingsInterface::MetaRefreshEnabled:
1145             view->triggerPageAction(QWebPage::StopScheduledPageRefresh);
1146             return true;
1147         case KParts::HtmlSettingsInterface::LocalStorageEnabled:
1148             settings->setAttribute(QWebSettings::LocalStorageEnabled, value.toBool());
1149             return true;
1150         case KParts::HtmlSettingsInterface::OfflineStorageDatabaseEnabled:
1151             settings->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, value.toBool());
1152             return true;
1153         case KParts::HtmlSettingsInterface::OfflineWebApplicationCacheEnabled:
1154             settings->setAttribute(QWebSettings::OfflineWebApplicationCacheEnabled, value.toBool());
1155             return true;
1156         case KParts::HtmlSettingsInterface::PrivateBrowsingEnabled:
1157             settings->setAttribute(QWebSettings::PrivateBrowsingEnabled, value.toBool());
1158             return true;
1159         case KParts::HtmlSettingsInterface::UserDefinedStyleSheetURL:
1160             //qCDebug(KWEBKITPART_LOG) << "Setting user style sheet for" << page << "to" << value.toUrl();
1161             settings->setUserStyleSheetUrl(value.toUrl());
1162             return true;
1163         default:
1164             break;
1165         }
1166     }
1167 
1168     return false;
1169 }
1170 
1171 KWebKitPart* KWebKitHtmlExtension::part() const
1172 {
1173     return static_cast<KWebKitPart*>(parent());
1174 }
1175 
1176 KWebKitScriptableExtension::KWebKitScriptableExtension(KWebKitPart* part)
1177     : ScriptableExtension(part)
1178 {
1179 }
1180 
1181 QVariant KWebKitScriptableExtension::rootObject()
1182 {
1183     return QVariant::fromValue(KParts::ScriptableExtension::Object(this, reinterpret_cast<quint64>(this)));
1184 }
1185 
1186 bool KWebKitScriptableExtension::setException (KParts::ScriptableExtension* callerPrincipal, const QString& message)
1187 {
1188     return KParts::ScriptableExtension::setException (callerPrincipal, message);
1189 }
1190 
1191 QVariant KWebKitScriptableExtension::get (KParts::ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName)
1192 {
1193     //qCDebug(KWEBKITPART_LOG) << "caller:" << callerPrincipal << "id:" << objId << "propName:" << propName;
1194     return callerPrincipal->get (nullptr, objId, propName);
1195 }
1196 
1197 bool KWebKitScriptableExtension::put (KParts::ScriptableExtension* callerPrincipal, quint64 objId, const QString& propName, const QVariant& value)
1198 {
1199     return KParts::ScriptableExtension::put (callerPrincipal, objId, propName, value);
1200 }
1201 
1202 static QVariant exception(const char* msg)
1203 {
1204     qCWarning(KWEBKITPART_LOG) << msg;
1205     return QVariant::fromValue(KParts::ScriptableExtension::Exception(QString::fromLatin1(msg)));
1206 }
1207 
1208 QVariant KWebKitScriptableExtension::evaluateScript (KParts::ScriptableExtension* callerPrincipal,
1209                                                      quint64 contextObjectId,
1210                                                      const QString& code,
1211                                                      KParts::ScriptableExtension::ScriptLanguage lang)
1212 {
1213     Q_UNUSED(contextObjectId);
1214     //qCDebug(KWEBKITPART_LOG) << "principal:" << callerPrincipal << "id:" << contextObjectId << "language:" << lang << "code:" << code;
1215 
1216     if (lang != ECMAScript)
1217         return exception("unsupported language");
1218 
1219 
1220     KParts::ReadOnlyPart* part = callerPrincipal ? qobject_cast<KParts::ReadOnlyPart*>(callerPrincipal->parent()) : nullptr;
1221     QWebFrame* frame = part ? qobject_cast<QWebFrame*>(part->parent()) : nullptr;
1222     if (!frame)
1223         return exception("failed to resolve principal");
1224 
1225     QVariant result (frame->evaluateJavaScript(code));
1226 
1227     if (result.type() == QVariant::Map) {
1228         const QVariantMap map (result.toMap());
1229         for (QVariantMap::const_iterator it = map.constBegin(), itEnd = map.constEnd(); it != itEnd; ++it) {
1230             callerPrincipal->put(callerPrincipal, 0, it.key(), it.value());
1231         }
1232     } else {
1233         const QString propName(code.contains(QLatin1String("__nsplugin")) ? QLatin1String("__nsplugin") : QString());
1234         callerPrincipal->put(callerPrincipal, 0, propName, result.toString());
1235     }
1236 
1237     return QVariant::fromValue(ScriptableExtension::Null());
1238 }
1239 
1240 bool KWebKitScriptableExtension::isScriptLanguageSupported (KParts::ScriptableExtension::ScriptLanguage lang) const
1241 {
1242     return (lang == KParts::ScriptableExtension::ECMAScript);
1243 }
1244 
1245 QVariant KWebKitScriptableExtension::encloserForKid (KParts::ScriptableExtension* kid)
1246 {
1247     KParts::ReadOnlyPart* part = kid ? qobject_cast<KParts::ReadOnlyPart*>(kid->parent()) : nullptr;
1248     QWebFrame* frame = part ? qobject_cast<QWebFrame*>(part->parent()) : nullptr;
1249     if (frame) {
1250         return QVariant::fromValue(KParts::ScriptableExtension::Object(kid, reinterpret_cast<quint64>(kid)));
1251     }
1252 
1253     return QVariant::fromValue(ScriptableExtension::Null());
1254 }
1255 
1256 KWebKitPart* KWebKitScriptableExtension::part()
1257 {
1258     return qobject_cast<KWebKitPart*>(parent());
1259 }