mirror of
https://github.com/NohamR/safari-internal-js.git
synced 2026-02-21 18:35:43 +00:00
Add Safari internal JS services and documentation
This commit is contained in:
216
.gitignore
vendored
Normal file
216
.gitignore
vendored
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[codz]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
# Pipfile.lock
|
||||||
|
|
||||||
|
# UV
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# uv.lock
|
||||||
|
|
||||||
|
# poetry
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||||
|
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||||
|
# commonly ignored for libraries.
|
||||||
|
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||||
|
# poetry.lock
|
||||||
|
# poetry.toml
|
||||||
|
|
||||||
|
# pdm
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||||
|
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
||||||
|
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
||||||
|
# pdm.lock
|
||||||
|
# pdm.toml
|
||||||
|
.pdm-python
|
||||||
|
.pdm-build/
|
||||||
|
|
||||||
|
# pixi
|
||||||
|
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
||||||
|
# pixi.lock
|
||||||
|
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
||||||
|
# in the .venv directory. It is recommended not to include this directory in version control.
|
||||||
|
.pixi
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
*.rdb
|
||||||
|
*.aof
|
||||||
|
*.pid
|
||||||
|
|
||||||
|
# RabbitMQ
|
||||||
|
mnesia/
|
||||||
|
rabbitmq/
|
||||||
|
rabbitmq-data/
|
||||||
|
|
||||||
|
# ActiveMQ
|
||||||
|
activemq-data/
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.envrc
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
||||||
|
|
||||||
|
# PyCharm
|
||||||
|
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||||
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
|
# .idea/
|
||||||
|
|
||||||
|
# Abstra
|
||||||
|
# Abstra is an AI-powered process automation framework.
|
||||||
|
# Ignore directories containing user credentials, local state, and settings.
|
||||||
|
# Learn more at https://abstra.io/docs
|
||||||
|
.abstra/
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
||||||
|
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
||||||
|
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
||||||
|
# you could uncomment the following to ignore the entire vscode folder
|
||||||
|
# .vscode/
|
||||||
|
|
||||||
|
# Ruff stuff:
|
||||||
|
.ruff_cache/
|
||||||
|
|
||||||
|
# PyPI configuration file
|
||||||
|
.pypirc
|
||||||
|
|
||||||
|
# Marimo
|
||||||
|
marimo/_static/
|
||||||
|
marimo/_lsp/
|
||||||
|
__marimo__/
|
||||||
|
|
||||||
|
# Streamlit
|
||||||
|
.streamlit/secrets.toml
|
||||||
|
.DS_Store
|
||||||
175
README.md
Normal file
175
README.md
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
# Safari Internal JavaScript Services
|
||||||
|
|
||||||
|
- Safari Version:** 15.7
|
||||||
|
- Extraction Method:** dyld_shared_cache
|
||||||
|
- Extraction Date:** 16/01/2026
|
||||||
|
|
||||||
|
## Disclaimer:
|
||||||
|
These files are provided for educational and research purposes only. They are extracted from Safari's internal implementation to help developers and researchers understand browser functionality. These files are property of Apple Inc. and should not be used in production environments or for any commercial purposes.
|
||||||
|
|
||||||
|
**Note:** The summaries and descriptions of each file below were AI-generated and may contain inaccuracies or inconsistencies.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Password & Form Autofill System
|
||||||
|
|
||||||
|
### **[AutomaticPasswords.js](js/forms/AutomaticPasswords.js)**
|
||||||
|
Manages Safari's automatic strong password generation:
|
||||||
|
- Removes auto-generated passwords from password fields
|
||||||
|
- Controls visibility of suggested strong passwords
|
||||||
|
- Handles focus/blur events when users interact with password fields
|
||||||
|
- Manages the "autofilled" state of password inputs
|
||||||
|
|
||||||
|
### **[FormMetadata.js](js/forms/FormMetadata.js)**
|
||||||
|
The brain of Safari's form autofill system:
|
||||||
|
- **Form Detection & Classification**: Identifies login forms, signup forms, password change forms, and standard forms
|
||||||
|
- **Smart Field Recognition**: Uses pattern matching, element positioning, visual analysis, and machine learning-like scoring to identify:
|
||||||
|
- Username fields
|
||||||
|
- Password fields (current, new, confirm)
|
||||||
|
- Credit card fields (number, CVV, expiration, cardholder)
|
||||||
|
- Address fields (street, city, postal code)
|
||||||
|
- Phone numbers (split across multiple fields)
|
||||||
|
- Email addresses
|
||||||
|
- One-time codes (2FA)
|
||||||
|
|
||||||
|
### **[FormMetadataClassification.js](js/forms/FormMetadataClassification.js)**
|
||||||
|
Intelligently classifies form fields to enable autofill:
|
||||||
|
- **Identifies field types**: credit cards, names, addresses, phone numbers, emails, birthdays, passwords, etc.
|
||||||
|
- **Handles multi-part fields**: splits fields like "First Name | Last Name" or phone numbers across multiple inputs
|
||||||
|
- **Continuation detection**: recognizes when a single piece of data (like credit card number) is split across multiple fields
|
||||||
|
- **Uses multiple signals**: autocomplete attributes, field names, placeholders, sizes, and positioning
|
||||||
|
- **Date field parsing**: understands various date formats and splits (day/month/year)
|
||||||
|
- **Smart matching**: uses pattern recognition to classify fields even without explicit HTML hints
|
||||||
|
|
||||||
|
### **[NodePath.js](js/utilities/NodePath.js)**
|
||||||
|
Creates stable references to DOM elements:
|
||||||
|
- **Path-based element identification**: creates a "fingerprint" for DOM nodes that works even when the DOM changes
|
||||||
|
- **Fuzzy matching**: uses similarity scoring (Levenshtein distance) to relocate elements after page updates
|
||||||
|
- **Handles shadow DOM and iframes**: traverses across shadow boundaries and iframe documents
|
||||||
|
- **Range support**: can reference text selections, not just elements
|
||||||
|
- **Resilient resolution**: uses multiple strategies (CSS selectors, position, attributes) to find elements
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reader Mode System
|
||||||
|
|
||||||
|
### **[Reader.js](js/reader/Reader.js)**
|
||||||
|
Powers Safari's Reader Mode core functionality:
|
||||||
|
- Manages visibility transitions for Reader view
|
||||||
|
- Handles iframe URL caching/restoration when entering/exiting Reader
|
||||||
|
- Checks JavaScript enablement settings
|
||||||
|
- Mac-specific UI adjustments
|
||||||
|
|
||||||
|
### **[ReaderArticleFinder.js](js/reader/ReaderArticleFinder.js)** (~3500 lines)
|
||||||
|
Safari's article detection and cleaning algorithm (similar to Mozilla's Readability):
|
||||||
|
|
||||||
|
**Article Detection Strategies:**
|
||||||
|
1. Schema.org metadata (`<article itemtype="Article">`)
|
||||||
|
2. OpenGraph tags (`<meta property="og:type" content="article">`)
|
||||||
|
3. Visual examination (hit-testing specific screen coordinates)
|
||||||
|
4. Quirks list for known sites (NYTimes, Medium, etc.)
|
||||||
|
|
||||||
|
**Scoring System:**
|
||||||
|
- Text density analysis
|
||||||
|
- Link density (fewer links = more likely article)
|
||||||
|
- Tag names (article, main, section boost score)
|
||||||
|
- Class names ("article", "content" boost; "comment", "sidebar" reduce)
|
||||||
|
- Position on page
|
||||||
|
- Font consistency
|
||||||
|
|
||||||
|
**Smart Cleaning:**
|
||||||
|
- Removes ads, comments, navigation
|
||||||
|
- Keeps images, videos, tweets
|
||||||
|
- Converts lazy-loaded images
|
||||||
|
- Preserves tables and code blocks
|
||||||
|
- Handles multi-column layouts
|
||||||
|
- Detects CJK (Chinese, Japanese, Korean) text using Unicode ranges
|
||||||
|
|
||||||
|
### **[ReaderSharedUI.js](js/reader/ReaderSharedUI.js)**
|
||||||
|
Powers the actual Reader Mode interface:
|
||||||
|
|
||||||
|
**Layout Management:**
|
||||||
|
- Multi-column pagination for long articles
|
||||||
|
- Responsive design adapting to window size
|
||||||
|
- 12+ font families (System, Charter, Georgia, Iowan, Palatino, etc.)
|
||||||
|
- 4 themes: White, Sepia, Gray, Night
|
||||||
|
- 12 text size levels with custom line heights per font
|
||||||
|
|
||||||
|
**Interactive Features:**
|
||||||
|
- Smooth scrolling with animations
|
||||||
|
- Content-aware navigation (stops at natural break points)
|
||||||
|
- Next page auto-loading for paginated articles
|
||||||
|
- Print/email formatting
|
||||||
|
- Reading position memory
|
||||||
|
- Table of Contents generation from headings
|
||||||
|
- AI-generated summary display with collapsible UI
|
||||||
|
- Sidebar for TOC/summary on wide screens
|
||||||
|
|
||||||
|
### **[ReaderSharedUINormalWorld.js](js/reader/ReaderSharedUINormalWorld.js)**
|
||||||
|
Enhances Reader Mode with rich content:
|
||||||
|
- **Twitter/X integration**: replaces simple tweet embeds with rich Twitter widgets
|
||||||
|
- Loads Twitter's widget JavaScript on demand
|
||||||
|
- Handles transition from placeholder tweets to interactive embeds
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Web Page Analysis & Data Extraction
|
||||||
|
|
||||||
|
### **[SchemaDataExtractor.js](js/schema/SchemaDataExtractor.js)**
|
||||||
|
Extracts contact information from web pages:
|
||||||
|
- Parses **Microdata** markup (HTML attributes like `itemscope`, `itemprop`)
|
||||||
|
- Parses **JSON-LD** structured data (schema.org formatted JSON)
|
||||||
|
- Extracts addresses, phone numbers, business names
|
||||||
|
- Enables Safari's "Add to Contacts" feature
|
||||||
|
|
||||||
|
### **[SchemaOrgMarkupChecker.js](js/schema/SchemaOrgMarkupChecker.js)**
|
||||||
|
Simple detection utility:
|
||||||
|
- Returns `true` if page contains schema.org structured data
|
||||||
|
- Checks both JSON-LD scripts and microdata attributes
|
||||||
|
- Used to determine if page has extractable structured information
|
||||||
|
|
||||||
|
### **[MetadataExtractor.js](js/metadata/MetadataExtractor.js)**
|
||||||
|
Extracts website icons and branding:
|
||||||
|
- Favicon URLs
|
||||||
|
- Apple Touch icons (for iOS home screen)
|
||||||
|
- Template icons with colors
|
||||||
|
- Sorts icons by size/quality
|
||||||
|
|
||||||
|
### **[WebContentLayoutAnalyzer.js](js/layout/WebContentLayoutAnalyzer.js)**
|
||||||
|
Analyzes page responsive design:
|
||||||
|
- Detects centered container elements
|
||||||
|
- Determines if containers have fixed width (non-responsive)
|
||||||
|
- Measures container movement during window resize
|
||||||
|
- Helps Safari optimize reader mode and display adjustments
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Search & Discovery
|
||||||
|
|
||||||
|
### **[OpenSearchURLFinder.js](js/search/OpenSearchURLFinder.js)**
|
||||||
|
Enables custom search engine discovery:
|
||||||
|
- Finds `<link rel="search">` tags in page header
|
||||||
|
- Powers Safari's search engine discovery feature
|
||||||
|
- Allows users to add custom search engines from websites
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Localization & Translation
|
||||||
|
|
||||||
|
### **[Translation.js](js/translation/Translation.js)**
|
||||||
|
Manages language attributes during translation:
|
||||||
|
- Updates page's `lang` attribute when Safari translates content
|
||||||
|
- Ensures accessibility tools and screen readers recognize current language
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Save & Archive
|
||||||
|
|
||||||
|
### **[SavePageInliningOrDiscardingExternalResources.js](js/utilities/SavePageInliningOrDiscardingExternalResources.js)**
|
||||||
|
Creates self-contained web archives:
|
||||||
|
- Copies all HTML elements and their styles
|
||||||
|
- Inlines CSS from stylesheets into the document
|
||||||
|
- Converts external resource URLs to local filenames
|
||||||
|
- Removes scripts, objects, and dynamic content
|
||||||
|
- Recursively captures iframe content
|
||||||
|
- Powers Safari's "Save As Web Archive" feature
|
||||||
43
js/forms/AutomaticPasswords.js
Normal file
43
js/forms/AutomaticPasswords.js
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//# sourceURL=__InjectedScript_AutomaticPasswords.js
|
||||||
|
/* Copyright (c) 2025 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();
|
||||||
4395
js/forms/FormMetadata.js
Normal file
4395
js/forms/FormMetadata.js
Normal file
File diff suppressed because it is too large
Load Diff
638
js/forms/FormMetadataClassification.js
Normal file
638
js/forms/FormMetadataClassification.js
Normal file
@@ -0,0 +1,638 @@
|
|||||||
|
//# sourceURL=__InjectedScript_FormMetadataClassification.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
"use strict";
|
||||||
|
const WBSABAddressProperty = "Address",
|
||||||
|
WBSABPhoneProperty = "Phone",
|
||||||
|
_WBSABAddressZIPKey = "ZIP",
|
||||||
|
WBSFormControlMetadataDefaultMaxLength = 524288,
|
||||||
|
WBSIgnoredClassificationToken = "-sf-ignored",
|
||||||
|
WBSDateDayOrderedPartToken = "-sf-day",
|
||||||
|
WBSDateMonthOrderedPartToken = "-sf-month",
|
||||||
|
WBSDateYearOrderedPartToken = "-sf-year",
|
||||||
|
WBSGivenNameOrderedPartToken = "given-name",
|
||||||
|
WBSAdditionalNameOrderedPartToken = "additional-name",
|
||||||
|
WBSFamilyNameOrderedPartToken = "family-name",
|
||||||
|
WBSLocaleForCreditCardExpirationDate = "en_US",
|
||||||
|
WBSCreditCardTypeClassificationToken = "cc-type",
|
||||||
|
WBSCreditCardHolderNameClassificationToken = "cc-name",
|
||||||
|
WBSCreditCardNumberClassificationToken = "cc-number",
|
||||||
|
WBSCreditCardExpirationClassificationToken = "cc-exp",
|
||||||
|
WBSCreditCardSecurityCodeClassificationToken = "cc-csc",
|
||||||
|
WBSCreditCardHolderNameClassificationDefaultOrderedParts = [
|
||||||
|
WBSGivenNameOrderedPartToken,
|
||||||
|
WBSAdditionalNameOrderedPartToken,
|
||||||
|
WBSFamilyNameOrderedPartToken,
|
||||||
|
],
|
||||||
|
WBSCreditCardExpirationClassificationDefaultOrderedParts = [
|
||||||
|
WBSDateMonthOrderedPartToken,
|
||||||
|
WBSDateYearOrderedPartToken,
|
||||||
|
],
|
||||||
|
WBSCredentialUsernameClassificationToken = "username",
|
||||||
|
WBSCredentialCurrentPasswordClassificationToken = "current-password",
|
||||||
|
WBSCredentialNewPasswordClassificationToken = "new-password",
|
||||||
|
WBSContactNameClassificationToken = "name",
|
||||||
|
WBSContactNameClassificationDefaultOrderedParts = [
|
||||||
|
WBSGivenNameOrderedPartToken,
|
||||||
|
WBSAdditionalNameOrderedPartToken,
|
||||||
|
WBSFamilyNameOrderedPartToken,
|
||||||
|
],
|
||||||
|
WBSNameOrderedPartTokensSet = new Set(
|
||||||
|
WBSContactNameClassificationDefaultOrderedParts,
|
||||||
|
),
|
||||||
|
WBSContactInstantMessageClassificationToken = "-sf-instant-message",
|
||||||
|
WBSContactPostalCodeClassificationToken = "postal-code",
|
||||||
|
WBSContactStreetAddressClassificationToken = "street-address",
|
||||||
|
WBSContactStreetAddressLine1OrderedPartToken = "address-line1",
|
||||||
|
WBSContactStreetAddressLine2OrderedPartToken = "address-line2",
|
||||||
|
WBSContactStreetAddressLine3OrderedPartToken = "address-line3",
|
||||||
|
WBSContactTelephoneClassificationToken = "tel",
|
||||||
|
WBSTelephoneCountryCodeOrderedPartToken = "tel-country-code",
|
||||||
|
WBSTelephoneAreaCodeOrderedPartToken = "tel-area-code",
|
||||||
|
WBSTelephoneLocalPrefixOrderedPartToken = "tel-local-prefix",
|
||||||
|
WBSTelephoneLocalSuffixOrderedPartToken = "tel-local-suffix",
|
||||||
|
WBSTelephoneExtensionOrderedPartToken = "tel-extension",
|
||||||
|
WBSTelephoneDefaultOrderedParts = [
|
||||||
|
WBSTelephoneCountryCodeOrderedPartToken,
|
||||||
|
WBSTelephoneAreaCodeOrderedPartToken,
|
||||||
|
WBSTelephoneLocalPrefixOrderedPartToken,
|
||||||
|
WBSTelephoneLocalSuffixOrderedPartToken,
|
||||||
|
WBSTelephoneExtensionOrderedPartToken,
|
||||||
|
],
|
||||||
|
WBSContactBirthdayClassificationToken = "bday",
|
||||||
|
WBSContactEmailClassificationToken = "email",
|
||||||
|
WBSDeviceEIDClassificationToken = "device-eid",
|
||||||
|
WBSDeviceIMEIClassificationToken = "device-imei",
|
||||||
|
AllowedControlTagsForStandaloneCreditCardCompositeExpirationControl = new Set(
|
||||||
|
["input", "select", "textarea"],
|
||||||
|
);
|
||||||
|
class FormMetadataClassification {
|
||||||
|
#e(e) {
|
||||||
|
return null != e && "object" == typeof e;
|
||||||
|
}
|
||||||
|
#t(e) {
|
||||||
|
return this.#e(e) && "string" == typeof e.ControlTagName;
|
||||||
|
}
|
||||||
|
#o(e) {
|
||||||
|
return this.#e(e) && "string" == typeof e.property;
|
||||||
|
}
|
||||||
|
fieldLooksLikeDateField(e) {
|
||||||
|
return !!(
|
||||||
|
e.ControlLooksLikeDayField ||
|
||||||
|
e.ControlLooksLikeMonthField ||
|
||||||
|
e.ControlLooksLikeYearField
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#r(e) {
|
||||||
|
let t = e.ControlMaxLength;
|
||||||
|
return (
|
||||||
|
(void 0 === t || t < 0 || t > WBSFormControlMetadataDefaultMaxLength) &&
|
||||||
|
(t = WBSFormControlMetadataDefaultMaxLength),
|
||||||
|
t
|
||||||
|
);
|
||||||
|
}
|
||||||
|
fieldLooksLikeItExpectsDataOfSize(e, t) {
|
||||||
|
return (e.ControlSize ?? 0) <= t || this.#r(e) <= t;
|
||||||
|
}
|
||||||
|
fieldCouldBeCreditCardNumberContinuation(e, t) {
|
||||||
|
const o = 4;
|
||||||
|
if (t.length >= o) return !1;
|
||||||
|
if (!t[0]?.ControlLooksLikeCreditCardNumberField) return !1;
|
||||||
|
const r = 2;
|
||||||
|
if (e.ControlMaxLength === r) return !1;
|
||||||
|
if (e.ControlLooksLikeCreditCardNumberField) return !0;
|
||||||
|
if (e.ControlLooksLikeCreditCardSecurityCodeField) return !1;
|
||||||
|
if (e.ControlLooksLikeCreditCardCompositeExpirationDateField) return !1;
|
||||||
|
const n = 6;
|
||||||
|
if (!this.fieldLooksLikeItExpectsDataOfSize(e, n)) return !1;
|
||||||
|
const i = t.at(-1);
|
||||||
|
return !(i && !this.fieldLooksLikeItExpectsDataOfSize(i, n));
|
||||||
|
}
|
||||||
|
labelsCouldRepresentContinuation(e, t, o, r) {
|
||||||
|
return (
|
||||||
|
!(!e || !o) &&
|
||||||
|
(e === o ||
|
||||||
|
(!!t &&
|
||||||
|
(!r ||
|
||||||
|
(t.property === r.property &&
|
||||||
|
(!r.component || t.component === r.component)))))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#n(e) {
|
||||||
|
const t = [
|
||||||
|
WBSContactStreetAddressLine1OrderedPartToken,
|
||||||
|
WBSContactStreetAddressLine2OrderedPartToken,
|
||||||
|
WBSContactStreetAddressLine3OrderedPartToken,
|
||||||
|
],
|
||||||
|
o = [
|
||||||
|
WBSContactStreetAddressLine2OrderedPartToken,
|
||||||
|
WBSContactStreetAddressLine3OrderedPartToken,
|
||||||
|
];
|
||||||
|
if (e.AutocompleteTokens)
|
||||||
|
for (let o of e.AutocompleteTokens)
|
||||||
|
switch (o) {
|
||||||
|
case "street-address":
|
||||||
|
return t;
|
||||||
|
case "address-line1":
|
||||||
|
return [WBSContactStreetAddressLine1OrderedPartToken];
|
||||||
|
case "address-line2":
|
||||||
|
case "address-level2":
|
||||||
|
return [WBSContactStreetAddressLine2OrderedPartToken];
|
||||||
|
case "address-line3":
|
||||||
|
case "address-level1":
|
||||||
|
return [WBSContactStreetAddressLine3OrderedPartToken];
|
||||||
|
}
|
||||||
|
let r = e.ControlFieldName,
|
||||||
|
n = r?.indexOf("1") ?? -1,
|
||||||
|
i = r?.indexOf("2") ?? -1;
|
||||||
|
return -1 === n
|
||||||
|
? -1 === i
|
||||||
|
? t
|
||||||
|
: o
|
||||||
|
: -1 === i || digit1location < digit2location
|
||||||
|
? [WBSContactStreetAddressLine1OrderedPartToken]
|
||||||
|
: o;
|
||||||
|
}
|
||||||
|
fieldCouldBePhoneNumberContinuation(e, t) {
|
||||||
|
const o = 5;
|
||||||
|
if (t.length >= o) return !1;
|
||||||
|
if (t[0]?.AddressBookValueSpecifier?.property !== WBSABPhoneProperty)
|
||||||
|
return !1;
|
||||||
|
const r = 5;
|
||||||
|
return !!this.fieldLooksLikeItExpectsDataOfSize(e, r);
|
||||||
|
}
|
||||||
|
fieldCouldBePostCodeContinuation(e, t) {
|
||||||
|
const o = 3;
|
||||||
|
if (t.length >= o) return !1;
|
||||||
|
if (t[0]?.AddressBookValueSpecifier?.component != _WBSABAddressZIPKey)
|
||||||
|
return !1;
|
||||||
|
const r = 6;
|
||||||
|
return !!this.fieldLooksLikeItExpectsDataOfSize(e, r);
|
||||||
|
}
|
||||||
|
fieldLooksLikeSameDataType(e, t) {
|
||||||
|
const o = t.at(-1);
|
||||||
|
return (
|
||||||
|
!!this.labelsCouldRepresentContinuation(
|
||||||
|
o?.AddressBookLabel,
|
||||||
|
o?.AddressBookValueSpecifier,
|
||||||
|
e?.AddressBookLabel,
|
||||||
|
e?.AddressBookValueSpecifier,
|
||||||
|
) ||
|
||||||
|
!!(
|
||||||
|
o &&
|
||||||
|
this.fieldLooksLikeDateField(o) &&
|
||||||
|
this.fieldLooksLikeDateField(e)
|
||||||
|
) ||
|
||||||
|
!!this.fieldCouldBePhoneNumberContinuation(e, t) ||
|
||||||
|
!!this.fieldCouldBePostCodeContinuation(e, t) ||
|
||||||
|
!!this.fieldCouldBeCreditCardNumberContinuation(e, t)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#i(e) {
|
||||||
|
if (
|
||||||
|
(globalThis.DOMRect ||
|
||||||
|
(globalThis.DOMRect = class {
|
||||||
|
constructor(e, t, o, r) {
|
||||||
|
((this.left = e),
|
||||||
|
(this.right = e + o),
|
||||||
|
(this.top = t),
|
||||||
|
(this.bottom = t + r),
|
||||||
|
(this.width = o),
|
||||||
|
(this.height = r));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
e.ControlRectLeft ||
|
||||||
|
e.ControlRectTop ||
|
||||||
|
e.ControlRectWidth ||
|
||||||
|
e.ControlRectHeight)
|
||||||
|
)
|
||||||
|
return new DOMRect(
|
||||||
|
e.ControlRectLeft,
|
||||||
|
e.ControlRectTop,
|
||||||
|
e.ControlRectWidth,
|
||||||
|
e.ControlRectHeight,
|
||||||
|
);
|
||||||
|
let t = globalThis.FormMetadataJS?.formControlWithUniqueID(
|
||||||
|
e.ControlUniqueID,
|
||||||
|
);
|
||||||
|
return t ? t.getBoundingClientRect() : new DOMRect(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
fieldLooksLikeContinuation(e, t, o) {
|
||||||
|
if (!e.ControlIsTextField && "SELECT" !== e.ControlTagName.toUpperCase())
|
||||||
|
return !1;
|
||||||
|
if (!this.fieldLooksLikeSameDataType(e, t)) return !1;
|
||||||
|
if (o) return !0;
|
||||||
|
const r = this.#i(t.at(-1)),
|
||||||
|
n = this.#i(e);
|
||||||
|
if (Math.abs(r.top - n.top) > 3) return !1;
|
||||||
|
let i, a;
|
||||||
|
return (
|
||||||
|
r.left < n.left ? ((i = r), (a = n)) : ((i = n), (a = r)),
|
||||||
|
!(a.left - i.right > 60)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
continuingFieldsInFormControls(e, t, o, r) {
|
||||||
|
const n = [e[t]];
|
||||||
|
for (let i = t + 1; i < e.length; ++i) {
|
||||||
|
const t = e[i];
|
||||||
|
if (o && !t.ControlIsTextField) break;
|
||||||
|
if (!this.fieldLooksLikeContinuation(t, n, r)) break;
|
||||||
|
n.push(t);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
classifyControlsRelatedToNameParts(e, t, o) {
|
||||||
|
const r = e[t];
|
||||||
|
((r.ControlClassification = o),
|
||||||
|
(r.ControlOrderedParts = [r.AddressBookValueSpecifier?.classification]));
|
||||||
|
const n = new Set([r.AddressBookValueSpecifier?.classification]),
|
||||||
|
i = [e[t]];
|
||||||
|
for (let r = t + 1; r < e.length; ++r) {
|
||||||
|
const t = e[r];
|
||||||
|
if (!t.ControlIsTextField) break;
|
||||||
|
const a = t.AddressBookValueSpecifier?.classification;
|
||||||
|
if (!a) break;
|
||||||
|
if (!WBSNameOrderedPartTokensSet.has(a) || n.has(a)) break;
|
||||||
|
((t.ControlClassification = o),
|
||||||
|
(t.ControlOrderedParts = [a]),
|
||||||
|
n.add(a),
|
||||||
|
i.push(t));
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
identifyDateFields(e) {
|
||||||
|
let t,
|
||||||
|
o,
|
||||||
|
r,
|
||||||
|
n = !1;
|
||||||
|
for (let i of e)
|
||||||
|
if (i.ControlLooksLikeDayField) {
|
||||||
|
if (t) return [!1];
|
||||||
|
((t = i), (n = !0));
|
||||||
|
} else if (i.ControlLooksLikeMonthField) {
|
||||||
|
if (o) return [!1];
|
||||||
|
((o = i), (n = !0));
|
||||||
|
} else if (i.ControlLooksLikeYearField) {
|
||||||
|
if (r) return [!1];
|
||||||
|
((r = i), (n = !0));
|
||||||
|
}
|
||||||
|
return [n, r, o, t];
|
||||||
|
}
|
||||||
|
canonicalizedDateTemplate(e) {
|
||||||
|
if (e && (e = e.replace(/\s/g, "")).length && !/[^dmyDMY\/.-]/g.test(e))
|
||||||
|
return (e = (e = (e = e.replace(/D/g, "d")).replace(/m/g, "M")).replace(
|
||||||
|
/Y/g,
|
||||||
|
"y",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
classifyDateFields(e, t, o, r, n, i, a) {
|
||||||
|
if (e.length > 3) return !1;
|
||||||
|
if (1 === e.length) {
|
||||||
|
if (!e[0].ControlIsTextField) return !1;
|
||||||
|
let i = e[0].ControlRequiredFormatForDateTimeInput;
|
||||||
|
if (!i) {
|
||||||
|
const t = n ? new Date(1999, 11, 30) : new Date(1999, 11);
|
||||||
|
let o = this.#r(e[0]),
|
||||||
|
r = this.canonicalizedDateTemplate(e[0].ControlPlaceholder),
|
||||||
|
s = r?.length ? r : n ? "ddMMy" : "MMyy";
|
||||||
|
i = FormMetadataJSController.dateFormatFromTemplate(s, a);
|
||||||
|
let l = FormMetadataJSController.stringFromDateFormat(i, t);
|
||||||
|
if (
|
||||||
|
(l.length > o &&
|
||||||
|
((s = n ? "dMMyy" : "MMyy"),
|
||||||
|
(i = FormMetadataJSController.dateFormatFromTemplate(s, a)),
|
||||||
|
(l = FormMetadataJSController.stringFromDateFormat(i, t)),
|
||||||
|
l.length > o &&
|
||||||
|
((s = n ? "dMyy" : "Myy"),
|
||||||
|
(i = FormMetadataJSController.dateFormatFromTemplate(s, a)),
|
||||||
|
(l = FormMetadataJSController.stringFromDateFormat(i, t)))),
|
||||||
|
l.length > o)
|
||||||
|
)
|
||||||
|
return !1;
|
||||||
|
}
|
||||||
|
const s = [];
|
||||||
|
for (const e of i) {
|
||||||
|
let t;
|
||||||
|
("y" === e ? (t = o) : "M" === e ? (t = r) : "d" === e && (t = n),
|
||||||
|
t && !s.includes(t) && s.push(t));
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
(e[0].ControlClassification = t),
|
||||||
|
(e[0].ControlOrderedParts = s),
|
||||||
|
(e[0].ControlRequiredFormatForDateTimeInput = i),
|
||||||
|
!0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let [s, l, d, C] = this.identifyDateFields(e);
|
||||||
|
if (!s) return !1;
|
||||||
|
if (C && !d) return !1;
|
||||||
|
let c = 0;
|
||||||
|
for (const a of e)
|
||||||
|
((a.ControlClassification = t),
|
||||||
|
(a.ControlContinuationID = i),
|
||||||
|
(a.ControlContinuationIndex = c++),
|
||||||
|
a === C
|
||||||
|
? (a.ControlOrderedParts = [n])
|
||||||
|
: a === d
|
||||||
|
? (a.ControlOrderedParts = [r])
|
||||||
|
: a === l && (a.ControlOrderedParts = [o]));
|
||||||
|
return !0;
|
||||||
|
}
|
||||||
|
classify(e) {
|
||||||
|
const t = e.FormControls,
|
||||||
|
o = t.length,
|
||||||
|
r = e.AutoFillFormType === WBSAutoFillFormTypeNewAccount,
|
||||||
|
n = e.AutoFillFormType === WBSAutoFillFormTypeChangePassword,
|
||||||
|
i = e.UsernameElementUniqueID,
|
||||||
|
a = e.PasswordElementUniqueID,
|
||||||
|
s = e.OldPasswordElementUniqueID,
|
||||||
|
l = e.ConfirmPasswordElementUniqueID;
|
||||||
|
for (let e of t)
|
||||||
|
(e.AutocompleteTokens || e.AddressBookLabel) &&
|
||||||
|
(e.AddressBookValueSpecifier =
|
||||||
|
FormMetadataJSController.specifierForAutocompleteTokensAndAddressBookLabel(
|
||||||
|
e.AutocompleteTokens,
|
||||||
|
e.AddressBookLabel,
|
||||||
|
));
|
||||||
|
let d = !1,
|
||||||
|
C = !1,
|
||||||
|
c = !1,
|
||||||
|
f = !1,
|
||||||
|
S = !1,
|
||||||
|
k = 0;
|
||||||
|
for (let u = 0, T = 1; u < o; u += T, T = 1) {
|
||||||
|
const o = t[u];
|
||||||
|
if (o.ControlLooksLikeIgnoredDataTypeField) {
|
||||||
|
o.ControlClassification = WBSIgnoredClassificationToken;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const B = o.ControlUniqueID;
|
||||||
|
if (B === a || B === l) {
|
||||||
|
o.ControlClassification =
|
||||||
|
r || n
|
||||||
|
? WBSCredentialNewPasswordClassificationToken
|
||||||
|
: WBSCredentialCurrentPasswordClassificationToken;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (B === s) {
|
||||||
|
o.ControlClassification =
|
||||||
|
WBSCredentialCurrentPasswordClassificationToken;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const h = o.AddressBookValueSpecifier?.classification;
|
||||||
|
if (h === WBSContactEmailClassificationToken) {
|
||||||
|
o.ControlClassification = WBSContactEmailClassificationToken;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (B === i) {
|
||||||
|
o.ControlClassification = WBSCredentialUsernameClassificationToken;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!C && o.ControlLooksLikeCreditCardCardholderField) {
|
||||||
|
if (((C = !0), h && WBSNameOrderedPartTokensSet.has(h))) {
|
||||||
|
const e = this.classifyControlsRelatedToNameParts(
|
||||||
|
t,
|
||||||
|
u,
|
||||||
|
WBSCreditCardHolderNameClassificationToken,
|
||||||
|
);
|
||||||
|
if (e.length > 1) {
|
||||||
|
let t = ++k,
|
||||||
|
o = 0;
|
||||||
|
for (let r of e)
|
||||||
|
((r.ControlContinuationID = t),
|
||||||
|
(r.ControlContinuationIndex = o++));
|
||||||
|
}
|
||||||
|
T = e.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
((o.ControlClassification = WBSCreditCardHolderNameClassificationToken),
|
||||||
|
(o.ControlOrderedParts =
|
||||||
|
WBSCreditCardHolderNameClassificationDefaultOrderedParts));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!d && o.ControlLooksLikeCreditCardNumberField) {
|
||||||
|
d = !0;
|
||||||
|
const e = this.continuingFieldsInFormControls(t, u, !0, !1);
|
||||||
|
let o = 0,
|
||||||
|
r = e.length > 1 ? ++k : 0;
|
||||||
|
for (let t of e)
|
||||||
|
((t.ControlClassification = WBSCreditCardNumberClassificationToken),
|
||||||
|
(t.ControlContinuationID = r),
|
||||||
|
(t.ControlContinuationIndex = o++));
|
||||||
|
T = e.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const P =
|
||||||
|
this.fieldLooksLikeDateField(o) ||
|
||||||
|
o.ControlLooksLikeCreditCardCompositeExpirationDateField;
|
||||||
|
if (!c && P) {
|
||||||
|
let e = f || C || d;
|
||||||
|
if (
|
||||||
|
((e ||=
|
||||||
|
!o.ControlLooksLikeOneTimeCodeField &&
|
||||||
|
1 ===
|
||||||
|
t.filter((e) =>
|
||||||
|
AllowedControlTagsForStandaloneCreditCardCompositeExpirationControl.has(
|
||||||
|
e.ControlTagName.toLowerCase(),
|
||||||
|
),
|
||||||
|
).length),
|
||||||
|
e)
|
||||||
|
) {
|
||||||
|
c = !0;
|
||||||
|
const e = this.continuingFieldsInFormControls(t, u, !1, !0);
|
||||||
|
let o = e.length > 1 ? ++k : 0;
|
||||||
|
(this.classifyDateFields(
|
||||||
|
e,
|
||||||
|
WBSCreditCardExpirationClassificationToken,
|
||||||
|
WBSDateYearOrderedPartToken,
|
||||||
|
WBSDateMonthOrderedPartToken,
|
||||||
|
void 0,
|
||||||
|
o,
|
||||||
|
WBSLocaleForCreditCardExpirationDate,
|
||||||
|
),
|
||||||
|
(T = e.length));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (S || !o.ControlLooksLikeCreditCardSecurityCodeField)
|
||||||
|
if (f || !o.ControlLooksLikeCreditCardTypeField)
|
||||||
|
if (h) {
|
||||||
|
const r = o.AddressBookValueSpecifier.classificationHint;
|
||||||
|
if (h === WBSContactNameClassificationToken) {
|
||||||
|
((o.ControlClassification = h),
|
||||||
|
(o.ControlOrderedParts =
|
||||||
|
WBSContactNameClassificationDefaultOrderedParts));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (WBSNameOrderedPartTokensSet.has(h)) {
|
||||||
|
const e = this.classifyControlsRelatedToNameParts(
|
||||||
|
t,
|
||||||
|
u,
|
||||||
|
WBSContactNameClassificationToken,
|
||||||
|
);
|
||||||
|
if (e.length > 1) {
|
||||||
|
let t = ++k,
|
||||||
|
o = 0;
|
||||||
|
for (let r of e)
|
||||||
|
((r.ControlContinuationID = t),
|
||||||
|
(r.ControlContinuationIndex = o++));
|
||||||
|
}
|
||||||
|
T = e.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (h === WBSContactPostalCodeClassificationToken) {
|
||||||
|
const e = this.continuingFieldsInFormControls(t, u, !0, !1);
|
||||||
|
let o = e.length > 1 ? ++k : 0,
|
||||||
|
r = 0;
|
||||||
|
for (let t of e)
|
||||||
|
((t.ControlClassification =
|
||||||
|
WBSContactPostalCodeClassificationToken),
|
||||||
|
(t.ControlContinuationID = o),
|
||||||
|
(t.ControlContinuationIndex = r++));
|
||||||
|
T = e.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (h === WBSContactStreetAddressClassificationToken) {
|
||||||
|
const e = this.continuingFieldsInFormControls(t, u, !0, !0);
|
||||||
|
let o = e.length > 1 ? ++k : 0,
|
||||||
|
r = 0;
|
||||||
|
for (let t of e)
|
||||||
|
((t.ControlClassification =
|
||||||
|
WBSContactStreetAddressClassificationToken),
|
||||||
|
(t.ControlContinuationID = o),
|
||||||
|
(t.ControlContinuationIndex = r++));
|
||||||
|
if (1 === e.length) {
|
||||||
|
let t = e[0];
|
||||||
|
t.ControlOrderedParts = this.#n(t);
|
||||||
|
} else
|
||||||
|
2 === e.length
|
||||||
|
? ((e[0].ControlOrderedParts = [
|
||||||
|
WBSContactStreetAddressLine1OrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[1].ControlOrderedParts = [
|
||||||
|
WBSContactStreetAddressLine2OrderedPartToken,
|
||||||
|
WBSContactStreetAddressLine3OrderedPartToken,
|
||||||
|
]))
|
||||||
|
: e.length >= 3 &&
|
||||||
|
((e[0].ControlOrderedParts = [
|
||||||
|
WBSContactStreetAddressLine1OrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[1].ControlOrderedParts = [
|
||||||
|
WBSContactStreetAddressLine2OrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[2].ControlOrderedParts = [
|
||||||
|
WBSContactStreetAddressLine3OrderedPartToken,
|
||||||
|
]));
|
||||||
|
T = e.length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (h === WBSContactInstantMessageClassificationToken) {
|
||||||
|
const e = this.continuingFieldsInFormControls(t, u, !0, !0);
|
||||||
|
(1 === e.length &&
|
||||||
|
((e[0].ControlClassification =
|
||||||
|
WBSContactInstantMessageClassificationToken),
|
||||||
|
r && (e[0].ControlClassificationHints = [r])),
|
||||||
|
(T = e.length));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (h.startsWith(WBSContactTelephoneClassificationToken)) {
|
||||||
|
const e = this.continuingFieldsInFormControls(t, u, !0, !1);
|
||||||
|
if (1 == e.length) {
|
||||||
|
((e[0].ControlClassification =
|
||||||
|
WBSContactTelephoneClassificationToken),
|
||||||
|
(e[0].ControlOrderedParts = WBSTelephoneDefaultOrderedParts),
|
||||||
|
r && (e[0].ControlClassificationHints = [r]));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let o = ++k,
|
||||||
|
n = 0;
|
||||||
|
for (let t of e)
|
||||||
|
((t.ControlClassification =
|
||||||
|
WBSContactTelephoneClassificationToken),
|
||||||
|
(t.ControlContinuationID = o),
|
||||||
|
(t.ControlContinuationIndex = n++),
|
||||||
|
r && (t.ControlClassificationHints = [r]));
|
||||||
|
(2 === e.length
|
||||||
|
? ((e[0].ControlOrderedParts = [
|
||||||
|
WBSTelephoneAreaCodeOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[1].ControlOrderedParts = [
|
||||||
|
WBSTelephoneLocalPrefixOrderedPartToken,
|
||||||
|
WBSTelephoneLocalSuffixOrderedPartToken,
|
||||||
|
]))
|
||||||
|
: 3 === e.length
|
||||||
|
? ((e[0].ControlOrderedParts = [
|
||||||
|
WBSTelephoneAreaCodeOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[1].ControlOrderedParts = [
|
||||||
|
WBSTelephoneLocalPrefixOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[2].ControlOrderedParts = [
|
||||||
|
WBSTelephoneLocalSuffixOrderedPartToken,
|
||||||
|
]))
|
||||||
|
: 4 === e.length
|
||||||
|
? ((e[0].ControlOrderedParts = [
|
||||||
|
WBSTelephoneCountryCodeOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[1].ControlOrderedParts = [
|
||||||
|
WBSTelephoneAreaCodeOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[2].ControlOrderedParts = [
|
||||||
|
WBSTelephoneLocalPrefixOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[3].ControlOrderedParts = [
|
||||||
|
WBSTelephoneLocalSuffixOrderedPartToken,
|
||||||
|
]))
|
||||||
|
: ((e[0].ControlOrderedParts = [
|
||||||
|
WBSTelephoneCountryCodeOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[1].ControlOrderedParts = [
|
||||||
|
WBSTelephoneAreaCodeOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[2].ControlOrderedParts = [
|
||||||
|
WBSTelephoneLocalPrefixOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[3].ControlOrderedParts = [
|
||||||
|
WBSTelephoneLocalSuffixOrderedPartToken,
|
||||||
|
]),
|
||||||
|
(e[4].ControlOrderedParts = [
|
||||||
|
WBSTelephoneExtensionOrderedPartToken,
|
||||||
|
])),
|
||||||
|
(T = e.length));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (h === WBSContactBirthdayClassificationToken) {
|
||||||
|
const o = this.continuingFieldsInFormControls(t, u, !1, !1),
|
||||||
|
r = o.length > 1 ? ++k : void 0,
|
||||||
|
n =
|
||||||
|
e.RequestType === WBSFormMetadataRequestTesting
|
||||||
|
? "en_US"
|
||||||
|
: void 0;
|
||||||
|
(this.classifyDateFields(
|
||||||
|
o,
|
||||||
|
WBSContactBirthdayClassificationToken,
|
||||||
|
WBSDateYearOrderedPartToken,
|
||||||
|
WBSDateMonthOrderedPartToken,
|
||||||
|
WBSDateDayOrderedPartToken,
|
||||||
|
r,
|
||||||
|
n,
|
||||||
|
),
|
||||||
|
(T = o.length));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
o.ControlClassification = h;
|
||||||
|
} else
|
||||||
|
o.ControlLooksLikeEIDField
|
||||||
|
? (o.ControlClassification = WBSDeviceEIDClassificationToken)
|
||||||
|
: o.ControlLooksLikeIMEIField &&
|
||||||
|
(o.ControlClassification = WBSDeviceIMEIClassificationToken);
|
||||||
|
else
|
||||||
|
((f = !0),
|
||||||
|
(o.ControlClassification = WBSCreditCardTypeClassificationToken));
|
||||||
|
else
|
||||||
|
((S = !0),
|
||||||
|
(o.ControlClassification =
|
||||||
|
WBSCreditCardSecurityCodeClassificationToken));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
globalThis.FormMetadataClassificationJS = new FormMetadataClassification();
|
||||||
71
js/layout/WebContentLayoutAnalyzer.js
Normal file
71
js/layout/WebContentLayoutAnalyzer.js
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
//# sourceURL=__InjectedScript_WebContentLayoutAnalyzer.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
// Copyright (c) 2013 Apple Inc. All rights reserved.
|
||||||
|
function elementAppearsCentered(e, t) {
|
||||||
|
var n = window.innerWidth - t.right - t.left;
|
||||||
|
return Math.abs(n) <= 1;
|
||||||
|
}
|
||||||
|
function centeredElementIsNotAContainer(e, t) {
|
||||||
|
if (e === document.documentElement || e === document.body) return !0;
|
||||||
|
if (0 === t.left && t.width === window.innerWidth) return !0;
|
||||||
|
if (!t.height) return !0;
|
||||||
|
var n = e.innerText;
|
||||||
|
return !n || !n.trim();
|
||||||
|
}
|
||||||
|
var WebContentLayoutAnalyzer = function () {
|
||||||
|
((this.centeredContainerElement = null),
|
||||||
|
(this.rectOfCenteredContainerElementBeforeResize = null),
|
||||||
|
(this.rectOfCenteredContainerElementAfterResize = null));
|
||||||
|
};
|
||||||
|
WebContentLayoutAnalyzer.prototype = {
|
||||||
|
findCenteredContainerElement: function () {
|
||||||
|
for (
|
||||||
|
var e = null,
|
||||||
|
t = null,
|
||||||
|
n = document.getElementsByTagName("*"),
|
||||||
|
r = n.length,
|
||||||
|
i = 0;
|
||||||
|
i < r;
|
||||||
|
++i
|
||||||
|
) {
|
||||||
|
var o = n[i],
|
||||||
|
l = o.getBoundingClientRect();
|
||||||
|
elementAppearsCentered(o, l) &&
|
||||||
|
(centeredElementIsNotAContainer(o, l) ||
|
||||||
|
((!t || l.width > t.width) && ((e = o), (t = l))));
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
},
|
||||||
|
collectInformationBeforeResize: function () {
|
||||||
|
((this.centeredContainerElement = this.findCenteredContainerElement()),
|
||||||
|
this.centeredContainerElement &&
|
||||||
|
(this.rectOfCenteredContainerElementBeforeResize =
|
||||||
|
this.centeredContainerElement.getBoundingClientRect()));
|
||||||
|
},
|
||||||
|
collectInformationAfterResize: function () {
|
||||||
|
this.centeredContainerElement &&
|
||||||
|
document.contains(this.centeredContainerElement) &&
|
||||||
|
(this.rectOfCenteredContainerElementAfterResize =
|
||||||
|
this.centeredContainerElement.getBoundingClientRect());
|
||||||
|
},
|
||||||
|
layoutInformation: function () {
|
||||||
|
var e = !1,
|
||||||
|
t = null;
|
||||||
|
return (
|
||||||
|
this.rectOfCenteredContainerElementBeforeResize &&
|
||||||
|
this.rectOfCenteredContainerElementAfterResize &&
|
||||||
|
((e =
|
||||||
|
this.rectOfCenteredContainerElementBeforeResize.width ===
|
||||||
|
this.rectOfCenteredContainerElementAfterResize.width),
|
||||||
|
(t =
|
||||||
|
this.rectOfCenteredContainerElementBeforeResize.left -
|
||||||
|
this.rectOfCenteredContainerElementAfterResize.left)),
|
||||||
|
{
|
||||||
|
FoundCenteredContainer: !!this.centeredContainerElement,
|
||||||
|
CenteredContainerIsFixedWidth: e,
|
||||||
|
DistanceContainerMoved: t,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var WebContentLayoutAnalyzerJS = new WebContentLayoutAnalyzer();
|
||||||
104
js/metadata/MetadataExtractor.js
Normal file
104
js/metadata/MetadataExtractor.js
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
//# sourceURL=__InjectedScript_MetadataExtractor.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
function getIconType(e) {
|
||||||
|
var o = e.getAttribute("rel");
|
||||||
|
return "apple-touch-icon" === o
|
||||||
|
? IconTypeAppleTouchIcon
|
||||||
|
: "apple-touch-icon-precomposed" === o
|
||||||
|
? IconTypeAppleTouchIconPrecomposed
|
||||||
|
: IconTypeFavicon;
|
||||||
|
}
|
||||||
|
function compareIconsDescending(e, o) {
|
||||||
|
var c = getIconType(e),
|
||||||
|
t = getIconType(o);
|
||||||
|
if (c === IconTypeFavicon && t !== IconTypeFavicon) return 1;
|
||||||
|
if (t === IconTypeFavicon && c !== IconTypeFavicon) return -1;
|
||||||
|
var n = e.getAttribute("sizes"),
|
||||||
|
r = o.getAttribute("sizes"),
|
||||||
|
p = 0,
|
||||||
|
a = 0;
|
||||||
|
return (
|
||||||
|
n
|
||||||
|
? (p = parseInt(n))
|
||||||
|
: n ||
|
||||||
|
(c !== IconTypeAppleTouchIcon &&
|
||||||
|
c !== IconTypeAppleTouchIconPrecomposed) ||
|
||||||
|
(p = AppleTouchIconDefaultWidth),
|
||||||
|
r
|
||||||
|
? (a = parseInt(r))
|
||||||
|
: r ||
|
||||||
|
(t !== IconTypeAppleTouchIcon &&
|
||||||
|
t !== IconTypeAppleTouchIconPrecomposed) ||
|
||||||
|
(a = AppleTouchIconDefaultWidth),
|
||||||
|
a > p
|
||||||
|
? 1
|
||||||
|
: a < p
|
||||||
|
? -1
|
||||||
|
: c !== IconTypeAppleTouchIconPrecomposed &&
|
||||||
|
t === IconTypeAppleTouchIconPrecomposed
|
||||||
|
? 1
|
||||||
|
: t !== IconTypeAppleTouchIconPrecomposed &&
|
||||||
|
c === IconTypeAppleTouchIconPrecomposed
|
||||||
|
? -1
|
||||||
|
: 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
function colorComponentsFromString(e) {
|
||||||
|
var o = document.createElement("canvas");
|
||||||
|
((o.width = 1), (o.height = 1));
|
||||||
|
var c = o.getContext("2d");
|
||||||
|
((c.fillStyle = e), c.fillRect(0, 0, 1, 1));
|
||||||
|
var t = c.getImageData(0, 0, 1, 1);
|
||||||
|
return [t.data[0], t.data[1], t.data[2]];
|
||||||
|
}
|
||||||
|
var MetadataExtractor = function () {};
|
||||||
|
const IconTypeFavicon = 0,
|
||||||
|
IconTypeAppleTouchIcon = 1,
|
||||||
|
IconTypeAppleTouchIconPrecomposed = 2,
|
||||||
|
AppleTouchIconDefaultWidth = 60;
|
||||||
|
MetadataExtractor.prototype = {
|
||||||
|
extractAndSortIconsWithSelector: function (e) {
|
||||||
|
var o = document.head.querySelectorAll(e);
|
||||||
|
return o.length
|
||||||
|
? Array.prototype.slice.call(o).sort(compareIconsDescending)
|
||||||
|
: [];
|
||||||
|
},
|
||||||
|
extractAppleTouchIconURLs: function () {
|
||||||
|
for (
|
||||||
|
var e = this.extractAndSortIconsWithSelector(
|
||||||
|
"link[rel=apple-touch-icon], link[rel=apple-touch-icon-precomposed]",
|
||||||
|
),
|
||||||
|
o = [],
|
||||||
|
c = 0;
|
||||||
|
c < e.length;
|
||||||
|
++c
|
||||||
|
) {
|
||||||
|
var t = e[c].href;
|
||||||
|
t && o.push(t);
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
},
|
||||||
|
extractFaviconURLs: function () {
|
||||||
|
for (
|
||||||
|
var e = this.extractAndSortIconsWithSelector(
|
||||||
|
"link[rel='shortcut icon'], link[rel=icon]",
|
||||||
|
),
|
||||||
|
o = [],
|
||||||
|
c = e.length,
|
||||||
|
t = 0;
|
||||||
|
t < c;
|
||||||
|
++t
|
||||||
|
)
|
||||||
|
o.push(e[t].href);
|
||||||
|
return o;
|
||||||
|
},
|
||||||
|
extractTemplateIconURLAndColor: function () {
|
||||||
|
var e = document.head.querySelector("link[rel=mask-icon]");
|
||||||
|
if (!e) return null;
|
||||||
|
var o = e.getAttribute("color");
|
||||||
|
return o && e.href
|
||||||
|
? { url: e.href, color: colorComponentsFromString(o) }
|
||||||
|
: null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var MetadataExtractorJS = new MetadataExtractor();
|
||||||
35
js/reader/Reader.js
Normal file
35
js/reader/Reader.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
//# sourceURL=__InjectedScript_Reader.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010 Apple Inc. All rights reserved.
|
||||||
|
*/
|
||||||
|
function setScrollTop(e) {
|
||||||
|
document.documentElement.scrollTop = e;
|
||||||
|
}
|
||||||
|
function readerWillBecomeVisible() {
|
||||||
|
setReaderIsActive(!0);
|
||||||
|
}
|
||||||
|
function readerWillEnterBackground() {
|
||||||
|
setReaderIsActive(!1);
|
||||||
|
}
|
||||||
|
ReaderJS._clickingOutsideOfPaperRectangleDismissesReader = !0;
|
||||||
|
let cachedIframeURLMap = new Map();
|
||||||
|
((ReaderJS._readerWillBecomeVisible = function () {
|
||||||
|
for (let e of document.querySelectorAll("iframe")) {
|
||||||
|
let r = cachedIframeURLMap.get(e);
|
||||||
|
r && ((e.src = r), cachedIframeURLMap.delete(e));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
(ReaderJS._readerWillEnterBackground = function () {
|
||||||
|
for (let e of document.querySelectorAll("iframe")) {
|
||||||
|
e.src && (cachedIframeURLMap.set(e, e.src), e.removeAttribute("src"));
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
(ReaderJS._isJavaScriptEnabled = function () {
|
||||||
|
return !!(ReaderJSController.initialConfiguration() || {})[
|
||||||
|
ReaderConfigurationJavaScriptEnabledKey
|
||||||
|
];
|
||||||
|
}),
|
||||||
|
(ReaderAppearanceJS._tryApplyStaticConfiguration = function () {
|
||||||
|
return (document.body.classList.add("mac"), !1);
|
||||||
|
}));
|
||||||
5076
js/reader/ReaderArticleFinder.js
Normal file
5076
js/reader/ReaderArticleFinder.js
Normal file
File diff suppressed because it is too large
Load Diff
2419
js/reader/ReaderSharedUI.js
Normal file
2419
js/reader/ReaderSharedUI.js
Normal file
File diff suppressed because it is too large
Load Diff
37
js/reader/ReaderSharedUINormalWorld.js
Normal file
37
js/reader/ReaderSharedUINormalWorld.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
//# sourceURL=__InjectedScript_ReaderSharedUINormalWorld.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
function loadTwitterJavaScript() {
|
||||||
|
window.twttr ||
|
||||||
|
(window.twttr = (function (e, t, r) {
|
||||||
|
var i,
|
||||||
|
a,
|
||||||
|
d = e.getElementsByTagName(t)[0];
|
||||||
|
if (!e.getElementById(r))
|
||||||
|
return (
|
||||||
|
((a = e.createElement(t)).id = r),
|
||||||
|
(a.src = "https://platform.twitter.com/widgets.js"),
|
||||||
|
d.parentNode.insertBefore(a, d),
|
||||||
|
window.twttr ||
|
||||||
|
(i = {
|
||||||
|
_e: [],
|
||||||
|
ready: function (e) {
|
||||||
|
i._e.push(e);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})(document, "script", "twitter-wjs"));
|
||||||
|
}
|
||||||
|
function richTweetWasCreatedFromSimpleTweet(e) {
|
||||||
|
e.parentNode.querySelector(".simple-tweet").classList.add("hidden");
|
||||||
|
}
|
||||||
|
function replaceSimpleTweetsWithRichTweets(e) {
|
||||||
|
let t = document.querySelectorAll("[data-reader-tweet-id]");
|
||||||
|
t.length &&
|
||||||
|
(loadTwitterJavaScript(),
|
||||||
|
twttr.ready(function (r) {
|
||||||
|
for (let i of t)
|
||||||
|
r.widgets
|
||||||
|
.createTweet(i.getAttribute("data-reader-tweet-id"), i, e)
|
||||||
|
.then(richTweetWasCreatedFromSimpleTweet);
|
||||||
|
}));
|
||||||
|
}
|
||||||
249
js/schema/SchemaDataExtractor.js
Normal file
249
js/schema/SchemaDataExtractor.js
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
//# sourceURL=__InjectedScript_SchemaDataExtractor.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
var SchemaDataExtractor = function () {};
|
||||||
|
((SchemaDataExtractor.validAddressProperties = {
|
||||||
|
addressCountry: 1,
|
||||||
|
addressLocality: 1,
|
||||||
|
addressRegion: 1,
|
||||||
|
postOfficeBoxNumber: 1,
|
||||||
|
postalCode: 1,
|
||||||
|
streetAddress: 1,
|
||||||
|
}),
|
||||||
|
(SchemaDataExtractor.validParentSchemaTypes = {
|
||||||
|
"http://schema.org/Person": 1,
|
||||||
|
"https://schema.org/Person": 1,
|
||||||
|
"http://schema.org/LocalBusiness": 1,
|
||||||
|
"https://schema.org/LocalBusiness": 1,
|
||||||
|
"http://schema.org/Organization": 1,
|
||||||
|
"https://schema.org/Organization": 1,
|
||||||
|
"http://schema.org/Restaurant": 1,
|
||||||
|
"https://schema.org/Restaurant": 1,
|
||||||
|
"http://schema.org/Corporation": 1,
|
||||||
|
"https://schema.org/Corporation": 1,
|
||||||
|
"http://schema.org/EducationalOrganization": 1,
|
||||||
|
"https://schema.org/EducationalOrganization": 1,
|
||||||
|
"http://schema.org/GovernmentOrganization": 1,
|
||||||
|
"https://schema.org/GovernmentOrganization": 1,
|
||||||
|
"http://schema.org/MedicalOrganization": 1,
|
||||||
|
"https://schema.org/MedicalOrganization": 1,
|
||||||
|
"http://schema.org/AnimalShelter": 1,
|
||||||
|
"https://schema.org/AnimalShelter": 1,
|
||||||
|
"http://schema.org/AutomotiveBusiness": 1,
|
||||||
|
"https://schema.org/AutomotiveBusiness": 1,
|
||||||
|
"http://schema.org/ChildCare": 1,
|
||||||
|
"https://schema.org/ChildCare": 1,
|
||||||
|
"http://schema.org/DryCleaningOrLaundry": 1,
|
||||||
|
"https://schema.org/DryCleaningOrLaundry": 1,
|
||||||
|
"http://schema.org/EmergencyService": 1,
|
||||||
|
"https://schema.org/EmergencyService": 1,
|
||||||
|
"http://schema.org/EmploymentAgency": 1,
|
||||||
|
"https://schema.org/EmploymentAgency": 1,
|
||||||
|
"http://schema.org/EntertainmentBusiness": 1,
|
||||||
|
"https://schema.org/EntertainmentBusiness": 1,
|
||||||
|
"http://schema.org/FinancialService": 1,
|
||||||
|
"https://schema.org/FinancialService": 1,
|
||||||
|
"http://schema.org/FoodEstablishment": 1,
|
||||||
|
"https://schema.org/FoodEstablishment": 1,
|
||||||
|
"http://schema.org/GovernmentOffice": 1,
|
||||||
|
"https://schema.org/GovernmentOffice": 1,
|
||||||
|
"http://schema.org/HealthAndBeautyBusiness": 1,
|
||||||
|
"https://schema.org/HealthAndBeautyBusiness": 1,
|
||||||
|
"http://schema.org/HomeAndConstructionBusiness": 1,
|
||||||
|
"https://schema.org/HomeAndConstructionBusiness": 1,
|
||||||
|
"http://schema.org/InternetCafe": 1,
|
||||||
|
"https://schema.org/InternetCafe": 1,
|
||||||
|
"http://schema.org/LegalService": 1,
|
||||||
|
"https://schema.org/LegalService": 1,
|
||||||
|
"http://schema.org/Library": 1,
|
||||||
|
"https://schema.org/Library": 1,
|
||||||
|
"http://schema.org/LodgingBusiness": 1,
|
||||||
|
"https://schema.org/LodgingBusiness": 1,
|
||||||
|
"http://schema.org/ProfessionalService": 1,
|
||||||
|
"https://schema.org/ProfessionalService": 1,
|
||||||
|
"http://schema.org/RadioStation": 1,
|
||||||
|
"https://schema.org/RadioStation": 1,
|
||||||
|
"http://schema.org/RealEstateAgent": 1,
|
||||||
|
"https://schema.org/RealEstateAgent": 1,
|
||||||
|
"http://schema.org/RecyclingCenter": 1,
|
||||||
|
"https://schema.org/RecyclingCenter": 1,
|
||||||
|
"http://schema.org/SelfStorage": 1,
|
||||||
|
"https://schema.org/SelfStorage": 1,
|
||||||
|
"http://schema.org/ShoppingCenter": 1,
|
||||||
|
"https://schema.org/ShoppingCenter": 1,
|
||||||
|
"http://schema.org/SportsActivityLocation": 1,
|
||||||
|
"https://schema.org/SportsActivityLocation": 1,
|
||||||
|
"http://schema.org/Store": 1,
|
||||||
|
"https://schema.org/Store": 1,
|
||||||
|
"http://schema.org/TelevisionStation": 1,
|
||||||
|
"https://schema.org/TelevisionStation": 1,
|
||||||
|
"http://schema.org/TouristInformationCenter": 1,
|
||||||
|
"https://schema.org/TouristInformationCenter": 1,
|
||||||
|
"http://schema.org/TravelAgency": 1,
|
||||||
|
"https://schema.org/TravelAgency": 1,
|
||||||
|
}),
|
||||||
|
(SchemaDataExtractor.validBaseSchemaTypes = {
|
||||||
|
"http://schema.org/PostalAddress": 1,
|
||||||
|
"https://schema.org/PostalAddress": 1,
|
||||||
|
}),
|
||||||
|
(SchemaDataExtractor.containsSchemaOrgKey = "containsSchemaOrg"),
|
||||||
|
(SchemaDataExtractor.containsMicrodataKey = "containsMicrodata"),
|
||||||
|
(SchemaDataExtractor.schemaOrgTypeDomain = "schema.org"),
|
||||||
|
(SchemaDataExtractor.prototype = {
|
||||||
|
isValidParentSchemaType: function (t) {
|
||||||
|
return SchemaDataExtractor.validParentSchemaTypes[t];
|
||||||
|
},
|
||||||
|
isValidBaseSchemaType: function (t) {
|
||||||
|
return SchemaDataExtractor.validBaseSchemaTypes[t];
|
||||||
|
},
|
||||||
|
extractFilteredSchemaValuesFromMicroData: function () {
|
||||||
|
const t = document.querySelectorAll("[itemscope]");
|
||||||
|
let e = [],
|
||||||
|
r = [],
|
||||||
|
a = !1;
|
||||||
|
for (let o of t) {
|
||||||
|
let t = o.getAttribute("itemType");
|
||||||
|
t &&
|
||||||
|
(this.isValidParentSchemaType(t) && e.push(o),
|
||||||
|
this.isValidBaseSchemaType(t) && r.push(o),
|
||||||
|
!a &&
|
||||||
|
t.includes(SchemaDataExtractor.schemaOrgTypeDomain) &&
|
||||||
|
(a = !0));
|
||||||
|
}
|
||||||
|
let o = {};
|
||||||
|
if (!a) return o;
|
||||||
|
if (((o[SchemaDataExtractor.containsSchemaOrgKey] = !0), 1 !== r.length))
|
||||||
|
return o;
|
||||||
|
const s = r[0],
|
||||||
|
c = s.getAttribute("itemtype");
|
||||||
|
if (!c || -1 === c.indexOf("PostalAddress")) return o;
|
||||||
|
const n = s.querySelectorAll("[itemprop]");
|
||||||
|
for (let t of n) {
|
||||||
|
let e = t.getAttribute("itemprop");
|
||||||
|
e &&
|
||||||
|
SchemaDataExtractor.validAddressProperties[e] &&
|
||||||
|
(o[e] = t.textContent ? t.textContent : t.getAttribute("content"));
|
||||||
|
}
|
||||||
|
let h = s.parentNode;
|
||||||
|
for (; null !== h && -1 === e.indexOf(h); ) h = h.parentNode;
|
||||||
|
const i = s.querySelectorAll("[itemprop='telephone']");
|
||||||
|
if (null !== h) {
|
||||||
|
let t = h.querySelectorAll("[itemprop='name']");
|
||||||
|
(t.length && (o.name = t[0].textContent),
|
||||||
|
0 === i.length && (i = h.querySelectorAll("[itemprop='telephone']")));
|
||||||
|
}
|
||||||
|
return (i.length && (o.telephone = i[0].textContent), o);
|
||||||
|
},
|
||||||
|
extractAllSchemaValuesFromMicroData: function () {
|
||||||
|
const t = document.querySelectorAll("[itemscope]");
|
||||||
|
let e = [],
|
||||||
|
r = !1;
|
||||||
|
for (let a of t) {
|
||||||
|
const t = a.getAttribute("itemType");
|
||||||
|
t &&
|
||||||
|
(e.push(a),
|
||||||
|
!r &&
|
||||||
|
t.includes(SchemaDataExtractor.schemaOrgTypeDomain) &&
|
||||||
|
(r = !0));
|
||||||
|
}
|
||||||
|
let a = {};
|
||||||
|
if (!r) return a;
|
||||||
|
if (((a[SchemaDataExtractor.containsSchemaOrgKey] = !0), 1 !== e.length))
|
||||||
|
return a;
|
||||||
|
const o = e[0],
|
||||||
|
s = (o.getAttribute("itemtype"), o.querySelectorAll("[itemprop]"));
|
||||||
|
for (let t of s) {
|
||||||
|
let e = t.getAttribute("itemprop");
|
||||||
|
e && (a[e] = t.textContent ? t.textContent : t.getAttribute("content"));
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
},
|
||||||
|
extractFilteredSchemaValuesFromJSONLD: function () {
|
||||||
|
let t = {};
|
||||||
|
const e = document.querySelector('script[type="application/ld+json"]');
|
||||||
|
if (!e) return t;
|
||||||
|
let r;
|
||||||
|
try {
|
||||||
|
r = JSON.parse(e.text);
|
||||||
|
} catch (e) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
let a = r["@context"];
|
||||||
|
if ("http://schema.org" !== a && "https://schema.org" !== a) return t;
|
||||||
|
t[SchemaDataExtractor.containsSchemaOrgKey] = !0;
|
||||||
|
let o = [];
|
||||||
|
for (o.unshift(r); o.length; ) {
|
||||||
|
let e = o.shift();
|
||||||
|
if (null != e) {
|
||||||
|
if (
|
||||||
|
(Object.prototype.hasOwnProperty.call(e, "telephone") &&
|
||||||
|
(t.telephone = e.telephone),
|
||||||
|
"PostalAddress" === e["@type"])
|
||||||
|
) {
|
||||||
|
for (let r in e)
|
||||||
|
SchemaDataExtractor.validAddressProperties[r] && (t[r] = e[r]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (let t in e) {
|
||||||
|
let r = e[t];
|
||||||
|
"object" == typeof r && o.push(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
extractAllSchemaValuesFromJSONLD: function () {
|
||||||
|
let t = {};
|
||||||
|
const e = document.querySelector('script[type="application/ld+json"]');
|
||||||
|
if (!e) return t;
|
||||||
|
let r, a;
|
||||||
|
try {
|
||||||
|
r = JSON.parse(e.text);
|
||||||
|
} catch (e) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
((a = Array.isArray(r) ? r[0]["@context"] : r["@context"]),
|
||||||
|
"http://schema.org" !== a && "https://schema.org" !== a)
|
||||||
|
)
|
||||||
|
return t;
|
||||||
|
t[SchemaDataExtractor.containsSchemaOrgKey] = !0;
|
||||||
|
let o = [];
|
||||||
|
o.unshift(r);
|
||||||
|
const s = o.shift();
|
||||||
|
for (let e in s) t[e] = s[e];
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
resultHasAddressOrTelephone: function (t) {
|
||||||
|
return (
|
||||||
|
null != t &&
|
||||||
|
(Object.prototype.hasOwnProperty.call(t, "streetAddress") ||
|
||||||
|
Object.prototype.hasOwnProperty.call(t, "telephone"))
|
||||||
|
);
|
||||||
|
},
|
||||||
|
resultHasSchemaOrgInfo: function (t) {
|
||||||
|
return (
|
||||||
|
null != t &&
|
||||||
|
Object.prototype.hasOwnProperty.call(
|
||||||
|
t,
|
||||||
|
SchemaDataExtractor.containsSchemaOrgKey,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
extractSchemaValuesFromSchemaOrg: function () {
|
||||||
|
let t = this.extractAllSchemaValuesFromMicroData(),
|
||||||
|
e = this.extractFilteredSchemaValuesFromMicroData();
|
||||||
|
return (
|
||||||
|
this.resultHasAddressOrTelephone(e) ||
|
||||||
|
(e = this.extractFilteredSchemaValuesFromJSONLD()),
|
||||||
|
this.resultHasAddressOrTelephone(t) ||
|
||||||
|
(t = this.extractAllSchemaValuesFromJSONLD()),
|
||||||
|
(this.resultHasAddressOrTelephone(e) ||
|
||||||
|
this.resultHasSchemaOrgInfo(e)) &&
|
||||||
|
(e.url = location.href),
|
||||||
|
[e, t]
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
"undefined" == typeof SchemaDataExtractorJS &&
|
||||||
|
(SchemaDataExtractorJS = new SchemaDataExtractor()),
|
||||||
|
SchemaDataExtractorJS.extractSchemaValuesFromSchemaOrg());
|
||||||
20
js/schema/SchemaOrgMarkupChecker.js
Normal file
20
js/schema/SchemaOrgMarkupChecker.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//# sourceURL=__InjectedScript_SchemaOrgMarkupChecker.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
(function () {
|
||||||
|
const e = "schema.org";
|
||||||
|
var t = document.querySelectorAll('script[type="application/ld+json"]');
|
||||||
|
for (let o of t) {
|
||||||
|
var r;
|
||||||
|
try {
|
||||||
|
r = JSON.parse(o.text);
|
||||||
|
} catch (e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (r["@context"].toLowerCase().includes(e)) return !0;
|
||||||
|
}
|
||||||
|
var o = document.querySelectorAll("[itemscope]");
|
||||||
|
for (let t of o) {
|
||||||
|
var c = t.getAttribute("itemType");
|
||||||
|
if (c && c.toLowerCase().includes(e)) return !0;
|
||||||
|
}
|
||||||
|
})();
|
||||||
22
js/search/OpenSearchURLFinder.js
Normal file
22
js/search/OpenSearchURLFinder.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
//# sourceURL=__InjectedScript_OpenSearchURLFinder.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
var OpenSearchURLFinder = function () {};
|
||||||
|
OpenSearchURLFinder.prototype = {
|
||||||
|
firstOpenSearchURLString: function () {
|
||||||
|
if (!document.head) return null;
|
||||||
|
for (
|
||||||
|
var e = document.head.getElementsByTagName("link"), r = e.length, n = 0;
|
||||||
|
n < r;
|
||||||
|
++n
|
||||||
|
) {
|
||||||
|
var t = e[n];
|
||||||
|
if (
|
||||||
|
"search" === t.getAttribute("rel") &&
|
||||||
|
"application/opensearchdescription+xml" === t.getAttribute("type")
|
||||||
|
)
|
||||||
|
return t.href;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var OpenSearchURLFinderJS = new OpenSearchURLFinder();
|
||||||
3
js/translation/Translation.js
Normal file
3
js/translation/Translation.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
//# sourceURL=__InjectedScript_Translation.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
function updateLanguageAttributesForTranslation(n){document.documentElement.lang&&(document.documentElement.lang=n)}
|
||||||
749
js/utilities/NodePath.js
Normal file
749
js/utilities/NodePath.js
Normal file
@@ -0,0 +1,749 @@
|
|||||||
|
//# sourceURL=__InjectedScript_NodePath.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
// Copyright (C) 2023-2024 Apple Inc. All rights reserved.
|
||||||
|
"use strict";
|
||||||
|
(globalThis.WAS || (globalThis.WAS = {}),
|
||||||
|
(WAS.NodePath = class {
|
||||||
|
static {
|
||||||
|
function e(e, t) {
|
||||||
|
if (e === t) return 0;
|
||||||
|
for (
|
||||||
|
var n = e.length, o = t.length, a = new Array(n + 1), i = 0;
|
||||||
|
i < n + 1;
|
||||||
|
++i
|
||||||
|
)
|
||||||
|
((a[i] = new Array(o + 1)), (a[i][0] = i));
|
||||||
|
for (var s = 0; s < o + 1; ++s) a[0][s] = s;
|
||||||
|
for (s = 1; s < o + 1; ++s) {
|
||||||
|
let o = t[s - 1];
|
||||||
|
for (i = 1; i < n + 1; ++i)
|
||||||
|
if (e[i - 1] === o) a[i][s] = a[i - 1][s - 1];
|
||||||
|
else {
|
||||||
|
var d = a[i - 1][s] + 1,
|
||||||
|
r = a[i][s - 1] + 1,
|
||||||
|
h = a[i - 1][s - 1] + 1;
|
||||||
|
a[i][s] = Math.min(d, r, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a[n][o];
|
||||||
|
}
|
||||||
|
((WAS.Assert =
|
||||||
|
WAS.Assert ||
|
||||||
|
class {
|
||||||
|
static isTrue(e, t, ...n) {}
|
||||||
|
static isType(e, ...t) {}
|
||||||
|
static optionalIsType(e, ...t) {}
|
||||||
|
static arrayContentIsType(e, ...t) {}
|
||||||
|
static optionalArrayContentIsType(e, ...t) {}
|
||||||
|
static isEnum(e, t) {}
|
||||||
|
static optionalIsEnum(e, t) {}
|
||||||
|
static isSubclass(e, t) {}
|
||||||
|
static notReached(e, ...t) {}
|
||||||
|
}),
|
||||||
|
Object.defineProperties(CharacterData, {
|
||||||
|
nodePath_isCharacterData: {
|
||||||
|
value(e) {
|
||||||
|
switch (Node.nodePath_nodeType(e)) {
|
||||||
|
case Node.TEXT_NODE:
|
||||||
|
case Node.CDATA_SECTION_NODE:
|
||||||
|
case Node.PROCESSING_INSTRUCTION_NODE:
|
||||||
|
case Node.COMMENT_NODE:
|
||||||
|
return !0;
|
||||||
|
default:
|
||||||
|
return !1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodePath_data: {
|
||||||
|
value: (e) =>
|
||||||
|
CharacterData.nodePath_isCharacterData(e)
|
||||||
|
? Object.nodePath_get(e, CharacterData, "data")
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(Document, {
|
||||||
|
nodePath_isDocument: {
|
||||||
|
value: (e) => Node.nodePath_nodeType(e) === Node.DOCUMENT_NODE,
|
||||||
|
},
|
||||||
|
nodePath_defaultView: {
|
||||||
|
value: (e) =>
|
||||||
|
Document.nodePath_isDocument(e)
|
||||||
|
? Object.nodePath_get(e, Document, "defaultView")
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(Element, {
|
||||||
|
nodePath_isElement: {
|
||||||
|
value: (e) => Node.nodePath_nodeType(e) === Node.ELEMENT_NODE,
|
||||||
|
},
|
||||||
|
nodePath_tagName: {
|
||||||
|
value: (e) =>
|
||||||
|
Element.nodePath_isElement(e)
|
||||||
|
? Object.nodePath_get(e, Element, "tagName")
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
nodePath_id: {
|
||||||
|
value: (e) =>
|
||||||
|
Element.nodePath_isElement(e)
|
||||||
|
? Object.nodePath_get(e, Element, "id")
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
nodePath_className: {
|
||||||
|
value: (e) =>
|
||||||
|
Element.nodePath_isElement(e)
|
||||||
|
? Object.nodePath_get(e, Element, "className")
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
nodePath_shadowRoot: {
|
||||||
|
value: (e) =>
|
||||||
|
Element.nodePath_isElement(e)
|
||||||
|
? Object.nodePath_get(e, Element, "shadowRoot")
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
nodePath_querySelectorAll: {
|
||||||
|
value: (e, t) =>
|
||||||
|
Element.nodePath_isElement(e)
|
||||||
|
? Element.prototype.querySelectorAll.call(e, t)
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(HTMLIFrameElement, {
|
||||||
|
nodePath_isHTMLIFrameElement: {
|
||||||
|
value: (e) =>
|
||||||
|
Node.nodePath_nodeType(e) === Node.ELEMENT_NODE &&
|
||||||
|
"HTMLIFrameElement" === Object.getPrototypeOf(e).constructor.name,
|
||||||
|
},
|
||||||
|
nodePath_contentWindowDocument: {
|
||||||
|
value(e) {
|
||||||
|
if (!HTMLIFrameElement.nodePath_isHTMLIFrameElement(e))
|
||||||
|
return null;
|
||||||
|
try {
|
||||||
|
return Object.nodePath_get(
|
||||||
|
e,
|
||||||
|
HTMLIFrameElement,
|
||||||
|
"contentWindow",
|
||||||
|
).document;
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(Node, {
|
||||||
|
nodePath_nodeType: {
|
||||||
|
value: (e) => (
|
||||||
|
WAS.Assert.isType(e, Node),
|
||||||
|
Object.nodePath_get(e, Node, "nodeType")
|
||||||
|
),
|
||||||
|
},
|
||||||
|
nodePath_firstChild: {
|
||||||
|
value: (e) => (
|
||||||
|
WAS.Assert.isType(e, Node),
|
||||||
|
Object.nodePath_get(e, Node, "firstChild")
|
||||||
|
),
|
||||||
|
},
|
||||||
|
nodePath_nextSibling: {
|
||||||
|
value: (e) => (
|
||||||
|
WAS.Assert.isType(e, Node),
|
||||||
|
Object.nodePath_get(e, Node, "nextSibling")
|
||||||
|
),
|
||||||
|
},
|
||||||
|
nodePath_previousSibling: {
|
||||||
|
value: (e) => (
|
||||||
|
WAS.Assert.isType(e, Node),
|
||||||
|
Object.nodePath_get(e, Node, "previousSibling")
|
||||||
|
),
|
||||||
|
},
|
||||||
|
nodePath_childNodes: {
|
||||||
|
value: (e) => (
|
||||||
|
WAS.Assert.isType(e, Node),
|
||||||
|
Object.nodePath_get(e, Node, "childNodes")
|
||||||
|
),
|
||||||
|
},
|
||||||
|
nodePath_textContent: {
|
||||||
|
value: (e) => (
|
||||||
|
WAS.Assert.isType(e, Node),
|
||||||
|
Object.nodePath_get(e, Node, "textContent")
|
||||||
|
),
|
||||||
|
},
|
||||||
|
nodePath_cloneNode: {
|
||||||
|
value: (e, { shouldIncludeSubtree: t }) => (
|
||||||
|
WAS.Assert.isType(e, Node),
|
||||||
|
Node.prototype.cloneNode.call(e, t)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
nodePath_isEmptyTextNode: {
|
||||||
|
value: (e) =>
|
||||||
|
Text.nodePath_isText(e) &&
|
||||||
|
CharacterData.nodePath_data(e)
|
||||||
|
.nodePath_isEmptyExcludingWhitespace,
|
||||||
|
},
|
||||||
|
nodePath_siblingIndexOfNode: {
|
||||||
|
value(e) {
|
||||||
|
let t = 0;
|
||||||
|
for (
|
||||||
|
let n = Node.nodePath_previousSibling(e);
|
||||||
|
n;
|
||||||
|
n = Node.nodePath_previousSibling(n)
|
||||||
|
)
|
||||||
|
Node.nodePath_includeWhenComputingSiblingIndex(n) && ++t;
|
||||||
|
return t;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodePath_includeWhenComputingSiblingIndex: {
|
||||||
|
value: (e) =>
|
||||||
|
!(
|
||||||
|
Node.nodePath_isEmptyTextNode(e) ||
|
||||||
|
(Element.nodePath_isElement(e) &&
|
||||||
|
"SCRIPT" === Element.nodePath_tagName(e).toUpperCase())
|
||||||
|
),
|
||||||
|
},
|
||||||
|
nodePath_immediateSourceMarkupOfNode: {
|
||||||
|
value: (e) =>
|
||||||
|
Node.nodePath_nodeType(e) === Node.DOCUMENT_FRAGMENT_NODE
|
||||||
|
? null
|
||||||
|
: Node.nodePath_cloneNode(e, { shouldIncludeSubtree: !1 })
|
||||||
|
.outerHTML,
|
||||||
|
},
|
||||||
|
nodePath_immediateInnerTextOfNode: {
|
||||||
|
value(e) {
|
||||||
|
if (!Node.prototype.hasChildNodes.call(e))
|
||||||
|
return Node.nodePath_textContent(e)?.trim();
|
||||||
|
let t = "";
|
||||||
|
for (let n of Node.nodePath_childNodes(e))
|
||||||
|
Text.nodePath_isText(n) &&
|
||||||
|
(t += CharacterData.nodePath_data(n));
|
||||||
|
return t.trim();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodePath_getBoundingClientRect: {
|
||||||
|
value(e) {
|
||||||
|
if ((WAS.Assert.isType(e, Node, Range), e instanceof Range))
|
||||||
|
return e.getBoundingClientRect();
|
||||||
|
if (Text.nodePath_isText(e)) {
|
||||||
|
let t = new Range();
|
||||||
|
return (
|
||||||
|
t.setStart(e, 0),
|
||||||
|
t.setEnd(e, CharacterData.nodePath_data(e).length),
|
||||||
|
t.getBoundingClientRect()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Element.nodePath_isElement(e)
|
||||||
|
? Element.prototype.getBoundingClientRect.call(e)
|
||||||
|
: null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(Object, {
|
||||||
|
nodePath_get: {
|
||||||
|
value: (e, t, n) =>
|
||||||
|
Object.getOwnPropertyDescriptor(t.prototype, n)?.get?.call?.(e),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(Range, {
|
||||||
|
nodePath_fromNode: {
|
||||||
|
value(e) {
|
||||||
|
let t = new Range();
|
||||||
|
return (t.selectNode(e), t);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodePath_isSingleElementRange: {
|
||||||
|
value: (e) =>
|
||||||
|
e.startContainer === e.endContainer &&
|
||||||
|
!Text.nodePath_isText(e.commonAncestorContainer) &&
|
||||||
|
1 === Math.abs(e.endOffset - e.startOffset),
|
||||||
|
},
|
||||||
|
nodePath_singleElementFromRange: {
|
||||||
|
value: (e) =>
|
||||||
|
Range.nodePath_isSingleElementRange(e)
|
||||||
|
? Node.nodePath_childNodes(e.commonAncestorContainer)[
|
||||||
|
e.startOffset
|
||||||
|
]
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
nodePath_startNodeFromRange: {
|
||||||
|
value: (e) =>
|
||||||
|
Text.nodePath_isText(e.startContainer)
|
||||||
|
? null
|
||||||
|
: Node.nodePath_childNodes(e.startContainer)[e.startOffset],
|
||||||
|
},
|
||||||
|
nodePath_endNodeFromRange: {
|
||||||
|
value: (e) =>
|
||||||
|
Text.nodePath_isText(e.endContainer)
|
||||||
|
? Node.nodePath_childNodes(e.endContainer)[e.endOffset - 1]
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(Range.prototype, {
|
||||||
|
nodePath_equals: {
|
||||||
|
value(e) {
|
||||||
|
return (
|
||||||
|
this.commonAncestorContainer === e.commonAncestorContainer &&
|
||||||
|
0 === this.compareBoundaryPoints(Range.START_TO_START, e) &&
|
||||||
|
0 === this.compareBoundaryPoints(Range.END_TO_END, e)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(ShadowRoot, {
|
||||||
|
nodePath_isShadowRoot: {
|
||||||
|
value: (e) =>
|
||||||
|
Node.nodePath_nodeType(e) === Node.DOCUMENT_FRAGMENT_NODE &&
|
||||||
|
"ShadowRoot" === Object.getPrototypeOf(e).constructor.name,
|
||||||
|
},
|
||||||
|
nodePath_host: {
|
||||||
|
value: (e) =>
|
||||||
|
ShadowRoot.nodePath_isShadowRoot(e)
|
||||||
|
? Object.nodePath_get(e, ShadowRoot, "host")
|
||||||
|
: null,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(String, {
|
||||||
|
_nodePath_matchAnyNonWhitespaceRegex: { value: /\S/ },
|
||||||
|
}),
|
||||||
|
Object.defineProperties(String.prototype, {
|
||||||
|
nodePath_isEmptyExcludingWhitespace: {
|
||||||
|
get() {
|
||||||
|
return (
|
||||||
|
!this.length ||
|
||||||
|
!String._nodePath_matchAnyNonWhitespaceRegex.test(this)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
nodePath_similarityTo: {
|
||||||
|
value(t) {
|
||||||
|
if (!t) return this.length ? 0 : 1;
|
||||||
|
let n = Math.max(this.length, t.length);
|
||||||
|
return n ? (n - e(this, t)) / n : 0;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
Object.defineProperties(Text, {
|
||||||
|
nodePath_isText: {
|
||||||
|
value: (e) => Node.nodePath_nodeType(e) === Node.TEXT_NODE,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
static ObjectRepresentationCodableInfo = { classPath: "WAS.NodePath" };
|
||||||
|
static #e = class {
|
||||||
|
#t;
|
||||||
|
#n;
|
||||||
|
#o;
|
||||||
|
#a;
|
||||||
|
#i;
|
||||||
|
#s;
|
||||||
|
#d;
|
||||||
|
#r;
|
||||||
|
constructor(
|
||||||
|
e,
|
||||||
|
t,
|
||||||
|
{
|
||||||
|
tag: n,
|
||||||
|
id: o,
|
||||||
|
classes: a,
|
||||||
|
text: i,
|
||||||
|
sourceMarkup: s,
|
||||||
|
boundingClientRect: d,
|
||||||
|
} = {},
|
||||||
|
) {
|
||||||
|
(WAS.Assert.isType(e, Number),
|
||||||
|
WAS.Assert.isType(t, Number),
|
||||||
|
WAS.Assert.optionalIsType(n, String),
|
||||||
|
WAS.Assert.optionalIsType(o, String),
|
||||||
|
WAS.Assert.optionalIsType(a, String),
|
||||||
|
WAS.Assert.optionalIsType(i, String),
|
||||||
|
WAS.Assert.optionalIsType(s, String),
|
||||||
|
WAS.Assert.optionalIsType(d, Object),
|
||||||
|
(this.#t = e),
|
||||||
|
(this.#n = t),
|
||||||
|
(this.#d = s),
|
||||||
|
(this.#r = d),
|
||||||
|
e === Node.ELEMENT_NODE
|
||||||
|
? (WAS.Assert.isTrue(n, "Tag must be present for ELEMENT_NODEs"),
|
||||||
|
(this.#o = n),
|
||||||
|
(this.#a = o?.length ? o : void 0),
|
||||||
|
(this.#i = a?.length ? a : void 0),
|
||||||
|
(this.#s = i))
|
||||||
|
: e === Node.TEXT_NODE && (this.#s = i));
|
||||||
|
}
|
||||||
|
static fromNode(e) {
|
||||||
|
WAS.Assert.isType(e, Node);
|
||||||
|
let t = Node.nodePath_nodeType(e),
|
||||||
|
n = Node.nodePath_siblingIndexOfNode(e),
|
||||||
|
o = {};
|
||||||
|
if (Element.nodePath_isElement(e)) {
|
||||||
|
((o.tag = Element.nodePath_tagName(e)),
|
||||||
|
(o.id = Element.nodePath_id(e)),
|
||||||
|
(o.classes = Element.nodePath_className(e)));
|
||||||
|
let t = Node.nodePath_immediateInnerTextOfNode(e);
|
||||||
|
t.length && (o.text = t);
|
||||||
|
} else
|
||||||
|
Text.nodePath_isText(e) && (o.text = CharacterData.nodePath_data(e));
|
||||||
|
o.sourceMarkup = Node.nodePath_immediateSourceMarkupOfNode(e);
|
||||||
|
let a = Node.nodePath_getBoundingClientRect(e);
|
||||||
|
return (
|
||||||
|
a &&
|
||||||
|
(o.boundingClientRect = {
|
||||||
|
x: a.x,
|
||||||
|
y: a.y,
|
||||||
|
width: a.width,
|
||||||
|
height: a.height,
|
||||||
|
}),
|
||||||
|
new WAS.NodePath.#e(t, n, o)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
static fromObjectRepresentation(e) {
|
||||||
|
return (
|
||||||
|
WAS.Assert.isType(e, Object),
|
||||||
|
new WAS.NodePath.#e(e.type, e.index, e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
get objectRepresentation() {
|
||||||
|
return {
|
||||||
|
type: this.#t,
|
||||||
|
index: this.#n,
|
||||||
|
tag: this.#o,
|
||||||
|
id: this.#a,
|
||||||
|
classes: this.#i,
|
||||||
|
text: this.#s,
|
||||||
|
sourceMarkup: this.#d,
|
||||||
|
boundingClientRect: this.#r,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
get type() {
|
||||||
|
return this.#t;
|
||||||
|
}
|
||||||
|
get index() {
|
||||||
|
return this.#n;
|
||||||
|
}
|
||||||
|
get tag() {
|
||||||
|
return this.#o;
|
||||||
|
}
|
||||||
|
get id() {
|
||||||
|
return this.#a;
|
||||||
|
}
|
||||||
|
get classes() {
|
||||||
|
return this.#i;
|
||||||
|
}
|
||||||
|
get text() {
|
||||||
|
return this.#s;
|
||||||
|
}
|
||||||
|
toElementCSSSelector() {
|
||||||
|
if (this.type !== Node.ELEMENT_NODE) return null;
|
||||||
|
let e = CSS.escape(this.tag);
|
||||||
|
this.id && (e += `#${CSS.escape(this.id)}`);
|
||||||
|
for (let t of this.classes?.split(" ") ?? [])
|
||||||
|
t.length && (e += `.${CSS.escape(t)}`);
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
toString() {
|
||||||
|
return JSON.stringify(this.objectRepresentation);
|
||||||
|
}
|
||||||
|
equals(e) {
|
||||||
|
return (
|
||||||
|
WAS.Assert.optionalIsType(e, WAS.NodePath.#e),
|
||||||
|
!!e &&
|
||||||
|
this.#t === e.#t &&
|
||||||
|
this.#n === e.#n &&
|
||||||
|
this.#o === e.#o &&
|
||||||
|
this.#a === e.#a &&
|
||||||
|
this.#i === e.#i &&
|
||||||
|
this.#s === e.#s
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static #h = 1e3;
|
||||||
|
static #l = 500;
|
||||||
|
static #c = 200;
|
||||||
|
static #m = 200;
|
||||||
|
static #N = 100;
|
||||||
|
static #p = 10;
|
||||||
|
#u;
|
||||||
|
#C;
|
||||||
|
#_;
|
||||||
|
#P;
|
||||||
|
#A;
|
||||||
|
#f;
|
||||||
|
constructor(
|
||||||
|
e,
|
||||||
|
{
|
||||||
|
startContainerAdditionalComponents: t,
|
||||||
|
startContainerOffset: n,
|
||||||
|
endContainerAdditionalComponents: o,
|
||||||
|
endContainerOffset: a,
|
||||||
|
} = {},
|
||||||
|
) {
|
||||||
|
(WAS.Assert.arrayContentIsType(e, WAS.NodePath.#e),
|
||||||
|
WAS.Assert.isTrue(
|
||||||
|
e[0]?.type == Node.DOCUMENT_NODE,
|
||||||
|
"First path component should always be a document node.",
|
||||||
|
),
|
||||||
|
(this.#u = e),
|
||||||
|
(this.#_ = t),
|
||||||
|
(this.#P = n),
|
||||||
|
(this.#A = o),
|
||||||
|
(this.#f = a));
|
||||||
|
}
|
||||||
|
static #g(e, t) {
|
||||||
|
WAS.Assert.isType(e, Node);
|
||||||
|
let n = [],
|
||||||
|
o = e,
|
||||||
|
a = 0;
|
||||||
|
for (; o && (++a, !(a > 512)); ) {
|
||||||
|
let e;
|
||||||
|
for (
|
||||||
|
;
|
||||||
|
o && (n.push(WAS.NodePath.#e.fromNode(o)), (e = o), o !== t);
|
||||||
|
o = o.parentNode
|
||||||
|
);
|
||||||
|
if (e === t) break;
|
||||||
|
let a = Document.nodePath_defaultView(e);
|
||||||
|
if (a) {
|
||||||
|
o = a.frameElement;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let i = ShadowRoot.nodePath_host(e);
|
||||||
|
i && (o = i);
|
||||||
|
}
|
||||||
|
return n.toReversed();
|
||||||
|
}
|
||||||
|
static from(e, t) {
|
||||||
|
return e instanceof Range
|
||||||
|
? WAS.NodePath.fromRange(e, t)
|
||||||
|
: WAS.NodePath.fromNode(e, t);
|
||||||
|
}
|
||||||
|
static fromNode(e, t) {
|
||||||
|
let n = new WAS.NodePath(WAS.NodePath.#g(e, t));
|
||||||
|
return ((n.#C = new WeakRef(Range.nodePath_fromNode(e))), n);
|
||||||
|
}
|
||||||
|
static fromRange(e, t) {
|
||||||
|
let n = Range.nodePath_singleElementFromRange(e);
|
||||||
|
if (n) return WAS.NodePath.fromNode(n, t);
|
||||||
|
let o,
|
||||||
|
a,
|
||||||
|
i,
|
||||||
|
s,
|
||||||
|
d = WAS.NodePath.#g(e.commonAncestorContainer, t),
|
||||||
|
r = Range.nodePath_startNodeFromRange(e);
|
||||||
|
r
|
||||||
|
? (o = WAS.NodePath.#g(r, e.commonAncestorContainer).toSpliced(0, 1))
|
||||||
|
: e.startContainer !== e.commonAncestorContainer
|
||||||
|
? ((o = WAS.NodePath.#g(
|
||||||
|
e.startContainer,
|
||||||
|
e.commonAncestorContainer,
|
||||||
|
).toSpliced(0, 1)),
|
||||||
|
(a = e.startOffset))
|
||||||
|
: (o = []);
|
||||||
|
let h = Range.nodePath_endNodeFromRange(e);
|
||||||
|
h
|
||||||
|
? (i = WAS.NodePath.#g(h, e.commonAncestorContainer).toSpliced(0, 1))
|
||||||
|
: e.endContainer !== e.commonAncestorContainer
|
||||||
|
? ((i = WAS.NodePath.#g(
|
||||||
|
e.endContainer,
|
||||||
|
e.commonAncestorContainer,
|
||||||
|
).toSpliced(0, 1)),
|
||||||
|
(s = e.endOffset))
|
||||||
|
: (i = []);
|
||||||
|
let l = new WAS.NodePath(d, {
|
||||||
|
startContainerAdditionalComponents: o,
|
||||||
|
startContainerOffset: a,
|
||||||
|
endContainerAdditionalComponents: i,
|
||||||
|
endContainerOffset: s,
|
||||||
|
});
|
||||||
|
return ((l.#C = new WeakRef(e)), l);
|
||||||
|
}
|
||||||
|
static fromObjectRepresentation(e) {
|
||||||
|
const t = (e) => (
|
||||||
|
WAS.Assert.isType(e, Array),
|
||||||
|
e.map((e) => WAS.NodePath.#e.fromObjectRepresentation(e))
|
||||||
|
);
|
||||||
|
return Array.isArray(e)
|
||||||
|
? new WAS.NodePath(t(e))
|
||||||
|
: (WAS.Assert.isType(e, Object),
|
||||||
|
new WAS.NodePath(t(e.pathComponents), {
|
||||||
|
startContainerAdditionalComponents:
|
||||||
|
e.startContainerAdditionalComponents
|
||||||
|
? t(e.startContainerAdditionalComponents)
|
||||||
|
: void 0,
|
||||||
|
startContainerOffset: e.startContainerOffset ?? void 0,
|
||||||
|
endContainerAdditionalComponents: e.endContainerAdditionalComponents
|
||||||
|
? t(e.endContainerAdditionalComponents)
|
||||||
|
: void 0,
|
||||||
|
endContainerOffset: e.endContainerOffset ?? void 0,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
get objectRepresentation() {
|
||||||
|
const e = (e) => (
|
||||||
|
WAS.Assert.isType(e, Array),
|
||||||
|
e.map((e) => e.objectRepresentation)
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
pathComponents: e(this.#u),
|
||||||
|
startContainerAdditionalComponents: this.#_ ? e(this.#_) : void 0,
|
||||||
|
startContainerOffset: this.#P,
|
||||||
|
endContainerAdditionalComponents: this.#A ? e(this.#A) : void 0,
|
||||||
|
endContainerOffset: this.#f,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static nodePathIsKnownFormControlInputElement(e) {
|
||||||
|
let t = e?.pathComponents.at(-1)?.tag?.toUpperCase();
|
||||||
|
switch (t) {
|
||||||
|
case "INPUT":
|
||||||
|
case "SELECT":
|
||||||
|
case "TEXTAREA":
|
||||||
|
return !0;
|
||||||
|
default:
|
||||||
|
return !1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get pathComponents() {
|
||||||
|
return this.#u;
|
||||||
|
}
|
||||||
|
get userFriendlySummary() {
|
||||||
|
let e = this.#u.at(-1);
|
||||||
|
return e.type === Node.TEXT_NODE
|
||||||
|
? e.text.trim()
|
||||||
|
: e.text
|
||||||
|
? `${e.tag.toLowerCase()}: "${e.text.trim()}"`
|
||||||
|
: e.tag.toLowerCase();
|
||||||
|
}
|
||||||
|
toString() {
|
||||||
|
return JSON.stringify(this.objectRepresentation);
|
||||||
|
}
|
||||||
|
equals(e) {
|
||||||
|
if ((WAS.Assert.optionalIsType(e, WAS.NodePath), !e)) return !1;
|
||||||
|
if (this.#u.length !== e.#u.length) return !1;
|
||||||
|
for (let t = 0; t < this.#u.length; ++t)
|
||||||
|
if (!this.#u[t].equals(e.#u[t])) return !1;
|
||||||
|
if (this.#_?.length !== e.#_?.length) return !1;
|
||||||
|
for (let t = 0; t < this.#_?.length; ++t)
|
||||||
|
if (!this.#_[t].equals(e.#_[t])) return !1;
|
||||||
|
if (this.#A?.length !== e.#A?.length) return !1;
|
||||||
|
for (let t = 0; t < this.#A?.length; ++t)
|
||||||
|
if (!this.#A[t].equals(e.#A[t])) return !1;
|
||||||
|
return this.#P === e.#P && this.#f === e.#f;
|
||||||
|
}
|
||||||
|
resolvedRangeInDocument(e) {
|
||||||
|
let t = this.#C?.deref();
|
||||||
|
if (t?.intersectsNode(e)) return t;
|
||||||
|
if (this.#_ && this.#A) {
|
||||||
|
let t = WAS.NodePath.#E(e, [...this.#u, ...this.#_]),
|
||||||
|
n = WAS.NodePath.#E(e, [...this.#u, ...this.#A]);
|
||||||
|
if (!t || !n) return null;
|
||||||
|
let o = new Range();
|
||||||
|
return (
|
||||||
|
this.#P ? o.setStart(t, this.#P) : o.setStartBefore(t),
|
||||||
|
this.#f ? o.setEnd(n, this.#f) : o.setEndAfter(n),
|
||||||
|
(this.#C = new WeakRef(o)),
|
||||||
|
o
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let n = WAS.NodePath.#E(e, this.#u);
|
||||||
|
if (!n) return null;
|
||||||
|
let o = Range.nodePath_fromNode(n);
|
||||||
|
return ((this.#C = new WeakRef(o)), o);
|
||||||
|
}
|
||||||
|
static #E(e, t) {
|
||||||
|
(WAS.Assert.isType(e, Node),
|
||||||
|
WAS.Assert.isTrue(
|
||||||
|
Document.nodePath_isDocument(e),
|
||||||
|
"Must provide root document node in which to resolve this NodePath.",
|
||||||
|
));
|
||||||
|
let n = e;
|
||||||
|
e: for (let e = 1; e < t.length && n; ++e) {
|
||||||
|
let o = t[e],
|
||||||
|
a = -1,
|
||||||
|
i = null;
|
||||||
|
const s = () => {
|
||||||
|
n = i;
|
||||||
|
let o = t.length > e ? t[e + 1] : null;
|
||||||
|
return n &&
|
||||||
|
HTMLIFrameElement.nodePath_isHTMLIFrameElement(n) &&
|
||||||
|
o?.type === Node.DOCUMENT_NODE
|
||||||
|
? (++e,
|
||||||
|
void (n = HTMLIFrameElement.nodePath_contentWindowDocument(n)))
|
||||||
|
: n && o?.type === Node.DOCUMENT_FRAGMENT_NODE
|
||||||
|
? (++e, void (n = Element.nodePath_shadowRoot(n)))
|
||||||
|
: void 0;
|
||||||
|
};
|
||||||
|
if (Element.nodePath_isElement(n)) {
|
||||||
|
let o = [],
|
||||||
|
a = e;
|
||||||
|
for (; a < t.length; ++a) {
|
||||||
|
let e = t[a];
|
||||||
|
if (e.type !== Node.ELEMENT_NODE) break;
|
||||||
|
o.push(e.toElementCSSSelector());
|
||||||
|
}
|
||||||
|
if (o.length) {
|
||||||
|
const t = (e) => o.slice(0, o.length - e).join(" > ");
|
||||||
|
let d = null;
|
||||||
|
for (let r = 0; r < o.length; ++r)
|
||||||
|
if (
|
||||||
|
((d = Element.nodePath_querySelectorAll(n, t(r))),
|
||||||
|
1 === d.length)
|
||||||
|
) {
|
||||||
|
((i = d.item(0)), (e = a - r - 1), s());
|
||||||
|
continue e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let d = 0;
|
||||||
|
for (
|
||||||
|
let e = Node.nodePath_firstChild(n);
|
||||||
|
e;
|
||||||
|
e = Node.nodePath_nextSibling(e)
|
||||||
|
) {
|
||||||
|
if (!Node.nodePath_includeWhenComputingSiblingIndex(e)) continue;
|
||||||
|
let t = Number.MIN_VALUE,
|
||||||
|
n = !0;
|
||||||
|
const s = (e, o) => {
|
||||||
|
e ? (t += o) : (n = !1);
|
||||||
|
},
|
||||||
|
r = (e, o) => {
|
||||||
|
(1 !== e && (n = !1), (t += e * o));
|
||||||
|
},
|
||||||
|
h = (e) => {
|
||||||
|
e && ((n = !1), (t -= e));
|
||||||
|
};
|
||||||
|
if (
|
||||||
|
(s(Node.nodePath_nodeType(e) === o.type, WAS.NodePath.#h),
|
||||||
|
Element.nodePath_isElement(e))
|
||||||
|
) {
|
||||||
|
(s(Element.nodePath_tagName(e) == o.tag, WAS.NodePath.#l),
|
||||||
|
s(Element.nodePath_id(e) == o.id, WAS.NodePath.#c));
|
||||||
|
let t = Element.nodePath_className(e)?.split(" ") ?? [],
|
||||||
|
n = t.length,
|
||||||
|
a = o.classes?.split(" ") ?? [],
|
||||||
|
i = a.length;
|
||||||
|
for (let e = 0; e < a.length; ++e) {
|
||||||
|
let n = a[e],
|
||||||
|
o = t.indexOf(n);
|
||||||
|
-1 !== o && (t.splice(o, 1), a.splice(e, 1), --e);
|
||||||
|
}
|
||||||
|
(r(
|
||||||
|
(n ? (n - t.length) / n : 1) * (i ? (i - a.length) / i : 1),
|
||||||
|
WAS.NodePath.#N,
|
||||||
|
),
|
||||||
|
r(
|
||||||
|
Node.nodePath_immediateInnerTextOfNode(e).nodePath_similarityTo(
|
||||||
|
o.text,
|
||||||
|
),
|
||||||
|
WAS.NodePath.#m,
|
||||||
|
));
|
||||||
|
} else if (Text.nodePath_isText(e)) {
|
||||||
|
let t = CharacterData.nodePath_data(e)?.nodePath_similarityTo(
|
||||||
|
o.text,
|
||||||
|
);
|
||||||
|
r(t, WAS.NodePath.#m);
|
||||||
|
}
|
||||||
|
if ((h(Math.abs(d - o.index) * WAS.NodePath.#p), n)) {
|
||||||
|
((a = Number.NaN), (i = e));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t > a ? ((a = t), (i = e)) : t === a && ++d;
|
||||||
|
}
|
||||||
|
s();
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}));
|
||||||
145
js/utilities/SavePageInliningOrDiscardingExternalResources.js
Normal file
145
js/utilities/SavePageInliningOrDiscardingExternalResources.js
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
//# sourceURL=__InjectedScript_SavePageInliningOrDiscardingExternalResources.js
|
||||||
|
/* Copyright (c) 2025 Apple Inc. All rights reserved. */
|
||||||
|
function copyPage() {
|
||||||
|
function e(e) {
|
||||||
|
function t(e) {
|
||||||
|
var t = document.createElement("a");
|
||||||
|
return ((t.href = e), t);
|
||||||
|
}
|
||||||
|
function r(e) {
|
||||||
|
var t = e.pathname.substring(1).split("/");
|
||||||
|
return (t[t.length - 1] || t.pop(), t);
|
||||||
|
}
|
||||||
|
function n(e) {
|
||||||
|
var t = r(e);
|
||||||
|
return t.length ? t[t.length - 1] : null;
|
||||||
|
}
|
||||||
|
return n(t(e));
|
||||||
|
}
|
||||||
|
function t(t) {
|
||||||
|
const r = /url\((.*?\/.*?)\)/gi;
|
||||||
|
for (;;) {
|
||||||
|
var n = r.exec(t);
|
||||||
|
if (!n) break;
|
||||||
|
t = t.replace(n[0], "url(" + e(n[1]) + ")");
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
function r(e) {
|
||||||
|
function r(e, n) {
|
||||||
|
if (e) {
|
||||||
|
var i, o;
|
||||||
|
try {
|
||||||
|
i = e.rules;
|
||||||
|
} catch (e) {
|
||||||
|
i = null;
|
||||||
|
}
|
||||||
|
if (!i) {
|
||||||
|
var u = e.ownerNode;
|
||||||
|
if (!u) return;
|
||||||
|
var c = u.parentNode;
|
||||||
|
if (!c) return;
|
||||||
|
var l = u.nextSibling;
|
||||||
|
return (c.removeChild(u), r(e, n), void c.insertBefore(u, l));
|
||||||
|
}
|
||||||
|
for (var d = i.length, s = 0; s < d; ++s) {
|
||||||
|
var m = i[s];
|
||||||
|
m.type !== CSSRule.IMPORT_RULE
|
||||||
|
? (o ||
|
||||||
|
((o = document.createElement("style")),
|
||||||
|
e.media &&
|
||||||
|
e.media.length > 0 &&
|
||||||
|
o.setAttribute("media", e.media.mediaText),
|
||||||
|
n && n.media && o.setAttribute("media", n.media.mediaText),
|
||||||
|
a.push(o)),
|
||||||
|
o.appendChild(document.createTextNode(t(m.cssText) + "\n")))
|
||||||
|
: r(m.styleSheet, m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var n = e.styleSheets, a = [], i = n.length, o = 0; o < i; ++o)
|
||||||
|
r(n[o]);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
function n(e, r) {
|
||||||
|
for (var n = e.attributes, a = n.length, i = 0; i < a; ++i) {
|
||||||
|
var o = n[i],
|
||||||
|
u = o.name.toLowerCase();
|
||||||
|
if ("on" !== u.substr(0, 2)) {
|
||||||
|
var c = o.value;
|
||||||
|
"style" === u && (c = t(c));
|
||||||
|
try {
|
||||||
|
r.setAttribute(o.name, c);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function a(e, t) {
|
||||||
|
for (var r = e.childNodes, n = r.length, a = 0; a < n; ++a) {
|
||||||
|
var o = i(r[a]);
|
||||||
|
o && t.appendChild(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function i(t) {
|
||||||
|
if (!t) return t;
|
||||||
|
if (t.nodeType === Node.TEXT_NODE) return document.createTextNode(t.data);
|
||||||
|
if (t.nodeType !== Node.ELEMENT_NODE) return null;
|
||||||
|
const c = new Set(["AUDIO", "OBJECT", "SCRIPT", "STYLE", "VIDEO"]);
|
||||||
|
var l = t.tagName.toUpperCase();
|
||||||
|
if (c.has(l)) return null;
|
||||||
|
if ("LINK" === l && "STYLESHEET" === t.rel.toUpperCase()) return null;
|
||||||
|
if ("META" === l && "CONTENT-TYPE" === t.httpEquiv.toUpperCase())
|
||||||
|
return null;
|
||||||
|
var d = document.createElement(t.tagName);
|
||||||
|
if (
|
||||||
|
(n(t, d),
|
||||||
|
a(t, d),
|
||||||
|
"IMG" === l || ("INPUT" === l && "IMAGE" === t.type.toUpperCase()))
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
(d.src = e(t.src)),
|
||||||
|
d.setAttribute("width", t.width),
|
||||||
|
d.setAttribute("height", t.height),
|
||||||
|
d
|
||||||
|
);
|
||||||
|
if ("IFRAME" === l) {
|
||||||
|
try {
|
||||||
|
var s = i(t.contentDocument.documentElement);
|
||||||
|
if (s) {
|
||||||
|
var m = "iframe_" + u + ".html";
|
||||||
|
((d.src = m),
|
||||||
|
(s.dataset.originalSource = t.src),
|
||||||
|
(o[m] = s.outerHTML),
|
||||||
|
u++);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
((d.src = ""),
|
||||||
|
d.appendChild(
|
||||||
|
document.createTextNode(
|
||||||
|
"Failed to copy <iframe>: " + e + ": " + e.stack,
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
if ("INPUT" === l) d.setAttribute("value", t.value);
|
||||||
|
else if ("HEAD" === l) {
|
||||||
|
for (var f = r(t.ownerDocument), h = f.length, p = 0; p < h; ++p)
|
||||||
|
(d.appendChild(document.createTextNode("\n")), d.appendChild(f[p]));
|
||||||
|
var v = document.createElement("meta");
|
||||||
|
((v.httpEquiv = "Content-Type"),
|
||||||
|
(v.content = "text/html; charset=UTF-8"),
|
||||||
|
d.insertBefore(v, d.firstChild));
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
var o = {},
|
||||||
|
u = 0,
|
||||||
|
c = i(document.documentElement);
|
||||||
|
return (
|
||||||
|
(c.dataset.originSource = window.location),
|
||||||
|
(o["main.html"] = c.outerHTML),
|
||||||
|
o
|
||||||
|
);
|
||||||
|
}
|
||||||
|
copyPage();
|
||||||
Reference in New Issue
Block a user