Created
August 20, 2024 07:38
-
-
Save jevinskie/240d9343a5230468664dbe74a5a9d170 to your computer and use it in GitHub Desktop.
SafariShared.framework embedded JavaScript and HTML - iOS 18.0 beta 6 22A5338b
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// # sourceURL=__InjectedScript_AutomaticPasswords.js | |
/* Copyright (c) 2024 Apple Inc. All rights reserved. */ | |
FormMetadata.prototype._collectExtraControlMetadata = function(t, o) { | |
let e = t.getAttribute("passwordrules"); | |
o.ControlPasswordRules = e || void 0 | |
}, FormMetadata.prototype.removeAutomaticStrongPasswordFromPasswordElement = function(t) { | |
let o = this.formControlWithUniqueID(t); | |
o && this._isTextField(o) && (this.clearField(t), this._updateAnnotationsForField(o), FormMetadataJSController.setInputElementAutofilled(o, !1)) | |
}; | |
let AutomaticPasswords = function() {}; | |
AutomaticPasswords.prototype = { | |
removeAutomaticPasswordElements : function(t, o, e) { | |
for (let o of t) | |
FormMetadataJS.removeAutomaticStrongPasswordFromPasswordElement(o); | |
if (!e) | |
return; | |
let r = document.activeElement, | |
a = o ? FormMetadataJS.formControlWithUniqueID(o) : null; | |
a && a.blur(), a && a === r && a.focus() | |
}, | |
blurControlWithID : function(t) { | |
let o = t ? FormMetadataJS.formControlWithUniqueID(t) : null; | |
o && o.blur() | |
}, | |
setStrongPasswordElementViewableIfAppropriate : function(t, o) { | |
for (let e of t) { | |
let t = FormMetadataJS.formControlWithUniqueID(e); | |
if (!t) | |
return; | |
if ("text" === t.type) | |
return FormMetadataJSController.setInputElementAutoFilledAndViewable(t, !1), void FormMetadataJSController.setInputElementAutofilled(t, !1); | |
FormMetadataJSController.setInputElementAutoFilledAndViewable(t, o) | |
} | |
} | |
}; | |
var AutomaticPasswordsJS = new AutomaticPasswords; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=utf-8"> | |
<meta name="viewport" content="width=device-width, viewport-fit=cover"> | |
<title class="l12n">This Connection Is Not Private</title> | |
<style> | |
body { | |
--font-color: #434343; | |
--compact-font-color: #434343; | |
--blue-color: rgb(0, 122, 255); | |
--horizontal-padding: 32px; | |
--compact-horizontal-padding: 20px; | |
--border-radius: 6px; | |
--ios-border-radius: 10px; | |
--title-color: #444; | |
--icon-element-color: #dc143c; | |
} | |
* { | |
padding: 0; | |
margin: 0; | |
} | |
body:not(.ios) * { | |
font-family: -apple-system-font; | |
} | |
html, body { | |
height: 100%; | |
width: 100%; | |
} | |
body { | |
font-size: 13px; | |
background: linear-gradient(30deg, #dfdfdf 0%, #fafafb 100%); | |
background-repeat: no-repeat; | |
background-attachment: fixed; | |
cursor: default; | |
-webkit-user-select: none; | |
} | |
#title { | |
overflow: hidden; | |
color: var(--title-color); | |
padding-top: 3px; | |
} | |
.alert { | |
background-color: white; | |
min-width: 320px; | |
max-width: 672px; | |
position: relative; | |
margin: 0 auto; | |
padding-top: 28px; | |
border-radius: var(--border-radius); | |
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.14); | |
} | |
.alert-body { | |
margin: 21px 0 0 0; | |
padding-left: var(--horizontal-padding); | |
padding-right: var(--horizontal-padding); | |
padding-bottom: 24px; | |
color: var(--font-color); | |
} | |
.alert-body p:first-of-type { | |
margin-bottom: 15px; | |
margin-top: 20px; | |
} | |
.alert-body p:last-of-type { | |
margin-bottom: 0; | |
} | |
.bottom-bar { | |
margin-top: 1.3em; | |
height: 22px; | |
} | |
.bottom-bar button { | |
float: right; | |
font-size: 13px; | |
line-height: 21px; | |
min-width: 90px; | |
margin: 0 4px; | |
vertical-align: bottom; | |
padding: 0 12px; | |
} | |
.bottom-bar .details { | |
float: left; | |
} | |
.bottom-bar .details a { | |
cursor: pointer; | |
font-size: 14px; | |
margin-top: 2px; | |
} | |
#details { | |
display: none; | |
padding: 22px var(--horizontal-padding) 10px var(--horizontal-padding); | |
border-top: 1px solid rgb(217, 217, 217); | |
color: var(--font-color); | |
background-color: rgb(243, 243, 243); | |
border-bottom-left-radius: var(--border-radius); | |
border-bottom-right-radius: var(--border-radius); | |
} | |
.bottom-bar.goBack .closePage, .bottom-bar.closePage .goBack, #ignoreWarning { | |
display: block; | |
} | |
#openDateAndTimeButton { | |
display: none; | |
} | |
a { | |
color: inherit; | |
text-decoration: underline; | |
cursor: pointer; | |
} | |
#lock, #clock { | |
float: left; | |
width: 30px; | |
top: 4px; | |
margin-right: 15px; | |
position: relative; | |
} | |
#clock { | |
display: none; | |
} | |
.lock-element { | |
fill: var(--icon-element-color); | |
} | |
.clock-element { | |
fill: var(--icon-element-color); | |
} | |
body.clockWarning #clock { | |
display: block; | |
} | |
body.clockWarning #lock { | |
display: none; | |
} | |
body.clockWarning #goBackButton { | |
display: none; | |
} | |
body.clockWarning #openDateAndTimeButton { | |
display: block; | |
} | |
h1 { | |
font-size: 2em; | |
font-weight: 700; | |
line-height: 30px; | |
padding: 0 var(--horizontal-padding); | |
margin-bottom: -6px; | |
} | |
p { | |
font-size: 14px; | |
line-height: 19px; | |
margin-bottom: 1em; | |
word-wrap: break-word; | |
} | |
body.ios .alert { | |
box-shadow: none; | |
border-radius: var(--ios-border-radius); | |
max-width: 640px; | |
} | |
body.ios .alert-body { | |
font: -apple-system-body; | |
} | |
body.ios #details { | |
font: -apple-system-body; | |
border-bottom-left-radius: var(--ios-border-radius); | |
border-bottom-right-radius: var(--ios-border-radius); | |
} | |
body.ios h1 { | |
font-size: 26px; | |
font-family: -webkit-system-font; | |
} | |
body.ios p { | |
font-size: 1.1em; | |
line-height: unset; | |
} | |
body.ios button { | |
background: none; | |
border: none; | |
color: var(--blue-color); | |
font: -apple-system-short-body; | |
} | |
body.ios #detailsButton { | |
color: var(--font-color); | |
} | |
@media screen and (max-width: 666px) { | |
/* iPhone 6 in landscape (667px) and smaller, including all iPhones in portrait */ | |
body { | |
color: var(--compact-font-color); | |
} | |
.alert { | |
box-shadow: none; | |
background-color: var(--red-color); | |
} | |
.alert-body { | |
color: var(--compact-font-color); | |
padding-left: var(--compact-horizontal-padding); | |
padding-right: var(--compact-horizontal-padding); | |
padding-bottom: 30px; | |
} | |
h1 { | |
color: var(--compact-font-color); | |
padding: 0 var(--compact-horizontal-padding); | |
} | |
body.ios button, | |
body.ios #detailsButton { | |
text-decoration: underline; | |
} | |
#details { | |
background-color: var(--red-color); | |
padding: 22px var(--compact-horizontal-padding) 22px var(--compact-horizontal-padding); | |
border-top-width: 1px; | |
border-top-color: rgba(0, 0, 0, .15); | |
} | |
} | |
/* RTL support */ | |
html[dir="rtl"] .bottom-bar button { | |
float: left; | |
} | |
html[dir="rtl"] :matches(#lock, #clock) { | |
float: right; | |
margin-left: 15px; | |
margin-right: 0; | |
} | |
</style> | |
<link rel=stylesheet type="text/css" href="safari-resource:/CertificateWarningExtras.css"> | |
<script type="text/javascript" src="safari-resource:/Utilities.js" charset="utf-8"></script> | |
<script type="text/javascript" src="safari-resource:/WBSHTMLViewController.js" charset="utf-8"></script> | |
<script type="text/javascript"> | |
// Should be kept in sync with WBSCertificateWarningCategory in WBSCertificateWarningPageContext.h. | |
var CertificateWarningCategory = { | |
Expired: 0, | |
InvalidCanBypass: 1, | |
InvalidCannotBypass: 2, | |
HostnameMismatch: 3, | |
IncorrectClock: 4, | |
LegacyTLS: 5, | |
}; | |
var CertificateWarning = { | |
_host: undefined, | |
_canGoBack: undefined, | |
_warningCategory: undefined, | |
_numberOfDaysInvalid: undefined, | |
_expiredCertificateDetails: undefined, | |
_clockSkew: undefined, | |
get host() | |
{ | |
return this._host; | |
}, | |
set host(value) | |
{ | |
if (this._host === value) | |
return; | |
this._host = value; | |
}, | |
get canGoBack() | |
{ | |
return this._canGoBack; | |
}, | |
set canGoBack(value) | |
{ | |
if (this._canGoBack === value) | |
return; | |
this._canGoBack = value; | |
}, | |
get warningCategory() | |
{ | |
return this._warningCategory; | |
}, | |
set warningCategory(value) | |
{ | |
if (this._warningCategory === value) | |
return; | |
this._warningCategory = value; | |
}, | |
get numberOfDaysInvalid() | |
{ | |
return this._numberOfDaysInvalid; | |
}, | |
set numberOfDaysInvalid(value) | |
{ | |
if (this._numberOfDaysInvalid === value) | |
return; | |
this._numberOfDaysInvalid = value; | |
}, | |
get expiredCertificateDetails() | |
{ | |
return this._expiredCertificateDetails; | |
}, | |
set expiredCertificateDetails(value) | |
{ | |
if (this._expiredCertificateDetails === value) | |
return; | |
this._expiredCertificateDetails = value; | |
}, | |
get clockSkew() | |
{ | |
return this._clockSkew; | |
}, | |
set clockSkew(value) | |
{ | |
if (this._clockSkew === value) | |
return; | |
this._clockSkew = value; | |
}, | |
pageLoaded: function() | |
{ | |
if (/Macintosh/g.test(navigator.userAgent)) | |
document.body.classList.add("mac"); | |
else | |
document.body.classList.add("ios"); | |
HTMLViewController.pageLoaded(); | |
CertificateWarningController.pageLoaded(); | |
window.addEventListener("resize", layOut, false); | |
layOut(); | |
}, | |
currentSystemTime: function() | |
{ | |
var dateFormatter = Intl.DateTimeFormat(undefined, { weekday: "long", day: "numeric", month: "long", year: "numeric" }); | |
return dateFormatter.format(new Date()); | |
}, | |
showIncorrectClockWarning: function() | |
{ | |
console.assert(this.warningCategory === CertificateWarningCategory.IncorrectClock); | |
console.assert(this.clockSkew !== 0); | |
document.body.classList.add("clockWarning"); | |
var title = HTMLViewController.UIString("Your Clock Is Set Incorrectly"); | |
document.title = title; | |
document.getElementById("title").textContent = title; | |
var incorrectClockHTMLTemplate = HTMLViewController.UIString("Safari can’t connect to “%hostname%” because your system clock is incorrectly set to %@. Set your system clock to the correct time and try again.").format(this.currentSystemTime()); | |
var incorrectClockHTML = incorrectClockHTMLTemplate.replace("%hostname%", this.host); | |
var warningText = document.getElementById("warningText"); | |
warningText.innerHTML = incorrectClockHTML; | |
var detailsTextHTMLTemplate = HTMLViewController.UIString("Because your system clock is set incorrectly, Safari can’t verify that your connection is private. If you understand the risks involved, you can %visit-this-site-link%."); | |
var detailsTextHTML = "<a role='button' onClick='CertificateWarningController.visitInsecureWebsiteWithTemporaryBypass();'>%@</a>".format(HTMLViewController.UIString("visit this website")); | |
var detailsText = detailsTextHTMLTemplate.replace("%visit-this-site-link%", detailsTextHTML); | |
document.getElementById("detailsText").innerHTML = detailsText; | |
setDetailsVisibility(false); | |
}, | |
updateDetailsStrings: function() | |
{ | |
if (this.warningCategory === CertificateWarningCategory.IncorrectClock) { | |
this.showIncorrectClockWarning(); | |
return; | |
} | |
var warningText = document.getElementById("warningText"); | |
var warningTextHTMLTemplate; | |
if (this.warningCategory === CertificateWarningCategory.LegacyTLS) { | |
if (this.canGoBack) | |
warningTextHTMLTemplate = HTMLViewController.UIString("This website has an outdated security configuration, which may allow an attacker to steal personal or financial information entered into “%hostname%”. You should go back to the previous page."); | |
else | |
warningTextHTMLTemplate = HTMLViewController.UIString("This website has an outdated security configuration, which may allow an attacker to steal personal or financial information entered into “%hostname%”. You should close this page."); | |
} else { | |
if (this.canGoBack) | |
warningTextHTMLTemplate = HTMLViewController.UIString("This website may be impersonating “%hostname%” to steal your personal or financial information. You should go back to the previous page."); | |
else | |
warningTextHTMLTemplate = HTMLViewController.UIString("This website may be impersonating “%hostname%” to steal your personal or financial information. You should close this page."); | |
} | |
var warningTextHTML = warningTextHTMLTemplate.replace("%hostname%", this.host); | |
warningText.innerHTML = warningTextHTML; | |
var bypassCertificateWarningHTMLTemplate = HTMLViewController.UIString("If you understand the risks involved, you can %visit-this-site-link%."); | |
var visitUnsafeWebsiteLinkHTML = "<a role='button' onClick='CertificateWarningController.visitInsecureWebsite();'>%@</a>".format(HTMLViewController.UIString("visit this website")); | |
var bypassCertificateWarningHTML = bypassCertificateWarningHTMLTemplate.replace("%visit-this-site-link%", visitUnsafeWebsiteLinkHTML); | |
var viewCertificateHTMLTemplate = HTMLViewController.UIString("To learn more, you can %view-the-certificate%."); | |
var viewCertificateLinkHTML = "<a role='button' onClick='CertificateWarningController.showCertificateInformation();'>%@</a>".format(HTMLViewController.UIString("view the certificate")); | |
var viewCertificateHTML = viewCertificateHTMLTemplate.replace("%view-the-certificate%", viewCertificateLinkHTML); | |
var detailsText = document.getElementById("detailsText"); | |
switch (this.warningCategory) { | |
case CertificateWarningCategory.Expired: | |
var firstParagraphHTMLTemplate = HTMLViewController.UIString("Safari warns you when a website has %certificate-description%. %expiration-date-details%. This may happen if the website is misconfigured, an attacker has compromised your connection, or your system clock is incorrect. Your system clock is set to %@. If this is not right, %fixing-the-clock% may address this warning."); | |
var firstParagraphWithDateHTMLTemplate = firstParagraphHTMLTemplate.format(this.currentSystemTime()); | |
var openClockSettingsLinkHTML = "<a role='button' onClick='CertificateWarningController.openClockSettings();'>%@</a>".format(HTMLViewController.UIString("fixing the clock")); | |
var firstParagraphWithClockHTMLTemplate = firstParagraphWithDateHTMLTemplate.replace("%fixing-the-clock%", openClockSettingsLinkHTML); | |
var firstParagraphWithExpirationDateDetails = firstParagraphWithClockHTMLTemplate.replace("%expiration-date-details%", this.expiredCertificateDetails); | |
var certificateDescription; | |
if (this.numberOfDaysInvalid > 0) | |
certificateDescription = HTMLViewController.UIString("an expired certificate"); | |
else | |
certificateDescription = HTMLViewController.UIString("a certificate that is not valid"); | |
var firstParagraph = firstParagraphWithExpirationDateDetails.replace("%certificate-description%", certificateDescription); | |
// Localizers: The space in between viewCertificateHTML and bypassCertificateWarningHTML should be translated to the appropriate space between two sentences. | |
detailsText.innerHTML = "<p>" + firstParagraph + "</p><p>" + viewCertificateHTML + " " + bypassCertificateWarningHTML + "</p>"; | |
break; | |
case CertificateWarningCategory.HostnameMismatch: | |
case CertificateWarningCategory.InvalidCanBypass: | |
// FIXME 30320099: Hostname mismatch should be its own unique case. | |
var firstParagraph = HTMLViewController.UIString("Safari warns you when a website has a certificate that is not valid. This may happen if the website is misconfigured or an attacker has compromised your connection."); | |
// Localizers: The space in between viewCertificateHTML and bypassCertificateWarningHTML should be translated to the appropriate space between two sentences. | |
detailsText.innerHTML = "<p>" + firstParagraph + "</p><p>" + viewCertificateHTML + " " + bypassCertificateWarningHTML + "</p>"; | |
break; | |
case CertificateWarningCategory.InvalidCannotBypass: | |
var firstParagraph = HTMLViewController.UIString("Safari warns you when a website has a certificate that is not valid. This may happen if an attacker has compromised your connection. For your protection, you can’t visit this website. You can check back later to see if this issue has been resolved. You can also contact the website owner to tell them about this error."); | |
// Localizers: The space in between firstParagraph and viewCertificateHTML should be translated to the appropriate space between two sentences. | |
detailsText.innerHTML = firstParagraph + " " + viewCertificateHTML; | |
break; | |
case CertificateWarningCategory.LegacyTLS: | |
var firstParagraph = HTMLViewController.UIString("Safari warns you when a website uses TLS 1.0 or TLS 1.1, which are not secure. This may allow an attacker to compromise your connection to steal your personal or financial information, including passwords, phone numbers, and credit cards."); | |
detailsText.innerHTML = "<p>" + firstParagraph + "</p><p>" + bypassCertificateWarningHTML + "</p>"; | |
break; | |
default: | |
console.assert(false, "Invalid warning category given"); | |
break; | |
} | |
setDetailsVisibility(false); | |
}, | |
updateUI: function(host, warningCategory, canGoBack, numberOfDaysInvalid, expiredCertificateDetails, clockSkew) | |
{ | |
this.warningCategory = warningCategory; | |
this.host = host; | |
this.canGoBack = canGoBack; | |
this.numberOfDaysInvalid = numberOfDaysInvalid; | |
this.expiredCertificateDetails = expiredCertificateDetails; | |
this.clockSkew = clockSkew; | |
if (!canGoBack) | |
document.getElementById("goBackButton").textContent = HTMLViewController.UIString("Close Page"); | |
this.updateDetailsStrings(); | |
}, | |
setTextDirection: function(textDirection) | |
{ | |
document.documentElement.setAttribute("dir", textDirection); | |
} | |
}; | |
function setDetailsVisibility(show) | |
{ | |
var detailsDiv = document.getElementById("details"); | |
if (show) { | |
detailsDiv.style.display = "block"; | |
document.getElementById("detailsButton").style.display = "none"; | |
detailsDiv.scrollIntoViewIfNeeded(); | |
} else { | |
detailsDiv.style.display = "none"; | |
document.getElementById("detailsButton").style.display = "block"; | |
} | |
layOut(); | |
} | |
function layOut() | |
{ | |
const minimumMarginTop = 22; | |
const maximumMarginTop = 156; | |
var alertBox = document.getElementById("alert"); | |
var alertHeight = alertBox.getBoundingClientRect().height; | |
var viewportHeight = window.innerHeight; | |
if (viewportHeight > alertHeight + 2 * maximumMarginTop) | |
alertBox.style.top = maximumMarginTop + "px"; | |
else | |
alertBox.style.top = Math.max(minimumMarginTop, (viewportHeight - alertHeight) / 2) + "px"; | |
} | |
HTMLViewController.loadLocalizedStrings(CertificateWarningController); | |
window.addEventListener("load", function() { CertificateWarning.pageLoaded(); }, false); | |
</script> | |
</head> | |
<body> | |
<div id="alert" class="alert"> | |
<h1> | |
<svg id="lock" x="0px" y="0px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"> | |
<polygon class="lock-element" points="9.9,19 9.9,20.2 38.8,47 40,47 "/> | |
<polygon class="lock-element" points="9.9,22.2 7.5,22.2 7.5,47 38.8,47 9.9,20.2 "/> | |
<path class="lock-element" d="M24.4,6.2c5.5,0,9.9,4.1,9.9,9.2v6.9h-3l10.4,9.5v-9.5h-2.5v-6.9c0-7.6-6.6-13.8-14.8-13.8c-4.4,0-8.3,1.8-11,4.6L17,9.4C18.8,7.4,21.4,6.2,24.4,6.2z"/> | |
<path class="lock-element" d="M49.3,47.9c1-0.9,1-2.4,0-3.3l-45-42c-1-0.9-2.6-0.9-3.6,0c-1,0.9-1,2.4,0,3.3l45,42C46.7,48.8,48.3,48.8,49.3,47.9z"/> | |
</svg> | |
<svg id="clock" x="0px" y="0px" viewBox="0 0 150 150" style="enable-background:new 0 0 150 150;" xml:space="preserve"> | |
<path class="clock-element" d="M75,0C33.6,0,0,33.6,0,75c0,41.4,33.6,75,75,75s75-33.6,75-75C150,33.6,116.4,0,75,0z M81,68v7 c0,3.3-2.7,6-6,6H45c-3.3,0-6-2.7-6-6v-1c0-3.3,2.7-6,6-6h23V26c0-3.3,2.7-6,6-6h1c3.3,0,6,2.7,6,6V68z"/> | |
</svg> | |
<div id="title" class="l12n">This Connection Is Not Private</div> | |
</h1> | |
<div class="alert-body"> | |
<div class="item"> | |
<p id="warningText"></p> | |
</div> | |
<div class="bottom-bar goBack closePage" id="bottom-bar"> | |
<button type="button" id="goBackButton" class="l12n goBack" onClick="CertificateWarningController.goBackSelected();">Go Back</button> | |
<button type="button" id="openDateAndTimeButton" class="l12n" onClick="CertificateWarningController.openClockSettings();">Open Date & Time…</button> | |
<button type="button" id="detailsButton" class="l12n" onClick="setDetailsVisibility(true);">Show Details</button> | |
</div> | |
</div> | |
<div id="details"> | |
<p id="detailsText"></p> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
This file has a UTF-8 BOM in it so it can be included from a UTF-16 page | |
without specifying an explicit character set. When editing it, please be | |
sure to preserve the BOM (first three bytes of the file, EF BB BF). | |
*/ | |
@media (prefers-dark-interface) { | |
body { | |
background: none; | |
background-color: rgb(30, 30, 30); | |
--font-color: rgb(181, 182, 184); | |
--compact-font-color: rgb(181, 182, 184); | |
--title-color: rgb(224, 225, 225); | |
} | |
.alert { | |
background-color: rgb(56, 57, 59); | |
box-shadow: 0 6px 12px rgba(0, 0, 0, .24); | |
} | |
#details { | |
background-color: rgb(46, 47, 49); | |
border-top-color: rgb(90, 92, 93); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="content-type" content="text/html; charset=utf-8"> | |
<meta name="viewport" content="width=device-width, viewport-fit=cover"> | |
<title class="l12n">This Connection Is Not Private</title> | |
<style> | |
:root { | |
--bypass-feature-icon-color: #000000; | |
} | |
@media (prefers-color-scheme:dark) { | |
:root { | |
--bypass-feature-icon-color: #FFFFFF; | |
} | |
} | |
body { | |
--font-color: #434343; | |
--compact-font-color: #434343; | |
--blue-color: rgb(0, 122, 255); | |
--horizontal-padding: 32px; | |
--compact-horizontal-padding: 20px; | |
--border-radius: 6px; | |
--ios-border-radius: 10px; | |
--title-color: #444; | |
--icon-element-color: #dc143c; | |
} | |
* { | |
padding: 0; | |
margin: 0; | |
} | |
body:not(.ios) * { | |
font-family: -apple-system-font; | |
} | |
html, body { | |
height: 100%; | |
width: 100%; | |
} | |
body { | |
font-size: 13px; | |
background: linear-gradient(30deg, #dfdfdf 0%, #fafafb 100%); | |
background-repeat: no-repeat; | |
background-attachment: fixed; | |
cursor: default; | |
-webkit-user-select: none; | |
} | |
#title { | |
overflow: hidden; | |
color: var(--title-color); | |
padding-top: 3px; | |
} | |
.alert { | |
background-color: white; | |
min-width: 320px; | |
max-width: 672px; | |
position: relative; | |
margin: 0 auto; | |
padding-top: 28px; | |
border-radius: var(--border-radius); | |
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.14); | |
} | |
.alert-body { | |
margin: 21px 0 0 0; | |
padding-left: var(--horizontal-padding); | |
padding-right: var(--horizontal-padding); | |
padding-bottom: 24px; | |
color: var(--font-color); | |
} | |
.alert-body p:first-of-type { | |
margin-bottom: 15px; | |
margin-top: 20px; | |
} | |
.alert-body p:last-of-type { | |
margin-bottom: 0; | |
} | |
.bottom-bar { | |
margin-top: 1.3em; | |
height: 22px; | |
} | |
.bottom-bar button { | |
float: right; | |
font-size: 13px; | |
line-height: 21px; | |
min-width: 90px; | |
margin: 0 4px; | |
vertical-align: bottom; | |
padding: 0 12px; | |
} | |
.bottom-bar .details { | |
float: left; | |
} | |
.bottom-bar .details a { | |
cursor: pointer; | |
font-size: 14px; | |
margin-top: 2px; | |
} | |
#details { | |
display: none; | |
padding: 22px var(--horizontal-padding) 10px var(--horizontal-padding); | |
border-top: 1px solid rgb(217, 217, 217); | |
color: var(--font-color); | |
background-color: rgb(243, 243, 243); | |
border-bottom-left-radius: var(--border-radius); | |
border-bottom-right-radius: var(--border-radius); | |
} | |
.bottom-bar.goBack .closePage, .bottom-bar.closePage .goBack, #ignoreWarning { | |
display: block; | |
} | |
#openDateAndTimeButton { | |
display: none; | |
} | |
#bypassFeatureButton { | |
display: none; | |
} | |
a { | |
color: inherit; | |
text-decoration: underline; | |
cursor: pointer; | |
} | |
#lock, #clock { | |
float: left; | |
width: 30px; | |
top: 4px; | |
margin-right: 15px; | |
position: relative; | |
} | |
#clock { | |
display: none; | |
} | |
#bypassFeatureIcon { | |
display: none; | |
} | |
.lock-element { | |
fill: var(--icon-element-color); | |
} | |
.clock-element { | |
fill: var(--icon-element-color); | |
} | |
body.clockWarning #clock { | |
display: block; | |
} | |
body.clockWarning #lock { | |
display: none; | |
} | |
body.clockWarning #goBackButton { | |
display: none; | |
} | |
body.clockWarning #openDateAndTimeButton { | |
display: block; | |
} | |
body.bypassFeature #bypassFeatureButton { | |
display: block; | |
} | |
body.bypassFeature #detailsButton { | |
display: none; | |
} | |
body.bypassFeature #bypassFeatureIcon { | |
display: block; | |
float: left; | |
width: 34px; | |
top: 4px; | |
margin-right: 15px; | |
position: relative; | |
} | |
body.bypassFeature #lock { | |
display: none; | |
} | |
h1 { | |
font-size: 2em; | |
font-weight: 700; | |
line-height: 30px; | |
padding: 0 var(--horizontal-padding); | |
margin-bottom: -6px; | |
} | |
p { | |
font-size: 14px; | |
line-height: 19px; | |
margin-bottom: 1em; | |
word-wrap: break-word; | |
} | |
body.ios .alert { | |
box-shadow: none; | |
border-radius: var(--ios-border-radius); | |
max-width: 640px; | |
} | |
body.ios .alert-body { | |
font: -apple-system-body; | |
} | |
body.ios #details { | |
font: -apple-system-body; | |
border-bottom-left-radius: var(--ios-border-radius); | |
border-bottom-right-radius: var(--ios-border-radius); | |
} | |
body.ios h1 { | |
font-size: 26px; | |
font-family: -webkit-system-font; | |
} | |
body.ios p { | |
font-size: 1.1em; | |
line-height: unset; | |
} | |
body.ios button { | |
background: none; | |
border: none; | |
color: var(--blue-color); | |
font: -apple-system-short-body; | |
} | |
body.ios #detailsButton { | |
color: var(--font-color); | |
} | |
body.ios #bypassFeatureIcon { | |
fill: #000000; | |
} | |
body:not(.ios) #bypassFeatureIcon { | |
fill: var(--bypass-feature-icon-color); | |
} | |
@media screen and (max-width: 666px) { | |
/* iPhone 6 in landscape (667px) and smaller, including all iPhones in portrait */ | |
body { | |
color: var(--compact-font-color); | |
} | |
.alert { | |
box-shadow: none; | |
background-color: var(--red-color); | |
} | |
.alert-body { | |
color: var(--compact-font-color); | |
padding-left: var(--compact-horizontal-padding); | |
padding-right: var(--compact-horizontal-padding); | |
padding-bottom: 30px; | |
} | |
h1 { | |
color: var(--compact-font-color); | |
padding: 0 var(--compact-horizontal-padding); | |
} | |
body.ios button, | |
body.ios #detailsButton { | |
text-decoration: underline; | |
} | |
#details { | |
background-color: var(--red-color); | |
padding: 22px var(--compact-horizontal-padding) 22px var(--compact-horizontal-padding); | |
border-top-width: 1px; | |
border-top-color: rgba(0, 0, 0, .15); | |
} | |
} | |
/* RTL support */ | |
html[dir="rtl"] .bottom-bar button { | |
float: left; | |
} | |
html[dir="rtl"] :matches(#lock, #clock, #bypassFeatureIcon) { | |
float: right; | |
margin-left: 15px; | |
margin-right: 0; | |
} | |
</style> | |
<link rel=stylesheet type="text/css" href="safari-resource:/CertificateWarningExtras.css"> | |
<script type="text/javascript" src="safari-resource:/Utilities.js" charset="utf-8"></script> | |
<script type="text/javascript" src="safari-resource:/WBSHTMLViewController.js" charset="utf-8"></script> | |
<script type="text/javascript"> | |
// Should be kept in sync with WBSCertificateWarningCategory in WBSCertificateWarningPageContext.h. | |
var CertificateWarningCategory = { | |
Expired: 0, | |
InvalidCanBypass: 1, | |
InvalidCannotBypass: 2, | |
HostnameMismatch: 3, | |
IncorrectClock: 4, | |
LegacyTLS: 5, | |
// Placeholder | |
BypassFeatureNormal: 7, | |
BypassFeatureUnencrypted: 8, | |
}; | |
var CertificateWarning = { | |
_host: undefined, | |
_canGoBack: undefined, | |
_warningCategory: undefined, | |
_numberOfDaysInvalid: undefined, | |
_expiredCertificateDetails: undefined, | |
_clockSkew: undefined, | |
get host() | |
{ | |
return this._host; | |
}, | |
set host(value) | |
{ | |
if (this._host === value) | |
return; | |
this._host = value; | |
}, | |
get canGoBack() | |
{ | |
return this._canGoBack; | |
}, | |
set canGoBack(value) | |
{ | |
if (this._canGoBack === value) | |
return; | |
this._canGoBack = value; | |
}, | |
get warningCategory() | |
{ | |
return this._warningCategory; | |
}, | |
set warningCategory(value) | |
{ | |
if (this._warningCategory === value) | |
return; | |
this._warningCategory = value; | |
}, | |
get numberOfDaysInvalid() | |
{ | |
return this._numberOfDaysInvalid; | |
}, | |
set numberOfDaysInvalid(value) | |
{ | |
if (this._numberOfDaysInvalid === value) | |
return; | |
this._numberOfDaysInvalid = value; | |
}, | |
get expiredCertificateDetails() | |
{ | |
return this._expiredCertificateDetails; | |
}, | |
set expiredCertificateDetails(value) | |
{ | |
if (this._expiredCertificateDetails === value) | |
return; | |
this._expiredCertificateDetails = value; | |
}, | |
get clockSkew() | |
{ | |
return this._clockSkew; | |
}, | |
set clockSkew(value) | |
{ | |
if (this._clockSkew === value) | |
return; | |
this._clockSkew = value; | |
}, | |
pageLoaded: function() | |
{ | |
if (/Macintosh/g.test(navigator.userAgent)) | |
document.body.classList.add("mac"); | |
else | |
document.body.classList.add("ios"); | |
HTMLViewController.pageLoaded(); | |
CertificateWarningController.pageLoaded(); | |
window.addEventListener("resize", layOut, false); | |
layOut(); | |
}, | |
currentSystemTime: function() | |
{ | |
var dateFormatter = Intl.DateTimeFormat(undefined, { weekday: "long", day: "numeric", month: "long", year: "numeric" }); | |
return dateFormatter.format(new Date()); | |
}, | |
showIncorrectClockWarning: function() | |
{ | |
console.assert(this.warningCategory === CertificateWarningCategory.IncorrectClock); | |
console.assert(this.clockSkew !== 0); | |
document.body.classList.add("clockWarning"); | |
var title = HTMLViewController.UIString("Your Clock Is Set Incorrectly"); | |
document.title = title; | |
document.getElementById("title").textContent = title; | |
var incorrectClockHTMLTemplate = HTMLViewController.UIString("Safari can’t connect to “%hostname%” because your system clock is incorrectly set to %@. Set your system clock to the correct time and try again.").format(this.currentSystemTime()); | |
var incorrectClockHTML = incorrectClockHTMLTemplate.replace("%hostname%", this.host); | |
var warningText = document.getElementById("warningText"); | |
warningText.innerHTML = incorrectClockHTML; | |
var detailsTextHTMLTemplate = HTMLViewController.UIString("Because your system clock is set incorrectly, Safari can’t verify that your connection is private. If you understand the risks involved, you can %visit-this-site-link%."); | |
var detailsTextHTML = "<a role='button' onClick='CertificateWarningController.visitInsecureWebsiteWithTemporaryBypass();'>%@</a>".format(HTMLViewController.UIString("visit this website")); | |
var detailsText = detailsTextHTMLTemplate.replace("%visit-this-site-link%", detailsTextHTML); | |
document.getElementById("detailsText").innerHTML = detailsText; | |
setDetailsVisibility(false); | |
}, | |
showBypassFeatureNavigationFailedWarning: function() | |
{ | |
console.assert(this.warningCategory === CertificateWarningCategory.BypassFeatureNormal || this.warningCategory === CertificateWarningCategory.BypassFeatureUnencrypted); | |
document.body.classList.add("bypassFeature"); | |
document.getElementById("title").textContent = CertificateWarningController.bypassFeatureTitleText(); | |
document.getElementById("warningText").textContent = CertificateWarningController.bypassFeatureWarningText(); | |
}, | |
updateDetailsStrings: function() | |
{ | |
if (this.warningCategory === CertificateWarningCategory.IncorrectClock) { | |
this.showIncorrectClockWarning(); | |
return; | |
} | |
if (this.warningCategory === CertificateWarningCategory.BypassFeatureNormal || this.warningCategory === CertificateWarningCategory.BypassFeatureUnencrypted) { | |
this.showBypassFeatureNavigationFailedWarning(); | |
return; | |
} | |
var warningText = document.getElementById("warningText"); | |
var warningTextHTMLTemplate; | |
if (this.warningCategory === CertificateWarningCategory.LegacyTLS) { | |
if (this.canGoBack) | |
warningTextHTMLTemplate = HTMLViewController.UIString("This website has an outdated security configuration, which may allow an attacker to steal personal or financial information entered into “%hostname%”. You should go back to the previous page."); | |
else | |
warningTextHTMLTemplate = HTMLViewController.UIString("This website has an outdated security configuration, which may allow an attacker to steal personal or financial information entered into “%hostname%”. You should close this page."); | |
} else { | |
if (this.canGoBack) | |
warningTextHTMLTemplate = HTMLViewController.UIString("This website may be impersonating “%hostname%” to steal your personal or financial information. You should go back to the previous page."); | |
else | |
warningTextHTMLTemplate = HTMLViewController.UIString("This website may be impersonating “%hostname%” to steal your personal or financial information. You should close this page."); | |
} | |
var warningTextHTML = warningTextHTMLTemplate.replace("%hostname%", this.host); | |
warningText.innerHTML = warningTextHTML; | |
var bypassCertificateWarningHTMLTemplate = HTMLViewController.UIString("If you understand the risks involved, you can %visit-this-site-link%."); | |
var visitUnsafeWebsiteLinkHTML = "<a role='button' onClick='CertificateWarningController.visitInsecureWebsite();'>%@</a>".format(HTMLViewController.UIString("visit this website")); | |
var bypassCertificateWarningHTML = bypassCertificateWarningHTMLTemplate.replace("%visit-this-site-link%", visitUnsafeWebsiteLinkHTML); | |
var viewCertificateHTMLTemplate = HTMLViewController.UIString("To learn more, you can %view-the-certificate%."); | |
var viewCertificateLinkHTML = "<a role='button' onClick='CertificateWarningController.showCertificateInformation();'>%@</a>".format(HTMLViewController.UIString("view the certificate")); | |
var viewCertificateHTML = viewCertificateHTMLTemplate.replace("%view-the-certificate%", viewCertificateLinkHTML); | |
var detailsText = document.getElementById("detailsText"); | |
switch (this.warningCategory) { | |
case CertificateWarningCategory.Expired: | |
var firstParagraphHTMLTemplate = HTMLViewController.UIString("Safari warns you when a website has %certificate-description%. %expiration-date-details%. This may happen if the website is misconfigured, an attacker has compromised your connection, or your system clock is incorrect. Your system clock is set to %@. If this is not right, %fixing-the-clock% may address this warning."); | |
var firstParagraphWithDateHTMLTemplate = firstParagraphHTMLTemplate.format(this.currentSystemTime()); | |
var openClockSettingsLinkHTML = "<a role='button' onClick='CertificateWarningController.openClockSettings();'>%@</a>".format(HTMLViewController.UIString("fixing the clock")); | |
var firstParagraphWithClockHTMLTemplate = firstParagraphWithDateHTMLTemplate.replace("%fixing-the-clock%", openClockSettingsLinkHTML); | |
var firstParagraphWithExpirationDateDetails = firstParagraphWithClockHTMLTemplate.replace("%expiration-date-details%", this.expiredCertificateDetails); | |
var certificateDescription; | |
if (this.numberOfDaysInvalid > 0) | |
certificateDescription = HTMLViewController.UIString("an expired certificate"); | |
else | |
certificateDescription = HTMLViewController.UIString("a certificate that is not valid"); | |
var firstParagraph = firstParagraphWithExpirationDateDetails.replace("%certificate-description%", certificateDescription); | |
// Localizers: The space in between viewCertificateHTML and bypassCertificateWarningHTML should be translated to the appropriate space between two sentences. | |
detailsText.innerHTML = "<p>" + firstParagraph + "</p><p>" + viewCertificateHTML + " " + bypassCertificateWarningHTML + "</p>"; | |
break; | |
case CertificateWarningCategory.HostnameMismatch: | |
case CertificateWarningCategory.InvalidCanBypass: | |
// FIXME 30320099: Hostname mismatch should be its own unique case. | |
var firstParagraph = HTMLViewController.UIString("Safari warns you when a website has a certificate that is not valid. This may happen if the website is misconfigured or an attacker has compromised your connection."); | |
// Localizers: The space in between viewCertificateHTML and bypassCertificateWarningHTML should be translated to the appropriate space between two sentences. | |
detailsText.innerHTML = "<p>" + firstParagraph + "</p><p>" + viewCertificateHTML + " " + bypassCertificateWarningHTML + "</p>"; | |
break; | |
case CertificateWarningCategory.InvalidCannotBypass: | |
var firstParagraph = HTMLViewController.UIString("Safari warns you when a website has a certificate that is not valid. This may happen if an attacker has compromised your connection. For your protection, you can’t visit this website. You can check back later to see if this issue has been resolved. You can also contact the website owner to tell them about this error."); | |
// Localizers: The space in between firstParagraph and viewCertificateHTML should be translated to the appropriate space between two sentences. | |
detailsText.innerHTML = firstParagraph + " " + viewCertificateHTML; | |
break; | |
case CertificateWarningCategory.LegacyTLS: | |
var firstParagraph = HTMLViewController.UIString("Safari warns you when a website uses TLS 1.0 or TLS 1.1, which are not secure. This may allow an attacker to compromise your connection to steal your personal or financial information, including passwords, phone numbers, and credit cards."); | |
detailsText.innerHTML = "<p>" + firstParagraph + "</p><p>" + bypassCertificateWarningHTML + "</p>"; | |
break; | |
default: | |
console.assert(false, "Invalid warning category given"); | |
break; | |
} | |
setDetailsVisibility(false); | |
}, | |
updateUI: function(host, warningCategory, canGoBack, numberOfDaysInvalid, expiredCertificateDetails, clockSkew) | |
{ | |
this.warningCategory = warningCategory; | |
this.host = host; | |
this.canGoBack = canGoBack; | |
this.numberOfDaysInvalid = numberOfDaysInvalid; | |
this.expiredCertificateDetails = expiredCertificateDetails; | |
this.clockSkew = clockSkew; | |
if (!canGoBack) | |
document.getElementById("goBackButton").textContent = HTMLViewController.UIString("Close Page"); | |
document.getElementById("bypassFeatureButton").textContent = CertificateWarningController.bypassFeatureButtonText(); | |
var svg = document.getElementById("bypassFeatureIcon"); | |
var path = document.createElementNS("http://www.w3.org/2000/svg", 'path'); | |
var pathString = CertificateWarningController.bypassFeatureIconPath(); | |
path.setAttribute("d", pathString); | |
path.style.opacity = 0.5; | |
svg.appendChild(path); | |
this.updateDetailsStrings(); | |
}, | |
setTextDirection: function(textDirection) | |
{ | |
document.documentElement.setAttribute("dir", textDirection); | |
} | |
}; | |
function setDetailsVisibility(show) | |
{ | |
var detailsDiv = document.getElementById("details"); | |
if (show) { | |
detailsDiv.style.display = "block"; | |
document.getElementById("detailsButton").style.display = "none"; | |
detailsDiv.scrollIntoViewIfNeeded(); | |
} else { | |
detailsDiv.style.display = "none"; | |
document.getElementById("detailsButton").style.display = "block"; | |
} | |
layOut(); | |
} | |
function layOut() | |
{ | |
const minimumMarginTop = 22; | |
const maximumMarginTop = 156; | |
var alertBox = document.getElementById("alert"); | |
var alertHeight = alertBox.getBoundingClientRect().height; | |
var viewportHeight = window.innerHeight; | |
if (viewportHeight > alertHeight + 2 * maximumMarginTop) | |
alertBox.style.top = maximumMarginTop + "px"; | |
else | |
alertBox.style.top = Math.max(minimumMarginTop, (viewportHeight - alertHeight) / 2) + "px"; | |
} | |
HTMLViewController.loadLocalizedStrings(CertificateWarningController); | |
window.addEventListener("load", function() { CertificateWarning.pageLoaded(); }, false); | |
</script> | |
</head> | |
<body> | |
<div id="alert" class="alert"> | |
<h1> | |
<svg id="lock" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="33.6768" height="31.2098"> | |
<rect height="30.1758" opacity="0" width="27.3834" x="0" y="0"/> | |
<path class="lock-element" d="M13.396 2.55615C16.1353 2.55615 18.5229 4.50439 18.5229 8.21045L18.5229 12.019L13.2056 12.019L23.4009 22.1851L23.4009 15.4907C23.4009 13.4692 22.5073 12.312 20.8374 12.0776L20.8374 8.51807C20.8374 3.01025 17.2339 0.344238 13.396 0.344238C10.3784 0.344238 7.56592 2.01416 6.49658 5.29541L8.37158 7.18506C8.75244 4.16748 10.9058 2.55615 13.396 2.55615ZM6.70166 29.0698L20.105 29.0698C20.7935 29.0698 21.3794 28.9087 21.8042 28.6304L5.42725 12.2681L5.29541 12.2681C4.09424 12.6636 3.40576 13.7769 3.40576 15.4907L3.40576 25.5835C3.40576 27.8979 4.54834 29.0698 6.70166 29.0698ZM25.4517 29.8462C25.9058 30.2856 26.6235 30.2856 27.0483 29.8462C27.4878 29.4067 27.5024 28.689 27.0483 28.2495L1.94092 3.14209C1.50146 2.70264 0.769043 2.70264 0.32959 3.14209C-0.109863 3.58154-0.109863 4.31396 0.32959 4.73877Z"/> | |
</svg> | |
<svg id="clock" x="0px" y="0px" viewBox="0 0 150 150" style="enable-background:new 0 0 150 150;" xml:space="preserve"> | |
<path class="clock-element" d="M75,0C33.6,0,0,33.6,0,75c0,41.4,33.6,75,75,75s75-33.6,75-75C150,33.6,116.4,0,75,0z M81,68v7 c0,3.3-2.7,6-6,6H45c-3.3,0-6-2.7-6-6v-1c0-3.3,2.7-6,6-6h23V26c0-3.3,2.7-6,6-6h1c3.3,0,6,2.7,6,6V68z"/> | |
</svg> | |
<svg id="bypassFeatureIcon" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="33.6768" height="31.2098"> | |
<rect height="31.2098" opacity="0" width="33.6768" x="0" y="0"/> | |
</svg> | |
<div id="title" class="l12n">This Connection Is Not Private</div> | |
</h1> | |
<div class="alert-body"> | |
<div class="item"> | |
<p id="warningText"></p> | |
</div> | |
<div class="bottom-bar goBack closePage" id="bottom-bar"> | |
<button type="button" id="goBackButton" class="l12n goBack" onClick="CertificateWarningController.goBackSelected();">Go Back</button> | |
<button type="button" id="openDateAndTimeButton" class="l12n" onClick="CertificateWarningController.openClockSettings();">Open Date & Time…</button> | |
<button type="button" id="detailsButton" class="l12n" onClick="setDetailsVisibility(true);">Show Details</button> | |
<button type="button" id="bypassFeatureButton" class="l12n" onClick="CertificateWarningController.bypassFeatureVisitWebsite();">Continue</button> | |
</div> | |
</div> | |
<div id="details"> | |
<p id="detailsText"></p> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// # sourceURL=__InjectedScript_FormMetadataClassification.js | |
/* Copyright (c) 2024 Apple Inc. All rights reserved. */ | |
"use strict"; | |
const WBSABAddressProperty = "Address", | |
WBSABPhoneProperty = "Phone", | |
_WBSABAddressZIPKey = "ZIP", | |
WBSFormControlMetadataDefaultMaxLength = 524288, | |
WBSIgnoredClassificationToken = "-sf-ignored", | |
WBSLocaleForCreditCardExpirationDate = "en_US", | |
WBSCreditCardTypeClassificationToken = "cc-type", | |
WBSCreditCardHolderNameClassificationToken = "cc-name", | |
WBSCreditCardNumberClassificationToken = "cc-number", | |
WBSCreditCardExpirationClassificationToken = "cc-exp", | |
WBSCreditCardSecurityCodeClassificationToken = "cc-csc", | |
WBSCreditCardHolderGivenNameClassificationToken = "cc-given-name", | |
WBSCreditCardHolderAdditionalNameClassificationToken = "cc-additional-name", | |
WBSCreditCardHolderFamilyNameClassificationToken = "cc-family-name", | |
WBSCreditCardExpirationMonthClassificationToken = "cc-exp-month", | |
WBSCreditCardExpirationYearClassificationToken = "cc-exp-year", | |
WBSCreditCardHolderNameClassificationDefaultOrderedParts = [ WBSCreditCardHolderGivenNameClassificationToken, WBSCreditCardHolderAdditionalNameClassificationToken, WBSCreditCardHolderFamilyNameClassificationToken ], | |
WBSCreditCardExpirationClassificationDefaultOrderedParts = [ WBSCreditCardExpirationMonthClassificationToken, WBSCreditCardExpirationYearClassificationToken ], | |
WBSCredentialUsernameClassificationToken = "username", | |
WBSCredentialCurrentPasswordClassificationToken = "current-password", | |
WBSCredentialNewPasswordClassificationToken = "new-password", | |
WBSContactNameClassificationToken = "name", | |
WBSContactGivenNameClassificationToken = "given-name", | |
WBSContactAdditionalNameClassificationToken = "additional-name", | |
WBSContactFamilyNameClassificationToken = "family-name", | |
WBSContactClassificationDefaultOrderedParts = [ WBSContactGivenNameClassificationToken, WBSContactAdditionalNameClassificationToken, WBSContactFamilyNameClassificationToken ], | |
WBSContactNamePartsSet = new Set(WBSContactClassificationDefaultOrderedParts), | |
WBSContactInstantMessageClassificationToken = "-sf-instant-message", | |
WBSContactPostalCodeClassificationToken = "postal-code", | |
WBSContactStreetAddressClassificationToken = "street-address", | |
WBSContactStreetAddressLine1ClassificationToken = "address-line1", | |
WBSContactStreetAddressLine2ClassificationToken = "address-line2", | |
WBSContactStreetAddressLine3ClassificationToken = "address-line3", | |
WBSContactTelephoneClassificationToken = "tel", | |
WBSContactTelephoneCountryCodeClassificationToken = "tel-country-code", | |
WBSContactTelephoneAreaCodeClassificationToken = "tel-area-code", | |
WBSContactTelephoneLocalPrefixClassificationToken = "tel-local-prefix", | |
WBSContactTelephoneLocalSuffixClassificationToken = "tel-local-suffix", | |
WBSContactTelephoneExtensionClassificationToken = "tel-extension", | |
WBSContactTelephoneDefaultOrderedParts = [ WBSContactTelephoneCountryCodeClassificationToken, WBSContactTelephoneAreaCodeClassificationToken, WBSContactTelephoneLocalPrefixClassificationToken, WBSContactTelephoneLocalSuffixClassificationToken, WBSContactTelephoneExtensionClassificationToken ], | |
WBSContactBirthdayClassificationToken = "bday", | |
WBSContactBirthdayDayClassificationToken = "bday-day", | |
WBSContactBirthdayMonthClassificationToken = "bday-month", | |
WBSContactBirthdayYearClassificationToken = "bday-year"; | |
class FormMetadataClassification { | |
#t(t) | |
{ | |
return null != t && "object" == typeof t | |
} | |
#e(t) | |
{ | |
return this.#t(t) && "string" == typeof t.ControlTagName | |
} | |
#o(t) | |
{ | |
return this.#t(t) && "string" == typeof t.property | |
} | |
fieldLooksLikeDateField(t) | |
{ | |
return !!(t.ControlLooksLikeDayField || t.ControlLooksLikeMonthField || t.ControlLooksLikeYearField) | |
} | |
#i(t) | |
{ | |
let e = t.ControlMaxLength; | |
return (void 0 === e || e < 0 || e > WBSFormControlMetadataDefaultMaxLength) && (e = WBSFormControlMetadataDefaultMaxLength), e | |
} | |
fieldLooksLikeItExpectsDataOfSize(t, e) | |
{ | |
return (t.ControlSize ?? 0) <= e || this.#i(t) <= e | |
} | |
fieldCouldBeCreditCardNumberContinuation(t, e) | |
{ | |
const o = 4; | |
if (e.length >= o) | |
return !1; | |
if (!e[0]?.ControlLooksLikeCreditCardNumberField) | |
return !1; | |
const i = 2; | |
if (t.ControlMaxLength === i) | |
return !1; | |
if (t.ControlLooksLikeCreditCardNumberField) | |
return !0; | |
if (t.ControlLooksLikeCreditCardSecurityCodeField) | |
return !1; | |
if (t.ControlLooksLikeCreditCardCompositeExpirationDateField) | |
return !1; | |
const n = 6; | |
if (!this.fieldLooksLikeItExpectsDataOfSize(t, n)) | |
return !1; | |
const a = e.at(-1); | |
return !(a && !this.fieldLooksLikeItExpectsDataOfSize(a, n)) | |
} | |
labelsCouldRepresentContinuation(t, e, o, i) | |
{ | |
return !(!t || !o) && (t === o || !!e && (!i || e.property === i.property && (i.component && e.component === i.component))) | |
} | |
fieldCouldBePhoneNumberContinuation(t, e) | |
{ | |
const o = 5; | |
if (e.length >= o) | |
return !1; | |
if (e[0]?.AddressBookValueSpecifier?.property !== WBSABPhoneProperty) | |
return !1; | |
const i = 5; | |
return !!this.fieldLooksLikeItExpectsDataOfSize(t, i) | |
} | |
fieldCouldBePostCodeContinuation(t, e) | |
{ | |
const o = 3; | |
if (e.length >= o) | |
return !1; | |
if (e[0]?.AddressBookValueSpecifier?.component != _WBSABAddressZIPKey) | |
return !1; | |
const i = 6; | |
return !!this.fieldLooksLikeItExpectsDataOfSize(t, i) | |
} | |
fieldLooksLikeSameDataType(t, e) | |
{ | |
const o = e.at(-1); | |
return !!this.labelsCouldRepresentContinuation(o?.AddressBookLabel, o?.AddressBookValueSpecifier, t?.AddressBookLabel, t?.AddressBookValueSpecifier) || (!!(o && this.fieldLooksLikeDateField(o) && this.fieldLooksLikeDateField(t)) || (!!this.fieldCouldBePhoneNumberContinuation(t, e) || (!!this.fieldCouldBePostCodeContinuation(t, e) || !!this.fieldCouldBeCreditCardNumberContinuation(t, e)))) | |
} | |
#n(t) | |
{ | |
return globalThis.DOMRect || (globalThis.DOMRect = class { | |
constructor(t, e, o, i) | |
{ | |
this.left = t, this.right = t + o, this.top = e, this.bottom = e + i, this.width = o, this.height = i | |
} | |
}), t.ControlRectLeft || t.ControlRectTop || t.ControlRectWidth || t.ControlRectHeight ? new DOMRect(t.ControlRectLeft, t.ControlRectTop, t.ControlRectWidth, t.ControlRectHeight) : globalThis.FormMetadataJS ? FormMetadataJS.formControlWithUniqueID(t.ControlUniqueID)?.getBoundingClientRect() | |
: new DOMRect(0, 0, 0, 0) | |
} | |
fieldLooksLikeContinuation(t, e, o) | |
{ | |
if (!t.ControlIsTextField && "SELECT" !== t.ControlTagName.toUpperCase()) | |
return !1; | |
if (!this.fieldLooksLikeSameDataType(t, e)) | |
return !1; | |
if (o) | |
return !0; | |
const i = this.#n(e.at(-1)), | |
n = this.#n(t); | |
if (Math.abs(i.top - n.top) > 3) | |
return !1; | |
let a, r; | |
return i.left < n.left ? (a = i, r = n) : (a = n, r = i), !(r.left - a.right > 60) | |
} | |
continuingFieldsInFormControls(t, e, o, i) | |
{ | |
const n = [ t[e] ]; | |
for (let a = e + 1; a < t.length; ++a) { | |
const e = t[a]; | |
if (o && !e.ControlIsTextField) | |
break; | |
if (!this.fieldLooksLikeContinuation(e, n, i)) | |
break; | |
n.push(e) | |
} | |
return n | |
} | |
classifyControlsRelatedToNameParts(t, e) | |
{ | |
const o = t[e]; | |
o.ControlClassification = WBSContactNameClassificationToken, o.ControlOrderedParts = [ o.AddressBookValueSpecifier?.classification ]; | |
const i = new Set([ o.AddressBookValueSpecifier?.classification ]), | |
n = [ t[e] ]; | |
for (let o = e + 1; o < t.length; ++o) { | |
const e = t[o]; | |
if (!e.ControlIsTextField) | |
break; | |
const a = e.AddressBookValueSpecifier?.classification; | |
if (!a) | |
break; | |
if (!WBSContactNamePartsSet.has(a) || i.has(a)) | |
break; | |
e.ControlClassification = WBSContactNameClassificationToken, e.ControlOrderedParts = [ a ], i.add(a), n.push(e) | |
} | |
return n | |
} | |
identifyDateFields(t) | |
{ | |
let e, o, i, n = !1; | |
for (let a of t) | |
if (a.ControlLooksLikeDayField) { | |
if (e) | |
return [ !1 ]; | |
e = a, n = !0 | |
} else if (a.ControlLooksLikeMonthField) { | |
if (o) | |
return [ !1 ]; | |
o = a, n = !0 | |
} else if (a.ControlLooksLikeYearField) { | |
if (i) | |
return [ !1 ]; | |
i = a, n = !0 | |
} | |
return [ n, i, o, e ] | |
} | |
canonicalizedDateTemplate(t) | |
{ | |
if (t && (t = t.replace(/\s/g, "")).length && !/[^dmyDMY\/.-]/g.test(t)) | |
return t = (t = (t = t.replace(/D/g, "d")).replace(/m/g, "M")).replace(/Y/g, "y") | |
} | |
classifyDateFields(t, e, o, i, n, a, r) | |
{ | |
if (t.length > 3) | |
return !1; | |
if (1 === t.length) { | |
if (!t[0].ControlIsTextField) | |
return !1; | |
let a = t[0].ControlRequiredFormatForDateTimeInput; | |
if (!a) { | |
const e = n ? new Date(1999, 11, 30) : new Date(1999, 11); | |
let o = this.#i(t[0]), | |
i = this.canonicalizedDateTemplate(t[0].ControlPlaceholder), | |
s = i?.length ? i : n ? "ddMMy" | |
: "MMyy"; | |
a = FormMetadataJSController.dateFormatFromTemplate(s, r); | |
let l = FormMetadataJSController.stringFromDateFormat(a, e); | |
if (l.length > o && (s = n ? "dMMyy" : "MMyy", a = FormMetadataJSController.dateFormatFromTemplate(s, r), l = FormMetadataJSController.stringFromDateFormat(a, e), l.length > o && (s = n ? "dMyy" : "Myy", a = FormMetadataJSController.dateFormatFromTemplate(s, r), l = FormMetadataJSController.stringFromDateFormat(a, e))), l.length > o) | |
return !1 | |
} | |
const s = []; | |
for (const t of a) { | |
let e; | |
"y" === t ? e = o : "M" === t ? e = i | |
: "d" === t && (e = n), | |
e && !s.includes(e) && s.push(e) | |
} | |
return t[0].ControlClassification = e, t[0].ControlOrderedParts = s, t[0].ControlRequiredFormatForDateTimeInput = a, !0 | |
} | |
let [s, l, C, d] = this.identifyDateFields(t); | |
if (!s) | |
return !1; | |
if (d && !C) | |
return !1; | |
let c = 0; | |
for (const r of t) | |
r.ControlClassification = e, r.ControlContinuationID = a, r.ControlContinuationIndex = c++, r === d ? r.ControlOrderedParts = [ n ] : r === C ? r.ControlOrderedParts = [ i ] | |
: r === l && (r.ControlOrderedParts = [ o ]); | |
return !0 | |
} | |
classify(t) | |
{ | |
const e = t.FormControls, | |
o = e.length, | |
i = t.AutoFillFormType === WBSAutoFillFormTypeNewAccount, | |
n = t.AutoFillFormType === WBSAutoFillFormTypeChangePassword, | |
a = t.UsernameElementUniqueID, | |
r = t.PasswordElementUniqueID, | |
s = t.OldPasswordElementUniqueID, | |
l = t.ConfirmPasswordElementUniqueID; | |
for (let t of e) | |
(t.AutocompleteTokens || t.AddressBookLabel) && (t.AddressBookValueSpecifier = FormMetadataJSController.specifierForAutocompleteTokensAndAddressBookLabel(t.AutocompleteTokens, t.AddressBookLabel)); | |
let C = !1, | |
d = !1, | |
c = !1, | |
f = !1, | |
k = !1, | |
S = 0; | |
for (let u = 0, T = 1; u < o; u += T, T = 1) { | |
const o = e[u]; | |
if (o.ControlLooksLikeIgnoredDataTypeField) { | |
o.ControlClassification = WBSIgnoredClassificationToken; | |
continue | |
} | |
const B = o.ControlUniqueID; | |
if (B === r || B === l) { | |
o.ControlClassification = i || n ? WBSCredentialNewPasswordClassificationToken : WBSCredentialCurrentPasswordClassificationToken; | |
continue | |
} | |
if (B === s) { | |
o.ControlClassification = WBSCredentialCurrentPasswordClassificationToken; | |
continue | |
} | |
if (B === a) { | |
o.ControlClassification = WBSCredentialUsernameClassificationToken; | |
continue | |
} | |
if (!d && o.ControlLooksLikeCreditCardCardholderField) { | |
d = !0, o.ControlClassification = WBSCreditCardHolderNameClassificationToken, o.ControlOrderedParts = WBSCreditCardHolderNameClassificationDefaultOrderedParts; | |
continue | |
} | |
if (!C && o.ControlLooksLikeCreditCardNumberField) { | |
C = !0; | |
const t = this.continuingFieldsInFormControls(e, u, !0, !1); | |
let o = 0, | |
i = t.length > 1 ? ++S : 0; | |
for (let e of t) | |
e.ControlClassification = WBSCreditCardNumberClassificationToken, e.ControlContinuationID = i, e.ControlContinuationIndex = o++; | |
T = t.length; | |
continue | |
} | |
const h = this.fieldLooksLikeDateField(o) || o.ControlLooksLikeCreditCardCompositeExpirationDateField; | |
if ((f || d || C) && !c && h) { | |
c = !0; | |
const t = this.continuingFieldsInFormControls(e, u, !1, !0); | |
let o = t.length > 1 ? ++S : 0; | |
this.classifyDateFields(t, WBSCreditCardExpirationClassificationToken, WBSCreditCardExpirationYearClassificationToken, WBSCreditCardExpirationMonthClassificationToken, void 0, o, WBSLocaleForCreditCardExpirationDate), T = t.length; | |
continue | |
} | |
if (!k && o.ControlLooksLikeCreditCardSecurityCodeField) { | |
k = !0, o.ControlClassification = WBSCreditCardSecurityCodeClassificationToken; | |
continue | |
} | |
if (!f && o.ControlLooksLikeCreditCardTypeField) { | |
f = !0, o.ControlClassification = WBSCreditCardTypeClassificationToken; | |
continue | |
} | |
const m = o.AddressBookValueSpecifier?.classification; | |
if (m) { | |
const i = o.AddressBookValueSpecifier.classificationHint; | |
if (m === WBSContactNameClassificationToken) { | |
o.ControlClassification = m, o.ControlOrderedParts = WBSContactClassificationDefaultOrderedParts; | |
continue | |
} | |
if (WBSContactNamePartsSet.has(m)) { | |
const t = this.classifyControlsRelatedToNameParts(e, u); | |
if (t.length > 1) { | |
let e = ++S, | |
o = 0; | |
for (let i of t) | |
i.ControlContinuationID = e, i.ControlContinuationIndex = o++ | |
} | |
T = t.length; | |
continue | |
} | |
if (m === WBSContactPostalCodeClassificationToken) { | |
const t = this.continuingFieldsInFormControls(e, u, !0, !1); | |
let o = t.length > 1 ? ++S : 0, | |
i = 0; | |
for (let e of t) | |
e.ControlClassification = WBSContactPostalCodeClassificationToken, e.ControlContinuationID = o, e.ControlContinuationIndex = i++; | |
T = t.length; | |
continue | |
} | |
if (m === WBSContactStreetAddressClassificationToken) { | |
const t = this.continuingFieldsInFormControls(e, u, !0, !0); | |
let o = t.length > 1 ? ++S : 0, | |
i = 0; | |
for (let e of t) | |
e.ControlClassification = WBSContactStreetAddressClassificationToken, e.ControlContinuationID = o, e.ControlContinuationIndex = i++; | |
1 === t.length ? t[0].ControlOrderedParts = [ WBSContactStreetAddressLine1ClassificationToken, WBSContactStreetAddressLine2ClassificationToken, WBSContactStreetAddressLine3ClassificationToken ] : 2 === t.length ? (t[0].ControlOrderedParts = [ WBSContactStreetAddressLine1ClassificationToken ], t[1].ControlOrderedParts = [ WBSContactStreetAddressLine2ClassificationToken, WBSContactStreetAddressLine3ClassificationToken ]) | |
: t.length >= 3 && (t[0].ControlOrderedParts = [ WBSContactStreetAddressLine1ClassificationToken ], t[1].ControlOrderedParts = [ WBSContactStreetAddressLine2ClassificationToken ], t[2].ControlOrderedParts = [ WBSContactStreetAddressLine3ClassificationToken ]), | |
T = t.length; | |
continue | |
} | |
if (m === WBSContactInstantMessageClassificationToken) { | |
const t = this.continuingFieldsInFormControls(e, u, !0, !0); | |
1 === t.length && (t[0].ControlClassification = WBSContactInstantMessageClassificationToken, i && (t[0].ControlClassificationHints = [ i ])), T = t.length; | |
continue | |
} | |
if (m.startsWith(WBSContactTelephoneClassificationToken)) { | |
const t = this.continuingFieldsInFormControls(e, u, !0, !1); | |
if (1 == t.length) { | |
t[0].ControlClassification = WBSContactTelephoneClassificationToken, t[0].ControlOrderedParts = WBSContactTelephoneDefaultOrderedParts, i && (t[0].ControlClassificationHints = [ i ]); | |
continue | |
} | |
let o = ++S, | |
n = 0; | |
for (let e of t) | |
e.ControlClassification = WBSContactTelephoneClassificationToken, e.ControlContinuationID = o, e.ControlContinuationIndex = n++, i && (e.ControlClassificationHints = [ i ]); | |
2 === t.length ? (t[0].ControlOrderedParts = [ WBSContactTelephoneAreaCodeClassificationToken ], t[1].ControlOrderedParts = [ WBSContactTelephoneLocalPrefixClassificationToken, WBSContactTelephoneLocalSuffixClassificationToken ]) : 3 === t.length ? (t[0].ControlOrderedParts = [ WBSContactTelephoneAreaCodeClassificationToken ], t[1].ControlOrderedParts = [ WBSContactTelephoneLocalPrefixClassificationToken ], t[2].ControlOrderedParts = [ WBSContactTelephoneLocalSuffixClassificationToken ]) | |
: 4 === t.length ? (t[0].ControlOrderedParts = [ WBSContactTelephoneCountryCodeClassificationToken ], t[1].ControlOrderedParts = [ WBSContactTelephoneAreaCodeClassificationToken ], t[2].ControlOrderedParts = [ WBSContactTelephoneLocalPrefixClassificationToken ], t[3].ControlOrderedParts = [ WBSContactTelephoneLocalSuffixClassificationToken ]) | |
: (t[0].ControlOrderedParts = [ WBSContactTelephoneCountryCodeClassificationToken ], t[1].ControlOrderedParts = [ WBSContactTelephoneAreaCodeClassificationToken ], t[2].ControlOrderedParts = [ WBSContactTelephoneLocalPrefixClassificationToken ], t[3].ControlOrderedParts = [ WBSContactTelephoneLocalSuffixClassificationToken ], t[4].ControlOrderedParts = [ WBSContactTelephoneExtensionClassificationToken ]), | |
T = t.length; | |
continue | |
} | |
if (m === WBSContactBirthdayClassificationToken) { | |
const o = this.continuingFieldsInFormControls(e, u, !1, !1), | |
i = o.length > 1 ? ++S : void 0, | |
n = t.RequestType === WBSFormMetadataRequestTesting ? "en_US" : void 0; | |
this.classifyDateFields(o, WBSContactBirthdayClassificationToken, WBSContactBirthdayYearClassificationToken, WBSContactBirthdayMonthClassificationToken, WBSContactBirthdayDayClassificationToken, i, n), T = o.length; | |
continue | |
} | |
o.ControlClassification = m | |
} else | |
; | |
} | |
} | |
} | |
globalThis.FormMetadataClassificationJS = new FormMetadataClassification; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// # sourceURL=__InjectedScript_FormMetadata.js | |
/* Copyright (c) 2024 Apple Inc. All rights reserved. */ | |
function legacyPlaceholderInfoForInputElement(e) | |
{ | |
if ("text" !== e.type) | |
return null; | |
if (doctypeLooksLikeHTML5) | |
return null; | |
var t = e.value.trim(); | |
if (!t) | |
return null; | |
for (var o = !1, r = !0, n = e.attributes, i = n.length, l = 0; l < i; ++l) { | |
var a = n[l]; | |
if (t === a.value.trim() && (o = !0, "value" !== a.name.toLowerCase())) { | |
r = !1; | |
break | |
} | |
} | |
return o ? { | |
Text : t, | |
AttributeMatchedWasValue : r | |
} | |
: null | |
} | |
function placeholderInfoForElement(e) | |
{ | |
var t = e.getAttribute("placeholder"); | |
if (t) | |
return { | |
Text : t, | |
AttributeMatchedWasValue : !1 | |
}; | |
var o = e.getAttribute("data-placeholder"); | |
return o && o.length ? { | |
Text : o, | |
AttributeMatchedWasValue : !1 | |
} | |
: isInputElement(e) ? legacyPlaceholderInfoForInputElement(e) | |
: null | |
} | |
function sharedPrefixLength(e, t) | |
{ | |
for (var o = 0, r = 0, n = e.length; r < n && e[r] === t[r]; ++r) | |
o++; | |
return o | |
} | |
function rowContainingLabelAboveRow(e) | |
{ | |
for (var t = e.getBoundingClientRect(), o = e.previousElementSibling; o instanceof HTMLTableRowElement; o = o.previousElementSibling) { | |
if (o.querySelector("input, select, textarea")) | |
return null; | |
var r = o.getBoundingClientRect(); | |
if (t.top - r.bottom > t.height / 2) | |
return null; | |
if (o.innerText.match(/\S/)) | |
return o | |
} | |
return null | |
} | |
function cellVisuallyAbove(e) | |
{ | |
let t = e.parentElementIncludingShadowDOMHost(); | |
if (!(t && t instanceof HTMLTableRowElement)) | |
return null; | |
var o = rowContainingLabelAboveRow(t); | |
if (!o) | |
return null; | |
for (var r = e.getBoundingClientRect(), n = o.children, i = n.length, l = null, a = 0, s = 0; s < i; ++s) { | |
var u = n[s], | |
c = u.getBoundingClientRect(), | |
d = Math.min(c.right, r.right) - Math.max(c.left, r.left); | |
(!l || d > a) && (a = d, l = u) | |
} | |
return l | |
} | |
function couldBeFormSubmissionControl(e) | |
{ | |
if (e instanceof HTMLButtonElement) | |
return !0; | |
if (e instanceof HTMLInputElement) { | |
var t = e.type; | |
return "submit" === t || "image" === t | |
} | |
return !1 | |
} | |
function isInputElement(e) | |
{ | |
return e instanceof HTMLInputElement | |
} | |
function isDateTimeInputElement(e) | |
{ | |
return !!isInputElement(e) && DateTimeInputTypes.includes(e.type) | |
} | |
function isRadioButtonElement(e) | |
{ | |
return !!isInputElement(e) && "radio" === e.type | |
} | |
function anchorWithURLString(e) | |
{ | |
var t = document.createElement("a"); | |
return t.href = e, t | |
} | |
function pathComponentsForLocation(e) | |
{ | |
var t = e.pathname.substring(1).split("/"); | |
return t[t.length - 1] || t.pop(), t | |
} | |
function lastPathComponentFromAnchor(e) | |
{ | |
var t = pathComponentsForLocation(e); | |
return t.length ? t[t.length - 1] : null | |
} | |
function lastPathComponentForURLString(e) | |
{ | |
return lastPathComponentFromAnchor(anchorWithURLString(e)) | |
} | |
function urlEncode(e) | |
{ | |
return encodeURIComponent(e).replace(/%20/g, "+") | |
} | |
function isCheckboxOrRadioButtonInDefaultState(e) | |
{ | |
return e.checked === e.defaultChecked | |
} | |
function isSelectInDefaultState(e) | |
{ | |
for (var t = e.options, o = t.length, r = 0; r < o; ++r) { | |
var n = t[r]; | |
if (n.selected !== n.defaultSelected) { | |
if (n.defaultSelected) | |
return !1; | |
if (e.multiple || r) | |
return !1 | |
} | |
} | |
return !0 | |
} | |
function formActionAsAnchorElement(e, t) | |
{ | |
if (!(e instanceof HTMLFormElement)) | |
return null; | |
let o = e.getAttribute("action"); | |
if (!o && t) | |
return null; | |
var r = document.createElement("a"); | |
return r.href = o || "", r | |
} | |
function eventThatBubbles(e) | |
{ | |
return new CustomEvent(e, { | |
bubbles : !0 | |
}) | |
} | |
function formControlHasBeenClassifiedInAnInterestingWay(e) | |
{ | |
return e.ControlIsActiveElement || e.ControlIsSecureTextField || e.ControlLooksLikePasswordCredentialField || e.ControlLooksLikeCreditCardNumberField || e.ControlLooksLikeCreditCardSecurityCodeField || e.ControlLooksLikeCreditCardCardholderField || e.ControlLooksLikeCreditCardTypeField || e.AddressBookLabel || e.ControlLooksLikeDayField || e.ControlLooksLikeMonthField || e.ControlLooksLikeYearField || e.ControlLooksLikeOneTimeCodeField || e.ControlLooksLikeCreditCardCompositeExpirationDateField || e.ControlLooksLikeEIDField || e.ControlLooksLikeIMEIField | |
} | |
function isValidUsernameOrEmail(e) | |
{ | |
const t = /^[a-z_][a-z0-9_.]{2,30}$/i, | |
o = /^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i; | |
return !(!e || e.length < 3 || "true" === e || "false" === e) && (t.test(e) || o.test(e)) | |
} | |
function selectorForElement(e) | |
{ | |
let t = e.localName, | |
o = e.getAttribute("id"); | |
o && (t += `#${o}`); | |
let r = e.classList, | |
n = r.length; | |
for (let e = 0; e < n; e++) | |
t += "." + r[e]; | |
return t | |
} | |
function hasOwnProperties(e) | |
{ | |
return Object.getOwnPropertyNames(e).length > 0 | |
} | |
function defaultOptionForSelectElement(e) | |
{ | |
for (var t = e.options, o = t.length, r = 0; r < o; ++r) { | |
var n = t[r]; | |
if (n.defaultSelected) | |
return n | |
} | |
return t[0] | |
} | |
function selectElementOptionsSequenceAnalysis(e, t) | |
{ | |
for (var o = e.options, r = o.length, n = 0, i = -1, l = -1, a = 0, s = 0; s < r; ++s) { | |
var u = o[s], | |
c = parseInt(u[t]); | |
isNaN(c) ? (a >= n && (n = a, i = l), l = -1, a = 0) : -1 === l ? (l = c, a = 1) | |
: c === l + 1 && (l = c, a++) | |
} | |
return a >= n && (n = a, i = l), | |
{ | |
lengthOfLongestSequence: n, | |
lastNumberInSequence: i | |
} | |
} | |
function isElementPositionedToBeEffectivelyInvisible(e) | |
{ | |
var t = !1; | |
for (let o = e; o; o = o.parentElementIncludingShadowDOMHost()) | |
if ("fixed" === getComputedStyle(o).position) { | |
t = !0; | |
break | |
} | |
var o, r, n, i = e.getBoundingClientRect(); | |
if (t) | |
o = i, r = window.innerWidth, n = window.innerHeight; | |
else { | |
var l = window.scrollY, | |
a = window.scrollX; | |
o = { | |
top : i.top + l, | |
right : i.right + a, | |
bottom : i.bottom + l, | |
left : i.left + a, | |
width : i.width, | |
height : i.height | |
}, | |
r = document.documentElement.scrollWidth, n = Math.max(document.documentElement.scrollHeight, window.innerHeight) | |
} | |
return o.top >= n || o.right <= 0 || o.bottom <= 0 || o.left >= r | |
} | |
function rectIsWithinDocumentViewport(e) | |
{ | |
return e.right >= 0 && e.bottom >= 0 && e.left <= window.innerWidth && e.top <= window.innerHeight | |
} | |
function isCredentialElementUniqueID(e, t) | |
{ | |
return t === e.UsernameElementUniqueID || t === e.PasswordElementUniqueID || t === e.ConfirmPasswordElementUniqueID || t === e.OldPasswordElementUniqueID | |
} | |
function autocompleteTokens(e) | |
{ | |
const t = [ "autocomplete", "autocompletetype", "x-autocompletetype" ]; | |
let o = []; | |
for (const r of t) | |
e.hasAttribute(r) && o.push(e.getAttribute(r).trim().toLowerCase()); | |
if (!o.length) | |
return null; | |
let r = o.join(" ").split(/\s+/).filter((function(e) { | |
return e.length && "off" !== e && "on" !== e | |
})); | |
return r.length ? r : null | |
} | |
function elementIDOrAutocompleteTokensHasToken(e, t, o) | |
{ | |
return !!e.id?.includes(o) || !!t?.includes(o) | |
} | |
function controlAppearsToBePartOfPhotoTaggingInterface(e) | |
{ | |
const t = /photo.*tag/i; | |
for (let o = e.parentElementIncludingShadowDOMHost(); o; o = o.parentElementIncludingShadowDOMHost()) | |
if (t.test(o.className)) | |
return !0; | |
return !1 | |
} | |
function levenshteinDistance(e, t) | |
{ | |
for (var o = e.length, r = t.length, n = new Array(o + 1), i = 0; i < o + 1; ++i) | |
n[i] = new Array(r + 1), n[i][0] = i; | |
for (var l = 0; l < r + 1; ++l) | |
n[0][l] = l; | |
for (l = 1; l < r + 1; ++l) | |
for (i = 1; i < o + 1; ++i) | |
if (e[i - 1] === t[l - 1]) | |
n[i][l] = n[i - 1][l - 1]; | |
else { | |
var a = n[i - 1][l] + 1, | |
s = n[i][l - 1] + 1, | |
u = n[i - 1][l - 1] + 1; | |
n[i][l] = Math.min(a, s, u) | |
} | |
return n[o][r] | |
} | |
function stringSimilarity(e, t) | |
{ | |
var o = Math.max(e.length, t.length); | |
return o ? (o - levenshteinDistance(e, t)) / o : 0 | |
} | |
function stripCommonPrefix(e, t) | |
{ | |
const o = e.length, | |
r = t.length, | |
n = o < r ? o : r; | |
let i = 0; | |
for (; i < n && e[i] === t[i];) | |
i++; | |
return [ e.slice(i), t.slice(i) ] | |
} | |
function articleTitleAndSiteNameFromTitleString(e, t) | |
{ | |
const o = [ " - ", " \u2013 ", " \u2014 ", ": ", " | ", " \xbb " ], | |
r = o.length, | |
n = .6; | |
for (var i, l, a = e.replace(/^(www|m|secure)\./, ""), s = a.replace(/\.(com|info|net|org|edu|gov)$/, "").toLowerCase(), u = 0; u < r; ++u) { | |
var c = t.split(o[u]); | |
if (2 === c.length) { | |
var d = c[0].trim(), | |
h = c[1].trim(), | |
m = d.toLowerCase(), | |
F = h.toLowerCase(), | |
f = Math.max(stringSimilarity(m, a), stringSimilarity(m, s)), | |
g = Math.max(stringSimilarity(F, a), stringSimilarity(F, s)), | |
p = Math.max(f, g); | |
(!l || p > l) && (l = p, i = f > g ? { | |
siteName : d, | |
articleTitle : h | |
} | |
: { | |
siteName : h, | |
articleTitle : d | |
}) | |
} | |
} | |
return i && l >= n ? i : null | |
} | |
function documentTitleWithoutHostNamePrefix() | |
{ | |
const e = document.title, | |
t = articleTitleAndSiteNameFromTitleString(window.location.host, e); | |
return t ? t.articleTitle : e | |
} | |
function querySelectorAllIncludingWithinShadowRoots(e, t) | |
{ | |
let o = []; | |
for (let r of e.querySelectorAll("*")) | |
if (r.shadowRoot) { | |
let e = querySelectorAllIncludingWithinShadowRoots(r.shadowRoot, t); | |
e.length && (o = o.concat(e)) | |
} else | |
r.matches(t) && o.push(r); | |
return o | |
} | |
function queryAllBySelector(e, t) | |
{ | |
try { | |
return window.collectMatchingElementsInFlatTree ? window.collectMatchingElementsInFlatTree(e, t) : querySelectorAllIncludingWithinShadowRoots(e, t) | |
} catch (e) { | |
return [] | |
} | |
} | |
function getElementByID(e) | |
{ | |
let t = queryAllBySelector(document, `[id='${e}']`); | |
return t.length ? t[0] : null | |
} | |
function siblingsIncludingSelfForElement(e) | |
{ | |
let t = e.parentElement; | |
if (t) | |
return t.children; | |
let o = e; | |
for (; o.previousElementSibling;) | |
o = o.previousElementSibling; | |
let r = [], | |
n = o; | |
for (; n;) | |
r.push(n), n = n.nextElementSibling; | |
return r | |
} | |
function regularExpressionFromUntrustedPatternAttributeString(e) | |
{ | |
if (e.startsWith("/") && e.endsWith("/") && (e = e.slice(1, -1)), !e.length) | |
return null; | |
try { | |
return new RegExp(e, "v"), new RegExp("^(?:" + e + ")$", "v") | |
} catch (e) { | |
return null | |
} | |
} | |
function regularExpressionsFromStrings(e) | |
{ | |
return e.map((e => new RegExp(e))) | |
} | |
function stringsMatchAnyRegularExpressions(e, t) | |
{ | |
for (let o of t) | |
for (let t of e) | |
if (o.test(t.toLowerCase())) | |
return !0; | |
return !1 | |
} | |
function pathFromAnchorWithoutLeadingSlash(e) | |
{ | |
let t = /\/(.*)/.exec(e.pathname); | |
return t && 2 === t.length ? t[1] : null | |
} | |
function innermostActiveElement() | |
{ | |
let e = document.activeElement, | |
t = e; | |
for (; t;) | |
t = t?.shadowRoot?.activeElement, t && (e = t); | |
return e | |
} | |
function elementAppearsToContinueCaptchaWidget(e) | |
{ | |
return !!e.querySelector("iframe[title*=captcha i], input[type=hidden][name*=recaptcha]") | |
} | |
const WBSAutoFillFormTypeUndetermined = 0, | |
WBSAutoFillFormTypeAutoFillableStandard = 1, | |
WBSAutoFillFormTypeNonAutoFillable = 2, | |
WBSAutoFillFormTypeAutoFillableLogin = 3, | |
WBSAutoFillFormTypeNewAccount = 4, | |
WBSAutoFillFormTypeChangePassword = 5, | |
WBSFormMetadataRequestNormal = 0, | |
WBSFormMetadataRequestPreFill = 1, | |
WBSFormMetadataRequestTesting = 2, | |
WBSFormMetadataRequestTextChange = 3, | |
WBSFormMetadataRequestCollectMetadataFromDebugMenu = 4, | |
ShouldStopAfterFirstMatch = { | |
CollectAllMatches : 0, | |
StopAfterFirstMatch : 1 | |
}, | |
ShouldFocus = { | |
No : 0, | |
Yes : 1 | |
}, | |
ShouldBlur = { | |
No : 0, | |
Yes : 1 | |
}, | |
ShouldAbandonCharacterByCharacterEntryIfTooSlow = { | |
No : 0, | |
Yes : 1 | |
}, | |
ShouldObscure = { | |
No : 0, | |
Yes : 1 | |
}, | |
ShouldSetAutoFilled = { | |
No : 0, | |
Yes : 1 | |
}, | |
ForceNonFormElementAsLogicalBackingElement = { | |
No : !1, | |
Yes : !0 | |
}, | |
LogicalFormCreationIsProvisional = { | |
No : !1, | |
Yes : !0 | |
}, | |
MatchCriteria = { | |
Property : 0, | |
Category : 1, | |
Literal : 2 | |
}, | |
PageScanCharactersSearchedThreshold = 500, | |
PageScanMaxCharactersSearched = 600, | |
MaximumNumberOfCharactersToCollectForLanguageIdentification = 300, | |
MinValueForMaxLengthAttributeToTreatAsPasswordField = 4, | |
UsernameCandidateScoreForPlainTextField = 1, | |
UsernameCandidateScoreForPlainTextFieldDirectlyBeforePasswordField = 2, | |
UsernameCandidateScoreForEmailLabeledFieldBelowPasswordField = 3, | |
UsernameCandidateScoreForUsernameLabeledFieldBelowPasswordField = 4, | |
UsernameCandidateScoreForEmailLabeledFieldAbovePasswordField = 5, | |
UsernameCandidateScoreForUsernameLabeledFieldAbovePasswordField = 6, | |
UsernameCandidateScoreBonusForVisibleElement = .5, | |
UsernameCandidateScorePenaltyForReadOnlyElement = .5, | |
UsernameCandidateScorePenaltyForMatchingNonUsernameFieldLabelPattern = 2, | |
UsernameCandidateScorePenaltyForMatchingSearchFieldLabelPattern = 1.5, | |
UsernameCandidateScorePenaltyForAnonymousElement = 1, | |
LowestScoreForUsernameFieldCandidate = UsernameCandidateScoreForPlainTextField, | |
LowestScoreForLabeledUsernameFieldCandidate = UsernameCandidateScoreForEmailLabeledFieldBelowPasswordField, | |
MaxLengthForFieldAboveWhichToTreatPotentialOneTimeCodeFieldAsRequiringHigherScrutiny = 10, | |
DateTimeInputTypes = [ "date", "datetime-local", "month", "time", "week" ], | |
DateTimeInputTypeFormats = { | |
date : "yyyy-MM-dd", | |
"datetime-local" : "yyyy-MM-dd'T'hh:mm", | |
month : "yyyy-MM", | |
time : "hh:mm", | |
week : "yyyy-'W'ww" | |
}, | |
numberOfConsecutiveElementsWithoutSuccessfulPageScanAfterWhichPageScanIsAbandoned = 40; | |
var mapOfFormTypeToProducerOfAssociatedKeywords = function() { | |
var e = {}; | |
return e[WBSAutoFillFormTypeNewAccount] = function() { | |
return FormMetadataJSController.mapOfKeywordsIndicatingNewAccountFormTypeToScoreForMatching | |
}, e[WBSAutoFillFormTypeAutoFillableLogin] = function() { | |
return FormMetadataJSController.mapOfKeywordsIndicatingLoginFormTypeToScoreForMatching | |
}, e[WBSAutoFillFormTypeChangePassword] = function() { | |
return FormMetadataJSController.mapOfKeywordsIndicatingChangePasswordFormTypeToScoreForMatching | |
}, e | |
}(), visibilityCacheGeneration = 0; | |
let doctypeLooksLikeHTML5 = "html" === document.doctype?.name && "" === document.doctype?.publicId && "" === document.doctype?.systemId; | |
console.autofillDebugLog = function() { | |
FormMetadataJSController.isDebugConsoleLoggingEnabled | |
}, Node.prototype.traversePreviousNode = function(e) { | |
if (this) { | |
var t = this.previousSibling; | |
if (e(t)) | |
return null; | |
for (; t && t.lastChild;) | |
if (e(t = t.lastChild)) | |
return null; | |
return t || this.parentNode | |
} | |
}, Node.prototype.traverseNextNode = function(e) { | |
if (this) { | |
var t = this.firstChild; | |
if (t) | |
return t; | |
if (e && this === e) | |
return null; | |
if (t = this.nextSibling) | |
return t; | |
for (t = this; t && !t.nextSibling && (!e || !t.parentNode || t.parentNode !== e);) | |
t = t.parentNode; | |
return t ? t.nextSibling : null | |
} | |
}, Node.prototype.isVisible = function() { | |
let e = this; | |
if (e._isVisible === visibilityCacheGeneration) | |
return !0; | |
if (e._isVisible === -visibilityCacheGeneration) | |
return !1; | |
let t = e.nodeType == Node.TEXT_NODE ? e.parentElementIncludingShadowDOMHost() : e, | |
o = getComputedStyle(t, null); | |
if (e._isVisible = -visibilityCacheGeneration, "none" === o.display || "visible" !== o.visibility) | |
return !1; | |
let r = 0 === parseFloat(o.opacity) ? 6 : 2; | |
return !(t.offsetWidth < r) && (!(t.offsetHeight < r) && (e._isVisible = visibilityCacheGeneration, !0)) | |
}, Object.defineProperty(Array.prototype, "joinFirstItems", { | |
value : function(e, t) { | |
t > this.length && (t = this.length); | |
for (var o = "", r = 0; r < t; ++r) | |
r > 0 && (o += e), o += this[r]; | |
return o | |
} | |
}), | |
DOMRect.prototype.isZeroRect = function() { | |
return !(this.top || this.right || this.bottom || this.left) | |
}, DOMRect.prototype.distanceToRect = function(e) { | |
function t(e) | |
{ | |
function t(e, t) | |
{ | |
return Math.pow(e.x - t.x, 2) + Math.pow(e.y - t.y, 2) | |
} | |
var o = e[0], | |
r = e[1]; | |
return o[0].x >= r[0].x && o[0].x < r[1].x || r[0].x >= o[0].x && r[0].x < o[1].x ? Math.abs(o[0].y - r[0].y) : o[0].y >= r[0].y && o[0].y < r[1].y || r[0].y >= o[0].y && r[0].y < o[1].y ? Math.abs(o[0].x - r[0].x) | |
: Math.sqrt(Math.min(t(o[0], r[1]), t(o[1], r[0]))) | |
} | |
var o = [ { | |
x : this.left, | |
y : this.top | |
}, | |
{ | |
x : this.right, | |
y : this.top | |
} ], | |
r = [ { | |
x : this.right, | |
y : this.top | |
}, | |
{ | |
x : this.right, | |
y : this.bottom | |
} ], | |
n = [ { | |
x : this.left, | |
y : this.bottom | |
}, | |
{ | |
x : this.right, | |
y : this.bottom | |
} ], | |
i = [ { | |
x : this.left, | |
y : this.top | |
}, | |
{ | |
x : this.left, | |
y : this.bottom | |
} ], | |
l = [ { | |
x : e.left, | |
y : e.top | |
}, | |
{ | |
x : e.right, | |
y : e.top | |
} ], | |
a = [ { | |
x : e.right, | |
y : e.top | |
}, | |
{ | |
x : e.right, | |
y : e.bottom | |
} ], | |
s = [ { | |
x : e.left, | |
y : e.bottom | |
}, | |
{ | |
x : e.right, | |
y : e.bottom | |
} ], | |
u = [ { | |
x : e.left, | |
y : e.top | |
}, | |
{ | |
x : e.left, | |
y : e.bottom | |
} ], | |
c = [ | |
[ i, u ], | |
[ i, a ], | |
[ o, l ], | |
[ o, s ], | |
[ r, u ], | |
[ r, a ], | |
[ n, l ], | |
[ n, s ] | |
].map(t); | |
return Math.min.apply(Math, c) | |
}, Node.prototype.parentElementIncludingShadowDOMHost = function() { | |
let e = this.parentElement; | |
if (e) | |
return e; | |
let t = this.getRootNode(); | |
return t && t.host ? t.host : null | |
}, Node.prototype.allAncestorsAndSelfIncludingShadowDOMHosts = function() { | |
let e = [], | |
t = this; | |
for (; t;) | |
e.push(t), t = t.parentElementIncludingShadowDOMHost(); | |
return e | |
}, HTMLElement.prototype.closestCommonAncestor = function(e) { | |
let t = this.parentElement; | |
for (; t;) { | |
if (t.contains(e)) | |
return t; | |
t = t.parentElement | |
} | |
let o = this.allAncestorsAndSelfIncludingShadowDOMHosts().reverse(), | |
r = e.allAncestorsAndSelfIncludingShadowDOMHosts().reverse(), | |
n = Math.min(o.length, r.length), | |
i = null; | |
for (let e = 0; e < n; ++e) { | |
if (!(o[e] === r[e])) | |
break; | |
i = o[e] | |
} | |
return i || null | |
}, HTMLElement.prototype.isHiddenFromAccessibilityTree = function() { | |
const e = 2; | |
for (let o = 0, r = this; o <= e && r; ++o, r = r.parentElementIncludingShadowDOMHost()) { | |
var t = r.getAttribute("aria-hidden"); | |
if (t && "true" === t.toLowerCase()) | |
return !0 | |
} | |
return !1 | |
}, HTMLFormElement.prototype.isVisible = function() { | |
if (Node.prototype.isVisible.call(this)) | |
return !0; | |
for (var e = this.elements, t = e.length, o = 0; o < t; ++o) | |
if (e[o].isVisible()) | |
return !0; | |
return !1 | |
}, LogicalForm = function(e, t, o) { | |
let r = e.length; | |
var n = e[0].form, | |
i = n; | |
!t && i || (i = 1 === r ? e[0] : e[0].closestCommonAncestor(e[r - 1])), n && n.contains(e[r - 1]) || (n = i); | |
let l = FormMetadataJSController.nextFormUniqueID; | |
i._logicalFormUniqueIDs || (i._logicalFormUniqueIDs = new Set), this._formUniqueID = l, i._logicalFormUniqueIDs.add(), this._metadata = {}, this._weakControls = Array.prototype.map.call(e, (e => new WeakRef(e))), this._weakFormElement = new WeakRef(n), this._weakBackingElement = new WeakRef(i), o || this.markElementsAsPartOfLogicalForm() | |
}, LogicalForm.prototype = { | |
get elements() { | |
return this._weakControls.flatMap((e => e.deref())) | |
}, | |
get formElement() { | |
return this._weakFormElement.deref() | |
}, | |
get backingElement() { | |
return this._weakBackingElement.deref() | |
}, | |
get formUniqueID() { | |
return this._formUniqueID | |
}, | |
get metadata() { | |
return this._metadata | |
}, | |
set metadata(e) { | |
this._metadata = e | |
}, | |
containsControl : function(e) { | |
return "function" == typeof e._logicalFormUniqueIDs?.has ? e._logicalFormUniqueIDs.has(this.formUniqueID) : e.form === this.formElement | |
}, | |
radioButtonsWithName : function(e) { | |
let t = queryAllBySelector(document.documentElement, `*[name="${e}"]`); | |
return Array.prototype.filter.call(t, (function(e) { | |
return (e.form === this.formElement || this.formElement?.contains(e)) && isRadioButtonElement(e) | |
}), | |
this) | |
}, | |
annotate : function(e) { | |
let t = this.formElement; | |
if (t) { | |
var o = t._annotations; | |
if (o) { | |
for (var r in e) { | |
var n = e[r]; | |
n ? o[r] = n : delete o[r] | |
} | |
hasOwnProperties(o) || delete t._annotations | |
} else | |
t._annotations = e | |
} | |
}, | |
markElementsAsPartOfLogicalForm : function() { | |
let e = this._weakControls.length; | |
for (let t = 0; t < e; t++) { | |
let o = this._weakControls[t].deref(); | |
o && (o._logicalFormUniqueIDs || (o._logicalFormUniqueIDs = new Set), o._logicalFormUniqueIDs.add(this.formUniqueID), t + 1 < e && (o._weakNextControlInLogicalForm = this._weakControls[t + 1]), t > 0 && (o._weakPreviousControlInLogicalForm = this._weakControls[t - 1])) | |
} | |
}, | |
get annotations() { | |
return this.formElement?._annotations | |
}, | |
get isAnnotated() { | |
return !!this.annotations | |
} | |
}, | |
LogicalFormCache = function() { | |
this._logicalFormsByUniqueID = new Map | |
}, LogicalFormCache.prototype = { | |
get size() { | |
return this._logicalFormsByUniqueID.size | |
}, | |
cleanupCache : function() { | |
let e = new Set; | |
for (let t of this._logicalFormsByUniqueID.values()) | |
t.formElement || t.backingElement || e.add(t); | |
for (let t of e) | |
this._logicalFormsByUniqueID.delete(t.formUniqueID) | |
}, | |
logicalFormForControl : function(e) { | |
this.cleanupCache(); | |
for (let t of this._logicalFormsByUniqueID.values()) | |
if (t.containsControl(e)) | |
return t; | |
return null | |
}, | |
allForms : function() { | |
return this.cleanupCache(), Array.from(this._logicalFormsByUniqueID.values()) | |
}, | |
addOrUpdate : function(e) { | |
this._logicalFormsByUniqueID.set(e.formUniqueID, e) | |
}, | |
clearCacheAndAdd : function(e) { | |
this._logicalFormsByUniqueID.clear(); | |
for (let t of e) | |
this.addOrUpdate(t) | |
}, | |
logicalFormWithUniqueID : function(e) { | |
return this._logicalFormsByUniqueID.get(e) | |
} | |
}, | |
FormMetadata = function() { | |
this._logicalFormsCache = new LogicalFormCache, this._elementsWithGeneratedPasswords = [], this._generatedPasswords = [], this._labels = queryAllBySelector(document, "label"), this._controlUniqueIDToWeakControlMap = new Map, this._mapOfFormTypeToExtraScoreProducer = function() { | |
let e = {}; | |
return e[WBSAutoFillFormTypeNewAccount] = function() { | |
return 0 | |
}, e[WBSAutoFillFormTypeAutoFillableLogin] = function(e) { | |
const t = 2, | |
o = function(e) { | |
return "checkbox" === e.type && FormMetadataJS._labelsForElement(e).some((e => /(remember|keep) me/i.test(e.innerText.trim()) && e.isVisible())) | |
}; | |
return 1 === e.elements.filter((e => o(e))).length ? t : 0 | |
}, e[WBSAutoFillFormTypeChangePassword] = function() { | |
return 0 | |
}, e | |
}(), this._requiredFormatForDateTimeInput = DateTimeInputTypes.reduce((function(e, t) { | |
let o = document.createElement("input"); | |
o.type = t; | |
let r = "a"; | |
return o.value = r, e[t] = "" === o.value ? DateTimeInputTypeFormats[t] : "", e | |
}), | |
{}) | |
}, FormMetadata.prototype = { | |
_getTagName : function(e) { | |
var t = e.tagName; | |
return "string" == typeof t || "string" == typeof (t = e.nodeName) ? t : void 0 | |
}, | |
_getNameOrId : function(e) { | |
return e.name && e.name.length ? e.name : e.id | |
}, | |
controlUniqueID : function(e) { | |
if (e._controlUniqueID) | |
return e._controlUniqueID; | |
var t = "ControlID-" + FormMetadataJSController.nextControlUniqueID; | |
e._controlUniqueID = t; | |
this._controlUniqueIDToWeakControlMap.get(t); | |
return this._controlUniqueIDToWeakControlMap.set(t, new WeakRef(e)), e._controlUniqueID | |
}, | |
_searchForLabelsAboveCell : function(e, t) { | |
var o = window.getComputedStyle(t, null); | |
if (!o || "table-cell" !== o.getPropertyValue("display")) | |
return null; | |
var r = cellVisuallyAbove(t); | |
if (!r) | |
return null; | |
for (var n = 0, i = r.firstChild; i; i = i.traverseNextNode(r)) | |
if (i.nodeType == Node.TEXT_NODE && i.isVisible()) { | |
var l = i.nodeValue, | |
a = e.searchReverse(l); | |
if (a) | |
return { | |
Distance : n, | |
Match : a[0], | |
Property : a[1], | |
Category : a[2], | |
ParentProperty : a[3] | |
}; | |
n += l.length | |
} | |
return null | |
}, | |
_collectStringFromNodeForPageScan : function(e, t, o) { | |
var r = e.nodeValue, | |
n = r.length; | |
return o + n > PageScanMaxCharactersSearched && (r = r.substr(-(PageScanCharactersSearchedThreshold - o)), n = PageScanCharactersSearchedThreshold - o), (r = r.trim()).length && t.push(r), o | |
}, | |
_dataForComputingMatchFromPageScanBeforeElement : function(e, t) { | |
function o(e) | |
{ | |
return e && e.nodeType == Node.ELEMENT_NODE && e.matches("nav") | |
} | |
var r, n = [], | |
i = 0; | |
let l = this._logicalFormsCache.logicalFormForControl(e); | |
if (!l) | |
return [ | |
[], null | |
]; | |
var a = l.formElement, | |
s = a && a.isVisible(); | |
t || (t = a); | |
for (var u = e.traversePreviousNode(o); u && i < PageScanCharactersSearchedThreshold; u = u.traversePreviousNode(o)) { | |
var c = u.localName; | |
if (u === t) | |
break; | |
if (this._isRenderedFormControl(u)) { | |
if (u.isVisible() || !s) | |
break | |
} else { | |
if (this._isLabelElement(u) && u.isVisible()) | |
break; | |
if ("td" !== c || r) { | |
if ("tr" === c && r) | |
break; | |
if ("ul" === c || "ol" === c || "dl" === c) | |
break; | |
if ("li" === c) { | |
if (!u.parentNode.contains(e)) | |
break | |
} else | |
u.nodeType == Node.TEXT_NODE && u.isVisible() && (i += this._collectStringFromNodeForPageScan(u, n, i)) | |
} else | |
r = u | |
} | |
} | |
return [ n, r ] | |
}, | |
_matchFromPageScanBeforeElement : function(e, t, o) { | |
var r = this._pageScanContext ? this._pageScanContext.backwardScanCache : null, | |
n = this._pageScanDataForElementWithCacheAndDataProducer(t, r, this._dataForComputingMatchFromPageScanBeforeElement.bind(this), o), | |
i = n[0], | |
l = this._matchFromPatternMatcherAndStringsFromPageScan(e, i); | |
if (l) | |
return l; | |
var a = n[1]; | |
if (a) { | |
var s = this._searchForLabelsAboveCell(e, a); | |
if (s) | |
return s.IsInCellAbove = !0, s | |
} | |
return null | |
}, | |
_isElementFollowedByForgotUserNameOrEmailAffordance : function(e, t) { | |
this._forgotUserNameRegularExpressions || (this._forgotUserNameRegularExpressions = regularExpressionsFromStrings(FormMetadataJSController.regularExpressionsForForgotUserNameAffordance)), this._forgotEmailRegularExpressions || (this._forgotEmailRegularExpressions = regularExpressionsFromStrings(FormMetadataJSController.regularExpressionsForForgotEmailAffordance)); | |
let o = this._stringsToEvaluateToDetermineIfElementIsFollowedByAffordance(e, t); | |
return !!stringsMatchAnyRegularExpressions(o, this._forgotUserNameRegularExpressions) || !!stringsMatchAnyRegularExpressions(o, this._forgotEmailRegularExpressions) | |
}, | |
_isElementFollowedByForgotPasswordAffordance : function(e, t) { | |
return this._forgotPasswordRegularExpressions || (this._forgotPasswordRegularExpressions = regularExpressionsFromStrings(FormMetadataJSController.regularExpressionsForForgotPasswordAffordance)), stringsMatchAnyRegularExpressions(this._stringsToEvaluateToDetermineIfElementIsFollowedByAffordance(e, t), this._forgotPasswordRegularExpressions) | |
}, | |
_numberOfForgotUserNameEmailOrPasswordAffordancesFollowingElement : function(e, t) { | |
this._forgotEmailRegularExpressions || (this._forgotEmailRegularExpressions = regularExpressionsFromStrings(FormMetadataJSController.regularExpressionsForForgotEmailAffordance)), this._forgotPasswordRegularExpressions || (this._forgotPasswordRegularExpressions = regularExpressionsFromStrings(FormMetadataJSController.regularExpressionsForForgotPasswordAffordance)), this._forgotUserNameRegularExpressions || (this._forgotUserNameRegularExpressions = regularExpressionsFromStrings(FormMetadataJSController.regularExpressionsForForgotUserNameAffordance)); | |
let o = this._stringsToEvaluateToDetermineIfElementIsFollowedByAffordance(e, t), | |
r = 0; | |
return stringsMatchAnyRegularExpressions(o, this._forgotUserNameRegularExpressions) && r++, stringsMatchAnyRegularExpressions(o, this._forgotEmailRegularExpressions) && r++, stringsMatchAnyRegularExpressions(o, this._forgotPasswordRegularExpressions) && r++, r | |
}, | |
_stringsToEvaluateToDetermineIfElementIsFollowedByAffordance : function(e, t) { | |
let o = this._dataForComputingMatchFromPageScanAfterElement(e, "A"); | |
if (!o.length) { | |
const t = e.traverseNextNode(); | |
if (t) { | |
let e = t; | |
t instanceof Node && (e = t.parentElementIncludingShadowDOMHost()); | |
const r = e.querySelector("a"); | |
if (r) { | |
o.push(r.innerText); | |
const e = pathFromAnchorWithoutLeadingSlash(r); | |
e && o.push(e) | |
} | |
} | |
} | |
if (!o.length) | |
for (let r of queryAllBySelector(t, "a")) { | |
if (e.compareDocumentPosition(r) & Node.DOCUMENT_POSITION_FOLLOWING) { | |
o.push(r.innerText); | |
const e = pathFromAnchorWithoutLeadingSlash(r); | |
e && o.push(e) | |
} | |
} | |
const r = e._weakNextControlInLogicalForm?.deref(); | |
return r && "button" === r.type && o.push(r.innerText), o | |
}, | |
_dataForComputingMatchFromPageScanAfterElement : function(e, t, o) { | |
var r = [], | |
n = 0, | |
i = this._logicalFormsCache.logicalFormForControl(e); | |
if (!i) | |
return []; | |
var l = i.formElement, | |
a = l && l.isVisible(); | |
let s = void 0 !== t; | |
o || (o = l); | |
for (var u = e.traverseNextNode(); u && n < PageScanCharactersSearchedThreshold; u = u.traverseNextNode()) { | |
var c = u.localName; | |
if (u === o) { | |
var d = this._pageScanContext; | |
d && !n && (d.forwardScanIsFutile = !0); | |
break | |
} | |
if (this._isRenderedFormControl(u)) { | |
if (u.isVisible() || !a) | |
break | |
} else { | |
if (this._isLabelElement(u) && u.isVisible()) | |
break; | |
if ("tr" === c) | |
break; | |
if ("ul" === c || "ol" === c || "dl" === c) | |
break; | |
if (u.nodeType == Node.TEXT_NODE && u.isVisible()) { | |
if (void 0 !== t && (!u.parentNode || u.parentNode.tagName !== t)) | |
continue; | |
if (n += this._collectStringFromNodeForPageScan(u, r, n), s) | |
break | |
} | |
} | |
} | |
return r | |
}, | |
_matchFromPageScanAfterElement : function(e, t, o) { | |
var r = this._pageScanContext ? this._pageScanContext.forwardScanCache : null, | |
n = this._pageScanDataForElementWithCacheAndDataProducer(t, r, this._dataForComputingMatchFromPageScanAfterElement.bind(this), o); | |
return this._matchFromPatternMatcherAndStringsFromPageScan(e, n) | |
}, | |
_pageScanDataForElementWithCacheAndDataProducer : function(e, t, o, r) { | |
if (!t) | |
return o(e, r); | |
if (n = t.get(e)) | |
return n; | |
var n = o(e, r); | |
return t.set(e, n), n | |
}, | |
_matchFromPatternMatcherAndStringsFromPageScan : function(e, t) { | |
for (var o = t.length, r = 0, n = 0; n < o; ++n) { | |
var i = t[n]; | |
r += i.length; | |
var l = e.searchReverse(i); | |
if (l) | |
return | |
{ | |
Distance: r, | |
Match: l[0], | |
Property: l[1], | |
Category: l[2], | |
ParentProperty: l[3] | |
} | |
} | |
return null | |
}, | |
_matchPatternAgainstString : function(e, t) { | |
if (!t) | |
return null; | |
var o = t.replace(/[\d_.-]/g, " "); | |
return o = o.replace(/[a-z][A-Z]/g, (function(e) { | |
return e[0] + " " + e[1] | |
})), | |
e.longestMatch(o) | |
}, | |
_controlsAreAllButtons : function(e) { | |
for (var t = e.length, o = 0; o < t; ++o) { | |
if (!(e[o] instanceof HTMLButtonElement)) | |
return !1 | |
} | |
return !0 | |
}, | |
_createLogicalFormsForControls : function(e, t, o) { | |
if (this._controlsAreAllButtons(e)) | |
return []; | |
let r, n, i = e.map((function(e) { | |
return e.getBoundingClientRect() | |
})), | |
l = e.length, | |
a = 0; | |
i[0].isZeroRect() ? (r = 0, n = null) : (r = 1, n = i[0]); | |
for (let h = 1; h < l; ++h) { | |
let m = i[h]; | |
if (!m.isZeroRect()) { | |
if (n) { | |
let F = n.distanceToRect(m); | |
F && (++r, a += F) | |
} | |
n = m | |
} | |
} | |
if (1 === r) { | |
function s(e) | |
{ | |
return e.closest("header, footer, aside") | |
} | |
let f = [], | |
g = 0; | |
for (; g < l;) { | |
let p = [ e[g] ], | |
C = s(e[g]); | |
for (let _ = g + 1; _ < l; ++_) { | |
let A = e[_]; | |
if (C !== s(e[_])) | |
break; | |
p.push(A) | |
} | |
f.push(new LogicalForm(p, t, o)), g += p.length | |
} | |
return f | |
} | |
let u = r ? a / r : 0, | |
c = [], | |
d = 0; | |
for (; d < l;) { | |
let b = [ e[d] ], | |
y = !1, | |
S = i[d].isZeroRect() ? null : i[d]; | |
for (let T = d + 1; T < l; ++T) { | |
let E = e[T], | |
I = i[T]; | |
if (!I.isZeroRect()) { | |
if (y) { | |
if (S && S.distanceToRect(I) > u) | |
break | |
} else | |
y = couldBeFormSubmissionControl(E); | |
S = I | |
} | |
b.push(E) | |
} | |
c.push(new LogicalForm(b, t, o)), d += b.length | |
} | |
return c | |
}, | |
_formLooksLikeAspnetForm : function(e) { | |
const t = 3; | |
var o = 0; | |
"aspnetForm" === e.getAttribute("id") && ++o, "aspnetForm" === e.getAttribute("name") && ++o; | |
for (var r = queryAllBySelector(e, "input"), n = 0, i = r.length; n < i; ++n) { | |
var l = r[n], | |
a = l.getAttribute("id"), | |
s = l.getAttribute("name"); | |
/ctl\d\d_/.test(a) && ++o, /ctl\d\d\$/.test(s) && ++o, "hidden" === l.getAttribute("type") && ("__VIEWSTATE" === s && "__VIEWSTATE" === a || "__EVENTTARGET" === s && "__EVENTTARGET" === a || "__EVENTARGUMENT" === s && "__EVENTARGUMENT" === a || "__LASTFOCUS" === s && "__LASTFOCUS" === a) && ++o | |
} | |
for (var u = queryAllBySelector(document, "script"), c = u.length, d = 0; d < c; ++d) { | |
var h = anchorWithURLString(u[d].src); | |
if (h.host === window.location.host) { | |
var m = lastPathComponentFromAnchor(h); | |
"WebResource.axd" !== m && "ScriptResource.axd" !== m || ++o | |
} | |
} | |
return o >= t | |
}, | |
_anchorLooksLikeSubmitButton : function(e) { | |
return /submit|button/i.test(e.getAttribute("id")) | |
}, | |
_visibleInputAndSelectElementsInForm : function(e) { | |
let t = queryAllBySelector(e, "input:not([type='hidden']), select"), | |
o = []; | |
for (var r = 0, n = t.length; r < n; ++r) { | |
let e = t[r]; | |
e.isVisible() && o.push(e) | |
} | |
return o | |
}, | |
_elementsActingAsButtonsInForm : function(e) { | |
let t = Array.prototype.slice.call(queryAllBySelector(e, "input[type='submit'], input[type='image']")), | |
o = queryAllBySelector(e, "a"); | |
for (var r = 0, n = o.length; r < n; ++r) { | |
let e = o[r]; | |
this._anchorLooksLikeSubmitButton(e) && e.isVisible() && t.push(e) | |
} | |
return t | |
}, | |
_logicalFormsForAspnetForm : function(e) { | |
function t(e) | |
{ | |
var o = e.length; | |
if (o <= 1) | |
a.push(new LogicalForm(e, ForceNonFormElementAsLogicalBackingElement.Yes)); | |
else { | |
var r = o - 1, | |
n = e[r]; | |
if (e[0].closestCommonAncestor(n) instanceof HTMLTableRowElement) { | |
for (var i = 0; i < r; ++i) { | |
if (!(e[i].closestCommonAncestor(n) instanceof HTMLTableRowElement)) | |
return t(e.slice(0, i)), void t(e.slice(i)) | |
} | |
a.push(new LogicalForm(e, ForceNonFormElementAsLogicalBackingElement.Yes)) | |
} else | |
a.push(new LogicalForm(e, ForceNonFormElementAsLogicalBackingElement.Yes)) | |
} | |
} | |
for (var o = this._visibleInputAndSelectElementsInForm(e), r = o.length, n = this._elementsActingAsButtonsInForm(e), i = n.length, l = 0; l < i; ++l) { | |
(s = n[l]).getAttribute("id") && (s._aspNetIDComponents = s.getAttribute("id").split("_")) | |
} | |
n.sort((function(e, t) { | |
var o = e._aspNetIDComponents || []; | |
return (t._aspNetIDComponents || []).length - o.length | |
})); | |
var a = []; | |
for (l = 0; l < i; ++l) { | |
var s, u = (s = n[l])._aspNetIDComponents; | |
if (u) { | |
var c = u.length; | |
if (!(c < 2)) { | |
for (var d = u.joinFirstItems("_", c - 1) + "_", h = [], m = r - 1; m >= 0; --m) { | |
var F = o[m], | |
f = F.getAttribute("id"); | |
f && (f.startsWith(d) && (h.push(F), o.splice(m, 1))) | |
} | |
if (h.length && t(h.reverse()), !(r = o.length)) | |
break | |
} | |
} | |
} | |
return r && t(o), a | |
}, | |
_logicalFormsInPage : function(e, t) { | |
let o = []; | |
const r = document.querySelector("form form"); | |
let n = {}, | |
i = r ? document.forms : queryAllBySelector(document, "form"), | |
l = 0, | |
a = i.length, | |
s = new Set; | |
for (var u = 0; u < a; ++u) { | |
let a = i[u], | |
c = r ? a.elements : queryAllBySelector(a, "input, select, textarea, button, fieldset"); | |
for (let e of c) | |
s.add(e); | |
if (c.length) { | |
if (l++, e && l >= e) | |
return o; | |
if (t) { | |
let e = [ a.method, a.name, a.action, a.className ].join("|"), | |
o = n[e] || 0; | |
if (o > t) | |
continue; | |
n[e] = o + 1 | |
} | |
this._formLooksLikeAspnetForm(a) ? o = o.concat(this._logicalFormsForAspnetForm(a)) : o.push(new LogicalForm(c)) | |
} | |
} | |
let c = [], | |
d = queryAllBySelector(document, "input, select, textarea, button"), | |
h = d.length; | |
for (let e = 0; e < h; ++e) { | |
let t = d[e]; | |
if (s.has(t)) { | |
if (!c.length) | |
continue; | |
o = o.concat(this._createLogicalFormsForControls(c)), c = [] | |
} else | |
(this._isRenderedFormControl(t) || autocompleteTokens(t)) && c.push(t) | |
} | |
c.length && (o = o.concat(this._createLogicalFormsForControls(c))); | |
let m = o.length; | |
for (u = 0; u < m - 1; ++u) { | |
let e = o[u], | |
t = e.backingElement, | |
r = t.getBoundingClientRect(), | |
n = o[u + 1], | |
i = n.backingElement, | |
l = i.getBoundingClientRect(); | |
const a = 40; | |
if (t.nextElementSibling === i && t.action === i.action && r.height && l.height && r.x === l.x && r.width === l.width && r.bottom + a >= l.top) { | |
let t = 1 === e.elements.filter((function(e) { | |
return e.isVisible() | |
})) | |
.length, | |
r = e.elements.includes((function(e) { | |
return e.matches("input[type=submit], button") && e.isVisible() | |
})); | |
if (t && !r) { | |
let t = e.elements.concat(n.elements), | |
r = this._createLogicalFormsForControls(t, ForceNonFormElementAsLogicalBackingElement.Yes, LogicalFormCreationIsProvisional.Yes); | |
if (1 === r.length) { | |
let e = r[0]; | |
e.markElementsAsPartOfLogicalForm(), o.splice(u, 2, e), m-- | |
} | |
} | |
} | |
} | |
return o | |
}, | |
_matchPatternAgainstElement : function(e, t, o) { | |
function r(e, t) | |
{ | |
if (!e) | |
return null; | |
var r = o[t], | |
n = sharedPrefixLength(r, e[t]); | |
return n ? r.substr(n) : null | |
} | |
function n(e, t) | |
{ | |
if (!t) | |
return null; | |
const o = t.text; | |
if (/^-.+-$/.test(o)) | |
return o; | |
if (!t.value.length && o.length) { | |
const r = e.options, | |
n = r.length; | |
let i = !0; | |
for (let e = 0; e < n; ++e) { | |
const o = r[e]; | |
if (o !== t && !o.value.length) { | |
i = !1; | |
break | |
} | |
} | |
if (i) | |
return o | |
} | |
return null | |
} | |
this._logicalFormsCache.logicalFormForControl(o); | |
var i = o._weakPreviousControlInLogicalForm?.deref(), | |
l = o._weakNextControlInLogicalForm?.deref(); | |
const a = [ "name", "id" ], | |
s = a.length; | |
for (var u = new Array(s), c = new Array(s), d = 0; d < s; ++d) { | |
var h = a[d]; | |
u[d] = r(i, h), c[d] = r(l, h) | |
} | |
const m = t.length; | |
for (var F = 0; F < m; ++F) { | |
var f, g = t[F]; | |
for (d = 0; d < s && !(f = this._matchPatternAgainstString(g, u[d])) && !(f = this._matchPatternAgainstString(g, c[d])) && !(f = this._matchPatternAgainstString(g, o[a[d]])); ++d) | |
; | |
const r = "select" === this._getTagName(o).toLowerCase(); | |
if (!f && r) { | |
const e = r ? defaultOptionForSelectElement(o) : null, | |
t = r ? o.options[0] : null; | |
let i = n(o, e); | |
i || e === t || (i = n(o, t)), f = this._matchPatternAgainstString(g, i) | |
} | |
f && e.push({ | |
FoundByPageScan : !1, | |
Match : f[0].toLowerCase(), | |
Property : f[1], | |
Category : f[2], | |
ParentProperty : f[3], | |
Priority : F | |
}) | |
} | |
}, | |
_labelsForElement : function(e) { | |
if (e._cachedLabels) | |
return e._cachedLabels; | |
e._cachedLabels = []; | |
let t = e.getAttribute("aria-labelledby"); | |
if (t && t.length) { | |
let r = t.split(" "); | |
for (var o = 0; o < r.length; o++) { | |
let t = getElementByID(r[o]); | |
t && e._cachedLabels.push(t) | |
} | |
} | |
if (e._cachedLabels.length) | |
return e._cachedLabels; | |
let r = function(e) { | |
return e.replace(/[^a-zA-Z0-9]+/g, "") | |
}; | |
for (let t of [e.getAttribute("id"), e.getAttribute("name")]) { | |
if (!t || !t.length) | |
continue; | |
let o = [], | |
n = e.form; | |
for (let i of this._labels) { | |
if (n === i.closest("form")) { | |
let n = i.getAttribute("for"); | |
if (n === t) | |
e._cachedLabels.push(i); | |
else if (n) { | |
let e = r(n); | |
e.length > 0 && e === r(t) && o.push(i) | |
} | |
} | |
} | |
if (0 === e._cachedLabels.length && 1 === o.length && (e._cachedLabels = o), e._cachedLabels.length) | |
return e._cachedLabels | |
} | |
let n = this._logicalFormsCache.logicalFormForControl(e)?.formElement; | |
for (let t = e.parentElementIncludingShadowDOMHost(); t && t !== n; t = t.parentElementIncludingShadowDOMHost()) | |
if (this._isLabelElement(t)) { | |
e._cachedLabels.push(t); | |
break | |
} | |
return e._cachedLabels | |
}, | |
_matchesForElement : function(e, t, o = !1) { | |
function r(e, o) | |
{ | |
for (var r = 0; r < l; ++r) { | |
var n = t[r].searchReverse(e); | |
if (n && (i.push({ | |
FoundByPageScan : !1, | |
Match : n[0].toLowerCase(), | |
Property : n[1], | |
Category : n[2], | |
ParentProperty : n[3], | |
Priority : r | |
}), | |
o === ShouldStopAfterFirstMatch.StopAfterFirstMatch)) | |
return | |
} | |
} | |
function n(e, t) | |
{ | |
return e && e.Match.length && (!t || !e.IsInCellAbove && t.IsInCellAbove || e.IsInCellAbove == t.IsInCellAbove && e.Distance < t.Distance) ? { | |
FoundByPageScan : !0, | |
Match : _.Match.toLowerCase(), | |
Property : _.Property, | |
Category : _.Category, | |
ParentProperty : _.ParentProperty, | |
Priority : y | |
} | |
: t | |
} | |
var i = [], | |
l = t.length; | |
this._matchPatternAgainstElement(i, t, e); | |
for (var a = !1, s = this._labelsForElement(e), u = 0; u < s.length; ++u) { | |
var c = s[u].innerText; | |
c && (a = !0, r(c, ShouldStopAfterFirstMatch.StopAfterFirstMatch)) | |
} | |
let d = placeholderInfoForElement(e); | |
d && !d.AttributeMatchedWasValue && r(d.Text, ShouldStopAfterFirstMatch.StopAfterFirstMatch); | |
var h = e.getAttribute("title"); | |
h && r(h, ShouldStopAfterFirstMatch.StopAfterFirstMatch); | |
var m = this._labelForElementIfElementAndLabelAreOnlyElementsOfTheirKindAmongSiblingElements(e); | |
m?.innerText.length && (a = !0, r(m.innerText, ShouldStopAfterFirstMatch.CollectAllMatches)); | |
let F = this._ariaLabelForElementOrParentOfElement(e); | |
F && r(F, ShouldStopAfterFirstMatch.StopAfterFirstMatch); | |
var f = e.getAttribute("formcontrolname"); | |
f && f.length && r(f, ShouldStopAfterFirstMatch.StopAfterFirstMatch); | |
var g = this._pageScanContext, | |
p = !0, | |
C = !1; | |
if (g && (g.shouldUsePageScan && (p = g.shouldUsePageScan()), g.reportPageScanUsedSuccessfully && (C = !0)), !p) | |
return i; | |
if (a) | |
return C && g.reportPageScanUsedSuccessfully(!1), i; | |
if (!0 === o) | |
return i; | |
for (var _, A = null, b = null, y = 0; y < l; ++y) | |
A = n(_ = this._matchFromPageScanBeforeElement(t[y], e), A), g && g.forwardScanIsFutile || (b = n(_ = this._matchFromPageScanAfterElement(t[y], e), b)); | |
var S = !1; | |
if (A && (i.push(A), S = !0), b) | |
for (var T = 0, E = i.length; T < E; ++T) { | |
var I = i[T]; | |
if (b.Priority === I.Priority) { | |
i.push(b), S = !0; | |
break | |
} | |
} | |
return C && g.reportPageScanUsedSuccessfully(S), i.length && d && d.AttributeMatchedWasValue && r(d.Text, ShouldStopAfterFirstMatch.StopAfterFirstMatch), i | |
}, | |
_bestMatchFromMatches : function(e) { | |
function t(e, t) | |
{ | |
for (var o = e.length, r = {}, n = 0; n < o; ++n) { | |
var i, l = e[n]; | |
switch (t) { | |
case MatchCriteria.Property: | |
i = l.Property || l.Match; | |
break; | |
case MatchCriteria.Category: | |
i = l.Category || l.Match; | |
break; | |
case MatchCriteria.Literal: | |
i = l.Match | |
} | |
r[i] ? r[i].Frequency += 1 : r[i] = { | |
Frequency : 1, | |
FirstMatchObject : l | |
} | |
} | |
var a = []; | |
for (var s in r) | |
a.push(r[s]); | |
var u = a.sort((function(e, t) { | |
return t.Frequency - e.Frequency | |
})), | |
c = u.length; | |
if (c <= 1) | |
return null; | |
if (t === MatchCriteria.Property) | |
for (n = 0; n < c; ++n) { | |
if (u[n].FirstMatchObject.ParentProperty in r) | |
return u[n].FirstMatchObject | |
} | |
return u[0].Frequency > u[1].Frequency ? u[0].FirstMatchObject : void 0 | |
} | |
var o = e.length; | |
if (0 === o) | |
return null; | |
if (1 === o) | |
return e[0]; | |
var r = t(e, MatchCriteria.Property); | |
return r || ((r = t(e, MatchCriteria.Category)) ? r : e.sort((function(e, t) { | |
return e.Priority - t.Priority | |
}))[0]) | |
}, | |
_bestMatchForElement : function(e, t, o = !1) { | |
if (!e) | |
return null; | |
var r = this._matchesForElement(e, t, o); | |
return this._bestMatchFromMatches(r, e, t) | |
}, | |
_labelForElementIfElementAndLabelAreOnlyElementsOfTheirKindAmongSiblingElements : function(e) { | |
for (var t = null, o = e.tagName, r = siblingsIncludingSelfForElement(e), n = r.length, i = 0; i < n; ++i) { | |
var l = r[i]; | |
if (e !== l) { | |
if (o === l.tagName) | |
return null; | |
if (this._isLabelElement(l)) { | |
if (t) | |
return null; | |
t = l | |
} | |
} | |
} | |
return t | |
}, | |
_ariaLabelForElementOrParentOfElement : function(e) { | |
var t = e; | |
let o = 3; | |
for (var r = 0; r < o && t; ++r) { | |
let e = t.getAttribute("aria-label"); | |
if (e && !t.isHiddenFromAccessibilityTree()) | |
return e; | |
t = t.parentElementIncludingShadowDOMHost() | |
} | |
return null | |
}, | |
_cachedOneTimeCodePatternMatcher : function() { | |
return this._cachedPatternMatchers("oneTimeCodeFieldLabelPatternMatchers")[0] | |
}, | |
_cachedPatternMatchers : function(e) { | |
let t = "_" + e, | |
o = this[t]; | |
return o || (this[t] = FormMetadataJSController[e], o = this[t]), o | |
}, | |
_cachedElementPatternMatch : function(e, t, o) { | |
var r = t + "_wasVisible", | |
n = e[r]; | |
if (!0 === n) | |
return e[t]; | |
var i = e.isVisible(); | |
if (n === i) | |
return e[t]; | |
e[r] = i; | |
let l = this._cachedPatternMatchers(o); | |
return e[t] = this._bestMatchForElement(e, l), e[t] | |
}, | |
_isLabeledUsernameField : function(e) { | |
return !!this._isAutoFillableTextField(e) && null !== this._cachedElementPatternMatch(e, "_usernameFieldPatternMatch", "usernameFieldLabelPatternMatchers") | |
}, | |
_isLabeledLoginField : function(e) { | |
return !!this._isAutoFillableTextField(e) && null !== this._cachedElementPatternMatch(e, "_loginFieldPatternMatch", "loginFormTypePatternMatchers") | |
}, | |
_isLabeledSignUpField : function(e) { | |
return !!this._isAutoFillableTextField(e) && null !== this._cachedElementPatternMatch(e, "_signUpFieldPatternMatch", "newAccountFormTypePatternMatchers") | |
}, | |
_isLabeledEmailField : function(e) { | |
return !!this._isAutoFillableTextField(e) && ("email" === e.type || null !== this._cachedElementPatternMatch(e, "_emailFieldPatternMatch", "emailFieldLabelPatternMatchers")) | |
}, | |
_addressBookLabelForElement : function(e) { | |
if (!this._isAutoFillableTextField(e) && !this._isAutoFillableSelectElement(e) && !this._isAutoFillableTextAreaElement(e)) | |
return null; | |
var t = this._cachedElementPatternMatch(e, "_addressBookPatternMatch", "addressBookFieldLabelPatternMatchers"); | |
return t ? t.Match : null | |
}, | |
_elementDisallowsAutocomplete : function(e) { | |
var t = e.getAttribute("autocomplete"); | |
return t && "off" === t.toLowerCase() | |
}, | |
_isTextArea : function(e) { | |
return e instanceof HTMLTextAreaElement | |
}, | |
_isSelectElement : function(e) { | |
return e instanceof HTMLSelectElement | |
}, | |
_isLabelElement : function(e) { | |
return e instanceof HTMLLabelElement | |
}, | |
_isRenderedFormControl : function(e) { | |
var t = e.localName; | |
if (!t) | |
return !1; | |
return t in { | |
button : !0, | |
isindex : !0, | |
fieldset : !0, | |
legend : !0, | |
meter : !0, | |
optgroup : !0, | |
option : !0, | |
progress : !0, | |
select : !0, | |
textarea : !0 | |
} | |
|| e instanceof HTMLInputElement && (!!this._isElementAHiddenUsername(e) || (!e.type || "hidden" !== e.type)) | |
}, | |
_isEditablePlainTextField : function(e) { | |
return !!isInputElement(e) && (!e.disabled && !e.readOnly && (!e.type || "text" === e.type)) | |
}, | |
_isTextField : function(e) { | |
if (this._isTextArea(e)) | |
return !0; | |
if (!isInputElement(e)) | |
return !1; | |
const t = { | |
date : !0, | |
"datetime-local" : !0, | |
email : !0, | |
isindex : !0, | |
month : !0, | |
number : !0, | |
password : !0, | |
search : !0, | |
tel : !0, | |
telephone : !0, | |
text : !0, | |
time : !0, | |
url : !0, | |
week : !0 | |
}; | |
var o = e.type; | |
return !o || o in t | |
}, | |
_isAutofocusedTextField : function(e) { | |
return !!this._isTextField(e) && !0 === e.autofocus | |
}, | |
_isAutoFilledTextField : function(e) { | |
return !!this._isTextField(e) && e.matches(":-webkit-autofill") | |
}, | |
_isSecureTextField : function(e) { | |
if (!isInputElement(e)) | |
return !1; | |
if (e._wasPreviouslySecureTextField) | |
return !0; | |
try { | |
if (e.matches(":-webkit-autofill-strong-password")) | |
return e._wasPreviouslySecureTextField = !0, !0 | |
} catch (e) { | |
} | |
const t = getComputedStyle(e, null).getPropertyValue("-webkit-text-security"), | |
o = e.type; | |
if ("none" !== t || "password" === o) | |
return e._wasPreviouslySecureTextField = !0, !0; | |
if (o && "text" !== o) | |
return !1; | |
const r = e._weakNextControlInLogicalForm?.deref(); | |
return !(!r || !this._looksLikeShowHidePasswordButton(r)) && (!!this._matchesPasswordFieldLabelPattern(e) && (e._wasPreviouslySecureTextField = !0, !0)) | |
}, | |
_isVerticalWritingMode : function(e) { | |
const t = getComputedStyle(e).writingMode; | |
return !("horizontal-tb" === t || "horizontal-bt" === t) | |
}, | |
_looksLikePasswordCredentialField : function(e) { | |
if (!this._isSecureTextField(e)) | |
return !1; | |
var t = e.getAttribute("maxlength"); | |
return !(t && parseInt(t) < MinValueForMaxLengthAttributeToTreatAsPasswordField) && null === this._cachedElementPatternMatch(e, "_nonAccountPasswordSecureTextEntryFieldPatternMatch", "nonAccountPasswordSecureTextEntryFieldLabelPatternMatchers") | |
}, | |
_looksLikeShowHidePasswordButton : function(e) { | |
return !(!this._isCustomFormButton(e) && !this._isCheckboxInputElement(e)) && !!this._cachedElementPatternMatch(e, "_showHideButtonPatternMatch", "showHideButtonLabelPatternMatchers") | |
}, | |
_isAutoFillable : function(e) { | |
return !e.disabled && !e.readOnly | |
}, | |
_isAutoFillableSelectElement : function(e) { | |
return this._isAutoFillable(e) && this._isSelectElement(e) | |
}, | |
_isAutoFillableTextAreaElement : function(e) { | |
return this._isAutoFillable(e) && this._isTextArea(e) | |
}, | |
_isAutoFillableTextField : function(e) { | |
return this._isAutoFillable(e) && this._isTextField(e) | |
}, | |
_looksLikeCreditCardNumberField : function(e, t) { | |
if (!this._isAutoFillableTextField(e)) | |
return !1; | |
if (this._cachedElementPatternMatch(e, "_nonCreditCardNumberPatternMatch", "nonCreditCardCardNumberFieldLabelPatternMatchers")) | |
return !1; | |
if (this._matchesCreditCardCompositeExpirationDateFieldLabelPatternMatchers(e)) | |
return !1; | |
if (elementIDOrAutocompleteTokensHasToken(e, t, "cc-number")) | |
return !0; | |
const o = e.placeholder; | |
let r = new RegExp("[0-9]{4}[ -][0-9]{4}[ -][0-9]{4}[ -][0-9]{4}"); | |
if (o && r.test(o)) | |
return !0; | |
let n = e.getAttribute("data-val-regex-pattern"); | |
if (n) { | |
let e = regularExpressionFromUntrustedPatternAttributeString(n); | |
if (e && !e.test("12345")) | |
return !1 | |
} | |
return null !== this._cachedElementPatternMatch(e, "_creditCardNumberPatternMatch", "creditCardNumberFieldLabelPatternMatchers") | |
}, | |
_looksLikeCreditCardSecurityCodeField : function(e, t) { | |
if (!this._isAutoFillableTextField(e)) | |
return !1; | |
if (elementIDOrAutocompleteTokensHasToken(e, t, "cc-csc")) | |
return !0; | |
let o = e.getAttribute("pattern"); | |
if (o) { | |
let e = regularExpressionFromUntrustedPatternAttributeString(o); | |
if (e && !e.test("123") && !e.test("1234")) | |
return !1 | |
} | |
return null !== this._cachedElementPatternMatch(e, "_creditCardSecurityCodePatternMatch", "creditCardSecurityCodeFieldLabelPatternMatchers") | |
}, | |
_looksLikeCreditCardCardholderField : function(e, t) { | |
return !!this._isEditablePlainTextField(e) && (!!elementIDOrAutocompleteTokensHasToken(e, t, "cc-name") || null !== this._cachedElementPatternMatch(e, "_creditCardCardholderPatternMatch", "creditCardCardholderFieldLabelPatternMatchers")) | |
}, | |
_looksLikeCreditCardCompositeExpirationDateField : function(e, t) { | |
return !(!this._isAutoFillableTextField(e) || this._isSecureTextField(e)) && (!!elementIDOrAutocompleteTokensHasToken(e, t, "cc-exp") || this._matchesCreditCardCompositeExpirationDateFieldLabelPatternMatchers(e)) | |
}, | |
_matchesCreditCardCompositeExpirationDateFieldLabelPatternMatchers : function(e) { | |
return null !== this._cachedElementPatternMatch(e, "_creditCardCompositeExpirationDateFieldPatternMatch", "creditCardCompositeExpirationDateFieldLabelPatternMatchers") | |
}, | |
_looksLikeCreditCardTypeField : function(e, t) { | |
return !(!this._isSelectElement(e) && !isRadioButtonElement(e)) && (!!elementIDOrAutocompleteTokensHasToken(e, t, "cc-type") || null !== this._cachedElementPatternMatch(e, "_creditCardTypePatternMatch", "creditCardTypeFieldLabelPatternMatchers")) | |
}, | |
_looksLikeEIDField : function(e, t) { | |
return !!elementIDOrAutocompleteTokensHasToken(e, t, "device-eid") | |
}, | |
_looksLikeIMEIField : function(e, t) { | |
return !!elementIDOrAutocompleteTokensHasToken(e, t, "device-imei") | |
}, | |
_looksLikeDayField : function(e) { | |
return !(!this._isAutoFillableTextField(e) && !this._isAutoFillableSelectElement(e)) && null !== this._cachedElementPatternMatch(e, "_dayFieldPatternMatch", "dayFieldLabelPatternMatchers") | |
}, | |
_looksLikeMonthField : function(e, t) { | |
if (!this._isAutoFillableTextField(e) && !this._isAutoFillableSelectElement(e)) | |
return !1; | |
if (elementIDOrAutocompleteTokensHasToken(e, t, "cc-exp-month")) | |
return !0; | |
if (null !== this._cachedElementPatternMatch(e, "_monthFieldPatternMatch", "monthFieldLabelPatternMatchers")) | |
return !0; | |
if ("select" !== this._getTagName(e).toLowerCase()) | |
return !1; | |
var o = e.options.length; | |
if (12 === o || 13 === o) | |
for (var r = [ selectElementOptionsSequenceAnalysis(e, "text"), selectElementOptionsSequenceAnalysis(e, "value") ], n = r.length, i = 0; i < n; i++) { | |
var l = r[i], | |
a = l.lengthOfLongestSequence, | |
s = l.lastNumberInSequence; | |
if (a >= 11 && 12 === s) | |
return !0 | |
} | |
return !1 | |
}, | |
_looksLikeYearField : function(e, t) { | |
if (!this._isAutoFillableTextField(e) && !this._isAutoFillableSelectElement(e)) | |
return !1; | |
if (elementIDOrAutocompleteTokensHasToken(e, t, "cc-exp-year")) | |
return !0; | |
if (null !== this._cachedElementPatternMatch(e, "_yearFieldPatternMatch", "yearFieldLabelPatternMatchers")) | |
return !0; | |
if ("select" !== this._getTagName(e).toLowerCase()) | |
return !1; | |
var o = selectElementOptionsSequenceAnalysis(e, "text"), | |
r = o.lengthOfLongestSequence, | |
n = o.lastNumberInSequence; | |
const i = 3; | |
return r >= e.options.length - i && 1e3 < n && n < 3e3 | |
}, | |
_looksLikeOneTimeCodeField : function(e, t, o, r, n, i) { | |
if (!this._isAutoFillableTextField(e) && !this._isAutoFillableSelectElement(e)) | |
return !1; | |
if (elementIDOrAutocompleteTokensHasToken(e, t, "one-time-code")) | |
return !0; | |
const l = e.type; | |
if ("password" === l) { | |
if (/^(.+\.)?chase\.com\.?$/.test(document.location.hostname)) | |
return !1; | |
if (this._matchesPasswordFieldLabelPattern(e)) | |
return !1 | |
} | |
if (/^(.+\.)?amazon\.(com|ae|com\.au|com\.br|ca|fr|de|in|it|com\.mx|nl|es|com\.tr|co\.uk|sa|sg|se|pl)\.?$/.test(document.location.hostname)) { | |
const t = /claim|promo/i; | |
if (t.test(e.id) || t.test(e.name)) | |
return !1 | |
} | |
if (null !== this._cachedElementPatternMatch(e, "_oneTimeCodePatternMatch", "oneTimeCodeFieldLabelPatternMatchers")) | |
return !0; | |
var a = e.getAttribute("maxlength"); | |
if (a && parseInt(a) > MaxLengthForFieldAboveWhichToTreatPotentialOneTimeCodeFieldAsRequiringHigherScrutiny) { | |
if (!n) | |
return !1; | |
if (i.ControlLooksLikeIgnoredDataTypeField || i.ControlLooksLikeCreditCardCardholderField || i.ControlLooksLikeCreditCardNumberField || i.ControlLooksLikeCreditCardSecurityCodeField || i.ControlLooksLikeCreditCardTypeField || i.AddressBookLabel) | |
return !1 | |
} | |
let s = e.pattern; | |
if (s) { | |
let e = regularExpressionFromUntrustedPatternAttributeString(s); | |
if (e && (e.test("1234") || e.test("123456") || e.test("12345678")) && !e.test("a") && !e.test("A")) | |
return !0 | |
} | |
const u = "number" === l || "tel" === l, | |
c = a ? parseInt(a) : void 0; | |
if (1 === c) { | |
if (u || o || r) | |
return !0; | |
const t = this._cachedOneTimeCodePatternMatcher(), | |
n = e.closest("fieldset"), | |
i = n?.querySelector("legend"), | |
l = n ? Array.from(n.querySelectorAll("input")) : [], | |
a = e === l[0]; | |
if (i && a && this._matchPatternAgainstString(t, i.innerText)) | |
return !0; | |
const s = l.length; | |
if ((6 === s || 8 === s) && a && l.every((e => 1 === parseInt(e.maxLength)))) | |
return !0 | |
} | |
const d = null !== this._cachedElementPatternMatch(e, "_weakOneTimeCodePatternMatch", "weakOneTimeCodeFieldLabelPatternMatchers"); | |
if (u && d) | |
return !0; | |
const h = e.placeholder; | |
if (h && d && /^[#]+$/.test(h.replace(/ /g, ""))) | |
return !0; | |
if ((4 === c || 6 === c) && d) | |
return !0; | |
if (7 === c && h && /\d{3} \d{3}/.test(h)) | |
return !0; | |
if (this._isAutofocusedTextField(e)) { | |
if (d) | |
return !0; | |
if ("0" === e.min && "9" === e.max) | |
return !0 | |
} | |
if (n) { | |
let t = 0; | |
d && t++, o && t++, r && t++; | |
const n = this._cachedOneTimeCodePatternMatcher(), | |
i = this._logicalFormsCache.logicalFormForControl(e); | |
if (i) { | |
const e = i.backingElement; | |
if (e) { | |
const o = e.querySelector("h1, h2, h3"); | |
if (o && this._matchPatternAgainstString(n, o.innerText)) | |
t++; | |
else { | |
const o = e.closest("section")?.querySelector("h1, h2, h3"); | |
o && this._matchPatternAgainstString(n, o.innerText) && t++ | |
} | |
} | |
} | |
const l = e.dataset.valRequired; | |
if ("string" == typeof l && this._matchPatternAgainstString(n, l) && t++, t >= 2) | |
return !0; | |
const a = function(e) { | |
if (this._matchPatternAgainstString(n, e)) | |
return !0; | |
const t = e.replaceAll("-", " "); | |
return e !== t && this._matchPatternAgainstString(n, t) | |
}.bind(this), s = window.location.protocol, u = "http:" === s || "https:" === s, c = lastPathComponentFromAnchor(window.location); | |
if (u && c && a(c)) | |
return !0; | |
{ | |
const e = document.querySelector("link[rel=canonical]"), | |
t = e ? lastPathComponentForURLString(e.href) : null; | |
if (t && a(t)) | |
return !0 | |
} | |
if (this._matchFromPageScanBeforeElement(n, e, document.body)) | |
return !0 | |
} | |
return !1 | |
}, | |
_looksLikeIgnoredDataTypeField : function(e, t) { | |
return !!this._isAutoFillableTextField(e) && (!t?.length && null !== this._cachedElementPatternMatch(e, "_ignoredDataTypePatternMatch", "ignoredDataTypeFieldLabelPatternMatchers")) | |
}, | |
_collectTextSample : function(e) { | |
if (!e) | |
return ""; | |
var t, o = "", | |
r = e; | |
do { | |
t = (o = r.innerText.replace(/\s+/g, " ").trim()).length, r = r.parentElementIncludingShadowDOMHost() | |
} while (t < MaximumNumberOfCharactersToCollectForLanguageIdentification && r); | |
return t > MaximumNumberOfCharactersToCollectForLanguageIdentification && (o = o.substr(0, MaximumNumberOfCharactersToCollectForLanguageIdentification)), o | |
}, | |
_explicitMaxLength : function(e) { | |
var t = e.getAttribute("maxlength"); | |
return t ? parseInt(t) : void 0 | |
}, | |
_explicitMinLength : function(e) { | |
let t = e.getAttribute("minlength"); | |
return t ? parseInt(t) : void 0 | |
}, | |
_observedMaxLength : function(e) { | |
const t = 20; | |
if ("password" !== e.type) | |
return null; | |
const o = e.getAttribute("ng-pattern"); | |
if (!o) | |
return null; | |
if (!o.startsWith("/") || !o.endsWith("/")) | |
return null; | |
let r = regularExpressionFromUntrustedPatternAttributeString(o); | |
if (!r) | |
return null; | |
let n, i = "a1Abbb", | |
l = !1; | |
for (; i.length <= t;) { | |
let e = r.test(i); | |
if (l && !e) | |
return n; | |
e && (l = !0, n = i.length), i += "b" | |
} | |
return null | |
}, | |
_collectControlMetadata : function(e, t, o, r, n, i, l) { | |
var a = { | |
ControlTagName : this._getTagName(e), | |
ControlFieldName : this._getNameOrId(e), | |
ControlUniqueID : this.controlUniqueID(e) | |
}; | |
e === innermostActiveElement() && (a.ControlIsActiveElement = !0), this._isAutoFilledTextField(e) && (a.ControlIsAutoFilledTextField = !0), e.disabled && (a.ControlIsDisabled = !0), e.readOnly && (a.ControlIsReadOnly = !0), this._isTextField(e) && (a.ControlIsTextField = !0), this._isSecureTextField(e) && (a.ControlIsSecureTextField = !0), this._isLabeledUsernameField(e) && (a.ControlIsLabeledUsernameField = !0), this._elementDisallowsAutocomplete(e) && (a.DisallowsAutocomplete = !0), this._isAutofocusedTextField(e) && (a.ControlIsAutofocusedTextField = !0); | |
const s = e.className; | |
s && s.length && (a.ControlFieldClass = s); | |
const u = e.id; | |
u && u.length && (a.ControlFieldID = u); | |
const c = e.value; | |
c && (a.ControlValue = c); | |
const d = this._associatedUsernameForControl(e); | |
d && (a.ControlAssociatedUsername = d); | |
const h = e.maxLength; | |
if (-1 !== h) | |
a.ControlMaxLength = h; | |
else { | |
const t = this._observedMaxLength(e); | |
t && (a.ControlMaxLength = t) | |
} | |
const m = this._explicitMinLength(e); | |
m && m > 0 && (a.ControlMinLength = m); | |
const F = e.size; | |
F > 0 && (a.ControlSize = F), e.isVisible() && (a.IsVisible = !0), isDateTimeInputElement(e) && (a.ControlRequiredFormatForDateTimeInput = this._requiredFormatForDateTimeInput[e.type]); | |
var f = autocompleteTokens(e); | |
f && (a.AutocompleteTokens = f, -1 !== f.indexOf("username") ? a.ControlClaimsToBeUsernameViaAutocompleteAttribute = !0 : -1 !== f.indexOf("current-password") ? a.ControlClaimsToBeCurrentPasswordViaAutocompleteAttribute = !0 | |
: -1 !== f.indexOf("new-password") && (a.ControlClaimsToBeNewPasswordViaAutocompleteAttribute = !0)), | |
this._looksLikePasswordCredentialField(e) && (a.ControlLooksLikePasswordCredentialField = !0, "function" == typeof this._collectExtraControlMetadata && this._collectExtraControlMetadata(e, a), a.IsVisible && !o && (a.IsVisible = !isElementPositionedToBeEffectivelyInvisible(e))); | |
let g = t === WBSFormMetadataRequestPreFill, | |
p = a.ControlIsActiveElement || !g; | |
if (p) { | |
const t = this._collectSelectElementInfo(e); | |
t && (a.SelectElementInfo = t), this._isVerticalWritingMode(e) && (a.ControlIsVerticalWritingMode = !0); | |
var C = placeholderInfoForElement(e); | |
C && !C.AttributeMatchedWasValue && (a.ControlPlaceholder = C.Text) | |
} | |
if (this._looksLikeIgnoredDataTypeField(e, f) ? a.ControlLooksLikeIgnoredDataTypeField = !0 : this._looksLikeCreditCardCardholderField(e, f) ? a.ControlLooksLikeCreditCardCardholderField = !0 | |
: this._looksLikeCreditCardNumberField(e, f) ? a.ControlLooksLikeCreditCardNumberField = !0 | |
: this._looksLikeCreditCardSecurityCodeField(e, f) ? a.ControlLooksLikeCreditCardSecurityCodeField = !0 | |
: this._looksLikeCreditCardTypeField(e, f) && (a.ControlLooksLikeCreditCardTypeField = !0), | |
p && (this._looksLikeMonthField(e, f) ? a.ControlLooksLikeMonthField = !0 : this._looksLikeYearField(e, f) ? a.ControlLooksLikeYearField = !0 | |
: this._looksLikeDayField(e) ? a.ControlLooksLikeDayField = !0 | |
: !a.ControlLooksLikeCreditCardSecurityCodeField && this._looksLikeCreditCardCompositeExpirationDateField(e, f) && (a.ControlLooksLikeCreditCardCompositeExpirationDateField = !0)), | |
g || (this._looksLikeEIDField(e, f) ? a.ControlLooksLikeEIDField = !0 : this._looksLikeIMEIField(e, f) && (a.ControlLooksLikeIMEIField = !0)), g || a.ControlLooksLikeIgnoredDataTypeField || a.ControlIsSecureTextField || a.ControlLooksLikeCreditCardNumberField || a.ControlLooksLikeCreditCardSecurityCodeField || a.ControlLooksLikeCreditCardTypeField || a.ControlLooksLikeCreditCardCompositeExpirationDateField || a.ControlLooksLikeEIDField || a.ControlLooksLikeIMEIField || (a.AddressBookLabel = this._addressBookLabelForElement(e)), a.ControlIsActiveElement || t === WBSFormMetadataRequestTesting || l) { | |
let t = i && a.IsVisible; | |
this._looksLikeOneTimeCodeField(e, f, r, n, t, a) && (a.ControlLooksLikeOneTimeCodeField = !0) | |
} | |
return a | |
}, | |
_usesGeneratedPassword : function(e) { | |
for (var t = !1, o = this._elementsWithGeneratedPasswords.length, r = 0; r < o; ++r) { | |
var n = this._elementsWithGeneratedPasswords[r]; | |
if (e.containsControl(n)) { | |
if (n.value !== this._generatedPasswords[r]) | |
return !1; | |
t = !0 | |
} | |
} | |
return t | |
}, | |
_associatedUsernameForControl : function(e) { | |
return this._isAutoFillableTextField(e) ? e.getAttribute("data-username") : null | |
}, | |
_collectSelectElementInfo : function(e) { | |
if (!this._isAutoFillableSelectElement(e)) | |
return null; | |
if (!e.options.length) | |
return null; | |
for (var t = [], o = e.options, r = o.length, n = 0; n < r; ++n) { | |
var i = o[n]; | |
i.disabled || (i.label || i.text) && t.push([ n, i.label ? i.label : i.text ]) | |
} | |
return t.length ? t : null | |
}, | |
_stringsToInspectForDeterminingFormType : function(e) { | |
let t = [], | |
o = e.formElement, | |
r = o.getAttribute("id"), | |
n = o.getAttribute("name"); | |
r && t.push(r), n && t.push(n); | |
let i = queryAllBySelector(o, "legend"); | |
1 === i.length && t.push(i[0].innerText); | |
let l = 0; | |
for (let e of this._logicalFormsCache.allForms()) | |
e.formElement.isVisible() && l++; | |
const a = .8; | |
if (1 === l && o.isVisible() && !o.ownerDocument.defaultView.frameElement && o.getBoundingClientRect().top < a * document.documentElement.clientHeight) { | |
let e = documentTitleWithoutHostNamePrefix(); | |
e && t.push(e); | |
const o = lastPathComponentFromAnchor(window.location); | |
o && o.length && t.push(o) | |
} | |
let s = []; | |
if (o.isVisible()) { | |
const e = function(e, t) { | |
return t.left <= e.left && e.right <= t.right && e.distanceToRect(t) < 100 || e.left - t.left == t.right - e.right && e.distanceToRect(t) < 200 | |
}; | |
let r = o.getBoundingClientRect(), | |
n = !1; | |
for (let i = 0, l = o; i <= 2 && l; ++i, l = l.parentElementIncludingShadowDOMHost()) { | |
let o = Array.prototype.slice.call(queryAllBySelector(l, "h1, h2, h3, [class*='header' i], [class*='heading' i]")), | |
i = [ | |
[], | |
[], | |
[], | |
[] | |
]; | |
for (headerElement of o) { | |
let e = headerElement.tagName; | |
"H1" === e ? i[0].push(headerElement) : "H2" === e ? i[1].push(headerElement) | |
: "H3" === e ? i[2].push(headerElement) | |
: i[3].push(headerElement) | |
} | |
let a = !0; | |
for (headerElementsOfType of i) { | |
let o = headerElementsOfType.length; | |
if (0 === o) { | |
a = !1; | |
continue | |
} | |
if (o > 1) | |
break; | |
let i = headerElementsOfType[0]; | |
if (!i.isVisible()) | |
break; | |
e(i.getBoundingClientRect(), r) && (t.push(i.innerText), n = !0); | |
break | |
} | |
if (a) | |
break | |
} | |
if (!n) { | |
let o = queryAllBySelector(document.documentElement, "h1"); | |
if (1 === o.length) { | |
let n = o[0]; | |
e(n.getBoundingClientRect(), r) && t.push(n.innerText) | |
} | |
} | |
for (let e = 0, t = o; e <= 2 && t; ++e, t = t.parentElementIncludingShadowDOMHost()) { | |
let e = Array.prototype.slice.call(queryAllBySelector(t, "button, input[type=submit]")).filter((function(e) { | |
if (!e.isVisible()) | |
return !1; | |
let t = e.getBoundingClientRect(); | |
return t.top > r.bottom && !o.contains(e) && r.left <= t.left && t.right <= r.right && t.distanceToRect(r) < 100 | |
})); | |
if (e.length) { | |
s = e; | |
break | |
} | |
} | |
} | |
let u = !1, | |
c = [], | |
d = e.elements.concat(s); | |
for (const e of d) { | |
const o = e.type; | |
"password" === o && (u = !0), "submit" !== o && "button" !== o || u && (e.isVisible() ? this._addInterestingStringsForButton(e, t) : c.push(e)) | |
} | |
if (0 === t.length) | |
for (control of c) | |
this._addInterestingStringsForButton(control, t); | |
return t | |
}, | |
_addInterestingStringsForButton : function(e, t) { | |
const o = e.getAttribute("id"); | |
o && t.push(o); | |
const r = e.getAttribute("value"); | |
r && t.push(r); | |
const n = e.innerText; | |
n && n.length > 0 && t.push(n) | |
}, | |
_autoFillFormTypeOfTypesUsingKeywordMatching : function(e, t, o, r) { | |
for (var n = t.length, i = [], l = 0; l < n; ++l) { | |
var a = (0, mapOfFormTypeToProducerOfAssociatedKeywords[t[l]])(); | |
i.push(a) | |
} | |
var s = this._stringsToInspectForDeterminingFormType(e), | |
u = this._keywordsIndicatingNonAutoFillableFormType; | |
u || (u = FormMetadataJSController.keywordsIndicatingNonAutoFillableFormType, this._keywordsIndicatingNonAutoFillableFormType = u); | |
var c = u.length, | |
d = []; | |
for (l = 0; l < n; ++l) | |
d.push(0); | |
if (r) | |
for (const [e, o] of Object.entries(r)) | |
d[t.indexOf(parseInt(e))] += o; | |
for (var h = s.length, m = 0; m < h; ++m) { | |
for (var F = s[m].toLowerCase(), f = 0; f < c; ++f) | |
if (-1 !== F.indexOf(u[f])) | |
return WBSAutoFillFormTypeNonAutoFillable; | |
for (l = 0; l < n; ++l) { | |
a = i[l]; | |
for (var g in a) | |
-1 !== F.indexOf(g) && (d[l] += a[g]) | |
} | |
} | |
for (let o = 0; o < n; ++o) { | |
const r = this._mapOfFormTypeToExtraScoreProducer[t[o]]; | |
d[o] += r(e) | |
} | |
for (l = 0; l < n; ++l) | |
0 !== d[l] && 0; | |
var p = formActionAsAnchorElement(e.formElement, !0); | |
if (p) { | |
var C = p.pathname.toLowerCase() + p.search.toLowerCase(); | |
for (l = 0; l < n; ++l) { | |
a = i[l]; | |
for (var g in a) | |
-1 !== C.indexOf(g) && (d[l] += a[g]) | |
} | |
} | |
var _ = [], | |
A = 0; | |
for (l = 0; l < n; ++l) { | |
var b = d[l]; | |
b > 0 && (b >= A ? (A = b, _.unshift(l)) : _.push(l)) | |
} | |
if (1 === _.length) | |
return t[_[0]]; | |
if (_.length > 1) { | |
var y = _[0]; | |
if (d[y] > d[_[1]]) | |
return t[y] | |
} | |
return o | |
}, | |
_matchesNonUsernameFieldLabelPattern : function(e) { | |
if (this._nonUsernameFieldPatternMatchers || (this._nonUsernameFieldPatternMatchers = FormMetadataJSController.nonUsernameFieldLabelPatternMatchers), this._bestMatchForElement(e, this._nonUsernameFieldPatternMatchers)) | |
return !0; | |
const t = e.value; | |
if (!e.id && !e.name && t && e.disabled) | |
for (const e of this._nonUsernameFieldPatternMatchers) | |
if (this._matchPatternAgainstString(e, t)) | |
return !0; | |
return !1 | |
}, | |
_matchSearchFieldLabelPattern : function(e) { | |
if (this._searchFieldLabelPatternMatchers || (this._searchFieldLabelPatternMatchers = FormMetadataJSController.searchFieldLabelPatternMatchers), this._bestMatchForElement(e, this._searchFieldLabelPatternMatchers, !0)) | |
return !0; | |
const t = e.value; | |
if (!e.id && !e.name && t && e.disabled) | |
for (const e of this._searchFieldLabelPatternMatchers) | |
if (this._matchPatternAgainstString(e, t)) | |
return !0; | |
return !1 | |
}, | |
_matchesNonEmailFieldLabelPattern : function(e) { | |
return this._nonEmailFieldPatternMatchers || (this._nonEmailFieldPatternMatchers = FormMetadataJSController.nonEmailFieldLabelPatternMatchers), !!this._bestMatchForElement(e, this._nonEmailFieldPatternMatchers) | |
}, | |
_scoreForUsernameFieldCandidateFromLabelingAndPositionOfField : function(e, t, o) { | |
return this._isLabeledUsernameField(e) ? t ? UsernameCandidateScoreForUsernameLabeledFieldBelowPasswordField : UsernameCandidateScoreForUsernameLabeledFieldAbovePasswordField : this._isLabeledEmailField(e) && !this._matchesNonEmailFieldLabelPattern(e) ? t ? UsernameCandidateScoreForEmailLabeledFieldBelowPasswordField : UsernameCandidateScoreForEmailLabeledFieldAbovePasswordField | |
: o ? UsernameCandidateScoreForPlainTextFieldDirectlyBeforePasswordField | |
: UsernameCandidateScoreForPlainTextField | |
}, | |
_scoreForUsernameFieldCandidate : function(e, t, o) { | |
var r = this._scoreForUsernameFieldCandidateFromLabelingAndPositionOfField(e, t, o); | |
return e.isVisible() && (r += UsernameCandidateScoreBonusForVisibleElement), this._matchesNonUsernameFieldLabelPattern(e) && (r -= UsernameCandidateScorePenaltyForMatchingNonUsernameFieldLabelPattern), this._matchSearchFieldLabelPattern(e) && (r -= UsernameCandidateScorePenaltyForMatchingSearchFieldLabelPattern), e.readOnly && (r -= UsernameCandidateScorePenaltyForReadOnlyElement), e.id || e.name || (r -= UsernameCandidateScorePenaltyForAnonymousElement), r | |
}, | |
_matchesPasswordFieldLabelPattern : function(e) { | |
return this._passwordFieldPatternMatchers || (this._passwordFieldPatternMatchers = FormMetadataJSController.passwordFieldLabelPatternMatchers), !!this._bestMatchForElement(e, this._passwordFieldPatternMatchers) | |
}, | |
_matchesConfirmPasswordFieldLabelPattern : function(e, t = !1) { | |
return this._confirmPasswordFieldPatternMatchers || (this._confirmPasswordFieldPatternMatchers = FormMetadataJSController.confirmPasswordFieldLabelPatternMatchers), !!this._bestMatchForElement(e, this._confirmPasswordFieldPatternMatchers, t) | |
}, | |
_matchesConfirmEmailFieldLabelPattern : function(e) { | |
return !!this._isLabeledEmailField(e) && (this._confirmEmailFieldPatternMatchers || (this._confirmEmailFieldPatternMatchers = FormMetadataJSController.confirmEmailFieldLabelPatternMatchers), !!this._bestMatchForElement(e, this._confirmEmailFieldPatternMatchers)) | |
}, | |
_collectRadioButtonInfo : function(e, t) { | |
function o(e, t) | |
{ | |
var o = e.trim(); | |
o && t.push(o) | |
} | |
function r(e, t) | |
{ | |
o(e.alt, t), o(e.title, t), o(lastPathComponentForURLString(e.src), t) | |
} | |
function n(e) | |
{ | |
let t = []; | |
o(e.innerText, t); | |
let n = queryAllBySelector(e, "img"), | |
i = n.length; | |
for (let e = 0; e < i; ++e) | |
r(n[e], t); | |
return t.length ? t : null | |
} | |
for (var i = e.radioButtonsWithName(t), l = i.length, a = !1, s = {}, u = 0; u < l; ++u) { | |
s[(f = i[u]).value] = [ f.value ]; | |
for (var c = this._labelsForElement(f), d = c.length, h = 0; h < d; ++h) { | |
a = !0; | |
var m = n(c[h]); | |
m && (s[f.value] = s[f.value].concat(m)) | |
} | |
} | |
if (a) | |
return s; | |
const F = 64; | |
for (u = 0; u < l; ++u) { | |
for (var f, g = "", p = (f = i[u]).traverseNextNode(); p && !this._isRenderedFormControl(p); p = p.traverseNextNode()) { | |
var C = p.localName; | |
if ("td" === C || "tr" === C || "ul" === C || "ol" === C || "dl" === C) | |
break; | |
if (p instanceof HTMLImageElement) | |
r(p, s[f.value]); | |
else if (p.nodeType === Node.TEXT_NODE) { | |
var _ = p.nodeValue.trim(); | |
if (_ && (g += _.substr(0, F - g.length)), g.length >= F) | |
break | |
} | |
} | |
g && s[f.value].push(g) | |
} | |
return s | |
}, | |
_bestUsernameFieldCandidate : function(e, t, o) { | |
var r = t.FormControls, | |
n = r.filter((function(e) { | |
return e.ControlClaimsToBeUsernameViaAutocompleteAttribute | |
})); | |
if (1 === n.length) | |
return n[0]; | |
for (var i = 0, l = [], a = !1, s = r.indexOf(o), u = r.length, c = 0; c < u; ++c) { | |
var d = r[c]; | |
if (d === o) { | |
a = !0; | |
continue | |
} | |
if (!d.ControlIsTextField || d.ControlIsSecureTextField) | |
continue; | |
if (t.IsVisible && !r[c].IsVisible && !d.ControlValue) | |
continue; | |
const n = 100; | |
let F = e[c]; | |
if (!(F.value.length > n)) { | |
var h = c + 1 < u && c + 1 === s, | |
m = this._scoreForUsernameFieldCandidate(F, a, h); | |
m > i ? (l = [ c ], i = m) : m === i && l.push(c) | |
} | |
} | |
var F = l.length; | |
if (i < LowestScoreForLabeledUsernameFieldCandidate && F > 1) | |
return null; | |
if (i < LowestScoreForUsernameFieldCandidate) | |
return null; | |
switch (F) { | |
case 0: | |
return null; | |
case 1: | |
return r[l[0]]; | |
default: | |
var f = e[s].getBoundingClientRect(), | |
g = {}; | |
return l.forEach((function(t) { | |
g[t] = f.distanceToRect(e[t].getBoundingClientRect()) | |
})), | |
r[l.sort((function(e, t) { | |
return g[e] - g[t] | |
}))[0]] | |
} | |
}, | |
_autoFillFormTypeFromCandidateFormTypes : function(e, t, o) { | |
switch (t.length) { | |
case 1: | |
return t[0]; | |
case 2: | |
return this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ t[0], t[1] ], o); | |
default: | |
return WBSAutoFillFormTypeAutoFillableStandard | |
} | |
}, | |
_shouldTrustElementThatClaimsToBeCurrentPasswordViaAutocompleteAttribute : function(e) { | |
return !e.dataset.valRegexPattern | |
}, | |
_identifyFormTypeAndPasswordFieldIndicesFromAutocompleteAttributes : function(e, t) { | |
const o = [ null, null ]; | |
if (/^(.+\.)?roll20\.net\.?$/.test(document.location.hostname)) | |
return o; | |
var r = t.length; | |
if (r > 3) | |
return o; | |
for (var n = [], i = [], l = 0; l < r; ++l) { | |
var a = t[l]; | |
a.ControlClaimsToBeCurrentPasswordViaAutocompleteAttribute && this._shouldTrustElementThatClaimsToBeCurrentPasswordViaAutocompleteAttribute(e[l]) ? n.push(l) : a.ControlClaimsToBeNewPasswordViaAutocompleteAttribute && i.push(l) | |
} | |
var s = n.length, | |
u = i.length; | |
if (s + u !== r) | |
return o; | |
switch (r) { | |
case 0: | |
return o; | |
case 1: | |
if (s) | |
return [ | |
[ WBSAutoFillFormTypeAutoFillableLogin ], { | |
PasswordFieldIndex : n[0] | |
} | |
]; | |
if (u) | |
return [ null, null, WBSAutoFillFormTypeNewAccount ]; | |
case 2: | |
if (1 === s && 1 === u) | |
return [ | |
[ WBSAutoFillFormTypeChangePassword ], { | |
OldPasswordFieldIndex : n[0], | |
PasswordFieldIndex : i[0] | |
} | |
]; | |
if (0 === s && 2 === u) | |
return [ | |
[ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeChangePassword ], { | |
PasswordFieldIndex : i[0], | |
ConfirmationFieldIndex : i[1] | |
} | |
]; | |
break; | |
case 3: | |
if (1 === s && 2 === u) | |
return [ | |
[ WBSAutoFillFormTypeChangePassword ], { | |
OldPasswordFieldIndex : n[0], | |
PasswordFieldIndex : i[0], | |
ConfirmationFieldIndex : i[1] | |
} | |
] | |
} | |
return o | |
}, | |
_identifyPasswordFieldIndices : function(e, t) { | |
var o = e.length; | |
if (0 === o) | |
return {}; | |
if (1 === o) | |
return { | |
PasswordFieldIndex : 0 | |
}; | |
if (this._oldPasswordPatternMatchers || (this._oldPasswordPatternMatchers = FormMetadataJSController.oldPasswordFieldLabelPatternMatchers), 2 === o) { | |
return this._bestMatchForElement(t[0], this._oldPasswordPatternMatchers) ? { | |
OldPasswordFieldIndex : 0, | |
PasswordFieldIndex : 1 | |
} | |
: this._bestMatchForElement(t[1], this._oldPasswordPatternMatchers) ? { | |
OldPasswordFieldIndex : 1, | |
PasswordFieldIndex : 0 | |
} | |
: { | |
PasswordFieldIndex : 0, | |
ConfirmationFieldIndex : 1 | |
} | |
} | |
return this._bestMatchForElement(t[o - 1], this._oldPasswordPatternMatchers) ? { | |
PasswordFieldIndex : o - 3, | |
ConfirmationFieldIndex : o - 2, | |
OldPasswordFieldIndex : o - 1 | |
} | |
: { | |
PasswordFieldIndex : o - 2, | |
ConfirmationFieldIndex : o - 1, | |
OldPasswordFieldIndex : o - 3 | |
} | |
}, | |
_removePlaceholderTextForFormMetadata : function(e, t) { | |
for (var o = e.length, r = 0; r < o; ++r) { | |
var n = t.FormControls[r]; | |
if (n.ControlValue && n.ControlIsTextField && !n.ControlIsSecureTextField && !n.ControlIsReadOnly) { | |
var i = legacyPlaceholderInfoForInputElement(e[r]); | |
i && (i.AttributeMatchedWasValue && n.ControlUniqueID === t.UsernameElementUniqueID || (n.ControlValue = "")) | |
} | |
} | |
}, | |
_isPasswordConfirmPair : function(e, t) { | |
var o = this._matchesPasswordFieldLabelPattern(e), | |
r = this._matchesConfirmPasswordFieldLabelPattern(t); | |
return o && r | |
}, | |
_trailingArgumentsForCollectControlMetadataFunction : function(e, t, o) { | |
let r = isElementPositionedToBeEffectivelyInvisible(e.backingElement), | |
n = !1, | |
i = !1; | |
if (innermostActiveElement() || t === WBSFormMetadataRequestTesting) { | |
let e = this._cachedOneTimeCodePatternMatcher(); | |
if (n = !!this._matchPatternAgainstString(e, documentTitleWithoutHostNamePrefix()), o) { | |
let t = location.pathname.split("/"), | |
r = stripCommonPrefix(o.pathname.split("/"), t)[0].join("/"); | |
r.length && (i = !!this._matchPatternAgainstString(e, r)) | |
} | |
} | |
let l = !1; | |
for (let t of e.elements) | |
if (this._isTextField(t) && t.isVisible()) { | |
if (l) { | |
l = !1; | |
break | |
} | |
l = !0 | |
} | |
return [ r, i, n, l ] | |
}, | |
_collectFormMetadata : function(e, t) { | |
var o, r, n = (r = 0, { | |
backwardScanCache : new WeakMap, | |
forwardScanCache : new WeakMap, | |
shouldUsePageScan : function() { | |
return r < numberOfConsecutiveElementsWithoutSuccessfulPageScanAfterWhichPageScanIsAbandoned | |
}, | |
willStartCollectingMetadataForControl : function() { | |
o = null | |
}, | |
reportPageScanUsedSuccessfully : function(e) { | |
o = !(!e && !o) | |
}, | |
didFinishCollectingMetadataForControl : function() { | |
!0 === o ? r = 0 : !1 === o && r++ | |
} | |
}); | |
this._pageScanContext = n; | |
var i = e.formElement, | |
l = { | |
FormID : e.formUniqueID, | |
ContainsActiveElement : !1, | |
FormControls : [], | |
AutoFillFormType : WBSAutoFillFormTypeAutoFillableStandard, | |
UsernameElementUniqueID : void 0, | |
OldPasswordElementUniqueID : void 0, | |
PasswordElementUniqueID : void 0, | |
ConfirmPasswordElementUniqueID : void 0, | |
UsesGeneratedPassword : this._usesGeneratedPassword(e), | |
FirstCreditCardCardholderFieldOrCreditCardNumberFieldUniqueID : void 0, | |
IsVisible : i.isVisible(), | |
TextSample : void 0, | |
RequestType : t | |
}; | |
this._elementDisallowsAutocomplete(i) && (l.DisallowsAutocomplete = !0), i instanceof HTMLFormElement && (l.FormIsSearchForm = this._isSearchForm(i, !0)), e.isAnnotated && (l.Annotations = e.annotations); | |
var a = i.getAttribute("rel"); | |
a && "async" === a.toLowerCase() && (l.FormUsesRelAsync = !0); | |
let s = formActionAsAnchorElement(i); | |
if (s && s.href && (l.FormAction = s.href), t == WBSFormMetadataRequestCollectMetadataFromDebugMenu || t == WBSFormMetadataRequestTesting) { | |
let e = selectorForElement(i); | |
e && e.length && (l.LogicalFormElementSelector = e) | |
} | |
var u = e.elements, | |
c = !u.some(this._isSecureTextField.bind(this)); | |
let [d, h, m, F] = this._trailingArgumentsForCollectControlMetadataFunction(e, t, s); | |
var f = 0, | |
g = !1, | |
p = [], | |
C = [], | |
_ = [], | |
A = [], | |
b = void 0, | |
y = void 0, | |
S = void 0, | |
T = void 0, | |
E = !1, | |
I = !1, | |
v = {}, | |
P = []; | |
let w = !1; | |
for (var L = u.length, M = 0; M < L; ++M) { | |
var x = u[M]; | |
if (c && !x.isVisible() && !x._relatesToCredentials) | |
continue; | |
var k = isRadioButtonElement(x), | |
B = x.name; | |
if (k && v[B]) | |
continue; | |
n.willStartCollectingMetadataForControl(); | |
const o = !w; | |
var U = this._collectControlMetadata(x, t, d, h, m, F, o); | |
if (n.didFinishCollectingMetadataForControl(), w = !0, M + 1 < L && (U.ControlNextFieldUniqueID = this.controlUniqueID(u[M + 1])), l.FormControls.push(U), P.push(x), U.IsVisible || !l.IsVisible || x._relatesToCredentials) | |
if (U.ControlIsActiveElement && (l.ContainsActiveElement = !0), B && k) | |
v[B] = 1, U.ControlValue = "", U.RadioButtonInfo = this._collectRadioButtonInfo(e, B); | |
else if (U.ControlIsTextField || U.SelectElementInfo) | |
if (!I && U.ControlLooksLikeCreditCardSecurityCodeField && (I = !0), E || !U.ControlLooksLikeCreditCardCardholderField && !U.ControlLooksLikeCreditCardNumberField) { | |
if (!(U.ControlLooksLikeDayField || U.ControlLooksLikeMonthField || U.ControlLooksLikeYearField || U.ControlLooksLikeCreditCardCompositeExpirationDateField)) { | |
if (U.ControlLooksLikePasswordCredentialField) { | |
if (U.ControlLooksLikeCreditCardSecurityCodeField || U.ControlLooksLikeCreditCardNumberField || U.ControlLooksLikeIgnoredDataTypeField) | |
continue; | |
x.isHiddenFromAccessibilityTree() ? (_.push(x), A.push(U)) : (p.push(x), C.push(U)) | |
} | |
if (this._isLabeledEmailField(x)) { | |
if (++f > 2) { | |
g = !1; | |
continue | |
} | |
if (!(M + 1 < L && this._matchesConfirmEmailFieldLabelPattern(u[M + 1]))) | |
continue; | |
g = !0 | |
} | |
} | |
} else | |
E = !0, l.FirstCreditCardCardholderFieldOrCreditCardNumberFieldUniqueID = U.ControlUniqueID | |
} | |
!p.length && _.length && (p = _, C = A); | |
var D, W, N = this._identifyFormTypeAndPasswordFieldIndicesFromAutocompleteAttributes(p, C), | |
q = N[0], | |
O = N[1], | |
R = N[2], | |
V = O || this._identifyPasswordFieldIndices(C, p); | |
if (void 0 !== V.PasswordFieldIndex && (b = C[V.PasswordFieldIndex], l.PasswordElementUniqueID = b.ControlUniqueID, y = this._explicitMaxLength(p[V.PasswordFieldIndex])), void 0 !== V.ConfirmationFieldIndex && (S = C[V.ConfirmationFieldIndex], l.ConfirmPasswordElementUniqueID = S.ControlUniqueID, T = this._explicitMaxLength(p[V.ConfirmationFieldIndex])), void 0 !== V.OldPasswordFieldIndex) { | |
var H = C[V.OldPasswordFieldIndex]; | |
l.OldPasswordElementUniqueID = H.ControlUniqueID | |
} | |
if (b && (D = this._bestUsernameFieldCandidate(P, l, b)), D ? l.UsernameElementUniqueID = D.ControlUniqueID : W = this._findHiddenUsernameElement(e, l, P), q) | |
l.AutoFillFormType = this._autoFillFormTypeFromCandidateFormTypes(e, q, q[0]); | |
else if (1 === p.length && g) | |
l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeChangePassword ], WBSAutoFillFormTypeNewAccount); | |
else if (l.UsernameElementUniqueID) | |
switch (p.length) { | |
case 0: | |
break; | |
case 1: | |
if (I && l.UsernameElementUniqueID === l.FirstCreditCardCardholderFieldOrCreditCardNumberFieldUniqueID && C[0].ControlLooksLikeCreditCardNumberField) | |
break; | |
if (this._matchesConfirmPasswordFieldLabelPattern(p[0])) { | |
let t = {}; | |
this._isElementFollowedByForgotPasswordAffordance(x, i) && (t[WBSAutoFillFormTypeAutoFillableLogin] = 2), l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeChangePassword ], R || WBSAutoFillFormTypeAutoFillableLogin, t) | |
} else { | |
let t = p[0], | |
o = {}, | |
r = 2 * this._numberOfForgotUserNameEmailOrPasswordAffordancesFollowingElement(t, i); | |
r && (o[WBSAutoFillFormTypeAutoFillableLogin] = r), l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeAutoFillableLogin ], R || WBSAutoFillFormTypeAutoFillableLogin, o) | |
} | |
break; | |
case 2: | |
y === T ? l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeChangePassword ], WBSAutoFillFormTypeNewAccount) : T ? this._isPasswordConfirmPair(p[0], p[1]) ? l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeChangePassword ], WBSAutoFillFormTypeNonAutoFillable) : l.AutoFillFormType = WBSAutoFillFormTypeNonAutoFillable | |
: l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeChangePassword ], WBSAutoFillFormTypeNonAutoFillable); | |
break; | |
case 3: | |
y === T || !T || this._isPasswordConfirmPair(p[V.PasswordFieldIndex], p[V.ConfirmationFieldIndex]) ? l.AutoFillFormType = WBSAutoFillFormTypeChangePassword : l.AutoFillFormType = WBSAutoFillFormTypeNonAutoFillable; | |
break; | |
default: | |
l.AutoFillFormType = WBSAutoFillFormTypeNonAutoFillable | |
} | |
else if (2 === p.length || 3 === p.length) | |
if (y !== T && T) | |
2 === p.length ? this._isPasswordConfirmPair(p[0], p[1]) ? l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeChangePassword ], WBSAutoFillFormTypeNonAutoFillable) : l.AutoFillFormType = WBSAutoFillFormTypeNonAutoFillable : this._isPasswordConfirmPair(p[V.PasswordFieldIndex], p[V.ConfirmationFieldIndex]) ? l.AutoFillFormType = WBSAutoFillFormTypeChangePassword | |
: l.AutoFillFormType = WBSAutoFillFormTypeNonAutoFillable; | |
else { | |
let t = {}; | |
this._isPasswordConfirmPair(p[V.PasswordFieldIndex], p[V.ConfirmationFieldIndex]) && (t[WBSAutoFillFormTypeChangePassword] = 2), l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeChangePassword ], WBSAutoFillFormTypeChangePassword, t) | |
} | |
else if (1 === p.length) { | |
var Y = p[0]; | |
if (this._matchesConfirmPasswordFieldLabelPattern(Y, !0)) { | |
let t = {}; | |
this._isElementFollowedByForgotPasswordAffordance(x, i) && (t[WBSAutoFillFormTypeAutoFillableLogin] = 2), l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeAutoFillableLogin, WBSAutoFillFormTypeChangePassword ], WBSAutoFillFormTypeChangePassword, t) | |
} else if (this._matchesPasswordFieldLabelPattern(Y)) | |
if (this._isElementFollowedByForgotPasswordAffordance(Y, i)) | |
l.AutoFillFormType = WBSAutoFillFormTypeAutoFillableLogin; | |
else { | |
var J = [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeAutoFillableLogin, WBSAutoFillFormTypeChangePassword ]; | |
l.AutoFillFormType = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, J, WBSAutoFillFormTypeNonAutoFillable), l.AutoFillFormType === WBSAutoFillFormTypeNonAutoFillable && W && (l.AutoFillFormType = WBSAutoFillFormTypeNewAccount) | |
} | |
else | |
l.AutoFillFormType = WBSAutoFillFormTypeNonAutoFillable | |
} else | |
0 !== p.length && (l.AutoFillFormType = WBSAutoFillFormTypeNonAutoFillable); | |
if (l.AutoFillFormType === WBSAutoFillFormTypeAutoFillableStandard) { | |
var G = null, | |
K = null, | |
z = null, | |
$ = 0, | |
j = P.length; | |
for (M = 0; M < j; ++M) { | |
x = P[M]; | |
var Z = l.FormControls[M], | |
X = Z.IsVisible; | |
if (X && Z.ControlIsTextField && $++, $ > 1) | |
break; | |
if (x.closest("footer")) | |
continue; | |
let t = {}; | |
this._isElementFollowedByForgotUserNameOrEmailAffordance(x, i) && (t[WBSAutoFillFormTypeAutoFillableLogin] = 2); | |
var Q = this._isLabeledEmailField(x); | |
if (X && (Z.ControlClaimsToBeUsernameViaAutocompleteAttribute || Z.ControlIsLabeledUsernameField || Q || this._isLabeledLoginField(x)) && !this._matchesNonUsernameFieldLabelPattern(x) && !this._matchSearchFieldLabelPattern(x) && !x.readOnly && "INPUT" === x.tagName && !this._isLabeledSignUpField(x)) { | |
let t = {}; | |
this._isElementFollowedByForgotUserNameOrEmailAffordance(x, i) && (t[WBSAutoFillFormTypeAutoFillableLogin] = 2), this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeAutoFillableLogin ], Q ? WBSAutoFillFormTypeNewAccount : WBSAutoFillFormTypeAutoFillableLogin, t) === WBSAutoFillFormTypeAutoFillableLogin && (G = x, K = Z, z = WBSAutoFillFormTypeAutoFillableLogin) | |
} | |
const o = Z.AutocompleteTokens; | |
if (o) { | |
const r = o.includes("username"), | |
n = o.includes("webauthn"); | |
if (r && n) { | |
G = x, K = Z, z = WBSAutoFillFormTypeAutoFillableLogin; | |
continue | |
} | |
r && Q && (G = x, K = Z, z = this._autoFillFormTypeOfTypesUsingKeywordMatching(e, [ WBSAutoFillFormTypeNewAccount, WBSAutoFillFormTypeAutoFillableLogin ], WBSAutoFillFormTypeAutoFillableLogin, t)) | |
} | |
} | |
1 === $ && K && z && !controlAppearsToBePartOfPhotoTaggingInterface(G) && (l.AutoFillFormType = z, l.UsernameElementUniqueID = K.ControlUniqueID) | |
} | |
l.AutoFillFormType === WBSAutoFillFormTypeNewAccount && l.FirstCreditCardCardholderFieldOrCreditCardNumberFieldUniqueID === l.UsernameElementUniqueID && (l.UsernameElementUniqueID = void 0), !l.UsernameElementUniqueID && W && this._extractMetadataForHiddenUsernameElement(W, l, P), l.AutoFillFormType != WBSAutoFillFormTypeAutoFillableLogin && l.AutoFillFormType != WBSAutoFillFormTypeNewAccount && l.AutoFillFormType != WBSAutoFillFormTypeChangePassword && (l.UsernameElementUniqueID = void 0, l.OldPasswordElementUniqueID = void 0, l.PasswordElementUniqueID = void 0, l.ConfirmPasswordElementUniqueID = void 0), l.IsVisible || l.AutoFillFormType == WBSAutoFillFormTypeAutoFillableLogin || l.AutoFillFormType == WBSAutoFillFormTypeNewAccount || l.AutoFillFormType == WBSAutoFillFormTypeChangePassword || (l.AutoFillFormType = WBSAutoFillFormTypeNonAutoFillable), t !== WBSFormMetadataRequestPreFill && (l.TextSample = this._collectTextSample(e.formElement)), l.FormIsEligibleForAutomaticLogin = this._formIsEligibleForAutomaticLogin(l, e.backingElement); | |
for (let e of l.FormControls) | |
if (e.ControlLooksLikeOneTimeCodeField && this._oneTimeCodeIsEligibleForAutomaticLogin(e, l)) { | |
e.OneTimeCodeIsEligibleForAutomaticLogin = !0; | |
break | |
} | |
var ee = FormMetadataJSController.shouldIncludeNonEmptyFields; | |
if (l.IsVisible) | |
for (M = (j = P.length) - 1; M >= 0; --M) | |
this._shouldIncludeControlMetadata(ee, l, P[M], l.FormControls[M]) || (t !== WBSFormMetadataRequestCollectMetadataFromDebugMenu ? (l.FormControls.splice(M, 1), P.splice(M, 1)) : l.FormControls[M].WOULD_NORMALLY_NOT_BE_SENT_TO_UI_PROCESS = !0); | |
return this._removePlaceholderTextForFormMetadata(P, l), delete this._pageScanContext, t !== WBSFormMetadataRequestPreFill && globalThis.FormMetadataClassificationJS && globalThis.FormMetadataClassificationJS.classify(l), l | |
}, | |
_formIsEligibleForAutomaticLogin : function(e, t) { | |
if (e.AutoFillFormType !== WBSAutoFillFormTypeAutoFillableLogin) | |
return !1; | |
let o = !1; | |
for (const t of e.FormControls) { | |
const r = t.ControlUniqueID; | |
if (r === e.UsernameElementUniqueID || r === e.PasswordElementUniqueID) | |
continue; | |
if (t.ControlIsDisabled) | |
continue; | |
if (t.ControlIsReadOnly) | |
continue; | |
if (!t.IsVisible) | |
continue; | |
const n = this.formControlWithUniqueID(r); | |
if (!n) | |
continue; | |
if (this._isTextArea(n)) | |
return !1; | |
if (this._isSelectElement(n)) | |
return !1; | |
if (this._isSubmitButton(n)) | |
continue; | |
if (this._looksLikeShowHidePasswordButton(n)) | |
continue; | |
if (!isInputElement(n)) | |
continue; | |
const i = n.type; | |
if ("button" !== i && "reset" !== i && "submit" !== i && "image" !== i) { | |
if (!this._isCheckboxInputElement(n)) | |
return !1; | |
if (o) | |
return !1; | |
o = !0 | |
} | |
} | |
return !t || !elementAppearsToContinueCaptchaWidget(t) | |
}, | |
_oneTimeCodeIsEligibleForAutomaticLogin : function(e, t) { | |
for (const e of t.FormControls) { | |
if (e.ControlLooksLikeOneTimeCodeField) | |
continue; | |
if (e.ControlIsDisabled) | |
continue; | |
if (e.ControlIsReadOnly) | |
continue; | |
if (!e.IsVisible) | |
continue; | |
const t = this.formControlWithUniqueID(e.ControlUniqueID); | |
if (!t) | |
continue; | |
if (this._isTextArea(t)) | |
return !1; | |
if (this._isSelectElement(t)) | |
return !1; | |
if (this._isSubmitButton(t)) | |
continue; | |
if (this._looksLikeShowHidePasswordButton(t)) | |
continue; | |
if (!isInputElement(t)) | |
continue; | |
const o = t.type; | |
if ("button" !== o && "reset" !== o && "submit" !== o && "image" !== o) | |
return !1 | |
} | |
return !0 | |
}, | |
_shouldIncludeControlMetadata : function(e, t, o, r) { | |
if (o._relatesToCredentials) | |
return !0; | |
if (r.IsVisible) { | |
if (formControlHasBeenClassifiedInAnInterestingWay(r)) | |
return !0; | |
if (e && r.ControlValue) | |
return !0 | |
} | |
return !(!t.UsernameElementUniqueID || r.ControlUniqueID !== t.UsernameElementUniqueID) | |
}, | |
_isElementAHiddenUsername : function(e) { | |
const t = /user|email/i; | |
return "hidden" === e.type && (!(!t.test(e.getAttribute("id")) && !t.test(e.getAttribute("name"))) && !!isValidUsernameOrEmail(e.value)) | |
}, | |
_findHiddenUsernameElement : function(e) { | |
var t = e.formElement; | |
if (!(t instanceof HTMLElement)) | |
return; | |
let o = queryAllBySelector(t, "input"), | |
r = o.length; | |
for (let e = 0; e < r; ++e) { | |
let t = o[e]; | |
if (this._isElementAHiddenUsername(t)) | |
return t | |
} | |
return null | |
}, | |
_extractMetadataForHiddenUsernameElement : function(e, t, o) { | |
var r = { | |
ControlTagName : this._getTagName(e), | |
ControlFieldName : this._getNameOrId(e), | |
ControlUniqueID : this.controlUniqueID(e), | |
ControlIsReadOnly : !0, | |
ControlValue : e.value | |
}; | |
t.UsernameElementUniqueID = r.ControlUniqueID, t.FormControls.push(r), o.push(e) | |
}, | |
_usernameFieldForPasswordField : function(e) { | |
let t = FormMetadataJS._cachedMetadataForLogicalForm(this._logicalFormsCache.logicalFormForControl(e)); | |
return t && t.UsernameElementUniqueID ? FormMetadataJS.formControlWithUniqueID(t.UsernameElementUniqueID) : null | |
}, | |
_cachedMetadataForLogicalForm : function(e) { | |
var t = e.metadata, | |
o = t?.FormControls, | |
r = o?.length ?? 0; | |
if (!r) | |
return null; | |
const n = innermostActiveElement(); | |
for (var i = 0; i < r; ++i) { | |
var l = o[i], | |
a = this.formControlWithUniqueID(l.ControlUniqueID); | |
a && (l.ControlIsActiveElement = a === n, l.ControlValue = a.value, l.ControlIsAutoFilledTextField = this._isAutoFilledTextField(a)) | |
} | |
return t.UsesGeneratedPassword = this._usesGeneratedPassword(e), t.Annotations = e.annotations, t | |
}, | |
_markFormIsBestForPageLevelAutoFill : function() { | |
function e(e) | |
{ | |
switch (e) { | |
case WBSAutoFillFormTypeAutoFillableLogin: | |
return 30; | |
case WBSAutoFillFormTypeNewAccount: | |
case WBSAutoFillFormTypeChangePassword: | |
return 20; | |
case WBSAutoFillFormTypeAutoFillableStandard: | |
return 10; | |
case WBSAutoFillFormTypeUndetermined: | |
case WBSAutoFillFormTypeNonAutoFillable: | |
return 0 | |
} | |
return -100 | |
} | |
function t(e) | |
{ | |
return e ? 50 : 0 | |
} | |
let o = this._logicalFormWithHighestScoreIfGreaterThanZero((function(o) { | |
var r = o.PasswordElementUniqueID ? 0 : -1; | |
return e(o.AutoFillFormType) + t(o.IsVisible) + r | |
})); | |
null !== o && (o.metadata.FormIsBestForPageLevelAutoFill = !0) | |
}, | |
_markFormIsBestForStreamlinedLogin : function() { | |
let e = this._logicalFormWithHighestScoreIfGreaterThanZero((function(e, t) { | |
if (!e.IsVisible) | |
return 0; | |
let o = t.getBoundingClientRect(); | |
if (!rectIsWithinDocumentViewport(o)) | |
return 0; | |
if (o.bottom + window.scrollY < 80) { | |
let e = !(location.hash || location.pathname && "/" !== location.pathname || location.search), | |
t = o.width / o.height; | |
if (!e && t > 4) | |
return 0 | |
} | |
if (t.closest("footer")) | |
return 0; | |
let r = e.AutoFillFormType === WBSAutoFillFormTypeAutoFillableLogin, | |
n = 0, | |
i = e.FormControls, | |
l = i.length; | |
for (var a = 0; a < l; ++a) { | |
let t = i[a]; | |
if (r) { | |
t.ControlIsAutofocusedTextField && (n += 1); | |
let o = t.ControlUniqueID; | |
if (o === e.UsernameElementUniqueID || o === e.PasswordElementUniqueID) { | |
n += 10; | |
continue | |
} | |
} | |
t.OneTimeCodeIsEligibleForAutomaticLogin && (n += 5) | |
} | |
return n | |
})); | |
null !== e && (e.metadata.FormIsBestForStreamlinedLogin = !0) | |
}, | |
_logicalFormWithHighestScoreIfGreaterThanZero : function(e) { | |
let t = null, | |
o = null; | |
for (let n of this._logicalFormsCache.allForms()) { | |
var r = e(n.metadata, n.backingElement); | |
(null === t || r > t) && (o = n, t = r) | |
} | |
return t > 0 ? o : null | |
}, | |
isAnyFormAnnotated : function() { | |
return this._logicalFormsCache.allForms().some((e => e.isAnnotated)) | |
}, | |
clearAnnotationsForFormWithID : function(e) { | |
let t = this._logicalFormsCache.logicalFormWithUniqueID(e); | |
t && t.clearAnnotations() | |
}, | |
annotateFormWithID : function(e, t) { | |
let o = this._logicalFormsCache.logicalFormWithUniqueID(e); | |
o && o.annotate(t) | |
}, | |
_collectMetadata : function(e) { | |
const t = 100, | |
o = 10; | |
var r = this._logicalFormsInPage(t, o); | |
this._logicalFormsCache.clearCacheAndAdd(r); | |
for (var n = r.length, i = 0; i < n; ++i) { | |
e === WBSFormMetadataRequestTesting && "function" == typeof willCollectFormMetadata && willCollectFormMetadata(); | |
let t = this._collectFormMetadata(r[i], e); | |
e === WBSFormMetadataRequestTesting && "function" == typeof evaluateCustomJavaScript && (t.ResultFromEvaluatingCustomJavaScript = evaluateCustomJavaScript(r[i], t)), r[i].metadata = t | |
} | |
this._markFormIsBestForPageLevelAutoFill(), e !== WBSFormMetadataRequestNormal && this._markFormIsBestForStreamlinedLogin() | |
}, | |
_collectAndCacheFormMetadata : function(e, t) { | |
let o = this._collectFormMetadata(e, t), | |
r = this._logicalFormsCache.logicalFormWithUniqueID(e.formUniqueID); | |
return r ? r.metadata = o : (e.metadata = o, this._logicalFormsCache.addOrUpdate(e)), o | |
}, | |
_metadataForFormWithID : function(e) { | |
return this._logicalFormsCache.logicalFormWithUniqueID(e)?.metadata | |
}, | |
_recollectMetadataForFormWithID : function(e) { | |
const t = this._logicalFormsCache.logicalFormWithUniqueID(e); | |
return t ? this._collectAndCacheFormMetadata(t, WBSFormMetadataRequestNormal) : null | |
}, | |
_fillControlWithGeneratedPassword : function(e, t) { | |
var o = this._elementsWithGeneratedPasswords.indexOf(e); | |
-1 === o && (this._elementsWithGeneratedPasswords.push(e), o = this._elementsWithGeneratedPasswords.length - 1), this._generatedPasswords[o] = t, this._autoFillControlWithValueWithSingleValueUpdate(e, t, ShouldFocus.Yes, ShouldBlur.Yes, ShouldSetAutoFilled.Yes) | |
}, | |
fillFormWithPassword : function(e, t, o) { | |
var r = this._metadataForFormWithID(e); | |
if (null === r) | |
return null; | |
const n = r.PasswordElementUniqueID, | |
i = n ? this.formControlWithUniqueID(n) : void 0, | |
l = o ? this.formControlWithUniqueID(o) : void 0; | |
var a = i || l; | |
const s = n || o; | |
if (!a) | |
return null; | |
this._fillControlWithGeneratedPassword(a, t); | |
let u = r.ConfirmPasswordElementUniqueID; | |
u || r.AutoFillFormType !== WBSAutoFillFormTypeChangePassword && r.AutoFillFormType !== WBSAutoFillFormTypeNewAccount || (u = (r = this._recollectMetadataForFormWithID(e) || r).ConfirmPasswordElementUniqueID); | |
let c = u ? this.formControlWithUniqueID(u) : null; | |
return c ? (this._fillControlWithGeneratedPassword(c, t), [ s, u ]) : [ s ] | |
}, | |
fillFieldWithGeneratedPassword : function(e, t) { | |
var o = this.formControlWithUniqueID(e); | |
o && this._isTextField(o) && this._fillControlWithGeneratedPassword(o, t) | |
}, | |
clearField : function(e) { | |
var t = this.formControlWithUniqueID(e); | |
this._clearFormField(t) | |
}, | |
_clearFormField : function(e, t) { | |
if (e) | |
if (this._isSelectElement(e)) | |
e.selectedIndex = 0; | |
else if (isDateTimeInputElement(e)) | |
e.value = ""; | |
else if (isRadioButtonElement(e)) { | |
let t = this._logicalFormsCache.logicalFormForControl(e).radioButtonsWithName(e.name), | |
o = t.length; | |
for (let e = 0; e < o; ++e) | |
t[e].checked = !1 | |
} else if (this._isTextField(e) && e.value.length) { | |
var o = e.matches(":focus"); | |
o || e.dispatchEvent(new Event("focus")), e.dispatchEvent(eventThatBubbles("keydown")), e.value = "", e.dispatchEvent(eventThatBubbles("input")), e.dispatchEvent(eventThatBubbles("keyup")), e.dispatchEvent(eventThatBubbles("change")), o || t === ShouldBlur.No || e.dispatchEvent(new Event("blur")) | |
} | |
}, | |
focusFormForStreamlinedLogin : function(e) { | |
function t(e) | |
{ | |
for (const t of e.FormControls) { | |
const o = t.ControlUniqueID; | |
if (o === e.UsernameElementUniqueID || o === e.PasswordElementUniqueID || t.ControlLooksLikeOneTimeCodeField) | |
return o | |
} | |
} | |
var o = this._metadataForFormWithID(e); | |
if (null !== o) { | |
var r = t(o); | |
if (r) { | |
var n = this.formControlWithUniqueID(r); | |
rectIsWithinDocumentViewport(n.getBoundingClientRect()) && n.focus() | |
} | |
} | |
}, | |
formsAndMetadata : function(e) { | |
visibilityCacheGeneration++, this._collectMetadata(e); | |
let t = [], | |
o = []; | |
for (let e of this._logicalFormsCache.allForms()) | |
t.push(e.formElement), o.push(e.metadata); | |
return [ t, o ] | |
}, | |
formControlWithUniqueID : function(e) { | |
let t = this._controlUniqueIDToWeakControlMap.get(e)?.deref(); | |
return t | |
}, | |
formElementWithFormID : function(e) { | |
return this._logicalFormsCache.logicalFormWithUniqueID(e)?.formElement | |
}, | |
selectIfTextField : function(e) { | |
this._isTextField(e) && e.select() | |
}, | |
_getOrCreateCachedMetadataForLogicalForm : function(e, t) { | |
var o = this._cachedMetadataForLogicalForm(e); | |
return !o || null != t && o.RequestType === WBSFormMetadataRequestPreFill && t !== WBSFormMetadataRequestPreFill ? this._collectAndCacheFormMetadata(e, t) : o | |
}, | |
_getOrCreateLogicalFormForTextFieldOrSelectElement : function(e) { | |
let t = this._logicalFormsCache.logicalFormForControl(e); | |
if (t) | |
for (var o = t.metadata, r = o?.FormControls, n = r?.length ?? 0, i = e._controlUniqueID, l = 0; l < n; ++l) | |
if (r[l].ControlUniqueID === i) | |
return t; | |
var a = this._logicalFormsInPage(), | |
s = a.length; | |
for (l = 0; l < s; ++l) { | |
var u = a[l]; | |
if (u.containsControl(e)) | |
return this._logicalFormsCache.addOrUpdate(u), u.metadata = this._collectFormMetadata(u, WBSFormMetadataRequestNormal), u | |
} | |
return null | |
}, | |
_cachedMetadataForFormWithTextFieldOrSelectElement : function(e, t) { | |
if (!this._isTextField(e) && !this._isSelectElement(e)) | |
return null; | |
var o = this._getOrCreateLogicalFormForTextFieldOrSelectElement(e); | |
return o ? this._getOrCreateCachedMetadataForLogicalForm(o, t) : null | |
}, | |
_isAnyPasswordElementUniqueID : function(e, t) { | |
return e.PasswordElementUniqueID === t || e.ConfirmPasswordElementUniqueID === t || e.OldPasswordElementUniqueID === t | |
}, | |
_isCurrentPasswordElementUniqueID : function(e, t) { | |
switch (e.AutoFillFormType) { | |
case WBSAutoFillFormTypeNewAccount: | |
case WBSAutoFillFormTypeChangePassword: | |
return e.OldPasswordElementUniqueID === t; | |
default: | |
return e.PasswordElementUniqueID === t | |
} | |
}, | |
_isNewPasswordElementUniqueID : function(e, t) { | |
switch (e.AutoFillFormType) { | |
case WBSAutoFillFormTypeNewAccount: | |
case WBSAutoFillFormTypeChangePassword: | |
return e.PasswordElementUniqueID === t || e.ConfirmPasswordElementUniqueID === t; | |
default: | |
return !1 | |
} | |
}, | |
_updateAnnotationsForField : function(e) { | |
var t = this._getOrCreateLogicalFormForTextFieldOrSelectElement(e); | |
if (t) { | |
var o = this._getOrCreateCachedMetadataForLogicalForm(t); | |
if (o) { | |
var r = e._controlUniqueID; | |
this._isCurrentPasswordElementUniqueID(o, r) ? t.annotate({ | |
CurrentPassword : e.value | |
}) | |
: this._isNewPasswordElementUniqueID(o, r) ? t.annotate({ | |
NewPassword : e.value | |
}) | |
: o.UsernameElementUniqueID === r && t.annotate({ | |
Username : e.value | |
}), | |
isCredentialElementUniqueID(o, r) && (e._relatesToCredentials = "" !== e.value) | |
} | |
} | |
}, | |
textFieldOrSelectElementMetadata : function(e, t, o) { | |
visibilityCacheGeneration++, this._logicalFormsCache.cleanupCache(); | |
var r = [ null, null ], | |
n = this._cachedMetadataForFormWithTextFieldOrSelectElement(e, t); | |
if (!n) | |
return r; | |
this._pageScanContext = { | |
backwardScanCache : new WeakMap, | |
forwardScanCache : new WeakMap | |
}; | |
let i = this._logicalFormsCache.logicalFormWithUniqueID(n.FormID), | |
l = formActionAsAnchorElement(i.formElement), | |
[ a, s, u, c ] = this._trailingArgumentsForCollectControlMetadataFunction(i, t, l); | |
const d = !0; | |
var h = this._collectControlMetadata(e, WBSFormMetadataRequestNormal, a, s, u, c, d); | |
if (delete this._pageScanContext, h.ControlLooksLikeOneTimeCodeField && this._oneTimeCodeIsEligibleForAutomaticLogin(h, n) && (h.OneTimeCodeIsEligibleForAutomaticLogin = !0), h.SelectionStart = e.selectionStart, h.SelectionLength = e.selectionEnd - e.selectionStart, t === WBSFormMetadataRequestTextChange && (!n.UsernameElementUniqueID && this._isAnyPasswordElementUniqueID(n, h.ControlUniqueID) && i.isAnnotated && i.annotate({ | |
Username : null | |
}), | |
this._updateAnnotationsForField(e)), | |
n.RequestType !== WBSFormMetadataRequestPreFill) | |
for (let e of n.FormControls) | |
if (h.ControlUniqueID === e.ControlUniqueID) { | |
h.ControlClassification = e.ControlClassification, h.ControlClassificationHints = e.ControlClassificationHints, h.ControlOrderedParts = e.ControlOrderedParts, h.ControlContinuationID = e.ControlContinuationID, h.ControlContinuationIndex = e.ControlContinuationIndex; | |
break | |
} | |
if (o) { | |
for (const e of n.FormControls) | |
e.ControlUniqueID == h.ControlUniqueID && (e.ControlValue = null); | |
const e = JSON.stringify(n); | |
this._cachedFormMetadata == e ? n = null : this._cachedFormMetadata = e | |
} | |
return r[0] = h, r[1] = n, r | |
}, | |
clearTextFieldOrSelectElementMetadataCache : function() { | |
this._cachedFormMetadata = null | |
}, | |
disableSpellCheckInFieldIfNeeded : function(e) { | |
if (e) { | |
var t = this.formControlWithUniqueID(e); | |
t && this._isAutoFillableTextField(t) && FormMetadataJSController.setInputElementSpellCheckEnabled(t, !1) | |
} | |
}, | |
selectionRangeInField : function(e) { | |
var t = this.formControlWithUniqueID(e); | |
return t && this._isTextField(t) ? [ t.selectionStart, t.selectionEnd - t.selectionStart ] : null | |
}, | |
setFormFieldSelection : function(e, t, o) { | |
var r = this.formControlWithUniqueID(e); | |
r && this._isTextField(r) && (r.selectionStart = t, r.selectionEnd = t + o) | |
}, | |
replaceFormFieldRangeAndSelectTail : function(e, t, o, r, n) { | |
var i = this.formControlWithUniqueID(e); | |
if (i && this._isTextField(i)) { | |
var l = i.value, | |
a = l.substr(0, t) + r + l.substr(t + o); | |
i.value = a, i.selectionStart = n, i.selectionEnd = a.length, i.dispatchEvent(eventThatBubbles("input")), i.dispatchEvent(eventThatBubbles("change")) | |
} | |
}, | |
_collectVisibleNonEmptyTextFieldsAndTextAreasInForm : function(e, t, o) { | |
visibilityCacheGeneration++; | |
for (var r = e.elements, n = r.length, i = 0; i < n; ++i) { | |
var l = r[i]; | |
l.isVisible() && (null != l.value && l.value.length && (this._isTextField(l) ? t.push(l) : this._isTextArea(l) && o.push(l))) | |
} | |
}, | |
visibleNonEmptyFormTextControls : function() { | |
var e = [], | |
t = []; | |
let o = queryAllBySelector(document, "form"); | |
for (let r = 0; r < o.length; ++r) | |
this._collectVisibleNonEmptyTextFieldsAndTextAreasInForm(o[r], e, t); | |
return [ e, t ] | |
}, | |
visibleNonEmptyFormTextControlsInForm : function(e) { | |
var t = [], | |
o = []; | |
return this._collectVisibleNonEmptyTextFieldsAndTextAreasInForm(e, t, o), [ t, o ] | |
}, | |
_autoFillRadioButton : function(e, t, o) { | |
var r = this._logicalFormsCache.logicalFormForControl(e), | |
n = r?.radioButtonsWithName(e.name) ?? []; | |
for (let e of n) | |
if (e.value === t) | |
return e.dispatchEvent(eventThatBubbles("click")), e.checked = !0, void FormMetadataJSController.setInputElementAutofilled(e, o) | |
}, | |
_autoFillControlWithValueWithSingleValueUpdate : function(e, t, o, r, n, i, l) { | |
o === ShouldFocus.Yes && e.dispatchEvent(new Event("focus")), e.dispatchEvent(eventThatBubbles("keydown")), e.value = t, this._updateAnnotationsForField(e), l || e.dispatchEvent(eventThatBubbles("input")), e.dispatchEvent(eventThatBubbles("keyup")), l || e.dispatchEvent(eventThatBubbles("change")), r === ShouldBlur.Yes && e.dispatchEvent(new Event("blur")), i === ShouldObscure.Yes ? FormMetadataJSController.setInputElementAutofilledAndObscured(e, t.length && n === ShouldSetAutoFilled.Yes) : FormMetadataJSController.setInputElementAutofilled(e, t.length && n === ShouldSetAutoFilled.Yes) | |
}, | |
_autoFillControlWithValueCharacterByCharacter : function(e, t, o, r, n, i, l) { | |
let a = t.split(""), | |
s = a.length, | |
u = Date.now(), | |
c = !e; | |
const d = 100, | |
h = () => { | |
this._autoFillControlWithValueWithSingleValueUpdate(e, t, ShouldFocus.Yes, ShouldBlur.Yes, o, r), i?.() | |
}; | |
let m = F => { | |
try { | |
if (F >= s) | |
return void i?.(); | |
c && (e = innermostActiveElement()); | |
let f = e.value, | |
g = a[F], | |
p = f.slice(-1); | |
if (p === g && F && !t.slice(F - 1).startsWith(p + g)) | |
return void setTimeout(m, 0, F + 1); | |
let C = 0 === F ? ShouldFocus.Yes : ShouldFocus.No, | |
_ = F === s - 1, | |
A = _ ? ShouldBlur.Yes : ShouldBlur.No, | |
b = _ ? o : ShouldSetAutoFilled.No, | |
y = _ ? r : ShouldObscure.No, | |
S = f + g, | |
T = !_; | |
if (l && (T = !1), this._autoFillControlWithValueWithSingleValueUpdate(e, S, C, A, b, y, T), !c && !this._controlContainsAllCharactersFromFilling(e.value, t.substring(0, F + 1))) | |
return void h(); | |
const E = Date.now() - u; | |
if (u = Date.now(), E > d && n === ShouldAbandonCharacterByCharacterEntryIfTooSlow.Yes) | |
return void h(); | |
setTimeout(m, 0, F + 1) | |
} catch (e) { | |
} | |
}; | |
m(0) | |
}, | |
_controlContainsAllCharactersFromFilling : function(e, t) { | |
if (e.length < t.length) | |
return !1; | |
var o = t; | |
for (let r = 0; r < t.length; r++) { | |
-1 !== e.indexOf(t[r]) && (e = e.replace(t[r], ""), o = o.replace(t[r], "")) | |
} | |
return !o.length | |
}, | |
_autoFillControlWithValueRecursively : function(e, t, o, r, n) { | |
if (isRadioButtonElement(e)) | |
return this._autoFillRadioButton(e, t, o === ShouldSetAutoFilled.Yes), void (n && n()); | |
if (this._isSelectElement(e)) | |
return this._autoFillSelectWithOptionIndex(e, t, o === ShouldSetAutoFilled.Yes), void (n && n()); | |
let i = this._logicalFormsCache.logicalFormForControl(e), | |
l = FormMetadataJS._cachedMetadataForLogicalForm(i); | |
if (!this._isTextField(e) || l && isCredentialElementUniqueID(l, e._controlUniqueID)) | |
return this._autoFillControlWithValueWithSingleValueUpdate(e, t, ShouldFocus.Yes, ShouldBlur.Yes, o, r), void (n && n()); | |
this._clearFormField(e, ShouldBlur.No); | |
let a = () => { | |
this._controlContainsAllCharactersFromFilling(e.value, t) || this._autoFillControlWithValueWithSingleValueUpdate(e, t, ShouldFocus.Yes, ShouldBlur.Yes, o, r), n && n() | |
}; | |
this._autoFillControlWithValueCharacterByCharacter(e, t, o, r, ShouldAbandonCharacterByCharacterEntryIfTooSlow.Yes, a) | |
}, | |
_autoFillSelectWithOptionIndex : function(e, t, o) { | |
e.dispatchEvent(eventThatBubbles("mousedown")), e.dispatchEvent(new Event("focus")), e.selectedIndex !== t && (e.selectedIndex = t, e.dispatchEvent(eventThatBubbles("input")), e.dispatchEvent(eventThatBubbles("change"))), e.dispatchEvent(eventThatBubbles("mouseup")), e.dispatchEvent(eventThatBubbles("click")), e.dispatchEvent(new Event("blur")), FormMetadataJSController.setInputElementAutofilled(e, o) | |
}, | |
autoFillOneTimeCodeFieldsWithValue : function(e, t) { | |
let o = innermostActiveElement(); | |
if (!this._isAutoFillableTextField(o)) | |
return; | |
this._clearFormField(o); | |
let r = () => { | |
FormMetadataJSController.finishedAutoFillingOneTimeCode(e, t) | |
}, n = !0; | |
this._autoFillControlWithValueCharacterByCharacter(null, e, ShouldSetAutoFilled.Yes, ShouldObscure.No, ShouldAbandonCharacterByCharacterEntryIfTooSlow.No, r, n) | |
}, | |
_removeGeneratedPasswordForElement : function(e) { | |
let t = this._elementsWithGeneratedPasswords.indexOf(e); | |
-1 !== t && (this._elementsWithGeneratedPasswords.splice(t, 1), this._generatedPasswords.splice(t, 1)) | |
}, | |
_shouldSelectElementAfterFillingForm : function(e) { | |
if (!/(^|\.)etrade\.com/.test(document.location.hostname)) | |
return !0; | |
var t = this._cachedMetadataForLogicalForm(e); | |
return !t || t.AutoFillFormType !== WBSAutoFillFormTypeAutoFillableLogin | |
}, | |
autoFillControlsByID : function(e, t, o, r, n, i) { | |
let l = arguments[arguments.length - 1], | |
a = o ? ShouldSetAutoFilled.Yes : ShouldSetAutoFilled.No, | |
s = r; | |
if (s) { | |
let e = s.getAttribute("onfocus"); | |
e && e.length && /this\.value/.test(e) && (s = null) | |
} else | |
s = innermostActiveElement(); | |
var u = null; | |
for (let t in e) { | |
let e = this.formControlWithUniqueID(t)._logicalFormUniqueIDs; | |
for (let t of e) | |
u ||= this._logicalFormsCache.logicalFormWithUniqueID(t); | |
if (u) | |
break | |
} | |
var c = function() { | |
n ? innermostActiveElement().blur() : s && this._shouldSelectElementAfterFillingForm(u) && this.selectIfTextField(s), u?.backingElement && elementAppearsToContinueCaptchaWidget(u.backingElement) && (l = !1), FormMetadataJSController.finishedAutoFillingControlsInForm(this._getOrCreateCachedMetadataForLogicalForm(u), l) | |
}.bind(this); | |
if (t) { | |
var d = []; | |
for (var h in e) | |
e.hasOwnProperty(h) && d.push([ this.formControlWithUniqueID(h), e[h] ]); | |
this._synchronouslyAutoFillControls(d, a, c) | |
} else | |
this._asynchronouslyAutoFillControls(e, u, a, i, c) | |
}, | |
_synchronouslyAutoFillControls : function(e, t, o) { | |
for (var r = e.length, n = 0; n < r; ++n) { | |
var i = e[n][0], | |
l = e[n][1]; | |
this._autoFillControlWithValueRecursively(i, l, t) | |
} | |
o() | |
}, | |
_asynchronouslyAutoFillControls : function(e, t, o, r, n) { | |
var i = t.elements, | |
l = i.length, | |
a = function(t) { | |
if (t >= l) | |
return void n(); | |
var s = i[t], | |
u = e[s._controlUniqueID]; | |
let c = () => { | |
a(t + 1) | |
}; | |
if (void 0 !== u) { | |
let e = r.some((e => s._controlUniqueID.includes(e))) ? ShouldObscure.Yes : ShouldObscure.No; | |
this._autoFillControlWithValueRecursively(s, u, o, e, c) | |
} else | |
c() | |
}.bind(this); | |
a(0) | |
}, | |
_isInputAllowedInSearchForm : function(e, t) { | |
var o = this._getTagName(e).toLowerCase(); | |
if ("button" === o || "fieldset" === o) | |
return !0; | |
if ("select" === o) | |
return !t || isSelectInDefaultState(e); | |
if ("input" !== o && !this._textAreaElementLookLikeItIsPartOfASearchForm(e)) | |
return !1; | |
var r = e.type; | |
return "radio" === r || "checkbox" === r ? !t || isCheckboxOrRadioButtonInDefaultState(e) : "hidden" === r || "reset" === r || "submit" === r || "button" === r || "image" === r || this._isTextField(e) && !this._isSecureTextField(e) | |
}, | |
_isSearchForm : function(e, t) { | |
if ("get" !== e.method) | |
return !1; | |
for (var o = e.elements, r = o.length, n = 0; n < r; ++n) | |
if (!this._isInputAllowedInSearchForm(o[n], t)) | |
return !1; | |
return !0 | |
}, | |
_textAreaElementLookLikeItIsPartOfASearchForm : function(e) { | |
return !!this._isTextArea(e) && ("search" === e.getAttribute("type") || ("search" === e.inputMode || "search" === e.getAttribute("enterkeyhint"))) | |
}, | |
_shouldInputBeIncludedInSearchURLQuery : function(e) { | |
if (e.disabled) | |
return !1; | |
if (!e.name.length) | |
return !1; | |
if (!e.value.length) | |
return !1; | |
if (this._isSelectElement(e)) | |
return !0; | |
var t = this._getTagName(e).toLowerCase(), | |
o = e.type; | |
return "button" === t ? "submit" === o : "input" === t && ("submit" === o || ("checkbox" === o || "radio" === o ? e.checked : "hidden" === o || this._isTextField(e))) | |
}, | |
_isSubmitButton : function(e) { | |
return (e instanceof HTMLButtonElement || e instanceof HTMLInputElement) && (e.type && "submit" === e.type) | |
}, | |
_isCustomFormButton : function(e) { | |
return "button" === e.type && (e instanceof HTMLButtonElement || e instanceof HTMLInputElement) | |
}, | |
_isCheckboxInputElement : function(e) { | |
return "checkbox" === e.type && e instanceof HTMLInputElement | |
}, | |
_setQueryString : function(e, t) { | |
var o = document.createElement("a"); | |
return o.href = e, o.search = t, o.href | |
}, | |
searchTextFieldFormSubmissionURLString : function(e, t) { | |
if (visibilityCacheGeneration++, !this._isTextField(e) || this._isSecureTextField(e) || !e.isVisible()) | |
return null; | |
var o = e.form; | |
if (!o) | |
return null; | |
var r = o.getAttribute("action"); | |
if (!r || !r.length) | |
return null; | |
if (!/^https?:/i.test(o.action)) | |
return null; | |
if (!this._isSearchForm(o, t)) | |
return null; | |
for (var n = null, i = "", l = o.elements, a = l.length, s = 0; s < a; ++s) { | |
var u = l[s]; | |
if ((u === e || this._shouldInputBeIncludedInSearchURLQuery(u)) && (!this._isSubmitButton(u) || (n || (n = u), u === n))) { | |
i.length && (i += "&"); | |
var c = u === e ? "{searchTerms}" : urlEncode(u.value); | |
i += urlEncode(u.name) + "=" + c | |
} | |
} | |
return this._setQueryString(o.action, i) | |
} | |
}; | |
var FormMetadataJS = new FormMetadata; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Grant Permissions for Web Extension?</title> | |
<style> | |
@media (prefers-color-scheme: dark) { | |
:root { | |
color-scheme: dark !important; | |
} | |
body { | |
background: rgb(30, 30, 30) !important; | |
--font-color: hsl(0, 0%, 85%) !important; | |
--title-color: rgb(224, 225, 225) !important; | |
} | |
.alert-container { | |
background-color: rgb(56, 57, 59) !important; | |
box-shadow: 0 6px 12px rgba(0, 0, 0, .24) !important; | |
} | |
} | |
body { | |
--font-color: #434343; | |
--horizontal-padding: 32px; | |
--border-radius: 6px; | |
--title-color: #444; | |
} | |
* { | |
padding: 0; | |
margin: 0; | |
font-family: -apple-system-font; | |
} | |
:root { | |
color-scheme: light; | |
} | |
html, body { | |
height: 100%; | |
width: 100%; | |
} | |
body { | |
font-size: 13px; | |
background: linear-gradient(30deg, #dfdfdf 0%, #fafafb 100%); | |
background-repeat: no-repeat; | |
background-attachment: fixed; | |
cursor: default; | |
-webkit-user-select: none; | |
overflow: hidden; | |
} | |
.vertical-flex-container { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
flex-direction: column; | |
flex-wrap: nowrap; | |
align-content: stretch; | |
padding-top: 156px; | |
} | |
@media (max-height: 30rem) { | |
.vertical-flex-container { | |
padding-top: min(calc(60vh - 150px), 156px); | |
} | |
} | |
.alert-container { | |
background-color: white; | |
min-width: 320px; | |
max-width: 672px; | |
position: relative; | |
margin: 0 auto; | |
padding-top: 24px; | |
border-radius: var(--border-radius); | |
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.14); | |
} | |
.alert-container h1 { | |
overflow: hidden; | |
color: var(--title-color); | |
padding-top: 3px; | |
} | |
.alert-body { | |
display: block; | |
margin: 21px 0 0 0; | |
padding-left: var(--horizontal-padding); | |
padding-right: var(--horizontal-padding); | |
padding-bottom: 28px; | |
color: var(--font-color); | |
} | |
.alert-body p:first-of-type { | |
margin-bottom: 15px; | |
margin-top: 20px; | |
} | |
.alert-body p:last-of-type { | |
margin-bottom: 0; | |
} | |
.button-bar { | |
display: flex; | |
justify-content: center; | |
align-items: center; | |
flex-direction: row; | |
flex-wrap: wrap; | |
align-content: stretch; | |
margin-top: 1.3em; | |
} | |
.button-bar button { | |
font-size: 13px; | |
line-height: 21px; | |
min-width: 90px; | |
margin: 4px; | |
vertical-align: bottom; | |
padding: 0 12px; | |
color: var(--font-color); | |
cursor: pointer; | |
} | |
.hidden { | |
display: none; | |
} | |
a { | |
color: inherit; | |
text-decoration: underline; | |
cursor: pointer; | |
} | |
h1 { | |
font-size: 1.5em; | |
font-weight: 700; | |
line-height: 30px; | |
padding: 0 var(--horizontal-padding); | |
margin-bottom: 1em; | |
} | |
p { | |
font-size: 14px; | |
line-height: 19px; | |
margin-bottom: 1em; | |
word-wrap: break-word; | |
} | |
</style> | |
<script> | |
// Note: these values are synonymous with the values of enum class Inspector::ExtensionError. | |
WI = { | |
WebInspectorExtension: { | |
ErrorCode: { | |
ContextDestroyed: "ContextDestroyed", | |
InternalError: "InternalError", | |
InvalidRequest: "InvalidRequest", | |
RegistrationFailed: "RegistrationFailed", | |
NotImplemented: "NotImplemented", | |
} | |
} | |
}; | |
function addButtonEventListener(elementID, callback) | |
{ | |
let button = document.getElementById(elementID); | |
if (!button) | |
return false; | |
button.addEventListener("click", callback); | |
return true; | |
} | |
// Note: this is expected to return a promise that fulfills when | |
// one of the buttons is clicked. The promise will be rejected if | |
// there are no buttons specified, and also just before the main | |
// frame navigates. | |
async function waitForPolicyDecision() | |
{ | |
if (window._waitForPolicyDecisionPromiseData) | |
return window._waitForPolicyDecisionPromiseData.promise; | |
window._waitForPolicyDecisionPromiseData = {}; | |
window._waitForPolicyDecisionPromiseData.promise = new Promise((resolve, reject) => { | |
window._waitForPolicyDecisionPromiseData.resolve = resolve; | |
window._waitForPolicyDecisionPromiseData.reject = reject; | |
}); | |
let buttonNames = ["policy-1", "policy-2", "policy-3"]; | |
let addedButtonsCount = buttonNames.filter((id) => addButtonEventListener(id, handlePolicyDecision)).length; | |
if (!addedButtonsCount) | |
window._waitForPolicyDecisionPromiseData.reject?.(WI.WebInspectorExtension.ErrorCode.InvalidRequest); | |
window.addEventListener("pagehide", () => { | |
window._waitForPolicyDecisionPromiseData.reject?.(WI.WebInspectorExtension.ErrorCode.ContextDestroyed); | |
}); | |
return window._waitForPolicyDecisionPromiseData.promise; | |
} | |
function handlePolicyDecision(event) | |
{ | |
if (!window._waitForPolicyDecisionPromiseData) | |
return; | |
// On the first button click, pull out the resolve and reject callbacks. | |
let {resolve, reject, promise} = window._waitForPolicyDecisionPromiseData; | |
if (!resolve || !reject) | |
return; | |
window._waitForPolicyDecisionPromiseData = { promise }; | |
// One of 'policy-1', 'policy-2', 'policy-3'. | |
resolve(event.target.id); | |
} | |
function receivePayload(payload) | |
{ | |
for (let placeholderID of ['titleText', 'descriptionText', 'policy-1', 'policy-2', 'policy-3']) { | |
let placeholderElement = document.getElementById(placeholderID); | |
if (!placeholderElement) { | |
console.error("Couldn't find placeholder element for placeholderID: " + placeholderID); | |
continue; | |
} | |
let payloadValue = payload[placeholderID]; | |
placeholderElement.textContent = payloadValue ?? "LOCALIZED STRING NOT FOUND"; | |
placeholderElement.classList.toggle("hidden", !payloadValue); | |
} | |
let anyButtonIsVisible = payload['policy-1'] || payload['policy-2'] || payload['policy-3']; | |
let bottomBarElement = document.getElementsByClassName('button-bar')[0]; | |
bottomBarElement.classList.toggle("hidden", !anyButtonIsVisible); | |
} | |
</script> | |
</head> | |
<body> | |
<div class="vertical-flex-container"> | |
<div id="alert-container" class="alert-container"> | |
<h1 id="titleText">An extension would like to access this website</h1> | |
</h1> | |
<div class="alert-body"> | |
<p id="descriptionText">The extension would be able to read and alter webpages and see your browsing history on this website. This could include sensitive information, including passwords, phone numbers, and credit cards.</p> | |
<div class="button-bar"> | |
<button type="button" id="policy-1">Allow for One Day</button> | |
<button type="button" id="policy-2">Always Allow on This Website</button> | |
<button type="button" id="policy-3">Always Allow on Every Website...</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Grant Permissions for Web Extension?</title> | |
<style> | |
@media (prefers-color-scheme: dark) { | |
:root { | |
color-scheme: dark; | |
} | |
body { | |
background: rgb(30, 30, 30) !important; | |
--font-color: hsl(0, 0%, 85%) !important; | |
--title-color: rgb(224, 225, 225) !important; | |
} | |
.alert { | |
background-color: rgb(56, 57, 59) !important; | |
box-shadow: 0 6px 12px rgba(0, 0, 0, .24) !important; | |
} | |
} | |
body { | |
--font-color: #434343; | |
--horizontal-padding: 32px; | |
--border-radius: 6px; | |
--title-color: #444; | |
} | |
* { | |
padding: 0; | |
margin: 0; | |
font-family: -apple-system-font; | |
} | |
:root { | |
color-scheme: light; | |
} | |
html, body { | |
height: 100%; | |
width: 100%; | |
} | |
body { | |
font-size: 13px; | |
background: linear-gradient(30deg, #dfdfdf 0%, #fafafb 100%); | |
background-repeat: no-repeat; | |
background-attachment: fixed; | |
cursor: default; | |
-webkit-user-select: none; | |
} | |
.alert { | |
background-color: white; | |
min-width: 320px; | |
max-width: 672px; | |
position: relative; | |
margin: 0 auto; | |
padding-top: 24px; | |
border-radius: var(--border-radius); | |
box-shadow: 0px 6px 10px rgba(0, 0, 0, 0.14); | |
} | |
.alert h1 { | |
overflow: hidden; | |
color: var(--title-color); | |
padding-top: 3px; | |
} | |
.alert-body { | |
margin: 21px 0 0 0; | |
padding-left: var(--horizontal-padding); | |
padding-right: var(--horizontal-padding); | |
padding-bottom: 28px; | |
color: var(--font-color); | |
} | |
.alert-body p:first-of-type { | |
margin-bottom: 15px; | |
margin-top: 20px; | |
} | |
.alert-body p:last-of-type { | |
margin-bottom: 0; | |
} | |
.bottom-bar { | |
margin-top: 1.3em; | |
height: 22px; | |
} | |
.bottom-bar button { | |
font-size: 13px; | |
line-height: 21px; | |
min-width: 90px; | |
margin: 0 4px; | |
vertical-align: bottom; | |
padding: 0 12px; | |
color: var(--font-color); | |
cursor: pointer; | |
} | |
a { | |
color: inherit; | |
text-decoration: underline; | |
cursor: pointer; | |
} | |
h1 { | |
font-size: 1.5em; | |
font-weight: 700; | |
line-height: 30px; | |
padding: 0 var(--horizontal-padding); | |
margin-bottom: 1em; | |
} | |
p { | |
font-size: 14px; | |
line-height: 19px; | |
margin-bottom: 1em; | |
word-wrap: break-word; | |
} | |
.hidden { | |
display: none; | |
} | |
/* RTL support */ | |
html[dir="rtl"] .bottom-bar button { | |
float: right; | |
} | |
</style> | |
<script> | |
// Note: this is expected to return a promise that fulfills when | |
// one of the buttons is clicked. | |
async function waitForPolicyDecision() | |
{ | |
if (window._waitForPolicyDecisionPromiseData) | |
return window._waitForPolicyDecisionPromiseData.promise; | |
window._waitForPolicyDecisionPromiseData = {}; | |
window._waitForPolicyDecisionPromiseData.promise = new Promise((resolve, reject) => { | |
window._waitForPolicyDecisionPromiseData.resolve = resolve; | |
window._waitForPolicyDecisionPromiseData.reject = reject; | |
}); | |
["policy-1", "policy-2", "policy-3"].forEach((id) => { addButtonEventListener(id, handlePolicyDecision); }); | |
return window._waitForPolicyDecisionPromiseData.promise; | |
} | |
function receivePayload(payload) | |
{ | |
for (let placeholderID of ['titleText', 'descriptionText', 'policy-1', 'policy-2', 'policy-3']) { | |
let placeholderElement = document.getElementById(placeholderID); | |
if (!placeholderElement) { | |
console.error("Couldn't find placeholder element for placeholderID: " + placeholderID); | |
continue; | |
} | |
let payloadValue = payload[placeholderID]; | |
placeholderElement.textContent = payloadValue ?? "LOCALIZED STRING NOT FOUND"; | |
placeholderElement.classList.toggle("hidden", !payloadValue); | |
} | |
let anyButtonIsVisible = payload['policy-1'] || payload['policy-2'] || payload['policy-3']; | |
let bottomBarElement = document.getElementsByClassName('bottom-bar')[0]; | |
bottomBarElement.classList.toggle("hidden", !anyButtonIsVisible); | |
} | |
function addButtonEventListener(elementID, callback) | |
{ | |
let button = document.getElementById(elementID); | |
if (!button) | |
return; | |
button.addEventListener("click", callback); | |
} | |
function handlePolicyDecision(event) | |
{ | |
if (!window._waitForPolicyDecisionPromiseData) | |
return; | |
// On the first button click, pull out the resolve and reject callbacks. | |
let {resolve, reject, promise} = window._waitForPolicyDecisionPromiseData; | |
if (!resolve || !reject) | |
return; | |
window._waitForPolicyDecisionPromiseData = { promise }; | |
// One of 'policy-1', 'policy-2', 'policy-3'. | |
resolve(event.target.id); | |
} | |
function pageLoaded() | |
{ | |
window.addEventListener("resize", performLayout); | |
performLayout(); | |
} | |
function performLayout() | |
{ | |
const minimumMarginTop = 22; | |
const maximumMarginTop = 156; | |
let alertElement = document.getElementById("alert"); | |
let alertElementHeight = alertElement.getBoundingClientRect().height; | |
let viewportHeight = window.innerHeight; | |
if (viewportHeight > alertElementHeight + 2 * maximumMarginTop) | |
alertElement.style.top = maximumMarginTop + "px"; | |
else | |
alertElement.style.top = Math.max(minimumMarginTop, (viewportHeight - alertElementHeight) / 2) + "px"; | |
} | |
window.addEventListener("load", () => { pageLoaded(); }); | |
</script> | |
</head> | |
<body> | |
<div id="alert" class="alert"> | |
<h1 id="titleText">An extension would like to access this website</h1> | |
</h1> | |
<div class="alert-body"> | |
<p id="descriptionText">The extension would be able to read and alter webpages and see your browsing history on this website. This could include sensitive information, including passwords, phone numbers, and credit cards.</p> | |
<div class="bottom-bar"> | |
<button type="button" id="policy-1">Allow for One Day</button> | |
<button type="button" id="policy-2">Always Allow on This Website</button> | |
<button type="button" id="policy-3">Always Allow on Every Website...</button> | |
</div> | |
</div> | |
</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// OpenSearch description document can be specified via the <link> tag with rel="search". | |
// See http://blog.whatwg.org/the-road-to-html-5-link-relations#rel-search. | |
// It should have the type "application/opensearchdescription+xml". | |
// See https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md#mime-type-applicationopensearchdescriptionxml. | |
(function() { | |
if (!document.head) | |
return null; | |
var linkTags = document.head.getElementsByTagName("link"); | |
var numberOfLinkTags = linkTags.length; | |
for (var i = 0; i < numberOfLinkTags; ++i) { | |
var linkTag = linkTags[i]; | |
if (linkTag.getAttribute("rel") === "search" && linkTag.getAttribute("type") === "application/opensearchdescription+xml") | |
return linkTag.href; | |
} | |
return null; | |
})(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name="disabled-adaptations" content="watch"> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
<meta name="viewport" content="initial-scale=1"> | |
<base> | |
<title>Reader</title> | |
<style id="article-content"> | |
h1, h2, h3, h4, h5, h6 { | |
font-weight: bold; | |
} | |
h1 { | |
font-size: 1.5em; | |
line-height: 1.4em; | |
} | |
h2 { | |
font-size: 1.43em; | |
} | |
h3 { | |
font-size: 1.25em; | |
} | |
h4, h5, h6 { | |
font-size: 1em; | |
margin: 1em 0; | |
} | |
body.watch h1 { | |
font-size: 1.1875rem; | |
} | |
body.watch h2 { | |
font-size: 1.125rem; | |
} | |
body.watch h3 { | |
font-size: 1.0625rem; | |
} | |
body.watch :matches(h4, h5, h6) { | |
font-size: 1rem; | |
} | |
h1.title { | |
font-weight: bold; | |
font-size: 1.95552em; | |
line-height: 1.2141em; | |
margin-top: 0; | |
margin-bottom: 0.5em; | |
} | |
.subhead { | |
font-weight: normal; | |
} | |
.title, .subhead, .metadata { | |
text-align: start; | |
hyphens: manual; | |
display: none; | |
} | |
:nth-child(1 of .page) :matches(.title, .subhead, .metadata) { | |
display: block; | |
} | |
.subhead { | |
color: rgba(27, 27, 27, 0.65); | |
font-size: 1.46664em; | |
margin-top: -0.35em; | |
line-height: 1.27275em; | |
} | |
.metadata { | |
margin-top: -0.75em; | |
margin-bottom: 1.45em; | |
} | |
body.watch .metadata { | |
line-height: 1.3em; | |
} | |
.metadata * { | |
font-size: 1em !important; | |
font-weight: normal !important; | |
font-style: normal !important; | |
display: inline !important; | |
margin: 0; | |
} | |
.metadata :matches(.byline, .date) { | |
display: inline !important; | |
} | |
.metadata :matches(ul, ol, li) { | |
list-style-type: none; | |
-webkit-padding-start: 0; | |
} | |
.title + .metadata { | |
margin-top: -0.75em; | |
} | |
.subhead + .metadata { | |
margin-top: -0.7em; | |
} | |
.page { | |
text-align: start; | |
word-wrap: break-word; | |
} | |
body.watch .page { | |
hyphens: auto; | |
} | |
.page.rtl { | |
direction: rtl; | |
} | |
a { | |
text-decoration: none; | |
} | |
a[href] { | |
color: rgb(65, 110, 210); | |
} | |
#article { | |
text-rendering: optimizeLegibility; | |
} | |
#article * { | |
/* Scale down anything larger than our view. Max-width maintains aspect ratios on images. */ | |
max-width: 100%; | |
} | |
#article img { | |
/* By default, images are centered on their own line. */ | |
margin: 0.5em auto; | |
display: block; | |
height: auto; | |
} | |
#article img.reader-image-tiny { | |
display: inline; | |
margin: 0; | |
} | |
#article .leading-image, figure, .auxiliary { | |
margin-bottom: 1.15em; | |
} | |
#article .leading-image img { | |
margin: auto; | |
display: block; | |
clear: both; | |
} | |
#article .leading-image .credit { | |
margin: 0; | |
} | |
#article .leading-image, | |
#article figure { | |
font-size: 0.75em; | |
line-height: 1.5em; | |
} | |
body.watch #article .leading-image, | |
body.watch #article figure { | |
font-size: 0.8125rem; | |
} | |
#article .leading-image :matches(.caption, .credit), | |
#article figcaption { | |
margin-top: 0.8em; | |
width: 100%; | |
} | |
body.watch #article .leading-image :matches(.caption, .credit), | |
body.watch #article figcaption { | |
margin-top: 4px; | |
} | |
body.watch #article figure img { | |
margin-bottom: 0; | |
} | |
#article figcaption > * { | |
margin-top: 0.25em; | |
margin-bottom: 0.25em; | |
} | |
#article :matches(.leading-image, figure) p { | |
margin-top: 0.4em; | |
margin-bottom: 0.4em; | |
} | |
#article .leading-image .credit + .caption { | |
margin-top: 0.1em; | |
} | |
#article .auxiliary { | |
display: block; | |
clear: both; | |
font-size: 0.75em; | |
line-height: 1.4em; | |
text-align: start; | |
} | |
body.watch #article .auxiliary { | |
font-size: 0.9em; | |
} | |
#article .pullquote { | |
font-size: 1.42em; | |
line-height: 1.38em; | |
font-weight: 300; | |
font-style: italic; | |
} | |
#article .pullquote:not(.float) { | |
margin-top: 1em; | |
margin-bottom: 1em; | |
-webkit-margin-start: 1em; | |
max-width: calc(100% - 1em); | |
} | |
#article .auxiliary > *:not(img) { | |
-webkit-margin-start: 0; | |
} | |
#article .auxiliary.float img, #article .auxiliary > *:first-child:not(img) { | |
margin: 0; | |
} | |
/* If the element immediately after an image is inline, it might bump up against the image. */ | |
#article .auxiliary img + * { | |
display: block; | |
} | |
#article .auxiliary figcaption { | |
font-size: 100%; | |
} | |
#article .auxiliary * { | |
margin-top: 0.5em; | |
margin-bottom: 0.5em; | |
} | |
body:not(.watch) #article .float.left { | |
float: left; | |
margin-right: 20px; | |
} | |
body:not(.watch) #article .float.right { | |
float: right; | |
margin-left: 20px; | |
} | |
body.watch #article .float { | |
width: auto !important; | |
} | |
#article .clear { | |
clear: both; | |
} | |
#article ul.list-style-type-none, | |
#article ol.list-style-type-none, | |
#article .list-style-type-none > li { | |
list-style-type: none; | |
-webkit-padding-start: 0; | |
} | |
#article .page .list-style-type-none.code-block code { | |
white-space: pre-wrap; | |
} | |
#article .page div.scrollable { | |
overflow-x: scroll; | |
word-wrap: normal; | |
} | |
#article .page div.scrollable table { | |
max-width: none; | |
} | |
#article .leading-image, #article figure, #article .auxiliary:not(.pullquote) { | |
font-family: -apple-system-font; | |
} | |
#article .leading-image, #article figure, #article .auxiliary, #article .pullquote { | |
color: rgba(0, 0, 0, 0.65); | |
} | |
figure { | |
margin: 0; | |
} | |
body:not(.watch) figure:not(.float) { | |
margin-top: 1.4em; | |
margin-bottom: 1.4em; | |
} | |
hr { | |
background: rgba(0, 0, 0, 0.2); | |
height: 1px; | |
border: 0; | |
} | |
pre { | |
font-family: -apple-system-ui-monospaced, Menlo; | |
font-size: 0.87em; | |
line-height: 1.45em; | |
} | |
blockquote, q { | |
color: rgba(0, 0, 0, 0.65); | |
} | |
blockquote:not(.pullquote) { | |
margin-left: 2px; | |
margin-right: 6px; | |
padding-left: 16px; | |
} | |
blockquote:not(.simple):not(.pullquote) { | |
border-left: 3px solid rgba(0, 0, 0, 0.1); | |
} | |
q.pullquote { | |
display: block; | |
} | |
.pullquote q::before, .pullquote q::after, q.pullquote::before, q.pullquote::after { | |
content: ""; | |
} | |
/* Collapse excess whitespace. */ | |
.page p > p:empty, | |
.page div > p:empty, | |
.page p > div:empty, | |
.page div > div:empty, | |
.page p + br, | |
.page img + br | |
{ | |
display: none; | |
} | |
.page table { | |
font-size: 0.9em; | |
text-align: start; | |
word-wrap: break-word; | |
border-collapse: collapse; | |
} | |
.page table td, .page table th { | |
padding: 0.25em 0.5em; | |
border: 1px solid rgb(216, 216, 216); | |
} | |
body.watch .page > * { | |
margin-left: 0; | |
margin-right: 0; | |
} | |
body.watch .page ol { | |
padding: 0 0 0 35px; | |
} | |
body.watch .page ul { | |
padding: 0 0 0 20px; | |
} | |
body.watch .page li { | |
margin: 0.8em 0; | |
} | |
body.watch .page blockquote { | |
padding: 0 0 0 8px; | |
} | |
.delimiter { | |
margin-left: 0.45em; | |
margin-right: 0.45em; | |
margin-top: 0.07em; | |
padding: 0; | |
} | |
.metadata.singleline .delimiter::after { | |
content: "•"; | |
} | |
.metadata:not(.singleline) .delimiter { | |
content: ""; | |
display: block !important; | |
} | |
.page table th { | |
background-color: rgba(0, 0, 0, 0.025); | |
} | |
.page sup, .page sub { | |
line-height: 1; | |
font-size: 0.75em; | |
} | |
.hidden { | |
display: none; | |
} | |
/* Special Font Customizations */ | |
.system { font-family: -apple-system-font; } | |
.watch.system { font: -apple-system-body; } | |
.yuantisc { | |
letter-spacing: 1px; | |
} | |
.yuantitc { | |
letter-spacing: 1px; | |
} | |
/* Printing and mailing. */ | |
#article.exported { | |
font-size: 1.2em; | |
} | |
.exported { | |
line-height: 1.5em; | |
} | |
.exported a[href] { | |
text-decoration: underline; | |
} | |
#article.exported { | |
margin: 0; | |
padding: 0; | |
} | |
.exported .float { | |
float: none; | |
margin-top: 1.4em; | |
margin-bottom: 1.4em; | |
} | |
#article.exported .leading-image, | |
#article.exported figcaption { | |
font-size: 0.75rem; | |
color: rgba(0, 0, 0, 0.8); | |
} | |
.exported .delimiter::after { | |
content: ""; | |
} | |
</style> | |
<style id="print"> | |
@media print { | |
body { | |
margin: 2mm 9mm; | |
} | |
.original-url { | |
display: none; | |
} | |
#article .float.left { | |
float: left !important; | |
} | |
#article .float.right { | |
float: right !important; | |
} | |
#article .float { | |
margin-top: 0 !important; | |
margin-bottom: 0 !important; | |
} | |
} | |
</style> | |
<style id="reader-ui"> | |
@media screen { | |
body { | |
margin: 0; | |
padding: 0; | |
-webkit-user-select: none; | |
overflow-x: hidden; | |
-webkit-text-size-adjust: none; | |
} | |
body.mac { | |
background-color: transparent; | |
} | |
#article { | |
pointer-events: auto; | |
-webkit-user-select: auto; | |
overflow: visible; | |
margin-bottom: 42vh !important; | |
} | |
#article:focus { | |
outline: none; | |
} | |
.page-number { | |
display: block; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) .page-number { | |
display: none; | |
} | |
body.watch #article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 0.15em; | |
} | |
.page-number, #incoming-page-corner { | |
font-weight: bold; | |
position: absolute; | |
-webkit-user-select: none; | |
font: 12px "Helvetica Neue"; | |
color: rgb(168, 168, 168); | |
cursor: default; | |
} | |
body.watch :matches(.page-number, #incoming-page-corner) { | |
top: 8px; | |
right: 16px; | |
} | |
.page { | |
margin-left: auto; | |
margin-right: auto; | |
padding-top: 35px; | |
padding-bottom: 35px; | |
position: relative; | |
border-top: 1px solid rgba(0, 0, 0, 0.2); | |
} | |
body.watch .page { | |
padding: 0 4px; | |
} | |
#article :nth-child(1 of .page) { | |
margin-top: 0; | |
border-top: none; | |
padding-top: 32px; | |
} | |
.page:last-of-type { | |
padding-bottom: 45px; | |
} | |
.page video { | |
height: auto; | |
position: relative; | |
} | |
#incoming-page-placeholder { | |
height: 30px; | |
margin-bottom: 0; | |
} | |
#incoming-page-corner { | |
position: absolute; | |
right: 10px; | |
top: 8px; | |
} | |
#incoming-page-text { | |
float: right; | |
-webkit-user-select: none; | |
} | |
#next-page-container { | |
position:absolute; | |
/* Workaround for <rdar://problem/8662842> iOS Reader: loading multiple pages stops at the 2nd page. */ | |
left: -1000px; | |
/* The iframe needs to be wider than the width threshold value for Reader detection, see <rdar://problem/9599297>. */ | |
width: 320px; | |
height: 0px; | |
} | |
.page div.scrollable { | |
-webkit-overflow-scrolling: touch; | |
} | |
} | |
@media screen and (-webkit-min-device-pixel-ratio:2) { | |
.page { | |
border-top-width: 0.5px; | |
} | |
hr { | |
height: 0.5px; | |
} | |
} | |
#article .extendsBeyondTextColumn { | |
max-width: none; | |
} | |
.iframe-wrapper { | |
background-color: black; | |
max-width: none; | |
text-align: center; | |
} | |
iframe { | |
border: 0; | |
} | |
@media screen and (min-width: 0px) { | |
/* Includes iPhone 5 in portrait */ | |
.page { padding-left: 16px; padding-right: 16px; } | |
.page-number, #incoming-page-corner { | |
top: 8px; | |
right: 16px; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 14px; | |
} | |
} | |
@media screen and (min-width: 161px) { | |
/* Apple Watch 40mm */ | |
body.watch .page { | |
padding: 0 8.5px; | |
} | |
} | |
@media screen and (min-width: 183px) { | |
/* Apple Watch 44mm */ | |
body.watch .page { | |
padding: 0 9.5px; | |
} | |
} | |
@media screen and (min-width: 375px) { | |
/* iPhone 6 in portrait */ | |
.page { padding-left: 18px; padding-right: 18px; } | |
.page-number, #incoming-page-corner { | |
top: 6px; | |
right: 18px; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 16px; | |
} | |
} | |
@media screen and (min-width: 414px) { | |
/* iPhone 6 Plus in portrait */ | |
.page { padding-left: 20px; padding-right: 20px; } | |
.page-number, #incoming-page-corner { | |
top: 6px; | |
right: 20px; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 18px; | |
} | |
} | |
/* iPhone 5 in landscape (568px) */ | |
@media screen and (min-width: 667px) { | |
/* iPhone 6 in landscape */ | |
.page { padding-left: 40px; padding-right: 40px; } | |
.page-number, #incoming-page-corner { | |
/* Stop lining this text up with .page's right margin. */ | |
top: 10px; | |
right: 10px; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 26px; | |
} | |
} | |
@media screen and (max-width: 569px) { | |
/* iPhone 5 in landscape (568px) and smaller, including all iPhones in portrait */ | |
h1.title { | |
font-size: 1.5558em; | |
} | |
h1 { | |
font-size: 1.4em; | |
} | |
h2 { | |
font-size: 1.2777em; | |
} | |
h3 { | |
font-size: 1.15em; | |
} | |
.subhead { | |
font-size: 1.2222em; | |
} | |
.metadata { | |
font-size: 0.9em; | |
line-height: 1.6em; | |
} | |
.title + .metadata { | |
margin-top: -0.65em; | |
} | |
} | |
@media screen and (min-width: 704px) { | |
/* iPad in landscape with the sidebar open */ | |
.page { padding-left: 42px; padding-right: 42px; } | |
} | |
@media screen and (min-width: 736px) { | |
/* iPhone 6 Plus in landscape */ | |
.page { padding-left: 60px; padding-right: 60px; } | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 46px; | |
} | |
} | |
@media only screen and (min-width: 780px) { | |
#article { | |
max-width: 800px; | |
margin: 0 auto; | |
} | |
/* Readable margins. */ | |
body.system #article { max-width: 83.2ex; } | |
body.athelas #article { max-width: 104ex; } | |
body.charter #article { max-width: 86ex; } | |
body.georgia #article { max-width: 94ex; } | |
body.iowanoldstyle #article { max-width: 90ex; } | |
body.palatino #article { max-width: 97ex; } | |
body.seravek #article { max-width: 87ex; } | |
body.timesnewroman #article { max-width: 97ex; } | |
body.uiserif #article { max-width: 93ex; } | |
:matches(body.pingfangsc, body.pingfangtc) #article { max-width: 87.6ex; } | |
:matches(body.heitisc, body.heititc) #article { max-width: 74.8ex; } | |
:matches(body.songtisc, body.songtitc) #article { max-width: 102ex; } | |
:matches(body.kaitisc, body.kaititc) #article { max-width: 102ex; } | |
:matches(body.yuantisc, body.yuantitc) #article { max-width: 86.2ex; } | |
:matches(body.libiansc, body.libiantc) #article { max-width: 95ex; } | |
:matches(body.weibeisc, body.weibeitc) #article { max-width: 99ex; } | |
:matches(body.yuppysc, body.yuppytc) #article { max-width: 87.6ex; } | |
body.hiraginosansw3 #article { max-width: 75.7ex; } | |
body.hiraginokakugothicpron #article { max-width: 76.4ex; } | |
body.hiraginominchopron #article { max-width: 77.5ex; } | |
body.hiraginomarugothicpron #article { max-width: 75.1ex; } | |
body.applesdgothicneo #article { max-width: 82ex; } | |
body.nanumgothic #article { max-width: 88.6ex; } | |
body.nanummyeongjo #article { max-width: 94.1ex; } | |
.page { | |
/* We don't want the lines seperating pages to extend beyond the primary text column. */ | |
padding-left: 0px; | |
padding-right: 0px; | |
margin-left: 70px; | |
margin-right: 70px; | |
} | |
} | |
#article { | |
-webkit-font-smoothing: subpixel-antialiased; | |
} | |
/* Reader's paper appearance. */ | |
html.paper { | |
height: 100%; | |
} | |
html.paper body { | |
height: calc(100% - 44px); | |
} | |
html.paper body:after { | |
content: ""; | |
height: 22px; | |
display: block; | |
} | |
/* Clearfix */ | |
html.paper .page::after { | |
content: ""; | |
display: table; | |
clear: both; | |
} | |
html.paper #article { | |
min-height: 100%; | |
margin: 22px auto 0 auto; | |
} | |
html.paper #article :nth-child(1 of .page), html.paper #article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 53px; | |
} | |
html.paper #article .page-number, html.paper #article #incoming-page-corner { | |
/* Stop lining this text up with .page's right margin. */ | |
top: 14px; | |
right: 0px; | |
} | |
/* End Reader's paper appearance. */ | |
/* Use slightly smaller page padding when vertically constrained. */ | |
@media screen and (max-height: 700px) { | |
.page { | |
padding-top: 32px; | |
padding-bottom: 32px; | |
} | |
} | |
</style> | |
<style id="theming"> | |
body.white { | |
--body-font-color: rgb(27, 27, 27); | |
--horizontal-line-color: rgb(220, 220, 220); | |
--paper-shadow-color: rgba(0, 0, 0, 0.2); | |
} | |
body.sepia { | |
--body-font-color: rgb(79, 50, 28); | |
--horizontal-line-color: rgb(230, 218, 201); | |
--paper-shadow-color: rgba(0, 0, 0, 0.2); | |
} | |
body.gray { | |
--body-font-color: rgba(255, 255, 255, 0.78); | |
--horizontal-line-color: rgb(111, 111, 111); | |
} | |
body.night { | |
--body-font-color: rgb(176, 176, 176); | |
--horizontal-line-color: rgb(62, 62, 62); | |
} | |
body.night.oled { | |
--body-font-color: rgb(210, 210, 210); | |
--horizontal-line-color: rgba(210, 210, 210, 0.35); | |
} | |
body.watch.night.oled { | |
--body-font-color: rgb(174, 180, 191); | |
} | |
html:not(.paper) body.white, body.white #article { | |
background-color: white; | |
} | |
html:not(.paper) body.sepia, body.sepia #article { | |
background-color: rgb(248, 241, 227); | |
} | |
html:not(.paper) body.gray, body.gray #article { | |
background-color: rgb(74, 74, 77); | |
} | |
html:not(.paper) body.night, body.night #article { | |
background-color: rgb(18, 18, 18); | |
} | |
html:not(.paper) body.night.oled, body.night.oled #article { | |
background-color: black; | |
} | |
/* OS X Reader draws backdrop background colors outside of web content, so the follow set only applies to iOS. */ | |
html.paper body.ios.white { | |
background-color: rgb(230, 230, 230); | |
} | |
html.paper body.ios.sepia { | |
background-color: rgb(224, 216, 200); | |
} | |
html.paper body.ios.gray { | |
background-color: rgb(50, 50, 51); | |
} | |
html.paper body.ios.night { | |
background-color: black; | |
} | |
body.watch.night .metadata * { | |
color: rgb(214, 217, 223) !important; | |
} | |
html.paper body.white #article, html.paper body.sepia #article { | |
box-shadow: 0px 6px 12px 3px var(--paper-shadow-color); | |
} | |
html.paper body.gray #article { | |
box-shadow: 0px 6px 12px 3px rgba(0, 0, 0, 0.24); | |
} | |
html.paper body.night #article { | |
outline: 1px solid #272727; | |
} | |
body.watch.night.oled :matches(h1, h2, h3, h4, h5, h6) { | |
color: white; | |
} | |
body.sepia #article :matches(.leading-image, figure, .auxiliary, .pullquote) { | |
color: rgba(79, 50, 28, 0.9); | |
} | |
body.gray #article :matches(.leading-image, figure, .auxiliary, .pullquote) { | |
color: rgba(255, 255, 255, 0.7); | |
} | |
body.night #article :matches(.leading-image, figure, .auxiliary, .pullquote) { | |
color: rgba(255, 255, 255, 0.67); | |
} | |
body.night.oled #article :matches(.leading-image, figure, .auxiliary, .pullquote) { | |
color: rgba(210, 210, 210, 0.9); | |
} | |
body.sepia #article a[href] { | |
color: rgb(209, 150, 0); | |
} | |
body.gray #article a[href], body.night #article a[href] { | |
color: rgb(90, 200, 250); | |
} | |
body.watch.night.oled #article a[href] { | |
color: rgb(32, 148, 250); | |
} | |
body #article :matches(.page, .metadata a[href]) { | |
color: var(--body-font-color); | |
} | |
body #article .page { | |
border-top-color: var(--horizontal-line-color); | |
} | |
body #article hr { | |
background: var(--horizontal-line-color); | |
} | |
body.sepia .subhead { | |
color: rgba(79, 50, 28, 0.72); | |
} | |
body.gray .subhead { | |
color: rgba(255, 255, 255, 0.65); | |
} | |
body.night .subhead { | |
color: rgba(185, 185, 185, 0.9); | |
} | |
body.night.oled .subhead { | |
color: rgba(210, 210, 210, 0.85); | |
} | |
body.sepia :matches(#article .page-number, #incoming-page-corner) { | |
color: rgba(63, 41, 23, 0.5); | |
} | |
body.gray :matches(#article .page-number, #incoming-page-corner) { | |
color: rgba(255, 255, 255, 0.45); | |
} | |
body.night :matches(#article .page-number, #incoming-page-corner) { | |
color: rgba(255, 255, 255, 0.55); | |
} | |
body.night.oled :matches(#article .page-number, #incoming-page-corner) { | |
color: rgba(210, 210, 210, 0.8); | |
} | |
body.sepia #article blockquote, body.sepia #article q { | |
color: rgb(140, 112, 79); | |
} | |
body.sepia #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgba(154, 128, 92, 0.1); | |
} | |
body.gray #article blockquote, body.gray #article q { | |
color: rgba(255, 255, 255, 0.6); | |
} | |
body.gray #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgba(255, 255, 255, 0.15); | |
} | |
body.night #article blockquote, body.night #article q { | |
color: rgba(255, 255, 255, 0.6); | |
} | |
body.night #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgba(255, 255, 255, 0.15); | |
} | |
body.night.oled #article blockquote, body.night.oled #article q { | |
color: rgba(210, 210, 210, 0.85); | |
} | |
body.night.oled #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgba(210, 210, 210, 0.2); | |
} | |
body.watch.night #article blockquote, body.watch.night #article q { | |
color: var(--body-font-color); | |
} | |
body.watch.night #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgb(51, 51, 51); | |
} | |
body.sepia table :matches(td, th) { | |
border-color: rgb(230, 218, 202); | |
} | |
body.sepia table th { | |
background-color: rgba(154, 128, 92, 0.06); | |
} | |
body.gray table :matches(td, th) { | |
border-color: rgb(106, 106, 106); | |
} | |
body.gray table th { | |
background-color: rgba(255, 255, 255, 0.035); | |
} | |
body.night table :matches(td, th) { | |
border-color: rgb(50, 50, 50); | |
} | |
body.night table th { | |
background-color: rgba(255, 255, 255, 0.045); | |
} | |
body.night.oled table th { | |
background-color: rgba(255, 255, 255, 0.075); | |
} | |
@media (inverted-colors) { | |
/* If the user has turned on the "smart invert" accessibility preference, they generally prefer | |
their images, such as photos, to not be inverted. Provide this by applying a filter that | |
inverts the colors again (effectively un-inverting). */ | |
body:not(.gray):not(.night) #article :matches(img, video) { | |
filter: invert(); | |
} | |
body:not(.gray):not(.night) #article picture { | |
filter: none !important; | |
} | |
body.gray, body.night { | |
filter: invert(); | |
} | |
body:matches(.gray, .night) #article :matches(img:not(picture > img), picture, video) { | |
filter: none !important; | |
} | |
body:matches(.gray, .night) #article iframe { | |
filter: invert(); | |
} | |
html.paper body.white #article, html.paper body.sepia #article { | |
--paper-shadow-color: rgba(255, 255, 255, 0.2); | |
} | |
/* The background color of <body> is not inverted by the filter. Achieve this by manually | |
setting the inverse color. */ | |
html:not(.paper) body.gray { | |
background-color: rgb(165, 165, 163) !important; | |
} | |
html.paper body.gray { | |
background-color: rgb(205, 205, 204) !important; | |
} | |
html:not(.paper) body.night { | |
background-color: rgb(237, 237, 237) !important; | |
} | |
html:not(.paper) body.night.oled { | |
background-color: white !important; | |
} | |
html.paper body.night { | |
background-color: white !important; | |
} | |
} | |
</style> | |
<style id="locale-specific-adjustments"> | |
.locale-ja .page { | |
text-align: justify; | |
} | |
.locale-zh-Hans .page { | |
text-align: justify; | |
} | |
.locale-zh-Hant .page { | |
text-align: justify; | |
word-break: break-all; | |
} | |
.locale-hi .title { | |
line-height: 1.65em; | |
} | |
/* See 32728279 and 54061051. */ | |
.locale-ur.notonastaliqurdu :matches(h1, h2, h3, h4, h5, h6) { | |
font-weight: normal; | |
line-height: 2.55em; | |
} | |
</style> | |
<style id="dynamic-article-content"></style> | |
<!-- For Twitter’s script to find and script world to be created (see 34937240). --> | |
<script> | |
window.isReaderPage = true; | |
</script> | |
</head> | |
<body> | |
<iframe aria-hidden="true" id="next-page-container"></iframe> | |
<div id="article" role="article"> | |
<!-- This node will contain a number of div.page. --> | |
</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// # sourceURL=__InjectedScript_ReaderArticleFinder.js | |
/* Copyright (c) 2024 Apple Inc. All rights reserved. */ | |
/* | |
* Copyright (c) 2010 Apple Inc. All rights reserved. | |
* | |
* Portions Copyright (c) 2009 Arc90 Inc | |
* Readability. An Arc90 Lab Experiment. | |
* Website: http://lab.arc90.com/experiments/readability | |
* Source: http://code.google.com/p/arc90labs-readability | |
* Readability is licensed under the Apache License, Version 2.0. | |
*/ | |
function hostnameMatchesHostKnownToContainEmbeddableMedia(e) | |
{ | |
return /^(.+\.)?(youtube(-nocookie)?\.com|vimeo\.com|dailymotion\.com|soundcloud\.com|mixcloud\.com|embedly\.com|embed\.ly)\.?$/.test(e) | |
} | |
function lazyLoadingImageURLForElement(e, t) | |
{ | |
function n(e) | |
{ | |
const t = /\.(jpe?g|png|gif|bmp)$/i; | |
if (t.test(e)) | |
return !0; | |
let n = urlFromString(e); | |
return !!n && t.test(n.pathname) | |
} | |
function r(e) | |
{ | |
let t = attributesForElement(e); | |
for (let r of t) { | |
let t = r.name; | |
if (a.has(t.toLowerCase())) | |
return e.getAttribute(t); | |
let i = n(r.value); | |
if (o.has(t.toLowerCase()) && i) | |
return e.getAttribute(t); | |
if (s && /^data.*(src|source)$/i.test(t) && i) | |
return e.getAttribute(t); | |
if (e instanceof HTMLImageElement && /^data-/.test(t) && i && 1 === e.naturalWidth && 1 === e.naturalHeight) | |
return e.getAttribute(t) | |
} | |
} | |
const i = /(data:image\/)?gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==/, | |
a = new Set([ "data-lazy-src", "data-original", "datasrc", "data-src", "original-src", "rel:bf_image_src", "deferred-src", "data-mediaviewer-src", "data-hi-res-src", "data-native-src" ]), | |
o = new Set([ "original" ]); | |
let l = e.getAttribute("src"), | |
s = /transparent|empty/i.test(l) || i.test(l); | |
const c = 2; | |
for (let t = e, n = 0; t && n < c; t = t.parentElement, ++n) { | |
let e = r(t); | |
if (e) | |
return e | |
} | |
let u = e.closest("*[itemscope]"); | |
if (u && /^https?:\/\/schema\.org\/ImageObject\/?$/.test(u.getAttribute("itemtype"))) { | |
let e = u.getAttribute("itemid"); | |
if (n(e) && !u.querySelector("img")) | |
return e | |
} | |
if (LazyLoadRegex.test(t) && "function" == typeof URL) { | |
var m; | |
try { | |
m = new URL(e.src) | |
} catch (e) { | |
} | |
if (m && m.search) { | |
var d, h; | |
const t = [ "w", "width" ]; | |
for (var g = t.length, f = 0; f < g; ++f) { | |
var p = t[f], | |
E = m.searchParams.get(p); | |
if (E && !isNaN(parseInt(E))) { | |
d = p; | |
break | |
} | |
} | |
const n = [ "h", "height" ]; | |
var v = n.length; | |
for (f = 0; f < v; ++f) { | |
var N = n[f], | |
C = m.searchParams.get(N); | |
if (C && !isNaN(parseInt(C))) { | |
h = N; | |
break | |
} | |
} | |
if (d && h) { | |
var A = e.getAttribute("width"), | |
S = e.getAttribute("height"); | |
if (!isNaN(parseInt(A)) && !isNaN(parseInt(S))) | |
return m.searchParams.set(d, A), m.searchParams.set(h, S), m.href | |
} | |
} | |
} | |
return null | |
} | |
function sanitizeElementByRemovingAttributes(e) | |
{ | |
elementLooksLikeEmbeddedIframeTweetWithSrc(e) && (e.setAttribute("height", e.style.height), e.setAttribute("width", e.style.width)); | |
const t = /^on|^id$|^class$|^style$|^autofocus$/; | |
for (var n = attributesForElement(e), r = 0; r < n.length; ++r) { | |
var i = n[r].nodeName; | |
t.test(i) && (e.removeAttribute(i), r--) | |
} | |
} | |
function characterAppearsToBeCJK(e) | |
{ | |
if (!e || 0 === e.length) | |
return !1; | |
var t = e.charCodeAt(0); | |
return t > 11904 && t < 12031 || (t > 12352 && t < 12543 || (t > 12736 && t < 19903 || (t > 19968 && t < 40959 || (t > 44032 && t < 55215 || (t > 63744 && t < 64255 || (t > 65072 && t < 65103 || (t > 131072 && t < 173791 || t > 194560 && t < 195103))))))) | |
} | |
function domDistance(e, t, n) | |
{ | |
for (var r = [], i = e; i;) | |
r.unshift(i), i = i.parentNode; | |
var a = []; | |
for (i = t; i;) | |
a.unshift(i), i = i.parentNode; | |
for (var o = Math.min(r.length, a.length), l = Math.abs(r.length - a.length), s = o; s >= 0 && r[s] !== a[s]; --s) | |
if (l += 2, n && l >= n) | |
return n; | |
return l | |
} | |
function fontSizeFromComputedStyle(e, t) | |
{ | |
var n = parseInt(e.fontSize); | |
return isNaN(n) && (n = t || BaseFontSize), n | |
} | |
function contentTextStyleForNode(e, t) | |
{ | |
function n(e) | |
{ | |
if (isNodeWhitespace(e)) | |
return null; | |
var t = getComputedStyle(e.parentNode); | |
return "none" !== t.float ? null : t | |
} | |
for (var r = "descendant::text()[not(parent::h1) and not(parent::h2) and not(parent::h3) and not(parent::h4) and not(parent::h5) and not(parent::h6)]", i = e.evaluate(r, t, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null), a = i.snapshotLength, o = 0; o < a; ++o) { | |
for (var l = i.snapshotItem(o), s = !1, c = l.parentElement; c !== t; c = c.parentElement) | |
if (NegativeRegEx.test(c.className)) { | |
s = !0; | |
break | |
} | |
if (!s) { | |
var u = n(l); | |
if (u) | |
return u | |
} | |
} | |
return null | |
} | |
function isNodeWhitespace(e) | |
{ | |
return !(!e || e.nodeType !== Node.TEXT_NODE) && !/\S/.test(e.data) | |
} | |
function removeWhitespace(e) | |
{ | |
return e.replace(/\s+/g, "") | |
} | |
function isElementNode(e) | |
{ | |
return !(!e || e.nodeType !== Node.ELEMENT_NODE) | |
} | |
function computedStyleIndicatesElementIsInvisibleDueToClipping(e) | |
{ | |
if ("absolute" !== e.position) | |
return !1; | |
var t = e.clip.match(/^rect\((\d+px|auto), (\d+px|auto), (\d+px|auto), (\d+px|auto)\)$/); | |
if (!t || 5 !== t.length) | |
return !1; | |
var n = t.map((function(e) { | |
return parseInt(e) | |
})), | |
r = n[1]; | |
isNaN(r) && (r = 0); | |
var i = n[2], | |
a = n[3], | |
o = n[4]; | |
return isNaN(o) && (o = 0), r >= a || i >= o | |
} | |
function isElementVisible(e) | |
{ | |
var t = getComputedStyle(e); | |
if ("visible" !== t.visibility || "none" === t.display) | |
return !1; | |
if (cachedElementBoundingRect(e).height) | |
return !0; | |
var n = document.createRange(); | |
return n.selectNode(e), !!n.getBoundingClientRect().height | |
} | |
function isElementPositionedOffScreen(e) | |
{ | |
var t = cachedElementBoundingRect(e); | |
return !(!t.height || !t.width) && (t.bottom <= 0 || t.right <= 0) | |
} | |
function elementDepth(e) | |
{ | |
for (var t = 0; e; e = e.parentElement) | |
t++; | |
return t | |
} | |
function depthOfElementWithinElement(e, t) | |
{ | |
for (var n = 0; e !== t; e = e.parentElement) { | |
if (!e) | |
return NaN; | |
n++ | |
} | |
return n | |
} | |
function nearestAncestorElementWithTagName(e, t, n) | |
{ | |
var r = {}; | |
if (n) | |
for (var i = 0; i < n.length; ++i) | |
r[n[i]] = !0; | |
if (r[normalizedElementTagName(e)]) | |
return null; | |
for (; e = e.parentElement;) { | |
var a = normalizedElementTagName(e); | |
if (r[a]) | |
break; | |
if (a === t) | |
return e | |
} | |
return null | |
} | |
function elementDescendsFromElementMatchingSelector(e, t) | |
{ | |
do { | |
if (e.matches(t)) | |
return !0 | |
} while (e = e.parentElement); | |
return !1 | |
} | |
function elementDescendsFromElementInSet(e, t) | |
{ | |
do { | |
if (t.has(e)) | |
return !0 | |
} while (e = e.parentElement); | |
return !1 | |
} | |
function elementIsHidingContentDueToContentVisibilityAuto(e) | |
{ | |
return !!window.ContentVisibilityAutoStateChangeEvent && ("auto" === getComputedStyle(e).contentVisibility && (!!e.children.length && !e.children[0].checkVisibility({ | |
contentVisibilityAuto : !0 | |
}))) | |
} | |
function cachedElementBoundingRect(e) | |
{ | |
if (e._cachedElementBoundingRect) | |
return e._cachedElementBoundingRect; | |
if (ReaderArticleFinderJS.shouldSuppressBoundingRectCalculationForSkippedElements() && elementIsHidingContentDueToContentVisibilityAuto(e)) { | |
let n = e.previousElementSibling; | |
return n && !elementIsHidingContentDueToContentVisibilityAuto(n) ? ((t = cachedElementBoundingRect(n)).top += t.height, t.bottom += t.height, t) : { | |
top : 0, | |
right : 0, | |
bottom : 0, | |
left : 0, | |
width : 0, | |
height : 0 | |
} | |
} | |
var t = e.getBoundingClientRect(); | |
return ReaderArticleFinderJS._elementsWithCachedBoundingRects.push(e), ReaderArticleFinderJS._cachedScrollX || ReaderArticleFinderJS._cachedScrollY ? (e._cachedElementBoundingRect = { | |
top : t.top + ReaderArticleFinderJS._cachedScrollY, | |
right : t.right + ReaderArticleFinderJS._cachedScrollX, | |
bottom : t.bottom + ReaderArticleFinderJS._cachedScrollY, | |
left : t.left + ReaderArticleFinderJS._cachedScrollX, | |
width : t.width, | |
height : t.height | |
}, | |
e._cachedElementBoundingRect) | |
: (e._cachedElementBoundingRect = t, e._cachedElementBoundingRect) | |
} | |
function clearCachedElementBoundingRects() | |
{ | |
for (var e = ReaderArticleFinderJS._elementsWithCachedBoundingRects, t = e.length, n = 0; n < t; ++n) | |
e[n]._cachedElementBoundingRect = null; | |
ReaderArticleFinderJS._elementsWithCachedBoundingRects = [] | |
} | |
function trimmedInnerTextIgnoringTextTransform(e) | |
{ | |
var t = e.innerText; | |
if (!/\S/.test(t)) | |
return e.textContent.trim(); | |
var n = getComputedStyle(e).textTransform; | |
return "uppercase" === n || "lowercase" === n ? e.textContent.trim() : t ? t.trim() | |
: "" | |
} | |
function levenshteinDistance(e, t) | |
{ | |
for (var n = e.length, r = t.length, i = new Array(n + 1), a = 0; a < n + 1; ++a) | |
i[a] = new Array(r + 1), i[a][0] = a; | |
for (var o = 0; o < r + 1; ++o) | |
i[0][o] = o; | |
for (o = 1; o < r + 1; ++o) | |
for (a = 1; a < n + 1; ++a) | |
if (e[a - 1] === t[o - 1]) | |
i[a][o] = i[a - 1][o - 1]; | |
else { | |
var l = i[a - 1][o] + 1, | |
s = i[a][o - 1] + 1, | |
c = i[a - 1][o - 1] + 1; | |
i[a][o] = Math.min(l, s, c) | |
} | |
return i[n][r] | |
} | |
function stringSimilarity(e, t) | |
{ | |
var n = Math.max(e.length, t.length); | |
return n ? (n - levenshteinDistance(e, t)) / n : 0 | |
} | |
function stringsAreNearlyIdentical(e, t) | |
{ | |
return e === t || stringSimilarity(e, t) > StringSimilarityToDeclareStringsNearlyIdentical | |
} | |
function elementIsCommentBlock(e) | |
{ | |
if (/(^|\s)comment/.test(e.className)) | |
return !0; | |
var t = e.getAttribute("id"); | |
return !(!t || 0 !== t.indexOf("comment") && 0 !== t.indexOf("Comment")) | |
} | |
function elementLooksLikeEmbeddedTweet(e) | |
{ | |
var t = null; | |
if ("iframe" === normalizedElementTagName(e)) { | |
if (!e.contentDocument) | |
return elementLooksLikeEmbeddedIframeTweetWithSrc(e); | |
t = e.contentDocument.documentElement | |
} else | |
"twitter-widget" === normalizedElementTagName(e) && (t = e.shadowRoot); | |
if (!t) | |
return !1; | |
if (e.closest(".twitter-video") && t.querySelector("[data-tweet-id]")) | |
return !0; | |
let n = 0, | |
r = t.querySelector("blockquote"); | |
r && TweetURLRegex.test(r.getAttribute("cite")) && ++n; | |
let i = t.querySelector("[data-iframe-title]"); | |
return i && TweetIframeTitleRegex.test(i.getAttribute("data-iframe-title")) && ++n, e.classList.contains("twitter-tweet") && ++n, t.querySelector("[data-tweet-id]") && ++n, n > 2 | |
} | |
function elementLooksLikeEmbeddedIframeTweetWithSrc(e) | |
{ | |
return EmbeddedTwitterIframeSrcRegEx.test(e.getAttribute("src")) && "Twitter Tweet" === e.getAttribute("title") | |
} | |
function elementLooksLikeACarousel(e) | |
{ | |
const t = /carousel-|carousel_|-carousel|_carousel|swiper-/; | |
return t.test(e.className) || t.test(e.getAttribute("data-analytics")) | |
} | |
function elementLooksLikePartOfACarousel(e) | |
{ | |
const t = 3; | |
for (var n = e, r = 0; r < t; ++r) { | |
if (!n) | |
return !1; | |
if (elementLooksLikeACarousel(n)) | |
return !0; | |
n = n.parentElement | |
} | |
return !1 | |
} | |
function urlIsHTTPFamilyProtocol(e) | |
{ | |
let t = e.protocol; | |
return "http:" === t || "https:" === t | |
} | |
function shouldPruneIframe(e) | |
{ | |
if (e.srcdoc) | |
return !0; | |
let t = urlFromString(e.src); | |
if (t) { | |
if (!urlIsHTTPFamilyProtocol(t)) | |
return !0; | |
if (hostnameMatchesHostKnownToContainEmbeddableMedia(t.hostname)) | |
return !1 | |
} | |
return !elementLooksLikeEmbeddedTweet(e.originalElement) | |
} | |
function textContentAppearsToBeCJK(e, t) | |
{ | |
if (!e || !e.length) | |
return !1; | |
let n = e.length; | |
t && !isNaN(t) && (n = Math.min(n, t)); | |
let r = 0; | |
for (let t = 0; t < n; t++) | |
characterAppearsToBeCJK(e[t]) && r++; | |
return r >= n * MinimumRatioOfCharactersForLanguageMultiplier | |
} | |
function languageScoreMultiplierForTextNodes(e) | |
{ | |
if (!e || !e.length) | |
return 1; | |
for (var t = Math.min(e.length, DefaultNumberOfTextNodesToCheckForLanguageMultiplier), n = 0, r = 0, i = 0; i < t; i++) { | |
for (var a = e[i].nodeValue.trim(), o = Math.min(a.length, NumberOfCharactersPerTextNodeToEvaluateForLanguageMultiplier), l = 0; l < o; l++) | |
characterAppearsToBeCJK(a[l]) && n++; | |
r += o | |
} | |
return n >= r * MinimumRatioOfCharactersForLanguageMultiplier ? ScoreMultiplierForChineseJapaneseKorean : 1 | |
} | |
function scoreMultiplierForElementTagNameAndAttributes(e) | |
{ | |
for (var t = 1, n = e; n; n = n.parentElement) { | |
var r = n.getAttribute("id"); | |
r && (ArticleRegEx.test(r) && (t += ArticleMatchBonus), CommentRegEx.test(r) && (t -= CommentMatchPenalty), CarouselRegEx.test(r) && (t -= CarouselMatchPenalty)); | |
var i = n.className; | |
i && (ArticleRegEx.test(i) && (t += ArticleMatchBonus), CommentRegEx.test(i) && (t -= CommentMatchPenalty), CarouselRegEx.test(i) && (t -= CarouselMatchPenalty)), "article" === normalizedElementTagName(n) && (t += ArticleMatchBonus) | |
} | |
return t < 0 ? 0 : t | |
} | |
function elementAtPoint(e, t, n) | |
{ | |
if ("undefined" != typeof ReaderArticleFinderJSController && ReaderArticleFinderJSController.nodeAtPoint) { | |
var r = ReaderArticleFinderJSController.nodeAtPoint(e, t); | |
return r && r.nodeType !== Node.ELEMENT_NODE && (r = r.parentElement), r | |
} | |
return n.elementFromPoint(e, t) | |
} | |
function userVisibleURLString(e) | |
{ | |
return "undefined" != typeof ReaderArticleFinderJSController && ReaderArticleFinderJSController.userVisibleURLString ? ReaderArticleFinderJSController.userVisibleURLString(e) : e | |
} | |
function urlFromString(e, t) | |
{ | |
try { | |
return null != t ? new URL(e, t) : new URL(e) | |
} catch (e) { | |
return null | |
} | |
} | |
function urlStringShouldHaveItsAnchorMadeNonFunctional(e, t) | |
{ | |
if (!e) | |
return !0; | |
var n = urlFromString(e); | |
if (n || (n = urlFromString(e, t)), !n || !n.href || !n.href.length) | |
return !0; | |
let r = n.href; | |
return "javascript:" === r.trim().substring(0, 11).toLowerCase() || "data:" === r.trim().substring(0, 5).toLowerCase() | |
} | |
function anchorLinksToAttachment(e) | |
{ | |
return /\battachment\b/i.test(e.getAttribute("rel")) | |
} | |
function anchorLinksToTagOrCategoryPage(e) | |
{ | |
return /\bcategory|tag\b/i.test(e.getAttribute("rel")) | |
} | |
function anchorLooksLikeDownloadFlashLink(e) | |
{ | |
return /^https?:\/\/(www\.|get\.)(adobe|macromedia)\.com\/(((products|[a-zA-Z]{1,2}|)\/flashplayer|flashplayer|go\/getflash(player)?)|(shockwave\/download\/(index|download)\.cgi\?P1_Prod_Version=ShockwaveFlash)\/?$)/i.test(e.href) | |
} | |
function elementsHaveSameTagAndClassNames(e, t) | |
{ | |
return normalizedElementTagName(e) === normalizedElementTagName(t) && e.className === t.className | |
} | |
function selectorForElement(e) | |
{ | |
let t = normalizedElementTagName(e); | |
for (var n = e.classList, r = n.length, i = 0; i < r; i++) | |
t += "." + n[i]; | |
return t | |
} | |
function elementFingerprintForDepth(e, t) | |
{ | |
function n(e, t) | |
{ | |
if (!e) | |
return ""; | |
var o = []; | |
o.push(selectorForElement(e)); | |
var l = e.children, | |
s = l.length; | |
if (s && t > 0) { | |
o.push(r); | |
for (var c = 0; c < s; ++c) | |
o.push(n(l[c], t - 1)), c !== s - 1 && o.push(a); | |
o.push(i) | |
} | |
return o.join("") | |
} | |
const r = " / ", | |
i = " \\", | |
a = " | "; | |
return n(e, t) | |
} | |
function childrenOfParentElement(e) | |
{ | |
var t = e.parentElement; | |
return t ? t.children : [] | |
} | |
function arrayOfKeysAndValuesOfObjectSortedByValueDescending(e) | |
{ | |
var t = []; | |
for (var n in e) | |
e.hasOwnProperty(n) && t.push({ | |
key : n, | |
value : e[n] | |
}); | |
return t.sort((function(e, t) { | |
return t.value - e.value | |
})), | |
t | |
} | |
function walkElementSubtree(e, t, n) | |
{ | |
if (!(t < 0)) { | |
for (var r = e.children, i = r.length, a = t - 1, o = 0; o < i; ++o) | |
walkElementSubtree(r[o], a, n); | |
n(e, t) | |
} | |
} | |
function elementIndicatesItIsASchemaDotOrgArticleContainer(e) | |
{ | |
var t = e.getAttribute("itemtype"); | |
return /^https?:\/\/schema\.org\/((News)?Article|APIReference)$/.test(t) | |
} | |
function elementIndicatesItIsASchemaDotOrgImageObject(e) | |
{ | |
var t = e.getAttribute("itemtype"); | |
return "https://schema.org/ImageObject" === t || "http://schema.org/ImageObject" === t | |
} | |
function elementWouldAppearBetterAsFigureOrAuxiliary(e, t) | |
{ | |
const n = /caption/i; | |
if (!e) | |
return !1; | |
if (t.closest("figure, .auxiliary")) | |
return !1; | |
if (elementIndicatesItIsASchemaDotOrgImageObject(e) && !t.querySelector("figure, .auxiliary")) | |
return !0; | |
var r = t.ownerDocument.createTreeWalker(t, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, { | |
acceptNode : function() { | |
return NodeFilter.FILTER_ACCEPT | |
} | |
}); | |
r.currentNode = t; | |
for (var i = !1, a = !1; r.nextNode();) { | |
var o = r.currentNode; | |
if (o.nodeType === Node.TEXT_NODE) { | |
if (!i && /\S/.test(o.nodeValue)) | |
return !1; | |
continue | |
} | |
if (o.nodeType !== Node.ELEMENT_NODE) | |
return !1; | |
let e = normalizedElementTagName(o); | |
if ("figure" === e || "table" === e) | |
return !1; | |
if (o.classList.contains("auxiliary")) | |
return !1; | |
if ("img" === e) { | |
if (i) | |
return !1; | |
i = !0 | |
} | |
var l = o.originalElement; | |
a || l && !hasClassMatchingRegexp(o.originalElement, n) || !/\S/.test(o.innerText) || (a = !0) | |
} | |
return i && a | |
} | |
function cleanStyleAndClassList(e) | |
{ | |
e.classList.length || e.removeAttribute("class"), e.getAttribute("style") || e.removeAttribute("style") | |
} | |
function getVisibleNonWhitespaceTextNodes(e, t, n, r, i) | |
{ | |
function a(e) | |
{ | |
var t = e.children[0]; | |
if (t) | |
for (var n = t.children, r = n.length, i = 0; i < r; ++i) | |
if ("none" !== getComputedStyle(n[i]).float) | |
return !1; | |
return !0 | |
} | |
function o(e, r) | |
{ | |
if (e.nodeType === Node.TEXT_NODE) | |
return void (/\S/.test(e.nodeValue) && s.push(e)); | |
if (e.nodeType !== Node.ELEMENT_NODE) | |
return; | |
if (!isElementVisible(e)) | |
return; | |
if (n && ++l > n) | |
return; | |
if (i && i.has(e)) | |
return; | |
let u = normalizedElementTagName(e); | |
if ("iframe" !== u && "form" !== u) { | |
if (c.has(u)) | |
r--; | |
else if ("ul" !== u && "ol" !== u || !a(e)) { | |
var m = e.parentElement; | |
if (m) | |
"section" !== normalizedElementTagName(m) || e.previousElementSibling || e.nextElementSibling || r-- | |
} else | |
r--; | |
var d = r + 1; | |
if (d < t) | |
for (var h = e.childNodes, g = h.length, f = 0; f < g; ++f) | |
o(h[f], d) | |
} | |
} | |
var l = 0, | |
s = []; | |
let c = new Set([ "p", "strong", "b", "em", "i", "span", "section" ]); | |
return r && (c.add("center"), c.add("font")), o(e, 0), s | |
} | |
function mapOfVisibleTextNodeComputedStyleReductionToNumberOfMatchingCharacters(e, t) | |
{ | |
for (var n = {}, r = getVisibleNonWhitespaceTextNodes(e, 100), i = r.length, a = 0; a < i; ++a) { | |
var o = r[a], | |
l = o.length, | |
s = o.parentElement, | |
c = t(getComputedStyle(s)); | |
n[c] ? n[c] += l : n[c] = l | |
} | |
return n | |
} | |
function keyOfMaximumValueInDictionary(e) | |
{ | |
var t, n; | |
for (var r in e) { | |
var i = e[r]; | |
(!n || i > n) && (t = r, n = i) | |
} | |
return t | |
} | |
function elementIsProtected(e) | |
{ | |
return e.classList.contains("protected") || e.querySelector(".protected") | |
} | |
function dominantFontFamilyAndSizeForElement(e) | |
{ | |
return keyOfMaximumValueInDictionary(mapOfVisibleTextNodeComputedStyleReductionToNumberOfMatchingCharacters(e, (function(e) { | |
return e.fontFamily + "|" + e.fontSize | |
}))) | |
} | |
function dominantFontSizeInPointsFromFontFamilyAndSizeString(e) | |
{ | |
return e ? parseInt(e.split("|")[1]) : null | |
} | |
function canvasElementHasNoUserVisibleContent(e) | |
{ | |
if (!e.width || !e.height) | |
return !0; | |
for (var t = e.getContext("2d").getImageData(0, 0, e.width, e.height).data, n = 0, r = t.length; n < r; n += 4) { | |
if (t[n + 3]) | |
return !1 | |
} | |
return !0 | |
} | |
function findArticleNodeSelectorsInQuirksListForHostname(e, t) | |
{ | |
const n = [ | |
[ AppleDotComAndSubdomainsRegex, "*[itemprop='articleBody']" ], | |
[ /^(.+\.)?buzzfeed\.com\.?$/, "article #buzz_sub_buzz" ], | |
[ /^(.+\.)?mashable\.com\.?$/, ".parsec-body .parsec-container" ], | |
[ /^(.+\.)?cnet\.com\.?$/, "#rbContent.container" ], | |
[ /^(.+\.)?engadget\.com\.?$/, "main article #page_body" ], | |
[ /^(.*\.)?m\.wikipedia\.org\.?$/, "#content #bodyContent" ], | |
[ /^(.*\.)?theintercept\.com\.?$/, ".PostContent" ], | |
[ /^(.*\.)?tools\.ietf\.org\.?$/, "div.content" ], | |
[ /^(.+\.)?meteoinfo\.ru\.?$/, "#jm-content-bottom" ], | |
[ /^(.*\.)?tmd\.go\.th\.?$/, "#sidebar" ] | |
]; | |
for (var r = n.length, i = 0; i < r; ++i) { | |
var a = n[i]; | |
if (a[0].test(e.toLowerCase())) | |
if (t(a[1])) | |
return | |
} | |
} | |
function functionToPreventPruningDueToInvisibilityInQuirksListForHostname(e) | |
{ | |
const t = [ | |
[ /^mobile\.nytimes\.com\.?$/, function(e, t) { | |
var n = e; | |
if (!t) | |
return !1; | |
for (; n && n !== t;) { | |
if (n.classList.contains("hidden")) | |
return !0; | |
n = n.parentElement | |
} | |
return !1 | |
} ] | |
]; | |
for (var n = t.length, r = 0; r < n; ++r) { | |
var i = t[r]; | |
if (i[0].test(e.toLowerCase())) | |
return i[1] | |
} | |
return null | |
} | |
function elementIsAHeader(e) | |
{ | |
return !!{ | |
h1 : 1, | |
h2 : 1, | |
h3 : 1, | |
h4 : 1, | |
h5 : 1, | |
h6 : 1 | |
}[normalizedElementTagName(e)] | |
} | |
function leafElementForElementAndDirection(e, t) | |
{ | |
var n = e.ownerDocument, | |
r = n.createTreeWalker(n.body, NodeFilter.SHOW_ELEMENT, { | |
acceptNode : function(e) { | |
return 0 === e.children.length ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP | |
} | |
}); | |
return r.currentNode = e, r[t]() | |
} | |
function previousLeafElementForElement(e) | |
{ | |
return leafElementForElementAndDirection(e, "previousNode") | |
} | |
function nextLeafElementForElement(e) | |
{ | |
return leafElementForElementAndDirection(e, "nextNode") | |
} | |
function nextNonFloatingVisibleElementSibling(e) | |
{ | |
for (var t = e; t = t.nextElementSibling;) | |
if (isElementVisible(t) && "none" === getComputedStyle(t).float) | |
return t; | |
return null | |
} | |
function elementWithLargestAreaFromElements(e) | |
{ | |
var t, n = e.length; | |
if (!n) | |
return null; | |
for (var r = 0, i = 0; i < n; ++i) { | |
var a = e[i], | |
o = cachedElementBoundingRect(a), | |
l = o.width * o.height; | |
l > r && (t = a, r = l) | |
} | |
return t | |
} | |
function unwrappedArticleContentElement(e) | |
{ | |
for (var t = e;;) { | |
for (var n = t.childNodes, r = n.length, i = null, a = 0; a < r; ++a) { | |
var o = n[a], | |
l = o.nodeType; | |
if (l === Node.ELEMENT_NODE || l === Node.TEXT_NODE && !isNodeWhitespace(o)) { | |
if (i) | |
return t; | |
var s = normalizedElementTagName(o); | |
if ("div" !== s && "article" !== s && "section" !== s) | |
return t; | |
i = o | |
} | |
} | |
if (!i) | |
break; | |
t = i | |
} | |
return t | |
} | |
function elementsMatchingClassesInClassList(e, t) | |
{ | |
return elementsOfSameClassIgnoringClassNamesMatchingRegexp(e, t) | |
} | |
function elementsMatchingClassesInClassListIgnoringCommonLayoutClassNames(e, t) | |
{ | |
return elementsOfSameClassIgnoringClassNamesMatchingRegexp(e, t, /clearfix/i) | |
} | |
function elementsMatchingClassesInClassListIgnoringClassesWithNumericSuffix(e, t) | |
{ | |
return elementsOfSameClassIgnoringClassNamesMatchingRegexp(e, t, /\d+$/) | |
} | |
function elementsOfSameClassIgnoringClassNamesMatchingRegexp(e, t, n) | |
{ | |
for (var r = "", i = e.length, a = 0; a < i; ++a) { | |
var o = e[a]; | |
n && n.test(o) || (r += "." + o) | |
} | |
try { | |
return t.querySelectorAll(r) | |
} catch (e) { | |
return [] | |
} | |
} | |
function imageIsContainedByContainerWithImageAsBackgroundImage(e) | |
{ | |
var t = e.parentElement; | |
if (!t || !t.style || !t.style.backgroundImage) | |
return !1; | |
var n = /url\((.*)\)/.exec(t.style.backgroundImage); | |
return !(!n || 2 !== n.length) && n[1] === e.src | |
} | |
function pseudoElementContent(e, t) | |
{ | |
var n = getComputedStyle(e, t).content, | |
r = /^\"(.*)\"$/.exec(n); | |
return r && 2 == r.length ? r[1] : null | |
} | |
function hasClassMatchingRegexp(e, t) | |
{ | |
for (var n = e.classList, r = n.length, i = 0; i < r; ++i) | |
if (t.test(n[i])) | |
return !0; | |
return !1 | |
} | |
function elementLooksLikeDropCap(e) | |
{ | |
return hasClassMatchingRegexp(e, DropCapRegex) && 1 === e.innerText.length | |
} | |
function changeElementType(e, t) | |
{ | |
for (var n = e.ownerDocument.createElement(t), r = attributesForElement(e), i = r.length, a = 0; a < i; ++a) { | |
var o = r.item(a); | |
n.setAttribute(o.nodeName, o.nodeValue) | |
} | |
for (; e.firstChild;) | |
n.appendChild(e.firstChild); | |
return e.replaceWith(n), n | |
} | |
function pathComponentsForAnchor(e) | |
{ | |
var t = e.pathname.substring(1).split("/"); | |
return t[t.length - 1] || t.pop(), t | |
} | |
function lastPathComponentFromAnchor(e) | |
{ | |
var t = pathComponentsForAnchor(e); | |
return t.length ? t[t.length - 1] : null | |
} | |
function clamp(e, t, n) | |
{ | |
return Math.min(Math.max(e, t), n) | |
} | |
function normalizedElementTagName(e) | |
{ | |
return e.localName | |
} | |
function childrenWithParallelStructure(e) | |
{ | |
var t = e.children; | |
if (!t) | |
return []; | |
var n = t.length; | |
if (!n) | |
return []; | |
for (var r = {}, i = 0; i < n; ++i) { | |
var a = t[i]; | |
if (!SetOfCandidateTagNamesToIgnore.has(normalizedElementTagName(a)) && a.className) | |
for (var o = a.classList, l = o.length, s = 0; s < l; ++s) { | |
(m = r[u = o[s]]) ? m.push(a) : r[u] = [ a ] | |
} | |
} | |
var c = Math.floor(n / 2); | |
for (var u in r) { | |
var m; | |
if ((m = r[u]).length > c) | |
return m | |
} | |
return [] | |
} | |
function elementAppearsToBeCollapsed(e) | |
{ | |
return !(!ReaderArticleFinderJS.isMediaWikiPage() || !/collaps/.test(e.className)) || "false" === e.getAttribute("aria-expanded") && !isElementVisible(e) | |
} | |
const ReaderMinimumScore = 1600, | |
ReaderMinimumAdvantage = 15, | |
ArticleMinimumScoreDensity = 4.25, | |
CandidateMinimumWidthPortionForIndicatorElements = .5, | |
CandidateMinumumListItemLineCount = 4, | |
SetOfCandidateTagNamesToIgnore = new Set([ "a", "embed", "form", "html", "iframe", "object", "ol", "option", "script", "style", "svg", "ul" ]), | |
PrependedArticleCandidateMinimumHeight = 50, | |
AppendedArticleCandidateMinimumHeight = 200, | |
AppendedArticleCandidateMaximumVerticalDistanceFromArticle = 150, | |
StylisticClassNames = { | |
justfy : 1, | |
justify : 1, | |
left : 1, | |
right : 1, | |
small : 1 | |
}, | |
CommentRegEx = /[Cc]omment|meta|footer|footnote|talkback/, | |
CommentMatchPenalty = .75, | |
ArticleRegEx = /(?:(?:^|\s)(?:(post|hentry|entry)[-_]{0,2}(?:content|text|body)?|article[-_]{0,2}(?:content|text|body|page|copy)?)(?:\s|$))/i, | |
ArticleMatchBonus = .5, | |
CarouselRegEx = /carousel/i, | |
CarouselMatchPenalty = .75, | |
SectionRegex = /section|content.*component/i, | |
DropCapRegex = /first.*letter|drop.*cap/i, | |
ProgressiveLoadingRegex = /progressive/i, | |
DensityExcludedElementSelector = "#disqus_thread, #comments, .userComments", | |
PositiveRegEx = /article|body|content|entry|hentry|page|pagination|post|related-asset|text/i, | |
NegativeRegEx = /advertisement|breadcrumb|combx|comment|contact|disqus|footer|link|meta|mod-conversations|promo|related|scroll|share|shoutbox|sidebar|social|sponsor|spotim|subscribe|talkback|tags|toolbox|widget|[-_]ad$|zoom-(in|out)/i, | |
VeryPositiveClassNameRegEx = /instapaper_body/, | |
VeryNegativeClassNameRegEx = /instapaper_ignore/, | |
SharingRegex = /email|print|rss|digg|slashdot|delicious|reddit|share|twitter|facebook|pinterest|whatsapp/i, | |
VeryLiberalCommentRegex = /comment/i, | |
AdvertisementHostRegex = /^adserver\.|doubleclick.net$/i, | |
SidebarRegex = /sidebar/i, | |
MinimumAverageDistanceBetweenHRElements = 400, | |
MinimumAverageDistanceBetweenHeaderElements = 400, | |
PortionOfCandidateHeightToIgnoreForHeaderCheck = .1, | |
DefaultNumberOfTextNodesToCheckForLanguageMultiplier = 3, | |
NumberOfCharactersPerTextNodeToEvaluateForLanguageMultiplier = 12, | |
MinimumRatioOfCharactersForLanguageMultiplier = .5, | |
ScoreMultiplierForChineseJapaneseKorean = 3, | |
MinimumContentMediaHeight = 150, | |
MinimumContentMediaWidthToArticleWidthRatio = .25, | |
MaximumContentMediaAreaToArticleAreaRatio = .2, | |
LinkContinueMatchRegEx = /continue/gi, | |
LinkNextMatchRegEx = /next/gi, | |
LinkPageMatchRegEx = /page/gi, | |
LinkListItemBonus = 5, | |
LinkPageMatchBonus = 10, | |
LinkNextMatchBonus = 15, | |
LinkContinueMatchBonus = 15, | |
LinkNextOrdinalValueBase = 3, | |
LinkMismatchValueBase = 2, | |
LinkMatchWeight = 200, | |
LinkMaxVerticalDistanceFromArticle = 200, | |
LinkVerticalDistanceFromArticleWeight = 150, | |
LinkCandidateXPathQuery = "descendant-or-self::*[(not(@id) or (@id!='disqus_thread' and @id!='comments')) and (not(@class) or @class!='userComments')]/a", | |
LinkDateRegex = /\D(?:\d\d(?:\d\d)?[\-\/](?:10|11|12|0?[1-9])[\-\/](?:30|31|[12][0-9]|0?[1-9])|\d\d(?:\d\d)?\/(?:10|11|12|0[1-9])|(?:10|11|12|0?[1-9])\-(?:30|31|[12][0-9]|0?[1-9])\-\d\d(?:\d\d)?|(?:30|31|[12][0-9]|0?[1-9])\-(?:10|11|12|0?[1-9])\-\d\d(?:\d\d)?)\D/, | |
LinkURLSearchParameterKeyMatchRegex = /(page|^p$|^pg$)/i, | |
LinkURLPageSlashNumberMatchRegex = /\/.*page.*\/\d+/i, | |
LinkURLSlashDigitEndMatchRegex = /\/\d+\/?$/, | |
LinkURLArchiveSlashDigitEndMatchRegex = /archives?\/\d+\/?$/, | |
LinkURLBadSearchParameterKeyMatchRegex = /author|comment|feed|id|nonce|related/i, | |
LinkURLSemanticMatchBonus = 100, | |
LinkMinimumURLSimilarityRatio = .75, | |
SubheadRegex = /sub(head|title)|description|dec?k|abstract/i, | |
HeaderMinimumDistanceFromArticleTop = 200, | |
HeaderLevenshteinDistanceToLengthRatio = .75, | |
MinimumRatioOfListItemsBeingRelatedToSharingToPruneEntireList = .5, | |
FloatMinimumHeight = 130, | |
ImageSizeTiny = 32, | |
ToleranceForLeadingMediaWidthToArticleWidthForFullWidthPresentation = 80, | |
MaximumFloatWidth = 325, | |
AnchorImageMinimumWidth = 100, | |
AnchorImageMinimumHeight = 100, | |
MinimumHeightForImagesAboveTheArticleTitle = 50, | |
MainImageMinimumWidthAndHeight = 83, | |
BaseFontSize = 16, | |
BaseLineHeightRatio = 1.125, | |
MaximumExactIntegralValue = 9007199254740992, | |
TitleCandidateDepthScoreMultiplier = .1, | |
TextNodeLengthPower = 1.25, | |
LazyLoadRegex = /lazy/i, | |
HeaderElementsSelector = "h1, h2, h3, h4, h5, h6", | |
PageType = { | |
homepage : "homepage", | |
searchResults : "search-results", | |
article : "article" | |
}, | |
StringSimilarityToDeclareStringsNearlyIdentical = .97, | |
FindArticleMode = { | |
Element : !1, | |
ExistenceOfElement : !0 | |
}, | |
AppleDotComAndSubdomainsRegex = /.*\.apple\.com\.?$/, | |
SchemaDotOrgArticleContainerSelector = "*[itemtype='https://schema.org/Article'], *[itemtype='https://schema.org/NewsArticle'], *[itemtype='https://schema.org/APIReference'], *[itemtype='http://schema.org/Article'], *[itemtype='http://schema.org/NewsArticle'], *[itemtype='http://schema.org/APIReference']", | |
CleaningType = { | |
MainArticleContent : 0, | |
MetadataContent : 1, | |
LeadingMedia : 2 | |
}, | |
MaximumWidthOrHeightOfImageInMetadataSection = 20; | |
var attributesForElement = function() { | |
var e = Element.prototype.__lookupGetter__("attributes"); | |
return function(t) { | |
return e.call(t) | |
} | |
}(); | |
const TweetURLRegex = /^https?:\/\/(.+\.)?twitter\.com\/.*\/status\/(.*\/)*[0-9]+\/?$/i, | |
TweetIframeTitleRegex = /tweet/i, | |
EmbeddedTwitterIframeSrcRegEx = /^https?:\/\/platform\.twitter\.com\/embed\/Tweet\.html/i; | |
CandidateElement = function(e, t) { | |
this.element = e, this.contentDocument = t, this.textNodes = this.usableTextNodesInElement(this.element), this.rawScore = this.calculateRawScore(), this.tagNameAndAttributesScoreMultiplier = this.calculateElementTagNameAndAttributesScoreMultiplier(), this.languageScoreMultiplier = 0, this.depthInDocument = 0 | |
}, CandidateElement.extraArticleCandidateIfElementIsViable = function(e, t, n, r) { | |
const i = "a, b, strong, i, em, u, span"; | |
var a = cachedElementBoundingRect(e), | |
o = cachedElementBoundingRect(t.element); | |
if ((r && a.height < PrependedArticleCandidateMinimumHeight || !r && a.height < AppendedArticleCandidateMinimumHeight) && e.childElementCount && e.querySelectorAll("*").length !== e.querySelectorAll(i).length) | |
return null; | |
if (r) { | |
if (a.bottom > o.top) | |
return null | |
} else if (a.top < o.bottom) | |
return null; | |
if (!r && a.top - o.bottom > AppendedArticleCandidateMaximumVerticalDistanceFromArticle) | |
return null; | |
if (a.left > o.right || a.right < o.left) | |
return null; | |
if (elementLooksLikePartOfACarousel(e)) | |
return null; | |
var l = new CandidateElement(e, n); | |
return l.isPrepended = r, l | |
}, CandidateElement.candidateIfElementIsViable = function(e, t, n) { | |
var r = cachedElementBoundingRect(e), | |
i = ReaderArticleFinderJS.candidateElementFilter; | |
return r.width < i.minimumWidth || r.height < i.minimumHeight || r.width * r.height < i.minimumArea || !n && r.top > i.maximumTop || CandidateElement.candidateElementAdjustedHeight(e) < i.minimumHeight ? null : new CandidateElement(e, t) | |
}, CandidateElement.candidateElementAdjustedHeight = function(e) { | |
for (var t = cachedElementBoundingRect(e), n = t.height, r = e.getElementsByTagName("form"), i = r.length, a = 0; a < i; ++a) { | |
var o = cachedElementBoundingRect(r[a]); | |
o.width > t.width * CandidateMinimumWidthPortionForIndicatorElements && (n -= o.height) | |
} | |
var l = e.querySelectorAll("ol, ul"), | |
s = l.length, | |
c = null; | |
for (a = 0; a < s; ++a) { | |
var u = l[a]; | |
if (!(c && c.compareDocumentPosition(u) & Node.DOCUMENT_POSITION_CONTAINED_BY)) { | |
var m = u.getElementsByTagName("li"), | |
d = m.length, | |
h = cachedElementBoundingRect(u); | |
if (d) { | |
var g = h.height / d, | |
f = getComputedStyle(m[0]), | |
p = parseInt(f.lineHeight); | |
if (isNaN(p)) | |
p = fontSizeFromComputedStyle(f) * BaseLineHeightRatio; | |
h.width > t.width * CandidateMinimumWidthPortionForIndicatorElements && g / p < CandidateMinumumListItemLineCount && (n -= h.height, c = u) | |
} else | |
n -= h.height | |
} | |
} | |
return n | |
}, CandidateElement.prototype = { | |
calculateRawScore : function() { | |
for (var e = 0, t = this.textNodes, n = t.length, r = 0; r < n; ++r) | |
e += this.rawScoreForTextNode(t[r]); | |
return e | |
}, | |
calculateElementTagNameAndAttributesScoreMultiplier : function() { | |
return scoreMultiplierForElementTagNameAndAttributes(this.element) | |
}, | |
calculateLanguageScoreMultiplier : function() { | |
0 === this.languageScoreMultiplier && (this.languageScoreMultiplier = languageScoreMultiplierForTextNodes(this.textNodes)) | |
}, | |
depth : function() { | |
return this.depthInDocument || (this.depthInDocument = elementDepth(this.element)), this.depthInDocument | |
}, | |
finalScore : function() { | |
return this.calculateLanguageScoreMultiplier(), this.basicScore() * this.languageScoreMultiplier | |
}, | |
basicScore : function() { | |
return this.rawScore * this.tagNameAndAttributesScoreMultiplier | |
}, | |
scoreDensity : function() { | |
var e = 0, | |
t = this.element.querySelector(DensityExcludedElementSelector); | |
t && (e = t.clientWidth * t.clientHeight); | |
for (var n = this.element.children || [], r = n.length, i = 0; i < r; ++i) { | |
var a = n[i]; | |
elementIsCommentBlock(a) && (e += a.clientWidth * a.clientHeight) | |
} | |
var o = cachedElementBoundingRect(this.element).width * cachedElementBoundingRect(this.element).height, | |
l = o * MaximumContentMediaAreaToArticleAreaRatio, | |
s = cachedElementBoundingRect(this.element).width * MinimumContentMediaWidthToArticleWidthRatio, | |
c = this.element.querySelectorAll("img, video"), | |
u = c.length; | |
for (i = 0; i < u; ++i) { | |
var m = cachedElementBoundingRect(c[i]); | |
if (m.width >= s && m.height > MinimumContentMediaHeight) { | |
var d = m.width * m.height; | |
d < l && (e += d) | |
} | |
} | |
var h = this.basicScore(), | |
g = o - e, | |
f = this.textNodes.length, | |
p = 0, | |
E = 0; | |
for (i = 0; i < f; ++i) { | |
var v = this.textNodes[i].parentNode; | |
v && (E += fontSizeFromComputedStyle(getComputedStyle(v)), p++) | |
} | |
var N = BaseFontSize; | |
return p && (N = E /= p), this.calculateLanguageScoreMultiplier(), h / g * 1e3 * (N / BaseFontSize) * this.languageScoreMultiplier | |
}, | |
usableTextNodesInElement : function(e) { | |
var t = []; | |
if (!e) | |
return t; | |
const n = new Set([ "a", "dd", "dt", "noscript", "ol", "option", "pre", "script", "style", "td", "ul", "iframe" ]); | |
var r = this.contentDocument, | |
i = function(e) { | |
const i = "text()|*/text()|*/a/text()|*/li/text()|*/li/p/text()|*/span/text()|*/em/text()|*/i/text()|*/strong/text()|*/b/text()|*/font/text()|blockquote/*/text()|div[count(./p)=count(./*)]/p/text()|div[count(*)=1]/div/p/text()|div[count(*)=1]/div/p/*/text()|div/div/text()"; | |
for (var a = r.evaluate(i, e, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null), o = a.snapshotLength, l = 0; l < o; ++l) { | |
var s = a.snapshotItem(l); | |
n.has(normalizedElementTagName(s.parentNode)) || s._countedTextNode || isNodeWhitespace(s) || (s._countedTextNode = !0, t.push(s)) | |
} | |
}; | |
i(e); | |
for (var a = childrenWithParallelStructure(e), o = a.length, l = 0; l < o; ++l) { | |
i(a[l]) | |
} | |
var s = t.length; | |
for (l = 0; l < s; ++l) | |
delete t[l]._countedTextNode; | |
return t | |
}, | |
addTextNodesFromCandidateElement : function(e) { | |
for (var t = this.textNodes.length, n = 0; n < t; ++n) | |
this.textNodes[n].alreadyCounted = !0; | |
var r = e.textNodes, | |
i = r.length; | |
for (n = 0; n < i; ++n) | |
r[n].alreadyCounted || this.textNodes.push(r[n]); | |
for (t = this.textNodes.length, n = 0; n < t; ++n) | |
this.textNodes[n].alreadyCounted = null; | |
this.rawScore = this.calculateRawScore() | |
}, | |
rawScoreForTextNode : function(e) { | |
const t = 20; | |
if (!e) | |
return 0; | |
var n = e.length; | |
if (n < t) | |
return 0; | |
var r = e.parentNode; | |
if (!isElementVisible(r)) | |
return 0; | |
for (var i = 1; r && r !== this.element;) | |
i -= .1, r = r.parentNode; | |
return Math.pow(n * i, TextNodeLengthPower) | |
}, | |
shouldDisqualifyDueToScoreDensity : function() { | |
return this.scoreDensity() < ArticleMinimumScoreDensity | |
}, | |
shouldDisqualifyDueToHorizontalRuleDensity : function() { | |
for (var e = this.element.getElementsByTagName("hr"), t = e.length, n = 0, r = cachedElementBoundingRect(this.element), i = .7 * r.width, a = 0; a < t; ++a) | |
e[a].clientWidth > i && n++; | |
if (n && r.height / n < MinimumAverageDistanceBetweenHRElements) | |
return !0; | |
return !1 | |
}, | |
shouldDisqualifyDueToHeaderDensity : function() { | |
var e = "(h1|h2|h3|h4|h5|h6|*/h1|*/h2|*/h3|*/h4|*/h5|*/h6)[a[@href]]", | |
t = this.contentDocument.evaluate(e, this.element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null), | |
n = t.snapshotLength; | |
if (n > 2) { | |
for (var r = 0, i = cachedElementBoundingRect(this.element), a = i.height * PortionOfCandidateHeightToIgnoreForHeaderCheck, o = 0; o < n; ++o) { | |
var l = t.snapshotItem(o); | |
if ("#" !== l.querySelector("a[href]").getAttribute("href").substring(0, 1)) { | |
var s = cachedElementBoundingRect(l); | |
s.top - i.top > a && i.bottom - s.bottom > a && r++ | |
} | |
} | |
if (i.height / r < MinimumAverageDistanceBetweenHeaderElements) | |
return !0 | |
} | |
return !1 | |
}, | |
shouldDisqualifyDueToSimilarElements : function(e) { | |
function t(e, t) | |
{ | |
if (!e || !t) | |
return !1; | |
var n = 1; | |
return e.className ? e.className === t.className : elementFingerprintForDepth(e, n) === elementFingerprintForDepth(t, n) | |
} | |
var n = function(e) { | |
const t = /related-posts/i; | |
for (var n = e.parentElement; n && n !== this.contentDocument.body; n = n.parentElement) | |
if (t.test(n.className)) | |
return !0; | |
return !1 | |
}.bind(this), r = this.element; | |
if ("article" === normalizedElementTagName(r.parentElement)) | |
return !1; | |
let i = normalizedElementTagName(r); | |
if ("li" === i || "dd" === i) | |
for (var a = r.parentNode, o = a.children.length, l = 0; l < o; ++l) { | |
if (normalizedElementTagName(f = a.children[l]) === i && f.className === r.className && f !== r) | |
return !0 | |
} | |
var s = r.classList; | |
if (s.length || (r = r.parentElement) && ((s = r.classList).length || (r = r.parentElement) && (s = r.classList)), s.length) { | |
e || (e = []); | |
var c = e.length; | |
for (l = 0; l < c; ++l) | |
e[l].element.candidateElement = e[l]; | |
var u = elementsMatchingClassesInClassListIgnoringCommonLayoutClassNames(s, this.contentDocument), | |
m = !1, | |
d = elementDepth(r), | |
h = n(r), | |
g = u.length; | |
for (l = 0; l < g; ++l) { | |
var f; | |
if ((f = u[l]) !== r && (f.parentElement !== r && r.parentElement !== f && isElementVisible(f))) { | |
var p = f.candidateElement; | |
if ((p || (p = new CandidateElement(f, this.contentDocument))) && p.basicScore() * ReaderMinimumAdvantage > this.basicScore()) { | |
if (f.closest("section") && r.closest("section")) | |
return !1; | |
if (SectionRegex.test(f.className) && SectionRegex.test(r.className)) | |
return !1; | |
if (n(f) && !h) | |
return !1; | |
if (!m && cachedElementBoundingRect(f).bottom < cachedElementBoundingRect(this.element).top) { | |
m = !0; | |
continue | |
} | |
if (t(r.previousElementSibling, f.previousElementSibling) || t(r.nextElementSibling, f.nextElementSibling)) { | |
var E = r.querySelector(HeaderElementsSelector), | |
v = f.querySelector(HeaderElementsSelector); | |
if (E && v && elementsHaveSameTagAndClassNames(E, v)) | |
return !0; | |
if (E = r.previousElementSibling, v = f.previousElementSibling, E && v && elementIsAHeader(E) && elementIsAHeader(v) && elementsHaveSameTagAndClassNames(E, v)) | |
return !0 | |
} | |
if (elementDepth(f) === d) | |
for (; f.parentElement && r.parentElement && f.parentElement !== r.parentElement;) | |
f = f.parentElement, r = r.parentElement; | |
for (; r.childElementCount <= 1;) { | |
if (!r.childElementCount || !f.childElementCount) | |
return !1; | |
if (f.childElementCount > 1) | |
return !1; | |
if (normalizedElementTagName(r.firstElementChild) !== normalizedElementTagName(f.firstElementChild)) | |
return !1; | |
r = r.firstElementChild, f = f.firstElementChild | |
} | |
if (f.childElementCount <= 1) | |
return !1; | |
v = f.firstElementChild; | |
var N = f.lastElementChild, | |
C = (E = r.firstElementChild, r.lastElementChild); | |
if (normalizedElementTagName(v) !== normalizedElementTagName(E)) | |
return !1; | |
if (normalizedElementTagName(N) !== normalizedElementTagName(C)) | |
return !1; | |
var A = v.className, | |
S = N.className, | |
b = E.className, | |
y = N.className, | |
T = y === b ? 2 : 1; | |
if (A.length || b.length) { | |
if (!A.length || !b.length) | |
return !1; | |
if (A === b && elementsMatchingClassesInClassList(E.classList, r).length <= T) | |
return !0 | |
} | |
if (S.length || y.length) { | |
if (!S.length || !y.length) | |
return !1; | |
if (S === y && elementsMatchingClassesInClassList(N.classList, r).length <= T) | |
return !0 | |
} | |
var x = E.clientHeight, | |
R = C.clientHeight; | |
return !(!x || !v.clientHeight) && (!(!R || !N.clientHeight) && (x === v.clientHeight || R === N.clientHeight)) | |
} | |
} | |
} | |
for (l = 0; l < c; ++l) | |
e[l].element.candidateElement = null | |
} | |
return !1 | |
}, | |
shouldDisqualifyForDeepLinking : function() { | |
const e = 5; | |
for (var t = this.element, n = this.contentDocument.location, r = pathComponentsForAnchor(n).length, i = [], a = t.getElementsByTagName("a"), o = a.length, l = 0; l < o; l++) { | |
var s = a[l]; | |
if (n.host === s.host && !(pathComponentsForAnchor(s).length <= r || 0 !== (s.host + s.pathname).indexOf(n.host + n.pathname) || anchorLinksToAttachment(s) || (i.push(s), i.length < e))) { | |
var c = t.offsetTop + t.offsetHeight / e; | |
return i[0].offsetTop < c | |
} | |
} | |
return !1 | |
} | |
}, | |
String.prototype.lastInteger = function() { | |
const e = /[0-9]+/g; | |
var t = this.match(e); | |
return t ? parseInt(t[t.length - 1]) : NaN | |
}; | |
ReaderArticleFinder = function(e) { | |
this.contentDocument = e, this.didSearchForArticleNode = !1, this.didChangeContentDocumentToFrameOnPage = !1, this.article = null, this.didSearchForExtraArticleNode = !1, this.extraArticle = null, this._leadingMediaElement = null, this._isMediaWikiPage = void 0, this._cachedScrollY = 0, this._cachedScrollX = 0, this._elementsWithCachedBoundingRects = [], this._cachedContentTextStyle = null, this.pageNumber = 1, this.prefixWithDateForNextPageURL = null, this.previouslyDiscoveredPageURLStrings = [], this.candidateElementFilter = { | |
minimumWidth : 280, | |
minimumHeight : 295, | |
minimumArea : 17e4, | |
maxTop : 1300 | |
}; | |
let t = 0; | |
this._nextUniqueID = function() { | |
return t++ + "" | |
}, this._mapOfUniqueIDToOriginalElement = new Map, this._weakMapOfOriginalElementToUniqueID = new WeakMap | |
}, ReaderArticleFinder.prototype = { | |
setCandidateElementFilter : function(e) { | |
let [t, n] = this._validityAndValidCandidateElementFilterFromFilter(e); | |
t && (this.candidateElementFilter = n) | |
}, | |
_validityAndValidCandidateElementFilterFromFilter : function(e) { | |
let t = {}, | |
n = !1; | |
for (let i of ["minimumWidth", "minimumHeight", "minimumArea", "maxTop"]) { | |
let r = (e || {})[i]; | |
if (void 0 === r || "number" != typeof r || r < 0) { | |
t = {}, n = !1; | |
break | |
} | |
t[i] = r, n = !0 | |
} | |
return [ n, t ] | |
}, | |
pointsForDominantIframeHitTest : function() { | |
const e = 60; | |
return [ | |
[ e, e ], | |
[ window.innerWidth - e, e ], | |
[ e, window.innerHeight - e ], | |
[ window.innerWidth - e, window.innerHeight - e ] | |
] | |
}, | |
dominantContentIframe : function() { | |
let e, t = this.pointsForDominantIframeHitTest(), | |
n = t.length; | |
for (let i = 0; i < n; i++) { | |
if (cornerElement = document.elementFromPoint(t[i][0], t[i][1]), !cornerElement || "IFRAME" !== cornerElement.tagName) | |
return null; | |
if (e) { | |
if (e !== cornerElement) | |
return null | |
} else | |
e = cornerElement | |
} | |
return e | |
}, | |
checkForIframeCoveringMostOfWebpage : function() { | |
let e = this.dominantContentIframe(); | |
e && !this.didChangeContentDocumentToFrameOnPage && (this.contentDocument = e.contentDocument, this.resetArticleInformation(), this.didChangeContentDocumentToFrameOnPage = !0) | |
}, | |
isReaderModeAvailable : function() { | |
return this.setSuppressBoundingRectCalculationForSkippedElements(!0), this.checkForIframeCoveringMostOfWebpage(), !!this.findArticleBySearchingQuirksList() || (this.cacheWindowScrollPosition(), !!this.findArticleFromMetadata(FindArticleMode.ExistenceOfElement) || (this.article = this.findArticleByVisualExamination(), this.article && this.articleIsLTR(), !!this.article)) | |
}, | |
resetArticleInformation : function() { | |
this.didSearchForArticleNode = !1, this.didSearchForExtraArticleNode = !1, delete this.article, delete this.extraArticle, delete this._articleTitleInformation, delete this._articleTitleElement, delete this._leadingMediaElement, delete this._cachedContentTextStyle, delete this._adoptableArticle, delete this._articleIsLTR, delete this._nextPageURL, delete this._cachedScrollY, delete this._cachedScrollX, clearCachedElementBoundingRects() | |
}, | |
reset : function() { | |
this.resetArticleInformation(), this.prepareToTransitionToReader() | |
}, | |
prepareToTransitionToReader : function() { | |
this.adoptableArticle(!0), this.nextPageURL(), this.articleIsLTR() | |
}, | |
nextPageURL : function() { | |
if (!this._nextPageURL) { | |
var e = this.nextPageURLString(); | |
"undefined" != typeof ReaderArticleFinderJSController && e && (e = ReaderArticleFinderJSController.substituteURLForNextPageURL(e)), this._nextPageURL = e | |
} | |
return this._nextPageURL | |
}, | |
containerElementsForMultiPageContent : function() { | |
const e = /(.*page[^0-9]*|.*article.*item[^0-9]*)(\d{1,2})(.*)/i, | |
t = 3; | |
for (var n, i = [], r = this.articleNode(), a = 0; !(n = e.exec(r.getAttribute("id")));) | |
if (!(r = r.parentElement) || a++ === t) | |
return []; | |
for (var l = childrenOfParentElement(r), o = l.length, s = 0; s < o; ++s) { | |
var c = l[s]; | |
if (c !== r) { | |
var m = e.exec(c.getAttribute("id")); | |
m && m[1] === n[1] && m[3] === n[3] && (isElementVisible(c) && !isElementPositionedOffScreen(c) || i.push(c)) | |
} | |
} | |
return i | |
}, | |
adoptableMultiPageContentElements : function() { | |
return this.containerElementsForMultiPageContent().map((function(e) { | |
return this.cleanArticleNode(e, e.cloneNode(!0), CleaningType.MainArticleContent, !1) | |
}), | |
this) | |
}, | |
classNameIsSignificantInRouteComputation : function(e) { | |
return !!e && !(e.toLowerCase() in StylisticClassNames) | |
}, | |
shouldIgnoreInRouteComputation : function(e) { | |
let t = normalizedElementTagName(e); | |
return "script" === t || "link" === t || "style" === t || "tr" === t && !e.offsetHeight | |
}, | |
routeToArticleNode : function() { | |
for (var e = [], t = this.articleNode(); t;) { | |
var n = {}; | |
n.tagName = normalizedElementTagName(t); | |
var i = t.getAttribute("id"); | |
i && (n.id = i), this.classNameIsSignificantInRouteComputation(t.className) && (n.className = t.className), n.index = 1; | |
for (var r = t.previousElementSibling; r; r = r.previousElementSibling) | |
this.shouldIgnoreInRouteComputation(r) || n.index++; | |
e.unshift(n), t = t.parentElement | |
} | |
return e | |
}, | |
adjustArticleNodeUpwardIfNecessary : function() { | |
if (!this.article) | |
return; | |
var e = this.article.element; | |
if (!e.parentElement) | |
return; | |
for (var t = e; t; t = t.parentElement) | |
if (VeryPositiveClassNameRegEx.test(t.className)) | |
return void (this.article.element = t); | |
if ("header" === normalizedElementTagName(e) && "article" === normalizedElementTagName(e.parentElement)) | |
return void (this.article.element = e.parentElement); | |
var n = e.previousElementSibling; | |
if (n && "figure" === normalizedElementTagName(n) && "article" === normalizedElementTagName(e.parentElement)) | |
return void (this.article.element = e.parentElement); | |
var i = "section" === normalizedElementTagName(e) ? e : nearestAncestorElementWithTagName(e, "section", [ "article" ]); | |
if (i) { | |
var r = i.parentElement, | |
a = function() { | |
for (var e = r.children, t = e.length, n = 0; n < t; ++n) { | |
var a = e[n], | |
l = normalizedElementTagName(a); | |
if (a !== i && ("section" === l || "header" === l)) | |
return !0 | |
} | |
return !1 | |
}(); | |
if (a && (/\barticleBody\b/.test(r.getAttribute("itemprop")) || "main" === normalizedElementTagName(r) || "main" === r.getAttribute("role") || "article" === normalizedElementTagName(r) || r === this.contentDocument.body || r.classList.contains("entry-content"))) | |
return void (this.article.element = r) | |
} | |
const l = /intro/i, | |
o = /body|content/i; | |
if (e = this.article.element, l.test(e.className) && e.nextElementSibling && o.test(e.nextElementSibling.className) || o.test(e.className) && e.previousElementSibling && l.test(e.previousElementSibling.className)) | |
return void (this.article.element = e.parentElement); | |
if ("article" !== normalizedElementTagName(e)) { | |
var s = e.parentElement.closest("*[itemprop='articleBody']"); | |
if (s && s.parentElement.closest(SchemaDotOrgArticleContainerSelector)) | |
return void (this.article.element = s) | |
} | |
var c = e.closest("article"); | |
if (c) { | |
e = unwrappedArticleContentElement(e); | |
var m, d = elementDepth(e); | |
"p" !== normalizedElementTagName(e) || e.className || (e = e.parentElement, d--), e.classList.length ? 1 === (m = elementsMatchingClassesInClassListIgnoringCommonLayoutClassNames(e.classList, this.contentDocument)).length && (m = elementsMatchingClassesInClassListIgnoringClassesWithNumericSuffix(e.classList, this.contentDocument)) : m = e.parentElement.children; | |
for (var h = m.length, u = 0; u < h; ++u) { | |
var g = m[u]; | |
if (e !== g && d === elementDepth(g) && (isElementVisible(g) && !g.querySelector("article") && Object.keys(e.dataset).join() === Object.keys(g.dataset).join() && dominantFontFamilyAndSizeForElement(e) === dominantFontFamilyAndSizeForElement(g))) | |
return void (this.article.element = c) | |
} | |
} | |
let f = this.findExtraArticle(), | |
p = f ? f.element : null; | |
if (p && p.parentElement && e.parentElement === p.parentElement && ArticleRegEx.test(e.parentElement.className)) { | |
if (dominantFontFamilyAndSizeForElement(e) === dominantFontFamilyAndSizeForElement(p)) | |
return void (this.article.element = e.parentElement) | |
} | |
let E = e.parentElement; | |
if (elementIsCommentBlock(e) && !elementIsCommentBlock(E) && ArticleRegEx.test(E.className)) { | |
let e = CandidateElement.candidateIfElementIsViable(E, this.contentDocument, !0); | |
if (e && e.finalScore() >= ReaderMinimumScore) | |
return void (this.article.element = E) | |
} | |
if (!(e = this.article.element).getAttribute("id") && e.className) { | |
var v = normalizedElementTagName(e), | |
T = e.className, | |
y = e.parentElement; | |
if (y) | |
for (var S = y.children, A = (u = 0, S.length); u < A; ++u) { | |
var N = S[u]; | |
if (N !== e && (normalizedElementTagName(N) === v && N.className === T)) { | |
var b = CandidateElement.candidateIfElementIsViable(N, this.contentDocument, !0); | |
if (b && !(b.finalScore() < ReaderMinimumScore)) | |
return void (this.article.element = y) | |
} | |
} | |
} | |
}, | |
findArticleBySearchingQuirksList : function() { | |
var e, t = this.contentDocument; | |
return findArticleNodeSelectorsInQuirksListForHostname(t.location.hostname, (function(n) { | |
var i = t.querySelectorAll(n); | |
if (1 === i.length) | |
return e = new CandidateElement(i[0], t), !0 | |
})), | |
e | |
}, | |
articleNode : function(e) { | |
return this.checkForIframeCoveringMostOfWebpage(), this.didSearchForArticleNode || (this.article = this.findArticleBySearchingQuirksList(), this.article || (this.article = this.findArticleBySearchingAllElements()), this.article || (this.article = this.findArticleByVisualExamination()), this.article || (this.article = this.findArticleFromMetadata()), !this.article && e && (this.article = this.findArticleBySearchingAllElements(!0)), this.didSearchForArticleNode = !0, this.adjustArticleNodeUpwardIfNecessary(), this.article && (this.article.element = unwrappedArticleContentElement(this.article.element)), this.article && this.articleIsLTR()), this.article ? this.article.element : null | |
}, | |
extraArticleNode : function() { | |
return this.didSearchForArticleNode || this.articleNode(), this.didSearchForExtraArticleNode || (this.extraArticle = this.findExtraArticle(), this.didSearchForExtraArticleNode = !0), this.extraArticle ? this.extraArticle.element : null | |
}, | |
cacheWindowScrollPosition : function() { | |
this._cachedScrollY = window.scrollY, this._cachedScrollX = window.scrollX | |
}, | |
contentTextStyle : function() { | |
return this._cachedContentTextStyle || (this._cachedContentTextStyle = contentTextStyleForNode(this.contentDocument, this.articleNode()), this._cachedContentTextStyle || (this._cachedContentTextStyle = getComputedStyle(this.articleNode()))), this._cachedContentTextStyle | |
}, | |
commaCountIsLessThan : function(e, t) { | |
for (var n = 0, i = e.textContent, r = -1; n < t && (r = i.indexOf(",", r + 1)) >= 0;) | |
n++; | |
return n < t | |
}, | |
calculateLinkDensityForPruningElement : function(e, t) { | |
var n = removeWhitespace(e.textContent).length; | |
if (!n) | |
return 0; | |
for (var i = this.article.element, r = function() { | |
for (var t = e.originalElement; t && t !== i; t = t.parentElement) | |
if ("none" !== getComputedStyle(t).float) | |
return t; | |
return null | |
}(), a = e.getElementsByTagName("a"), l = 0, o = a.length, s = 0; s < o; ++s) { | |
var c = a[s]; | |
!r && c.href && t && t === dominantFontFamilyAndSizeForElement(c.originalElement) || (l += removeWhitespace(c.textContent).length) | |
} | |
return l / n | |
}, | |
shouldPruneElement : function(e, t, n) { | |
const i = .33, | |
r = .5, | |
a = .2, | |
l = 25, | |
o = 4e4; | |
let s = normalizedElementTagName(e); | |
if (!e.parentElement) | |
return !1; | |
if (t.classList.contains("footnotes")) | |
return !1; | |
if (e.querySelector(".tweet-wrapper")) | |
return !1; | |
if ("figure" === normalizedElementTagName(e.parentElement) && e.querySelector("img")) | |
return !1; | |
if ("iframe" === s) | |
return shouldPruneIframe(e); | |
if ("canvas" !== s) { | |
for (var c = !1, m = e.childNodes.length, d = 0; d < m; ++d) { | |
var h = e.childNodes[d], | |
u = h.nodeType; | |
if (u === Node.ELEMENT_NODE || u === Node.TEXT_NODE && !isNodeWhitespace(h)) { | |
c = !0; | |
break | |
} | |
} | |
if (!c) { | |
if ("p" === s) { | |
var g = e.previousSibling, | |
f = e.nextSibling; | |
if (g && g.nodeType === Node.TEXT_NODE && !isNodeWhitespace(g) && f && f.nodeType === Node.TEXT_NODE && !isNodeWhitespace(f)) | |
return !1 | |
} | |
return !0 | |
} | |
if ("p" === s) | |
return !1 | |
} | |
if ("canvas" === s) | |
return window.innerWidth === t.width && window.innerHeight === t.height || (!(!ProgressiveLoadingRegex.test(t.className) || "img" !== normalizedElementTagName(t.nextElementSibling)) || (!!canvasElementHasNoUserVisibleContent(t) || "cufon" === normalizedElementTagName(e.parentNode))); | |
if (e.closest("figure") && e.querySelector("picture")) | |
return !1; | |
var p = 0; | |
if (t) { | |
if (VeryNegativeClassNameRegEx.test(t.className)) | |
return !0; | |
var E = t.className, | |
v = t.getAttribute("id"); | |
PositiveRegEx.test(E) && p++, PositiveRegEx.test(v) && p++, NegativeRegEx.test(E) && p--, NegativeRegEx.test(v) && p-- | |
} | |
let T = this.isMediaWikiPage(); | |
if (p < 0 && !T) | |
return !0; | |
if (elementIsProtected(e)) | |
return !1; | |
if ("ul" === s || "ol" === s) { | |
if (t.querySelector("iframe") && t.querySelector("script")) | |
return !0; | |
var y = t.children, | |
S = y.length; | |
if (!S && !/\S/.test(e.innerText)) | |
return !0; | |
var A = 0, | |
N = 0; | |
for (d = 0; d < S; ++d) { | |
var b = y[d]; | |
if (SharingRegex.test(b.className)) | |
A++; | |
else { | |
var x = b.children; | |
1 === x.length && SharingRegex.test(x[0].className) && A++ | |
} | |
NegativeRegEx.test(y[d].className) && N++ | |
} | |
return A / S >= MinimumRatioOfListItemsBeingRelatedToSharingToPruneEntireList || N / S >= MinimumRatioOfListItemsBeingRelatedToSharingToPruneEntireList | |
} | |
if (1 === e.childElementCount) { | |
var C = e.firstElementChild; | |
if ("a" === normalizedElementTagName(C)) | |
return !1; | |
if ("span" === normalizedElementTagName(C) && "converted-anchor" === C.className && nearestAncestorElementWithTagName(C, "table")) | |
return !1 | |
} | |
var D = e.getElementsByTagName("img"), | |
I = D.length; | |
if (I) { | |
var M = 0; | |
for (d = 0; d < I; ++d) { | |
var L = D[d].originalElement; | |
if (isElementVisible(L)) { | |
var R = cachedElementBoundingRect(L); | |
M += R.width / I * (R.height / I) | |
} | |
} | |
if (M > o) | |
return !1 | |
} | |
if (!this.commaCountIsLessThan(e, 10)) | |
return !1; | |
var w = e.getElementsByTagName("p").length, | |
F = e.getElementsByTagName("br").length, | |
_ = w + Math.floor(F / 2); | |
if (I > _ && "table" !== s) | |
return !0; | |
if (!e.closest("table") && !e._originalElementDepthInCollapsedArea && !T) { | |
if (e.getElementsByTagName("li").length > _ && dominantFontFamilyAndSizeForElement(t.querySelector("li")) !== n) | |
return !0; | |
if (e.textContent.length < l && 1 !== I) | |
return !0; | |
let i = this.calculateLinkDensityForPruningElement(e, n); | |
if (p >= 1 && i > r) | |
return !0; | |
if (p < 1 && i > a) | |
return !0 | |
} | |
if (e.getElementsByTagName("input").length / _ > i) | |
return !0; | |
if ("table" === s) { | |
if (removeWhitespace(e.innerText).length <= .5 * removeWhitespace(t.innerText).length) | |
return !0; | |
if (T && t.classList.contains("toc")) | |
return !0 | |
} | |
return !1 | |
}, | |
wordCountIsLessThan : function(e, t) { | |
for (var n = 0, i = e.textContent, r = -1; | |
(r = i.indexOf(" ", r + 1)) >= 0 && n < t;) | |
n++; | |
return n < t | |
}, | |
leadingMediaIsAppropriateWidth : function(e) { | |
return !(!this.article || !e) && e.getBoundingClientRect().width >= this.article.element.getBoundingClientRect().width - ToleranceForLeadingMediaWidthToArticleWidthForFullWidthPresentation | |
}, | |
newDivFromNode : function(e) { | |
var t = this.contentDocument.createElement("div"); | |
return e && (t.innerHTML = e.innerHTML), t | |
}, | |
headerElement : function() { | |
if (!this.article) | |
return null; | |
var e = this.article.element.previousElementSibling; | |
if (e && "header" === normalizedElementTagName(e)) | |
return e; | |
var t = this._articleTitleElement; | |
if (!t) | |
return null; | |
var n = t.parentElement; | |
if (n && "header" === normalizedElementTagName(n) && !this.article.element.contains(n)) | |
for (var i = n.querySelectorAll("img"), r = i.length, a = 0; a < r; ++a) { | |
var l = i[a], | |
o = cachedElementBoundingRect(l); | |
if (o.width >= MainImageMinimumWidthAndHeight && o.height >= MainImageMinimumWidthAndHeight) | |
return n | |
} | |
return null | |
}, | |
adoptableLeadingMedia : function() { | |
if (!this.article || !this._leadingMediaElement || !this.leadingMediaIsAppropriateWidth(this._leadingMediaElement)) | |
return null; | |
var e = this._leadingMediaElement.closest("figure"); | |
if (e) | |
return this.cleanArticleNode(e, e.cloneNode(!0), CleaningType.LeadingMedia, !0); | |
if ("img" !== normalizedElementTagName(this._leadingMediaElement)) | |
return this.cleanArticleNode(this._leadingMediaElement, this._leadingMediaElement.cloneNode(!0), CleaningType.LeadingMedia, !0); | |
const t = 5, | |
n = /credit/, | |
i = /caption/, | |
r = /src|alt/; | |
var a = this._leadingMediaElement.parentNode, | |
l = null, | |
o = null, | |
s = a.children.length; | |
if ("div" === normalizedElementTagName(a) && s > 1 && s < t) | |
for (var c = a.cloneNode(!0).querySelectorAll("p, div"), m = c.length, d = 0; d < m; ++d) { | |
var h = c[d]; | |
n.test(h.className) ? l = h.cloneNode(!0) : i.test(h.className) && (o = h.cloneNode(!0)) | |
} | |
var u = this._leadingMediaElement.cloneNode(!1), | |
g = lazyLoadingImageURLForElement(u, u.className); | |
g && u.setAttribute("src", g), !g && u.hasAttribute("src") || !u.hasAttribute("data-srcset") || u.setAttribute("srcset", u.getAttribute("data-srcset")); | |
var f = attributesForElement(u); | |
for (d = 0; d < f.length; ++d) { | |
var p = f[d].nodeName; | |
r.test(p) || (u.removeAttribute(p), d--) | |
} | |
var E = this.contentDocument.createElement("div"); | |
if (E.className = "leading-image", E.appendChild(u), l) { | |
var v = this.newDivFromNode(l); | |
v.className = "credit", E.appendChild(v) | |
} | |
if (o) { | |
var T = this.newDivFromNode(o); | |
T.className = "caption", E.appendChild(T) | |
} | |
return E | |
}, | |
articleBoundingRect : function() { | |
return this._articleBoundingRect || (this._articleBoundingRect = cachedElementBoundingRect(this.article.element)), this._articleBoundingRect | |
}, | |
adoptableArticle : function(e) { | |
if (this._adoptableArticle) | |
return this._adoptableArticle.cloneNode(!0); | |
this.setSuppressBoundingRectCalculationForSkippedElements(!1), clearCachedElementBoundingRects(), this.cacheWindowScrollPosition(); | |
var t = this.articleNode(e); | |
if (this._adoptableArticle = t ? t.cloneNode(!0) : null, !this._adoptableArticle) | |
return this._adoptableArticle; | |
if (this._adoptableArticle = this.cleanArticleNode(t, this._adoptableArticle, CleaningType.MainArticleContent, !1), "p" === normalizedElementTagName(this._adoptableArticle)) { | |
var n = document.createElement("div"); | |
n.appendChild(this._adoptableArticle), this._adoptableArticle = n | |
} | |
var i = this.extraArticleNode(); | |
if (i) { | |
var r = this.cleanArticleNode(i, i.cloneNode(!0), CleaningType.MainArticleContent, !0); | |
r ? this.extraArticle.isPrepended ? this._adoptableArticle.insertBefore(r, this._adoptableArticle.firstChild) : this._adoptableArticle.appendChild(r) : i = null; | |
var a = cachedElementBoundingRect(this.article.element), | |
l = cachedElementBoundingRect(this.extraArticle.element), | |
o = { | |
top : Math.min(a.top, l.top), | |
right : Math.max(a.right, l.right), | |
bottom : Math.max(a.bottom, l.bottom), | |
left : Math.min(a.left, l.left) | |
}; | |
o.width = o.right - o.left, o.height = o.bottom - o.top, this._articleBoundingRect = o | |
} | |
this._articleTextContent = this._adoptableArticle.innerText; | |
var s = this.headerElement(); | |
if (this._leadingMediaElement && (!s || !s.contains(this._leadingMediaElement))) { | |
var c = this.adoptableLeadingMedia(); | |
c && this._adoptableArticle.insertBefore(c, this._adoptableArticle.firstChild) | |
} | |
var m = !!s; | |
if (m && i && (i === s && (m = !1), m)) { | |
var d = i.compareDocumentPosition(s); | |
(d & Node.DOCUMENT_POSITION_CONTAINS || d & Node.DOCUMENT_POSITION_CONTAINED_BY) && (m = !1) | |
} | |
if (m) { | |
var h = this.cleanArticleNode(s, s.cloneNode(!0), CleaningType.MainArticleContent, !0); | |
h && this._adoptableArticle.insertBefore(h, this._adoptableArticle.firstChild) | |
} | |
return this._adoptableArticle | |
}, | |
dominantContentSelectorAndDepth : function(e) { | |
var t, n = {}, | |
i = {}; | |
walkElementSubtree(e, 2, (function(e, t) { | |
if (isElementVisible(e)) { | |
var r = selectorForElement(e) + " | " + t; | |
i[r] ? i[r] += 1 : (i[r] = 1, n[r] = e) | |
} | |
})); | |
var r = arrayOfKeysAndValuesOfObjectSortedByValueDescending(i); | |
switch (r.length) { | |
case 0: | |
break; | |
case 1: | |
t = r[0].key; | |
break; | |
default: | |
var a = r[0]; | |
a.value > r[1].value && (t = a.key) | |
} | |
if (!t) | |
return null; | |
var l = n[t]; | |
return | |
{ | |
selector: selectorForElement(l), | |
depth: depthOfElementWithinElement(l, e) | |
} | |
}, | |
functionToPreventPruningElementDueToInvisibility : function() { | |
return functionToPreventPruningDueToInvisibilityInQuirksListForHostname(this.contentDocument.location.hostname) || function() { | |
return !1 | |
} | |
}, | |
cleanArticleNode : function(e, t, n, i) { | |
function r(e) | |
{ | |
v += e, T && (T += e), y && (y += e), S && (S += e), A && (A += e), N && (N += e) | |
} | |
function a() | |
{ | |
1 === T && (T = 0), 1 === y && (y = 0), 1 === S && (S = 0), 1 === A && (A = 0), 1 === N && (N = 0) | |
} | |
function l() | |
{ | |
const t = .8; | |
var n = cachedElementBoundingRect(e); | |
if (0 === n.width || 0 === n.height) | |
return !0; | |
var i, r = childrenWithParallelStructure(e), | |
a = r.length; | |
if (a) { | |
i = []; | |
for (var l = 0; l < a; ++l) { | |
var o = r[l]; | |
if ("none" === getComputedStyle(o).float) | |
for (var s = o.children, c = s.length, m = 0; m < c; ++m) | |
i.push(s[m]); | |
else | |
i.push(o) | |
} | |
} else | |
i = e.children; | |
var d = i.length, | |
h = 0; | |
for (l = 0; l < d; ++l) { | |
var u = i[l]; | |
"none" !== getComputedStyle(u).float && (h += u.innerText.length) | |
} | |
return h / e.innerText.length > t | |
} | |
function o(t) | |
{ | |
const n = 50; | |
if (cachedElementBoundingRect(t).height > n) | |
return !1; | |
return !!new Set([ "ul", "li", "nav" ]).has(normalizedElementTagName(t)) || t.parentElement === e && !t.nextElementSibling | |
} | |
function s(e, t) | |
{ | |
const n = .9; | |
return !(cachedElementBoundingRect(e).height > n * cachedElementBoundingRect(t).height) | |
} | |
function c(e, t) | |
{ | |
const n = 1.1, | |
i = 1.4; | |
t && H && (e.matches(HeaderElementsSelector) || (t > i * H || V.test(b.className) && t > n * H) && !e.closest(".pullquote") && (e.classList.add("pullquote"), e.classList.contains("float") || (e.style.width = null, cleanStyleAndClassList(e)))) | |
} | |
function m(e, t) | |
{ | |
for (var n = e[t]; n; n = n[t]) | |
if (!isNodeWhitespace(n) && n.nodeType !== Node.COMMENT_NODE) | |
return !1; | |
return !0 | |
} | |
const d = new Set([ "form", "script", "style", "link", "button", "object", "embed", "applet" ]), | |
h = new Set([ "div", "table", "ul", "canvas", "p", "iframe", "aside", "section", "footer", "nav", "ol", "menu", "svg" ]), | |
u = new Set([ "i", "em" ]), | |
g = new Set([ "b", "strong", "h1", "h2", "h3", "h4", "h5", "h6" ]), | |
f = new Set([ "i-amphtml-sizer" ]), | |
p = /lightbox/i; | |
var E = [], | |
v = 0, | |
T = 0, | |
y = 0, | |
S = 0, | |
A = 0, | |
N = 0, | |
b = e, | |
x = b.ownerDocument.defaultView, | |
C = t, | |
D = this.articleTitle(), | |
I = this._articleTitleElement, | |
M = (this.articleSubhead(), this._articleSubheadElement), | |
L = I && cachedElementBoundingRect(I).top > cachedElementBoundingRect(e).bottom, | |
R = isElementVisible(e), | |
w = new Set([ I, M ]), | |
F = new Set; | |
if (n === CleaningType.MainArticleContent) { | |
this.updateArticleBylineAndDateElementsIfNecessary(); | |
var _ = this.articleBylineElement(); | |
_ && F.add(_); | |
var O = this.articleDateElement(); | |
O && F.add(O) | |
} | |
var B = this.dominantContentSelectorAndDepth(e), | |
P = l(), | |
k = new Set; | |
this.previouslyDiscoveredPageURLStrings.forEach((function(e) { | |
k.add(e) | |
})); | |
var q = this.nextPageURL(); | |
q && k.add(q); | |
var z = null; | |
this._articleTitleElement && (z = cachedElementBoundingRect(this._articleTitleElement)); | |
var W = this.functionToPreventPruningElementDueToInvisibility(), | |
U = dominantFontFamilyAndSizeForElement(e), | |
H = dominantFontSizeInPointsFromFontFamilyAndSizeString(U); | |
const V = /pull(ed)?quote/i; | |
for (var j = [], G = [], X = [], Y = [], K = []; b;) { | |
try { | |
var Q, J = null, | |
$ = normalizedElementTagName(C), | |
Z = !1, | |
ee = elementLooksLikeDropCap(b); | |
if (C.originalElement = b, !N && elementAppearsToBeCollapsed(b) && (N = 1), (d.has($) || this.isAMPPage() && f.has($)) && (J = C), !J && b !== e && w.has(b) ? J = C : !J && b !== e && F.has(b) ? (C.parentElementBeforePruning = C.parentElement, J = C, j.push(C)) | |
: elementIsAHeader(C) && previousLeafElementForElement(b) === I && C.classList.add("protected"), | |
"twitter-widget" === $ && C.classList.add("protected"), !J && ("h1" === $ || "h2" === $)) | |
if (b.offsetTop - e.offsetTop < HeaderMinimumDistanceFromArticleTop) { | |
var te = trimmedInnerTextIgnoringTextTransform(b), | |
ne = te.length * HeaderLevenshteinDistanceToLengthRatio; | |
levenshteinDistance(D, te) <= ne && (J = C) | |
} | |
if (J || this.isMediaWikiPage() && /editsection|icon-edit|edit-page|mw-empty-elt/.test(b.className) && (J = C), "video" === $) | |
if (C.getAttribute("src")) { | |
C.classList.add("protected"); | |
var ie = cachedElementBoundingRect(b); | |
C.setAttribute("width", ie.width), C.setAttribute("height", ie.height), C.removeAttribute("style"); | |
b.hasAttribute("autoplay") && b.hasAttribute("muted") && b.hasAttribute("loop") ? C.setAttribute("data-reader-silent-looped-animation", "") : (C.setAttribute("controls", !0), C.removeAttribute("autoplay"), C.removeAttribute("preload")) | |
} else | |
J = C; | |
J || (Q = getComputedStyle(b)); | |
let t = function() { | |
if ("div" !== $ && "span" !== $) | |
return !1; | |
if (LazyLoadRegex.test(b.className)) | |
return !0; | |
for (let e of attributesForElement(b)) | |
if (/^data-/.test(e.name) && LazyLoadRegex.test(e.value) && cachedElementBoundingRect(b).height) | |
return !0; | |
return !1 | |
}(); | |
if (!J && t && (!b.innerText || b.previousElementSibling && "noscript" === normalizedElementTagName(b.previousElementSibling))) | |
if (Ie = lazyLoadingImageURLForElement(C, b.className)) { | |
var re = this.contentDocument.createElement("img"); | |
re.setAttribute("src", Ie), C.parentNode.replaceChild(re, C), (C = re).originalElement = b, $ = normalizedElementTagName(C), J = C, C.classList.add("protected") | |
} | |
if (!J && "img" !== $ && /img/.test($)) { | |
lazyLoadingImageURLForElement(C, b.className) && ((C = changeElementType(C, "img")).originalElement = b, $ = "img") | |
} | |
if (!J && "div" === $ && C.parentNode) { | |
var ae = b.querySelectorAll("a, blockquote, dl, div, img, ol, p, pre, table, ul"), | |
le = T || "none" !== Q.float, | |
oe = null; | |
if (le || ae.length ? elementIndicatesItIsASchemaDotOrgImageObject(b) && !C.querySelector("figure, .auxiliary") ? oe = "figure" : ee && (oe = "span") : oe = "p", oe) { | |
for (var se = C.parentNode, ce = this.contentDocument.createElement(oe); C.firstChild;) { | |
var me = C.firstChild; | |
ce.appendChild(me) | |
} | |
se.replaceChild(ce, C), (C = ce).originalElement = b, $ = normalizedElementTagName(C) | |
} | |
} | |
if (b.dataset && b.dataset.mathml && b.querySelector("math") && X.push(C), !J && C.parentNode && h.has($) && (C._originalElementDepthInCollapsedArea = N, E.push(C)), J || (isElementPositionedOffScreen(b) ? J = C : b === e || T || "none" === Q.float || P || !(cachedElementBoundingRect(b).height >= FloatMinimumHeight || b.childElementCount > 1) || (T = 1)), !J) { | |
if (sanitizeElementByRemovingAttributes(C), n === CleaningType.MetadataContent) | |
if ("|" === C.innerText) | |
C.innerText = "", C.classList.add("delimiter"); | |
else if ("time" === normalizedElementTagName(C)) { | |
var de = C.previousElementSibling; | |
if (de && "span" === normalizedElementTagName(de) && !de.classList.contains("delimiter")) { | |
var he = this.contentDocument.createElement("span"); | |
he.classList.add("delimiter"), C.before(he) | |
} | |
} else | |
"figure" === $ && (J = C); | |
if ("both" === Q.clear && C.classList.add("clear"), "ul" === $ || "ol" === $ || "menu" === $) { | |
if (z && !N && cachedElementBoundingRect(b).top < z.top) | |
J = C; | |
else if ("none" === Q["list-style-type"] && "none" === Q["background-image"]) { | |
for (var ue = b.children, ge = ue.length, fe = !0, pe = 0; pe < ge; ++pe) { | |
var Ee = ue[pe], | |
ve = getComputedStyle(Ee); | |
if ("none" !== ve["list-style-type"] || 0 !== parseInt(ve["-webkit-padding-start"])) { | |
fe = !1; | |
break | |
} | |
var Te = getComputedStyle(Ee, ":before").content; | |
if (/\u2022|\u25e6|\u2023|\u2219|counter/.test(Te)) { | |
fe = !1; | |
break | |
} | |
} | |
fe && C.classList.add("list-style-type-none") | |
} | |
if (b.querySelector("code")) { | |
const e = /monospace|menlo|courier/i; | |
var ye = dominantFontFamilyAndSizeForElement(b); | |
e.test(ye) && (C.classList.add("code-block"), C.classList.add("protected")) | |
} | |
} | |
if (S || "normal" === Q.fontStyle || (u.has($) || C.style && (C.style.fontStyle = Q.fontStyle), S = 1), !A && "normal" !== Q.fontWeight) { | |
if (!g.has($)) { | |
var Se = parseInt(Q.fontWeight), | |
Ae = null; | |
isNaN(Se) ? Ae = Q.fontWeight : Se <= 400 || Se >= 500 && (Ae = "bold"), Ae && C.style && (C.style.fontWeight = Ae) | |
} | |
A = 1 | |
} | |
if (T && "section" !== $ && s(b, e) || "aside" === $) { | |
ye = dominantFontFamilyAndSizeForElement(b); | |
var Ne = dominantFontSizeInPointsFromFontFamilyAndSizeString(ye), | |
be = ye && ye === U; | |
if (1 !== T || ee || (cachedElementBoundingRect(b).width <= MaximumFloatWidth ? C.setAttribute("class", "auxiliary float " + Q.float) : be || C.classList.add("auxiliary")), C.closest(".auxiliary") && b.style) { | |
var xe = b.style.getPropertyValue("width"); | |
if ("table" === Q.display && /%/.test(xe) && parseInt(xe) < 2) | |
C.style.width = Q.width; | |
else if (xe) | |
C.style.width = xe; | |
else { | |
var Ce = x.getMatchedCSSRules(b, "", !0); | |
if (Ce) | |
for (pe = Ce.length - 1; pe >= 0; --pe) { | |
xe = Ce[pe].style.getPropertyValue("width"); | |
var De = parseInt(xe); | |
if (xe && (isNaN(De) || De > 0)) { | |
C.style.width = xe; | |
break | |
} | |
} | |
} | |
1 !== T || xe || (C.style.width = cachedElementBoundingRect(b).width + "px") | |
} | |
ee || c(C, Ne) | |
} | |
if ("table" === $) | |
y || (y = 1); | |
else if ("img" === $) { | |
var Ie; | |
if (Ie = lazyLoadingImageURLForElement(C, b.className)) { | |
C.setAttribute("src", Ie); | |
var Me = !!C.closest("figure"); | |
if (!Me) { | |
var Le = attributesForElement(b), | |
Re = Le.length; | |
for (pe = 0; pe < Re; ++pe) | |
if (p.test(Le[pe].nodeName)) { | |
Me = !0; | |
break | |
} | |
} | |
Me && C.classList.add("protected"), Z = !0 | |
} | |
!Ie && C.hasAttribute("src") || !b.hasAttribute("data-srcset") || C.setAttribute("srcset", b.getAttribute("data-srcset")), C.removeAttribute("border"), C.removeAttribute("hspace"), C.removeAttribute("vspace"); | |
var we = C.getAttribute("align"); | |
if (C.removeAttribute("align"), "left" !== we && "right" !== we || (C.classList.add("float"), C.classList.add(we)), !T && !Z) { | |
var Fe, _e = (Fe = cachedElementBoundingRect(b)).width, | |
Oe = Fe.height; | |
hasClassMatchingRegexp(b, ProgressiveLoadingRegex) && b.nextElementSibling && "img" === normalizedElementTagName(b.nextElementSibling) ? J = C : imageIsContainedByContainerWithImageAsBackgroundImage(b) ? C.classList.add("protected") | |
: 1 === _e&& 1 === Oe || z&& Oe < MinimumHeightForImagesAboveTheArticleTitle&& Fe.bottom < z.top ? J = C | |
: _e < ImageSizeTiny && Oe < ImageSizeTiny && C.setAttribute("class", "reader-image-tiny") | |
} | |
if (n === CleaningType.MetadataContent) | |
((Fe = cachedElementBoundingRect(b)).width > MaximumWidthOrHeightOfImageInMetadataSection || Fe.height > MaximumWidthOrHeightOfImageInMetadataSection) && (J = C); | |
if (b.classList.contains("emoji")) { | |
let e = urlFromString(C.src); | |
if (e && "s.w.org" === e.hostname && e.pathname.startsWith("/images/core/emoji/")) { | |
let e = this.replaceImageWithAltText(C); | |
e && ((C = e).originalElement = b, $ = normalizedElementTagName(C), J = C, C.classList.add("protected")) | |
} | |
} | |
} else if ("font" === $) | |
C.removeAttribute("size"), C.removeAttribute("face"), C.removeAttribute("color"); | |
else if ("a" === $ && C.parentNode) { | |
let e, t; | |
C instanceof HTMLAnchorElement ? (e = C.getAttribute("href"), t = HTMLAnchorElement) : C instanceof SVGAElement && (e = C.getAttribute("xlink:href"), t = SVGAElement); | |
let i = C.originalElement.ownerDocument.location, | |
r = urlStringShouldHaveItsAnchorMadeNonFunctional(e, i); | |
if (t === HTMLAnchorElement && "author" === b.getAttribute("itemprop")) | |
C.classList.add("protected"); | |
else if (e && e.length && ("#" === e[0] || r)) { | |
const e = new Set([ "li", "sup" ]); | |
if (!y && !C.childElementCount && 1 === C.parentElement.childElementCount && !e.has(normalizedElementTagName(C.parentElement))) | |
this.contentDocument.evaluate("text()", C.parentElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotLength || (J = C); | |
if (!J) { | |
ce = this.contentDocument.createElement("span"); | |
if (1 === C.childElementCount && "img" === normalizedElementTagName(C.firstElementChild)) { | |
var Be = C.firstElementChild; | |
Be.width > AnchorImageMinimumWidth && Be.height > AnchorImageMinimumHeight && ce.setAttribute("class", "converted-image-anchor") | |
} | |
for (ce.className || ce.setAttribute("class", "converted-anchor"); C.firstChild;) | |
ce.appendChild(C.firstChild); | |
C.parentNode.replaceChild(ce, C), (C = ce).originalElement = b | |
} | |
} else if (AdvertisementHostRegex.test(C.host) && !C.innerText) | |
J = C; | |
else if (n !== CleaningType.MetadataContent && I && !L && I.compareDocumentPosition(b) & document.DOCUMENT_POSITION_PRECEDING && cachedElementBoundingRect(b).top < cachedElementBoundingRect(I).top) | |
G.push(C); | |
else { | |
var Pe = b.children; | |
1 === Pe.length && "img" === normalizedElementTagName(Pe[0]) && !b.innerText && anchorLooksLikeDownloadFlashLink(b) && (J = C) | |
} | |
r && (C.removeAttribute("xlink:href"), C.removeAttribute("href")) | |
} else if ("aside" === $ || "blockquote" === $ || "q" === $ || "div" === $ && V.test(b.className)) { | |
ye = dominantFontFamilyAndSizeForElement(b), Ne = dominantFontSizeInPointsFromFontFamilyAndSizeString(ye); | |
ee || c(C, Ne) | |
} else if ("cite" === $) { | |
var ke = pseudoElementContent(b, ":after") ?? "", | |
qe = document.createElement("span"); | |
qe.innerText = ke, C.after(qe) | |
} else | |
"pre" === $ ? C.style.whiteSpace = Q.whiteSpace : "source" === $ && b.hasAttribute("data-srcset") ? (C.setAttribute("srcset", b.getAttribute("data-srcset")), C.classList.add("protected")) | |
: C instanceof SVGAnimateElement && "xlink:href" === C.attributes.attributeName.value && (J = C) | |
} | |
if (Q && R && !Z) { | |
var ze = "none" === Q.display || "visible" !== Q.visibility || computedStyleIndicatesElementIsInvisibleDueToClipping(Q); | |
if (ze || "img" === $ || (ze = "0" === Q.opacity && "absolute" === Q.position && !C.closest("figure")), ze && !N) | |
!!B && (v === B.depth && selectorForElement(b) === B.selector) || W(b, e) || (J = C) | |
} | |
if (!J && elementIsCommentBlock(b) && (J = C), !J && z && cachedElementBoundingRect(b).top < z.top && VeryLiberalCommentRegex.test(b.className) && C.parentElement && (J = C), !J && "a" === $ && k.has(b.href)) { | |
for (var We, Ue, He = b, Ve = C; | |
(He = He.parentElement) && (Ve = Ve.parentElement);) { | |
const t = 10; | |
if (cachedElementBoundingRect(He).top - cachedElementBoundingRect(b).top > t) | |
break; | |
if (He === e) | |
break; | |
o(He) && (We = He, Ue = Ve) | |
} | |
We && (J = Ue, b = We, (C = Ue).originalElement = b, $ = normalizedElementTagName(C)), He = null, Ve = null, We = null, Ue = null | |
} | |
} catch (e) { | |
J = C | |
} | |
if (!J || J.parentElement || i || (J = null), "div" === $ ? Y.push(C) : "aside" === $ && K.push(C), !J) { | |
let e = this._weakMapOfOriginalElementToUniqueID.get(C.originalElement); | |
e || (e = this._nextUniqueID()), this._mapOfUniqueIDToOriginalElement.set(e, C.originalElement), C.setAttribute(this.elementReaderUniqueIDAttributeKey(), e), this._weakMapOfOriginalElementToUniqueID.set(C.originalElement, e) | |
} | |
var je = J ? null : b.firstElementChild; | |
if (je) | |
b = je, C = C.firstElementChild, r(1); | |
else { | |
for (var Ge; b !== e && !(Ge = b.nextElementSibling);) | |
b = b.parentElement, C = C.parentElement, r(-1); | |
if (b === e) { | |
if (J && !elementIsProtected(J)) | |
if (J.parentElement) | |
J.remove(); | |
else if (i) | |
return null; | |
break | |
} | |
b = Ge, C = C.nextElementSibling, a() | |
} | |
if (J && !elementIsProtected(J)) | |
if (J.parentElement) | |
J.remove(); | |
else if (i) | |
return null | |
} | |
for (let e of t.querySelectorAll("iframe")) { | |
if (elementLooksLikeEmbeddedTweet(e.originalElement)) | |
(Xe = this.adoptableSimpleTweetFromTwitterElement(e)) && e.parentElement.replaceChild(Xe, e); | |
e.classList.add("protected"), e.setAttribute("sandbox", "allow-scripts allow-same-origin") | |
} | |
for (let e of t.querySelectorAll("twitter-widget")) { | |
var Xe; | |
if (elementLooksLikeEmbeddedTweet(e.originalElement)) | |
(Xe = this.adoptableSimpleTweetFromTwitterElement(e)) && e.parentElement.replaceChild(Xe, e); | |
e.classList.add("protected") | |
} | |
const Ye = t.querySelectorAll("blockquote"), | |
Ke = Ye.length; | |
for (pe = 0; pe < Ke; ++pe) { | |
const e = Ye[pe], | |
t = e.originalElement; | |
t && this.convertBlockquoteTweetToSimpleTweetIfAppropriate(e, t) | |
} | |
for (pe = E.length - 1; pe >= 0; --pe) { | |
(vt = E[pe]).parentNode && this.shouldPruneElement(vt, vt.originalElement, U) && vt.remove(), delete vt._originalElementDepthInCollapsedArea | |
} | |
var Qe = G.length; | |
for (pe = 0; pe < Qe; ++pe) | |
G[pe].remove(); | |
var Je = t.querySelectorAll(".float"); | |
for (pe = 0; pe < Je.length; ++pe) { | |
var $e = !1, | |
Ze = Je[pe]; | |
if (!$e) { | |
var et = Ze.querySelectorAll("a, span.converted-image-anchor"), | |
tt = Ze.querySelectorAll("span.converted-anchor"); | |
$e = Ze.parentNode && tt.length > et.length | |
} | |
if (!$e) { | |
var nt = Ze.querySelectorAll("embed, object").length, | |
it = Ze.originalElement.querySelectorAll("embed, object").length; | |
!nt && it && ($e = !0) | |
} | |
if (!$e) { | |
for (var rt = Ze.originalElement.getElementsByTagName("img"), at = rt.length, lt = 0, ot = 0; ot < at && (R && isElementVisible(rt[ot]) && lt++, !(lt > 1)); ++ot) | |
; | |
if (1 === lt) | |
Ze.getElementsByTagName("img").length || ($e = !0) | |
} | |
if (!$e) { | |
const e = "img, video, embed, iframe, object, svg"; | |
/\S/.test(Ze.innerText) || Ze.matches(e) || Ze.querySelector(e) || ($e = !0) | |
} | |
$e && !elementIsProtected(Ze) && Ze.remove() | |
} | |
var st = t.querySelectorAll("br"); | |
for (pe = st.length - 1; pe >= 0; --pe) { | |
var ct = st[pe]; | |
ct.originalElement && "block" === getComputedStyle(ct.originalElement.parentElement).display && (m(ct, "nextSibling") || m(ct, "previousSibling")) && ct.remove() | |
} | |
if (i && !removeWhitespace(t.innerText).length && (n !== CleaningType.LeadingMedia || !t.querySelector("video, iframe, img"))) | |
return null; | |
var mt = {}, | |
dt = (et = t.querySelectorAll("a")).length; | |
for (pe = 0; pe < dt; ++pe) { | |
mt[ht = (ft = et[pe]).style.fontWeight] || (mt[ht] = []), mt[ht].push(ft) | |
} | |
for (var ht in mt) { | |
var ut = mt[ht], | |
gt = ut.length; | |
if (gt > .7 * dt) | |
for (pe = 0; pe < gt; ++pe) { | |
var ft; | |
(ft = ut[pe]).style.fontWeight = null, ft.getAttribute("style") || ft.removeAttribute("style") | |
} | |
} | |
var pt = t.querySelectorAll(".protected"), | |
Et = pt.length; | |
for (pe = 0; pe < Et; ++pe) { | |
var vt; | |
(vt = pt[pe]).classList.remove("protected"), vt.classList.length || vt.removeAttribute("class") | |
} | |
var Tt = t.querySelectorAll("p.auxiliary"), | |
yt = Tt.length; | |
for (pe = 0; pe < yt; ++pe) { | |
for (var St = Tt[pe], At = [ St ], Nt = St.nextElementSibling; Nt && "p" === normalizedElementTagName(Nt) && Nt.classList.contains("auxiliary");) | |
At.push(Nt), Nt = Nt.nextElementSibling; | |
var bt = At.length; | |
if (bt > 1) { | |
for (ot = 0; ot < bt; ++ot) { | |
var xt = At[ot]; | |
xt.classList.remove("auxiliary"), xt.style && (xt.style.width = null), cleanStyleAndClassList(xt) | |
} | |
pe += bt - 1 | |
} | |
} | |
for (pe = Y.length - 1; pe >= 0; --pe) { | |
var Ct = Y[pe]; | |
Ct !== t && elementWouldAppearBetterAsFigureOrAuxiliary(Ct.originalElement, Ct) && changeElementType(Ct, "figure") | |
} | |
for (pe = K.length - 1; pe >= 0; --pe) { | |
var Dt = K[pe]; | |
Dt !== t && elementWouldAppearBetterAsFigureOrAuxiliary(Dt.originalElement, Dt) && Dt.classList.add("auxiliary") | |
} | |
var It = j.length; | |
for (pe = 0; pe < It; ++pe) { | |
var Mt = j[pe], | |
Lt = Mt.parentElementBeforePruning, | |
Rt = null, | |
wt = null; | |
if (Lt) | |
Rt = depthOfElementWithinElement(Lt, t), wt = selectorForElement(Lt); | |
var Ft = Lt ? Lt.closest("ul") : null; | |
if (Ft) | |
Ft.remove(); | |
else { | |
const e = 40; | |
Lt && cachedElementBoundingRect(Lt.originalElement).height < e && (!B || B.selector !== wt || B.depth !== Rt) ? Lt.remove() : Mt.remove() | |
} | |
} | |
var _t = X.length; | |
for (pe = 0; pe < _t; ++pe) { | |
var Ot = X[pe], | |
Bt = this.contentDocument.createElement("div"); | |
Bt.innerHTML = Ot.dataset ? Ot.dataset.mathml : "", Ot.parentNode.replaceChild(Bt, Ot) | |
} | |
return t | |
}, | |
convertBlockquoteTweetToSimpleTweetIfAppropriate : function(e, t) { | |
const n = t.classList; | |
if (!n.contains("twitter-tweet") && !n.contains("twitter-video")) | |
return; | |
const i = t.getElementsByTagName("a"), | |
r = i.length; | |
if (r < 1) | |
return; | |
const a = i[r - 1]; | |
if ("twitter.com" !== a.host) | |
return; | |
const l = lastPathComponentFromAnchor(a); | |
if (isNaN(parseInt(l))) | |
return; | |
const o = this.contentDocument.createElement("div"); | |
o.setAttribute("data-reader-tweet-id", l), o.classList.add("tweet-wrapper"), e.parentElement.replaceChild(o, e), e.classList.add("simple-tweet"), o.appendChild(e) | |
}, | |
adoptableSimpleTweetFromTwitterElement : function(e) { | |
var t = function(e) { | |
var t = this.contentDocument.createElement("div"), | |
n = this.contentDocument.createTextNode(e); | |
return t.appendChild(n), t.innerHTML | |
}.bind(this); | |
let n = null, | |
i = e.originalElement; | |
if ("iframe" === normalizedElementTagName(e) ? n = i.contentDocument ? i.contentDocument.documentElement : null : "twitter-widget" === normalizedElementTagName(e) && (n = i.shadowRoot), !n) | |
return null; | |
var r = n.querySelector("[data-tweet-id].expanded") || n.querySelector("[data-tweet-id]"); | |
if (!r) | |
return null; | |
var a = this.contentDocument.createElement("div"); | |
a.classList.add("tweet-wrapper"); | |
var l = this.contentDocument.createElement("blockquote"); | |
l.classList.add("simple-tweet"), a.appendChild(l); | |
var o = r.getAttribute("data-tweet-id"); | |
a.setAttribute("data-reader-tweet-id", o); | |
var s = r.querySelector(".dateline"), | |
c = r.querySelector('[data-scribe="element:screen_name"]'), | |
m = r.querySelector('[data-scribe="element:name"]'), | |
d = r.querySelector(".e-entry-title"); | |
if (!(s && c && m && d)) | |
return a; | |
var h = "— " + t(m.innerText) + " (" + t(c.innerText) + ")", | |
u = this.contentDocument.createElement("p"); | |
u.innerHTML = d.innerHTML, l.appendChild(u), l.insertAdjacentHTML("beforeend", h); | |
var g = this.contentDocument.createElement("span"); | |
g.innerHTML = s.innerHTML, l.appendChild(g); | |
for (let e of l.querySelectorAll("img.twitter-emoji")) | |
this.replaceImageWithAltText(e); | |
for (var f = l.getElementsByTagName("*"), p = f.length, E = 0; E < p; ++E) { | |
e = f[E]; | |
"script" === normalizedElementTagName(e) ? e.remove() : sanitizeElementByRemovingAttributes(e) | |
} | |
return a | |
}, | |
replaceImageWithAltText : function(e) { | |
var t = e.getAttribute("alt"); | |
if (!t || t.length < 1) | |
return null; | |
let n = this.contentDocument.createElement("span"); | |
return n.innerText = t, e.parentNode.replaceChild(n, e), n | |
}, | |
leadingVideoNode : function() { | |
var e = this.leadingContentNodeWithSelector("video, iframe"); | |
return e && e.parentElement && !e.previousElementSibling && !e.nextElementSibling ? e.parentElement : null | |
}, | |
leadingImageNode : function() { | |
return this.leadingContentNodeWithSelector("figure img, img") | |
}, | |
ancestorsOfElement : function(e) { | |
let t = [], | |
n = e.parentNode; | |
for (; n;) | |
t.push(n), n = n.parentNode; | |
return t | |
}, | |
leadingContentNodeWithSelector : function(e) { | |
const t = 250, | |
n = .5, | |
i = .9, | |
r = 3; | |
if (!this.article || !this.article.element) | |
return null; | |
let a = 0; | |
if (this._articleTitleElement) { | |
let e, t = this.ancestorsOfElement(this.article.element); | |
for (let n of t) | |
if (n.contains(this._articleTitleElement)) { | |
e = n; | |
break | |
} | |
a = t.length - this.ancestorsOfElement(e).length + 2 | |
} | |
let l = Math.max(r, a); | |
for (var o = this.article.element, s = 0; s < l && o.parentNode; ++s) { | |
var c = (o = o.parentNode).querySelectorAll(e); | |
for (var m of c) | |
if (m && isElementVisible(m)) { | |
var d = cachedElementBoundingRect(m); | |
if (!(d.width >= window.innerWidth * i) && d.height < t) | |
continue; | |
if (d.width < this._articleWidth * n) | |
continue; | |
var h = this.article.element.compareDocumentPosition(m); | |
if (!(h & Node.DOCUMENT_POSITION_PRECEDING) || h & Node.DOCUMENT_POSITION_CONTAINED_BY) | |
continue; | |
var u = this.extraArticle ? this.extraArticle.element : null; | |
if (u && this.article.element.compareDocumentPosition(u) & Node.DOCUMENT_POSITION_FOLLOWING && (h = u.compareDocumentPosition(m)) && (!(h & Node.DOCUMENT_POSITION_PRECEDING) || h & Node.DOCUMENT_POSITION_CONTAINED_BY)) | |
continue; | |
return m | |
} | |
} | |
return null | |
}, | |
pageImageURLFromMetadata : function(e) { | |
var t = e["property:og:image"]; | |
if (t || (t = e["property:twitter:image"]), t || (t = e["property:twitter:image:src"]), t) { | |
let e = urlFromString(t); | |
if (e) { | |
let n = e.href; | |
n && urlIsHTTPFamilyProtocol(e) && (t = n) | |
} | |
} | |
return t | |
}, | |
mainImageNode : function() { | |
var e = this.leadingImageNode(); | |
if (e) | |
return e; | |
if (this.article && this.article.element) | |
for (var t = this.article.element.querySelectorAll("img"), n = t.length, i = 0; i < n; ++i) { | |
var r = t[i], | |
a = r._cachedElementBoundingRect; | |
if (a || (a = r.getBoundingClientRect()), a.width >= MainImageMinimumWidthAndHeight && a.height >= MainImageMinimumWidthAndHeight) | |
return r | |
} | |
return null | |
}, | |
schemaDotOrgMetadataObjectForArticle : function() { | |
if (this._schemaDotOrgMetadataObjectForArticle) | |
return this._schemaDotOrgMetadataObjectForArticle; | |
const e = new Set([ "Article", "NewsArticle", "Report", "ScholarlyArticle", "SocialMediaPosting", "BlogPosting", "LiveBlogPosting", "DiscussionForumPosting", "TechArticle", "APIReference" ]); | |
var t = this.contentDocument.querySelectorAll("script[type='application/ld+json']"), | |
n = t.length; | |
try { | |
for (var i = 0; i < n; ++i) { | |
var r = t[i], | |
a = JSON.parse(r.textContent), | |
l = a["@context"]; | |
if ("https://schema.org" === l || "http://schema.org" === l) { | |
var o = a["@type"]; | |
if (e.has(o)) | |
return this._schemaDotOrgMetadataObjectForArticle = a, a | |
} | |
} | |
return null | |
} catch (e) { | |
return null | |
} | |
}, | |
articleTitle : function() { | |
var e = this.articleTitleInformation(); | |
return e ? e.titleText : "" | |
}, | |
articleTitleInformation : function() { | |
function e(e, t) | |
{ | |
var n = e ? t.indexOf(e) : -1; | |
return -1 !== n && (0 === n || n + e.length === t.length) | |
} | |
function t(e, t) | |
{ | |
return e.host === t.host && e.pathname === t.pathname && e.hash === t.hash | |
} | |
function n(e) | |
{ | |
let t = nearestAncestorElementWithTagName(e, "a") || e.querySelector("a"); | |
return t ? urlStringShouldHaveItsAnchorMadeNonFunctional(t.href, t.ownerDocument.location) ? null : t : null | |
} | |
if (!this.articleNode()) | |
return; | |
if (this._articleTitleInformation) | |
return this._articleTitleInformation; | |
const i = /((article|post).*title|headline|instapaper_title|inside-head)/i, | |
r = 600, | |
a = 20, | |
l = 8, | |
o = 1.1, | |
s = 1.25, | |
c = /header|title|headline|instapaper_title/i, | |
m = 1.5, | |
d = 1.8, | |
h = 1.5, | |
u = .6, | |
g = 3, | |
f = 1.5, | |
p = .8, | |
E = .8, | |
v = 9, | |
T = 1.5, | |
y = /byline|author/i; | |
var S = function(e, t) { | |
var n = this.contentFromUniqueMetadataSelector(e, t); | |
if (n) { | |
var i = this.articleTitleAndSiteNameFromTitleString(n); | |
i && (n = i.articleTitle) | |
} | |
return n | |
}.bind(this), A = function() { | |
for (var e = this.articleNode(); e; e = e.parentElement) | |
if (elementIndicatesItIsASchemaDotOrgArticleContainer(e)) | |
return e; | |
return null | |
}.bind(this)(), N = A ? this.contentFromUniqueMetadataSelector(A, "meta[itemprop=headline]") : "", b = A ? this.contentFromUniqueMetadataSelector(A, "meta[itemprop=alternativeHeadline]") : "", x = this.contentDocument, C = x.location, D = x.title, I = S(x, "meta[property='og:title']"), M = this.contentFromUniqueMetadataSelector(x, "meta[property='og:site_name']"), L = S(x, "meta[name='twitter:title']"), R = S(x, "meta[name='sailthru.headline']"), w = this.schemaDotOrgMetadataObjectForArticle(), F = w ? w.headline : null, _ = this.articleNode(), O = cachedElementBoundingRect(_); | |
this.extraArticleNode() && this.extraArticle.isPrepended && (O = cachedElementBoundingRect(this.extraArticleNode())); | |
var B = O.left + O.width / 2, | |
P = O.top, | |
k = P; | |
(this._articleWidth = O.width, this._leadingMediaElement = this.leadingImageNode(), this._leadingMediaElement || (this._leadingMediaElement = this.leadingVideoNode()), this._leadingMediaElement) && (k = (cachedElementBoundingRect(this._leadingMediaElement).top + P) / 2); | |
var q = "h1, h2, h3, h4, h5, a:not(svg a), p, div, span", | |
z = normalizedElementTagName(this.article.element); | |
"dl" !== z && "dd" !== z || (q += ", dt"); | |
for (var W = [], U = x.querySelectorAll(q), H = U.length, V = 0; V < H; ++V) { | |
var j = U[V], | |
G = normalizedElementTagName(j); | |
if ("a" === G) | |
j.innerText === I && t(j, C) && (j.previousElementSibling || j.nextElementSibling ? W.push(j) : W.push(j.parentElement)); | |
else if ("div" === G || "span" === G || "p" === G) { | |
if (hasClassMatchingRegexp(j, i) || i.test(j.getAttribute("id"))) { | |
var X = j.parentElement; | |
elementIsAHeader(X) || W.push(j) | |
} | |
} else | |
W.push(j) | |
} | |
W = Array.prototype.slice.call(W, 0); | |
const Y = 2; | |
var K = this.article.element; | |
for (V = 0; V < Y; ++V) | |
K.parentElement && (K = K.parentElement); | |
for (var Q, J = K.querySelectorAll("a:not(svg a)"), $ = (V = 0, J.length); V < $; ++V) { | |
var Z = J[V]; | |
if (Z.offsetTop > _.offsetTop + a) | |
break; | |
if (t(Z, C) && "#" !== Z.getAttribute("href")) { | |
W.push(Z); | |
break | |
} | |
} | |
var ee = W.map(trimmedInnerTextIgnoringTextTransform), | |
te = W.length, | |
ne = 0, | |
ie = [], | |
re = [], | |
ae = [], | |
le = [], | |
oe = [], | |
se = [], | |
ce = []; | |
const me = {}, | |
de = e => { | |
const t = me[e]; | |
if (t) | |
return t; | |
const n = stringSimilarity(D, e); | |
return me[e] = n, n | |
}; | |
for (V = 0; V < te; ++V) { | |
var he = W[V], | |
ue = ee[V]; | |
const e = {}, | |
t = t => { | |
const n = e[t]; | |
if (n) | |
return n; | |
const i = stringSimilarity(ue, t); | |
return e[t] = i, i | |
}; | |
let n = de(ue); | |
if (I) { | |
const e = t(I); | |
n += e, e > StringSimilarityToDeclareStringsNearlyIdentical && re.push(he) | |
} | |
if (L) { | |
const e = t(L); | |
n += e, e > StringSimilarityToDeclareStringsNearlyIdentical && ae.push(he) | |
} | |
if (N) { | |
const e = t(N); | |
n += e, e > StringSimilarityToDeclareStringsNearlyIdentical && le.push(he) | |
} | |
if (b) { | |
const e = t(b); | |
n += e, e > StringSimilarityToDeclareStringsNearlyIdentical && oe.push(he) | |
} | |
if (R) { | |
const e = t(R); | |
n += e, e > StringSimilarityToDeclareStringsNearlyIdentical && se.push(he) | |
} | |
if (F) { | |
const e = t(F); | |
n += e, e > StringSimilarityToDeclareStringsNearlyIdentical && ce.push(he) | |
} | |
n === ne ? ie.push(he) : n > ne && (ne = n, ie = [ he ]) | |
} | |
let ge = []; | |
for (let e of W) { | |
let t = e.nextElementSibling; | |
t && SubheadRegex.test(t.className) && ge.push(e) | |
} | |
if (1 === re.length ? (Q = re[0]).headerText = trimmedInnerTextIgnoringTextTransform(Q) : 1 === ae.length ? (Q = ae[0]).headerText = trimmedInnerTextIgnoringTextTransform(Q) | |
: 1 === le.length ? (Q = le[0]).headerText = trimmedInnerTextIgnoringTextTransform(Q) | |
: 1 === se.length ? (Q = se[0]).headerText = trimmedInnerTextIgnoringTextTransform(Q) | |
: 1 === ce.length && ((Q = ce[0]).headerText = trimmedInnerTextIgnoringTextTransform(Q)), | |
!Q) | |
for (V = 0; V < te; ++V) { | |
he = W[V]; | |
if (!isElementVisible(he)) | |
continue; | |
var fe = cachedElementBoundingRect(he), | |
pe = fe.left + fe.width / 2, | |
Ee = pe - B, | |
ve = fe.top + fe.height / 2 - k, | |
Te = -1 !== re.indexOf(he), | |
ye = -1 !== ae.indexOf(he), | |
Se = he.classList.contains("instapaper_title"), | |
Ae = /\bheadline\b/.test(he.getAttribute("itemprop")), | |
Ne = -1 !== le.indexOf(he), | |
be = -1 !== oe.indexOf(he), | |
xe = -1 !== se.indexOf(he), | |
Ce = -1 !== ce.indexOf(he); | |
let t = ge.includes(he) && ve < 0; | |
var De = Te || ye || Se || Ae || Ne || be || xe || Ce || t, | |
Ie = Math.sqrt(Ee * Ee + ve * ve), | |
Me = De ? r : Math.max(r - Ie, 0), | |
Le = (ue = ee[V], he.getAttribute("property")); | |
if (Le) { | |
var Re = /dc.title/i.exec(Le); | |
if (Re && Re[0]) | |
if (1 === this.contentDocument.querySelectorAll('*[property~="' + Re[0] + '"]').length) { | |
(Q = he).headerText = ue; | |
break | |
} | |
} | |
if (!y.test(he.className)) { | |
if (!De) { | |
if (Ie > r) | |
continue; | |
if (pe < O.left || pe > O.right) | |
continue | |
} | |
if (D && stringsAreNearlyIdentical(ue, D)) | |
Me *= g; | |
else if (e(ue, D)) | |
Me *= f; | |
else if (ue.length < l) | |
continue; | |
if (ue !== M || !I) { | |
var we = !1; | |
if (We = n(he)) { | |
if ("author" === We.getAttribute("rel")) | |
continue; | |
var Fe = We.host === C.host, | |
_e = We.pathname === C.pathname; | |
if (Fe && _e) | |
Me *= h; | |
else { | |
if (Fe && nearestAncestorElementWithTagName(he, "li")) | |
continue; | |
Me *= u, we = !0 | |
} | |
} | |
var Oe = fontSizeFromComputedStyle(getComputedStyle(he)); | |
we || (Me *= Oe / BaseFontSize), Me *= 1 + TitleCandidateDepthScoreMultiplier * elementDepth(he); | |
var Be = parseInt(this.contentTextStyle().fontSize); | |
parseInt(Oe) > Be * o && (Me *= s), (c.test(he.className) || c.test(he.getAttribute("id"))) && (Me *= m); | |
var Pe = he.parentElement; | |
Pe && (c.test(Pe.className) || c.test(Pe.getAttribute("id"))) && (Me *= m), -1 !== ie.indexOf(he) && (Me *= d); | |
_ = this.article.element; | |
for (var ke = he; ke && ke !== _; ke = ke.parentElement) | |
if (SidebarRegex.test(ke.className)) { | |
Me *= p; | |
break | |
} | |
he.closest("li") && (Me *= E), (!Q || Me > Q.headerScore) && ((Q = he).headerScore = Me, Q.headerText = ue) | |
} | |
} | |
} | |
var qe; | |
if (Q && domDistance(Q, _, v + 1) > v && parseInt(getComputedStyle(Q).fontSize) < T * Be && (Q = null), Q) { | |
this._articleTitleElement = Q; | |
var ze = Q.headerText.trim(); | |
qe = I && e(I, ze) ? I : D && e(D, ze) ? D | |
: ze | |
} | |
this._leadingMediaElement || (this._leadingMediaElement = this.leadingImageNode()), this._leadingMediaElement || (this._leadingMediaElement = this.leadingVideoNode()), qe || (qe = I && e(I, D) ? I : D); | |
var We, Ue = null, | |
He = !1, | |
Ve = !1; | |
Q && ((We = n(Q)) && (Ue = We.href, He = "_blank" === We.getAttribute("target"), Ve = We.host !== C.host || We.pathname !== C.pathname)); | |
let je = { | |
titleText : qe, | |
linkURL : Ue, | |
linkIsTargetBlank : He, | |
linkIsForExternalPage : Ve | |
}; | |
if (this._articleTitleElement) { | |
const e = this.titleUniqueID(); | |
this._mapOfUniqueIDToOriginalElement.set(e, Q), this._weakMapOfOriginalElementToUniqueID.set(Q, e) | |
} | |
return this._articleTitleInformation = je, je | |
}, | |
contentFromUniqueMetadataSelector : function(e, t) { | |
var n = e.querySelectorAll(t); | |
if (1 !== n.length) | |
return null; | |
var i = n[0]; | |
return i ? this.elementAttributesContainImproperQuote(i) ? null : i.content : null | |
}, | |
elementAttributesContainImproperQuote : function(e) { | |
for (var t = attributesForElement(e), n = t.length, i = 0; i < n; ++i) | |
if (/['"]/.test(t[i].name)) | |
return !0; | |
return !1 | |
}, | |
articleSubhead : function() { | |
function e(e) | |
{ | |
return elementIsAHeader(e) ? parseInt(/h(\d)?/.exec(normalizedElementTagName(e))[1]) : NaN | |
} | |
function t(e) | |
{ | |
if (!e) | |
return null; | |
var t = e.content; | |
return t ? t.trim() : null | |
} | |
const n = /author|kicker/i; | |
if (this._articleSubhead) | |
return this._articleSubhead; | |
var i = this.articleNode(); | |
if (!i) | |
return; | |
var r = this._articleTitleElement; | |
if (!r) | |
return; | |
var a = this.contentDocument, | |
l = a.location, | |
o = e(r), | |
s = cachedElementBoundingRect(r), | |
c = new Set, | |
m = t(a.querySelector("meta[property='og:description']")); | |
m && c.add(m); | |
var d = t(a.querySelector("meta[name=description]")); | |
d && c.add(d); | |
var h, u = this.schemaDotOrgMetadataObjectForArticle(); | |
if (u) { | |
var g = u.description; | |
g && "string" == typeof g && c.add(g.trim()) | |
} | |
var f = this.contentFromUniqueMetadataSelector(a, "head meta.swiftype[name=dek]"); | |
f && (h = f); | |
let p = [], | |
E = nextNonFloatingVisibleElementSibling(r); | |
E && p.push(E); | |
let v = nextLeafElementForElement(r); | |
if (v && r && r.contains(v) && v.innerText && v.innerText.trim() === r.innerText.trim() && (v = nextLeafElementForElement(v)), v && p.push(v), c.size) | |
for (var T = a.querySelectorAll(HeaderElementsSelector + ", *[itemprop=description]"), y = T.length, S = 0; S < y; ++S) { | |
var A = T[S]; | |
c.has(A.innerText.trim()) && p.push(A) | |
} | |
var N = p.length; | |
for (S = 0; S < N; ++S) { | |
var b = p[S]; | |
if (!b) | |
continue; | |
if (b === i) | |
continue; | |
var x = b.className; | |
if (n.test(x)) | |
continue; | |
var C = b.closest("a"); | |
if (C) { | |
var D = C.host === l.host, | |
I = C.pathname === l.pathname; | |
if (!D || !I) | |
continue | |
} | |
var M, L = !1; | |
if (elementIsAHeader(b)) | |
if (isNaN(o)) | |
L = !0; | |
else | |
e(b) - 1 === o && (L = !0); | |
if (!L && SubheadRegex.test(x) && (L = !0), !L) { | |
const e = b.getAttribute("itemprop"); | |
/\bdescription\b/.test(e) && !/\barticleBody\b/.test(e) && (L = !0) | |
} | |
if (!L && c.has(b.innerText) && (L = !0), !L && h && h === b.innerText && (L = !0), L || "summary" !== b.getAttribute("itemprop") || (L = !0), !L) | |
continue; | |
if ("meta" === normalizedElementTagName(b)) { | |
var R = b.getAttribute("content"); | |
M = R ? R.trim() : ""; | |
var w = b.nextElementSibling; | |
if (!w || trimmedInnerTextIgnoringTextTransform(w) !== M) | |
continue; | |
b = w | |
} else { | |
if (cachedElementBoundingRect(b).top < (s.bottom + s.top) / 2) | |
continue; | |
M = trimmedInnerTextIgnoringTextTransform(b).trim() | |
} | |
if (!M.length) | |
continue; | |
this._articleSubheadElement = b; | |
const t = this.subheadUniqueID(); | |
this._mapOfUniqueIDToOriginalElement.set(t, b), this._weakMapOfOriginalElementToUniqueID.set(b, t), this._articleSubhead = M; | |
break | |
} | |
return this._articleSubhead | |
}, | |
adoptableMetadataBlock : function() { | |
function e(e) | |
{ | |
function t(e, i) | |
{ | |
if (e.nodeType !== Node.TEXT_NODE) { | |
if (e.nodeType === Node.ELEMENT_NODE) { | |
var r = e.childNodes, | |
a = r.length; | |
0 !== a && (1 !== a ? (i !== n.Right && t(r[0], n.Left), i !== n.Left && t(r[a - 1], n.Right)) : t(r[0], i)) | |
} | |
} else | |
i === n.Left ? e.textContent = e.textContent.trimLeft() : i === n.Right ? e.textContent = e.textContent.trimRight() | |
: e.textContent = e.textContent.trim() | |
} | |
const n = { | |
Left : 1, | |
Right : 2, | |
Both : 3 | |
}; | |
t(e) | |
} | |
this.updateArticleBylineAndDateElementsIfNecessary(); | |
var t = this.articleBylineElement(), | |
n = this.articleDateElement(); | |
if (!t && !n) | |
return null; | |
if (t && n) { | |
var i = t.compareDocumentPosition(n); | |
i&Node.DOCUMENT_POSITION_CONTAINS && (t = null), i&Node.DOCUMENT_POSITION_CONTAINED_BY && (n = null), t === n && (n = null) | |
} | |
var r, a = this.contentDocument.createElement("div"), | |
l = !1, | |
o = !1; | |
t && (e(r = this.cleanArticleNode(t, t.cloneNode(!0), CleaningType.MetadataContent, !1)), r.innerText.trim() && (l = !0, r.classList.add("byline"))); | |
if (n) { | |
var s = this.cleanArticleNode(n, n.cloneNode(!0), CleaningType.MetadataContent, !1); | |
e(s), s.innerText.trim() && (o = !0, s.classList.add("date")) | |
} | |
if (l && a.appendChild(r), l && o) { | |
var c = document.createElement("span"); | |
c.classList.add("delimiter"), a.appendChild(c) | |
} | |
return o && a.appendChild(s), a | |
}, | |
articleBylineElement : function() { | |
return this._articleBylineElement | |
}, | |
findArticleBylineElement : function() { | |
var e = this.findArticleBylineElementWithoutRejection(); | |
return e && ("footer" === normalizedElementTagName(e) || e.closest("figure")) ? null : e | |
}, | |
findArticleBylineElementWithoutRejection : function() { | |
function e(e) | |
{ | |
if (!e.length) | |
return null; | |
e = e.filter(isElementVisible); | |
for (var t = new Set, n = new Set, r = e.length, o = 0; o < r - 1; ++o) { | |
var s = e[o], | |
c = e[o + 1]; | |
if (isElementVisible(s) && isElementVisible(c)) { | |
var m = s.parentElement; | |
m === c.parentElement && (m.contains(i) || (n.add(s.parentElement), t.add(s), t.add(c))) | |
} | |
} | |
var d = new Set(e); | |
n.forEach((function(e) { | |
d.add(e) | |
})), | |
t.forEach((function(e) { | |
d.delete(e) | |
})), | |
e = [], d.forEach((function(t) { | |
e.push(t) | |
})); | |
var h, u = null; | |
r = e.length; | |
for (o = 0; o < r; ++o) { | |
s = e[o]; | |
if (isElementVisible(s)) { | |
var g = cachedElementBoundingRect(s), | |
f = g.left + g.width / 2, | |
p = g.top + g.height / 2, | |
E = a - f, | |
v = l - p, | |
T = Math.sqrt(E * E + v * v); | |
(!u || T < h) && (u = s, h = T) | |
} | |
} | |
return u | |
} | |
const t = "[itemprop~=author], a[rel='author']:not(svg a)", | |
n = "#byline, .byline, .article-byline, .byline__author, .entry-meta, .author-name, .byline-dateline, .article-author, [itemprop~=author], a[rel='author']:not(svg a)"; | |
var i = this._articleSubheadElement || this._articleTitleElement; | |
if (i) | |
var r, a = (r = i ? cachedElementBoundingRect(i) : null).left + r.width / 2, | |
l = r.top + r.height / 2; | |
var o = this.contentFromUniqueMetadataSelector(this.contentDocument, "head meta[name=author]"); | |
if (o || (o = this.contentFromUniqueMetadataSelector(this.contentDocument, "head meta[property=author]")), !o) { | |
var s = this.schemaDotOrgMetadataObjectForArticle(); | |
if (s) { | |
var c = s.author; | |
c && "object" == typeof c && (o = c.name) | |
} | |
} | |
var m = this.article.element, | |
d = m.querySelectorAll(n); | |
if (1 === d.length) | |
return d[0]; | |
var h = i ? i.nextElementSibling : null; | |
if (h) { | |
if (h.matches(n) || h.innerText === o || (h = h.querySelector(n)), h) | |
if (h.querySelector("li")) { | |
var u = h.querySelector(n); | |
u && (h = u) | |
} | |
if (h) | |
return h | |
} | |
for (var g = this.contentDocument.getElementsByTagName("a"), f = 0, p = g.length; f < p; ++f) { | |
var E = g[f]; | |
if (trimmedInnerTextIgnoringTextTransform(E) === o) | |
return E | |
} | |
var v = m.closest("article"); | |
if (i && v) { | |
if (y = e(Array.from(v.querySelectorAll(t)))) | |
return y; | |
if (y = e(Array.from(v.querySelectorAll(n)))) | |
return y | |
} | |
var T = m.previousElementSibling; | |
if (T) { | |
var y; | |
if (y = e(Array.from(T.querySelectorAll(t)))) | |
return y; | |
if (y = e(Array.from(T.querySelectorAll(n)))) | |
return y | |
} | |
return null | |
}, | |
articleDateElement : function() { | |
return this._articleDateElement | |
}, | |
findArticleDateElement : function() { | |
function e(e) | |
{ | |
for (var t = e; t && t !== l; t = t.parentElement) | |
if (elementIsCommentBlock(t) || elementLooksLikeACarousel(t)) | |
return !0; | |
return !1 | |
} | |
function t(t) | |
{ | |
for (var n, i = null, r = t.length, a = 0; a < r; ++a) { | |
var l = t[a]; | |
if (isElementVisible(l) && !e(l)) { | |
var o = cachedElementBoundingRect(l), | |
s = o.left + o.width / 2, | |
d = o.top + o.height / 2, | |
h = c - s, | |
u = m - d, | |
g = Math.sqrt(h * h + u * u); | |
(!i || g < n) && (i = l, n = g) | |
} | |
} | |
return i | |
} | |
const n = /date/i, | |
i = "time, .dateline, .entry-date"; | |
var r, a = this._articleSubheadElement || this._articleTitleElement, | |
l = this.article.element, | |
o = a ? a.nextElementSibling : null; | |
if (o && 1 === (r = o.querySelectorAll(i)).length && (o = r[0]), !o || o.matches(i) || hasClassMatchingRegexp(o, n) || o.querySelector(i) || (o = null), o && o.contains(l) && (o = null), o) | |
return o; | |
if (a) | |
var s, c = (s = a ? cachedElementBoundingRect(a) : null).left + s.width / 2, | |
m = s.top + s.height / 2; | |
if ((r = l.querySelectorAll(i)).length) | |
return t(r); | |
if ((l = l.closest("article")) && (r = l.querySelectorAll(i)).length) | |
return t(r); | |
return null | |
}, | |
articleDateElementWithBylineElementHint : function(e) { | |
function t(e) | |
{ | |
return /date/.test(e.className) || /\bdatePublished\b/.test(e.getAttribute("itemprop")) | |
} | |
var n = e.nextElementSibling; | |
if (n && t(n)) | |
return n; | |
var i = nextLeafElementForElement(e); | |
return i && t(i) ? i : null | |
}, | |
updateArticleBylineAndDateElementsIfNecessary : function() { | |
this.article && (this._didArticleBylineAndDateElementDetection || (this.updateArticleBylineAndDateElements(), this._didArticleBylineAndDateElementDetection = !0)) | |
}, | |
updateArticleBylineAndDateElements : function() { | |
var e = this.findArticleBylineElement(), | |
t = this.findArticleDateElement(); | |
!t && e && (t = this.articleDateElementWithBylineElementHint(e)), this._articleDateElement = t, this._articleBylineElement = e | |
}, | |
articleIsLTR : function() { | |
if (!this._articleIsLTR) { | |
var e = getComputedStyle(this.article.element); | |
this._articleIsLTR = !e || "ltr" === e.direction | |
} | |
return this._articleIsLTR | |
}, | |
findSuggestedCandidate : function() { | |
var e, t, n = this.suggestedRouteToArticle; | |
if (!n || !n.length) | |
return null; | |
for (t = n.length - 1; t >= 0 && (!n[t].id || !(e = this.contentDocument.getElementById(n[t].id))); --t) | |
; | |
for (t++, e || (e = this.contentDocument); t < n.length;) { | |
for (var i = n[t], r = e.nodeType === Node.DOCUMENT_NODE ? e.documentElement : e.firstElementChild, a = 1; r && a < i.index; r = r.nextElementSibling) | |
this.shouldIgnoreInRouteComputation(r) || a++; | |
if (!r) | |
return null; | |
if (normalizedElementTagName(r) !== normalizedElementTagName(i)) | |
return null; | |
if (i.className && r.className !== i.className) | |
return null; | |
e = r, t++ | |
} | |
return isElementVisible(e) ? new CandidateElement(e, this.contentDocument) : null | |
}, | |
findArticleBySearchingAllElements : function(e) { | |
var t = this.findSuggestedCandidate(), | |
n = this.findCandidateElements(); | |
if (!n || !n.length) | |
return t; | |
if (t && t.basicScore() >= ReaderMinimumScore) | |
return t; | |
for (var i = this.highestScoringCandidateFromCandidates(n), r = i.element; r !== this.contentDocument; r = r.parentNode) | |
if ("blockquote" === normalizedElementTagName(r)) { | |
for (var a = r.parentNode, l = n.length, o = 0; o < l; ++o) { | |
var s = n[o]; | |
if (s.element === a) { | |
i = s; | |
break | |
} | |
} | |
break | |
} | |
if (t && i.finalScore() < ReaderMinimumScore) | |
return t; | |
if (!e) { | |
if (i.shouldDisqualifyDueToScoreDensity()) | |
return null; | |
if (i.shouldDisqualifyDueToHorizontalRuleDensity()) | |
return null; | |
if (i.shouldDisqualifyDueToHeaderDensity()) | |
return null; | |
if (i.shouldDisqualifyDueToSimilarElements(n)) | |
return null | |
} | |
return i | |
}, | |
findExtraArticle : function() { | |
if (!this.article) | |
return null; | |
for (var e = 0, t = this.article.element; e < 3 && t; ++e, t = t.parentNode) { | |
var n = this.findExtraArticleCandidateElements(t); | |
if (n && n.length) | |
for (var i, r = this.sortCandidateElementsInDescendingScoreOrder(n), a = 0; a < r.length && ((i = r[a]) && i.basicScore()); a++) | |
if (!i.shouldDisqualifyDueToScoreDensity() && !i.shouldDisqualifyDueToHorizontalRuleDensity() && !(i.shouldDisqualifyDueToHeaderDensity() || cachedElementBoundingRect(i.element).height < PrependedArticleCandidateMinimumHeight && cachedElementBoundingRect(this.article.element).width !== cachedElementBoundingRect(i.element).width)) { | |
var l = contentTextStyleForNode(this.contentDocument, i.element); | |
if (l && l.fontFamily === this.contentTextStyle().fontFamily && l.fontSize === this.contentTextStyle().fontSize && i) | |
return i | |
} | |
} | |
return null | |
}, | |
highestScoringCandidateFromCandidates : function(e) { | |
for (var t = 0, n = null, i = e.length, r = 0; r < i; ++r) { | |
var a = e[r], | |
l = a.basicScore(); | |
l >= t && (t = l, n = a) | |
} | |
return n | |
}, | |
sortCandidateElementsInDescendingScoreOrder : function(e) { | |
function t(e, t) | |
{ | |
return e.basicScore() !== t.basicScore() ? t.basicScore() - e.basicScore() : t.depth() - e.depth() | |
} | |
return e.sort(t) | |
}, | |
findCandidateElements : function() { | |
const e = 1e3; | |
for (var t = Date.now() + e, n = this.contentDocument.getElementsByTagName("*"), i = n.length, r = [], a = 0; a < i; ++a) { | |
var l = n[a]; | |
if (!SetOfCandidateTagNamesToIgnore.has(normalizedElementTagName(l))) { | |
var o = CandidateElement.candidateIfElementIsViable(l, this.contentDocument); | |
if (o && r.push(o), Date.now() > t) { | |
r = []; | |
break | |
} | |
} | |
} | |
var s = r.length; | |
for (a = 0; a < s; ++a) | |
r[a].element.candidateElement = r[a]; | |
for (a = 0; a < s; ++a) { | |
var c = r[a]; | |
if ("blockquote" === normalizedElementTagName(c.element)) { | |
var m = c.element.parentElement.candidateElement; | |
m && m.addTextNodesFromCandidateElement(c) | |
} | |
} | |
for (a = 0; a < s; ++a) | |
r[a].element.candidateElement = null; | |
return r | |
}, | |
findExtraArticleCandidateElements : function(e) { | |
if (!this.article) | |
return []; | |
e || (e = this.article.element); | |
for (var t = "preceding-sibling::*/descendant-or-self::*", n = this.contentDocument.evaluate(t, e, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null), i = n.snapshotLength, r = [], a = 0; a < i; ++a) { | |
var l = n.snapshotItem(a); | |
if (!SetOfCandidateTagNamesToIgnore.has(normalizedElementTagName(l))) | |
(o = CandidateElement.extraArticleCandidateIfElementIsViable(l, this.article, this.contentDocument, !0)) && r.push(o) | |
} | |
t = "following-sibling::*/descendant-or-self::*", i = (n = this.contentDocument.evaluate(t, e, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)).snapshotLength; | |
for (a = 0; a < i; ++a) { | |
var o; | |
l = n.snapshotItem(a); | |
if (!SetOfCandidateTagNamesToIgnore.has(normalizedElementTagName(l))) | |
(o = CandidateElement.extraArticleCandidateIfElementIsViable(l, this.article, this.contentDocument, !1)) && r.push(o) | |
} | |
return r | |
}, | |
isGeneratedBy : function(e) { | |
var t = this.contentDocument.head ? this.contentDocument.head.querySelector("meta[name=generator]") : null; | |
if (!t) | |
return !1; | |
var n = t.content; | |
return !!n && e.test(n) | |
}, | |
isMediaWikiPage : function() { | |
return void 0 === this._isMediaWikiPage && (this._isMediaWikiPage = this.isGeneratedBy(/^MediaWiki /)), this._isMediaWikiPage | |
}, | |
isWordPressSite : function() { | |
return this.isGeneratedBy(/^WordPress/) | |
}, | |
isAMPPage : function() { | |
return this.contentDocument.documentElement.hasAttribute("amp-version") | |
}, | |
nextPageURLString : function() { | |
if (!this.article) | |
return null; | |
if (this.isMediaWikiPage()) | |
return null; | |
var e, t = 0, | |
n = this.article.element; | |
n.parentNode && "inline" === getComputedStyle(n).display && (n = n.parentNode); | |
for (var i = n, r = cachedElementBoundingRect(n).bottom + LinkMaxVerticalDistanceFromArticle; isElementNode(i) && cachedElementBoundingRect(i).bottom <= r;) | |
i = i.parentNode; | |
i === n || i !== this.contentDocument && !isElementNode(i) || (n = i); | |
var a = this.contentDocument.evaluate(LinkCandidateXPathQuery, n, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null), | |
l = a.snapshotLength; | |
if (this.pageNumber <= 2 && !this.prefixWithDateForNextPageURL) { | |
var o = this.contentDocument.location.pathname, | |
s = o.match(LinkDateRegex); | |
s && (s = s[0], this.prefixWithDateForNextPageURL = o.substring(0, o.indexOf(s) + s.length)) | |
} | |
for (var c = 0; c < l; ++c) { | |
var m = a.snapshotItem(c), | |
d = this.scoreNextPageLinkCandidate(m); | |
d > t && (e = m, t = d) | |
} | |
return e ? e.href : null | |
}, | |
scoreNextPageLinkCandidate : function(e) { | |
function t(e, t, n, i) | |
{ | |
t.substring(0, e.length) === e && (t = t.substring(e.length), e = ""); | |
var r = t.lastInteger(); | |
if (isNaN(r)) | |
return !1; | |
var a = e ? e.lastInteger() : NaN; | |
return (isNaN(a) || a >= MaximumExactIntegralValue) && (a = i), r === a ? n.lastInteger() === a + 1 : r === a + 1 | |
} | |
function n(e) | |
{ | |
for (var t = {}, n = e.substring(1).split("&"), i = n.length, r = 0; r < i; ++r) { | |
var a = n[r], | |
l = a.indexOf("="); | |
-1 === l ? t[a] = null : t[a.substring(0, l)] = a.substring(l + 1) | |
} | |
return t | |
} | |
var i = this.contentDocument.location; | |
if (e.host !== i.host) | |
return 0; | |
if (e.pathname === i.pathname && e.search === i.search) | |
return 0; | |
if (-1 !== e.toString().indexOf("#")) | |
return 0; | |
if (anchorLinksToAttachment(e) || anchorLinksToTagOrCategoryPage(e)) | |
return 0; | |
if (!isElementVisible(e)) | |
return 0; | |
var r = cachedElementBoundingRect(e), | |
a = this.articleBoundingRect(), | |
l = Math.max(0, Math.max(a.top - (r.top + r.height), r.top - (a.top + a.height))); | |
if (r.top < a.top) | |
return 0; | |
if (l > LinkMaxVerticalDistanceFromArticle) | |
return 0; | |
if (Math.max(0, Math.max(a.left - (r.left + r.width), r.left - (a.left + a.width))) > 0) | |
return 0; | |
var o = i.pathname, | |
s = e.pathname; | |
if (this.prefixWithDateForNextPageURL) { | |
if (-1 === e.pathname.indexOf(this.prefixWithDateForNextPageURL)) | |
return 0; | |
o = o.substring(this.prefixWithDateForNextPageURL.length), s = s.substring(this.prefixWithDateForNextPageURL.length) | |
} | |
var c = s.substring(1).split("/"); | |
c[c.length - 1] || c.pop(); | |
var m = c.length, | |
d = o.substring(1).split("/"), | |
h = !1; | |
d[d.length - 1] || (h = !0, d.pop()); | |
var u = d.length; | |
if (m < u) | |
return 0; | |
for (var g = 0, f = 0, p = e.textContent, E = 0; E < m; ++E) { | |
var v = c[E], | |
T = E < u ? d[E] : ""; | |
if (T !== v) { | |
if (E < u - 2) | |
return 0; | |
if (v.length >= T.length) { | |
for (var y = 0; v[v.length - 1 - y] === T[T.length - 1 - y];) | |
y++; | |
y && (v = v.substring(0, v.length - y), T = T.substring(0, T.length - y)); | |
var S = v.indexOf(T); | |
-1 !== S && (v = v.substring(S)) | |
} | |
t(T, v, p, this.pageNumber) ? f = Math.pow(LinkNextOrdinalValueBase, E - m + 1) : g++ | |
} | |
if (g > 1) | |
return 0 | |
} | |
var A = !1; | |
if (e.search) | |
for (var N in linkParameters = n(e.search), referenceParameters = n(i.search), linkParameters) { | |
var b = linkParameters[N], | |
x = N in referenceParameters ? referenceParameters[N] : null; | |
if (x !== b) | |
if (null === x && (x = ""), null === b && (b = ""), b.length < x.length) | |
g++; | |
else if (t(x, b, p, this.pageNumber)) { | |
if (LinkURLSearchParameterKeyMatchRegex.test(N)) { | |
if (o.toLowerCase() !== s.toLowerCase()) | |
return 0; | |
if (this.isWordPressSite() && h) | |
return 0; | |
A = !0 | |
} | |
if (LinkURLBadSearchParameterKeyMatchRegex.test(N)) { | |
g++; | |
continue | |
} | |
f = Math.max(f, 1 / LinkNextOrdinalValueBase) | |
} else | |
g++ | |
} | |
if (!f) | |
return 0; | |
if ((LinkURLPageSlashNumberMatchRegex.test(e.href) || LinkURLSlashDigitEndMatchRegex.test(e.href)) && (A = !0), !A && m === u && stringSimilarity(o, s) < LinkMinimumURLSimilarityRatio) | |
return 0; | |
if (LinkURLArchiveSlashDigitEndMatchRegex.test(e)) | |
return 0; | |
var C = LinkMatchWeight * (Math.pow(LinkMismatchValueBase, -g) + f) + LinkVerticalDistanceFromArticleWeight * l / LinkMaxVerticalDistanceFromArticle; | |
A && (C += LinkURLSemanticMatchBonus), "li" === normalizedElementTagName(e.parentNode) && (C += LinkListItemBonus); | |
p = e.innerText; | |
return LinkNextMatchRegEx.test(p) && (C += LinkNextMatchBonus), LinkPageMatchRegEx.test(p) && (C += LinkPageMatchBonus), LinkContinueMatchRegEx.test(p) && (C += LinkContinueMatchBonus), C | |
}, | |
elementContainsEnoughTextOfSameStyle : function(e, t, n) { | |
const i = 110; | |
var r = "body" === normalizedElementTagName(e), | |
a = getVisibleNonWhitespaceTextNodes(e, r ? 2 : 3, i, r, t); | |
const l = .2, | |
o = n / clamp(scoreMultiplierForElementTagNameAndAttributes(e), l, 1 / 0) / languageScoreMultiplierForTextNodes(a); | |
for (var s = {}, c = a.length, m = 0; m < c; ++m) { | |
var d = a[m], | |
h = d.length, | |
u = d.parentElement, | |
g = window.getComputedStyle(u), | |
f = g.fontFamily + "|" + g.fontSize, | |
p = Math.pow(h, TextNodeLengthPower); | |
if (s[f]) { | |
if ((s[f] += p) > o) | |
break | |
} else | |
s[f] = p | |
} | |
for (var f in s) | |
if (s[f] > o) | |
return !0; | |
return !1 | |
}, | |
openGraphMetadataClaimsPageTypeIsArticle : function() { | |
if (!this._openGraphMetadataClaimsPageTypeIsArticle) { | |
var e = this.contentDocument.querySelector("head meta[property='og:type']"); | |
this._openGraphMetadataClaimsPageTypeIsArticle = e && "article" === e.content | |
} | |
return this._openGraphMetadataClaimsPageTypeIsArticle | |
}, | |
prismGenreClaimsPageIsHomepage : function() { | |
return "homePage" === this.contentFromUniqueMetadataSelector(this.contentDocument, "head meta[name='prism.genre']") | |
}, | |
pointsToUseForHitTesting : function() { | |
const e = window.innerWidth, | |
t = e / 4, | |
n = e / 2, | |
i = 128, | |
r = 320; | |
var a = [ | |
[ n, 800 ], | |
[ n, 600 ], | |
[ t, 800 ], | |
[ n, 400 ], | |
[ n - i, 1100 ], | |
[ r, 700 ], | |
[ 3 * t, 800 ], | |
[ e - r, 700 ] | |
]; | |
return this.openGraphMetadataClaimsPageTypeIsArticle() && a.push([ n - i, 1400 ]), a | |
}, | |
findArticleByVisualExamination : function() { | |
for (var e = new Set, t = this.pointsToUseForHitTesting(), n = t.length, i = AppleDotComAndSubdomainsRegex.test(this.contentDocument.location.hostname.toLowerCase()) ? 7200 : 1800, r = this.candidateElementFilter, a = 0; a < n; a++) | |
for (var l = t[a][0], o = t[a][1], s = elementAtPoint(l, o, this.contentDocument); s && !e.has(s); s = s.parentElement) { | |
if (VeryPositiveClassNameRegEx.test(s.className)) | |
return new CandidateElement(s, this.contentDocument); | |
if (!SetOfCandidateTagNamesToIgnore.has(normalizedElementTagName(s))) { | |
var c = s.offsetWidth, | |
m = s.offsetHeight; | |
if (!c && !m) { | |
var d = cachedElementBoundingRect(s); | |
c = d.width, m = d.height | |
} | |
if (!(c < r.minimumWidth || m < r.minimumHeight || c * m < r.minimumArea)) { | |
var h = this.elementContainsEnoughTextOfSameStyle(s, e, i); | |
if (e.add(s), h && !(CandidateElement.candidateElementAdjustedHeight(s) < r.minimumHeight)) { | |
var u = new CandidateElement(s, this.contentDocument); | |
if (!u.shouldDisqualifyDueToSimilarElements()) { | |
if (u.shouldDisqualifyDueToHorizontalRuleDensity()) | |
return null; | |
if (u.shouldDisqualifyDueToHeaderDensity()) | |
return null; | |
if (!u.shouldDisqualifyForDeepLinking()) | |
return u | |
} | |
} | |
} | |
} | |
} | |
return null | |
}, | |
findTextSamplesByVisualExamination : function() { | |
function e(e) | |
{ | |
if (!e || !e.innerText) | |
return null; | |
let n = t(e.innerText.trim()); | |
return n && a.add(e), n | |
} | |
function t(e) | |
{ | |
const t = 10; | |
let i = textContentAppearsToBeCJK(e, d) ? d : m, | |
r = e.length; | |
if (r < i) | |
return null; | |
if (r > f * c) | |
return null; | |
let a = n(e); | |
return (a.match(/\n/g) || []).length > t ? null : a | |
} | |
function n(e) | |
{ | |
return e.substring(0, h) | |
} | |
function i(t, n) | |
{ | |
let i = [], | |
r = s.querySelectorAll(t); | |
for (let t of r) { | |
if (i.length >= n) | |
break; | |
if (elementDescendsFromElementInSet(t, l)) | |
continue; | |
let r = e(t); | |
r && i.push([ t, r ]) | |
} | |
return i | |
} | |
function r(e) | |
{ | |
const n = document.querySelectorAll("div"), | |
i = new Set; | |
for (let r of n) { | |
if (r.firstElementChild) | |
continue; | |
let n = t(r.textContent); | |
if (n && (i.add(n), i.size >= e)) | |
break | |
} | |
return i | |
} | |
this.setSuppressBoundingRectCalculationForSkippedElements(!0); | |
var a = new Set, | |
l = new Set, | |
o = new Set, | |
s = this.contentDocument, | |
c = s.body.innerText.length; | |
const m = 20, | |
d = 10, | |
h = 200, | |
u = 5, | |
g = 5, | |
f = .8; | |
let p = s.title, | |
E = t(p); | |
E && (o.add(E), l.add(p)); | |
let v = this.pointsToUseForHitTesting(), | |
T = v.length; | |
for (var y = 0; y < T; y++) { | |
let t = v[y][0], | |
n = v[y][1], | |
i = 0; | |
for (let r = elementAtPoint(t, n, this.contentDocument); r && !a.has(r) && !(i > u); r = r.parentElement, i++) { | |
let t = e(r); | |
if (t) { | |
if (elementDescendsFromElementMatchingSelector(r, "code, form")) | |
break; | |
o.add(t), l.add(r); | |
break | |
} | |
} | |
} | |
let S = { | |
p : 3, | |
h1 : 2, | |
h2 : 2, | |
h3 : 1 | |
}; | |
for (let [e, t] of Object.entries(S)) { | |
let n = i(e, t); | |
for (let [e, t] of n) | |
e && t && (o.add(t), l.add(e)) | |
} | |
if (o.size < g) { | |
let e = [ "article", "header", "a", "footer", "body" ]; | |
for (let t of e) { | |
let e = i(t, 1) || [], | |
[ n, r ] = e.length > 0 ? e[0] : [ null, null ]; | |
if (n && r) { | |
o.add(r), l.add(n); | |
break | |
} | |
} | |
} | |
if (o.size < g) { | |
const e = r(g - o.size); | |
o = o.union(e) | |
} | |
return Array.from(o) | |
}, | |
findArticleFromMetadata : function(e) { | |
var t = this.contentDocument.querySelectorAll(SchemaDotOrgArticleContainerSelector); | |
if (1 === t.length) { | |
var n = t[0]; | |
if (n.matches("article, *[itemprop=articleBody]")) | |
if (o = CandidateElement.candidateIfElementIsViable(n, this.contentDocument, !0)) | |
return e === FindArticleMode.ExistenceOfElement || o; | |
var i = n.querySelectorAll("article, *[itemprop=articleBody]"), | |
r = elementWithLargestAreaFromElements(i); | |
if (r) | |
if (o = CandidateElement.candidateIfElementIsViable(r, this.contentDocument, !0)) | |
return e === FindArticleMode.ExistenceOfElement || o; | |
return new CandidateElement(n, this.contentDocument) | |
} | |
if (this.openGraphMetadataClaimsPageTypeIsArticle() && !this.prismGenreClaimsPageIsHomepage()) { | |
var a = this.contentDocument.querySelectorAll("main article"), | |
l = elementWithLargestAreaFromElements(a); | |
if (l) | |
if (o = CandidateElement.candidateIfElementIsViable(l, this.contentDocument, !0)) | |
return e === FindArticleMode.ExistenceOfElement || o; | |
var o, s = this.contentDocument.querySelectorAll("article"); | |
if (1 === s.length) | |
if (o = CandidateElement.candidateIfElementIsViable(s[0], this.contentDocument, !0)) | |
return e === FindArticleMode.ExistenceOfElement || o | |
} | |
return null | |
}, | |
articleTextContent : function() { | |
return this._articleTextContent || this.adoptableArticle(), this._articleTextContent | |
}, | |
unformattedArticleTextContentIncludingMetadata : function(e) { | |
this.setSuppressBoundingRectCalculationForSkippedElements(!0); | |
var t = this.articleNode(); | |
if (t) { | |
if (!e) | |
return t.innerText; | |
var n = "", | |
i = this.articleTitle(); | |
i && (n += i + "\n"); | |
var r = this.articleSubhead(); | |
r && (n += r + "\n"); | |
var a = this.adoptableMetadataBlock(); | |
return a && (n += this.plaintextVersionOfNodeAppendingNewlinesBetweenBlockElements(a) + "\n"), n + t.innerText | |
} | |
}, | |
plaintextVersionOfNodeAppendingNewlinesBetweenBlockElements : function(e) { | |
var t = this.contentDocument.createTreeWalker(e, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, null), | |
n = ""; | |
for (t.currentNode = e; t.nextNode();) { | |
var i = t.currentNode; | |
if (i.nodeType !== Node.TEXT_NODE) { | |
var r = normalizedElementTagName(i); | |
"p" !== r && "div" !== r || (n += "\n") | |
} else | |
n += i.textContent | |
} | |
return n | |
}, | |
pageDescription : function() { | |
for (var e = this.contentDocument.querySelectorAll("head meta[name]"), t = e.length, n = 0; n < t; ++n) { | |
var i = e[n]; | |
if ("description" === i.getAttribute("name").toLowerCase()) { | |
var r = i.getAttribute("content"); | |
if (r) | |
return r.trim() | |
} | |
} | |
return null | |
}, | |
articleTitleAndSiteNameFromTitleString : function(e) { | |
const t = [ " - ", " \u2013 ", " \u2014 ", ": ", " | ", " \xbb " ], | |
n = t.length, | |
i = .6; | |
for (var r, a, l = this.contentDocument.location.host.replace(/^(www|m|secure)\./, ""), o = l.replace(/\.(com|info|net|org|edu|gov)$/, "").toLowerCase(), s = 0; s < n; ++s) { | |
var c = e.split(t[s]); | |
if (2 === c.length) { | |
var m = c[0].trim(), | |
d = c[1].trim(), | |
h = m.toLowerCase(), | |
u = d.toLowerCase(), | |
g = Math.max(stringSimilarity(h, l), stringSimilarity(h, o)), | |
f = Math.max(stringSimilarity(u, l), stringSimilarity(u, o)), | |
p = Math.max(g, f); | |
(!a || p > a) && (a = p, r = g > f ? { | |
siteName : m, | |
articleTitle : d | |
} | |
: { | |
siteName : d, | |
articleTitle : m | |
}) | |
} | |
} | |
return r && a >= i ? r : null | |
}, | |
pageInformation : function(e, t) { | |
var n, i = this.pageDescription(), | |
r = !1; | |
this.adoptableArticle() ? (n = this.articleTitle(), i = i || this.articleTextContent(), r = !0) : (n = this.contentDocument.title, this.contentDocument.body && (i = i || this.contentDocument.body.innerText)); | |
var a = "", | |
l = this.buildMapOfMetaTags(), | |
o = this.pageImageURLFromMetadata(l); | |
if (o) | |
a = o; | |
else { | |
var s = this.mainImageNode(); | |
s && (a = s.src) | |
} | |
n || (n = userVisibleURLString(this.contentDocument.location.href)), n = n.trim(), e && (n = n.substring(0, e)); | |
var c = this.contentFromUniqueMetadataSelector(this.contentDocument, "head meta[property='og:site_name']"); | |
if (!c) { | |
var m = this.articleTitleAndSiteNameFromTitleString(this.contentDocument.title); | |
m && m.articleTitle === n && (c = m.siteName) | |
} | |
return c || (c = ""), i = i ? i.trim() : "", t && (i = i.substring(0, t)), | |
{ | |
title: n, | |
previewText: i = i.replace(/[\s]+/g, " "), | |
siteName: c, | |
mainImageURL: a, | |
isReaderAvailable: r | |
} | |
}, | |
readingListItemInformation : function() { | |
const e = 220, | |
t = 220; | |
return this.pageInformation(e, t) | |
}, | |
buildMapOfMetaTags : function() { | |
var e = {}; | |
const t = this.contentDocument.head.getElementsByTagName("meta"), | |
n = t.length; | |
for (var i = 0; i < n; ++i) { | |
const n = t[i], | |
r = n.content; | |
if (!r) | |
continue; | |
if (this.elementAttributesContainImproperQuote(n)) | |
continue; | |
n.name && (e["name:" + n.name.toLowerCase()] = r); | |
const a = n.getAttribute("property"); | |
a && (e["property:" + a.toLowerCase()] = r) | |
} | |
return e | |
}, | |
longestPageMetadataDescriptionForTextAnalysis : function(e) { | |
var t = []; | |
const n = e["name:description"]; | |
n && n.length && t.push(n); | |
const i = e["property:og:description"]; | |
i && i.length && t.push(i); | |
const r = e["name:twitter:description"]; | |
return r && r.length && t.push(r), t.length ? t.reduce((function(e, t) { | |
return e.length > t.length ? e : t | |
})) | |
: null | |
}, | |
pageTypeForTextAnalysis : function(e) { | |
const t = this.contentDocument.documentElement.getAttribute("itemtype"); | |
if ("http://schema.org/SearchResultsPage" === t || "https://schema.org/SearchResultsPage" === t) | |
return PageType.searchResults; | |
const n = e["name:section"]; | |
if (n && "homepage" === n.toLowerCase()) | |
return PageType.homepage; | |
const i = e["property:og:type"]; | |
if (i) { | |
const e = i.toLowerCase(); | |
if ("homepage" === e) | |
return PageType.homepage; | |
if ("article" === e) | |
return PageType.article | |
} | |
const r = e["property:analytics-s-channel"]; | |
return r && "homepage" === r.toLowerCase() ? PageType.homepage : null | |
}, | |
pageTitleForTextAnalysis : function(e) { | |
const t = this.contentDocument; | |
var n = e["property:og:title"]; | |
return n || (n = e["name:twitter:title"]), n || (n = e["name:sailthru.headline"]), n || (n = t.title), n | |
}, | |
pageKeywordsForTextAnalysis : function(e) { | |
return e["name:keywords"] | |
}, | |
pageAuthorForTextAnalysis : function(e) { | |
return e["name:author"] || e["property:author"] | |
}, | |
pageMetadataCommonToTextAnalysisAndArticleContent : function() { | |
var e = {}; | |
const t = this.buildMapOfMetaTags(), | |
n = this.pageTitleForTextAnalysis(t); | |
n && (e.title = n); | |
const i = this.pageAuthorForTextAnalysis(t); | |
i && (e.author = i); | |
const r = this.pageImageURLFromMetadata(t); | |
return r && (e.imageURL = r), e | |
}, | |
pageMetadataForTextAnalysis : function() { | |
let e = this.pageMetadataCommonToTextAnalysisAndArticleContent(); | |
const t = this.pageTypeForTextAnalysis(metadataMap); | |
t && (e.type = t); | |
const n = this.longestPageMetadataDescriptionForTextAnalysis(metadataMap); | |
n && (e.description = n); | |
const i = this.pageKeywordsForTextAnalysis(metadataMap); | |
return i && (e.keywords = i), e | |
}, | |
extractedArticleContent : function() { | |
try { | |
const e = this.adoptableArticle(!0), | |
t = this.elementReaderUniqueIDAttributeKey(); | |
for (let n of e.getElementsByTagName("*")) | |
n.removeAttribute(t); | |
let n = this.pageMetadataCommonToTextAnalysisAndArticleContent(); | |
if (e) { | |
const t = e.innerHTML; | |
n.body = t | |
} | |
this.updateArticleBylineAndDateElementsIfNecessary(); | |
const i = this.articleDateElement(); | |
i && (n.publishedDate = trimmedInnerTextIgnoringTextTransform(i)); | |
const r = this.articleBylineElement(); | |
return !n.author && r && (n.author = trimmedInnerTextIgnoringTextTransform(r)), n | |
} catch (e) { | |
let t = {}; | |
const n = e.message, | |
i = e.stack; | |
return n && (t.error = n), i && (t.stack = i), t | |
} | |
}, | |
readerUniqueIDOfElementPinnedToTopOfViewport : function() { | |
const e = 120; | |
if (window.scrollY < e) | |
return null; | |
const t = this.articleNode(); | |
if (!t) | |
return null; | |
const n = t.getBoundingClientRect(), | |
i = (n.left + n.right) / 2; | |
for (const e of [0, 15, 35, 50, 80, 110]) { | |
const n = t.ownerDocument.elementFromPoint(i, e); | |
if (n !== t && (t.contains(n) || n === this._articleTitleElement || n === this._articleSubheadElement)) { | |
const e = this._weakMapOfOriginalElementToUniqueID.get(n); | |
if (e) | |
return e | |
} | |
} | |
return null | |
}, | |
elementReaderUniqueIDAttributeKey : function() { | |
return "data-reader-unique-id" | |
}, | |
titleUniqueID : function() { | |
return "titleElement" | |
}, | |
subheadUniqueID : function() { | |
return "subheadElement" | |
}, | |
rectOfElementWithReaderUniqueID : function(e) { | |
function t(e) | |
{ | |
return | |
{ | |
top: e.top + window.scrollY, | |
right: e.right + window.scrollX, | |
bottom: e.bottom + window.scrollY, | |
left: e.left + window.scrollX, | |
width: e.width, | |
height: e.height | |
} | |
} | |
if (!this._mapOfUniqueIDToOriginalElement) | |
return null; | |
let n = this._mapOfUniqueIDToOriginalElement.get(e); | |
return n && n.parentElement ? t(n.getBoundingClientRect()) : null | |
}, | |
scrollY : function() { | |
return window.scrollY | |
}, | |
scrollToOffset : function(e) { | |
if ("number" == typeof e) | |
try { | |
clearCachedElementBoundingRects(), this.cacheWindowScrollPosition(), this.contentDocument.scrollingElement.scrollTop = e | |
} catch (e) { | |
} | |
}, | |
documentURLString : function() { | |
return this.contentDocument.location.href | |
}, | |
usesSearchEngineOptimizationMetadata : function() { | |
return !!document.head.querySelector('meta[property^="og:"]') | |
}, | |
extractCanonicalLink : function() { | |
var e = document.head.querySelector("link[rel='canonical']"); | |
if (!e) | |
return null; | |
var t = e.getAttribute("href"); | |
if (!t) | |
return null; | |
var n = document.baseURI, | |
i = urlFromString(t, n); | |
return "/" !== document.location.pathname && "/" === i.pathname || "localhost" === i.hostname && "localhost" !== document.location.hostname ? null : i.href | |
}, | |
setSuppressBoundingRectCalculationForSkippedElements : function(e) { | |
this._shouldSuppressBoundingRectCalculationForSkippedElements = e | |
}, | |
shouldSuppressBoundingRectCalculationForSkippedElements : function() { | |
return !!this._shouldSuppressBoundingRectCalculationForSkippedElements | |
} | |
}; | |
var ReaderArticleFinderJS = new ReaderArticleFinder(document); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta name="disabled-adaptations" content="watch"> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> | |
<meta name="viewport" content="initial-scale=1"> | |
<base> | |
<title>Reader</title> | |
<style id="assistant-content"> | |
#summary-container { | |
pointer-events: auto; | |
-webkit-user-select: auto; | |
background: transparent; | |
} | |
#summary-header { | |
padding-top: 30px; | |
margin: 0px; | |
line-height: 1.6em; | |
} | |
#summary-text { | |
padding-top: 4px; | |
margin: 0px; | |
line-height: 1.6em; | |
padding-bottom: 30px | |
} | |
#tableOfContents-container { | |
padding-bottom: 34px; | |
} | |
#tableOfContents-header { | |
margin: 0px; | |
line-height: 1.6em; | |
padding-top: 30px | |
} | |
#tableOfContents-list { | |
margin-left: 0px; | |
margin-right: 0px; | |
margin-top: 4px; | |
padding-left: 1.8em; | |
line-height: 1.6em; | |
} | |
.innerTableOfContents-listItem { | |
border-bottom: 1px solid var(--separator-color); | |
margin-bottom: 6px; | |
margin-top: 6px; | |
} | |
.innerTableOfContents-listItem:last-child { | |
border-bottom: none; | |
} | |
.collapsible { | |
cursor: pointer; | |
font-weight: 600; | |
padding-left: 16px; | |
padding-top: 18px; | |
padding-bottom: 18px; | |
padding-right: 0px; | |
width: 100%; | |
outline: none | |
overflow: hidden; | |
background: transparent; | |
background-repeat: no-repeat; | |
text-align: left; | |
border: none; | |
-webkit-tap-highlight-color: transparent; | |
} | |
.collapsible:nth-of-type(2):not(:first-of-type) { | |
border-top: 1px solid var(--separator-color); | |
} | |
.collapsible:after { | |
content: url('data:image/svg+xml,<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="7.15323" height="12.4569"><g><rect height="12.4569" opacity="0" width="7.15323" x="0" y="0"/><path d="M7.15323 6.22406C7.15165 5.96742 7.06077 5.74734 6.85599 5.54414L1.51768 0.255233C1.35263 0.0829682 1.14362 0 0.897181 0C0.395505 0 0 0.386716 0 0.885228C0 1.12446 0.105292 1.35175 0.272634 1.53034L5.01961 6.22248L0.272634 10.9178C0.106874 11.0964 0 11.3164 0 11.5645C0 12.063 0.395505 12.4497 0.897181 12.4497C1.14204 12.4497 1.35263 12.3667 1.51768 12.1945L6.85599 6.90397C7.06235 6.70077 7.15323 6.47911 7.15323 6.22406Z" fill="%23868686" fill-opacity="0.95"/></g></svg>'); | |
width: 12px; | |
height: 12px; | |
float: right; | |
padding-left: 12px; | |
padding-right: 22px; | |
} | |
.collapsedContent { | |
margin: 0; | |
padding: 0; | |
max-height: 0; | |
overflow: auto; | |
padding-left: 16px; | |
margin-right: 1.25em; | |
transition: max-height 0.2s ease-out; | |
} | |
.expandedContent:after { | |
content:url('data:image/svg+xml,<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12.4569" height="7.76214"><g><rect height="7.76214" opacity="0" width="12.4569" x="0" y="0"/><path d="M6.23285 7.76214C6.48949 7.76056 6.72239 7.6681 6.91276 7.4649L12.2017 2.12501C12.3667 1.95995 12.4569 1.75095 12.4569 1.50451C12.4569 1.00283 12.0702 0.607328 11.5717 0.607328C11.3324 0.607328 11.098 0.71262 10.9266 0.879962L5.86564 5.99169L6.5976 5.99169L1.53192 0.879962C1.36054 0.714202 1.14046 0.607328 0.892435 0.607328C0.393923 0.607328 0 1.00283 0 1.50451C0 1.74937 0.0917573 1.95837 0.255233 2.12501L5.55293 7.4649C5.75051 7.66968 5.97058 7.76214 6.23285 7.76214Z" fill="%23868686" fill-opacity="0.95"/></g></svg>'); | |
width: 12px; | |
height: 12px; | |
padding-right: 30px; | |
} | |
#innerAssistantContainer { | |
margin-top: 21px; | |
margin-bottom: 21px; | |
border-radius: 22px; | |
background: var(--narrow-assistant-background-color); | |
} | |
#onDeviceSummaryButton { | |
cursor: pointer; | |
font-weight: bold; | |
padding-left: 16px; | |
padding-right: 22px; | |
padding-top: 15px; | |
padding-bottom: 12px; | |
width: 100%; | |
outline: none | |
overflow: hidden; | |
background: var(--narrow-assistant-background-color); | |
background-repeat: no-repeat; | |
text-align: left; | |
font-size: 16px; | |
margin-top: 21px; | |
margin-bottom: 21px; | |
border-radius: 18px; | |
border: none; | |
} | |
#glyph { | |
height: 30px; | |
width: 30px; | |
float: left; | |
margin: -4px -4px 0px 0px; | |
} | |
#assistant-container { | |
background: var(--assistant-sidebar-color); | |
padding-top: 34px; | |
padding-bottom: 34px; | |
padding-left: 16px; | |
padding-right: 16px; | |
transition: right 0.5s cubic-bezier(.17,.67,.99,1); | |
width: 350px; | |
right: 20vw; | |
} | |
#sidebarButton { | |
margin-top: 40px; | |
position: fixed; | |
right: 19vw; | |
transition: right 0.5s cubic-bezier(.17,.67,.99,1); | |
} | |
#article { | |
transition: left 0.5s cubic-bezier(.17,.67,.99,1); | |
} | |
</style> | |
<style id="article-content"> | |
h1, h2, h3, h4, h5, h6 { | |
font-weight: bold; | |
} | |
h1 { | |
font-size: 1.5em; | |
line-height: 1.4em; | |
} | |
h2 { | |
font-size: 1.43em; | |
} | |
h3 { | |
font-size: 1.25em; | |
} | |
h4, h5, h6 { | |
font-size: 1em; | |
margin: 1em 0; | |
} | |
body.watch h1 { | |
font-size: 1.1875rem; | |
} | |
body.watch h2 { | |
font-size: 1.125rem; | |
} | |
body.watch h3 { | |
font-size: 1.0625rem; | |
} | |
body.watch :matches(h4, h5, h6) { | |
font-size: 1rem; | |
} | |
h1.title { | |
font-weight: bold; | |
font-size: 1.95552em; | |
line-height: 1.2141em; | |
margin-top: 0; | |
margin-bottom: 0.5em; | |
} | |
.subhead { | |
font-weight: normal; | |
} | |
.title, .subhead, .metadata { | |
text-align: start; | |
hyphens: manual; | |
display: none; | |
} | |
:nth-child(1 of .page) :matches(.title, .subhead, .metadata) { | |
display: block; | |
} | |
.subhead { | |
color: rgba(27, 27, 27, 0.65); | |
font-size: 1.46664em; | |
margin-top: -0.35em; | |
line-height: 1.27275em; | |
} | |
.metadata { | |
margin-top: -0.75em; | |
margin-bottom: 1.45em; | |
} | |
body.watch .metadata { | |
line-height: 1.3em; | |
} | |
.metadata * { | |
font-size: 1em !important; | |
font-weight: normal !important; | |
font-style: normal !important; | |
display: inline !important; | |
margin: 0; | |
} | |
.metadata :matches(.byline, .date) { | |
display: inline !important; | |
} | |
.metadata :matches(ul, ol, li) { | |
list-style-type: none; | |
-webkit-padding-start: 0; | |
} | |
.title + .metadata { | |
margin-top: -0.75em; | |
} | |
.subhead + .metadata { | |
margin-top: -0.7em; | |
} | |
.page { | |
text-align: start; | |
word-wrap: break-word; | |
} | |
body.watch .page { | |
hyphens: auto; | |
} | |
.page.rtl { | |
direction: rtl; | |
} | |
a { | |
text-decoration: none; | |
} | |
a[href] { | |
color: rgb(65, 110, 210); | |
} | |
#article { | |
text-rendering: optimizeLegibility; | |
} | |
#article * { | |
/* Scale down anything larger than our view. Max-width maintains aspect ratios on images. */ | |
max-width: 100%; | |
} | |
#article img { | |
/* By default, images are centered on their own line. */ | |
margin: 0.5em auto; | |
display: block; | |
height: auto; | |
} | |
#article img.reader-image-tiny { | |
display: inline; | |
margin: 0; | |
} | |
#article .leading-image, figure, .auxiliary { | |
margin-bottom: 1.15em; | |
} | |
#article .leading-image img { | |
margin: auto; | |
display: block; | |
clear: both; | |
} | |
#article .leading-image .credit { | |
margin: 0; | |
} | |
#article .leading-image, | |
#article figure { | |
font-size: 0.75em; | |
line-height: 1.5em; | |
} | |
body.watch #article .leading-image, | |
body.watch #article figure { | |
font-size: 0.8125rem; | |
} | |
#article .leading-image :matches(.caption, .credit), | |
#article figcaption { | |
margin-top: 0.8em; | |
width: 100%; | |
} | |
body.watch #article .leading-image :matches(.caption, .credit), | |
body.watch #article figcaption { | |
margin-top: 4px; | |
} | |
body.watch #article figure img { | |
margin-bottom: 0; | |
} | |
#article figcaption > * { | |
margin-top: 0.25em; | |
margin-bottom: 0.25em; | |
} | |
#article :matches(.leading-image, figure) p { | |
margin-top: 0.4em; | |
margin-bottom: 0.4em; | |
} | |
#article .leading-image .credit + .caption { | |
margin-top: 0.1em; | |
} | |
#article .auxiliary { | |
display: block; | |
clear: both; | |
font-size: 0.75em; | |
line-height: 1.4em; | |
text-align: start; | |
} | |
body.watch #article .auxiliary { | |
font-size: 0.9em; | |
} | |
#article .pullquote { | |
font-size: 1.42em; | |
line-height: 1.38em; | |
font-weight: 300; | |
font-style: italic; | |
} | |
#article .pullquote:not(.float) { | |
margin-top: 1em; | |
margin-bottom: 1em; | |
-webkit-margin-start: 1em; | |
max-width: calc(100% - 1em); | |
} | |
#article .auxiliary > *:not(img) { | |
-webkit-margin-start: 0; | |
} | |
#article .auxiliary.float img, #article .auxiliary > *:first-child:not(img) { | |
margin: 0; | |
} | |
/* If the element immediately after an image is inline, it might bump up against the image. */ | |
#article .auxiliary img + * { | |
display: block; | |
} | |
#article .auxiliary figcaption { | |
font-size: 100%; | |
} | |
#article .auxiliary * { | |
margin-top: 0.5em; | |
margin-bottom: 0.5em; | |
} | |
body:not(.watch) #article .float.left { | |
float: left; | |
margin-right: 20px; | |
} | |
body:not(.watch) #article .float.right { | |
float: right; | |
margin-left: 20px; | |
} | |
body.watch #article .float { | |
width: auto !important; | |
} | |
#article .clear { | |
clear: both; | |
} | |
#article ul.list-style-type-none, | |
#article ol.list-style-type-none, | |
#article .list-style-type-none > li { | |
list-style-type: none; | |
-webkit-padding-start: 0; | |
} | |
#article .page .list-style-type-none.code-block code { | |
white-space: pre-wrap; | |
} | |
#article .page div.scrollable { | |
overflow-x: scroll; | |
word-wrap: normal; | |
} | |
#article .page div.scrollable table { | |
max-width: none; | |
} | |
#article .leading-image, #article figure, #article .auxiliary:not(.pullquote) { | |
font-family: -apple-system-font; | |
} | |
#article .leading-image, #article figure, #article .auxiliary, #article .pullquote { | |
color: rgba(0, 0, 0, 0.65); | |
} | |
figure { | |
margin: 0; | |
} | |
body:not(.watch) figure:not(.float) { | |
margin-top: 1.4em; | |
margin-bottom: 1.4em; | |
} | |
hr { | |
background: rgba(0, 0, 0, 0.2); | |
height: 1px; | |
border: 0; | |
} | |
pre { | |
font-family: -apple-system-ui-monospaced, Menlo; | |
font-size: 0.87em; | |
line-height: 1.45em; | |
} | |
blockquote, q { | |
color: rgba(0, 0, 0, 0.65); | |
} | |
blockquote:not(.pullquote) { | |
margin-left: 2px; | |
margin-right: 6px; | |
padding-left: 16px; | |
} | |
blockquote:not(.simple):not(.pullquote) { | |
border-left: 3px solid rgba(0, 0, 0, 0.1); | |
} | |
q.pullquote { | |
display: block; | |
} | |
.pullquote q::before, .pullquote q::after, q.pullquote::before, q.pullquote::after { | |
content: ""; | |
} | |
/* Collapse excess whitespace. */ | |
.page p > p:empty, | |
.page div > p:empty, | |
.page p > div:empty, | |
.page div > div:empty, | |
.page p + br, | |
.page img + br | |
{ | |
display: none; | |
} | |
.page table { | |
font-size: 0.9em; | |
text-align: start; | |
word-wrap: break-word; | |
border-collapse: collapse; | |
} | |
.page table td, .page table th { | |
padding: 0.25em 0.5em; | |
border: 1px solid rgb(216, 216, 216); | |
} | |
body.watch .page > * { | |
margin-left: 0; | |
margin-right: 0; | |
} | |
body.watch .page ol { | |
padding: 0 0 0 35px; | |
} | |
body.watch .page ul { | |
padding: 0 0 0 20px; | |
} | |
body.watch .page li { | |
margin: 0.8em 0; | |
} | |
body.watch .page blockquote { | |
padding: 0 0 0 8px; | |
} | |
.delimiter { | |
margin-left: 0.45em; | |
margin-right: 0.45em; | |
margin-top: 0.07em; | |
padding: 0; | |
} | |
.metadata.singleline .delimiter::after { | |
content: "•"; | |
} | |
.metadata:not(.singleline) .delimiter { | |
content: ""; | |
display: block !important; | |
} | |
.page table th { | |
background-color: rgba(0, 0, 0, 0.025); | |
} | |
.page sup, .page sub { | |
line-height: 1; | |
font-size: 0.75em; | |
} | |
.hidden { | |
display: none; | |
} | |
/* Special Font Customizations */ | |
.system { font-family: -apple-system-font; } | |
.watch.system { font: -apple-system-body; } | |
.yuantisc { | |
letter-spacing: 1px; | |
} | |
.yuantitc { | |
letter-spacing: 1px; | |
} | |
/* Printing and mailing. */ | |
#article.exported { | |
font-size: 1.2em; | |
} | |
.exported { | |
line-height: 1.5em; | |
} | |
.exported a[href] { | |
text-decoration: underline; | |
} | |
#article.exported { | |
margin: 0; | |
padding: 0; | |
} | |
.exported .float { | |
float: none; | |
margin-top: 1.4em; | |
margin-bottom: 1.4em; | |
} | |
#article.exported .leading-image, | |
#article.exported figcaption { | |
font-size: 0.75rem; | |
color: rgba(0, 0, 0, 0.8); | |
} | |
.exported .delimiter::after { | |
content: ""; | |
} | |
</style> | |
<style id="print"> | |
@media print { | |
body { | |
margin: 2mm 9mm; | |
} | |
.original-url { | |
display: none; | |
} | |
#article .float.left { | |
float: left !important; | |
} | |
#article .float.right { | |
float: right !important; | |
} | |
#article .float { | |
margin-top: 0 !important; | |
margin-bottom: 0 !important; | |
} | |
} | |
</style> | |
<style id="reader-ui"> | |
@media screen { | |
body { | |
margin: 0; | |
padding: 0; | |
-webkit-user-select: none; | |
overflow-x: hidden; | |
-webkit-text-size-adjust: none; | |
} | |
body.mac { | |
background-color: transparent; | |
} | |
#article { | |
pointer-events: auto; | |
-webkit-user-select: auto; | |
overflow: visible; | |
margin-bottom: 42vh !important; | |
} | |
#article:focus { | |
outline: none; | |
} | |
.page-number { | |
display: block; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) .page-number { | |
display: none; | |
} | |
body.watch #article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 0.15em; | |
} | |
.page-number, #incoming-page-corner { | |
font-weight: bold; | |
position: absolute; | |
-webkit-user-select: none; | |
font: 12px "Helvetica Neue"; | |
color: rgb(168, 168, 168); | |
cursor: default; | |
} | |
body.watch :matches(.page-number, #incoming-page-corner) { | |
top: 8px; | |
right: 16px; | |
} | |
.page { | |
margin-left: auto; | |
margin-right: auto; | |
padding-top: 35px; | |
padding-bottom: 35px; | |
position: relative; | |
border-top: 1px solid rgba(0, 0, 0, 0.2); | |
} | |
body.watch .page { | |
padding: 0 4px; | |
} | |
#article :nth-child(1 of .page) { | |
margin-top: 0; | |
border-top: none; | |
padding-top: 32px; | |
} | |
.page:last-of-type { | |
padding-bottom: 45px; | |
} | |
.page video { | |
height: auto; | |
position: relative; | |
} | |
#incoming-page-placeholder { | |
height: 30px; | |
margin-bottom: 0; | |
} | |
#incoming-page-corner { | |
position: absolute; | |
right: 10px; | |
top: 8px; | |
} | |
#incoming-page-text { | |
float: right; | |
-webkit-user-select: none; | |
} | |
#next-page-container { | |
position:absolute; | |
/* Workaround for <rdar://problem/8662842> iOS Reader: loading multiple pages stops at the 2nd page. */ | |
left: -1000px; | |
/* The iframe needs to be wider than the width threshold value for Reader detection, see <rdar://problem/9599297>. */ | |
width: 320px; | |
height: 0px; | |
} | |
.page div.scrollable { | |
-webkit-overflow-scrolling: touch; | |
} | |
} | |
@media screen and (-webkit-min-device-pixel-ratio:2) { | |
.page { | |
border-top-width: 0.5px; | |
} | |
hr { | |
height: 0.5px; | |
} | |
} | |
#article .extendsBeyondTextColumn { | |
max-width: none; | |
} | |
.iframe-wrapper { | |
background-color: black; | |
max-width: none; | |
text-align: center; | |
} | |
iframe { | |
border: 0; | |
} | |
@media screen and (min-width: 0px) { | |
/* Includes iPhone 5 in portrait */ | |
.page { padding-left: 16px; padding-right: 16px; } | |
.page-number, #incoming-page-corner { | |
top: 8px; | |
right: 16px; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 14px; | |
} | |
} | |
@media screen and (min-width: 161px) { | |
/* Apple Watch 40mm */ | |
body.watch .page { | |
padding: 0 8.5px; | |
} | |
} | |
@media screen and (min-width: 183px) { | |
/* Apple Watch 44mm */ | |
body.watch .page { | |
padding: 0 9.5px; | |
} | |
} | |
@media screen and (min-width: 375px) { | |
/* iPhone 6 in portrait */ | |
.page { padding-left: 18px; padding-right: 18px; } | |
.page-number, #incoming-page-corner { | |
top: 6px; | |
right: 18px; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 16px; | |
} | |
} | |
@media screen and (min-width: 414px) { | |
/* iPhone 6 Plus in portrait */ | |
.page { padding-left: 20px; padding-right: 20px; } | |
.page-number, #incoming-page-corner { | |
top: 6px; | |
right: 20px; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 18px; | |
} | |
} | |
/* iPhone 5 in landscape (568px) */ | |
@media screen and (min-width: 667px) { | |
/* iPhone 6 in landscape */ | |
.page { padding-left: 40px; padding-right: 40px; } | |
.page-number, #incoming-page-corner { | |
/* Stop lining this text up with .page's right margin. */ | |
top: 10px; | |
right: 10px; | |
} | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 26px; | |
} | |
} | |
@media screen and (max-width: 569px) { | |
/* iPhone 5 in landscape (568px) and smaller, including all iPhones in portrait */ | |
h1.title { | |
font-size: 1.5558em; | |
} | |
h1 { | |
font-size: 1.4em; | |
} | |
h2 { | |
font-size: 1.2777em; | |
} | |
h3 { | |
font-size: 1.15em; | |
} | |
.subhead { | |
font-size: 1.2222em; | |
} | |
.metadata { | |
font-size: 0.9em; | |
line-height: 1.6em; | |
} | |
.title + .metadata { | |
margin-top: -0.65em; | |
} | |
} | |
@media screen and (min-width: 704px) { | |
/* iPad in landscape with the sidebar open */ | |
.page { padding-left: 42px; padding-right: 42px; } | |
} | |
@media screen and (min-width: 736px) { | |
/* iPhone 6 Plus in landscape */ | |
.page { padding-left: 60px; padding-right: 60px; } | |
#article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 46px; | |
} | |
} | |
@media only screen and (min-width: 780px) { | |
#article { | |
max-width: 800px; | |
margin: 0 auto; | |
} | |
/* Readable margins. */ | |
body.system #article { max-width: 83.2ex; } | |
body.athelas #article { max-width: 104ex; } | |
body.charter #article { max-width: 86ex; } | |
body.georgia #article { max-width: 94ex; } | |
body.iowanoldstyle #article { max-width: 90ex; } | |
body.palatino #article { max-width: 97ex; } | |
body.seravek #article { max-width: 87ex; } | |
body.timesnewroman #article { max-width: 97ex; } | |
body.uiserif #article { max-width: 93ex; } | |
:matches(body.pingfangsc, body.pingfangtc) #article { max-width: 87.6ex; } | |
:matches(body.heitisc, body.heititc) #article { max-width: 74.8ex; } | |
:matches(body.songtisc, body.songtitc) #article { max-width: 102ex; } | |
:matches(body.kaitisc, body.kaititc) #article { max-width: 102ex; } | |
:matches(body.yuantisc, body.yuantitc) #article { max-width: 86.2ex; } | |
:matches(body.libiansc, body.libiantc) #article { max-width: 95ex; } | |
:matches(body.weibeisc, body.weibeitc) #article { max-width: 99ex; } | |
:matches(body.yuppysc, body.yuppytc) #article { max-width: 87.6ex; } | |
body.hiraginosansw3 #article { max-width: 75.7ex; } | |
body.hiraginokakugothicpron #article { max-width: 76.4ex; } | |
body.hiraginominchopron #article { max-width: 77.5ex; } | |
body.hiraginomarugothicpron #article { max-width: 75.1ex; } | |
body.applesdgothicneo #article { max-width: 82ex; } | |
body.nanumgothic #article { max-width: 88.6ex; } | |
body.nanummyeongjo #article { max-width: 94.1ex; } | |
.page { | |
/* We don't want the lines seperating pages to extend beyond the primary text column. */ | |
padding-left: 0px; | |
padding-right: 0px; | |
margin-left: 70px; | |
margin-right: 70px; | |
} | |
} | |
#article { | |
-webkit-font-smoothing: subpixel-antialiased; | |
} | |
/* Reader's paper appearance. */ | |
html.paper { | |
height: 100%; | |
} | |
html.paper body { | |
height: calc(100% - 44px); | |
} | |
html.paper body:after { | |
content: ""; | |
height: 22px; | |
display: block; | |
} | |
/* Clearfix */ | |
html.paper .page::after { | |
content: ""; | |
display: table; | |
clear: both; | |
} | |
html.paper #article { | |
min-height: 100%; | |
margin: 22px auto 0 auto; | |
} | |
html.paper #article :nth-child(1 of .page), html.paper #article :nth-child(1 of .page):nth-last-child(1 of .page) { | |
padding-top: 53px; | |
} | |
html.paper #article .page-number, html.paper #article #incoming-page-corner { | |
/* Stop lining this text up with .page's right margin. */ | |
top: 14px; | |
right: 0px; | |
} | |
/* End Reader's paper appearance. */ | |
/* Use slightly smaller page padding when vertically constrained. */ | |
@media screen and (max-height: 700px) { | |
.page { | |
padding-top: 32px; | |
padding-bottom: 32px; | |
} | |
} | |
</style> | |
<style id="theming"> | |
body.white { | |
--body-font-color: rgb(27, 27, 27); | |
--assistant-secondary-color: rgb(27, 27, 27, 0.5); | |
--horizontal-line-color: rgb(220, 220, 220); | |
--assistant-sidebar-color: rgb(220, 220, 220); | |
--paper-shadow-color: rgba(0, 0, 0, 0.2); | |
--separator-color: rgb(220, 220, 220); | |
--assistant-sidebar-color: rgb(220, 220, 220); | |
--narrow-assistant-background-color: rgba(18, 18, 18, 0.1); | |
} | |
body.sepia { | |
--body-font-color: rgb(79, 50, 28); | |
--assistant-secondary-color: rgb(79, 50, 28, 0.5); | |
--horizontal-line-color: rgb(230, 218, 201); | |
--separator-color: rgb(204, 191, 157); | |
--assistant-sidebar-color: rgb(230, 218, 201); | |
--paper-shadow-color: rgba(0, 0, 0, 0.2); | |
--narrow-assistant-background-color: rgba(18, 18, 18, 0.1); | |
} | |
body.gray { | |
--body-font-color: rgba(255, 255, 255, 0.78); | |
--assistant-secondary-color: rgba(255, 255, 255, 0.39); | |
--horizontal-line-color: rgb(111, 111, 111); | |
--separator-color: rgb(111, 111, 111); | |
--assistant-sidebar-color: rgb(111, 111, 111); | |
--narrow-assistant-background-color: rgba(18, 18, 18, 0.1); | |
} | |
body.night { | |
--body-font-color: rgb(176, 176, 176); | |
--assistant-secondary-color: rgb(176, 176, 176, 0.5); | |
--horizontal-line-color: rgb(62, 62, 62); | |
--separator-color: rgb(62, 62, 62); | |
--assistant-sidebar-color: rgb(62, 62, 62); | |
--narrow-assistant-background-color: rgba(50, 50, 50, 0.3); | |
} | |
body.night.oled { | |
--body-font-color: rgb(210, 210, 210); | |
--assistant-secondary-color: rgb(210, 210, 210, 0.5); | |
--horizontal-line-color: rgba(210, 210, 210, 0.35); | |
--separator-color: rgba(210, 210, 210, 0.35); | |
--assistant-sidebar-color: rgba(210, 210, 210, 0.35); | |
--narrow-assistant-background-color: rgba(50, 50, 50, 0.3); | |
} | |
body.watch.night.oled { | |
--body-font-color: rgb(174, 180, 191); | |
} | |
html:not(.paper) body.white, body.white #article { | |
background-color: white; | |
} | |
html:not(.paper) body.sepia, body.sepia #article { | |
background-color: rgb(248, 241, 227); | |
} | |
html:not(.paper) body.gray, body.gray #article { | |
background-color: rgb(74, 74, 77); | |
} | |
html:not(.paper) body.night, body.night #article { | |
background-color: rgb(18, 18, 18); | |
} | |
html:not(.paper) body.night.oled, body.night.oled #article { | |
background-color: black; | |
} | |
/* OS X Reader draws backdrop background colors outside of web content, so the follow set only applies to iOS. */ | |
html.paper body.ios.white { | |
background-color: rgb(230, 230, 230); | |
} | |
html.paper body.ios.sepia { | |
background-color: rgb(224, 216, 200); | |
} | |
html.paper body.ios.gray { | |
background-color: rgb(50, 50, 51); | |
} | |
html.paper body.ios.night { | |
background-color: black; | |
} | |
body.watch.night .metadata * { | |
color: rgb(214, 217, 223) !important; | |
} | |
html.paper body.white #article, html.paper body.sepia #article { | |
box-shadow: 0px 6px 12px 3px var(--paper-shadow-color); | |
} | |
html.paper body.gray #article { | |
box-shadow: 0px 6px 12px 3px rgba(0, 0, 0, 0.24); | |
} | |
html.paper body.night #article { | |
outline: 1px solid #272727; | |
} | |
body.watch.night.oled :matches(h1, h2, h3, h4, h5, h6) { | |
color: white; | |
} | |
body.sepia #article :matches(.leading-image, figure, .auxiliary, .pullquote) { | |
color: rgba(79, 50, 28, 0.9); | |
} | |
body.gray #article :matches(.leading-image, figure, .auxiliary, .pullquote) { | |
color: rgba(255, 255, 255, 0.7); | |
} | |
body.night #article :matches(.leading-image, figure, .auxiliary, .pullquote) { | |
color: rgba(255, 255, 255, 0.67); | |
} | |
body.night.oled #article :matches(.leading-image, figure, .auxiliary, .pullquote) { | |
color: rgba(210, 210, 210, 0.9); | |
} | |
body.sepia #article a[href] { | |
color: rgb(209, 150, 0); | |
} | |
body.gray #article a[href], body.night #article a[href] { | |
color: rgb(90, 200, 250); | |
} | |
body.watch.night.oled #article a[href] { | |
color: rgb(32, 148, 250); | |
} | |
body #article :matches(.page, .metadata a[href]) { | |
color: var(--body-font-color); | |
} | |
body #article .page { | |
border-top-color: var(--horizontal-line-color); | |
} | |
body #article hr { | |
background: var(--horizontal-line-color); | |
} | |
body #assistant-container p { | |
color: var(--assistant-secondary-color); | |
} | |
body #assistant-container ol { | |
color: var(--assistant-secondary-color); | |
} | |
body #assistant-container h2 { | |
color: var(--body-font-color); | |
font-size: 1.43em; | |
} | |
body #assistant-container h3 { | |
color: var(--body-font-color); | |
font-size: 1.25em; | |
} | |
body #assistant-container h1 { | |
font-size: 1.5em; | |
line-height: 1.4em; | |
color: var(--body-font-color); | |
margin: 0px; | |
} | |
body #assistant-container a { | |
color: var(--assistant-secondary-color); | |
} | |
body #summary-container p { | |
color: var(--assistant-secondary-color); | |
margin: 0px; | |
padding-top: 4px; | |
} | |
body #summary-container h2 { | |
color: var(--body-font-color); | |
} | |
body #summary-container h1 { | |
color: var(--body-font-color); | |
} | |
body #tableOfContentsInsideArticle-list a { | |
color: var(--body-font-color); | |
font-size: 1em; | |
} | |
body #innerAssistantContainer p { | |
color: var(--body-font-color); | |
margin-top: 0; | |
margin-bottom: 0.4em; | |
} | |
body #innerAssistantContainer ol { | |
color: var(--body-font-color); | |
} | |
body #innerAssistantContainer li { | |
margin-left: 2em; | |
} | |
body #innerAssistantContainer ol li::marker { | |
color: var(--assistant-secondary-color); | |
} | |
body #innerAssistantContainer button { | |
color: var(--body-font-color); | |
font-size: 1em; | |
} | |
body #onDeviceSummaryButton { | |
color: var(--body-font-color); | |
} | |
body.sepia .subhead { | |
color: rgba(79, 50, 28, 0.72); | |
} | |
body.gray .subhead { | |
color: rgba(255, 255, 255, 0.65); | |
} | |
body.night .subhead { | |
color: rgba(185, 185, 185, 0.9); | |
} | |
body.night.oled .subhead { | |
color: rgba(210, 210, 210, 0.85); | |
} | |
body.sepia :matches(#article .page-number, #incoming-page-corner) { | |
color: rgba(63, 41, 23, 0.5); | |
} | |
body.gray :matches(#article .page-number, #incoming-page-corner) { | |
color: rgba(255, 255, 255, 0.45); | |
} | |
body.night :matches(#article .page-number, #incoming-page-corner) { | |
color: rgba(255, 255, 255, 0.55); | |
} | |
body.night.oled :matches(#article .page-number, #incoming-page-corner) { | |
color: rgba(210, 210, 210, 0.8); | |
} | |
body.sepia #article blockquote, body.sepia #article q { | |
color: rgb(140, 112, 79); | |
} | |
body.sepia #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgba(154, 128, 92, 0.1); | |
} | |
body.gray #article blockquote, body.gray #article q { | |
color: rgba(255, 255, 255, 0.6); | |
} | |
body.gray #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgba(255, 255, 255, 0.15); | |
} | |
body.night #article blockquote, body.night #article q { | |
color: rgba(255, 255, 255, 0.6); | |
} | |
body.night #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgba(255, 255, 255, 0.15); | |
} | |
body.night.oled #article blockquote, body.night.oled #article q { | |
color: rgba(210, 210, 210, 0.85); | |
} | |
body.night.oled #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgba(210, 210, 210, 0.2); | |
} | |
body.watch.night #article blockquote, body.watch.night #article q { | |
color: var(--body-font-color); | |
} | |
body.watch.night #article blockquote:not(.simple):not(.pullquote) { | |
border-left-color: rgb(51, 51, 51); | |
} | |
body.sepia table :matches(td, th) { | |
border-color: rgb(230, 218, 202); | |
} | |
body.sepia table th { | |
background-color: rgba(154, 128, 92, 0.06); | |
} | |
body.gray table :matches(td, th) { | |
border-color: rgb(106, 106, 106); | |
} | |
body.gray table th { | |
background-color: rgba(255, 255, 255, 0.035); | |
} | |
body.night table :matches(td, th) { | |
border-color: rgb(50, 50, 50); | |
} | |
body.night table th { | |
background-color: rgba(255, 255, 255, 0.045); | |
} | |
body.night.oled table th { | |
background-color: rgba(255, 255, 255, 0.075); | |
} | |
@media (inverted-colors) { | |
/* If the user has turned on the "smart invert" accessibility preference, they generally prefer | |
their images, such as photos, to not be inverted. Provide this by applying a filter that | |
inverts the colors again (effectively un-inverting). */ | |
body:not(.gray):not(.night) #article :matches(img, video) { | |
filter: invert(); | |
} | |
body:not(.gray):not(.night) #article picture { | |
filter: none !important; | |
} | |
body.gray, body.night { | |
filter: invert(); | |
} | |
body:matches(.gray, .night) #article :matches(img:not(picture > img), picture, video) { | |
filter: none !important; | |
} | |
body:matches(.gray, .night) #article iframe { | |
filter: invert(); | |
} | |
html.paper body.white #article, html.paper body.sepia #article { | |
--paper-shadow-color: rgba(255, 255, 255, 0.2); | |
} | |
/* The background color of <body> is not inverted by the filter. Achieve this by manually | |
setting the inverse color. */ | |
html:not(.paper) body.gray { | |
background-color: rgb(165, 165, 163) !important; | |
} | |
html.paper body.gray { | |
background-color: rgb(205, 205, 204) !important; | |
} | |
html:not(.paper) body.night { | |
background-color: rgb(237, 237, 237) !important; | |
} | |
html:not(.paper) body.night.oled { | |
background-color: white !important; | |
} | |
html.paper body.night { | |
background-color: white !important; | |
} | |
} | |
</style> | |
<style id="locale-specific-adjustments"> | |
.locale-ja .page { | |
text-align: justify; | |
} | |
.locale-zh-Hans .page { | |
text-align: justify; | |
} | |
.locale-zh-Hant .page { | |
text-align: justify; | |
word-break: break-all; | |
} | |
.locale-hi .title { | |
line-height: 1.65em; | |
} | |
/* See 32728279 and 54061051. */ | |
.locale-ur.notonastaliqurdu :matches(h1, h2, h3, h4, h5, h6) { | |
font-weight: normal; | |
line-height: 2.55em; | |
} | |
</style> | |
<style id="dynamic-article-content"></style> | |
<!-- For Twitter’s script to find and script world to be created (see 34937240). --> | |
<script> | |
window.isReaderPage = true; | |
</script> | |
</head> | |
<body> | |
<iframe aria-hidden="true" id="next-page-container"></iframe> | |
<div id="article" role="article"> | |
<!-- This node will contain a number of div.page. --> | |
</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (C) 2010 Apple Inc. All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without | |
* modification, are permitted provided that the following conditions | |
* are met: | |
* | |
* 1. Redistributions of source code must retain the above copyright | |
* notice, this list of conditions and the following disclaimer. | |
* 2. Redistributions in binary form must reproduce the above copyright | |
* notice, this list of conditions and the following disclaimer in the | |
* documentation and/or other materials provided with the distribution. | |
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
* its contributors may be used to endorse or promote products derived | |
* from this software without specific prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
*/ | |
// Utilities taken from WebCore/inspector/front-end/utilities.js with some additions for Safari. | |
Object.type = function(obj, win) | |
{ | |
if (obj === null) | |
return "null"; | |
var type = typeof obj; | |
if (type !== "object" && type !== "function") | |
return type; | |
win = win || window; | |
if (obj instanceof win.Node) | |
return "node"; | |
if (obj instanceof win.String) | |
return "string"; | |
if (obj instanceof win.Array) | |
return "array"; | |
if (obj instanceof win.Boolean) | |
return "boolean"; | |
if (obj instanceof win.Number) | |
return "number"; | |
if (obj instanceof win.Date) | |
return "date"; | |
if (obj instanceof win.RegExp) | |
return "regexp"; | |
if (obj instanceof win.Error) | |
return "error"; | |
return type; | |
} | |
Function.prototype.bind = function(thisObject) | |
{ | |
var func = this; | |
var args = Array.prototype.slice.call(arguments, 1); | |
return function() { return func.apply(thisObject, args.concat(Array.prototype.slice.call(arguments, 0))) }; | |
} | |
String.prototype.format = function() | |
{ | |
var stringParts = this.split("%@"); | |
for (var i = 0; i < arguments.length; ++i) | |
stringParts.splice(i * 2 + 1, 0, arguments[i].toString()); | |
return stringParts.join(""); | |
} | |
Element.prototype.indexOfChildNode = function(childNode) | |
{ | |
var childNodes = this.childNodes; | |
for (var i = 0; i < childNodes.length; ++i) { | |
if (childNodes[i] === childNode) | |
return i; | |
} | |
return -1; | |
} | |
Element.prototype.removeChildren = function() | |
{ | |
while (this.firstChild) | |
this.removeChild(this.firstChild); | |
} | |
Element.prototype.__defineGetter__("totalOffsetLeft", function() | |
{ | |
var total = 0; | |
for (var element = this; element; element = element.offsetParent) | |
total += element.offsetLeft + (this !== element ? element.clientLeft : 0); | |
return total; | |
}); | |
Element.prototype.__defineGetter__("totalOffsetTop", function() | |
{ | |
var total = 0; | |
for (var element = this; element; element = element.offsetParent) | |
total += element.offsetTop + (this !== element ? element.clientTop : 0); | |
return total; | |
}); | |
Element.prototype.__defineGetter__("totalScrollTop", function() | |
{ | |
var total = 0; | |
for (var element = this; element; element = element.offsetParent) | |
total += element.scrollTop; | |
return total; | |
}); | |
Array.prototype.remove = function(value, onlyFirst) | |
{ | |
if (onlyFirst) { | |
var index = this.indexOf(value); | |
if (index !== -1) | |
this.splice(index, 1); | |
return; | |
} | |
var length = this.length; | |
for (var i = 0; i < length; ++i) { | |
if (this[i] === value) | |
this.splice(i, 1); | |
} | |
} | |
// @param element (HTML Element) The element whose total offset from left edge of the | |
// page is desired. | |
// @return (integer) The total offset from the left edge of the page if the element is | |
// not null or undefined or does not have a defined offsetLeft. -1 otherwise. | |
function totalLeftOffset(element) | |
{ | |
if (!element || typeof element.offsetLeft === "undefined") | |
return -1; | |
return element.totalOffsetLeft; | |
} | |
// @param element (HTML Element) The element whose total offset from top edge of the | |
// page is desired. | |
// @return (integer) The total offset from the top edge of the page if the element is | |
// not null or undefined or does not have a defined offsetTop. -1 otherwise. | |
function totalTopOffset(element) | |
{ | |
if (!element || typeof element.offsetTop === "undefined") | |
return -1; | |
return element.totalOffsetTop; | |
} | |
Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray) | |
{ | |
for (var node = this; node && node !== this.ownerDocument; node = node.parentNode) | |
for (var i = 0; i < nameArray.length; ++i) | |
if (node.nodeName.toLowerCase() === nameArray[i].toLowerCase()) | |
return node; | |
return null; | |
} | |
Node.prototype.enclosingNodeOrSelfWithNodeName = function(nodeName) | |
{ | |
return this.enclosingNodeOrSelfWithNodeNameInArray([nodeName]); | |
} | |
Number.constrain = function(num, min, max) | |
{ | |
if (num < min) | |
num = min; | |
else if (num > max) | |
num = max; | |
return num; | |
} | |
// JS class inheritance. NOTE: You should use the __proto__ approach instead of this. | |
var JSClass = { | |
inherit: function(subclass, baseClass) { | |
function inheritance() { } | |
inheritance.prototype = baseClass.prototype; | |
subclass.prototype = new inheritance(); | |
subclass.prototype.constructor = subclass; | |
subclass.baseConstructor = baseClass; | |
subclass.superClass = baseClass.prototype; | |
} | |
} | |
// Dragging utilities --------------------------------------------------------- | |
var Direction = { | |
HORIZONTAL: 0, | |
VERTICAL: 1, | |
}; | |
var Dragger = { | |
// Sets up and starts the drag of an HTML element. | |
// | |
// @param element (HTML element) Element to drag. | |
// @param elementDragging (function (event)) Function to be called while | |
// element is dragging. | |
// @param elementDragEnd (function (event)) Function to be called when the | |
// drag ends. | |
// @param event (event) The event that triggered the drag. | |
// @param cursor (string) The cursor style to use while dragging. | |
elementDragStart: function(element, elementDragging, elementDragEnd, event, cursor) | |
{ | |
if (this._elementDraggingEventListener || this._elementEndDraggingEventListener) | |
this.elementDragEnd(event); | |
this._elementDraggingEventListener = elementDragging; | |
this._elementEndDraggingEventListener = elementDragEnd; | |
document.addEventListener("mousemove", elementDragging, true); | |
document.addEventListener("mouseup", elementDragEnd, true); | |
document.body.style.cursor = cursor; | |
event.preventDefault(); | |
}, | |
// Finishes and tears down the drag of an element. | |
// | |
// @param event (event) Event that causes the drag to end. | |
elementDragEnd: function(event) | |
{ | |
document.removeEventListener("mousemove", this._elementDraggingEventListener, true); | |
document.removeEventListener("mouseup", this._elementEndDraggingEventListener, true); | |
document.body.style.removeProperty("cursor"); | |
delete this._elementDraggingEventListener; | |
delete this._elementEndDraggingEventListener; | |
event.preventDefault(); | |
}, | |
// Updates the position of the element and all the elements around it. | |
// If the direction of movement is horizontal (Dragger.HORIZONTAL), then A | |
// is "left" and B is "right". | |
// If the direction of movement is vertical (Dragger.VERTICAL), then A is | |
// "above" and B is "below". | |
// | |
// @param element (HTML element) The element whose position to update. | |
// @param direction (Direction.HORIZONTAL | Direction.VERTICAL) The direction | |
// in which the element is moving. | |
// @param elementsToA (array of HTML elements) The elements to the A of the | |
// element. | |
// @param elementsToB (array of HTML elements) The elements to the B of the | |
// element. | |
// @param distanceToDragPoint (integer) The distance in pixels from the | |
// dragPoint to where the element should be placed. | |
// @param minPos (integer) The minimum position the element can be at. | |
// @param maxPos (integer) The maximum position the element can be at. | |
// @param dragPoint (integer) The point at which the element has been | |
// dragged to. | |
updateElementPosition: function(element, direction, elementsToA, elementsToB, | |
distanceToDragPoint, minPos, maxPos, dragPoint) | |
{ | |
if ((direction == Direction.HORIZONTAL && elementsToA[0].offsetWidth <= 0) | |
|| (elementsToA[0].offsetHeight <= 0)) { | |
// The stylesheet hasn't loaded yet or the window is closed, | |
// so we can't calculate what is need. Return early. | |
return; | |
} | |
if (!("_currentElementPosition" in elementsToA[0])) { | |
if (direction == Direction.HORIZONTAL) | |
elementsToA[0]._currentElementPosition = elementsToA[0].offsetWidth; | |
else | |
elementsToA[0]._currentElementPosition = elementsToA[0].offsetHeight; | |
} | |
if (typeof dragPoint === "undefined") | |
dragPoint = elementsToA[0]._currentElementPosition; | |
dragPoint = Number.constrain(dragPoint, minPos, maxPos); | |
elementsToA[0]._currentElementPosition = dragPoint; | |
for (var i = 0; i < elementsToA.length; i++) { | |
if (direction == Direction.HORIZONTAL) | |
elementsToA[i].style.width = dragPoint + "px"; | |
else | |
elementsToA[i].style.height = dragPoint + "px"; | |
} | |
for (var j = 0; j < elementsToB.length; j++) { | |
if (direction == Direction.HORIZONTAL) | |
elementsToB[j].style.left = dragPoint + "px"; | |
else | |
elementsToB[j].style.top = dragPoint + "px"; | |
} | |
if (direction == Direction.HORIZONTAL) | |
element.style.left = (dragPoint - distanceToDragPoint) + "px"; | |
else | |
element.style.top = (dragPoint - distanceToDragPoint) + "px"; | |
} | |
}; | |
// Listeners (taken from the WebInspector.Object in | |
// WebCore\inspector\frontend\Object.js) | |
Listeners = function() { | |
} | |
Listeners.prototype = { | |
addEventListener: function(eventType, listener, thisObject) { | |
if (!("_listeners" in this)) | |
this._listeners = {}; | |
if (!(eventType in this._listeners)) | |
this._listeners[eventType] = []; | |
this._listeners[eventType].push({ thisObject: thisObject, listener: listener }); | |
}, | |
removeEventListener: function(eventType, listener, thisObject) { | |
if (!("_listeners" in this) || !(eventType in this._listeners)) | |
return; | |
var listeners = this._listeners[eventType]; | |
for (var i = 0; i < listeners.length; ++i) { | |
if (listener && listeners[i].listener === listener && listeners[i].thisObject === thisObject) | |
listeners.splice(i, 1); | |
else if (!listener && thisObject && listeners[i].thisObject === thisObject) | |
listeners.splice(i, 1); | |
} | |
if (!listeners.length) | |
delete this._listeners[eventType]; | |
}, | |
dispatchEventToListeners: function(eventType) { | |
if (!("_listeners" in this) || !(eventType in this._listeners)) | |
return; | |
var stoppedPropagation = false; | |
function stopPropagation() | |
{ | |
stoppedPropagation = true; | |
} | |
function preventDefault() | |
{ | |
this.defaultPrevented = true; | |
} | |
var event = {target: this, type: eventType, defaultPrevented: false}; | |
event.stopPropagation = stopPropagation.bind(event); | |
event.preventDefault = preventDefault.bind(event); | |
var listeners = this._listeners[eventType]; | |
for (var i = 0; i < listeners.length; ++i) { | |
listeners[i].listener.call(listeners[i].thisObject, event); | |
if (stoppedPropagation) | |
break; | |
} | |
return event.defaultPrevented; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"1rx.io": { | |
"d": "RhythmOne" | |
}, | |
"2mdn.net": { | |
"d": "Google" | |
}, | |
"2o7.net": { | |
"d": "Adobe" | |
}, | |
"33across.com": { | |
"d": "33Across" | |
}, | |
"360yield.com": { | |
"d": "Improve Digital" | |
}, | |
"3lift.com": { | |
"d": "TripleLift" | |
}, | |
"abtasty.com": { | |
"d": "AB Tasty" | |
}, | |
"acuityplatform.com": { | |
"d": "AcuityAds" | |
}, | |
"addthis.com": { | |
"d": "Oracle" | |
}, | |
"addtoany.com": { | |
"d": "AddToAny" | |
}, | |
"adentifi.com": { | |
"d": "AdTheorent" | |
}, | |
"adform.net": { | |
"d": "Adform" | |
}, | |
"adgrx.com": { | |
"d": "AdGear" | |
}, | |
"adhigh.net": { | |
"d": "GetIntent" | |
}, | |
"adition.com": { | |
"d": "Virtual Minds" | |
}, | |
"adkernel.com": { | |
"d": "Adkernel" | |
}, | |
"adlightning.com": { | |
"d": "Ad Lightning" | |
}, | |
"admedo.com": { | |
"d": "Admedo" | |
}, | |
"admixer.net": { | |
"d": "Admixer" | |
}, | |
"adnxs.com": { | |
"d": "Microsoft" | |
}, | |
"adobedtm.com": { | |
"d": "Adobe" | |
}, | |
"adotmob.com": { | |
"d": "A.Mob" | |
}, | |
"adriver.ru": { | |
"d": "Internest-holding" | |
}, | |
"adroll.com": { | |
"d": "AdRoll" | |
}, | |
"ads-twitter.com": { | |
"d": "Twitter" | |
}, | |
"adsafeprotected.com": { | |
"d": "Integral Ad Science" | |
}, | |
"adscale.de": { | |
"d": "Ströer Group" | |
}, | |
"adsco.re": { | |
"d": "Adscore" | |
}, | |
"adsrvr.org": { | |
"d": "The Trade Desk" | |
}, | |
"adstanding.com": { | |
"d": "AdStanding" | |
}, | |
"adswizz.com": { | |
"d": "Sirius XM" | |
}, | |
"adtdp.com": { | |
"d": "CyberAgent" | |
}, | |
"adthrive.com": { | |
"d": "AdThrive" | |
}, | |
"advertising.com": { | |
"d": "Verizon Media" | |
}, | |
"affec.tv": { | |
"d": "Affectv" | |
}, | |
"agkn.com": { | |
"d": "Neustar" | |
}, | |
"aidata.io": { | |
"d": "Aidata" | |
}, | |
"amazon-adsystem.com": { | |
"d": "Amazon" | |
}, | |
"amplitude.com": { | |
"d": "Amplitude" | |
}, | |
"amung.us": { | |
"d": "whos.amung.us" | |
}, | |
"app.link": { | |
"d": "Branch Metrics" | |
}, | |
"appdynamics.com": { | |
"d": "Cisco Systems" | |
}, | |
"appier.net": { | |
"d": "Appier" | |
}, | |
"attn.tv": { | |
"d": "Attentive Mobile" | |
}, | |
"basis.net": { | |
"d": "Centro" | |
}, | |
"betrad.com": { | |
"d": "Crownpeak" | |
}, | |
"betweendigital.com": { | |
"d": "SSP Network" | |
}, | |
"bfmio.com": { | |
"d": "Beachfront Media" | |
}, | |
"bidr.io": { | |
"d": "Beeswax" | |
}, | |
"bidswitch.net": { | |
"d": "IPONWEB" | |
}, | |
"bing.com": { | |
"d": "Microsoft" | |
}, | |
"bkrtx.com": { | |
"d": "Oracle" | |
}, | |
"blismedia.com": { | |
"d": "Blis" | |
}, | |
"bluecava.com": { | |
"d": "ALC" | |
}, | |
"blueconic.net": { | |
"d": "BlueConic" | |
}, | |
"bluekai.com": { | |
"d": "Oracle" | |
}, | |
"bounceexchange.com": { | |
"d": "Bounce Exchange" | |
}, | |
"branch.io": { | |
"d": "Branch Metrics" | |
}, | |
"brealtime.com": { | |
"d": "EMX Digital" | |
}, | |
"browser-update.org": { | |
"d": "Browser Update" | |
}, | |
"bttrack.com": { | |
"d": "Bidtellect" | |
}, | |
"buysellads.com": { | |
"d": "BuySellAds" | |
}, | |
"casalemedia.com": { | |
"d": "Index Exchange" | |
}, | |
"cdnwidget.com": { | |
"d": "CDNWIDGET.COM" | |
}, | |
"chartbeat.com": { | |
"d": "Chartbeat" | |
}, | |
"chaturbate.com": { | |
"d": "Chaturbate" | |
}, | |
"clickagy.com": { | |
"d": "Clickagy" | |
}, | |
"clickcertain.com": { | |
"d": "ClickCertain" | |
}, | |
"clicktale.net": { | |
"d": "ClickTale" | |
}, | |
"colossusssp.com": { | |
"d": "Colossus Media" | |
}, | |
"company-target.com": { | |
"d": "Demandbase" | |
}, | |
"consentmanager.net": { | |
"d": "ConsentManager" | |
}, | |
"contentsquare.net": { | |
"d": "ContentSquare" | |
}, | |
"contextweb.com": { | |
"d": "Pulsepoint" | |
}, | |
"cookiepro.com": { | |
"d": "OneTrust" | |
}, | |
"cpx.to": { | |
"d": "Captify" | |
}, | |
"cquotient.com": { | |
"d": "Salesforce.com" | |
}, | |
"crazyegg.com": { | |
"d": "Crazy Egg" | |
}, | |
"creative-serving.com": { | |
"d": "Platform161" | |
}, | |
"creativecdn.com": { | |
"d": "RTB House" | |
}, | |
"criteo.com": { | |
"d": "Criteo" | |
}, | |
"criteo.net": { | |
"d": "Criteo" | |
}, | |
"crsspxl.com": { | |
"d": "Cross Pixel Media" | |
}, | |
"crwdcntrl.net": { | |
"d": "Lotame Solutions" | |
}, | |
"ctnsnet.com": { | |
"d": "Crimtan Holdings" | |
}, | |
"cxense.com": { | |
"d": "Piano Software" | |
}, | |
"deepintent.com": { | |
"d": "DeepIntent" | |
}, | |
"demandbase.com": { | |
"d": "Demandbase" | |
}, | |
"demdex.net": { | |
"d": "Adobe" | |
}, | |
"disqus.com": { | |
"d": "Disqus" | |
}, | |
"dotomi.com": { | |
"d": "Conversant" | |
}, | |
"doubleclick.net": { | |
"d": "Google" | |
}, | |
"doubleverify.com": { | |
"d": "DoubleVerify" | |
}, | |
"driftt.com": { | |
"d": "Drift.com" | |
}, | |
"dtscout.com": { | |
"d": "DTS" | |
}, | |
"dwin1.com": { | |
"d": "Awin" | |
}, | |
"dynamicyield.com": { | |
"d": "Dynamic Yield" | |
}, | |
"e-planning.net": { | |
"d": "Teroa" | |
}, | |
"eloqua.com": { | |
"d": "Oracle" | |
}, | |
"emxdgt.com": { | |
"d": "Engine USA" | |
}, | |
"en25.com": { | |
"d": "Oracle" | |
}, | |
"ensighten.com": { | |
"d": "Ensighten" | |
}, | |
"everestjs.net": { | |
"d": "Adobe" | |
}, | |
"everesttech.net": { | |
"d": "Adobe" | |
}, | |
"evidon.com": { | |
"d": "Crownpeak" | |
}, | |
"exelator.com": { | |
"d": "The Nielsen Company" | |
}, | |
"exoclick.com": { | |
"d": "ExoClick" | |
}, | |
"exosrv.com": { | |
"d": "ExoClick" | |
}, | |
"exponential.com": { | |
"d": "Exponential Interactive" | |
}, | |
"eyeota.net": { | |
"d": "eyeota" | |
}, | |
"ezoic.net": { | |
"d": "Ezoic" | |
}, | |
"facebook.com": { | |
"d": "Facebook" | |
}, | |
"facebook.net": { | |
"d": "Facebook" | |
}, | |
"fastly-insights.com": { | |
"d": "Fastly" | |
}, | |
"flashtalking.com": { | |
"d": "Flashtalking" | |
}, | |
"foresee.com": { | |
"d": "ForeSee Results" | |
}, | |
"forter.com": { | |
"d": "Forter" | |
}, | |
"fullstory.com": { | |
"d": "FullStory" | |
}, | |
"fwmrm.net": { | |
"d": "FreeWheel" | |
}, | |
"gemius.pl": { | |
"d": "Gemius" | |
}, | |
"getclicky.com": { | |
"d": "Roxr Software" | |
}, | |
"getsitecontrol.com": { | |
"d": "GetWebCraft" | |
}, | |
"go-mpulse.net": { | |
"d": "Akamai" | |
}, | |
"google-analytics.com": { | |
"d": "Google" | |
}, | |
"googleadservices.com": { | |
"d": "Google" | |
}, | |
"googlesyndication.com": { | |
"d": "Google" | |
}, | |
"googletagmanager.com": { | |
"d": "Google" | |
}, | |
"googletagservices.com": { | |
"d": "Google" | |
}, | |
"gumgum.com": { | |
"d": "GumGum" | |
}, | |
"heapanalytics.com": { | |
"d": "Heap" | |
}, | |
"hellobar.com": { | |
"d": "Crazy Egg" | |
}, | |
"histats.com": { | |
"d": "wisecode" | |
}, | |
"hotjar.com": { | |
"d": "Hotjar" | |
}, | |
"hs-analytics.net": { | |
"d": "HubSpot" | |
}, | |
"hsadspixel.net": { | |
"d": "HubSpot" | |
}, | |
"hsleadflows.net": { | |
"d": "HubSpot" | |
}, | |
"hubspot.com": { | |
"d": "HubSpot" | |
}, | |
"hybrid.ai": { | |
"d": "Hybrid Adtech" | |
}, | |
"ib-ibi.com": { | |
"d": "KBM Group" | |
}, | |
"id5-sync.com": { | |
"d": "ID5" | |
}, | |
"igodigital.com": { | |
"d": "Salesforce.com" | |
}, | |
"impactradius-event.com": { | |
"d": "Impact" | |
}, | |
"imrworldwide.com": { | |
"d": "The Nielsen Company" | |
}, | |
"indexww.com": { | |
"d": "Index Exchange" | |
}, | |
"innovid.com": { | |
"d": "Innovid Media" | |
}, | |
"insightexpressai.com": { | |
"d": "Kantar Operations" | |
}, | |
"inspectlet.com": { | |
"d": "Inspectlet" | |
}, | |
"instagram.com": { | |
"d": "Facebook" | |
}, | |
"intentiq.com": { | |
"d": "Intent IQ" | |
}, | |
"ipredictive.com": { | |
"d": "Adelphic" | |
}, | |
"ispot.tv": { | |
"d": "iSpot.tv" | |
}, | |
"juicyads.com": { | |
"d": "JuicyAds" | |
}, | |
"justpremium.com": { | |
"d": "JustPremium" | |
}, | |
"kampyle.com": { | |
"d": "Medallia" | |
}, | |
"kargo.com": { | |
"d": "Kargo" | |
}, | |
"klaviyo.com": { | |
"d": "Klaviyo" | |
}, | |
"krxd.net": { | |
"d": "Salesforce.com" | |
}, | |
"liadm.com": { | |
"d": "LiveIntent" | |
}, | |
"lijit.com": { | |
"d": "Sovrn Holdings" | |
}, | |
"linkedin.com": { | |
"d": "Microsoft" | |
}, | |
"linksynergy.com": { | |
"d": "Rakuten" | |
}, | |
"list-manage.com": { | |
"d": "Intuit" | |
}, | |
"listrak.com": { | |
"d": "Listrak" | |
}, | |
"listrakbi.com": { | |
"d": "Listrak" | |
}, | |
"livechatinc.com": { | |
"d": "LiveChat" | |
}, | |
"liveperson.net": { | |
"d": "LivePerson" | |
}, | |
"lkqd.net": { | |
"d": "Nexstar Media Group" | |
}, | |
"loopme.me": { | |
"d": "LoopMe" | |
}, | |
"lpsnmedia.net": { | |
"d": "LivePerson" | |
}, | |
"mail.ru": { | |
"d": "VK" | |
}, | |
"mailchimp.com": { | |
"d": "Intuit" | |
}, | |
"marketo.com": { | |
"d": "Adobe" | |
}, | |
"marketo.net": { | |
"d": "Adobe" | |
}, | |
"mathtag.com": { | |
"d": "MediaMath" | |
}, | |
"maxmind.com": { | |
"d": "MaxMind" | |
}, | |
"media.net": { | |
"d": "Media.net Advertising" | |
}, | |
"media6degrees.com": { | |
"d": "Dstillery" | |
}, | |
"mediarithmics.com": { | |
"d": "mediarithmics" | |
}, | |
"mediavine.com": { | |
"d": "Mediavine" | |
}, | |
"mediawallahscript.com": { | |
"d": "MediaWallah" | |
}, | |
"mfadsrvr.com": { | |
"d": "IPONWEB" | |
}, | |
"mgid.com": { | |
"d": "MGID" | |
}, | |
"micpn.com": { | |
"d": "Movable Ink" | |
}, | |
"microad.jp": { | |
"d": "MicroAd" | |
}, | |
"mktoresp.com": { | |
"d": "Adobe" | |
}, | |
"ml314.com": { | |
"d": "Bombora" | |
}, | |
"moatads.com": { | |
"d": "Oracle" | |
}, | |
"monetate.net": { | |
"d": "Monetate" | |
}, | |
"mookie1.com": { | |
"d": "WPP" | |
}, | |
"mouseflow.com": { | |
"d": "Mouseflow" | |
}, | |
"mxpnl.com": { | |
"d": "Mixpanel" | |
}, | |
"mxptint.net": { | |
"d": "Valassis Digital" | |
}, | |
"navdmp.com": { | |
"d": "Navegg" | |
}, | |
"newrelic.com": { | |
"d": "New Relic" | |
}, | |
"ninthdecimal.com": { | |
"d": "NinthDecimal" | |
}, | |
"npttech.com": { | |
"d": "Piano Software" | |
}, | |
"nr-data.net": { | |
"d": "New Relic" | |
}, | |
"ntv.io": { | |
"d": "Nativo" | |
}, | |
"o333o.com": { | |
"d": "AdSpyglass" | |
}, | |
"olark.com": { | |
"d": "Olark" | |
}, | |
"omnitagjs.com": { | |
"d": "Adyoulike" | |
}, | |
"omtrdc.net": { | |
"d": "Adobe" | |
}, | |
"onesignal.com": { | |
"d": "OneSignal" | |
}, | |
"online-metrix.net": { | |
"d": "RELX Group" | |
}, | |
"openx.net": { | |
"d": "OpenX" | |
}, | |
"opmnstr.com": { | |
"d": "Retyp" | |
}, | |
"optimizely.com": { | |
"d": "Optimizely" | |
}, | |
"outbrain.com": { | |
"d": "Outbrain" | |
}, | |
"owneriq.net": { | |
"d": "Inmar" | |
}, | |
"pardot.com": { | |
"d": "Salesforce.com" | |
}, | |
"parsely.com": { | |
"d": "Parsely" | |
}, | |
"paypal.com": { | |
"d": "PayPal" | |
}, | |
"permutive.com": { | |
"d": "Permutive" | |
}, | |
"pingdom.net": { | |
"d": "Pingdom" | |
}, | |
"pippio.com": { | |
"d": "LiveRamp" | |
}, | |
"postrelease.com": { | |
"d": "Nativo" | |
}, | |
"pro-market.net": { | |
"d": "Datonics" | |
}, | |
"pswec.com": { | |
"d": "Proclivity Media" | |
}, | |
"pubmatic.com": { | |
"d": "PubMatic" | |
}, | |
"px-cloud.net": { | |
"d": "Human Security" | |
}, | |
"qualtrics.com": { | |
"d": "SAP" | |
}, | |
"quantserve.com": { | |
"d": "Quantcast" | |
}, | |
"quora.com": { | |
"d": "Quora" | |
}, | |
"rambler.ru": { | |
"d": "Rambler Internet Holding" | |
}, | |
"realsrv.com": { | |
"d": "ExoClick" | |
}, | |
"reddit.com": { | |
"d": "Reddit" | |
}, | |
"redditstatic.com": { | |
"d": "Reddit" | |
}, | |
"reson8.com": { | |
"d": "Resonate Networks" | |
}, | |
"revcontent.com": { | |
"d": "RevContent" | |
}, | |
"rezync.com": { | |
"d": "Zeta Global" | |
}, | |
"rfihub.com": { | |
"d": "Zeta Global" | |
}, | |
"rfihub.net": { | |
"d": "Zeta Global" | |
}, | |
"rkdms.com": { | |
"d": "Merkle" | |
}, | |
"rlcdn.com": { | |
"d": "LiveRamp" | |
}, | |
"rmtag.com": { | |
"d": "Rakuten" | |
}, | |
"rqtrk.eu": { | |
"d": "Roq.ad" | |
}, | |
"rtmark.net": { | |
"d": "Propeller Ads" | |
}, | |
"rubiconproject.com": { | |
"d": "Magnite" | |
}, | |
"rutarget.ru": { | |
"d": "RuTarget" | |
}, | |
"s-onetag.com": { | |
"d": "Sovrn Holdings" | |
}, | |
"s3xified.com": { | |
"d": "AdMedia" | |
}, | |
"sail-horizon.com": { | |
"d": "CM Group" | |
}, | |
"salesforceliveagent.com": { | |
"d": "Salesforce.com" | |
}, | |
"samplicio.us": { | |
"d": "Lucid Holdings" | |
}, | |
"sascdn.com": { | |
"d": "Smartadserver" | |
}, | |
"sc-static.net": { | |
"d": "Snap" | |
}, | |
"scarabresearch.com": { | |
"d": "SAP" | |
}, | |
"scorecardresearch.com": { | |
"d": "comScore" | |
}, | |
"securedvisit.com": { | |
"d": "4Cite Marketing" | |
}, | |
"segment.com": { | |
"d": "Segment.io" | |
}, | |
"segment.io": { | |
"d": "Segment.io" | |
}, | |
"semasio.net": { | |
"d": "Semasio" | |
}, | |
"serving-sys.com": { | |
"d": "Amazon" | |
}, | |
"shareaholic.com": { | |
"d": "Shareaholic" | |
}, | |
"sharethis.com": { | |
"d": "ShareThis" | |
}, | |
"sharethrough.com": { | |
"d": "Sharethrough" | |
}, | |
"simpli.fi": { | |
"d": "Simplifi Holdings" | |
}, | |
"siteimproveanalytics.com": { | |
"d": "Siteimprove" | |
}, | |
"sitescout.com": { | |
"d": "Centro" | |
}, | |
"skimresources.com": { | |
"d": "Skimbit" | |
}, | |
"smaato.net": { | |
"d": "Smaato" | |
}, | |
"smartadserver.com": { | |
"d": "Smartadserver" | |
}, | |
"snapchat.com": { | |
"d": "Snap" | |
}, | |
"socdm.com": { | |
"d": "Supership" | |
}, | |
"sojern.com": { | |
"d": "Sojern" | |
}, | |
"sonobi.com": { | |
"d": "Sonobi" | |
}, | |
"springserve.com": { | |
"d": "SpringServe" | |
}, | |
"stackadapt.com": { | |
"d": "Collective Roll" | |
}, | |
"statcounter.com": { | |
"d": "StatCounter" | |
}, | |
"steelhousemedia.com": { | |
"d": "Steel House" | |
}, | |
"stickyadstv.com": { | |
"d": "FreeWheel" | |
}, | |
"storygize.net": { | |
"d": "Storygize" | |
}, | |
"sundaysky.com": { | |
"d": "SundaySky" | |
}, | |
"t.co": { | |
"d": "Twitter" | |
}, | |
"taboola.com": { | |
"d": "Taboola" | |
}, | |
"tagcommander.com": { | |
"d": "Fjord" | |
}, | |
"tapad.com": { | |
"d": "Tapad" | |
}, | |
"teads.tv": { | |
"d": "Teads" | |
}, | |
"tealiumiq.com": { | |
"d": "Tealium" | |
}, | |
"technoratimedia.com": { | |
"d": "Synacor" | |
}, | |
"thrtle.com": { | |
"d": "Throtle" | |
}, | |
"tinypass.com": { | |
"d": "Piano Software" | |
}, | |
"tiqcdn.com": { | |
"d": "Tealium" | |
}, | |
"tns-counter.ru": { | |
"d": "ADFACT" | |
}, | |
"trackcmp.net": { | |
"d": "ActiveCampaign" | |
}, | |
"treasuredata.com": { | |
"d": "Treasure Data" | |
}, | |
"tremorhub.com": { | |
"d": "Telaria" | |
}, | |
"tribalfusion.com": { | |
"d": "Exponential Interactive" | |
}, | |
"tru.am": { | |
"d": "trueAnthem" | |
}, | |
"truoptik.com": { | |
"d": "21 Productions" | |
}, | |
"truste.com": { | |
"d": "TrustArc" | |
}, | |
"trustpilot.com": { | |
"d": "Trustpilot" | |
}, | |
"tsyndicate.com": { | |
"d": "Traffic Stars" | |
}, | |
"tubemogul.com": { | |
"d": "Adobe" | |
}, | |
"turn.com": { | |
"d": "Amobee" | |
}, | |
"tvsquared.com": { | |
"d": "TVSquared" | |
}, | |
"twitter.com": { | |
"d": "Twitter" | |
}, | |
"tynt.com": { | |
"d": "33Across" | |
}, | |
"ubembed.com": { | |
"d": "Unbounce" | |
}, | |
"undertone.com": { | |
"d": "Undertone Networks" | |
}, | |
"unrulymedia.com": { | |
"d": "Unruly Group" | |
}, | |
"usabilla.com": { | |
"d": "Momentive" | |
}, | |
"usemessages.com": { | |
"d": "HubSpot" | |
}, | |
"usercentrics.eu": { | |
"d": "Usercentrics" | |
}, | |
"userreport.com": { | |
"d": "AudienceProject" | |
}, | |
"viglink.com": { | |
"d": "Sovrn Holdings" | |
}, | |
"visualwebsiteoptimizer.com": { | |
"d": "Wingify" | |
}, | |
"vk.com": { | |
"d": "VK" | |
}, | |
"w55c.net": { | |
"d": "Roku" | |
}, | |
"walmart.com": { | |
"d": "Walmart" | |
}, | |
"weborama.fr": { | |
"d": "Weborama" | |
}, | |
"webvisor.org": { | |
"d": "Yandex" | |
}, | |
"xg4ken.com": { | |
"d": "Kenshoo TLD" | |
}, | |
"xiti.com": { | |
"d": "AT Internet" | |
}, | |
"yadro.ru": { | |
"d": "ECO PC - Complex Solutions" | |
}, | |
"yahoo.co.jp": { | |
"d": "LY-Corporation" | |
}, | |
"yahoo.com": { | |
"d": "Verizon Media" | |
}, | |
"yandex.ru": { | |
"d": "Yandex" | |
}, | |
"yieldlab.net": { | |
"d": "Virtual Minds" | |
}, | |
"yieldmo.com": { | |
"d": "YieldMo" | |
}, | |
"yieldoptimizer.com": { | |
"d": "WarnerMedia" | |
}, | |
"yimg.jp": { | |
"d": "LY-Corporation" | |
}, | |
"yotpo.com": { | |
"d": "Yotpo" | |
}, | |
"ywxi.net": { | |
"d": "PathDefender" | |
}, | |
"zemanta.com": { | |
"d": "Outbrain" | |
}, | |
"zopim.com": { | |
"d": "Zendesk" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"LoginFormTypeKeywords": { | |
"@me": 1, | |
"welcome back": 1, | |
"log on": 1, | |
"登录": 1, | |
"iniciar sesión": 1, | |
"login": 1, | |
"log in": 1, | |
"sign in": 1, | |
"forgot user": 1, | |
"enter your password": 2, | |
"登入": 1, | |
"signon": 1, | |
"reauth": 2, | |
"anmelden": 1, | |
"signin": 1, | |
"log_on": 1, | |
"sign on": 1, | |
"connexion": 1, | |
"absenden": 1, | |
"logg inn": 1 | |
}, | |
"ForgotEmailAffordanceRegularExpressions": [ | |
"^forgot.*email", | |
"email\\?$" | |
], | |
"ForgotUserNameAffordanceRegularExpressions": [ | |
"^forgot.*user.*name" | |
], | |
"NonAccountPasswordSecureTextEntryFieldLabels": [ | |
"debit", | |
"answer", | |
"account number", | |
"routing number", | |
"date of birth", | |
"zip code" | |
], | |
"ChangePasswordFormTypeKeywords": { | |
"forgotpassword": 1, | |
"forgot password": 1, | |
"reset": 1, | |
"update": 1, | |
"change": 1, | |
"再設定": 1 | |
}, | |
"NewAccountFormTypeKeywords": { | |
"set up": 1, | |
"signup": 1, | |
"create": 1, | |
"create an account": 1, | |
"create account": 1, | |
"setup": 1, | |
"sign up": 1, | |
"enrollment": 1, | |
"reg": 1, | |
"activate": 1, | |
"注册": 1 | |
}, | |
"IgnoredDataTypeFieldLabels": [ | |
"search", | |
"social security", | |
"socialsecurity", | |
"tax id number", | |
"ssn", | |
"ssno", | |
"ssnum", | |
"airport", | |
"gate code", | |
"relationship" | |
], | |
"NonAutoFillableFormTypeKeywords": [ | |
"import" | |
], | |
"OldPasswordFieldLabels": [ | |
"current", | |
"old", | |
"original" | |
], | |
"ConfirmEmailFieldLabels": [ | |
"confirm" | |
], | |
"ConfirmPasswordFieldLabels": [ | |
"repeat", | |
"retype", | |
"confirm", | |
"verify", | |
"new" | |
], | |
"ShowHideButtonLabels": [ | |
"show", | |
"hide" | |
], | |
"SearchFieldLabels": [ | |
"search" | |
], | |
"NonUsernameFieldLabels": [ | |
"login code", | |
"otpcode", | |
"password", | |
"captcha", | |
"recaptcha", | |
"sound", | |
"answer", | |
"confirmation code", | |
"verification code", | |
"zip code", | |
"stock symbol", | |
"chart", | |
"table", | |
"certificate", | |
"cash card number" | |
], | |
"PasswordFieldLabels": [ | |
"password", | |
"passwd", | |
"设置密码", | |
"passwort" | |
], | |
"ForgotPasswordAffordanceRegularExpressions": [ | |
"^forgot.*password" | |
], | |
"NonEmailFieldLabels": [ | |
"確認コード" | |
], | |
"UsernameFieldLabels": [ | |
"username", | |
"user name", | |
"screenname", | |
"screen name", | |
"loginname", | |
"login name", | |
"account name", | |
"userID", | |
"user ID", | |
"loginID", | |
"accountID", | |
"Online ID", | |
"GmailAddress", | |
"Gmail Address", | |
"usuario", | |
"Library Card Number", | |
"E-Mail-Adresse" | |
], | |
"OneTimeCodeFieldLabels": [ | |
"security code", | |
"login code", | |
"enter the code", | |
"enter code", | |
"otp", | |
"onetimecode", | |
"onetimepasscode", | |
"one time password", | |
"one time passcode", | |
"verification code", | |
"verificationCode", | |
"confirmation code", | |
"identification code", | |
"identificationCode", | |
"activation code", | |
"access code", | |
"SMS", | |
"digit code", | |
"2fa", | |
"twofactor", | |
"two-factor", | |
"two factor", | |
"authentication code", | |
"two step sign in", | |
"two-step sign in", | |
"MFA code", | |
"sign-in code", | |
"passcode texted", | |
"passcode expires", | |
"验证码", | |
"校验码", | |
"驗證碼", | |
"驗証碼", | |
"確認碼", | |
"認證碼", | |
"確認コード", | |
"認証コード", | |
"인증번호", | |
"확인코드", | |
"code de sécurité", | |
"code de vérification", | |
"code de validation", | |
"code d'identification", | |
"code d'authentification", | |
"code d'autorisation", | |
"code de confirmation", | |
"code SMS de vérification", | |
"code de connexion", | |
"Authorisierungscode", | |
"Sicherheitscode", | |
"Überprüfungscode", | |
"Bestätigungscode", | |
"Bestatigungscode", | |
"Verifizierungscode", | |
"Aktivierungscode", | |
"Codice di sicurezza", | |
"Codice attivazione", | |
"codice di attivazione", | |
"codice di conferma", | |
"codice di verifica", | |
"Kod bezpieczeństwa", | |
"Kod autoryzacyjny", | |
"Kod weryfikacyjny", | |
"código de seguridad", | |
"código de confirmación", | |
"código de seguranca", | |
"digite o codigo", | |
"código de verificación", | |
"código de verificação", | |
"código de confirmacao", | |
"Код проверки", | |
"код безопасности", | |
"код подтверждения", | |
"Код аутентификации", | |
"код підтвердження", | |
"dogrulama kodu", | |
"mã bảo mật", | |
"Mã Xác Minh", | |
"mã kích hoạt", | |
"รหัสความปลอดภัย", | |
"รหัสยืนยัน", | |
"รหัสOTP", | |
"รหัสการตรวจสอบยืนยัน", | |
"รหัสการยืนยัน", | |
"Kode keamanan", | |
"Kode konfirmasi", | |
"Kode verifikasi", | |
"सत्यापन कोड", | |
"Kod pengesahan", | |
"Masukkan Kod", | |
"Codul de confirmare" | |
], | |
"WeakOneTimeCodeFieldLabels": [ | |
"code", | |
"passcode", | |
"PIN", | |
"token", | |
"código", | |
"코드", | |
"コード", | |
"код" | |
], | |
"DayFieldLabels": [ | |
"day", | |
"jour" | |
], | |
"MonthFieldLabels": [ | |
"month", | |
"date m", | |
"date mo", | |
"mois" | |
], | |
"YearFieldLabels": [ | |
"year", | |
"date y", | |
"date yr", | |
"année" | |
] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var pageArguments = {}; | |
var HTMLViewController = { | |
trySubmit: function(button) | |
{ | |
var computedStyle = window.getComputedStyle(button); | |
// Don't use button.type here, since the default type for button is annoyingly "submit". | |
// Check for an explicit type attribute value of "submit". | |
if (button.getAttribute("type") !== "submit" || computedStyle.visibility === "hidden" || computedStyle.display === "none") | |
return false; | |
button.click(); | |
return true; | |
}, | |
// On Mac, the submit button always has the default button look. | |
keyDown: function(event) | |
{ | |
if (event.target.tagName === "TEXTAREA" || event.keyIdentifier !== "Enter") | |
return; | |
var buttons = document.getElementsByTagName("button"); | |
for (var i = 0; i < buttons.length; ++i) { | |
if (HTMLViewController.trySubmit(buttons[i])) { | |
event.preventDefault(); | |
return; | |
} | |
} | |
var inputButtons = document.getElementsByTagName("input"); | |
for (var i = 0; i < inputButtons.length; ++i) { | |
if (HTMLViewController.trySubmit(inputButtons[i])) { | |
event.preventDefault(); | |
return; | |
} | |
} | |
}, | |
setItemText: function(itemID, value) | |
{ | |
var ele = document.getElementById(itemID); | |
if (ele.tagName == "INPUT" || ele.tagName == "SELECT" || ele.tagName == "TEXTAREA") | |
ele.value = value; | |
else | |
ele.innerText = value; | |
}, | |
itemText: function(itemID) | |
{ | |
var ele = document.getElementById(itemID); | |
if (ele.tagName == "INPUT" || ele.tagName == "SELECT" || ele.tagName == "TEXTAREA") | |
return ele.value; | |
else if (ele.firstChild) | |
return ele.firstChild.data; | |
else return ""; | |
}, | |
setItemChecked: function(itemID, value) | |
{ | |
document.getElementById(itemID).checked = value; | |
}, | |
itemChecked: function(itemID) | |
{ | |
return document.getElementById(itemID).checked; | |
}, | |
setItemEnabled: function(itemID, value) | |
{ | |
var item = document.getElementById(itemID); | |
item.disabled = !value; | |
if (item.parentElement.tagName == "LABEL") { | |
if (value) | |
item.parentElement.classList.remove("disabled"); | |
else | |
item.parentElement.classList.add("disabled"); | |
} | |
}, | |
insertOptionInSelect: function(selectID, position, label, value) | |
{ | |
var select = document.getElementById(selectID); | |
var option = document.createElement("option"); | |
option.appendChild(document.createTextNode(label)); | |
option.value = value; | |
select.add(option, select.options[position]); | |
}, | |
appendToSelect: function(itemID, label, itemValue, itemStyle) | |
{ | |
var selectEle = document.getElementById(itemID); | |
var o; | |
if (label == "") | |
o = document.createElement("hr"); | |
else { | |
o = document.createElement("option"); | |
o.appendChild(document.createTextNode(label)); | |
o.value = itemValue ? itemValue : selectEle.length; | |
o.style.cssText = itemStyle; | |
} | |
selectEle.add(o, null); | |
}, | |
setSelectIndex: function(itemID, index) | |
{ | |
var selectEle = document.getElementById(itemID); | |
selectEle.selectedIndex = index; | |
}, | |
setOptionEnabled: function(selectID, optionIndex, enabled) | |
{ | |
document.getElementById(selectID)[optionIndex].disabled = !enabled; | |
}, | |
indexOfItemWithValue: function(selectID, value) | |
{ | |
var select = document.getElementById(selectID); | |
for (var i = 0; i < select.options.length; ++i) { | |
if (select.options[i].value == value) | |
return i; | |
} | |
return -1; | |
}, | |
clearSelect: function(itemID) | |
{ | |
var selectEle = document.getElementById(itemID); | |
selectEle.removeChildren(); | |
}, | |
setWidth: function(width) | |
{ | |
window.resizeTo(width); | |
}, | |
htmlOffsetHeight: function() | |
{ | |
return document.getElementsByTagName("html")[0].offsetHeight; | |
}, | |
addClass: function(itemID, itemClass) | |
{ | |
document.getElementById(itemID).classList.add(itemClass); | |
}, | |
removeClass: function(itemID, itemClass) | |
{ | |
document.getElementById(itemID).classList.remove(itemClass); | |
}, | |
setAttribute: function(itemID, attrName, attrValue) | |
{ | |
document.getElementById(itemID).setAttribute(attrName, attrValue); | |
}, | |
setTitle: function(newTitle) | |
{ | |
document.title = newTitle; | |
}, | |
focusItem: function(itemID) | |
{ | |
var ele = document.getElementById(itemID); | |
ele.focus(); | |
ele.selectionStart = 0; | |
ele.selectionEnd = ele.value.length; | |
}, | |
contextMenu: function(event) | |
{ | |
if (event.target.tagName === "TEXTAREA") | |
return; | |
if (event.target.tagName === "INPUT" && (event.target.type === "password" || event.target.type === "text" || event.target.type == "search")) | |
return; | |
event.preventDefault(); | |
}, | |
pageLoaded: function() | |
{ | |
var query = document.location.search; | |
if (query) { | |
query = query.substr(1); | |
var args = query.split("&"); | |
for (var i = 0; i < args.length; i++) { | |
var nameValue = args[i].split("="); | |
pageArguments[nameValue[0]] = nameValue[1]; | |
} | |
} | |
document.body.addEventListener("keydown", HTMLViewController.keyDown); | |
document.addEventListener("contextmenu", HTMLViewController.contextMenu); | |
HTMLViewController.localize(); | |
}, | |
UIString: function(string) | |
{ | |
if (window.localizedStrings && string in window.localizedStrings) | |
string = window.localizedStrings[string]; | |
else { | |
console.error("Localized string \"" + string + "\" not found."); | |
string = "LOCALIZED STRING NOT FOUND"; | |
} | |
return string; | |
}, | |
loadLocalizedStrings: function(controller) | |
{ | |
document.write("<script type='text/javascript' charset='utf-8' src='safari-resource:/WBSLocalizedStrings.js'></" + "script>"); | |
}, | |
localize: function() | |
{ | |
var elements = document.getElementsByClassName("l12n"); | |
for (var i = 0; i < elements.length; ++i) | |
elements[i].firstChild.data = HTMLViewController.UIString(elements[i].firstChild.data); | |
var toolTipElements = document.getElementsByClassName("l12n-tooltip"); | |
for (var i = 0; i < toolTipElements.length; ++i) | |
toolTipElements[i].title = HTMLViewController.UIString(toolTipElements[i].title); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment