File indexing completed on 2024-05-12 04:58:29
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 * ============================================================ */ 0018 #include "webpage.h" 0019 #include "tabbedwebview.h" 0020 #include "browserwindow.h" 0021 #include "pluginproxy.h" 0022 #include "downloadmanager.h" 0023 #include "mainapplication.h" 0024 #include "checkboxdialog.h" 0025 #include "qztools.h" 0026 #include "speeddial.h" 0027 #include "autofill.h" 0028 #include "popupwebview.h" 0029 #include "popupwindow.h" 0030 #include "iconprovider.h" 0031 #include "qzsettings.h" 0032 #include "useragentmanager.h" 0033 #include "delayedfilewatcher.h" 0034 #include "searchenginesmanager.h" 0035 #include "html5permissions/html5permissionsmanager.h" 0036 #include "javascript/externaljsobject.h" 0037 #include "tabwidget.h" 0038 #include "networkmanager.h" 0039 #include "webhittestresult.h" 0040 #include "ui_jsconfirm.h" 0041 #include "ui_jsalert.h" 0042 #include "ui_jsprompt.h" 0043 #include "passwordmanager.h" 0044 #include "scripts.h" 0045 #include "ocssupport.h" 0046 0047 #include <iostream> 0048 0049 #include <QDir> 0050 #include <QMouseEvent> 0051 #include <QWebChannel> 0052 #include <QWebEngineHistory> 0053 #include <QWebEngineSettings> 0054 #include <QTimer> 0055 #include <QDesktopServices> 0056 #include <QMessageBox> 0057 #include <QFileDialog> 0058 #include <QAuthenticator> 0059 #include <QPushButton> 0060 #include <QUrlQuery> 0061 #include <QtWebEngineWidgetsVersion> 0062 0063 #include <QWebEngineRegisterProtocolHandlerRequest> 0064 0065 QString WebPage::s_lastUploadLocation = QDir::homePath(); 0066 QUrl WebPage::s_lastUnsupportedUrl; 0067 QElapsedTimer WebPage::s_lastUnsupportedUrlTime; 0068 QStringList s_supportedSchemes; 0069 0070 static const bool kEnableJsOutput = qEnvironmentVariableIsSet("FALKON_ENABLE_JS_OUTPUT"); 0071 static const bool kEnableJsNonBlockDialogs = qEnvironmentVariableIsSet("FALKON_ENABLE_JS_NONBLOCK_DIALOGS"); 0072 0073 WebPage::WebPage(QObject* parent) 0074 : QWebEnginePage(mApp->webProfile(), parent) 0075 , m_fileWatcher(nullptr) 0076 , m_runningLoop(nullptr) 0077 , m_loadProgress(100) 0078 , m_blockAlerts(false) 0079 , m_secureStatus(false) 0080 { 0081 auto *channel = new QWebChannel(this); 0082 ExternalJsObject::setupWebChannel(channel, this); 0083 setWebChannel(channel, SafeJsWorld); 0084 0085 connect(this, &QWebEnginePage::loadProgress, this, &WebPage::progress); 0086 connect(this, &QWebEnginePage::loadFinished, this, &WebPage::finished); 0087 connect(this, &QWebEnginePage::urlChanged, this, &WebPage::urlChanged); 0088 connect(this, &QWebEnginePage::featurePermissionRequested, this, &WebPage::featurePermissionRequested); 0089 connect(this, &QWebEnginePage::windowCloseRequested, this, &WebPage::windowCloseRequested); 0090 connect(this, &QWebEnginePage::fullScreenRequested, this, &WebPage::fullScreenRequested); 0091 connect(this, &QWebEnginePage::renderProcessTerminated, this, &WebPage::renderProcessTerminated); 0092 connect(this, &QWebEnginePage::certificateError, this, &WebPage::onCertificateError); 0093 0094 connect(this, &QWebEnginePage::authenticationRequired, this, [this](const QUrl &url, QAuthenticator *auth) { 0095 mApp->networkManager()->authentication(url, auth, view()); 0096 }); 0097 0098 connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, [this](const QUrl &, QAuthenticator *auth, const QString &proxyHost) { 0099 mApp->networkManager()->proxyAuthentication(proxyHost, auth, view()); 0100 }); 0101 0102 // Workaround QWebEnginePage not scrolling to anchors when opened in background tab 0103 m_contentsResizedConnection = connect(this, &QWebEnginePage::contentsSizeChanged, this, [this]() { 0104 const QString fragment = url().fragment(); 0105 if (!fragment.isEmpty()) { 0106 runJavaScript(Scripts::scrollToAnchor(fragment)); 0107 } 0108 disconnect(m_contentsResizedConnection); 0109 }); 0110 0111 // Workaround for broken load started/finished signals in QtWebEngine 5.10, 5.11 0112 connect(this, &QWebEnginePage::loadProgress, this, [this](int progress) { 0113 if (progress == 100) { 0114 Q_EMIT loadFinished(true); 0115 } 0116 }); 0117 0118 connect(this, &QWebEnginePage::registerProtocolHandlerRequested, this, [this](QWebEngineRegisterProtocolHandlerRequest request) { 0119 delete m_registerProtocolHandlerRequest; 0120 m_registerProtocolHandlerRequest = new QWebEngineRegisterProtocolHandlerRequest(request); 0121 }); 0122 connect(this, &QWebEnginePage::printRequested, this, &WebPage::printRequested); 0123 connect(this, &QWebEnginePage::selectClientCertificate, this, [this](QWebEngineClientCertificateSelection selection) { 0124 // TODO: It should prompt user 0125 selection.select(selection.certificates().at(0)); 0126 }); 0127 } 0128 0129 WebPage::~WebPage() 0130 { 0131 delete m_registerProtocolHandlerRequest; 0132 0133 if (m_runningLoop) { 0134 m_runningLoop->exit(1); 0135 m_runningLoop = nullptr; 0136 } 0137 } 0138 0139 WebView *WebPage::view() const 0140 { 0141 return static_cast<WebView*>(QWebEngineView::forPage(this)); 0142 } 0143 0144 bool WebPage::execPrintPage(QPrinter *printer, int timeout) 0145 { 0146 QPointer<QEventLoop> loop = new QEventLoop; 0147 bool result = false; 0148 QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit); 0149 0150 connect(view(), &QWebEngineView::printFinished, this, [loop, &result](bool res) { 0151 if (loop && loop->isRunning()) { 0152 result = res; 0153 loop->quit(); 0154 } 0155 }); 0156 view()->print(printer); 0157 0158 loop->exec(); 0159 delete loop; 0160 0161 return result; 0162 } 0163 0164 QVariant WebPage::execJavaScript(const QString &scriptSource, quint32 worldId, int timeout) 0165 { 0166 QPointer<QEventLoop> loop = new QEventLoop; 0167 QVariant result; 0168 QTimer::singleShot(timeout, loop.data(), &QEventLoop::quit); 0169 0170 runJavaScript(scriptSource, worldId, [loop, &result](const QVariant &res) { 0171 if (loop && loop->isRunning()) { 0172 result = res; 0173 loop->quit(); 0174 } 0175 }); 0176 0177 loop->exec(QEventLoop::ExcludeUserInputEvents); 0178 delete loop; 0179 0180 return result; 0181 } 0182 0183 QPointF WebPage::mapToViewport(const QPointF &pos) const 0184 { 0185 return QPointF(pos.x() / zoomFactor(), pos.y() / zoomFactor()); 0186 } 0187 0188 WebHitTestResult WebPage::hitTestContent(const QPoint &pos) const 0189 { 0190 return WebHitTestResult(this, pos); 0191 } 0192 0193 void WebPage::scroll(int x, int y) 0194 { 0195 runJavaScript(QSL("window.scrollTo(window.scrollX + %1, window.scrollY + %2)").arg(x).arg(y), SafeJsWorld); 0196 } 0197 0198 void WebPage::setScrollPosition(const QPointF &pos) 0199 { 0200 const QPointF v = mapToViewport(pos.toPoint()); 0201 runJavaScript(QSL("window.scrollTo(%1, %2)").arg(v.x()).arg(v.y()), SafeJsWorld); 0202 } 0203 0204 bool WebPage::isRunningLoop() 0205 { 0206 return m_runningLoop; 0207 } 0208 0209 bool WebPage::isLoading() const 0210 { 0211 return m_loadProgress < 100; 0212 } 0213 0214 // static 0215 QStringList WebPage::internalSchemes() 0216 { 0217 return QStringList{ 0218 QSL("http"), 0219 QSL("https"), 0220 QSL("file"), 0221 QSL("ftp"), 0222 QSL("data"), 0223 QSL("about"), 0224 QSL("view-source"), 0225 QSL("chrome") 0226 }; 0227 } 0228 0229 // static 0230 QStringList WebPage::supportedSchemes() 0231 { 0232 if (s_supportedSchemes.isEmpty()) { 0233 s_supportedSchemes = internalSchemes(); 0234 } 0235 return s_supportedSchemes; 0236 } 0237 0238 // static 0239 void WebPage::addSupportedScheme(const QString &scheme) 0240 { 0241 s_supportedSchemes = supportedSchemes(); 0242 if (!s_supportedSchemes.contains(scheme)) { 0243 s_supportedSchemes.append(scheme); 0244 } 0245 } 0246 0247 // static 0248 void WebPage::removeSupportedScheme(const QString &scheme) 0249 { 0250 s_supportedSchemes.removeOne(scheme); 0251 } 0252 0253 void WebPage::urlChanged(const QUrl &url) 0254 { 0255 Q_UNUSED(url) 0256 0257 if (isLoading()) { 0258 m_blockAlerts = false; 0259 } 0260 } 0261 0262 void WebPage::progress(int prog) 0263 { 0264 m_loadProgress = prog; 0265 0266 bool secStatus = url().scheme() == QL1S("https"); 0267 0268 if (secStatus != m_secureStatus) { 0269 m_secureStatus = secStatus; 0270 Q_EMIT privacyChanged(secStatus); 0271 } 0272 } 0273 0274 void WebPage::finished() 0275 { 0276 progress(100); 0277 0278 // File scheme watcher 0279 if (url().scheme() == QLatin1String("file")) { 0280 QFileInfo info(url().toLocalFile()); 0281 if (info.isFile()) { 0282 if (!m_fileWatcher) { 0283 m_fileWatcher = new DelayedFileWatcher(this); 0284 connect(m_fileWatcher, &DelayedFileWatcher::delayedFileChanged, this, &WebPage::watchedFileChanged); 0285 } 0286 0287 const QString filePath = url().toLocalFile(); 0288 0289 if (QFile::exists(filePath) && !m_fileWatcher->files().contains(filePath)) { 0290 m_fileWatcher->addPath(filePath); 0291 } 0292 } 0293 } 0294 else if (m_fileWatcher && !m_fileWatcher->files().isEmpty()) { 0295 m_fileWatcher->removePaths(m_fileWatcher->files()); 0296 } 0297 0298 // AutoFill 0299 m_autoFillUsernames = mApp->autoFill()->completePage(this, url()); 0300 } 0301 0302 void WebPage::watchedFileChanged(const QString &file) 0303 { 0304 if (url().toLocalFile() == file) { 0305 triggerAction(QWebEnginePage::Reload); 0306 } 0307 } 0308 0309 void WebPage::handleUnknownProtocol(const QUrl &url) 0310 { 0311 const QString protocol = url.scheme(); 0312 0313 if (protocol == QLatin1String("mailto")) { 0314 desktopServicesOpen(url); 0315 return; 0316 } 0317 0318 if (qzSettings->blockedProtocols.contains(protocol)) { 0319 qDebug() << "WebPage::handleUnknownProtocol Protocol" << protocol << "is blocked!"; 0320 return; 0321 } 0322 0323 if (qzSettings->autoOpenProtocols.contains(protocol)) { 0324 desktopServicesOpen(url); 0325 return; 0326 } 0327 0328 CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, view()); 0329 dialog.setDefaultButton(QMessageBox::Yes); 0330 0331 const QString wrappedUrl = QzTools::alignTextToWidth(url.toString(), QSL("<br/>"), dialog.fontMetrics(), 450); 0332 const QString text = tr("Falkon cannot handle <b>%1:</b> links. The requested link " 0333 "is <ul><li>%2</li></ul>Do you want Falkon to try " 0334 "open this link in system application?").arg(protocol, wrappedUrl); 0335 0336 dialog.setText(text); 0337 dialog.setCheckBoxText(tr("Remember my choice for this protocol")); 0338 dialog.setWindowTitle(tr("External Protocol Request")); 0339 dialog.setIcon(QMessageBox::Question); 0340 0341 switch (dialog.exec()) { 0342 case QMessageBox::Yes: 0343 if (dialog.isChecked()) { 0344 qzSettings->autoOpenProtocols.append(protocol); 0345 qzSettings->saveSettings(); 0346 } 0347 0348 0349 QDesktopServices::openUrl(url); 0350 break; 0351 0352 case QMessageBox::No: 0353 if (dialog.isChecked()) { 0354 qzSettings->blockedProtocols.append(protocol); 0355 qzSettings->saveSettings(); 0356 } 0357 0358 break; 0359 0360 default: 0361 break; 0362 } 0363 } 0364 0365 void WebPage::desktopServicesOpen(const QUrl &url) 0366 { 0367 // Open same url only once in 2 secs 0368 const int sameUrlTimeout = 2 * 1000; 0369 0370 if ((s_lastUnsupportedUrl != url) || (!s_lastUnsupportedUrlTime.isValid()) || (s_lastUnsupportedUrlTime.elapsed() > sameUrlTimeout)) { 0371 s_lastUnsupportedUrl = url; 0372 s_lastUnsupportedUrlTime.restart(); 0373 QDesktopServices::openUrl(url); 0374 } 0375 else { 0376 qWarning() << "WebPage::desktopServicesOpen Url" << url << "has already been opened!\n" 0377 "Ignoring it to prevent infinite loop!"; 0378 } 0379 } 0380 0381 void WebPage::windowCloseRequested() 0382 { 0383 if (!view()) 0384 return; 0385 view()->closeView(); 0386 } 0387 0388 void WebPage::fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest) 0389 { 0390 view()->requestFullScreen(fullScreenRequest.toggleOn()); 0391 0392 const bool accepted = fullScreenRequest.toggleOn() == view()->isFullScreen(); 0393 0394 if (accepted) 0395 fullScreenRequest.accept(); 0396 else 0397 fullScreenRequest.reject(); 0398 } 0399 0400 void WebPage::featurePermissionRequested(const QUrl &origin, const QWebEnginePage::Feature &feature) 0401 { 0402 if (feature == MouseLock && view()->isFullScreen()) 0403 setFeaturePermission(origin, feature, PermissionGrantedByUser); 0404 else 0405 mApp->html5PermissionsManager()->requestPermissions(this, origin, feature); 0406 } 0407 0408 void WebPage::renderProcessTerminated(QWebEnginePage::RenderProcessTerminationStatus terminationStatus, int exitCode) 0409 { 0410 Q_UNUSED(exitCode) 0411 0412 if (terminationStatus == NormalTerminationStatus) 0413 return; 0414 0415 QTimer::singleShot(0, this, [this]() { 0416 QString page = QzTools::readAllFileContents(QSL(":html/tabcrash.html")); 0417 page.replace(QL1S("%IMAGE%"), QzTools::pixmapToDataUrl(IconProvider::standardIcon(QStyle::SP_MessageBoxWarning).pixmap(45)).toString()); 0418 page.replace(QL1S("%TITLE%"), tr("Failed loading page")); 0419 page.replace(QL1S("%HEADING%"), tr("Failed loading page")); 0420 page.replace(QL1S("%LI-1%"), tr("Something went wrong while loading this page.")); 0421 page.replace(QL1S("%LI-2%"), tr("Try reloading the page or closing some tabs to make more memory available.")); 0422 page.replace(QL1S("%RELOAD-PAGE%"), tr("Reload page")); 0423 page = QzTools::applyDirectionToPage(page); 0424 setHtml(page, url()); 0425 }); 0426 } 0427 0428 bool WebPage::acceptNavigationRequest(const QUrl &url, QWebEnginePage::NavigationType type, bool isMainFrame) 0429 { 0430 if (mApp->isClosing()) { 0431 return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame); 0432 } 0433 0434 if (!mApp->plugins()->acceptNavigationRequest(this, url, type, isMainFrame)) 0435 return false; 0436 0437 if (url.scheme() == QL1S("falkon")) { 0438 if (url.path() == QL1S("AddSearchProvider")) { 0439 QUrlQuery query(url); 0440 mApp->searchEnginesManager()->addEngine(QUrl(query.queryItemValue(QSL("url")))); 0441 return false; 0442 } 0443 } 0444 0445 if (url.scheme() == QL1S("ocs") && OcsSupport::instance()->handleUrl(url)) { 0446 return false; 0447 } 0448 0449 const bool result = QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame); 0450 0451 if (result) { 0452 if (isMainFrame) { 0453 const bool isWeb = url.scheme() == QL1S("http") || url.scheme() == QL1S("https") || url.scheme() == QL1S("file"); 0454 const bool globalJsEnabled = mApp->webSettings()->testAttribute(QWebEngineSettings::JavascriptEnabled); 0455 settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, isWeb ? globalJsEnabled : true); 0456 } 0457 Q_EMIT navigationRequestAccepted(url, type, isMainFrame); 0458 } 0459 0460 return result; 0461 } 0462 0463 void WebPage::onCertificateError(QWebEngineCertificateError error) 0464 { 0465 auto mutableError = const_cast<QWebEngineCertificateError&>(error); 0466 if (mApp->networkManager()->certificateError(mutableError, view())) 0467 mutableError.acceptCertificate(); 0468 else 0469 mutableError.rejectCertificate(); 0470 } 0471 0472 QStringList WebPage::chooseFiles(QWebEnginePage::FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) 0473 { 0474 Q_UNUSED(acceptedMimeTypes); 0475 0476 QStringList files; 0477 QString suggestedFileName = s_lastUploadLocation; 0478 if (!oldFiles.isEmpty()) 0479 suggestedFileName = oldFiles.at(0); 0480 0481 switch (mode) { 0482 case FileSelectOpen: 0483 files = QStringList(QzTools::getOpenFileName(QSL("WebPage-ChooseFile"), view(), tr("Choose file..."), suggestedFileName)); 0484 break; 0485 0486 case FileSelectOpenMultiple: 0487 files = QzTools::getOpenFileNames(QSL("WebPage-ChooseFile"), view(), tr("Choose files..."), suggestedFileName); 0488 break; 0489 0490 default: 0491 files = QWebEnginePage::chooseFiles(mode, oldFiles, acceptedMimeTypes); 0492 break; 0493 } 0494 0495 if (!files.isEmpty()) 0496 s_lastUploadLocation = files.at(0); 0497 0498 return files; 0499 } 0500 0501 QStringList WebPage::autoFillUsernames() const 0502 { 0503 return m_autoFillUsernames; 0504 } 0505 0506 QUrl WebPage::registerProtocolHandlerRequestUrl() const 0507 { 0508 if (m_registerProtocolHandlerRequest && url().host() == m_registerProtocolHandlerRequest->origin().host()) { 0509 return m_registerProtocolHandlerRequest->origin(); 0510 } 0511 return {}; 0512 } 0513 0514 QString WebPage::registerProtocolHandlerRequestScheme() const 0515 { 0516 if (m_registerProtocolHandlerRequest && url().host() == m_registerProtocolHandlerRequest->origin().host()) { 0517 return m_registerProtocolHandlerRequest->scheme(); 0518 } 0519 return {}; 0520 } 0521 0522 bool WebPage::javaScriptPrompt(const QUrl &securityOrigin, const QString &msg, const QString &defaultValue, QString* result) 0523 { 0524 if (!kEnableJsNonBlockDialogs) { 0525 return QWebEnginePage::javaScriptPrompt(securityOrigin, msg, defaultValue, result); 0526 } 0527 0528 if (m_runningLoop) { 0529 return false; 0530 } 0531 0532 auto *widget = new QFrame(view()->overlayWidget()); 0533 0534 widget->setObjectName("jsFrame"); 0535 auto* ui = new Ui_jsPrompt(); 0536 ui->setupUi(widget); 0537 ui->message->setText(msg); 0538 ui->lineEdit->setText(defaultValue); 0539 ui->lineEdit->setFocus(); 0540 widget->resize(view()->size()); 0541 widget->show(); 0542 0543 QAbstractButton *clicked = nullptr; 0544 connect(ui->buttonBox, &QDialogButtonBox::clicked, this, [&](QAbstractButton *button) { 0545 clicked = button; 0546 }); 0547 0548 connect(view(), &WebView::viewportResized, widget, QOverload<const QSize &>::of(&QFrame::resize)); 0549 connect(ui->lineEdit, SIGNAL(returnPressed()), ui->buttonBox->button(QDialogButtonBox::Ok), SLOT(animateClick())); 0550 0551 QEventLoop eLoop; 0552 m_runningLoop = &eLoop; 0553 connect(ui->buttonBox, &QDialogButtonBox::clicked, &eLoop, &QEventLoop::quit); 0554 0555 if (eLoop.exec() == 1) { 0556 return result; 0557 } 0558 m_runningLoop = nullptr; 0559 0560 QString x = ui->lineEdit->text(); 0561 bool _result = ui->buttonBox->buttonRole(clicked) == QDialogButtonBox::AcceptRole; 0562 *result = x; 0563 0564 delete widget; 0565 view()->setFocus(); 0566 0567 return _result; 0568 } 0569 0570 bool WebPage::javaScriptConfirm(const QUrl &securityOrigin, const QString &msg) 0571 { 0572 if (!kEnableJsNonBlockDialogs) { 0573 return QWebEnginePage::javaScriptConfirm(securityOrigin, msg); 0574 } 0575 0576 if (m_runningLoop) { 0577 return false; 0578 } 0579 0580 auto *widget = new QFrame(view()->overlayWidget()); 0581 0582 widget->setObjectName("jsFrame"); 0583 auto* ui = new Ui_jsConfirm(); 0584 ui->setupUi(widget); 0585 ui->message->setText(msg); 0586 ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); 0587 widget->resize(view()->size()); 0588 widget->show(); 0589 0590 QAbstractButton *clicked = nullptr; 0591 connect(ui->buttonBox, &QDialogButtonBox::clicked, this, [&](QAbstractButton *button) { 0592 clicked = button; 0593 }); 0594 0595 connect(view(), &WebView::viewportResized, widget, QOverload<const QSize &>::of(&QFrame::resize)); 0596 0597 QEventLoop eLoop; 0598 m_runningLoop = &eLoop; 0599 connect(ui->buttonBox, &QDialogButtonBox::clicked, &eLoop, &QEventLoop::quit); 0600 0601 if (eLoop.exec() == 1) { 0602 return false; 0603 } 0604 m_runningLoop = nullptr; 0605 0606 bool result = ui->buttonBox->buttonRole(clicked) == QDialogButtonBox::AcceptRole; 0607 0608 delete widget; 0609 view()->setFocus(); 0610 0611 return result; 0612 } 0613 0614 void WebPage::javaScriptAlert(const QUrl &securityOrigin, const QString &msg) 0615 { 0616 Q_UNUSED(securityOrigin) 0617 0618 if (m_blockAlerts || m_runningLoop) { 0619 return; 0620 } 0621 0622 if (!kEnableJsNonBlockDialogs) { 0623 QString title = tr("JavaScript alert"); 0624 if (!url().host().isEmpty()) { 0625 title.append(QSL(" - %1").arg(url().host())); 0626 } 0627 0628 CheckBoxDialog dialog(QMessageBox::Ok, view()); 0629 dialog.setDefaultButton(QMessageBox::Ok); 0630 dialog.setWindowTitle(title); 0631 dialog.setText(msg); 0632 dialog.setCheckBoxText(tr("Prevent this page from creating additional dialogs")); 0633 dialog.setIcon(QMessageBox::Information); 0634 dialog.exec(); 0635 0636 m_blockAlerts = dialog.isChecked(); 0637 return; 0638 } 0639 0640 auto *widget = new QFrame(view()->overlayWidget()); 0641 0642 widget->setObjectName("jsFrame"); 0643 auto* ui = new Ui_jsAlert(); 0644 ui->setupUi(widget); 0645 ui->message->setText(msg); 0646 ui->buttonBox->button(QDialogButtonBox::Ok)->setFocus(); 0647 widget->resize(view()->size()); 0648 widget->show(); 0649 0650 connect(view(), &WebView::viewportResized, widget, QOverload<const QSize &>::of(&QFrame::resize)); 0651 0652 QEventLoop eLoop; 0653 m_runningLoop = &eLoop; 0654 connect(ui->buttonBox, &QDialogButtonBox::clicked, &eLoop, &QEventLoop::quit); 0655 0656 if (eLoop.exec() == 1) { 0657 return; 0658 } 0659 m_runningLoop = nullptr; 0660 0661 m_blockAlerts = ui->preventAlerts->isChecked(); 0662 0663 delete widget; 0664 0665 view()->setFocus(); 0666 } 0667 0668 void WebPage::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID) 0669 { 0670 if (!kEnableJsOutput) { 0671 return; 0672 } 0673 0674 switch (level) { 0675 case InfoMessageLevel: 0676 std::cout << "[I] "; 0677 break; 0678 0679 case WarningMessageLevel: 0680 std::cout << "[W] "; 0681 break; 0682 0683 case ErrorMessageLevel: 0684 std::cout << "[E] "; 0685 break; 0686 } 0687 0688 std::cout << qPrintable(sourceID) << ":" << lineNumber << " " << qPrintable(message); 0689 } 0690 0691 QWebEnginePage* WebPage::createWindow(QWebEnginePage::WebWindowType type) 0692 { 0693 auto *tView = qobject_cast<TabbedWebView*>(view()); 0694 BrowserWindow *window = tView ? tView->browserWindow() : mApp->getWindow(); 0695 0696 auto createTab = [=](Qz::NewTabPositionFlags pos) { 0697 int index = window->tabWidget()->addView(QUrl(), pos); 0698 TabbedWebView* view = window->weView(index); 0699 view->setPage(new WebPage); 0700 if (tView) { 0701 tView->webTab()->addChildTab(view->webTab()); 0702 } 0703 // Workaround focus issue when creating tab 0704 if (pos.testFlag(Qz::NT_SelectedTab)) { 0705 QPointer<TabbedWebView> pview = view; 0706 pview->setFocus(); 0707 QTimer::singleShot(100, this, [pview]() { 0708 if (pview && pview->webTab()->isCurrentTab()) { 0709 pview->setFocus(); 0710 } 0711 }); 0712 } 0713 return view->page(); 0714 }; 0715 0716 switch (type) { 0717 case QWebEnginePage::WebBrowserWindow: { 0718 BrowserWindow *window = mApp->createWindow(Qz::BW_NewWindow); 0719 auto *page = new WebPage; 0720 window->setStartPage(page); 0721 return page; 0722 } 0723 0724 case QWebEnginePage::WebDialog: 0725 if (!qzSettings->openPopupsInTabs) { 0726 auto* view = new PopupWebView; 0727 view->setPage(new WebPage); 0728 auto* popup = new PopupWindow(view); 0729 popup->show(); 0730 window->addDeleteOnCloseWidget(popup); 0731 return view->page(); 0732 } 0733 // else fallthrough 0734 0735 case QWebEnginePage::WebBrowserTab: 0736 return createTab(Qz::NT_CleanSelectedTab); 0737 0738 case QWebEnginePage::WebBrowserBackgroundTab: 0739 return createTab(Qz::NT_CleanNotSelectedTab); 0740 0741 default: 0742 break; 0743 } 0744 0745 return nullptr; 0746 }